在有角度的应用程序中,TSLint能否通过相对路径通过路径映射iso强制执行模块导入?

时间:2019-01-18 15:13:46

标签: angular typescript tslint

说我对角度项目有以下设置:

apps/my-app
libs/my-comp/my-lib

在my-app代码中,我使用my-lib中的代码。我可以通过打字稿导入来导入my-lib代码,例如import ../../libs/my-comp/my-lib,但这很丑陋且容易出错。使用path mapping,我可以模拟模块导入,例如import { MyLibModule} from @my-comp/my-lib。更清洁。

但是,我们可以强制执行吗?我们如何防止开发人员使用相对路径从另一个模块导入代码?是否有TSLint规则?我们应该编写自定义的TSLint代码吗?有人已经尝试这样做了吗:)?

1 个答案:

答案 0 :(得分:1)

我们有类似的设置,并且实现了2个自定义的皮棉规则:

  • 禁止从my-lib进行相对导入,
  • 禁止从@my-comp/my-lib内部导入库本身

也许更好的设置是使用nx-workspace(请参阅“预建约束”部分)。它具有类似的规则,并增加了更多内容:

  • 库无法导入应用。
  • 通过loadChildren加载库的项目也无法使用ESM导入来导入它。
  • 不允许循环依赖。
  • 不能使用相对导入来导入库。

这是我们禁止从库中进行相对导入的规则的实现。它可以工作,但可能有一些我们尚未发现的严重问题(例如使皮棉变慢:)

import * as ts from 'typescript';
import * as Lint from 'tslint';

export class Rule extends Lint.Rules.AbstractRule {
    static readonly FAILURE_STRING = `Import should be from '${Rule.SHARED_IMPORT}'`;
    static readonly SHARED_IMPORT = 'my-lib';

    public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
        return this.applyWithFunction(sourceFile, walk);
    }
}

function walk(ctx: Lint.WalkContext<void>) {
    return ts.forEachChild(ctx.sourceFile, cb);

    function cb(node: ts.Node): void {
        if (node.kind !== ts.SyntaxKind.ImportDeclaration) {
            return;
        }

        const importLocation = getImportLocation(node.getText());

        if (containsIncorrectImportFromSharedFolder(importLocation)) {
            const locationWidth = importLocation.length + 3;
            const fix = new Lint.Replacement(node.getEnd() - locationWidth, locationWidth, `'${Rule.SHARED_IMPORT}';`);
            return ctx.addFailureAtNode(node, Rule.FAILURE_STRING, fix);
        }

        return ts.forEachChild(node, cb);
    }

    function containsIncorrectImportFromSharedFolder(importLocation: String): boolean {
        return importLocation.indexOf(Rule.SHARED_IMPORT) > -1 && importLocation !== Rule.SHARED_IMPORT;
    }

    function getImportLocation(location: string): string {
        const importLocation = location.match(/'(.*?[^'])'/);
        return importLocation !== null ? importLocation[1] : '';
    }
}

您必须使用js将规则编译为tsc

node "node_modules/typescript/bin/tsc" tools/tslint-rules/myLibImportRule.ts

,您必须将其添加到tslint.json

"rulesDirectory": [
    ...
    "tools/tslint-rules",
    ...
],
"rules": {
    ...,
    "my-lib-import": true,
    ...
}

规则名称是文件myLibImportRule.js => my-lib-import的名称。