Closed9

GritQL を使って Biome の Plugin を書いてみる

まっつーまっつー

試しに Hello world とマッチする GritQL を書いてみる

no-hello-world-console.grit
`console.log("Hello, world!")`
test.js
console.log("Hello, world!");
biome.jsonc
{
	"$schema": "https://biomejs.dev/schemas/2.0.6/schema.json",
	"formatter": {
		"enabled": true,
		"indentStyle": "tab"
	},
	"linter": {
		"enabled": true,
		"rules": {
			"recommended": false,
			"suspicious": {
			// "noConsole": "warn"
			}
		}
	},
	"javascript": {
		"formatter": {
			"quoteStyle": "double"
		}
	},
	"assist": {
		"enabled": false
	},
	"plugins": ["./plugins/no-hello-world-console.grit"]
}

Lint を実行しても警告が出てくれない。

全く同じ構文で biome search コマンドを実行するという検知してくれる。

まっつーまっつー

他の書き方を試したがこれも警告が出ない。

`console.log($message)`
`console.$method($message)` where {
    $method <: `log`
}

どちらとも biome search では検知される。

まっつーまっつー
no-object-assign.grit
`$fn($args)` where {
    $fn <: `Object.assign`,
    register_diagnostic(
        span = $fn,
        message = "Prefer object spread instead of `Object.assign()`"
    )
}
test.js
Object.assign({}, { a: 1, b: 2 });

Linter プラグインの例にあるパターンを試したら動いた。

まっつーまっつー

CSS 用のルールを書く場合は一番上に language の指定が必要。

no-explicit-colors.grit
language css;

`$selector { $props }` where {
    $props <: contains `color: $color` as $rule,
    not $selector <: r"\.color-.*",
    register_diagnostic(
        span = $rule,
        message = "Don't set explicit colors. Use `.color-*` classes instead."
    )
}
test.css
a {
    color: red;
}

.color-primary {
    color: blue;
}

.color-secondary {
    color: green;
}

この場合 .color-* クラス以外で色を設定すると警告が出る。

まっつーまっつー

単純にノードを使ってマッチングするだけじゃだめで register_diagnostic() を使って、

  • span: 警告対象のノード
  • message: エラーメッセージ
  • severity: 重要度 (オプショナル)

を指定する必要がある。
最初の console.log に対する Plugin はこれがないから何も表示されなかった。

no-hello-world-console.grit
`console.log($args)` where {
  $args <: `"Hello, world!"`,
  register_diagnostic(
    span = $args,
    message = "Avoid using console.log('Hello, world!') in production code",
    severity = "error"
  )
}

無事に動いた。

まっつーまっつー
no-console.grit
`console.$method($args)` where {
  register_diagnostic(
    span = $method,
    message = "Don't use console methods in production code",
    severity = "warn"
    )
}

console* を一括で禁止したい場合は上記のように Metavariables を使って書くことができる。

まっつーまっつー

感想や気になったことなど

  • ESLint の no-restricted-syntax みたいに AST Explorer 使って、サクッと書くみたいな方法があるのかな。ある程度は Metavariables でカバーできそうな気もするけど。
  • テストがマークダウンと YAML しかサポートされてなさそう?
  • Pattern ModifiersConditional Operators を使った複雑なクエリも試したい
  • Rewrites の例にあるように lint error の autofix 対応がしやすそう
    • こういうやつ
      `console.log($my_message)` => `winston.info($my_message)`
      
  • Playground 使おうとしたら壊れてた😇
このスクラップは3ヶ月前にクローズされました