@markuplint/parser-utils 5.0.0-rc.0 → 5.0.0-rc.1
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/CHANGELOG.md +4 -0
- package/lib/debugger.js +1 -1
- package/lib/get-namespace.js +1 -1
- package/lib/ignore-block.js +4 -0
- package/lib/parser-error.d.ts +2 -43
- package/lib/parser-error.js +2 -47
- package/lib/parser.js +28 -11
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
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-rc.1](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.0...v5.0.0-rc.1) (2026-03-27)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @markuplint/parser-utils
|
|
9
|
+
|
|
6
10
|
# [5.0.0-rc.0](https://github.com/markuplint/markuplint/compare/v5.0.0-alpha.3...v5.0.0-rc.0) (2026-03-12)
|
|
7
11
|
|
|
8
12
|
**Note:** Version bump only for package @markuplint/parser-utils
|
package/lib/debugger.js
CHANGED
|
@@ -70,7 +70,7 @@ export function nodeTreeDebugView(nodeTree, idFilter = false) {
|
|
|
70
70
|
return;
|
|
71
71
|
}
|
|
72
72
|
lines.push(`${i.toString().padStart(3, '0')}: [${filter(n.uuid)}] ${' '.repeat(Math.max(n.depth, 0))}${n.type === 'endtag' ? '/' : ''}${n.nodeName}(${filter(n.uuid)})${n.type === 'starttag' && n.isGhost ? '[👻]' : ''}${n.type === 'starttag'
|
|
73
|
-
? ` => ${n.
|
|
73
|
+
? ` => ${n.pairNodeUuid ? `/${nodeTree.find(p => p.uuid === n.pairNodeUuid)?.nodeName ?? '?'}(${filter(n.pairNodeUuid)})` : '💀'}`
|
|
74
74
|
: ''}`);
|
|
75
75
|
if (n.type === 'starttag' || n.type === 'psblock') {
|
|
76
76
|
for (const c of n.childNodes ?? []) {
|
package/lib/get-namespace.js
CHANGED
package/lib/ignore-block.js
CHANGED
|
@@ -75,6 +75,7 @@ ignoreBlock, throwErrorWhenTagHasUnresolved = true) {
|
|
|
75
75
|
type: 'psblock',
|
|
76
76
|
depth: node.depth,
|
|
77
77
|
nodeName: `#ps:${tag.type}`,
|
|
78
|
+
parentNodeUuid: node.parentNode?.uuid ?? null,
|
|
78
79
|
parentNode: node.parentNode,
|
|
79
80
|
childNodes: [],
|
|
80
81
|
blockBehavior: null,
|
|
@@ -94,6 +95,7 @@ ignoreBlock, throwErrorWhenTagHasUnresolved = true) {
|
|
|
94
95
|
...token,
|
|
95
96
|
nodeName: '#text',
|
|
96
97
|
type: 'text',
|
|
98
|
+
parentNodeUuid: node.parentNode?.uuid ?? null,
|
|
97
99
|
parentNode: node.parentNode,
|
|
98
100
|
depth: node.depth,
|
|
99
101
|
};
|
|
@@ -106,6 +108,7 @@ ignoreBlock, throwErrorWhenTagHasUnresolved = true) {
|
|
|
106
108
|
type: 'psblock',
|
|
107
109
|
depth: node.depth,
|
|
108
110
|
nodeName: `#ps:${tag.type}`,
|
|
111
|
+
parentNodeUuid: node.parentNode?.uuid ?? null,
|
|
109
112
|
parentNode: node.parentNode,
|
|
110
113
|
childNodes: [],
|
|
111
114
|
blockBehavior: null,
|
|
@@ -120,6 +123,7 @@ ignoreBlock, throwErrorWhenTagHasUnresolved = true) {
|
|
|
120
123
|
...token,
|
|
121
124
|
nodeName: '#text',
|
|
122
125
|
type: 'text',
|
|
126
|
+
parentNodeUuid: node.parentNode?.uuid ?? null,
|
|
123
127
|
parentNode: node.parentNode,
|
|
124
128
|
depth: node.depth,
|
|
125
129
|
};
|
package/lib/parser-error.d.ts
CHANGED
|
@@ -1,43 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* used to construct meaningful error messages with source locations.
|
|
4
|
-
*/
|
|
5
|
-
export type ParserErrorInfo = {
|
|
6
|
-
readonly line?: number;
|
|
7
|
-
readonly col?: number;
|
|
8
|
-
readonly raw?: string;
|
|
9
|
-
readonly stack?: string;
|
|
10
|
-
};
|
|
11
|
-
/**
|
|
12
|
-
* An error that occurs during parsing, carrying the source line, column,
|
|
13
|
-
* and raw text where the error was encountered.
|
|
14
|
-
*/
|
|
15
|
-
export declare class ParserError extends Error {
|
|
16
|
-
readonly col: number;
|
|
17
|
-
readonly line: number;
|
|
18
|
-
name: string;
|
|
19
|
-
readonly raw: string;
|
|
20
|
-
constructor(message: string, info: ParserErrorInfo);
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* A parser error specific to a particular HTML element, including
|
|
24
|
-
* the node name of the element that caused the error in the message.
|
|
25
|
-
*/
|
|
26
|
-
export declare class TargetParserError extends ParserError {
|
|
27
|
-
name: string;
|
|
28
|
-
readonly nodeName: string | null;
|
|
29
|
-
constructor(message: string, info: ParserErrorInfo & {
|
|
30
|
-
readonly nodeName?: string | null;
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* A parser error that occurs while reading a configuration file,
|
|
35
|
-
* including the file path in the error message for easier debugging.
|
|
36
|
-
*/
|
|
37
|
-
export declare class ConfigParserError extends ParserError {
|
|
38
|
-
readonly filePath: string;
|
|
39
|
-
name: string;
|
|
40
|
-
constructor(message: string, info: ParserErrorInfo & {
|
|
41
|
-
readonly filePath: string;
|
|
42
|
-
});
|
|
43
|
-
}
|
|
1
|
+
export { ConfigParserError, ParserError, TargetParserError } from '@markuplint/shared';
|
|
2
|
+
export type { ParserErrorInfo } from '@markuplint/shared';
|
package/lib/parser-error.js
CHANGED
|
@@ -1,47 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* and raw text where the error was encountered.
|
|
4
|
-
*/
|
|
5
|
-
export class ParserError extends Error {
|
|
6
|
-
col;
|
|
7
|
-
line;
|
|
8
|
-
name = 'ParserError';
|
|
9
|
-
raw;
|
|
10
|
-
constructor(message, info) {
|
|
11
|
-
super(message);
|
|
12
|
-
this.line = info.line ?? 1;
|
|
13
|
-
this.col = info.col ?? 0;
|
|
14
|
-
this.raw = info.raw ?? '';
|
|
15
|
-
this.stack = info.stack ?? this.stack;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* A parser error specific to a particular HTML element, including
|
|
20
|
-
* the node name of the element that caused the error in the message.
|
|
21
|
-
*/
|
|
22
|
-
export class TargetParserError extends ParserError {
|
|
23
|
-
name = 'TargetParserError';
|
|
24
|
-
nodeName;
|
|
25
|
-
constructor(message, info) {
|
|
26
|
-
const errMsg = info.nodeName
|
|
27
|
-
? `The ${info.nodeName} is invalid element (${info.line}:${info.col}): ${message}`
|
|
28
|
-
: message;
|
|
29
|
-
super(errMsg, info);
|
|
30
|
-
this.nodeName = info.nodeName ?? null;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* A parser error that occurs while reading a configuration file,
|
|
35
|
-
* including the file path in the error message for easier debugging.
|
|
36
|
-
*/
|
|
37
|
-
export class ConfigParserError extends ParserError {
|
|
38
|
-
filePath;
|
|
39
|
-
name = 'ConfigParserError';
|
|
40
|
-
constructor(message, info) {
|
|
41
|
-
const pos = info.line != null && info.line != null ? `(${info.line}:${info.col})` : '';
|
|
42
|
-
const file = ` in ${info.filePath}${pos}`;
|
|
43
|
-
const errMsg = `${message}${file}`;
|
|
44
|
-
super(errMsg, info);
|
|
45
|
-
this.filePath = info.filePath;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
// Re-export from @markuplint/shared — these classes are now defined there.
|
|
2
|
+
export { ConfigParserError, ParserError, TargetParserError } from '@markuplint/shared';
|
package/lib/parser.js
CHANGED
|
@@ -196,6 +196,13 @@ export class Parser {
|
|
|
196
196
|
}
|
|
197
197
|
nodeList = [fmNode, ...newNodeList];
|
|
198
198
|
}
|
|
199
|
+
timer.push('removeCircularRefs');
|
|
200
|
+
// Remove circular object references (parentNodeUuid/pairNodeUuid are already set)
|
|
201
|
+
for (const node of nodeList) {
|
|
202
|
+
const n = node;
|
|
203
|
+
delete n.parentNode;
|
|
204
|
+
delete n.pairNode;
|
|
205
|
+
}
|
|
199
206
|
timer.log();
|
|
200
207
|
domLog(nodeList);
|
|
201
208
|
this.#reset();
|
|
@@ -381,6 +388,7 @@ export class Parser {
|
|
|
381
388
|
...this.createToken(token),
|
|
382
389
|
type: 'doctype',
|
|
383
390
|
nodeName: '#doctype',
|
|
391
|
+
parentNodeUuid: token.parentNode?.uuid ?? null,
|
|
384
392
|
};
|
|
385
393
|
return [node];
|
|
386
394
|
}
|
|
@@ -401,6 +409,7 @@ export class Parser {
|
|
|
401
409
|
type: 'comment',
|
|
402
410
|
nodeName: '#comment',
|
|
403
411
|
isBogus,
|
|
412
|
+
parentNodeUuid: token.parentNode?.uuid ?? null,
|
|
404
413
|
};
|
|
405
414
|
return [node];
|
|
406
415
|
}
|
|
@@ -419,6 +428,7 @@ export class Parser {
|
|
|
419
428
|
...this.createToken(token),
|
|
420
429
|
type: 'text',
|
|
421
430
|
nodeName: '#text',
|
|
431
|
+
parentNodeUuid: token.parentNode?.uuid ?? null,
|
|
422
432
|
};
|
|
423
433
|
if (options?.researchTags) {
|
|
424
434
|
const nodes = this.parseCodeFragment(token);
|
|
@@ -457,7 +467,9 @@ export class Parser {
|
|
|
457
467
|
childNodes: [],
|
|
458
468
|
blockBehavior: null,
|
|
459
469
|
parentNode: token.parentNode,
|
|
470
|
+
parentNodeUuid: token.parentNode?.uuid ?? null,
|
|
460
471
|
pairNode: null,
|
|
472
|
+
pairNodeUuid: null,
|
|
461
473
|
tagCloseChar: '',
|
|
462
474
|
tagOpenChar: '',
|
|
463
475
|
isGhost: true,
|
|
@@ -504,6 +516,7 @@ export class Parser {
|
|
|
504
516
|
nodeName: `#ps:${token.nodeName}`,
|
|
505
517
|
childNodes: [],
|
|
506
518
|
isBogus: false,
|
|
519
|
+
parentNodeUuid: token.parentNode?.uuid ?? null,
|
|
507
520
|
};
|
|
508
521
|
const siblings = this.visitChildren(childNodes, block);
|
|
509
522
|
return [block, ...siblings];
|
|
@@ -664,6 +677,7 @@ export class Parser {
|
|
|
664
677
|
depth,
|
|
665
678
|
nodeName: '#text',
|
|
666
679
|
parentNode: null,
|
|
680
|
+
parentNodeUuid: null,
|
|
667
681
|
};
|
|
668
682
|
nodes.push(textNode);
|
|
669
683
|
}
|
|
@@ -853,7 +867,7 @@ export class Parser {
|
|
|
853
867
|
const newChildNodes = [...parentNode.childNodes];
|
|
854
868
|
for (const appendingChild of childNodes) {
|
|
855
869
|
const currentIndex = parentNode.childNodes.findIndex(n => n.uuid === appendingChild.uuid);
|
|
856
|
-
Object.assign(appendingChild, { parentNode });
|
|
870
|
+
Object.assign(appendingChild, { parentNode, parentNodeUuid: parentNode.uuid });
|
|
857
871
|
if (currentIndex === -1) {
|
|
858
872
|
newChildNodes.push(appendingChild);
|
|
859
873
|
continue;
|
|
@@ -921,9 +935,9 @@ export class Parser {
|
|
|
921
935
|
raw: nodes.map(n => n.raw).join(''),
|
|
922
936
|
};
|
|
923
937
|
for (const node of nodes) {
|
|
924
|
-
this.#removeChild(node.parentNode, node);
|
|
938
|
+
this.#removeChild(node.parentNode ?? null, node);
|
|
925
939
|
}
|
|
926
|
-
this.appendChild(textNode.parentNode, textNode);
|
|
940
|
+
this.appendChild(textNode.parentNode ?? null, textNode);
|
|
927
941
|
return textNode;
|
|
928
942
|
}
|
|
929
943
|
#convertIntoInvalidNode(node) {
|
|
@@ -986,7 +1000,7 @@ export class Parser {
|
|
|
986
1000
|
const prevEndOffset = sequentailPrevNode
|
|
987
1001
|
? sequentailPrevNode.offset + sequentailPrevNode.raw.length
|
|
988
1002
|
: 0;
|
|
989
|
-
const remnantNodes = this.#createRemnantNode(prevEndOffset, node.offset, node.depth, node.parentNode, invalidNode, whitespace);
|
|
1003
|
+
const remnantNodes = this.#createRemnantNode(prevEndOffset, node.offset, node.depth, node.parentNode ?? null, invalidNode, whitespace);
|
|
990
1004
|
if (remnantNodes) {
|
|
991
1005
|
newNodeList.push(...remnantNodes);
|
|
992
1006
|
}
|
|
@@ -997,7 +1011,7 @@ export class Parser {
|
|
|
997
1011
|
if (!lastNode) {
|
|
998
1012
|
return newNodeList;
|
|
999
1013
|
}
|
|
1000
|
-
const remnantNodes = this.#createRemnantNode(lastNode.offset + lastNode.raw.length, undefined, lastNode.depth, lastNode.parentNode, invalidNode, whitespace);
|
|
1014
|
+
const remnantNodes = this.#createRemnantNode(lastNode.offset + lastNode.raw.length, undefined, lastNode.depth, lastNode.parentNode ?? null, invalidNode, whitespace);
|
|
1001
1015
|
if (!remnantNodes) {
|
|
1002
1016
|
return newNodeList;
|
|
1003
1017
|
}
|
|
@@ -1020,12 +1034,12 @@ export class Parser {
|
|
|
1020
1034
|
* @returns `true` if `node` is a descendant of `potentialAncestor`.
|
|
1021
1035
|
*/
|
|
1022
1036
|
#isDescendantOf(node, potentialAncestor) {
|
|
1023
|
-
let current = 'parentNode' in node ? node.parentNode : null;
|
|
1037
|
+
let current = 'parentNode' in node ? (node.parentNode ?? null) : null;
|
|
1024
1038
|
while (current) {
|
|
1025
1039
|
if (current === potentialAncestor) {
|
|
1026
1040
|
return true;
|
|
1027
1041
|
}
|
|
1028
|
-
current = current.parentNode;
|
|
1042
|
+
current = current.parentNode ?? null;
|
|
1029
1043
|
}
|
|
1030
1044
|
return false;
|
|
1031
1045
|
}
|
|
@@ -1034,7 +1048,7 @@ export class Parser {
|
|
|
1034
1048
|
for (let node of nodeList) {
|
|
1035
1049
|
if (node.type === 'endtag') {
|
|
1036
1050
|
const endTagUUID = node.uuid;
|
|
1037
|
-
const openTag = newNodeList.findLast((n) => n.type === 'starttag' && !n.isGhost ? n.
|
|
1051
|
+
const openTag = newNodeList.findLast((n) => n.type === 'starttag' && !n.isGhost ? n.pairNodeUuid === endTagUUID : false);
|
|
1038
1052
|
if (!openTag) {
|
|
1039
1053
|
node = this.#convertIntoInvalidNode(node);
|
|
1040
1054
|
}
|
|
@@ -1044,9 +1058,9 @@ export class Parser {
|
|
|
1044
1058
|
return newNodeList;
|
|
1045
1059
|
}
|
|
1046
1060
|
#pairing(startTag, endTag) {
|
|
1047
|
-
Object.assign(startTag, { pairNode: endTag });
|
|
1048
|
-
Object.assign(endTag, { pairNode: startTag });
|
|
1049
|
-
this.appendChild(startTag.parentNode, endTag);
|
|
1061
|
+
Object.assign(startTag, { pairNode: endTag, pairNodeUuid: endTag.uuid });
|
|
1062
|
+
Object.assign(endTag, { pairNode: startTag, pairNodeUuid: startTag.uuid });
|
|
1063
|
+
this.appendChild(startTag.parentNode ?? null, endTag);
|
|
1050
1064
|
}
|
|
1051
1065
|
#parseEndTag(token, namelessFragment) {
|
|
1052
1066
|
const parsed = this.#parseTag(token, true, false, namelessFragment);
|
|
@@ -1219,6 +1233,7 @@ export class Parser {
|
|
|
1219
1233
|
depth,
|
|
1220
1234
|
nodeName: isFragment ? '#jsx-fragment' : tagName,
|
|
1221
1235
|
parentNode: null,
|
|
1236
|
+
parentNodeUuid: null,
|
|
1222
1237
|
};
|
|
1223
1238
|
const tag = isOpenTag
|
|
1224
1239
|
? {
|
|
@@ -1232,6 +1247,7 @@ export class Parser {
|
|
|
1232
1247
|
attributes: attrs,
|
|
1233
1248
|
childNodes: [],
|
|
1234
1249
|
pairNode: null,
|
|
1250
|
+
pairNodeUuid: null,
|
|
1235
1251
|
tagOpenChar: '<',
|
|
1236
1252
|
tagCloseChar: selfClosingSolidusChar + '>',
|
|
1237
1253
|
blockBehavior: null,
|
|
@@ -1243,6 +1259,7 @@ export class Parser {
|
|
|
1243
1259
|
...commons,
|
|
1244
1260
|
type: 'endtag',
|
|
1245
1261
|
pairNode: {},
|
|
1262
|
+
pairNodeUuid: null,
|
|
1246
1263
|
tagOpenChar: '</',
|
|
1247
1264
|
tagCloseChar: '>',
|
|
1248
1265
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/parser-utils",
|
|
3
|
-
"version": "5.0.0-rc.
|
|
3
|
+
"version": "5.0.0-rc.1",
|
|
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,16 +31,16 @@
|
|
|
31
31
|
"clean": "tsc --build --clean tsconfig.build.json"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@markuplint/ml-ast": "5.0.0-rc.
|
|
35
|
-
"@markuplint/ml-spec": "5.0.0-rc.
|
|
36
|
-
"@markuplint/shared": "5.0.0-rc.
|
|
37
|
-
"@markuplint/types": "5.0.0-rc.
|
|
34
|
+
"@markuplint/ml-ast": "5.0.0-rc.1",
|
|
35
|
+
"@markuplint/ml-spec": "5.0.0-rc.1",
|
|
36
|
+
"@markuplint/shared": "5.0.0-rc.1",
|
|
37
|
+
"@markuplint/types": "5.0.0-rc.1",
|
|
38
38
|
"debug": "4.4.3",
|
|
39
39
|
"espree": "11.2.0",
|
|
40
|
-
"type-fest": "5.
|
|
40
|
+
"type-fest": "5.5.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@typescript-eslint/typescript-estree": "8.57.
|
|
43
|
+
"@typescript-eslint/typescript-estree": "8.57.2"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "0d6b4324d9a7d6b9e1ba57d4a57e45d36975cba9"
|
|
46
46
|
}
|