@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,371 @@
|
|
|
1
|
+
# ルールマッピング — ルールがノードに適用される仕組み
|
|
2
|
+
|
|
3
|
+
**ソース:** `src/ml-dom/node/document.ts`(`_ruleMapping()`)、`src/ml-dom/node/rule-mapper.ts`(`RuleMapper`)
|
|
4
|
+
|
|
5
|
+
## 概要
|
|
6
|
+
|
|
7
|
+
ルールマッピングは、ユーザーの設定からルール設定を個々の MLDOM ノードに配布するプロセスです。各ノードには `rules` プロパティ(`Record<string, AnyRule>`)があり、そのノードに適用されるすべてのルールの解決済み設定を格納します。
|
|
8
|
+
|
|
9
|
+
マッピングは3つの設定レイヤー — `rules`、`nodeRules`、`childNodeRules` — を定義された順序で処理し、CSS セレクタの詳細度を使用して競合を解決します。
|
|
10
|
+
|
|
11
|
+
設定構文については、[markuplint 設定ドキュメント](https://markuplint.dev/docs/configuration)を参照してください。
|
|
12
|
+
|
|
13
|
+
## アーキテクチャ
|
|
14
|
+
|
|
15
|
+
### ルールマッピングが実行されるタイミング
|
|
16
|
+
|
|
17
|
+
ルールマッピングは `MLDocument` のコンストラクション中に、pretender の初期化後、ルール実行の前に**一度だけ**実行されます:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
MLDocument コンストラクタ
|
|
21
|
+
├── 1. AST をパース → MLDOM ノードを作成(nodeList)
|
|
22
|
+
├── 2. _pretending(pretenders)
|
|
23
|
+
├── 3. _ruleMapping(ruleset) ← ルールマッピング
|
|
24
|
+
└── 4.(ルール検証の準備完了)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
この順序は重要です:
|
|
28
|
+
|
|
29
|
+
- Pretender が先に確立されている必要があります。これにより、ルールマッピングでのセレクタマッチングが pretender のアイデンティティに対してマッチできます(例: `button` をターゲットにした `nodeRules` エントリが、`<button>` として振る舞う `<MyButton>` にマッチする)
|
|
30
|
+
- ルールマッピングは検証前に完了する必要があります。ルールが `walkOn()` 中に `node.rules` を読み取れるようにするためです
|
|
31
|
+
|
|
32
|
+
### コンポーネント
|
|
33
|
+
|
|
34
|
+
| コンポーネント | ソース | 役割 |
|
|
35
|
+
| ---------------- | -------------------------------- | ---------------------------------------------------------------- |
|
|
36
|
+
| `Ruleset` | `src/ruleset/index.ts` | ユーザー設定から `rules`、`nodeRules`、`childNodeRules` を抽出 |
|
|
37
|
+
| `RuleMapper` | `src/ml-dom/node/rule-mapper.ts` | 詳細度付きのルールからノードへのマッピングを蓄積し、ノードに適用 |
|
|
38
|
+
| `_ruleMapping()` | `src/ml-dom/node/document.ts` | 3層処理のオーケストレーション |
|
|
39
|
+
|
|
40
|
+
## 3つのレイヤー
|
|
41
|
+
|
|
42
|
+
### レイヤー 1: グローバルルール(`rules`)
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"rules": {
|
|
47
|
+
"attr-duplication": true,
|
|
48
|
+
"case-sensitive-tag-name": "warning"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
グローバルルールは `#document` ノード自体を含むドキュメント内の**すべてのノード**に適用されます。固定の詳細度 `[0, 0, 0]` を持ちます。
|
|
54
|
+
|
|
55
|
+
**処理:**
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// #document に適用
|
|
59
|
+
for (const ruleName of Object.keys(ruleset.rules)) {
|
|
60
|
+
ruleMapper.set(document, ruleName, {
|
|
61
|
+
from: 'rules',
|
|
62
|
+
specificity: [0, 0, 0],
|
|
63
|
+
rule,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// nodeList のすべてのノードに適用
|
|
68
|
+
for (const node of document.nodeList) {
|
|
69
|
+
for (const ruleName of Object.keys(ruleset.rules)) {
|
|
70
|
+
ruleMapper.set(node, ruleName, {
|
|
71
|
+
from: 'rules',
|
|
72
|
+
specificity: [0, 0, 0],
|
|
73
|
+
rule,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### レイヤー 2: ノードルール(`nodeRules`)
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"nodeRules": [
|
|
84
|
+
{
|
|
85
|
+
"selector": "img",
|
|
86
|
+
"rules": {
|
|
87
|
+
"required-attr": { "value": "alt" }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
ノードルールは**セレクタにマッチする要素**に対してグローバルルールをオーバーライドします。`ELEMENT_NODE` と `TEXT_NODE` のみが対象です。テキストノードはセレクタのターゲットになれないため、実際にマッチするのは要素のみです。
|
|
95
|
+
|
|
96
|
+
**処理:**
|
|
97
|
+
|
|
98
|
+
1. 各 `nodeRule` エントリについて、`matchMLSelector(selector)` で現在の要素がマッチするかチェック
|
|
99
|
+
2. マッチした場合、エントリ内の各ルールに対して:
|
|
100
|
+
- `exchangeValueOnRule(rule, matches.data)` — 正規表現セレクタのキャプチャから Mustache テンプレート変数をレンダリング
|
|
101
|
+
- `mergeRule(globalRule, convertedRule)` — グローバルルール設定とマージ([マージ](#グローバルルールとのマージ)を参照)
|
|
102
|
+
- `ruleMapper.set(node, ruleName, { from: 'nodeRules', specificity: matches.specificity, rule: mergedRule })`
|
|
103
|
+
|
|
104
|
+
詳細度は要素をマッチさせるために使用された CSS セレクタから取得されます。
|
|
105
|
+
|
|
106
|
+
### レイヤー 3: 子ノードルール(`childNodeRules`)
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"childNodeRules": [
|
|
111
|
+
{
|
|
112
|
+
"selector": "table",
|
|
113
|
+
"inheritance": true,
|
|
114
|
+
"rules": {
|
|
115
|
+
"class-naming": "/^table-/"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
子ノードルールは、マッチした要素の**子(または子孫)**にルールを適用します。セレクタは**親**にマッチし、ルールはその子に配布されます。
|
|
123
|
+
|
|
124
|
+
**処理:**
|
|
125
|
+
|
|
126
|
+
1. 各 `childNodeRule` エントリについて、`matchMLSelector(selector)` で現在の要素がマッチするかチェック
|
|
127
|
+
2. マッチした場合、ターゲットノードを決定:
|
|
128
|
+
- `inheritance: true` → すべての**子孫**(`syncWalk` で収集)
|
|
129
|
+
- `inheritance: false`(デフォルト)→ **直接の子**のみ(`childNodes`)
|
|
130
|
+
3. エントリ内の各ルールについて、マージされたルールをすべてのターゲットノードに適用
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const targetDescendants = nodeRule.inheritance ? descendants : children;
|
|
134
|
+
|
|
135
|
+
for (const descendant of targetDescendants) {
|
|
136
|
+
ruleMapper.set(descendant, ruleName, {
|
|
137
|
+
from: 'childNodeRules',
|
|
138
|
+
specificity: matches.specificity,
|
|
139
|
+
rule: mergedRule,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
注:詳細度は子ではなく**親の**セレクタマッチのものです。
|
|
145
|
+
|
|
146
|
+
## 処理順序
|
|
147
|
+
|
|
148
|
+
3つのレイヤーは `_ruleMapping()` 内で特定の順序で処理されます:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
#document ノードに対して:
|
|
152
|
+
1. すべてのグローバルルールを適用(詳細度 [0,0,0])
|
|
153
|
+
|
|
154
|
+
nodeList の各ノードに対して:
|
|
155
|
+
2. すべてのグローバルルールを適用(詳細度 [0,0,0])
|
|
156
|
+
3. マッチする nodeRules を適用(セレクタの詳細度)
|
|
157
|
+
4. マッチする childNodeRules を適用(親のセレクタの詳細度)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`RuleMapper.set()` は詳細度で競合を解決するため、同じ詳細度レベル内での処理順序が重要です:
|
|
161
|
+
|
|
162
|
+
- **同じ詳細度**:後の `set()` 呼び出しが前のものを上書き(後勝ち)
|
|
163
|
+
- **高い詳細度**:順序に関係なく常に勝利
|
|
164
|
+
- **低い詳細度**:暗黙的にスキップ
|
|
165
|
+
|
|
166
|
+
つまり:
|
|
167
|
+
|
|
168
|
+
| シナリオ | 勝者 |
|
|
169
|
+
| ----------------------------------------------------------- | ----------------------------------------------------- |
|
|
170
|
+
| `rules` vs `nodeRules`(任意のセレクタ) | `nodeRules`(セレクタ詳細度 `≥ [0,0,1]` > `[0,0,0]`) |
|
|
171
|
+
| `rules` vs `childNodeRules`(任意のセレクタ) | `childNodeRules`(同じ理由) |
|
|
172
|
+
| `nodeRules[0]` vs `nodeRules[1]`(同じ詳細度) | `nodeRules[1]`(配列内で後) |
|
|
173
|
+
| `nodeRules`(低い詳細度) vs `childNodeRules`(高い詳細度) | `childNodeRules`(高い詳細度が勝利) |
|
|
174
|
+
| `nodeRules`(高い詳細度) vs `childNodeRules`(低い詳細度) | `nodeRules`(高い詳細度が勝利) |
|
|
175
|
+
|
|
176
|
+
## 詳細度
|
|
177
|
+
|
|
178
|
+
### 詳細度とは
|
|
179
|
+
|
|
180
|
+
詳細度は CSS Selectors 仕様に基づく3要素のタプル `[a, b, c]` です:
|
|
181
|
+
|
|
182
|
+
| 要素 | カウント対象 | 例 |
|
|
183
|
+
| ---- | ---------------------------------------- | --------------------------------------------------- |
|
|
184
|
+
| `a` | ID セレクタ | `#main` → `[1, 0, 0]` |
|
|
185
|
+
| `b` | クラスセレクタ、属性セレクタ、擬似クラス | `.foo` → `[0, 1, 0]`、`[type="text"]` → `[0, 1, 0]` |
|
|
186
|
+
| `c` | タイプセレクタ、擬似要素 | `div` → `[0, 0, 1]`、`img` → `[0, 0, 1]` |
|
|
187
|
+
|
|
188
|
+
### 詳細度の比較方法
|
|
189
|
+
|
|
190
|
+
`@markuplint/selector` の `compareSpecificity(a, b)` は辞書式比較を行います:
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
function compareSpecificity(a: Specificity, b: Specificity): -1 | 0 | 1 {
|
|
194
|
+
// a[0] vs b[0] を比較、次に a[1] vs b[1]、最後に a[2] vs b[2]
|
|
195
|
+
// 戻り値: -1 (a < b)、0(等しい)、1 (a > b)
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### `RuleMapper.set()` での詳細度の使用
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
set(node, ruleName, rule: MappingLayer) {
|
|
203
|
+
const currentRule = rules[ruleName];
|
|
204
|
+
if (currentRule) {
|
|
205
|
+
const order = compareSpecificity(currentRule.specificity, rule.specificity);
|
|
206
|
+
if (order === 1) {
|
|
207
|
+
return; // 現在の方が高い詳細度 → 新しいルールをスキップ
|
|
208
|
+
}
|
|
209
|
+
// order === 0 または -1 → 新しいルールで上書き
|
|
210
|
+
}
|
|
211
|
+
rules[ruleName] = rule;
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
- `order === 1`(現在 > 新規):**スキップ** — 既存の高詳細度ルールが保持される
|
|
216
|
+
- `order === 0`(等しい):**上書き** — 後のマッピングが勝つ
|
|
217
|
+
- `order === -1`(現在 < 新規):**上書き** — 高い詳細度のルールが勝つ
|
|
218
|
+
|
|
219
|
+
### 詳細度の例
|
|
220
|
+
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"rules": {
|
|
224
|
+
"class-naming": "/^prefix-/"
|
|
225
|
+
},
|
|
226
|
+
"nodeRules": [
|
|
227
|
+
{
|
|
228
|
+
"selector": "div",
|
|
229
|
+
"rules": { "class-naming": "/^div-/" }
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"selector": "div.special",
|
|
233
|
+
"rules": { "class-naming": "/^special-/" }
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
"selector": "#main",
|
|
237
|
+
"rules": { "class-naming": "/^main-/" }
|
|
238
|
+
}
|
|
239
|
+
]
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
`<div id="main" class="special">` の場合:
|
|
244
|
+
|
|
245
|
+
| ソース | セレクタ | 詳細度 | `class-naming` の値 |
|
|
246
|
+
| -------------- | -------------- | ----------- | ------------------- |
|
|
247
|
+
| `rules` | (グローバル) | `[0, 0, 0]` | `/^prefix-/` |
|
|
248
|
+
| `nodeRules[0]` | `div` | `[0, 0, 1]` | `/^div-/` |
|
|
249
|
+
| `nodeRules[1]` | `div.special` | `[0, 1, 1]` | `/^special-/` |
|
|
250
|
+
| `nodeRules[2]` | `#main` | `[1, 0, 0]` | `/^main-/` |
|
|
251
|
+
|
|
252
|
+
処理順序:`rules` → `nodeRules[0]` → `nodeRules[1]` → `nodeRules[2]`
|
|
253
|
+
|
|
254
|
+
結果:`class-naming` = `/^main-/`(詳細度 `[1, 0, 0]` が最も高い)
|
|
255
|
+
|
|
256
|
+
## グローバルルールとのマージ
|
|
257
|
+
|
|
258
|
+
`nodeRules` や `childNodeRules` のエントリがルールを指定する場合、値は単純に置換されるのではなく、グローバルルール設定と**マージ**されます:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
const globalRule = ruleset.rules[ruleName];
|
|
262
|
+
const mergedRule = globalRule == null ? convertedRule : mergeRule(globalRule, convertedRule);
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
`mergeRule(a, b)`(`@markuplint/ml-config` から)は右側優先で適用されます:
|
|
266
|
+
|
|
267
|
+
| シナリオ | 結果 |
|
|
268
|
+
| -------------------- | ------------------------------------------------------------------------------------------------ |
|
|
269
|
+
| `b` が `false` | ルールが無効化される(`false` を返す) |
|
|
270
|
+
| `b` がプリミティブ値 | `a` の値を置換 |
|
|
271
|
+
| 両方がオブジェクト | `b` のプロパティが `a` をオーバーライド。`severity`、`value`、`options`、`reason` は個別にマージ |
|
|
272
|
+
| `b.options` が存在 | `a.options` とマージ(オブジェクトはスプレッド、配列は連結) |
|
|
273
|
+
| `b.value` が未設定 | `a.value` を継承 |
|
|
274
|
+
|
|
275
|
+
### マージの例
|
|
276
|
+
|
|
277
|
+
```json
|
|
278
|
+
{
|
|
279
|
+
"rules": {
|
|
280
|
+
"my-rule": {
|
|
281
|
+
"severity": "error",
|
|
282
|
+
"value": "strict",
|
|
283
|
+
"options": { "allow": ["a", "b"] }
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
"nodeRules": [
|
|
287
|
+
{
|
|
288
|
+
"selector": "nav",
|
|
289
|
+
"rules": {
|
|
290
|
+
"my-rule": {
|
|
291
|
+
"options": { "allow": ["c"] }
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
]
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
`<nav>` の場合、`my-rule` は以下に解決されます:
|
|
300
|
+
|
|
301
|
+
```json
|
|
302
|
+
{
|
|
303
|
+
"severity": "error",
|
|
304
|
+
"value": "strict",
|
|
305
|
+
"options": { "allow": ["c"] }
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
`severity` と `value` はグローバル設定から継承されます。`options.allow` は `nodeRules` エントリによって上書きされます(`options` レベルでのオブジェクトスプレッドであり、個別のサブプロパティレベルではありません — `options` 自体がスプレッドされます)。
|
|
310
|
+
|
|
311
|
+
## 正規表現セレクタとテンプレート変数
|
|
312
|
+
|
|
313
|
+
`nodeRules` と `childNodeRules` は正規表現セレクタをサポートし、要素の属性からデータをキャプチャできます。キャプチャされた値はルール設定で Mustache テンプレート変数として利用可能です:
|
|
314
|
+
|
|
315
|
+
```json
|
|
316
|
+
{
|
|
317
|
+
"nodeRules": [
|
|
318
|
+
{
|
|
319
|
+
"regexSelector": {
|
|
320
|
+
"attrName": "data-prefix",
|
|
321
|
+
"attrValue": "/^(?<prefix>.+)$/"
|
|
322
|
+
},
|
|
323
|
+
"rules": {
|
|
324
|
+
"class-naming": "/^{{ prefix }}-/"
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
]
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
`exchangeValueOnRule(rule, matches.data)` はマージ前にこれらのテンプレートをレンダリングします。
|
|
332
|
+
|
|
333
|
+
## データフロー図
|
|
334
|
+
|
|
335
|
+
```
|
|
336
|
+
Config
|
|
337
|
+
│
|
|
338
|
+
▼
|
|
339
|
+
Ruleset (rules, nodeRules, childNodeRules)
|
|
340
|
+
│
|
|
341
|
+
▼
|
|
342
|
+
_ruleMapping(ruleset)
|
|
343
|
+
│
|
|
344
|
+
├─── レイヤー 1: グローバルルール
|
|
345
|
+
│ └─ すべてのノード(#document を含む)に対して:
|
|
346
|
+
│ ruleMapper.set(node, name, { from: 'rules', specificity: [0,0,0], rule })
|
|
347
|
+
│
|
|
348
|
+
├─── レイヤー 2: ノードルール
|
|
349
|
+
│ └─ 各 nodeRule エントリに対して:
|
|
350
|
+
│ └─ セレクタにマッチする各 ELEMENT_NODE に対して:
|
|
351
|
+
│ ├─ exchangeValueOnRule(テンプレートレンダリング)
|
|
352
|
+
│ ├─ mergeRule(グローバルとマージ)
|
|
353
|
+
│ └─ ruleMapper.set(node, name, { from: 'nodeRules', specificity, rule })
|
|
354
|
+
│
|
|
355
|
+
└─── レイヤー 3: 子ノードルール
|
|
356
|
+
└─ 各 childNodeRule エントリに対して:
|
|
357
|
+
└─ セレクタにマッチする各 ELEMENT_NODE に対して:
|
|
358
|
+
└─ 各子(inheritance: true の場合は子孫)に対して:
|
|
359
|
+
├─ exchangeValueOnRule(テンプレートレンダリング)
|
|
360
|
+
├─ mergeRule(グローバルとマージ)
|
|
361
|
+
└─ ruleMapper.set(child, name, { from: 'childNodeRules', specificity, rule })
|
|
362
|
+
│
|
|
363
|
+
▼
|
|
364
|
+
ruleMapper.apply()
|
|
365
|
+
│
|
|
366
|
+
└─ マップ内の各ノードに対して:
|
|
367
|
+
node.rules[ruleName] = rule
|
|
368
|
+
│
|
|
369
|
+
▼
|
|
370
|
+
node.rules が設定される → walkOn() での検証準備完了
|
|
371
|
+
```
|