@markuplint/ml-core 5.0.0-alpha.1 → 5.0.0-alpha.3

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.
Files changed (46) hide show
  1. package/ARCHITECTURE.ja.md +158 -5
  2. package/ARCHITECTURE.md +209 -6
  3. package/CHANGELOG.md +25 -0
  4. package/docs/ml-dom/document.ja.md +7 -14
  5. package/docs/ml-dom/document.md +7 -14
  6. package/docs/ml-dom/element.ja.md +9 -24
  7. package/docs/ml-dom/element.md +9 -24
  8. package/docs/rule-system.ja.md +1 -1
  9. package/docs/rule-system.md +1 -1
  10. package/lib/cursor-offset.d.ts +13 -0
  11. package/lib/cursor-offset.js +34 -0
  12. package/lib/fix-applier.d.ts +32 -0
  13. package/lib/fix-applier.js +75 -0
  14. package/lib/index.d.ts +3 -0
  15. package/lib/index.js +2 -0
  16. package/lib/ml-core.d.ts +53 -8
  17. package/lib/ml-core.js +197 -59
  18. package/lib/ml-dom/helper/get-indent.d.ts +0 -1
  19. package/lib/ml-dom/helper/get-indent.js +5 -18
  20. package/lib/ml-dom/node/attr.d.ts +2 -13
  21. package/lib/ml-dom/node/attr.js +3 -35
  22. package/lib/ml-dom/node/block.js +2 -1
  23. package/lib/ml-dom/node/character-data.d.ts +35 -0
  24. package/lib/ml-dom/node/character-data.js +35 -6
  25. package/lib/ml-dom/node/document.d.ts +2 -27
  26. package/lib/ml-dom/node/document.js +7 -46
  27. package/lib/ml-dom/node/dom-token-list.d.ts +0 -1
  28. package/lib/ml-dom/node/dom-token-list.js +3 -3
  29. package/lib/ml-dom/node/element-close-tag.d.ts +1 -1
  30. package/lib/ml-dom/node/element-close-tag.js +2 -16
  31. package/lib/ml-dom/node/element.d.ts +2 -19
  32. package/lib/ml-dom/node/element.js +3 -65
  33. package/lib/ml-dom/token/token.d.ts +3 -18
  34. package/lib/ml-dom/token/token.js +7 -28
  35. package/lib/ml-rule/index.d.ts +1 -0
  36. package/lib/ml-rule/index.js +1 -0
  37. package/lib/ml-rule/ml-rule-context.d.ts +2 -31
  38. package/lib/ml-rule/ml-rule-context.js +18 -18
  39. package/lib/ml-rule/ml-rule.d.ts +6 -11
  40. package/lib/ml-rule/ml-rule.js +36 -37
  41. package/lib/ml-rule/rule-fixer.d.ts +20 -0
  42. package/lib/ml-rule/rule-fixer.js +38 -0
  43. package/lib/ml-rule/types.d.ts +1 -2
  44. package/lib/test/index.d.ts +1 -10
  45. package/lib/test/index.js +0 -11
  46. package/package.json +12 -12
package/lib/ml-core.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { ParserError } from '@markuplint/parser-utils';
2
2
  import { log, enableDebug } from './debug.js';
3
+ import { applyFixes } from './fix-applier.js';
3
4
  import { Document } from './ml-dom/index.js';
4
5
  import { expandNamedNodeRules, expandNamedRules } from './virtual-rule.js';
5
6
  const resultLog = log.extend('result');
@@ -69,8 +70,8 @@ export class MLCore {
69
70
  };
70
71
  this.#disabledNamespaces = extractDisabledNamespaces(resolvedRules);
71
72
  this.#configErrors.push(...namedRulesResult.errors, ...nodeRuleResult.errors, ...childNodeRuleResult.errors);
72
- this._parse();
73
- this._createDocument();
73
+ this.#parse();
74
+ this.#createDocument();
74
75
  }
75
76
  /**
76
77
  * The parsed document, or a {@link ParserError} if parsing failed.
@@ -85,8 +86,8 @@ export class MLCore {
85
86
  */
