@markuplint/parser-utils 5.0.0-alpha.0 → 5.0.0-alpha.2

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.
@@ -21,7 +21,7 @@ src/
21
21
  ├── debugger.ts — デバッグ・テスト用ユーティリティ
22
22
  ├── parser-error.ts — ParserError, TargetParserError, ConfigParserError
23
23
  ├── sort-nodes.ts — ノード位置ソート
24
- ├── const.ts — MASK_CHAR, SVG 要素リスト, defaultSpaces
24
+ ├── const.ts — MASK_CHAR, SVG/MathML 要素リスト, defaultSpaces
25
25
  ├── get-location.ts — 行/列/オフセット計算ユーティリティ
26
26
  └── decision.ts — カスタム要素名判定
27
27
  ```
@@ -99,7 +99,7 @@ flowchart TD
99
99
  | `debugger.ts` | テスト・デバッグユーティリティ | `nodeListToDebugMaps`, `attributesToDebugMaps`, `nodeTreeDebugView` |
100
100
  | `parser-error.ts` | エラークラス | `ParserError`, `TargetParserError`, `ConfigParserError` |
101
101
  | `sort-nodes.ts` | ノードの位置ソート | `sortNodes` |
102
- | `const.ts` | 定数 | `MASK_CHAR`, `svgElementList`, `defaultSpaces` |
102
+ | `const.ts` | 定数 | `MASK_CHAR`, `svgElementList`, `mathmlElementList`, `defaultSpaces` |
103
103
  | `get-location.ts` | 位置計算 | `getPosition`, `getEndLine`, `getEndCol`, `getEndPosition`, `getOffsetsFromCode` |
104
104
  | `decision.ts` | カスタム要素名判定 | `isPotentialCustomElementName`, `isSVGElement` |
105
105
 
@@ -148,7 +148,7 @@ ParserError (基底クラス)
148
148
 
149
149
  ## IDL 属性マッピング
150
150
 
151
- `searchIDLAttribute` は React スタイルの IDL 属性名と HTML コンテンツ属性名の双方向マッピングを提供します(例: `className` → `class`、`htmlFor` → `for`)。spec が `useIDLAttributeNames: true` を設定している場合に、`@markuplint/ml-core` の `MLAttr` コンストラクタから呼び出されます。
151
+ `searchIDLAttribute` は React スタイルの IDL 属性名と HTML コンテンツ属性名の双方向マッピングを提供します(例: `className` → `class`、`htmlFor` → `for`)。spec が `acceptedAttrNames`(`'idl'` または `'both'`)を設定している場合に、`@markuplint/ml-core` の `MLAttr` コンストラクタから呼び出されます。
152
152
 
153
153
  ## 外部依存
154
154
 
package/ARCHITECTURE.md CHANGED
@@ -22,7 +22,7 @@ src/
22
22
  ├── debug.ts — Performance timer and debug logging via `debug` package
23
23
  ├── parser-error.ts — ParserError, TargetParserError, ConfigParserError
24
24
  ├── sort-nodes.ts — Node position sorting
25
- ├── const.ts — MASK_CHAR, SVG element list, defaultSpaces
25
+ ├── const.ts — MASK_CHAR, SVG/MathML element lists, defaultSpaces
26
26
  ├── get-location.ts — Line/column/offset calculation utilities
27
27
  └── decision.ts — Custom element name detection
28
28
  ```
@@ -59,7 +59,7 @@ flowchart TD
59
59
  parserError["parser-error.ts\nParserError hierarchy"]
60
60
  sortNodes["sort-nodes.ts\nsortNodes()"]
61
61
  getLoc["get-location.ts\ngetPosition(), getEndLine()"]
62
- constMod["const.ts\nMASK_CHAR, svgElementList"]
62
+ constMod["const.ts\nMASK_CHAR, svgElementList,\nmathmlElementList"]
63
63
  end
64
64
 
65
65
  subgraph external ["External Dependencies"]
@@ -112,9 +112,9 @@ flowchart TD
112
112
  | `debug.ts` | Performance timing and debug logging | `PerformanceTimer`, `domLog`, `log` |
113
113
  | `parser-error.ts` | Error classes with positional information | `ParserError`, `TargetParserError`, `ConfigParserError` |
114
114
  | `sort-nodes.ts` | Node position sorting by offset | `sortNodes` |
115
- | `const.ts` | Constants used across the package | `MASK_CHAR`, `svgElementList`, `defaultSpaces` |
115
+ | `const.ts` | Constants used across the package | `MASK_CHAR`, `svgElementList`, `mathmlElementList`, `defaultSpaces` |
116
116
  | `get-location.ts` | Line/column/offset position calculations | `getPosition`, `getEndLine`, `getEndCol`, `getEndPosition`, `getOffsetsFromCode` |
