@markuplint/pug-parser 3.12.0 → 4.0.0-alpha.10
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/index.d.ts +1 -2
- package/lib/index.js +1 -6
- package/lib/parser.d.ts +29 -0
- package/lib/parser.js +162 -0
- package/lib/pug-parser/index.d.ts +97 -111
- package/lib/pug-parser/index.js +19 -31
- package/lib/utils/get-offset-from-line-and-col.js +2 -6
- package/package.json +12 -8
- package/lib/attr-tokenizer.d.ts +0 -3
- package/lib/attr-tokenizer.js +0 -141
- package/lib/parse.d.ts +0 -2
- package/lib/parse.js +0 -250
- package/test/index.spec.js +0 -585
- package/test/pug-parser/index.spec.js +0 -1752
- package/test/utils/get-offset-from-line-and-col.spec.js +0 -26
package/LICENSE
CHANGED
package/lib/index.d.ts
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export declare const endTag = 'never';
|
|
1
|
+
export { parser } from './parser.js';
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.endTag = exports.parse = void 0;
|
|
4
|
-
var parse_1 = require("./parse");
|
|
5
|
-
Object.defineProperty(exports, "parse", { enumerable: true, get: function () { return parse_1.parse; } });
|
|
6
|
-
exports.endTag = 'never';
|
|
1
|
+
export { parser } from './parser.js';
|
package/lib/parser.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ASTNode } from './pug-parser/index.js';
|
|
2
|
+
import type { MLASTAttr, MLASTNodeTreeItem, MLASTParentNode } from '@markuplint/ml-ast';
|
|
3
|
+
import type { ChildToken, Token } from '@markuplint/parser-utils';
|
|
4
|
+
import { ParserError, Parser } from '@markuplint/parser-utils';
|
|
5
|
+
declare class PugParser extends Parser<ASTNode> {
|
|
6
|
+
constructor();
|
|
7
|
+
tokenize(): {
|
|
8
|
+
ast: ASTNode[];
|
|
9
|
+
isFragment: boolean;
|
|
10
|
+
};
|
|
11
|
+
parseError(error: any): ParserError;
|
|
12
|
+
nodeize(originNode: ASTNode, parentNode: MLASTParentNode | null, depth: number): readonly MLASTNodeTreeItem[];
|
|
13
|
+
afterFlattenNodes(nodeList: readonly MLASTNodeTreeItem[]): readonly MLASTNodeTreeItem[];
|
|
14
|
+
visitElement(token: ChildToken & {
|
|
15
|
+
readonly nodeName: string;
|
|
16
|
+
readonly namespace: string;
|
|
17
|
+
}, childNodes: readonly ASTNode[], options: {
|
|
18
|
+
readonly overwriteProps: {
|
|
19
|
+
readonly attributes: readonly MLASTAttr[];
|
|
20
|
+
};
|
|
21
|
+
}): MLASTNodeTreeItem[];
|
|
22
|
+
visitAttr(token: Token): (import("@markuplint/ml-ast").MLASTHTMLAttr & {
|
|
23
|
+
__rightText?: string | undefined;
|
|
24
|
+
}) | (import("@markuplint/ml-ast").MLASTSpreadAttr & {
|
|
25
|
+
__rightText?: string | undefined;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
export declare const parser: PugParser;
|
|
29
|
+
export {};
|
package/lib/parser.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { getNamespace, parser as htmlParser } from '@markuplint/html-parser';
|
|
2
|
+
import { ParserError, Parser, AttrState, removeQuote, scriptParser } from '@markuplint/parser-utils';
|
|
3
|
+
import { pugParse } from './pug-parser/index.js';
|
|
4
|
+
class PugParser extends Parser {
|
|
5
|
+
constructor() {
|
|
6
|
+
super({
|
|
7
|
+
endTagType: 'never',
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
tokenize() {
|
|
11
|
+
return {
|
|
12
|
+
ast: pugParse(this.rawCode).nodes,
|
|
13
|
+
isFragment: true,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
parseError(error) {
|
|
17
|
+
if (error instanceof Error && 'msg' in error && 'line' in error && 'column' in error && 'src' in error) {
|
|
18
|
+
return new ParserError(error.msg, {
|
|
19
|
+
line: error.line,
|
|
20
|
+
col: error.column,
|
|
21
|
+
raw: error.src,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return super.parseError(error);
|
|
25
|
+
}
|
|
26
|
+
nodeize(
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
28
|
+
originNode, parentNode, depth) {
|
|
29
|
+
const parentNamespace = parentNode && 'namespace' in parentNode ? parentNode.namespace : 'http://www.w3.org/1999/xhtml';
|
|
30
|
+
const token = this.sliceFragment(originNode.offset, originNode.endOffset);
|
|
31
|
+
switch (originNode.type) {
|
|
32
|
+
case 'Doctype': {
|
|
33
|
+
return this.visitDoctype({
|
|
34
|
+
...token,
|
|
35
|
+
depth,
|
|
36
|
+
parentNode,
|
|
37
|
+
name: originNode.val ?? '',
|
|
38
|
+
publicId: '',
|
|
39
|
+
systemId: '',
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
case 'Text': {
|
|
43
|
+
if (originNode.raw.trim() === '') {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
const htmlDoc = htmlParser.parse(originNode.raw, {
|
|
47
|
+
offsetOffset: originNode.offset,
|
|
48
|
+
offsetLine: originNode.line,
|
|
49
|
+
offsetColumn: originNode.column,
|
|
50
|
+
depth,
|
|
51
|
+
});
|
|
52
|
+
return htmlDoc.nodeList;
|
|
53
|
+
}
|
|
54
|
+
case 'Comment': {
|
|
55
|
+
return this.visitComment({
|
|
56
|
+
...token,
|
|
57
|
+
depth,
|
|
58
|
+
parentNode,
|
|
59
|
+
}, {
|
|
60
|
+
isBogus: false,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
case 'Tag': {
|
|
64
|
+
const namespace = getNamespace(originNode.name, parentNamespace);
|
|
65
|
+
return this.visitElement({
|
|
66
|
+
...token,
|
|
67
|
+
depth,
|
|
68
|
+
parentNode,
|
|
69
|
+
nodeName: originNode.name,
|
|
70
|
+
namespace,
|
|
71
|
+
}, originNode.block.nodes, {
|
|
72
|
+
overwriteProps: {
|
|
73
|
+
attributes: originNode.attrs.map(attr => {
|
|
74
|
+
const token = this.sliceFragment(attr.offset, attr.endOffset);
|
|
75
|
+
return this.visitAttr(token);
|
|
76
|
+
}),
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
default: {
|
|
81
|
+
return this.visitPsBlock({
|
|
82
|
+
...token,
|
|
83
|
+
depth,
|
|
84
|
+
parentNode,
|
|
85
|
+
nodeName: originNode.type,
|
|
86
|
+
}, 'block' in originNode && originNode.block ? originNode.block.nodes : []);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
afterFlattenNodes(nodeList) {
|
|
91
|
+
return super.afterFlattenNodes(nodeList, {
|
|
92
|
+
exposeInvalidNode: false,
|
|
93
|
+
exposeWhiteSpace: false,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
visitElement(token,
|
|
97
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
98
|
+
childNodes, options) {
|
|
99
|
+
const startTag = {
|
|
100
|
+
...token,
|
|
101
|
+
...this.createToken(token),
|
|
102
|
+
...options.overwriteProps,
|
|
103
|
+
type: 'starttag',
|
|
104
|
+
elementType: this.detectElementType(token.nodeName),
|
|
105
|
+
childNodes: [],
|
|
106
|
+
pairNode: null,
|
|
107
|
+
tagOpenChar: '',
|
|
108
|
+
tagCloseChar: '',
|
|
109
|
+
isGhost: false,
|
|
110
|
+
};
|
|
111
|
+
const siblings = this.visitChildren(childNodes, startTag);
|
|
112
|
+
return [startTag, ...siblings];
|
|
113
|
+
}
|
|
114
|
+
visitAttr(token) {
|
|
115
|
+
if (token.raw[0] === '#' || token.raw[0] === '.') {
|
|
116
|
+
const attr = super.visitAttr(token, {
|
|
117
|
+
startState: AttrState.BeforeValue,
|
|
118
|
+
quoteSet: [],
|
|
119
|
+
quoteInValueChars: [],
|
|
120
|
+
endOfUnquotedValueChars: [],
|
|
121
|
+
});
|
|
122
|
+
if (attr.type === 'spread') {
|
|
123
|
+
return attr;
|
|
124
|
+
}
|
|
125
|
+
this.updateAttr(attr, {
|
|
126
|
+
potentialName: token.raw[0] === '#' ? 'id' : 'class',
|
|
127
|
+
potentialValue: attr.value.raw.slice(1),
|
|
128
|
+
isDuplicatable: attr.potentialName === 'class',
|
|
129
|
+
});
|
|
130
|
+
return attr;
|
|
131
|
+
}
|
|
132
|
+
const attr = super.visitAttr(token, {
|
|
133
|
+
quoteSet: [],
|
|
134
|
+
quoteInValueChars: [],
|
|
135
|
+
endOfUnquotedValueChars: [],
|
|
136
|
+
});
|
|
137
|
+
if (attr.type === 'spread') {
|
|
138
|
+
return attr;
|
|
139
|
+
}
|
|
140
|
+
if (attr.name.raw.toLowerCase() === 'class') {
|
|
141
|
+
this.updateAttr(attr, { isDuplicatable: true });
|
|
142
|
+
}
|
|
143
|
+
const valueCodeTokens = scriptParser(attr.value.raw.trim());
|
|
144
|
+
if (valueCodeTokens.length === 1) {
|
|
145
|
+
const token = valueCodeTokens[0];
|
|
146
|
+
if (token.type === 'Numeric' || token.type === 'Boolean') {
|
|
147
|
+
this.updateAttr(attr, { potentialValue: token.value });
|
|
148
|
+
}
|
|
149
|
+
else if (token.type === 'String' || token.type === 'Template') {
|
|
150
|
+
this.updateAttr(attr, { potentialValue: removeQuote(token.value) });
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
this.updateAttr(attr, { isDynamicValue: true });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
this.updateAttr(attr, { isDynamicValue: true });
|
|
158
|
+
}
|
|
159
|
+
return attr;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
export const parser = new PugParser();
|
|
@@ -1,21 +1,7 @@
|
|
|
1
1
|
export declare function pugParse(pug: string): ASTBlock;
|
|
2
2
|
export type ASTBlock = PugAST<ASTNode>;
|
|
3
|
-
export type ASTNode =
|
|
4
|
-
|
|
5
|
-
| ASTTextNode
|
|
6
|
-
| ASTCodeNode
|
|
7
|
-
| ASTComment
|
|
8
|
-
| ASTDoctype
|
|
9
|
-
| ASTIncludeNode
|
|
10
|
-
| ASTMixinNode
|
|
11
|
-
| ASTMixinSlotNode
|
|
12
|
-
| ASTFilterNode
|
|
13
|
-
| ASTEachNode
|
|
14
|
-
| ASTConditionalNode
|
|
15
|
-
| ASTCaseNode
|
|
16
|
-
| ASTCaseWhenNode;
|
|
17
|
-
export type ASTTagNode = Omit<PugASTTagNode<ASTAttr, ASTBlock>, 'attributeBlocks' | 'selfClosing' | 'isInline'> &
|
|
18
|
-
AdditionalASTData;
|
|
3
|
+
export type ASTNode = ASTTagNode | ASTTextNode | ASTCodeNode | ASTComment | ASTDoctype | ASTIncludeNode | ASTMixinNode | ASTMixinSlotNode | ASTFilterNode | ASTEachNode | ASTConditionalNode | ASTCaseNode | ASTCaseWhenNode;
|
|
4
|
+
export type ASTTagNode = Omit<PugASTTagNode<ASTAttr, ASTBlock>, 'attributeBlocks' | 'selfClosing' | 'isInline'> & AdditionalASTData;
|
|
19
5
|
export type ASTTextNode = Omit<PugASTTextNode, 'val'> & AdditionalASTData;
|
|
20
6
|
export type ASTCodeNode = PugASTCodeNode & AdditionalASTData;
|
|
21
7
|
export type ASTComment = PugASTCommentNode & AdditionalASTData;
|
|
@@ -26,135 +12,135 @@ export type ASTMixinSlotNode = PugASTMixinSlotNode & AdditionalASTData;
|
|
|
26
12
|
export type ASTFilterNode = PugASTFilterNode<ASTAttr, ASTBlock> & AdditionalASTData;
|
|
27
13
|
export type ASTEachNode = PugASTEachNode<ASTBlock> & AdditionalASTData;
|
|
28
14
|
export type ASTConditionalNode = Omit<PugASTConditionalNode<ASTBlock>, 'consequent' | 'alternate'> & {
|
|
29
|
-
|
|
15
|
+
block: ASTBlock;
|
|
30
16
|
} & AdditionalASTData;
|
|
31
17
|
export type ASTCaseNode = PugASTCaseNode<ASTBlock> & AdditionalASTData;
|
|
32
18
|
export type ASTCaseWhenNode = PugASTCaseWhenNode<ASTBlock> & AdditionalASTData;
|
|
33
19
|
export type ASTAttr = PugASTAttr & AdditionalASTData;
|
|
34
20
|
type AdditionalASTData = {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
21
|
+
raw: string;
|
|
22
|
+
offset: number;
|
|
23
|
+
endOffset: number;
|
|
24
|
+
endLine: number;
|
|
25
|
+
endColumn: number;
|
|
40
26
|
};
|
|
41
27
|
interface PugAST<N> {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
28
|
+
type: 'Block';
|
|
29
|
+
nodes: N[];
|
|
30
|
+
line: number;
|
|
45
31
|
}
|
|
46
32
|
type PugASTTagNode<A, B> = {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
33
|
+
type: 'Tag';
|
|
34
|
+
name: string;
|
|
35
|
+
selfClosing: boolean;
|
|
36
|
+
attrs: A[];
|
|
37
|
+
attributeBlocks: never[];
|
|
38
|
+
isInline: boolean;
|
|
39
|
+
line: number;
|
|
40
|
+
column: number;
|
|
41
|
+
block: B;
|
|
56
42
|
};
|
|
57
43
|
type PugASTTextNode = {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
44
|
+
type: 'Text';
|
|
45
|
+
val: string;
|
|
46
|
+
isHtml?: true;
|
|
47
|
+
line: number;
|
|
48
|
+
column: number;
|
|
63
49
|
};
|
|
64
50
|
type PugASTCodeNode = {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
51
|
+
type: 'Code';
|
|
52
|
+
val: string;
|
|
53
|
+
buffer: boolean;
|
|
54
|
+
mustEscape: boolean;
|
|
55
|
+
isInline: boolean;
|
|
56
|
+
line: number;
|
|
57
|
+
column: number;
|
|
72
58
|
};
|
|
73
59
|
type PugASTCommentNode = {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
60
|
+
type: 'Comment';
|
|
61
|
+
val: string;
|
|
62
|
+
buffer: boolean;
|
|
63
|
+
line: number;
|
|
64
|
+
column: number;
|
|
79
65
|
};
|
|
80
66
|
type PugASTDoctypeNode = {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
67
|
+
type: 'Doctype';
|
|
68
|
+
val: string;
|
|
69
|
+
line: number;
|
|
70
|
+
column: number;
|
|
85
71
|
};
|
|
86
72
|
type PugASTIncludeNode<B> = {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
73
|
+
type: 'Include';
|
|
74
|
+
file: {
|
|
75
|
+
type: 'FileReference';
|
|
76
|
+
path: string;
|
|
77
|
+
line: number;
|
|
78
|
+
column: number;
|
|
79
|
+
};
|
|
80
|
+
block: B;
|
|
81
|
+
line: number;
|
|
82
|
+
column: number;
|
|
97
83
|
};
|
|
98
84
|
type PugASTEachNode<B> = {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
85
|
+
type: 'Each';
|
|
86
|
+
obj: string;
|
|
87
|
+
val: string;
|
|
88
|
+
key: string | null;
|
|
89
|
+
block: B;
|
|
90
|
+
line: number;
|
|
91
|
+
column: number;
|
|
106
92
|
};
|
|
107
93
|
type PugASTMixinNode<A, B> = {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
94
|
+
type: 'Mixin';
|
|
95
|
+
name: string;
|
|
96
|
+
args: string;
|
|
97
|
+
call: boolean;
|
|
98
|
+
block: B | null;
|
|
99
|
+
attrs?: A[];
|
|
100
|
+
attributeBlocks: never[];
|
|
101
|
+
line: number;
|
|
102
|
+
column: number;
|
|
117
103
|
};
|
|
118
104
|
type PugASTMixinSlotNode = {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
105
|
+
type: 'MixinBlock';
|
|
106
|
+
line: number;
|
|
107
|
+
column: number;
|
|
122
108
|
};
|
|
123
109
|
type PugASTFilterNode<A, B> = {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
110
|
+
type: 'Filter';
|
|
111
|
+
name: string;
|
|
112
|
+
block: B;
|
|
113
|
+
attrs: A[];
|
|
114
|
+
line: number;
|
|
115
|
+
column: number;
|
|
130
116
|
};
|
|
131
117
|
type PugASTConditionalNode<B> = {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
118
|
+
type: 'Conditional';
|
|
119
|
+
test: string;
|
|
120
|
+
consequent: B;
|
|
121
|
+
alternate?: B | PugASTConditionalNode<B>;
|
|
122
|
+
line: number;
|
|
123
|
+
column: number;
|
|
138
124
|
};
|
|
139
125
|
type PugASTCaseNode<B> = {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
126
|
+
type: 'Case';
|
|
127
|
+
expr: string;
|
|
128
|
+
block: B;
|
|
129
|
+
line: number;
|
|
130
|
+
column: number;
|
|
145
131
|
};
|
|
146
132
|
type PugASTCaseWhenNode<B> = {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
133
|
+
type: 'When';
|
|
134
|
+
expr: string;
|
|
135
|
+
block: B;
|
|
136
|
+
line: number;
|
|
137
|
+
column: number;
|
|
152
138
|
};
|
|
153
139
|
type PugASTAttr = {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
140
|
+
name: string;
|
|
141
|
+
val: string | true;
|
|
142
|
+
mustEscape: boolean;
|
|
143
|
+
line: number;
|
|
144
|
+
column: number;
|
|
159
145
|
};
|
|
160
146
|
export {};
|
package/lib/pug-parser/index.js
CHANGED
|
@@ -1,24 +1,17 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.pugParse = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
1
|
// @ts-ignore
|
|
6
|
-
|
|
2
|
+
import lexer from 'pug-lexer';
|
|
7
3
|
// @ts-ignore
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function pugParse(pug) {
|
|
11
|
-
const lexOrigin = (
|
|
4
|
+
import parser from 'pug-parser';
|
|
5
|
+
import { getOffsetFromLineAndCol } from '../utils/get-offset-from-line-and-col.js';
|
|
6
|
+
export function pugParse(pug) {
|
|
7
|
+
const lexOrigin = lexer(pug);
|
|
12
8
|
const lex = JSON.parse(JSON.stringify(lexOrigin));
|
|
13
|
-
const originAst = (
|
|
14
|
-
// console.log(lex);
|
|
15
|
-
// console.log(JSON.stringify(originAst, null, 2));
|
|
9
|
+
const originAst = parser(lexOrigin);
|
|
16
10
|
const ast = optimizeAST(originAst, lex, pug);
|
|
17
11
|
return ast;
|
|
18
12
|
}
|
|
19
|
-
exports.pugParse = pugParse;
|
|
20
13
|
function getOffsetsFromLines(pug) {
|
|
21
|
-
const lines = pug.split(/\n/
|
|
14
|
+
const lines = pug.split(/\n/);
|
|
22
15
|
let chars = 0;
|
|
23
16
|
const result = lines.map(line => {
|
|
24
17
|
chars += line.length + 1;
|
|
@@ -29,10 +22,9 @@ function getOffsetsFromLines(pug) {
|
|
|
29
22
|
function mergeTextNode(
|
|
30
23
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
31
24
|
nodes, pug) {
|
|
32
|
-
var _a;
|
|
33
25
|
const baseNodes = [];
|
|
34
26
|
for (const node of nodes) {
|
|
35
|
-
const prevNode =
|
|
27
|
+
const prevNode = baseNodes.at(-1) ?? null;
|
|
36
28
|
if (prevNode && prevNode.type === 'Text' && node.type === 'Text') {
|
|
37
29
|
prevNode.raw = pug.slice(prevNode.offset, node.endOffset);
|
|
38
30
|
prevNode.endColumn = node.endColumn;
|
|
@@ -55,13 +47,12 @@ function optimizeAST(
|
|
|
55
47
|
originalAST,
|
|
56
48
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
57
49
|
tokens, pug) {
|
|
58
|
-
var _a;
|
|
59
50
|
const nodes = [];
|
|
60
51
|
for (const node of originalAST.nodes) {
|
|
61
52
|
const line = node.line;
|
|
62
53
|
const column = node.column;
|
|
63
54
|
const offsets = getOffsetsFromLines(pug);
|
|
64
|
-
const lineOffset = Math.max(
|
|
55
|
+
const lineOffset = Math.max(offsets[line - 2] ?? 0, 0);
|
|
65
56
|
const offset = lineOffset + column - 1;
|
|
66
57
|
const { endLine, endColumn, endOffset } = getLocationFromToken(offset, line, column, tokens);
|
|
67
58
|
const raw = pug.slice(offset, endOffset);
|
|
@@ -299,8 +290,9 @@ tokens, pug) {
|
|
|
299
290
|
continue;
|
|
300
291
|
}
|
|
301
292
|
default: {
|
|
293
|
+
throw new Error(`Unsupported syntax: The "${
|
|
302
294
|
// @ts-ignore
|
|
303
|
-
|
|
295
|
+
node.type}" node\n${JSON.stringify(node, null, 2)}`);
|
|
304
296
|
}
|
|
305
297
|
}
|
|
306
298
|
}
|
|
@@ -316,7 +308,6 @@ function optimizeASTOfConditionalNode(
|
|
|
316
308
|
node,
|
|
317
309
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
318
310
|
tokens, pug, offsets, depth) {
|
|
319
|
-
var _a, _b;
|
|
320
311
|
const altNodes = [];
|
|
321
312
|
let tokenOfCurrentNode = null;
|
|
322
313
|
for (const token of tokens) {
|
|
@@ -327,7 +318,7 @@ tokens, pug, offsets, depth) {
|
|
|
327
318
|
}
|
|
328
319
|
if (tokenOfCurrentNode) {
|
|
329
320
|
// console.log(JSON.stringify(node, null, 2));
|
|
330
|
-
const lineOffset = Math.max(
|
|
321
|
+
const lineOffset = Math.max(offsets[node.line - 2] ?? 0, 0);
|
|
331
322
|
const offset = lineOffset + node.column - 1;
|
|
332
323
|
const length = tokenOfCurrentNode.loc.end.column - tokenOfCurrentNode.loc.start.column;
|
|
333
324
|
const endOffset = offset + length;
|
|
@@ -359,7 +350,7 @@ tokens, pug, offsets, depth) {
|
|
|
359
350
|
if (!tokenOfCurrentNode) {
|
|
360
351
|
return [];
|
|
361
352
|
}
|
|
362
|
-
const lineOffset = Math.max(
|
|
353
|
+
const lineOffset = Math.max(offsets[tokenOfCurrentNode.loc.start.line - 2] ?? 0, 0);
|
|
363
354
|
const offset = lineOffset + tokenOfCurrentNode.loc.start.column - 1;
|
|
364
355
|
const length = tokenOfCurrentNode.loc.end.column - tokenOfCurrentNode.loc.start.column;
|
|
365
356
|
const endOffset = offset + length;
|
|
@@ -390,7 +381,7 @@ tokens, pug, offsets, depth) {
|
|
|
390
381
|
function getLocationFromToken(offset, line, column,
|
|
391
382
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
392
383
|
tokens, tokenType) {
|
|
393
|
-
const tokenTypes = typeof tokenType === 'string' ? (tokenType
|
|
384
|
+
const tokenTypes = typeof tokenType === 'string' ? (tokenType === '' ? null : [tokenType]) : tokenType ?? null;
|
|
394
385
|
let tokenOfCurrentNode = null;
|
|
395
386
|
for (const token of tokens) {
|
|
396
387
|
if ((tokenTypes == null || tokenTypes.includes(token.type)) &&
|
|
@@ -416,10 +407,9 @@ function getAttrs(
|
|
|
416
407
|
originalAttrs,
|
|
417
408
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
418
409
|
tokens, offsets, pug) {
|
|
419
|
-
var _a;
|
|
420
410
|
const attrs = [];
|
|
421
411
|
for (const attr of originalAttrs) {
|
|
422
|
-
const attrLineOffset =
|
|
412
|
+
const attrLineOffset = offsets[attr.line - 2] ?? 0;
|
|
423
413
|
const attrOffset = attrLineOffset + attr.column - 1;
|
|
424
414
|
let tokenOfCurrentAttr = null;
|
|
425
415
|
for (const token of tokens) {
|
|
@@ -452,7 +442,6 @@ tokens, offsets, pug) {
|
|
|
452
442
|
function getEndAttributeLocation(nodeName, offset, line, column,
|
|
453
443
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
454
444
|
tokens, offsets) {
|
|
455
|
-
var _a;
|
|
456
445
|
let beforeNewlineToken = null;
|
|
457
446
|
for (const token of tokens) {
|
|
458
447
|
// Searching token after the tag node.
|
|
@@ -463,7 +452,7 @@ tokens, offsets) {
|
|
|
463
452
|
token.type !== 'end-attributes' &&
|
|
464
453
|
token.type !== 'id' &&
|
|
465
454
|
token.type !== 'class') {
|
|
466
|
-
const endAttrLineOffset = Math.max(
|
|
455
|
+
const endAttrLineOffset = Math.max(offsets[beforeNewlineToken.loc.end.line - 2] ?? 0, 0);
|
|
467
456
|
const endAttrOffset = endAttrLineOffset + beforeNewlineToken.loc.end.column - 1;
|
|
468
457
|
return {
|
|
469
458
|
endOffset: endAttrOffset,
|
|
@@ -500,8 +489,8 @@ tokens) {
|
|
|
500
489
|
if (startPipelessText.loc.start.line < node.line && node.line < endPipelessText.loc.start.line) {
|
|
501
490
|
const { line, column } = startPipelessText.loc.start;
|
|
502
491
|
const { line: endLine, column: endColumn } = endPipelessText.loc.end;
|
|
503
|
-
const offset =
|
|
504
|
-
const endOffset =
|
|
492
|
+
const offset = getOffsetFromLineAndCol(pug, line, column);
|
|
493
|
+
const endOffset = getOffsetFromLineAndCol(pug, endLine, endColumn);
|
|
505
494
|
const raw = pug.slice(offset, endOffset);
|
|
506
495
|
return {
|
|
507
496
|
raw,
|
|
@@ -518,7 +507,6 @@ tokens) {
|
|
|
518
507
|
function getRawTextAndLocationEnd(val, offset, line, column,
|
|
519
508
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
520
509
|
tokens, offsets, pug) {
|
|
521
|
-
var _a;
|
|
522
510
|
let beforeNewlineToken = null;
|
|
523
511
|
for (const token of tokens) {
|
|
524
512
|
// Searching token after the text.
|
|
@@ -528,7 +516,7 @@ tokens, offsets, pug) {
|
|
|
528
516
|
token.type !== 'text-html' &&
|
|
529
517
|
token.type !== 'indent' &&
|
|
530
518
|
token.type !== 'outdent') {
|
|
531
|
-
const endAttrLineOffset = Math.max(
|
|
519
|
+
const endAttrLineOffset = Math.max(offsets[beforeNewlineToken.loc.end.line - 2] ?? 0, 0);
|
|
532
520
|
const endAttrOffset = endAttrLineOffset + beforeNewlineToken.loc.end.column - 1;
|
|
533
521
|
return {
|
|
534
522
|
endOffset: endAttrOffset,
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getOffsetFromLineAndCol = void 0;
|
|
4
|
-
function getOffsetFromLineAndCol(str, line, col) {
|
|
1
|
+
export function getOffsetFromLineAndCol(str, line, col) {
|
|
5
2
|
const lines = str.split('\n').slice(0, line);
|
|
6
3
|
const lastLine = lines.pop();
|
|
7
4
|
if (lastLine) {
|
|
8
|
-
lines.push(lastLine.
|
|
5
|
+
lines.push([...lastLine].slice(0, col).join(''));
|
|
9
6
|
}
|
|
10
7
|
return lines.join('\n').length;
|
|
11
8
|
}
|
|
12
|
-
exports.getOffsetFromLineAndCol = getOffsetFromLineAndCol;
|