TSLint仕様を使用してコードをカスタマイズするRule
10343 ワード
TSLint仕様を使用してコードをカスタマイズするRule
TSLintはあなたのコードを規範化することができて、vs codeの上のTSLintプラグインに協力して、あなたのコードの潔癖さを治療することができます.
社内のコードスタイルを統一するために、最近会社もいくつかのRuleを開発して、Prettierに協力してまだエイズではありませんか?私はこのRuleの開発を担当しています.TSlintは国内の資料が少ないし、TSLint自身のドキュメントもカスタムRuleの開発について曖昧なので、いろいろな資料を探したり、ソースコードを見たりすることは避けられません.最初のRuleを書くと、後の開発がスムーズになります.今も開発中なので、暇を見つけてブログを書いて、カスタムRuleを書きたい人たちを助けて、回り道をしないでください.興味があれば、私たちが開発しているMagicSpaceにも足を踏み入れることができます.まだ開発中ですが、Star✨下呗:)
公式の例から見ると
本題に入る.
公式の例もはっきりしているので、まず公式の例を見てみましょう.
あなたが書くRuleをnoImportRuleと呼ぶとします.ts、このファイルでは、Ruleという名前のクラスをエクスポートし、継承Rulesを表示する必要があります.AbstraactRuleを実装し、そのapplyメソッドを実装します.applyメソッドには、現在Ruleが適用されているソースファイルであるsourceFileのパラメータがあります.戻り値はRuleFailureであり、TSLintでは、Ruleに一致しないものはFailureとみなされ、この戻り値はFailure配列であり、もちろん、私たちは直接それを返すのではなく、Walkerを返します.
WalkerはRuleの核心部分であり、どこが規定に合わないのか、どこでfailureを加えるべきかを判断する仕事です.NoImportsWalkerを宣言します.ここにはRuleWalkerを継承すると書かれています.RuleWalkerはアクセス者に相当します.visitImportDeclarationなど、ソースファイルにアクセスするすべてのimport宣言文にアクセスできます.パラメータnodeが手に入れたのはimportの式で、NodeはASTのノードを表します(TSLintではルールをチェックする前に、まずあなたのソースコードをASTに変換し、いくつかの方法でASTのノードを抽出します.TSLintではTSUtilというツールを使っています.TSLintがこんなに火をつけていると同時に、TSUtilは数十人のstarしかありません.TSLintは火をつけていないようですね.皆さんがASTのノードをどのように抽出するか興味がないのかもしれません.興味があるのはTSLintでしょう)、あとでこのノードを手に入れることでこのノード上の方法を実行することができます.例えば、getText()でこの点の内容を取得したり、getChildren、getParentでこのノードの親子ノードを取得したりするなど、似たような方法がたくさんあります.
コードの
このruleの機能はimport文を禁止して、実行して効果を見ますか?
例えばここで勝手にモジュールを導入します
この文はTSLintによって間違って報告されていることがわかります.これはaddFailureの役割です.
WalkerとFunction
簡単なRuleで書きました.このように見るのは簡単ではないでしょうか.
実は普通はカスタマイズのRuleをする時、私達は普通は直接RuleWalkerを継承しないで、AbstractWalkerを継承して、それからそのwalkの方法を実現して、例えば以下は私のMagicSpaceの中の1つのコードの断片です
このwalkerは、関数式、矢印関数、関数宣言文、メソッド宣言など、私が望む関数ノードを取得するために使用されます.TSLintはルールチェックをするときにwalkを呼び出すので、ルール判定要求を達成するために判断ロジックを書くことができます.
それ以外に、ruleが簡単であれば、walkerクラスを作成する必要はありませんが、applyWithFunctionを直接使用することができます.機能的にwalkerと差は多くありません.walkerの代わりに関数を使うだけです.
たとえば
この関数はWalkerのwalkメソッドに相当し、ルールをチェックするときにもこの関数を呼び出し、ctxパラメータはWalkerのコンテキストに相当します.addFailureを呼び出す場合は、
基本的にwalkerと同じ機能を実現できます.
論理的に比較的簡単なRuleでは、
Metadata
それ以外に、このRuleを記述するために、Ruleのクラスにメタデータを書くこともできます.私が書いたMetadataを見て
ここのフィールドの意味はやはりみんながドキュメントを見に来て、ここではもう説明しません.多くのフィールドはオプションで、自分の状況を見て選択する必要があります.具体的には、
対応する式の検索
ファイル全体のimport宣言文を収集したい場合、kindで判断できるように、対応する式を探す必要があります.kindって何?
Oh、実際の例を見てみましょう.
ここではstatementごとのkindを比較することですべてのimportの宣言文を取得できますが、
上のコードは
便利かどうかはたくさんありますが、もちろん、importだけではありません.
まとめ
TSLintはもちろんTSに必要なスタイルチェックのツールですが、TSLintが持っているいくつかのルールは私たちの奇妙な要求を満たすことができません.それでは、自分でTSLint Ruleを書いて、スタイルの面でコードを規範化するのを助ける必要があります.しばらくはこれらを書くことだけを考えて、国内のTSLint資料は少なすぎて、この博文はただみんなに少しの構想を見つけることを助けて、もちろん、やはりドキュメントとソースコードを結びつけて自分のTSLint規則を構築しなければなりません.
TSLintはあなたのコードを規範化することができて、vs codeの上のTSLintプラグインに協力して、あなたのコードの潔癖さを治療することができます.
社内のコードスタイルを統一するために、最近会社もいくつかのRuleを開発して、Prettierに協力してまだエイズではありませんか?私はこのRuleの開発を担当しています.TSlintは国内の資料が少ないし、TSLint自身のドキュメントもカスタムRuleの開発について曖昧なので、いろいろな資料を探したり、ソースコードを見たりすることは避けられません.最初のRuleを書くと、後の開発がスムーズになります.今も開発中なので、暇を見つけてブログを書いて、カスタムRuleを書きたい人たちを助けて、回り道をしないでください.興味があれば、私たちが開発しているMagicSpaceにも足を踏み入れることができます.まだ開発中ですが、Star✨下呗:)
公式の例から見ると
本題に入る.
公式の例もはっきりしているので、まず公式の例を見てみましょう.
import * as ts from "typescript";
import * as Lint from "tslint";
export class Rule extends Lint.Rules.AbstractRule {
public static FAILURE_STRING = "import statement forbidden";
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithWalker(new NoImportsWalker(sourceFile, this.getOptions()));
}
}
// The walker takes care of all the work.
class NoImportsWalker extends Lint.RuleWalker {
public visitImportDeclaration(node: ts.ImportDeclaration) {
// create a failure at the current position
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING));
// call the base version of this visitor to actually parse this node
super.visitImportDeclaration(node);
}
}
あなたが書くRuleをnoImportRuleと呼ぶとします.ts、このファイルでは、Ruleという名前のクラスをエクスポートし、継承Rulesを表示する必要があります.AbstraactRuleを実装し、そのapplyメソッドを実装します.applyメソッドには、現在Ruleが適用されているソースファイルであるsourceFileのパラメータがあります.戻り値はRuleFailureであり、TSLintでは、Ruleに一致しないものはFailureとみなされ、この戻り値はFailure配列であり、もちろん、私たちは直接それを返すのではなく、Walkerを返します.
WalkerはRuleの核心部分であり、どこが規定に合わないのか、どこでfailureを加えるべきかを判断する仕事です.NoImportsWalkerを宣言します.ここにはRuleWalkerを継承すると書かれています.RuleWalkerはアクセス者に相当します.visitImportDeclarationなど、ソースファイルにアクセスするすべてのimport宣言文にアクセスできます.パラメータnodeが手に入れたのはimportの式で、NodeはASTのノードを表します(TSLintではルールをチェックする前に、まずあなたのソースコードをASTに変換し、いくつかの方法でASTのノードを抽出します.TSLintではTSUtilというツールを使っています.TSLintがこんなに火をつけていると同時に、TSUtilは数十人のstarしかありません.TSLintは火をつけていないようですね.皆さんがASTのノードをどのように抽出するか興味がないのかもしれません.興味があるのはTSLintでしょう)、あとでこのノードを手に入れることでこのノード上の方法を実行することができます.例えば、getText()でこの点の内容を取得したり、getChildren、getParentでこのノードの親子ノードを取得したりするなど、似たような方法がたくさんあります.
コードの
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING));
は、addFailureを呼び出してエラーを追加する目的です.このruleの機能はimport文を禁止して、実行して効果を見ますか?
例えばここで勝手にモジュールを導入します
import * as Foo from './foo'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [import statement forbidden]
この文はTSLintによって間違って報告されていることがわかります.これはaddFailureの役割です.
WalkerとFunction
簡単なRuleで書きました.このように見るのは簡単ではないでしょうか.
実は普通はカスタマイズのRuleをする時、私達は普通は直接RuleWalkerを継承しないで、AbstractWalkerを継承して、それからそのwalkの方法を実現して、例えば以下は私のMagicSpaceの中の1つのコードの断片です
class ExplicitReturnTypeWalker extends AbstractWalker<undefined> {
/** */
walk(sourceFile: TypeScript.SourceFile): void {
let cb = (node: TypeScript.Node): void => {
if (
(TypeScript.isFunctionDeclaration(node) ||
TypeScript.isArrowFunction(node) ||
TypeScript.isFunctionExpression(node) ||
TypeScript.isMethodDeclaration(node)) &&
node.type
) {
}
TypeScript.forEachChild(node, cb);
};
TypeScript.forEachChild(sourceFile, cb);
}
}
このwalkerは、関数式、矢印関数、関数宣言文、メソッド宣言など、私が望む関数ノードを取得するために使用されます.TSLintはルールチェックをするときにwalkを呼び出すので、ルール判定要求を達成するために判断ロジックを書くことができます.
それ以外に、ruleが簡単であれば、walkerクラスを作成する必要はありませんが、applyWithFunctionを直接使用することができます.機能的にwalkerと差は多くありません.walkerの代わりに関数を使うだけです.
protected applyWithFunction(sourceFile: ts.SourceFile, walkFn: (ctx: WalkContext<void>) => void): RuleFailure[];
protected applyWithFunction<T>(sourceFile: ts.SourceFile, walkFn: (ctx: WalkContext) => void, options: NoInfer) : RuleFailure[];
protected applyWithFunction<T, U>(sourceFile: ts.SourceFile, walkFn: (ctx: WalkContext, programOrChecker: U) => void, options: NoInfer, checker: NoInfer) : RuleFailure[];
たとえば
applyWithFunction(souceFile, ctx => {
// some logic
})
この関数はWalkerのwalkメソッドに相当し、ルールをチェックするときにもこの関数を呼び出し、ctxパラメータはWalkerのコンテキストに相当します.addFailureを呼び出す場合は、
this.addFailure
で呼び出すのではなく、ctx.addFailure
で呼び出す.基本的にwalkerと同じ機能を実現できます.
論理的に比較的簡単なRuleでは、
applyWithFunction
の方が軽量になる可能性があります.Metadata
それ以外に、このRuleを記述するために、Ruleのクラスにメタデータを書くこともできます.私が書いたMetadataを見て
static metadata: IRuleMetadata = {
ruleName: 'import-groups',
description: 'Validate that module imports are grouped as expected.',
optionsDescription: '',
options: {
properties: {
groups: {
items: {
properties: {
name: {
type: 'string',
},
test: {
type: 'string',
},
},
type: 'object',
},
type: 'array',
},
ordered: {
type: 'boolean',
},
},
type: 'object',
},
optionExamples: [
[
true,
{
groups: [
{name: 'node-core', test: '$node-core'},
{name: 'node-modules', test: '$node-modules'},
],
ordered: true,
},
],
],
type: 'maintainability',
hasFix: true,
typescriptOnly: false,
};
ここのフィールドの意味はやはりみんながドキュメントを見に来て、ここではもう説明しません.多くのフィールドはオプションで、自分の状況を見て選択する必要があります.具体的には、
rule.d.ts
のIMetadataインタフェースを参照してください.対応する式の検索
ファイル全体のimport宣言文を収集したい場合、kindで判断できるように、対応する式を探す必要があります.kindって何?
Node.kind
は、このノードの意味タイプを表す整数であり、列挙クラスts.SyntaxKind
は完全な対応関係を有する.Oh、実際の例を見てみましょう.
import * as TypeScript form 'typescript'
for (let statement of sourceFile.statements) {
if (statement.kind === Typescript.SyntaxKind.ImportDeclaration) {
//...
}
ここではstatementごとのkindを比較することですべてのimportの宣言文を取得できますが、
isImportDeclaration
などの直接呼び出す方法がtsutilにカプセル化されています.上のコードは
import * as TypeScript form 'typescript'
for (let statement of sourceFile.statements) {
if (isImportDeclaration(statement)) {
//...
}
findImports
の方法で、すべてのimport文を迅速に見つけることができます.for (const expression of findImports(
sourceFile,
ImportKind.AllStaticImports,
)) {
//...
}
便利かどうかはたくさんありますが、もちろん、importだけではありません.
まとめ
TSLintはもちろんTSに必要なスタイルチェックのツールですが、TSLintが持っているいくつかのルールは私たちの奇妙な要求を満たすことができません.それでは、自分でTSLint Ruleを書いて、スタイルの面でコードを規範化するのを助ける必要があります.しばらくはこれらを書くことだけを考えて、国内のTSLint資料は少なすぎて、この博文はただみんなに少しの構想を見つけることを助けて、もちろん、やはりドキュメントとソースコードを結びつけて自分のTSLint規則を構築しなければなりません.