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 +15 -0
- package/README.md +44 -0
- package/lib/index.js +32 -0
- package/lib/rules/config.js +86 -0
- package/lib/rules/hbs-worker.js +21 -0
- package/lib/rules/lint.js +83 -0
- package/package.json +50 -0
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
|
+
}
|