117
- | `decision.ts` | Custom element name detection and SVG element lookup | `isPotentialCustomElementName`, `isSVGElement` |
117
+ | `decision.ts` | Custom element name detection and SVG/MathML element lookup | `isPotentialCustomElementName`, `isSVGElement` |
118
118
 
119
119
  ## Parse Pipeline Overview
120
120
 
@@ -174,7 +174,7 @@ Additionally, `debug.ts` provides `PerformanceTimer` for measuring parse phase d
174
174
 
175
175
  ## IDL Attribute Mapping
176
176
 
177
- `searchIDLAttribute` maps between React-style IDL attribute names and HTML content attribute names. It is called by `@markuplint/ml-core`'s `MLAttr` constructor when the spec sets `useIDLAttributeNames: true`. It maintains a comprehensive mapping table derived from React's `possibleStandardNames.js`, covering:
177
+ `searchIDLAttribute` maps between React-style IDL attribute names and HTML content attribute names. It is called by `@markuplint/ml-core`'s `MLAttr` constructor when the spec sets `acceptedAttrNames` (either `'idl'` or `'both'`). It maintains a comprehensive mapping table derived from React's `possibleStandardNames.js`, covering:
178
178
 
179
179
  - HTML attributes (e.g., `className` -> `class`, `htmlFor` -> `for`, `tabIndex` -> `tabindex`)
180
180
  - SVG attributes (e.g., `strokeWidth` -> `stroke-width`, `clipPath` -> `clip-path`)
