@angular-eslint/eslint-plugin-template 22.6.1-alpha.2 → 22.6.1-alpha.3
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/README.md +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -4
- package/dist/inline-styles.d.ts +15 -0
- package/dist/inline-styles.d.ts.map +1 -0
- package/dist/inline-styles.js +335 -0
- package/dist/inline-templates.d.ts +40 -0
- package/dist/inline-templates.d.ts.map +1 -0
- package/dist/inline-templates.js +245 -0
- package/dist/processors.d.ts +19 -31
- package/dist/processors.d.ts.map +1 -1
- package/dist/processors.js +40 -258
- package/dist/rules/eqeqeq.d.ts.map +1 -1
- package/dist/rules/eqeqeq.js +7 -5
- package/dist/rules/i18n.js +1 -1
- package/dist/rules/no-distracting-elements.js +1 -1
- package/dist/rules/no-interpolation-in-attributes.d.ts.map +1 -1
- package/dist/rules/no-interpolation-in-attributes.js +1 -1
- package/dist/rules/prefer-at-else.d.ts.map +1 -1
- package/dist/rules/prefer-at-else.js +11 -1
- package/dist/rules/prefer-style-binding.d.ts +7 -2
- package/dist/rules/prefer-style-binding.d.ts.map +1 -1
- package/dist/rules/prefer-style-binding.js +196 -4
- package/dist/rules/prefer-template-literal.d.ts.map +1 -1
- package/dist/rules/prefer-template-literal.js +11 -2
- package/dist/rules/valid-aria.d.ts +1 -1
- package/dist/rules/valid-aria.d.ts.map +1 -1
- package/dist/rules/valid-aria.js +56 -17
- package/dist/utils/literal-primitive.d.ts +3 -1
- package/dist/utils/literal-primitive.d.ts.map +1 -1
- package/dist/utils/literal-primitive.js +12 -0
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -72,7 +72,7 @@ The premade flat configs that combine these rules are provided by the umbrella [
|
|
|
72
72
|
| [`prefer-contextual-for-variables`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/prefer-contextual-for-variables.md) | Ensures that contextual variables are used in @for blocks where possible instead of aliasing them. | | :wrench: | | |
|
|
73
73
|
| [`prefer-control-flow`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/prefer-control-flow.md) | Ensures that the built-in control flow is used. | :white_check_mark: | | | |
|
|
74
74
|
| [`prefer-ngsrc`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/prefer-ngsrc.md) | Ensures ngSrc is used instead of src for img elements | | | :bulb: | |
|
|
75
|
-
| [`prefer-style-binding`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/prefer-style-binding.md) | Suggests using [style] bindings over ngStyle where applicable | |
|
|
75
|
+
| [`prefer-style-binding`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/prefer-style-binding.md) | Suggests using [style] bindings over ngStyle where applicable | | :wrench: | :bulb: | |
|
|
76
76
|
| [`prefer-template-literal`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/prefer-template-literal.md) | Ensure that template literals are used instead of concatenating strings or expressions. | | :wrench: | | |
|
|
77
77
|
| [`require-switch-default`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/require-switch-default.md) | Requires a `@default` block on every `@switch` to ensure all cases are handled. This is the template equivalent of the `@typescript-eslint/switch-exhaustiveness-check` rule. | | | | |
|
|
78
78
|
| [`role-has-required-aria`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/role-has-required-aria.md) | [Accessibility] Ensures elements with ARIA roles have all required properties for that role. | | | :bulb: | :accessibility: |
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { createProcessor } from './processors';
|
|
1
2
|
declare const _default: {
|
|
3
|
+
createProcessor: typeof createProcessor;
|
|
2
4
|
processors: {
|
|
3
5
|
'extract-inline-html': {
|
|
4
6
|
meta: {
|
|
5
7
|
name: string;
|
|
6
8
|
};
|
|
7
|
-
preprocess: typeof import("./
|
|
8
|
-
postprocess: typeof import("./
|
|
9
|
-
supportsAutofix:
|
|
9
|
+
preprocess: typeof import("./inline-templates").preprocessComponentFile;
|
|
10
|
+
postprocess: typeof import("./inline-templates").postprocessComponentFile;
|
|
11
|
+
supportsAutofix: true;
|
|
10
12
|
};
|
|
11
13
|
};
|
|
12
14
|
rules: {
|
|
@@ -115,7 +117,7 @@ declare const _default: {
|
|
|
115
117
|
"prefer-static-string-properties": import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferStaticStringProperties", import("./rules/prefer-static-string-properties").Options, import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
116
118
|
name: string;
|
|
117
119
|
};
|
|
118
|
-
"prefer-style-binding": import("@typescript-eslint/utils/ts-eslint").RuleModule<"
|
|
120
|
+
"prefer-style-binding": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/prefer-style-binding").MessageIds, import("./rules/prefer-style-binding").Options, import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
119
121
|
name: string;
|
|
120
122
|
};
|
|
121
123
|
"prefer-template-literal": import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferTemplateLiteral", [], import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsH3D,kBA+CE"}
|
package/dist/index.js
CHANGED
|
@@ -32,10 +32,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
-
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
const processors_1 = __importDefault(require("./processors"));
|
|
35
|
+
const processors_1 = __importStar(require("./processors"));
|
|
39
36
|
const alt_text_1 = __importStar(require("./rules/alt-text"));
|
|
40
37
|
const attributes_order_1 = __importStar(require("./rules/attributes-order"));
|
|
41
38
|
const banana_in_box_1 = __importStar(require("./rules/banana-in-box"));
|
|
@@ -79,6 +76,7 @@ const table_scope_1 = __importStar(require("./rules/table-scope"));
|
|
|
79
76
|
const use_track_by_function_1 = __importStar(require("./rules/use-track-by-function"));
|
|
80
77
|
const valid_aria_1 = __importStar(require("./rules/valid-aria"));
|
|
81
78
|
module.exports = {
|
|
79
|
+
createProcessor: processors_1.createProcessor,
|
|
82
80
|
processors: processors_1.default,
|
|
83
81
|
rules: {
|
|
84
82
|
[alt_text_1.RULE_NAME]: alt_text_1.default,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { postprocessComponentFile, type PreprocessResult } from './inline-templates';
|
|
2
|
+
export declare const inlineStyleLanguages: readonly ["css", "scss", "sass", "less"];
|
|
3
|
+
export type InlineStyleLanguage = (typeof inlineStyleLanguages)[number];
|
|
4
|
+
declare function postprocessInlineStyles(multiDimensionalMessages: Parameters<typeof postprocessComponentFile>[0], filename: string): readonly unknown[];
|
|
5
|
+
export interface InlineStylesProcessor {
|
|
6
|
+
meta: {
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
preprocess: (text: string, filename: string) => PreprocessResult;
|
|
10
|
+
postprocess: typeof postprocessInlineStyles;
|
|
11
|
+
supportsAutofix: true;
|
|
12
|
+
}
|
|
13
|
+
export declare function createInlineStylesProcessor(inlineStyleLanguage: InlineStyleLanguage, inlineTemplates: boolean): InlineStylesProcessor;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=inline-styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inline-styles.d.ts","sourceRoot":"","sources":["../src/inline-styles.ts"],"names":[],"mappings":"AASA,OAAO,EAIL,wBAAwB,EACxB,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAC;AAoU5B,eAAO,MAAM,oBAAoB,0CAA2C,CAAC;AAE7E,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AA8ExE,iBAAS,uBAAuB,CAC9B,wBAAwB,EAAE,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC,CAAC,CAAC,EACxE,QAAQ,EAAE,MAAM,GACf,SAAS,OAAO,EAAE,CAkCpB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,gBAAgB,CAAC;IACjE,WAAW,EAAE,OAAO,uBAAuB,CAAC;IAC5C,eAAe,EAAE,IAAI,CAAC;CACvB;AAED,wBAAgB,2BAA2B,CACzC,mBAAmB,EAAE,mBAAmB,EACxC,eAAe,EAAE,OAAO,GACvB,qBAAqB,CAevB"}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.inlineStyleLanguages = void 0;
|
|
7
|
+
exports.createInlineStylesProcessor = createInlineStylesProcessor;
|
|
8
|
+
const path_1 = require("path");
|
|
9
|
+
const bundled_angular_compiler_1 = require("@angular-eslint/bundled-angular-compiler");
|
|
10
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
11
|
+
const inline_templates_1 = require("./inline-templates");
|
|
12
|
+
function createTextSource(text) {
|
|
13
|
+
const lineStarts = [0];
|
|
14
|
+
for (let index = 0; index < text.length; index++) {
|
|
15
|
+
const character = text.charCodeAt(index);
|
|
16
|
+
if (character === 13 && text.charCodeAt(index + 1) === 10) {
|
|
17
|
+
index++;
|
|
18
|
+
}
|
|
19
|
+
if (character === 10 ||
|
|
20
|
+
character === 13 ||
|
|
21
|
+
character === 0x2028 ||
|
|
22
|
+
character === 0x2029) {
|
|
23
|
+
lineStarts.push(index + 1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
text,
|
|
28
|
+
offsetAt(line, column) {
|
|
29
|
+
const start = lineStarts[line - 1];
|
|
30
|
+
if (start === undefined || column < 1 || !Number.isInteger(column)) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
const offset = start + column - 1;
|
|
34
|
+
const nextStart = lineStarts[line];
|
|
35
|
+
if (nextStart !== undefined ? offset >= nextStart : offset > text.length) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
return offset;
|
|
39
|
+
},
|
|
40
|
+
locationAt(offset) {
|
|
41
|
+
let start = 0;
|
|
42
|
+
let end = lineStarts.length;
|
|
43
|
+
while (start + 1 < end) {
|
|
44
|
+
const middle = Math.floor((start + end) / 2);
|
|
45
|
+
if (lineStarts[middle] > offset) {
|
|
46
|
+
end = middle;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
start = middle;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { line: start + 1, column: offset - lineStarts[start] + 1 };
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const unsafeLiteralFixText = {
|
|
57
|
+
"'": /[\\'\r\n]/,
|
|
58
|
+
'"': /[\\"\r\n]/,
|
|
59
|
+
'`': /[\\`]|\$\{/,
|
|
60
|
+
};
|
|
61
|
+
function mapLiteral(literal, sourceFile, source) {
|
|
62
|
+
const start = literal.getStart(sourceFile);
|
|
63
|
+
const quote = sourceFile.text[start];
|
|
64
|
+
const raw = sourceFile.text.slice(start + 1, literal.end - 1);
|
|
65
|
+
const offsets = [start + 1];
|
|
66
|
+
const scanner = typescript_1.default.createScanner(typescript_1.default.ScriptTarget.Latest, false);
|
|
67
|
+
let text = '';
|
|
68
|
+
for (let index = 0; index < raw.length;) {
|
|
69
|
+
const escape = raw[index] === '\\'
|
|
70
|
+
? /^\\(?:u\{[\da-fA-F]+\}|u[\da-fA-F]{4}|x[\da-fA-F]{2}|\r\n|[\s\S])/.exec(raw.slice(index))?.[0]
|
|
71
|
+
: undefined;
|
|
72
|
+
const chunk = escape ?? (raw.startsWith('\r\n', index) ? '\r\n' : raw[index]);
|
|
73
|
+
let decoded = chunk;
|
|
74
|
+
if (escape) {
|
|
75
|
+
scanner.setText(quote + chunk + quote);
|
|
76
|
+
scanner.scan();
|
|
77
|
+
decoded = scanner.getTokenValue();
|
|
78
|
+
}
|
|
79
|
+
else if (quote === '`' && chunk.startsWith('\r')) {
|
|
80
|
+
decoded = '\n';
|
|
81
|
+
}
|
|
82
|
+
index += chunk.length;
|
|
83
|
+
text += decoded;
|
|
84
|
+
for (let count = 0; count < decoded.length; count++) {
|
|
85
|
+
offsets.push(start + 1 + index);
|
|
86
|
+
}
|
|
87
|
+
if (!decoded.length) {
|
|
88
|
+
offsets[offsets.length - 1] = start + 1 + index;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (text !== literal.text) {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
kind: 'component',
|
|
96
|
+
text,
|
|
97
|
+
offsets,
|
|
98
|
+
source,
|
|
99
|
+
virtualSource: createTextSource(text),
|
|
100
|
+
unsafeFixText: [unsafeLiteralFixText[quote]],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function extractTemplateStyles(template) {
|
|
104
|
+
const styles = [];
|
|
105
|
+
const parsed = new bundled_angular_compiler_1.HtmlParser().parse(template.text, 'template.html', {
|
|
106
|
+
tokenizeBlocks: true,
|
|
107
|
+
});
|
|
108
|
+
class StyleVisitor extends bundled_angular_compiler_1.RecursiveVisitor {
|
|
109
|
+
visitAttribute(attribute) {
|
|
110
|
+
if (attribute.name !== 'style' || !attribute.valueSpan) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const valueTokens = attribute.valueTokens ?? [];
|
|
114
|
+
// Interpolation tokens are [start, expression, end]; like [style] bindings they are not static CSS
|
|
115
|
+
if (valueTokens.some((token) => token.parts.length === 3)) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const offsets = [attribute.valueSpan.start.offset];
|
|
119
|
+
let value = '';
|
|
120
|
+
for (const token of valueTokens) {
|
|
121
|
+
const decoded = token.parts[0];
|
|
122
|
+
const start = token.sourceSpan.start.offset;
|
|
123
|
+
const end = token.sourceSpan.end.offset;
|
|
124
|
+
const raw = template.text.slice(start, end);
|
|
125
|
+
let rawIndex = 0;
|
|
126
|
+
for (let index = 0; index < decoded.length; index++) {
|
|
127
|
+
rawIndex +=
|
|
128
|
+
raw.startsWith('\r\n', rawIndex) && decoded[index] === '\n' ? 2 : 1;
|
|
129
|
+
offsets.push(token.parts.length > 1 ? end : start + rawIndex);
|
|
130
|
+
}
|
|
131
|
+
value += decoded;
|
|
132
|
+
}
|
|
133
|
+
if (value !== attribute.value) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const start = offsets[0];
|
|
137
|
+
const end = offsets[offsets.length - 1];
|
|
138
|
+
const quote = template.text[start - 1];
|
|
139
|
+
const text = `a{${value}}`;
|
|
140
|
+
styles.push({
|
|
141
|
+
kind: 'attribute',
|
|
142
|
+
text,
|
|
143
|
+
offsets: [start, start, ...offsets, end].map((offset) => template.offsets[offset]),
|
|
144
|
+
source: template.source,
|
|
145
|
+
virtualSource: createTextSource(text),
|
|
146
|
+
unsafeFixText: [
|
|
147
|
+
...template.unsafeFixText,
|
|
148
|
+
quote === '"' || quote === "'"
|
|
149
|
+
? new RegExp(`[${quote}&]`)
|
|
150
|
+
: /[\s=<>"'`&]/,
|
|
151
|
+
],
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
(0, bundled_angular_compiler_1.visitAll)(new StyleVisitor(), parsed.rootNodes);
|
|
156
|
+
return styles;
|
|
157
|
+
}
|
|
158
|
+
function extractComponentStyles(sourceFile) {
|
|
159
|
+
const styles = [];
|
|
160
|
+
const source = createTextSource(sourceFile.text);
|
|
161
|
+
for (const metadata of (0, inline_templates_1.getComponentMetadata)(sourceFile)) {
|
|
162
|
+
for (const property of metadata.properties) {
|
|
163
|
+
if (!typescript_1.default.isPropertyAssignment(property)) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
const propertyName = property.name.getText(sourceFile);
|
|
167
|
+
if (propertyName !== 'styles' && propertyName !== 'template') {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const values = typescript_1.default.isArrayLiteralExpression(property.initializer)
|
|
171
|
+
? property.initializer.elements
|
|
172
|
+
: [property.initializer];
|
|
173
|
+
for (const value of values) {
|
|
174
|
+
if (!typescript_1.default.isStringLiteral(value) &&
|
|
175
|
+
!typescript_1.default.isNoSubstitutionTemplateLiteral(value)) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const mapped = mapLiteral(value, sourceFile, source);
|
|
179
|
+
if (!mapped) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (propertyName === 'template') {
|
|
183
|
+
styles.push(...extractTemplateStyles(mapped));
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
styles.push(mapped);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return styles;
|
|
192
|
+
}
|
|
193
|
+
function mapStyleMessage(message, style) {
|
|
194
|
+
function location(line, column, fallbackOffset) {
|
|
195
|
+
const offset = style.virtualSource.offsetAt(line, column);
|
|
196
|
+
const sourceOffset = (offset === undefined ? undefined : style.offsets[offset]) ??
|
|
197
|
+
fallbackOffset;
|
|
198
|
+
return style.source.locationAt(sourceOffset);
|
|
199
|
+
}
|
|
200
|
+
function fix(edit) {
|
|
201
|
+
const [startOffset, endOffset] = edit.range;
|
|
202
|
+
const start = style.offsets[startOffset];
|
|
203
|
+
const end = style.offsets[endOffset];
|
|
204
|
+
if (start === undefined || end === undefined) {
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
if (style.source.text.slice(start, end) !==
|
|
208
|
+
style.text.slice(startOffset, endOffset)) {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
if (style.unsafeFixText.some((pattern) => pattern.test(edit.text))) {
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
const boundaryText = style.source.text.slice(Math.max(0, start - 1), start) +
|
|
215
|
+
edit.text +
|
|
216
|
+
style.source.text.slice(end, end + 1);
|
|
217
|
+
if (boundaryText.includes('${') &&
|
|
218
|
+
style.unsafeFixText.some((pattern) => pattern.test('${'))) {
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
return { ...edit, range: [start, end] };
|
|
222
|
+
}
|
|
223
|
+
const mapped = { ...message };
|
|
224
|
+
if (message.line !== undefined && message.column !== undefined) {
|
|
225
|
+
Object.assign(mapped, location(message.line, message.column, style.offsets[0]));
|
|
226
|
+
}
|
|
227
|
+
if (message.endLine !== undefined && message.endColumn !== undefined) {
|
|
228
|
+
const end = location(message.endLine, message.endColumn, style.offsets[style.offsets.length - 1]);
|
|
229
|
+
mapped.endLine = end.line;
|
|
230
|
+
mapped.endColumn = end.column;
|
|
231
|
+
}
|
|
232
|
+
if (message.fix) {
|
|
233
|
+
mapped.fix = fix(message.fix);
|
|
234
|
+
}
|
|
235
|
+
if (message.suggestions) {
|
|
236
|
+
mapped.suggestions = message.suggestions.flatMap((suggestion) => {
|
|
237
|
+
const edit = suggestion.fix ? fix(suggestion.fix) : undefined;
|
|
238
|
+
return edit ? [{ ...suggestion, fix: edit }] : [];
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
return mapped;
|
|
242
|
+
}
|
|
243
|
+
const pendingStyles = new Map();
|
|
244
|
+
exports.inlineStyleLanguages = ['css', 'scss', 'sass', 'less'];
|
|
245
|
+
function preprocessInlineStyles(text, filename, inlineStyleLanguage, inlineTemplates) {
|
|
246
|
+
pendingStyles.delete(filename);
|
|
247
|
+
const baseFilename = (0, path_1.basename)(filename);
|
|
248
|
+
if (filename.endsWith('.html')) {
|
|
249
|
+
if (/inline-template-.+-\d+\.component\.html$/.test(baseFilename) ||
|
|
250
|
+
!/\bstyle\s*=/i.test(text)) {
|
|
251
|
+
return [text];
|
|
252
|
+
}
|
|
253
|
+
let styles;
|
|
254
|
+
try {
|
|
255
|
+
styles = extractTemplateStyles({
|
|
256
|
+
text,
|
|
257
|
+
source: createTextSource(text),
|
|
258
|
+
offsets: Array.from({ length: text.length + 1 }, (_, index) => index),
|
|
259
|
+
unsafeFixText: [],
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
return [text];
|
|
264
|
+
}
|
|
265
|
+
if (!styles.length) {
|
|
266
|
+
return [text];
|
|
267
|
+
}
|
|
268
|
+
pendingStyles.set(filename, { templateCount: 1, styles });
|
|
269
|
+
return [
|
|
270
|
+
text,
|
|
271
|
+
...styles.map((style, index) => ({
|
|
272
|
+
text: style.text,
|
|
273
|
+
filename: `attribute-style-${baseFilename}-${index + 1}.css`,
|
|
274
|
+
})),
|
|
275
|
+
];
|
|
276
|
+
}
|
|
277
|
+
if (!filename.endsWith('.ts') ||
|
|
278
|
+
!(0, inline_templates_1.isFileLikelyToContainComponentDeclarations)(text, filename)) {
|
|
279
|
+
return [text];
|
|
280
|
+
}
|
|
281
|
+
const sourceFile = typescript_1.default.createSourceFile(filename, text, typescript_1.default.ScriptTarget.Latest,
|
|
282
|
+
/* setParentNodes */ true);
|
|
283
|
+
const templates = inlineTemplates
|
|
284
|
+
? (0, inline_templates_1.preprocessComponentFile)(text, filename, sourceFile)
|
|
285
|
+
: [text];
|
|
286
|
+
let styles;
|
|
287
|
+
try {
|
|
288
|
+
styles = extractComponentStyles(sourceFile);
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
return templates;
|
|
292
|
+
}
|
|
293
|
+
pendingStyles.set(filename, { templateCount: templates.length, styles });
|
|
294
|
+
return [
|
|
295
|
+
...templates,
|
|
296
|
+
...styles.map((style, index) => ({
|
|
297
|
+
text: style.text,
|
|
298
|
+
filename: style.kind === 'attribute'
|
|
299
|
+
? `attribute-style-${baseFilename}-${index + 1}.css`
|
|
300
|
+
: `inline-style-${baseFilename}-${index + 1}.${inlineStyleLanguage}`,
|
|
301
|
+
})),
|
|
302
|
+
];
|
|
303
|
+
}
|
|
304
|
+
function postprocessInlineStyles(multiDimensionalMessages, filename) {
|
|
305
|
+
const pending = pendingStyles.get(filename);
|
|
306
|
+
pendingStyles.delete(filename);
|
|
307
|
+
if (!pending) {
|
|
308
|
+
return (0, inline_templates_1.postprocessComponentFile)(multiDimensionalMessages, filename);
|
|
309
|
+
}
|
|
310
|
+
const results = (0, inline_templates_1.postprocessComponentFile)(multiDimensionalMessages.slice(0, pending.templateCount), filename);
|
|
311
|
+
return [
|
|
312
|
+
...results,
|
|
313
|
+
...pending.styles.flatMap((style, index) => (multiDimensionalMessages[pending.templateCount + index] ?? [])
|
|
314
|
+
.filter((message) => {
|
|
315
|
+
if (style.kind !== 'attribute' ||
|
|
316
|
+
message.fatal === true) {
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
const offset = style.virtualSource.offsetAt(message.line, message.column);
|
|
320
|
+
return (offset === undefined ||
|
|
321
|
+
(offset >= 2 && offset !== style.text.length - 1));
|
|
322
|
+
})
|
|
323
|
+
.map((message) => mapStyleMessage(message, style))),
|
|
324
|
+
];
|
|
325
|
+
}
|
|
326
|
+
function createInlineStylesProcessor(inlineStyleLanguage, inlineTemplates) {
|
|
327
|
+
return {
|
|
328
|
+
meta: {
|
|
329
|
+
name: `extract-inline[${inlineTemplates ? 'templates,' : ''}styles=${inlineStyleLanguage}]`,
|
|
330
|
+
},
|
|
331
|
+
preprocess: (text, filename) => preprocessInlineStyles(text, filename, inlineStyleLanguage, inlineTemplates),
|
|
332
|
+
postprocess: postprocessInlineStyles,
|
|
333
|
+
supportsAutofix: true,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Because ultimately a user is in control of how and when this processor gets invoked,
|
|
4
|
+
* we can't fully protect them against doing more work than is necessary in all cases.
|
|
5
|
+
*
|
|
6
|
+
* Therefore, before we do a full parse of a TypeScript file to try and extract one or
|
|
7
|
+
* more Component declarations we want to do a really quick check for whether or not
|
|
8
|
+
* a file is likely to contain them.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isFileLikelyToContainComponentDeclarations(text: string, filename: string): boolean;
|
|
11
|
+
export type PreprocessResult = (string | {
|
|
12
|
+
text: string;
|
|
13
|
+
filename: string;
|
|
14
|
+
})[];
|
|
15
|
+
export declare function preprocessComponentFile(text: string, filename: string,
|
|
16
|
+
/** Lets callers that already parsed the file avoid a second full parse */
|
|
17
|
+
parsedSourceFile?: ts.SourceFile): PreprocessResult;
|
|
18
|
+
export declare function getComponentMetadata(sourceFile: ts.SourceFile): ts.ObjectLiteralExpression[];
|
|
19
|
+
export declare function postprocessComponentFile(multiDimensionalMessages: {
|
|
20
|
+
ruleId: string;
|
|
21
|
+
severity: number;
|
|
22
|
+
message: string;
|
|
23
|
+
line: number;
|
|
24
|
+
column: number;
|
|
25
|
+
nodeType: string;
|
|
26
|
+
messageId: string;
|
|
27
|
+
endLine: number;
|
|
28
|
+
endColumn: number;
|
|
29
|
+
fix?: {
|
|
30
|
+
range: number[];
|
|
31
|
+
text: string;
|
|
32
|
+
};
|
|
33
|
+
suggestions?: {
|
|
34
|
+
fix: {
|
|
35
|
+
range: number[];
|
|
36
|
+
text: string;
|
|
37
|
+
};
|
|
38
|
+
}[];
|
|
39
|
+
}[][], filename: string): readonly unknown[];
|
|
40
|
+
//# sourceMappingURL=inline-templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inline-templates.d.ts","sourceRoot":"","sources":["../src/inline-templates.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,YAAY,CAAC;AAI5B;;;;;;;GAOG;AACH,wBAAgB,0CAA0C,CACxD,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,OAAO,CA2BT;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,EAAE,CAAC;AAE/E,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM;AAChB,0EAA0E;AAC1E,gBAAgB,CAAC,EAAE,EAAE,CAAC,UAAU,GAC/B,gBAAgB,CAwGlB;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,EAAE,CAAC,UAAU,GACxB,EAAE,CAAC,uBAAuB,EAAE,CAiB9B;AAyDD,wBAAgB,wBAAwB,CACtC,wBAAwB,EAAE;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE;QACJ,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,WAAW,CAAC,EAAE;QACZ,GAAG,EAAE;YACH,KAAK,EAAE,MAAM,EAAE,CAAC;YAChB,IAAI,EAAE,MAAM,CAAC;SACd,CAAC;KACH,EAAE,CAAC;CACL,EAAE,EAAE,EACL,QAAQ,EAAE,MAAM,GACf,SAAS,OAAO,EAAE,CA6EpB"}
|