ember-eslint-parser 0.2.3 → 0.2.4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-eslint-parser",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "repository": {
@@ -6,6 +6,31 @@ const TypescriptScope = require('@typescript-eslint/scope-manager');
6
6
  const { Reference, Scope, Variable, Definition } = require('eslint-scope');
7
7
  const htmlTags = require('html-tags');
8
8
 
9
+ const BufferMap = new Map();
10
+
11
+ function getBuffer(str) {
12
+ let buf = BufferMap.get(str);
13
+ if (!buf) {
14
+ buf = Buffer.from(str);
15
+ BufferMap.set(str, buf);
16
+ }
17
+ return buf;
18
+ }
19
+
20
+ function sliceByteRange(str, a, b) {
21
+ const buf = getBuffer(str);
22
+ return buf.slice(a, b).toString();
23
+ }
24
+
25
+ function byteToCharIndex(str, byteOffset) {
26
+ const buf = getBuffer(str);
27
+ return buf.slice(0, byteOffset + 1).toString().length - 1;
28
+ }
29
+
30
+ function byteLength(str) {
31
+ return getBuffer(str).length;
32
+ }
33
+
9
34
  /**
10
35
  * finds the nearest node scope
11
36
  * @param scopeManager
@@ -202,17 +227,23 @@ module.exports.preprocessGlimmerTemplates = function preprocessGlimmerTemplates(
202
227
  const templateInfos = info.templateInfos.map((r) => ({
203
228
  range: [r.contentRange.start, r.contentRange.end],
204
229
  templateRange: [r.range.start, r.range.end],
230
+ utf16Range: [byteToCharIndex(code, r.range.start), byteToCharIndex(code, r.range.end)],
205
231
  }));
206
232
  const templateVisitorKeys = {};
207
233
  const codeLines = new DocumentLines(code);
208
234
  const comments = [];
209
- const textNodes = [];
210
235
  for (const tpl of templateInfos) {
236
+ const currentComments = [];
237
+ const textNodes = [];
211
238
  const range = tpl.range;
212
- const template = code.slice(...range);
239
+ const template = sliceByteRange(code, ...range);
213
240
  const docLines = new DocumentLines(template);
214
241
  const ast = glimmer.preprocess(template, { mode: 'codemod' });
215
- ast.tokens = tokenize(code.slice(...tpl.templateRange), codeLines, tpl.templateRange[0]);
242
+ ast.tokens = tokenize(
243
+ sliceByteRange(code, ...tpl.templateRange),
244
+ codeLines,
245
+ tpl.templateRange[0]
246
+ );
216
247
  const allNodes = [];
217
248
  glimmer.traverse(ast, {
218
249
  All(node, path) {
@@ -221,6 +252,7 @@ module.exports.preprocessGlimmerTemplates = function preprocessGlimmerTemplates(
221
252
  allNodes.push(node);
222
253
  if (node.type === 'CommentStatement' || node.type === 'MustacheCommentStatement') {
223
254
  comments.push(node);
255
+ currentComments.push(node);
224
256
  }
225
257
  if (node.type === 'TextNode') {
226
258
  n.value = node.chars;
@@ -265,17 +297,12 @@ module.exports.preprocessGlimmerTemplates = function preprocessGlimmerTemplates(
265
297
  n.name = n.tag;
266
298
  n.parts = [];
267
299
  let start = n.range[0];
268
- let codeSlice = code.slice(...n.range);
300
+ let codeSlice = sliceByteRange(code, ...n.range);
269
301
  for (const part of n.tag.split('.')) {
270
- let pattern = `\\b${part}\\b`;
271
- if (part.startsWith(':')) {
272
- pattern = `${part}\\b`;
273
- }
274
- const regex = new RegExp(pattern);
275
- const match = codeSlice.match(regex);
276
- const range = [start + match.index, 0];
302
+ const idx = codeSlice.indexOf(part);
303
+ const range = [start + idx, 0];
277
304
  range[1] = range[0] + part.length;
278
- codeSlice = code.slice(range[1], n.range[1]);
305
+ codeSlice = sliceByteRange(code, range[1], n.range[1]);
279
306
  start = range[1];
280
307
  n.parts.push({
281
308
  type: 'GlimmerElementNodePart',
@@ -295,8 +322,11 @@ module.exports.preprocessGlimmerTemplates = function preprocessGlimmerTemplates(
295
322
  n.params = [];
296
323
  }
297
324
  if ('blockParams' in n && n.parent) {
298
- let part = code.slice(...n.parent.range);
299
- let start = n.parent.range[0];
325
+ // for blocks {{x as |b|}} the block range does not contain the block params...
326
+ // for element tag it does <x as b />
327
+ const blockRange = n.type === 'Block' ? n.parent.range : n.range;
328
+ let part = sliceByteRange(code, ...blockRange);
329
+ let start = blockRange[0];
300
330
  let idx = part.indexOf('|') + 1;
301
331
  start += idx;
302
332
  part = part.slice(idx, -1);
@@ -323,10 +353,12 @@ module.exports.preprocessGlimmerTemplates = function preprocessGlimmerTemplates(
323
353
  allNodeTypes.add(n.type);
324
354
  }
325
355
  // ast should not contain comment nodes
326
- for (const comment of comments) {
356
+ for (const comment of currentComments) {
327
357
  const parentBody = comment.parent.body || comment.parent.children;
328
358
  const idx = parentBody.indexOf(comment);
329
- parentBody.splice(idx, 1);
359
+ if (idx >= 0) {
360
+ parentBody.splice(idx, 1);
361
+ }
330
362
  // comment type can be a block comment or a line comment
331
363
  // mark comments as always block comment, this works for eslint in all cases
332
364
  comment.type = 'Block';
@@ -400,8 +432,8 @@ module.exports.convertAst = function convertAst(result, preprocessedResult, visi
400
432
 
401
433
  const template = templateInfos.find(
402
434
  (t) =>
403
- t.templateRange[0] === range[0] &&
404
- (t.templateRange[1] === range[1] || t.templateRange[1] === range[1] + 1)
435
+ t.utf16Range[0] === range[0] &&
436
+ (t.utf16Range[1] === range[1] || t.utf16Range[1] === range[1] + 1)
405
437
  );
406
438
  if (!template) {
407
439
  return null;
@@ -439,6 +471,7 @@ module.exports.convertAst = function convertAst(result, preprocessedResult, visi
439
471
  if (
440
472
  n.name !== 'this' &&
441
473
  !n.name.startsWith(':') &&
474
+ !n.name.startsWith('@') &&
442
475
  scope &&
443
476
  (variable ||
444
477
  isUpperCase(n.name[0]) ||
@@ -471,7 +504,7 @@ module.exports.convertAst = function convertAst(result, preprocessedResult, visi
471
504
  };
472
505
 
473
506
  const replaceRange = function replaceRange(s, start, end, substitute) {
474
- return s.slice(0, start) + substitute + s.slice(end);
507
+ return sliceByteRange(s, 0, start) + substitute + sliceByteRange(s, end);
475
508
  };
476
509
  module.exports.replaceRange = replaceRange;
477
510
 
@@ -505,20 +538,21 @@ module.exports.transformForLint = function transformForLint(code) {
505
538
  */
