@html-eslint/eslint-plugin 0.30.0 → 0.31.1-alpha.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.
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @typedef {import("../../types").AnyNode} AnyNode
3
+ * @typedef {{ [key in AnyNode['type']]?: number}} IncLevelOptions
4
+ * @typedef {(node: AnyNode) => number} GetIncreasingLevel
5
+ */
6
+
7
+ class IndentLevel {
8
+ /**
9
+ * @param {Object} config
10
+ * @param {GetIncreasingLevel} config.getIncreasingLevel
11
+ */
12
+ constructor(config) {
13
+ /**
14
+ * @member
15
+ * @private
16
+ * @type {number}
17
+ */
18
+ this.level = -1;
19
+ /**
20
+ * @member
21
+ * @private
22
+ * @type {number}
23
+ */
24
+ this.baseLevel = 0;
25
+ /**
26
+ * @member
27
+ * @private
28
+ */
29
+ this.getInc = config.getIncreasingLevel;
30
+ }
31
+
32
+ /**
33
+ * @returns {number}
34
+ */
35
+ value() {
36
+ return this.level + this.baseLevel;
37
+ }
38
+
39
+ /**
40
+ * @param {AnyNode} node
41
+ */
42
+ indent(node) {
43
+ this.level += this.getInc(node);
44
+ }
45
+
46
+ /**
47
+ * @param {AnyNode} node
48
+ */
49
+ dedent(node) {
50
+ this.level -= this.getInc(node);
51
+ }
52
+
53
+ /**
54
+ * @param {number} base
55
+ */
56
+ setBase(base) {
57
+ this.baseLevel = base;
58
+ }
59
+ }
60
+
61
+ module.exports = IndentLevel;
@@ -0,0 +1,369 @@
1
+ /**
2
+ * @typedef { import("../../types").RuleModule } RuleModule
3
+ * @typedef { import("../../types").AnyNode } AnyNode
4
+ * @typedef { import("../../types").LineNode } LineNode
5
+ * @typedef { import("../../types").BaseNode } BaseNode
6
+ * @typedef { import("../../types").TagNode } TagNode
7
+ * @typedef { import("../../types").RuleListener } RuleListener
8
+ * @typedef { import("eslint").AST.Token } Token
9
+ * @typedef { import("eslint").SourceCode } SourceCode
10
+ * @typedef { import("estree").TemplateLiteral } TemplateLiteral
11
+ * @typedef {Object} IndentType
12
+ * @property {"tab"} TAB
13
+ * @property {"space"} SPACE
14
+ * @typedef {Object} MessageId
15
+ * @property {"wrongIndent"} WRONG_INDENT
16
+ */
17
+
18
+ const { parse } = require("@html-eslint/template-parser");
19
+ const { RULE_CATEGORY } = require("../../constants");
20
+ const { splitToLineNodes } = require("../utils/node");
21
+ const {
22
+ shouldCheckTaggedTemplateExpression,
23
+ shouldCheckTemplateLiteral,
24
+ } = require("../utils/settings");
25
+ const { getSourceCode } = require("../utils/source-code");
26
+ const IndentLevel = require("./indent-level");
27
+
28
+ /** @type {MessageId} */
29
+ const MESSAGE_ID = {
30
+ WRONG_INDENT: "wrongIndent",
31
+ };
32
+
33
+ /** @type {IndentType} */
34
+ const INDENT_TYPES = {
35
+ TAB: "tab",
36
+ SPACE: "space",
37
+ };
38
+
39
+ const IGNORING_NODES = ["pre", "xmp"];
40
+
41
+ /**
42
+ * @type {RuleModule}
43
+ */
44
+ module.exports = {
45
+ meta: {
46
+ type: "code",
47
+
48
+ docs: {
49
+ description: "Enforce consistent indentation",
50
+ category: RULE_CATEGORY.STYLE,
51
+ recommended: true,
52
+ },
53
+
54
+ fixable: true,
55
+ schema: [
56
+ {
57
+ oneOf: [
58
+ {
59
+ enum: ["tab"],
60
+ },
61
+ {
62
+ type: "integer",
63
+ minimum: 0,
64
+ },
65
+ ],
66
+ },
67
+ {
68
+ type: "object",
69
+ properties: {
70
+ Attribute: {
71
+ type: "integer",
72
+ minimum: 1,
73
+ default: 1,
74
+ },
75
+ },
76
+ },
77
+ ],
78
+ messages: {
79
+ [MESSAGE_ID.WRONG_INDENT]:
80
+ "Expected indentation of {{expected}} but found {{actual}}.",
81
+ },
82
+ },
83
+ create(context) {
84
+ const sourceCode = getSourceCode(context);
85
+ const indentLevelOptions = (context.options && context.options[1]) || {};
86
+ const lines = sourceCode.getLines();
87
+ const { indentType, indentSize, indentChar } = (function () {
88
+ const options = context.options;
89
+ /**
90
+ * @type {IndentType['SPACE'] | IndentType['TAB']}
91
+ */
92
+ let indentType = INDENT_TYPES.SPACE;
93
+ let indentSize = 4;
94
+ if (options.length) {
95
+ if (options[0] === INDENT_TYPES.TAB) {
96
+ indentType = INDENT_TYPES.TAB;
97
+ } else {
98
+ indentSize = options[0];
99
+ }
100
+ }
101
+ const indentChar =
102
+ indentType === INDENT_TYPES.SPACE ? " ".repeat(indentSize) : "\t";
103
+ return { indentType, indentSize, indentChar };
104
+ })();
105
+
106
+ /**
107
+ * @param {string} str
108
+ * @returns {number}
109
+ */
110
+ function countLeftPadding(str) {
111
+ return str.length - str.replace(/^[\s\t]+/, "").length;
112
+ }
113
+
114
+ /**
115
+ * @param {AnyNode} node
116
+ * @returns {node is LineNode}
117
+ */
118
+ function isLineNode(node) {
119
+ return node.type === "Line";
120
+ }
121
+
122
+ /**
123
+ *
124
+ * @param {TemplateLiteral} node
125
+ * @returns {number}
126
+ */
127
+ function getTemplateLiteralBaseIndentLevel(node) {
128
+ // @ts-ignore
129
+ const lineIndex = node.loc.start.line - 1;
130
+ const line = lines[lineIndex];
131
+
132
+ const spaceCount = countLeftPadding(line);
133
+ if (indentType === "space") {
134
+ return Math.floor(spaceCount / indentSize) + 1;
135
+ } else {
136
+ return spaceCount + 1;
137
+ }
138
+ }
139
+
140
+ /**
141
+ * @param {number} baseLevel
142
+ */
143
+ function createIndentVisitor(baseLevel) {
144
+ const indentLevel = new IndentLevel({
145
+ getIncreasingLevel(node) {
146
+ return typeof indentLevelOptions[node.type] === "number"
147
+ ? indentLevelOptions[node.type]
148
+ : 1;
149
+ },
150
+ });
151
+ indentLevel.setBase(baseLevel);
152
+
153
+ let parentIgnoringChildCount = 0;
154
+
155
+ /**
156
+ * @param {AnyNode} node
157
+ * @returns {string}
158
+ */
159
+ function getActualIndent(node) {
160
+ const lines = sourceCode.getLines();
161
+ const line = lines[node.loc.start.line - 1];
162
+ let column = node.loc.start.column;
163
+
164
+ if (isLineNode(node)) {
165
+ column += countLeftPadding(node.value);
166
+ }
167
+
168
+ return line.slice(0, column);
169
+ }
170
+
171
+ /**
172
+ * @returns {string}
173
+ */
174
+ function getExpectedIndent() {
175
+ return indentChar.repeat(indentLevel.value());
176
+ }
177
+
178
+ /**
179
+ * @param {AnyNode} node
180
+ * @param {string} actualIndent
181
+ * @return {BaseNode}
182
+ */
183
+ function getIndentNodeToReport(node, actualIndent) {
184
+ let rangeStart = node.range[0];
185
+
186
+ if (node.type !== "Line") {
187
+ rangeStart -= actualIndent.length;
188
+ }
189
+
190
+ return {
191
+ range: [rangeStart, rangeStart + actualIndent.length],
192
+ loc: {
193
+ start: {
194
+ column: 0,
195
+ line: node.loc.start.line,
196
+ },
197
+ end: {
198
+ column: actualIndent.length,
199
+ line: node.loc.start.line,
200
+ },
201
+ },
202
+ };
203
+ }
204
+
205
+ /**
206
+ * @param {string} actualIndent
207
+ * @param {number} expectedIndentSize
208
+ */
209
+ function getMessageData(actualIndent, expectedIndentSize) {
210
+ const actualTabs = (actualIndent.match(/\t/g) || []).length;
211
+ const actualSpaces = (actualIndent.match(/[^\S\t\n\r]/g) || []).length;
212
+ let actual = "";
213
+ if (!actualTabs && !actualSpaces) {
214
+ actual = "no indent";
215
+ } else {
216
+ if (actualTabs) {
217
+ actual += `${actualTabs} tab`;
218
+ }
219
+ if (actualSpaces) {
220
+ if (actual) {
221
+ actual += ", ";
222
+ }
223
+ actual += `${actualSpaces} space`;
224
+ }
225
+ }
226
+
227
+ if (indentType === "space") {
228
+ expectedIndentSize *= indentSize;
229
+ }
230
+
231
+ return {
232
+ actual,
233
+ expected: `${expectedIndentSize} ${indentType}`,
234
+ };
235
+ }
236
+
237
+ /**
238
+ * @param {AnyNode} node
239
+ */
240
+ function checkIndent(node) {
241
+ if (parentIgnoringChildCount > 0) {
242
+ return;
243
+ }
244
+ const actualIndent = getActualIndent(node);
245
+ const expectedIndent = getExpectedIndent();
246
+
247
+ if (actualIndent.trim().length) {
248
+ return;
249
+ }
250
+ if (actualIndent !== expectedIndent) {
251
+ const targetNode = getIndentNodeToReport(node, actualIndent);
252
+ context.report({
253
+ node: targetNode,
254
+ messageId: MESSAGE_ID.WRONG_INDENT,
255
+ data: getMessageData(actualIndent, indentLevel.value()),
256
+ fix(fixer) {
257
+ return fixer.replaceText(targetNode, expectedIndent);
258
+ },
259
+ });
260
+ }
261
+ }
262
+
263
+ /**
264
+ * @type {RuleListener}
265
+ */
266
+ const visitor = {
267
+ Tag(node) {
268
+ if (IGNORING_NODES.includes(node.name)) {
269
+ parentIgnoringChildCount++;
270
+ }
271
+ indentLevel.indent(node);
272
+ },
273
+ ScriptTag(node) {
274
+ indentLevel.indent(node);
275
+ },
276
+ "ScriptTag:exit"(node) {
277
+ indentLevel.dedent(node);
278
+ },
279
+ OpenScriptTagStart: checkIndent,
280
+ OpenScriptTagEnd: checkIndent,
281
+ StyleTag(node) {
282
+ indentLevel.indent(node);
283
+ },
284
+ "StyleTag:exit"(node) {
285
+ indentLevel.dedent(node);
286
+ },
287
+ OpenStyleTagStart: checkIndent,
288
+ OpenStyleTagEnd: checkIndent,
289
+ OpenTagStart: checkIndent,
290
+ OpenTagEnd: checkIndent,
291
+ CloseTag: checkIndent,
292
+ "Tag:exit"(node) {
293
+ if (IGNORING_NODES.includes(node.name)) {
294
+ parentIgnoringChildCount--;
295
+ }
296
+ indentLevel.dedent(node);
297
+ },
298
+
299
+ // Attribute
300
+ Attribute(node) {
301
+ indentLevel.indent(node);
302
+ },
303
+ AttributeKey: checkIndent,
304
+ AttributeValue: checkIndent,
305
+ "Attribute:exit"(node) {
306
+ indentLevel.dedent(node);
307
+ },
308
+
309
+ // Text
310
+ Text(node) {
311
+ indentLevel.indent(node);
312
+ const lineNodes = splitToLineNodes(node);
313
+
314
+ lineNodes.forEach((lineNode) => {
315
+ if (lineNode.skipIndentCheck) {
316
+ return;
317
+ }
318
+ if (lineNode.value.trim().length) {
319
+ checkIndent(lineNode);
320
+ }
321
+ });
322
+ },
323
+ "Text:exit"(node) {
324
+ indentLevel.dedent(node);
325
+ },
326
+ Comment(node) {
327
+ indentLevel.indent(node);
328
+ },
329
+ CommentOpen: checkIndent,
330
+ CommentContent(node) {
331
+ indentLevel.indent(node);
332
+ const lineNodes = splitToLineNodes(node);
333
+ lineNodes.forEach((lineNode) => {
334
+ if (lineNode.skipIndentCheck) {
335
+ return;
336
+ }
337
+ if (lineNode.value.trim().length) {
338
+ checkIndent(lineNode);
339
+ }
340
+ });
341
+ },
342
+ CommentClose: checkIndent,
343
+ "Comment:exit"(node) {
344
+ indentLevel.dedent(node);
345
+ },
346
+ "CommentContent:exit"(node) {
347
+ indentLevel.dedent(node);
348
+ },
349
+ };
350
+ return visitor;
351
+ }
352
+
353
+ return {
354
+ ...createIndentVisitor(0),
355
+ TaggedTemplateExpression(node) {
356
+ if (shouldCheckTaggedTemplateExpression(node, context)) {
357
+ const base = getTemplateLiteralBaseIndentLevel(node.quasi);
358
+ parse(node.quasi, getSourceCode(context), createIndentVisitor(base));
359
+ }
360
+ },
361
+ TemplateLiteral(node) {
362
+ if (shouldCheckTemplateLiteral(node, context)) {
363
+ const base = getTemplateLiteralBaseIndentLevel(node);
364
+ parse(node, getSourceCode(context), createIndentVisitor(base));
365
+ }
366
+ },
367
+ };
368
+ },
369
+ };
@@ -0,0 +1,2 @@
1
+ const indent = require("./indent");
2
+ module.exports = indent;
@@ -86,30 +86,10 @@ function splitToLineNodes(node) {
86
86
  * @param {import("../../types").Range} range
87
87
  */
88
88
  function shouldSkipIndentCheck(range) {
89
- const overlappedTemplates = templates.filter(
89
+ return templates.some(
90
90
  (template) =>
91
91
  template.isTemplate && isRangesOverlap(template.range, range)
92
92
  );
93
-
94
- const isLineInTemplate = overlappedTemplates.some((template) => {
95
- return template.range[0] <= range[0] && template.range[1] >= range[1];
96
- });
97
- if (isLineInTemplate) {
98
- return true;
99
- }
100
- const isLineBeforeTemplate = overlappedTemplates.some((template) => {
101
- return template.range[0] <= range[0] && template.range[1] <= range[1];
102
- });
103
- if (isLineBeforeTemplate) {
104
- return true;
105
- }
106
- const isLineAfterTemplate = overlappedTemplates.some((template) => {
107
- return template.range[1] <= range[0];
108
- });
109
- if (isLineAfterTemplate) {
110
- return true;
111
- }
112
- return false;
113
93
  }
114
94
 
115
95
  node.value.split("\n").forEach((value, index) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@html-eslint/eslint-plugin",
3
- "version": "0.30.0",
3
+ "version": "0.31.1-alpha.0",
4
4
  "description": "ESLint plugin for html",
5
5
  "author": "yeonjuan",
6
6
  "homepage": "https://github.com/yeonjuan/html-eslint#readme",
@@ -45,15 +45,15 @@
45
45
  "accessibility"
46
46
  ],
47
47
  "dependencies": {
48
- "@html-eslint/template-parser": "^0.30.0"
48
+ "@html-eslint/template-parser": "^0.31.0"
49
49
  },
50
50
  "devDependencies": {
51
- "@html-eslint/parser": "^0.30.0",
51
+ "@html-eslint/parser": "^0.31.0",
52
52
  "@types/eslint": "^9.6.1",
53
53
  "@types/estree": "^0.0.47",
54
54
  "es-html-parser": "^1.0.0-alpha.4",
55
55
  "espree": "^10.3.0",
56
56
  "typescript": "^5.7.2"
57
57
  },
58
- "gitHead": "29f274f996d9cd41b82f2f2fa5c642564d3bc756"
58
+ "gitHead": "ae36c432e1500a56da5cc3aa1a26a8a40e8f2128"
59
59
  }
@@ -0,0 +1,55 @@
1
+ export = IndentLevel;
2
+ /**
3
+ * @typedef {import("../../types").AnyNode} AnyNode
4
+ * @typedef {{ [key in AnyNode['type']]?: number}} IncLevelOptions
5
+ * @typedef {(node: AnyNode) => number} GetIncreasingLevel
6
+ */
7
+ declare class IndentLevel {
8
+ /**
9
+ * @param {Object} config
10
+ * @param {GetIncreasingLevel} config.getIncreasingLevel
11
+ */
12
+ constructor(config: {
13
+ getIncreasingLevel: GetIncreasingLevel;
14
+ });
15
+ /**
16
+ * @member
17
+ * @private
18
+ * @type {number}
19
+ */
20
+ private level;
21
+ /**
22
+ * @member
23
+ * @private
24
+ * @type {number}
25
+ */
26
+ private baseLevel;
27
+ /**
28
+ * @member
29
+ * @private
30
+ */
31
+ private getInc;
32
+ /**
33
+ * @returns {number}
34
+ */
35
+ value(): number;
36
+ /**
37
+ * @param {AnyNode} node
38
+ */
39
+ indent(node: AnyNode): void;
40
+ /**
41
+ * @param {AnyNode} node
42
+ */
43
+ dedent(node: AnyNode): void;
44
+ /**
45
+ * @param {number} base
46
+ */
47
+ setBase(base: number): void;
48
+ }
49
+ declare namespace IndentLevel {
50
+ export { AnyNode, IncLevelOptions, GetIncreasingLevel };
51
+ }
52
+ type AnyNode = import("../../types").AnyNode;
53
+ type IncLevelOptions = { [key in AnyNode["type"]]?: number; };
54
+ type GetIncreasingLevel = (node: AnyNode) => number;
55
+ //# sourceMappingURL=indent-level.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indent-level.d.ts","sourceRoot":"","sources":["../../../lib/rules/indent/indent-level.js"],"names":[],"mappings":";AAAA;;;;GAIG;AAEH;IACE;;;OAGG;IACH,oBAFG;QAAmC,kBAAkB,EAA7C,kBAAkB;KAC5B,EAmBA;IAjBC;;;;OAIG;IACH,cAAe;IACf;;;;OAIG;IACH,kBAAkB;IAClB;;;OAGG;IACH,eAAuC;IAGzC;;OAEG;IACH,SAFa,MAAM,CAIlB;IAED;;OAEG;IACH,aAFW,OAAO,QAIjB;IAED;;OAEG;IACH,aAFW,OAAO,QAIjB;IAED;;OAEG;IACH,cAFW,MAAM,QAIhB;CACF;;;;eAzDY,OAAO,aAAa,EAAE,OAAO;uBAC7B,GAAG,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,GAAC;0BACpC,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM"}
@@ -0,0 +1,22 @@
1
+ declare namespace _exports {
2
+ export { RuleModule, AnyNode, LineNode, BaseNode, TagNode, RuleListener, Token, SourceCode, TemplateLiteral, IndentType, MessageId };
3
+ }
4
+ declare const _exports: RuleModule;
5
+ export = _exports;
6
+ type RuleModule = import("../../types").RuleModule;
7
+ type AnyNode = import("../../types").AnyNode;
8
+ type LineNode = import("../../types").LineNode;
9
+ type BaseNode = import("../../types").BaseNode;
10
+ type TagNode = import("../../types").TagNode;
11
+ type RuleListener = import("../../types").RuleListener;
12
+ type Token = import("eslint").AST.Token;
13
+ type SourceCode = import("eslint").SourceCode;
14
+ type TemplateLiteral = import("estree").TemplateLiteral;
15
+ type IndentType = {
16
+ TAB: "tab";
17
+ SPACE: "space";
18
+ };
19
+ type MessageId = {
20
+ WRONG_INDENT: "wrongIndent";
21
+ };
22
+ //# sourceMappingURL=indent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indent.d.ts","sourceRoot":"","sources":["../../../lib/rules/indent/indent.js"],"names":[],"mappings":";;;wBAyCU,UAAU;;kBAxCN,OAAO,aAAa,EAAE,UAAU;eAChC,OAAO,aAAa,EAAE,OAAO;gBAC7B,OAAO,aAAa,EAAE,QAAQ;gBAC9B,OAAO,aAAa,EAAE,QAAQ;eAC9B,OAAO,aAAa,EAAE,OAAO;oBAC7B,OAAO,aAAa,EAAE,YAAY;aAClC,OAAO,QAAQ,EAAE,GAAG,CAAC,KAAK;kBAC1B,OAAO,QAAQ,EAAE,UAAU;uBAC3B,OAAO,QAAQ,EAAE,eAAe;;SAEhC,KAAK;WACL,OAAO;;;kBAEP,aAAa"}
@@ -0,0 +1,3 @@
1
+ export = indent;
2
+ import indent = require("./indent");
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/rules/indent/index.js"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"indent.d.ts","sourceRoot":"","sources":["../../lib/rules/indent.js"],"names":[],"mappings":";;;wBAwCU,UAAU;;kBAvCN,OAAO,UAAU,EAAE,UAAU;eAC7B,OAAO,UAAU,EAAE,OAAO;gBAC1B,OAAO,UAAU,EAAE,QAAQ;gBAC3B,OAAO,UAAU,EAAE,QAAQ;eAC3B,OAAO,UAAU,EAAE,OAAO;oBAC1B,OAAO,UAAU,EAAE,YAAY;aAC/B,OAAO,QAAQ,EAAE,GAAG,CAAC,KAAK;kBAC1B,OAAO,QAAQ,EAAE,UAAU;uBAC3B,OAAO,QAAQ,EAAE,eAAe;;SAEhC,KAAK;WACL,OAAO;;;kBAEP,aAAa"}
1
+ {"version":3,"file":"indent.d.ts","sourceRoot":"","sources":["../../lib/rules/indent.js"],"names":[],"mappings":";;;wBAyCU,UAAU;;kBAxCN,OAAO,UAAU,EAAE,UAAU;eAC7B,OAAO,UAAU,EAAE,OAAO;gBAC1B,OAAO,UAAU,EAAE,QAAQ;gBAC3B,OAAO,UAAU,EAAE,QAAQ;eAC3B,OAAO,UAAU,EAAE,OAAO;oBAC1B,OAAO,UAAU,EAAE,YAAY;aAC/B,OAAO,QAAQ,EAAE,GAAG,CAAC,KAAK;kBAC1B,OAAO,QAAQ,EAAE,UAAU;uBAC3B,OAAO,QAAQ,EAAE,eAAe;;SAEhC,KAAK;WACL,OAAO;;;kBAEP,aAAa"}
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../lib/rules/utils/node.js"],"names":[],"mappings":"sBACc,OAAO,gBAAgB,EAAE,OAAO;4BAChC,OAAO,gBAAgB,EAAE,aAAa;2BACtC,OAAO,gBAAgB,EAAE,YAAY;4BACrC,OAAO,gBAAgB,EAAE,aAAa;iCACtC,OAAO,gBAAgB,EAAE,kBAAkB;sBAC3C,OAAO,gBAAgB,EAAE,OAAO;uBAChC,OAAO,gBAAgB,EAAE,QAAQ;iCACjC,OAAO,gBAAgB,EAAE,kBAAkB;0BAC3C,OAAO,gBAAgB,EAAE,WAAW;uBACpC,OAAO,gBAAgB,EAAE,QAAQ;uBACjC,OAAO,aAAa,EAAE,QAAQ;uBAC9B,OAAO,aAAa,EAAE,QAAQ;uBAC9B,OAAO,aAAa,EAAE,QAAQ;oBAC9B,OAAO,aAAa,EAAE,KAAK;AAKzC;;;;GAIG;AACH,+BAJW,OAAO,GAAG,aAAa,GAAG,YAAY,OACtC,MAAM,GACJ,aAAa,GAAG,SAAS,CAMrC;AAED;;;;GAIG;AACH,wCAHW,OAAO,GAAG,aAAa,GAAG,YAAY,GACpC,OAAO,CAInB;AAED;;;;GAIG;AACH,6CAHW,OAAO,GACL,OAAO,CAInB;AAuBD;;;;GAIG;AACH,uCAHW,QAAQ,GAAG,kBAAkB,GAC3B,QAAQ,EAAE,CA4EtB;AAED;;;;;GAKG;AACH,sCAJW,QAAQ,SACR,QAAQ,GACN,QAAQ,CAOpB;AAED;;;GAGG;AACH,6CAHW,kBAAkB,GACjB,OAAO,CAOlB;AAED;;;GAGG;AACH,4BAHW,OAAO,GACL,IAAI,IAAI,OAAO,CAI3B;AAED;;;GAGG;AACH,gCAHW,OAAO,GACL,IAAI,IAAI,WAAW,CAI/B;AAED;;;GAGG;AACH,6BAHW,OAAO,GACL,IAAI,IAAI,QAAQ,CAI5B;AA1ID;;;;GAIG;AACH,kDAJW,CAAC,QAAQ,GAAG,kBAAkB,CAAC,CAAC,WAAW,CAAC,SAC5C,KAAK,GACH,OAAO,CAMnB;AAqID;;;GAGG;AACH,oCAHW,MAAM,GACJ,MAAM,EAAE,CAIpB;AA9JD;;;;;GAKG;AACH,wCAJW,KAAK,UACL,KAAK,GACH,OAAO,CAInB;AAwJD;;;;GAIG;AACH,0CAHW,QAAQ,EAAE,GACR,CAAC,CAAC,kBAAkB,GAAG,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAapE"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../lib/rules/utils/node.js"],"names":[],"mappings":"sBACc,OAAO,gBAAgB,EAAE,OAAO;4BAChC,OAAO,gBAAgB,EAAE,aAAa;2BACtC,OAAO,gBAAgB,EAAE,YAAY;4BACrC,OAAO,gBAAgB,EAAE,aAAa;iCACtC,OAAO,gBAAgB,EAAE,kBAAkB;sBAC3C,OAAO,gBAAgB,EAAE,OAAO;uBAChC,OAAO,gBAAgB,EAAE,QAAQ;iCACjC,OAAO,gBAAgB,EAAE,kBAAkB;0BAC3C,OAAO,gBAAgB,EAAE,WAAW;uBACpC,OAAO,gBAAgB,EAAE,QAAQ;uBACjC,OAAO,aAAa,EAAE,QAAQ;uBAC9B,OAAO,aAAa,EAAE,QAAQ;uBAC9B,OAAO,aAAa,EAAE,QAAQ;oBAC9B,OAAO,aAAa,EAAE,KAAK;AAKzC;;;;GAIG;AACH,+BAJW,OAAO,GAAG,aAAa,GAAG,YAAY,OACtC,MAAM,GACJ,aAAa,GAAG,SAAS,CAMrC;AAED;;;;GAIG;AACH,wCAHW,OAAO,GAAG,aAAa,GAAG,YAAY,GACpC,OAAO,CAInB;AAED;;;;GAIG;AACH,6CAHW,OAAO,GACL,OAAO,CAInB;AAuBD;;;;GAIG;AACH,uCAHW,QAAQ,GAAG,kBAAkB,GAC3B,QAAQ,EAAE,CAwDtB;AAED;;;;;GAKG;AACH,sCAJW,QAAQ,SACR,QAAQ,GACN,QAAQ,CAOpB;AAED;;;GAGG;AACH,6CAHW,kBAAkB,GACjB,OAAO,CAOlB;AAED;;;GAGG;AACH,4BAHW,OAAO,GACL,IAAI,IAAI,OAAO,CAI3B;AAED;;;GAGG;AACH,gCAHW,OAAO,GACL,IAAI,IAAI,WAAW,CAI/B;AAED;;;GAGG;AACH,6BAHW,OAAO,GACL,IAAI,IAAI,QAAQ,CAI5B;AAtHD;;;;GAIG;AACH,kDAJW,CAAC,QAAQ,GAAG,kBAAkB,CAAC,CAAC,WAAW,CAAC,SAC5C,KAAK,GACH,OAAO,CAMnB;AAiHD;;;GAGG;AACH,oCAHW,MAAM,GACJ,MAAM,EAAE,CAIpB;AA1ID;;;;;GAKG;AACH,wCAJW,KAAK,UACL,KAAK,GACH,OAAO,CAInB;AAoID;;;;GAIG;AACH,0CAHW,QAAQ,EAAE,GACR,CAAC,CAAC,kBAAkB,GAAG,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAapE"}
@@ -1,378 +0,0 @@
1
- /**
2
- * @typedef { import("../types").RuleModule } RuleModule
3
- * @typedef { import("../types").AnyNode } AnyNode
4
- * @typedef { import("../types").LineNode } LineNode
5
- * @typedef { import("../types").BaseNode } BaseNode
6
- * @typedef { import("../types").TagNode } TagNode
7
- * @typedef { import("../types").RuleListener } RuleListener
8
- * @typedef { import("eslint").AST.Token } Token
9
- * @typedef { import("eslint").SourceCode } SourceCode
10
- * @typedef { import("estree").TemplateLiteral } TemplateLiteral
11
- * @typedef {Object} IndentType
12
- * @property {"tab"} TAB
13
- * @property {"space"} SPACE
14
- * @typedef {Object} MessageId
15
- * @property {"wrongIndent"} WRONG_INDENT
16
- */
17
-
18
- const { parse } = require("@html-eslint/template-parser");
19
- const { RULE_CATEGORY } = require("../constants");
20
- const { splitToLineNodes } = require("./utils/node");
21
- const {
22
- shouldCheckTaggedTemplateExpression,
23
- shouldCheckTemplateLiteral,
24
- } = require("./utils/settings");
25
- const { getSourceCode } = require("./utils/source-code");
26
-
27
- /** @type {MessageId} */
28
- const MESSAGE_ID = {
29
- WRONG_INDENT: "wrongIndent",
30
- };
31
-
32
- /** @type {IndentType} */
33
- const INDENT_TYPES = {
34
- TAB: "tab",
35
- SPACE: "space",
36
- };
37
-
38
- const IGNORING_NODES = ["pre", "xmp"];
39
-
40
- /**
41
- * @type {RuleModule}
42
- */
43
- module.exports = {
44
- meta: {
45
- type: "code",
46
-
47
- docs: {
48
- description: "Enforce consistent indentation",
49
- category: RULE_CATEGORY.STYLE,
50
- recommended: true,
51
- },
52
-
53
- fixable: true,
54
- schema: [
55
- {
56
- oneOf: [
57
- {
58
- enum: ["tab"],
59
- },
60
- {
61
- type: "integer",
62
- minimum: 0,
63
- },
64
- ],
65
- },
66
- ],
67
- messages: {
68
- [MESSAGE_ID.WRONG_INDENT]:
69
- "Expected indentation of {{expected}} but found {{actual}}.",
70
- },
71
- },
72
- create(context) {
73
- const sourceCode = getSourceCode(context);
74
-
75
- let baseIndentLevel = 0;
76
- let indentLevel = -1;
77
- let parentIgnoringChildCount = 0;
78
-
79
- const { indentType, indentSize, indentChar } = (function () {
80
- const options = context.options;
81
- /**
82
- * @type {IndentType['SPACE'] | IndentType['TAB']}
83
- */
84
- let indentType = INDENT_TYPES.SPACE;
85
- let indentSize = 4;
86
- if (options.length) {
87
- if (options[0] === INDENT_TYPES.TAB) {
88
- indentType = INDENT_TYPES.TAB;
89
- } else {
90
- indentSize = options[0];
91
- }
92
- }
93
- const indentChar =
94
- indentType === INDENT_TYPES.SPACE ? " ".repeat(indentSize) : "\t";
95
- return { indentType, indentSize, indentChar };
96
- })();
97
-
98
- function indent() {
99
- indentLevel++;
100
- }
101
- function unindent() {
102
- indentLevel--;
103
- }
104
- function getIndentLevel() {
105
- return indentLevel + baseIndentLevel;
106
- }
107
-
108
- /**
109
- * @param {string} str
110
- * @returns {number}
111
- */
112
- function countLeftPadding(str) {
113
- return str.length - str.replace(/^[\s\t]+/, "").length;
114
- }
115
-
116
- /**
117
- * @param {AnyNode} node
118
- * @returns {node is LineNode}
119
- */
120
- function isLineNode(node) {
121
- return node.type === "Line";
122
- }
123
-
124
- /**
125
- * @param {AnyNode} node
126
- * @returns {string}
127
- */
128
- function getActualIndent(node) {
129
- const lines = sourceCode.getLines();
130
- const line = lines[node.loc.start.line - 1];
131
- let column = node.loc.start.column;
132
-
133
- if (isLineNode(node)) {
134
- column += countLeftPadding(node.value);
135
- }
136
-
137
- return line.slice(0, column);
138
- }
139
-
140
- /**
141
- * @returns {string}
142
- */
143
- function getExpectedIndent() {
144
- return indentChar.repeat(getIndentLevel());
145
- }
146
-
147
- /**
148
- * @param {AnyNode} node
149
- * @param {string} actualIndent
150
- * @return {BaseNode}
151
- */
152
- function getIndentNodeToReport(node, actualIndent) {
153
- let rangeStart = node.range[0];
154
-
155
- if (node.type !== "Line") {
156
- rangeStart -= actualIndent.length;
157
- }
158
-
159
- return {
160
- range: [rangeStart, rangeStart + actualIndent.length],
161
- loc: {
162
- start: {
163
- column: 0,
164
- line: node.loc.start.line,
165
- },
166
- end: {
167
- column: actualIndent.length,
168
- line: node.loc.start.line,
169
- },
170
- },
171
- };
172
- }
173
-
174
- /**
175
- * @param {string} actualIndent
176
- * @param {number} expectedIndentSize
177
- */
178
- function getMessageData(actualIndent, expectedIndentSize) {
179
- const actualTabs = (actualIndent.match(/\t/g) || []).length;
180
- const actualSpaces = (actualIndent.match(/[^\S\t\n\r]/g) || []).length;
181
- let actual = "";
182
- if (!actualTabs && !actualSpaces) {
183
- actual = "no indent";
184
- } else {
185
- if (actualTabs) {
186
- actual += `${actualTabs} tab`;
187
- }
188
- if (actualSpaces) {
189
- if (actual) {
190
- actual += ", ";
191
- }
192
- actual += `${actualSpaces} space`;
193
- }
194
- }
195
-
196
- if (indentType === "space") {
197
- expectedIndentSize *= indentSize;
198
- }
199
-
200
- return {
201
- actual,
202
- expected: `${expectedIndentSize} ${indentType}`,
203
- };
204
- }
205
-
206
- /**
207
- * @param {AnyNode} node
208
- */
209
- function checkIndent(node) {
210
- if (parentIgnoringChildCount > 0) {
211
- return;
212
- }
213
- const actualIndent = getActualIndent(node);
214
- const expectedIndent = getExpectedIndent();
215
-
216
- if (actualIndent.trim().length) {
217
- return;
218
- }
219
- if (actualIndent !== expectedIndent) {
220
- const targetNode = getIndentNodeToReport(node, actualIndent);
221
- context.report({
222
- node: targetNode,
223
- messageId: MESSAGE_ID.WRONG_INDENT,
224
- data: getMessageData(actualIndent, getIndentLevel()),
225
- fix(fixer) {
226
- return fixer.replaceText(targetNode, expectedIndent);
227
- },
228
- });
229
- }
230
- }
231
-
232
- /**
233
- *
234
- * @param {Token} token
235
- */
236
- function getBaseIndentToken(token) {
237
- /**
238
- * @type {Token | null}
239
- */
240
- let currentToken = token;
241
- let tokenBefore = token;
242
-
243
- while (
244
- // @ts-ignore
245
- (tokenBefore = sourceCode.getTokenBefore(currentToken, {
246
- includeComments: true,
247
- }))
248
- ) {
249
- if (!tokenBefore) {
250
- return currentToken;
251
- }
252
- if (tokenBefore.loc.start.line !== currentToken.loc.start.line) {
253
- return currentToken;
254
- }
255
- currentToken = tokenBefore;
256
- }
257
- return tokenBefore;
258
- }
259
-
260
- /**
261
- *
262
- * @param {TemplateLiteral} node
263
- * @returns {number}
264
- */
265
- function getBaseIndentLevel(node) {
266
- const firstToken = sourceCode.getFirstToken(node);
267
- if (!firstToken) return 0;
268
- const baseToken = getBaseIndentToken(firstToken);
269
- if (!baseToken) {
270
- return 0;
271
- }
272
- const spaceCount = baseToken.loc.start.column;
273
-
274
- if (indentType === "space") {
275
- return Math.floor(spaceCount / indentSize);
276
- } else {
277
- return spaceCount;
278
- }
279
- }
280
- /**
281
- * @type {RuleListener}
282
- */
283
- const visitor = {
284
- Tag(node) {
285
- if (IGNORING_NODES.includes(node.name)) {
286
- parentIgnoringChildCount++;
287
- }
288
- indent();
289
- },
290
- ScriptTag: indent,
291
- "ScriptTag:exit": unindent,
292
- OpenScriptTagStart: checkIndent,
293
- OpenScriptTagEnd: checkIndent,
294
- StyleTag: indent,
295
- "StyleTag:exit": unindent,
296
- OpenStyleTagStart: checkIndent,
297
- OpenStyleTagEnd: checkIndent,
298
- OpenTagStart: checkIndent,
299
- OpenTagEnd: checkIndent,
300
- CloseTag: checkIndent,
301
- /**
302
- * @param {TagNode} node
303
- */
304
- "Tag:exit"(node) {
305
- if (IGNORING_NODES.includes(node.name)) {
306
- parentIgnoringChildCount--;
307
- }
308
- unindent();
309
- },
310
-
311
- // Attribute
312
- Attribute: indent,
313
- AttributeKey: checkIndent,
314
- AttributeValue: checkIndent,
315
- "Attribute:exit": unindent,
316
-
317
- // Text
318
- Text(node) {
319
- indent();
320
- const lineNodes = splitToLineNodes(node);
321
- lineNodes.forEach((lineNode) => {
322
- if (lineNode.skipIndentCheck) {
323
- return;
324
- }
325
- if (lineNode.value.trim().length) {
326
- checkIndent(lineNode);
327
- }
328
- });
329
- },
330
- "Text:exit": unindent,
331
-
332
- // Comment
333
- Comment: indent,
334
- CommentOpen: checkIndent,
335
- CommentContent(node) {
336
- indent();
337
- const lineNodes = splitToLineNodes(node);
338
- lineNodes.forEach((lineNode) => {
339
- if (lineNode.skipIndentCheck) {
340
- return;
341
- }
342
- if (lineNode.value.trim().length) {
343
- checkIndent(lineNode);
344
- }
345
- });
346
- },
347
- CommentClose: checkIndent,
348
- "Comment:exit": unindent,
349
- "CommentContent:exit": unindent,
350
- };
351
-
352
- return {
353
- ...visitor,
354
- TaggedTemplateExpression(node) {
355
- if (shouldCheckTaggedTemplateExpression(node, context)) {
356
- baseIndentLevel = getBaseIndentLevel(node.quasi) + 1;
357
- parse(node.quasi, getSourceCode(context), visitor);
358
- }
359
- },
360
- "TaggedTemplateExpression:exit"(node) {
361
- if (shouldCheckTaggedTemplateExpression(node, context)) {
362
- baseIndentLevel = 0;
363
- }
364
- },
365
- TemplateLiteral(node) {
366
- if (shouldCheckTemplateLiteral(node, context)) {
367
- baseIndentLevel = getBaseIndentLevel(node) + 1;
368
- parse(node, getSourceCode(context), visitor);
369
- }
370
- },
371
- "TemplateLiteral:exit"(node) {
372
- if (shouldCheckTemplateLiteral(node, context)) {
373
- baseIndentLevel = 0;
374
- }
375
- },
376
- };
377
- },
378
- };