@platformos/liquid-html-parser 0.0.2
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/README.md +62 -0
- package/dist/conditional-comment.d.ts +5 -0
- package/dist/conditional-comment.js +16 -0
- package/dist/errors.d.ts +27 -0
- package/dist/errors.js +57 -0
- package/dist/grammar.d.ts +16 -0
- package/dist/grammar.js +42 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +28 -0
- package/dist/stage-1-cst.d.ts +477 -0
- package/dist/stage-1-cst.js +1104 -0
- package/dist/stage-2-ast.d.ts +794 -0
- package/dist/stage-2-ast.js +1513 -0
- package/dist/types.d.ts +124 -0
- package/dist/types.js +146 -0
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +31 -0
- package/grammar/liquid-html.ohm +750 -0
- package/grammar/liquid-html.ohm.js +751 -0
- package/package.json +41 -0
|
@@ -0,0 +1,1513 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* This is the second stage of the parser.
|
|
4
|
+
*
|
|
5
|
+
* Input:
|
|
6
|
+
* - A Concrete Syntax Tree (CST)
|
|
7
|
+
*
|
|
8
|
+
* Output:
|
|
9
|
+
* - An Abstract Syntax Tree (AST)
|
|
10
|
+
*
|
|
11
|
+
* This stage traverses the flat tree we get from the previous stage and
|
|
12
|
+
* establishes the parent/child relationship between the nodes.
|
|
13
|
+
*
|
|
14
|
+
* Recall the Liquid example we had in the first stage:
|
|
15
|
+
* {% if cond %}hi <em>there!</em>{% endif %}
|
|
16
|
+
*
|
|
17
|
+
* Whereas the previous stage gives us this CST:
|
|
18
|
+
* - LiquidTagOpen/if
|
|
19
|
+
* condition: LiquidVariableExpression/cond
|
|
20
|
+
* - TextNode/"hi "
|
|
21
|
+
* - HtmlTagOpen/em
|
|
22
|
+
* - TextNode/"there!"
|
|
23
|
+
* - HtmlTagClose/em
|
|
24
|
+
* - LiquidTagClose/if
|
|
25
|
+
*
|
|
26
|
+
* We now traverse all the nodes and turn that into a proper AST:
|
|
27
|
+
* - LiquidTag/if
|
|
28
|
+
* condition: LiquidVariableExpression
|
|
29
|
+
* children:
|
|
30
|
+
* - TextNode/"hi "
|
|
31
|
+
* - HtmlElement/em
|
|
32
|
+
* children:
|
|
33
|
+
* - TextNode/"there!"
|
|
34
|
+
*
|
|
35
|
+
*/
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.RawMarkupKinds = void 0;
|
|
38
|
+
exports.isBranchedTag = isBranchedTag;
|
|
39
|
+
exports.toLiquidAST = toLiquidAST;
|
|
40
|
+
exports.toLiquidHtmlAST = toLiquidHtmlAST;
|
|
41
|
+
exports.getName = getName;
|
|
42
|
+
exports.cstToAst = cstToAst;
|
|
43
|
+
exports.walk = walk;
|
|
44
|
+
exports.isLiquidHtmlNode = isLiquidHtmlNode;
|
|
45
|
+
const stage_1_cst_1 = require("./stage-1-cst");
|
|
46
|
+
const types_1 = require("./types");
|
|
47
|
+
const utils_1 = require("./utils");
|
|
48
|
+
const errors_1 = require("./errors");
|
|
49
|
+
const grammar_1 = require("./grammar");
|
|
50
|
+
const stage_1_cst_2 = require("./stage-1-cst");
|
|
51
|
+
/**
|
|
52
|
+
* The infered kind of raw markup
|
|
53
|
+
* - `<script>` is javascript
|
|
54
|
+
* - `<script type="application/json">` is JSON
|
|
55
|
+
* - `<style>` is css
|
|
56
|
+
* - etc.
|
|
57
|
+
*/
|
|
58
|
+
var RawMarkupKinds;
|
|
59
|
+
(function (RawMarkupKinds) {
|
|
60
|
+
RawMarkupKinds["css"] = "css";
|
|
61
|
+
RawMarkupKinds["html"] = "html";
|
|
62
|
+
RawMarkupKinds["javascript"] = "javascript";
|
|
63
|
+
RawMarkupKinds["json"] = "json";
|
|
64
|
+
RawMarkupKinds["markdown"] = "markdown";
|
|
65
|
+
RawMarkupKinds["typescript"] = "typescript";
|
|
66
|
+
RawMarkupKinds["text"] = "text";
|
|
67
|
+
})(RawMarkupKinds || (exports.RawMarkupKinds = RawMarkupKinds = {}));
|
|
68
|
+
function isBranchedTag(node) {
|
|
69
|
+
return (node.type === types_1.NodeTypes.LiquidTag && ['if', 'for', 'unless', 'case', 'try'].includes(node.name));
|
|
70
|
+
}
|
|
71
|
+
function isConcreteLiquidBranchDisguisedAsTag(node) {
|
|
72
|
+
return (node.type === stage_1_cst_1.ConcreteNodeTypes.LiquidTag &&
|
|
73
|
+
['else', 'elsif', 'when', 'catch'].includes(node.name));
|
|
74
|
+
}
|
|
75
|
+
function toLiquidAST(source, options = {
|
|
76
|
+
allowUnclosedDocumentNode: true,
|
|
77
|
+
mode: 'tolerant',
|
|
78
|
+
}) {
|
|
79
|
+
const cst = (0, stage_1_cst_2.toLiquidCST)(source, { mode: options.mode });
|
|
80
|
+
const root = {
|
|
81
|
+
type: types_1.NodeTypes.Document,
|
|
82
|
+
source: source,
|
|
83
|
+
_source: source, // this can get replaced somewhere else...
|
|
84
|
+
children: cstToAst(cst, options),
|
|
85
|
+
name: '#document',
|
|
86
|
+
position: {
|
|
87
|
+
start: 0,
|
|
88
|
+
end: source.length,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
return root;
|
|
92
|
+
}
|
|
93
|
+
function toLiquidHtmlAST(source, options = {
|
|
94
|
+
allowUnclosedDocumentNode: false,
|
|
95
|
+
mode: 'tolerant',
|
|
96
|
+
}) {
|
|
97
|
+
const cst = (0, stage_1_cst_1.toLiquidHtmlCST)(source, { mode: options.mode });
|
|
98
|
+
const root = {
|
|
99
|
+
type: types_1.NodeTypes.Document,
|
|
100
|
+
source: source,
|
|
101
|
+
_source: source,
|
|
102
|
+
children: cstToAst(cst, options),
|
|
103
|
+
name: '#document',
|
|
104
|
+
position: {
|
|
105
|
+
start: 0,
|
|
106
|
+
end: source.length,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
return root;
|
|
110
|
+
}
|
|
111
|
+
class ASTBuilder {
|
|
112
|
+
constructor(source) {
|
|
113
|
+
this.ast = [];
|
|
114
|
+
this.cursor = [];
|
|
115
|
+
this.source = source;
|
|
116
|
+
}
|
|
117
|
+
// Returns the array to push nodes to.
|
|
118
|
+
get current() {
|
|
119
|
+
return (0, utils_1.deepGet)(this.cursor, this.ast);
|
|
120
|
+
}
|
|
121
|
+
// Returns the position of the current node in the array
|
|
122
|
+
get currentPosition() {
|
|
123
|
+
return (this.current || []).length - 1;
|
|
124
|
+
}
|
|
125
|
+
get parent() {
|
|
126
|
+
if (this.cursor.length == 0)
|
|
127
|
+
return undefined;
|
|
128
|
+
return (0, utils_1.deepGet)((0, utils_1.dropLast)(1, this.cursor), this.ast);
|
|
129
|
+
}
|
|
130
|
+
get grandparent() {
|
|
131
|
+
if (this.cursor.length < 4)
|
|
132
|
+
return undefined;
|
|
133
|
+
return (0, utils_1.deepGet)((0, utils_1.dropLast)(3, this.cursor), this.ast);
|
|
134
|
+
}
|
|
135
|
+
open(node) {
|
|
136
|
+
this.current.push(node);
|
|
137
|
+
this.cursor.push(this.currentPosition);
|
|
138
|
+
this.cursor.push('children');
|
|
139
|
+
if (isBranchedTag(node)) {
|
|
140
|
+
this.open(toUnnamedLiquidBranch(node));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
push(node) {
|
|
144
|
+
if (node.type === types_1.NodeTypes.LiquidBranch) {
|
|
145
|
+
const previousBranch = this.findCloseableParentBranch(node);
|
|
146
|
+
if (previousBranch) {
|
|
147
|
+
previousBranch.blockEndPosition = { start: node.position.start, end: node.position.start };
|
|
148
|
+
// close dangling open HTML nodes
|
|
149
|
+
while (this.parent &&
|
|
150
|
+
this.parent !== previousBranch &&
|
|
151
|
+
this.parent.type === types_1.NodeTypes.HtmlElement) {
|
|
152
|
+
// 0-length blockEndPosition at the position of the next branch
|
|
153
|
+
this.parent.blockEndPosition = { start: node.position.start, end: node.position.start };
|
|
154
|
+
this.closeParentWith(node);
|
|
155
|
+
}
|
|
156
|
+
// close the previous branch
|
|
157
|
+
this.closeParentWith(node);
|
|
158
|
+
}
|
|
159
|
+
this.open(node);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
this.current.push(node);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
close(node, nodeType) {
|
|
166
|
+
if (isLiquidBranch(this.parent)) {
|
|
167
|
+
this.parent.blockEndPosition = { start: node.locStart, end: node.locStart };
|
|
168
|
+
this.closeParentWith(node);
|
|
169
|
+
}
|
|
170
|
+
if (!this.parent) {
|
|
171
|
+
throw new errors_1.LiquidHTMLASTParsingError(`Attempting to close ${nodeType} '${getName(node)}' before it was opened`, this.source, node.locStart, node.locEnd);
|
|
172
|
+
}
|
|
173
|
+
if (getName(this.parent) !== getName(node) || this.parent.type !== nodeType) {
|
|
174
|
+
const suitableParent = this.findCloseableParentNode(node);
|
|
175
|
+
if (this.parent.type === types_1.NodeTypes.HtmlElement && suitableParent) {
|
|
176
|
+
// close dangling open HTML nodes
|
|
177
|
+
while (this.parent !== suitableParent) {
|
|
178
|
+
// 0-length end block position
|
|
179
|
+
this.parent.blockEndPosition = { start: node.locStart, end: node.locStart };
|
|
180
|
+
this.closeParentWith(node);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
throw new errors_1.LiquidHTMLASTParsingError(`Attempting to close ${nodeType} '${getName(node)}' before ${this.parent.type} '${getName(this.parent)}' was closed`, this.source, this.parent.position.start, node.locEnd, getUnclosed(this.parent));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// The parent end is the end of the outer tag.
|
|
188
|
+
this.parent.position.end = node.locEnd;
|
|
189
|
+
this.parent.blockEndPosition = position(node);
|
|
190
|
+
if (this.parent.type == types_1.NodeTypes.LiquidTag && node.type == stage_1_cst_1.ConcreteNodeTypes.LiquidTagClose) {
|
|
191
|
+
this.parent.delimiterWhitespaceStart = node.whitespaceStart ?? '';
|
|
192
|
+
this.parent.delimiterWhitespaceEnd = node.whitespaceEnd ?? '';
|
|
193
|
+
}
|
|
194
|
+
this.cursor.pop();
|
|
195
|
+
this.cursor.pop();
|
|
196
|
+
}
|
|
197
|
+
// This function performs the following tasks:
|
|
198
|
+
// - Tries to find a parent branch to close when pushing a new branch.
|
|
199
|
+
// - This is necessary because we allow unclosed HTML element nodes.
|
|
200
|
+
// - The function traverses up the tree until it finds a LiquidBranch.
|
|
201
|
+
// - If it encounters anything other than an Unclosed HTML Element, it throws.
|
|
202
|
+
findCloseableParentBranch(next) {
|
|
203
|
+
for (let index = this.cursor.length - 1; index > 0; index -= 2) {
|
|
204
|
+
const parent = (0, utils_1.deepGet)(this.cursor.slice(0, index), this.ast);
|
|
205
|
+
const parentProperty = this.cursor[index];
|
|
206
|
+
const isUnclosedHtmlElement = parent.type === types_1.NodeTypes.HtmlElement && parentProperty === 'children';
|
|
207
|
+
if (parent.type === types_1.NodeTypes.LiquidBranch) {
|
|
208
|
+
return parent;
|
|
209
|
+
}
|
|
210
|
+
else if (!isUnclosedHtmlElement) {
|
|
211
|
+
throw new errors_1.LiquidHTMLASTParsingError(`Attempting to open LiquidBranch '${next.name}' before ${parent.type} '${getName(parent)}' was closed`, this.source, parent.position.start, next.position.end);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
// Check if there's a parent in the ancestry that this node correctly closes
|
|
217
|
+
findCloseableParentNode(current) {
|
|
218
|
+
for (let index = this.cursor.length - 1; index > 0; index -= 2) {
|
|
219
|
+
const parent = (0, utils_1.deepGet)(this.cursor.slice(0, index), this.ast);
|
|
220
|
+
if (getName(parent) === getName(current) &&
|
|
221
|
+
parent.type === types_1.NodeTypes.LiquidTag &&
|
|
222
|
+
['if', 'unless', 'case'].includes(parent.name)) {
|
|
223
|
+
return parent;
|
|
224
|
+
}
|
|
225
|
+
else if (parent.type === types_1.NodeTypes.LiquidTag) {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
// sets the parent's end position to the start of the next one.
|
|
232
|
+
closeParentWith(next) {
|
|
233
|
+
if (this.parent) {
|
|
234
|
+
if ('locStart' in next) {
|
|
235
|
+
this.parent.position.end = next.locStart;
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
this.parent.position.end = next.position.start;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
this.cursor.pop();
|
|
242
|
+
this.cursor.pop();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function isLiquidBranch(node) {
|
|
246
|
+
return !!node && node.type === types_1.NodeTypes.LiquidBranch;
|
|
247
|
+
}
|
|
248
|
+
function getName(node) {
|
|
249
|
+
if (!node)
|
|
250
|
+
return null;
|
|
251
|
+
switch (node.type) {
|
|
252
|
+
case types_1.NodeTypes.HtmlElement:
|
|
253
|
+
case types_1.NodeTypes.HtmlDanglingMarkerClose:
|
|
254
|
+
case types_1.NodeTypes.HtmlSelfClosingElement:
|
|
255
|
+
case stage_1_cst_1.ConcreteNodeTypes.HtmlTagClose:
|
|
256
|
+
return node.name
|
|
257
|
+
.map((part) => {
|
|
258
|
+
if (part.type === types_1.NodeTypes.TextNode || part.type == stage_1_cst_1.ConcreteNodeTypes.TextNode) {
|
|
259
|
+
return part.value;
|
|
260
|
+
}
|
|
261
|
+
else if (typeof part.markup === 'string') {
|
|
262
|
+
return `{{${part.markup.trim()}}}`;
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
return `{{${part.markup.rawSource}}}`;
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
.join('');
|
|
269
|
+
case types_1.NodeTypes.AttrEmpty:
|
|
270
|
+
case types_1.NodeTypes.AttrUnquoted:
|
|
271
|
+
case types_1.NodeTypes.AttrDoubleQuoted:
|
|
272
|
+
case types_1.NodeTypes.AttrSingleQuoted:
|
|
273
|
+
// <a href="{{ hello }}">
|
|
274
|
+
return node.name
|
|
275
|
+
.map((part) => {
|
|
276
|
+
if (typeof part === 'string') {
|
|
277
|
+
return part;
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
return part.source.slice(part.position.start, part.position.end);
|
|
281
|
+
}
|
|
282
|
+
})
|
|
283
|
+
.join('');
|
|
284
|
+
default:
|
|
285
|
+
return node.name;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
function cstToAst(cst, options) {
|
|
289
|
+
if (cst.length === 0)
|
|
290
|
+
return [];
|
|
291
|
+
const builder = buildAst(cst, options);
|
|
292
|
+
if (!options.allowUnclosedDocumentNode && builder.cursor.length !== 0) {
|
|
293
|
+
throw new errors_1.LiquidHTMLASTParsingError(`Attempting to end parsing before ${builder.parent?.type} '${getName(builder.parent)}' was closed`, builder.source, builder.source.length - 1, builder.source.length, getUnclosed(builder.parent, builder.grandparent));
|
|
294
|
+
}
|
|
295
|
+
return builder.ast;
|
|
296
|
+
}
|
|
297
|
+
function buildAst(cst, options) {
|
|
298
|
+
const builder = new ASTBuilder(cst[0].source);
|
|
299
|
+
for (let i = 0; i < cst.length; i++) {
|
|
300
|
+
const node = cst[i];
|
|
301
|
+
switch (node.type) {
|
|
302
|
+
case stage_1_cst_1.ConcreteNodeTypes.TextNode: {
|
|
303
|
+
builder.push(toTextNode(node));
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
case stage_1_cst_1.ConcreteNodeTypes.LiquidVariableOutput: {
|
|
307
|
+
builder.push(toLiquidVariableOutput(node));
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
case stage_1_cst_1.ConcreteNodeTypes.LiquidTagOpen: {
|
|
311
|
+
builder.open(toLiquidTag(node, { ...options, isBlockTag: true }));
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
case stage_1_cst_1.ConcreteNodeTypes.LiquidTagClose: {
|
|
315
|
+
builder.close(node, types_1.NodeTypes.LiquidTag);
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
case stage_1_cst_1.ConcreteNodeTypes.LiquidTag: {
|
|
319
|
+
builder.push(toLiquidTag(node, { ...options, isBlockTag: false }));
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
case stage_1_cst_1.ConcreteNodeTypes.LiquidRawTag: {
|
|
323
|
+
builder.push({
|
|
324
|
+
type: types_1.NodeTypes.LiquidRawTag,
|
|
325
|
+
markup: markup(node.name, node.markup),
|
|
326
|
+
name: node.name,
|
|
327
|
+
body: toRawMarkup(node, options),
|
|
328
|
+
whitespaceStart: node.whitespaceStart ?? '',
|
|
329
|
+
whitespaceEnd: node.whitespaceEnd ?? '',
|
|
330
|
+
delimiterWhitespaceStart: node.delimiterWhitespaceStart ?? '',
|
|
331
|
+
delimiterWhitespaceEnd: node.delimiterWhitespaceEnd ?? '',
|
|
332
|
+
position: position(node),
|
|
333
|
+
blockStartPosition: {
|
|
334
|
+
start: node.blockStartLocStart,
|
|
335
|
+
end: node.blockStartLocEnd,
|
|
336
|
+
},
|
|
337
|
+
blockEndPosition: {
|
|
338
|
+
start: node.blockEndLocStart,
|
|
339
|
+
end: node.blockEndLocEnd,
|
|
340
|
+
},
|
|
341
|
+
source: node.source,
|
|
342
|
+
});
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
case stage_1_cst_1.ConcreteNodeTypes.HtmlTagOpen: {
|
|
346
|
+
builder.open(toHtmlElement(node, options));
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
case stage_1_cst_1.ConcreteNodeTypes.HtmlTagClose: {
|
|
350
|
+
if (isAcceptableDanglingMarkerClose(builder, cst, i, options.mode)) {
|
|
351
|
+
builder.push(toHtmlDanglingMarkerClose(node, options));
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
builder.close(node, types_1.NodeTypes.HtmlElement);
|
|
355
|
+
}
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
case stage_1_cst_1.ConcreteNodeTypes.HtmlVoidElement: {
|
|
359
|
+
builder.push(toHtmlVoidElement(node, options));
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
case stage_1_cst_1.ConcreteNodeTypes.HtmlSelfClosingElement: {
|
|
363
|
+
builder.push(toHtmlSelfClosingElement(node, options));
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
case stage_1_cst_1.ConcreteNodeTypes.HtmlDoctype: {
|
|
367
|
+
builder.push({
|
|
368
|
+
type: types_1.NodeTypes.HtmlDoctype,
|
|
369
|
+
legacyDoctypeString: node.legacyDoctypeString,
|
|
370
|
+
position: position(node),
|
|
371
|
+
source: node.source,
|
|
372
|
+
});
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
case stage_1_cst_1.ConcreteNodeTypes.HtmlComment: {
|
|
376
|
+
builder.push({
|
|
377
|
+
type: types_1.NodeTypes.HtmlComment,
|
|
378
|
+
body: node.body,
|
|
379
|
+
position: position(node),
|
|
380
|
+
source: node.source,
|
|
381
|
+
});
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
384
|
+
case stage_1_cst_1.ConcreteNodeTypes.HtmlRawTag: {
|
|
385
|
+
builder.push({
|
|
386
|
+
type: types_1.NodeTypes.HtmlRawNode,
|
|
387
|
+
name: node.name,
|
|
388
|
+
body: toRawMarkup(node, options),
|
|
389
|
+
attributes: toAttributes(node.attrList || [], options),
|
|
390
|
+
position: position(node),
|
|
391
|
+
source: node.source,
|
|
392
|
+
blockStartPosition: {
|
|
393
|
+
start: node.blockStartLocStart,
|
|
394
|
+
end: node.blockStartLocEnd,
|
|
395
|
+
},
|
|
396
|
+
blockEndPosition: {
|
|
397
|
+
start: node.blockEndLocStart,
|
|
398
|
+
end: node.blockEndLocEnd,
|
|
399
|
+
},
|
|
400
|
+
});
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
case stage_1_cst_1.ConcreteNodeTypes.AttrEmpty: {
|
|
404
|
+
builder.push({
|
|
405
|
+
type: types_1.NodeTypes.AttrEmpty,
|
|
406
|
+
name: cstToAst(node.name, options),
|
|
407
|
+
position: position(node),
|
|
408
|
+
source: node.source,
|
|
409
|
+
});
|
|
410
|
+
break;
|
|
411
|
+
}
|
|
412
|
+
case stage_1_cst_1.ConcreteNodeTypes.AttrSingleQuoted:
|
|
413
|
+
case stage_1_cst_1.ConcreteNodeTypes.AttrDoubleQuoted:
|
|
414
|
+
case stage_1_cst_1.ConcreteNodeTypes.AttrUnquoted: {
|
|
415
|
+
const abstractNode = {
|
|
416
|
+
type: node.type,
|
|
417
|
+
name: cstToAst(node.name, options),
|
|
418
|
+
position: position(node),
|
|
419
|
+
source: node.source,
|
|
420
|
+
// placeholders
|
|
421
|
+
attributePosition: { start: -1, end: -1 },
|
|
422
|
+
value: [],
|
|
423
|
+
};
|
|
424
|
+
const value = toAttributeValue(node.value, options);
|
|
425
|
+
abstractNode.value = value;
|
|
426
|
+
abstractNode.attributePosition = toAttributePosition(node, value);
|
|
427
|
+
builder.push(abstractNode);
|
|
428
|
+
break;
|
|
429
|
+
}
|
|
430
|
+
case stage_1_cst_1.ConcreteNodeTypes.YAMLFrontmatter: {
|
|
431
|
+
builder.push({
|
|
432
|
+
type: types_1.NodeTypes.YAMLFrontmatter,
|
|
433
|
+
body: node.body,
|
|
434
|
+
position: position(node),
|
|
435
|
+
source: node.source,
|
|
436
|
+
});
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
case stage_1_cst_1.ConcreteNodeTypes.LiquidDocParamNode: {
|
|
440
|
+
builder.push({
|
|
441
|
+
type: types_1.NodeTypes.LiquidDocParamNode,
|
|
442
|
+
name: node.name,
|
|
443
|
+
position: position(node),
|
|
444
|
+
source: node.source,
|
|
445
|
+
paramName: toTextNode(node.paramName.content),
|
|
446
|
+
paramDescription: toNullableTextNode(node.paramDescription),
|
|
447
|
+
paramType: toNullableTextNode(node.paramType),
|
|
448
|
+
required: node.paramName.required,
|
|
449
|
+
});
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
case stage_1_cst_1.ConcreteNodeTypes.LiquidDocDescriptionNode: {
|
|
453
|
+
builder.push({
|
|
454
|
+
type: types_1.NodeTypes.LiquidDocDescriptionNode,
|
|
455
|
+
name: node.name,
|
|
456
|
+
position: position(node),
|
|
457
|
+
source: node.source,
|
|
458
|
+
content: toTextNode(node.content),
|
|
459
|
+
isImplicit: node.isImplicit,
|
|
460
|
+
isInline: node.isInline,
|
|
461
|
+
});
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
case stage_1_cst_1.ConcreteNodeTypes.LiquidDocExampleNode: {
|
|
465
|
+
builder.push({
|
|
466
|
+
type: types_1.NodeTypes.LiquidDocExampleNode,
|
|
467
|
+
name: node.name,
|
|
468
|
+
position: position(node),
|
|
469
|
+
source: node.source,
|
|
470
|
+
content: toTextNode(node.content),
|
|
471
|
+
isInline: node.isInline,
|
|
472
|
+
});
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
475
|
+
case stage_1_cst_1.ConcreteNodeTypes.LiquidDocPromptNode: {
|
|
476
|
+
builder.push({
|
|
477
|
+
type: types_1.NodeTypes.LiquidDocPromptNode,
|
|
478
|
+
name: node.name,
|
|
479
|
+
position: position(node),
|
|
480
|
+
source: node.source,
|
|
481
|
+
content: toTextNode(node.content),
|
|
482
|
+
});
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
default: {
|
|
486
|
+
(0, utils_1.assertNever)(node);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return builder;
|
|
491
|
+
}
|
|
492
|
+
function nameLength(names) {
|
|
493
|
+
const start = names.at(0);
|
|
494
|
+
const end = names.at(-1);
|
|
495
|
+
return end.locEnd - start.locStart;
|
|
496
|
+
}
|
|
497
|
+
function toAttributePosition(node, value) {
|
|
498
|
+
if (value.length === 0) {
|
|
499
|
+
// This is bugged when there's whitespace on either side. But I don't
|
|
500
|
+
// think it's worth solving.
|
|
501
|
+
return {
|
|
502
|
+
start: node.locStart + nameLength(node.name) + '='.length + '"'.length,
|
|
503
|
+
// name=""
|
|
504
|
+
// 012345678
|
|
505
|
+
// 0 + 4 + 1 + 1
|
|
506
|
+
// = 6
|
|
507
|
+
end: node.locStart + nameLength(node.name) + '='.length + '"'.length,
|
|
508
|
+
// name=""
|
|
509
|
+
// 012345678
|
|
510
|
+
// 0 + 4 + 1 + 2
|
|
511
|
+
// = 6
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
return {
|
|
515
|
+
start: value[0].position.start,
|
|
516
|
+
end: value[value.length - 1].position.end,
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
function toAttributeValue(value, options) {
|
|
520
|
+
return cstToAst(value, options);
|
|
521
|
+
}
|
|
522
|
+
function toAttributes(attrList, options) {
|
|
523
|
+
return cstToAst(attrList, options);
|
|
524
|
+
}
|
|
525
|
+
function liquidTagBaseAttributes(node) {
|
|
526
|
+
return {
|
|
527
|
+
type: types_1.NodeTypes.LiquidTag,
|
|
528
|
+
position: position(node),
|
|
529
|
+
whitespaceStart: node.whitespaceStart ?? '',
|
|
530
|
+
whitespaceEnd: node.whitespaceEnd ?? '',
|
|
531
|
+
blockStartPosition: position(node),
|
|
532
|
+
source: node.source,
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
function liquidBranchBaseAttributes(node) {
|
|
536
|
+
return {
|
|
537
|
+
type: types_1.NodeTypes.LiquidBranch,
|
|
538
|
+
children: [],
|
|
539
|
+
position: position(node),
|
|
540
|
+
whitespaceStart: node.whitespaceStart ?? '',
|
|
541
|
+
whitespaceEnd: node.whitespaceEnd ?? '',
|
|
542
|
+
blockStartPosition: position(node),
|
|
543
|
+
blockEndPosition: { start: -1, end: -1 },
|
|
544
|
+
source: node.source,
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
function toLiquidTag(node, options) {
|
|
548
|
+
if (typeof node.markup !== 'string') {
|
|
549
|
+
return toNamedLiquidTag(node, options);
|
|
550
|
+
}
|
|
551
|
+
else if (isConcreteLiquidBranchDisguisedAsTag(node)) {
|
|
552
|
+
// `elsif`, `else`, `case`, but with unparseable markup.
|
|
553
|
+
return toNamedLiquidBranchBaseCase(node);
|
|
554
|
+
}
|
|
555
|
+
else if (options.isBlockTag) {
|
|
556
|
+
return {
|
|
557
|
+
name: node.name,
|
|
558
|
+
markup: markup(node.name, node.markup),
|
|
559
|
+
children: options.isBlockTag ? [] : undefined,
|
|
560
|
+
...liquidTagBaseAttributes(node),
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
return {
|
|
564
|
+
name: node.name,
|
|
565
|
+
markup: markup(node.name, node.markup),
|
|
566
|
+
...liquidTagBaseAttributes(node),
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
function toNamedLiquidTag(node, options) {
|
|
570
|
+
switch (node.name) {
|
|
571
|
+
case types_1.NamedTags.echo: {
|
|
572
|
+
return {
|
|
573
|
+
...liquidTagBaseAttributes(node),
|
|
574
|
+
name: types_1.NamedTags.echo,
|
|
575
|
+
markup: toLiquidVariable(node.markup),
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
case types_1.NamedTags.assign: {
|
|
579
|
+
return {
|
|
580
|
+
...liquidTagBaseAttributes(node),
|
|
581
|
+
name: types_1.NamedTags.assign,
|
|
582
|
+
markup: toAssignMarkup(node.markup),
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
case types_1.NamedTags.hash_assign: {
|
|
586
|
+
return {
|
|
587
|
+
...liquidTagBaseAttributes(node),
|
|
588
|
+
name: types_1.NamedTags.hash_assign,
|
|
589
|
+
markup: toHashAssignMarkup(node.markup),
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
case types_1.NamedTags.cycle: {
|
|
593
|
+
return {
|
|
594
|
+
...liquidTagBaseAttributes(node),
|
|
595
|
+
name: node.name,
|
|
596
|
+
markup: toCycleMarkup(node.markup),
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
case types_1.NamedTags.increment:
|
|
600
|
+
case types_1.NamedTags.decrement: {
|
|
601
|
+
return {
|
|
602
|
+
...liquidTagBaseAttributes(node),
|
|
603
|
+
name: node.name,
|
|
604
|
+
markup: toExpression(node.markup),
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
case types_1.NamedTags.capture: {
|
|
608
|
+
return {
|
|
609
|
+
...liquidTagBaseAttributes(node),
|
|
610
|
+
name: node.name,
|
|
611
|
+
markup: toExpression(node.markup),
|
|
612
|
+
children: [],
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
case types_1.NamedTags.content_for: {
|
|
616
|
+
return {
|
|
617
|
+
...liquidTagBaseAttributes(node),
|
|
618
|
+
name: node.name,
|
|
619
|
+
markup: toContentForMarkup(node.markup),
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
case types_1.NamedTags.include:
|
|
623
|
+
case types_1.NamedTags.render: {
|
|
624
|
+
return {
|
|
625
|
+
...liquidTagBaseAttributes(node),
|
|
626
|
+
name: node.name,
|
|
627
|
+
markup: toRenderMarkup(node.markup),
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
case types_1.NamedTags.function: {
|
|
631
|
+
return {
|
|
632
|
+
...liquidTagBaseAttributes(node),
|
|
633
|
+
name: node.name,
|
|
634
|
+
markup: toFunctionMarkup(node.markup),
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
case types_1.NamedTags.graphql: {
|
|
638
|
+
// Handle both file-based and inline syntax
|
|
639
|
+
if (node.markup.type === stage_1_cst_1.ConcreteNodeTypes.GraphQLInlineMarkup) {
|
|
640
|
+
return {
|
|
641
|
+
...liquidTagBaseAttributes(node),
|
|
642
|
+
name: node.name,
|
|
643
|
+
markup: toGraphQLInlineMarkup(node.markup),
|
|
644
|
+
children: [],
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
return {
|
|
648
|
+
...liquidTagBaseAttributes(node),
|
|
649
|
+
name: node.name,
|
|
650
|
+
markup: toGraphQLMarkup(node.markup),
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
case types_1.NamedTags.layout:
|
|
654
|
+
case types_1.NamedTags.section: {
|
|
655
|
+
return {
|
|
656
|
+
...liquidTagBaseAttributes(node),
|
|
657
|
+
name: node.name,
|
|
658
|
+
markup: toExpression(node.markup),
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
case types_1.NamedTags.sections: {
|
|
662
|
+
return {
|
|
663
|
+
...liquidTagBaseAttributes(node),
|
|
664
|
+
name: node.name,
|
|
665
|
+
markup: toExpression(node.markup),
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
case types_1.NamedTags.form: {
|
|
669
|
+
return {
|
|
670
|
+
...liquidTagBaseAttributes(node),
|
|
671
|
+
name: node.name,
|
|
672
|
+
markup: node.markup.map(toLiquidArgument),
|
|
673
|
+
children: [],
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
case types_1.NamedTags.tablerow:
|
|
677
|
+
case types_1.NamedTags.for: {
|
|
678
|
+
return {
|
|
679
|
+
...liquidTagBaseAttributes(node),
|
|
680
|
+
name: node.name,
|
|
681
|
+
markup: toForMarkup(node.markup),
|
|
682
|
+
children: [],
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
case types_1.NamedTags.paginate: {
|
|
686
|
+
return {
|
|
687
|
+
...liquidTagBaseAttributes(node),
|
|
688
|
+
name: node.name,
|
|
689
|
+
markup: toPaginateMarkup(node.markup),
|
|
690
|
+
children: [],
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
case types_1.NamedTags.if:
|
|
694
|
+
case types_1.NamedTags.unless: {
|
|
695
|
+
return {
|
|
696
|
+
...liquidTagBaseAttributes(node),
|
|
697
|
+
name: node.name,
|
|
698
|
+
markup: toConditionalExpression(node.markup),
|
|
699
|
+
blockEndPosition: { start: -1, end: -1 },
|
|
700
|
+
children: [],
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
case types_1.NamedTags.elsif: {
|
|
704
|
+
return {
|
|
705
|
+
...liquidBranchBaseAttributes(node),
|
|
706
|
+
name: node.name,
|
|
707
|
+
markup: toConditionalExpression(node.markup),
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
case types_1.NamedTags.case: {
|
|
711
|
+
return {
|
|
712
|
+
...liquidTagBaseAttributes(node),
|
|
713
|
+
name: node.name,
|
|
714
|
+
markup: toExpression(node.markup),
|
|
715
|
+
children: [],
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
case types_1.NamedTags.when: {
|
|
719
|
+
return {
|
|
720
|
+
...liquidBranchBaseAttributes(node),
|
|
721
|
+
name: node.name,
|
|
722
|
+
markup: node.markup.map(toExpression),
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
case types_1.NamedTags.liquid: {
|
|
726
|
+
return {
|
|
727
|
+
...liquidTagBaseAttributes(node),
|
|
728
|
+
name: node.name,
|
|
729
|
+
markup: cstToAst(node.markup, options),
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
// platformos tags
|
|
733
|
+
case types_1.NamedTags.background: {
|
|
734
|
+
// Handle both file-based and inline syntax
|
|
735
|
+
if (node.markup.type === stage_1_cst_1.ConcreteNodeTypes.BackgroundInlineMarkup) {
|
|
736
|
+
return {
|
|
737
|
+
...liquidTagBaseAttributes(node),
|
|
738
|
+
name: node.name,
|
|
739
|
+
markup: toBackgroundInlineMarkup(node.markup),
|
|
740
|
+
children: [],
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
return {
|
|
744
|
+
...liquidTagBaseAttributes(node),
|
|
745
|
+
name: node.name,
|
|
746
|
+
markup: toBackgroundMarkup(node.markup),
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
case types_1.NamedTags.cache: {
|
|
750
|
+
return {
|
|
751
|
+
...liquidTagBaseAttributes(node),
|
|
752
|
+
name: node.name,
|
|
753
|
+
markup: toCacheMarkup(node.markup),
|
|
754
|
+
children: [],
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
case types_1.NamedTags.parse_json: {
|
|
758
|
+
return {
|
|
759
|
+
...liquidTagBaseAttributes(node),
|
|
760
|
+
name: node.name,
|
|
761
|
+
markup: toExpression(node.markup),
|
|
762
|
+
children: [],
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
case types_1.NamedTags.transaction: {
|
|
766
|
+
return {
|
|
767
|
+
...liquidTagBaseAttributes(node),
|
|
768
|
+
name: node.name,
|
|
769
|
+
markup: node.markup.map(toNamedArgument),
|
|
770
|
+
children: [],
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
case types_1.NamedTags.try: {
|
|
774
|
+
return {
|
|
775
|
+
...liquidTagBaseAttributes(node),
|
|
776
|
+
name: node.name,
|
|
777
|
+
markup: '',
|
|
778
|
+
blockEndPosition: { start: -1, end: -1 },
|
|
779
|
+
children: [],
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
case types_1.NamedTags.catch: {
|
|
783
|
+
return {
|
|
784
|
+
...liquidBranchBaseAttributes(node),
|
|
785
|
+
name: node.name,
|
|
786
|
+
markup: toExpression(node.markup),
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
case types_1.NamedTags.log: {
|
|
790
|
+
return {
|
|
791
|
+
...liquidTagBaseAttributes(node),
|
|
792
|
+
name: node.name,
|
|
793
|
+
markup: toLogMarkup(node.markup),
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
case types_1.NamedTags.print:
|
|
797
|
+
case types_1.NamedTags.return: {
|
|
798
|
+
return {
|
|
799
|
+
...liquidTagBaseAttributes(node),
|
|
800
|
+
name: node.name,
|
|
801
|
+
markup: toLiquidVariable(node.markup),
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
case types_1.NamedTags.yield: {
|
|
805
|
+
return {
|
|
806
|
+
...liquidTagBaseAttributes(node),
|
|
807
|
+
name: node.name,
|
|
808
|
+
markup: toExpression(node.markup),
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
case types_1.NamedTags.session: {
|
|
812
|
+
return {
|
|
813
|
+
...liquidTagBaseAttributes(node),
|
|
814
|
+
name: node.name,
|
|
815
|
+
markup: toSessionMarkup(node.markup),
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
case types_1.NamedTags.export: {
|
|
819
|
+
return {
|
|
820
|
+
...liquidTagBaseAttributes(node),
|
|
821
|
+
name: node.name,
|
|
822
|
+
markup: toExportMarkup(node.markup),
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
case types_1.NamedTags.context:
|
|
826
|
+
case types_1.NamedTags.sign_in: {
|
|
827
|
+
return {
|
|
828
|
+
...liquidTagBaseAttributes(node),
|
|
829
|
+
name: node.name,
|
|
830
|
+
markup: node.markup.map(toNamedArgument),
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
case types_1.NamedTags.redirect_to: {
|
|
834
|
+
return {
|
|
835
|
+
...liquidTagBaseAttributes(node),
|
|
836
|
+
name: node.name,
|
|
837
|
+
markup: toRedirectToMarkup(node.markup),
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
case types_1.NamedTags.include_form: {
|
|
841
|
+
return {
|
|
842
|
+
...liquidTagBaseAttributes(node),
|
|
843
|
+
name: node.name,
|
|
844
|
+
markup: toIncludeFormMarkup(node.markup),
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
case types_1.NamedTags.spam_protection: {
|
|
848
|
+
return {
|
|
849
|
+
...liquidTagBaseAttributes(node),
|
|
850
|
+
name: node.name,
|
|
851
|
+
markup: toSpamProtectionMarkup(node.markup),
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
case types_1.NamedTags.theme_render_rc: {
|
|
855
|
+
return {
|
|
856
|
+
...liquidTagBaseAttributes(node),
|
|
857
|
+
name: node.name,
|
|
858
|
+
markup: toRenderMarkup(node.markup),
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
case types_1.NamedTags.response_status: {
|
|
862
|
+
return {
|
|
863
|
+
...liquidTagBaseAttributes(node),
|
|
864
|
+
name: node.name,
|
|
865
|
+
markup: toExpression(node.markup),
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
case types_1.NamedTags.response_headers: {
|
|
869
|
+
return {
|
|
870
|
+
...liquidTagBaseAttributes(node),
|
|
871
|
+
name: node.name,
|
|
872
|
+
markup: toExpression(node.markup),
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
case types_1.NamedTags.rollback: {
|
|
876
|
+
return {
|
|
877
|
+
...liquidTagBaseAttributes(node),
|
|
878
|
+
name: node.name,
|
|
879
|
+
markup: '',
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
default: {
|
|
883
|
+
return (0, utils_1.assertNever)(node);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
function toNamedLiquidBranchBaseCase(node) {
|
|
888
|
+
return {
|
|
889
|
+
name: node.name,
|
|
890
|
+
type: types_1.NodeTypes.LiquidBranch,
|
|
891
|
+
markup: node.name !== 'else' ? node.markup : '', // stripping superfluous else stuff...
|
|
892
|
+
position: { start: node.locStart, end: node.locEnd },
|
|
893
|
+
children: [],
|
|
894
|
+
blockStartPosition: { start: node.locStart, end: node.locEnd },
|
|
895
|
+
blockEndPosition: { start: -1, end: -1 },
|
|
896
|
+
whitespaceStart: node.whitespaceStart ?? '',
|
|
897
|
+
whitespaceEnd: node.whitespaceEnd ?? '',
|
|
898
|
+
source: node.source,
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
function toUnnamedLiquidBranch(parentNode) {
|
|
902
|
+
return {
|
|
903
|
+
type: types_1.NodeTypes.LiquidBranch,
|
|
904
|
+
name: null,
|
|
905
|
+
markup: '',
|
|
906
|
+
position: { start: parentNode.position.end, end: parentNode.position.end },
|
|
907
|
+
blockStartPosition: { start: parentNode.position.end, end: parentNode.position.end },
|
|
908
|
+
blockEndPosition: { start: -1, end: -1 },
|
|
909
|
+
children: [],
|
|
910
|
+
whitespaceStart: '',
|
|
911
|
+
whitespaceEnd: '',
|
|
912
|
+
source: parentNode.source,
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
function toAssignMarkup(node) {
|
|
916
|
+
return {
|
|
917
|
+
type: types_1.NodeTypes.AssignMarkup,
|
|
918
|
+
name: node.name,
|
|
919
|
+
value: toLiquidVariable(node.value),
|
|
920
|
+
position: position(node),
|
|
921
|
+
source: node.source,
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
function toHashAssignMarkup(node) {
|
|
925
|
+
return {
|
|
926
|
+
type: types_1.NodeTypes.HashAssignMarkup,
|
|
927
|
+
target: toExpression(node.target),
|
|
928
|
+
value: toLiquidVariable(node.value),
|
|
929
|
+
position: position(node),
|
|
930
|
+
source: node.source,
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
function toCycleMarkup(node) {
|
|
934
|
+
return {
|
|
935
|
+
type: types_1.NodeTypes.CycleMarkup,
|
|
936
|
+
groupName: node.groupName ? toExpression(node.groupName) : null,
|
|
937
|
+
args: node.args.map(toExpression),
|
|
938
|
+
position: position(node),
|
|
939
|
+
source: node.source,
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
function toForMarkup(node) {
|
|
943
|
+
return {
|
|
944
|
+
type: types_1.NodeTypes.ForMarkup,
|
|
945
|
+
variableName: node.variableName,
|
|
946
|
+
collection: toExpression(node.collection),
|
|
947
|
+
args: node.args.map(toNamedArgument),
|
|
948
|
+
reversed: !!node.reversed,
|
|
949
|
+
position: position(node),
|
|
950
|
+
source: node.source,
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
function toPaginateMarkup(node) {
|
|
954
|
+
return {
|
|
955
|
+
type: types_1.NodeTypes.PaginateMarkup,
|
|
956
|
+
collection: toExpression(node.collection),
|
|
957
|
+
pageSize: toExpression(node.pageSize),
|
|
958
|
+
position: position(node),
|
|
959
|
+
args: node.args ? node.args.map(toNamedArgument) : [],
|
|
960
|
+
source: node.source,
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
function toRawMarkup(node, options) {
|
|
964
|
+
return {
|
|
965
|
+
type: types_1.NodeTypes.RawMarkup,
|
|
966
|
+
kind: toRawMarkupKind(node),
|
|
967
|
+
nodes: cstToAst(node.children, options),
|
|
968
|
+
value: node.body,
|
|
969
|
+
position: {
|
|
970
|
+
start: node.blockStartLocEnd,
|
|
971
|
+
end: node.blockEndLocStart,
|
|
972
|
+
},
|
|
973
|
+
source: node.source,
|
|
974
|
+
};
|
|
975
|
+
}
|
|
976
|
+
function toRawMarkupKind(node) {
|
|
977
|
+
switch (node.type) {
|
|
978
|
+
case stage_1_cst_1.ConcreteNodeTypes.HtmlRawTag:
|
|
979
|
+
return toRawMarkupKindFromHtmlNode(node);
|
|
980
|
+
case stage_1_cst_1.ConcreteNodeTypes.LiquidRawTag:
|
|
981
|
+
return toRawMarkupKindFromLiquidNode(node);
|
|
982
|
+
default:
|
|
983
|
+
return (0, utils_1.assertNever)(node);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
const liquidToken = /(\{%|\{\{)-?/g;
|
|
987
|
+
function toRawMarkupKindFromHtmlNode(node) {
|
|
988
|
+
switch (node.name) {
|
|
989
|
+
case 'script': {
|
|
990
|
+
const scriptAttr = node.attrList?.find((attr) => 'name' in attr &&
|
|
991
|
+
typeof attr.name !== 'string' &&
|
|
992
|
+
attr.name.length === 1 &&
|
|
993
|
+
attr.name[0].type === stage_1_cst_1.ConcreteNodeTypes.TextNode &&
|
|
994
|
+
attr.name[0].value === 'type');
|
|
995
|
+
if (!scriptAttr ||
|
|
996
|
+
!('value' in scriptAttr) ||
|
|
997
|
+
scriptAttr.value.length === 0 ||
|
|
998
|
+
scriptAttr.value[0].type !== stage_1_cst_1.ConcreteNodeTypes.TextNode) {
|
|
999
|
+
return RawMarkupKinds.javascript;
|
|
1000
|
+
}
|
|
1001
|
+
const type = scriptAttr.value[0].value;
|
|
1002
|
+
if (type === 'text/markdown') {
|
|
1003
|
+
return RawMarkupKinds.markdown;
|
|
1004
|
+
}
|
|
1005
|
+
if (type === 'application/x-typescript') {
|
|
1006
|
+
return RawMarkupKinds.typescript;
|
|
1007
|
+
}
|
|
1008
|
+
if (type === 'text/html') {
|
|
1009
|
+
return RawMarkupKinds.html;
|
|
1010
|
+
}
|
|
1011
|
+
if ((type && (type.endsWith('json') || type.endsWith('importmap'))) ||
|
|
1012
|
+
type === 'speculationrules') {
|
|
1013
|
+
return RawMarkupKinds.json;
|
|
1014
|
+
}
|
|
1015
|
+
return RawMarkupKinds.javascript;
|
|
1016
|
+
}
|
|
1017
|
+
case 'style':
|
|
1018
|
+
if (liquidToken.test(node.body)) {
|
|
1019
|
+
return RawMarkupKinds.text;
|
|
1020
|
+
}
|
|
1021
|
+
return RawMarkupKinds.css;
|
|
1022
|
+
default:
|
|
1023
|
+
return RawMarkupKinds.text;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
function toRawMarkupKindFromLiquidNode(node) {
|
|
1027
|
+
switch (node.name) {
|
|
1028
|
+
case 'javascript':
|
|
1029
|
+
return RawMarkupKinds.javascript;
|
|
1030
|
+
case 'stylesheet':
|
|
1031
|
+
case 'style':
|
|
1032
|
+
if (liquidToken.test(node.body)) {
|
|
1033
|
+
return RawMarkupKinds.text;
|
|
1034
|
+
}
|
|
1035
|
+
return RawMarkupKinds.css;
|
|
1036
|
+
case 'schema':
|
|
1037
|
+
return RawMarkupKinds.json;
|
|
1038
|
+
default:
|
|
1039
|
+
return RawMarkupKinds.text;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
function toContentForMarkup(node) {
|
|
1043
|
+
return {
|
|
1044
|
+
type: types_1.NodeTypes.ContentForMarkup,
|
|
1045
|
+
contentForType: toExpression(node.contentForType),
|
|
1046
|
+
/**
|
|
1047
|
+
* When we're in completion mode we won't necessarily have valid named
|
|
1048
|
+
* arguments so we need to call toLiquidArgument instead of toNamedArgument.
|
|
1049
|
+
* We cast using `as` so that this doesn't affect the type system used in
|
|
1050
|
+
* other areas (like theme check) for a scenario that only occurs in
|
|
1051
|
+
* completion mode. This means that our types are *wrong* in completion mode
|
|
1052
|
+
* but this is the compromise we're making to get completions to work.
|
|
1053
|
+
*/
|
|
1054
|
+
args: node.args.map(toLiquidArgument),
|
|
1055
|
+
position: position(node),
|
|
1056
|
+
source: node.source,
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
1059
|
+
function toRenderMarkup(node) {
|
|
1060
|
+
return {
|
|
1061
|
+
type: types_1.NodeTypes.RenderMarkup,
|
|
1062
|
+
snippet: toExpression(node.snippet),
|
|
1063
|
+
alias: toRenderAliasExpression(node.alias),
|
|
1064
|
+
variable: toRenderVariableExpression(node.variable),
|
|
1065
|
+
/**
|
|
1066
|
+
* When we're in completion mode we won't necessarily have valid named
|
|
1067
|
+
* arguments so we need to call toLiquidArgument instead of toNamedArgument.
|
|
1068
|
+
* We cast using `as` so that this doesn't affect the type system used in
|
|
1069
|
+
* other areas (like theme check) for a scenario that only occurs in
|
|
1070
|
+
* completion mode. This means that our types are *wrong* in completion mode
|
|
1071
|
+
* but this is the compromise we're making to get completions to work.
|
|
1072
|
+
*/
|
|
1073
|
+
args: node.renderArguments.map(toLiquidArgument),
|
|
1074
|
+
position: position(node),
|
|
1075
|
+
source: node.source,
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
function toFunctionMarkup(node) {
|
|
1079
|
+
return {
|
|
1080
|
+
name: node.name,
|
|
1081
|
+
type: types_1.NodeTypes.FunctionMarkup,
|
|
1082
|
+
partial: toExpression(node.partial),
|
|
1083
|
+
/**
|
|
1084
|
+
* When we're in completion mode we won't necessarily have valid named
|
|
1085
|
+
* arguments so we need to call toLiquidArgument instead of toNamedArgument.
|
|
1086
|
+
* We cast using `as` so that this doesn't affect the type system used in
|
|
1087
|
+
* other areas (like theme check) for a scenario that only occurs in
|
|
1088
|
+
* completion mode. This means that our types are *wrong* in completion mode
|
|
1089
|
+
* but this is the compromise we're making to get completions to work.
|
|
1090
|
+
*/
|
|
1091
|
+
args: node.functionArguments.map(toLiquidArgument),
|
|
1092
|
+
position: position(node),
|
|
1093
|
+
source: node.source,
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
function toGraphQLMarkup(node) {
|
|
1097
|
+
return {
|
|
1098
|
+
name: node.name,
|
|
1099
|
+
type: types_1.NodeTypes.GraphQLMarkup,
|
|
1100
|
+
graphql: toExpression(node.graphql),
|
|
1101
|
+
/**
|
|
1102
|
+
* When we're in completion mode we won't necessarily have valid named
|
|
1103
|
+
* arguments so we need to call toLiquidArgument instead of toNamedArgument.
|
|
1104
|
+
* We cast using `as` so that this doesn't affect the type system used in
|
|
1105
|
+
* other areas (like theme check) for a scenario that only occurs in
|
|
1106
|
+
* completion mode. This means that our types are *wrong* in completion mode
|
|
1107
|
+
* but this is the compromise we're making to get completions to work.
|
|
1108
|
+
*/
|
|
1109
|
+
args: node.functionArguments.map(toLiquidArgument),
|
|
1110
|
+
position: position(node),
|
|
1111
|
+
source: node.source,
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
function toGraphQLInlineMarkup(node) {
|
|
1115
|
+
return {
|
|
1116
|
+
name: node.name,
|
|
1117
|
+
type: types_1.NodeTypes.GraphQLInlineMarkup,
|
|
1118
|
+
/**
|
|
1119
|
+
* When we're in completion mode we won't necessarily have valid named
|
|
1120
|
+
* arguments so we need to call toLiquidArgument instead of toNamedArgument.
|
|
1121
|
+
* We cast using `as` so that this doesn't affect the type system used in
|
|
1122
|
+
* other areas (like theme check) for a scenario that only occurs in
|
|
1123
|
+
* completion mode. This means that our types are *wrong* in completion mode
|
|
1124
|
+
* but this is the compromise we're making to get completions to work.
|
|
1125
|
+
*/
|
|
1126
|
+
args: node.args.map(toLiquidArgument),
|
|
1127
|
+
position: position(node),
|
|
1128
|
+
source: node.source,
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1131
|
+
// platformos markup conversion functions
|
|
1132
|
+
function toBackgroundMarkup(node) {
|
|
1133
|
+
return {
|
|
1134
|
+
jobId: node.jobId,
|
|
1135
|
+
type: types_1.NodeTypes.BackgroundMarkup,
|
|
1136
|
+
partial: toExpression(node.partial),
|
|
1137
|
+
args: node.args.map(toLiquidArgument),
|
|
1138
|
+
position: position(node),
|
|
1139
|
+
source: node.source,
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
function toBackgroundInlineMarkup(node) {
|
|
1143
|
+
return {
|
|
1144
|
+
type: types_1.NodeTypes.BackgroundInlineMarkup,
|
|
1145
|
+
jobId: toExpression(node.jobId),
|
|
1146
|
+
args: node.args.map(toLiquidArgument),
|
|
1147
|
+
position: position(node),
|
|
1148
|
+
source: node.source,
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
function toCacheMarkup(node) {
|
|
1152
|
+
return {
|
|
1153
|
+
type: types_1.NodeTypes.CacheMarkup,
|
|
1154
|
+
key: toExpression(node.key),
|
|
1155
|
+
args: node.args.map(toLiquidArgument),
|
|
1156
|
+
position: position(node),
|
|
1157
|
+
source: node.source,
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
function toLogMarkup(node) {
|
|
1161
|
+
return {
|
|
1162
|
+
type: types_1.NodeTypes.LogMarkup,
|
|
1163
|
+
value: toExpression(node.value),
|
|
1164
|
+
args: node.args.map(toLiquidArgument),
|
|
1165
|
+
position: position(node),
|
|
1166
|
+
source: node.source,
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
function toSessionMarkup(node) {
|
|
1170
|
+
return {
|
|
1171
|
+
type: types_1.NodeTypes.SessionMarkup,
|
|
1172
|
+
name: node.name,
|
|
1173
|
+
value: toExpression(node.value),
|
|
1174
|
+
position: position(node),
|
|
1175
|
+
source: node.source,
|
|
1176
|
+
};
|
|
1177
|
+
}
|
|
1178
|
+
function toExportMarkup(node) {
|
|
1179
|
+
return {
|
|
1180
|
+
type: types_1.NodeTypes.ExportMarkup,
|
|
1181
|
+
variables: node.variables.map((v) => toExpression(v)),
|
|
1182
|
+
namespace: toNamedArgument(node.namespace),
|
|
1183
|
+
position: position(node),
|
|
1184
|
+
source: node.source,
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
function toRedirectToMarkup(node) {
|
|
1188
|
+
return {
|
|
1189
|
+
type: types_1.NodeTypes.RedirectToMarkup,
|
|
1190
|
+
url: toExpression(node.url),
|
|
1191
|
+
args: node.args.map(toLiquidArgument),
|
|
1192
|
+
position: position(node),
|
|
1193
|
+
source: node.source,
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
function toIncludeFormMarkup(node) {
|
|
1197
|
+
return {
|
|
1198
|
+
type: types_1.NodeTypes.IncludeFormMarkup,
|
|
1199
|
+
form: toExpression(node.form),
|
|
1200
|
+
args: node.args.map(toLiquidArgument),
|
|
1201
|
+
position: position(node),
|
|
1202
|
+
source: node.source,
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
function toSpamProtectionMarkup(node) {
|
|
1206
|
+
return {
|
|
1207
|
+
type: types_1.NodeTypes.SpamProtectionMarkup,
|
|
1208
|
+
version: toExpression(node.version),
|
|
1209
|
+
args: node.args.map(toLiquidArgument),
|
|
1210
|
+
position: position(node),
|
|
1211
|
+
source: node.source,
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
function toRenderVariableExpression(node) {
|
|
1215
|
+
if (!node)
|
|
1216
|
+
return null;
|
|
1217
|
+
return {
|
|
1218
|
+
type: types_1.NodeTypes.RenderVariableExpression,
|
|
1219
|
+
kind: node.kind,
|
|
1220
|
+
name: toExpression(node.name),
|
|
1221
|
+
position: position(node),
|
|
1222
|
+
source: node.source,
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
function toRenderAliasExpression(node) {
|
|
1226
|
+
if (!node)
|
|
1227
|
+
return null;
|
|
1228
|
+
return {
|
|
1229
|
+
type: types_1.NodeTypes.RenderAliasExpression,
|
|
1230
|
+
value: node.value,
|
|
1231
|
+
position: position(node),
|
|
1232
|
+
source: node.source,
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
function toConditionalExpression(nodes) {
|
|
1236
|
+
if (nodes.length === 1) {
|
|
1237
|
+
return toComparisonOrExpression(nodes[0]);
|
|
1238
|
+
}
|
|
1239
|
+
const [first, second] = nodes;
|
|
1240
|
+
const [, ...rest] = nodes;
|
|
1241
|
+
return {
|
|
1242
|
+
type: types_1.NodeTypes.LogicalExpression,
|
|
1243
|
+
relation: second.relation,
|
|
1244
|
+
left: toComparisonOrExpression(first),
|
|
1245
|
+
right: toConditionalExpression(rest),
|
|
1246
|
+
position: {
|
|
1247
|
+
start: first.locStart,
|
|
1248
|
+
end: nodes[nodes.length - 1].locEnd,
|
|
1249
|
+
},
|
|
1250
|
+
source: first.source,
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
function toComparisonOrExpression(node) {
|
|
1254
|
+
const expression = node.expression;
|
|
1255
|
+
switch (expression.type) {
|
|
1256
|
+
case stage_1_cst_1.ConcreteNodeTypes.Comparison:
|
|
1257
|
+
return toComparison(expression);
|
|
1258
|
+
default:
|
|
1259
|
+
return toExpression(expression);
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
function toComparison(node) {
|
|
1263
|
+
return {
|
|
1264
|
+
type: types_1.NodeTypes.Comparison,
|
|
1265
|
+
comparator: node.comparator,
|
|
1266
|
+
left: toExpression(node.left),
|
|
1267
|
+
right: toExpression(node.right),
|
|
1268
|
+
position: position(node),
|
|
1269
|
+
source: node.source,
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
function toLiquidVariableOutput(node) {
|
|
1273
|
+
return {
|
|
1274
|
+
type: types_1.NodeTypes.LiquidVariableOutput,
|
|
1275
|
+
markup: typeof node.markup === 'string' ? node.markup : toLiquidVariable(node.markup),
|
|
1276
|
+
whitespaceStart: node.whitespaceStart ?? '',
|
|
1277
|
+
whitespaceEnd: node.whitespaceEnd ?? '',
|
|
1278
|
+
position: position(node),
|
|
1279
|
+
source: node.source,
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1282
|
+
function toLiquidVariable(node) {
|
|
1283
|
+
return {
|
|
1284
|
+
type: types_1.NodeTypes.LiquidVariable,
|
|
1285
|
+
expression: toComplexExpression(node.expression),
|
|
1286
|
+
filters: node.filters.map(toFilter),
|
|
1287
|
+
position: position(node),
|
|
1288
|
+
rawSource: node.rawSource,
|
|
1289
|
+
source: node.source,
|
|
1290
|
+
};
|
|
1291
|
+
}
|
|
1292
|
+
function toComplexExpression(node) {
|
|
1293
|
+
switch (node.type) {
|
|
1294
|
+
case stage_1_cst_1.ConcreteNodeTypes.BooleanExpression: {
|
|
1295
|
+
return {
|
|
1296
|
+
type: types_1.NodeTypes.BooleanExpression,
|
|
1297
|
+
position: position(node),
|
|
1298
|
+
condition: toConditionalExpression(node.conditions),
|
|
1299
|
+
source: node.source,
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
default: {
|
|
1303
|
+
return toExpression(node);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
function toExpression(node) {
|
|
1308
|
+
switch (node.type) {
|
|
1309
|
+
case stage_1_cst_1.ConcreteNodeTypes.String: {
|
|
1310
|
+
return {
|
|
1311
|
+
type: types_1.NodeTypes.String,
|
|
1312
|
+
position: position(node),
|
|
1313
|
+
single: node.single,
|
|
1314
|
+
value: node.value,
|
|
1315
|
+
source: node.source,
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
case stage_1_cst_1.ConcreteNodeTypes.Number: {
|
|
1319
|
+
return {
|
|
1320
|
+
type: types_1.NodeTypes.Number,
|
|
1321
|
+
position: position(node),
|
|
1322
|
+
value: node.value,
|
|
1323
|
+
source: node.source,
|
|
1324
|
+
};
|
|
1325
|
+
}
|
|
1326
|
+
case stage_1_cst_1.ConcreteNodeTypes.LiquidLiteral: {
|
|
1327
|
+
return {
|
|
1328
|
+
type: types_1.NodeTypes.LiquidLiteral,
|
|
1329
|
+
position: position(node),
|
|
1330
|
+
value: node.value,
|
|
1331
|
+
keyword: node.keyword,
|
|
1332
|
+
source: node.source,
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
case stage_1_cst_1.ConcreteNodeTypes.Range: {
|
|
1336
|
+
return {
|
|
1337
|
+
type: types_1.NodeTypes.Range,
|
|
1338
|
+
start: toExpression(node.start),
|
|
1339
|
+
end: toExpression(node.end),
|
|
1340
|
+
position: position(node),
|
|
1341
|
+
source: node.source,
|
|
1342
|
+
};
|
|
1343
|
+
}
|
|
1344
|
+
case stage_1_cst_1.ConcreteNodeTypes.VariableLookup: {
|
|
1345
|
+
return {
|
|
1346
|
+
type: types_1.NodeTypes.VariableLookup,
|
|
1347
|
+
name: node.name,
|
|
1348
|
+
lookups: node.lookups.map(toExpression),
|
|
1349
|
+
position: position(node),
|
|
1350
|
+
source: node.source,
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
default: {
|
|
1354
|
+
return (0, utils_1.assertNever)(node);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
function toFilter(node) {
|
|
1359
|
+
return {
|
|
1360
|
+
type: types_1.NodeTypes.LiquidFilter,
|
|
1361
|
+
name: node.name,
|
|
1362
|
+
args: node.args.map(toLiquidArgument),
|
|
1363
|
+
position: position(node),
|
|
1364
|
+
source: node.source,
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
function toLiquidArgument(node) {
|
|
1368
|
+
switch (node.type) {
|
|
1369
|
+
case stage_1_cst_1.ConcreteNodeTypes.NamedArgument: {
|
|
1370
|
+
return toNamedArgument(node);
|
|
1371
|
+
}
|
|
1372
|
+
default: {
|
|
1373
|
+
return toExpression(node);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
function toNamedArgument(node) {
|
|
1378
|
+
return {
|
|
1379
|
+
type: types_1.NodeTypes.NamedArgument,
|
|
1380
|
+
name: node.name,
|
|
1381
|
+
value: toExpression(node.value),
|
|
1382
|
+
position: position(node),
|
|
1383
|
+
source: node.source,
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1386
|
+
function toHtmlElement(node, options) {
|
|
1387
|
+
return {
|
|
1388
|
+
type: types_1.NodeTypes.HtmlElement,
|
|
1389
|
+
name: cstToAst(node.name, options),
|
|
1390
|
+
attributes: toAttributes(node.attrList || [], options),
|
|
1391
|
+
position: position(node),
|
|
1392
|
+
blockStartPosition: position(node),
|
|
1393
|
+
blockEndPosition: { start: -1, end: -1 },
|
|
1394
|
+
children: [],
|
|
1395
|
+
source: node.source,
|
|
1396
|
+
};
|
|
1397
|
+
}
|
|
1398
|
+
function toHtmlDanglingMarkerClose(node, options) {
|
|
1399
|
+
return {
|
|
1400
|
+
type: types_1.NodeTypes.HtmlDanglingMarkerClose,
|
|
1401
|
+
name: cstToAst(node.name, options),
|
|
1402
|
+
position: position(node),
|
|
1403
|
+
blockStartPosition: position(node),
|
|
1404
|
+
source: node.source,
|
|
1405
|
+
};
|
|
1406
|
+
}
|
|
1407
|
+
function toHtmlVoidElement(node, options) {
|
|
1408
|
+
return {
|
|
1409
|
+
type: types_1.NodeTypes.HtmlVoidElement,
|
|
1410
|
+
name: node.name,
|
|
1411
|
+
attributes: toAttributes(node.attrList || [], options),
|
|
1412
|
+
position: position(node),
|
|
1413
|
+
blockStartPosition: position(node),
|
|
1414
|
+
source: node.source,
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
function toHtmlSelfClosingElement(node, options) {
|
|
1418
|
+
return {
|
|
1419
|
+
type: types_1.NodeTypes.HtmlSelfClosingElement,
|
|
1420
|
+
name: cstToAst(node.name, options),
|
|
1421
|
+
attributes: toAttributes(node.attrList || [], options),
|
|
1422
|
+
position: position(node),
|
|
1423
|
+
blockStartPosition: position(node),
|
|
1424
|
+
source: node.source,
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
function toNullableTextNode(node) {
|
|
1428
|
+
if (!node || node.value === '')
|
|
1429
|
+
return null;
|
|
1430
|
+
return toTextNode(node);
|
|
1431
|
+
}
|
|
1432
|
+
function toTextNode(node) {
|
|
1433
|
+
return {
|
|
1434
|
+
type: types_1.NodeTypes.TextNode,
|
|
1435
|
+
value: node.value,
|
|
1436
|
+
position: position(node),
|
|
1437
|
+
source: node.source,
|
|
1438
|
+
};
|
|
1439
|
+
}
|
|
1440
|
+
function isAcceptableDanglingMarkerClose(builder, cst, currIndex, mode) {
|
|
1441
|
+
if (mode === 'completion') {
|
|
1442
|
+
const current = cst[currIndex];
|
|
1443
|
+
const parentIsOfCorrectName = builder.parent &&
|
|
1444
|
+
builder.parent.type === types_1.NodeTypes.HtmlElement &&
|
|
1445
|
+
getName(builder.parent) === getName(current);
|
|
1446
|
+
return !parentIsOfCorrectName;
|
|
1447
|
+
}
|
|
1448
|
+
return isAcceptableDanglingMarker(builder);
|
|
1449
|
+
}
|
|
1450
|
+
// This function checks that the builder.current node accepts dangling nodes.
|
|
1451
|
+
//
|
|
1452
|
+
// The current logic is:
|
|
1453
|
+
// - Grandparent node must be an if-like statement
|
|
1454
|
+
// - Parent node must be a LiquidBranch
|
|
1455
|
+
function isAcceptableDanglingMarker(builder) {
|
|
1456
|
+
const { parent, grandparent } = builder;
|
|
1457
|
+
if (!parent || !grandparent)
|
|
1458
|
+
return false;
|
|
1459
|
+
return (parent.type === types_1.NodeTypes.LiquidBranch &&
|
|
1460
|
+
grandparent.type === types_1.NodeTypes.LiquidTag &&
|
|
1461
|
+
['if', 'unless', 'case'].includes(grandparent.name));
|
|
1462
|
+
}
|
|
1463
|
+
// checking that is a {% else %} or {% endif %}
|
|
1464
|
+
function isConcreteExceptionEnd(node) {
|
|
1465
|
+
return (!node ||
|
|
1466
|
+
node.type === stage_1_cst_1.ConcreteNodeTypes.LiquidTagClose ||
|
|
1467
|
+
isConcreteLiquidBranchDisguisedAsTag(node));
|
|
1468
|
+
}
|
|
1469
|
+
function markup(name, markup) {
|
|
1470
|
+
if (grammar_1.TAGS_WITHOUT_MARKUP.includes(name))
|
|
1471
|
+
return '';
|
|
1472
|
+
return markup;
|
|
1473
|
+
}
|
|
1474
|
+
function position(node) {
|
|
1475
|
+
return {
|
|
1476
|
+
start: node.locStart,
|
|
1477
|
+
end: node.locEnd,
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
function walk(ast, fn, parentNode) {
|
|
1481
|
+
for (const key of Object.keys(ast)) {
|
|
1482
|
+
if (types_1.nonTraversableProperties.has(key)) {
|
|
1483
|
+
continue;
|
|
1484
|
+
}
|
|
1485
|
+
const value = ast[key];
|
|
1486
|
+
if (Array.isArray(value)) {
|
|
1487
|
+
value.filter(isLiquidHtmlNode).forEach((node) => walk(node, fn, ast));
|
|
1488
|
+
}
|
|
1489
|
+
else if (isLiquidHtmlNode(value)) {
|
|
1490
|
+
walk(value, fn, ast);
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
fn(ast, parentNode);
|
|
1494
|
+
}
|
|
1495
|
+
function isLiquidHtmlNode(value) {
|
|
1496
|
+
return (value !== null &&
|
|
1497
|
+
typeof value === 'object' &&
|
|
1498
|
+
'type' in value &&
|
|
1499
|
+
types_1.NodeTypes.hasOwnProperty(value.type));
|
|
1500
|
+
}
|
|
1501
|
+
function getUnclosed(node, parentNode) {
|
|
1502
|
+
if (!node)
|
|
1503
|
+
return undefined;
|
|
1504
|
+
if (getName(node) === null && parentNode) {
|
|
1505
|
+
node = parentNode;
|
|
1506
|
+
}
|
|
1507
|
+
return {
|
|
1508
|
+
type: node.type,
|
|
1509
|
+
name: getName(node) ?? '',
|
|
1510
|
+
blockStartPosition: 'blockStartPosition' in node ? node.blockStartPosition : node.position,
|
|
1511
|
+
};
|
|
1512
|
+
}
|
|
1513
|
+
//# sourceMappingURL=stage-2-ast.js.map
|