eslint-plugin-ember-template-lint 0.2.0 → 0.5.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.
@@ -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
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-ember-template-lint",
3
- "version": "0.2.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"