@so1ve/eslint-plugin 4.1.7 → 4.2.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.
Files changed (31) hide show
  1. package/dist/index.d.mts +25 -83
  2. package/dist/index.mjs +13 -1254
  3. package/dist/rules/function-style.d.mts +8 -0
  4. package/dist/rules/function-style.mjs +145 -0
  5. package/dist/rules/html-spaced-comment.d.mts +8 -0
  6. package/dist/rules/html-spaced-comment.mjs +41 -0
  7. package/dist/rules/import-dedupe.d.mts +8 -0
  8. package/dist/rules/import-dedupe.mjs +42 -0
  9. package/dist/rules/import-export-newline.d.mts +8 -0
  10. package/dist/rules/import-export-newline.mjs +98 -0
  11. package/dist/rules/no-import-promises-as.d.mts +8 -0
  12. package/dist/rules/no-import-promises-as.mjs +45 -0
  13. package/dist/rules/no-inline-type-modifier.d.mts +8 -0
  14. package/dist/rules/no-inline-type-modifier.mjs +86 -0
  15. package/dist/rules/no-negated-comparison.d.mts +8 -0
  16. package/dist/rules/no-negated-comparison.mjs +45 -0
  17. package/dist/rules/no-useless-template-string.d.mts +8 -0
  18. package/dist/rules/no-useless-template-string.mjs +30 -0
  19. package/dist/rules/prefer-ts-expect-error.d.mts +8 -0
  20. package/dist/rules/prefer-ts-expect-error.mjs +46 -0
  21. package/dist/rules/require-async-with-await.d.mts +8 -0
  22. package/dist/rules/require-async-with-await.mjs +51 -0
  23. package/dist/rules/sort-exports.d.mts +8 -0
  24. package/dist/rules/sort-exports.mjs +68 -0
  25. package/dist/rules/sort-imports.d.mts +10 -0
  26. package/dist/rules/sort-imports.mjs +104 -0
  27. package/dist/rules/vue-root-element-sort-attributes.d.mts +11 -0
  28. package/dist/rules/vue-root-element-sort-attributes.mjs +66 -0
  29. package/dist/utils/index.mjs +19 -0
  30. package/dist/utils/sort-imports.mjs +417 -0
  31. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1,1258 +1,17 @@
1
- import { AST_NODE_TYPES, TSESTree } from "@typescript-eslint/types";
2
- import { AST_TOKEN_TYPES, ESLintUtils } from "@typescript-eslint/utils";
3
- import natsort from "natsort";
1
+ import function_style_default from "./rules/function-style.mjs";
2
+ import html_spaced_comment_default from "./rules/html-spaced-comment.mjs";
3
+ import import_dedupe_default from "./rules/import-dedupe.mjs";
4
+ import import_export_newline_default from "./rules/import-export-newline.mjs";
5
+ import no_import_promises_as_default from "./rules/no-import-promises-as.mjs";
6
+ import no_inline_type_modifier_default from "./rules/no-inline-type-modifier.mjs";
7
+ import no_negated_comparison_default from "./rules/no-negated-comparison.mjs";
8
+ import no_useless_template_string_default from "./rules/no-useless-template-string.mjs";
9
+ import prefer_ts_expect_error_default from "./rules/prefer-ts-expect-error.mjs";
10
+ import require_async_with_await_default from "./rules/require-async-with-await.mjs";
11
+ import sort_exports_default from "./rules/sort-exports.mjs";
12
+ import sort_imports_default from "./rules/sort-imports.mjs";
13
+ import vue_root_element_sort_attributes_default from "./rules/vue-root-element-sort-attributes.mjs";
4
14
 
