eslint-plugin-ember-template-lint 0.2.0 → 0.6.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/lib/ember-teplate-lint/info.js +3 -8
 - package/lib/parser/gts-parser.js +6 -29
 - package/lib/parser/hbs-parser.js +14 -21
 - package/lib/rules/config.js +1 -1
 - package/lib/rules/hbs-worker.js +63 -7
 - package/lib/rules/lint.js +41 -36
 - package/package.json +5 -4
 
| 
         @@ -12,6 +12,7 @@ const allMessages = {}; 
     | 
|
| 
       12 
12 
     | 
    
         
             
            const reporter = {
         
     | 
| 
       13 
13 
     | 
    
         
             
              setup(context) {
         
     | 
| 
       14 
14 
     | 
    
         
             
                this.getSourceCode = context.getSourceCode;
         
     | 
| 
      
 15 
     | 
    
         
            +
                this.getPhysicalFilename = context.getPhysicalFilename;
         
     | 
| 
       15 
16 
     | 
    
         
             
              },
         
     | 
| 
       16 
17 
     | 
    
         
             
              report(message) {
         
     | 
| 
       17 
18 
     | 
    
         
             
                message.meta = {
         
     | 
| 
         @@ -42,14 +43,8 @@ class Rule { 
     | 
|
| 
       42 
43 
     | 
    
         
             
                  enter(node) {
         
     | 
| 
       43 
44 
     | 
    
         
             
                    if (!activeRules.get(node)) {
         
     | 
| 
       44 
45 
     | 
    
         
             
                      activeRules.set(node, 0);
         
     | 
| 
       45 
     | 
    
         
            -
                      const sourceCode = context.getSourceCode();
         
     | 
| 
       46 
     | 
    
         
            -
                      const { scopeManager } = sourceCode;
         
     | 
| 
       47 
     | 
    
         
            -
                      const scopes = scopeManager.scopes.filter(x => x.block.range[0] < node.range[0] && x.block.range[1] > node.range[1]);
         
     | 
| 
       48 
     | 
    
         
            -
                      const scopeVars = scopes.map(s => s.variables.map(x => x.name)).flat();
         
     | 
| 
       49 
     | 
    
         
            -
                      const filename = context.getPhysicalFilename();
         
     | 
| 
       50 
     | 
    
         
            -
                      const start = node.range[0] || 0;
         
     | 
| 
       51 
46 
     | 
    
         
             
                      reporter.setup(context);
         
     | 
| 
       52 
     | 
    
         
            -
                      runTemplateLint(node 
     | 
| 
      
 47 
     | 
    
         
            +
                      runTemplateLint(node, reporter);
         
     | 
| 
       53 
48 
     | 
    
         
             
                    }
         
     | 
| 
       54 
49 
     | 
    
         
             
                    activeRules.set(node, activeRules.get(node) + 1);
         
     | 
| 
       55 
50 
     | 
    
         
             
                  },
         
     | 
| 
         @@ -108,4 +103,4 @@ module.exports = { 
     | 
|
| 
       108 
103 
     | 
    
         
             
              configs: configs,
         
     | 
| 
       109 
104 
     | 
    
         
             
              rules: createRules(rules),
         
     | 
| 
       110 
105 
     | 
    
         
             
              configuredRules: configuredRules
         
     | 
| 
       111 
     | 
    
         
            -
            };
         
     | 
| 
      
 106 
     | 
    
         
            +
            };
         
     | 
    
        package/lib/parser/gts-parser.js
    CHANGED
    
    | 
         @@ -1,34 +1,12 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            const { preprocess, traverse, Source } = require('@glimmer/syntax');
         
     | 
| 
       2 
1 
     | 
    
         
             
            const gts =  require('ember-template-imports');
         
     | 
| 
       3 
2 
     | 
    
         
             
            const typescriptParser =  require('@typescript-eslint/parser');
         
     | 
| 
       4 
3 
     | 
    
         
             
            const typescriptEstree = require('@typescript-eslint/typescript-estree');
         
     | 
| 
       5 
4 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            function visitorKeysForAst(source, ast) {
         
     | 
| 
       7 
     | 
    
         
            -
              const tokens = [];
         
     | 
| 
       8 
     | 
    
         
            -
              const types = new Set();
         
     | 
| 
       9 
     | 
    
         
            -
              traverse(ast, {
         
     | 
| 
       10 
     | 
    
         
            -
                All(node) {
         
     | 
| 
       11 
     | 
    
         
            -
                  types.add(`__TEMPLATE__${node.type}`);
         
     | 
| 
       12 
     | 
    
         
            -
                  tokens.push(node);
         
     | 
| 
       13 
     | 
    
         
            -
                }
         
     | 
| 
       14 
     | 
    
         
            -
              });
         
     | 
| 
       15 
     | 
    
         
            -
              ast.tokens = tokens;
         
     | 
| 
       16 
     | 
    
         
            -
              const visitorKeys = {};
         
     | 
| 
       17 
     | 
    
         
            -
              types.forEach((t) => {
         
     | 
| 
       18 
     | 
    
         
            -
                // visitorKeys[t] = ['body', 'name', 'path', 'params', 'attributes', 'hash', 'modifiers', 'comments', 'value', 'program', 'inverse', 'children']
         
     | 
| 
       19 
     | 
    
         
            -
                visitorKeys[t] = [];
         
     | 
| 
       20 
     | 
    
         
            -
              });
         
     | 
| 
       21 
     | 
    
         
            -
              tokens.forEach((node) => {
         
     | 
| 
       22 
     | 
    
         
            -
                node.type = `__TEMPLATE__${node.type}`;
         
     | 
| 
       23 
     | 
    
         
            -
              });
         
     | 
| 
       24 
     | 
    
         
            -
              return visitorKeys;
         
     | 
| 
       25 
     | 
    
         
            -
            }
         
     | 
| 
       26 
5 
     | 
    
         | 
| 
       27 
6 
     | 
    
         
             
            function replaceRange(s, start, end, substitute) {
         
     | 
| 
       28 
7 
     | 
    
         
             
              return s.substring(0, start) + substitute + s.substring(end);
         
     | 
| 
       29 
8 
     | 
    
         
             
            }
         
     | 
| 
       30 
9 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
10 
     | 
    
         
             
            module.exports = {
         
     | 
| 
       33 
11 
     | 
    
         
             
              parseForESLint(code, options) {
         
     | 
| 
       34 
12 
     | 
    
         
             
                let jsCode = code;
         
     | 
| 
         @@ -43,14 +21,15 @@ module.exports = { 
     | 
|
| 
       43 
21 
     | 
    
         
             
                  });
         
     | 
| 
       44 
22 
     | 
    
         
             
                  const emptyText = '[`' + lines.join('\n').slice(4) + '`]';
         
     | 
| 
       45 
23 
     | 
    
         
             
                  jsCode = replaceRange(jsCode, ...range, emptyText);
         
     | 
| 
       46 
     | 
    
         
            -
                  const  
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
                   
     | 
| 
       49 
     | 
    
         
            -
                  ast. 
     | 
| 
      
 24 
     | 
    
         
            +
                  const ast = {
         
     | 
| 
      
 25 
     | 
    
         
            +
                    type: '__TEMPLATE__Template',
         
     | 
| 
      
 26 
     | 
    
         
            +
                  };
         
     | 
| 
      
 27 
     | 
    
         
            +
                  ast.range = range;
         
     | 
| 
      
 28 
     | 
    
         
            +
                  ast.contents = template;
         
     | 
| 
       50 
29 
     | 
    
         
             
                  tpl.ast = ast;
         
     | 
| 
       51 
30 
     | 
    
         
             
                });
         
     | 
| 
       52 
31 
     | 
    
         
             
                const result = typescriptParser.parseForESLint(jsCode, options);
         
     | 
| 
       53 
     | 
    
         
            -
                const visitorKeys = {...result.visitorKeys};
         
     | 
| 
      
 32 
     | 
    
         
            +
                const visitorKeys = {...result.visitorKeys, '__TEMPLATE__Template': []};
         
     | 
| 
       54 
33 
     | 
    
         
             
                result.ast.tokens.forEach((token) => {
         
     | 
| 
       55 
34 
     | 
    
         
             
                  if (token.type === 'Template') {
         
     | 
| 
       56 
35 
     | 
    
         
             
                    const range = [token.range[0] - 1, token.range[1] + 1];
         
     | 
| 
         @@ -58,8 +37,6 @@ module.exports = { 
     | 
|
| 
       58 
37 
     | 
    
         
             
                    if (!template) return;
         
     | 
| 
       59 
38 
     | 
    
         
             
                    const ast = template.ast;
         
     | 
| 
       60 
39 
     | 
    
         
             
                    ast.loc = token.loc;
         
     | 
| 
       61 
     | 
    
         
            -
                    const source = new Source(code);
         
     | 
| 
       62 
     | 
    
         
            -
                    Object.assign(visitorKeys, visitorKeysForAst(source, ast));
         
     | 
| 
       63 
40 
     | 
    
         
             
                    Object.assign(token, ast);
         
     | 
| 
       64 
41 
     | 
    
         
             
                  }
         
     | 
| 
       65 
42 
     | 
    
         
             
                });
         
     | 
    
        package/lib/parser/hbs-parser.js
    CHANGED
    
    | 
         @@ -1,4 +1,3 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            const { preprocess, traverse, Source } = require('@glimmer/syntax');
         
     | 
| 
       2 
1 
     | 
    
         | 
| 
       3 
2 
     | 
    
         
             
            class Scope {
         
     | 
| 
       4 
3 
     | 
    
         
             
              type = 'global';
         
     | 
| 
         @@ -26,25 +25,22 @@ class ScopeManager { 
     | 
|
| 
       26 
25 
     | 
    
         | 
| 
       27 
26 
     | 
    
         
             
            module.exports = {
         
     | 
| 
       28 
27 
     | 
    
         
             
              parseForESLint(code) {
         
     | 
| 
       29 
     | 
    
         
            -
                const source = new Source(code);
         
     | 
| 
       30 
     | 
    
         
            -
                const ast = preprocess(source, { mode: 'codemod' });
         
     | 
| 
       31 
     | 
    
         
            -
                const tokens = [];
         
     | 
| 
       32 
28 
     | 
    
         
             
                const comments = [];
         
     | 
| 
       33 
     | 
    
         
            -
                const types = new Set();
         
     | 
| 
       34 
     | 
    
         
            -
                 
     | 
| 
       35 
     | 
    
         
            -
                 
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
                     
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
                     
     | 
| 
      
 29 
     | 
    
         
            +
                const types = new Set(['Program']);
         
     | 
| 
      
 30 
     | 
    
         
            +
                const ast = {};
         
     | 
| 
      
 31 
     | 
    
         
            +
                ast.tokens = [ast];
         
     | 
| 
      
 32 
     | 
    
         
            +
                ast.range = [0, code.length];
         
     | 
| 
      
 33 
     | 
    
         
            +
                const lines = code.split('\n');
         
     | 
| 
      
 34 
     | 
    
         
            +
                ast.loc = {
         
     | 
| 
      
 35 
     | 
    
         
            +
                  start: {
         
     | 
| 
      
 36 
     | 
    
         
            +
                    line: 1,
         
     | 
| 
      
 37 
     | 
    
         
            +
                    column: 1
         
     | 
| 
      
 38 
     | 
    
         
            +
                  },
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end: {
         
     | 
| 
      
 40 
     | 
    
         
            +
                    line: lines.length,
         
     | 
| 
      
 41 
     | 
    
         
            +
                    column: lines[lines.length - 1].length
         
     | 
| 
       45 
42 
     | 
    
         
             
                  }
         
     | 
| 
       46 
     | 
    
         
            -
                } 
     | 
| 
       47 
     | 
    
         
            -
                ast.tokens = tokens;
         
     | 
| 
      
 43 
     | 
    
         
            +
                };
         
     | 
| 
       48 
44 
     | 
    
         
             
                ast.comments = comments;
         
     | 
| 
       49 
45 
     | 
    
         
             
                const visitorKeys = {};
         
     | 
| 
       50 
46 
     | 
    
         
             
                types.forEach((t) => {
         
     | 
| 
         @@ -53,9 +49,6 @@ module.exports = { 
     | 
|
| 
       53 
49 
     | 
    
         
             
                ast.type = 'Program';
         
     | 
| 
       54 
50 
     | 
    
         
             
                ast.isHbs = true;
         
     | 
| 
       55 
51 
     | 
    
         
             
                ast.contents = code;
         
     | 
| 
       56 
     | 
    
         
            -
                tokens.slice(1).forEach((node) => {
         
     | 
| 
       57 
     | 
    
         
            -
                  node.type = `__TEMPLATE__${node.type}`;
         
     | 
| 
       58 
     | 
    
         
            -
                });
         
     | 
| 
       59 
52 
     | 
    
         
             
                const scope = new ScopeManager();
         
     | 
| 
       60 
53 
     | 
    
         
             
                scope.globalScope.block = ast;
         
     | 
| 
       61 
54 
     | 
    
         
             
                return { ast, scopeManager: scope, visitorKeys };
         
     | 
    
        package/lib/rules/config.js
    CHANGED
    
    | 
         @@ -14,7 +14,7 @@ const runTemplateLint = (text, filename, context, scopeVars=[], offset=0, option 
     | 
|
| 
       14 
14 
     | 
    
         
             
                const diffs = response.diff;
         
     | 
| 
       15 
15 
     | 
    
         
             
                const document = new DocumentLines(text);
         
     | 
| 
       16 
16 
     | 
    
         
             
                diffs.forEach((d) => {
         
     | 
| 
       17 
     | 
    
         
            -
                  d.range = [d.offset, d.offset + d.deleteText 
     | 
| 
      
 17 
     | 
    
         
            +
                  d.range = [d.offset, d.offset + (d.deleteText?.length || 0)];
         
     | 
| 
       18 
18 
     | 
    
         
             
                });
         
     | 
| 
       19 
19 
     | 
    
         
             
                lintMessages.forEach((m) => {
         
     | 
| 
       20 
20 
     | 
    
         
             
                  m.range = [
         
     | 
    
        package/lib/rules/hbs-worker.js
    CHANGED
    
    | 
         @@ -1,21 +1,77 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            const { runAsWorker } = require('synckit');
         
     | 
| 
       2 
2 
     | 
    
         
             
            const { generateDifferences } = require('prettier-linter-helpers');
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
      
 4 
     | 
    
         
            +
            async function _applyFixes(options, results, columnOffset) {
         
     | 
| 
      
 5 
     | 
    
         
            +
              const { transform } = await import('ember-template-recast');
         
     | 
| 
      
 6 
     | 
    
         
            +
              let currentSource = options.source;
         
     | 
| 
      
 7 
     | 
    
         
            +
              let fixableIssues = results.filter((r) => r.isFixable);
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              // nothing to do, bail out
         
     | 
| 
      
 10 
     | 
    
         
            +
              if (fixableIssues.length === 0) {
         
     | 
| 
      
 11 
     | 
    
         
            +
                return currentSource;
         
     | 
| 
      
 12 
     | 
    
         
            +
              }
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              let fileConfig = this._moduleStatusCache.getConfigForFile(options);
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              let ruleNames = new Set(fixableIssues.map((r) => r.rule));
         
     | 
| 
      
 17 
     | 
    
         
            +
              const spaces = ' '.repeat(columnOffset);
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              for (let ruleName of ruleNames) {
         
     | 
| 
      
 20 
     | 
    
         
            +
                let templateInfos = [{
         
     | 
| 
      
 21 
     | 
    
         
            +
                  template: currentSource,
         
     | 
| 
      
 22 
     | 
    
         
            +
                  columnOffset: 0,
         
     | 
| 
      
 23 
     | 
    
         
            +
                  isStrictMode: false
         
     | 
| 
      
 24 
     | 
    
         
            +
                }];
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                for (let templateInfo of templateInfos) {
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  let rule = this._buildRule(ruleName, {
         
     | 
| 
      
 29 
     | 
    
         
            +
                    shouldFix: true,
         
     | 
| 
      
 30 
     | 
    
         
            +
                    filePath: options.filePath,
         
     | 
| 
      
 31 
     | 
    
         
            +
                    columnOffset: templateInfo.columnOffset,
         
     | 
| 
      
 32 
     | 
    
         
            +
                    rawSource: templateInfo.template,
         
     | 
| 
      
 33 
     | 
    
         
            +
                    isStrictMode: templateInfo.isStrictMode,
         
     | 
| 
      
 34 
     | 
    
         
            +
                    fileConfig,
         
     | 
| 
      
 35 
     | 
    
         
            +
                  });
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  let visitor = await rule.getVisitor();
         
     | 
| 
      
 38 
     | 
    
         
            +
                  let { code } = transform(templateInfo.template, () => visitor);
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  if (code !== templateInfo.template) {
         
     | 
| 
      
 41 
     | 
    
         
            +
                    let template = templateInfo.template;
         
     | 
| 
      
 42 
     | 
    
         
            +
                    if (columnOffset) {
         
     | 
| 
      
 43 
     | 
    
         
            +
                      template = spaces + template.split('\n').join('\n' + spaces);
         
     | 
| 
      
 44 
     | 
    
         
            +
                    }
         
     | 
| 
      
 45 
     | 
    
         
            +
                    if (columnOffset) {
         
     | 
| 
      
 46 
     | 
    
         
            +
                      code = spaces + code.split('\n').join('\n' + spaces);
         
     | 
| 
      
 47 
     | 
    
         
            +
                    }
         
     | 
| 
      
 48 
     | 
    
         
            +
                    const diffs = generateDifferences(template, code);
         
     | 
| 
      
 49 
     | 
    
         
            +
                    fixableIssues.filter(r => r.rule === ruleName).forEach((r, i) => {
         
     | 
| 
      
 50 
     | 
    
         
            +
                      r.fix = diffs[i];
         
     | 
| 
      
 51 
     | 
    
         
            +
                    });
         
     | 
| 
      
 52 
     | 
    
         
            +
                  }
         
     | 
| 
      
 53 
     | 
    
         
            +
                }
         
     | 
| 
      
 54 
     | 
    
         
            +
              }
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
              return currentSource;
         
     | 
| 
      
 57 
     | 
    
         
            +
            }
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            runAsWorker(async (filename, text, options, columnOffset=0) => {
         
     | 
| 
       5 
60 
     | 
    
         
             
              const Lint = await import('ember-template-lint');
         
     | 
| 
       6 
61 
     | 
    
         
             
              const lint = new Lint.default(options);
         
     | 
| 
       7 
62 
     | 
    
         
             
              process.env.emberTemplateLintFileName = filename;
         
     | 
| 
       8 
63 
     | 
    
         
             
              process.env.emberTemplateLintFixMode = false;
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
       9 
65 
     | 
    
         
             
              const messages = await lint.verify({
         
     | 
| 
       10 
     | 
    
         
            -
                source: text
         
     | 
| 
      
 66 
     | 
    
         
            +
                source: text,
         
     | 
| 
      
 67 
     | 
    
         
            +
                filePath: filename.replace('.gts', '.hbs')
         
     | 
| 
       11 
68 
     | 
    
         
             
              });
         
     | 
| 
       12 
69 
     | 
    
         
             
              process.env.emberTemplateLintFixMode = true;
         
     | 
| 
       13 
     | 
    
         
            -
               
     | 
| 
       14 
     | 
    
         
            -
                source: text
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
               
     | 
| 
      
 70 
     | 
    
         
            +
              await _applyFixes.call(lint,{
         
     | 
| 
      
 71 
     | 
    
         
            +
                source: text,
         
     | 
| 
      
 72 
     | 
    
         
            +
                filePath: filename.replace('.gts', '.hbs'),
         
     | 
| 
      
 73 
     | 
    
         
            +
              }, messages, columnOffset);
         
     | 
| 
       17 
74 
     | 
    
         
             
              return {
         
     | 
| 
       18 
75 
     | 
    
         
             
                messages,
         
     | 
| 
       19 
     | 
    
         
            -
                diff
         
     | 
| 
       20 
76 
     | 
    
         
             
              };
         
     | 
| 
       21 
77 
     | 
    
         
             
            });
         
     | 
    
        package/lib/rules/lint.js
    CHANGED
    
    | 
         @@ -3,53 +3,58 @@ const synckit = require('synckit'); 
     | 
|
| 
       3 
3 
     | 
    
         
             
            const DocumentLines = require('../utils/document');
         
     | 
| 
       4 
4 
     | 
    
         
             
            const { templateLintConfig } = require('../ember-teplate-lint/config');
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            function runTemplateLint( 
     | 
| 
      
 6 
     | 
    
         
            +
            function runTemplateLint(node, context) {
         
     | 
| 
      
 7 
     | 
    
         
            +
              const sourceCode = context.getSourceCode();
         
     | 
| 
      
 8 
     | 
    
         
            +
              const { scopeManager, text: sourceCodeText } = sourceCode;
         
     | 
| 
      
 9 
     | 
    
         
            +
              const scopes = scopeManager.scopes.filter(x => x.block.range[0] < node.range[0] && x.block.range[1] > node.range[1]);
         
     | 
| 
      
 10 
     | 
    
         
            +
              const scopeVars = scopes.map(s => s.variables.map(x => x.name)).flat();
         
     | 
| 
      
 11 
     | 
    
         
            +
              const filename = context.getPhysicalFilename();
         
     | 
| 
      
 12 
     | 
    
         
            +
              let text = node.contents;
         
     | 
| 
      
 13 
     | 
    
         
            +
              const initialLine = sourceCodeText.split('\n')[node.loc.start.line-1];
         
     | 
| 
      
 14 
     | 
    
         
            +
              const columnOffset = initialLine.match(/\s+/)?.[0].length || 0;
         
     | 
| 
      
 15 
     | 
    
         
            +
              const offset = (node.range[0] || 0);
         
     | 
| 
      
 16 
     | 
    
         
            +
              const spaces = ' '.repeat(columnOffset);
         
     | 
| 
      
 17 
     | 
    
         
            +
              const originalDocument = new DocumentLines(spaces + text);
         
     | 
| 
      
 18 
     | 
    
         
            +
              if (columnOffset) {
         
     | 
| 
      
 19 
     | 
    
         
            +
                text = text.split('\n').map(l => l.replace(new RegExp(`^\\s{1,${columnOffset}}`), '')).join('\n');
         
     | 
| 
      
 20 
     | 
    
         
            +
                text = text.trim();
         
     | 
| 
      
 21 
     | 
    
         
            +
              }
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
       7 
23 
     | 
    
         
             
              try {
         
     | 
| 
       8 
24 
     | 
    
         
             
                const syncFn = synckit.createSyncFn(require.resolve('./hbs-worker'));
         
     | 
| 
       9 
     | 
    
         
            -
                const response = syncFn(filename, text, { config: templateLintConfig });
         
     | 
| 
      
 25 
     | 
    
         
            +
                const response = syncFn(filename, text, { config: templateLintConfig }, columnOffset);
         
     | 
| 
       10 
26 
     | 
    
         
             
                const lintMessages = response.messages;
         
     | 
| 
       11 
     | 
    
         
            -
                const diffs = response.diff;
         
     | 
| 
       12 
     | 
    
         
            -
                const document = new DocumentLines(text);
         
     | 
| 
       13 
     | 
    
         
            -
                diffs.forEach((d) => {
         
     | 
| 
       14 
     | 
    
         
            -
                  d.range = [d.offset, d.offset + d.deleteText.length];
         
     | 
| 
       15 
     | 
    
         
            -
                });
         
     | 
| 
       16 
27 
     | 
    
         
             
                lintMessages.forEach((m) => {
         
     | 
| 
      
 28 
     | 
    
         
            +
                  if (m.fix) {
         
     | 
| 
      
 29 
     | 
    
         
            +
                    const d = m.fix;
         
     | 
| 
      
 30 
     | 
    
         
            +
                    m.fix.range = [d.offset, d.offset + (d.deleteText?.length || 0)];
         
     | 
| 
      
 31 
     | 
    
         
            +
                    m.range = m.fix.range;
         
     | 
| 
      
 32 
     | 
    
         
            +
                    const start = originalDocument.offsetToPosition(m.fix.range[0]);
         
     | 
| 
      
 33 
     | 
    
         
            +
                    const end = originalDocument.offsetToPosition(m.fix.range[1]);
         
     | 
| 
      
 34 
     | 
    
         
            +
                    m.fix.range = [
         
     | 
| 
      
 35 
     | 
    
         
            +
                      originalDocument.positionToOffset({
         
     | 
| 
      
 36 
     | 
    
         
            +
                        line: start.line,
         
     | 
| 
      
 37 
     | 
    
         
            +
                        character: start.character
         
     | 
| 
      
 38 
     | 
    
         
            +
                      }),
         
     | 
| 
      
 39 
     | 
    
         
            +
                      originalDocument.positionToOffset({
         
     | 
| 
      
 40 
     | 
    
         
            +
                        line: end.line,
         
     | 
| 
      
 41 
     | 
    
         
            +
                        character: end.character
         
     | 
| 
      
 42 
     | 
    
         
            +
                      })
         
     | 
| 
      
 43 
     | 
    
         
            +
                    ];
         
     | 
| 
      
 44 
     | 
    
         
            +
                    m.fix.range = m.fix.range.map(x => offset + x);
         
     | 
| 
      
 45 
     | 
    
         
            +
                  }
         
     | 
| 
       17 
46 
     | 
    
         
             
                  m.range = [
         
     | 
| 
       18 
     | 
    
         
            -
                     
     | 
| 
      
 47 
     | 
    
         
            +
                    originalDocument.positionToOffset({
         
     | 
| 
       19 
48 
     | 
    
         
             
                      line: m.line - 1,
         
     | 
| 
       20 
     | 
    
         
            -
                      character: m.column 
     | 
| 
      
 49 
     | 
    
         
            +
                      character: m.column
         
     | 
| 
       21 
50 
     | 
    
         
             
                    }),
         
     | 
| 
       22 
     | 
    
         
            -
                     
     | 
| 
      
 51 
     | 
    
         
            +
                    originalDocument.positionToOffset({
         
     | 
| 
       23 
52 
     | 
    
         
             
                      line: m.endLine - 1,
         
     | 
| 
       24 
     | 
    
         
            -
                      character: m.endColumn 
     | 
| 
      
 53 
     | 
    
         
            +
                      character: m.endColumn
         
     | 
| 
       25 
54 
     | 
    
         
             
                    })];
         
     | 
| 
       26 
     | 
    
         
            -
                  const isInside = (d) => d.range[0] >= m.range[0] && d.range[1] <= m.range[1];
         
     | 
| 
       27 
     | 
    
         
            -
                  const doesContain = (d) => d.range[0] <= m.range[0] && d.range[1] >= m.range[1];
         
     | 
| 
       28 
     | 
    
         
            -
                  const idx = diffs.findIndex(d => isInside(d) || doesContain(d));
         
     | 
| 
       29 
     | 
    
         
            -
                  if (idx !== -1) {
         
     | 
| 
       30 
     | 
    
         
            -
                    const d = diffs.splice(idx, 1);
         
     | 
| 
       31 
     | 
    
         
            -
                    m.fix = d[0];
         
     | 
| 
       32 
     | 
    
         
            -
                    m.fix.range = m.fix.range.map(x => offset + x);
         
     | 
| 
       33 
     | 
    
         
            -
                  }
         
     | 
| 
       34 
55 
     | 
    
         
             
                  m.range = m.range.map(x => offset + x);
         
     | 
| 
       35 
56 
     | 
    
         
             
                });
         
     | 
| 
       36 
57 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
                if (diffs.length) {
         
     | 
| 
       38 
     | 
    
         
            -
                  diffs.forEach((d) => {
         
     | 
| 
       39 
     | 
    
         
            -
                    const range = d.range;
         
     | 
| 
       40 
     | 
    
         
            -
                    const [start, end] = range.map(index =>
         
     | 
| 
       41 
     | 
    
         
            -
                      context.getSourceCode().getLocFromIndex(index)
         
     | 
| 
       42 
     | 
    
         
            -
                    );
         
     | 
| 
       43 
     | 
    
         
            -
                    context.report({
         
     | 
| 
       44 
     | 
    
         
            -
                      fix: (fixer) => {
         
     | 
| 
       45 
     | 
    
         
            -
                        return fixer.replaceTextRange(range, d.fix.insertText || '');
         
     | 
| 
       46 
     | 
    
         
            -
                      },
         
     | 
| 
       47 
     | 
    
         
            -
                      loc: { start, end },
         
     | 
| 
       48 
     | 
    
         
            -
                      message: 'template error',
         
     | 
| 
       49 
     | 
    
         
            -
                    });
         
     | 
| 
       50 
     | 
    
         
            -
                  });
         
     | 
| 
       51 
     | 
    
         
            -
                }
         
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
58 
     | 
    
         
             
                lintMessages.forEach((msg) => {
         
     | 
| 
       54 
59 
     | 
    
         
             
                  if (msg.rule === 'no-implicit-this') {
         
     | 
| 
       55 
60 
     | 
    
         
             
                    if (scopeVars.includes(msg.source)) {
         
     | 
| 
         @@ -80,4 +85,4 @@ function runTemplateLint(text, filename, context, scopeVars=[], offset=0) { 
     | 
|
| 
       80 
85 
     | 
    
         | 
| 
       81 
86 
     | 
    
         
             
            module.exports = {
         
     | 
| 
       82 
87 
     | 
    
         
             
              runTemplateLint
         
     | 
| 
       83 
     | 
    
         
            -
            };
         
     | 
| 
      
 88 
     | 
    
         
            +
            };
         
     | 
    
        package/package.json
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            {
         
     | 
| 
       2 
2 
     | 
    
         
             
              "name": "eslint-plugin-ember-template-lint",
         
     | 
| 
       3 
     | 
    
         
            -
              "version": "0. 
     | 
| 
      
 3 
     | 
    
         
            +
              "version": "0.6.0",
         
     | 
| 
       4 
4 
     | 
    
         
             
              "description": "Provide linting for ember template",
         
     | 
| 
       5 
5 
     | 
    
         
             
              "keywords": [
         
     | 
| 
       6 
6 
     | 
    
         
             
                "eslint",
         
     | 
| 
         @@ -17,13 +17,14 @@ 
     | 
|
| 
       17 
17 
     | 
    
         
             
              },
         
     | 
| 
       18 
18 
     | 
    
         
             
              "dependencies": {
         
     | 
| 
       19 
19 
     | 
    
         
             
                "@glimmer/syntax": "^0.84.3",
         
     | 
| 
       20 
     | 
    
         
            -
                "typescript": "^5.0.4",
         
     | 
| 
       21 
20 
     | 
    
         
             
                "@typescript-eslint/parser": "^5.59.7",
         
     | 
| 
       22 
21 
     | 
    
         
             
                "@typescript-eslint/typescript-estree": "^5.59.7",
         
     | 
| 
       23 
22 
     | 
    
         
             
                "ember-template-imports": "^3.4.2",
         
     | 
| 
       24 
     | 
    
         
            -
                "prettier-linter-helpers": "^1.0.0",
         
     | 
| 
       25 
23 
     | 
    
         
             
                "ember-template-lint": "^5.7.3",
         
     | 
| 
       26 
     | 
    
         
            -
                " 
     | 
| 
      
 24 
     | 
    
         
            +
                "ember-template-recast": "^6.1.4",
         
     | 
| 
      
 25 
     | 
    
         
            +
                "prettier-linter-helpers": "^1.0.0",
         
     | 
| 
      
 26 
     | 
    
         
            +
                "synckit": "^0.8.5",
         
     | 
| 
      
 27 
     | 
    
         
            +
                "typescript": "^5.0.4"
         
     | 
| 
       27 
28 
     | 
    
         
             
              },
         
     | 
| 
       28 
29 
     | 
    
         
             
              "peerDependencies": {
         
     | 
| 
       29 
30 
     | 
    
         
             
                "ember-template-lint": "^5.7.3"
         
     |