eslint-plugin-ember-template-lint 0.1.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -24,14 +24,34 @@ Add `hbs` to the plugins section of your `.eslintrc` configuration file. You can
24
24
 
25
25
  ### 2. Modify your `.eslintrc.js`
26
26
 
27
+ you can use the presets from here https://github.com/ember-template-lint/ember-template-lint#presets
28
+ like this:
29
+ `plugin:ember-template-lint/<preset>`
30
+
31
+ to just use the `.template-lintrc.js` config file just use
32
+ `plugin:ember-template-lint/config`
33
+
34
+ to load ember-template-lint plugins in eslinrc you need to manually register them:
35
+ ```js
36
+ require('eslint-plugin-ember-template-lint/lib/ember-teplate-lint/config').registerPlugin('ember-template-lint-plugin-prettier');
37
+ ```
38
+
39
+ ## IMPORTANT
40
+ Do NOT set parser to anything in your .eslintrc.js as it will override the parser from here
41
+
42
+ for typescript parser you can extend its base config, then it will work correctly
43
+
27
44
  ```js
28
45
  // .eslintrc.js
29
46
  // optional:
30
47
  require('eslint-plugin-ember-template-lint/lib/ember-teplate-lint/config').registerPlugin('ember-template-lint-plugin-prettier');
31
48
 
49
+
32
50
  module.exports = {
33
51
  extends: [
34
52
  'eslint:recommended',
53
+ 'plugin:@typescript-eslint/base',
54
+ 'plugin:ember-template-lint/config',
35
55
  'plugin:ember-template-lint/recommended',
36
56
  //optional:
37
57
  'plugin:ember-template-lint/ember-template-lint-plugin-prettier:recommended'
@@ -0,0 +1,20 @@
1
+ module.exports = {
2
+ root: true,
3
+
4
+ plugins: ['ember-template-lint'],
5
+
6
+ rules: {},
7
+
8
+ overrides: [
9
+ {
10
+ files: ['**/*.hbs'],
11
+ parser: require.resolve('../parser/hbs-parser'),
12
+ processor: 'ember-template-lint/noop'
13
+ },
14
+ {
15
+ files: ['**/*.gts', '**/*.gjs'],
16
+ parser: require.resolve('../parser/gts-parser'),
17
+ processor: 'ember-template-lint/noop'
18
+ },
19
+ ],
20
+ };
@@ -0,0 +1,20 @@
1
+ const info = require('../ember-teplate-lint/info');
2
+ const base = require('./base');
3
+
4
+ const configs = {};
5
+
6
+ Object.entries(info.configs).forEach(([name, config]) => {
7
+ Object.entries(config.rules).forEach(([name, conf]) => {
8
+ if (typeof conf == 'boolean') {
9
+ config.rules[name] = [conf ? 'error' : 'off'];
10
+ }
11
+ });
12
+ configs[name] = {...base, rules: config.rules};
13
+ });
14
+ configs['config'] = {
15
+ ...base,
16
+ rules: info.configuredRules
17
+ };
18
+
19
+ module.exports = configs;
20
+
@@ -0,0 +1,18 @@
1
+ const templateLintConfig = {
2
+ rules: {},
3
+ plugins: [],
4
+ };
5
+
6
+ function registerRule(name, config) {
7
+ templateLintConfig.rules[name] = config;
8
+ }
9
+
10
+ function registerPlugin(name) {
11
+ templateLintConfig.plugins.push(name);
12
+ }
13
+
14
+ module.exports = {
15
+ registerRule,
16
+ registerPlugin,
17
+ templateLintConfig
18
+ };
@@ -0,0 +1,111 @@
1
+ const synckit = require('synckit');
2
+ const syncFn = synckit.createSyncFn(require.resolve('./worker'));
3
+ const { runTemplateLint } = require('../rules/lint');
4
+ const { registerRule, templateLintConfig } = require('../ember-teplate-lint/config');
5
+
6
+ const lintWithEslintConfigs = syncFn({ config: templateLintConfig });
7
+ const lintConfigs = syncFn();
8
+
9
+ const activeRules = new Map();
10
+ const allMessages = {};
11
+
12
+ const reporter = {
13
+ setup(context) {
14
+ this.getSourceCode = context.getSourceCode;
15
+ },
16
+ report(message) {
17
+ message.meta = {
18
+ fixable: 'code'
19
+ };
20
+ allMessages[message.rule] = allMessages[message.rule] || [];
21
+ allMessages[message.rule].push(message);
22
+ }
23
+ };
24
+
25
+ class Rule {
26
+
27
+ constructor(name) {
28
+ this.create = this.create.bind(this);
29
+ this.name = name;
30
+ this.meta = {
31
+ fixable: 'code'
32
+ };
33
+ }
34
+ create(context) {
35
+ const rule = this;
36
+ let options = context.options;
37
+ if (options.length === 0) {
38
+ options = true;
39
+ }
40
+ registerRule(this.name, options);
41
+ const visitor = {
42
+ enter(node) {
43
+ if (!activeRules.get(node)) {
44
+ 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
+ reporter.setup(context);
52
+ runTemplateLint(node.contents, filename, reporter, scopeVars, start);
53
+ }
54
+ activeRules.set(node, activeRules.get(node) + 1);
55
+ },
56
+ exit(node) {
57
+ const messages = allMessages[rule.name] || [];
58
+ messages.forEach(m => context.report(m));
59
+ activeRules.set(node, activeRules.get(node) - 1);
60
+ allMessages[rule.name] = [];
61
+ },
62
+ };
63
+ return {
64
+ 'Program': (node) => node.isHbs && visitor.enter(node),
65
+ 'Program:exit': (node) => node.isHbs && visitor.exit(node),
66
+ '__TEMPLATE__Template': visitor.enter,
67
+ '__TEMPLATE__Template:exit': visitor.exit,
68
+ };
69
+ }
70
+ }
71
+
72
+ function createRules(rules) {
73
+ const created = rules.map(r => new Rule(r));
74
+ const map = {};
75
+ created.forEach(r => {
76
+ map[r.name] = r;
77
+ });
78
+ return map;
79
+ }
80
+
81
+ const configs = {
82
+ ...lintWithEslintConfigs.configs,
83
+ ...lintConfigs.configs
84
+ };
85
+
86
+ const rules = [...new Set([...lintConfigs.rules, ...lintWithEslintConfigs.rules])];
87
+
88
+ delete configs.recommended.overrides;
89
+
90
+ Object.values(configs).forEach((config) => {
91
+ const rules = {};
92
+ Object.entries(config.rules).forEach(([rule, conf]) => {
93
+ rules['ember-template-lint/' + rule] = conf;
94
+ });
95
+ config.rules = rules;
96
+ });
97
+
98
+
99
+ const configuredRules = {};
100
+ Object.entries(lintConfigs.configuredRules).forEach(([name, conf]) => {
101
+ configuredRules['ember-template-lint/' + name] = conf.config && [conf.severity];
102
+ if (typeof conf.config !== 'boolean') {
103
+ configuredRules['ember-template-lint/' + name].push(conf.config);
104
+ }
105
+ });
106
+
107
+ module.exports = {
108
+ configs: configs,
109
+ rules: createRules(rules),
110
+ configuredRules: configuredRules
111
+ };
@@ -0,0 +1,12 @@
1
+ const { runAsWorker } = require('synckit');
2
+
3
+ runAsWorker(async (options) => {
4
+ const Lint = await import('ember-template-lint');
5
+ const lint = new Lint.default(options);
6
+ await lint.loadConfig();
7
+ return {
8
+ configs: lint.config.loadedConfigurations,
9
+ rules: Object.keys(lint.config.loadedRules),
10
+ configuredRules: lint.config.rules,
11
+ };
12
+ });
@@ -0,0 +1,80 @@
1
+ const { preprocess, traverse, Source } = require('@glimmer/syntax');
2
+ const gts = require('ember-template-imports');
3
+ const typescriptParser = require('@typescript-eslint/parser');
4
+ const typescriptEstree = require('@typescript-eslint/typescript-estree');
5
+
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
+
27
+ function replaceRange(s, start, end, substitute) {
28
+ return s.substring(0, start) + substitute + s.substring(end);
29
+ }
30
+
31
+
32
+ module.exports = {
33
+ parseForESLint(code, options) {
34
+ let jsCode = code;
35
+ const templateInfos = gts.parseTemplates(jsCode, options.filePath);
36
+ templateInfos.forEach((tpl) => {
37
+ const range = [tpl.start.index, tpl.end.index + tpl.end[0].length];
38
+ tpl.range = range;
39
+ const template = jsCode.slice(...range);
40
+ const lines = template.split('\n');
41
+ lines.forEach((line, i) => {
42
+ lines[i] = ' '.repeat(line.length);
43
+ });
44
+ const emptyText = '[`' + lines.join('\n').slice(4) + '`]';
45
+ jsCode = replaceRange(jsCode, ...range, emptyText);
46
+ const source = new Source(tpl.contents);
47
+ const ast = preprocess(source, { mode: 'codemod' });
48
+ ast.range = [tpl.start.index + tpl.start[0].length + 1, tpl.end.index];
49
+ ast.contents = tpl.contents;
50
+ tpl.ast = ast;
51
+ });
52
+ const result = typescriptParser.parseForESLint(jsCode, options);
53
+ const visitorKeys = {...result.visitorKeys};
54
+ result.ast.tokens.forEach((token) => {
55
+ if (token.type === 'Template') {
56
+ const range = [token.range[0] - 1, token.range[1] + 1];
57
+ const template = templateInfos.find(t => t.range[0] >= range[0] && t.range[1] <= range[1]);
58
+ if (!template) return;
59
+ const ast = template.ast;
60
+ ast.loc = token.loc;
61
+ const source = new Source(code);
62
+ Object.assign(visitorKeys, visitorKeysForAst(source, ast));
63
+ Object.assign(token, ast);
64
+ }
65
+ });
66
+ typescriptEstree.simpleTraverse(result.ast, {
67
+ enter(node) {
68
+ if (node.type === 'TemplateLiteral') {
69
+ const range = [node.range[0] - 1, node.range[1] + 1];
70
+ const template = templateInfos.find(t => t.range[0] >= range[0] && t.range[1] <= range[1]);
71
+ if (!template) return;
72
+ const ast = template.ast;
73
+ Object.assign(node, ast);
74
+ }
75
+ }
76
+ });
77
+
78
+ return { ...result, visitorKeys };
79
+ }
80
+ };
@@ -0,0 +1,63 @@
1
+ const { preprocess, traverse, Source } = require('@glimmer/syntax');
2
+
3
+ class Scope {
4
+ type = 'global';
5
+ variables = [];
6
+ through= [];
7
+ set = new Map();
8
+ upper = null;
9
+ childScopes = [];
10
+ references = [];
11
+ block = null;
12
+ }
13
+
14
+ class ScopeManager {
15
+ globalScope = new Scope();
16
+ scopes = [this.globalScope];
17
+
18
+ acquire() {
19
+ return;
20
+ }
21
+
22
+ getDeclaredVariables() {
23
+ return [];
24
+ }
25
+ }
26
+
27
+ module.exports = {
28
+ parseForESLint(code) {
29
+ const source = new Source(code);
30
+ const ast = preprocess(source, { mode: 'codemod' });
31
+ const tokens = [];
32
+ const comments = [];
33
+ const types = new Set();
34
+ types.add('Program');
35
+ traverse(ast, {
36
+ All(node) {
37
+ types.add(`__TEMPLATE__${node.type}`);
38
+ const span = source.spanFor(node.loc);
39
+ node.range = [span.getStart().offset, span.getEnd().offset];
40
+ if (node.type.toLowerCase().includes('comment')) {
41
+ comments.push(node);
42
+ return;
43
+ }
44
+ tokens.push(node);
45
+ }
46
+ });
47
+ ast.tokens = tokens;
48
+ ast.comments = comments;
49
+ const visitorKeys = {};
50
+ types.forEach((t) => {
51
+ visitorKeys[t] = [];
52
+ });
53
+ ast.type = 'Program';
54
+ ast.isHbs = true;
55
+ ast.contents = code;
56
+ tokens.slice(1).forEach((node) => {
57
+ node.type = `__TEMPLATE__${node.type}`;
58
+ });
59
+ const scope = new ScopeManager();
60
+ scope.globalScope.block = ast;
61
+ return { ast, scopeManager: scope, visitorKeys };
62
+ }
63
+ };
@@ -0,0 +1,11 @@
1
+
2
+
3
+ module.exports = {
4
+ preprocess: (text, filename) => {
5
+ return [{text: text, filename}];
6
+ },
7
+ postprocess: (messages) => {
8
+ return messages.flat();
9
+ },
10
+ supportsAutofix: true
11
+ };
@@ -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.length];
17
+ d.range = [d.offset, d.offset + (d.deleteText?.length || 0)];
18
18
  });
19
19
  lintMessages.forEach((m) => {
20
20
  m.range = [
@@ -1,21 +1,68 @@
1
1
  const { runAsWorker } = require('synckit');
2
2
  const { generateDifferences } = require('prettier-linter-helpers');
3
3
 
4
+ async function _applyFixes(options, results) {
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
+
18
+ for (let ruleName of ruleNames) {
19
+ let templateInfos = [{
20
+ template: currentSource,
21
+ columnOffset: 0,
22
+ isStrictMode: false
23
+ }];
24
+
25
+ for (let templateInfo of templateInfos) {
26
+
27
+ let rule = this._buildRule(ruleName, {
28
+ shouldFix: true,
29
+ filePath: options.filePath,
30
+ columnOffset: templateInfo.columnOffset,
31
+ rawSource: templateInfo.template,
32
+ isStrictMode: templateInfo.isStrictMode,
33
+ fileConfig,
34
+ });
35
+
36
+ let visitor = await rule.getVisitor();
37
+ let { code } = transform(templateInfo.template, () => visitor);
38
+
39
+ if (code !== templateInfo.template) {
40
+ const diffs = generateDifferences(templateInfo.template, code);
41
+ fixableIssues.filter(r => r.rule === ruleName).forEach((r, i) => {
42
+ r.fix = diffs[i];
43
+ });
44
+ }
45
+ }
46
+ }
47
+
48
+ return currentSource;
49
+ }
50
+
4
51
  runAsWorker(async (filename, text, options) => {
5
52
  const Lint = await import('ember-template-lint');
6
53
  const lint = new Lint.default(options);
7
54
  process.env.emberTemplateLintFileName = filename;
8
55
  process.env.emberTemplateLintFixMode = false;
9
56
  const messages = await lint.verify({
10
- source: text
57
+ source: text,
58
+ filePath: filename.replace('.gts', '.hbs')
11
59
  });
12
60
  process.env.emberTemplateLintFixMode = true;
13
- const fixedText = (await lint.verifyAndFix({
14
- source: text
15
- })).output;
16
- const diff = generateDifferences(text, fixedText);
61
+ await _applyFixes.call(lint,{
62
+ source: text,
63
+ filePath: filename.replace('.gts', '.hbs')
64
+ }, messages);
17
65
  return {
18
66
  messages,
19
- diff
20
67
  };
21
68
  });
package/lib/rules/lint.js CHANGED
@@ -4,52 +4,57 @@ const DocumentLines = require('../utils/document');
4
4
  const { templateLintConfig } = require('../ember-teplate-lint/config');
5
5
 
6
6
  function runTemplateLint(text, filename, context, scopeVars=[], offset=0) {
7
+ const originalDocument = new DocumentLines(text);
7
8
  try {
9
+ let columnOffset = 0;
10
+ let lineOffset = 0;
11
+ if (text.startsWith('\n')) {
12
+ text = text.slice(1);
13
+ lineOffset += 1;
14
+ }
15
+ columnOffset = text.match(/\s+/)[0].length;
16
+ text = text.split('\n').map(l => l.replace(new RegExp(`^\\s{1,${columnOffset}}`), '')).join('\n');
17
+ text = text.trim();
8
18
  const syncFn = synckit.createSyncFn(require.resolve('./hbs-worker'));
9
19
  const response = syncFn(filename, text, { config: templateLintConfig });
10
20
  const lintMessages = response.messages;
11
- const diffs = response.diff;
12
21
  const document = new DocumentLines(text);
13
- diffs.forEach((d) => {
14
- d.range = [d.offset, d.offset + d.deleteText.length];
15
- });
16
22
  lintMessages.forEach((m) => {
23
+ if (m.fix) {
24
+ const d = m.fix;
25
+ if (d.insertText) {
26
+ d.insertText = d.insertText.replace(/\n/g, '\n' + ' '.repeat(columnOffset));
27
+ }
28
+ m.fix.range = [d.offset, d.offset + (d.deleteText?.length || 0)];
29
+ m.range = m.fix.range;
30
+ const start = document.offsetToPosition(m.fix.range[0]);
31
+ const end = document.offsetToPosition(m.fix.range[1]);
32
+ m.fix.range = [
33
+ originalDocument.positionToOffset({
34
+ line: start.line + lineOffset,
35
+ character: start.character + columnOffset - 1
36
+ }),
37
+ originalDocument.positionToOffset({
38
+ line: end.line + lineOffset,
39
+ character: end.character + columnOffset - 1
40
+ })
41
+ ];
42
+ m.fix.range = m.fix.range.map(x => offset + x);
43
+ m.range = m.fix.range;
44
+ return;
45
+ }
17
46
  m.range = [
18
- document.positionToOffset({
19
- line: m.line - 1,
20
- character: m.column - 1
47
+ originalDocument.positionToOffset({
48
+ line: m.line - 1 + lineOffset,
49
+ character: m.column + columnOffset - 1
21
50
  }),
22
- document.positionToOffset({
23
- line: m.endLine - 1,
24
- character: m.endColumn - 1
51
+ originalDocument.positionToOffset({
52
+ line: m.endLine - 1 + lineOffset,
53
+ character: m.endColumn + columnOffset - 1
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
+ };
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @typedef {{ line: number; character: number }} Position
3
+ */
4
+
5
+ // Helper class to convert line/column from and to offset
6
+ // taken and adapt from https://github.com/typed-ember/glint/blob/main/packages/core/src/language-server/util/position.ts
7
+ class DocumentLines {
8
+ /**
9
+ * @param {string} contents
10
+ */
11
+ constructor(contents) {
12
+ this.lineStarts = computeLineStarts(contents);
13
+ }
14
+
15
+ /**
16
+ * @param {Position} position
17
+ * @return {number}
18
+ */
19
+ positionToOffset(position) {
20
+ const { line, character } = position;
21
+ return this.lineStarts[line] + character;
22
+ }
23
+
24
+ /**
25
+ *
26
+ * @param {number} position
27
+ * @return {Position}
28
+ */
29
+ offsetToPosition(position) {
30
+ const lineStarts = this.lineStarts;
31
+ let line = 0;
32
+ while (line + 1 < lineStarts.length && lineStarts[line + 1] <= position) {
33
+ line++;
34
+ }
35
+ const character = position - lineStarts[line];
36
+ return { line, character };
37
+ }
38
+ }
39
+
40
+ /**
41
+ * @returns {number[]}
42
+ * @param {string} text
43
+ */
44
+ function computeLineStarts(text) {
45
+ const result = [];
46
+ let pos = 0;
47
+ let lineStart = 0;
48
+ while (pos < text.length) {
49
+ const ch = text.codePointAt(pos);
50
+ pos++;
51
+ switch (ch) {
52
+ case 13 /* carriageReturn */: {
53
+ if (text.codePointAt(pos) === 10 /* lineFeed */) {
54
+ pos++;
55
+ }
56
+ }
57
+ // falls through
58
+ case 10 /* lineFeed */: {
59
+ result.push(lineStart);
60
+ lineStart = pos;
61
+ break;
62
+ }
63
+ default: {
64
+ if (ch > 127 /* maxAsciiCharacter */ && isLineBreak(ch)) {
65
+ result.push(lineStart);
66
+ lineStart = pos;
67
+ }
68
+ break;
69
+ }
70
+ }
71
+ }
72
+ result.push(lineStart);
73
+ return result;
74
+ }
75
+
76
+ /* istanbul ignore next */
77
+ /**
78
+ * @param {number} ch
79
+ * @return {boolean}
80
+ */
81
+ function isLineBreak(ch) {
82
+ // ES5 7.3:
83
+ // The ECMAScript line terminator characters are listed in Table 3.
84
+ // Table 3: Line Terminator Characters
85
+ // Code Unit Value Name Formal Name
86
+ // \u000A Line Feed <LF>
87
+ // \u000D Carriage Return <CR>
88
+ // \u2028 Line separator <LS>
89
+ // \u2029 Paragraph separator <PS>
90
+ // Only the characters in Table 3 are treated as line terminators. Other new line or line
91
+ // breaking characters are treated as white space but not as line terminators.
92
+ return (
93
+ ch === 10 /* lineFeed */ ||
94
+ ch === 13 /* carriageReturn */ ||
95
+ ch === 8232 /* lineSeparator */ ||
96
+ ch === 8233 /* paragraphSeparator */
97
+ );
98
+ }
99
+
100
+ module.exports = DocumentLines;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-ember-template-lint",
3
- "version": "0.1.0",
3
+ "version": "0.5.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
- "synckit": "^0.8.5"
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"
@@ -45,6 +46,6 @@
45
46
  },
46
47
  "license": "ISC",
47
48
  "files": [
48
- "lib/rules/*.js"
49
+ "lib/**/*.js"
49
50
  ]
50
51
  }