package/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [5.0.0-alpha.2](https://github.com/markuplint/markuplint/compare/v5.0.0-alpha.1...v5.0.0-alpha.2) (2026-02-23)
7
+
8
+ ### Features
9
+
10
+ - **parser-utils:** add MathML namespace detection ([6c27e45](https://github.com/markuplint/markuplint/commit/6c27e45475104d744a8109e8e36698bd9dba4e8b))
11
+
12
+ # [5.0.0-alpha.1](https://github.com/markuplint/markuplint/compare/v5.0.0-alpha.0...v5.0.0-alpha.1) (2026-02-22)
13
+
14
+ ### Bug Fixes
15
+
16
+ - **parser-utils:** skip text trimming when text node is a descendant of the next node ([1bfcede](https://github.com/markuplint/markuplint/commit/1bfcedebbd115ea817df76a979b4e10a26d0a2b2))
17
+
6
18
  # [5.0.0-alpha.0](https://github.com/markuplint/markuplint/compare/v4.14.1...v5.0.0-alpha.0) (2026-02-20)
7
19
 
8
20
  ### Bug Fixes
@@ -173,7 +173,7 @@ afterFlattenNodes(
173
173
  1. **残留ノードの露出** — 既知のノード間の空白と無効なマークアップを発見する
174
174
  2. **孤立終了タグ → ボーガス** — 対応する開始タグがない終了タグを `invalid` ノードに変換する
175
175
  3. **テキストの結合** — 同じオフセットにある隣接する `#text` ノードをマージする
176
- 4. **テキストのトリム** — 重複するテキストノードの境界をトリムする
176
+ 4. **テキストのトリム** — フラットリスト上で次のノードとソース範囲が重複するテキストノードをトリムする。テキストノードがツリー上で次のノードの子孫である場合はスキップする(Markdown 等の合成パーサーでは、子要素が親要素と同じソース範囲を共有することがあるため)
177
177
 
178
178
  ### ステップ 9: restoreNode()
179
179
 
@@ -173,7 +173,7 @@ Performs four cleanup passes:
173
173
  1. **Expose remnant nodes** — discovers whitespace and invalid markup between known nodes
174
174
  2. **Orphan end tags → bogus** — converts unmatched end tags to `invalid` nodes
175
175
  3. **Concatenate text** — merges adjacent `#text` nodes at the same offset
176
- 4. **Trim text** — trims overlapping text node boundaries
176
+ 4. **Trim text** — trims text nodes whose source range overlaps with the next node in the flat list. Skips trimming when the text node is a tree-descendant of the next node, which can occur with synthetic parsers (e.g., Markdown) where child elements share the same source range as their parent
177
177
 
178
178
  ### Step 9: restoreNode()
179
179
 
@@ -25,7 +25,7 @@ function getParentNamespace(parentNode) {
25
25
  return 'http://www.w3.org/1999/xhtml';
26
26
  }
27
27
  if ('namespace' in parentNode && parentNode.namespace) {
28
- const ns = parentNode.namespace.toLowerCase().trim();
28
+ const ns = parentNode.namespace.trim();
29
29
  return ns === 'http://www.w3.org/1999/xhtml'
30
30
  ? 'http://www.w3.org/1999/xhtml'
31
31
  : ns === 'http://www.w3.org/2000/svg'
package/lib/parser.js CHANGED
@@ -1011,6 +1011,24 @@ export class Parser {
1011
1011
  col: getEndCol(token.raw, token.col),
1012
1012
  };
1013
1013
  }
1014
+ /**
1015
+ * Checks whether a node is a descendant of another node by walking up
1016
+ * the parent chain.
1017
+ *
1018
+ * @param node - The node to test.
1019
+ * @param potentialAncestor - The node that may be an ancestor.
1020
+ * @returns `true` if `node` is a descendant of `potentialAncestor`.
1021
+ */
1022
+ #isDescendantOf(node, potentialAncestor) {
1023
+ let current = 'parentNode' in node ? node.parentNode : null;
1024
+ while (current) {
1025
+ if (current === potentialAncestor) {
1026
+ return true;
1027
+ }
1028
+ current = current.parentNode;
1029
+ }
1030
+ return false;
1031
+ }
1014
1032
  #orphanEndTagToBogusMark(nodeList) {
1015
1033
  const newNodeList = [];
1016
1034
  for (let node of nodeList) {
@@ -1304,10 +1322,17 @@ export class Parser {
1304
1322
  this.#originalRawCode = originalRawCode ?? this.#originalRawCode;
1305
1323
  }
1306
1324
  /**
1307
- * Trim overlapping sections of text nodes for proper node separation
1325
+ * Trims text nodes whose source range overlaps with the next node in
1326
+ * the flat list. This prevents text content from bleeding into adjacent
1327
+ * elements that occupy a later (or overlapping) source range.
1328
+ *
1329
+ * Skips trimming when the text node is a descendant of the next node
1330
+ * in the tree hierarchy, because synthetic parsers (e.g., Markdown)
1331
+ * can produce child elements that share the same source range as their
1332
+ * parent and therefore appear before the parent in offset-sorted order.
1308
1333
  *
1309
- * @param nodeList
1310
- * @returns
1334
+ * @param nodeList - The flat, offset-sorted node list to process.
1335
+ * @returns A new node list with overlapping text nodes trimmed.
1311
1336
  */
1312
1337
  #trimText(nodeList) {
1313
1338
  const newNodeList = [];
@@ -1318,7 +1343,7 @@ export class Parser {
1318
1343
  node.raw.length > 0) {
1319
1344
  const prevNodeEndOffset = prevNode.offset + prevNode.raw.length;
1320
1345
  const nodeStartOffset = node.offset;
1321
- if (prevNodeEndOffset > nodeStartOffset) {
1346
+ if (prevNodeEndOffset > nodeStartOffset && !this.#isDescendantOf(prevNode, node)) {
1322
1347
  const prevNodeRaw = prevNode.raw;
1323
1348
  const prevNodeTrimmedRaw = prevNodeRaw.slice(0, nodeStartOffset - prevNode.offset);
1324
1349
  this.updateRaw(prevNode, prevNodeTrimmedRaw);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markuplint/parser-utils",
3
- "version": "5.0.0-alpha.0",
3
+ "version": "5.0.0-alpha.2",
4
4
  "description": "Utility module for markuplint parser plugin",
5
5
  "repository": "git@github.com:markuplint/markuplint.git",
6
6
  "author": "Yusuke Hirao <yusukehirao@me.com>",
@@ -31,15 +31,15 @@
31
31
  "clean": "tsc --build --clean tsconfig.build.json"
32
32
  },
33
33
  "dependencies": {
34
- "@markuplint/ml-ast": "5.0.0-alpha.0",
35
- "@markuplint/ml-spec": "5.0.0-alpha.0",
36
- "@markuplint/types": "5.0.0-alpha.0",
34
+ "@markuplint/ml-ast": "5.0.0-alpha.2",
35
+ "@markuplint/ml-spec": "5.0.0-alpha.2",
36
+ "@markuplint/types": "5.0.0-alpha.2",
37
37
  "debug": "4.4.3",
38
- "espree": "11.1.0",
38
+ "espree": "11.1.1",
39
39
  "type-fest": "5.4.4"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@typescript-eslint/typescript-estree": "8.56.0"
43
43
  },
44
- "gitHead": "13dcfc84ec83d87360c720e253383b60767e1b56"
44
+ "gitHead": "31ccf1e81443ea3f93597d287595211f1823ddcf"
45
45
  }