shopware-twig-parser 0.1.0 → 0.3.0
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/dist/commonjs/index.d.ts +45 -4
- package/dist/commonjs/index.d.ts.map +1 -1
- package/dist/commonjs/index.js +295 -5
- package/dist/commonjs/index.js.map +1 -1
- package/dist/esm/index.d.ts +45 -4
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +295 -5
- package/dist/esm/index.js.map +1 -1
- package/package.json +2 -2
package/dist/commonjs/index.d.ts
CHANGED
|
@@ -3,13 +3,27 @@ type Tree = {
|
|
|
3
3
|
};
|
|
4
4
|
type TemplateNode = {
|
|
5
5
|
type: "template";
|
|
6
|
-
children: TwigStatementDirectiveNode[];
|
|
6
|
+
children: (TwigStatementDirectiveNode | HtmlElementNode | ContentNode | HtmlDoctypeNode | HtmlNamedEntityNode | HtmlNumericEntityNode)[];
|
|
7
7
|
};
|
|
8
8
|
type TwigStatementDirectiveNode = {
|
|
9
9
|
type: "twig_statement_directive";
|
|
10
|
-
tag
|
|
11
|
-
variable
|
|
12
|
-
|
|
10
|
+
tag?: TwigTagNode;
|
|
11
|
+
variable?: TwigVariableNode;
|
|
12
|
+
function?: TwigFunctionNode;
|
|
13
|
+
condition?: TwigConditionNode;
|
|
14
|
+
children?: (TwigStatementDirectiveNode | ContentNode | HtmlElementNode | HtmlDoctypeNode | HtmlNamedEntityNode | HtmlNumericEntityNode)[];
|
|
15
|
+
};
|
|
16
|
+
type TwigConditionNode = {
|
|
17
|
+
type: "twig_condition";
|
|
18
|
+
expression: TwigExpressionNode;
|
|
19
|
+
};
|
|
20
|
+
type TwigExpressionNode = {
|
|
21
|
+
type: "twig_expression";
|
|
22
|
+
content: string;
|
|
23
|
+
};
|
|
24
|
+
type ContentNode = {
|
|
25
|
+
type: "content";
|
|
26
|
+
content: string;
|
|
13
27
|
};
|
|
14
28
|
type TwigTagNode = {
|
|
15
29
|
type: "twig_tag";
|
|
@@ -19,6 +33,33 @@ type TwigVariableNode = {
|
|
|
19
33
|
type: "twig_variable";
|
|
20
34
|
content: string;
|
|
21
35
|
};
|
|
36
|
+
type TwigFunctionNode = {
|
|
37
|
+
type: "twig_function";
|
|
38
|
+
name: string;
|
|
39
|
+
};
|
|
40
|
+
type HtmlAttributeNode = {
|
|
41
|
+
type: "html_attribute";
|
|
42
|
+
name: string;
|
|
43
|
+
value?: string;
|
|
44
|
+
};
|
|
45
|
+
type HtmlElementNode = {
|
|
46
|
+
type: "html_element";
|
|
47
|
+
name: string;
|
|
48
|
+
attributes?: HtmlAttributeNode[];
|
|
49
|
+
children: (HtmlElementNode | ContentNode | HtmlNamedEntityNode | HtmlNumericEntityNode)[];
|
|
50
|
+
void?: boolean;
|
|
51
|
+
};
|
|
52
|
+
type HtmlDoctypeNode = {
|
|
53
|
+
type: "doctype";
|
|
54
|
+
};
|
|
55
|
+
type HtmlNamedEntityNode = {
|
|
56
|
+
type: "html_named_entity";
|
|
57
|
+
content: string;
|
|
58
|
+
};
|
|
59
|
+
type HtmlNumericEntityNode = {
|
|
60
|
+
type: "html_numeric_entity";
|
|
61
|
+
content: string;
|
|
62
|
+
};
|
|
22
63
|
export declare function parse(content: string): Tree;
|
|
23
64
|
export {};
|
|
24
65
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAGA,KAAK,IAAI,GAAG;IACV,QAAQ,EAAE,YAAY,CAAC;CACxB,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,0BAA0B,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAGA,KAAK,IAAI,GAAG;IACV,QAAQ,EAAE,YAAY,CAAC;CACxB,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,CACN,0BAA0B,GAC1B,eAAe,GACf,WAAW,GACX,eAAe,GACf,mBAAmB,GACnB,qBAAqB,CACxB,EAAE,CAAC;CACL,CAAC;AAEF,KAAK,0BAA0B,GAAG;IAChC,IAAI,EAAE,0BAA0B,CAAC;IACjC,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,QAAQ,CAAC,EAAE,CACP,0BAA0B,GAC1B,WAAW,GACX,eAAe,GACf,eAAe,GACf,mBAAmB,GACnB,qBAAqB,CACxB,EAAE,CAAC;CACL,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,IAAI,EAAE,gBAAgB,CAAC;IACvB,UAAU,EAAE,kBAAkB,CAAC;CAChC,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,iBAAiB,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACjC,QAAQ,EAAE,CACN,eAAe,GACf,WAAW,GACX,mBAAmB,GACnB,qBAAqB,CACxB,EAAE,CAAC;IACJ,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,IAAI,EAAE,SAAS,CAAC;CACjB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,IAAI,EAAE,mBAAmB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,qBAAqB,GAAG;IAC3B,IAAI,EAAE,qBAAqB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAMF,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAoe3C"}
|
package/dist/commonjs/index.js
CHANGED
|
@@ -13,9 +13,24 @@ function parse(content) {
|
|
|
13
13
|
const tree = parser.parse(content);
|
|
14
14
|
function convertNode(node) {
|
|
15
15
|
if (node.type === "statement_directive") {
|
|
16
|
+
// Check for if_statement
|
|
17
|
+
const ifStatement = node.children.find((child) => child.type === "if_statement");
|
|
18
|
+
if (ifStatement) {
|
|
19
|
+
const conditionalNode = ifStatement.children.find((child) => child.type === "conditional");
|
|
20
|
+
const variableNode = ifStatement.children.find((child) => child.type === "variable");
|
|
21
|
+
if (conditionalNode && conditionalNode.text === "if" && variableNode) {
|
|
22
|
+
return {
|
|
23
|
+
type: "if",
|
|
24
|
+
expression: variableNode.text,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Check for tag_statement
|
|
16
29
|
const tagStatement = node.children.find((child) => child.type === "tag_statement");
|
|
30
|
+
const functionCall = node.children.find((child) => child.type === "function_call");
|
|
17
31
|
if (tagStatement) {
|
|
18
32
|
const tagNode = tagStatement.children.find((child) => child.type === "tag");
|
|
33
|
+
const conditionalNode = tagStatement.children.find((child) => child.type === "conditional");
|
|
19
34
|
const variableNode = tagStatement.children.find((child) => child.type === "variable");
|
|
20
35
|
if (tagNode && tagNode.text === "block" && variableNode) {
|
|
21
36
|
return {
|
|
@@ -28,16 +43,158 @@ function parse(content) {
|
|
|
28
43
|
type: "endblock",
|
|
29
44
|
};
|
|
30
45
|
}
|
|
46
|
+
else if (conditionalNode && conditionalNode.text === "endif") {
|
|
47
|
+
return {
|
|
48
|
+
type: "endif",
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else if (functionCall) {
|
|
53
|
+
const functionIdentifier = functionCall.children.find((child) => child.type === "function_identifier");
|
|
54
|
+
if (functionIdentifier) {
|
|
55
|
+
return {
|
|
56
|
+
type: "function",
|
|
57
|
+
functionName: functionIdentifier.text,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
31
60
|
}
|
|
32
61
|
}
|
|
33
62
|
return null;
|
|
34
63
|
}
|
|
35
64
|
// First pass: convert all nodes to intermediate format
|
|
36
65
|
const rawNodes = [];
|
|
66
|
+
// Also collect content nodes
|
|
67
|
+
const allNodes = [];
|
|
68
|
+
function convertHtmlEntity(node) {
|
|
69
|
+
if (node.type === "html_entity") {
|
|
70
|
+
const entityText = node.text;
|
|
71
|
+
// Check if it's a numeric entity (starts with &#)
|
|
72
|
+
if (entityText.startsWith("&#")) {
|
|
73
|
+
return {
|
|
74
|
+
type: "html_numeric_entity",
|
|
75
|
+
content: entityText,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
else if (entityText.startsWith("&")) {
|
|
79
|
+
return {
|
|
80
|
+
type: "html_named_entity",
|
|
81
|
+
content: entityText,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
function convertHtmlElement(node) {
|
|
88
|
+
if (node.type === "html_element") {
|
|
89
|
+
// Check for self-closing tag first
|
|
90
|
+
const selfClosingTag = node.children.find((child) => child.type === "html_self_closing_tag");
|
|
91
|
+
// Find the start tag to get the element name
|
|
92
|
+
const startTag = node.children.find((child) => child.type === "html_start_tag");
|
|
93
|
+
// Use self-closing tag if available, otherwise start tag
|
|
94
|
+
const tagToUse = selfClosingTag || startTag;
|
|
95
|
+
if (!tagToUse)
|
|
96
|
+
return null;
|
|
97
|
+
const tagName = tagToUse.children.find((child) => child.type === "html_tag_name");
|
|
98
|
+
if (!tagName)
|
|
99
|
+
return null;
|
|
100
|
+
// Check if this is a void element (no end tag and not self-closing)
|
|
101
|
+
const hasEndTag = node.children.some((child) => child.type === "html_end_tag");
|
|
102
|
+
const isVoid = !hasEndTag;
|
|
103
|
+
// Parse attributes from the tag (either self-closing or start tag)
|
|
104
|
+
const attributes = [];
|
|
105
|
+
const attributeNodes = tagToUse.children.filter((child) => child.type === "html_attribute");
|
|
106
|
+
for (const attrNode of attributeNodes) {
|
|
107
|
+
const nameNode = attrNode.children.find((child) => child.type === "html_attribute_name");
|
|
108
|
+
if (!nameNode)
|
|
109
|
+
continue;
|
|
110
|
+
const valueNode = attrNode.children.find((child) => child.type === "html_attribute_value");
|
|
111
|
+
const quotedValueNode = attrNode.children.find((child) => child.type === "html_quoted_attribute_value");
|
|
112
|
+
let value;
|
|
113
|
+
if (quotedValueNode) {
|
|
114
|
+
// For quoted values, find the inner html_attribute_value
|
|
115
|
+
const innerValueNode = quotedValueNode.children.find((child) => child.type === "html_attribute_value");
|
|
116
|
+
value = innerValueNode ? innerValueNode.text : undefined;
|
|
117
|
+
}
|
|
118
|
+
else if (valueNode) {
|
|
119
|
+
value = valueNode.text;
|
|
120
|
+
}
|
|
121
|
+
const attribute = {
|
|
122
|
+
type: "html_attribute",
|
|
123
|
+
name: nameNode.text,
|
|
124
|
+
};
|
|
125
|
+
// Only include value property if there's actually a value
|
|
126
|
+
if (value !== undefined) {
|
|
127
|
+
attribute.value = value;
|
|
128
|
+
}
|
|
129
|
+
attributes.push(attribute);
|
|
130
|
+
}
|
|
131
|
+
const elementChildren = [];
|
|
132
|
+
// Process all children that are not start/end tags
|
|
133
|
+
for (const child of node.children) {
|
|
134
|
+
if (child.type === "content") {
|
|
135
|
+
elementChildren.push({
|
|
136
|
+
type: "content",
|
|
137
|
+
content: child.text,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
else if (child.type === "html_element") {
|
|
141
|
+
const nestedElement = convertHtmlElement(child);
|
|
142
|
+
if (nestedElement) {
|
|
143
|
+
elementChildren.push(nestedElement);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else if (child.type === "html_entity") {
|
|
147
|
+
const entityNode = convertHtmlEntity(child);
|
|
148
|
+
if (entityNode) {
|
|
149
|
+
elementChildren.push(entityNode);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const result = {
|
|
154
|
+
type: "html_element",
|
|
155
|
+
name: tagName.text,
|
|
156
|
+
children: elementChildren,
|
|
157
|
+
};
|
|
158
|
+
if (attributes.length > 0) {
|
|
159
|
+
result.attributes = attributes;
|
|
160
|
+
}
|
|
161
|
+
if (isVoid) {
|
|
162
|
+
result.void = true;
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
37
168
|
for (const child of tree.rootNode.children) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
169
|
+
if (child.type === "content") {
|
|
170
|
+
allNodes.push({
|
|
171
|
+
type: "content",
|
|
172
|
+
content: child.text,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
else if (child.type === "html_element") {
|
|
176
|
+
const htmlElement = convertHtmlElement(child);
|
|
177
|
+
if (htmlElement) {
|
|
178
|
+
allNodes.push(htmlElement);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else if (child.type === "html_doctype") {
|
|
182
|
+
allNodes.push({
|
|
183
|
+
type: "doctype",
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
else if (child.type === "html_entity") {
|
|
187
|
+
const entityNode = convertHtmlEntity(child);
|
|
188
|
+
if (entityNode) {
|
|
189
|
+
allNodes.push(entityNode);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
const converted = convertNode(child);
|
|
194
|
+
if (converted) {
|
|
195
|
+
rawNodes.push(converted);
|
|
196
|
+
allNodes.push(converted);
|
|
197
|
+
}
|
|
41
198
|
}
|
|
42
199
|
}
|
|
43
200
|
// Second pass: build nested structure using a stack
|
|
@@ -60,7 +217,10 @@ function parse(content) {
|
|
|
60
217
|
};
|
|
61
218
|
if (stack.length > 0) {
|
|
62
219
|
// Add to the current parent's children
|
|
63
|
-
stack[stack.length - 1]
|
|
220
|
+
const parent = stack[stack.length - 1];
|
|
221
|
+
if (parent && parent.children) {
|
|
222
|
+
parent.children.push(blockNode);
|
|
223
|
+
}
|
|
64
224
|
}
|
|
65
225
|
else {
|
|
66
226
|
// Add to root level
|
|
@@ -73,10 +233,140 @@ function parse(content) {
|
|
|
73
233
|
// Pop from stack when we encounter an endblock
|
|
74
234
|
stack.pop();
|
|
75
235
|
}
|
|
236
|
+
else if (node.type === "if") {
|
|
237
|
+
const ifNode = {
|
|
238
|
+
type: "twig_statement_directive",
|
|
239
|
+
condition: {
|
|
240
|
+
type: "twig_condition",
|
|
241
|
+
expression: {
|
|
242
|
+
type: "twig_expression",
|
|
243
|
+
content: node.expression,
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
children: [],
|
|
247
|
+
};
|
|
248
|
+
if (stack.length > 0) {
|
|
249
|
+
// Add to the current parent's children
|
|
250
|
+
const parent = stack[stack.length - 1];
|
|
251
|
+
if (parent && parent.children) {
|
|
252
|
+
parent.children.push(ifNode);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
// Add to root level
|
|
257
|
+
result.push(ifNode);
|
|
258
|
+
}
|
|
259
|
+
// Push to stack for nesting
|
|
260
|
+
stack.push(ifNode);
|
|
261
|
+
}
|
|
262
|
+
else if (node.type === "endif") {
|
|
263
|
+
// Pop from stack when we encounter an endif
|
|
264
|
+
stack.pop();
|
|
265
|
+
}
|
|
266
|
+
else if (node.type === "function") {
|
|
267
|
+
const functionNode = {
|
|
268
|
+
type: "twig_statement_directive",
|
|
269
|
+
function: {
|
|
270
|
+
type: "twig_function",
|
|
271
|
+
name: node.functionName,
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
if (stack.length > 0) {
|
|
275
|
+
// Add to the current parent's children
|
|
276
|
+
const parent = stack[stack.length - 1];
|
|
277
|
+
if (parent && parent.children) {
|
|
278
|
+
parent.children.push(functionNode);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
// Add to root level
|
|
283
|
+
result.push(functionNode);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else if (node.type === "content") {
|
|
287
|
+
const contentNode = {
|
|
288
|
+
type: "content",
|
|
289
|
+
content: node.content,
|
|
290
|
+
};
|
|
291
|
+
if (stack.length > 0) {
|
|
292
|
+
// Add to the current parent's children
|
|
293
|
+
const parent = stack[stack.length - 1];
|
|
294
|
+
if (parent && parent.children) {
|
|
295
|
+
parent.children.push(contentNode);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
// Content at root level - this shouldn't happen in well-formed templates
|
|
300
|
+
// but we'll handle it gracefully
|
|
301
|
+
result.push({
|
|
302
|
+
type: "twig_statement_directive",
|
|
303
|
+
children: [contentNode],
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
else if (node.type === "html_element" && "name" in node) {
|
|
308
|
+
// HTML elements are already processed and can be added directly
|
|
309
|
+
const htmlNode = node;
|
|
310
|
+
if (stack.length > 0) {
|
|
311
|
+
// Add to the current parent's children
|
|
312
|
+
const parent = stack[stack.length - 1];
|
|
313
|
+
if (parent && parent.children) {
|
|
314
|
+
parent.children.push(htmlNode);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
// Add to root level
|
|
319
|
+
result.push(htmlNode);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
else if (node.type === "doctype") {
|
|
323
|
+
const doctypeNode = {
|
|
324
|
+
type: "doctype",
|
|
325
|
+
};
|
|
326
|
+
if (stack.length > 0) {
|
|
327
|
+
// Add to the current parent's children
|
|
328
|
+
const parent = stack[stack.length - 1];
|
|
329
|
+
if (parent && parent.children) {
|
|
330
|
+
parent.children.push(doctypeNode);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
// Add to root level
|
|
335
|
+
result.push(doctypeNode);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
else if (node.type === "html_named_entity" && "content" in node) {
|
|
339
|
+
const entityNode = node;
|
|
340
|
+
if (stack.length > 0) {
|
|
341
|
+
// Add to the current parent's children
|
|
342
|
+
const parent = stack[stack.length - 1];
|
|
343
|
+
if (parent && parent.children) {
|
|
344
|
+
parent.children.push(entityNode);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
// Add to root level
|
|
349
|
+
result.push(entityNode);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
else if (node.type === "html_numeric_entity" && "content" in node) {
|
|
353
|
+
const entityNode = node;
|
|
354
|
+
if (stack.length > 0) {
|
|
355
|
+
// Add to the current parent's children
|
|
356
|
+
const parent = stack[stack.length - 1];
|
|
357
|
+
if (parent && parent.children) {
|
|
358
|
+
parent.children.push(entityNode);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
// Add to root level
|
|
363
|
+
result.push(entityNode);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
76
366
|
}
|
|
77
367
|
return result;
|
|
78
368
|
}
|
|
79
|
-
const children = buildNestedStructure(
|
|
369
|
+
const children = buildNestedStructure(allNodes);
|
|
80
370
|
return {
|
|
81
371
|
rootNode: {
|
|
82
372
|
type: "template",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;AAiCA,sBA2FC;AA5HD,8DAAiC;AACjC,0FAAqD;AA4BrD,MAAM,MAAM,GAAG,IAAI,qBAAM,EAAE,CAAC;AAC5B,mBAAmB;AACnB,MAAM,CAAC,WAAW,CAAC,mCAAY,CAAC,CAAC;AAEjC,SAAgB,KAAK,CAAC,OAAe;IACnC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEnC,SAAS,WAAW,CAClB,IAAS;QAET,IAAI,IAAI,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;YACxC,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CACrC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,eAAe,CAC/C,CAAC;YACF,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,IAAI,CACxC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,CACrC,CAAC;gBACF,MAAM,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAC,IAAI,CAC7C,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,UAAU,CAC1C,CAAC;gBAEF,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,YAAY,EAAE,CAAC;oBACxD,OAAO;wBACL,IAAI,EAAE,OAAO;wBACb,IAAI,EAAE,YAAY,CAAC,IAAI;qBACxB,CAAC;gBACJ,CAAC;qBAAM,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;oBAClD,OAAO;wBACL,IAAI,EAAE,UAAU;qBACjB,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uDAAuD;IACvD,MAAM,QAAQ,GAAoD,EAAE,CAAC;IACrE,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,SAAS,EAAE,CAAC;YACd,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,oDAAoD;IACpD,SAAS,oBAAoB,CAC3B,KAAsD;QAEtD,MAAM,MAAM,GAAiC,EAAE,CAAC;QAChD,MAAM,KAAK,GAAiC,EAAE,CAAC;QAE/C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC1B,MAAM,SAAS,GAA+B;oBAC5C,GAAG,EAAE;wBACH,IAAI,EAAE,UAAU;wBAChB,IAAI,EAAE,OAAO;qBACd;oBACD,IAAI,EAAE,0BAA0B;oBAChC,QAAQ,EAAE;wBACR,IAAI,EAAE,eAAe;wBACrB,OAAO,EAAE,IAAI,CAAC,IAAK;qBACpB;oBACD,QAAQ,EAAE,EAAE;iBACb,CAAC;gBAEF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,uCAAuC;oBACvC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACpD,CAAC;qBAAM,CAAC;oBACN,oBAAoB;oBACpB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACzB,CAAC;gBAED,4BAA4B;gBAC5B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,CAAC;iBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBACpC,+CAA+C;gBAC/C,KAAK,CAAC,GAAG,EAAE,CAAC;YACd,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,QAAQ,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAEhD,OAAO;QACL,QAAQ,EAAE;YACR,IAAI,EAAE,UAAU;YAChB,QAAQ;SACT;KACF,CAAC;AACJ,CAAC","sourcesContent":["import Parser from \"tree-sitter\";\nimport ShopwareTwig from \"tree-sitter-shopware-twig\";\n\ntype Tree = {\n rootNode: TemplateNode;\n};\n\ntype TemplateNode = {\n type: \"template\";\n children: TwigStatementDirectiveNode[];\n};\n\ntype TwigStatementDirectiveNode = {\n type: \"twig_statement_directive\";\n tag: TwigTagNode;\n variable: TwigVariableNode;\n children: TwigStatementDirectiveNode[];\n};\n\ntype TwigTagNode = {\n type: \"twig_tag\";\n name: string;\n};\n\ntype TwigVariableNode = {\n type: \"twig_variable\";\n content: string;\n};\n\nconst parser = new Parser();\n// @ts-expect-error\nparser.setLanguage(ShopwareTwig);\n\nexport function parse(content: string): Tree {\n const tree = parser.parse(content);\n\n function convertNode(\n node: any\n ): { type: \"block\" | \"endblock\"; name?: string } | null {\n if (node.type === \"statement_directive\") {\n const tagStatement = node.children.find(\n (child: any) => child.type === \"tag_statement\"\n );\n if (tagStatement) {\n const tagNode = tagStatement.children.find(\n (child: any) => child.type === \"tag\"\n );\n const variableNode = tagStatement.children.find(\n (child: any) => child.type === \"variable\"\n );\n\n if (tagNode && tagNode.text === \"block\" && variableNode) {\n return {\n type: \"block\",\n name: variableNode.text,\n };\n } else if (tagNode && tagNode.text === \"endblock\") {\n return {\n type: \"endblock\",\n };\n }\n }\n }\n return null;\n }\n\n // First pass: convert all nodes to intermediate format\n const rawNodes: { type: \"block\" | \"endblock\"; name?: string }[] = [];\n for (const child of tree.rootNode.children) {\n const converted = convertNode(child);\n if (converted) {\n rawNodes.push(converted);\n }\n }\n\n // Second pass: build nested structure using a stack\n function buildNestedStructure(\n nodes: { type: \"block\" | \"endblock\"; name?: string }[]\n ): TwigStatementDirectiveNode[] {\n const result: TwigStatementDirectiveNode[] = [];\n const stack: TwigStatementDirectiveNode[] = [];\n\n for (const node of nodes) {\n if (node.type === \"block\") {\n const blockNode: TwigStatementDirectiveNode = {\n tag: {\n type: \"twig_tag\",\n name: \"block\",\n },\n type: \"twig_statement_directive\",\n variable: {\n type: \"twig_variable\",\n content: node.name!,\n },\n children: [],\n };\n\n if (stack.length > 0) {\n // Add to the current parent's children\n stack[stack.length - 1]?.children.push(blockNode);\n } else {\n // Add to root level\n result.push(blockNode);\n }\n\n // Push to stack for nesting\n stack.push(blockNode);\n } else if (node.type === \"endblock\") {\n // Pop from stack when we encounter an endblock\n stack.pop();\n }\n }\n\n return result;\n }\n\n const children = buildNestedStructure(rawNodes);\n\n return {\n rootNode: {\n type: \"template\",\n children,\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import Parser from \"tree-sitter\";\nimport ShopwareTwig from \"tree-sitter-shopware-twig\";\n\ntype Tree = {\n rootNode: TemplateNode;\n};\n\ntype TemplateNode = {\n type: \"template\";\n children: (\n | TwigStatementDirectiveNode\n | HtmlElementNode\n | ContentNode\n | HtmlDoctypeNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n )[];\n};\n\ntype TwigStatementDirectiveNode = {\n type: \"twig_statement_directive\";\n tag?: TwigTagNode;\n variable?: TwigVariableNode;\n function?: TwigFunctionNode;\n condition?: TwigConditionNode;\n children?: (\n | TwigStatementDirectiveNode\n | ContentNode\n | HtmlElementNode\n | HtmlDoctypeNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n )[];\n};\n\ntype TwigConditionNode = {\n type: \"twig_condition\";\n expression: TwigExpressionNode;\n};\n\ntype TwigExpressionNode = {\n type: \"twig_expression\";\n content: string;\n};\n\ntype ContentNode = {\n type: \"content\";\n content: string;\n};\n\ntype TwigTagNode = {\n type: \"twig_tag\";\n name: string;\n};\n\ntype TwigVariableNode = {\n type: \"twig_variable\";\n content: string;\n};\n\ntype TwigFunctionNode = {\n type: \"twig_function\";\n name: string;\n};\n\ntype HtmlAttributeNode = {\n type: \"html_attribute\";\n name: string;\n value?: string;\n};\n\ntype HtmlElementNode = {\n type: \"html_element\";\n name: string;\n attributes?: HtmlAttributeNode[];\n children: (\n | HtmlElementNode\n | ContentNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n )[];\n void?: boolean;\n};\n\ntype HtmlDoctypeNode = {\n type: \"doctype\";\n};\n\ntype HtmlNamedEntityNode = {\n type: \"html_named_entity\";\n content: string;\n};\n\ntype HtmlNumericEntityNode = {\n type: \"html_numeric_entity\";\n content: string;\n};\n\nconst parser = new Parser();\n// @ts-expect-error\nparser.setLanguage(ShopwareTwig);\n\nexport function parse(content: string): Tree {\n const tree = parser.parse(content);\n\n function convertNode(node: any): {\n type: \"block\" | \"endblock\" | \"function\" | \"if\" | \"endif\";\n name?: string;\n functionName?: string;\n expression?: string;\n } | null {\n if (node.type === \"statement_directive\") {\n // Check for if_statement\n const ifStatement = node.children.find(\n (child: any) => child.type === \"if_statement\"\n );\n if (ifStatement) {\n const conditionalNode = ifStatement.children.find(\n (child: any) => child.type === \"conditional\"\n );\n const variableNode = ifStatement.children.find(\n (child: any) => child.type === \"variable\"\n );\n\n if (conditionalNode && conditionalNode.text === \"if\" && variableNode) {\n return {\n type: \"if\",\n expression: variableNode.text,\n };\n }\n }\n\n // Check for tag_statement\n const tagStatement = node.children.find(\n (child: any) => child.type === \"tag_statement\"\n );\n const functionCall = node.children.find(\n (child: any) => child.type === \"function_call\"\n );\n\n if (tagStatement) {\n const tagNode = tagStatement.children.find(\n (child: any) => child.type === \"tag\"\n );\n const conditionalNode = tagStatement.children.find(\n (child: any) => child.type === \"conditional\"\n );\n const variableNode = tagStatement.children.find(\n (child: any) => child.type === \"variable\"\n );\n\n if (tagNode && tagNode.text === \"block\" && variableNode) {\n return {\n type: \"block\",\n name: variableNode.text,\n };\n } else if (tagNode && tagNode.text === \"endblock\") {\n return {\n type: \"endblock\",\n };\n } else if (conditionalNode && conditionalNode.text === \"endif\") {\n return {\n type: \"endif\",\n };\n }\n } else if (functionCall) {\n const functionIdentifier = functionCall.children.find(\n (child: any) => child.type === \"function_identifier\"\n );\n\n if (functionIdentifier) {\n return {\n type: \"function\",\n functionName: functionIdentifier.text,\n };\n }\n }\n }\n return null;\n }\n\n // First pass: convert all nodes to intermediate format\n const rawNodes: {\n type: \"block\" | \"endblock\" | \"function\" | \"if\" | \"endif\";\n name?: string;\n functionName?: string;\n expression?: string;\n }[] = [];\n\n // Also collect content nodes\n const allNodes: Array<\n | {\n type:\n | \"block\"\n | \"endblock\"\n | \"function\"\n | \"if\"\n | \"endif\"\n | \"content\"\n | \"html_element\"\n | \"doctype\";\n name?: string;\n functionName?: string;\n expression?: string;\n content?: string;\n }\n | HtmlElementNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n > = [];\n\n function convertHtmlEntity(\n node: any\n ): HtmlNamedEntityNode | HtmlNumericEntityNode | null {\n if (node.type === \"html_entity\") {\n const entityText = node.text;\n\n // Check if it's a numeric entity (starts with &#)\n if (entityText.startsWith(\"&#\")) {\n return {\n type: \"html_numeric_entity\",\n content: entityText,\n };\n } else if (entityText.startsWith(\"&\")) {\n return {\n type: \"html_named_entity\",\n content: entityText,\n };\n }\n }\n return null;\n }\n\n function convertHtmlElement(node: any): HtmlElementNode | null {\n if (node.type === \"html_element\") {\n // Check for self-closing tag first\n const selfClosingTag = node.children.find(\n (child: any) => child.type === \"html_self_closing_tag\"\n );\n\n // Find the start tag to get the element name\n const startTag = node.children.find(\n (child: any) => child.type === \"html_start_tag\"\n );\n\n // Use self-closing tag if available, otherwise start tag\n const tagToUse = selfClosingTag || startTag;\n if (!tagToUse) return null;\n\n const tagName = tagToUse.children.find(\n (child: any) => child.type === \"html_tag_name\"\n );\n if (!tagName) return null;\n\n // Check if this is a void element (no end tag and not self-closing)\n const hasEndTag = node.children.some(\n (child: any) => child.type === \"html_end_tag\"\n );\n const isVoid = !hasEndTag;\n\n // Parse attributes from the tag (either self-closing or start tag)\n const attributes: HtmlAttributeNode[] = [];\n const attributeNodes = tagToUse.children.filter(\n (child: any) => child.type === \"html_attribute\"\n );\n\n for (const attrNode of attributeNodes) {\n const nameNode = attrNode.children.find(\n (child: any) => child.type === \"html_attribute_name\"\n );\n if (!nameNode) continue;\n\n const valueNode = attrNode.children.find(\n (child: any) => child.type === \"html_attribute_value\"\n );\n const quotedValueNode = attrNode.children.find(\n (child: any) => child.type === \"html_quoted_attribute_value\"\n );\n\n let value: string | undefined;\n if (quotedValueNode) {\n // For quoted values, find the inner html_attribute_value\n const innerValueNode = quotedValueNode.children.find(\n (child: any) => child.type === \"html_attribute_value\"\n );\n value = innerValueNode ? innerValueNode.text : undefined;\n } else if (valueNode) {\n value = valueNode.text;\n }\n\n const attribute: HtmlAttributeNode = {\n type: \"html_attribute\",\n name: nameNode.text,\n };\n\n // Only include value property if there's actually a value\n if (value !== undefined) {\n attribute.value = value;\n }\n\n attributes.push(attribute);\n }\n\n const elementChildren: (\n | HtmlElementNode\n | ContentNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n )[] = [];\n\n // Process all children that are not start/end tags\n for (const child of node.children) {\n if (child.type === \"content\") {\n elementChildren.push({\n type: \"content\",\n content: child.text,\n });\n } else if (child.type === \"html_element\") {\n const nestedElement = convertHtmlElement(child);\n if (nestedElement) {\n elementChildren.push(nestedElement);\n }\n } else if (child.type === \"html_entity\") {\n const entityNode = convertHtmlEntity(child);\n if (entityNode) {\n elementChildren.push(entityNode);\n }\n }\n }\n\n const result: HtmlElementNode = {\n type: \"html_element\",\n name: tagName.text,\n children: elementChildren,\n };\n\n if (attributes.length > 0) {\n result.attributes = attributes;\n }\n\n if (isVoid) {\n result.void = true;\n }\n\n return result;\n }\n return null;\n }\n\n for (const child of tree.rootNode.children) {\n if (child.type === \"content\") {\n allNodes.push({\n type: \"content\",\n content: child.text,\n });\n } else if (child.type === \"html_element\") {\n const htmlElement = convertHtmlElement(child);\n if (htmlElement) {\n allNodes.push(htmlElement);\n }\n } else if (child.type === \"html_doctype\") {\n allNodes.push({\n type: \"doctype\",\n });\n } else if (child.type === \"html_entity\") {\n const entityNode = convertHtmlEntity(child);\n if (entityNode) {\n allNodes.push(entityNode);\n }\n } else {\n const converted = convertNode(child);\n if (converted) {\n rawNodes.push(converted);\n allNodes.push(converted);\n }\n }\n }\n\n // Second pass: build nested structure using a stack\n function buildNestedStructure(\n nodes: Array<\n | {\n type:\n | \"block\"\n | \"endblock\"\n | \"function\"\n | \"if\"\n | \"endif\"\n | \"content\"\n | \"html_element\"\n | \"doctype\";\n name?: string;\n functionName?: string;\n expression?: string;\n content?: string;\n }\n | HtmlElementNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n >\n ): (\n | TwigStatementDirectiveNode\n | HtmlElementNode\n | ContentNode\n | HtmlDoctypeNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n )[] {\n const result: (\n | TwigStatementDirectiveNode\n | HtmlElementNode\n | ContentNode\n | HtmlDoctypeNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n )[] = [];\n const stack: TwigStatementDirectiveNode[] = [];\n\n for (const node of nodes) {\n if (node.type === \"block\") {\n const blockNode: TwigStatementDirectiveNode = {\n tag: {\n type: \"twig_tag\",\n name: \"block\",\n },\n type: \"twig_statement_directive\",\n variable: {\n type: \"twig_variable\",\n content: node.name!,\n },\n children: [],\n };\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(blockNode);\n }\n } else {\n // Add to root level\n result.push(blockNode);\n }\n\n // Push to stack for nesting\n stack.push(blockNode);\n } else if (node.type === \"endblock\") {\n // Pop from stack when we encounter an endblock\n stack.pop();\n } else if (node.type === \"if\") {\n const ifNode: TwigStatementDirectiveNode = {\n type: \"twig_statement_directive\",\n condition: {\n type: \"twig_condition\",\n expression: {\n type: \"twig_expression\",\n content: node.expression!,\n },\n },\n children: [],\n };\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(ifNode);\n }\n } else {\n // Add to root level\n result.push(ifNode);\n }\n\n // Push to stack for nesting\n stack.push(ifNode);\n } else if (node.type === \"endif\") {\n // Pop from stack when we encounter an endif\n stack.pop();\n } else if (node.type === \"function\") {\n const functionNode: TwigStatementDirectiveNode = {\n type: \"twig_statement_directive\",\n function: {\n type: \"twig_function\",\n name: node.functionName!,\n },\n };\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(functionNode);\n }\n } else {\n // Add to root level\n result.push(functionNode);\n }\n } else if (node.type === \"content\") {\n const contentNode: ContentNode = {\n type: \"content\",\n content: node.content!,\n };\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(contentNode);\n }\n } else {\n // Content at root level - this shouldn't happen in well-formed templates\n // but we'll handle it gracefully\n result.push({\n type: \"twig_statement_directive\",\n children: [contentNode],\n });\n }\n } else if (node.type === \"html_element\" && \"name\" in node) {\n // HTML elements are already processed and can be added directly\n const htmlNode = node as HtmlElementNode;\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(htmlNode);\n }\n } else {\n // Add to root level\n result.push(htmlNode);\n }\n } else if (node.type === \"doctype\") {\n const doctypeNode: HtmlDoctypeNode = {\n type: \"doctype\",\n };\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(doctypeNode);\n }\n } else {\n // Add to root level\n result.push(doctypeNode);\n }\n } else if (node.type === \"html_named_entity\" && \"content\" in node) {\n const entityNode = node as HtmlNamedEntityNode;\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(entityNode);\n }\n } else {\n // Add to root level\n result.push(entityNode);\n }\n } else if (node.type === \"html_numeric_entity\" && \"content\" in node) {\n const entityNode = node as HtmlNumericEntityNode;\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(entityNode);\n }\n } else {\n // Add to root level\n result.push(entityNode);\n }\n }\n }\n\n return result;\n }\n\n const children = buildNestedStructure(allNodes);\n\n return {\n rootNode: {\n type: \"template\",\n children,\n },\n };\n}\n"]}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -3,13 +3,27 @@ type Tree = {
|
|
|
3
3
|
};
|
|
4
4
|
type TemplateNode = {
|
|
5
5
|
type: "template";
|
|
6
|
-
children: TwigStatementDirectiveNode[];
|
|
6
|
+
children: (TwigStatementDirectiveNode | HtmlElementNode | ContentNode | HtmlDoctypeNode | HtmlNamedEntityNode | HtmlNumericEntityNode)[];
|
|
7
7
|
};
|
|
8
8
|
type TwigStatementDirectiveNode = {
|
|
9
9
|
type: "twig_statement_directive";
|
|
10
|
-
tag
|
|
11
|
-
variable
|
|
12
|
-
|
|
10
|
+
tag?: TwigTagNode;
|
|
11
|
+
variable?: TwigVariableNode;
|
|
12
|
+
function?: TwigFunctionNode;
|
|
13
|
+
condition?: TwigConditionNode;
|
|
14
|
+
children?: (TwigStatementDirectiveNode | ContentNode | HtmlElementNode | HtmlDoctypeNode | HtmlNamedEntityNode | HtmlNumericEntityNode)[];
|
|
15
|
+
};
|
|
16
|
+
type TwigConditionNode = {
|
|
17
|
+
type: "twig_condition";
|
|
18
|
+
expression: TwigExpressionNode;
|
|
19
|
+
};
|
|
20
|
+
type TwigExpressionNode = {
|
|
21
|
+
type: "twig_expression";
|
|
22
|
+
content: string;
|
|
23
|
+
};
|
|
24
|
+
type ContentNode = {
|
|
25
|
+
type: "content";
|
|
26
|
+
content: string;
|
|
13
27
|
};
|
|
14
28
|
type TwigTagNode = {
|
|
15
29
|
type: "twig_tag";
|
|
@@ -19,6 +33,33 @@ type TwigVariableNode = {
|
|
|
19
33
|
type: "twig_variable";
|
|
20
34
|
content: string;
|
|
21
35
|
};
|
|
36
|
+
type TwigFunctionNode = {
|
|
37
|
+
type: "twig_function";
|
|
38
|
+
name: string;
|
|
39
|
+
};
|
|
40
|
+
type HtmlAttributeNode = {
|
|
41
|
+
type: "html_attribute";
|
|
42
|
+
name: string;
|
|
43
|
+
value?: string;
|
|
44
|
+
};
|
|
45
|
+
type HtmlElementNode = {
|
|
46
|
+
type: "html_element";
|
|
47
|
+
name: string;
|
|
48
|
+
attributes?: HtmlAttributeNode[];
|
|
49
|
+
children: (HtmlElementNode | ContentNode | HtmlNamedEntityNode | HtmlNumericEntityNode)[];
|
|
50
|
+
void?: boolean;
|
|
51
|
+
};
|
|
52
|
+
type HtmlDoctypeNode = {
|
|
53
|
+
type: "doctype";
|
|
54
|
+
};
|
|
55
|
+
type HtmlNamedEntityNode = {
|
|
56
|
+
type: "html_named_entity";
|
|
57
|
+
content: string;
|
|
58
|
+
};
|
|
59
|
+
type HtmlNumericEntityNode = {
|
|
60
|
+
type: "html_numeric_entity";
|
|
61
|
+
content: string;
|
|
62
|
+
};
|
|
22
63
|
export declare function parse(content: string): Tree;
|
|
23
64
|
export {};
|
|
24
65
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAGA,KAAK,IAAI,GAAG;IACV,QAAQ,EAAE,YAAY,CAAC;CACxB,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,0BAA0B,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAGA,KAAK,IAAI,GAAG;IACV,QAAQ,EAAE,YAAY,CAAC;CACxB,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,CACN,0BAA0B,GAC1B,eAAe,GACf,WAAW,GACX,eAAe,GACf,mBAAmB,GACnB,qBAAqB,CACxB,EAAE,CAAC;CACL,CAAC;AAEF,KAAK,0BAA0B,GAAG;IAChC,IAAI,EAAE,0BAA0B,CAAC;IACjC,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,QAAQ,CAAC,EAAE,CACP,0BAA0B,GAC1B,WAAW,GACX,eAAe,GACf,eAAe,GACf,mBAAmB,GACnB,qBAAqB,CACxB,EAAE,CAAC;CACL,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,IAAI,EAAE,gBAAgB,CAAC;IACvB,UAAU,EAAE,kBAAkB,CAAC;CAChC,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,iBAAiB,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACjC,QAAQ,EAAE,CACN,eAAe,GACf,WAAW,GACX,mBAAmB,GACnB,qBAAqB,CACxB,EAAE,CAAC;IACJ,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,IAAI,EAAE,SAAS,CAAC;CACjB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,IAAI,EAAE,mBAAmB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,qBAAqB,GAAG;IAC3B,IAAI,EAAE,qBAAqB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAMF,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAoe3C"}
|
package/dist/esm/index.js
CHANGED
|
@@ -7,9 +7,24 @@ export function parse(content) {
|
|
|
7
7
|
const tree = parser.parse(content);
|
|
8
8
|
function convertNode(node) {
|
|
9
9
|
if (node.type === "statement_directive") {
|
|
10
|
+
// Check for if_statement
|
|
11
|
+
const ifStatement = node.children.find((child) => child.type === "if_statement");
|
|
12
|
+
if (ifStatement) {
|
|
13
|
+
const conditionalNode = ifStatement.children.find((child) => child.type === "conditional");
|
|
14
|
+
const variableNode = ifStatement.children.find((child) => child.type === "variable");
|
|
15
|
+
if (conditionalNode && conditionalNode.text === "if" && variableNode) {
|
|
16
|
+
return {
|
|
17
|
+
type: "if",
|
|
18
|
+
expression: variableNode.text,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// Check for tag_statement
|
|
10
23
|
const tagStatement = node.children.find((child) => child.type === "tag_statement");
|
|
24
|
+
const functionCall = node.children.find((child) => child.type === "function_call");
|
|
11
25
|
if (tagStatement) {
|
|
12
26
|
const tagNode = tagStatement.children.find((child) => child.type === "tag");
|
|
27
|
+
const conditionalNode = tagStatement.children.find((child) => child.type === "conditional");
|
|
13
28
|
const variableNode = tagStatement.children.find((child) => child.type === "variable");
|
|
14
29
|
if (tagNode && tagNode.text === "block" && variableNode) {
|
|
15
30
|
return {
|
|
@@ -22,16 +37,158 @@ export function parse(content) {
|
|
|
22
37
|
type: "endblock",
|
|
23
38
|
};
|
|
24
39
|
}
|
|
40
|
+
else if (conditionalNode && conditionalNode.text === "endif") {
|
|
41
|
+
return {
|
|
42
|
+
type: "endif",
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else if (functionCall) {
|
|
47
|
+
const functionIdentifier = functionCall.children.find((child) => child.type === "function_identifier");
|
|
48
|
+
if (functionIdentifier) {
|
|
49
|
+
return {
|
|
50
|
+
type: "function",
|
|
51
|
+
functionName: functionIdentifier.text,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
25
54
|
}
|
|
26
55
|
}
|
|
27
56
|
return null;
|
|
28
57
|
}
|
|
29
58
|
// First pass: convert all nodes to intermediate format
|
|
30
59
|
const rawNodes = [];
|
|
60
|
+
// Also collect content nodes
|
|
61
|
+
const allNodes = [];
|
|
62
|
+
function convertHtmlEntity(node) {
|
|
63
|
+
if (node.type === "html_entity") {
|
|
64
|
+
const entityText = node.text;
|
|
65
|
+
// Check if it's a numeric entity (starts with &#)
|
|
66
|
+
if (entityText.startsWith("&#")) {
|
|
67
|
+
return {
|
|
68
|
+
type: "html_numeric_entity",
|
|
69
|
+
content: entityText,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
else if (entityText.startsWith("&")) {
|
|
73
|
+
return {
|
|
74
|
+
type: "html_named_entity",
|
|
75
|
+
content: entityText,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
function convertHtmlElement(node) {
|
|
82
|
+
if (node.type === "html_element") {
|
|
83
|
+
// Check for self-closing tag first
|
|
84
|
+
const selfClosingTag = node.children.find((child) => child.type === "html_self_closing_tag");
|
|
85
|
+
// Find the start tag to get the element name
|
|
86
|
+
const startTag = node.children.find((child) => child.type === "html_start_tag");
|
|
87
|
+
// Use self-closing tag if available, otherwise start tag
|
|
88
|
+
const tagToUse = selfClosingTag || startTag;
|
|
89
|
+
if (!tagToUse)
|
|
90
|
+
return null;
|
|
91
|
+
const tagName = tagToUse.children.find((child) => child.type === "html_tag_name");
|
|
92
|
+
if (!tagName)
|
|
93
|
+
return null;
|
|
94
|
+
// Check if this is a void element (no end tag and not self-closing)
|
|
95
|
+
const hasEndTag = node.children.some((child) => child.type === "html_end_tag");
|
|
96
|
+
const isVoid = !hasEndTag;
|
|
97
|
+
// Parse attributes from the tag (either self-closing or start tag)
|
|
98
|
+
const attributes = [];
|
|
99
|
+
const attributeNodes = tagToUse.children.filter((child) => child.type === "html_attribute");
|
|
100
|
+
for (const attrNode of attributeNodes) {
|
|
101
|
+
const nameNode = attrNode.children.find((child) => child.type === "html_attribute_name");
|
|
102
|
+
if (!nameNode)
|
|
103
|
+
continue;
|
|
104
|
+
const valueNode = attrNode.children.find((child) => child.type === "html_attribute_value");
|
|
105
|
+
const quotedValueNode = attrNode.children.find((child) => child.type === "html_quoted_attribute_value");
|
|
106
|
+
let value;
|
|
107
|
+
if (quotedValueNode) {
|
|
108
|
+
// For quoted values, find the inner html_attribute_value
|
|
109
|
+
const innerValueNode = quotedValueNode.children.find((child) => child.type === "html_attribute_value");
|
|
110
|
+
value = innerValueNode ? innerValueNode.text : undefined;
|
|
111
|
+
}
|
|
112
|
+
else if (valueNode) {
|
|
113
|
+
value = valueNode.text;
|
|
114
|
+
}
|
|
115
|
+
const attribute = {
|
|
116
|
+
type: "html_attribute",
|
|
117
|
+
name: nameNode.text,
|
|
118
|
+
};
|
|
119
|
+
// Only include value property if there's actually a value
|
|
120
|
+
if (value !== undefined) {
|
|
121
|
+
attribute.value = value;
|
|
122
|
+
}
|
|
123
|
+
attributes.push(attribute);
|
|
124
|
+
}
|
|
125
|
+
const elementChildren = [];
|
|
126
|
+
// Process all children that are not start/end tags
|
|
127
|
+
for (const child of node.children) {
|
|
128
|
+
if (child.type === "content") {
|
|
129
|
+
elementChildren.push({
|
|
130
|
+
type: "content",
|
|
131
|
+
content: child.text,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
else if (child.type === "html_element") {
|
|
135
|
+
const nestedElement = convertHtmlElement(child);
|
|
136
|
+
if (nestedElement) {
|
|
137
|
+
elementChildren.push(nestedElement);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else if (child.type === "html_entity") {
|
|
141
|
+
const entityNode = convertHtmlEntity(child);
|
|
142
|
+
if (entityNode) {
|
|
143
|
+
elementChildren.push(entityNode);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const result = {
|
|
148
|
+
type: "html_element",
|
|
149
|
+
name: tagName.text,
|
|
150
|
+
children: elementChildren,
|
|
151
|
+
};
|
|
152
|
+
if (attributes.length > 0) {
|
|
153
|
+
result.attributes = attributes;
|
|
154
|
+
}
|
|
155
|
+
if (isVoid) {
|
|
156
|
+
result.void = true;
|
|
157
|
+
}
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
31
162
|
for (const child of tree.rootNode.children) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
163
|
+
if (child.type === "content") {
|
|
164
|
+
allNodes.push({
|
|
165
|
+
type: "content",
|
|
166
|
+
content: child.text,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
else if (child.type === "html_element") {
|
|
170
|
+
const htmlElement = convertHtmlElement(child);
|
|
171
|
+
if (htmlElement) {
|
|
172
|
+
allNodes.push(htmlElement);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else if (child.type === "html_doctype") {
|
|
176
|
+
allNodes.push({
|
|
177
|
+
type: "doctype",
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
else if (child.type === "html_entity") {
|
|
181
|
+
const entityNode = convertHtmlEntity(child);
|
|
182
|
+
if (entityNode) {
|
|
183
|
+
allNodes.push(entityNode);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
const converted = convertNode(child);
|
|
188
|
+
if (converted) {
|
|
189
|
+
rawNodes.push(converted);
|
|
190
|
+
allNodes.push(converted);
|
|
191
|
+
}
|
|
35
192
|
}
|
|
36
193
|
}
|
|
37
194
|
// Second pass: build nested structure using a stack
|
|
@@ -54,7 +211,10 @@ export function parse(content) {
|
|
|
54
211
|
};
|
|
55
212
|
if (stack.length > 0) {
|
|
56
213
|
// Add to the current parent's children
|
|
57
|
-
stack[stack.length - 1]
|
|
214
|
+
const parent = stack[stack.length - 1];
|
|
215
|
+
if (parent && parent.children) {
|
|
216
|
+
parent.children.push(blockNode);
|
|
217
|
+
}
|
|
58
218
|
}
|
|
59
219
|
else {
|
|
60
220
|
// Add to root level
|
|
@@ -67,10 +227,140 @@ export function parse(content) {
|
|
|
67
227
|
// Pop from stack when we encounter an endblock
|
|
68
228
|
stack.pop();
|
|
69
229
|
}
|
|
230
|
+
else if (node.type === "if") {
|
|
231
|
+
const ifNode = {
|
|
232
|
+
type: "twig_statement_directive",
|
|
233
|
+
condition: {
|
|
234
|
+
type: "twig_condition",
|
|
235
|
+
expression: {
|
|
236
|
+
type: "twig_expression",
|
|
237
|
+
content: node.expression,
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
children: [],
|
|
241
|
+
};
|
|
242
|
+
if (stack.length > 0) {
|
|
243
|
+
// Add to the current parent's children
|
|
244
|
+
const parent = stack[stack.length - 1];
|
|
245
|
+
if (parent && parent.children) {
|
|
246
|
+
parent.children.push(ifNode);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
// Add to root level
|
|
251
|
+
result.push(ifNode);
|
|
252
|
+
}
|
|
253
|
+
// Push to stack for nesting
|
|
254
|
+
stack.push(ifNode);
|
|
255
|
+
}
|
|
256
|
+
else if (node.type === "endif") {
|
|
257
|
+
// Pop from stack when we encounter an endif
|
|
258
|
+
stack.pop();
|
|
259
|
+
}
|
|
260
|
+
else if (node.type === "function") {
|
|
261
|
+
const functionNode = {
|
|
262
|
+
type: "twig_statement_directive",
|
|
263
|
+
function: {
|
|
264
|
+
type: "twig_function",
|
|
265
|
+
name: node.functionName,
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
if (stack.length > 0) {
|
|
269
|
+
// Add to the current parent's children
|
|
270
|
+
const parent = stack[stack.length - 1];
|
|
271
|
+
if (parent && parent.children) {
|
|
272
|
+
parent.children.push(functionNode);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
// Add to root level
|
|
277
|
+
result.push(functionNode);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
else if (node.type === "content") {
|
|
281
|
+
const contentNode = {
|
|
282
|
+
type: "content",
|
|
283
|
+
content: node.content,
|
|
284
|
+
};
|
|
285
|
+
if (stack.length > 0) {
|
|
286
|
+
// Add to the current parent's children
|
|
287
|
+
const parent = stack[stack.length - 1];
|
|
288
|
+
if (parent && parent.children) {
|
|
289
|
+
parent.children.push(contentNode);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
// Content at root level - this shouldn't happen in well-formed templates
|
|
294
|
+
// but we'll handle it gracefully
|
|
295
|
+
result.push({
|
|
296
|
+
type: "twig_statement_directive",
|
|
297
|
+
children: [contentNode],
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
else if (node.type === "html_element" && "name" in node) {
|
|
302
|
+
// HTML elements are already processed and can be added directly
|
|
303
|
+
const htmlNode = node;
|
|
304
|
+
if (stack.length > 0) {
|
|
305
|
+
// Add to the current parent's children
|
|
306
|
+
const parent = stack[stack.length - 1];
|
|
307
|
+
if (parent && parent.children) {
|
|
308
|
+
parent.children.push(htmlNode);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
// Add to root level
|
|
313
|
+
result.push(htmlNode);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
else if (node.type === "doctype") {
|
|
317
|
+
const doctypeNode = {
|
|
318
|
+
type: "doctype",
|
|
319
|
+
};
|
|
320
|
+
if (stack.length > 0) {
|
|
321
|
+
// Add to the current parent's children
|
|
322
|
+
const parent = stack[stack.length - 1];
|
|
323
|
+
if (parent && parent.children) {
|
|
324
|
+
parent.children.push(doctypeNode);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
// Add to root level
|
|
329
|
+
result.push(doctypeNode);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
else if (node.type === "html_named_entity" && "content" in node) {
|
|
333
|
+
const entityNode = node;
|
|
334
|
+
if (stack.length > 0) {
|
|
335
|
+
// Add to the current parent's children
|
|
336
|
+
const parent = stack[stack.length - 1];
|
|
337
|
+
if (parent && parent.children) {
|
|
338
|
+
parent.children.push(entityNode);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
// Add to root level
|
|
343
|
+
result.push(entityNode);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
else if (node.type === "html_numeric_entity" && "content" in node) {
|
|
347
|
+
const entityNode = node;
|
|
348
|
+
if (stack.length > 0) {
|
|
349
|
+
// Add to the current parent's children
|
|
350
|
+
const parent = stack[stack.length - 1];
|
|
351
|
+
if (parent && parent.children) {
|
|
352
|
+
parent.children.push(entityNode);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
// Add to root level
|
|
357
|
+
result.push(entityNode);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
70
360
|
}
|
|
71
361
|
return result;
|
|
72
362
|
}
|
|
73
|
-
const children = buildNestedStructure(
|
|
363
|
+
const children = buildNestedStructure(allNodes);
|
|
74
364
|
return {
|
|
75
365
|
rootNode: {
|
|
76
366
|
type: "template",
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import Parser from \"tree-sitter\";\nimport ShopwareTwig from \"tree-sitter-shopware-twig\";\n\ntype Tree = {\n rootNode: TemplateNode;\n};\n\ntype TemplateNode = {\n type: \"template\";\n children: TwigStatementDirectiveNode[];\n};\n\ntype TwigStatementDirectiveNode = {\n type: \"twig_statement_directive\";\n tag: TwigTagNode;\n variable: TwigVariableNode;\n children: TwigStatementDirectiveNode[];\n};\n\ntype TwigTagNode = {\n type: \"twig_tag\";\n name: string;\n};\n\ntype TwigVariableNode = {\n type: \"twig_variable\";\n content: string;\n};\n\nconst parser = new Parser();\n// @ts-expect-error\nparser.setLanguage(ShopwareTwig);\n\nexport function parse(content: string): Tree {\n const tree = parser.parse(content);\n\n function convertNode(\n node: any\n ): { type: \"block\" | \"endblock\"; name?: string } | null {\n if (node.type === \"statement_directive\") {\n const tagStatement = node.children.find(\n (child: any) => child.type === \"tag_statement\"\n );\n if (tagStatement) {\n const tagNode = tagStatement.children.find(\n (child: any) => child.type === \"tag\"\n );\n const variableNode = tagStatement.children.find(\n (child: any) => child.type === \"variable\"\n );\n\n if (tagNode && tagNode.text === \"block\" && variableNode) {\n return {\n type: \"block\",\n name: variableNode.text,\n };\n } else if (tagNode && tagNode.text === \"endblock\") {\n return {\n type: \"endblock\",\n };\n }\n }\n }\n return null;\n }\n\n // First pass: convert all nodes to intermediate format\n const rawNodes: { type: \"block\" | \"endblock\"; name?: string }[] = [];\n for (const child of tree.rootNode.children) {\n const converted = convertNode(child);\n if (converted) {\n rawNodes.push(converted);\n }\n }\n\n // Second pass: build nested structure using a stack\n function buildNestedStructure(\n nodes: { type: \"block\" | \"endblock\"; name?: string }[]\n ): TwigStatementDirectiveNode[] {\n const result: TwigStatementDirectiveNode[] = [];\n const stack: TwigStatementDirectiveNode[] = [];\n\n for (const node of nodes) {\n if (node.type === \"block\") {\n const blockNode: TwigStatementDirectiveNode = {\n tag: {\n type: \"twig_tag\",\n name: \"block\",\n },\n type: \"twig_statement_directive\",\n variable: {\n type: \"twig_variable\",\n content: node.name!,\n },\n children: [],\n };\n\n if (stack.length > 0) {\n // Add to the current parent's children\n stack[stack.length - 1]?.children.push(blockNode);\n } else {\n // Add to root level\n result.push(blockNode);\n }\n\n // Push to stack for nesting\n stack.push(blockNode);\n } else if (node.type === \"endblock\") {\n // Pop from stack when we encounter an endblock\n stack.pop();\n }\n }\n\n return result;\n }\n\n const children = buildNestedStructure(rawNodes);\n\n return {\n rootNode: {\n type: \"template\",\n children,\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,YAAY,MAAM,2BAA2B,CAAC;AAiGrD,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;AAC5B,mBAAmB;AACnB,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;AAEjC,MAAM,UAAU,KAAK,CAAC,OAAe;IACnC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEnC,SAAS,WAAW,CAAC,IAAS;QAM5B,IAAI,IAAI,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;YACxC,yBAAyB;YACzB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CACpC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,cAAc,CAC9C,CAAC;YACF,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,eAAe,GAAG,WAAW,CAAC,QAAQ,CAAC,IAAI,CAC/C,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,aAAa,CAC7C,CAAC;gBACF,MAAM,YAAY,GAAG,WAAW,CAAC,QAAQ,CAAC,IAAI,CAC5C,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,UAAU,CAC1C,CAAC;gBAEF,IAAI,eAAe,IAAI,eAAe,CAAC,IAAI,KAAK,IAAI,IAAI,YAAY,EAAE,CAAC;oBACrE,OAAO;wBACL,IAAI,EAAE,IAAI;wBACV,UAAU,EAAE,YAAY,CAAC,IAAI;qBAC9B,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,0BAA0B;YAC1B,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CACrC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,eAAe,CAC/C,CAAC;YACF,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CACrC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,eAAe,CAC/C,CAAC;YAEF,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,IAAI,CACxC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,CACrC,CAAC;gBACF,MAAM,eAAe,GAAG,YAAY,CAAC,QAAQ,CAAC,IAAI,CAChD,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,aAAa,CAC7C,CAAC;gBACF,MAAM,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAC,IAAI,CAC7C,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,UAAU,CAC1C,CAAC;gBAEF,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,YAAY,EAAE,CAAC;oBACxD,OAAO;wBACL,IAAI,EAAE,OAAO;wBACb,IAAI,EAAE,YAAY,CAAC,IAAI;qBACxB,CAAC;gBACJ,CAAC;qBAAM,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;oBAClD,OAAO;wBACL,IAAI,EAAE,UAAU;qBACjB,CAAC;gBACJ,CAAC;qBAAM,IAAI,eAAe,IAAI,eAAe,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAC/D,OAAO;wBACL,IAAI,EAAE,OAAO;qBACd,CAAC;gBACJ,CAAC;YACH,CAAC;iBAAM,IAAI,YAAY,EAAE,CAAC;gBACxB,MAAM,kBAAkB,GAAG,YAAY,CAAC,QAAQ,CAAC,IAAI,CACnD,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,qBAAqB,CACrD,CAAC;gBAEF,IAAI,kBAAkB,EAAE,CAAC;oBACvB,OAAO;wBACL,IAAI,EAAE,UAAU;wBAChB,YAAY,EAAE,kBAAkB,CAAC,IAAI;qBACtC,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uDAAuD;IACvD,MAAM,QAAQ,GAKR,EAAE,CAAC;IAET,6BAA6B;IAC7B,MAAM,QAAQ,GAmBV,EAAE,CAAC;IAEP,SAAS,iBAAiB,CACxB,IAAS;QAET,IAAI,IAAI,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAChC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC;YAE7B,kDAAkD;YAClD,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBAChC,OAAO;oBACL,IAAI,EAAE,qBAAqB;oBAC3B,OAAO,EAAE,UAAU;iBACpB,CAAC;YACJ,CAAC;iBAAM,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtC,OAAO;oBACL,IAAI,EAAE,mBAAmB;oBACzB,OAAO,EAAE,UAAU;iBACpB,CAAC;YACJ,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,SAAS,kBAAkB,CAAC,IAAS;QACnC,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACjC,mCAAmC;YACnC,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CACvC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,uBAAuB,CACvD,CAAC;YAEF,6CAA6C;YAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CACjC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,gBAAgB,CAChD,CAAC;YAEF,yDAAyD;YACzD,MAAM,QAAQ,GAAG,cAAc,IAAI,QAAQ,CAAC;YAC5C,IAAI,CAAC,QAAQ;gBAAE,OAAO,IAAI,CAAC;YAE3B,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CACpC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,eAAe,CAC/C,CAAC;YACF,IAAI,CAAC,OAAO;gBAAE,OAAO,IAAI,CAAC;YAE1B,oEAAoE;YACpE,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAClC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,cAAc,CAC9C,CAAC;YACF,MAAM,MAAM,GAAG,CAAC,SAAS,CAAC;YAE1B,mEAAmE;YACnE,MAAM,UAAU,GAAwB,EAAE,CAAC;YAC3C,MAAM,cAAc,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAC7C,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,gBAAgB,CAChD,CAAC;YAEF,KAAK,MAAM,QAAQ,IAAI,cAAc,EAAE,CAAC;gBACtC,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CACrC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,qBAAqB,CACrD,CAAC;gBACF,IAAI,CAAC,QAAQ;oBAAE,SAAS;gBAExB,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CACtC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,sBAAsB,CACtD,CAAC;gBACF,MAAM,eAAe,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAC5C,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,6BAA6B,CAC7D,CAAC;gBAEF,IAAI,KAAyB,CAAC;gBAC9B,IAAI,eAAe,EAAE,CAAC;oBACpB,yDAAyD;oBACzD,MAAM,cAAc,GAAG,eAAe,CAAC,QAAQ,CAAC,IAAI,CAClD,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,sBAAsB,CACtD,CAAC;oBACF,KAAK,GAAG,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC3D,CAAC;qBAAM,IAAI,SAAS,EAAE,CAAC;oBACrB,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC;gBACzB,CAAC;gBAED,MAAM,SAAS,GAAsB;oBACnC,IAAI,EAAE,gBAAgB;oBACtB,IAAI,EAAE,QAAQ,CAAC,IAAI;iBACpB,CAAC;gBAEF,0DAA0D;gBAC1D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACxB,SAAS,CAAC,KAAK,GAAG,KAAK,CAAC;gBAC1B,CAAC;gBAED,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC7B,CAAC;YAED,MAAM,eAAe,GAKf,EAAE,CAAC;YAET,mDAAmD;YACnD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;oBAC7B,eAAe,CAAC,IAAI,CAAC;wBACnB,IAAI,EAAE,SAAS;wBACf,OAAO,EAAE,KAAK,CAAC,IAAI;qBACpB,CAAC,CAAC;gBACL,CAAC;qBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;oBACzC,MAAM,aAAa,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;oBAChD,IAAI,aAAa,EAAE,CAAC;wBAClB,eAAe,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;oBACtC,CAAC;gBACH,CAAC;qBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;oBACxC,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;oBAC5C,IAAI,UAAU,EAAE,CAAC;wBACf,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;oBACnC,CAAC;gBACH,CAAC;YACH,CAAC;YAED,MAAM,MAAM,GAAoB;gBAC9B,IAAI,EAAE,cAAc;gBACpB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,QAAQ,EAAE,eAAe;aAC1B,CAAC;YAEF,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,MAAM,CAAC,UAAU,GAAG,UAAU,CAAC;YACjC,CAAC;YAED,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;YACrB,CAAC;YAED,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAC3C,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC7B,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,KAAK,CAAC,IAAI;aACpB,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACzC,MAAM,WAAW,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAC9C,IAAI,WAAW,EAAE,CAAC;gBAChB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACzC,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,SAAS;aAChB,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YACxC,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAC5C,IAAI,UAAU,EAAE,CAAC;gBACf,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;YACrC,IAAI,SAAS,EAAE,CAAC;gBACd,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACzB,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IAED,oDAAoD;IACpD,SAAS,oBAAoB,CAC3B,KAmBC;QASD,MAAM,MAAM,GAON,EAAE,CAAC;QACT,MAAM,KAAK,GAAiC,EAAE,CAAC;QAE/C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC1B,MAAM,SAAS,GAA+B;oBAC5C,GAAG,EAAE;wBACH,IAAI,EAAE,UAAU;wBAChB,IAAI,EAAE,OAAO;qBACd;oBACD,IAAI,EAAE,0BAA0B;oBAChC,QAAQ,EAAE;wBACR,IAAI,EAAE,eAAe;wBACrB,OAAO,EAAE,IAAI,CAAC,IAAK;qBACpB;oBACD,QAAQ,EAAE,EAAE;iBACb,CAAC;gBAEF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,uCAAuC;oBACvC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBACvC,IAAI,MAAM,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;wBAC9B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBAClC,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,oBAAoB;oBACpB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACzB,CAAC;gBAED,4BAA4B;gBAC5B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,CAAC;iBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBACpC,+CAA+C;gBAC/C,KAAK,CAAC,GAAG,EAAE,CAAC;YACd,CAAC;iBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;gBAC9B,MAAM,MAAM,GAA+B;oBACzC,IAAI,EAAE,0BAA0B;oBAChC,SAAS,EAAE;wBACT,IAAI,EAAE,gBAAgB;wBACtB,UAAU,EAAE;4BACV,IAAI,EAAE,iBAAiB;4BACvB,OAAO,EAAE,IAAI,CAAC,UAAW;yBAC1B;qBACF;oBACD,QAAQ,EAAE,EAAE;iBACb,CAAC;gBAEF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,uCAAuC;oBACvC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBACvC,IAAI,MAAM,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;wBAC9B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBAC/B,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,oBAAoB;oBACpB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACtB,CAAC;gBAED,4BAA4B;gBAC5B,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACrB,CAAC;iBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBACjC,4CAA4C;gBAC5C,KAAK,CAAC,GAAG,EAAE,CAAC;YACd,CAAC;iBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBACpC,MAAM,YAAY,GAA+B;oBAC/C,IAAI,EAAE,0BAA0B;oBAChC,QAAQ,EAAE;wBACR,IAAI,EAAE,eAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,YAAa;qBACzB;iBACF,CAAC;gBAEF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,uCAAuC;oBACvC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBACvC,IAAI,MAAM,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;wBAC9B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;oBACrC,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,oBAAoB;oBACpB,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAC5B,CAAC;YACH,CAAC;iBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBACnC,MAAM,WAAW,GAAgB;oBAC/B,IAAI,EAAE,SAAS;oBACf,OAAO,EAAE,IAAI,CAAC,OAAQ;iBACvB,CAAC;gBAEF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,uCAAuC;oBACvC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBACvC,IAAI,MAAM,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;wBAC9B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;oBACpC,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,yEAAyE;oBACzE,iCAAiC;oBACjC,MAAM,CAAC,IAAI,CAAC;wBACV,IAAI,EAAE,0BAA0B;wBAChC,QAAQ,EAAE,CAAC,WAAW,CAAC;qBACxB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;iBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;gBAC1D,gEAAgE;gBAChE,MAAM,QAAQ,GAAG,IAAuB,CAAC;gBAEzC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,uCAAuC;oBACvC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBACvC,IAAI,MAAM,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;wBAC9B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBACjC,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,oBAAoB;oBACpB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC;iBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBACnC,MAAM,WAAW,GAAoB;oBACnC,IAAI,EAAE,SAAS;iBAChB,CAAC;gBAEF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,uCAAuC;oBACvC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBACvC,IAAI,MAAM,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;wBAC9B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;oBACpC,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,oBAAoB;oBACpB,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC;iBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,mBAAmB,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;gBAClE,MAAM,UAAU,GAAG,IAA2B,CAAC;gBAE/C,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,uCAAuC;oBACvC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBACvC,IAAI,MAAM,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;wBAC9B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;oBACnC,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,oBAAoB;oBACpB,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAC1B,CAAC;YACH,CAAC;iBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,qBAAqB,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;gBACpE,MAAM,UAAU,GAAG,IAA6B,CAAC;gBAEjD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,uCAAuC;oBACvC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBACvC,IAAI,MAAM,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;wBAC9B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;oBACnC,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,oBAAoB;oBACpB,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,QAAQ,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAEhD,OAAO;QACL,QAAQ,EAAE;YACR,IAAI,EAAE,UAAU;YAChB,QAAQ;SACT;KACF,CAAC;AACJ,CAAC","sourcesContent":["import Parser from \"tree-sitter\";\nimport ShopwareTwig from \"tree-sitter-shopware-twig\";\n\ntype Tree = {\n rootNode: TemplateNode;\n};\n\ntype TemplateNode = {\n type: \"template\";\n children: (\n | TwigStatementDirectiveNode\n | HtmlElementNode\n | ContentNode\n | HtmlDoctypeNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n )[];\n};\n\ntype TwigStatementDirectiveNode = {\n type: \"twig_statement_directive\";\n tag?: TwigTagNode;\n variable?: TwigVariableNode;\n function?: TwigFunctionNode;\n condition?: TwigConditionNode;\n children?: (\n | TwigStatementDirectiveNode\n | ContentNode\n | HtmlElementNode\n | HtmlDoctypeNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n )[];\n};\n\ntype TwigConditionNode = {\n type: \"twig_condition\";\n expression: TwigExpressionNode;\n};\n\ntype TwigExpressionNode = {\n type: \"twig_expression\";\n content: string;\n};\n\ntype ContentNode = {\n type: \"content\";\n content: string;\n};\n\ntype TwigTagNode = {\n type: \"twig_tag\";\n name: string;\n};\n\ntype TwigVariableNode = {\n type: \"twig_variable\";\n content: string;\n};\n\ntype TwigFunctionNode = {\n type: \"twig_function\";\n name: string;\n};\n\ntype HtmlAttributeNode = {\n type: \"html_attribute\";\n name: string;\n value?: string;\n};\n\ntype HtmlElementNode = {\n type: \"html_element\";\n name: string;\n attributes?: HtmlAttributeNode[];\n children: (\n | HtmlElementNode\n | ContentNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n )[];\n void?: boolean;\n};\n\ntype HtmlDoctypeNode = {\n type: \"doctype\";\n};\n\ntype HtmlNamedEntityNode = {\n type: \"html_named_entity\";\n content: string;\n};\n\ntype HtmlNumericEntityNode = {\n type: \"html_numeric_entity\";\n content: string;\n};\n\nconst parser = new Parser();\n// @ts-expect-error\nparser.setLanguage(ShopwareTwig);\n\nexport function parse(content: string): Tree {\n const tree = parser.parse(content);\n\n function convertNode(node: any): {\n type: \"block\" | \"endblock\" | \"function\" | \"if\" | \"endif\";\n name?: string;\n functionName?: string;\n expression?: string;\n } | null {\n if (node.type === \"statement_directive\") {\n // Check for if_statement\n const ifStatement = node.children.find(\n (child: any) => child.type === \"if_statement\"\n );\n if (ifStatement) {\n const conditionalNode = ifStatement.children.find(\n (child: any) => child.type === \"conditional\"\n );\n const variableNode = ifStatement.children.find(\n (child: any) => child.type === \"variable\"\n );\n\n if (conditionalNode && conditionalNode.text === \"if\" && variableNode) {\n return {\n type: \"if\",\n expression: variableNode.text,\n };\n }\n }\n\n // Check for tag_statement\n const tagStatement = node.children.find(\n (child: any) => child.type === \"tag_statement\"\n );\n const functionCall = node.children.find(\n (child: any) => child.type === \"function_call\"\n );\n\n if (tagStatement) {\n const tagNode = tagStatement.children.find(\n (child: any) => child.type === \"tag\"\n );\n const conditionalNode = tagStatement.children.find(\n (child: any) => child.type === \"conditional\"\n );\n const variableNode = tagStatement.children.find(\n (child: any) => child.type === \"variable\"\n );\n\n if (tagNode && tagNode.text === \"block\" && variableNode) {\n return {\n type: \"block\",\n name: variableNode.text,\n };\n } else if (tagNode && tagNode.text === \"endblock\") {\n return {\n type: \"endblock\",\n };\n } else if (conditionalNode && conditionalNode.text === \"endif\") {\n return {\n type: \"endif\",\n };\n }\n } else if (functionCall) {\n const functionIdentifier = functionCall.children.find(\n (child: any) => child.type === \"function_identifier\"\n );\n\n if (functionIdentifier) {\n return {\n type: \"function\",\n functionName: functionIdentifier.text,\n };\n }\n }\n }\n return null;\n }\n\n // First pass: convert all nodes to intermediate format\n const rawNodes: {\n type: \"block\" | \"endblock\" | \"function\" | \"if\" | \"endif\";\n name?: string;\n functionName?: string;\n expression?: string;\n }[] = [];\n\n // Also collect content nodes\n const allNodes: Array<\n | {\n type:\n | \"block\"\n | \"endblock\"\n | \"function\"\n | \"if\"\n | \"endif\"\n | \"content\"\n | \"html_element\"\n | \"doctype\";\n name?: string;\n functionName?: string;\n expression?: string;\n content?: string;\n }\n | HtmlElementNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n > = [];\n\n function convertHtmlEntity(\n node: any\n ): HtmlNamedEntityNode | HtmlNumericEntityNode | null {\n if (node.type === \"html_entity\") {\n const entityText = node.text;\n\n // Check if it's a numeric entity (starts with &#)\n if (entityText.startsWith(\"&#\")) {\n return {\n type: \"html_numeric_entity\",\n content: entityText,\n };\n } else if (entityText.startsWith(\"&\")) {\n return {\n type: \"html_named_entity\",\n content: entityText,\n };\n }\n }\n return null;\n }\n\n function convertHtmlElement(node: any): HtmlElementNode | null {\n if (node.type === \"html_element\") {\n // Check for self-closing tag first\n const selfClosingTag = node.children.find(\n (child: any) => child.type === \"html_self_closing_tag\"\n );\n\n // Find the start tag to get the element name\n const startTag = node.children.find(\n (child: any) => child.type === \"html_start_tag\"\n );\n\n // Use self-closing tag if available, otherwise start tag\n const tagToUse = selfClosingTag || startTag;\n if (!tagToUse) return null;\n\n const tagName = tagToUse.children.find(\n (child: any) => child.type === \"html_tag_name\"\n );\n if (!tagName) return null;\n\n // Check if this is a void element (no end tag and not self-closing)\n const hasEndTag = node.children.some(\n (child: any) => child.type === \"html_end_tag\"\n );\n const isVoid = !hasEndTag;\n\n // Parse attributes from the tag (either self-closing or start tag)\n const attributes: HtmlAttributeNode[] = [];\n const attributeNodes = tagToUse.children.filter(\n (child: any) => child.type === \"html_attribute\"\n );\n\n for (const attrNode of attributeNodes) {\n const nameNode = attrNode.children.find(\n (child: any) => child.type === \"html_attribute_name\"\n );\n if (!nameNode) continue;\n\n const valueNode = attrNode.children.find(\n (child: any) => child.type === \"html_attribute_value\"\n );\n const quotedValueNode = attrNode.children.find(\n (child: any) => child.type === \"html_quoted_attribute_value\"\n );\n\n let value: string | undefined;\n if (quotedValueNode) {\n // For quoted values, find the inner html_attribute_value\n const innerValueNode = quotedValueNode.children.find(\n (child: any) => child.type === \"html_attribute_value\"\n );\n value = innerValueNode ? innerValueNode.text : undefined;\n } else if (valueNode) {\n value = valueNode.text;\n }\n\n const attribute: HtmlAttributeNode = {\n type: \"html_attribute\",\n name: nameNode.text,\n };\n\n // Only include value property if there's actually a value\n if (value !== undefined) {\n attribute.value = value;\n }\n\n attributes.push(attribute);\n }\n\n const elementChildren: (\n | HtmlElementNode\n | ContentNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n )[] = [];\n\n // Process all children that are not start/end tags\n for (const child of node.children) {\n if (child.type === \"content\") {\n elementChildren.push({\n type: \"content\",\n content: child.text,\n });\n } else if (child.type === \"html_element\") {\n const nestedElement = convertHtmlElement(child);\n if (nestedElement) {\n elementChildren.push(nestedElement);\n }\n } else if (child.type === \"html_entity\") {\n const entityNode = convertHtmlEntity(child);\n if (entityNode) {\n elementChildren.push(entityNode);\n }\n }\n }\n\n const result: HtmlElementNode = {\n type: \"html_element\",\n name: tagName.text,\n children: elementChildren,\n };\n\n if (attributes.length > 0) {\n result.attributes = attributes;\n }\n\n if (isVoid) {\n result.void = true;\n }\n\n return result;\n }\n return null;\n }\n\n for (const child of tree.rootNode.children) {\n if (child.type === \"content\") {\n allNodes.push({\n type: \"content\",\n content: child.text,\n });\n } else if (child.type === \"html_element\") {\n const htmlElement = convertHtmlElement(child);\n if (htmlElement) {\n allNodes.push(htmlElement);\n }\n } else if (child.type === \"html_doctype\") {\n allNodes.push({\n type: \"doctype\",\n });\n } else if (child.type === \"html_entity\") {\n const entityNode = convertHtmlEntity(child);\n if (entityNode) {\n allNodes.push(entityNode);\n }\n } else {\n const converted = convertNode(child);\n if (converted) {\n rawNodes.push(converted);\n allNodes.push(converted);\n }\n }\n }\n\n // Second pass: build nested structure using a stack\n function buildNestedStructure(\n nodes: Array<\n | {\n type:\n | \"block\"\n | \"endblock\"\n | \"function\"\n | \"if\"\n | \"endif\"\n | \"content\"\n | \"html_element\"\n | \"doctype\";\n name?: string;\n functionName?: string;\n expression?: string;\n content?: string;\n }\n | HtmlElementNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n >\n ): (\n | TwigStatementDirectiveNode\n | HtmlElementNode\n | ContentNode\n | HtmlDoctypeNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n )[] {\n const result: (\n | TwigStatementDirectiveNode\n | HtmlElementNode\n | ContentNode\n | HtmlDoctypeNode\n | HtmlNamedEntityNode\n | HtmlNumericEntityNode\n )[] = [];\n const stack: TwigStatementDirectiveNode[] = [];\n\n for (const node of nodes) {\n if (node.type === \"block\") {\n const blockNode: TwigStatementDirectiveNode = {\n tag: {\n type: \"twig_tag\",\n name: \"block\",\n },\n type: \"twig_statement_directive\",\n variable: {\n type: \"twig_variable\",\n content: node.name!,\n },\n children: [],\n };\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(blockNode);\n }\n } else {\n // Add to root level\n result.push(blockNode);\n }\n\n // Push to stack for nesting\n stack.push(blockNode);\n } else if (node.type === \"endblock\") {\n // Pop from stack when we encounter an endblock\n stack.pop();\n } else if (node.type === \"if\") {\n const ifNode: TwigStatementDirectiveNode = {\n type: \"twig_statement_directive\",\n condition: {\n type: \"twig_condition\",\n expression: {\n type: \"twig_expression\",\n content: node.expression!,\n },\n },\n children: [],\n };\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(ifNode);\n }\n } else {\n // Add to root level\n result.push(ifNode);\n }\n\n // Push to stack for nesting\n stack.push(ifNode);\n } else if (node.type === \"endif\") {\n // Pop from stack when we encounter an endif\n stack.pop();\n } else if (node.type === \"function\") {\n const functionNode: TwigStatementDirectiveNode = {\n type: \"twig_statement_directive\",\n function: {\n type: \"twig_function\",\n name: node.functionName!,\n },\n };\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(functionNode);\n }\n } else {\n // Add to root level\n result.push(functionNode);\n }\n } else if (node.type === \"content\") {\n const contentNode: ContentNode = {\n type: \"content\",\n content: node.content!,\n };\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(contentNode);\n }\n } else {\n // Content at root level - this shouldn't happen in well-formed templates\n // but we'll handle it gracefully\n result.push({\n type: \"twig_statement_directive\",\n children: [contentNode],\n });\n }\n } else if (node.type === \"html_element\" && \"name\" in node) {\n // HTML elements are already processed and can be added directly\n const htmlNode = node as HtmlElementNode;\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(htmlNode);\n }\n } else {\n // Add to root level\n result.push(htmlNode);\n }\n } else if (node.type === \"doctype\") {\n const doctypeNode: HtmlDoctypeNode = {\n type: \"doctype\",\n };\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(doctypeNode);\n }\n } else {\n // Add to root level\n result.push(doctypeNode);\n }\n } else if (node.type === \"html_named_entity\" && \"content\" in node) {\n const entityNode = node as HtmlNamedEntityNode;\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(entityNode);\n }\n } else {\n // Add to root level\n result.push(entityNode);\n }\n } else if (node.type === \"html_numeric_entity\" && \"content\" in node) {\n const entityNode = node as HtmlNumericEntityNode;\n\n if (stack.length > 0) {\n // Add to the current parent's children\n const parent = stack[stack.length - 1];\n if (parent && parent.children) {\n parent.children.push(entityNode);\n }\n } else {\n // Add to root level\n result.push(entityNode);\n }\n }\n }\n\n return result;\n }\n\n const children = buildNestedStructure(allNodes);\n\n return {\n rootNode: {\n type: \"template\",\n children,\n },\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shopware-twig-parser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"main": "./dist/commonjs/index.js",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"tree-sitter": "^0.25.0",
|
|
21
|
-
"tree-sitter-shopware-twig": "^0.2.
|
|
21
|
+
"tree-sitter-shopware-twig": "^0.2.4"
|
|
22
22
|
},
|
|
23
23
|
"type": "module",
|
|
24
24
|
"tshy": {
|