@kikiutils/eslint-config 9.3.2 → 10.0.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.
package/README.md CHANGED
@@ -26,6 +26,14 @@ You can also use `yarn`, `npm`, or `bun`.
26
26
 
27
27
  ## Usage
28
28
 
29
+ TypeScript and Vue configs enable type-aware checks using TypeScript's Project Service.
30
+ Linted files must belong to a discoverable `tsconfig.json`; project references are supported.
31
+ The default setup does not require an additional `typescript.tsconfigPath` option.
32
+ JavaScript files retain syntax-only linting.
33
+ TypeScript tool configs (`*.config.ts`, `*.config.mts`, `*.config.cts`) are excluded from type-aware checks.
34
+ Base configs keep linting Markdown itself, but exclude its code blocks from all lint rules.
35
+ Style configs format CSS and SCSS; indented Sass (`.sass`) is not supported.
36
+
29
37
  ## License
30
38
 
31
39
  [MIT License](./LICENSE)
@@ -1 +1 @@
1
- {"version":3,"file":"consistent-parameter-layout.d.ts","names":[],"sources":["../../../src/_internals/rules/consistent-parameter-layout.ts"],"mappings":";qBAaa,2BAA2B,KAAK"}
1
+ {"version":3,"file":"consistent-parameter-layout.d.ts","names":[],"sources":["../../../src/_internals/rules/consistent-parameter-layout.ts"],"mappings":";qBAgBa,2BAA2B,KAAK"}
@@ -2,86 +2,133 @@ import { defineScriptAndTemplateVisitors } from "../utils.js";
2
2
  // src/_internals/rules/consistent-parameter-layout.ts
