@angular-eslint/eslint-plugin-template 22.3.1-alpha.2 → 22.3.1-alpha.4
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/dist/rules/no-inline-styles.d.ts.map +1 -1
- package/dist/rules/no-inline-styles.js +23 -48
- package/dist/rules/prefer-self-closing-tags.d.ts.map +1 -1
- package/dist/rules/prefer-self-closing-tags.js +16 -4
- package/dist/utils/literal-primitive.d.ts.map +1 -1
- package/dist/utils/literal-primitive.js +6 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-inline-styles.d.ts","sourceRoot":"","sources":["../../src/rules/no-inline-styles.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,OAAO,GAAG;IACpB;QACE,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;QAChC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;KACrC;CACF,CAAC;AAKF,MAAM,MAAM,UAAU,GAAG,gBAAgB,CAAC;AAC1C,eAAO,MAAM,SAAS,qBAAqB,CAAC;;;;
|
|
1
|
+
{"version":3,"file":"no-inline-styles.d.ts","sourceRoot":"","sources":["../../src/rules/no-inline-styles.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,OAAO,GAAG;IACpB;QACE,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;QAChC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;KACrC;CACF,CAAC;AAKF,MAAM,MAAM,UAAU,GAAG,gBAAgB,CAAC;AAC1C,eAAO,MAAM,SAAS,qBAAqB,CAAC;;;;AAM5C,wBA4EG;AAEH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RULE_DOCS_EXTENSION = exports.RULE_NAME = void 0;
|
|
4
|
+
const bundled_angular_compiler_1 = require("@angular-eslint/bundled-angular-compiler");
|
|
4
5
|
const utils_1 = require("@angular-eslint/utils");
|
|
5
6
|
const create_eslint_rule_1 = require("../utils/create-eslint-rule");
|
|
6
7
|
const DEFAULT_OPTIONS = {
|
|
@@ -40,22 +41,27 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
|
|
|
40
41
|
const parserServices = (0, utils_1.getTemplateParserServices)(context);
|
|
41
42
|
return {
|
|
42
43
|
Element(node) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
44
|
+
const hasDisallowedInput = node.inputs.some((input) => {
|
|
45
|
+
const { __originalType: originalType, type } = input;
|
|
46
|
+
switch (originalType ?? type) {
|
|
47
|
+
case bundled_angular_compiler_1.BindingType.Attribute:
|
|
48
|
+
return input.name === 'style';
|
|
49
|
+
case bundled_angular_compiler_1.BindingType.Style:
|
|
50
|
+
return !allowBindToStyle;
|
|
51
|
+
case bundled_angular_compiler_1.BindingType.Property:
|
|
52
|
+
if (input.name === 'style') {
|
|
53
|
+
return !allowBindToStyle;
|
|
54
|
+
}
|
|
55
|
+
if (input.name === 'ngStyle') {
|
|
56
|
+
return !allowNgStyle;
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
default:
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
const isInvalid = node.attributes.some(({ name }) => name === 'style') ||
|
|
64
|
+
hasDisallowedInput;
|
|
59
65
|
if (isInvalid) {
|
|
60
66
|
const loc = parserServices.convertElementSourceSpanToLoc(context, node);
|
|
61
67
|
context.report({
|
|
@@ -70,37 +76,6 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
|
|
|
70
76
|
};
|
|
71
77
|
},
|
|
72
78
|
});
|
|
73
|
-
/**
|
|
74
|
-
* Check that an element (for example `<img>`) has a `style` attribute or `attr.style` binding.
|
|
75
|
-
*/
|
|
76
|
-
function isNodeHasStyleAttribute(node) {
|
|
77
|
-
return (node.attributes.some(({ name }) => isStyle(name)) ||
|
|
78
|
-
node.inputs.some(({ name }) => isStyle(name)));
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Check that an element (for example `<img>`) has a `ngStyle` attribute binding.
|
|
82
|
-
*/
|
|
83
|
-
function isNodeHasNgStyleAttribute(node) {
|
|
84
|
-
return node.inputs.some(({ name }) => isNgStyle(name));
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Check that an element (for example `<img>`) has a `[style.background-color]` attribute binding.
|
|
88
|
-
*/
|
|
89
|
-
function isNodeHasBindingToStyleAttribute(node) {
|
|
90
|
-
return node.inputs.some(({ keySpan }) => isStyleBound(keySpan));
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Check element is style
|
|
94
|
-
*/
|
|
95
|
-
function isStyle(name) {
|
|
96
|
-
return name === 'style';
|
|
97
|
-
}
|
|
98
|
-
function isNgStyle(name) {
|
|
99
|
-
return name === 'ngStyle';
|
|
100
|
-
}
|
|
101
|
-
function isStyleBound(keySpan) {
|
|
102
|
-
return keySpan?.details ? keySpan.details.includes('style.') : false;
|
|
103
|
-
}
|
|
104
79
|
exports.RULE_DOCS_EXTENSION = {
|
|
105
|
-
rationale: 'Inline styles in templates (style attribute, ngStyle directive, or [style.property] bindings) make it difficult to maintain consistent styling across an application and can violate Content Security Policy (CSP) restrictions. Styles should be defined in component stylesheets or CSS classes where they can be managed centrally, reused, cached by browsers, and easily modified. Inline styles also mix presentation concerns with template structure, making templates harder to read. Using CSS classes with [class] or [ngClass] bindings provides the same dynamic styling capabilities while keeping styles organized and maintainable. This rule can be configured to allow ngStyle or style bindings if needed for specific use cases.',
|
|
80
|
+
rationale: 'Inline styles in templates (style attribute, ngStyle directive, [style] bindings, or [style.property] bindings) make it difficult to maintain consistent styling across an application and can violate Content Security Policy (CSP) restrictions. Styles should be defined in component stylesheets or CSS classes where they can be managed centrally, reused, cached by browsers, and easily modified. Inline styles also mix presentation concerns with template structure, making templates harder to read. Using CSS classes with [class] or [ngClass] bindings provides the same dynamic styling capabilities while keeping styles organized and maintainable. This rule can be configured to allow ngStyle or style bindings if needed for specific use cases.',
|
|
106
81
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prefer-self-closing-tags.d.ts","sourceRoot":"","sources":["../../src/rules/prefer-self-closing-tags.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAAG,uBAAuB,CAAC;AACjD,eAAO,MAAM,SAAS,6BAA6B,CAAC;;;;AAEpD,
|
|
1
|
+
{"version":3,"file":"prefer-self-closing-tags.d.ts","sourceRoot":"","sources":["../../src/rules/prefer-self-closing-tags.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAAG,uBAAuB,CAAC;AACjD,eAAO,MAAM,SAAS,6BAA6B,CAAC;;;;AAEpD,wBAiKG;AAoDH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
|
|
@@ -22,9 +22,11 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
|
|
|
22
22
|
},
|
|
23
23
|
create(context) {
|
|
24
24
|
const parserServices = (0, utils_1.getTemplateParserServices)(context);
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
// An index.html file is served to the browser as-is rather than being
|
|
26
|
+
// compiled as an Angular template, and browsers do not support
|
|
27
|
+
// self-closing tags for custom elements, so skip the rule for any
|
|
28
|
+
// file with that name regardless of where it lives.
|
|
29
|
+
if (/(^|[\\/])index\.html$/.test(context.physicalFilename)) {
|
|
28
30
|
return {};
|
|
29
31
|
}
|
|
30
32
|
return {
|
|
@@ -34,7 +36,7 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
|
|
|
34
36
|
}
|
|
35
37
|
else {
|
|
36
38
|
// Ignore native elements.
|
|
37
|
-
if ('name' in node && (
|
|
39
|
+
if ('name' in node && isNativeElement(node.name)) {
|
|
38
40
|
return;
|
|
39
41
|
}
|
|
40
42
|
processElementOrTemplateNode(node);
|
|
@@ -135,6 +137,16 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
|
|
|
135
137
|
}
|
|
136
138
|
},
|
|
137
139
|
});
|
|
140
|
+
function isNativeElement(name) {
|
|
141
|
+
const lowerCaseName = name.toLowerCase();
|
|
142
|
+
// The Angular compiler namespaces the children of `<svg>` and `<math>`
|
|
143
|
+
// (e.g. `:svg:use` and `:math:mi`). These are foreign elements that are
|
|
144
|
+
// native to the browser, and self-closing some of them (such as `<title />`)
|
|
145
|
+
// produces a template that Angular cannot parse.
|
|
146
|
+
return (lowerCaseName.startsWith(':svg:') ||
|
|
147
|
+
lowerCaseName.startsWith(':math:') ||
|
|
148
|
+
(0, get_dom_elements_1.getDomElements)().has(lowerCaseName));
|
|
149
|
+
}
|
|
138
150
|
function isContentNode(node) {
|
|
139
151
|
return 'name' in node && node.name.toLowerCase() === 'ng-content';
|
|
140
152
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"literal-primitive.d.ts","sourceRoot":"","sources":["../../src/utils/literal-primitive.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,GAAG,EACH,gBAAgB,EACjB,MAAM,0CAA0C,CAAC;AAElD,MAAM,MAAM,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEpC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,IAAI,gBAAgB,
|
|
1
|
+
{"version":3,"file":"literal-primitive.d.ts","sourceRoot":"","sources":["../../src/utils/literal-primitive.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,GAAG,EACH,gBAAgB,EACjB,MAAM,0CAA0C,CAAC;AAElD,MAAM,MAAM,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEpC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,IAAI,gBAAgB,CAStE;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,GAAG,GACR,IAAI,IAAI,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAE7D;AAED,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,gBAAgB,EACtB,KAAK,EAAE,KAAK,GACX,MAAM,CAIR"}
|
|
@@ -5,7 +5,12 @@ exports.isStringLiteralPrimitive = isStringLiteralPrimitive;
|
|
|
5
5
|
exports.getLiteralPrimitiveStringValue = getLiteralPrimitiveStringValue;
|
|
6
6
|
const bundled_angular_compiler_1 = require("@angular-eslint/bundled-angular-compiler");
|
|
7
7
|
function isLiteralPrimitive(node) {
|
|
8
|
-
|
|
8
|
+
// The template parser stamps `type` from `constructor.name`. `instanceof`
|
|
9
|
+
// fails when more than one copy of `@angular-eslint/bundled-angular-compiler`
|
|
10
|
+
// is installed (version mismatches, Yarn `hoistingLimits`, etc.).
|
|
11
|
+
return (!!node &&
|
|
12
|
+
(node.type === 'LiteralPrimitive' ||
|
|
13
|
+
node instanceof bundled_angular_compiler_1.LiteralPrimitive));
|
|
9
14
|
}
|
|
10
15
|
function isStringLiteralPrimitive(node) {
|
|
11
16
|
return isLiteralPrimitive(node) && typeof node.value === 'string';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular-eslint/eslint-plugin-template",
|
|
3
|
-
"version": "22.3.1-alpha.
|
|
3
|
+
"version": "22.3.1-alpha.4",
|
|
4
4
|
"description": "ESLint plugin for Angular Templates",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -19,17 +19,17 @@
|
|
|
19
19
|
"LICENSE"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@angular-eslint/bundled-angular-compiler": "22.3.1-alpha.
|
|
23
|
-
"@angular-eslint/utils": "22.3.1-alpha.
|
|
22
|
+
"@angular-eslint/bundled-angular-compiler": "22.3.1-alpha.4",
|
|
23
|
+
"@angular-eslint/utils": "22.3.1-alpha.4",
|
|
24
24
|
"aria-query": "5.3.2",
|
|
25
25
|
"axobject-query": "4.1.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@angular-eslint/test-utils": "22.3.1-alpha.
|
|
28
|
+
"@angular-eslint/test-utils": "22.3.1-alpha.4",
|
|
29
29
|
"@types/aria-query": "5.0.4"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@angular-eslint/template-parser": "22.3.1-alpha.
|
|
32
|
+
"@angular-eslint/template-parser": "22.3.1-alpha.4",
|
|
33
33
|
"@typescript-eslint/types": "^8.0.0",
|
|
34
34
|
"@typescript-eslint/utils": "^8.0.0",
|
|
35
35
|
"eslint": "^9.0.0 || ^10.0.0",
|