@markuplint/parser-utils 4.0.0-dev.0 → 4.0.0-dev.12
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/LICENSE +1 -1
- package/lib/attr-tokenizer.d.ts +16 -4
- package/lib/attr-tokenizer.js +164 -70
- package/lib/const.d.ts +2 -1
- package/lib/const.js +2 -1
- package/lib/debugger.d.ts +3 -2
- package/lib/debugger.js +35 -19
- package/lib/enums.d.ts +16 -0
- package/lib/enums.js +18 -0
- package/lib/get-location.d.ts +4 -13
- package/lib/get-location.js +10 -21
- package/lib/ignore-block.d.ts +3 -2
- package/lib/ignore-block.js +62 -124
- package/lib/ignore-front-matter.d.ts +4 -1
- package/lib/ignore-front-matter.js +12 -3
- package/lib/index.d.ts +3 -16
- package/lib/index.js +3 -16
- package/lib/parser-error.d.ts +1 -0
- package/lib/parser-error.js +1 -0
- package/lib/parser.d.ts +108 -0
- package/lib/parser.js +1076 -0
- package/lib/script-parser.d.ts +1 -1
- package/lib/script-parser.js +1 -1
- package/lib/sort-nodes.d.ts +2 -0
- package/lib/sort-nodes.js +18 -0
- package/lib/types.d.ts +34 -0
- package/package.json +9 -5
- package/lib/attr-parser.d.ts +0 -25
- package/lib/attr-parser.js +0 -188
- package/lib/create-token.d.ts +0 -4
- package/lib/create-token.js +0 -29
- package/lib/flatten-nodes.d.ts +0 -2
- package/lib/flatten-nodes.js +0 -247
- package/lib/get-space-before.d.ts +0 -1
- package/lib/get-space-before.js +0 -8
- package/lib/parse-attr.d.ts +0 -24
- package/lib/parse-attr.js +0 -144
- package/lib/remove-deprecated-node.d.ts +0 -7
- package/lib/remove-deprecated-node.js +0 -39
- package/lib/siblings-correction.d.ts +0 -9
- package/lib/siblings-correction.js +0 -21
- package/lib/tag-parser.d.ts +0 -10
- package/lib/tag-parser.js +0 -152
- package/lib/tag-splitter.d.ts +0 -7
- package/lib/tag-splitter.js +0 -96
- package/lib/walker.d.ts +0 -2
- package/lib/walker.js +0 -18
package/lib/script-parser.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare function scriptParser(script: string):
|
|
1
|
+
export declare function scriptParser(script: string): ScriptTokenType[];
|
|
2
2
|
export declare function removeQuote(str: string): string;
|
|
3
3
|
export type ScriptTokenType = {
|
|
4
4
|
type: 'Identifier' | 'Boolean' | 'Numeric' | 'String' | 'Template' | 'Punctuator';
|
package/lib/script-parser.js
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function sortNodes(a, b) {
|
|
2
|
+
if (a.startOffset === b.startOffset) {
|
|
3
|
+
return sort(a, b, 'endOffset');
|
|
4
|
+
}
|
|
5
|
+
return sort(a, b, 'startOffset');
|
|
6
|
+
}
|
|
7
|
+
function sort(a, b, key) {
|
|
8
|
+
if (Number.isNaN(a[key]) || Number.isNaN(b[key])) {
|
|
9
|
+
return 0;
|
|
10
|
+
}
|
|
11
|
+
if (a[key] < b[key]) {
|
|
12
|
+
return -1;
|
|
13
|
+
}
|
|
14
|
+
if (a[key] > b[key]) {
|
|
15
|
+
return 1;
|
|
16
|
+
}
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
package/lib/types.d.ts
CHANGED
|
@@ -1,9 +1,43 @@
|
|
|
1
|
+
import type { EndTagType, MLASTParentNode, ParserOptions as ConfigParserOptions } from '@markuplint/ml-ast';
|
|
2
|
+
export type ParserOptions = {
|
|
3
|
+
readonly booleanish?: boolean;
|
|
4
|
+
readonly endTagType?: EndTagType;
|
|
5
|
+
readonly ignoreTags?: readonly IgnoreTag[];
|
|
6
|
+
readonly maskChar?: string;
|
|
7
|
+
readonly tagNameCaseSensitive?: boolean;
|
|
8
|
+
readonly selfCloseType?: SelfCloseType;
|
|
9
|
+
readonly spaceChars?: readonly string[];
|
|
10
|
+
readonly rawTextElements?: readonly string[];
|
|
11
|
+
};
|
|
12
|
+
export type ParseOptions = ConfigParserOptions & {
|
|
13
|
+
readonly offsetOffset?: number;
|
|
14
|
+
readonly offsetLine?: number;
|
|
15
|
+
readonly offsetColumn?: number;
|
|
16
|
+
readonly depth?: number;
|
|
17
|
+
};
|
|
18
|
+
export type Tokenized<N extends {} = {}, State extends unknown = null> = {
|
|
19
|
+
readonly ast: N[];
|
|
20
|
+
readonly isFragment: boolean;
|
|
21
|
+
readonly state?: State;
|
|
22
|
+
};
|
|
23
|
+
export type Token = {
|
|
24
|
+
readonly raw: string;
|
|
25
|
+
readonly startOffset: number;
|
|
26
|
+
readonly startLine: number;
|
|
27
|
+
readonly startCol: number;
|
|
28
|
+
};
|
|
29
|
+
export type ChildToken = Token & {
|
|
30
|
+
readonly depth: number;
|
|
31
|
+
readonly parentNode: MLASTParentNode | null;
|
|
32
|
+
};
|
|
33
|
+
export type SelfCloseType = 'html' | 'xml' | 'html+xml';
|
|
1
34
|
export type Code = {
|
|
2
35
|
readonly type: string;
|
|
3
36
|
readonly index: number;
|
|
4
37
|
readonly startTag: string;
|
|
5
38
|
readonly taggedCode: string;
|
|
6
39
|
readonly endTag: string | null;
|
|
40
|
+
resolved: boolean;
|
|
7
41
|
};
|
|
8
42
|
export type IgnoreTag = {
|
|
9
43
|
readonly type: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/parser-utils",
|
|
3
|
-
"version": "4.0.0-dev.
|
|
3
|
+
"version": "4.0.0-dev.12+2275fbeb0",
|
|
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>",
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
12
|
"import": "./lib/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./location": {
|
|
15
|
+
"import": "./lib/get-location.js"
|
|
13
16
|
}
|
|
14
17
|
},
|
|
15
18
|
"types": "lib/index.d.ts",
|
|
@@ -24,12 +27,13 @@
|
|
|
24
27
|
"clean": "tsc --build --clean"
|
|
25
28
|
},
|
|
26
29
|
"dependencies": {
|
|
27
|
-
"@markuplint/ml-ast": "4.0.0-dev.
|
|
28
|
-
"@markuplint/
|
|
30
|
+
"@markuplint/ml-ast": "4.0.0-dev.12+2275fbeb0",
|
|
31
|
+
"@markuplint/ml-spec": "4.0.0-dev.12+2275fbeb0",
|
|
32
|
+
"@markuplint/types": "4.0.0-dev.12+2275fbeb0",
|
|
29
33
|
"@types/uuid": "^9.0.7",
|
|
30
34
|
"espree": "^9.6.1",
|
|
31
|
-
"type-fest": "^4.
|
|
35
|
+
"type-fest": "^4.9.0",
|
|
32
36
|
"uuid": "^9.0.1"
|
|
33
37
|
},
|
|
34
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "2275fbeb053605b636f080f4fafd7cd4fc57a9a3"
|
|
35
39
|
}
|
package/lib/attr-parser.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { QuoteSet } from './types.js';
|
|
2
|
-
export declare enum AttrState {
|
|
3
|
-
BeforeName = 0,
|
|
4
|
-
Name = 1,
|
|
5
|
-
Equal = 2,
|
|
6
|
-
BeforeValue = 3,
|
|
7
|
-
Value = 4,
|
|
8
|
-
AfterValue = 5
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* @see https://html.spec.whatwg.org/multipage/parsing.html#tag-name-state
|
|
12
|
-
* @see https://html.spec.whatwg.org/multipage/parsing.html#before-attribute-name-state
|
|
13
|
-
* @see https://html.spec.whatwg.org/multipage/parsing.html#attribute-name-state
|
|
14
|
-
*/
|
|
15
|
-
export declare function attrParser(raw: string, quoteSet?: readonly QuoteSet[], startState?: AttrState, quoteInValueChars?: ReadonlyArray<QuoteSet>, spaces?: ReadonlyArray<string>): {
|
|
16
|
-
spacesBeforeAttrName: string;
|
|
17
|
-
attrName: string;
|
|
18
|
-
spacesBeforeEqual: string;
|
|
19
|
-
equal: string;
|
|
20
|
-
spacesAfterEqual: string;
|
|
21
|
-
quoteStart: string;
|
|
22
|
-
attrValue: string;
|
|
23
|
-
quoteEnd: string;
|
|
24
|
-
leftover: string;
|
|
25
|
-
};
|
package/lib/attr-parser.js
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import { defaultSpaces } from './const.js';
|
|
2
|
-
const defaultQuoteSet = [
|
|
3
|
-
{ start: '"', end: '"' },
|
|
4
|
-
{ start: "'", end: "'" },
|
|
5
|
-
];
|
|
6
|
-
const defaultQuoteInValueChars = [];
|
|
7
|
-
const EQUAL = '=';
|
|
8
|
-
export var AttrState;
|
|
9
|
-
(function (AttrState) {
|
|
10
|
-
AttrState[AttrState["BeforeName"] = 0] = "BeforeName";
|
|
11
|
-
AttrState[AttrState["Name"] = 1] = "Name";
|
|
12
|
-
AttrState[AttrState["Equal"] = 2] = "Equal";
|
|
13
|
-
AttrState[AttrState["BeforeValue"] = 3] = "BeforeValue";
|
|
14
|
-
AttrState[AttrState["Value"] = 4] = "Value";
|
|
15
|
-
AttrState[AttrState["AfterValue"] = 5] = "AfterValue";
|
|
16
|
-
})(AttrState || (AttrState = {}));
|
|
17
|
-
/**
|
|
18
|
-
* @see https://html.spec.whatwg.org/multipage/parsing.html#tag-name-state
|
|
19
|
-
* @see https://html.spec.whatwg.org/multipage/parsing.html#before-attribute-name-state
|
|
20
|
-
* @see https://html.spec.whatwg.org/multipage/parsing.html#attribute-name-state
|
|
21
|
-
*/
|
|
22
|
-
export function attrParser(raw, quoteSet = defaultQuoteSet, startState = AttrState.BeforeName, quoteInValueChars = defaultQuoteInValueChars, spaces = defaultSpaces) {
|
|
23
|
-
let state = startState;
|
|
24
|
-
let spacesBeforeAttrName = '';
|
|
25
|
-
let attrName = '';
|
|
26
|
-
let spacesBeforeEqual = '';
|
|
27
|
-
let equal = '';
|
|
28
|
-
let spacesAfterEqual = '';
|
|
29
|
-
let quoteTypeIndex = -1;
|
|
30
|
-
let quoteStart = '';
|
|
31
|
-
let attrValue = '';
|
|
32
|
-
let quoteEnd = '';
|
|
33
|
-
const quoteModeStack = [];
|
|
34
|
-
const chars = [...raw];
|
|
35
|
-
while (chars.length > 0) {
|
|
36
|
-
if (state === AttrState.AfterValue) {
|
|
37
|
-
break;
|
|
38
|
-
}
|
|
39
|
-
const char = chars.shift();
|
|
40
|
-
switch (state) {
|
|
41
|
-
case AttrState.BeforeName: {
|
|
42
|
-
if (char === '>') {
|
|
43
|
-
chars.unshift(char);
|
|
44
|
-
state = AttrState.AfterValue;
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
if (char === '/') {
|
|
48
|
-
chars.unshift(char);
|
|
49
|
-
state = AttrState.AfterValue;
|
|
50
|
-
break;
|
|
51
|
-
}
|
|
52
|
-
if (spaces.includes(char)) {
|
|
53
|
-
spacesBeforeAttrName += char;
|
|
54
|
-
break;
|
|
55
|
-
}
|
|
56
|
-
attrName += char;
|
|
57
|
-
state = AttrState.Name;
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
case AttrState.Name: {
|
|
61
|
-
if (char === '>') {
|
|
62
|
-
chars.unshift(char);
|
|
63
|
-
state = AttrState.AfterValue;
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
|
-
if (char === '/') {
|
|
67
|
-
chars.unshift(char);
|
|
68
|
-
state = AttrState.AfterValue;
|
|
69
|
-
break;
|
|
70
|
-
}
|
|
71
|
-
if (spaces.includes(char)) {
|
|
72
|
-
spacesBeforeEqual += char;
|
|
73
|
-
state = AttrState.Equal;
|
|
74
|
-
break;
|
|
75
|
-
}
|
|
76
|
-
if (char === EQUAL) {
|
|
77
|
-
equal += char;
|
|
78
|
-
state = AttrState.BeforeValue;
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
attrName += char;
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
case AttrState.Equal: {
|
|
85
|
-
if (spaces.includes(char)) {
|
|
86
|
-
spacesBeforeEqual += char;
|
|
87
|
-
break;
|
|
88
|
-
}
|
|
89
|
-
if (char === EQUAL) {
|
|
90
|
-
equal += char;
|
|
91
|
-
state = AttrState.BeforeValue;
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
// End of attribute
|
|
95
|
-
chars.unshift(spacesBeforeEqual, char);
|
|
96
|
-
spacesBeforeEqual = '';
|
|
97
|
-
state = AttrState.AfterValue;
|
|
98
|
-
break;
|
|
99
|
-
}
|
|
100
|
-
case AttrState.BeforeValue: {
|
|
101
|
-
if (spaces.includes(char)) {
|
|
102
|
-
spacesAfterEqual += char;
|
|
103
|
-
break;
|
|
104
|
-
}
|
|
105
|
-
quoteTypeIndex = quoteSet.findIndex(quote => quote.start === char);
|
|
106
|
-
const quote = quoteSet[quoteTypeIndex];
|
|
107
|
-
if (quote) {
|
|
108
|
-
quoteStart = quote.start;
|
|
109
|
-
state = AttrState.Value;
|
|
110
|
-
break;
|
|
111
|
-
}
|
|
112
|
-
const raw = char + chars.join('');
|
|
113
|
-
const inQuote = quoteInValueChars.find(quote => raw.startsWith(quote.start));
|
|
114
|
-
if (inQuote) {
|
|
115
|
-
quoteModeStack.push(inQuote);
|
|
116
|
-
attrValue += inQuote.start;
|
|
117
|
-
chars.splice(0, inQuote.start.length - 1);
|
|
118
|
-
state = AttrState.Value;
|
|
119
|
-
break;
|
|
120
|
-
}
|
|
121
|
-
chars.unshift(char);
|
|
122
|
-
state = AttrState.Value;
|
|
123
|
-
break;
|
|
124
|
-
}
|
|
125
|
-
case AttrState.Value: {
|
|
126
|
-
// console.log(
|
|
127
|
-
// char,
|
|
128
|
-
// quoteSet[quoteTypeIndex]?.end,
|
|
129
|
-
// quoteModeStack.map(q => `${q.start}${q.end}`),
|
|
130
|
-
// );
|
|
131
|
-
if (!quoteSet[quoteTypeIndex]) {
|
|
132
|
-
if (spaces.includes(char)) {
|
|
133
|
-
chars.unshift(char);
|
|
134
|
-
state = AttrState.AfterValue;
|
|
135
|
-
break;
|
|
136
|
-
}
|
|
137
|
-
if (char === '/') {
|
|
138
|
-
chars.unshift(char);
|
|
139
|
-
state = AttrState.AfterValue;
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
if (char === '>') {
|
|
143
|
-
chars.unshift(char);
|
|
144
|
-
state = AttrState.AfterValue;
|
|
145
|
-
break;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
if (quoteModeStack.length === 0 && char === quoteSet[quoteTypeIndex]?.end) {
|
|
149
|
-
quoteEnd = char;
|
|
150
|
-
state = AttrState.AfterValue;
|
|
151
|
-
break;
|
|
152
|
-
}
|
|
153
|
-
const raw = char + chars.join('');
|
|
154
|
-
const inQuoteEnd = quoteModeStack.at(-1);
|
|
155
|
-
if (inQuoteEnd && raw.startsWith(inQuoteEnd.end)) {
|
|
156
|
-
quoteModeStack.pop();
|
|
157
|
-
attrValue += inQuoteEnd.end;
|
|
158
|
-
chars.splice(0, inQuoteEnd.end.length - 1);
|
|
159
|
-
break;
|
|
160
|
-
}
|
|
161
|
-
const inQuoteStart = quoteInValueChars.find(quote => raw.startsWith(quote.start));
|
|
162
|
-
if (inQuoteStart) {
|
|
163
|
-
quoteModeStack.push(inQuoteStart);
|
|
164
|
-
attrValue += inQuoteStart.start;
|
|
165
|
-
chars.splice(0, inQuoteStart.start.length - 1);
|
|
166
|
-
break;
|
|
167
|
-
}
|
|
168
|
-
attrValue += char;
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
if (state === AttrState.Value && quoteTypeIndex !== -1) {
|
|
174
|
-
throw new SyntaxError(`Unclosed attribute value: ${raw}`);
|
|
175
|
-
}
|
|
176
|
-
const leftover = chars.join('');
|
|
177
|
-
return {
|
|
178
|
-
spacesBeforeAttrName,
|
|
179
|
-
attrName,
|
|
180
|
-
spacesBeforeEqual,
|
|
181
|
-
equal,
|
|
182
|
-
spacesAfterEqual,
|
|
183
|
-
quoteStart,
|
|
184
|
-
attrValue,
|
|
185
|
-
quoteEnd,
|
|
186
|
-
leftover,
|
|
187
|
-
};
|
|
188
|
-
}
|
package/lib/create-token.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { MLToken } from '@markuplint/ml-ast';
|
|
2
|
-
export declare function tokenizer(raw: string | null, startLine: number, startCol: number, startOffset: number): MLToken;
|
|
3
|
-
export declare function createTokenFromRawCode(raw: string | null, startOffset: number, rawCode: string): MLToken;
|
|
4
|
-
export declare function uuid(): string;
|
package/lib/create-token.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { v4 as uuid4 } from 'uuid';
|
|
2
|
-
import { getEndCol, getEndLine, sliceFragment } from './get-location.js';
|
|
3
|
-
export function tokenizer(raw, startLine, startCol, startOffset) {
|
|
4
|
-
raw = raw ?? '';
|
|
5
|
-
const endLine = getEndLine(raw, startLine);
|
|
6
|
-
const endCol = getEndCol(raw, startCol);
|
|
7
|
-
const endOffset = startOffset + raw.length;
|
|
8
|
-
return {
|
|
9
|
-
uuid: uuid(),
|
|
10
|
-
raw,
|
|
11
|
-
startOffset,
|
|
12
|
-
endOffset,
|
|
13
|
-
startLine,
|
|
14
|
-
endLine,
|
|
15
|
-
startCol,
|
|
16
|
-
endCol,
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
export function createTokenFromRawCode(raw, startOffset, rawCode) {
|
|
20
|
-
raw = raw ?? '';
|
|
21
|
-
const loc = sliceFragment(rawCode, startOffset, startOffset + raw.length);
|
|
22
|
-
return {
|
|
23
|
-
uuid: uuid(),
|
|
24
|
-
...loc,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
export function uuid() {
|
|
28
|
-
return uuid4();
|
|
29
|
-
}
|
package/lib/flatten-nodes.d.ts
DELETED
package/lib/flatten-nodes.js
DELETED
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
import { uuid } from './create-token.js';
|
|
2
|
-
import { getEndCol, getEndLine } from './get-location.js';
|
|
3
|
-
import { removeDeprecatedNode } from './remove-deprecated-node.js';
|
|
4
|
-
import { tagSplitter } from './tag-splitter.js';
|
|
5
|
-
import { walk } from './walker.js';
|
|
6
|
-
export function flattenNodes(
|
|
7
|
-
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
8
|
-
nodeTree, rawHtml, createLastText = true) {
|
|
9
|
-
const nodeOrders = arrayize(nodeTree, rawHtml);
|
|
10
|
-
{
|
|
11
|
-
/**
|
|
12
|
-
* Correction prev/next/parent
|
|
13
|
-
*/
|
|
14
|
-
let prevToken = null;
|
|
15
|
-
for (const node of nodeOrders) {
|
|
16
|
-
if (!prevToken) {
|
|
17
|
-
prevToken = node;
|
|
18
|
-
continue;
|
|
19
|
-
}
|
|
20
|
-
if (node.type !== 'endtag') {
|
|
21
|
-
prevToken = node;
|
|
22
|
-
continue;
|
|
23
|
-
}
|
|
24
|
-
const endTag = node;
|
|
25
|
-
if (endTag.nodeName.toLowerCase() === 'body' && prevToken.type === 'text') {
|
|
26
|
-
const prevWreckagesText = prevToken;
|
|
27
|
-
const wreckages = tagSplitter(prevWreckagesText.raw, prevWreckagesText.startLine, prevWreckagesText.startCol);
|
|
28
|
-
if (wreckages.length > 0 && wreckages[0]) {
|
|
29
|
-
// console.log('wreckages\n', wreckages);
|
|
30
|
-
const lastText = wreckages[0];
|
|
31
|
-
const raw = lastText.raw;
|
|
32
|
-
const startLine = lastText.line;
|
|
33
|
-
const startCol = lastText.col;
|
|
34
|
-
prevWreckagesText.raw = raw;
|
|
35
|
-
prevWreckagesText.endOffset = prevWreckagesText.startOffset + raw.length;
|
|
36
|
-
prevWreckagesText.startLine = startLine;
|
|
37
|
-
prevWreckagesText.endLine = getEndLine(raw, startLine);
|
|
38
|
-
prevWreckagesText.startCol = startCol;
|
|
39
|
-
prevWreckagesText.endCol = getEndCol(raw, startCol);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
removeDeprecatedNode(nodeOrders);
|
|
45
|
-
{
|
|
46
|
-
/**
|
|
47
|
-
* getting last node
|
|
48
|
-
*/
|
|
49
|
-
let lastNode = null;
|
|
50
|
-
for (const node of nodeOrders) {
|
|
51
|
-
if (node.isGhost) {
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
lastNode = node;
|
|
55
|
-
}
|
|
56
|
-
if (lastNode) {
|
|
57
|
-
if (lastNode.type === 'text') {
|
|
58
|
-
// Correction for Parse5 AST
|
|
59
|
-
// prev node: ? -> html
|
|
60
|
-
lastNode.prevNode = lastNode.parentNode?.parentNode ?? lastNode.parentNode;
|
|
61
|
-
if (lastNode.prevNode) {
|
|
62
|
-
lastNode.prevNode.nextNode = lastNode;
|
|
63
|
-
}
|
|
64
|
-
// parent node: body -> null
|
|
65
|
-
lastNode.parentNode = null;
|
|
66
|
-
// next node: ? -> null
|
|
67
|
-
lastNode.nextNode = null;
|
|
68
|
-
}
|
|
69
|
-
else if (createLastText) {
|
|
70
|
-
/**
|
|
71
|
-
* create Last spaces
|
|
72
|
-
*/
|
|
73
|
-
let lastOffset = 0;
|
|
74
|
-
for (const node of nodeOrders) {
|
|
75
|
-
lastOffset = Math.max(node.endOffset, lastOffset);
|
|
76
|
-
}
|
|
77
|
-
// console.log(lastOffset);
|
|
78
|
-
const lastTextContent = rawHtml.slice(lastOffset);
|
|
79
|
-
// console.log(`"${lastTextContent}"`);
|
|
80
|
-
if (lastTextContent) {
|
|
81
|
-
const line = lastNode?.endLine ?? 0;
|
|
82
|
-
const col = lastNode?.endCol ?? 0;
|
|
83
|
-
const lastTextNode = {
|
|
84
|
-
uuid: uuid(),
|
|
85
|
-
raw: lastTextContent,
|
|
86
|
-
startOffset: lastOffset,
|
|
87
|
-
endOffset: lastOffset + lastTextContent.length,
|
|
88
|
-
startLine: line,
|
|
89
|
-
endLine: getEndLine(lastTextContent, line),
|
|
90
|
-
startCol: col,
|
|
91
|
-
endCol: getEndCol(lastTextContent, col),
|
|
92
|
-
nodeName: '#text',
|
|
93
|
-
type: 'text',
|
|
94
|
-
parentNode: null,
|
|
95
|
-
prevNode: lastNode,
|
|
96
|
-
nextNode: null,
|
|
97
|
-
isFragment: false,
|
|
98
|
-
isGhost: false,
|
|
99
|
-
};
|
|
100
|
-
lastNode.nextNode = lastTextNode;
|
|
101
|
-
if ((lastNode.type === 'starttag' || lastNode.type === 'endtag') && lastNode.pearNode) {
|
|
102
|
-
lastNode.pearNode.nextNode = lastTextNode;
|
|
103
|
-
}
|
|
104
|
-
nodeOrders.push(lastTextNode);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* concat text nodes
|
|
111
|
-
*/
|
|
112
|
-
const result = [];
|
|
113
|
-
for (const node of nodeOrders) {
|
|
114
|
-
const prevNode = result.at(-1) ?? null;
|
|
115
|
-
if (node.type === 'text' && prevNode?.type === 'text') {
|
|
116
|
-
prevNode.raw = prevNode.raw + node.raw;
|
|
117
|
-
prevNode.endOffset = node.endOffset;
|
|
118
|
-
prevNode.endLine = node.endLine;
|
|
119
|
-
prevNode.endCol = node.endCol;
|
|
120
|
-
prevNode.nextNode = node.nextNode;
|
|
121
|
-
if (prevNode.parentNode) {
|
|
122
|
-
if (prevNode.parentNode.childNodes) {
|
|
123
|
-
if (prevNode.parentNode.childNodes.findIndex(currentChild => currentChild.uuid === prevNode.uuid) === -1) {
|
|
124
|
-
prevNode.parentNode.childNodes.unshift(prevNode);
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
prevNode.parentNode.childNodes = [prevNode];
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
prevNode.parentNode.childNodes = prevNode.parentNode.childNodes?.filter(n => n.uuid !== node.uuid);
|
|
131
|
-
}
|
|
132
|
-
if (node.nextNode) {
|
|
133
|
-
node.nextNode.prevNode = prevNode;
|
|
134
|
-
}
|
|
135
|
-
continue;
|
|
136
|
-
}
|
|
137
|
-
result.push(node);
|
|
138
|
-
}
|
|
139
|
-
{
|
|
140
|
-
/**
|
|
141
|
-
* Correction prev/next/parent
|
|
142
|
-
*/
|
|
143
|
-
let prevToken = null;
|
|
144
|
-
for (const node of result) {
|
|
145
|
-
if (!prevToken) {
|
|
146
|
-
prevToken = node;
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
if (((prevToken.type === 'endtag' && prevToken.nodeName.toLowerCase() === 'body') ||
|
|
150
|
-
prevToken.type === 'doctype') &&
|
|
151
|
-
node.type === 'text') {
|
|
152
|
-
const nextNode = prevToken.nextNode;
|
|
153
|
-
prevToken.nextNode = node;
|
|
154
|
-
if (prevToken.type === 'endtag' && prevToken.pearNode) {
|
|
155
|
-
prevToken.pearNode.nextNode = node;
|
|
156
|
-
}
|
|
157
|
-
node.prevNode = prevToken;
|
|
158
|
-
node.nextNode = nextNode;
|
|
159
|
-
node.parentNode = prevToken.parentNode;
|
|
160
|
-
}
|
|
161
|
-
// EndTag
|
|
162
|
-
if (node.type === 'starttag' && node.pearNode) {
|
|
163
|
-
const endTag = node.pearNode;
|
|
164
|
-
endTag.pearNode = node;
|
|
165
|
-
endTag.prevNode = node.prevNode;
|
|
166
|
-
endTag.nextNode = node.nextNode;
|
|
167
|
-
}
|
|
168
|
-
// Children
|
|
169
|
-
if (node.type === 'text') {
|
|
170
|
-
const parent = node.parentNode;
|
|
171
|
-
if (parent &&
|
|
172
|
-
parent.type === 'starttag' &&
|
|
173
|
-
parent.nodeName.toLowerCase() === 'html' &&
|
|
174
|
-
parent.childNodes &&
|
|
175
|
-
!parent.childNodes.some(n => n.uuid === node.uuid)) {
|
|
176
|
-
parent.childNodes.push(node);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
prevToken = node;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
// console.log(nodeOrders.map((n, i) => `${i}: ${n.raw.trim()}`));
|
|
183
|
-
return result;
|
|
184
|
-
}
|
|
185
|
-
function arrayize(
|
|
186
|
-
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
187
|
-
nodeTree, rawHtml) {
|
|
188
|
-
const nodeOrders = [];
|
|
189
|
-
let prevLine = 1;
|
|
190
|
-
let prevCol = 1;
|
|
191
|
-
let currentEndOffset = 0;
|
|
192
|
-
/**
|
|
193
|
-
* pushing list
|
|
194
|
-
*/
|
|
195
|
-
walk(nodeTree, node => {
|
|
196
|
-
const diff = node.startOffset - currentEndOffset;
|
|
197
|
-
if (diff > 0) {
|
|
198
|
-
const html = rawHtml.slice(currentEndOffset, node.startOffset);
|
|
199
|
-
/**
|
|
200
|
-
* first white spaces
|
|
201
|
-
*/
|
|
202
|
-
if (/^\s+$/.test(html)) {
|
|
203
|
-
const spaces = html;
|
|
204
|
-
const textNode = {
|
|
205
|
-
uuid: uuid(),
|
|
206
|
-
raw: spaces,
|
|
207
|
-
startOffset: currentEndOffset,
|
|
208
|
-
endOffset: currentEndOffset + spaces.length,
|
|
209
|
-
startLine: prevLine,
|
|
210
|
-
endLine: getEndLine(spaces, prevLine),
|
|
211
|
-
startCol: prevCol,
|
|
212
|
-
endCol: getEndCol(spaces, prevCol),
|
|
213
|
-
nodeName: '#text',
|
|
214
|
-
type: 'text',
|
|
215
|
-
parentNode: node.parentNode,
|
|
216
|
-
prevNode: node.prevNode,
|
|
217
|
-
nextNode: node,
|
|
218
|
-
isFragment: false,
|
|
219
|
-
isGhost: false,
|
|
220
|
-
};
|
|
221
|
-
node.prevNode = textNode;
|
|
222
|
-
if (node.parentNode && node.parentNode.childNodes) {
|
|
223
|
-
const newChildNodes = [...node.parentNode.childNodes];
|
|
224
|
-
if (newChildNodes.some(child => {
|
|
225
|
-
return (
|
|
226
|
-
// Out of start offset
|
|
227
|
-
textNode.endOffset < child.startOffset ||
|
|
228
|
-
// Out of end offset
|
|
229
|
-
child.endOffset < textNode.startOffset);
|
|
230
|
-
})) {
|
|
231
|
-
newChildNodes.push(textNode);
|
|
232
|
-
}
|
|
233
|
-
newChildNodes.sort((a, b) => a.startOffset - b.startOffset);
|
|
234
|
-
node.parentNode.childNodes = newChildNodes;
|
|
235
|
-
}
|
|
236
|
-
nodeOrders.push(textNode);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
currentEndOffset = node.startOffset + node.raw.length;
|
|
240
|
-
prevLine = node.endLine;
|
|
241
|
-
prevCol = node.endCol;
|
|
242
|
-
// for ghost nodes
|
|
243
|
-
node.endOffset = node.endOffset ?? currentEndOffset;
|
|
244
|
-
nodeOrders.push(node);
|
|
245
|
-
});
|
|
246
|
-
return [...nodeOrders];
|
|
247
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function getSpaceBefore(offset: number, rawCode: string): import("packages/@markuplint/ml-ast/lib/types.js").MLToken;
|
package/lib/get-space-before.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { createTokenFromRawCode } from './create-token.js';
|
|
2
|
-
export function getSpaceBefore(offset, rawCode) {
|
|
3
|
-
const aboveCode = rawCode.slice(0, offset);
|
|
4
|
-
const aboveAttrMatched = aboveCode.match(/\s+$/m);
|
|
5
|
-
const aboveAttrChar = aboveAttrMatched?.[0] ?? '';
|
|
6
|
-
const spacesBefore = createTokenFromRawCode(aboveAttrChar, offset - aboveAttrChar.length, rawCode);
|
|
7
|
-
return spacesBefore;
|
|
8
|
-
}
|
package/lib/parse-attr.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { MLASTHTMLAttr } from '@markuplint/ml-ast';
|
|
2
|
-
type ParseAttrOptions = {
|
|
3
|
-
readonly booleanish?: boolean;
|
|
4
|
-
readonly valueDelimiters?: readonly ValueDelimiter[];
|
|
5
|
-
readonly equal?: string;
|
|
6
|
-
};
|
|
7
|
-
type ValueDelimiter = {
|
|
8
|
-
readonly start: string;
|
|
9
|
-
readonly end: string;
|
|
10
|
-
};
|
|
11
|
-
export declare const defaultValueDelimiters: readonly ValueDelimiter[];
|
|
12
|
-
export declare function parseAttr(raw: string, offset: number, html: string, options?: ParseAttrOptions): MLASTHTMLAttr;
|
|
13
|
-
export declare function tokenize(raw: string, options?: ParseAttrOptions): {
|
|
14
|
-
beforeName: string;
|
|
15
|
-
name: string;
|
|
16
|
-
afterName: string;
|
|
17
|
-
equal: string;
|
|
18
|
-
beforeValue: string;
|
|
19
|
-
startQuote: string;
|
|
20
|
-
value: string;
|
|
21
|
-
endQuote: string;
|
|
22
|
-
afterAttr: string;
|
|
23
|
-
};
|
|
24
|
-
export {};
|