eslint-plugin-ember-template-lint 0.1.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/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
|
+
}
|