@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
@@ -0,0 +1,8 @@
1
+ import { ESLintUtils } from "@typescript-eslint/utils";
2
+
3
+ //#region src/rules/require-async-with-await.d.ts
4
+ type MessageIds = "requireAsyncWithAwait";
5
+ type Options = [];
6
+ declare const rule: ESLintUtils.RuleModule<MessageIds, Options>;
7
+ //#endregion
8
+ export { rule };
@@ -0,0 +1,51 @@
1
+ import { createEslintRule } from "../utils/index.mjs";
2
+ import { TSESTree } from "@typescript-eslint/types";
3
+
4
+ //#region src/rules/require-async-with-await.ts
5
+ const RULE_NAME = "require-async-with-await";
6
+ const rule = createEslintRule({
7
+ name: RULE_NAME,
8
+ meta: {
9
+ type: "problem",
10
+ docs: { description: "Require using async keyword with await." },
11
+ fixable: "code",
12
+ schema: [],
13
+ messages: { requireAsyncWithAwait: "Expect using async keyword with await." }
14
+ },
15
+ defaultOptions: [],
16
+ create: (context) => {
17
+ const functionNodeStack = [];
18
+ function setupNode(node) {
19
+ functionNodeStack.push(node);
20
+ }
21
+ function clearNode() {
22
+ functionNodeStack.pop();
23
+ }
24
+ return {
25
+ "FunctionExpression": setupNode,
26
+ "FunctionExpression:exit": clearNode,
27
+ "FunctionDeclaration": setupNode,
28
+ "FunctionDeclaration:exit": clearNode,
29
+ "ArrowFunctionExpression": setupNode,
30
+ "ArrowFunctionExpression:exit": clearNode,
31
+ AwaitExpression() {
32
+ const node = functionNodeStack[functionNodeStack.length - 1];
33
+ if (!node || node.async) return;
34
+ let fixRange;
35
+ if (node.type === TSESTree.AST_NODE_TYPES.ArrowFunctionExpression) fixRange = node.range;
36
+ 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) {
37
+ if (node.parent.kind === "method" || node.parent.kind === "init") fixRange = node.parent.key.range;
38
+ } else fixRange = node.range;
39
+ if (fixRange) context.report({
40
+ node,
41
+ messageId: "requireAsyncWithAwait",
42
+ fix: (fixer) => fixer.insertTextBeforeRange(fixRange, "async ")
43
+ });
44
+ }
45
+ };
46
+ }
47
+ });
48
+ var require_async_with_await_default = rule;
49
+
50
+ //#endregion
51
+ export { require_async_with_await_default as default };
@@ -0,0 +1,8 @@
1
+ import { ESLintUtils } from "@typescript-eslint/utils";
2
+
3
+ //#region src/rules/sort-exports.d.ts
4
+ type MessageIds = "sort";
5
+ type Options = [];
6
+ declare const rule: ESLintUtils.RuleModule<MessageIds, Options>;
7
+ //#endregion
8
+ export { rule };
@@ -0,0 +1,68 @@
1
+ import { createEslintRule } from "../utils/index.mjs";
2
+ import { extractChunks, getImportExportItems, maybeReportSorting, printSortedItems, printWithSortedSpecifiers, sortImportExportItems } from "../utils/sort-imports.mjs";
3
+
4
+ //#region src/rules/sort-exports.ts
5
+ const RULE_NAME = "sort-exports";
6
+ function isParentWithBody(node) {
7
+ if (!node) return false;
8
+ if (!("body" in node)) return false;
9
+ const maybe = node;
10
+ return Array.isArray(maybe.body);
11
+ }
12
+ const isExportFrom = (node) => node.type === "ExportNamedDeclaration" && node.source != null || node.type === "ExportAllDeclaration" && node.source != null;
13
+ function isPartOfChunk(node, lastNode, sourceCode) {
14
+ if (!isExportFrom(node)) return "NotPartOfChunk";
15
+ 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";
16
+ }
17
+ const getSpecifiers = (exportNode) => exportNode.type === "ExportNamedDeclaration" ? exportNode.specifiers : [];
18
+ function maybeReportChunkSorting(chunk, context) {
19
+ const sourceCode = context.sourceCode;
20
+ const items = getImportExportItems(chunk.filter(isExportFrom), sourceCode, () => false, getSpecifiers);
21
+ const sorted = printSortedItems([[sortImportExportItems(items)]], items, sourceCode);
22
+ const start = items[0].start;
23
+ const end = items[items.length - 1].end;
24
+ maybeReportSorting(context, sorted, start, end);
25
+ }
26
+ function maybeReportExportSpecifierSorting(node, context) {
27
+ const sorted = printWithSortedSpecifiers(node, context.sourceCode, (n) => n.specifiers);
28
+ const [start, end] = node.range;
29
+ maybeReportSorting(context, sorted, start, end);
30
+ }
31
+ const rule = createEslintRule({
32
+ name: RULE_NAME,
33
+ meta: {
34
+ type: "layout",
35
+ docs: {
36
+ description: "Sort export declarations.",
37
+ url: "https://github.com/lydell/eslint-plugin-simple-import-sort#sort-order"
38
+ },
39
+ fixable: "code",
40
+ schema: [],
41
+ messages: { sort: "Run autofix to sort these exports!" }
42
+ },
43
+ defaultOptions: [],
44
+ create: (context) => {
45
+ const parents = /* @__PURE__ */ new Set();
46
+ function addParent(node) {
47
+ if (isExportFrom(node) && isParentWithBody(node.parent)) parents.add(node.parent);
48
+ }
49
+ return {
50
+ ExportNamedDeclaration(node) {
51
+ if (node.source == null && node.declaration == null) maybeReportExportSpecifierSorting(node, context);
52
+ else addParent(node);
53
+ },
54
+ ExportAllDeclaration(node) {
55
+ addParent(node);
56
+ },
57
+ "Program:exit"() {
58
+ const sourceCode = context.sourceCode;
59
+ for (const parent of parents) for (const chunk of extractChunks(parent, (node, lastNode) => isPartOfChunk(node, lastNode, sourceCode))) maybeReportChunkSorting(chunk, context);
60
+ parents.clear();
61
+ }
62
+ };
63
+ }
64
+ });
65
+ var sort_exports_default = rule;
66
+
67
+ //#endregion
68
+ export { sort_exports_default as default };
@@ -0,0 +1,10 @@
1
+ import { ESLintUtils } from "@typescript-eslint/utils";
2
+
3
+ //#region src/rules/sort-imports.d.ts
4
+ type MessageIds = "sort";
5
+ type Options = [{
6
+ groups?: string[][];
7
+ }];
8
+ declare const rule: ESLintUtils.RuleModule<MessageIds, Options>;
9
+ //#endregion
10
+ export { rule };
@@ -0,0 +1,104 @@
1
+ import { createEslintRule } from "../utils/index.mjs";
2
+ import { extractChunks, getImportExportItems, isPunctuator, maybeReportSorting, printSortedItems, sortImportExportItems } from "../utils/sort-imports.mjs";
3
+
4
+ //#region src/rules/sort-imports.ts
5
+ const RULE_NAME = "sort-imports";
6
+ function isParentWithBody(node) {
7
+ if (!node) return false;
8
+ if (!("body" in node)) return false;
9
+ const maybe = node;
10
+ return Array.isArray(maybe.body);
11
+ }
12
+ const defaultGroups = [
13
+ ["^node:"],
14
+ ["^@?\\w"],
15
+ ["^"],
16
+ ["^\\."],
17
+ ["^\\u0000"]
18
+ ];
19
+ const isImportSpecifier = (node) => node.type === "ImportSpecifier";
20
+ const getSpecifiers = (importNode) => importNode.specifiers.filter(isImportSpecifier);
21
+ const isImport = (node) => node.type === "ImportDeclaration";
22
+ function isSideEffectImport(importNode, sourceCode) {
23
+ const token = sourceCode.getFirstToken(importNode, { skip: 1 });
24
+ const startsWithBrace = token != null && isPunctuator(token, "{");
25
+ return importNode.specifiers.length === 0 && (!importNode.importKind || importNode.importKind === "value") && !startsWithBrace;
26
+ }
27
+ const rule = createEslintRule({
28
+ name: RULE_NAME,
29
+ meta: {
30
+ type: "layout",
31
+ docs: {
32
+ description: "Sort import declarations.",
33
+ url: "https://github.com/lydell/eslint-plugin-simple-import-sort#sort-order"
34
+ },
35
+ fixable: "code",
36
+ schema: [{
37
+ type: "object",
38
+ properties: { groups: {
39
+ type: "array",
40
+ items: {
41
+ type: "array",
42
+ items: { type: "string" }
43
+ }
44
+ } },
45
+ additionalProperties: false
46
+ }],
47
+ messages: { sort: "Run autofix to sort these imports!" }
48
+ },
49
+ defaultOptions: [{ groups: defaultGroups }],
50
+ create: (context) => {
51
+ const outerGroups = (context.options[0]?.groups ?? defaultGroups).map((groups) => groups.map((item) => new RegExp(item, "u")));
52
+ const parents = /* @__PURE__ */ new Set();
53
+ return {
54
+ ImportDeclaration(node) {
55
+ if (isParentWithBody(node.parent)) parents.add(node.parent);
56
+ },
57
+ "Program:exit"() {
58
+ const sourceCode = context.sourceCode;
59
+ for (const parent of parents) for (const chunk of extractChunks(parent, (node, lastNode) => {
60
+ if (!isImport(node)) return "NotPartOfChunk";
61
+ return lastNode != null && isImport(lastNode) && lastNode.loc.end.line === node.loc.start.line ? "PartOfNewChunk" : "PartOfChunk";
62
+ })) maybeReportChunkSorting(chunk, context, outerGroups, sourceCode);
63
+ parents.clear();
64
+ }
65
+ };
66
+ }
67
+ });
68
+ var sort_imports_default = rule;
69
+ function maybeReportChunkSorting(chunk, context, outerGroups, sourceCode) {
70
+ const items = getImportExportItems(chunk.filter(isImport), sourceCode, isSideEffectImport, getSpecifiers);
71
+ const sorted = printSortedItems(makeSortedItems(items, outerGroups), items, sourceCode);
72
+ const start = items[0].start;
73
+ const end = items[items.length - 1].end;
74
+ maybeReportSorting(context, sorted, start, end);
75
+ }
76
+ function makeSortedItems(items, outerGroups) {
77
+ const itemGroups = outerGroups.map((groups) => groups.map((regex) => ({
78
+ regex,
79
+ items: []
80
+ })));
81
+ const rest = [];
82
+ for (const item of items) {
83
+ const { originalSource } = item.source;
84
+ const source = item.isSideEffectImport ? `\0${originalSource}` : item.source.kind === "value" ? originalSource : `${originalSource}\0`;
85
+ let matchedGroup;
86
+ let longestMatchLength = -1;
87
+ for (const groups of itemGroups) for (const group of groups) {
88
+ const match = group.regex.exec(source);
89
+ if (match != null && match[0].length > longestMatchLength) {
90
+ matchedGroup = group;
91
+ longestMatchLength = match[0].length;
92
+ }
93
+ }
94
+ if (matchedGroup == null) rest.push(item);
95
+ else matchedGroup.items.push(item);
96
+ }
97
+ return [...itemGroups, [{
98
+ regex: /^/,
99
+ items: rest
100
+ }]].map((groups) => groups.filter((group) => group.items.length > 0)).filter((groups) => groups.length > 0).map((groups) => groups.map((group) => sortImportExportItems(group.items)));
101
+ }
102
+
103
+ //#endregion
104
+ export { sort_imports_default as default };
@@ -0,0 +1,11 @@
1
+ import { ESLintUtils } from "@typescript-eslint/utils";
2
+
3
+ //#region src/rules/vue-root-element-sort-attributes.d.ts
4
+ type MessageIds = "wrongOrder";
5
+ type Options = [{
6
+ script?: string[];
7
+ [otherElement: string]: string[] | undefined;
8
+ }];
9
+ declare const rule: ESLintUtils.RuleModule<MessageIds, Options>;
10
+ //#endregion
11
+ export { rule };
@@ -0,0 +1,66 @@
1
+ import { createEslintRule } from "../utils/index.mjs";
2
+
3
+ //#region src/rules/vue-root-element-sort-attributes.ts
4
+ const RULE_NAME = "vue-root-element-sort-attributes";
5
+ const defaultOptions = { script: ["setup", "lang"] };
6
+ const rule = createEslintRule({
7
+ name: RULE_NAME,
8
+ meta: {
9
+ type: "layout",
10
+ docs: { description: "Sort attributes of root <script>, <template>, and <style> elements in Vue files." },
11
+ fixable: "code",
12
+ schema: [{
13
+ type: "object",
14
+ properties: { script: {
15
+ type: "array",
16
+ items: { type: "string" }
17
+ } },
18
+ additionalProperties: true
19
+ }],
20
+ messages: { wrongOrder: "Attributes of root element should be sorted in a specific order." }
21
+ },
22
+ defaultOptions: [defaultOptions],
23
+ create(context, [options]) {
24
+ const order = {
25
+ ...options,
26
+ script: options.script ?? defaultOptions.script
27
+ };
28
+ const sourceCode = context.sourceCode;
29
+ const documentFragment = sourceCode.parserServices.getDocumentFragment?.();
30
+ function getTopLevelHTMLElements() {
31
+ if (documentFragment) return documentFragment.children.filter((n) => n.type === "VElement");
32
+ return [];
33
+ }
34
+ return { Program: (_node) => {
35
+ const topLevelElements = getTopLevelHTMLElements();
36
+ for (const element of topLevelElements) {
37
+ if (!(element.name in order)) continue;
38
+ const expectedOrder = order[element.name];
39
+ const attributesToCheck = [];
40
+ let reprintAttributes = false;
41
+ for (const attribute of element.startTag.attributes) {
42
+ if (attribute.key.type !== "VIdentifier" || attribute.directive) continue;
43
+ if (expectedOrder.includes(attribute.key.name)) attributesToCheck.push(attribute);
44
+ }
45
+ const currentOrder = attributesToCheck.map((attr) => attr.key.name);
46
+ const expectedFilteredOrder = expectedOrder.filter((name) => currentOrder.includes(name));
47
+ if (JSON.stringify(currentOrder) !== JSON.stringify(expectedFilteredOrder)) reprintAttributes = true;
48
+ if (reprintAttributes) context.report({
49
+ node: element.startTag,
50
+ messageId: "wrongOrder",
51
+ *fix(fixer) {
52
+ const sortedAttributes = [...attributesToCheck].sort((a, b) => expectedOrder.indexOf(a.key.name) - expectedOrder.indexOf(b.key.name));
53
+ for (const [i, originalAttr] of attributesToCheck.entries()) {
54
+ const sortedAttr = sortedAttributes[i];
55
+ if (originalAttr.key.name !== sortedAttr.key.name) yield fixer.replaceText(originalAttr, sourceCode.getText(sortedAttr));
56
+ }
57
+ }
58
+ });
59
+ }
60
+ } };
61
+ }
62
+ });
63
+ var vue_root_element_sort_attributes_default = rule;
64
+
65
+ //#endregion
66
+ export { vue_root_element_sort_attributes_default as default };
@@ -0,0 +1,19 @@
1
+ import { ESLintUtils } from "@typescript-eslint/utils";
2
+
3
+ //#region src/utils/index.ts
4
+ const createEslintRule = ESLintUtils.RuleCreator((ruleName) => ruleName);
5
+ function getSiblingNode(node, offset) {
6
+ if (!node) return;
7
+ const { parent } = node;
8
+ if (parent && "body" in parent) {
9
+ const { body } = parent;
10
+ if (!Array.isArray(body)) return;
11
+ const targetIndex = body.indexOf(node) + offset;
12
+ if (targetIndex >= 0 && targetIndex < body.length) return body[targetIndex];
13
+ }
14
+ }
15
+ const getPreviousNode = (node) => getSiblingNode(node, -1);
16
+ const getNextNode = (node) => getSiblingNode(node, 1);
17
+
18
+ //#endregion
19
+ export { createEslintRule, getNextNode, getPreviousNode };