5
- //#region src/utils/index.ts
6
- const createEslintRule = ESLintUtils.RuleCreator((ruleName) => ruleName);
7
- function getSiblingNode(node, offset) {
8
- if (!node) return;
9
- const { parent } = node;
10
- if (parent && "body" in parent) {
11
- const { body } = parent;
12
- if (!Array.isArray(body)) return;
13
- const targetIndex = body.indexOf(node) + offset;
14
- if (targetIndex >= 0 && targetIndex < body.length) return body[targetIndex];
15
- }
16
- }
17
- const getPreviousNode = (node) => getSiblingNode(node, -1);
18
- const getNextNode = (node) => getSiblingNode(node, 1);
19
-
20
- //#endregion
21
- //#region src/rules/function-style.ts
22
- const RULE_NAME$11 = "function-style";
23
- const rule$12 = createEslintRule({
24
- name: RULE_NAME$11,
25
- meta: {
26
- type: "problem",
27
- docs: { description: "Enforce function style." },
28
- fixable: "code",
29
- schema: [],
30
- messages: {
31
- arrow: "Expected an arrow function shorthand.",
32
- declaration: "Expected a function declaration."
33
- }
34
- },
35
- defaultOptions: [],
36
- create: (context) => {
37
- const sourceCode = context.sourceCode;
38
- const scopeStack = [];
39
- let haveThisAccess = false;
40
- function getSingleReturnStatement(node) {
41
- const { body } = node;
42
- if (body.type !== AST_NODE_TYPES.BlockStatement) return;
43
- const { body: blockBody } = body;
44
- if (blockBody.length !== 1) return;
45
- const [statement] = blockBody;
46
- if (statement?.type !== AST_NODE_TYPES.ReturnStatement) return;
47
- const allComments = sourceCode.getCommentsInside(node);
48
- const statementComments = sourceCode.getCommentsInside(statement);
49
- if (allComments.length !== statementComments.length) return;
50
- return statement;
51
- }
52
- const extractFunctionInfo = (node) => ({
53
- async: node.async,
54
- generics: node.typeParameters ? sourceCode.getText(node.typeParameters) : "",
55
- params: node.params.map((param) => sourceCode.getText(param)).join(", "),
56
- returnType: node.returnType ? sourceCode.getText(node.returnType) : "",
57
- body: sourceCode.getText(node.body)
58
- });
59
- function generateArrowFunction(name, info, returnValue, asVariable = true) {
60
- const asyncKeyword = info.async ? "async " : "";
61
- return `${asVariable && name ? `const ${name} = ` : ""}${asyncKeyword}${info.generics}(${info.params})${info.returnType} => ${returnValue};`;
62
- }
63
- function generateFunctionDeclaration(name, info) {
64
- return `${info.async ? "async " : ""}function ${name}${info.generics}(${info.params})${info.returnType} ${info.body}`;
65
- }
66
- function setupScope(node) {
67
- scopeStack.push(sourceCode.getScope(node));
68
- }
69
- function clearThisAccess() {
70
- scopeStack.pop();
71
- haveThisAccess = false;
72
- }
73
- function getFunctionExpressionParentNameString(node) {
74
- const parent = node.parent;
75
- if (parent?.id?.typeAnnotation || parent?.type !== AST_NODE_TYPES.VariableDeclarator || haveThisAccess) return null;
76
- return parent.id.name;
77
- }
78
- function shouldConvertFunctionDeclarationToArrow(node) {
79
- if (haveThisAccess) return { shouldConvert: false };
80
- const previousNode = getPreviousNode(node.parent);
81
- if (previousNode?.type === AST_NODE_TYPES.ExportNamedDeclaration && previousNode.declaration?.type === AST_NODE_TYPES.TSDeclareFunction) return { shouldConvert: false };
82
- const returnStatement = getSingleReturnStatement(node);
83
- const isExportDefault = node.parent?.type === AST_NODE_TYPES.ExportDefaultDeclaration;
84
- if (!returnStatement?.argument || !node.id?.name && !isExportDefault || node.generator) return { shouldConvert: false };
85
- return {
86
- shouldConvert: true,
87
- returnStatement
88
- };
89
- }
90
- return {
91
- "FunctionExpression": setupScope,
92
- "FunctionExpression:exit"(node) {
93
- const name = getFunctionExpressionParentNameString(node);
94
- if (!name) {
95
- clearThisAccess();
96
- return;
97
- }
98
- const info = extractFunctionInfo(node);
99
- const grandParent = node.parent?.parent;
100
- if (!grandParent) return;
101
- context.report({
102
- node,
103
- messageId: "declaration",
104
- fix: (fixer) => fixer.replaceText(grandParent, generateFunctionDeclaration(name, info))
105
- });
106
- clearThisAccess();
107
- },
108
- "FunctionDeclaration:not(TSDeclareFunction + FunctionDeclaration)": setupScope,
109
- "FunctionDeclaration:not(TSDeclareFunction + FunctionDeclaration):exit"(node) {
110
- if (haveThisAccess) return;
111
- const { shouldConvert, returnStatement } = shouldConvertFunctionDeclarationToArrow(node);
112
- if (!shouldConvert || !returnStatement?.argument) {
113
- clearThisAccess();
114
- return;
115
- }
116
- const info = extractFunctionInfo(node);
117
- const isExportDefault = node.parent?.type === AST_NODE_TYPES.ExportDefaultDeclaration;
118
- const returnValue = `(${sourceCode.getText(returnStatement.argument)})`;
119
- context.report({
120
- node,
121
- messageId: "arrow",
122
- fix: (fixer) => fixer.replaceText(node, generateArrowFunction(node.id?.name ?? null, info, returnValue, !isExportDefault))
123
- });
124
- clearThisAccess();
125
- },
126
- "ArrowFunctionExpression": setupScope,
127
- "ArrowFunctionExpression:exit"(node) {
128
- if (haveThisAccess) return;
129
- const { body, parent } = node;
130
- const returnStatement = getSingleReturnStatement(node);
131
- if (returnStatement?.argument) {
132
- const returnValue = `(${sourceCode.getText(returnStatement.argument)})`;
133
- context.report({
134
- node,
135
- messageId: "arrow",
136
- fix: (fixer) => fixer.replaceText(node.body, returnValue)
137
- });
138
- } else if (body.type === AST_NODE_TYPES.BlockStatement && !parent?.id?.typeAnnotation) {
139
- const { body: blockBody } = body;
140
- if (blockBody.length > 0 && node.parent?.parent?.type === AST_NODE_TYPES.VariableDeclaration) {
141
- const grandParent = node.parent.parent;
142
- const name = node.parent.id.name;
143
- const info = extractFunctionInfo(node);
144
- context.report({
145
- node: grandParent,
146
- messageId: "declaration",
147
- fix: (fixer) => fixer.replaceText(grandParent, generateFunctionDeclaration(name, info))
148
- });
149
- }
150
- }
151
- clearThisAccess();
152
- },
153
- ThisExpression(node) {
154
- haveThisAccess = scopeStack.includes(sourceCode.getScope(node));
155
- }
156
- };
157
- }
158
- });
159
- var function_style_default = rule$12;
160
-
161
- //#endregion
162
- //#region src/rules/html-spaced-comment.ts
163
- const RULE_NAME$10 = "html-spaced-comment";
164
- const rule$11 = createEslintRule({
165
- name: RULE_NAME$10,
166
- meta: {
167
- type: "layout",
168
- docs: { description: "Enforce consistent spacing in HTML comments" },
169
- fixable: "whitespace",
170
- schema: [],
171
- messages: {
172
- expectedSpaceBefore: "Expected space after '<!--'.",
173
- expectedSpaceAfter: "Expected space before '-->'."
174
- }
175
- },
176
- defaultOptions: [],
177
- create: (context) => ({ Comment(node) {
178
- if (node.value?.type !== "CommentContent") return;
179
- const rawValue = node.value.value;
180
- if (rawValue.trim().length === 0) return;
181
- if (!rawValue.startsWith(" ") && !rawValue.startsWith("\n")) context.report({
182
- node: node.value,
183
- messageId: "expectedSpaceBefore",
184
- fix(fixer) {
185
- return fixer.insertTextBefore(node.value, " ");
186
- }
187
- });
188
- if (!rawValue.endsWith(" ") && !rawValue.endsWith("\n")) context.report({
189
- node: node.value,
190
- messageId: "expectedSpaceAfter",
191
- fix(fixer) {
192
- return fixer.insertTextAfter(node.value, " ");
193
- }
194
- });
195
- } })
196
- });
197
- var html_spaced_comment_default = rule$11;
198
-
199
- //#endregion
200
- //#region src/rules/import-dedupe.ts
201
- const RULE_NAME$9 = "import-dedupe";
202
- const rule$10 = createEslintRule({
203
- name: RULE_NAME$9,
204
- meta: {
205
- type: "problem",
206
- docs: { description: "Fix duplication in imports." },
207
- fixable: "code",
208
- schema: [],
209
- messages: { importDedupe: "Expect no duplication in imports." }
210
- },
211
- defaultOptions: [],
212
- create: (context) => ({ ImportDeclaration(node) {
213
- if (node.specifiers.length <= 1) return;
214
- const names = /* @__PURE__ */ new Set();
215
- for (const n of node.specifiers) {
216
- const id = n.local.name;
217
- if (names.has(id)) context.report({
218
- node,
219
- loc: {
220
- start: n.loc.end,
221
- end: n.loc.start
222
- },
223
- messageId: "importDedupe",
224
- fix(fixer) {
225
- const start = n.range[0];
226
- let end = n.range[1];
227
- const nextToken = context.sourceCode.getTokenAfter(n);
228
- if (nextToken?.value === ",") end = nextToken.range[1];
229
- return fixer.removeRange([start, end]);
230
- }
231
- });
232
- names.add(id);
233
- }
234
- } })
235
- });
236
- var import_dedupe_default = rule$10;
237
-
238
- //#endregion
239
- //#region src/rules/import-export-newline.ts
240
- const RULE_NAME$8 = "import-export-newline";
241
- const isExportDeclaration = (node) => node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration" || node.type === "ExportAllDeclaration";
242
- const rule$9 = createEslintRule({
243
- name: RULE_NAME$8,
244
- meta: {
245
- type: "problem",
246
- docs: { description: "Enforce spacing between imports and exports." },
247
- fixable: "code",
248
- schema: [],
249
- messages: {
250
- newlineAfterLastImport: "Expected a blank line after the last import.",
251
- newlineBeforeExport: "Expected a blank line before the export.",
252
- newlineAfterExport: "Expected a blank line after the export."
253
- }
254
- },
255
- defaultOptions: [],
256
- create: (context) => {
257
- const sourceCode = context.sourceCode;
258
- let lastImportNode = null;
259
- const exportNodes = [];
260
- function checkExport(node) {
261
- exportNodes.push(node);
262
- }
263
- function checkNewline(node, direction) {
264
- let token;
265
- let expectedLine;
266
- let tokenLine;
267
- if (direction === "after") {
268
- const endNode = sourceCode.getCommentsAfter(node).find((c) => c.loc.start.line === node.loc.end.line) ?? node;
269
- token = sourceCode.getTokenAfter(endNode);
270
- const nextComment = sourceCode.getCommentsAfter(endNode)[0];
271
- expectedLine = endNode.loc.end.line + 1;
272
- tokenLine = token?.loc.start.line;
273
- const commentLine = nextComment?.loc.start.line;
274
- if (token && (expectedLine === tokenLine || expectedLine === commentLine || tokenLine === endNode.loc.end.line) && token.value !== "}" && token.value !== "<\/script>") return endNode;
275
- return null;
276
- }
277
- const startNode = sourceCode.getCommentsBefore(node)[0] || node;
278
- token = sourceCode.getTokenBefore(startNode);
279
- expectedLine = startNode.loc.start.line - 1;
280
- tokenLine = token?.loc.end.line;
281
- if (token && expectedLine === tokenLine) return startNode;
282
- return null;
283
- }
284
- return {
285
- ImportDeclaration(node) {
286
- lastImportNode = node;
287
- },
288
- ExportNamedDeclaration: checkExport,
289
- ExportDefaultDeclaration: checkExport,
290
- ExportAllDeclaration: checkExport,
291
- "Program:exit"() {
292
- if (lastImportNode) {
293
- const parent = lastImportNode.parent;
294
- const nextNode = getNextNode(lastImportNode);
295
- const isLastInBlock = parent && "body" in parent && Array.isArray(parent.body) && parent.body[parent.body.length - 1] === lastImportNode;
296
- if (nextNode && !isLastInBlock) {
297
- const lastImportFixNode = checkNewline(lastImportNode, "after");
298
- if (lastImportFixNode) context.report({
299
- node: lastImportNode,
300
- messageId: "newlineAfterLastImport",
301
- fix: (fixer) => fixer.insertTextAfter(lastImportFixNode, "\n")
302
- });
303
- }
304
- }
305
- for (const node of exportNodes) {
306
- const prevNode = getPreviousNode(node);
307
- const parent = node.parent;
308
- const isFirstInBlock = parent && "body" in parent && Array.isArray(parent.body) && parent.body[0] === node;
309
- if ((!prevNode || !isExportDeclaration(prevNode)) && (!lastImportNode || prevNode !== lastImportNode) && !isFirstInBlock) {
310
- const beforeFixNode = checkNewline(node, "before");
311
- if (beforeFixNode) context.report({
312
- node,
313
- messageId: "newlineBeforeExport",
314
- fix: (fixer) => fixer.insertTextBefore(beforeFixNode, "\n")
315
- });
316
- }
317
- const nextNode = getNextNode(node);
318
- if (nextNode && !isExportDeclaration(nextNode)) {
319
- const afterFixNode = checkNewline(node, "after");
320
- if (afterFixNode) context.report({
321
- node,
322
- messageId: "newlineAfterExport",
323
- fix: (fixer) => fixer.insertTextAfter(afterFixNode, "\n")
324
- });
325
- }
326
- }
327
- }
328
- };
329
- }
330
- });
331
- var import_export_newline_default = rule$9;
332
-
333
- //#endregion
334
- //#region src/rules/no-import-promises-as.ts
335
- const RULE_NAME$7 = "no-import-promises-as";
336
- const POSSIBLE_IMPORT_SOURCES = [
337
- "dns",
338
- "fs",
339
- "readline",
340
- "stream"
341
- ].flatMap((s) => [s, `node:${s}`]);
342
- const rule$8 = createEslintRule({
343
- name: RULE_NAME$7,
344
- meta: {
345
- type: "problem",
346
- docs: { description: "Disallow import promises as." },
347
- fixable: "code",
348
- schema: [],
349
- messages: { noImportPromisesAs: "Expect no import promises as." }
350
- },
351
- defaultOptions: [],
352
- create: (context) => {
353
- const { text } = context.sourceCode;
354
- return { ImportDeclaration(node) {
355
- if (!POSSIBLE_IMPORT_SOURCES.includes(node.source.value)) return;
356
- const promisesSpecifier = node.specifiers.find((s) => s.type === "ImportSpecifier" && s.imported.type === "Identifier" && s.imported.name === "promises" && s.local.name !== "promises");
357
- const as = promisesSpecifier?.local.name;
358
- if (!promisesSpecifier || !as) return;
359
- context.report({
360
- node,
361
- messageId: "noImportPromisesAs",
362
- *fix(fixer) {
363
- const s = promisesSpecifier.range[0];
364
- let e = promisesSpecifier.range[1];
365
- if (text[e] === ",") e += 1;
366
- yield fixer.removeRange([s, e]);
367
- yield fixer.insertTextAfter(node, `\nimport ${as} from "${node.source.value}/promises";`);
368
- }
369
- });
370
- } };
371
- }
372
- });
373
- var no_import_promises_as_default = rule$8;
374
-
375
- //#endregion
376
- //#region src/rules/no-inline-type-modifier.ts
377
- const RULE_NAME$6 = "no-inline-type-modifier";
378
- const getName = (node) => node.type === AST_NODE_TYPES.Identifier ? node.name : node.raw;
379
- function getSpecifierText(s) {
380
- const isExport = s.type === AST_NODE_TYPES.ExportSpecifier;
381
- const name1 = getName(isExport ? s.local : s.imported);
382
- const name2 = getName(isExport ? s.exported : s.local);
383
- return name1 === name2 ? name1 : `${name1} as ${name2}`;
384
- }
385
- function generateSpecifiersText(specifiers) {
386
- return `{ ${specifiers.map(getSpecifierText).join(", ")} }`;
387
- }
388
- const generateTypeText = (specifiers) => `type ${generateSpecifiersText(specifiers)}`;
389
- function generateValueText(valueSpecifiers, defaultSpecifier) {
390
- const parts = [];
391
- if (defaultSpecifier) parts.push(defaultSpecifier.local.name);
392
- if (valueSpecifiers.length > 0) parts.push(generateSpecifiersText(valueSpecifiers));
393
- return parts.join(", ");
394
- }
395
- function classifySpecifiers(specifiers) {
396
- const typeSpecifiers = [];
397
- const valueSpecifiers = [];
398
- let defaultSpecifier;
399
- for (const s of specifiers) if (s.type === AST_NODE_TYPES.ImportDefaultSpecifier) defaultSpecifier = s;
400
- else if (s.type === AST_NODE_TYPES.ImportSpecifier) if (s.importKind === "type") typeSpecifiers.push(s);
401
- else valueSpecifiers.push(s);
402
- else if (s.type === AST_NODE_TYPES.ExportSpecifier) if (s.exportKind === "type") typeSpecifiers.push(s);
403
- else valueSpecifiers.push(s);
404
- return {
405
- typeSpecifiers,
406
- valueSpecifiers,
407
- defaultSpecifier
408
- };
409
- }
410
- const rule$7 = createEslintRule({
411
- name: RULE_NAME$6,
412
- meta: {
413
- type: "layout",
414
- docs: { description: "Disallow inline type modifiers in import/export." },
415
- fixable: "code",
416
- schema: [],
417
- messages: { noInlineTypeModifier: "Expected no inline type modifier." }
418
- },
419
- defaultOptions: [],
420
- create: (context) => ({
421
- ImportDeclaration: (node) => {
422
- const { typeSpecifiers, valueSpecifiers, defaultSpecifier } = classifySpecifiers(node.specifiers);
423
- if (typeSpecifiers.length === 0) return;
424
- const texts = [];
425
- texts.push(generateTypeText(typeSpecifiers));
426
- if (defaultSpecifier || valueSpecifiers.length > 0) texts.push(generateValueText(valueSpecifiers, defaultSpecifier));
427
- const textToReport = texts.map((text) => `import ${text} from "${node.source.value}";`).join("\n");
428
- context.report({
429
- node,
430
- messageId: "noInlineTypeModifier",
431
- fix(fixer) {
432
- return fixer.replaceText(node, textToReport);
433
- }
434
- });
435
- },
436
- ExportNamedDeclaration: (node) => {
437
- if (node.declaration || node.exportKind === "type") return;
438
- const { typeSpecifiers, valueSpecifiers } = classifySpecifiers(node.specifiers);
439
- if (typeSpecifiers.length === 0) return;
440
- const fromText = node.source ? ` from "${node.source.value}"` : "";
441
- const texts = [];
442
- texts.push(generateTypeText(typeSpecifiers));
443
- if (valueSpecifiers.length > 0) texts.push(generateValueText(valueSpecifiers));
444
- const textToReport = texts.map((text) => `export ${text}${fromText};`).join("\n");
445
- context.report({
446
- node,
447
- messageId: "noInlineTypeModifier",
448
- fix(fixer) {
449
- return fixer.replaceText(node, textToReport);
450
- }
451
- });
452
- }
453
- })
454
- });
455
- var no_inline_type_modifier_default = rule$7;
456
-
457
- //#endregion
458
- //#region src/rules/no-negated-comparison.ts
459
- const RULE_NAME$5 = "no-negated-comparison";
460
- const negatedToPositive = {
461
- "==": "!=",
462
- "===": "!==",
463
- "!=": "==",
464
- "!==": "===",
465
- "<": ">=",
466
- "<=": ">",
467
- ">": "<=",
468
- ">=": "<"
469
- };
470
- const negatives = Object.keys(negatedToPositive);
471
- const rule$6 = createEslintRule({
472
- name: RULE_NAME$5,
473
- meta: {
474
- type: "problem",
475
- docs: { description: "Disallow negated comparison." },
476
- fixable: "code",
477
- schema: [],
478
- messages: { noNegatedComparison: "Expect no negated comparison." }
479
- },
480
- defaultOptions: [],
481
- create: (context) => ({ BinaryExpression(node) {
482
- const { parent, left, right, operator } = node;
483
- if (!parent) return;
484
- if (negatives.includes(operator) && parent.type === AST_NODE_TYPES.UnaryExpression && parent.operator === "!") context.report({
485
- node,
486
- messageId: "noNegatedComparison",
487
- *fix(fixer) {
488
- const operatorRange = [left.range[1], right.range[0]];
489
- const fixedOperator = negatedToPositive[operator];
490
- yield fixer.replaceTextRange(operatorRange, fixedOperator);
491
- yield fixer.removeRange([parent.range[0], parent.range[0] + 1]);
492
- }
493
- });
494
- } })
495
- });
496
- var no_negated_comparison_default = rule$6;
497
-
498
- //#endregion
499
- //#region src/rules/no-useless-template-string.ts
500
- const RULE_NAME$4 = "no-useless-template-string";
501
- const rule$5 = createEslintRule({
502
- name: RULE_NAME$4,
503
- meta: {
504
- type: "problem",
505
- docs: { description: "No useless template string." },
506
- fixable: "code",
507
- schema: [],
508
- messages: { noUselessTemplateString: "No useless template string." }
509
- },
510
- defaultOptions: [],
511
- create: (context) => ({ "TemplateLiteral:not(TaggedTemplateExpression > TemplateLiteral)"(node) {
512
- const { quasis } = node;
513
- const isSafe = !quasis.some(({ value: { raw } }) => raw.includes("\"") || raw.includes("'") || raw.includes("\n"));
514
- if (node.expressions.length === 0 && isSafe) context.report({
515
- node,
516
- messageId: "noUselessTemplateString",
517
- fix(fixer) {
518
- return fixer.replaceTextRange(node.range, `"${node.quasis[0].value.raw}"`);
519
- }
520
- });
521
- } })
522
- });
523
- var no_useless_template_string_default = rule$5;
524
-
525
- //#endregion
526
- //#region src/rules/prefer-ts-expect-error.ts
527
- const rule$4 = createEslintRule({
528
- name: "prefer-ts-expect-error",
529
- meta: {
530
- type: "problem",
531
- docs: { description: "Enforce using `@ts-expect-error` over `@ts-ignore`" },
532
- fixable: "code",
533
- messages: { preferExpectErrorComment: "Use \"@ts-expect-error\" to ensure an error is actually being suppressed." },
534
- replacedBy: ["@typescript-eslint/ban-ts-comment"],
535
- schema: []
536
- },
537
- defaultOptions: [],
538
- create(context) {
539
- const tsIgnoreRegExpSingleLine = /^\s*(?:\/\s*)?@ts-ignore/;
540
- const tsIgnoreRegExpMultiLine = /^\s*(?:(?:\/|\*)+\s*)?@ts-ignore/;
541
- const isLineComment$1 = (comment) => comment.type === AST_TOKEN_TYPES.Line;
542
- function getLastCommentLine(comment) {
543
- if (isLineComment$1(comment)) return comment.value;
544
- const commentlines = comment.value.split("\n");
545
- return commentlines[commentlines.length - 1];
546
- }
547
- function isValidTsIgnorePresent(comment) {
548
- const line = getLastCommentLine(comment);
549
- return isLineComment$1(comment) ? tsIgnoreRegExpSingleLine.test(line) : tsIgnoreRegExpMultiLine.test(line);
550
- }
551
- return { Program() {
552
- const comments = context.sourceCode.getAllComments();
553
- for (const comment of comments) if (isValidTsIgnorePresent(comment)) {
554
- const lineCommentRuleFixer = (fixer) => fixer.replaceText(comment, `//${comment.value.replace("@ts-ignore", "@ts-expect-error")}`);
555
- const blockCommentRuleFixer = (fixer) => fixer.replaceText(comment, `/*${comment.value.replace("@ts-ignore", "@ts-expect-error")}*/`);
556
- context.report({
557
- node: comment,
558
- messageId: "preferExpectErrorComment",
559
- fix: isLineComment$1(comment) ? lineCommentRuleFixer : blockCommentRuleFixer
560
- });
561
- }
562
- } };
563
- }
564
- });
565
- var prefer_ts_expect_error_default = rule$4;
566
-
567
- //#endregion
568
- //#region src/rules/require-async-with-await.ts
569
- const RULE_NAME$3 = "require-async-with-await";
570
- const rule$3 = createEslintRule({
571
- name: RULE_NAME$3,
572
- meta: {
573
- type: "problem",
574
- docs: { description: "Require using async keyword with await." },
575
- fixable: "code",
576
- schema: [],
577
- messages: { requireAsyncWithAwait: "Expect using async keyword with await." }
578
- },
579
- defaultOptions: [],
580
- create: (context) => {
581
- const functionNodeStack = [];
582
- function setupNode(node) {
583
- functionNodeStack.push(node);
584
- }
585
- function clearNode() {
586
- functionNodeStack.pop();
587
- }
588
- return {
589
- "FunctionExpression": setupNode,
590
- "FunctionExpression:exit": clearNode,
591
- "FunctionDeclaration": setupNode,
592
- "FunctionDeclaration:exit": clearNode,
593
- "ArrowFunctionExpression": setupNode,
594
- "ArrowFunctionExpression:exit": clearNode,
595
- AwaitExpression() {
596
- const node = functionNodeStack[functionNodeStack.length - 1];
597
- if (!node || node.async) return;
598
- let fixRange;
599
- if (node.type === TSESTree.AST_NODE_TYPES.ArrowFunctionExpression) fixRange = node.range;
600
- if (node.type === TSESTree.AST_NODE_TYPES.FunctionDeclaration || node.type === TSESTree.AST_NODE_TYPES.FunctionExpression) if (node.parent.type === TSESTree.AST_NODE_TYPES.Property || node.parent.type === TSESTree.AST_NODE_TYPES.MethodDefinition) {
601
- if (node.parent.kind === "method" || node.parent.kind === "init") fixRange = node.parent.key.range;
602
- } else fixRange = node.range;
603
- if (fixRange) context.report({
604
- node,
605
- messageId: "requireAsyncWithAwait",
606
- fix: (fixer) => fixer.insertTextBeforeRange(fixRange, "async ")
607
- });
608
- }
609
- };
610
- }
611
- });
612
- var require_async_with_await_default = rule$3;
613
-
614
- //#endregion
615
- //#region src/utils/sort-imports.ts
616
- const NEWLINE = /(\r?\n)/;
617
- const hasNewline = (text) => NEWLINE.test(text);
618
- function guessNewline(sourceCode) {
619
- const match = NEWLINE.exec(sourceCode.text);
620
- return match == null ? "\n" : match[0];
621
- }
622
- const withCode = (token, sourceCode) => ({
623
- ...token,
624
- code: sourceCode.getText(token)
625
- });
626
- function parseWhitespace(whitespace) {
627
- const allItems = whitespace.split(NEWLINE);
628
- return (allItems.length >= 5 ? [...allItems.slice(0, 2), ...allItems.slice(-1)] : allItems).map((spacesOrNewline, index) => index % 2 === 0 ? {
629
- type: "Spaces",
630
- code: spacesOrNewline
631
- } : {
632
- type: "Newline",
633
- code: spacesOrNewline
634
- }).filter((token) => token.code !== "");
635
- }
636
- const naturalSort = ("default" in natsort ? natsort.default : natsort)();
637
- function compare(path1, path2) {
638
- const path1Depth = path1.split("-").filter((p) => p === "__").length;
639
- const path2Depth = path2.split("-").filter((p) => p === "__").length;
640
- const path1IsDot = path1 === "_-,";
641
- const path2IsDot = path2 === "_-,";
642
- if (path1IsDot && !path2IsDot) return 1;
643
- if (path2IsDot && !path1IsDot) return -1;
644
- return path1Depth === path2Depth ? naturalSort(path1, path2) : path2Depth - path1Depth;
645
- }
646
- const isIdentifier = (node) => node.type === "Identifier";
647
- const isKeyword = (node) => node.type === "Keyword";
648
- const isPunctuator = (node, value) => node.type === "Punctuator" && typeof node.value === "string" && node.value === value;
649
- const isBlockComment = (node) => node.type === "Block";
650
- const isLineComment = (node) => node.type === "Line";
651
- const isSpaces = (node) => node.type === "Spaces";
652
- const isNewline = (node) => node.type === "Newline";
653
- const getImportExportKind = (node) => node.importKind ?? node.exportKind ?? "value";
654
- function getSource(node) {
655
- const source = String(node.source.value);
656
- return {
657
- source: source.replace(/^[./]*\.$/, "$&/").replace(/^[./]*\/$/, "$&,").replace(/[./_-]/g, (char) => {
658
- switch (char) {
659
- case ".": return "_";
660
- case "/": return "-";
661
- case "_": return ".";
662
- case "-": return "/";
663
- default: throw new Error(`Unknown source substitution character: ${char}`);
664
- }
665
- }),
666
- originalSource: source,
667
- kind: getImportExportKind(node)
668
- };
669
- }
670
- function findLastIndex(array, fn) {
671
- for (let index = array.length - 1; index >= 0; index--) if (fn(array[index], index, array)) return index;
672
- return -1;
673
- }
674
- const flatMap = (array, fn) => array.flatMap((item, index) => fn(item, index));
675
- function getAllTokens(node, sourceCode) {
676
- const tokens = sourceCode.getTokens(node);
677
- const lastTokenIndex = tokens.length - 1;
678
- return flatMap(tokens, (token, tokenIndex) => {
679
- const newToken = withCode(token, sourceCode);
680
- if (tokenIndex === lastTokenIndex) return [newToken];
681
- const comments = sourceCode.getCommentsAfter(token);
682
- const last = comments.length > 0 ? comments[comments.length - 1] : token;
683
- const nextToken = tokens[tokenIndex + 1];
684
- return [
685
- newToken,
686
- ...flatMap(comments, (comment, commentIndex) => {
687
- const previous = commentIndex === 0 ? token : comments[commentIndex - 1];
688
- return [...parseWhitespace(sourceCode.text.slice(previous.range[1], comment.range[0])), withCode(comment, sourceCode)];
689
- }),
690
- ...parseWhitespace(sourceCode.text.slice(last.range[1], nextToken.range[0]))
691
- ];
692
- });
693
- }
694
- const printTokens = (tokens) => tokens.map((token) => token.code).join("");
695
- const removeBlankLines = (whitespace) => printTokens(parseWhitespace(whitespace));
696
- function printCommentsBefore(node, comments, sourceCode) {
697
- const lastIndex = comments.length - 1;
698
- return comments.map((comment, index) => {
699
- const next = index === lastIndex ? node : comments[index + 1];
700
- return sourceCode.getText(comment) + removeBlankLines(sourceCode.text.slice(comment.range[1], next.range[0]));
701
- }).join("");
702
- }
703
- const printCommentsAfter = (node, comments, sourceCode) => comments.map((comment, index) => {
704
- const previous = index === 0 ? node : comments[index - 1];
705
- return removeBlankLines(sourceCode.text.slice(previous.range[1], comment.range[0])) + sourceCode.getText(comment);
706
- }).join("");
707
- function getIndentationAt(index, sourceCode) {
708
- const lines = sourceCode.text.slice(0, index).split(NEWLINE);
709
- const linePrefix = lines[lines.length - 1];
710
- return /^\s*$/u.test(linePrefix) ? linePrefix : "";
711
- }
712
- function getTrailingSpacesAt(index, sourceCode) {
713
- const { text } = sourceCode;
714
- let end = index;
715
- while (end < text.length) {
716
- const char = text[end];
717
- if (char === " " || char === " ") {
718
- end++;
719
- continue;
720
- }
721
- break;
722
- }
723
- return text.slice(index, end);
724
- }
725
- const sortImportExportItems = (items) => [...items].sort((itemA, itemB) => itemA.isSideEffectImport && itemB.isSideEffectImport ? itemA.index - itemB.index : itemA.isSideEffectImport ? -1 : itemB.isSideEffectImport ? 1 : compare(itemA.source.source, itemB.source.source) || compare(itemA.source.originalSource, itemB.source.originalSource) || compare(itemA.source.kind, itemB.source.kind) || itemA.index - itemB.index);
726
- const getSpecifierName = (node) => node.type === "Identifier" ? node.name : node.value;
727
- const getExternalName = (node) => getSpecifierName("imported" in node ? node.imported : node.exported);
728
- const getLocalName = (node) => getSpecifierName(node.local);
729
- function compareImportExportKind(kindA, kindB) {
730
- if (kindA === kindB) return 0;
731
- return kindA === "type" ? -1 : 1;
732
- }
733
- const sortSpecifierItems = (items) => [...items].sort((itemA, itemB) => compareImportExportKind(getImportExportKind(itemA.node), getImportExportKind(itemB.node)) || compare(getExternalName(itemA.node), getExternalName(itemB.node)) || compare(getLocalName(itemA.node), getLocalName(itemB.node)) || itemA.index - itemB.index);
734
- function extractChunks(parentNode, isPartOfChunk$1) {
735
- const chunks = [];
736
- let chunk = [];
737
- let lastNode;
738
- for (const node of parentNode.body) {
739
- const result = isPartOfChunk$1(node, lastNode);
740
- switch (result) {
741
- case "PartOfChunk":
742
- chunk.push(node);
743
- break;
744
- case "PartOfNewChunk":
745
- if (chunk.length > 0) chunks.push(chunk);
746
- chunk = [node];
747
- break;
748
- case "NotPartOfChunk":
749
- if (chunk.length > 0) {
750
- chunks.push(chunk);
751
- chunk = [];
752
- }
753
- break;
754
- default: {
755
- const _never = result;
756
- throw new Error(`Unknown chunk result: ${String(_never)}`);
757
- }
758
- }
759
- lastNode = node;
760
- }
761
- if (chunk.length > 0) chunks.push(chunk);
762
- return chunks;
763
- }
764
- function maybeReportSorting(context, sorted, start, end) {
765
- const sourceCode = context.sourceCode;
766
- if (sourceCode.getText().slice(start, end) !== sorted) context.report({
767
- messageId: "sort",
768
- loc: {
769
- start: sourceCode.getLocFromIndex(start),
770
- end: sourceCode.getLocFromIndex(end)
771
- },
772
- fix: (fixer) => fixer.replaceTextRange([start, end], sorted)
773
- });
774
- }
775
- function printSortedItems(sortedItems, originalItems, sourceCode) {
776
- const newline = guessNewline(sourceCode);
777
- const sorted = sortedItems.map((groups) => groups.map((groupItems) => groupItems.map((item) => item.code).join(newline)).join(newline)).join(newline + newline);
778
- const flattened = flatMap(sortedItems, (groups) => flatMap(groups, (g) => g));
779
- const lastSortedItem = flattened[flattened.length - 1];
780
- const lastOriginalItem = originalItems[originalItems.length - 1];
781
- const nextToken = lastSortedItem.needsNewline ? sourceCode.getTokenAfter(lastOriginalItem.node, {
782
- includeComments: true,
783
- filter: (token) => token.type !== "Line" && (token.type !== "Block" || token.loc.end.line !== lastOriginalItem.node.loc.end.line)
784
- }) : void 0;
785
- return sorted + (nextToken != null && nextToken.loc.start.line === lastOriginalItem.node.loc.end.line ? newline : "");
786
- }
787
- const makeEmptyItem = () => ({
788
- state: "before",
789
- before: [],
790
- after: [],
791
- specifier: [],
792
- hadComma: false
793
- });
794
- function getSpecifierItems(tokens) {
795
- const result = {
796
- before: [],
797
- after: [],
798
- items: []
799
- };
800
- let current = makeEmptyItem();
801
- for (const token of tokens) switch (current.state) {
802
- case "before":
803
- switch (token.type) {
804
- case "Newline":
805
- current.before.push(token);
806
- if (result.before.length === 0 && result.items.length === 0) {
807
- result.before = current.before;
808
- current = makeEmptyItem();
809
- }
810
- break;
811
- case "Spaces":
812
- case "Block":
813
- case "Line":
814
- current.before.push(token);
815
- break;
816
- default:
817
- if (result.before.length === 0 && result.items.length === 0) {
818
- result.before = current.before;
819
- current = makeEmptyItem();
820
- }
821
- current.state = "specifier";
822
- current.specifier.push(token);
823
- }
824
- break;
825
- case "specifier":
826
- switch (token.type) {
827
- case "Punctuator":
828
- if (isPunctuator(token, ",")) {
829
- current.hadComma = true;
830
- current.state = "after";
831
- } else current.specifier.push(token);
832
- break;
833
- default: current.specifier.push(token);
834
- }
835
- break;
836
- case "after":
837
- switch (token.type) {
838
- case "Newline":
839
- current.after.push(token);
840
- result.items.push(current);
841
- current = makeEmptyItem();
842
- break;
843
- case "Spaces":
844
- case "Line":
845
- current.after.push(token);
846
- break;
847
- case "Block":
848
- if (hasNewline(token.code)) {
849
- result.items.push(current);
850
- current = makeEmptyItem();
851
- current.before.push(token);
852
- } else current.after.push(token);
853
- break;
854
- default:
855
- result.items.push(current);
856
- current = makeEmptyItem();
857
- current.state = "specifier";
858
- current.specifier.push(token);
859
- }
860
- break;
861
- default: {
862
- const _never = current.state;
863
- throw new Error(`Unknown state: ${String(_never)}`);
864
- }
865
- }
866
- switch (current.state) {
867
- case "before":
868
- result.after = current.before;
869
- break;
870
- case "specifier": {
871
- const lastIdentifierIndex = findLastIndex(current.specifier, (t) => isIdentifier(t) || isKeyword(t));
872
- const specifier = current.specifier.slice(0, lastIdentifierIndex + 1);
873
- const after = current.specifier.slice(lastIdentifierIndex + 1);
874
- const newlineIndexRaw = after.findIndex((t) => isNewline(t));
875
- const newlineIndex = newlineIndexRaw === -1 ? -1 : newlineIndexRaw + 1;
876
- const multilineBlockCommentIndex = after.findIndex((t) => isBlockComment(t) && hasNewline(t.code));
877
- const sliceIndex = newlineIndex >= 0 && multilineBlockCommentIndex !== -1 ? Math.min(newlineIndex, multilineBlockCommentIndex) : newlineIndex >= 0 ? newlineIndex : multilineBlockCommentIndex === -1 ? endsWithSpaces(after) ? after.length - 1 : -1 : multilineBlockCommentIndex;
878
- current.specifier = specifier;
879
- current.after = sliceIndex === -1 ? after : after.slice(0, sliceIndex);
880
- result.items.push(current);
881
- result.after = sliceIndex === -1 ? [] : after.slice(sliceIndex);
882
- break;
883
- }
884
- case "after":
885
- if (endsWithSpaces(current.after)) {
886
- const last = current.after.pop();
887
- if (last) result.after = [last];
888
- }
889
- result.items.push(current);
890
- break;
891
- default: {
892
- const _never = current.state;
893
- throw new Error(`Unknown state: ${String(_never)}`);
894
- }
895
- }
896
- return {
897
- before: result.before,
898
- after: result.after,
899
- items: result.items.map((item) => ({
900
- before: item.before,
901
- after: item.after,
902
- specifier: item.specifier,
903
- hadComma: item.hadComma
904
- }))
905
- };
906
- }
907
- function needsStartingNewline(tokens) {
908
- const before = tokens.filter((token) => !isSpaces(token));
909
- if (before.length === 0) return false;
910
- const firstToken = before[0];
911
- return isLineComment(firstToken) || isBlockComment(firstToken) && !hasNewline(firstToken.code);
912
- }
913
- function endsWithSpaces(tokens) {
914
- const last = tokens.length > 0 ? tokens[tokens.length - 1] : void 0;
915
- return last == null ? false : isSpaces(last);
916
- }
917
- function printWithSortedSpecifiers(node, sourceCode, getSpecifiers$2) {
918
- const allTokens = getAllTokens(node, sourceCode);
919
- const openBraceIndex = allTokens.findIndex((token) => isPunctuator(token, "{"));
920
- const closeBraceIndex = allTokens.findIndex((token) => isPunctuator(token, "}"));
921
- const specifiers = getSpecifiers$2(node);
922
- if (openBraceIndex === -1 || closeBraceIndex === -1 || specifiers.length <= 1) return printTokens(allTokens);
923
- const itemsResult = getSpecifierItems(allTokens.slice(openBraceIndex + 1, closeBraceIndex));
924
- const sortedItems = sortSpecifierItems(itemsResult.items.map((originalItem, index) => ({
925
- ...originalItem,
926
- node: specifiers[index],
927
- index
928
- })));
929
- const newline = guessNewline(sourceCode);
930
- const hasTrailingComma = (() => {
931
- for (let index = closeBraceIndex - 1; index > openBraceIndex; index--) {
932
- const token = allTokens[index];
933
- if (token.type === "Spaces" || token.type === "Newline" || token.type === "Block" || token.type === "Line") continue;
934
- return isPunctuator(token, ",");
935
- }
936
- return false;
937
- })();
938
- const lastIndex = sortedItems.length - 1;
939
- const sorted = flatMap(sortedItems, (item, index) => {
940
- const previous = index === 0 ? void 0 : sortedItems[index - 1];
941
- const maybeNewline$1 = previous != null && needsStartingNewline(item.before) && (previous.after.length <= 0 || !isNewline(previous.after[previous.after.length - 1])) ? [{
942
- type: "Newline",
943
- code: newline
944
- }] : [];
945
- if (index < lastIndex || hasTrailingComma) return [
946
- ...maybeNewline$1,
947
- ...item.before,
948
- ...item.specifier,
949
- {
950
- type: "Comma",
951
- code: ","
952
- },
953
- ...item.after
954
- ];
955
- const nonBlankIndex = item.after.findIndex((token) => !isNewline(token) && !isSpaces(token));
956
- const after = item.hadComma ? nonBlankIndex === -1 ? [] : item.after.slice(nonBlankIndex) : item.after;
957
- return [
958
- ...maybeNewline$1,
959
- ...item.before,
960
- ...item.specifier,
961
- ...after
962
- ];
963
- });
964
- const maybeNewline = needsStartingNewline(itemsResult.after) && !isNewline(sorted[sorted.length - 1]) ? [{
965
- type: "Newline",
966
- code: newline
967
- }] : [];
968
- return printTokens([
969
- ...allTokens.slice(0, openBraceIndex + 1),
970
- ...itemsResult.before,
971
- ...sorted,
972
- ...maybeNewline,
973
- ...itemsResult.after,
974
- ...allTokens.slice(closeBraceIndex)
975
- ]);
976
- }
977
- function handleLastSemicolon(chunk, sourceCode) {
978
- const lastIndex = chunk.length - 1;
979
- const lastNode = chunk[lastIndex];
980
- const tokens = sourceCode.getLastTokens(lastNode, { count: 2 });
981
- if (tokens.length < 2) return [...chunk];
982
- const [nextToLastToken, lastToken] = tokens;
983
- if (!(lastToken.type === "Punctuator" && lastToken.value === ";")) return [...chunk];
984
- if (nextToLastToken.loc.end.line === lastToken.loc.start.line || sourceCode.getTokenAfter(lastToken) == null) return [...chunk];
985
- const newLastNode = {
986
- ...lastNode,
987
- range: [lastNode.range[0], nextToLastToken.range[1]],
988
- loc: {
989
- start: lastNode.loc.start,
990
- end: nextToLastToken.loc.end
991
- }
992
- };
993
- return [...chunk.slice(0, lastIndex), newLastNode];
994
- }
995
- function getImportExportItems(passedChunk, sourceCode, isSideEffectImport$1, getSpecifiers$2) {
996
- const chunk = handleLastSemicolon(passedChunk, sourceCode);
997
- return chunk.map((node, nodeIndex) => {
998
- const lastLine = nodeIndex === 0 ? node.loc.start.line - 1 : chunk[nodeIndex - 1].loc.end.line;
999
- const commentsBefore = sourceCode.getCommentsBefore(node).filter((comment) => comment.loc.start.line <= node.loc.start.line && comment.loc.end.line > lastLine && (nodeIndex > 0 || comment.loc.start.line > lastLine));
1000
- const commentsAfter = sourceCode.getCommentsAfter(node).filter((comment) => comment.loc.end.line === node.loc.end.line);
1001
- const before = printCommentsBefore(node, commentsBefore, sourceCode);
1002
- const after = printCommentsAfter(node, commentsAfter, sourceCode);
1003
- const indentation = getIndentationAt((commentsBefore.length > 0 ? commentsBefore[0] : node).range[0], sourceCode);
1004
- const trailingSpaces = getTrailingSpacesAt((commentsAfter.length > 0 ? commentsAfter[commentsAfter.length - 1] : node).range[1], sourceCode);
1005
- const code = indentation + before + printWithSortedSpecifiers(node, sourceCode, getSpecifiers$2) + after + trailingSpaces;
1006
- const all = [
1007
- ...commentsBefore,
1008
- node,
1009
- ...commentsAfter
1010
- ];
1011
- const [start] = all[0].range;
1012
- const [, end] = all[all.length - 1].range;
1013
- const source = getSource(node);
1014
- const lastAfter = commentsAfter.length > 0 ? commentsAfter[commentsAfter.length - 1] : void 0;
1015
- return {
1016
- node,
1017
- code,
1018
- start: start - indentation.length,
1019
- end: end + trailingSpaces.length,
1020
- isSideEffectImport: isSideEffectImport$1(node, sourceCode),
1021
- source,
1022
- index: nodeIndex,
1023
- needsNewline: lastAfter?.type === "Line"
1024
- };
1025
- });
1026
- }
1027
-
1028
- //#endregion
1029
- //#region src/rules/sort-exports.ts
1030
- const RULE_NAME$2 = "sort-exports";
1031
- function isParentWithBody$1(node) {
1032
- if (!node) return false;
1033
- if (!("body" in node)) return false;
1034
- const maybe = node;
1035
- return Array.isArray(maybe.body);
1036
- }
1037
- const isExportFrom = (node) => node.type === "ExportNamedDeclaration" && node.source != null || node.type === "ExportAllDeclaration" && node.source != null;
1038
- function isPartOfChunk(node, lastNode, sourceCode) {
1039
- if (!isExportFrom(node)) return "NotPartOfChunk";
1040
- return sourceCode.getCommentsBefore(node).some((comment) => (lastNode == null || comment.loc.start.line > lastNode.loc.end.line) && comment.loc.end.line < node.loc.start.line) ? "PartOfNewChunk" : "PartOfChunk";
1041
- }
1042
- const getSpecifiers$1 = (exportNode) => exportNode.type === "ExportNamedDeclaration" ? exportNode.specifiers : [];
1043
- function maybeReportChunkSorting$1(chunk, context) {
1044
- const sourceCode = context.sourceCode;
1045
- const items = getImportExportItems(chunk.filter(isExportFrom), sourceCode, () => false, getSpecifiers$1);
1046
- const sorted = printSortedItems([[sortImportExportItems(items)]], items, sourceCode);
1047
- const start = items[0].start;
1048
- const end = items[items.length - 1].end;
1049
- maybeReportSorting(context, sorted, start, end);
1050
- }
1051
- function maybeReportExportSpecifierSorting(node, context) {
1052
- const sorted = printWithSortedSpecifiers(node, context.sourceCode, (n) => n.specifiers);
1053
- const [start, end] = node.range;
1054
- maybeReportSorting(context, sorted, start, end);
1055
- }
1056
- const rule$2 = createEslintRule({
1057
- name: RULE_NAME$2,
1058
- meta: {
1059
- type: "layout",
1060
- docs: {
1061
- description: "Sort export declarations.",
1062
- url: "https://github.com/lydell/eslint-plugin-simple-import-sort#sort-order"
1063
- },
1064
- fixable: "code",
1065
- schema: [],
1066
- messages: { sort: "Run autofix to sort these exports!" }
1067
- },
1068
- defaultOptions: [],
1069
- create: (context) => {
1070
- const parents = /* @__PURE__ */ new Set();
1071
- function addParent(node) {
1072
- if (isExportFrom(node) && isParentWithBody$1(node.parent)) parents.add(node.parent);
1073
- }
1074
- return {
1075
- ExportNamedDeclaration(node) {
1076
- if (node.source == null && node.declaration == null) maybeReportExportSpecifierSorting(node, context);
1077
- else addParent(node);
1078
- },
1079
- ExportAllDeclaration(node) {
1080
- addParent(node);
1081
- },
1082
- "Program:exit"() {
1083
- const sourceCode = context.sourceCode;
1084
- for (const parent of parents) for (const chunk of extractChunks(parent, (node, lastNode) => isPartOfChunk(node, lastNode, sourceCode))) maybeReportChunkSorting$1(chunk, context);
1085
- parents.clear();
1086
- }
1087
- };
1088
- }
1089
- });
1090
- var sort_exports_default = rule$2;
1091
-
1092
- //#endregion
1093
- //#region src/rules/sort-imports.ts
1094
- const RULE_NAME$1 = "sort-imports";
1095
- function isParentWithBody(node) {
1096
- if (!node) return false;
1097
- if (!("body" in node)) return false;
1098
- const maybe = node;
1099
- return Array.isArray(maybe.body);
1100
- }
1101
- const defaultGroups = [
1102
- ["^node:"],
1103
- ["^@?\\w"],
1104
- ["^"],
1105
- ["^\\."],
1106
- ["^\\u0000"]
1107
- ];
1108
- const isImportSpecifier = (node) => node.type === "ImportSpecifier";
1109
- const getSpecifiers = (importNode) => importNode.specifiers.filter(isImportSpecifier);
1110
- const isImport = (node) => node.type === "ImportDeclaration";
1111
- function isSideEffectImport(importNode, sourceCode) {
1112
- const token = sourceCode.getFirstToken(importNode, { skip: 1 });
1113
- const startsWithBrace = token != null && isPunctuator(token, "{");
1114
- return importNode.specifiers.length === 0 && (!importNode.importKind || importNode.importKind === "value") && !startsWithBrace;
1115
- }
1116
- const rule$1 = createEslintRule({
1117
- name: RULE_NAME$1,
1118
- meta: {
1119
- type: "layout",
1120
- docs: {
1121
- description: "Sort import declarations.",
1122
- url: "https://github.com/lydell/eslint-plugin-simple-import-sort#sort-order"
1123
- },
1124
- fixable: "code",
1125
- schema: [{
1126
- type: "object",
1127
- properties: { groups: {
1128
- type: "array",
1129
- items: {
1130
- type: "array",
1131
- items: { type: "string" }
1132
- }
1133
- } },
1134
- additionalProperties: false
1135
- }],
1136
- messages: { sort: "Run autofix to sort these imports!" }
1137
- },
1138
- defaultOptions: [{ groups: defaultGroups }],
1139
- create: (context) => {
1140
- const outerGroups = (context.options[0]?.groups ?? defaultGroups).map((groups) => groups.map((item) => new RegExp(item, "u")));
1141
- const parents = /* @__PURE__ */ new Set();
1142
- return {
1143
- ImportDeclaration(node) {
1144
- if (isParentWithBody(node.parent)) parents.add(node.parent);
1145
- },
1146
- "Program:exit"() {
1147
- const sourceCode = context.sourceCode;
1148
- for (const parent of parents) for (const chunk of extractChunks(parent, (node, lastNode) => {
1149
- if (!isImport(node)) return "NotPartOfChunk";
1150
- return lastNode != null && isImport(lastNode) && lastNode.loc.end.line === node.loc.start.line ? "PartOfNewChunk" : "PartOfChunk";
1151
- })) maybeReportChunkSorting(chunk, context, outerGroups, sourceCode);
1152
- parents.clear();
1153
- }
1154
- };
1155
- }
1156
- });
1157
- var sort_imports_default = rule$1;
1158
- function maybeReportChunkSorting(chunk, context, outerGroups, sourceCode) {
1159
- const items = getImportExportItems(chunk.filter(isImport), sourceCode, isSideEffectImport, getSpecifiers);
1160
- const sorted = printSortedItems(makeSortedItems(items, outerGroups), items, sourceCode);
1161
- const start = items[0].start;
1162
- const end = items[items.length - 1].end;
1163
- maybeReportSorting(context, sorted, start, end);
1164
- }
1165
- function makeSortedItems(items, outerGroups) {
1166
- const itemGroups = outerGroups.map((groups) => groups.map((regex) => ({
1167
- regex,
1168
- items: []
1169
- })));
1170
- const rest = [];
1171
- for (const item of items) {
1172
- const { originalSource } = item.source;
1173
- const source = item.isSideEffectImport ? `\0${originalSource}` : item.source.kind === "value" ? originalSource : `${originalSource}\0`;
1174
- let matchedGroup;
1175
- let longestMatchLength = -1;
1176
- for (const groups of itemGroups) for (const group of groups) {
1177
- const match = group.regex.exec(source);
1178
- if (match != null && match[0].length > longestMatchLength) {
1179
- matchedGroup = group;
1180
- longestMatchLength = match[0].length;
1181
- }
1182
- }
1183
- if (matchedGroup == null) rest.push(item);
1184
- else matchedGroup.items.push(item);
1185
- }
1186
- return [...itemGroups, [{
1187
- regex: /^/,
1188
- items: rest
1189
- }]].map((groups) => groups.filter((group) => group.items.length > 0)).filter((groups) => groups.length > 0).map((groups) => groups.map((group) => sortImportExportItems(group.items)));
1190
- }
1191
-
1192
- //#endregion
1193
- //#region src/rules/vue-root-element-sort-attributes.ts
1194
- const RULE_NAME = "vue-root-element-sort-attributes";
1195
- const defaultOptions = { script: ["setup", "lang"] };
1196
- const rule = createEslintRule({
1197
- name: RULE_NAME,
1198
- meta: {
1199
- type: "layout",
1200
- docs: { description: "Sort attributes of root <script>, <template>, and <style> elements in Vue files." },
1201
- fixable: "code",
1202
- schema: [{
1203
- type: "object",
1204
- properties: { script: {
1205
- type: "array",
1206
- items: { type: "string" }
1207
- } },
1208
- additionalProperties: true
1209
- }],
1210
- messages: { wrongOrder: "Attributes of root element should be sorted in a specific order." }
1211
- },
1212
- defaultOptions: [defaultOptions],
1213
- create(context, [options]) {
1214
- const order = {
1215
- ...options,
1216
- script: options.script ?? defaultOptions.script
1217
- };
1218
- const sourceCode = context.sourceCode;
1219
- const documentFragment = sourceCode.parserServices.getDocumentFragment?.();
1220
- function getTopLevelHTMLElements() {
1221
- if (documentFragment) return documentFragment.children.filter((n) => n.type === "VElement");
1222
- return [];
1223
- }
1224
- return { Program: (_node) => {
1225
- const topLevelElements = getTopLevelHTMLElements();
1226
- for (const element of topLevelElements) {
1227
- if (!(element.name in order)) continue;
1228
- const expectedOrder = order[element.name];
1229
- const attributesToCheck = [];
1230
- let reprintAttributes = false;
1231
- for (const attribute of element.startTag.attributes) {
1232
- if (attribute.key.type !== "VIdentifier" || attribute.directive) continue;
1233
- if (expectedOrder.includes(attribute.key.name)) attributesToCheck.push(attribute);
1234
- }
1235
- const currentOrder = attributesToCheck.map((attr) => attr.key.name);
1236
- const expectedFilteredOrder = expectedOrder.filter((name) => currentOrder.includes(name));
1237
- if (JSON.stringify(currentOrder) !== JSON.stringify(expectedFilteredOrder)) reprintAttributes = true;
1238
- if (reprintAttributes) context.report({
1239
- node: element.startTag,
1240
- messageId: "wrongOrder",
1241
- *fix(fixer) {
1242
- const sortedAttributes = [...attributesToCheck].sort((a, b) => expectedOrder.indexOf(a.key.name) - expectedOrder.indexOf(b.key.name));
1243
- for (const [i, originalAttr] of attributesToCheck.entries()) {
1244
- const sortedAttr = sortedAttributes[i];
1245
- if (originalAttr.key.name !== sortedAttr.key.name) yield fixer.replaceText(originalAttr, sourceCode.getText(sortedAttr));
1246
- }
1247
- }
1248
- });
1249
- }
1250
- } };
1251
- }
1252
- });
1253
- var vue_root_element_sort_attributes_default = rule;
1254
-
1255
- //#endregion
1256
15
  //#region src/index.ts
1257
16
  var src_default = { rules: {
1258
17
  "function-style": function_style_default,