ember-eslint-parser 0.2.6 → 0.3.1
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/package.json +5 -3
- package/src/parser/gjs-gts-parser.js +1 -0
- package/src/parser/transforms.js +80 -71
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ember-eslint-parser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"repository": {
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"eslint-plugin-promise": "^6.0.0",
|
|
31
31
|
"execa": "^8.0.1",
|
|
32
32
|
"fs-extra": "^11.2.0",
|
|
33
|
-
"
|
|
33
|
+
"vite": "^5.0.12",
|
|
34
|
+
"vitest": "^1.2.2",
|
|
34
35
|
"prettier": "^3.1.1",
|
|
35
36
|
"publint": "^0.2.6",
|
|
36
37
|
"release-plan": "^0.6.0",
|
|
@@ -38,7 +39,7 @@
|
|
|
38
39
|
},
|
|
39
40
|
"dependencies": {
|
|
40
41
|
"@babel/eslint-parser": "^7.23.3",
|
|
41
|
-
"@glimmer/syntax": "^0.
|
|
42
|
+
"@glimmer/syntax": "^0.88.0",
|
|
42
43
|
"@typescript-eslint/scope-manager": "^6.15.0",
|
|
43
44
|
"content-tag": "^1.2.2",
|
|
44
45
|
"eslint-scope": "^7.2.2",
|
|
@@ -53,6 +54,7 @@
|
|
|
53
54
|
"typescript": "^5.3.3"
|
|
54
55
|
},
|
|
55
56
|
"scripts": {
|
|
57
|
+
"test": "vitest run",
|
|
56
58
|
"lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
|
|
57
59
|
"lint:js": "eslint .",
|
|
58
60
|
"lint:package": "pnpm publint",
|
|
@@ -52,6 +52,7 @@ module.exports = {
|
|
|
52
52
|
return result;
|
|
53
53
|
}
|
|
54
54
|
const preprocessedResult = preprocessGlimmerTemplates(info, code);
|
|
55
|
+
preprocessedResult.code = code;
|
|
55
56
|
const { templateVisitorKeys } = preprocessedResult;
|
|
56
57
|
const visitorKeys = { ...result.visitorKeys, ...templateVisitorKeys };
|
|
57
58
|
result.isTypescript = isTypescript;
|
package/src/parser/transforms.js
CHANGED
|
@@ -125,6 +125,16 @@ function traverse(visitorKeys, node, visitor) {
|
|
|
125
125
|
if (!currentPath.node) continue;
|
|
126
126
|
|
|
127
127
|
const visitorKeys = allVisitorKeys[currentPath.node.type];
|
|
128
|
+
if (currentPath.node.type === 'GlimmerElementNode') {
|
|
129
|
+
if (!visitorKeys.includes('blockParamNodes')) {
|
|
130
|
+
visitorKeys.push('blockParamNodes', 'parts');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (currentPath.node.type === 'GlimmerProgram') {
|
|
134
|
+
if (!visitorKeys.includes('blockParamNodes')) {
|
|
135
|
+
visitorKeys.push('blockParamNodes');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
128
138
|
if (!visitorKeys) {
|
|
129
139
|
continue;
|
|
130
140
|
}
|
|
@@ -240,15 +250,13 @@ module.exports.preprocessGlimmerTemplates = function preprocessGlimmerTemplates(
|
|
|
240
250
|
for (const tpl of templateInfos) {
|
|
241
251
|
const currentComments = [];
|
|
242
252
|
const textNodes = [];
|
|
243
|
-
const
|
|
244
|
-
const
|
|
253
|
+
const emptyTextNodes = [];
|
|
254
|
+
const range = tpl.utf16Range;
|
|
255
|
+
const offset = range[0];
|
|
256
|
+
const template = code.slice(...range);
|
|
245
257
|
const docLines = new DocumentLines(template);
|
|
246
258
|
const ast = glimmer.preprocess(template, { mode: 'codemod' });
|
|
247
|
-
ast.tokens = tokenize(
|
|
248
|
-
sliceByteRange(code, ...tpl.templateRange),
|
|
249
|
-
codeLines,
|
|
250
|
-
tpl.templateRange[0]
|
|
251
|
-
);
|
|
259
|
+
ast.tokens = tokenize(sliceByteRange(code, ...tpl.templateRange), codeLines, tpl.utf16Range[0]);
|
|
252
260
|
const allNodes = [];
|
|
253
261
|
glimmer.traverse(ast, {
|
|
254
262
|
All(node, path) {
|
|
@@ -261,7 +269,13 @@ module.exports.preprocessGlimmerTemplates = function preprocessGlimmerTemplates(
|
|
|
261
269
|
}
|
|
262
270
|
if (node.type === 'TextNode') {
|
|
263
271
|
n.value = node.chars;
|
|
264
|
-
|
|
272
|
+
// empty text nodes are not allowed, it's empty if its only whitespace or line terminators
|
|
273
|
+
// it's okay for AttrNodes
|
|
274
|
+
if (n.value.trim().length !== 0 || n.parent.type === 'AttrNode') {
|
|
275
|
+
textNodes.push(node);
|
|
276
|
+
} else {
|
|
277
|
+
emptyTextNodes.push(node);
|
|
278
|
+
}
|
|
265
279
|
}
|
|
266
280
|
},
|
|
267
281
|
});
|
|
@@ -270,8 +284,8 @@ module.exports.preprocessGlimmerTemplates = function preprocessGlimmerTemplates(
|
|
|
270
284
|
for (const n of allNodes) {
|
|
271
285
|
if (n.type === 'PathExpression') {
|
|
272
286
|
n.head.range = [
|
|
273
|
-
|
|
274
|
-
|
|
287
|
+
offset + docLines.positionToOffset(n.head.loc.start),
|
|
288
|
+
offset + docLines.positionToOffset(n.head.loc.end),
|
|
275
289
|
];
|
|
276
290
|
n.head.loc = {
|
|
277
291
|
start: codeLines.offsetToPosition(n.head.range[0]),
|
|
@@ -280,12 +294,11 @@ module.exports.preprocessGlimmerTemplates = function preprocessGlimmerTemplates(
|
|
|
280
294
|
}
|
|
281
295
|
n.range =
|
|
282
296
|
n.type === 'Template'
|
|
283
|
-
? [tpl.
|
|
297
|
+
? [...tpl.utf16Range]
|
|
284
298
|
: [
|
|
285
|
-
|
|
286
|
-
|
|
299
|
+
offset + docLines.positionToOffset(n.loc.start),
|
|
300
|
+
offset + docLines.positionToOffset(n.loc.end),
|
|
287
301
|
];
|
|
288
|
-
|
|
289
302
|
n.start = n.range[0];
|
|
290
303
|
n.end = n.range[1];
|
|
291
304
|
n.loc = {
|
|
@@ -293,70 +306,47 @@ module.exports.preprocessGlimmerTemplates = function preprocessGlimmerTemplates(
|
|
|
293
306
|
end: codeLines.offsetToPosition(n.range[1]),
|
|
294
307
|
};
|
|
295
308
|
if (n.type === 'Template') {
|
|
296
|
-
n.loc.start = codeLines.offsetToPosition(tpl.
|
|
297
|
-
n.loc.end = codeLines.offsetToPosition(tpl.
|
|
309
|
+
n.loc.start = codeLines.offsetToPosition(tpl.utf16Range[0]);
|
|
310
|
+
n.loc.end = codeLines.offsetToPosition(tpl.utf16Range[1]);
|
|
298
311
|
}
|
|
299
|
-
|
|
300
|
-
// parts <Foo.Bar /> -> nodes for `Foo` and `Bar`
|
|
312
|
+
|
|
301
313
|
if (n.type === 'ElementNode') {
|
|
302
314
|
n.name = n.tag;
|
|
303
|
-
n.parts =
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
type: 'GlimmerElementNodePart',
|
|
314
|
-
name: part,
|
|
315
|
-
range,
|
|
316
|
-
parent: n,
|
|
317
|
-
loc: {
|
|
318
|
-
start: codeLines.offsetToPosition(range[0]),
|
|
319
|
-
end: codeLines.offsetToPosition(range[1]),
|
|
320
|
-
},
|
|
321
|
-
});
|
|
322
|
-
}
|
|
315
|
+
n.parts = n.parts.map((p) => ({
|
|
316
|
+
...p,
|
|
317
|
+
parent: n,
|
|
318
|
+
type: 'GlimmerElementNodePart',
|
|
319
|
+
name: p.value,
|
|
320
|
+
range: [
|
|
321
|
+
offset + docLines.positionToOffset(p.loc.start),
|
|
322
|
+
offset + docLines.positionToOffset(p.loc.end),
|
|
323
|
+
],
|
|
324
|
+
}));
|
|
323
325
|
}
|
|
324
|
-
|
|
325
|
-
// add our own nodes so we can reference them
|
|
326
|
+
|
|
326
327
|
if ('blockParams' in n) {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
part = part.slice(idx, -1);
|
|
338
|
-
idx = part.indexOf('|');
|
|
339
|
-
part = part.slice(0, idx);
|
|
340
|
-
for (const param of n.blockParams) {
|
|
341
|
-
const regex = new RegExp(`\\b${param}\\b`);
|
|
342
|
-
const match = part.match(regex);
|
|
343
|
-
const range = [start + match.index, 0];
|
|
344
|
-
range[1] = range[0] + param.length;
|
|
345
|
-
n.params.push({
|
|
346
|
-
type: 'BlockParam',
|
|
347
|
-
name: param,
|
|
348
|
-
range,
|
|
349
|
-
parent: n,
|
|
350
|
-
loc: {
|
|
351
|
-
start: codeLines.offsetToPosition(range[0]),
|
|
352
|
-
end: codeLines.offsetToPosition(range[1]),
|
|
353
|
-
},
|
|
354
|
-
});
|
|
355
|
-
}
|
|
328
|
+
// program does have blockParams but not blockParamNodes
|
|
329
|
+
n.params = (n.blockParamNodes || []).map((p) => ({
|
|
330
|
+
...p,
|
|
331
|
+
parent: n,
|
|
332
|
+
name: p.value,
|
|
333
|
+
range: [
|
|
334
|
+
offset + docLines.positionToOffset(p.loc.start),
|
|
335
|
+
offset + docLines.positionToOffset(p.loc.end),
|
|
336
|
+
],
|
|
337
|
+
}));
|
|
356
338
|
}
|
|
357
339
|
n.type = `Glimmer${n.type}`;
|
|
358
340
|
allNodeTypes.add(n.type);
|
|
359
341
|
}
|
|
342
|
+
|
|
343
|
+
// ast should not contains empty text nodes
|
|
344
|
+
for (const node of emptyTextNodes) {
|
|
345
|
+
const children = node.parent.children || node.parent.body;
|
|
346
|
+
const idx = children.indexOf(node);
|
|
347
|
+
children.splice(idx, 1);
|
|
348
|
+
}
|
|
349
|
+
|
|
360
350
|
// ast should not contain comment nodes
|
|
361
351
|
for (const comment of currentComments) {
|
|
362
352
|
const parentBody = comment.parent.body || comment.parent.children;
|
|
@@ -416,8 +406,8 @@ module.exports.convertAst = function convertAst(result, preprocessedResult, visi
|
|
|
416
406
|
result.ast.comments.push(...preprocessedResult.comments);
|
|
417
407
|
|
|
418
408
|
for (const ti of templateInfos) {
|
|
419
|
-
const firstIdx = result.ast.tokens.findIndex((t) => t.range[0] === ti.
|
|
420
|
-
const lastIdx = result.ast.tokens.findIndex((t) => t.range[1] === ti.
|
|
409
|
+
const firstIdx = result.ast.tokens.findIndex((t) => t.range[0] === ti.utf16Range[0]);
|
|
410
|
+
const lastIdx = result.ast.tokens.findIndex((t) => t.range[1] === ti.utf16Range[1]);
|
|
421
411
|
result.ast.tokens.splice(firstIdx, lastIdx - firstIdx + 1, ...ti.ast.tokens);
|
|
422
412
|
}
|
|
423
413
|
|
|
@@ -425,6 +415,7 @@ module.exports.convertAst = function convertAst(result, preprocessedResult, visi
|
|
|
425
415
|
traverse(visitorKeys, result.ast, (path) => {
|
|
426
416
|
const node = path.node;
|
|
427
417
|
if (!node) return null;
|
|
418
|
+
|
|
428
419
|
if (
|
|
429
420
|
node.type === 'ExpressionStatement' ||
|
|
430
421
|
node.type === 'StaticBlock' ||
|
|
@@ -504,6 +495,21 @@ module.exports.convertAst = function convertAst(result, preprocessedResult, visi
|
|
|
504
495
|
return null;
|
|
505
496
|
});
|
|
506
497
|
|
|
498
|
+
traverse(visitorKeys, result.ast, (path) => {
|
|
499
|
+
const node = path.node;
|
|
500
|
+
if (!node) return null;
|
|
501
|
+
|
|
502
|
+
if (
|
|
503
|
+
['GlimmerMustacheStatement', 'GlimmerBlockStatement', 'GlimmerSubExpression'].includes(
|
|
504
|
+
node.type
|
|
505
|
+
)
|
|
506
|
+
) {
|
|
507
|
+
if (node.hash && node.hash.pairs.length === 0) {
|
|
508
|
+
node.hash = null;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
|
|
507
513
|
if (counter !== templateInfos.length) {
|
|
508
514
|
throw new Error('failed to process all templates');
|
|
509
515
|
}
|
|
@@ -572,3 +578,6 @@ module.exports.transformForLint = function transformForLint(code) {
|
|
|
572
578
|
output: jsCode,
|
|
573
579
|
};
|
|
574
580
|
};
|
|
581
|
+
|
|
582
|
+
module.exports.traverse = traverse;
|
|
583
|
+
module.exports.tokenize = tokenize;
|