eslint-plugin-ember-template-lint 0.18.0 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: 'ember-eslint-parser',
17
+ processor: 'ember-template-lint/noop'
18
+ },
19
+ ],
20
+ };
@@ -0,0 +1,20 @@
1
+ const info = require('../ember-template-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] = 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
+ };
@@ -0,0 +1,109 @@
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-template-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
+ 'GlimmerTemplate': visitor.enter,
62
+ 'GlimmerTemplate: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
+ if (conf.severity) {
97
+ configuredRules['ember-template-lint/' + name] = configuredRules['ember-template-lint/' + name] || [];
98
+ configuredRules['ember-template-lint/' + name].push(conf.severity);
99
+ if (typeof conf.config !== 'boolean') {
100
+ configuredRules['ember-template-lint/' + name].push(conf.config);
101
+ }
102
+ }
103
+ });
104
+
105
+ module.exports = {
106
+ configs: configs,
107
+ rules: createRules(rules),
108
+ configuredRules: configuredRules
109
+ };
@@ -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,57 @@
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
+ };
@@ -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
+ };
@@ -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.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "Provide linting for ember template",
5
5
  "keywords": [
6
6
  "eslint",
@@ -46,6 +46,6 @@
46
46
  },
47
47
  "license": "ISC",
48
48
  "files": [
49
- "lib/rules/*.js"
49
+ "lib/**/*.js"
50
50
  ]
51
51
  }