@markuplint/pug-parser 4.6.15 → 4.6.16
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 +6 -0
- package/lib/parser.d.ts +1 -1
- package/lib/parser.js +7 -6
- package/lib/pug-parser/index.d.ts +1 -177
- package/lib/pug-parser/index.js +126 -8
- package/lib/types.d.ts +342 -0
- package/lib/types.js +1 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
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
|
+
## [4.6.16](https://github.com/markuplint/markuplint/compare/@markuplint/pug-parser@4.6.15...@markuplint/pug-parser@4.6.16) (2025-02-11)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- **pug-parser:** implemented previously unsupported nodes, including `InterpolatedTag` ([a89e39a](https://github.com/markuplint/markuplint/commit/a89e39ab5bc09bfef2c7bc7fdcba65f6b672eb34)), closes [#2440](https://github.com/markuplint/markuplint/issues/2440)
|
|
11
|
+
|
|
6
12
|
## [4.6.15](https://github.com/markuplint/markuplint/compare/@markuplint/pug-parser@4.6.14...@markuplint/pug-parser@4.6.15) (2025-02-04)
|
|
7
13
|
|
|
8
14
|
**Note:** Version bump only for package @markuplint/pug-parser
|
package/lib/parser.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ASTNode } from './
|
|
1
|
+
import type { ASTNode } from './types.js';
|
|
2
2
|
import type { MLASTAttr, MLASTNodeTreeItem, MLASTParentNode } from '@markuplint/ml-ast';
|
|
3
3
|
import type { ChildToken, ParseOptions, Token } from '@markuplint/parser-utils';
|
|
4
4
|
import { ParserError, Parser } from '@markuplint/parser-utils';
|
package/lib/parser.js
CHANGED
|
@@ -27,8 +27,9 @@ class PugParser extends Parser {
|
|
|
27
27
|
}
|
|
28
28
|
tokenize(options) {
|
|
29
29
|
const offsetOffset = options?.offsetOffset ?? 0;
|
|
30
|
+
const ast = pugParse(this.rawCode, offsetOffset >= 1).nodes;
|
|
30
31
|
return {
|
|
31
|
-
ast:
|
|
32
|
+
ast: [...ast],
|
|
32
33
|
isFragment: true,
|
|
33
34
|
};
|
|
34
35
|
}
|
|
@@ -53,7 +54,7 @@ class PugParser extends Parser {
|
|
|
53
54
|
...token,
|
|
54
55
|
depth,
|
|
55
56
|
parentNode,
|
|
56
|
-
name: originNode.
|
|
57
|
+
name: originNode.raw ?? '',
|
|
57
58
|
publicId: '',
|
|
58
59
|
systemId: '',
|
|
59
60
|
});
|
|
@@ -72,7 +73,7 @@ class PugParser extends Parser {
|
|
|
72
73
|
const htmlDoc = new HtmlInPugParser().parse(originNode.raw, {
|
|
73
74
|
offsetOffset: originNode.offset,
|
|
74
75
|
offsetLine: originNode.line,
|
|
75
|
-
offsetColumn: originNode.column,
|
|
76
|
+
offsetColumn: originNode.column ?? parentNode?.endCol,
|
|
76
77
|
depth,
|
|
77
78
|
});
|
|
78
79
|
const newNodeList = [];
|
|
@@ -103,7 +104,7 @@ class PugParser extends Parser {
|
|
|
103
104
|
});
|
|
104
105
|
}
|
|
105
106
|
case 'BlockComment': {
|
|
106
|
-
const lastBlock = originNode.block
|
|
107
|
+
const lastBlock = originNode.block?.nodes.at(-1);
|
|
107
108
|
const endOffset = lastBlock ? lastBlock.endOffset : originNode.endOffset;
|
|
108
109
|
const token = this.sliceFragment(originNode.offset, endOffset);
|
|
109
110
|
return this.visitComment({
|
|
@@ -154,7 +155,7 @@ class PugParser extends Parser {
|
|
|
154
155
|
nodeName: originNode.name,
|
|
155
156
|
namespace,
|
|
156
157
|
isFragment: false,
|
|
157
|
-
}, originNode.block
|
|
158
|
+
}, originNode.block?.nodes ?? [], {
|
|
158
159
|
overwriteProps: {
|
|
159
160
|
attributes: [...attrs, ...andAttr],
|
|
160
161
|
},
|
|
@@ -162,7 +163,7 @@ class PugParser extends Parser {
|
|
|
162
163
|
}
|
|
163
164
|
default: {
|
|
164
165
|
let tokenIncludesFile = token;
|
|
165
|
-
if ('file' in originNode) {
|
|
166
|
+
if ('file' in originNode && originNode.file.column != null) {
|
|
166
167
|
const interval = originNode.file.column - originNode.endColumn;
|
|
167
168
|
const fileOffset = originNode.endOffset + interval;
|
|
168
169
|
const fileEndOffset = fileOffset + originNode.file.path.length;
|
|
@@ -1,178 +1,2 @@
|
|
|
1
|
+
import type { ASTBlock } from '../types.js';
|
|
1
2
|
export declare function pugParse(pug: string, useOffset?: boolean): ASTBlock;
|
|
2
|
-
export type ASTBlock = PugAST<ASTNode>;
|
|
3
|
-
export type ASTNode = ASTTagNode | ASTTextNode | ASTCodeNode | ASTComment | ASTBlockComment | ASTDoctype | ASTIncludeNode | ASTRawIncludeNode | ASTMixinNode | ASTMixinSlotNode | ASTNamedBlockNode | ASTFilterNode | ASTEachNode | ASTConditionalNode | ASTCaseNode | ASTCaseWhenNode;
|
|
4
|
-
export type ASTTagNode = Omit<PugASTTagNode<ASTAttr, ASTBlock>, 'selfClosing' | 'isInline'> & AdditionalASTData;
|
|
5
|
-
export type ASTTextNode = Omit<PugASTTextNode, 'val'> & AdditionalASTData;
|
|
6
|
-
export type ASTCodeNode = PugASTCodeNode & AdditionalASTData;
|
|
7
|
-
export type ASTComment = PugASTCommentNode & AdditionalASTData;
|
|
8
|
-
export type ASTBlockComment = PugASTBlockCommentNode<ASTBlock> & AdditionalASTData;
|
|
9
|
-
export type ASTDoctype = PugASTDoctypeNode & AdditionalASTData;
|
|
10
|
-
export type ASTIncludeNode = PugASTIncludeNode<ASTBlock> & AdditionalASTData;
|
|
11
|
-
export type ASTRawIncludeNode = PugASTRawIncludeNode & AdditionalASTData;
|
|
12
|
-
export type ASTMixinNode = Omit<PugASTMixinNode<ASTAttr, ASTBlock>, 'attributeBlocks'> & AdditionalASTData;
|
|
13
|
-
export type ASTMixinSlotNode = PugASTMixinSlotNode & AdditionalASTData;
|
|
14
|
-
export type ASTNamedBlockNode = PugASTNamedBlockNode<ASTNode> & AdditionalASTData;
|
|
15
|
-
export type ASTFilterNode = PugASTFilterNode<ASTAttr, ASTBlock> & AdditionalASTData;
|
|
16
|
-
export type ASTEachNode = PugASTEachNode<ASTBlock> & AdditionalASTData;
|
|
17
|
-
export type ASTConditionalNode = Omit<PugASTConditionalNode<ASTBlock>, 'consequent' | 'alternate'> & {
|
|
18
|
-
block: ASTBlock;
|
|
19
|
-
} & AdditionalASTData;
|
|
20
|
-
export type ASTCaseNode = PugASTCaseNode<ASTBlock> & AdditionalASTData;
|
|
21
|
-
export type ASTCaseWhenNode = PugASTCaseWhenNode<ASTBlock> & AdditionalASTData;
|
|
22
|
-
export type ASTAttr = PugASTAttr & AdditionalASTData;
|
|
23
|
-
type AdditionalASTData = {
|
|
24
|
-
raw: string;
|
|
25
|
-
offset: number;
|
|
26
|
-
endOffset: number;
|
|
27
|
-
endLine: number;
|
|
28
|
-
endColumn: number;
|
|
29
|
-
};
|
|
30
|
-
interface PugAST<N> {
|
|
31
|
-
type: 'Block';
|
|
32
|
-
nodes: N[];
|
|
33
|
-
line: number;
|
|
34
|
-
}
|
|
35
|
-
type PugASTTagNode<A, B> = {
|
|
36
|
-
type: 'Tag';
|
|
37
|
-
name: string;
|
|
38
|
-
selfClosing: boolean;
|
|
39
|
-
attrs: A[];
|
|
40
|
-
attributeBlocks: {
|
|
41
|
-
type: 'AttributeBlock';
|
|
42
|
-
val: string;
|
|
43
|
-
line: number;
|
|
44
|
-
column: number;
|
|
45
|
-
}[];
|
|
46
|
-
isInline: boolean;
|
|
47
|
-
line: number;
|
|
48
|
-
column: number;
|
|
49
|
-
block: B;
|
|
50
|
-
};
|
|
51
|
-
type PugASTTextNode = {
|
|
52
|
-
type: 'Text';
|
|
53
|
-
val: string;
|
|
54
|
-
isHtml?: true;
|
|
55
|
-
line: number;
|
|
56
|
-
column: number;
|
|
57
|
-
};
|
|
58
|
-
type PugASTCodeNode = {
|
|
59
|
-
type: 'Code';
|
|
60
|
-
val: string;
|
|
61
|
-
buffer: boolean;
|
|
62
|
-
mustEscape: boolean;
|
|
63
|
-
isInline: boolean;
|
|
64
|
-
line: number;
|
|
65
|
-
column: number;
|
|
66
|
-
};
|
|
67
|
-
type PugASTCommentNode = {
|
|
68
|
-
type: 'Comment';
|
|
69
|
-
val: string;
|
|
70
|
-
buffer: boolean;
|
|
71
|
-
line: number;
|
|
72
|
-
column: number;
|
|
73
|
-
};
|
|
74
|
-
type PugASTBlockCommentNode<B> = {
|
|
75
|
-
type: 'BlockComment';
|
|
76
|
-
val: string;
|
|
77
|
-
block: B;
|
|
78
|
-
buffer: boolean;
|
|
79
|
-
line: number;
|
|
80
|
-
column: number;
|
|
81
|
-
};
|
|
82
|
-
type PugASTDoctypeNode = {
|
|
83
|
-
type: 'Doctype';
|
|
84
|
-
val: string;
|
|
85
|
-
line: number;
|
|
86
|
-
column: number;
|
|
87
|
-
};
|
|
88
|
-
type PugASTIncludeNode<B> = {
|
|
89
|
-
type: 'Include';
|
|
90
|
-
file: RugASTIncludeFile;
|
|
91
|
-
block: B;
|
|
92
|
-
line: number;
|
|
93
|
-
column: number;
|
|
94
|
-
};
|
|
95
|
-
type PugASTRawIncludeNode = {
|
|
96
|
-
type: 'RawInclude';
|
|
97
|
-
file: RugASTIncludeFile;
|
|
98
|
-
line: number;
|
|
99
|
-
column: number;
|
|
100
|
-
filters: unknown[];
|
|
101
|
-
};
|
|
102
|
-
type RugASTIncludeFile = {
|
|
103
|
-
type: 'FileReference';
|
|
104
|
-
path: string;
|
|
105
|
-
line: number;
|
|
106
|
-
column: number;
|
|
107
|
-
};
|
|
108
|
-
type PugASTEachNode<B> = {
|
|
109
|
-
type: 'Each';
|
|
110
|
-
obj: string;
|
|
111
|
-
val: string;
|
|
112
|
-
key: string | null;
|
|
113
|
-
block: B;
|
|
114
|
-
line: number;
|
|
115
|
-
column: number;
|
|
116
|
-
};
|
|
117
|
-
type PugASTMixinNode<A, B> = {
|
|
118
|
-
type: 'Mixin';
|
|
119
|
-
name: string;
|
|
120
|
-
args: string;
|
|
121
|
-
call: boolean;
|
|
122
|
-
block: B | null;
|
|
123
|
-
attrs?: A[];
|
|
124
|
-
attributeBlocks: never[];
|
|
125
|
-
line: number;
|
|
126
|
-
column: number;
|
|
127
|
-
};
|
|
128
|
-
type PugASTMixinSlotNode = {
|
|
129
|
-
type: 'MixinBlock';
|
|
130
|
-
line: number;
|
|
131
|
-
column: number;
|
|
132
|
-
};
|
|
133
|
-
interface PugASTNamedBlockNode<N> {
|
|
134
|
-
type: 'NamedBlock';
|
|
135
|
-
name: string;
|
|
136
|
-
mode: 'replace' | 'append' | 'prepend';
|
|
137
|
-
nodes: N[];
|
|
138
|
-
line: number;
|
|
139
|
-
column: number;
|
|
140
|
-
}
|
|
141
|
-
type PugASTFilterNode<A, B> = {
|
|
142
|
-
type: 'Filter';
|
|
143
|
-
name: string;
|
|
144
|
-
block: B;
|
|
145
|
-
attrs: A[];
|
|
146
|
-
line: number;
|
|
147
|
-
column: number;
|
|
148
|
-
};
|
|
149
|
-
type PugASTConditionalNode<B> = {
|
|
150
|
-
type: 'Conditional';
|
|
151
|
-
test: string;
|
|
152
|
-
consequent: B;
|
|
153
|
-
alternate?: B | PugASTConditionalNode<B>;
|
|
154
|
-
line: number;
|
|
155
|
-
column: number;
|
|
156
|
-
};
|
|
157
|
-
type PugASTCaseNode<B> = {
|
|
158
|
-
type: 'Case';
|
|
159
|
-
expr: string;
|
|
160
|
-
block: B;
|
|
161
|
-
line: number;
|
|
162
|
-
column: number;
|
|
163
|
-
};
|
|
164
|
-
type PugASTCaseWhenNode<B> = {
|
|
165
|
-
type: 'When';
|
|
166
|
-
expr: string;
|
|
167
|
-
block: B;
|
|
168
|
-
line: number;
|
|
169
|
-
column: number;
|
|
170
|
-
};
|
|
171
|
-
type PugASTAttr = {
|
|
172
|
-
name: string;
|
|
173
|
-
val: string | true;
|
|
174
|
-
mustEscape: boolean;
|
|
175
|
-
line: number;
|
|
176
|
-
column: number;
|
|
177
|
-
};
|
|
178
|
-
export {};
|
package/lib/pug-parser/index.js
CHANGED
|
@@ -61,15 +61,27 @@ originalAST,
|
|
|
61
61
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
62
62
|
tokens, pug) {
|
|
63
63
|
const nodes = [];
|
|
64
|
+
if (!originalAST) {
|
|
65
|
+
return {
|
|
66
|
+
type: 'Block',
|
|
67
|
+
nodes: [],
|
|
68
|
+
line: 0,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
64
71
|
for (const node of originalAST.nodes) {
|
|
65
72
|
const line = node.line;
|
|
66
|
-
const column = node.column;
|
|
73
|
+
const column = node.column ?? 0;
|
|
67
74
|
const offsets = getOffsetsFromLines(pug);
|
|
68
75
|
const lineOffset = Math.max(offsets[line - 2] ?? 0, 0);
|
|
69
76
|
const offset = lineOffset + column - 1;
|
|
70
77
|
const { endLine, endColumn, endOffset } = getLocationFromToken(offset, line, column, tokens);
|
|
71
78
|
const raw = pug.slice(offset, endOffset);
|
|
72
79
|
switch (node.type) {
|
|
80
|
+
case 'Block': {
|
|
81
|
+
const block = optimizeAST(node, tokens, pug);
|
|
82
|
+
nodes.push(...block.nodes);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
73
85
|
case 'Tag': {
|
|
74
86
|
const attrs = getAttrs(node.attrs, tokens, offsets, pug);
|
|
75
87
|
const { endOffset, endLine, endColumn } = getEndAttributeLocation(node.name, offset, line, column, tokens, offsets);
|
|
@@ -87,7 +99,10 @@ tokens, pug) {
|
|
|
87
99
|
endColumn,
|
|
88
100
|
block,
|
|
89
101
|
attrs,
|
|
90
|
-
attributeBlocks: node.attributeBlocks,
|
|
102
|
+
attributeBlocks: node.attributeBlocks ?? [],
|
|
103
|
+
selfClosing: node.selfClosing,
|
|
104
|
+
isInline: node.isInline,
|
|
105
|
+
filename: node.filename ?? null,
|
|
91
106
|
};
|
|
92
107
|
nodes.push(tagNode);
|
|
93
108
|
continue;
|
|
@@ -105,6 +120,7 @@ tokens, pug) {
|
|
|
105
120
|
column,
|
|
106
121
|
endColumn,
|
|
107
122
|
block,
|
|
123
|
+
filename: node.filename ?? null,
|
|
108
124
|
};
|
|
109
125
|
nodes.push(condNode);
|
|
110
126
|
const altNodes = optimizeASTOfConditionalNode(node, tokens, pug, offsets, 0);
|
|
@@ -126,6 +142,7 @@ tokens, pug) {
|
|
|
126
142
|
column,
|
|
127
143
|
endColumn,
|
|
128
144
|
block,
|
|
145
|
+
filename: node.filename ?? null,
|
|
129
146
|
};
|
|
130
147
|
nodes.push(eachNode);
|
|
131
148
|
continue;
|
|
@@ -143,6 +160,7 @@ tokens, pug) {
|
|
|
143
160
|
column,
|
|
144
161
|
endColumn,
|
|
145
162
|
block,
|
|
163
|
+
filename: node.filename ?? null,
|
|
146
164
|
};
|
|
147
165
|
nodes.push(includeNode);
|
|
148
166
|
continue;
|
|
@@ -159,6 +177,7 @@ tokens, pug) {
|
|
|
159
177
|
column,
|
|
160
178
|
endColumn,
|
|
161
179
|
filters: node.filters,
|
|
180
|
+
filename: node.filename ?? null,
|
|
162
181
|
};
|
|
163
182
|
nodes.push(includeNode);
|
|
164
183
|
continue;
|
|
@@ -187,6 +206,8 @@ tokens, pug) {
|
|
|
187
206
|
endColumn,
|
|
188
207
|
block,
|
|
189
208
|
attrs,
|
|
209
|
+
attributeBlocks: node.attributeBlocks ?? [],
|
|
210
|
+
filename: node.filename ?? null,
|
|
190
211
|
};
|
|
191
212
|
nodes.push(mixinNode);
|
|
192
213
|
continue;
|
|
@@ -201,6 +222,7 @@ tokens, pug) {
|
|
|
201
222
|
endLine,
|
|
202
223
|
column,
|
|
203
224
|
endColumn,
|
|
225
|
+
filename: node.filename ?? null,
|
|
204
226
|
};
|
|
205
227
|
nodes.push(mixinNode);
|
|
206
228
|
continue;
|
|
@@ -235,6 +257,7 @@ tokens, pug) {
|
|
|
235
257
|
endLine,
|
|
236
258
|
column,
|
|
237
259
|
endColumn,
|
|
260
|
+
filename: node.filename ?? null,
|
|
238
261
|
};
|
|
239
262
|
nodes.push(commentNode);
|
|
240
263
|
continue;
|
|
@@ -253,11 +276,13 @@ tokens, pug) {
|
|
|
253
276
|
endLine,
|
|
254
277
|
column,
|
|
255
278
|
endColumn,
|
|
279
|
+
filename: node.filename ?? null,
|
|
256
280
|
};
|
|
257
281
|
nodes.push(commentNode);
|
|
258
282
|
continue;
|
|
259
283
|
}
|
|
260
284
|
case 'Code': {
|
|
285
|
+
const block = optimizeAST(node.block, tokens, pug);
|
|
261
286
|
const newNode = {
|
|
262
287
|
type: node.type,
|
|
263
288
|
raw,
|
|
@@ -271,6 +296,8 @@ tokens, pug) {
|
|
|
271
296
|
endLine,
|
|
272
297
|
column,
|
|
273
298
|
endColumn,
|
|
299
|
+
block,
|
|
300
|
+
filename: node.filename ?? null,
|
|
274
301
|
};
|
|
275
302
|
nodes.push(newNode);
|
|
276
303
|
continue;
|
|
@@ -279,7 +306,7 @@ tokens, pug) {
|
|
|
279
306
|
const pipelessText = getPipelessText(node, pug, tokens);
|
|
280
307
|
if (pipelessText) {
|
|
281
308
|
const textNode = {
|
|
282
|
-
|
|
309
|
+
...node,
|
|
283
310
|
...pipelessText,
|
|
284
311
|
};
|
|
285
312
|
nodes.push(textNode);
|
|
@@ -292,7 +319,6 @@ tokens, pug) {
|
|
|
292
319
|
case 'Doctype': {
|
|
293
320
|
const commentNode = {
|
|
294
321
|
type: node.type,
|
|
295
|
-
val: node.val,
|
|
296
322
|
raw,
|
|
297
323
|
offset,
|
|
298
324
|
endOffset,
|
|
@@ -300,6 +326,7 @@ tokens, pug) {
|
|
|
300
326
|
endLine,
|
|
301
327
|
column,
|
|
302
328
|
endColumn,
|
|
329
|
+
filename: node.filename ?? null,
|
|
303
330
|
};
|
|
304
331
|
nodes.push(commentNode);
|
|
305
332
|
continue;
|
|
@@ -318,6 +345,7 @@ tokens, pug) {
|
|
|
318
345
|
column,
|
|
319
346
|
endColumn,
|
|
320
347
|
block,
|
|
348
|
+
filename: node.filename ?? null,
|
|
321
349
|
};
|
|
322
350
|
nodes.push(caseNode);
|
|
323
351
|
continue;
|
|
@@ -339,14 +367,100 @@ tokens, pug) {
|
|
|
339
367
|
endColumn,
|
|
340
368
|
block,
|
|
341
369
|
attrs,
|
|
370
|
+
filename: node.filename ?? null,
|
|
342
371
|
};
|
|
343
372
|
nodes.push(filterNode);
|
|
344
373
|
continue;
|
|
345
374
|
}
|
|
375
|
+
case 'Extends': {
|
|
376
|
+
const optimizedNode = {
|
|
377
|
+
...node,
|
|
378
|
+
raw,
|
|
379
|
+
offset,
|
|
380
|
+
endOffset,
|
|
381
|
+
line,
|
|
382
|
+
endLine,
|
|
383
|
+
column,
|
|
384
|
+
endColumn,
|
|
385
|
+
};
|
|
386
|
+
nodes.push(optimizedNode);
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
case 'FileReference': {
|
|
390
|
+
const optimizedNode = {
|
|
391
|
+
...node,
|
|
392
|
+
raw,
|
|
393
|
+
offset,
|
|
394
|
+
endOffset,
|
|
395
|
+
line,
|
|
396
|
+
endLine,
|
|
397
|
+
column,
|
|
398
|
+
endColumn,
|
|
399
|
+
};
|
|
400
|
+
nodes.push(optimizedNode);
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
case 'IncludeFilter': {
|
|
404
|
+
const optimizedNode = {
|
|
405
|
+
...node,
|
|
406
|
+
raw,
|
|
407
|
+
offset,
|
|
408
|
+
endOffset,
|
|
409
|
+
line,
|
|
410
|
+
endLine,
|
|
411
|
+
column,
|
|
412
|
+
endColumn,
|
|
413
|
+
};
|
|
414
|
+
nodes.push(optimizedNode);
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
case 'InterpolatedTag': {
|
|
418
|
+
const block = optimizeAST(node.block, tokens, pug);
|
|
419
|
+
const optimizedNode = {
|
|
420
|
+
...node,
|
|
421
|
+
raw,
|
|
422
|
+
offset,
|
|
423
|
+
endOffset,
|
|
424
|
+
line,
|
|
425
|
+
endLine,
|
|
426
|
+
column,
|
|
427
|
+
endColumn,
|
|
428
|
+
block,
|
|
429
|
+
};
|
|
430
|
+
nodes.push(optimizedNode);
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
case 'While': {
|
|
434
|
+
const optimizedNode = {
|
|
435
|
+
...node,
|
|
436
|
+
raw,
|
|
437
|
+
offset,
|
|
438
|
+
endOffset,
|
|
439
|
+
line,
|
|
440
|
+
endLine,
|
|
441
|
+
column,
|
|
442
|
+
endColumn,
|
|
443
|
+
};
|
|
444
|
+
nodes.push(optimizedNode);
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
case 'YieldBlock': {
|
|
448
|
+
const optimizedNode = {
|
|
449
|
+
...node,
|
|
450
|
+
raw,
|
|
451
|
+
offset,
|
|
452
|
+
endOffset,
|
|
453
|
+
line,
|
|
454
|
+
endLine,
|
|
455
|
+
column,
|
|
456
|
+
endColumn,
|
|
457
|
+
};
|
|
458
|
+
nodes.push(optimizedNode);
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
346
461
|
default: {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
node.type}" node\n${JSON.stringify(node, null, 2)}`);
|
|
462
|
+
// @ts-expect-error
|
|
463
|
+
throw new Error(`Unsupported syntax: The "${node.type}" node\n${JSON.stringify(node, null, 2)}`);
|
|
350
464
|
}
|
|
351
465
|
}
|
|
352
466
|
}
|
|
@@ -373,7 +487,7 @@ tokens, pug, offsets, depth) {
|
|
|
373
487
|
if (tokenOfCurrentNode) {
|
|
374
488
|
// console.log(JSON.stringify(node, null, 2));
|
|
375
489
|
const lineOffset = Math.max(offsets[node.line - 2] ?? 0, 0);
|
|
376
|
-
const offset = lineOffset + node.column - 1;
|
|
490
|
+
const offset = lineOffset + (node.column ?? 0) - 1;
|
|
377
491
|
const length = tokenOfCurrentNode.loc.end.column - tokenOfCurrentNode.loc.start.column;
|
|
378
492
|
const endOffset = offset + length;
|
|
379
493
|
const raw = pug.slice(offset, endOffset);
|
|
@@ -389,6 +503,7 @@ tokens, pug, offsets, depth) {
|
|
|
389
503
|
column: tokenOfCurrentNode.loc.start.column,
|
|
390
504
|
endColumn: tokenOfCurrentNode.loc.end.column,
|
|
391
505
|
block,
|
|
506
|
+
filename: node.filename ?? null,
|
|
392
507
|
});
|
|
393
508
|
}
|
|
394
509
|
if ('alternate' in node && node.alternate) {
|
|
@@ -421,6 +536,7 @@ tokens, pug, offsets, depth) {
|
|
|
421
536
|
column: tokenOfCurrentNode.loc.start.column,
|
|
422
537
|
endColumn: tokenOfCurrentNode.loc.end.column,
|
|
423
538
|
block,
|
|
539
|
+
filename: node.filename ?? null,
|
|
424
540
|
});
|
|
425
541
|
break;
|
|
426
542
|
}
|
|
@@ -605,12 +721,14 @@ tokens, pug) {
|
|
|
605
721
|
result.push({
|
|
606
722
|
type: 'Text',
|
|
607
723
|
raw,
|
|
724
|
+
val: raw,
|
|
608
725
|
offset,
|
|
609
726
|
endOffset: rawLoc.endOffset,
|
|
610
727
|
line,
|
|
611
728
|
endLine,
|
|
612
729
|
column,
|
|
613
730
|
endColumn,
|
|
731
|
+
filename: null,
|
|
614
732
|
});
|
|
615
733
|
}
|
|
616
734
|
offset = rawLoc.endOffset;
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
export type AdditionalASTData = {
|
|
2
|
+
raw: string;
|
|
3
|
+
offset: number;
|
|
4
|
+
endOffset: number;
|
|
5
|
+
endLine: number;
|
|
6
|
+
endColumn: number;
|
|
7
|
+
};
|
|
8
|
+
export type ASTNode = ASTDoctype | ASTComment | ASTBlockComment | ASTText | ASTTag | ASTInterpolatedTag | ASTCode | ASTConditional | ASTCase | ASTWhen | ASTWhile | ASTEach | ASTMixin | ASTMixinBlock | ASTYieldBlock | ASTFileReference | ASTInclude | ASTRawInclude | ASTIncludeFilter | ASTExtends | ASTNamedBlock | ASTFilter;
|
|
9
|
+
export type ASTBlock = {
|
|
10
|
+
type: 'Block';
|
|
11
|
+
nodes: readonly ASTNode[];
|
|
12
|
+
line: number;
|
|
13
|
+
};
|
|
14
|
+
export type ASTDoctype = PugAST.Doctype & AdditionalASTData;
|
|
15
|
+
export type ASTComment = PugAST.Comments.Comment & AdditionalASTData;
|
|
16
|
+
export type ASTBlockComment = Omit<PugAST.Comments.BlockComment, 'block'> & {
|
|
17
|
+
block: ASTBlock | null;
|
|
18
|
+
} & AdditionalASTData;
|
|
19
|
+
export type ASTText = PugAST.Text & AdditionalASTData;
|
|
20
|
+
export type ASTTag = Omit<PugAST.Tag, 'attrs' | 'block'> & {
|
|
21
|
+
attrs: readonly ASTAttr[];
|
|
22
|
+
block: ASTBlock | null;
|
|
23
|
+
} & AdditionalASTData;
|
|
24
|
+
export type ASTInterpolatedTag = Omit<PugAST.InterpolatedTag, 'block'> & {
|
|
25
|
+
block: ASTBlock | null;
|
|
26
|
+
} & AdditionalASTData;
|
|
27
|
+
export type ASTCode = Omit<PugAST.Code, 'block'> & {
|
|
28
|
+
block: ASTBlock | null;
|
|
29
|
+
} & AdditionalASTData;
|
|
30
|
+
export type ASTConditional = Omit<PugAST.CodeHelpers.Conditional, 'consequent' | 'alternate'> & {
|
|
31
|
+
block: ASTBlock | null;
|
|
32
|
+
} & AdditionalASTData;
|
|
33
|
+
export type ASTCase = Omit<PugAST.CodeHelpers.CaseWhen.Case, 'block'> & {
|
|
34
|
+
block: ASTBlock | null;
|
|
35
|
+
} & AdditionalASTData;
|
|
36
|
+
export type ASTWhen = Omit<PugAST.CodeHelpers.CaseWhen.When, 'block'> & {
|
|
37
|
+
block: ASTBlock | null;
|
|
38
|
+
} & AdditionalASTData;
|
|
39
|
+
export type ASTWhile = PugAST.While & AdditionalASTData;
|
|
40
|
+
export type ASTEach = Omit<PugAST.Each, 'block' | 'alternate'> & {
|
|
41
|
+
block: ASTBlock | null;
|
|
42
|
+
} & AdditionalASTData;
|
|
43
|
+
export type ASTMixin = Omit<PugAST.Mixin, 'block'> & {
|
|
44
|
+
block: ASTBlock | null;
|
|
45
|
+
} & AdditionalASTData;
|
|
46
|
+
export type ASTMixinBlock = PugAST.MixinBlock & AdditionalASTData;
|
|
47
|
+
export type ASTYieldBlock = PugAST.YieldBlock & AdditionalASTData;
|
|
48
|
+
export type ASTFileReference = PugAST.FileOperations.FileReference & AdditionalASTData;
|
|
49
|
+
export type ASTInclude = Omit<PugAST.FileOperations.Include, 'block'> & {
|
|
50
|
+
block: ASTBlock | null;
|
|
51
|
+
} & AdditionalASTData;
|
|
52
|
+
export type ASTRawInclude = PugAST.FileOperations.RawInclude & AdditionalASTData;
|
|
53
|
+
export type ASTIncludeFilter = PugAST.FileOperations.IncludeFilter & AdditionalASTData;
|
|
54
|
+
export type ASTExtends = PugAST.FileOperations.Extends & AdditionalASTData;
|
|
55
|
+
export type ASTNamedBlock = Omit<PugAST.FileOperations.NamedBlock, 'nodes'> & {
|
|
56
|
+
nodes: readonly ASTNode[];
|
|
57
|
+
} & AdditionalASTData;
|
|
58
|
+
export type ASTFilter = Omit<PugAST.Filter, 'block'> & {
|
|
59
|
+
block: ASTBlock | null;
|
|
60
|
+
} & AdditionalASTData;
|
|
61
|
+
export type ASTAttr = PugAST.AbstractNodeTypes.Attribute & AdditionalASTData;
|
|
62
|
+
export declare namespace PugAST {
|
|
63
|
+
/**
|
|
64
|
+
* Node objects
|
|
65
|
+
*
|
|
66
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#node-objects
|
|
67
|
+
*/
|
|
68
|
+
interface _Node {
|
|
69
|
+
type: string;
|
|
70
|
+
line: number;
|
|
71
|
+
column: number | null;
|
|
72
|
+
filename: string | null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Block
|
|
76
|
+
*
|
|
77
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#blocks
|
|
78
|
+
*/
|
|
79
|
+
export interface Block extends _Node {
|
|
80
|
+
type: 'Block';
|
|
81
|
+
nodes: Node[];
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Abstract Node Types
|
|
85
|
+
*
|
|
86
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#abstract-node-types
|
|
87
|
+
*/
|
|
88
|
+
export namespace AbstractNodeTypes {
|
|
89
|
+
interface AttributedNode extends _Node {
|
|
90
|
+
attrs: Attribute[];
|
|
91
|
+
attributeBlocks: AttributeBlock[];
|
|
92
|
+
}
|
|
93
|
+
interface BlockNode extends _Node {
|
|
94
|
+
block: Block | null;
|
|
95
|
+
}
|
|
96
|
+
interface ExpressionNode extends _Node {
|
|
97
|
+
expr: JavaScriptExpression;
|
|
98
|
+
}
|
|
99
|
+
interface PlaceholderNode extends _Node {
|
|
100
|
+
}
|
|
101
|
+
interface ValueNode extends _Node {
|
|
102
|
+
val: string;
|
|
103
|
+
}
|
|
104
|
+
interface Attribute {
|
|
105
|
+
name: string;
|
|
106
|
+
val: JavaScriptExpression;
|
|
107
|
+
mustEscape: boolean;
|
|
108
|
+
line: number;
|
|
109
|
+
column: number;
|
|
110
|
+
}
|
|
111
|
+
type JavaScriptExpression = string & {};
|
|
112
|
+
type JavaScriptIdentifier = string & {};
|
|
113
|
+
interface AttributeBlock {
|
|
114
|
+
type: 'AttributeBlock';
|
|
115
|
+
val: JavaScriptExpression;
|
|
116
|
+
line: number;
|
|
117
|
+
column: number;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Doctypes
|
|
122
|
+
*
|
|
123
|
+
* https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#doctypes
|
|
124
|
+
*/
|
|
125
|
+
export interface Doctype extends _Node {
|
|
126
|
+
type: 'Doctype';
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Comments
|
|
130
|
+
*
|
|
131
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#comments
|
|
132
|
+
*/
|
|
133
|
+
export namespace Comments {
|
|
134
|
+
interface CommonComment extends AbstractNodeTypes.ValueNode {
|
|
135
|
+
buffer: boolean;
|
|
136
|
+
}
|
|
137
|
+
export interface Comment extends CommonComment {
|
|
138
|
+
type: 'Comment';
|
|
139
|
+
}
|
|
140
|
+
export interface BlockComment extends AbstractNodeTypes.BlockNode, CommonComment {
|
|
141
|
+
type: 'BlockComment';
|
|
142
|
+
}
|
|
143
|
+
export {};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Text
|
|
147
|
+
*
|
|
148
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#text
|
|
149
|
+
*/
|
|
150
|
+
export interface Text extends AbstractNodeTypes.ValueNode {
|
|
151
|
+
type: 'Text';
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Tag
|
|
155
|
+
*
|
|
156
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#tag
|
|
157
|
+
*/
|
|
158
|
+
export interface CommonTag extends AbstractNodeTypes.AttributedNode, AbstractNodeTypes.BlockNode {
|
|
159
|
+
selfClosing: boolean;
|
|
160
|
+
isInline: boolean;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Regular Tag
|
|
164
|
+
*
|
|
165
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#regular-tag
|
|
166
|
+
*/
|
|
167
|
+
export interface Tag extends CommonTag {
|
|
168
|
+
type: 'Tag';
|
|
169
|
+
name: string;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Interpolated Tag
|
|
173
|
+
*
|
|
174
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#interpolated-tag
|
|
175
|
+
*/
|
|
176
|
+
export interface InterpolatedTag extends CommonTag, AbstractNodeTypes.ExpressionNode {
|
|
177
|
+
type: 'InterpolatedTag';
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Code
|
|
181
|
+
*
|
|
182
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#code
|
|
183
|
+
*/
|
|
184
|
+
export interface Code extends AbstractNodeTypes.BlockNode, AbstractNodeTypes.ValueNode {
|
|
185
|
+
type: 'Code';
|
|
186
|
+
buffer: boolean;
|
|
187
|
+
mustEscape: boolean;
|
|
188
|
+
isInline: boolean;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Code Helpers
|
|
192
|
+
*
|
|
193
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#code-helpers
|
|
194
|
+
*/
|
|
195
|
+
export namespace CodeHelpers {
|
|
196
|
+
/**
|
|
197
|
+
* Conditional
|
|
198
|
+
*
|
|
199
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#conditional
|
|
200
|
+
*/
|
|
201
|
+
interface Conditional extends _Node {
|
|
202
|
+
type: 'Conditional';
|
|
203
|
+
test: AbstractNodeTypes.JavaScriptExpression;
|
|
204
|
+
consequent: Block;
|
|
205
|
+
alternate: Conditional | Block | null;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Case/When
|
|
209
|
+
*
|
|
210
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#casewhen
|
|
211
|
+
*/
|
|
212
|
+
namespace CaseWhen {
|
|
213
|
+
export interface Case extends AbstractNodeTypes.BlockNode, AbstractNodeTypes.ExpressionNode {
|
|
214
|
+
type: 'Case';
|
|
215
|
+
block: WhenBlock;
|
|
216
|
+
}
|
|
217
|
+
interface WhenBlock extends Block {
|
|
218
|
+
}
|
|
219
|
+
export interface When extends AbstractNodeTypes.BlockNode, AbstractNodeTypes.ExpressionNode {
|
|
220
|
+
type: 'When';
|
|
221
|
+
expr: AbstractNodeTypes.JavaScriptExpression | 'default';
|
|
222
|
+
}
|
|
223
|
+
export {};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* While
|
|
228
|
+
*
|
|
229
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#while
|
|
230
|
+
*/
|
|
231
|
+
export interface While extends _Node {
|
|
232
|
+
type: 'While';
|
|
233
|
+
test: AbstractNodeTypes.JavaScriptExpression;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Each
|
|
237
|
+
*
|
|
238
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#each
|
|
239
|
+
*/
|
|
240
|
+
export interface Each extends AbstractNodeTypes.BlockNode {
|
|
241
|
+
type: 'Each';
|
|
242
|
+
obj: AbstractNodeTypes.JavaScriptExpression;
|
|
243
|
+
val: AbstractNodeTypes.JavaScriptIdentifier;
|
|
244
|
+
key: AbstractNodeTypes.JavaScriptIdentifier | null;
|
|
245
|
+
alternate: Block | null;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Mixin
|
|
249
|
+
*
|
|
250
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#mixin
|
|
251
|
+
*/
|
|
252
|
+
export interface Mixin extends AbstractNodeTypes.AttributedNode, AbstractNodeTypes.BlockNode {
|
|
253
|
+
type: 'Mixin';
|
|
254
|
+
name: AbstractNodeTypes.JavaScriptIdentifier;
|
|
255
|
+
call: boolean;
|
|
256
|
+
args: string;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* MixinBlock
|
|
260
|
+
*
|
|
261
|
+
* @see
|
|
262
|
+
*/
|
|
263
|
+
export interface MixinBlock extends AbstractNodeTypes.PlaceholderNode {
|
|
264
|
+
type: 'MixinBlock';
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Yield
|
|
268
|
+
*
|
|
269
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#yield
|
|
270
|
+
*/
|
|
271
|
+
export interface YieldBlock extends AbstractNodeTypes.PlaceholderNode {
|
|
272
|
+
type: 'YieldBlock';
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* File Operations
|
|
276
|
+
*
|
|
277
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#file-operations
|
|
278
|
+
*/
|
|
279
|
+
export namespace FileOperations {
|
|
280
|
+
/**
|
|
281
|
+
* FileReference
|
|
282
|
+
*
|
|
283
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#filereference
|
|
284
|
+
*/
|
|
285
|
+
export interface FileReference extends _Node {
|
|
286
|
+
type: 'FileReference';
|
|
287
|
+
path: string;
|
|
288
|
+
}
|
|
289
|
+
interface FileNode extends _Node {
|
|
290
|
+
file: FileReference;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Pug Include
|
|
294
|
+
*
|
|
295
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#pug-include
|
|
296
|
+
*/
|
|
297
|
+
export interface Include extends AbstractNodeTypes.BlockNode, FileNode {
|
|
298
|
+
type: 'Include';
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Raw Include
|
|
302
|
+
*
|
|
303
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#raw-include
|
|
304
|
+
*/
|
|
305
|
+
export interface RawInclude extends FileNode {
|
|
306
|
+
type: 'RawInclude';
|
|
307
|
+
filters: IncludeFilter[];
|
|
308
|
+
}
|
|
309
|
+
export interface IncludeFilter extends FilterNode {
|
|
310
|
+
type: 'IncludeFilter';
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Extends/NamedBlock
|
|
314
|
+
*
|
|
315
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#extendsnamedblock
|
|
316
|
+
*/
|
|
317
|
+
export interface Extends extends FileNode {
|
|
318
|
+
type: 'Extends';
|
|
319
|
+
}
|
|
320
|
+
export interface NamedBlock extends AbstractNodeTypes.PlaceholderNode {
|
|
321
|
+
type: 'NamedBlock';
|
|
322
|
+
name: string;
|
|
323
|
+
mode: 'replace' | 'append' | 'prepend';
|
|
324
|
+
nodes: Node[];
|
|
325
|
+
}
|
|
326
|
+
export {};
|
|
327
|
+
}
|
|
328
|
+
interface FilterNode extends _Node {
|
|
329
|
+
name: string;
|
|
330
|
+
attrs: AbstractNodeTypes.Attribute[];
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Filters
|
|
334
|
+
*
|
|
335
|
+
* @see https://github.com/pugjs/pug-ast-spec/blob/master/parser.md#filter
|
|
336
|
+
*/
|
|
337
|
+
export interface Filter extends FilterNode, AbstractNodeTypes.BlockNode {
|
|
338
|
+
type: 'Filter';
|
|
339
|
+
}
|
|
340
|
+
export type Node = Block | Doctype | Comments.Comment | Comments.BlockComment | Text | Tag | InterpolatedTag | Code | CodeHelpers.Conditional | CodeHelpers.CaseWhen.Case | CodeHelpers.CaseWhen.When | While | Each | Mixin | MixinBlock | YieldBlock | FileOperations.FileReference | FileOperations.Include | FileOperations.RawInclude | FileOperations.IncludeFilter | FileOperations.Extends | FileOperations.NamedBlock | Filter;
|
|
341
|
+
export {};
|
|
342
|
+
}
|
package/lib/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/pug-parser",
|
|
3
|
-
"version": "4.6.
|
|
3
|
+
"version": "4.6.16",
|
|
4
4
|
"description": "Pug parser for markuplint",
|
|
5
5
|
"repository": "git@github.com:markuplint/markuplint.git",
|
|
6
6
|
"author": "Yusuke Hirao <yusukehirao@me.com>",
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
"clean": "tsc --build --clean"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@markuplint/html-parser": "4.6.
|
|
25
|
+
"@markuplint/html-parser": "4.6.16",
|
|
26
26
|
"@markuplint/ml-ast": "4.4.9",
|
|
27
|
-
"@markuplint/parser-utils": "4.8.
|
|
27
|
+
"@markuplint/parser-utils": "4.8.4",
|
|
28
28
|
"pug-lexer": "5.0.1",
|
|
29
29
|
"pug-parser": "6.0.0"
|
|
30
30
|
},
|
|
31
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "f9f6c415b8a3a231aac56181892bb393aeb8ae1a"
|
|
32
32
|
}
|