506
539
  const result = processor.parse(code);
507
540
  for (const tplInfo of result.reverse()) {
508
- const lineBreaks = [...tplInfo.contents].reduce(
509
- (prev, curr) => prev + (DocumentLines.isLineBreak(curr.codePointAt(0)) ? 1 : 0),
541
+ const backticks = [...tplInfo.contents].reduce(
542
+ (prev, curr) => (prev + (curr.codePointAt(0) === '`') ? 1 : 0),
510
543
  0
511
544
  );
545
+ const content = tplInfo.contents.replace(/`/g, '\\`');
512
546
  if (tplInfo.type === 'class-member') {
513
547
  const tplLength = tplInfo.range.end - tplInfo.range.start;
514
- const spaces = tplLength - 'static{`'.length - '`}'.length - lineBreaks;
515
- const total = ' '.repeat(spaces) + '\n'.repeat(lineBreaks);
548
+ const spaces = tplLength - byteLength(content) - 'static{`'.length - '`}'.length - backticks;
549
+ const total = content + ' '.repeat(spaces);
516
550
  const replacementCode = `static{\`${total}\`}`;
517
551
  jsCode = replaceRange(jsCode, tplInfo.range.start, tplInfo.range.end, replacementCode);
518
552
  } else {
519
553
  const tplLength = tplInfo.range.end - tplInfo.range.start;
520
- const spaces = tplLength - '""`'.length - '`'.length - lineBreaks;
521
- const total = ' '.repeat(spaces) + '\n'.repeat(lineBreaks);
554
+ const spaces = tplLength - byteLength(content) - '""`'.length - '`'.length - backticks;
555
+ const total = content + ' '.repeat(spaces);
522
556
  const replacementCode = `""\`${total}\``;
523
557
  jsCode = replaceRange(jsCode, tplInfo.range.start, tplInfo.range.end, replacementCode);
524
558
  }