装饰器, ESLint与代码检查
My Dear Decorator ~ Love story between ESLint & TypeScript Decorator!
Zapic
2024-11-29 0

装饰器, HTTP请求与Typescript中, 我们使用装饰器实现了声明式的API描述与调用, 但问题在于ESLint并不认为这是好的.
no-unused-vars
为了让ESLint能够识别这个新的用法, 我们需要写一些新的ESLint规则.

1. 这是好的

首先我们需要让ESLint停止将这些变量标记为未使用, 由于我能力有限, 实在没有找到合适的办法, 只能hook原来的no-unused-vars检查函数, 并检查每个被报告为未使用的函数参数是否被装饰器装饰:

import { plugin } from "typescript-eslint";

const OrigNoUnUsedVars = plugin.rules["no-unused-vars"];
const rules = {
    "no-unused-vars": {
        meta: OrigNoUnUsedVars.meta,
        defaultOptions: OrigNoUnUsedVars.defaultOptions,
        create(ctx) {
            const hookedCtx = new Proxy({}, {
                get(target, name, receiver) {
                    if (name === "report") {
                        return function report(data) {
                            const node = ctx.sourceCode.getNodeByRangeIndex(ctx.sourceCode.getIndexFromLoc(data.loc.start));
                            if (node.type === "Identifier") {
                                // 普通参数, e.g. function a (@Deco p: string) {}
                                //                                 ^
                                if (node.decorators?.length > 0 && node.parent.type === "FunctionExpression") {
                                    return;
                                // 带默认值的参数, e.g. function a (@Deco p = "default") {}
                                //                                      ^
                                } else if (node.parent?.type === "AssignmentPattern" && node.parent.decorators?.length > 0) {
                                    return;
                                }
                            }
                            return ctx.report(data);
                        };
                    // 啥也不是
                    } else {
                        return Reflect.get(ctx, name, receiver);
                    }
                }
            });
            return OrigNoUnUsedVars.create(hookedCtx);
        }
    }
}

然后再将其添加回ESLint的ruleset中, 覆盖掉原来的no-unused-vars, 就会发现被装饰器装饰的函数参数不再被报未使用了.
但是这样显然太简单了, 既然都开始写了, 那我们也可以写一些更详细的检查.

2. 找出坏人

人能有多坏?

  1. 在一个方法/参数上同时使用多个装饰器

    @Get("/") 
    @Post("/") // 这是坏的!
    function a () {}
    @Get("/") 
    function a (
      @Param("a") @Param("b") a: string
      //          ^^^^^^^^^^^ 这是坏的!
    ) {}
  2. @Get等装饰器的URL参数变量未被声明

    @Get("/{id}")   
    //     ^^^^ 这是坏的!
    function a () {}
  3. @Path装饰器声明的参数在URL中没有对应的变量

    @Get("/")
    function a (
      @Path("a") a: string
    //^^^^^^^^^^ 这是坏的!
    ) {}

我们需要识别这些问题并给出提示.
// TO BE CONTINUE...

评论 0
没有评论
评论已关闭
发表评论
评论 取消回复
Copyright © 2024 Zapic's Blog