@markuplint/ml-core 4.13.2 → 5.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.ja.md +524 -0
- package/ARCHITECTURE.md +524 -0
- package/CHANGELOG.md +52 -2
- package/README.md +5 -0
- package/SKILL.md +61 -0
- package/docs/linting-pipeline.ja.md +307 -0
- package/docs/linting-pipeline.md +307 -0
- package/docs/maintenance.ja.md +210 -0
- package/docs/maintenance.md +210 -0
- package/docs/ml-dom/attr.ja.md +103 -0
- package/docs/ml-dom/attr.md +103 -0
- package/docs/ml-dom/block.ja.md +272 -0
- package/docs/ml-dom/block.md +272 -0
- package/docs/ml-dom/document.ja.md +141 -0
- package/docs/ml-dom/document.md +141 -0
- package/docs/ml-dom/element.ja.md +176 -0
- package/docs/ml-dom/element.md +176 -0
- package/docs/ml-dom/helpers.ja.md +203 -0
- package/docs/ml-dom/helpers.md +203 -0
- package/docs/ml-dom/node.ja.md +199 -0
- package/docs/ml-dom/node.md +199 -0
- package/docs/ml-dom/others.ja.md +120 -0
- package/docs/ml-dom/others.md +120 -0
- package/docs/ml-dom/overview.ja.md +102 -0
- package/docs/ml-dom/overview.md +102 -0
- package/docs/ml-dom/pretender.ja.md +269 -0
- package/docs/ml-dom/pretender.md +269 -0
- package/docs/ml-dom/rule-mapping.ja.md +371 -0
- package/docs/ml-dom/rule-mapping.md +371 -0
- package/docs/ml-dom.ja.md +18 -0
- package/docs/ml-dom.md +18 -0
- package/docs/rule-system.ja.md +287 -0
- package/docs/rule-system.md +287 -0
- package/lib/convert-ruleset.d.ts +7 -0
- package/lib/convert-ruleset.js +7 -0
- package/lib/debug.d.ts +4 -0
- package/lib/debug.js +4 -0
- package/lib/index.d.ts +4 -3
- package/lib/index.js +1 -1
- package/lib/ml-core.d.ts +37 -1
- package/lib/ml-core.js +171 -82
- package/lib/ml-dom/helper/accname.d.ts +8 -0
- package/lib/ml-dom/helper/accname.js +71 -55
- package/lib/ml-dom/helper/create-node.js +1 -0
- package/lib/ml-dom/helper/get-indent.d.ts +4 -1
- package/lib/ml-dom/helper/get-indent.js +21 -30
- package/lib/ml-dom/node/attr.d.ts +65 -4
- package/lib/ml-dom/node/attr.js +151 -53
- package/lib/ml-dom/node/block.d.ts +23 -2
- package/lib/ml-dom/node/block.js +24 -1
- package/lib/ml-dom/node/child-node.d.ts +9 -0
- package/lib/ml-dom/node/child-node.js +9 -0
- package/lib/ml-dom/node/comment.d.ts +7 -0
- package/lib/ml-dom/node/comment.js +7 -0
- package/lib/ml-dom/node/document-fragment.d.ts +8 -0
- package/lib/ml-dom/node/document-fragment.js +8 -0
- package/lib/ml-dom/node/document-type.d.ts +22 -0
- package/lib/ml-dom/node/document-type.js +25 -0
- package/lib/ml-dom/node/document.d.ts +88 -7
- package/lib/ml-dom/node/document.js +128 -32
- package/lib/ml-dom/node/dom-token-list.js +17 -30
- package/lib/ml-dom/node/element-close-tag.js +1 -0
- package/lib/ml-dom/node/element.d.ts +151 -5
- package/lib/ml-dom/node/element.js +242 -50
- package/lib/ml-dom/node/node-store.js +6 -15
- package/lib/ml-dom/node/node.d.ts +19 -1
- package/lib/ml-dom/node/node.js +175 -166
- package/lib/ml-dom/node/parent-node.js +14 -30
- package/lib/ml-dom/node/rule-mapper.js +7 -20
- package/lib/ml-dom/node/text.d.ts +19 -0
- package/lib/ml-dom/node/text.js +21 -0
- package/lib/ml-dom/node/types.d.ts +68 -0
- package/lib/ml-dom/token/token.d.ts +42 -0
- package/lib/ml-dom/token/token.js +59 -39
- package/lib/ml-rule/create-rule.d.ts +17 -1
- package/lib/ml-rule/ml-rule-context.js +7 -11
- package/lib/ml-rule/ml-rule.d.ts +66 -1
- package/lib/ml-rule/ml-rule.js +95 -25
- package/lib/ml-rule/types.d.ts +41 -0
- package/lib/plugin/plugin.d.ts +8 -0
- package/lib/plugin/plugin.js +8 -0
- package/lib/plugin/types.d.ts +21 -0
- package/lib/ruleset/index.d.ts +10 -0
- package/lib/ruleset/index.js +13 -0
- package/lib/test/index.d.ts +42 -1
- package/lib/test/index.js +39 -2
- package/lib/types.d.ts +10 -1
- package/lib/violation-collector.d.ts +33 -0
- package/lib/violation-collector.js +48 -28
- package/lib/virtual-rule.d.ts +72 -0
- package/lib/virtual-rule.js +233 -0
- package/package.json +16 -13
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# ルールシステム
|
|
2
|
+
|
|
3
|
+
`@markuplint/ml-core` のルールフレームワークの詳細リファレンスです。
|
|
4
|
+
|
|
5
|
+
## 概要
|
|
6
|
+
|
|
7
|
+
ルールフレームワークはリントルールの完全なライフサイクルを処理します:定義、設定、ノードへのマッピング、実行、違反収集。主要コンポーネント:
|
|
8
|
+
|
|
9
|
+
- **RuleSeed** — ルール定義型(verify/fix 関数 + デフォルト値)
|
|
10
|
+
- **MLRule** — ルール実行クラス(シードを名前と設定解決でラップ)
|
|
11
|
+
- **MLRuleContext** — ルールの実行コンテキスト(ドキュメントアクセス、翻訳、違反報告)
|
|
12
|
+
- **RuleMapper** — セレクタ詳細度に基づいてルール設定を特定の DOM ノードにマッピング
|
|
13
|
+
- **Ruleset** — Config から rules、nodeRules、childNodeRules を抽出
|
|
14
|
+
|
|
15
|
+
## RuleSeed
|
|
16
|
+
|
|
17
|
+
ソース: `src/ml-rule/types.ts`
|
|
18
|
+
|
|
19
|
+
`RuleSeed<T, O>` 型はルールの実装を定義します。
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
type RuleSeed<T extends RuleConfigValue = boolean, O extends PlainData = undefined> = {
|
|
23
|
+
readonly meta?: {
|
|
24
|
+
readonly category?: 'validation' | 'style' | 'naming-convention' | 'a11y' | 'maintainability';
|
|
25
|
+
};
|
|
26
|
+
readonly defaultSeverity?: Severity;
|
|
27
|
+
readonly defaultValue?: T;
|
|
28
|
+
readonly defaultOptions?: O;
|
|
29
|
+
verify(context: ProvidedContext<T, O>): void | Promise<void>;
|
|
30
|
+
fix?(context: ProvidedContext<T, O>): void | Promise<void>;
|
|
31
|
+
};
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### カテゴリ値
|
|
35
|
+
|
|
36
|
+
| カテゴリ | 説明 |
|
|
37
|
+
| --------------------- | ------------------------------------ |
|
|
38
|
+
| `'validation'` | HTML 標準準拠チェック |
|
|
39
|
+
| `'style'` | コードスタイルとフォーマットのルール |
|
|
40
|
+
| `'naming-convention'` | 命名規則の強制 |
|
|
41
|
+
| `'a11y'` | アクセシビリティチェック |
|
|
42
|
+
| `'maintainability'` | コード保守性のルール |
|
|
43
|
+
|
|
44
|
+
### デフォルト値
|
|
45
|
+
|
|
46
|
+
- `defaultSeverity` — 未指定の場合 `'error'`
|
|
47
|
+
- `defaultValue` — 未指定の場合 `true`
|
|
48
|
+
- `defaultOptions` — 未指定の場合 `undefined`
|
|
49
|
+
|
|
50
|
+
## createRule
|
|
51
|
+
|
|
52
|
+
ソース: `src/ml-rule/create-rule.ts`
|
|
53
|
+
|
|
54
|
+
型安全なルールシード作成のためのファクトリ関数:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
function createRule<T extends RuleConfigValue, O extends PlainData = undefined>(
|
|
58
|
+
seed: Readonly<RuleSeed<T, O>>,
|
|
59
|
+
): RuleSeed<T, O>;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
シードをそのまま返します。主に TypeScript の型推論のためのヘルパーとして機能します。
|
|
63
|
+
|
|
64
|
+
### 使用例
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { createRule } from '@markuplint/ml-core';
|
|
68
|
+
|
|
69
|
+
export default createRule({
|
|
70
|
+
defaultSeverity: 'error',
|
|
71
|
+
defaultValue: true,
|
|
72
|
+
async verify({ document, report, t }) {
|
|
73
|
+
await document.walkOn('Element', el => {
|
|
74
|
+
if (/* 違反条件 */) {
|
|
75
|
+
report({ scope: el, message: t('エラーメッセージ') });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## MLRule
|
|
83
|
+
|
|
84
|
+
ソース: `src/ml-rule/ml-rule.ts`
|
|
85
|
+
|
|
86
|
+
`MLRule<T, O>` は `RuleSeed` を名前でラップし、設定解決と検証実行を提供します。
|
|
87
|
+
|
|
88
|
+
### コンストラクタ
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
constructor(o: Readonly<RuleSeed<T, O>> & { readonly name: string })
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### プロパティ
|
|
95
|
+
|
|
96
|
+
| プロパティ | 型 | 説明 |
|
|
97
|
+
| ----------------- | ------------------------------ | ------------------------------------------------------------------ |
|
|
98
|
+
| `name` | `string` | ルール識別子(例: `"attr-duplication"` または `"a11y/html-lang"`) |
|
|
99
|
+
| `defaultSeverity` | `Severity` | デフォルトの重大度レベル(シードまたは `'error'`) |
|
|
100
|
+
| `defaultValue` | `T` | デフォルト設定値(シードまたは `true`) |
|
|
101
|
+
| `defaultOptions` | `O` | デフォルトオプション(シードから) |
|
|
102
|
+
| `baseRuleId` | `string \| undefined` | 仮想ルールの場合: ベースルール名(例: `"required-attr"`) |
|
|
103
|
+
| `groupName` | `string \| undefined` | 複数エントリ仮想ルールの場合: 一括無効化用のグループ名 |
|
|
104
|
+
| `specConformance` | `SpecConformance \| undefined` | 仮想ルールの場合: `'normative'` または `'non-normative'` |
|
|
105
|
+
|
|
106
|
+
### メソッド
|
|
107
|
+
|
|
108
|
+
#### `verify(document, locale, fix): Promise<Violation[]>`
|
|
109
|
+
|
|
110
|
+
ドキュメントに対してルールを実行します。
|
|
111
|
+
|
|
112
|
+
**フロー:**
|
|
113
|
+
|
|
114
|
+
1. `document.setRule(this)` — ドキュメントに現在のルールコンテキストを設定
|
|
115
|
+
2. `new MLRuleContext(document, locale)` — 実行コンテキストを作成
|
|
116
|
+
3. `context.provide()` — 提供可能なコンテキストオブジェクトを生成
|
|
117
|
+
4. `await seed.verify(context)` — 検証を実行
|
|
118
|
+
5. `await seed.fix(context)` — 修正を実行(`fix=true` かつ fix 関数がある場合)
|
|
119
|
+
6. `context.reports` → `Violation[]` — レポートを違反にマッピング
|
|
120
|
+
7. `document.setRule(null)` — ルールコンテキストをクリア
|
|
121
|
+
|
|
122
|
+
**Report → Violation のマッピング:**
|
|
123
|
+
|
|
124
|
+
- スコープベースのレポート: `report.scope`(ノード)から `line`, `col`, `raw` を抽出、重大度は `report.scope.rule.severity` から
|
|
125
|
+
- 直接レポート: `report.line`, `report.col`, `report.raw` を直接使用、重大度は `document.rule.severity` から
|
|
126
|
+
|
|
127
|
+
#### `getRuleInfo(ruleSet, ruleName): GlobalRuleInfo<T, O>`
|
|
128
|
+
|
|
129
|
+
ルールセットから完全なルール情報を解決します。
|
|
130
|
+
|
|
131
|
+
戻り値:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
{
|
|
135
|
+
...RuleInfo<T, O>, // グローバルルール設定
|
|
136
|
+
nodeRules: RuleInfo<T, O>[], // 無効でないノードレベルのオーバーライド
|
|
137
|
+
childNodeRules: RuleInfo<T, O>[], // 無効でない子ノードレベルのオーバーライド
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### `createAlias(aliasName, options?): MLRule<T, O>`
|
|
142
|
+
|
|
143
|
+
このルールの verify/fix ロジックを別名で再利用する仮想ルールを作成します。named nodeRules を実装するために `expandNamedNodeRules()` が内部的に使用します。
|
|
144
|
+
|
|
145
|
+
オプション:
|
|
146
|
+
|
|
147
|
+
| オプション | 型 | 説明 |
|
|
148
|
+
| ----------------- | ----------------- | ------------------------------------------------------------------------------------------------------ |
|
|
149
|
+
| `defaultSeverity` | `Severity` | ベースルールのデフォルト重大度をオーバーライド(明示的な指定のみ。specConformance による自動設定なし) |
|
|
150
|
+
| `specConformance` | `SpecConformance` | `'normative'` または `'non-normative'` |
|
|
151
|
+
| `groupName` | `string` | 複数エントリ named nodeRule のグループ名 |
|
|
152
|
+
|
|
153
|
+
エイリアスルールはベースルールの verify/fix 関数、meta、デフォルト値を継承します。`baseRuleId` プロパティでベースルール名を返します。
|
|
154
|
+
|
|
155
|
+
#### `optimizeOption(configSettings): RuleInfo<T, O>`
|
|
156
|
+
|
|
157
|
+
生のルール設定を解決済み `RuleInfo` に正規化します。
|
|
158
|
+
|
|
159
|
+
| 入力 | 結果 |
|
|
160
|
+
| -------------------------- | --------------------------------------------------------------------------------------------- |
|
|
161
|
+
| `undefined` または `false` | `{ disabled: true, severity: デフォルト, value: デフォルト, options: デフォルト }` |
|
|
162
|
+
| `true` | `{ disabled: false, severity: デフォルト, value: デフォルト, options: デフォルト }` |
|
|
163
|
+
| `RuleConfig` オブジェクト | `{ disabled: false, severity: 設定/デフォルト, value: 設定/デフォルト, options: マージ済み }` |
|
|
164
|
+
| プリミティブ値 | `{ disabled: false, severity: デフォルト, value: 入力値, options: デフォルト }` |
|
|
165
|
+
|
|
166
|
+
オプションのマージ: 配列はスプレッド(`[...a, ...b]`)、オブジェクトはスプレッド(`{...a, ...b}`)、それ以外は `b ?? a` にフォールバック。
|
|
167
|
+
|
|
168
|
+
## MLRuleContext
|
|
169
|
+
|
|
170
|
+
ソース: `src/ml-rule/ml-rule-context.ts`
|
|
171
|
+
|
|
172
|
+
`MLRuleContext<T, O>` はルールの実行コンテキストを提供します。
|
|
173
|
+
|
|
174
|
+
### コンストラクタ
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
constructor(document: MLDocument<T, O>, locale: LocaleSet)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
ロケールから翻訳関数を作成し、ドキュメント参照を保存します。
|
|
181
|
+
|
|
182
|
+
### プロパティ
|
|
183
|
+
|
|
184
|
+
| プロパティ | 型 | 説明 |
|
|
185
|
+
| ----------- | ------------------ | ----------------------- |
|
|
186
|
+
| `document` | `MLDocument<T, O>` | 検証対象のドキュメント |
|
|
187
|
+
| `locale` | `string` | ロケール文字列 |
|
|
188
|
+
| `translate` | `Translator` | i18n メッセージ翻訳関数 |
|
|
189
|
+
|
|
190
|
+
### `provide(): ProvidedContext`
|
|
191
|
+
|
|
192
|
+
`RuleSeed.verify()` と `RuleSeed.fix()` に渡されるコンテキストオブジェクトを返します:
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
{
|
|
196
|
+
document: MLDocument<T, O>,
|
|
197
|
+
translate: Translator,
|
|
198
|
+
t: Translator, // translate のエイリアス
|
|
199
|
+
reports: Report<T, O>[],
|
|
200
|
+
report: (report) => void | boolean,
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### `report(report)`
|
|
205
|
+
|
|
206
|
+
2 つのオーバーロード:
|
|
207
|
+
|
|
208
|
+
1. **直接レポート**(`Report<T, O>`): レポートを直接プッシュ。`undefined` を返す。
|
|
209
|
+
2. **チェッカーレポート**(`CheckerReport<T, O>`): 翻訳関数で関数を呼び出す。レポートが返された場合プッシュして `true` を返す。`null`/`undefined` の場合 `false` を返す。
|
|
210
|
+
|
|
211
|
+
### 重複排除
|
|
212
|
+
|
|
213
|
+
レポートは `_push()` で以下の基準で重複排除されます:
|
|
214
|
+
|
|
215
|
+
- **スコープベース**: 同じ `scope` オブジェクト + 同じ `message`
|
|
216
|
+
- **位置ベース**: 同じ `col` + `line` + `message` + `raw`
|
|
217
|
+
|
|
218
|
+
### メッセージの最終処理
|
|
219
|
+
|
|
220
|
+
英語ロケール(`'en'`)の場合、最初の小文字が大文字に変換されます。他のロケールはそのまま通過します。
|
|
221
|
+
|
|
222
|
+
## チェッカー型
|
|
223
|
+
|
|
224
|
+
ソース: `src/ml-rule/types.ts`
|
|
225
|
+
|
|
226
|
+
チェッカー関数を構築するためのユーティリティ型:
|
|
227
|
+
|
|
228
|
+
| 型 | シグネチャ | 説明 |
|
|
229
|
+
| ------------------------- | ------------------------------------------------------------ | ------------------ |
|
|
230
|
+
| `Checker<T, O, P>` | `(params: P) => CheckerReport<T, O>` | 汎用チェッカー |
|
|
231
|
+
| `ElementChecker<T, O, P>` | `(params: P & { el: Element<T, O> }) => CheckerReport<T, O>` | 要素固有チェッカー |
|
|
232
|
+
| `AttrChecker<T, O, P>` | `(params: P & { attr: Attr<T, O> }) => CheckerReport<T, O>` | 属性固有チェッカー |
|
|
233
|
+
| `CheckerReport<T, O>` | `(t: Translator) => Report<T, O> \| undefined \| null` | 遅延レポート関数 |
|
|
234
|
+
|
|
235
|
+
## ルールマッピング
|
|
236
|
+
|
|
237
|
+
`RuleMapper`、ルール設定の解決(`rules`、`nodeRules`、`childNodeRules` の3層処理)、詳細度ベースの競合解決、マージ動作、正規表現セレクタのテンプレート変数についての詳細なドキュメントは、専用の[ルールマッピング](./ml-dom/rule-mapping.ja.md)リファレンスを参照してください。
|
|
238
|
+
|
|
239
|
+
## Ruleset
|
|
240
|
+
|
|
241
|
+
ソース: `src/ruleset/index.ts`
|
|
242
|
+
|
|
243
|
+
`Config` オブジェクトからルール設定を抽出します。
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
class Ruleset {
|
|
247
|
+
readonly rules: Rules;
|
|
248
|
+
readonly nodeRules: readonly NodeRule[];
|
|
249
|
+
readonly childNodeRules: readonly ChildNodeRule[];
|
|
250
|
+
|
|
251
|
+
constructor(config: Config);
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
- `rules` — グローバルルール定義(`config.rules` から、デフォルトは `{}`)
|
|
256
|
+
- `nodeRules` — ノード固有のオーバーライド(`config.nodeRules` から、デフォルトは `[]`)
|
|
257
|
+
- `childNodeRules` — 子ノード固有のオーバーライド(`config.childNodeRules` から、デフォルトは `[]`)
|
|
258
|
+
|
|
259
|
+
## テストユーティリティ
|
|
260
|
+
|
|
261
|
+
ソース: `src/ml-rule/create-test-rule.ts`
|
|
262
|
+
|
|
263
|
+
### createTestRule
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
function createRule<T, O>(seed: Readonly<RuleSeed<T, O>> & { readonly name: string }): MLRule<T, O>;
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
テスト用の `MLRule` インスタンスを作成します。`create-rule.ts` の `createRule()` とは異なり、`name` プロパティが必須で、実際の `MLRule` インスタンスを返します。
|
|
270
|
+
|
|
271
|
+
### テストパターン
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
import { createRule } from '@markuplint/ml-core/test';
|
|
275
|
+
import { createTestDocument } from '@markuplint/ml-core/test';
|
|
276
|
+
|
|
277
|
+
const rule = createRule({
|
|
278
|
+
name: 'my-rule',
|
|
279
|
+
defaultSeverity: 'error',
|
|
280
|
+
async verify({ document, report, t }) {
|
|
281
|
+
// 検証ロジック
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const doc = createTestDocument('<div></div>');
|
|
286
|
+
const violations = await rule.verify(doc, { locale: 'en' }, false);
|
|
287
|
+
```
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# Rule System
|
|
2
|
+
|
|
3
|
+
Detailed reference for the rule framework in `@markuplint/ml-core`.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The rule framework handles the full lifecycle of lint rules: definition, configuration, mapping to nodes, execution, and violation collection. The key components are:
|
|
8
|
+
|
|
9
|
+
- **RuleSeed** -- Rule definition type (verify/fix functions + defaults)
|
|
10
|
+
- **MLRule** -- Rule execution class (wraps a seed with name and config resolution)
|
|
11
|
+
- **MLRuleContext** -- Execution context for rules (document access, translation, violation reporting)
|
|
12
|
+
- **RuleMapper** -- Maps rule configurations to specific DOM nodes based on selector specificity
|
|
13
|
+
- **Ruleset** -- Extracts rules, nodeRules, and childNodeRules from Config
|
|
14
|
+
|
|
15
|
+
## RuleSeed
|
|
16
|
+
|
|
17
|
+
Source: `src/ml-rule/types.ts`
|
|
18
|
+
|
|
19
|
+
The `RuleSeed<T, O>` type defines a rule's implementation.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
type RuleSeed<T extends RuleConfigValue = boolean, O extends PlainData = undefined> = {
|
|
23
|
+
readonly meta?: {
|
|
24
|
+
readonly category?: 'validation' | 'style' | 'naming-convention' | 'a11y' | 'maintainability';
|
|
25
|
+
};
|
|
26
|
+
readonly defaultSeverity?: Severity;
|
|
27
|
+
readonly defaultValue?: T;
|
|
28
|
+
readonly defaultOptions?: O;
|
|
29
|
+
verify(context: ProvidedContext<T, O>): void | Promise<void>;
|
|
30
|
+
fix?(context: ProvidedContext<T, O>): void | Promise<void>;
|
|
31
|
+
};
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Category Values
|
|
35
|
+
|
|
36
|
+
| Category | Description |
|
|
37
|
+
| --------------------- | ------------------------------- |
|
|
38
|
+
| `'validation'` | HTML standard compliance checks |
|
|
39
|
+
| `'style'` | Code style and formatting rules |
|
|
40
|
+
| `'naming-convention'` | Naming convention enforcement |
|
|
41
|
+
| `'a11y'` | Accessibility checks |
|
|
42
|
+
| `'maintainability'` | Code maintainability rules |
|
|
43
|
+
|
|
44
|
+
### Default Values
|
|
45
|
+
|
|
46
|
+
- `defaultSeverity` defaults to `'error'` if not specified
|
|
47
|
+
- `defaultValue` defaults to `true` if not specified
|
|
48
|
+
- `defaultOptions` defaults to `undefined`
|
|
49
|
+
|
|
50
|
+
## createRule
|
|
51
|
+
|
|
52
|
+
Source: `src/ml-rule/create-rule.ts`
|
|
53
|
+
|
|
54
|
+
Factory function for type-safe rule seed creation:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
function createRule<T extends RuleConfigValue, O extends PlainData = undefined>(
|
|
58
|
+
seed: Readonly<RuleSeed<T, O>>,
|
|
59
|
+
): RuleSeed<T, O>;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Returns the seed as-is. Serves primarily as a type helper for TypeScript inference.
|
|
63
|
+
|
|
64
|
+
### Usage
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { createRule } from '@markuplint/ml-core';
|
|
68
|
+
|
|
69
|
+
export default createRule({
|
|
70
|
+
defaultSeverity: 'error',
|
|
71
|
+
defaultValue: true,
|
|
72
|
+
async verify({ document, report, t }) {
|
|
73
|
+
await document.walkOn('Element', el => {
|
|
74
|
+
if (/* violation condition */) {
|
|
75
|
+
report({ scope: el, message: t('Error message') });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## MLRule
|
|
83
|
+
|
|
84
|
+
Source: `src/ml-rule/ml-rule.ts`
|
|
85
|
+
|
|
86
|
+
`MLRule<T, O>` wraps a `RuleSeed` with a name and provides configuration resolution and verification execution.
|
|
87
|
+
|
|
88
|
+
### Constructor
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
constructor(o: Readonly<RuleSeed<T, O>> & { readonly name: string })
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Properties
|
|
95
|
+
|
|
96
|
+
| Property | Type | Description |
|
|
97
|
+
| ----------------- | ------------------------------ | ------------------------------------------------------------------ |
|
|
98
|
+
| `name` | `string` | Rule identifier (e.g., `"attr-duplication"` or `"a11y/html-lang"`) |
|
|
99
|
+
| `defaultSeverity` | `Severity` | Default severity level (from seed or `'error'`) |
|
|
100
|
+
| `defaultValue` | `T` | Default config value (from seed or `true`) |
|
|
101
|
+
| `defaultOptions` | `O` | Default options (from seed) |
|
|
102
|
+
| `baseRuleId` | `string \| undefined` | For virtual rules: the base rule's name (e.g., `"required-attr"`) |
|
|
103
|
+
| `groupName` | `string \| undefined` | For multi-entry virtual rules: group name for batch disable |
|
|
104
|
+
| `specConformance` | `SpecConformance \| undefined` | For virtual rules: `'normative'` or `'non-normative'` |
|
|
105
|
+
|
|
106
|
+
### Methods
|
|
107
|
+
|
|
108
|
+
#### `verify(document, locale, fix): Promise<Violation[]>`
|
|
109
|
+
|
|
110
|
+
Executes the rule against a document.
|
|
111
|
+
|
|
112
|
+
**Flow:**
|
|
113
|
+
|
|
114
|
+
1. `document.setRule(this)` -- sets current rule context on document
|
|
115
|
+
2. `new MLRuleContext(document, locale)` -- creates execution context
|
|
116
|
+
3. `context.provide()` -- generates providable context object
|
|
117
|
+
4. `await seed.verify(context)` -- runs verification
|
|
118
|
+
5. `await seed.fix(context)` -- runs fix (if `fix=true` and fix function exists)
|
|
119
|
+
6. `context.reports` -> `Violation[]` -- maps reports to violations
|
|
120
|
+
7. `document.setRule(null)` -- clears rule context
|
|
121
|
+
|
|
122
|
+
**Report -> Violation mapping:**
|
|
123
|
+
|
|
124
|
+
- Scope-based reports: extracts `line`, `col`, `raw` from `report.scope` (the node), severity from `report.scope.rule.severity`
|
|
125
|
+
- Direct reports: uses `report.line`, `report.col`, `report.raw` directly, severity from `document.rule.severity`
|
|
126
|
+
|
|
127
|
+
#### `getRuleInfo(ruleSet, ruleName): GlobalRuleInfo<T, O>`
|
|
128
|
+
|
|
129
|
+
Resolves the full rule information from a ruleset.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
{
|
|
135
|
+
...RuleInfo<T, O>, // Global rule config
|
|
136
|
+
nodeRules: RuleInfo<T, O>[], // Non-disabled node-level overrides
|
|
137
|
+
childNodeRules: RuleInfo<T, O>[], // Non-disabled child-node-level overrides
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### `createAlias(aliasName, options?): MLRule<T, O>`
|
|
142
|
+
|
|
143
|
+
Creates a virtual rule that reuses this rule's verify/fix logic under a different name. Used internally by `expandNamedNodeRules()` to implement named nodeRules.
|
|
144
|
+
|
|
145
|
+
Options:
|
|
146
|
+
|
|
147
|
+
| Option | Type | Description |
|
|
148
|
+
| ----------------- | ----------------- | ------------------------------------------------------------------------------------- |
|
|
149
|
+
| `defaultSeverity` | `Severity` | Override the base rule's default severity (explicit only; not set by specConformance) |
|
|
150
|
+
| `specConformance` | `SpecConformance` | `'normative'` or `'non-normative'` |
|
|
151
|
+
| `groupName` | `string` | Group name for multi-entry named nodeRules |
|
|
152
|
+
|
|
153
|
+
The alias rule inherits the base rule's verify/fix functions, meta, and defaults. Its `baseRuleId` property returns the base rule's name.
|
|
154
|
+
|
|
155
|
+
#### `optimizeOption(configSettings): RuleInfo<T, O>`
|
|
156
|
+
|
|
157
|
+
Normalizes raw rule settings into resolved `RuleInfo`.
|
|
158
|
+
|
|
159
|
+
| Input | Result |
|
|
160
|
+
| ---------------------- | --------------------------------------------------------------------------------------- |
|
|
161
|
+
| `undefined` or `false` | `{ disabled: true, severity: default, value: default, options: default }` |
|
|
162
|
+
| `true` | `{ disabled: false, severity: default, value: default, options: default }` |
|
|
163
|
+
| `RuleConfig` object | `{ disabled: false, severity: config/default, value: config/default, options: merged }` |
|
|
164
|
+
| Primitive value | `{ disabled: false, severity: default, value: input, options: default }` |
|
|
165
|
+
|
|
166
|
+
Options merging: arrays are spread (`[...a, ...b]`), objects are spread (`{...a, ...b}`), otherwise fallback to `b ?? a`.
|
|
167
|
+
|
|
168
|
+
## MLRuleContext
|
|
169
|
+
|
|
170
|
+
Source: `src/ml-rule/ml-rule-context.ts`
|
|
171
|
+
|
|
172
|
+
`MLRuleContext<T, O>` provides the execution context for rules.
|
|
173
|
+
|
|
174
|
+
### Constructor
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
constructor(document: MLDocument<T, O>, locale: LocaleSet)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Creates translator from locale, stores document reference.
|
|
181
|
+
|
|
182
|
+
### Properties
|
|
183
|
+
|
|
184
|
+
| Property | Type | Description |
|
|
185
|
+
| ----------- | ------------------ | --------------------------- |
|
|
186
|
+
| `document` | `MLDocument<T, O>` | The document being verified |
|
|
187
|
+
| `locale` | `string` | Locale string |
|
|
188
|
+
| `translate` | `Translator` | i18n message translator |
|
|
189
|
+
|
|
190
|
+
### `provide(): ProvidedContext`
|
|
191
|
+
|
|
192
|
+
Returns the context object passed to `RuleSeed.verify()` and `RuleSeed.fix()`:
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
{
|
|
196
|
+
document: MLDocument<T, O>,
|
|
197
|
+
translate: Translator,
|
|
198
|
+
t: Translator, // alias for translate
|
|
199
|
+
reports: Report<T, O>[],
|
|
200
|
+
report: (report) => void | boolean,
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### `report(report)`
|
|
205
|
+
|
|
206
|
+
Two overloads:
|
|
207
|
+
|
|
208
|
+
1. **Direct report** (`Report<T, O>`): Pushes the report directly. Returns `undefined`.
|
|
209
|
+
2. **Checker report** (`CheckerReport<T, O>`): Calls the function with translator. If it returns a report, pushes it and returns `true`. If `null`/`undefined`, returns `false`.
|
|
210
|
+
|
|
211
|
+
### Deduplication
|
|
212
|
+
|
|
213
|
+
Reports are deduplicated in `_push()` using:
|
|
214
|
+
|
|
215
|
+
- **Scope-based**: same `scope` object + same `message`
|
|
216
|
+
- **Position-based**: same `col` + `line` + `message` + `raw`
|
|
217
|
+
|
|
218
|
+
### Message Finalization
|
|
219
|
+
|
|
220
|
+
For English locale (`'en'`), the first lowercase letter is capitalized. Other locales pass through unchanged.
|
|
221
|
+
|
|
222
|
+
## Checker Types
|
|
223
|
+
|
|
224
|
+
Source: `src/ml-rule/types.ts`
|
|
225
|
+
|
|
226
|
+
Utility types for building checker functions:
|
|
227
|
+
|
|
228
|
+
| Type | Signature | Description |
|
|
229
|
+
| ------------------------- | ------------------------------------------------------------ | -------------------------- |
|
|
230
|
+
| `Checker<T, O, P>` | `(params: P) => CheckerReport<T, O>` | Generic checker |
|
|
231
|
+
| `ElementChecker<T, O, P>` | `(params: P & { el: Element<T, O> }) => CheckerReport<T, O>` | Element-specific checker |
|
|
232
|
+
| `AttrChecker<T, O, P>` | `(params: P & { attr: Attr<T, O> }) => CheckerReport<T, O>` | Attribute-specific checker |
|
|
233
|
+
| `CheckerReport<T, O>` | `(t: Translator) => Report<T, O> \| undefined \| null` | Deferred report function |
|
|
234
|
+
|
|
235
|
+
## Rule Mapping
|
|
236
|
+
|
|
237
|
+
For detailed documentation on `RuleMapper`, rule configuration resolution (three-layer processing with `rules`, `nodeRules`, `childNodeRules`), specificity-based conflict resolution, merging behavior, and regex selector templates, see the dedicated [Rule Mapping](./ml-dom/rule-mapping.md) reference.
|
|
238
|
+
|
|
239
|
+
## Ruleset
|
|
240
|
+
|
|
241
|
+
Source: `src/ruleset/index.ts`
|
|
242
|
+
|
|
243
|
+
Extracts rule configuration from a `Config` object.
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
class Ruleset {
|
|
247
|
+
readonly rules: Rules;
|
|
248
|
+
readonly nodeRules: readonly NodeRule[];
|
|
249
|
+
readonly childNodeRules: readonly ChildNodeRule[];
|
|
250
|
+
|
|
251
|
+
constructor(config: Config);
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
- `rules` -- Global rule definitions (from `config.rules`, defaults to `{}`)
|
|
256
|
+
- `nodeRules` -- Node-specific overrides (from `config.nodeRules`, defaults to `[]`)
|
|
257
|
+
- `childNodeRules` -- Child-node-specific overrides (from `config.childNodeRules`, defaults to `[]`)
|
|
258
|
+
|
|
259
|
+
## Test Utilities
|
|
260
|
+
|
|
261
|
+
Source: `src/ml-rule/create-test-rule.ts`
|
|
262
|
+
|
|
263
|
+
### createTestRule
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
function createRule<T, O>(seed: Readonly<RuleSeed<T, O>> & { readonly name: string }): MLRule<T, O>;
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Creates an `MLRule` instance for testing. Unlike `createRule()` in `create-rule.ts`, this requires a `name` property and returns an actual `MLRule` instance.
|
|
270
|
+
|
|
271
|
+
### Test Pattern
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
import { createRule } from '@markuplint/ml-core/test';
|
|
275
|
+
import { createTestDocument } from '@markuplint/ml-core/test';
|
|
276
|
+
|
|
277
|
+
const rule = createRule({
|
|
278
|
+
name: 'my-rule',
|
|
279
|
+
defaultSeverity: 'error',
|
|
280
|
+
async verify({ document, report, t }) {
|
|
281
|
+
// verification logic
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const doc = createTestDocument('<div></div>');
|
|
286
|
+
const violations = await rule.verify(doc, { locale: 'en' }, false);
|
|
287
|
+
```
|
package/lib/convert-ruleset.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
import type { Config } from '@markuplint/ml-config';
|
|
2
2
|
import { Ruleset } from './ruleset/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Converts a markuplint {@link Config} object into a {@link Ruleset} instance
|
|
5
|
+
* that can be used by the linting engine.
|
|
6
|
+
*
|
|
7
|
+
* @param config - The configuration to convert (defaults to an empty config)
|
|
8
|
+
* @returns A new Ruleset instance
|
|
9
|
+
*/
|
|
3
10
|
export declare function convertRuleset(config?: Config): Ruleset;
|
package/lib/convert-ruleset.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { Ruleset } from './ruleset/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Converts a markuplint {@link Config} object into a {@link Ruleset} instance
|
|
4
|
+
* that can be used by the linting engine.
|
|
5
|
+
*
|
|
6
|
+
* @param config - The configuration to convert (defaults to an empty config)
|
|
7
|
+
* @returns A new Ruleset instance
|
|
8
|
+
*/
|
|
2
9
|
export function convertRuleset(config = {}) {
|
|
3
10
|
return new Ruleset(config);
|
|
4
11
|
}
|
package/lib/debug.d.ts
CHANGED
package/lib/debug.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import debug from 'debug';
|
|
2
2
|
const CLI_NS = 'markuplint-cli';
|
|
3
3
|
export const log = debug('ml-core');
|
|
4
|
+
/**
|
|
5
|
+
* Enables debug logging for the `ml-core` namespace and the CLI namespace.
|
|
6
|
+
* No-op if debug logging is already enabled.
|
|
7
|
+
*/
|
|
4
8
|
export function enableDebug() {
|
|
5
9
|
if (!log.enabled) {
|
|
6
10
|
debug.enable(`${log.namespace}*`);
|
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { RuleInfo, RuleConfig, RuleConfigValue } from '@markuplint/ml-config';
|
|
1
|
+
export type { RuleInfo, RuleConfig, RuleConfigValue } from '@markuplint/ml-config';
|
|
2
2
|
export { ariaSpecs, contentModelCategoryToTagNames, getAttrSpecs, getComputedRole, getImplicitRole, getPermittedRoles, getRoleSpec, getSpec, resolveNamespace, } from '@markuplint/ml-spec';
|
|
3
3
|
export { Ruleset } from './ruleset/index.js';
|
|
4
4
|
export { enableDebug } from './debug.js';
|
|
@@ -9,7 +9,8 @@ export * from './ml-dom/index.js';
|
|
|
9
9
|
export * from './ml-rule/index.js';
|
|
10
10
|
export * from './plugin/index.js';
|
|
11
11
|
export * from './test/index.js';
|
|
12
|
-
export * from './types.js';
|
|
12
|
+
export type * from './types.js';
|
|
13
13
|
export * from './utils/index.js';
|
|
14
14
|
export * from './violation-collector.js';
|
|
15
|
-
export
|
|
15
|
+
export * from './virtual-rule.js';
|
|
16
|
+
export type { AccessibilityProperties } from './ml-dom/node/types.js';
|
package/lib/index.js
CHANGED
|
@@ -8,6 +8,6 @@ export * from './ml-dom/index.js';
|
|
|
8
8
|
export * from './ml-rule/index.js';
|
|
9
9
|
export * from './plugin/index.js';
|
|
10
10
|
export * from './test/index.js';
|
|
11
|
-
export * from './types.js';
|
|
12
11
|
export * from './utils/index.js';
|
|
13
12
|
export * from './violation-collector.js';
|
|
13
|
+
export * from './virtual-rule.js';
|