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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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"