86
87
  setCode(sourceCode) {
87
88
  this.#sourceCode = sourceCode;
88
- this._parse();
89
- this._createDocument();
89
+ this.#parse();
90
+ this.#createDocument();
90
91
  }
91
92
  /**
92
93
  * Updates the linting configuration and re-creates the document.
@@ -128,30 +129,23 @@ export class MLCore {
128
129
  if (parserOptions &&
129
130
  (parserOptions.ignoreFrontMatter !== this.#parserOptions.ignoreFrontMatter ||
130
131
  parserOptions.authoredElementName !== this.#parserOptions.authoredElementName)) {
131
- this._parse();
132
+ this.#parse();
132
133
  }
133
- this._createDocument();
134
+ this.#createDocument();
134
135
  }
135
- /**
136
- * Runs all configured rules against the parsed document and returns violations.
137
- *
138
- * If the document failed to parse, a single parse-error violation is returned
139
- * (unless parse errors are suppressed via severity options).
140
- *
141
- * @param fix - Whether to attempt auto-fixing violations
142
- * @returns An array of violations found during verification
143
- */
144
- async verify(fix = false) {
136
+ async verify(fixOrOptions) {
137
+ const options = typeof fixOrOptions === 'boolean' ? { fix: fixOrOptions } : (fixOrOptions ?? {});
138
+ const fix = options.fix ?? false;
145
139
  log('verify: start');
146
140
  const violations = [];
147
141
  if (this.#document instanceof ParserError) {
148
- const parseError = this._createParseError(this.#document.message, this.#document.line, this.#document.col, this.#document.raw);
142
+ const parseError = this.#createParseError(this.#document.message, this.#document.line, this.#document.col, this.#document.raw);
149
143
  if (!parseError) {
150
- return [];
144
+ return { violations: [], fixedCode: fix ? this.#sourceCode : undefined };
151
145
  }
152
146
  violations.push(parseError);
153
147
  log('verify: error %o', this.#document.message);
154
- return violations;
148
+ return { violations, fixedCode: fix ? this.#sourceCode : undefined };
155
149
  }
156
150
  const definedRuleName = new Set(this.#rules.map(rule => rule.name));
157
151
  const setRuleNames = new Set([
@@ -185,42 +179,8 @@ export class MLCore {
185
179
  raw: '',
186
180
  });
187
181
  }
188
- for (const rule of this.#rules) {
189
- // For virtual rules, check disable conditions:
190
- // 1. Exact name match: rules["alias/name"]: false
191
- // 2. Group disable: rules["groupName"]: false (multi-entry named nodeRules)
192
- // 3. Namespace wildcard: rules["scope/*"]: false
193
- // Note: base rule name disable (rules["baseRuleName"]: false) is handled
194
- // during expandNamedRules for named rule groups in the rules section.
195
- if (rule.baseRuleId &&
196
- (this.#ruleset.rules[rule.name] === false ||
197
- (rule.groupName && this.#ruleset.rules[rule.groupName] === false) ||
198
- this.#disabledNamespaces.some(ns => rule.name.startsWith(ns)))) {
199
- continue;
200
- }
201
- const ruleInfo = rule.getRuleInfo(this.#ruleset, rule.name);
202
- if (ruleInfo.disabled && ruleInfo.nodeRules.length === 0 && ruleInfo.childNodeRules.length === 0) {
203
- continue;
204
- }
205
- log('%s Rule: verify', rule.name);
206
- const results = await rule.verify(this.#document, this.#locale, fix).catch(error => {
207
- if (error instanceof ParserError) {
208
- return error;
209
- }
210
- throw error;
211
- });
212
- if (results instanceof ParserError) {
213
- const parseError = this._createParseError(results.message, results.line, results.col, results.raw);
214
- if (parseError) {
215
- log('%s Rule: verify error %o', rule.name, results.message);
216
- violations.push(parseError);
217
- }
218
- }
219
- else {
220
- violations.push(...results);
221
- }
222
- log('%s Rule: verify end', rule.name);
223
- }
182
+ const ruleViolations = await this.#runAllRules(fix);
183
+ violations.push(...ruleViolations);
224
184
  if (resultLog.enabled) {
225
185
  // eslint-disable-next-line unicorn/no-array-reduce
226
186
  const { e, w, i } = violations.reduce((c, v) => {
@@ -236,10 +196,42 @@ export class MLCore {
236
196
  resultLog('Warning: %d', w);
237
197
  resultLog('Info: %d', i);
238
198
  }
199
+ // Apply fixes if enabled
200
+ let fixedCode;
201
+ let fixSummary;
202
+ if (fix) {
203
+ const hasFixes = violations.some(v => v.fix);
204
+ if (hasFixes) {
205
+ const originalSourceCode = this.#sourceCode;
206
+ const originalAst = this.#ast;
207
+ const originalDocument = this.#document;
208
+ try {
209
+ const fixResult = await this.#multiPassFix(violations);
210
+ fixedCode = fixResult.code;
211
+ fixSummary = fixResult.summary;
212
+ }
213
+ finally {
214
+ // Restore original state - verify() must be non-mutating
215
+ this.#sourceCode = originalSourceCode;
216
+ this.#ast = originalAst;
217
+ this.#document = originalDocument;
218
+ }
219
+ }
220
+ else {
221
+ fixedCode = this.#sourceCode;
222
+ fixSummary = {
223
+ passCount: 0,
224
+ totalApplied: 0,
225
+ totalSkipped: 0,
226
+ reachedMaxPasses: false,
227
+ firstPassEdits: [],
228
+ };
229
+ }
230
+ }
239
231
  log('verify: end');
240
- return violations;
232
+ return { violations, fixedCode, fixSummary };
241
233
  }
242
- _createDocument() {
234
+ #createDocument() {
243
235
  if (!this.#ast) {
244
236
  return;
245
237
  }
@@ -261,7 +253,7 @@ export class MLCore {
261
253
  }
262
254
  }
263
255
  }
264
- _createParseError(message, line, col, raw) {
256
+ #createParseError(message, line, col, raw) {
265
257
  if (this.#severity.parseError === false || this.#severity.parseError === 'off') {
266
258
  return null;
267
259
  }
@@ -278,7 +270,138 @@ export class MLCore {
278
270
  raw,
279
271
  };
280
272
  }
281
- _parse() {
273
+ /**
274
+ * Iteratively applies fixes, re-parses, and re-verifies until no overlapping
275
+ * fixes remain or the maximum pass count is reached (ESLint-style multi-pass loop).
276
+ *
277
+ * **Callers must save/restore `#sourceCode`, `#ast`, and `#document`** because
278
+ * this method mutates them during intermediate re-parse steps.
279
+ *
280
+ * @param initialViolations - Violations from the first verification pass
281
+ * @returns The final fixed source code and a summary of the fix process
282
+ */
283
+ async #multiPassFix(initialViolations) {
284
+ const MAX_FIX_PASSES = 10;
285
+ let currentCode = this.#sourceCode;
286
+ let previousCode;
287
+ let fixes = extractFixes(initialViolations);
288
+ let totalApplied = 0;
289
+ let totalSkipped = 0;
290
+ let firstPassEdits = [];
291
+ let pass = 0;
292
+ for (; pass < MAX_FIX_PASSES; pass++) {
293
+ log('fix pass %d: %d fixes', pass, fixes.length);
294
+ const result = applyFixes(currentCode, fixes);
295
+ totalApplied += result.applied.length;
296
+ totalSkipped += result.skipped.length;
297
+ if (pass === 0) {
298
+ firstPassEdits = result.appliedEdits;
299
+ }
300
+ if (result.applied.length === 0) {
301
+ log('fix pass %d: no fixes applied, stopping', pass);
302
+ break;
303
+ }
304
+ if (result.output === currentCode) {
305
+ log('fix pass %d: output unchanged, stopping', pass);
306
+ break;
307
+ }
308
+ // Cycle detection: if the output matches the code from two passes ago,
309
+ // fixes are oscillating (A → B → A) and will never converge.
310
+ if (previousCode !== undefined && result.output === previousCode) {
311
+ log('fix pass %d: cycle detected (output matches pass %d), stopping', pass, pass - 2);
312
+ currentCode = result.output;
313
+ break;
314
+ }
315
+ previousCode = currentCode;
316
+ currentCode = result.output;
317
+ if (result.skipped.length === 0) {
318
+ log('fix pass %d: all fixes applied, stopping', pass);
319
+ break;
320
+ }
321
+ // --- Multi-pass path (only when overlapping fixes exist) ---
322
+ log('fix pass %d: %d skipped, re-parsing for next pass', pass, result.skipped.length);
323
+ const previousGoodCode = currentCode;
324
+ this.#sourceCode = currentCode;
325
+ this.#parse();
326
+ this.#createDocument();
327
+ if (this.#document instanceof ParserError) {
328
+ log('fix pass %d: produced unparsable code, reverting to previous state', pass);
329
+ currentCode = previousGoodCode;
330
+ break;
331
+ }
332
+ const newViolations = await this.#runAllRules(true);
333
+ fixes = extractFixes(newViolations);
334
+ if (fixes.length === 0) {
335
+ log('fix pass %d: no more fixable violations, stopping', pass);
336
+ break;
337
+ }
338
+ }
339
+ const reachedMaxPasses = pass === MAX_FIX_PASSES;
340
+ if (reachedMaxPasses) {
341
+ log('fix: reached maximum number of passes (%d), some fixes may not have been applied', MAX_FIX_PASSES);
342
+ }
343
+ return {
344
+ code: currentCode,
345
+ summary: {
346
+ passCount: Math.min(pass + 1, MAX_FIX_PASSES),
347
+ totalApplied,
348
+ totalSkipped,
349
+ reachedMaxPasses,
350
+ firstPassEdits,
351
+ },
352
+ };
353
+ }
354
+ /**
355
+ * Executes all configured rules against the current document and collects violations.
356
+ * Skips disabled rules and handles virtual rule disable conditions.
357
+ *
358
+ * @param fix - Whether to execute fix callbacks on violations
359
+ * @returns All violations produced by the rule set
360
+ */
361
+ async #runAllRules(fix) {
362
+ const violations = [];
363
+ if (this.#document instanceof ParserError) {
364
+ return violations;
365
+ }
366
+ for (const rule of this.#rules) {
367
+ // For virtual rules, check disable conditions:
368
+ // 1. Exact name match: rules["alias/name"]: false
369
+ // 2. Group disable: rules["groupName"]: false (multi-entry named nodeRules)
370
+ // 3. Namespace wildcard: rules["scope/*"]: false
371
+ // Note: base rule name disable (rules["baseRuleName"]: false) is handled
372
+ // during expandNamedRules for named rule groups in the rules section.
373
+ if (rule.baseRuleId &&
374
+ (this.#ruleset.rules[rule.name] === false ||
375
+ (rule.groupName && this.#ruleset.rules[rule.groupName] === false) ||
376
+ this.#disabledNamespaces.some(ns => rule.name.startsWith(ns)))) {
377
+ continue;
378
+ }
379
+ const ruleInfo = rule.getRuleInfo(this.#ruleset, rule.name);
380
+ if (ruleInfo.disabled && ruleInfo.nodeRules.length === 0 && ruleInfo.childNodeRules.length === 0) {
381
+ continue;
382
+ }
383
+ log('%s Rule: verify', rule.name);
384
+ const results = await rule.verify(this.#document, this.#locale, fix).catch(error => {
385
+ if (error instanceof ParserError) {
386
+ return error;
387
+ }
388
+ throw error;
389
+ });
390
+ if (results instanceof ParserError) {
391
+ const parseError = this.#createParseError(results.message, results.line, results.col, results.raw);
392
+ if (parseError) {
393
+ log('%s Rule: verify error %o', rule.name, results.message);
394
+ violations.push(parseError);
395
+ }
396
+ }
397
+ else {
398
+ violations.push(...results);
399
+ }
400
+ log('%s Rule: verify end', rule.name);
401
+ }
402
+ return violations;
403
+ }
404
+ #parse() {
282
405
  try {
283
406
  this.#ast = this.#parser.parse(this.#sourceCode, this.#parserOptions);
284
407
  }
@@ -303,3 +426,18 @@ function extractDisabledNamespaces(rules) {
303
426
  .filter(([key, value]) => key.endsWith('/*') && value === false)
304
427
  .map(([key]) => key.slice(0, -1)); // "a11y/*" → "a11y/"
305
428
  }
429
+ /**
430
+ * Collects all `FixData` from violations that have a fix callback result.
431
+ *
432
+ * @param violations - The violations to extract fixes from
433
+ * @returns An array of `FixData` objects ready for `applyFixes()`
434
+ */
435
+ function extractFixes(violations) {
436
+ const fixes = [];
437
+ for (const v of violations) {
438
+ if (v.fix) {
439
+ fixes.push(v.fix);
440
+ }
441
+ }
442
+ return fixes;
443
+ }
@@ -16,6 +16,5 @@ declare class MLDOMIndentation {
16
16
  get raw(): string;
17
17
  get type(): 'tab' | 'space' | 'mixed' | 'none';
18
18
  get width(): number;
19
- fix(raw: string): void;
20
19
  }
21
20
  export {};
@@ -39,7 +39,6 @@ node) {
39
39
  const matched = isFirstToken(prevToken)
40
40
  ? prevToken.raw.match(/^(?:[\t ]*\r?\n)*([\t ]*)$/)
41
41
  : prevToken.raw.match(/\r?\n([\t ]*)$/);
42
- // console.log({ [`${this}`]: matched, _: prevToken.raw, f: prevToken._isFirstToken() });
43
42
  if (matched) {
44
43
  // Spaces will include empty string.
45
44
  const spaces = matched[1];
@@ -50,7 +49,7 @@ node) {
50
49
  return null;
51
50
  }
52
51
  class MLDOMIndentation {
53
- #fixed;
52
+ #raw;
54
53
  line;
55
54
  #node;
56
55
  #parent;
@@ -62,38 +61,26 @@ class MLDOMIndentation {
62
61
  this.line = line;
63
62
  this.#node = originTextNode;
64
63
  this.#parent = parentNode;
65
- this.#fixed = raw;
64
+ this.#raw = raw;
66
65
  }
67
66
  get raw() {
68
67
  if (!this.#parent.is(this.#parent.TEXT_NODE) && this.line !== this.#node.endLine) {
69
68
  return '';
70
69
  }
71
- return this.#fixed;
70
+ return this.#raw;
72
71
  }
73
72
  get type() {
74
73
  if (!this.#parent.is(this.#parent.TEXT_NODE) && this.line !== this.#node.endLine) {
75
74
  return 'none';
76
75
  }
77
- const raw = this.#fixed;
76
+ const raw = this.#raw;
78
77
  return raw === '' ? 'none' : /^\t+$/.test(raw) ? 'tab' : /^[^\t]+$/.test(raw) ? 'space' : 'mixed';
79
78
  }
80
79
  get width() {
81
80
  if (!this.#parent.is(this.#parent.TEXT_NODE) && this.line !== this.#node.endLine) {
82
81
  return 0;
83
82
  }
84
- return this.#fixed.length;
85
- }
86
- fix(raw) {
87
- const current = this.#fixed;
88
- this.#fixed = raw;
89
- const node = this.#node;
90
- const line = node.startLine;
91
- const lines = node.raw.split(/\r?\n/);
92
- const index = this.line - line;
93
- if (lines[index] != null) {
94
- lines[index] = lines[index].replace(current, this.#fixed);
95
- }
96
- node.fix(lines.join('\n'));
83
+ return this.#raw.length;
97
84
  }
98
85
  }
99
86
  function isFirstToken(
@@ -152,15 +152,6 @@ export declare class MLAttr<T extends RuleConfigValue, O extends PlainData = und
152
152
  * @see https://dom.spec.whatwg.org/#dom-attr-value
153
153
  */
154
154
  get value(): string;
155
- /**
156
- * Fixes the attribute value.
157
- * If the attribute is not a spread attribute, it calls the `fix` method of the `valueNode`.
158
- *
159
- * @implements `@markuplint/ml-core` API: `MLAttr`
160
- *
161
- * @param raw - The raw attribute value.
162
- */
163
- fix(raw: string): void;
164
155
  /**
165
156
  * Returns a normalized string representation of the attribute,
166
157
  * stripping extraneous whitespace around the name, equal sign, and value tokens.
@@ -171,12 +162,10 @@ export declare class MLAttr<T extends RuleConfigValue, O extends PlainData = und
171
162
  */
172
163
  toNormalizeString(): string;
173
164
  /**
174
- * Returns a string representation of the attribute.
165
+ * Returns the raw string representation of the attribute.
175
166
  *
176
167
  * @implements DOM API: `Attr`
177
- *
178
- * @param includesSpacesBeforeName - Whether to include spaces before the attribute name.
179
168
  * @returns The string representation of the attribute.
180
169
  */
181
- toString(fixed?: boolean): string;
170
+ toString(): string;
182
171
  }
@@ -251,21 +251,6 @@ export class MLAttr extends MLNode {
251
251
  get value() {
252
252
  return this.#potentialValue;
253
253
  }
254
- /**
255
- * Fixes the attribute value.
256
- * If the attribute is not a spread attribute, it calls the `fix` method of the `valueNode`.
257
- *
258
- * @implements `@markuplint/ml-core` API: `MLAttr`
259
- *
260
- * @param raw - The raw attribute value.
261
- */
262
- fix(raw) {
263
- if (this.localName === '#spread') {
264
- return;
265
- }
266
- // `valueNode` is not null when it is no spread.
267
- this.valueNode?.fix(raw);
268
- }
269
254
  /**
270
255
  * Returns a normalized string representation of the attribute,
271
256
  * stripping extraneous whitespace around the name, equal sign, and value tokens.
@@ -281,29 +266,12 @@ export class MLAttr extends MLNode {
281
266
  return this.raw;
282
267
  }
283
268
  /**
284
- * Returns a string representation of the attribute.
269
+ * Returns the raw string representation of the attribute.
285
270
  *
286
271
  * @implements DOM API: `Attr`
287
- *
288
- * @param includesSpacesBeforeName - Whether to include spaces before the attribute name.
289
272
  * @returns The string representation of the attribute.
290
273
  */
291
- toString(fixed = false) {
292
- if (!fixed) {
293
- return this.raw;
294
- }
295
- if (this.localName === '#spread') {
296
- return this.raw;
297
- }
298
- const tokens = [this.nameNode?.toString(true) ?? ''];
299
- if (this.equal && this.equal.toString(true) !== '') {
300
- tokens.push(this.spacesBeforeEqual?.toString(true) ?? '', this.equal?.toString(true) ?? '', this.spacesAfterEqual?.toString(true) ?? '', this.startQuote?.toString(true) ?? '', this.valueNode?.toString(true) ?? '', this.endQuote?.toString(true) ?? '');
301
- }
302
- else if (this.valueNode && this.valueNode.toString(true) !== '') {
303
- tokens.push(
304
- //
305
- '=', this.startQuote?.toString(true) || '"', this.valueNode.toString(true), this.endQuote?.toString(true) || '"');
306
- }
307
- return tokens.join('');
274
+ toString() {
275
+ return this.raw;
308
276
  }
309
277
  }
@@ -28,7 +28,8 @@ export class MLBlock extends MLNode {
28
28
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
29
29
  document) {
30
30
  super(astNode, document, astNode.isFragment);
31
- // TODO:
31
+ // Always transparent: blockBehavior may restrict child treatment in the future,
32
+ // but currently all preprocessor blocks are transparent for tree traversal.
32
33
  this.isTransparent = true;
33
34
  this.blockBehavior = astNode.blockBehavior;
34
35
  }
@@ -42,21 +42,56 @@ export declare abstract class MLCharacterData<T extends RuleConfigValue, O exten
42
42
  * @implements DOM API: `CharacterData`
43
43
  */
44
44
  after(...nodes: (string | MLElement<any, any>)[]): void;
45
+ /**
46
+ * **IT THROWS AN ERROR WHEN CALLING THIS.**
47
+ *
48
+ * @unsupported
49
+ * @implements DOM API: `CharacterData`
50
+ * @see https://dom.spec.whatwg.org/#dom-characterdata-appenddata
51
+ */
45
52
  appendData(data: string): void;
46
53
  /**
47
54
  * @implements DOM API: `CharacterData`
48
55
  */
49
56
  before(...nodes: (string | MLElement<any, any>)[]): void;
57
+ /**
58
+ * **IT THROWS AN ERROR WHEN CALLING THIS.**
59
+ *
60
+ * @unsupported
61
+ * @implements DOM API: `CharacterData`
62
+ * @see https://dom.spec.whatwg.org/#dom-characterdata-deletedata
63
+ */
50
64
  deleteData(offset: number, count: number): void;
65
+ /**
66
+ * **IT THROWS AN ERROR WHEN CALLING THIS.**
67
+ *
68
+ * @unsupported
69
+ * @implements DOM API: `CharacterData`
70
+ * @see https://dom.spec.whatwg.org/#dom-characterdata-insertdata
71
+ */
51
72
  insertData(offset: number, data: string): void;
52
73
  /**
53
74
  * @implements DOM API: `CharacterData`
54
75
  */
55
76
  remove(): void;
77
+ /**
78
+ * **IT THROWS AN ERROR WHEN CALLING THIS.**
79
+ *
80
+ * @unsupported
81
+ * @implements DOM API: `CharacterData`
82
+ * @see https://dom.spec.whatwg.org/#dom-characterdata-replacedata
83
+ */
56
84
  replaceData(offset: number, count: number, data: string): void;
57
85
  /**
58
86
  * @implements DOM API: `CharacterData`
59
87
  */
60
88
  replaceWith(...nodes: (string | MLElement<any, any>)[]): void;
89
+ /**
90
+ * **IT THROWS AN ERROR WHEN CALLING THIS.**
91
+ *
92
+ * @unsupported
93
+ * @implements DOM API: `CharacterData`
94
+ * @see https://dom.spec.whatwg.org/#dom-characterdata-substringdata
95
+ */
61
96
  substringData(offset: number, count: number): string;
62
97
  }
@@ -7,7 +7,6 @@ export class MLCharacterData extends MLNode {
7
7
  * @see https://dom.spec.whatwg.org/#dom-characterdata-data
8
8
  */
9
9
  get data() {
10
- // TODO:
11
10
  return this.raw;
12
11
  }
13
12
  /**
@@ -58,7 +57,13 @@ export class MLCharacterData extends MLNode {
58
57
  ...nodes) {
59
58
  after(this, ...nodes);
60
59
  }
61
- // TODO
60
+ /**
61
+ * **IT THROWS AN ERROR WHEN CALLING THIS.**
62
+ *
63
+ * @unsupported
64
+ * @implements DOM API: `CharacterData`
65
+ * @see https://dom.spec.whatwg.org/#dom-characterdata-appenddata
66
+ */
62
67
  appendData(data) { }
63
68
  /**
64
69
  * @implements DOM API: `CharacterData`
@@ -68,9 +73,21 @@ export class MLCharacterData extends MLNode {
68
73
  ...nodes) {
69
74
  before(this, ...nodes);
70
75
  }
71
- // TODO
76
+ /**
77
+ * **IT THROWS AN ERROR WHEN CALLING THIS.**
78
+ *
79
+ * @unsupported
80
+ * @implements DOM API: `CharacterData`
81
+ * @see https://dom.spec.whatwg.org/#dom-characterdata-deletedata
82
+ */
72
83
  deleteData(offset, count) { }
73
- // TODO
84
+ /**
85
+ * **IT THROWS AN ERROR WHEN CALLING THIS.**
86
+ *
87
+ * @unsupported
88
+ * @implements DOM API: `CharacterData`
89
+ * @see https://dom.spec.whatwg.org/#dom-characterdata-insertdata
90
+ */
74
91
  insertData(offset, data) { }
75
92
  /**
76
93
  * @implements DOM API: `CharacterData`
@@ -78,7 +95,13 @@ export class MLCharacterData extends MLNode {
78
95
  remove() {
79
96
  remove(this);
80
97
  }
81
- // TODO
98
+ /**
99
+ * **IT THROWS AN ERROR WHEN CALLING THIS.**
100
+ *
101
+ * @unsupported
102
+ * @implements DOM API: `CharacterData`
103
+ * @see https://dom.spec.whatwg.org/#dom-characterdata-replacedata
104
+ */
82
105
  replaceData(offset, count, data) { }
83
106
  /**
84
107
  * @implements DOM API: `CharacterData`
@@ -88,7 +111,13 @@ export class MLCharacterData extends MLNode {
88
111
  ...nodes) {
89
112
  replaceWith(this, ...nodes);
90
113
  }
91
- // TODO
114
+ /**
115
+ * **IT THROWS AN ERROR WHEN CALLING THIS.**
116
+ *
117
+ * @unsupported
118
+ * @implements DOM API: `CharacterData`
119
+ * @see https://dom.spec.whatwg.org/#dom-characterdata-substringdata
120
+ */
92
121
  substringData(offset, count) {
93
122
  return '';
94
123
  }
@@ -1577,14 +1577,6 @@ export declare class MLDocument<T extends RuleConfigValue, O extends PlainData =
1577
1577
  * @implements DOM API: `Document`
1578
1578
  */
1579
1579
  getSelection(): Selection | null;
1580
- /**
1581
- * Returns a flat, offset-sorted list of all tokens in the document,
1582
- * including element close tags. The result is cached after the first call.
1583
- *
1584
- * @implements `@markuplint/ml-core` API: `MLDocument`
1585
- * @returns A frozen array of tokens sorted by their starting offset
1586
- */
1587
- getTokenList(): readonly MLToken<import("@markuplint/ml-ast").MLASTToken>[];
1588
1580
  /**
1589
1581
  * **IT THROWS AN ERROR WHEN CALLING THIS.**
1590
1582
  *
@@ -1693,15 +1685,12 @@ export declare class MLDocument<T extends RuleConfigValue, O extends PlainData =
1693
1685
  */
1694
1686
  startViewTransition(callbackOptions?: ViewTransitionUpdateCallback): ViewTransition;
1695
1687
  /**
1696
- * Returns a string representation of the entire document. When `fixed` is true,
1697
- * returns the document with all lint fixes applied by substituting
1698
- * fixed token content at the appropriate offsets.
1688
+ * Returns the raw string representation of the document.
1699
1689
  *
1700
1690
  * @implements `@markuplint/ml-core` API: `MLDocument`
1701
- * @param fixed - When true, returns the fixed content; otherwise returns the original raw content
1702
1691
  * @returns The string content of the document
1703
1692
  */
1704
- toString(fixed?: boolean): string;
1693
+ toString(): string;
1705
1694
  /**
1706
1695
  * Walks the document tree, visiting nodes of the specified type and invoking
1707
1696
  * the walker callback for each one. Supports walking Element, Text, Comment,
@@ -1732,18 +1721,4 @@ export declare class MLDocument<T extends RuleConfigValue, O extends PlainData =
1732
1721
  * @implements DOM API: `Document`
1733
1722
  */
1734
1723
  writeln(...text: readonly string[]): void;
1735
- /**
1736
- * Initializes pretender contexts for all element nodes in the document.
1737
- *
1738
- * @param pretenders - Optional pretender configurations from the document options
1739
- */
1740
- private _pretending;
1741
- /**
1742
- * Maps the ruleset configuration to each node in the document.
1743
- * Applies global rules, node-specific rules (by selector), and
1744
- * child-node rules to build the per-node rule configuration.
1745
- *
1746
- * @param ruleset - The ruleset containing rules, nodeRules, and childNodeRules
1747
- */
1748
- private _ruleMapping;
1749
1724
  }