eslint-plugin-ember-template-lint 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
package/LICENSE.md ADDED
@@ -0,0 +1,15 @@
1
+ ISC License (ISC)
2
+
3
+ Copyright 2017, Patrick Pircher
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
11
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # eslint-plugin-hbs-template
2
+
3
+ Provide linting for hbs templates files
4
+
5
+ ## Installation
6
+
7
+ You'll first need to install [ESLint](http://eslint.org):
8
+
9
+ ```
10
+ $ npm i eslint --save-dev
11
+ ```
12
+
13
+ Next, install `eslint-plugin-ember-template-lint`:
14
+
15
+ ```
16
+ $ npm install eslint-plugin-ember-template-lint --save-dev
17
+ ```
18
+
19
+ **Note:** If you installed ESLint globally (using the `-g` flag) then you must also install `eslint-plugin-ember-template-lint` globally.
20
+
21
+ ## Usage
22
+
23
+ Add `hbs` to the plugins section of your `.eslintrc` configuration file. You can omit the `eslint-plugin-` prefix:
24
+
25
+ ### 2. Modify your `.eslintrc.js`
26
+
27
+ ```js
28
+ // .eslintrc.js
29
+ // optional:
30
+ require('eslint-plugin-ember-template-lint/lib/ember-teplate-lint/config').registerPlugin('ember-template-lint-plugin-prettier');
31
+
32
+ module.exports = {
33
+ extends: [
34
+ 'eslint:recommended',
35
+ 'plugin:ember-template-lint/recommended',
36
+ //optional:
37
+ 'plugin:ember-template-lint/ember-template-lint-plugin-prettier:recommended'
38
+ ]
39
+ };
40
+ ```
41
+
42
+
43
+
44
+
package/lib/index.js ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @fileoverview Provide linting for hbs template literals inside of JavaScript
3
+ * @author Peter Banka
4
+ */
5
+ 'use strict';
6
+
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const configs = require('./config');
12
+ const base = require('./config/base');
13
+ const templateRules = require('./ember-teplate-lint/info');
14
+ const processor = require('./processor');
15
+
16
+ //------------------------------------------------------------------------------
17
+ // Plugin Definition
18
+ //------------------------------------------------------------------------------
19
+
20
+
21
+ module.exports = {
22
+ rules: {
23
+ ...templateRules.rules
24
+ },
25
+ configs: {
26
+ base,
27
+ ...configs
28
+ },
29
+ processors: {
30
+ 'noop': processor,
31
+ }
32
+ };
@@ -0,0 +1,86 @@
1
+ 'use strict';
2
+ const synckit = require('synckit');
3
+ const DocumentLines = require('../utils/document');
4
+
5
+ //------------------------------------------------------------------------------
6
+ // Rule Definition
7
+ //------------------------------------------------------------------------------
8
+
9
+ const runTemplateLint = (text, filename, context, scopeVars=[], offset=0, options) => {
10
+ try {
11
+ const syncFn = synckit.createSyncFn(require.resolve('./hbs-worker'));
12
+ const response = syncFn(filename, text, options);
13
+ const lintMessages = response.messages;
14
+ const diffs = response.diff;
15
+ const document = new DocumentLines(text);
16
+ diffs.forEach((d) => {
17
+ d.range = [d.offset, d.offset + d.deleteText.length];
18
+ });
19
+ lintMessages.forEach((m) => {
20
+ m.range = [
21
+ document.positionToOffset({
22
+ line: m.line - 1,
23
+ character: m.column - 1
24
+ }),
25
+ document.positionToOffset({
26
+ line: m.endLine - 1,
27
+ character: m.endColumn - 1
28
+ })];
29
+ const isInside = (d) => d.range[0] >= m.range[0] && d.range[1] <= m.range[1];
30
+ const doesContain = (d) => d.range[0] < m.range[0] && d.range[1] > m.range[1];
31
+ const idx = diffs.findIndex(d => isInside(d) || doesContain(d));
32
+ if (idx !== -1) {
33
+ const d = diffs.splice(idx, 1);
34
+ m.fix = d[0];
35
+ m.fix.range = m.fix.range.map(x => offset + x);
36
+ }
37
+ m.range = m.range.map(x => offset + x);
38
+ });
39
+
40
+ if (diffs.length) {
41
+ diffs.forEach((d) => {
42
+ const range = d.range[0];
43
+ const [start, end] = range.map(index =>
44
+ context.getSourceCode().getLocFromIndex(index)
45
+ );
46
+ context.report({
47
+ fix: (fixer) => {
48
+ return fixer.replaceTextRange(range, d.fix.insertText || '');
49
+ },
50
+ loc: { start, end },
51
+ message: 'template error',
52
+ });
53
+ });
54
+ }
55
+
56
+ lintMessages.forEach((msg) => {
57
+ if (msg.rule === 'no-implicit-this') {
58
+ if (scopeVars.includes(msg.source)) {
59
+ return;
60
+ }
61
+ }
62
+ const [start, end] = msg.range.map(index =>
63
+ context.getSourceCode().getLocFromIndex(index)
64
+ );
65
+
66
+ context.report({
67
+ rule: msg.rule,
68
+ fix: (fixer) => {
69
+ if (!msg.isFixable || !msg.fix) {
70
+ return null;
71
+ }
72
+ const range = msg.range;
73
+ return fixer.replaceTextRange(range, msg.fix.insertText || '');
74
+ },
75
+ loc: { start, end },
76
+ message: msg.message,
77
+ });
78
+ });
79
+ } catch(e) {
80
+ console.error(e);
81
+ }
82
+ };
83
+
84
+ module.exports = {
85
+ runTemplateLint
86
+ };
@@ -0,0 +1,21 @@
1
+ const { runAsWorker } = require('synckit');
2
+ const { generateDifferences } = require('prettier-linter-helpers');
3
+
4
+ runAsWorker(async (filename, text, options) => {
5
+ const Lint = await import('ember-template-lint');
6
+ const lint = new Lint.default(options);
7
+ process.env.emberTemplateLintFileName = filename;
8
+ process.env.emberTemplateLintFixMode = false;
9
+ const messages = await lint.verify({
10
+ source: text
11
+ });
12
+ process.env.emberTemplateLintFixMode = true;
13
+ const fixedText = (await lint.verifyAndFix({
14
+ source: text
15
+ })).output;
16
+ const diff = generateDifferences(text, fixedText);
17
+ return {
18
+ messages,
19
+ diff
20
+ };
21
+ });
@@ -0,0 +1,83 @@
1
+ 'use strict';
2
+ const synckit = require('synckit');
3
+ const DocumentLines = require('../utils/document');
4
+ const { templateLintConfig } = require('../ember-teplate-lint/config');
5
+
6
+ function runTemplateLint(text, filename, context, scopeVars=[], offset=0) {
7
+ try {
8
+ const syncFn = synckit.createSyncFn(require.resolve('./hbs-worker'));
9
+ const response = syncFn(filename, text, { config: templateLintConfig });
10
+ const lintMessages = response.messages;
11
+ const diffs = response.diff;
12
+ const document = new DocumentLines(text);
13
+ diffs.forEach((d) => {
14
+ d.range = [d.offset, d.offset + d.deleteText.length];
15
+ });
16
+ lintMessages.forEach((m) => {
17
+ m.range = [
18
+ document.positionToOffset({
19
+ line: m.line - 1,
20
+ character: m.column - 1
21
+ }),
22
+ document.positionToOffset({
23
+ line: m.endLine - 1,
24
+ character: m.endColumn - 1
25
+ })];
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
+ m.range = m.range.map(x => offset + x);
35
+ });
36
+
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
+ lintMessages.forEach((msg) => {
54
+ if (msg.rule === 'no-implicit-this') {
55
+ if (scopeVars.includes(msg.source)) {
56
+ return;
57
+ }
58
+ }
59
+ const [start, end] = msg.range.map(index =>
60
+ context.getSourceCode().getLocFromIndex(index)
61
+ );
62
+
63
+ context.report({
64
+ rule: msg.rule,
65
+ fix: (fixer) => {
66
+ if (!msg.isFixable || !msg.fix) {
67
+ return null;
68
+ }
69
+ const range = msg.range;
70
+ return fixer.replaceTextRange(range, msg.fix.insertText || '');
71
+ },
72
+ loc: { start, end },
73
+ message: msg.message,
74
+ });
75
+ });
76
+ } catch(e) {
77
+ console.error(e);
78
+ }
79
+ }
80
+
81
+ module.exports = {
82
+ runTemplateLint
83
+ };
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "eslint-plugin-ember-template-lint",
3
+ "version": "0.1.0",
4
+ "description": "Provide linting for ember template",
5
+ "keywords": [
6
+ "eslint",
7
+ "eslintplugin",
8
+ "eslint-plugin"
9
+ ],
10
+ "author": "Patrick Pircher",
11
+ "main": "lib/index.js",
12
+ "repository": "patricklx/eslint-plugin-ember-template-lint",
13
+ "scripts": {
14
+ "test": "jest",
15
+ "lint:js": "eslint --cache .",
16
+ "test:watch": "jest --watchAll"
17
+ },
18
+ "dependencies": {
19
+ "@glimmer/syntax": "^0.84.3",
20
+ "typescript": "^5.0.4",
21
+ "@typescript-eslint/parser": "^5.59.7",
22
+ "@typescript-eslint/typescript-estree": "^5.59.7",
23
+ "ember-template-imports": "^3.4.2",
24
+ "prettier-linter-helpers": "^1.0.0",
25
+ "ember-template-lint": "^5.7.3",
26
+ "synckit": "^0.8.5"
27
+ },
28
+ "peerDependencies": {
29
+ "ember-template-lint": "^5.7.3"
30
+ },
31
+ "devDependencies": {
32
+ "ember-template-lint-plugin-prettier": "^4.1.0",
33
+ "eslint": "^8.41.0",
34
+ "eslint-plugin-jest": "^27.2.1",
35
+ "eslint-plugin-node": "^11.1.0",
36
+ "jest": "^29.5.0"
37
+ },
38
+ "jest": {
39
+ "testMatch": [
40
+ "**/tests/**/*.js"
41
+ ]
42
+ },
43
+ "engines": {
44
+ "node": ">=12.0.0"
45
+ },
46
+ "license": "ISC",
47
+ "files": [
48
+ "lib/rules/*.js"
49
+ ]
50
+ }