eslint-plugin-ember-template-lint 0.14.0 → 0.16.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/README.md CHANGED
@@ -57,14 +57,24 @@ require('eslint-plugin-ember-template-lint/lib/ember-teplate-lint/config').regis
57
57
 
58
58
 
59
59
  module.exports = {
60
- extends: [
61
- 'eslint:recommended',
62
- 'plugin:@typescript-eslint/base',
63
- 'plugin:ember-template-lint/config',
64
- 'plugin:ember-template-lint/recommended',
65
- //optional:
66
- 'plugin:ember-template-lint/ember-template-lint-plugin-prettier:recommended'
67
- ]
60
+ overrides: [
61
+ {
62
+ files: ['**/*.hbs'],
63
+ parser: 'ember-template-lint/lib/parser/hbs-parser',
64
+ extends: [
65
+ 'plugin:ember-template-lint/config',
66
+ 'plugin:ember-template-lint/recommended',
67
+ ],
68
+ },
69
+ {
70
+ files: ['**/*.gjs'],
71
+ parser: 'ember-eslint-parser',
72
+ extends: [
73
+ 'plugin:ember-template-lint/config',
74
+ 'plugin:ember-template-lint/recommended',
75
+ ],
76
+ },
77
+ ],
68
78
  };
69
79
  ```
70
80
 
@@ -53,14 +53,6 @@ async function _applyFixes(options, results, columnOffset) {
53
53
  fileConfig,
54
54
  });
55
55
 
56
- if (ruleName === 'prettier') {
57
- const getPrettierOptions = rule.getPrettierOptions;
58
- rule.getPrettierOptions = function () {
59
- const options = getPrettierOptions.call(this);
60
- return Object.assign(options, fileConfig.rules[ruleName]?.config || {});
61
- };
62
- }
63
-
64
56
  let visitor = await rule.getVisitor();
65
57
  let { code } = transform(templateInfo.template, () => visitor);
66
58
 
@@ -126,6 +118,16 @@ runAsWorker(async (filename, text, options, columnOffset=0) => {
126
118
  const lint = new Lint.default(options);
127
119
  process.env.emberTemplateLintFileName = filename;
128
120
  process.env.emberTemplateLintFixMode = false;
121
+ await lint.loadConfig();
122
+ let fileConfig = lint._moduleStatusCache.getConfigForFile(options);
123
+ if (fileConfig.loadedRules['prettier']) {
124
+ const rule = fileConfig.loadedRules['prettier'].prototype;
125
+ const getPrettierOptions = rule.getPrettierOptions;
126
+ rule.getPrettierOptions = function () {
127
+ const options = getPrettierOptions.call(this);
128
+ return Object.assign(options, fileConfig.rules.prettier?.config || {});
129
+ };
130
+ }
129
131
 
130
132
  const messages = await lint.verify({
131
133
  source: text,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-ember-template-lint",
3
- "version": "0.14.0",
3
+ "version": "0.16.0",
4
4
  "description": "Provide linting for ember template",
5
5
  "keywords": [
6
6
  "eslint",
@@ -19,18 +19,18 @@
19
19
  "@glimmer/syntax": "^0.84.3",
20
20
  "@typescript-eslint/parser": "^5.59.7",
21
21
  "@typescript-eslint/typescript-estree": "^5.59.7",
22
- "ember-template-imports": "^3.4.2",
23
- "ember-template-lint": "^5.7.3",
24
- "ember-template-recast": "^6.1.4",
22
+ "ember-eslint-parser": "^0.5.6",
23
+ "ember-template-recast": "^6.1.5",
24
+ "ember-template-lint": "^6.0.0",
25
25
  "prettier-linter-helpers": "^1.0.0",
26
26
  "synckit": "^0.8.5",
27
27
  "typescript": "^5.0.4"
28
28
  },
29
29
  "peerDependencies": {
30
- "ember-template-lint": "^5.7.3"
30
+ "ember-template-lint": "^6.0.0"
31
31
  },
32
32
  "devDependencies": {
33
- "ember-template-lint-plugin-prettier": "^4.1.0",
33
+ "ember-template-lint-plugin-prettier": "^5.0.0",
34
34
  "eslint": "^8.41.0",
35
35
  "eslint-plugin-jest": "^27.2.1",
36
36
  "eslint-plugin-node": "^11.1.0",
@@ -46,6 +46,6 @@
46
46
  },
47
47
  "license": "ISC",
48
48
  "files": [
49
- "lib/**/*.js"
49
+ "lib/rules/*.js"
50
50
  ]
51
51
  }
@@ -1,20 +0,0 @@
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
- };
@@ -1,20 +0,0 @@
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
-
@@ -1,18 +0,0 @@
1
- const templateLintConfig = {
2
- rules: {},
3
- plugins: [],
4
- };
5
-
6
- function registerRule(name, config) {
7
- templateLintConfig.rules[name] = Array.isArray(config) ? config[0] : config;
8
- }
9
-
10
- function registerPlugin(name) {
11
- templateLintConfig.plugins.push(name);
12
- }
13
-
14
- module.exports = {
15
- registerRule,
16
- registerPlugin,
17
- templateLintConfig
18
- };
@@ -1,106 +0,0 @@
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
- this.getPhysicalFilename = context.getPhysicalFilename;
16
- },
17
- report(message) {
18
- message.meta = {
19
- fixable: 'code'
20
- };
21
- allMessages[message.rule] = allMessages[message.rule] || [];
22
- allMessages[message.rule].push(message);
23
- }
24
- };
25
-
26
- class Rule {
27
-
28
- constructor(name) {
29
- this.create = this.create.bind(this);
30
- this.name = name;
31
- this.meta = {
32
- fixable: 'code'
33
- };
34
- }
35
- create(context) {
36
- const rule = this;
37
- let options = context.options;
38
- if (options.length === 0) {
39
- options = true;
40
- }
41
- registerRule(this.name, options);
42
- const visitor = {
43
- enter(node) {
44
- if (!activeRules.get(node)) {
45
- activeRules.set(node, 0);
46
- reporter.setup(context);
47
- runTemplateLint(node, reporter);
48
- }
49
- activeRules.set(node, activeRules.get(node) + 1);
50
- },
51
- exit(node) {
52
- const messages = allMessages[rule.name] || [];
53
- messages.forEach(m => context.report(m));
54
- activeRules.set(node, activeRules.get(node) - 1);
55
- allMessages[rule.name] = [];
56
- },
57
- };
58
- return {
59
- 'Program': (node) => node.isHbs && visitor.enter(node),
60
- 'Program:exit': (node) => node.isHbs && visitor.exit(node),
61
- '__TEMPLATE__Template': visitor.enter,
62
- '__TEMPLATE__Template:exit': visitor.exit,
63
- };
64
- }
65
- }
66
-
67
- function createRules(rules) {
68
- const created = rules.map(r => new Rule(r));
69
- const map = {};
70
- created.forEach(r => {
71
- map[r.name] = r;
72
- });
73
- return map;
74
- }
75
-
76
- const configs = {
77
- ...lintWithEslintConfigs.configs,
78
- ...lintConfigs.configs
79
- };
80
-
81
- const rules = [...new Set([...lintConfigs.rules, ...lintWithEslintConfigs.rules])];
82
-
83
- delete configs.recommended.overrides;
84
-
85
- Object.values(configs).forEach((config) => {
86
- const rules = {};
87
- Object.entries(config.rules).forEach(([rule, conf]) => {
88
- rules['ember-template-lint/' + rule] = conf;
89
- });
90
- config.rules = rules;
91
- });
92
-
93
-
94
- const configuredRules = {};
95
- Object.entries(lintConfigs.configuredRules).forEach(([name, conf]) => {
96
- configuredRules['ember-template-lint/' + name] = conf.config && [conf.severity];
97
- if (typeof conf.config !== 'boolean') {
98
- configuredRules['ember-template-lint/' + name].push(conf.config);
99
- }
100
- });
101
-
102
- module.exports = {
103
- configs: configs,
104
- rules: createRules(rules),
105
- configuredRules: configuredRules
106
- };
@@ -1,12 +0,0 @@
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
- });
@@ -1,57 +0,0 @@
1
- const gts = require('ember-template-imports');
2
- const typescriptParser = require('@typescript-eslint/parser');
3
- const typescriptEstree = require('@typescript-eslint/typescript-estree');
4
-
5
-
6
- function replaceRange(s, start, end, substitute) {
7
- return s.substring(0, start) + substitute + s.substring(end);
8
- }
9
-
10
- module.exports = {
11
- parseForESLint(code, options) {
12
- let jsCode = code;
13
- const templateInfos = gts.parseTemplates(jsCode, options.filePath);
14
- templateInfos.forEach((tpl) => {
15
- const range = [tpl.start.index, tpl.end.index + tpl.end[0].length];
16
- tpl.range = range;
17
- const template = jsCode.slice(...range);
18
- const lines = template.split('\n');
19
- lines.forEach((line, i) => {
20
- lines[i] = ' '.repeat(line.length);
21
- });
22
- const emptyText = '[`' + lines.join('\n').slice(4) + '`]';
23
- jsCode = replaceRange(jsCode, ...range, emptyText);
24
- const ast = {
25
- type: '__TEMPLATE__Template',
26
- };
27
- ast.range = range;
28
- ast.contents = template;
29
- tpl.ast = ast;
30
- });
31
- const result = typescriptParser.parseForESLint(jsCode, options);
32
- const visitorKeys = {...result.visitorKeys, '__TEMPLATE__Template': []};
33
- result.ast.tokens.forEach((token) => {
34
- if (token.type === 'Template') {
35
- const range = [token.range[0] - 1, token.range[1] + 1];
36
- const template = templateInfos.find(t => t.range[0] >= range[0] && t.range[1] <= range[1]);
37
- if (!template) return;
38
- const ast = template.ast;
39
- ast.loc = token.loc;
40
- Object.assign(token, ast);
41
- }
42
- });
43
- typescriptEstree.simpleTraverse(result.ast, {
44
- enter(node) {
45
- if (node.type === 'TemplateLiteral') {
46
- const range = [node.range[0] - 1, node.range[1] + 1];
47
- const template = templateInfos.find(t => t.range[0] >= range[0] && t.range[1] <= range[1]);
48
- if (!template) return;
49
- const ast = template.ast;
50
- Object.assign(node, ast);
51
- }
52
- }
53
- });
54
-
55
- return { ...result, visitorKeys };
56
- }
57
- };
@@ -1,57 +0,0 @@
1
-
2
- class Scope {
3
- type = 'global';
4
- variables = [];
5
- through= [];
6
- set = new Map();
7
- upper = null;
8
- childScopes = [];
9
- references = [];
10
- block = null;
11
- }
12
-
13
- class ScopeManager {
14
- globalScope = new Scope();
15
- scopes = [this.globalScope];
16
-
17
- acquire() {
18
- return;
19
- }
20
-
21
- getDeclaredVariables() {
22
- return [];
23
- }
24
- }
25
-
26
- module.exports = {
27
- parseForESLint(code) {
28
- const comments = [];
29
- const types = new Set(['Program']);
30
- const ast = {};
31
- ast.body = [];
32
- ast.tokens = [ast];
33
- ast.range = [0, code.length];
34
- const lines = code.split('\n');
35
- ast.loc = {
36
- start: {
37
- line: 1,
38
- column: 1
39
- },
40
- end: {
41
- line: lines.length,
42
- column: lines[lines.length - 1].length
43
- }
44
- };
45
- ast.comments = comments;
46
- const visitorKeys = {};
47
- types.forEach((t) => {
48
- visitorKeys[t] = [];
49
- });
50
- ast.type = 'Program';
51
- ast.isHbs = true;
52
- ast.contents = code;
53
- const scope = new ScopeManager();
54
- scope.globalScope.block = ast;
55
- return { ast, scopeManager: scope, visitorKeys };
56
- }
57
- };
package/lib/processor.js DELETED
@@ -1,11 +0,0 @@
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
- };
@@ -1,100 +0,0 @@
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;