@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,199 @@
|
|
|
1
|
+
# MLNode / MLParentNode
|
|
2
|
+
|
|
3
|
+
## MLNode
|
|
4
|
+
|
|
5
|
+
**Source:** `src/ml-dom/node/node.ts`
|
|
6
|
+
|
|
7
|
+
Abstract base class for all markuplint DOM node wrappers. Extends `MLToken` with DOM `Node` interface compliance, tree traversal, rule configuration access, and child node management.
|
|
8
|
+
|
|
9
|
+
### Node Type Constants
|
|
10
|
+
|
|
11
|
+
| Constant | Value | DOM Standard |
|
|
12
|
+
| ------------------------------- | ----- | ------------------------- |
|
|
13
|
+
| `ELEMENT_NODE` | `1` | Yes |
|
|
14
|
+
| `ATTRIBUTE_NODE` | `2` | Yes |
|
|
15
|
+
| `TEXT_NODE` | `3` | Yes |
|
|
16
|
+
| `CDATA_SECTION_NODE` | `4` | Yes |
|
|
17
|
+
| `PROCESSING_INSTRUCTION_NODE` | `7` | Yes |
|
|
18
|
+
| `COMMENT_NODE` | `8` | Yes |
|
|
19
|
+
| `DOCUMENT_NODE` | `9` | Yes |
|
|
20
|
+
| `DOCUMENT_TYPE_NODE` | `10` | Yes |
|
|
21
|
+
| `DOCUMENT_FRAGMENT_NODE` | `11` | Yes |
|
|
22
|
+
| `MARKUPLINT_PREPROCESSOR_BLOCK` | `101` | No (markuplint extension) |
|
|
23
|
+
|
|
24
|
+
### Tree Structure Properties
|
|
25
|
+
|
|
26
|
+
| Property | Type | Description |
|
|
27
|
+
| ----------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------- |
|
|
28
|
+
| `parentNode` | `MLDocument \| MLDocumentFragment \| MLElement \| null` | DOM-compliant parent. Transparent `MLBlock` parents are skipped. |
|
|
29
|
+
| `parentElement` | `MLElement \| null` | Nearest ancestor that is an `MLElement` |
|
|
30
|
+
| `syntacticalParentNode` | `MLDocument \| MLDocumentFragment \| MLElement \| MLBlock \| null` | Syntactical parent including `MLBlock` nodes |
|
|
31
|
+
| `childNodes` | `NodeListOf<MLChildNode>` | Child nodes (Element, Text, Comment, Block). Fragment children are inlined. |
|
|
32
|
+
| `firstChild` | `MLChildNode \| null` | First child node |
|
|
33
|
+
| `lastChild` | `MLChildNode \| null` | Last child node |
|
|
34
|
+
| `nextSibling` | `MLChildNode \| null` | Next sibling with the same `parentNode` |
|
|
35
|
+
| `previousSibling` | `MLChildNode \| null` | Previous sibling with the same `parentNode` |
|
|
36
|
+
| `nextNode` | `MLNode \| null` | Next node in syntactical sibling list (from `syntacticalParentNode.childNodes`) |
|
|
37
|
+
| `prevNode` | `MLNode \| null` | Previous node in syntactical sibling list |
|
|
38
|
+
| `prevToken` | `MLNode \| null` | Previous node in document-order `nodeList` (skips omitted elements) |
|
|
39
|
+
| `ownerDocument` | `any` | Owner document (DOM-compatible, typed as `any`) |
|
|
40
|
+
| `ownerMLDocument` | `MLDocument<T, O>` | Owner document with proper generic types |
|
|
41
|
+
| `isFragment` | `boolean` | Whether this node acts as a fragment |
|
|
42
|
+
|
|
43
|
+
#### `nextNode`/`prevNode` vs `nextSibling`/`previousSibling`
|
|
44
|
+
|
|
45
|
+
These two pairs serve different purposes:
|
|
46
|
+
|
|
47
|
+
- **`nextNode`/`prevNode`**: Navigate the syntactical sibling list from `syntacticalParentNode.childNodes` (or `nodeList` if no syntactical parent). These include `MLBlock` nodes and work at the AST level.
|
|
48
|
+
- **`nextSibling`/`previousSibling`**: Navigate siblings sharing the same DOM `parentNode`. These skip over nodes whose `parentNode` differs (e.g., nodes inside non-transparent blocks).
|
|
49
|
+
|
|
50
|
+
#### `prevToken` and Omitted Elements
|
|
51
|
+
|
|
52
|
+
`prevToken` walks the document-order `nodeList` but **skips omitted (ghost) elements**. Omitted elements have no corresponding source tokens, so including them would break offset calculations. This is important for indentation analysis and source reconstruction.
|
|
53
|
+
|
|
54
|
+
### `childNodes` and Fragment Expansion
|
|
55
|
+
|
|
56
|
+
When a child node has `isFragment === true`, its own children are inlined into the parent's `childNodes`:
|
|
57
|
+
|
|
58
|
+
```jsx
|
|
59
|
+
// JSX fragment
|
|
60
|
+
<div>
|
|
61
|
+
<>
|
|
62
|
+
{' '}
|
|
63
|
+
{/* isFragment = true */}
|
|
64
|
+
<p>A</p>
|
|
65
|
+
<p>B</p>
|
|
66
|
+
</>
|
|
67
|
+
<p>C</p>
|
|
68
|
+
</div>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`div.childNodes` yields `[<p>A</p>, <p>B</p>, <p>C</p>]` -- the fragment wrapper is transparent.
|
|
72
|
+
|
|
73
|
+
### `parentNode` and MLBlock Transparency
|
|
74
|
+
|
|
75
|
+
The `parentNode` getter handles `MLBlock` transparency:
|
|
76
|
+
|
|
77
|
+
1. Get the `syntacticalParentNode`
|
|
78
|
+
2. If the parent is an `MLBlock` with `isTransparent === true`: return the block's `parentNode` (recursive skip)
|
|
79
|
+
3. If the parent is an `MLBlock` with `isTransparent === false`: return `null` (the node is "orphaned" from the DOM perspective)
|
|
80
|
+
4. If the parent is a fragment `MLDocument` (i.e., `isFragment === true`): return `null`
|
|
81
|
+
5. Otherwise: return the parent as-is
|
|
82
|
+
|
|
83
|
+
| Scenario | `syntacticalParentNode` | `parentNode` |
|
|
84
|
+
| --------------------------------------------- | ----------------------- | -------------------------- |
|
|
85
|
+
| `<div>` inside `<body>` | `<body>` | `<body>` |
|
|
86
|
+
| `<span>` inside Pug `if` block inside `<div>` | `#ml-block` | `<div>` (transparent skip) |
|
|
87
|
+
| `<span>` inside non-transparent block | `#ml-block` | `null` |
|
|
88
|
+
| Top-level in fragment document | `#document` | `null` |
|
|
89
|
+
|
|
90
|
+
```pug
|
|
91
|
+
//- Pug example
|
|
92
|
+
div
|
|
93
|
+
if foo
|
|
94
|
+
span
|
|
95
|
+
//- syntacticalParentNode: #ml-block
|
|
96
|
+
//- parentNode: <div> (block is transparent, skipped)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### `conditionalChildNodes()` -- Conditional Branch Pattern Generation
|
|
100
|
+
|
|
101
|
+
Generates all possible child node combinations from template engine conditional branches. This is used by rules like `permitted-contents` to verify content models against every possible rendering path.
|
|
102
|
+
|
|
103
|
+
#### Algorithm
|
|
104
|
+
|
|
105
|
+
1. Walk `childNodes` sequentially
|
|
106
|
+
2. When an `MLBlock` is encountered, determine the branch `mode` from its `blockBehavior?.type`:
|
|
107
|
+
- `'if'` or `'if:elseif'` → mode `'if'`
|
|
108
|
+
- `'switch:case'` → mode `'switch'`
|
|
109
|
+
- `'if:else'`, `'each'`, `'each:empty'`, `'switch:default'`, `'await'`, `'await:catch'`, `'await:then'` → continue in current mode (no new mode set)
|
|
110
|
+
- Other types → skip (not a conditional branch)
|
|
111
|
+
3. Recursively call `conditionalChildNodes()` on the block to get its sub-patterns
|
|
112
|
+
4. Collect branches; when a non-block child is reached, close the current branch group
|
|
113
|
+
5. Whitespace-only text nodes are skipped
|
|
114
|
+
6. For `'if'` and `'switch'` modes: a `null` sentinel is appended to represent the "empty branch" (the case where nothing is rendered)
|
|
115
|
+
7. Pass the collected branches to `branchesToPatterns()` to generate the Cartesian product of all combinations
|
|
116
|
+
|
|
117
|
+
#### Example
|
|
118
|
+
|
|
119
|
+
```html
|
|
120
|
+
<ul>
|
|
121
|
+
{% if cond %}
|
|
122
|
+
<li>A</li>
|
|
123
|
+
{% else %}
|
|
124
|
+
<li>B</li>
|
|
125
|
+
{% endif %}
|
|
126
|
+
<li>C</li>
|
|
127
|
+
</ul>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`ul.conditionalChildNodes()` returns:
|
|
131
|
+
|
|
132
|
+
- Pattern 1: `[<li>A</li>, <li>C</li>]`
|
|
133
|
+
- Pattern 2: `[<li>B</li>, <li>C</li>]`
|
|
134
|
+
|
|
135
|
+
The `permitted-contents` rule checks **every** pattern to ensure validity.
|
|
136
|
+
|
|
137
|
+
### `findSubsequentNodes(selector?)`
|
|
138
|
+
|
|
139
|
+
Collects nodes appearing after this node in document order:
|
|
140
|
+
|
|
141
|
+
1. Iterates `ownerMLDocument.nodeList`
|
|
142
|
+
2. Skips nodes whose `endOffset <= this.endOffset`
|
|
143
|
+
3. Skips descendants (via `this.contains(node)`)
|
|
144
|
+
4. If `selector` is provided: only includes elements matching the CSS selector
|
|
145
|
+
5. If no `selector`: includes all subsequent `MLChildNode` instances (Element, Text, Comment, Block)
|
|
146
|
+
|
|
147
|
+
### Rule Properties
|
|
148
|
+
|
|
149
|
+
| Property | Type | Description |
|
|
150
|
+
| -------- | ------------------------- | -------------------------------------------- |
|
|
151
|
+
| `rules` | `Record<string, AnyRule>` | Rules mapped to this node by `RuleMapper` |
|
|
152
|
+
| `rule` | `RuleInfo<T, O>` | Current rule's resolved config for this node |
|
|
153
|
+
|
|
154
|
+
The `rule` getter retrieves the setting for the currently-evaluating rule (via `document.currentRule.name`) from the `rules` record, then resolves it through `optimizeOption()`. It throws an error if no rule is currently being evaluated.
|
|
155
|
+
|
|
156
|
+
### Type Narrowing with `is()`
|
|
157
|
+
|
|
158
|
+
The `is()` method returns `this is NodeTypeOf<NType, T, O>`, enabling TypeScript type narrowing:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
function processNode(node: MLNode<any, any>) {
|
|
162
|
+
if (node.is(node.ELEMENT_NODE)) {
|
|
163
|
+
// node is narrowed to MLElement<any, any>
|
|
164
|
+
console.log(node.localName);
|
|
165
|
+
} else if (node.is(node.TEXT_NODE)) {
|
|
166
|
+
// node is narrowed to MLText<any, any>
|
|
167
|
+
console.log(node.isWhitespace());
|
|
168
|
+
} else if (node.is(node.MARKUPLINT_PREPROCESSOR_BLOCK)) {
|
|
169
|
+
// node is narrowed to MLBlock<any, any>
|
|
170
|
+
console.log(node.blockBehavior?.type);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## MLParentNode
|
|
176
|
+
|
|
177
|
+
**Source:** `src/ml-dom/node/parent-node.ts`
|
|
178
|
+
|
|
179
|
+
Abstract base class for nodes that can have children (`MLElement`, `MLDocument`, `MLDocumentFragment`). Implements the DOM `ParentNode` mixin.
|
|
180
|
+
|
|
181
|
+
### Properties
|
|
182
|
+
|
|
183
|
+
| Property | Type | Description |
|
|
184
|
+
| ------------------- | ----------------------------- | ------------------------------ |
|
|
185
|
+
| `children` | `HTMLCollectionOf<MLElement>` | Element-only children (cached) |
|
|
186
|
+
| `childElementCount` | `number` | Number of element children |
|
|
187
|
+
| `firstElementChild` | `MLElement \| null` | First child element |
|
|
188
|
+
| `lastElementChild` | `MLElement \| null` | Last child element |
|
|
189
|
+
|
|
190
|
+
### Methods
|
|
191
|
+
|
|
192
|
+
| Method | Signature | Description |
|
|
193
|
+
| ------------------ | ------------------------------------------------------------ | ------------------------------------------------------------------ |
|
|
194
|
+
| `querySelector` | `querySelector(selectors: string): MLElement \| null` | First descendant matching CSS selector |
|
|
195
|
+
| `querySelectorAll` | `querySelectorAll(selectors: string): NodeListOf<MLElement>` | All descendants matching CSS selector (cached per selector string) |
|
|
196
|
+
|
|
197
|
+
### `_descendantsToArray(filter?)`
|
|
198
|
+
|
|
199
|
+
Protected method that walks the tree recursively via `syncWalk` and returns a filtered array of descendants. Used internally by `querySelectorAll`.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# その他のノード型
|
|
2
|
+
|
|
3
|
+
MLBlock のドキュメントは専用の [MLBlock](./block.ja.md) リファレンスを参照してください。
|
|
4
|
+
|
|
5
|
+
## MLCharacterData(抽象)
|
|
6
|
+
|
|
7
|
+
**ソース:** `src/ml-dom/node/character-data.ts`
|
|
8
|
+
|
|
9
|
+
テキストコンテンツノードの抽象基底クラスです。DOM `CharacterData` インターフェースを実装します。
|
|
10
|
+
|
|
11
|
+
| プロパティ | 型 | 説明 |
|
|
12
|
+
| ------------------------ | ------------------- | --------------------------------------- |
|
|
13
|
+
| `data` | `string` | 文字データの内容(現在は `raw` を返す) |
|
|
14
|
+
| `nodeValue` | `string \| null` | `data` と同じ |
|
|
15
|
+
| `textContent` | `string` | `data` と同じ |
|
|
16
|
+
| `nextElementSibling` | `MLElement \| null` | 次の兄弟要素 |
|
|
17
|
+
| `previousElementSibling` | `MLElement \| null` | 前の兄弟要素 |
|
|
18
|
+
|
|
19
|
+
メソッド: `after()`、`before()`、`remove()`、`replaceWith()`。
|
|
20
|
+
|
|
21
|
+
## MLText
|
|
22
|
+
|
|
23
|
+
**ソース:** `src/ml-dom/node/text.ts`
|
|
24
|
+
|
|
25
|
+
テキストノードです。`MLCharacterData` を継承し、DOM `Text` を実装します。
|
|
26
|
+
|
|
27
|
+
- `nodeName`: `'#text'`
|
|
28
|
+
- `nodeType`: `3`(`TEXT_NODE`)
|
|
29
|
+
|
|
30
|
+
| プロパティ / メソッド | 戻り値 | 説明 |
|
|
31
|
+
| --------------------------- | --------- | -------------------------------------------------- |
|
|
32
|
+
| `isBogus` | `boolean` | 不正な AST ノードから生成されたノードの場合 `true` |
|
|
33
|
+
| `isWhitespace()` | `boolean` | テキストが `/^\s+$/` にマッチする場合 `true` |
|
|
34
|
+
| `isRawTextElementContent()` | `boolean` | 親要素が `<script>` または `<style>` の場合 `true` |
|
|
35
|
+
|
|
36
|
+
## MLComment
|
|
37
|
+
|
|
38
|
+
**ソース:** `src/ml-dom/node/comment.ts`
|
|
39
|
+
|
|
40
|
+
コメントノードです。`MLCharacterData` を継承し、DOM `Comment` を実装します。
|
|
41
|
+
|
|
42
|
+
- `nodeName`: `'#comment'`
|
|
43
|
+
- `nodeType`: `8`(`COMMENT_NODE`)
|
|
44
|
+
- `textContent`: コメントの `data` を返す
|
|
45
|
+
|
|
46
|
+
## MLDocumentType
|
|
47
|
+
|
|
48
|
+
**ソース:** `src/ml-dom/node/document-type.ts`
|
|
49
|
+
|
|
50
|
+
DOCTYPE ノードです。`MLNode` を継承し、DOM `DocumentType` を実装します。
|
|
51
|
+
|
|
52
|
+
- `nodeType`: `10`(`DOCUMENT_TYPE_NODE`)
|
|
53
|
+
- `nodeName`: `name` と同じ
|
|
54
|
+
- `textContent`: 常に `null`
|
|
55
|
+
|
|
56
|
+
| プロパティ | 型 | 説明 |
|
|
57
|
+
| ---------- | -------- | ------------------------------------ |
|
|
58
|
+
| `name` | `string` | ドキュメントタイプ名(例: `"html"`) |
|
|
59
|
+
| `publicId` | `string` | パブリック識別子、または空文字列 |
|
|
60
|
+
| `systemId` | `string` | システム識別子、または空文字列 |
|
|
61
|
+
|
|
62
|
+
## MLElementCloseTag
|
|
63
|
+
|
|
64
|
+
**ソース:** `src/ml-dom/node/element-close-tag.ts`
|
|
65
|
+
|
|
66
|
+
対応する開始タグ要素とペアになる閉じタグです。`MLNode` を継承します。閉じタグはドキュメントの `nodeList` の一部**ではなく**、ペアの `MLElement` のサテライトとしてのみ存在します。
|
|
67
|
+
|
|
68
|
+
MLElementCloseTag は2つの目的で存在します:
|
|
69
|
+
|
|
70
|
+
1. **構文位置の追跡**: 閉じタグのソース位置(`startLine`、`startCol`、`raw` など)を記録します。`case-sensitive-tag-name` のようなルールは、開始タグではなく閉じタグの正確な位置で違反を報告するためにこれを使用します。
|
|
71
|
+
2. **存在の有無の検出**: 閉じタグが存在しない場合、`MLElement.closeTag` は `null` になります。`end-tag` のようなルールは `el.closeTag != null` で非 void 要素の閉じタグの欠落(省略や漏れ)を検出します。
|
|
72
|
+
|
|
73
|
+
### プロパティ
|
|
74
|
+
|
|
75
|
+
| プロパティ | 型 | 説明 |
|
|
76
|
+
| ---------- | ----------- | ----------------------------------------------- |
|
|
77
|
+
| `pair` | `MLElement` | 対応する開始要素 |
|
|
78
|
+
| `rawName` | `string` | ソースに記述されたタグ名(AST `nodeName` から) |
|
|
79
|
+
| `nodeName` | `string` | ペアの要素の `nodeName` から導出されたタグ名 |
|
|
80
|
+
|
|
81
|
+
### ルールでの使用例
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
// end-tag ルール: 閉じタグの欠落を検出
|
|
85
|
+
if (el.closeTag != null) {
|
|
86
|
+
return; // 閉じタグが存在する → OK
|
|
87
|
+
}
|
|
88
|
+
report({ scope: el, message: t('Missing {0}', t('the {0}', 'end tag')) });
|
|
89
|
+
|
|
90
|
+
// case-sensitive-tag-name ルール: 閉じタグのソース位置でレポート
|
|
91
|
+
const closeTag = el.closeTag;
|
|
92
|
+
if (closeTag && deny.test(closeTag.raw)) {
|
|
93
|
+
report({
|
|
94
|
+
scope: {
|
|
95
|
+
rule: el.rule,
|
|
96
|
+
startLine: closeTag.startLine,
|
|
97
|
+
startCol: closeTag.startCol,
|
|
98
|
+
raw: closeTag.raw,
|
|
99
|
+
},
|
|
100
|
+
message,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### `toString(fixed?)`
|
|
106
|
+
|
|
107
|
+
`fixed=true` の場合:
|
|
108
|
+
|
|
109
|
+
- 要素が仮想要素(`#` で始まる)または省略された要素 → `raw` を返す
|
|
110
|
+
- それ以外:ペアの区切り文字を使って `tagOpenChar` + `/` + タグ名 + `tagCloseChar` を再構築する。タグ名は `pair.fixedNodeName === pair.rawName`(修正なし)の場合は `this.rawName` を使い、それ以外は `pair.fixedNodeName` を使う
|
|
111
|
+
|
|
112
|
+
## MLDocumentFragment
|
|
113
|
+
|
|
114
|
+
**ソース:** `src/ml-dom/node/document-fragment.ts`
|
|
115
|
+
|
|
116
|
+
JSX フラグメント(`<>...</>`)や同様の構文のフラグメントルートノードです。`MLParentNode` を継承し、DOM `DocumentFragment` を実装します。
|
|
117
|
+
|
|
118
|
+
- `nodeName`: `'#document-fragment'`
|
|
119
|
+
- `nodeType`: `11`(`DOCUMENT_FRAGMENT_NODE`)
|
|
120
|
+
- `textContent`: すべての子ノードのテキストコンテンツの連結
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Other Node Types
|
|
2
|
+
|
|
3
|
+
For MLBlock documentation, see the dedicated [MLBlock](./block.md) reference.
|
|
4
|
+
|
|
5
|
+
## MLCharacterData (abstract)
|
|
6
|
+
|
|
7
|
+
**Source:** `src/ml-dom/node/character-data.ts`
|
|
8
|
+
|
|
9
|
+
Abstract base class for text content nodes. Implements DOM `CharacterData` interface.
|
|
10
|
+
|
|
11
|
+
| Property | Type | Description |
|
|
12
|
+
| ------------------------ | ------------------- | ------------------------------------------------ |
|
|
13
|
+
| `data` | `string` | Character data content (currently returns `raw`) |
|
|
14
|
+
| `nodeValue` | `string \| null` | Same as `data` |
|
|
15
|
+
| `textContent` | `string` | Same as `data` |
|
|
16
|
+
| `nextElementSibling` | `MLElement \| null` | Next sibling element |
|
|
17
|
+
| `previousElementSibling` | `MLElement \| null` | Previous sibling element |
|
|
18
|
+
|
|
19
|
+
Methods: `after()`, `before()`, `remove()`, `replaceWith()`.
|
|
20
|
+
|
|
21
|
+
## MLText
|
|
22
|
+
|
|
23
|
+
**Source:** `src/ml-dom/node/text.ts`
|
|
24
|
+
|
|
25
|
+
Text node. Extends `MLCharacterData` and implements DOM `Text`.
|
|
26
|
+
|
|
27
|
+
- `nodeName`: `'#text'`
|
|
28
|
+
- `nodeType`: `3` (`TEXT_NODE`)
|
|
29
|
+
|
|
30
|
+
| Property / Method | Returns | Description |
|
|
31
|
+
| --------------------------- | --------- | ------------------------------------------------------- |
|
|
32
|
+
| `isBogus` | `boolean` | `true` if this node originated from an invalid AST node |
|
|
33
|
+
| `isWhitespace()` | `boolean` | `true` if text matches `/^\s+$/` |
|
|
34
|
+
| `isRawTextElementContent()` | `boolean` | `true` if parent element is `<script>` or `<style>` |
|
|
35
|
+
|
|
36
|
+
## MLComment
|
|
37
|
+
|
|
38
|
+
**Source:** `src/ml-dom/node/comment.ts`
|
|
39
|
+
|
|
40
|
+
Comment node. Extends `MLCharacterData` and implements DOM `Comment`.
|
|
41
|
+
|
|
42
|
+
- `nodeName`: `'#comment'`
|
|
43
|
+
- `nodeType`: `8` (`COMMENT_NODE`)
|
|
44
|
+
- `textContent`: Returns the comment's `data`
|
|
45
|
+
|
|
46
|
+
## MLDocumentType
|
|
47
|
+
|
|
48
|
+
**Source:** `src/ml-dom/node/document-type.ts`
|
|
49
|
+
|
|
50
|
+
DOCTYPE node. Extends `MLNode` and implements DOM `DocumentType`.
|
|
51
|
+
|
|
52
|
+
- `nodeType`: `10` (`DOCUMENT_TYPE_NODE`)
|
|
53
|
+
- `nodeName`: Same as `name`
|
|
54
|
+
- `textContent`: Always `null`
|
|
55
|
+
|
|
56
|
+
| Property | Type | Description |
|
|
57
|
+
| ---------- | -------- | ----------------------------------- |
|
|
58
|
+
| `name` | `string` | Document type name (e.g., `"html"`) |
|
|
59
|
+
| `publicId` | `string` | Public identifier, or empty string |
|
|
60
|
+
| `systemId` | `string` | System identifier, or empty string |
|
|
61
|
+
|
|
62
|
+
## MLElementCloseTag
|
|
63
|
+
|
|
64
|
+
**Source:** `src/ml-dom/node/element-close-tag.ts`
|
|
65
|
+
|
|
66
|
+
Close tag paired with its corresponding open tag element. Extends `MLNode`. Close tags are **not** part of the document `nodeList`; they exist only as satellites of their paired `MLElement`.
|
|
67
|
+
|
|
68
|
+
MLElementCloseTag exists for two purposes:
|
|
69
|
+
|
|
70
|
+
1. **Syntax location tracking**: It records the source position (`startLine`, `startCol`, `raw`, etc.) of the close tag. Rules like `case-sensitive-tag-name` use this to report violations at the exact close tag location rather than the open tag.
|
|
71
|
+
2. **Presence/absence detection**: `MLElement.closeTag` is `null` when no close tag exists. Rules like `end-tag` check `el.closeTag != null` to detect missing close tags (omissions or errors) on non-void elements.
|
|
72
|
+
|
|
73
|
+
### Properties
|
|
74
|
+
|
|
75
|
+
| Property | Type | Description |
|
|
76
|
+
| ---------- | ----------- | ----------------------------------------------------- |
|
|
77
|
+
| `pair` | `MLElement` | The corresponding opening element |
|
|
78
|
+
| `rawName` | `string` | Tag name as written in source (from AST `nodeName`) |
|
|
79
|
+
| `nodeName` | `string` | Tag name derived from the paired element's `nodeName` |
|
|
80
|
+
|
|
81
|
+
### Usage in Rules
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
// end-tag rule: detect missing close tags
|
|
85
|
+
if (el.closeTag != null) {
|
|
86
|
+
return; // close tag exists → OK
|
|
87
|
+
}
|
|
88
|
+
report({ scope: el, message: t('Missing {0}', t('the {0}', 'end tag')) });
|
|
89
|
+
|
|
90
|
+
// case-sensitive-tag-name rule: report at the close tag's source position
|
|
91
|
+
const closeTag = el.closeTag;
|
|
92
|
+
if (closeTag && deny.test(closeTag.raw)) {
|
|
93
|
+
report({
|
|
94
|
+
scope: {
|
|
95
|
+
rule: el.rule,
|
|
96
|
+
startLine: closeTag.startLine,
|
|
97
|
+
startCol: closeTag.startCol,
|
|
98
|
+
raw: closeTag.raw,
|
|
99
|
+
},
|
|
100
|
+
message,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### `toString(fixed?)`
|
|
106
|
+
|
|
107
|
+
When `fixed=true`:
|
|
108
|
+
|
|
109
|
+
- If the element is a virtual element (starts with `#`) or is omitted → returns `raw`
|
|
110
|
+
- Otherwise: reconstructs `tagOpenChar` + `/` + tag name + `tagCloseChar` using the pair's delimiters. The tag name is determined as: if `pair.fixedNodeName === pair.rawName` (no fix applied), use `this.rawName`; otherwise use `pair.fixedNodeName`
|
|
111
|
+
|
|
112
|
+
## MLDocumentFragment
|
|
113
|
+
|
|
114
|
+
**Source:** `src/ml-dom/node/document-fragment.ts`
|
|
115
|
+
|
|
116
|
+
Fragment root node for JSX fragments (`<>...</>`) and similar constructs. Extends `MLParentNode` and implements DOM `DocumentFragment`.
|
|
117
|
+
|
|
118
|
+
- `nodeName`: `'#document-fragment'`
|
|
119
|
+
- `nodeType`: `11` (`DOCUMENT_FRAGMENT_NODE`)
|
|
120
|
+
- `textContent`: Concatenation of all child nodes' text content
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# MLDOM 概要
|
|
2
|
+
|
|
3
|
+
## 概要
|
|
4
|
+
|
|
5
|
+
MLDOM は DOM Standard に準拠した抽象化レイヤーで、`@markuplint/ml-ast` の AST ノードを DOM インターフェース実装クラスにラップします。各 MLDOM クラスは対応する DOM API(`Node`、`Element`、`Document` など)を提供しつつ、ルール格納、トークンレベルのソース追跡、アクセシブル名の計算など markuplint 固有の機能で拡張しています。
|
|
6
|
+
|
|
7
|
+
すべての MLDOM クラスは2つの型パラメータを持つジェネリクスです:
|
|
8
|
+
|
|
9
|
+
- `T extends RuleConfigValue` -- ルール設定値の型
|
|
10
|
+
- `O extends PlainData` -- ルールオプションの型
|
|
11
|
+
|
|
12
|
+
これらのジェネリクスは **`createRule` のためだけに存在**します。ノードツリー全体に伝播することで、サードパーティのルール作成者が `verify()` / `fix()` コールバック内で `node.rule` に型安全にアクセスできるようにしています:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// サードパーティルール -- T = 'always' | 'never', O = { allow: string[] }
|
|
16
|
+
export default createRule<'always' | 'never', { allow: string[] }>({
|
|
17
|
+
defaultValue: 'always',
|
|
18
|
+
defaultOptions: { allow: [] },
|
|
19
|
+
async verify({ document, report, t }) {
|
|
20
|
+
await document.walkOn('Element', el => {
|
|
21
|
+
// el.rule の型は RuleInfo<'always' | 'never', { allow: string[] }>
|
|
22
|
+
const { value, options } = el.rule;
|
|
23
|
+
// ^'always'|'never' ^{ allow: string[] }
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
型の伝播経路: `createRule<T, O>` → `RuleSeed<T, O>` → `MLRuleContext<T, O>` → `MLDocument<T, O>` → `walkOn` ウォーカー → `MLElement<T, O>` → `el.rule: RuleInfo<T, O>`
|
|
30
|
+
|
|
31
|
+
#### ランタイムの実態: 意図的に dirty な実装
|
|
32
|
+
|
|
33
|
+
ジェネリクスはすべての MLDOM クラスに存在しますが、**ランタイム実装は型安全性を完全にバイパス**しています。これは意図的で実用的な設計上の選択です:
|
|
34
|
+
|
|
35
|
+
1. **`node.rules` は型なし**: `Record<string, AnyRule>` として宣言(`node.ts` 190行目)
|
|
36
|
+
2. **`RuleMapper` は `<any, any>` を使用**: マッパーは `MLNode<any, any>` を受け取り、型制約なしでルールを代入(`rule-mapper.ts` 47行目: `node.rules[ruleName] = rule.rule`)
|
|
37
|
+
3. **型安全性はキャストで回復**: `node.rule` ゲッターが格納されたルールを `as Rule<T, O>` でキャストし、型付きの `RuleInfo<T, O>` を生成(`node.ts` 514行目: `settingRule as Rule<T, O>`)
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
コンパイル時: MLNode<T, O> → node.rule: RuleInfo<T, O> ← ルール作成者にとって型安全
|
|
41
|
+
↕
|
|
42
|
+
ランタイム: node.rules = Record<string, AnyRule> ← 型なしストレージ
|
|
43
|
+
RuleMapper は <any, any> でルールを代入 ← ジェネリクスを無視
|
|
44
|
+
node.rule ゲッターが `as Rule<T, O>` でキャスト ← 型を回復
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
初めてコードベースを見る開発者は、すべての MLDOM クラスに `<T, O>` が存在するのにランタイムで実際に制約されている箇所が見つからず困惑するかもしれません。答えは:ランタイムでは制約されていません。ジェネリクスは `createRule` を使用するサードパーティのルール作成者の DX のためだけに存在する、コンパイル時のみのメカニズムです。
|
|
48
|
+
|
|
49
|
+
### UnexpectedCallError
|
|
50
|
+
|
|
51
|
+
MLDOM クラスは TypeScript 組み込みの DOM 型インターフェース(例: `MLNode implements Node`、`MLElement implements Element`)を実装しています。この `implements` 宣言は**メンテナンス戦略**です。DOM インターフェースへの準拠を宣言することで、TypeScript の型チェッカーが MLDOM クラスを DOM API サーフェスと同期させ続けることを保証します。組み込み DOM 型定義が更新された場合(例: `Element` に新しいプロパティが追加された場合)、コンパイラがエラーを報告し、気づかないうちにギャップが生じることを防ぎます。
|
|
52
|
+
|
|
53
|
+
静的解析のコンテキストでは意味を持たない DOM メソッド(markuplint のルールやカスタムルールで使用される可能性が低いもの)は、呼び出されると `UnexpectedCallError` をスローします。これにはミューテーションメソッド(`appendChild`、`removeChild`)、イベントメソッド(`addEventListener`、`dispatchEvent`)、レイアウト依存プロパティ(`clientHeight`、`offsetWidth`)が含まれます。
|
|
54
|
+
|
|
55
|
+
## クラス階層
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
MLToken<A extends MLASTToken>
|
|
59
|
+
└── MLNode<T, O, A extends MLASTNode> (abstract, implements Node)
|
|
60
|
+
├── MLAttr<T, O> (implements Attr)
|
|
61
|
+
├── MLCharacterData<T, O, A> (abstract, implements CharacterData)
|
|
62
|
+
│ ├── MLText<T, O> (implements Text)
|
|
63
|
+
│ └── MLComment<T, O> (implements Comment)
|
|
64
|
+
├── MLDocumentType<T, O> (implements DocumentType)
|
|
65
|
+
├── MLBlock<T, O>
|
|
66
|
+
├── MLElementCloseTag<T, O>
|
|
67
|
+
└── MLParentNode<T, O, A> (abstract, implements ParentNode)
|
|
68
|
+
├── MLElement<T, O> (implements Element, HTMLElement)
|
|
69
|
+
├── MLDocumentFragment<T, O> (implements DocumentFragment)
|
|
70
|
+
└── MLDocument<T, O> (implements Document)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## MLToken
|
|
74
|
+
|
|
75
|
+
**ソース:** `src/ml-dom/token/token.ts`
|
|
76
|
+
|
|
77
|
+
基底トークンクラスで、`MLASTToken` を位置情報でラップし、元の文字列(raw)と修正済み(fixed)の文字列表現を提供します。これはすべての MLDOM ノードの基盤です。
|
|
78
|
+
|
|
79
|
+
### プロパティ
|
|
80
|
+
|
|
81
|
+
| プロパティ | 型 | 説明 |
|
|
82
|
+
| ------------- | -------- | ----------------------------------------------------------------------------- |
|
|
83
|
+
| `uuid` | `string` | このトークンの一意な識別子 |
|
|
84
|
+
| `raw` | `string` | 元のソーステキスト(不変) |
|
|
85
|
+
| `fixed` | `string` | 修正済みのソーステキスト。初期値は `raw` と同じ。`fix()` メソッドで更新される |
|
|
86
|
+
| `startLine` | `number` | 1始まりの開始行番号 |
|
|
87
|
+
| `endLine` | `number` | 1始まりの終了行番号 |
|
|
88
|
+
| `startCol` | `number` | 1始まりの開始列番号 |
|
|
89
|
+
| `endCol` | `number` | 1始まりの終了列番号 |
|
|
90
|
+
| `startOffset` | `number` | 0始まりの開始文字オフセット |
|
|
91
|
+
| `endOffset` | `number` | 0始まりの終了文字オフセット |
|
|
92
|
+
|
|
93
|
+
### メソッド
|
|
94
|
+
|
|
95
|
+
| メソッド | シグネチャ | 説明 |
|
|
96
|
+
| ---------- | ----------------------------------- | ----------------------------------------------------------- |
|
|
97
|
+
| `fix` | `fix(raw: string): void` | リント自動修正用に `fixed` を修正内容で更新する |
|
|
98
|
+
| `toString` | `toString(fixed?: boolean): string` | `true` の場合 `fixed` の内容を、そうでなければ `raw` を返す |
|
|
99
|
+
|
|
100
|
+
### 座標系
|
|
101
|
+
|
|
102
|
+
オフセットは0始まり(0からカウント)、行と列は1始まり(1からカウント)です。これはほとんどのテキストエディタやエラーレポーターで使用される慣例に一致しています。
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# MLDOM Overview
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
MLDOM is a DOM Standard-conforming abstraction layer that wraps `@markuplint/ml-ast` AST nodes into DOM interface implementation classes. Each MLDOM class provides the corresponding DOM API (`Node`, `Element`, `Document`, etc.) while extending it with markuplint-specific features like rule storage, token-level source tracking, and accessible name computation.
|
|
6
|
+
|
|
7
|
+
All MLDOM classes are generic over two type parameters:
|
|
8
|
+
|
|
9
|
+
- `T extends RuleConfigValue` -- The rule configuration value type
|
|
10
|
+
- `O extends PlainData` -- The rule options type
|
|
11
|
+
|
|
12
|
+
These generics exist **solely for `createRule`**. They propagate through the entire node tree so that 3rd party rule authors get type-safe access to `node.rule` within `verify()` and `fix()` callbacks:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// 3rd party rule -- T = 'always' | 'never', O = { allow: string[] }
|
|
16
|
+
export default createRule<'always' | 'never', { allow: string[] }>({
|
|
17
|
+
defaultValue: 'always',
|
|
18
|
+
defaultOptions: { allow: [] },
|
|
19
|
+
async verify({ document, report, t }) {
|
|
20
|
+
await document.walkOn('Element', el => {
|
|
21
|
+
// el.rule is typed as RuleInfo<'always' | 'never', { allow: string[] }>
|
|
22
|
+
const { value, options } = el.rule;
|
|
23
|
+
// ^'always'|'never' ^{ allow: string[] }
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The type flow is: `createRule<T, O>` → `RuleSeed<T, O>` → `MLRuleContext<T, O>` → `MLDocument<T, O>` → `walkOn` walker → `MLElement<T, O>` → `el.rule: RuleInfo<T, O>`.
|
|
30
|
+
|
|
31
|
+
#### Runtime Reality: Intentionally Dirty Implementation
|
|
32
|
+
|
|
33
|
+
Despite the generics appearing on every MLDOM class, the **runtime implementation bypasses type safety entirely**. This is a deliberate, pragmatic design choice:
|
|
34
|
+
|
|
35
|
+
1. **`node.rules` is untyped**: declared as `Record<string, AnyRule>` (`node.ts` line 190)
|
|
36
|
+
2. **`RuleMapper` uses `<any, any>`**: the mapper accepts `MLNode<any, any>` and assigns rules without type constraints (`rule-mapper.ts` line 47: `node.rules[ruleName] = rule.rule`)
|
|
37
|
+
3. **Type safety is recovered via cast**: the `node.rule` getter casts the stored rule with `as Rule<T, O>` to produce a typed `RuleInfo<T, O>` (`node.ts` line 514: `settingRule as Rule<T, O>`)
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
Compile time: MLNode<T, O> → node.rule: RuleInfo<T, O> ← type-safe for rule authors
|
|
41
|
+
↕
|
|
42
|
+
Runtime: node.rules = Record<string, AnyRule> ← untyped storage
|
|
43
|
+
RuleMapper assigns rules as <any, any> ← ignores generics
|
|
44
|
+
node.rule getter casts `as Rule<T, O>` ← recovers type
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
This approach may confuse first-time contributors who see `<T, O>` on every MLDOM class but cannot find where these types are actually constrained at runtime. The answer is: they are not. The generics are a compile-time-only mechanism that exists entirely for the DX of 3rd party rule authors using `createRule`.
|
|
48
|
+
|
|
49
|
+
### UnexpectedCallError
|
|
50
|
+
|
|
51
|
+
MLDOM classes implement TypeScript's built-in DOM type interfaces (e.g., `MLNode implements Node`, `MLElement implements Element`). This `implements` declaration is a **maintenance strategy**: by declaring conformance to the DOM interfaces, TypeScript's type checker ensures that MLDOM classes keep up with the DOM API surface. When the built-in DOM type definitions are updated (e.g., new properties added to `Element`), the compiler reports errors, preventing unnoticed gaps.
|
|
52
|
+
|
|
53
|
+
DOM methods that are not meaningful in a static analysis context (i.e., unlikely to be used by markuplint rules or custom rules) throw `UnexpectedCallError` when called. This includes mutation methods (`appendChild`, `removeChild`), event methods (`addEventListener`, `dispatchEvent`), and layout-dependent properties (`clientHeight`, `offsetWidth`).
|
|
54
|
+
|
|
55
|
+
## Class Hierarchy
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
MLToken<A extends MLASTToken>
|
|
59
|
+
└── MLNode<T, O, A extends MLASTNode> (abstract, implements Node)
|
|
60
|
+
├── MLAttr<T, O> (implements Attr)
|
|
61
|
+
├── MLCharacterData<T, O, A> (abstract, implements CharacterData)
|
|
62
|
+
│ ├── MLText<T, O> (implements Text)
|
|
63
|
+
│ └── MLComment<T, O> (implements Comment)
|
|
64
|
+
├── MLDocumentType<T, O> (implements DocumentType)
|
|
65
|
+
├── MLBlock<T, O>
|
|
66
|
+
├── MLElementCloseTag<T, O>
|
|
67
|
+
└── MLParentNode<T, O, A> (abstract, implements ParentNode)
|
|
68
|
+
├── MLElement<T, O> (implements Element, HTMLElement)
|
|
69
|
+
├── MLDocumentFragment<T, O> (implements DocumentFragment)
|
|
70
|
+
└── MLDocument<T, O> (implements Document)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## MLToken
|
|
74
|
+
|
|
75
|
+
**Source:** `src/ml-dom/token/token.ts`
|
|
76
|
+
|
|
77
|
+
Base token class that wraps an `MLASTToken` with positional information and provides both raw and fixed (corrected) string representations. This is the foundation for all MLDOM nodes.
|
|
78
|
+
|
|
79
|
+
### Properties
|
|
80
|
+
|
|
81
|
+
| Property | Type | Description |
|
|
82
|
+
| ------------- | -------- | --------------------------------------------------------------------------------- |
|
|
83
|
+
| `uuid` | `string` | Unique identifier for this token |
|
|
84
|
+
| `raw` | `string` | Original source text (immutable) |
|
|
85
|
+
| `fixed` | `string` | Fixed (modified) source text; initially equals `raw`. Updated via `fix()` method. |
|
|
86
|
+
| `startLine` | `number` | One-based start line number |
|
|
87
|
+
| `endLine` | `number` | One-based end line number |
|
|
88
|
+
| `startCol` | `number` | One-based start column number |
|
|
89
|
+
| `endCol` | `number` | One-based end column number |
|
|
90
|
+
| `startOffset` | `number` | Zero-based start character offset |
|
|
91
|
+
| `endOffset` | `number` | Zero-based end character offset |
|
|
92
|
+
|
|
93
|
+
### Methods
|
|
94
|
+
|
|
95
|
+
| Method | Signature | Description |
|
|
96
|
+
| ---------- | ----------------------------------- | ------------------------------------------------------------ |
|
|
97
|
+
| `fix` | `fix(raw: string): void` | Updates `fixed` with corrected content for lint auto-fix |
|
|
98
|
+
| `toString` | `toString(fixed?: boolean): string` | Returns `fixed` content when `true`, otherwise returns `raw` |
|
|
99
|
+
|
|
100
|
+
### Coordinate System
|
|
101
|
+
|
|
102
|
+
Offsets are zero-based (counting from 0), while lines and columns are one-based (counting from 1). This matches the conventions used by most text editors and error reporters.
|