3
3
  const consistentParameterLayout = {
4
4
  create(context) {
5
- const isTestFile = /\.test\.[jt]sx?$/.test(context.filename);
6
- function checkParameterLayout(node, items, tokenStore, isTemplate) {
7
- const first = items[0];
8
- if (!first) return;
9
- const isSingleParameter = items.length === 1;
10
- const firstType = first.type;
11
- if (isSingleParameter && (firstType === "JSXElement" || firstType === "JSXFragment")) return;
12
- let openingParen;
13
- if (node.type === "CallExpression" || node.type === "NewExpression") {
14
- const call = node;
15
- openingParen = tokenStore.getTokenAfter(call.typeArguments ?? call.callee, (token) => token.type === "Punctuator" && token.value === "(");
16
- } else openingParen = tokenStore.getTokenBefore(first);
17
- if (!openingParen || openingParen.value !== "(") return;
18
- if (openingParen.range[0] < node.range[0]) return;
19
- const closingParen = node.type === "CallExpression" || node.type === "NewExpression" ? tokenStore.getLastToken(node) : tokenStore.getTokenAfter(items.at(-1), (token) => token.value === ")");
20
- const next = tokenStore.getTokenAfter(openingParen);
21
- if (isSingleParameter) {
22
- if (!closingParen || closingParen.value !== ")") return;
23
- let previous = tokenStore.getTokenBefore(closingParen);
24
- if (previous.value === ",") previous = tokenStore.getTokenBefore(previous);
25
- if (tokenStore.commentsExistBetween(openingParen, next) || tokenStore.commentsExistBetween(previous, closingParen)) return;
26
- const hasOpeningNewline = openingParen.loc.end.line !== next.loc.start.line;
27
- if (hasOpeningNewline === (tokenStore.getTokenBefore(closingParen).loc.end.line !== closingParen.loc.start.line)) return;
5
+ const compactTestCalls = context.options[0]?.compactTestCalls === true;
6
+ function createVisitor(tokenStore, isTemplate) {
7
+ function checkTestCallLayout(node) {
8
+ const items = node.arguments;
9
+ if (!items.length) return;
10
+ const openingParen = tokenStore.getTokenAfter(node.typeArguments ?? node.callee, (token) => token.type === "Punctuator" && token.value === "(");
11
+ const closingParen = tokenStore.getLastToken(node);
12
+ const previous = tokenStore.getTokenBefore(closingParen);
13
+ const gaps = [[
14
+ openingParen,
15
+ tokenStore.getTokenAfter(openingParen),
16
+ ""
17
+ ], [
18
+ previous,
19
+ closingParen,
20
+ ""
21
+ ]];
22
+ for (let index = 1; index < items.length; index++) {
23
+ const comma = tokenStore.getTokensBetween(items[index - 1], items[index]).find((token) => token.type === "Punctuator" && token.value === ",");
24
+ gaps.push([
25
+ tokenStore.getTokenBefore(comma),
26
+ comma,
27
+ ""
28
+ ], [
29
+ comma,
30
+ tokenStore.getTokenAfter(comma),
31
+ " "
32
+ ]);
33
+ }
34
+ if (previous.value === ",") gaps.push([
35
+ tokenStore.getTokenBefore(previous),
36
+ previous,
37
+ ""
38
+ ]);
39
+ if (gaps.some(([left, right]) => tokenStore.commentsExistBetween(left, right))) return;
40
+ const multilineGaps = gaps.filter(([left, right]) => left.loc.end.line !== right.loc.start.line);
41
+ if (!multilineGaps.length) return;
28
42
  context.report({
29
- fix: (fixer) => hasOpeningNewline ? fixer.insertTextBefore(closingParen, "\n") : fixer.insertTextAfter(openingParen, "\n"),
30
- messageId: "singleBoundary",
43
+ fix: (fixer) => multilineGaps.map(([left, right, text]) => fixer.replaceTextRange([left.range[1], right.range[0]], text)),
44
+ messageId: "compactTestCall",
31
45
  node
32
46
  });
33
- return;
34
47
  }
35
- if (!closingParen || openingParen.loc.start.line === closingParen.loc.end.line) return;
36
- if (isTemplate) {
37
- const newlineOffsets = [];
38
- if (openingParen.loc.end.line === next.loc.start.line) newlineOffsets.push(openingParen.range[1]);
39
- for (let index = 1; index < items.length; index++) {
40
- const item = items[index];
41
- const comma = tokenStore.getTokensBetween(items[index - 1], item).find((token) => token.value === ",");
42
- if (comma && comma.loc.end.line === tokenStore.getTokenAfter(comma).loc.start.line) newlineOffsets.push(comma.range[1]);
48
+ function checkParameterLayout(node, items) {
49
+ const first = items[0];
50
+ if (!first) return;
51
+ const isSingleParameter = items.length === 1;
52
+ const firstType = first.type;
53
+ if (isSingleParameter && (firstType === "JSXElement" || firstType === "JSXFragment")) return;
54
+ let openingParen;
55
+ if (node.type === "CallExpression" || node.type === "NewExpression") openingParen = tokenStore.getTokenAfter(node.typeArguments ?? node.callee, (token) => token.type === "Punctuator" && token.value === "(");
56
+ else openingParen = tokenStore.getTokenBefore(first);
57
+ if (!openingParen || openingParen.value !== "(") return;
58
+ if (openingParen.range[0] < node.range[0]) return;
59
+ const closingParen = node.type === "CallExpression" || node.type === "NewExpression" ? tokenStore.getLastToken(node) : tokenStore.getTokenAfter(items.at(-1), (token) => token.value === ")");
60
+ const next = tokenStore.getTokenAfter(openingParen);
61
+ if (isSingleParameter) {
62
+ if (!closingParen || closingParen.value !== ")") return;
63
+ let previous = tokenStore.getTokenBefore(closingParen);
64
+ if (previous.value === ",") previous = tokenStore.getTokenBefore(previous);
65
+ if (tokenStore.commentsExistBetween(openingParen, next) || tokenStore.commentsExistBetween(previous, closingParen)) return;
66
+ const hasOpeningNewline = openingParen.loc.end.line !== next.loc.start.line;
67
+ if (hasOpeningNewline === (tokenStore.getTokenBefore(closingParen).loc.end.line !== closingParen.loc.start.line)) return;
68
+ context.report({
69
+ fix: (fixer) => hasOpeningNewline ? fixer.insertTextBefore(closingParen, "\n") : fixer.insertTextAfter(openingParen, "\n"),
70
+ messageId: "singleBoundary",
71
+ node
72
+ });
73
+ return;
43
74
  }
44
- if (closingParen.value === ")" && tokenStore.getTokenBefore(closingParen).loc.end.line === closingParen.loc.start.line) newlineOffsets.push(closingParen.range[0]);
45
- if (newlineOffsets.length) context.report({
46
- fix: (fixer) => newlineOffsets.map((offset) => fixer.insertTextAfterRange([offset, offset], "\n")),
75
+ if (!closingParen || openingParen.loc.start.line === closingParen.loc.end.line) return;
76
+ if (isTemplate) {
77
+ const newlineOffsets = [];
78
+ if (openingParen.loc.end.line === next.loc.start.line) newlineOffsets.push(openingParen.range[1]);
79
+ for (let index = 1; index < items.length; index++) {
80
+ const item = items[index];
81
+ const comma = tokenStore.getTokensBetween(items[index - 1], item).find((token) => token.value === ",");
82
+ if (comma && comma.loc.end.line === tokenStore.getTokenAfter(comma).loc.start.line) newlineOffsets.push(comma.range[1]);
83
+ }
84
+ if (closingParen.value === ")" && tokenStore.getTokenBefore(closingParen).loc.end.line === closingParen.loc.start.line) newlineOffsets.push(closingParen.range[0]);
85
+ if (newlineOffsets.length) context.report({
86
+ fix: (fixer) => newlineOffsets.map((offset) => fixer.insertTextBeforeRange([offset, offset], "\n")),
87
+ messageId: "newline",
88
+ node: first
89
+ });
90
+ return;
91
+ }
92
+ if (openingParen.loc.end.line !== next.loc.start.line) return;
93
+ context.report({
94
+ fix: (fixer) => fixer.insertTextAfter(openingParen, "\n"),
47
95
  messageId: "newline",
48
96
  node: first
49
97
  });
50
- return;
51
98
  }
52
- if (openingParen.loc.end.line !== next.loc.start.line) return;
53
- context.report({
54
- fix: (fixer) => fixer.insertTextAfter(openingParen, "\n"),
55
- messageId: "newline",
56
- node: first
57
- });
58
- }
59
- function createVisitor(tokenStore, isTemplate) {
60
99
  return {
61
- ArrowFunctionExpression: (node) => checkParameterLayout(node, node.params, tokenStore, isTemplate),
100
+ ArrowFunctionExpression: (node) => checkParameterLayout(node, node.params),
62
101
  CallExpression: (node) => {
63
102
  const { callee } = node;
64
- if (isTestFile) {
103
+ if (compactTestCalls) {
65
104
  const target = callee.type === "MemberExpression" && !callee.computed && callee.property.type === "Identifier" && callee.property.name === "concurrent" ? callee.object : callee;
66
- if (target.type === "Identifier" && (target.name === "describe" || target.name === "it")) return;
105
+ if (target.type === "Identifier" && (target.name === "describe" || target.name === "it")) {
106
+ checkTestCallLayout(node);
107
+ return;
108
+ }
67
109
  }
68
- checkParameterLayout(node, node.arguments, tokenStore, isTemplate);
110
+ checkParameterLayout(node, node.arguments);
69
111
  },
70
- FunctionDeclaration: (node) => checkParameterLayout(node, node.params, tokenStore, isTemplate),
71
- FunctionExpression: (node) => checkParameterLayout(node, node.params, tokenStore, isTemplate),
72
- NewExpression: (node) => checkParameterLayout(node, node.arguments, tokenStore, isTemplate)
112
+ FunctionDeclaration: (node) => checkParameterLayout(node, node.params),
113
+ FunctionExpression: (node) => checkParameterLayout(node, node.params),
114
+ NewExpression: (node) => checkParameterLayout(node, node.arguments)
73
115
  };
74
116
  }
75
117
  return defineScriptAndTemplateVisitors(context.sourceCode, createVisitor);
76
118
  },
77
119
  meta: {
78
- docs: { description: "Preserve consistent single-parameter boundaries and expand multiline parameter lists." },
120
+ docs: { description: "Keep parameter boundaries consistent, expand multiline lists, and compact test calls." },
79
121
  fixable: "whitespace",
80
122
  messages: {
123
+ compactTestCall: "Keep test-call arguments beside their parentheses and each other.",
81
124
  newline: "Start a multiline parameter list on a new line.",
82
125
  singleBoundary: "Use matching newline boundaries around a single parameter."
83
126
  },
84
- schema: [],
127
+ schema: [{
128
+ additionalProperties: false,
129
+ properties: { compactTestCalls: { type: "boolean" } },
130
+ type: "object"
131
+ }],
85
132
  type: "layout"
86
133
  }
87
134
  };
@@ -1 +1 @@
1
- {"version":3,"file":"consistent-parameter-layout.js","names":[],"sources":["../../../src/_internals/rules/consistent-parameter-layout.ts"],"sourcesContent":["import type { Rule } from 'eslint';\n\nimport type { TokenStore } from '../utils';\nimport { defineScriptAndTemplateVisitors } from '../utils';\n\ntype CallNode = Extract<Rule.Node, { type: 'CallExpression' | 'NewExpression' }> & { typeArguments?: Rule.Node };\ntype FunctionNode = Extract<\n Rule.Node,\n { type: 'ArrowFunctionExpression' | 'FunctionDeclaration' | 'FunctionExpression' }\n>;\n\ntype ListItem = CallNode['arguments'][number] | FunctionNode['params'][number];\n\nexport const consistentParameterLayout: Rule.RuleModule = {\n create(context) {\n const isTestFile = /\\.test\\.[jt]sx?$/.test(context.filename);\n\n function checkParameterLayout(\n node: Rule.Node,\n items: readonly ListItem[],\n tokenStore: TokenStore,\n isTemplate: boolean,\n ): void {\n const first = items[0];\n if (!first) return;\n const isSingleParameter = items.length === 1;\n\n // JSX argument layout belongs to the JSX formatting rules.\n const firstType: string = first.type;\n if (isSingleParameter && (firstType === 'JSXElement' || firstType === 'JSXFragment')) return;\n let openingParen;\n if (node.type === 'CallExpression' || node.type === 'NewExpression') {\n const call = node as CallNode;\n openingParen = tokenStore.getTokenAfter(\n call.typeArguments ?? call.callee,\n (token) => token.type === 'Punctuator' && token.value === '(',\n );\n } else {\n openingParen = tokenStore.getTokenBefore(first);\n }\n\n if (!openingParen || openingParen.value !== '(') return;\n // An unparenthesized arrow must not borrow its parent's delimiters.\n if (openingParen.range[0] < node.range![0]) return;\n const closingParen = node.type === 'CallExpression' || node.type === 'NewExpression'\n ? tokenStore.getLastToken(node)\n : tokenStore.getTokenAfter(items.at(-1)!, (token) => token.value === ')');\n\n const next = tokenStore.getTokenAfter(openingParen)!;\n\n if (isSingleParameter) {\n if (!closingParen || closingParen.value !== ')') return;\n let previous = tokenStore.getTokenBefore(closingParen)!;\n if (previous.value === ',') previous = tokenStore.getTokenBefore(previous)!;\n if (\n tokenStore.commentsExistBetween(openingParen, next)\n || tokenStore.commentsExistBetween(previous, closingParen)\n ) return;\n\n const hasOpeningNewline = openingParen.loc.end.line !== next.loc.start.line;\n const hasClosingNewline = tokenStore.getTokenBefore(closingParen)!.loc.end.line\n !== closingParen.loc.start.line;\n\n if (hasOpeningNewline === hasClosingNewline) return;\n\n context.report({\n fix: (fixer) => hasOpeningNewline\n ? fixer.insertTextBefore(closingParen, '\\n')\n : fixer.insertTextAfter(openingParen, '\\n'),\n messageId: 'singleBoundary',\n node,\n });\n\n return;\n }\n\n if (!closingParen || openingParen.loc.start.line === closingParen.loc.end.line) return;\n\n if (isTemplate) {\n // Script list formatters do not traverse Vue template expressions.\n const newlineOffsets: number[] = [];\n if (openingParen.loc.end.line === next.loc.start.line) newlineOffsets.push(openingParen.range[1]);\n for (let index = 1; index < items.length; index++) {\n const item = items[index]!;\n const comma = tokenStore.getTokensBetween(items[index - 1]!, item)\n .find((token) => token.value === ',');\n\n if (comma && comma.loc.end.line === tokenStore.getTokenAfter(comma)!.loc.start.line) {\n newlineOffsets.push(comma.range[1]);\n }\n }\n\n if (\n closingParen.value === ')'\n && tokenStore.getTokenBefore(closingParen)!.loc.end.line === closingParen.loc.start.line\n ) newlineOffsets.push(closingParen.range[0]);\n\n if (newlineOffsets.length) {\n context.report({\n fix: (fixer) => newlineOffsets.map((offset) => fixer.insertTextAfterRange(\n [\n offset,\n offset,\n ],\n '\\n',\n )),\n messageId: 'newline',\n node: first,\n });\n }\n\n return;\n }\n\n if (openingParen.loc.end.line !== next.loc.start.line) return;\n\n context.report({\n fix: (fixer) => fixer.insertTextAfter(openingParen, '\\n'),\n messageId: 'newline',\n node: first,\n });\n }\n\n function createVisitor(tokenStore: TokenStore, isTemplate: boolean): Rule.RuleListener {\n return {\n ArrowFunctionExpression: (node) => checkParameterLayout(node, node.params, tokenStore, isTemplate),\n CallExpression: (node) => {\n const { callee } = node;\n if (isTestFile) {\n const target = callee.type === 'MemberExpression'\n && !callee.computed\n && callee.property.type === 'Identifier'\n && callee.property.name === 'concurrent'\n ? callee.object\n : callee;\n\n if (\n target.type === 'Identifier'\n && (target.name === 'describe' || target.name === 'it')\n ) return;\n }\n\n checkParameterLayout(node, node.arguments, tokenStore, isTemplate);\n },\n FunctionDeclaration: (node) => checkParameterLayout(node, node.params, tokenStore, isTemplate),\n FunctionExpression: (node) => checkParameterLayout(node, node.params, tokenStore, isTemplate),\n NewExpression: (node) => checkParameterLayout(node, node.arguments, tokenStore, isTemplate),\n };\n }\n\n return defineScriptAndTemplateVisitors(context.sourceCode, createVisitor);\n },\n meta: {\n docs: { description: 'Preserve consistent single-parameter boundaries and expand multiline parameter lists.' },\n fixable: 'whitespace',\n messages: {\n newline: 'Start a multiline parameter list on a new line.',\n singleBoundary: 'Use matching newline boundaries around a single parameter.',\n },\n schema: [],\n type: 'layout',\n },\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"consistent-parameter-layout.js","names":[],"sources":["../../../src/_internals/rules/consistent-parameter-layout.ts"],"sourcesContent":["import type {\n AST,\n Rule,\n} from 'eslint';\n\nimport type { TokenStore } from '../utils';\nimport { defineScriptAndTemplateVisitors } from '../utils';\n\ntype CallNode = Extract<Rule.Node, { type: 'CallExpression' | 'NewExpression' }> & { typeArguments?: Rule.Node };\ntype FunctionNode = Extract<\n Rule.Node,\n { type: 'ArrowFunctionExpression' | 'FunctionDeclaration' | 'FunctionExpression' }\n>;\n\ntype ListItem = CallNode['arguments'][number] | FunctionNode['params'][number];\n\nexport const consistentParameterLayout: Rule.RuleModule = {\n create(context) {\n const compactTestCalls = context.options[0]?.compactTestCalls === true;\n\n function createVisitor(tokenStore: TokenStore, isTemplate: boolean): Rule.RuleListener {\n function checkTestCallLayout(node: CallNode): void {\n const items = node.arguments;\n if (!items.length) return;\n const openingParen = tokenStore.getTokenAfter(\n node.typeArguments ?? node.callee,\n (token) => token.type === 'Punctuator' && token.value === '(',\n )!;\n\n const closingParen = tokenStore.getLastToken(node)!;\n const previous = tokenStore.getTokenBefore(closingParen)!;\n const gaps: Array<[AST.Token, AST.Token, string]> = [\n [\n openingParen,\n tokenStore.getTokenAfter(openingParen)!,\n '',\n ],\n [\n previous,\n closingParen,\n '',\n ],\n ];\n\n for (let index = 1; index < items.length; index++) {\n const comma = tokenStore.getTokensBetween(items[index - 1]!, items[index]!)\n .find((token) => token.type === 'Punctuator' && token.value === ',')!;\n\n gaps.push(\n [\n tokenStore.getTokenBefore(comma)!,\n comma,\n '',\n ],\n [\n comma,\n tokenStore.getTokenAfter(comma)!,\n ' ',\n ],\n );\n }\n\n if (previous.value === ',') {\n gaps.push([\n tokenStore.getTokenBefore(previous)!,\n previous,\n '',\n ]);\n }\n\n // Keep the whole list's layout when a boundary comment prevents safe compaction.\n if (gaps.some(([left, right]) => tokenStore.commentsExistBetween(left, right))) return;\n const multilineGaps = gaps.filter(([left, right]) => left.loc.end.line !== right.loc.start.line);\n if (!multilineGaps.length) return;\n\n context.report({\n fix: (fixer) => multilineGaps.map(([\n left,\n right,\n text,\n ]) => fixer.replaceTextRange(\n [\n left.range[1],\n right.range[0],\n ],\n text,\n )),\n messageId: 'compactTestCall',\n node,\n });\n }\n\n function checkParameterLayout(\n node: CallNode | FunctionNode,\n items: readonly ListItem[],\n ): void {\n const first = items[0];\n if (!first) return;\n const isSingleParameter = items.length === 1;\n\n // JSX argument layout belongs to the JSX formatting rules.\n const firstType: string = first.type;\n if (isSingleParameter && (firstType === 'JSXElement' || firstType === 'JSXFragment')) return;\n let openingParen;\n if (node.type === 'CallExpression' || node.type === 'NewExpression') {\n openingParen = tokenStore.getTokenAfter(\n node.typeArguments ?? node.callee,\n (token) => token.type === 'Punctuator' && token.value === '(',\n );\n } else {\n openingParen = tokenStore.getTokenBefore(first);\n }\n\n if (!openingParen || openingParen.value !== '(') return;\n // An unparenthesized arrow must not borrow its parent's delimiters.\n if (openingParen.range[0] < node.range![0]) return;\n const closingParen = node.type === 'CallExpression' || node.type === 'NewExpression'\n ? tokenStore.getLastToken(node)\n : tokenStore.getTokenAfter(items.at(-1)!, (token) => token.value === ')');\n\n const next = tokenStore.getTokenAfter(openingParen)!;\n\n if (isSingleParameter) {\n if (!closingParen || closingParen.value !== ')') return;\n let previous = tokenStore.getTokenBefore(closingParen)!;\n if (previous.value === ',') previous = tokenStore.getTokenBefore(previous)!;\n if (\n tokenStore.commentsExistBetween(openingParen, next)\n || tokenStore.commentsExistBetween(previous, closingParen)\n ) return;\n\n const hasOpeningNewline = openingParen.loc.end.line !== next.loc.start.line;\n const hasClosingNewline = tokenStore.getTokenBefore(closingParen)!.loc.end.line\n !== closingParen.loc.start.line;\n\n if (hasOpeningNewline === hasClosingNewline) return;\n\n context.report({\n fix: (fixer) => hasOpeningNewline\n ? fixer.insertTextBefore(closingParen, '\\n')\n : fixer.insertTextAfter(openingParen, '\\n'),\n messageId: 'singleBoundary',\n node,\n });\n\n return;\n }\n\n if (!closingParen || openingParen.loc.start.line === closingParen.loc.end.line) return;\n\n if (isTemplate) {\n // Script list formatters do not traverse Vue template expressions.\n const newlineOffsets: number[] = [];\n if (openingParen.loc.end.line === next.loc.start.line) newlineOffsets.push(openingParen.range[1]);\n for (let index = 1; index < items.length; index++) {\n const item = items[index]!;\n const comma = tokenStore.getTokensBetween(items[index - 1]!, item)\n .find((token) => token.value === ',');\n\n if (comma && comma.loc.end.line === tokenStore.getTokenAfter(comma)!.loc.start.line) {\n newlineOffsets.push(comma.range[1]);\n }\n }\n\n if (\n closingParen.value === ')'\n && tokenStore.getTokenBefore(closingParen)!.loc.end.line === closingParen.loc.start.line\n ) newlineOffsets.push(closingParen.range[0]);\n\n if (newlineOffsets.length) {\n context.report({\n fix: (fixer) => newlineOffsets.map((offset) => fixer.insertTextBeforeRange(\n [\n offset,\n offset,\n ],\n '\\n',\n )),\n messageId: 'newline',\n node: first,\n });\n }\n\n return;\n }\n\n if (openingParen.loc.end.line !== next.loc.start.line) return;\n\n context.report({\n fix: (fixer) => fixer.insertTextAfter(openingParen, '\\n'),\n messageId: 'newline',\n node: first,\n });\n }\n\n return {\n ArrowFunctionExpression: (node) => checkParameterLayout(node, node.params),\n CallExpression: (node) => {\n const { callee } = node;\n if (compactTestCalls) {\n const target = callee.type === 'MemberExpression'\n && !callee.computed\n && callee.property.type === 'Identifier'\n && callee.property.name === 'concurrent'\n ? callee.object\n : callee;\n\n if (\n target.type === 'Identifier'\n && (target.name === 'describe' || target.name === 'it')\n ) {\n checkTestCallLayout(node);\n return;\n }\n }\n\n checkParameterLayout(node, node.arguments);\n },\n FunctionDeclaration: (node) => checkParameterLayout(node, node.params),\n FunctionExpression: (node) => checkParameterLayout(node, node.params),\n NewExpression: (node) => checkParameterLayout(node, node.arguments),\n };\n }\n\n return defineScriptAndTemplateVisitors(context.sourceCode, createVisitor);\n },\n meta: {\n docs: { description: 'Keep parameter boundaries consistent, expand multiline lists, and compact test calls.' },\n fixable: 'whitespace',\n messages: {\n compactTestCall: 'Keep test-call arguments beside their parentheses and each other.',\n newline: 'Start a multiline parameter list on a new line.',\n singleBoundary: 'Use matching newline boundaries around a single parameter.',\n },\n schema: [\n {\n additionalProperties: false,\n properties: { compactTestCalls: { type: 'boolean' } },\n type: 'object',\n },\n ],\n type: 'layout',\n },\n};\n"],"mappings":"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"}
@@ -6,12 +6,11 @@ const statementPadding = {
6
6
  for (let index = 1; index < statements.length; index++) {
7
7
  const previous = statements[index - 1];
8
8
  const next = statements[index];
9
+ if ([previous, next].some((node) => node.type === "ImportDeclaration" || node.type === "ExportAllDeclaration" || node.type === "ExportNamedDeclaration" && node.source)) continue;
10
+ const previousFirstToken = sourceCode.getFirstToken(previous);
9
11
  const lastToken = sourceCode.getLastToken(previous);
10
12
  const firstToken = sourceCode.getFirstToken(next);
11
- const closingLine = sourceCode.lines[lastToken.loc.end.line - 1];
12
- const openingLine = sourceCode.lines[firstToken.loc.start.line - 1];
13
- const hasDifferentIndent = /^\s*/.exec(closingLine)[0] !== /^\s*/.exec(openingLine)[0];
14
- const hasStandaloneClosing = /^[)\]}]+;?$/.test(closingLine.slice(0, lastToken.loc.end.column).trim());
13
+ const isMultiline = previousFirstToken.loc.start.line !== lastToken.loc.end.line;
15
14
  const blockNode = previous.type === "ExportDefaultDeclaration" || previous.type === "ExportNamedDeclaration" ? previous.declaration : previous;
16
15
  const hasBlockClosing = lastToken.value === "}" && blockNode && [
17
16
  "BlockStatement",
@@ -27,13 +26,24 @@ const statementPadding = {
27
26
  "WhileStatement",
28
27
  "WithStatement"
29
28
  ].includes(blockNode.type);
30
- if (!hasDifferentIndent && !hasStandaloneClosing && !hasBlockClosing) continue;
31
- const comments = sourceCode.getCommentsBefore(next);
32
- if (sourceCode.lines.slice(lastToken.loc.end.line, firstToken.loc.start.line - 1).some((line, index) => !line.trim() && !comments.some((comment) => comment.loc.start.line <= lastToken.loc.end.line + index + 1 && comment.loc.end.line >= lastToken.loc.end.line + index + 1))) continue;
33
- const boundary = comments.find((comment) => comment.loc.start.line > lastToken.loc.end.line) ?? firstToken;
34
- const offset = boundary.loc.start.line > lastToken.loc.end.line ? boundary.range[0] - boundary.loc.start.column : boundary.range[0];
29
+ if (!isMultiline && !hasBlockClosing) continue;
30
+ let previousEnd = lastToken.range[1];
31
+ let previousEndLine = lastToken.loc.end.line;
32
+ let nextStart = firstToken.range[0];
33
+ let nextStartLine = firstToken.loc.start.line;
34
+ for (const comment of sourceCode.getCommentsBefore(next)) if (comment.loc.start.line === previousEndLine) {
35
+ previousEnd = comment.range[1];
36
+ previousEndLine = comment.loc.end.line;
37
+ } else {
38
+ nextStart = comment.range[0];
39
+ nextStartLine = comment.loc.start.line;
40
+ break;
41
+ }
42
+ if (nextStartLine > previousEndLine + 1) continue;
43
+ const linebreakIndex = sourceCode.text.slice(previousEnd, nextStart).indexOf("\n");
44
+ const offset = linebreakIndex === -1 ? nextStart : previousEnd + linebreakIndex + 1;
35
45
  context.report({
36
- fix: (fixer) => fixer.insertTextBeforeRange([offset, offset], boundary.loc.start.line === lastToken.loc.end.line ? "\n\n" : "\n"),
46
+ fix: (fixer) => fixer.insertTextBeforeRange([offset, offset], linebreakIndex === -1 ? "\n\n" : "\n"),
37
47
  messageId: "blankLine",
38
48
  node: next
39
49
  });
@@ -47,7 +57,7 @@ const statementPadding = {
47
57
  };
48
58
  },
49
59
  meta: {
50
- docs: { description: "Separate statements after closing lines, blocks, or indentation changes." },
60
+ docs: { description: "Separate complete multiline statements and block-ending statements with blank lines." },
51
61
  fixable: "whitespace",
52
62
  messages: { blankLine: "Add a blank line between these complete statements." },
53
63
  schema: [],
@@ -1 +1 @@
1
- {"version":3,"file":"statement-padding.js","names":[],"sources":["../../../src/_internals/rules/statement-padding.ts"],"sourcesContent":["import type { Rule } from 'eslint';\n\ntype StatementNode = Extract<Rule.Node, { type: 'Program' }>['body'][number];\n\nexport const statementPadding: Rule.RuleModule = {\n create(context) {\n const { sourceCode } = context;\n\n function checkStatements(statements: readonly StatementNode[]): void {\n for (let index = 1; index < statements.length; index++) {\n const previous = statements[index - 1]!;\n const next = statements[index]!;\n const lastToken = sourceCode.getLastToken(previous)!;\n const firstToken = sourceCode.getFirstToken(next)!;\n const closingLine = sourceCode.lines[lastToken.loc.end.line - 1]!;\n const openingLine = sourceCode.lines[firstToken.loc.start.line - 1]!;\n const hasDifferentIndent = /^\\s*/.exec(closingLine)![0] !== /^\\s*/.exec(openingLine)![0];\n const hasStandaloneClosing = /^[)\\]}]+;?$/.test(closingLine.slice(0, lastToken.loc.end.column).trim());\n const blockNode = previous.type === 'ExportDefaultDeclaration'\n || previous.type === 'ExportNamedDeclaration'\n ? previous.declaration\n : previous;\n\n const hasBlockClosing = lastToken.value === '}' && blockNode && [\n 'BlockStatement',\n 'ClassDeclaration',\n 'ForInStatement',\n 'ForOfStatement',\n 'ForStatement',\n 'FunctionDeclaration',\n 'IfStatement',\n 'LabeledStatement',\n 'SwitchStatement',\n 'TryStatement',\n 'WhileStatement',\n 'WithStatement',\n ].includes(blockNode.type);\n\n if (!hasDifferentIndent && !hasStandaloneClosing && !hasBlockClosing) continue;\n const comments = sourceCode.getCommentsBefore(next);\n if (\n sourceCode\n .lines\n .slice(lastToken.loc.end.line, firstToken.loc.start.line - 1)\n .some((line, index) => !line.trim() && !comments.some((comment) =>\n comment.loc!.start.line <= lastToken.loc.end.line + index + 1\n && comment.loc!.end.line >= lastToken.loc.end.line + index + 1))\n ) continue;\n\n // Keep leading comments attached to the next statement and trailing comments in place.\n const boundary = comments\n .find((comment) => comment.loc!.start.line > lastToken.loc.end.line) ?? firstToken;\n\n const offset = boundary.loc!.start.line > lastToken.loc.end.line\n ? boundary.range![0] - boundary.loc!.start.column\n : boundary.range![0];\n\n context.report({\n fix: (fixer) => fixer.insertTextBeforeRange(\n [\n offset,\n offset,\n ],\n boundary.loc!.start.line === lastToken.loc.end.line ? '\\n\\n' : '\\n',\n ),\n messageId: 'blankLine',\n node: next,\n });\n }\n }\n\n return {\n BlockStatement: (node) => checkStatements(node.body),\n Program: (node) => checkStatements(node.body),\n StaticBlock: (node) => checkStatements(node.body),\n SwitchCase: (node) => checkStatements(node.consequent),\n };\n },\n meta: {\n docs: { description: 'Separate statements after closing lines, blocks, or indentation changes.' },\n fixable: 'whitespace',\n messages: { blankLine: 'Add a blank line between these complete statements.' },\n schema: [],\n type: 'layout',\n },\n};\n"],"mappings":";AAIA,MAAa,mBAAoC;CAC7C,OAAO,SAAS;EACZ,MAAM,EAAE,eAAe;EAEvB,SAAS,gBAAgB,YAA4C;GACjE,KAAK,IAAI,QAAQ,GAAG,QAAQ,WAAW,QAAQ,SAAS;IACpD,MAAM,WAAW,WAAW,QAAQ;IACpC,MAAM,OAAO,WAAW;IACxB,MAAM,YAAY,WAAW,aAAa,QAAQ;IAClD,MAAM,aAAa,WAAW,cAAc,IAAI;IAChD,MAAM,cAAc,WAAW,MAAM,UAAU,IAAI,IAAI,OAAO;IAC9D,MAAM,cAAc,WAAW,MAAM,WAAW,IAAI,MAAM,OAAO;IACjE,MAAM,qBAAqB,OAAO,KAAK,WAAW,CAAC,CAAE,OAAO,OAAO,KAAK,WAAW,CAAC,CAAE;IACtF,MAAM,uBAAuB,cAAc,KAAK,YAAY,MAAM,GAAG,UAAU,IAAI,IAAI,MAAM,CAAC,CAAC,KAAK,CAAC;IACrG,MAAM,YAAY,SAAS,SAAS,8BAC/B,SAAS,SAAS,2BACjB,SAAS,cACT;IAEN,MAAM,kBAAkB,UAAU,UAAU,OAAO,aAAa;KAC5D;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACJ,CAAC,CAAC,SAAS,UAAU,IAAI;IAEzB,IAAI,CAAC,sBAAsB,CAAC,wBAAwB,CAAC,iBAAiB;IACtE,MAAM,WAAW,WAAW,kBAAkB,IAAI;IAClD,IACI,WACK,MACA,MAAM,UAAU,IAAI,IAAI,MAAM,WAAW,IAAI,MAAM,OAAO,CAAC,CAAC,CAC5D,MAAM,MAAM,UAAU,CAAC,KAAK,KAAK,KAAK,CAAC,SAAS,MAAM,YACnD,QAAQ,IAAK,MAAM,QAAQ,UAAU,IAAI,IAAI,OAAO,QAAQ,KACzD,QAAQ,IAAK,IAAI,QAAQ,UAAU,IAAI,IAAI,OAAO,QAAQ,CAAC,CAAC,GACzE;IAGF,MAAM,WAAW,SACZ,MAAM,YAAY,QAAQ,IAAK,MAAM,OAAO,UAAU,IAAI,IAAI,IAAI,KAAK;IAE5E,MAAM,SAAS,SAAS,IAAK,MAAM,OAAO,UAAU,IAAI,IAAI,OACtD,SAAS,MAAO,KAAK,SAAS,IAAK,MAAM,SACzC,SAAS,MAAO;IAEtB,QAAQ,OAAO;KACX,MAAM,UAAU,MAAM,sBAClB,CACI,QACA,MACJ,GACA,SAAS,IAAK,MAAM,SAAS,UAAU,IAAI,IAAI,OAAO,SAAS,IACnE;KACA,WAAW;KACX,MAAM;IACV,CAAC;GACL;EACJ;EAEA,OAAO;GACH,iBAAiB,SAAS,gBAAgB,KAAK,IAAI;GACnD,UAAU,SAAS,gBAAgB,KAAK,IAAI;GAC5C,cAAc,SAAS,gBAAgB,KAAK,IAAI;GAChD,aAAa,SAAS,gBAAgB,KAAK,UAAU;EACzD;CACJ;CACA,MAAM;EACF,MAAM,EAAE,aAAa,2EAA2E;EAChG,SAAS;EACT,UAAU,EAAE,WAAW,sDAAsD;EAC7E,QAAQ,CAAC;EACT,MAAM;CACV;AACJ"}
1
+ {"version":3,"file":"statement-padding.js","names":[],"sources":["../../../src/_internals/rules/statement-padding.ts"],"sourcesContent":["import type { Rule } from 'eslint';\n\ntype StatementNode = Extract<Rule.Node, { type: 'Program' }>['body'][number];\n\nexport const statementPadding: Rule.RuleModule = {\n create(context) {\n const { sourceCode } = context;\n\n function checkStatements(statements: readonly StatementNode[]): void {\n for (let index = 1; index < statements.length; index++) {\n const previous = statements[index - 1]!;\n const next = statements[index]!;\n if (\n [\n previous,\n next,\n ].some((node) =>\n node.type === 'ImportDeclaration'\n || node.type === 'ExportAllDeclaration'\n || (node.type === 'ExportNamedDeclaration' && node.source))\n ) continue;\n\n const previousFirstToken = sourceCode.getFirstToken(previous)!;\n const lastToken = sourceCode.getLastToken(previous)!;\n const firstToken = sourceCode.getFirstToken(next)!;\n const isMultiline = previousFirstToken.loc.start.line !== lastToken.loc.end.line;\n const blockNode = previous.type === 'ExportDefaultDeclaration'\n || previous.type === 'ExportNamedDeclaration'\n ? previous.declaration\n : previous;\n\n const hasBlockClosing = lastToken.value === '}' && blockNode && [\n 'BlockStatement',\n 'ClassDeclaration',\n 'ForInStatement',\n 'ForOfStatement',\n 'ForStatement',\n 'FunctionDeclaration',\n 'IfStatement',\n 'LabeledStatement',\n 'SwitchStatement',\n 'TryStatement',\n 'WhileStatement',\n 'WithStatement',\n ].includes(blockNode.type);\n\n if (!isMultiline && !hasBlockClosing) continue;\n let previousEnd = lastToken.range[1];\n let previousEndLine = lastToken.loc.end.line;\n let nextStart = firstToken.range[0];\n let nextStartLine = firstToken.loc.start.line;\n\n // Include trailing comments in the previous boundary, not leading comments of the next statement.\n for (const comment of sourceCode.getCommentsBefore(next)) {\n if (comment.loc!.start.line === previousEndLine) {\n previousEnd = comment.range![1];\n previousEndLine = comment.loc!.end.line;\n } else {\n nextStart = comment.range![0];\n nextStartLine = comment.loc!.start.line;\n break;\n }\n }\n\n if (nextStartLine > previousEndLine + 1) continue;\n const linebreakIndex = sourceCode.text.slice(previousEnd, nextStart).indexOf('\\n');\n const offset = linebreakIndex === -1 ? nextStart : previousEnd + linebreakIndex + 1;\n\n context.report({\n fix: (fixer) => fixer.insertTextBeforeRange(\n [\n offset,\n offset,\n ],\n linebreakIndex === -1 ? '\\n\\n' : '\\n',\n ),\n messageId: 'blankLine',\n node: next,\n });\n }\n }\n\n return {\n BlockStatement: (node) => checkStatements(node.body),\n Program: (node) => checkStatements(node.body),\n StaticBlock: (node) => checkStatements(node.body),\n SwitchCase: (node) => checkStatements(node.consequent),\n };\n },\n meta: {\n docs: { description: 'Separate complete multiline statements and block-ending statements with blank lines.' },\n fixable: 'whitespace',\n messages: { blankLine: 'Add a blank line between these complete statements.' },\n schema: [],\n type: 'layout',\n },\n};\n"],"mappings":";AAIA,MAAa,mBAAoC;CAC7C,OAAO,SAAS;EACZ,MAAM,EAAE,eAAe;EAEvB,SAAS,gBAAgB,YAA4C;GACjE,KAAK,IAAI,QAAQ,GAAG,QAAQ,WAAW,QAAQ,SAAS;IACpD,MAAM,WAAW,WAAW,QAAQ;IACpC,MAAM,OAAO,WAAW;IACxB,IACI,CACI,UACA,IACJ,CAAC,CAAC,MAAM,SACJ,KAAK,SAAS,uBACX,KAAK,SAAS,0BACb,KAAK,SAAS,4BAA4B,KAAK,MAAO,GAChE;IAEF,MAAM,qBAAqB,WAAW,cAAc,QAAQ;IAC5D,MAAM,YAAY,WAAW,aAAa,QAAQ;IAClD,MAAM,aAAa,WAAW,cAAc,IAAI;IAChD,MAAM,cAAc,mBAAmB,IAAI,MAAM,SAAS,UAAU,IAAI,IAAI;IAC5E,MAAM,YAAY,SAAS,SAAS,8BAC/B,SAAS,SAAS,2BACjB,SAAS,cACT;IAEN,MAAM,kBAAkB,UAAU,UAAU,OAAO,aAAa;KAC5D;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACJ,CAAC,CAAC,SAAS,UAAU,IAAI;IAEzB,IAAI,CAAC,eAAe,CAAC,iBAAiB;IACtC,IAAI,cAAc,UAAU,MAAM;IAClC,IAAI,kBAAkB,UAAU,IAAI,IAAI;IACxC,IAAI,YAAY,WAAW,MAAM;IACjC,IAAI,gBAAgB,WAAW,IAAI,MAAM;IAGzC,KAAK,MAAM,WAAW,WAAW,kBAAkB,IAAI,GACnD,IAAI,QAAQ,IAAK,MAAM,SAAS,iBAAiB;KAC7C,cAAc,QAAQ,MAAO;KAC7B,kBAAkB,QAAQ,IAAK,IAAI;IACvC,OAAO;KACH,YAAY,QAAQ,MAAO;KAC3B,gBAAgB,QAAQ,IAAK,MAAM;KACnC;IACJ;IAGJ,IAAI,gBAAgB,kBAAkB,GAAG;IACzC,MAAM,iBAAiB,WAAW,KAAK,MAAM,aAAa,SAAS,CAAC,CAAC,QAAQ,IAAI;IACjF,MAAM,SAAS,mBAAmB,KAAK,YAAY,cAAc,iBAAiB;IAElF,QAAQ,OAAO;KACX,MAAM,UAAU,MAAM,sBAClB,CACI,QACA,MACJ,GACA,mBAAmB,KAAK,SAAS,IACrC;KACA,WAAW;KACX,MAAM;IACV,CAAC;GACL;EACJ;EAEA,OAAO;GACH,iBAAiB,SAAS,gBAAgB,KAAK,IAAI;GACnD,UAAU,SAAS,gBAAgB,KAAK,IAAI;GAC5C,cAAc,SAAS,gBAAgB,KAAK,IAAI;GAChD,aAAa,SAAS,gBAAgB,KAAK,UAAU;EACzD;CACJ;CACA,MAAM;EACF,MAAM,EAAE,aAAa,uFAAuF;EAC5G,SAAS;EACT,UAAU,EAAE,WAAW,sDAAsD;EAC7E,QAAQ,CAAC;EACT,MAAM;CACV;AACJ"}
@@ -0,0 +1,3 @@
1
+ import { TypedFlatConfigItem } from "@antfu/eslint-config";
2
+ export declare function createTypeAwareConfig(): TypedFlatConfigItem;
3
+ //# sourceMappingURL=type-aware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-aware.d.ts","names":[],"sources":["../../src/_internals/type-aware.ts"],"mappings":";wBAEgB,yBAAyB"}
@@ -0,0 +1,25 @@
1
+ // src/_internals/type-aware.ts
2
+ function createTypeAwareConfig() {
3
+ return {
4
+ languageOptions: { parserOptions: {
5
+ projectService: true,
6
+ tsconfigRootDir: process.cwd()
7
+ } },
8
+ rules: {
9
+ "require-await": "off",
10
+ "ts/await-thenable": "error",
11
+ "ts/no-base-to-string": "error",
12
+ "ts/no-floating-promises": "error",
13
+ "ts/no-for-in-array": "error",
14
+ "ts/no-misused-promises": "error",
15
+ "ts/no-misused-spread": "error",
16
+ "ts/no-unnecessary-type-assertion": "error",
17
+ "ts/require-await": "error",
18
+ "ts/return-await": "error",
19
+ "ts/switch-exhaustiveness-check": ["error", { considerDefaultExhaustiveForUnions: true }]
20
+ }
21
+ };
22
+ }
23
+ export { createTypeAwareConfig };
24
+
25
+ //# sourceMappingURL=type-aware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-aware.js","names":[],"sources":["../../src/_internals/type-aware.ts"],"sourcesContent":["import type { TypedFlatConfigItem } from '@antfu/eslint-config';\n\nexport function createTypeAwareConfig(): TypedFlatConfigItem {\n return {\n languageOptions: {\n parserOptions: {\n projectService: true,\n tsconfigRootDir: process.cwd(),\n },\n },\n rules: {\n 'require-await': 'off',\n 'ts/await-thenable': 'error',\n 'ts/no-base-to-string': 'error',\n 'ts/no-floating-promises': 'error',\n 'ts/no-for-in-array': 'error',\n 'ts/no-misused-promises': 'error',\n 'ts/no-misused-spread': 'error',\n 'ts/no-unnecessary-type-assertion': 'error',\n 'ts/require-await': 'error',\n 'ts/return-await': 'error',\n 'ts/switch-exhaustiveness-check': [\n 'error',\n { considerDefaultExhaustiveForUnions: true },\n ],\n },\n };\n}\n"],"mappings":";AAEA,SAAgB,wBAA6C;CACzD,OAAO;EACH,iBAAiB,EACb,eAAe;GACX,gBAAgB;GAChB,iBAAiB,QAAQ,IAAI;EACjC,EACJ;EACA,OAAO;GACH,iBAAiB;GACjB,qBAAqB;GACrB,wBAAwB;GACxB,2BAA2B;GAC3B,sBAAsB;GACtB,0BAA0B;GAC1B,wBAAwB;GACxB,oCAAoC;GACpC,oBAAoB;GACpB,mBAAmB;GACnB,kCAAkC,CAC9B,SACA,EAAE,oCAAoC,KAAK,CAC/C;EACJ;CACJ;AACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","names":[],"sources":["../src/base.ts"],"mappings":";wBAgBgB,kBAAkB,+BAAuC;wBA+EzD,gBAAgB,+BAAuC"}
1
+ {"version":3,"file":"base.d.ts","names":[],"sources":["../src/base.ts"],"mappings":";wBAoCgB,kBAAkB,+BAAuC;wBAsGzD,gBAAgB,+BAAuC"}
package/dist/base.js CHANGED
@@ -1,18 +1,36 @@
1
1
  import { customPlugins } from "./_internals/plugins.js";
2
+ import { createTypeAwareConfig } from "./_internals/type-aware.js";
3
+ import { GLOB_JS, GLOB_JSX, GLOB_TESTS, GLOB_TS, GLOB_TSX } from "@antfu/eslint-config";
2
4
  import promise from "eslint-plugin-promise";
3
5
  // src/base.ts
4
6
  const basePerfectionistSortOptions = {
5
7
  ignoreCase: false,
6
8
  type: "natural"
7
9
  };
10
+ const vscodeOrderSensitiveArrayProperties = [
11
+ "args",
12
+ "autoAttachSmartPattern",
13
+ "dependsOn",
14
+ "options",
15
+ "outFiles",
16
+ "problemMatcher",
17
+ "resolveSourceMapLocations",
18
+ "runtimeArgs",
19
+ "skipFiles"
20
+ ].join("|");
8
21
  function createBaseConfigs(environment = "node") {
9
22
  return [
10
23
  { rules: {
11
- "e18e/ban-dependencies": ["error", { allowed: ["axios", "rimraf"] }],
12
- "e18e/prefer-static-regex": ["off"]
24
+ "e18e/ban-dependencies": ["error", { allowed: ["axios"] }],
25
+ "e18e/prefer-static-regex": "off"
13
26
  } },
14
27
  {
15
- files: ["**/*.{cjs,js,mjs}"],
28
+ files: [
29
+ GLOB_JS,
30
+ GLOB_JSX,
31
+ GLOB_TS,
32
+ GLOB_TSX
33
+ ],
16
34
  plugins: {
17
35
  kikiutils: customPlugins,
18
36
  promise
@@ -23,18 +41,26 @@ function createBaseConfigs(environment = "node") {
23
41
  }
24
42
  },
25
43
  {
26
- files: ["**/*.{ts,tsx}"],
27
- plugins: {
28
- kikiutils: customPlugins,
29
- promise
30
- },
44
+ files: [GLOB_TS, GLOB_TSX],
31
45
  rules: {
32
- ...createBaseRules(environment),
33
- "node/prefer-global/process": ["error", "always"],
46
+ "ts/array-type": ["error", { default: "array-simple" }],
34
47
  "ts/consistent-generic-constructors": ["error", "constructor"],
35
48
  "ts/no-redeclare": "off"
36
49
  }
37
50
  },
51
+ {
52
+ ...createTypeAwareConfig(),
53
+ files: [GLOB_TS, GLOB_TSX],
54
+ ignores: ["**/*.config.?([cm])ts"]
55
+ },
56
+ {
57
+ files: GLOB_TESTS,
58
+ rules: {
59
+ "kikiutils/consistent-parameter-layout": ["error", { compactTestCalls: true }],
60
+ "test/valid-expect": "error",
61
+ "test/valid-expect-in-promise": "error"
62
+ }
63
+ },
38
64
  {
39
65
  files: ["**/.vscode/*.json"],
40
66
  rules: {
@@ -43,7 +69,7 @@ function createBaseConfigs(environment = "node") {
43
69
  natural: true,
44
70
  type: "asc"
45
71
  },
46
- pathPattern: "^.*$"
72
+ pathPattern: String.raw`^(?!.*(?:^|\.|\[")(?:${vscodeOrderSensitiveArrayProperties})(?:$|\.|\[|"\])).*`
47
73
  }],
48
74
  "jsonc/sort-keys": [
49
75
  "error",
@@ -54,7 +80,8 @@ function createBaseConfigs(environment = "node") {
54
80
  }
55
81
  ]
56
82
  }
57
- }
83
+ },
84
+ { ignores: ["**/*.md/**"] }
58
85
  ];
59
86
  }
60
87
  function createBaseRules(environment = "node") {
@@ -74,16 +101,15 @@ function createBaseRules(environment = "node") {
74
101
  "kikiutils/consistent-parameter-layout": "error",
75
102
  "kikiutils/statement-padding": "error",
76
103
  "max-classes-per-file": ["error", 1],
104
+ "no-constant-binary-expression": "error",
77
105
  "no-promise-executor-return": ["error", { allowVoid: true }],
106
+ "no-useless-assignment": "error",
78
107
  "perfectionist/sort-array-includes": ["error", basePerfectionistSortOptions],
79
108
  "perfectionist/sort-enums": ["error", {
80
109
  ...basePerfectionistSortOptions,
81
110
  sortByValue: "never"
82
111
  }],
83
- "perfectionist/sort-heritage-clauses": ["error", {
84
- ignoreCase: false,
85
- type: "natural"
86
- }],
112
+ "perfectionist/sort-heritage-clauses": ["error", basePerfectionistSortOptions],
87
113
  "perfectionist/sort-imports": ["error", {
88
114
  environment,
89
115
  groups: [
@@ -133,6 +159,7 @@ function createBaseRules(environment = "node") {
133
159
  }],
134
160
  "perfectionist/sort-union-types": ["error", basePerfectionistSortOptions],
135
161
  "perfectionist/sort-variable-declarations": ["error", basePerfectionistSortOptions],
162
+ "preserve-caught-error": "error",
136
163
  "promise/no-multiple-resolved": "error",
137
164
  "promise/no-return-in-finally": "error",
138
165
  "promise/no-return-wrap": "error",
package/dist/base.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","names":[],"sources":["../src/base.ts"],"sourcesContent":["import type {\n Rules,\n TypedFlatConfigItem,\n} from '@antfu/eslint-config';\n// @ts-expect-error No declare file.\nimport promise from 'eslint-plugin-promise';\n\nimport { customPlugins } from './_internals/plugins';\n\n// Constants/Variables\nconst basePerfectionistSortOptions = {\n ignoreCase: false,\n type: 'natural',\n} as const;\n\n// Functions\nexport function createBaseConfigs(environment: 'bun' | 'node' = 'node'): TypedFlatConfigItem[] {\n return [\n // All files\n {\n rules: {\n 'e18e/ban-dependencies': [\n 'error',\n {\n allowed: [\n 'axios',\n 'rimraf',\n ],\n },\n ],\n 'e18e/prefer-static-regex': ['off'],\n },\n },\n // JavaScript\n {\n files: ['**/*.{cjs,js,mjs}'],\n plugins: {\n kikiutils: customPlugins,\n promise,\n },\n rules: {\n ...createBaseRules(environment),\n 'node/prefer-global/process': [\n 'error',\n 'always',\n ],\n },\n },\n // TypeScript\n {\n files: ['**/*.{ts,tsx}'],\n plugins: {\n kikiutils: customPlugins,\n promise,\n },\n rules: {\n ...createBaseRules(environment),\n 'node/prefer-global/process': [\n 'error',\n 'always',\n ],\n 'ts/consistent-generic-constructors': [\n 'error',\n 'constructor',\n ],\n 'ts/no-redeclare': 'off',\n },\n },\n // VsCode jsonc\n {\n files: ['**/.vscode/*.json'],\n rules: {\n 'jsonc/sort-array-values': [\n 'error',\n {\n order: {\n natural: true,\n type: 'asc',\n },\n pathPattern: '^.*$',\n },\n ],\n 'jsonc/sort-keys': [\n 'error',\n 'asc',\n {\n caseSensitive: true,\n natural: true,\n },\n ],\n },\n },\n ];\n}\n\nexport function createBaseRules(environment: 'bun' | 'node' = 'node'): Rules {\n return {\n 'antfu/consistent-list-newline': [\n 'error',\n {\n ArrayExpression: false,\n ArrayPattern: false,\n },\n ],\n 'antfu/curly': 'off',\n 'antfu/if-newline': 'off',\n 'antfu/no-top-level-await': 'off',\n 'antfu/reasonable-newline': 'off',\n 'arrow-body-style': [\n 'error',\n 'as-needed',\n ],\n 'curly': [\n 'error',\n 'multi-line',\n ],\n 'kikiutils/compact-iteration-layout': 'error',\n 'kikiutils/consistent-condition-layout': 'error',\n 'kikiutils/consistent-parameter-layout': 'error',\n 'kikiutils/statement-padding': 'error',\n 'max-classes-per-file': [\n 'error',\n 1,\n ],\n 'no-promise-executor-return': [\n 'error',\n { allowVoid: true },\n ],\n 'perfectionist/sort-array-includes': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-enums': [\n 'error',\n {\n ...basePerfectionistSortOptions,\n sortByValue: 'never',\n },\n ],\n 'perfectionist/sort-heritage-clauses': [\n 'error',\n {\n ignoreCase: false,\n type: 'natural',\n },\n ],\n 'perfectionist/sort-imports': [\n 'error',\n {\n environment,\n groups: [\n 'side-effect',\n 'side-effect-style',\n 'style',\n [\n 'value-builtin',\n 'type-builtin',\n ],\n [\n 'value-external',\n 'type-external',\n ],\n [\n 'value-internal',\n 'type-internal',\n ],\n [\n 'value-parent',\n 'type-parent',\n ],\n [\n 'value-sibling',\n 'type-sibling',\n ],\n [\n 'value-index',\n 'type-index',\n ],\n 'unknown',\n ],\n ignoreCase: false,\n internalPattern: [\n '^#.*',\n '^@/.*',\n '^~/.*',\n ],\n type: 'natural',\n },\n ],\n 'perfectionist/sort-interfaces': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-intersection-types': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-maps': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-modules': [\n 'error',\n {\n ...basePerfectionistSortOptions,\n groups: [\n 'declare-type',\n [\n 'export-type',\n 'type',\n ],\n 'declare-interface',\n [\n 'export-interface',\n 'interface',\n ],\n 'declare-enum',\n [\n 'enum',\n 'export-enum',\n ],\n 'declare-class',\n [\n 'class',\n 'export-class',\n ],\n 'declare-function',\n [\n 'export-function',\n 'function',\n ],\n ],\n },\n ],\n 'perfectionist/sort-object-types': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-objects': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-sets': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-switch-case': [\n 'error',\n {\n ignoreCase: false,\n type: 'natural',\n },\n ],\n 'perfectionist/sort-union-types': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-variable-declarations': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'promise/no-multiple-resolved': 'error',\n 'promise/no-return-in-finally': 'error',\n 'promise/no-return-wrap': 'error',\n 'require-await': 'error',\n 'style/array-bracket-newline': [\n 'error',\n { multiline: true },\n ],\n 'style/array-element-newline': [\n 'error',\n {\n ArrayExpression: {\n consistent: true,\n minItems: 2,\n },\n ArrayPattern: { minItems: 3 },\n },\n ],\n 'style/arrow-parens': [\n 'error',\n 'always',\n ],\n 'style/brace-style': [\n 'error',\n '1tbs',\n { allowSingleLine: false },\n ],\n 'style/function-call-spacing': [\n 'error',\n 'never',\n ],\n 'style/indent': [\n 'error',\n 4,\n ],\n 'style/max-len': [\n 'warn',\n {\n code: 120,\n comments: 120,\n },\n ],\n 'style/member-delimiter-style': [\n 'error',\n {\n multiline: {\n delimiter: 'semi',\n requireLast: true,\n },\n },\n ],\n 'style/no-extra-parens': [\n 'error',\n 'all',\n { nestedBinaryExpressions: false },\n ],\n 'style/no-extra-semi': 'error',\n 'style/object-curly-newline': [\n 'error',\n {\n ExportDeclaration: {\n minProperties: 2,\n multiline: true,\n },\n ImportDeclaration: {\n minProperties: 2,\n multiline: true,\n },\n ObjectExpression: {\n minProperties: 2,\n multiline: true,\n },\n ObjectPattern: {\n minProperties: 3,\n multiline: true,\n },\n },\n ],\n 'style/operator-linebreak': [\n 'error',\n 'before',\n { overrides: { '=': 'after' } },\n ],\n 'style/padding-line-between-statements': [\n 'error',\n {\n blankLine: 'always',\n next: [\n 'class',\n 'enum',\n 'function',\n ],\n prev: '*',\n },\n {\n blankLine: 'always',\n next: '*',\n prev: [\n 'class',\n 'function',\n ],\n },\n ],\n 'style/semi': [\n 'error',\n 'always',\n ],\n };\n}\n"],"mappings":";;;AAUA,MAAM,+BAA+B;CACjC,YAAY;CACZ,MAAM;AACV;AAGA,SAAgB,kBAAkB,cAA8B,QAA+B;CAC3F,OAAO;EAEH,EACI,OAAO;GACH,yBAAyB,CACrB,SACA,EACI,SAAS,CACL,SACA,QACJ,EACJ,CACJ;GACA,4BAA4B,CAAC,KAAK;EACtC,EACJ;EAEA;GACI,OAAO,CAAC,mBAAmB;GAC3B,SAAS;IACL,WAAW;IACX;GACJ;GACA,OAAO;IACH,GAAG,gBAAgB,WAAW;IAC9B,8BAA8B,CAC1B,SACA,QACJ;GACJ;EACJ;EAEA;GACI,OAAO,CAAC,eAAe;GACvB,SAAS;IACL,WAAW;IACX;GACJ;GACA,OAAO;IACH,GAAG,gBAAgB,WAAW;IAC9B,8BAA8B,CAC1B,SACA,QACJ;IACA,sCAAsC,CAClC,SACA,aACJ;IACA,mBAAmB;GACvB;EACJ;EAEA;GACI,OAAO,CAAC,mBAAmB;GAC3B,OAAO;IACH,2BAA2B,CACvB,SACA;KACI,OAAO;MACH,SAAS;MACT,MAAM;KACV;KACA,aAAa;IACjB,CACJ;IACA,mBAAmB;KACf;KACA;KACA;MACI,eAAe;MACf,SAAS;KACb;IACJ;GACJ;EACJ;CACJ;AACJ;AAEA,SAAgB,gBAAgB,cAA8B,QAAe;CACzE,OAAO;EACH,iCAAiC,CAC7B,SACA;GACI,iBAAiB;GACjB,cAAc;EAClB,CACJ;EACA,eAAe;EACf,oBAAoB;EACpB,4BAA4B;EAC5B,4BAA4B;EAC5B,oBAAoB,CAChB,SACA,WACJ;EACA,SAAS,CACL,SACA,YACJ;EACA,sCAAsC;EACtC,yCAAyC;EACzC,yCAAyC;EACzC,+BAA+B;EAC/B,wBAAwB,CACpB,SACA,CACJ;EACA,8BAA8B,CAC1B,SACA,EAAE,WAAW,KAAK,CACtB;EACA,qCAAqC,CACjC,SACA,4BACJ;EACA,4BAA4B,CACxB,SACA;GACI,GAAG;GACH,aAAa;EACjB,CACJ;EACA,uCAAuC,CACnC,SACA;GACI,YAAY;GACZ,MAAM;EACV,CACJ;EACA,8BAA8B,CAC1B,SACA;GACI;GACA,QAAQ;IACJ;IACA;IACA;IACA,CACI,iBACA,cACJ;IACA,CACI,kBACA,eACJ;IACA,CACI,kBACA,eACJ;IACA,CACI,gBACA,aACJ;IACA,CACI,iBACA,cACJ;IACA,CACI,eACA,YACJ;IACA;GACJ;GACA,YAAY;GACZ,iBAAiB;IACb;IACA;IACA;GACJ;GACA,MAAM;EACV,CACJ;EACA,iCAAiC,CAC7B,SACA,4BACJ;EACA,yCAAyC,CACrC,SACA,4BACJ;EACA,2BAA2B,CACvB,SACA,4BACJ;EACA,8BAA8B,CAC1B,SACA;GACI,GAAG;GACH,QAAQ;IACJ;IACA,CACI,eACA,MACJ;IACA;IACA,CACI,oBACA,WACJ;IACA;IACA,CACI,QACA,aACJ;IACA;IACA,CACI,SACA,cACJ;IACA;IACA,CACI,mBACA,UACJ;GACJ;EACJ,CACJ;EACA,mCAAmC,CAC/B,SACA,4BACJ;EACA,8BAA8B,CAC1B,SACA,4BACJ;EACA,2BAA2B,CACvB,SACA,4BACJ;EACA,kCAAkC,CAC9B,SACA;GACI,YAAY;GACZ,MAAM;EACV,CACJ;EACA,kCAAkC,CAC9B,SACA,4BACJ;EACA,4CAA4C,CACxC,SACA,4BACJ;EACA,gCAAgC;EAChC,gCAAgC;EAChC,0BAA0B;EAC1B,iBAAiB;EACjB,+BAA+B,CAC3B,SACA,EAAE,WAAW,KAAK,CACtB;EACA,+BAA+B,CAC3B,SACA;GACI,iBAAiB;IACb,YAAY;IACZ,UAAU;GACd;GACA,cAAc,EAAE,UAAU,EAAE;EAChC,CACJ;EACA,sBAAsB,CAClB,SACA,QACJ;EACA,qBAAqB;GACjB;GACA;GACA,EAAE,iBAAiB,MAAM;EAC7B;EACA,+BAA+B,CAC3B,SACA,OACJ;EACA,gBAAgB,CACZ,SACA,CACJ;EACA,iBAAiB,CACb,QACA;GACI,MAAM;GACN,UAAU;EACd,CACJ;EACA,gCAAgC,CAC5B,SACA,EACI,WAAW;GACP,WAAW;GACX,aAAa;EACjB,EACJ,CACJ;EACA,yBAAyB;GACrB;GACA;GACA,EAAE,yBAAyB,MAAM;EACrC;EACA,uBAAuB;EACvB,8BAA8B,CAC1B,SACA;GACI,mBAAmB;IACf,eAAe;IACf,WAAW;GACf;GACA,mBAAmB;IACf,eAAe;IACf,WAAW;GACf;GACA,kBAAkB;IACd,eAAe;IACf,WAAW;GACf;GACA,eAAe;IACX,eAAe;IACf,WAAW;GACf;EACJ,CACJ;EACA,4BAA4B;GACxB;GACA;GACA,EAAE,WAAW,EAAE,KAAK,QAAQ,EAAE;EAClC;EACA,yCAAyC;GACrC;GACA;IACI,WAAW;IACX,MAAM;KACF;KACA;KACA;IACJ;IACA,MAAM;GACV;GACA;IACI,WAAW;IACX,MAAM;IACN,MAAM,CACF,SACA,UACJ;GACJ;EACJ;EACA,cAAc,CACV,SACA,QACJ;CACJ;AACJ"}
1
+ {"version":3,"file":"base.js","names":[],"sources":["../src/base.ts"],"sourcesContent":["import type {\n Rules,\n TypedFlatConfigItem,\n} from '@antfu/eslint-config';\nimport {\n GLOB_JS,\n GLOB_JSX,\n GLOB_TESTS,\n GLOB_TS,\n GLOB_TSX,\n} from '@antfu/eslint-config';\n// @ts-expect-error No declare file.\nimport promise from 'eslint-plugin-promise';\n\nimport { customPlugins } from './_internals/plugins';\nimport { createTypeAwareConfig } from './_internals/type-aware';\n\n// Constants/Variables\nconst basePerfectionistSortOptions = {\n ignoreCase: false,\n type: 'natural',\n} as const;\n\nconst vscodeOrderSensitiveArrayProperties = [\n 'args',\n 'autoAttachSmartPattern',\n 'dependsOn',\n 'options',\n 'outFiles',\n 'problemMatcher',\n 'resolveSourceMapLocations',\n 'runtimeArgs',\n 'skipFiles',\n].join('|');\n\n// Functions\nexport function createBaseConfigs(environment: 'bun' | 'node' = 'node'): TypedFlatConfigItem[] {\n return [\n // All files\n {\n rules: {\n 'e18e/ban-dependencies': [\n 'error',\n { allowed: ['axios'] },\n ],\n 'e18e/prefer-static-regex': 'off',\n },\n },\n // JavaScript and TypeScript\n {\n files: [\n GLOB_JS,\n GLOB_JSX,\n GLOB_TS,\n GLOB_TSX,\n ],\n plugins: {\n kikiutils: customPlugins,\n promise,\n },\n rules: {\n ...createBaseRules(environment),\n 'node/prefer-global/process': [\n 'error',\n 'always',\n ],\n },\n },\n // TypeScript\n {\n files: [\n GLOB_TS,\n GLOB_TSX,\n ],\n rules: {\n 'ts/array-type': [\n 'error',\n { default: 'array-simple' },\n ],\n 'ts/consistent-generic-constructors': [\n 'error',\n 'constructor',\n ],\n 'ts/no-redeclare': 'off',\n },\n },\n // Type-aware TypeScript\n {\n ...createTypeAwareConfig(),\n files: [\n GLOB_TS,\n GLOB_TSX,\n ],\n ignores: ['**/*.config.?([cm])ts'],\n },\n // Tests\n {\n files: GLOB_TESTS,\n rules: {\n 'kikiutils/consistent-parameter-layout': [\n 'error',\n { compactTestCalls: true },\n ],\n 'test/valid-expect': 'error',\n 'test/valid-expect-in-promise': 'error',\n },\n },\n // VS Code JSONC\n {\n files: ['**/.vscode/*.json'],\n rules: {\n 'jsonc/sort-array-values': [\n 'error',\n {\n order: {\n natural: true,\n type: 'asc',\n },\n // Preserve ordered fields and any argument or option arrays nested inside them.\n // eslint-disable-next-line style/max-len\n pathPattern: String.raw`^(?!.*(?:^|\\.|\\[\")(?:${vscodeOrderSensitiveArrayProperties})(?:$|\\.|\\[|\"\\])).*`,\n },\n ],\n 'jsonc/sort-keys': [\n 'error',\n 'asc',\n {\n caseSensitive: true,\n natural: true,\n },\n ],\n },\n },\n // Ignore all extracted Markdown code blocks, but keep linting Markdown itself.\n { ignores: ['**/*.md/**'] },\n ];\n}\n\nexport function createBaseRules(environment: 'bun' | 'node' = 'node'): Rules {\n return {\n 'antfu/consistent-list-newline': [\n 'error',\n {\n ArrayExpression: false,\n ArrayPattern: false,\n },\n ],\n 'antfu/curly': 'off',\n 'antfu/if-newline': 'off',\n 'antfu/no-top-level-await': 'off',\n 'antfu/reasonable-newline': 'off',\n 'arrow-body-style': [\n 'error',\n 'as-needed',\n ],\n 'curly': [\n 'error',\n 'multi-line',\n ],\n 'kikiutils/compact-iteration-layout': 'error',\n 'kikiutils/consistent-condition-layout': 'error',\n 'kikiutils/consistent-parameter-layout': 'error',\n 'kikiutils/statement-padding': 'error',\n 'max-classes-per-file': [\n 'error',\n 1,\n ],\n 'no-constant-binary-expression': 'error',\n 'no-promise-executor-return': [\n 'error',\n { allowVoid: true },\n ],\n 'no-useless-assignment': 'error',\n 'perfectionist/sort-array-includes': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-enums': [\n 'error',\n {\n ...basePerfectionistSortOptions,\n sortByValue: 'never',\n },\n ],\n 'perfectionist/sort-heritage-clauses': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-imports': [\n 'error',\n {\n environment,\n groups: [\n 'side-effect',\n 'side-effect-style',\n 'style',\n [\n 'value-builtin',\n 'type-builtin',\n ],\n [\n 'value-external',\n 'type-external',\n ],\n [\n 'value-internal',\n 'type-internal',\n ],\n [\n 'value-parent',\n 'type-parent',\n ],\n [\n 'value-sibling',\n 'type-sibling',\n ],\n [\n 'value-index',\n 'type-index',\n ],\n 'unknown',\n ],\n ignoreCase: false,\n internalPattern: [\n '^#.*',\n '^@/.*',\n '^~/.*',\n ],\n type: 'natural',\n },\n ],\n 'perfectionist/sort-interfaces': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-intersection-types': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-maps': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-modules': [\n 'error',\n {\n ...basePerfectionistSortOptions,\n groups: [\n 'declare-type',\n [\n 'export-type',\n 'type',\n ],\n 'declare-interface',\n [\n 'export-interface',\n 'interface',\n ],\n 'declare-enum',\n [\n 'enum',\n 'export-enum',\n ],\n 'declare-class',\n [\n 'class',\n 'export-class',\n ],\n 'declare-function',\n [\n 'export-function',\n 'function',\n ],\n ],\n },\n ],\n 'perfectionist/sort-object-types': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-objects': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-sets': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-switch-case': [\n 'error',\n {\n ignoreCase: false,\n type: 'natural',\n },\n ],\n 'perfectionist/sort-union-types': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'perfectionist/sort-variable-declarations': [\n 'error',\n basePerfectionistSortOptions,\n ],\n 'preserve-caught-error': 'error',\n 'promise/no-multiple-resolved': 'error',\n 'promise/no-return-in-finally': 'error',\n 'promise/no-return-wrap': 'error',\n 'require-await': 'error',\n 'style/array-bracket-newline': [\n 'error',\n { multiline: true },\n ],\n 'style/array-element-newline': [\n 'error',\n {\n ArrayExpression: {\n consistent: true,\n minItems: 2,\n },\n ArrayPattern: { minItems: 3 },\n },\n ],\n 'style/arrow-parens': [\n 'error',\n 'always',\n ],\n 'style/brace-style': [\n 'error',\n '1tbs',\n { allowSingleLine: false },\n ],\n 'style/function-call-spacing': [\n 'error',\n 'never',\n ],\n 'style/indent': [\n 'error',\n 4,\n ],\n 'style/max-len': [\n 'warn',\n {\n code: 120,\n comments: 120,\n },\n ],\n 'style/member-delimiter-style': [\n 'error',\n {\n multiline: {\n delimiter: 'semi',\n requireLast: true,\n },\n },\n ],\n 'style/no-extra-parens': [\n 'error',\n 'all',\n { nestedBinaryExpressions: false },\n ],\n 'style/no-extra-semi': 'error',\n 'style/object-curly-newline': [\n 'error',\n {\n ExportDeclaration: {\n minProperties: 2,\n multiline: true,\n },\n ImportDeclaration: {\n minProperties: 2,\n multiline: true,\n },\n ObjectExpression: {\n minProperties: 2,\n multiline: true,\n },\n ObjectPattern: {\n minProperties: 3,\n multiline: true,\n },\n },\n ],\n 'style/operator-linebreak': [\n 'error',\n 'before',\n { overrides: { '=': 'after' } },\n ],\n 'style/padding-line-between-statements': [\n 'error',\n {\n blankLine: 'always',\n next: [\n 'class',\n 'enum',\n 'function',\n ],\n prev: '*',\n },\n {\n blankLine: 'always',\n next: '*',\n prev: [\n 'class',\n 'function',\n ],\n },\n ],\n 'style/semi': [\n 'error',\n 'always',\n ],\n };\n}\n"],"mappings":";;;;;AAkBA,MAAM,+BAA+B;CACjC,YAAY;CACZ,MAAM;AACV;AAEA,MAAM,sCAAsC;CACxC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACJ,CAAC,CAAC,KAAK,GAAG;AAGV,SAAgB,kBAAkB,cAA8B,QAA+B;CAC3F,OAAO;EAEH,EACI,OAAO;GACH,yBAAyB,CACrB,SACA,EAAE,SAAS,CAAC,OAAO,EAAE,CACzB;GACA,4BAA4B;EAChC,EACJ;EAEA;GACI,OAAO;IACH;IACA;IACA;IACA;GACJ;GACA,SAAS;IACL,WAAW;IACX;GACJ;GACA,OAAO;IACH,GAAG,gBAAgB,WAAW;IAC9B,8BAA8B,CAC1B,SACA,QACJ;GACJ;EACJ;EAEA;GACI,OAAO,CACH,SACA,QACJ;GACA,OAAO;IACH,iBAAiB,CACb,SACA,EAAE,SAAS,eAAe,CAC9B;IACA,sCAAsC,CAClC,SACA,aACJ;IACA,mBAAmB;GACvB;EACJ;EAEA;GACI,GAAG,sBAAsB;GACzB,OAAO,CACH,SACA,QACJ;GACA,SAAS,CAAC,uBAAuB;EACrC;EAEA;GACI,OAAO;GACP,OAAO;IACH,yCAAyC,CACrC,SACA,EAAE,kBAAkB,KAAK,CAC7B;IACA,qBAAqB;IACrB,gCAAgC;GACpC;EACJ;EAEA;GACI,OAAO,CAAC,mBAAmB;GAC3B,OAAO;IACH,2BAA2B,CACvB,SACA;KACI,OAAO;MACH,SAAS;MACT,MAAM;KACV;KAGA,aAAa,OAAO,GAAG,wBAAwB,oCAAoC;IACvF,CACJ;IACA,mBAAmB;KACf;KACA;KACA;MACI,eAAe;MACf,SAAS;KACb;IACJ;GACJ;EACJ;EAEA,EAAE,SAAS,CAAC,YAAY,EAAE;CAC9B;AACJ;AAEA,SAAgB,gBAAgB,cAA8B,QAAe;CACzE,OAAO;EACH,iCAAiC,CAC7B,SACA;GACI,iBAAiB;GACjB,cAAc;EAClB,CACJ;EACA,eAAe;EACf,oBAAoB;EACpB,4BAA4B;EAC5B,4BAA4B;EAC5B,oBAAoB,CAChB,SACA,WACJ;EACA,SAAS,CACL,SACA,YACJ;EACA,sCAAsC;EACtC,yCAAyC;EACzC,yCAAyC;EACzC,+BAA+B;EAC/B,wBAAwB,CACpB,SACA,CACJ;EACA,iCAAiC;EACjC,8BAA8B,CAC1B,SACA,EAAE,WAAW,KAAK,CACtB;EACA,yBAAyB;EACzB,qCAAqC,CACjC,SACA,4BACJ;EACA,4BAA4B,CACxB,SACA;GACI,GAAG;GACH,aAAa;EACjB,CACJ;EACA,uCAAuC,CACnC,SACA,4BACJ;EACA,8BAA8B,CAC1B,SACA;GACI;GACA,QAAQ;IACJ;IACA;IACA;IACA,CACI,iBACA,cACJ;IACA,CACI,kBACA,eACJ;IACA,CACI,kBACA,eACJ;IACA,CACI,gBACA,aACJ;IACA,CACI,iBACA,cACJ;IACA,CACI,eACA,YACJ;IACA;GACJ;GACA,YAAY;GACZ,iBAAiB;IACb;IACA;IACA;GACJ;GACA,MAAM;EACV,CACJ;EACA,iCAAiC,CAC7B,SACA,4BACJ;EACA,yCAAyC,CACrC,SACA,4BACJ;EACA,2BAA2B,CACvB,SACA,4BACJ;EACA,8BAA8B,CAC1B,SACA;GACI,GAAG;GACH,QAAQ;IACJ;IACA,CACI,eACA,MACJ;IACA;IACA,CACI,oBACA,WACJ;IACA;IACA,CACI,QACA,aACJ;IACA;IACA,CACI,SACA,cACJ;IACA;IACA,CACI,mBACA,UACJ;GACJ;EACJ,CACJ;EACA,mCAAmC,CAC/B,SACA,4BACJ;EACA,8BAA8B,CAC1B,SACA,4BACJ;EACA,2BAA2B,CACvB,SACA,4BACJ;EACA,kCAAkC,CAC9B,SACA;GACI,YAAY;GACZ,MAAM;EACV,CACJ;EACA,kCAAkC,CAC9B,SACA,4BACJ;EACA,4CAA4C,CACxC,SACA,4BACJ;EACA,yBAAyB;EACzB,gCAAgC;EAChC,gCAAgC;EAChC,0BAA0B;EAC1B,iBAAiB;EACjB,+BAA+B,CAC3B,SACA,EAAE,WAAW,KAAK,CACtB;EACA,+BAA+B,CAC3B,SACA;GACI,iBAAiB;IACb,YAAY;IACZ,UAAU;GACd;GACA,cAAc,EAAE,UAAU,EAAE;EAChC,CACJ;EACA,sBAAsB,CAClB,SACA,QACJ;EACA,qBAAqB;GACjB;GACA;GACA,EAAE,iBAAiB,MAAM;EAC7B;EACA,+BAA+B,CAC3B,SACA,OACJ;EACA,gBAAgB,CACZ,SACA,CACJ;EACA,iBAAiB,CACb,QACA;GACI,MAAM;GACN,UAAU;EACd,CACJ;EACA,gCAAgC,CAC5B,SACA,EACI,WAAW;GACP,WAAW;GACX,aAAa;EACjB,EACJ,CACJ;EACA,yBAAyB;GACrB;GACA;GACA,EAAE,yBAAyB,MAAM;EACrC;EACA,uBAAuB;EACvB,8BAA8B,CAC1B,SACA;GACI,mBAAmB;IACf,eAAe;IACf,WAAW;GACf;GACA,mBAAmB;IACf,eAAe;IACf,WAAW;GACf;GACA,kBAAkB;IACd,eAAe;IACf,WAAW;GACf;GACA,eAAe;IACX,eAAe;IACf,WAAW;GACf;EACJ,CACJ;EACA,4BAA4B;GACxB;GACA;GACA,EAAE,WAAW,EAAE,KAAK,QAAQ,EAAE;EAClC;EACA,yCAAyC;GACrC;GACA;IACI,WAAW;IACX,MAAM;KACF;KACA;KACA;IACJ;IACA,MAAM;GACV;GACA;IACI,WAAW;IACX,MAAM;IACN,MAAM,CACF,SACA,UACJ;GACJ;EACJ;EACA,cAAc,CACV,SACA,QACJ;CACJ;AACJ"}