@saasmakers/eslint 0.2.6 → 0.2.7
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/dist/chunks/formatters.cjs +248 -0
- package/dist/chunks/formatters.mjs +246 -0
- package/dist/chunks/import.cjs +53 -0
- package/dist/chunks/import.mjs +51 -0
- package/dist/chunks/index.cjs +120 -0
- package/dist/chunks/index.mjs +101 -0
- package/dist/chunks/index2.cjs +880 -0
- package/dist/chunks/index2.mjs +868 -0
- package/dist/chunks/index3.cjs +982 -0
- package/dist/chunks/index3.mjs +979 -0
- package/dist/chunks/index4.cjs +12099 -0
- package/dist/chunks/index4.mjs +12077 -0
- package/dist/chunks/jsdoc.cjs +38398 -0
- package/dist/chunks/jsdoc.mjs +38391 -0
- package/dist/chunks/regexp.cjs +18518 -0
- package/dist/chunks/regexp.mjs +18511 -0
- package/dist/chunks/stylistic.cjs +23935 -0
- package/dist/chunks/stylistic.mjs +23932 -0
- package/dist/chunks/typescript.cjs +56168 -0
- package/dist/chunks/typescript.mjs +56154 -0
- package/dist/chunks/unicorn.cjs +82775 -0
- package/dist/chunks/unicorn.mjs +82764 -0
- package/dist/chunks/vue.cjs +96233 -0
- package/dist/chunks/vue.mjs +96220 -0
- package/dist/eslint.config.cjs +19 -10875
- package/dist/eslint.config.d.cts +3897 -16
- package/dist/eslint.config.d.mts +3897 -16
- package/dist/eslint.config.d.ts +3897 -16
- package/dist/eslint.config.mjs +18 -10853
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +6 -2
- package/dist/index.d.mts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.mjs +1 -1
- package/dist/shared/eslint.05nu4VbT.mjs +9 -0
- package/dist/shared/eslint.07qTxm9w.mjs +3352 -0
- package/dist/shared/eslint.6MAvpL4q.cjs +2141 -0
- package/dist/shared/{eslint.CohBuu1-.mjs → eslint.B3ywQ3NK.mjs} +157 -331
- package/dist/shared/eslint.BGpVg2tt.cjs +13 -0
- package/dist/shared/eslint.BL4sYiVQ.cjs +820 -0
- package/dist/shared/eslint.BOOP2x9L.cjs +67 -0
- package/dist/shared/eslint.Bf7aat-e.mjs +10 -0
- package/dist/shared/eslint.Bh1W2iVQ.cjs +37181 -0
- package/dist/shared/eslint.Bl69eiyD.cjs +7073 -0
- package/dist/shared/eslint.BtkqW7nC.mjs +818 -0
- package/dist/shared/eslint.C12_M0Cw.cjs +9 -0
- package/dist/shared/eslint.CMfxPSSy.cjs +14 -0
- package/dist/shared/eslint.COweQ1RR.mjs +5 -0
- package/dist/shared/eslint.CUi9znUC.mjs +13 -0
- package/dist/shared/eslint.Cg6Ty7p7.mjs +2699 -0
- package/dist/shared/eslint.CxAZpd0w.cjs +3365 -0
- package/dist/shared/eslint.CyJA7jO6.cjs +3813 -0
- package/dist/shared/eslint.DDD2xc4l.cjs +25 -0
- package/dist/shared/eslint.DI7QBrVD.mjs +6 -0
- package/dist/shared/eslint.DUamuDzp.cjs +7 -0
- package/dist/shared/eslint.DV_fpPxQ.mjs +3805 -0
- package/dist/shared/{eslint.DhFjwkxh.cjs → eslint.Dhg0jKDi.cjs} +167 -330
- package/dist/shared/eslint.Difk5awg.mjs +2139 -0
- package/dist/shared/eslint.Dlgr3LGM.mjs +7070 -0
- package/dist/shared/eslint.DoYGbUIG.cjs +2724 -0
- package/dist/shared/eslint.Dprsk9zl.mjs +65 -0
- package/dist/shared/eslint.DuJbNenz.mjs +37140 -0
- package/dist/shared/eslint.MfgVmFE7.cjs +3054 -0
- package/dist/shared/eslint.W7RM7aEw.mjs +3052 -0
- package/package.json +2 -1
|
@@ -0,0 +1,982 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
//#region node_modules/.pnpm/es-toolkit@1.44.0/node_modules/es-toolkit/dist/predicate/isPrimitive.mjs
|
|
4
|
+
function isPrimitive(value) {
|
|
5
|
+
return value == null || typeof value !== "object" && typeof value !== "function";
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region node_modules/.pnpm/es-toolkit@1.44.0/node_modules/es-toolkit/dist/predicate/isTypedArray.mjs
|
|
10
|
+
function isTypedArray(x) {
|
|
11
|
+
return ArrayBuffer.isView(x) && !(x instanceof DataView);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region node_modules/.pnpm/es-toolkit@1.44.0/node_modules/es-toolkit/dist/object/clone.mjs
|
|
16
|
+
function clone(obj) {
|
|
17
|
+
if (isPrimitive(obj)) return obj;
|
|
18
|
+
if (Array.isArray(obj) || isTypedArray(obj) || obj instanceof ArrayBuffer || typeof SharedArrayBuffer !== "undefined" && obj instanceof SharedArrayBuffer) return obj.slice(0);
|
|
19
|
+
const prototype = Object.getPrototypeOf(obj);
|
|
20
|
+
if (prototype == null) return Object.assign(Object.create(prototype), obj);
|
|
21
|
+
const Constructor = prototype.constructor;
|
|
22
|
+
if (obj instanceof Date || obj instanceof Map || obj instanceof Set) return new Constructor(obj);
|
|
23
|
+
if (obj instanceof RegExp) {
|
|
24
|
+
const newRegExp = new Constructor(obj);
|
|
25
|
+
newRegExp.lastIndex = obj.lastIndex;
|
|
26
|
+
return newRegExp;
|
|
27
|
+
}
|
|
28
|
+
if (obj instanceof DataView) return new Constructor(obj.buffer.slice(0));
|
|
29
|
+
if (obj instanceof Error) {
|
|
30
|
+
let newError;
|
|
31
|
+
if (obj instanceof AggregateError) newError = new Constructor(obj.errors, obj.message, { cause: obj.cause });
|
|
32
|
+
else newError = new Constructor(obj.message, { cause: obj.cause });
|
|
33
|
+
newError.stack = obj.stack;
|
|
34
|
+
Object.assign(newError, obj);
|
|
35
|
+
return newError;
|
|
36
|
+
}
|
|
37
|
+
if (typeof File !== "undefined" && obj instanceof File) return new Constructor([obj], obj.name, {
|
|
38
|
+
type: obj.type,
|
|
39
|
+
lastModified: obj.lastModified
|
|
40
|
+
});
|
|
41
|
+
if (typeof obj === "object") {
|
|
42
|
+
const newObject = Object.create(prototype);
|
|
43
|
+
return Object.assign(newObject, obj);
|
|
44
|
+
}
|
|
45
|
+
return obj;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region node_modules/.pnpm/es-toolkit@1.44.0/node_modules/es-toolkit/dist/predicate/isPlainObject.mjs
|
|
50
|
+
function isPlainObject(value) {
|
|
51
|
+
if (!value || typeof value !== "object") return false;
|
|
52
|
+
const proto = Object.getPrototypeOf(value);
|
|
53
|
+
if (!(proto === null || proto === Object.prototype || Object.getPrototypeOf(proto) === null)) return false;
|
|
54
|
+
return Object.prototype.toString.call(value) === "[object Object]";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region node_modules/.pnpm/es-toolkit@1.44.0/node_modules/es-toolkit/dist/_internal/isUnsafeProperty.mjs
|
|
59
|
+
function isUnsafeProperty(key) {
|
|
60
|
+
return key === "__proto__";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region node_modules/.pnpm/es-toolkit@1.44.0/node_modules/es-toolkit/dist/object/mergeWith.mjs
|
|
65
|
+
function mergeWith(target, source, merge) {
|
|
66
|
+
const sourceKeys = Object.keys(source);
|
|
67
|
+
for (let i = 0; i < sourceKeys.length; i++) {
|
|
68
|
+
const key = sourceKeys[i];
|
|
69
|
+
if (isUnsafeProperty(key)) continue;
|
|
70
|
+
const sourceValue = source[key];
|
|
71
|
+
const targetValue = target[key];
|
|
72
|
+
const merged = merge(targetValue, sourceValue, key, target, source);
|
|
73
|
+
if (merged !== void 0) target[key] = merged;
|
|
74
|
+
else if (Array.isArray(sourceValue)) if (Array.isArray(targetValue)) target[key] = mergeWith(targetValue, sourceValue, merge);
|
|
75
|
+
else target[key] = mergeWith([], sourceValue, merge);
|
|
76
|
+
else if (isPlainObject(sourceValue)) if (isPlainObject(targetValue)) target[key] = mergeWith(targetValue, sourceValue, merge);
|
|
77
|
+
else target[key] = mergeWith({}, sourceValue, merge);
|
|
78
|
+
else if (targetValue === void 0 || sourceValue !== void 0) target[key] = sourceValue;
|
|
79
|
+
}
|
|
80
|
+
return target;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region node_modules/.pnpm/es-toolkit@1.44.0/node_modules/es-toolkit/dist/object/toMerged.mjs
|
|
85
|
+
function toMerged(target, source) {
|
|
86
|
+
return mergeWith(clone(target), source, function mergeRecursively(targetValue, sourceValue) {
|
|
87
|
+
if (Array.isArray(sourceValue)) if (Array.isArray(targetValue)) return mergeWith(clone(targetValue), sourceValue, mergeRecursively);
|
|
88
|
+
else return mergeWith([], sourceValue, mergeRecursively);
|
|
89
|
+
else if (isPlainObject(sourceValue)) if (isPlainObject(targetValue)) return mergeWith(clone(targetValue), sourceValue, mergeRecursively);
|
|
90
|
+
else return mergeWith({}, sourceValue, mergeRecursively);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
//#region src/utils/index.ts
|
|
95
|
+
function createRule({ name, create, defaultOptions = [], meta }) {
|
|
96
|
+
return {
|
|
97
|
+
create: ((context) => {
|
|
98
|
+
const optionsCount = Math.max(context.options.length, defaultOptions.length);
|
|
99
|
+
return create(context, Array.from({ length: optionsCount }, (_, i) => {
|
|
100
|
+
if (isPlainObject(context.options[i]) && isPlainObject(defaultOptions[i])) return toMerged(defaultOptions[i], context.options[i]);
|
|
101
|
+
return context.options[i] ?? defaultOptions[i];
|
|
102
|
+
}));
|
|
103
|
+
}),
|
|
104
|
+
defaultOptions,
|
|
105
|
+
meta: {
|
|
106
|
+
...meta,
|
|
107
|
+
docs: {
|
|
108
|
+
...meta.docs,
|
|
109
|
+
url: `https://github.com/9romise/eslint-plugin-import-lite/blob/main/src/rules/${name}/README.md`
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/utils/ast.ts
|
|
117
|
+
function isCommaToken(token) {
|
|
118
|
+
return token.type === "Punctuator" && token.value === ",";
|
|
119
|
+
}
|
|
120
|
+
function getValue(node) {
|
|
121
|
+
switch (node.type) {
|
|
122
|
+
case "Identifier": return node.name;
|
|
123
|
+
case "Literal": return node.value;
|
|
124
|
+
default: throw new Error(`Unsupported node type: ${node.type}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
//#endregion
|
|
129
|
+
//#region src/utils/compat.ts
|
|
130
|
+
function sourceType(context) {
|
|
131
|
+
if ("sourceType" in context.parserOptions) return context.parserOptions.sourceType;
|
|
132
|
+
if ("languageOptions" in context && context.languageOptions) return context.languageOptions.sourceType;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
//#endregion
|
|
136
|
+
//#region src/utils/resolve.ts
|
|
137
|
+
function resolve(path) {
|
|
138
|
+
return path;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
//#region src/rules/consistent-type-specifier-style/consistent-type-specifier-style.ts
|
|
142
|
+
function getImportText(node, sourceCode, specifiers) {
|
|
143
|
+
const sourceString = sourceCode.getText(node.source);
|
|
144
|
+
if (specifiers.length === 0) return "";
|
|
145
|
+
return `import type {${specifiers.map((s) => {
|
|
146
|
+
const importedName = getValue(s.imported);
|
|
147
|
+
if (importedName === s.local.name) return importedName;
|
|
148
|
+
return `${importedName} as ${s.local.name}`;
|
|
149
|
+
}).join(", ")}} from ${sourceString};`;
|
|
150
|
+
}
|
|
151
|
+
var consistent_type_specifier_style_default = createRule({
|
|
152
|
+
name: "consistent-type-specifier-style",
|
|
153
|
+
meta: {
|
|
154
|
+
type: "suggestion",
|
|
155
|
+
docs: { description: "Enforce or ban the use of inline type-only markers for named imports." },
|
|
156
|
+
fixable: "code",
|
|
157
|
+
schema: [{
|
|
158
|
+
type: "string",
|
|
159
|
+
enum: [
|
|
160
|
+
"top-level",
|
|
161
|
+
"inline",
|
|
162
|
+
"prefer-top-level"
|
|
163
|
+
],
|
|
164
|
+
default: "top-level"
|
|
165
|
+
}],
|
|
166
|
+
messages: {
|
|
167
|
+
inline: "Prefer using inline {{kind}} specifiers instead of a top-level {{kind}}-only import.",
|
|
168
|
+
topLevel: "Prefer using a top-level {{kind}}-only import instead of inline {{kind}} specifiers."
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
defaultOptions: ["top-level"],
|
|
172
|
+
create(context, [options]) {
|
|
173
|
+
const { sourceCode } = context;
|
|
174
|
+
if (options === "inline") return { ImportDeclaration(node) {
|
|
175
|
+
if (node.importKind === "value" || node.importKind == null) return;
|
|
176
|
+
if (node.specifiers.length === 0 || node.specifiers.length === 1 && (node.specifiers[0].type === "ImportDefaultSpecifier" || node.specifiers[0].type === "ImportNamespaceSpecifier")) return;
|
|
177
|
+
context.report({
|
|
178
|
+
node,
|
|
179
|
+
messageId: "inline",
|
|
180
|
+
data: { kind: node.importKind },
|
|
181
|
+
fix(fixer) {
|
|
182
|
+
const kindToken = sourceCode.getFirstToken(node, { skip: 1 });
|
|
183
|
+
return [kindToken ? fixer.remove(kindToken) : [], node.specifiers.map((specifier) => fixer.insertTextBefore(specifier, `${node.importKind} `))].flat();
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
} };
|
|
187
|
+
return { ImportDeclaration(node) {
|
|
188
|
+
if (node.importKind === "type" || node.specifiers.length === 0 || node.specifiers.length === 1 && (node.specifiers[0].type === "ImportDefaultSpecifier" || node.specifiers[0].type === "ImportNamespaceSpecifier")) return;
|
|
189
|
+
const typeSpecifiers = [];
|
|
190
|
+
const valueSpecifiers = [];
|
|
191
|
+
let defaultSpecifier = null;
|
|
192
|
+
for (const specifier of node.specifiers) {
|
|
193
|
+
if (specifier.type === "ImportDefaultSpecifier") {
|
|
194
|
+
defaultSpecifier = specifier;
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
if (!("importKind" in specifier)) continue;
|
|
198
|
+
if (specifier.importKind === "type") typeSpecifiers.push(specifier);
|
|
199
|
+
else if (specifier.importKind === "value" || specifier.importKind == null) valueSpecifiers.push(specifier);
|
|
200
|
+
}
|
|
201
|
+
const typeImport = getImportText(node, sourceCode, typeSpecifiers);
|
|
202
|
+
if (typeSpecifiers.length === node.specifiers.length) context.report({
|
|
203
|
+
node,
|
|
204
|
+
messageId: "topLevel",
|
|
205
|
+
data: { kind: "type" },
|
|
206
|
+
fix(fixer) {
|
|
207
|
+
return fixer.replaceText(node, typeImport);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
else if (options === "top-level") for (const specifier of typeSpecifiers) context.report({
|
|
211
|
+
node: specifier,
|
|
212
|
+
messageId: "topLevel",
|
|
213
|
+
data: { kind: specifier.importKind },
|
|
214
|
+
fix(fixer) {
|
|
215
|
+
const fixes = [];
|
|
216
|
+
if (valueSpecifiers.length > 0) {
|
|
217
|
+
for (const specifier of typeSpecifiers) {
|
|
218
|
+
const token = sourceCode.getTokenAfter(specifier);
|
|
219
|
+
if (token && isCommaToken(token)) fixes.push(fixer.remove(token));
|
|
220
|
+
fixes.push(fixer.remove(specifier));
|
|
221
|
+
}
|
|
222
|
+
const maybeComma = sourceCode.getTokenAfter(valueSpecifiers.at(-1));
|
|
223
|
+
if (isCommaToken(maybeComma)) fixes.push(fixer.remove(maybeComma));
|
|
224
|
+
} else if (defaultSpecifier) {
|
|
225
|
+
const comma = sourceCode.getTokenAfter(defaultSpecifier, isCommaToken);
|
|
226
|
+
const closingBrace = sourceCode.getTokenAfter(node.specifiers.at(-1), (token) => token.type === "Punctuator" && token.value === "}");
|
|
227
|
+
fixes.push(fixer.removeRange([comma.range[0], closingBrace.range[1]]));
|
|
228
|
+
}
|
|
229
|
+
return [...fixes, fixer.insertTextAfter(node, `\n${typeImport}`)];
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
} };
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
//#region src/rules/exports-last/exports-last.ts
|
|
237
|
+
function isNonExportStatement({ type }) {
|
|
238
|
+
return type !== "ExportDefaultDeclaration" && type !== "ExportNamedDeclaration" && type !== "ExportAllDeclaration";
|
|
239
|
+
}
|
|
240
|
+
var exports_last_default = createRule({
|
|
241
|
+
name: "exports-last",
|
|
242
|
+
meta: {
|
|
243
|
+
type: "suggestion",
|
|
244
|
+
docs: { description: "Ensure all exports appear after other statements." },
|
|
245
|
+
schema: [],
|
|
246
|
+
messages: { end: "Export statements should appear at the end of the file" }
|
|
247
|
+
},
|
|
248
|
+
defaultOptions: [],
|
|
249
|
+
create(context) {
|
|
250
|
+
return { Program({ body }) {
|
|
251
|
+
const lastNonExportStatementIndex = body.findLastIndex(isNonExportStatement);
|
|
252
|
+
if (lastNonExportStatementIndex !== -1) {
|
|
253
|
+
for (const node of body.slice(0, lastNonExportStatementIndex)) if (!isNonExportStatement(node)) context.report({
|
|
254
|
+
node,
|
|
255
|
+
messageId: "end"
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
} };
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
//#region src/rules/first/first.ts
|
|
263
|
+
function getImportValue(node) {
|
|
264
|
+
return node.type === "ImportDeclaration" ? node.source.value : "moduleReference" in node && "expression" in node.moduleReference && "value" in node.moduleReference.expression && node.moduleReference.expression.value;
|
|
265
|
+
}
|
|
266
|
+
function isPossibleDirective(node) {
|
|
267
|
+
return node.type === "ExpressionStatement" && node.expression.type === "Literal" && typeof node.expression.value === "string";
|
|
268
|
+
}
|
|
269
|
+
var first_default = createRule({
|
|
270
|
+
name: "first",
|
|
271
|
+
meta: {
|
|
272
|
+
type: "suggestion",
|
|
273
|
+
docs: { description: "Ensure all imports appear before other statements." },
|
|
274
|
+
fixable: "code",
|
|
275
|
+
schema: [{
|
|
276
|
+
type: "string",
|
|
277
|
+
enum: ["absolute-first", "disable-absolute-first"]
|
|
278
|
+
}],
|
|
279
|
+
messages: {
|
|
280
|
+
absolute: "Absolute imports should come before relative imports.",
|
|
281
|
+
order: "Import in body of module; reorder to top."
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
defaultOptions: [],
|
|
285
|
+
create(context, options) {
|
|
286
|
+
return { Program(n) {
|
|
287
|
+
const body = n.body;
|
|
288
|
+
if (!body?.length) return;
|
|
289
|
+
const absoluteFirst = options[0] === "absolute-first";
|
|
290
|
+
const { sourceCode } = context;
|
|
291
|
+
const originSourceCode = sourceCode.getText();
|
|
292
|
+
let nonImportCount = 0;
|
|
293
|
+
let anyExpressions = false;
|
|
294
|
+
let anyRelative = false;
|
|
295
|
+
let lastLegalImp = null;
|
|
296
|
+
const errorInfos = [];
|
|
297
|
+
let shouldSort = true;
|
|
298
|
+
let lastSortNodesIndex = 0;
|
|
299
|
+
for (const [index, node] of body.entries()) {
|
|
300
|
+
if (!anyExpressions && isPossibleDirective(node)) continue;
|
|
301
|
+
anyExpressions = true;
|
|
302
|
+
if (node.type === "ImportDeclaration" || node.type === "TSImportEqualsDeclaration") {
|
|
303
|
+
if (absoluteFirst) {
|
|
304
|
+
const importValue = getImportValue(node);
|
|
305
|
+
if (typeof importValue === "string" && /^\./.test(importValue)) anyRelative = true;
|
|
306
|
+
else if (anyRelative) context.report({
|
|
307
|
+
node: node.type === "ImportDeclaration" ? node.source : node.moduleReference,
|
|
308
|
+
messageId: "absolute"
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
if (nonImportCount > 0) {
|
|
312
|
+
/** @see https://eslint.org/docs/next/use/migrate-to-9.0.0#-removed-multiple-context-methods */
|
|
313
|
+
for (const variable of sourceCode.getDeclaredVariables(node)) {
|
|
314
|
+
if (!shouldSort) break;
|
|
315
|
+
for (const reference of variable.references) if (reference.identifier.range[0] < node.range[1]) {
|
|
316
|
+
shouldSort = false;
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (shouldSort) lastSortNodesIndex = errorInfos.length;
|
|
321
|
+
errorInfos.push({
|
|
322
|
+
node,
|
|
323
|
+
range: [body[index - 1].range[1], node.range[1]]
|
|
324
|
+
});
|
|
325
|
+
} else lastLegalImp = node;
|
|
326
|
+
} else nonImportCount++;
|
|
327
|
+
}
|
|
328
|
+
if (errorInfos.length === 0) return;
|
|
329
|
+
for (const [index, { node }] of errorInfos.entries()) {
|
|
330
|
+
let fix;
|
|
331
|
+
if (index < lastSortNodesIndex) fix = (fixer) => fixer.insertTextAfter(node, "");
|
|
332
|
+
else if (index === lastSortNodesIndex) {
|
|
333
|
+
const sortNodes = errorInfos.slice(0, lastSortNodesIndex + 1);
|
|
334
|
+
fix = (fixer) => {
|
|
335
|
+
const removeFixers = sortNodes.map(({ range }) => fixer.removeRange(range));
|
|
336
|
+
const range = [0, removeFixers.at(-1).range[1]];
|
|
337
|
+
let insertSourceCode = sortNodes.map(({ range }) => {
|
|
338
|
+
const nodeSourceCode = originSourceCode.slice(...range);
|
|
339
|
+
if (/\S/.test(nodeSourceCode[0])) return `\n${nodeSourceCode}`;
|
|
340
|
+
return nodeSourceCode;
|
|
341
|
+
}).join("");
|
|
342
|
+
let replaceSourceCode = "";
|
|
343
|
+
if (!lastLegalImp) insertSourceCode = insertSourceCode.trim() + insertSourceCode.match(/^(\s+)/)[0];
|
|
344
|
+
const fixers = [lastLegalImp ? fixer.insertTextAfter(lastLegalImp, insertSourceCode) : fixer.insertTextBefore(body[0], insertSourceCode), ...removeFixers];
|
|
345
|
+
for (const [i, computedFixer] of fixers.entries()) replaceSourceCode += originSourceCode.slice(fixers[i - 1] ? fixers[i - 1].range[1] : 0, computedFixer.range[0]) + computedFixer.text;
|
|
346
|
+
return fixer.replaceTextRange(range, replaceSourceCode);
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
context.report({
|
|
350
|
+
node,
|
|
351
|
+
messageId: "order",
|
|
352
|
+
fix
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
} };
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
//#region src/rules/newline-after-import/newline-after-import.ts
|
|
360
|
+
function isStaticRequire(node) {
|
|
361
|
+
return node && node.callee && node.callee.type === "Identifier" && node.callee.name === "require" && node.arguments.length === 1 && node.arguments[0].type === "Literal" && typeof node.arguments[0].value === "string";
|
|
362
|
+
}
|
|
363
|
+
function containsNodeOrEqual(outerNode, innerNode) {
|
|
364
|
+
return outerNode.range[0] <= innerNode.range[0] && outerNode.range[1] >= innerNode.range[1];
|
|
365
|
+
}
|
|
366
|
+
function getScopeBody(scope) {
|
|
367
|
+
if (scope.block.type === "SwitchStatement") {
|
|
368
|
+
console.log("SwitchStatement scopes not supported");
|
|
369
|
+
return [];
|
|
370
|
+
}
|
|
371
|
+
const body = "body" in scope.block ? scope.block.body : null;
|
|
372
|
+
if (body && "type" in body && body.type === "BlockStatement") return body.body;
|
|
373
|
+
return Array.isArray(body) ? body : [];
|
|
374
|
+
}
|
|
375
|
+
function findNodeIndexInScopeBody(body, nodeToFind) {
|
|
376
|
+
return body.findIndex((node) => containsNodeOrEqual(node, nodeToFind));
|
|
377
|
+
}
|
|
378
|
+
function getLineDifference(node, nextNode) {
|
|
379
|
+
return nextNode.loc.start.line - node.loc.end.line;
|
|
380
|
+
}
|
|
381
|
+
function isClassWithDecorator(node) {
|
|
382
|
+
return node.type === "ClassDeclaration" && !!node.decorators?.length;
|
|
383
|
+
}
|
|
384
|
+
function isExportDefaultClass(node) {
|
|
385
|
+
return node.type === "ExportDefaultDeclaration" && node.declaration.type === "ClassDeclaration";
|
|
386
|
+
}
|
|
387
|
+
function isExportNameClass(node) {
|
|
388
|
+
return node.type === "ExportNamedDeclaration" && node.declaration?.type === "ClassDeclaration";
|
|
389
|
+
}
|
|
390
|
+
var newline_after_import_default = createRule({
|
|
391
|
+
name: "newline-after-import",
|
|
392
|
+
meta: {
|
|
393
|
+
type: "layout",
|
|
394
|
+
docs: { description: "Enforce a newline after import statements." },
|
|
395
|
+
fixable: "whitespace",
|
|
396
|
+
schema: [{
|
|
397
|
+
type: "object",
|
|
398
|
+
properties: {
|
|
399
|
+
count: {
|
|
400
|
+
type: "integer",
|
|
401
|
+
minimum: 1
|
|
402
|
+
},
|
|
403
|
+
exactCount: { type: "boolean" },
|
|
404
|
+
considerComments: { type: "boolean" }
|
|
405
|
+
},
|
|
406
|
+
additionalProperties: false
|
|
407
|
+
}],
|
|
408
|
+
messages: { newline: "Expected {{count}} empty line{{lineSuffix}} after {{type}} statement not followed by another {{type}}." }
|
|
409
|
+
},
|
|
410
|
+
defaultOptions: [{
|
|
411
|
+
count: 1,
|
|
412
|
+
exactCount: false,
|
|
413
|
+
considerComments: false
|
|
414
|
+
}],
|
|
415
|
+
create(context, [options]) {
|
|
416
|
+
const { count = 1, exactCount = false, considerComments = false } = options || {};
|
|
417
|
+
let level = 0;
|
|
418
|
+
const requireCalls = [];
|
|
419
|
+
function checkForNewLine(node, nextNode, type) {
|
|
420
|
+
if (isExportDefaultClass(nextNode) || isExportNameClass(nextNode)) {
|
|
421
|
+
const classNode = nextNode.declaration;
|
|
422
|
+
if (isClassWithDecorator(classNode)) nextNode = classNode.decorators[0];
|
|
423
|
+
} else if (isClassWithDecorator(nextNode)) nextNode = nextNode.decorators[0];
|
|
424
|
+
const lineDifference = getLineDifference(node, nextNode);
|
|
425
|
+
const EXPECTED_LINE_DIFFERENCE = count + 1;
|
|
426
|
+
if (lineDifference < EXPECTED_LINE_DIFFERENCE || exactCount && lineDifference !== EXPECTED_LINE_DIFFERENCE) {
|
|
427
|
+
let column = node.loc.start.column;
|
|
428
|
+
if (node.loc.start.line !== node.loc.end.line) column = 0;
|
|
429
|
+
context.report({
|
|
430
|
+
loc: {
|
|
431
|
+
line: node.loc.end.line,
|
|
432
|
+
column
|
|
433
|
+
},
|
|
434
|
+
messageId: "newline",
|
|
435
|
+
data: {
|
|
436
|
+
count,
|
|
437
|
+
lineSuffix: count > 1 ? "s" : "",
|
|
438
|
+
type
|
|
439
|
+
},
|
|
440
|
+
fix: exactCount && EXPECTED_LINE_DIFFERENCE < lineDifference ? void 0 : (fixer) => fixer.insertTextAfter(node, "\n".repeat(EXPECTED_LINE_DIFFERENCE - lineDifference))
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
function commentAfterImport(node, nextComment, type) {
|
|
445
|
+
const lineDifference = getLineDifference(node, nextComment);
|
|
446
|
+
const EXPECTED_LINE_DIFFERENCE = count + 1;
|
|
447
|
+
if (lineDifference < EXPECTED_LINE_DIFFERENCE) {
|
|
448
|
+
let column = node.loc.start.column;
|
|
449
|
+
if (node.loc.start.line !== node.loc.end.line) column = 0;
|
|
450
|
+
context.report({
|
|
451
|
+
loc: {
|
|
452
|
+
line: node.loc.end.line,
|
|
453
|
+
column
|
|
454
|
+
},
|
|
455
|
+
messageId: "newline",
|
|
456
|
+
data: {
|
|
457
|
+
count,
|
|
458
|
+
lineSuffix: count > 1 ? "s" : "",
|
|
459
|
+
type
|
|
460
|
+
},
|
|
461
|
+
fix: exactCount && EXPECTED_LINE_DIFFERENCE < lineDifference ? void 0 : (fixer) => fixer.insertTextAfter(node, "\n".repeat(EXPECTED_LINE_DIFFERENCE - lineDifference))
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
function incrementLevel() {
|
|
466
|
+
level++;
|
|
467
|
+
}
|
|
468
|
+
function decrementLevel() {
|
|
469
|
+
level--;
|
|
470
|
+
}
|
|
471
|
+
function checkImport(node) {
|
|
472
|
+
const { parent } = node;
|
|
473
|
+
if (!parent || !("body" in parent) || !parent.body) return;
|
|
474
|
+
const root = parent;
|
|
475
|
+
const nodePosition = root.body.indexOf(node);
|
|
476
|
+
const nextNode = root.body[nodePosition + 1];
|
|
477
|
+
const endLine = node.loc.end.line;
|
|
478
|
+
let nextComment;
|
|
479
|
+
if (root.comments !== void 0 && considerComments) nextComment = root.comments.find((o) => o.loc.start.line >= endLine && o.loc.start.line <= endLine + count + 1);
|
|
480
|
+
if (node.type === "TSImportEqualsDeclaration" && node.isExport) return;
|
|
481
|
+
if (nextComment) commentAfterImport(node, nextComment, "import");
|
|
482
|
+
else if (nextNode && nextNode.type !== "ImportDeclaration" && (nextNode.type !== "TSImportEqualsDeclaration" || nextNode.isExport)) checkForNewLine(node, nextNode, "import");
|
|
483
|
+
}
|
|
484
|
+
return {
|
|
485
|
+
"ImportDeclaration": checkImport,
|
|
486
|
+
"TSImportEqualsDeclaration": checkImport,
|
|
487
|
+
CallExpression(node) {
|
|
488
|
+
if (isStaticRequire(node) && level === 0) requireCalls.push(node);
|
|
489
|
+
},
|
|
490
|
+
"Program:exit": function(node) {
|
|
491
|
+
const scopeBody = getScopeBody(context.sourceCode.getScope(node));
|
|
492
|
+
for (const [index, node] of requireCalls.entries()) {
|
|
493
|
+
const nodePosition = findNodeIndexInScopeBody(scopeBody, node);
|
|
494
|
+
const statementWithRequireCall = scopeBody[nodePosition];
|
|
495
|
+
const nextStatement = scopeBody[nodePosition + 1];
|
|
496
|
+
const nextRequireCall = requireCalls[index + 1];
|
|
497
|
+
if (nextRequireCall && containsNodeOrEqual(statementWithRequireCall, nextRequireCall)) continue;
|
|
498
|
+
if (nextStatement && (!nextRequireCall || !containsNodeOrEqual(nextStatement, nextRequireCall))) {
|
|
499
|
+
let nextComment;
|
|
500
|
+
if ("comments" in statementWithRequireCall.parent && statementWithRequireCall.parent.comments !== void 0 && considerComments) {
|
|
501
|
+
const endLine = node.loc.end.line;
|
|
502
|
+
nextComment = statementWithRequireCall.parent.comments.find((o) => o.loc.start.line >= endLine && o.loc.start.line <= endLine + count + 1);
|
|
503
|
+
}
|
|
504
|
+
if (nextComment && nextComment !== void 0) commentAfterImport(statementWithRequireCall, nextComment, "require");
|
|
505
|
+
else checkForNewLine(statementWithRequireCall, nextStatement, "require");
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
"FunctionDeclaration": incrementLevel,
|
|
510
|
+
"FunctionExpression": incrementLevel,
|
|
511
|
+
"ArrowFunctionExpression": incrementLevel,
|
|
512
|
+
"BlockStatement": incrementLevel,
|
|
513
|
+
"ObjectExpression": incrementLevel,
|
|
514
|
+
"Decorator": incrementLevel,
|
|
515
|
+
"FunctionDeclaration:exit": decrementLevel,
|
|
516
|
+
"FunctionExpression:exit": decrementLevel,
|
|
517
|
+
"ArrowFunctionExpression:exit": decrementLevel,
|
|
518
|
+
"BlockStatement:exit": decrementLevel,
|
|
519
|
+
"ObjectExpression:exit": decrementLevel,
|
|
520
|
+
"Decorator:exit": decrementLevel
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
//#region src/rules/no-default-export/no-default-export.ts
|
|
526
|
+
var no_default_export_default = createRule({
|
|
527
|
+
name: "no-default-export",
|
|
528
|
+
meta: {
|
|
529
|
+
type: "suggestion",
|
|
530
|
+
docs: { description: "Forbid default exports." },
|
|
531
|
+
schema: [],
|
|
532
|
+
messages: {
|
|
533
|
+
preferNamed: "Prefer named exports.",
|
|
534
|
+
noAliasDefault: "Do not alias `{{local}}` as `default`. Just export `{{local}}` itself instead."
|
|
535
|
+
}
|
|
536
|
+
},
|
|
537
|
+
defaultOptions: [],
|
|
538
|
+
create(context) {
|
|
539
|
+
if (sourceType(context) !== "module") return {};
|
|
540
|
+
const { sourceCode } = context;
|
|
541
|
+
return {
|
|
542
|
+
ExportDefaultDeclaration(node) {
|
|
543
|
+
const { loc } = sourceCode.getFirstTokens(node)[1] || {};
|
|
544
|
+
context.report({
|
|
545
|
+
node,
|
|
546
|
+
messageId: "preferNamed",
|
|
547
|
+
loc
|
|
548
|
+
});
|
|
549
|
+
},
|
|
550
|
+
ExportNamedDeclaration(node) {
|
|
551
|
+
for (const specifier of node.specifiers.filter((specifier) => getValue(specifier.exported) === "default")) {
|
|
552
|
+
const { loc } = sourceCode.getFirstTokens(node)[1] || {};
|
|
553
|
+
if (specifier.type === "ExportDefaultSpecifier") context.report({
|
|
554
|
+
node,
|
|
555
|
+
messageId: "preferNamed",
|
|
556
|
+
loc
|
|
557
|
+
});
|
|
558
|
+
else if (specifier.type === "ExportSpecifier") context.report({
|
|
559
|
+
node,
|
|
560
|
+
messageId: "noAliasDefault",
|
|
561
|
+
data: { local: getValue(specifier.local) },
|
|
562
|
+
loc
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
//#region src/rules/no-duplicates/no-duplicates.ts
|
|
571
|
+
function checkImports(imported, context) {
|
|
572
|
+
imported.forEach((nodes, module) => {
|
|
573
|
+
if (nodes.length <= 1) return;
|
|
574
|
+
for (let i = 0, len = nodes.length; i < len; i++) {
|
|
575
|
+
const node = nodes[i];
|
|
576
|
+
context.report({
|
|
577
|
+
node: node.source,
|
|
578
|
+
messageId: "duplicate",
|
|
579
|
+
data: { module },
|
|
580
|
+
fix: i === 0 ? getFix(nodes, context.sourceCode, context) : null
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
function getSpecifiersByKind(node) {
|
|
586
|
+
const typeSpecs = [];
|
|
587
|
+
const valueSpecs = [];
|
|
588
|
+
for (const spec of node.specifiers) {
|
|
589
|
+
if (spec.type !== "ImportSpecifier") continue;
|
|
590
|
+
const name = spec.imported.type === "Identifier" ? spec.imported.name : spec.imported.value;
|
|
591
|
+
const localName = spec.local.name;
|
|
592
|
+
("importKind" in spec && spec.importKind === "type" ? typeSpecs : valueSpecs).push({
|
|
593
|
+
name,
|
|
594
|
+
localName
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
return {
|
|
598
|
+
typeSpecs,
|
|
599
|
+
valueSpecs
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
function formatSpecifier(s) {
|
|
603
|
+
return s.name !== s.localName ? `${s.name} as ${s.localName}` : s.name;
|
|
604
|
+
}
|
|
605
|
+
function getFix(nodes, sourceCode, context) {
|
|
606
|
+
const first = nodes[0];
|
|
607
|
+
const isTypeOnlyImport = first.importKind === "type";
|
|
608
|
+
if (hasProblematicComments(first, sourceCode) || hasNamespace(first)) return null;
|
|
609
|
+
const defaultImportNames = new Set(nodes.flatMap((x) => getDefaultImportName(x) || []));
|
|
610
|
+
if (defaultImportNames.size > 1) return null;
|
|
611
|
+
const restWithoutCommentsAndNamespaces = nodes.slice(1).filter((node) => !hasProblematicComments(node, sourceCode) && !hasNamespace(node));
|
|
612
|
+
const restWithoutCommentsAndNamespacesHasSpecifiers = restWithoutCommentsAndNamespaces.map(hasSpecifiers);
|
|
613
|
+
const specifiers = restWithoutCommentsAndNamespaces.reduce((acc, node, nodeIndex) => {
|
|
614
|
+
const tokens = sourceCode.getTokens(node);
|
|
615
|
+
const openBrace = tokens.find((token) => isPunctuator(token, "{"));
|
|
616
|
+
const closeBrace = tokens.find((token) => isPunctuator(token, "}"));
|
|
617
|
+
if (openBrace == null || closeBrace == null) return acc;
|
|
618
|
+
const entry = {
|
|
619
|
+
importNode: node,
|
|
620
|
+
identifiers: sourceCode.text.slice(openBrace.range[1], closeBrace.range[0]).split(","),
|
|
621
|
+
isEmpty: !restWithoutCommentsAndNamespacesHasSpecifiers[nodeIndex]
|
|
622
|
+
};
|
|
623
|
+
if (isTypeOnlyImport && node.importKind !== "type") {
|
|
624
|
+
const { typeSpecs, valueSpecs } = getSpecifiersByKind(node);
|
|
625
|
+
if (typeSpecs.length > 0 && valueSpecs.length > 0) {
|
|
626
|
+
entry.typeSpecs = typeSpecs;
|
|
627
|
+
entry.valueSpecs = valueSpecs;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
acc.push(entry);
|
|
631
|
+
return acc;
|
|
632
|
+
}, []);
|
|
633
|
+
const unnecessaryImports = restWithoutCommentsAndNamespaces.filter((node, nodeIndex) => !restWithoutCommentsAndNamespacesHasSpecifiers[nodeIndex] && !specifiers.some((specifier) => specifier.importNode === node));
|
|
634
|
+
const shouldAddSpecifiers = specifiers.length > 0;
|
|
635
|
+
const shouldRemoveUnnecessary = unnecessaryImports.length > 0;
|
|
636
|
+
const shouldAddDefault = getDefaultImportName(first) == null && defaultImportNames.size === 1;
|
|
637
|
+
if (!shouldAddSpecifiers && !shouldRemoveUnnecessary && !shouldAddDefault) return null;
|
|
638
|
+
const preferInline = context.options[0] && context.options[0]["prefer-inline"];
|
|
639
|
+
return (fixer) => {
|
|
640
|
+
const tokens = sourceCode.getTokens(first);
|
|
641
|
+
const openBrace = tokens.find((token) => isPunctuator(token, "{"));
|
|
642
|
+
const closeBrace = tokens.find((token) => isPunctuator(token, "}"));
|
|
643
|
+
const firstToken = sourceCode.getFirstToken(first);
|
|
644
|
+
const [defaultImportName] = defaultImportNames;
|
|
645
|
+
const firstHasTrailingComma = closeBrace != null && isPunctuator(sourceCode.getTokenBefore(closeBrace), ",");
|
|
646
|
+
const firstIsEmpty = !hasSpecifiers(first);
|
|
647
|
+
const firstExistingIdentifiers = firstIsEmpty ? /* @__PURE__ */ new Set() : new Set(sourceCode.text.slice(openBrace.range[1], closeBrace.range[0]).split(",").map((x) => x.split(" as ")[0].trim()));
|
|
648
|
+
const [specifiersText] = specifiers.reduce(([result, needsComma, existingIdentifiers], specifier) => {
|
|
649
|
+
if (specifier.typeSpecs) {
|
|
650
|
+
const newSpecs = specifier.typeSpecs.filter((ts) => !existingIdentifiers.has(ts.name));
|
|
651
|
+
if (newSpecs.length === 0) return [
|
|
652
|
+
result,
|
|
653
|
+
needsComma,
|
|
654
|
+
existingIdentifiers
|
|
655
|
+
];
|
|
656
|
+
const text = newSpecs.map(formatSpecifier).join(", ");
|
|
657
|
+
const updatedSet = new Set(existingIdentifiers);
|
|
658
|
+
newSpecs.forEach((ts) => updatedSet.add(ts.name));
|
|
659
|
+
return [
|
|
660
|
+
needsComma ? `${result}, ${text}` : `${result}${text}`,
|
|
661
|
+
true,
|
|
662
|
+
updatedSet
|
|
663
|
+
];
|
|
664
|
+
}
|
|
665
|
+
const isTypeSpecifier = "importNode" in specifier && specifier.importNode.importKind === "type";
|
|
666
|
+
const [specifierText, updatedExistingIdentifiers] = specifier.identifiers.reduce(([text, set], cur) => {
|
|
667
|
+
const trimmed = cur.trim();
|
|
668
|
+
if (trimmed.length === 0 || existingIdentifiers.has(trimmed)) return [text, set];
|
|
669
|
+
const curWithType = preferInline && isTypeSpecifier ? cur.replace(/^(\s*)/, "$1type ") : cur;
|
|
670
|
+
return [text.length > 0 ? `${text},${curWithType}` : curWithType, set.add(trimmed)];
|
|
671
|
+
}, ["", existingIdentifiers]);
|
|
672
|
+
return [
|
|
673
|
+
needsComma && !specifier.isEmpty && specifierText.length > 0 ? `${result},${specifierText}` : `${result}${specifierText}`,
|
|
674
|
+
specifier.isEmpty ? needsComma : true,
|
|
675
|
+
updatedExistingIdentifiers
|
|
676
|
+
];
|
|
677
|
+
}, [
|
|
678
|
+
"",
|
|
679
|
+
!firstHasTrailingComma && !firstIsEmpty,
|
|
680
|
+
firstExistingIdentifiers
|
|
681
|
+
]);
|
|
682
|
+
const fixes = [];
|
|
683
|
+
if (shouldAddSpecifiers && preferInline && first.importKind === "type") {
|
|
684
|
+
const typeIdentifierToken = tokens.find((token) => token.type === "Identifier" && token.value === "type");
|
|
685
|
+
if (typeIdentifierToken) fixes.push(fixer.removeRange([typeIdentifierToken.range[0], typeIdentifierToken.range[1] + 1]));
|
|
686
|
+
for (const identifier of tokens.filter((token) => firstExistingIdentifiers.has(token.value))) fixes.push(fixer.replaceTextRange([identifier.range[0], identifier.range[1]], `type ${identifier.value}`));
|
|
687
|
+
}
|
|
688
|
+
if (openBrace == null && shouldAddSpecifiers && shouldAddDefault) fixes.push(fixer.insertTextAfter(firstToken, ` ${defaultImportName}, {${specifiersText}} from`));
|
|
689
|
+
else if (openBrace == null && !shouldAddSpecifiers && shouldAddDefault) fixes.push(fixer.insertTextAfter(firstToken, ` ${defaultImportName} from`));
|
|
690
|
+
else if (openBrace != null && closeBrace != null && shouldAddDefault) {
|
|
691
|
+
fixes.push(fixer.insertTextAfter(firstToken, ` ${defaultImportName},`));
|
|
692
|
+
if (shouldAddSpecifiers) fixes.push(fixer.insertTextBefore(closeBrace, specifiersText));
|
|
693
|
+
} else if (openBrace == null && shouldAddSpecifiers && !shouldAddDefault) if (first.specifiers.length === 0) fixes.push(fixer.insertTextAfter(firstToken, ` {${specifiersText}} from`));
|
|
694
|
+
else fixes.push(fixer.insertTextAfter(first.specifiers[0], `, {${specifiersText}}`));
|
|
695
|
+
else if (openBrace != null && closeBrace != null && !shouldAddDefault) {
|
|
696
|
+
const tokenBefore = sourceCode.getTokenBefore(closeBrace);
|
|
697
|
+
fixes.push(fixer.insertTextAfter(tokenBefore, specifiersText));
|
|
698
|
+
}
|
|
699
|
+
for (const specifier of specifiers) {
|
|
700
|
+
const importNode = specifier.importNode;
|
|
701
|
+
if (specifier.valueSpecs) {
|
|
702
|
+
const nodeTokens = sourceCode.getTokens(importNode);
|
|
703
|
+
const nodeOpenBrace = nodeTokens.find((token) => isPunctuator(token, "{"));
|
|
704
|
+
const nodeCloseBrace = nodeTokens.find((token) => isPunctuator(token, "}"));
|
|
705
|
+
if (nodeOpenBrace && nodeCloseBrace) fixes.push(fixer.replaceTextRange([nodeOpenBrace.range[1], nodeCloseBrace.range[0]], ` ${specifier.valueSpecs.map(formatSpecifier).join(", ")} `));
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
fixes.push(fixer.remove(importNode));
|
|
709
|
+
const charAfterImportRange = [importNode.range[1], importNode.range[1] + 1];
|
|
710
|
+
if (sourceCode.text.slice(charAfterImportRange[0], charAfterImportRange[1]) === "\n") fixes.push(fixer.removeRange(charAfterImportRange));
|
|
711
|
+
}
|
|
712
|
+
for (const node of unnecessaryImports) {
|
|
713
|
+
fixes.push(fixer.remove(node));
|
|
714
|
+
const charAfterImportRange = [node.range[1], node.range[1] + 1];
|
|
715
|
+
if (sourceCode.text.slice(charAfterImportRange[0], charAfterImportRange[1]) === "\n") fixes.push(fixer.removeRange(charAfterImportRange));
|
|
716
|
+
}
|
|
717
|
+
return fixes;
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
function isPunctuator(node, value) {
|
|
721
|
+
return node.type === "Punctuator" && node.value === value;
|
|
722
|
+
}
|
|
723
|
+
function getDefaultImportName(node) {
|
|
724
|
+
return node.specifiers.find((specifier) => specifier.type === "ImportDefaultSpecifier")?.local.name;
|
|
725
|
+
}
|
|
726
|
+
function hasNamespace(node) {
|
|
727
|
+
return node.specifiers.some((specifier) => specifier.type === "ImportNamespaceSpecifier");
|
|
728
|
+
}
|
|
729
|
+
function hasSpecifiers(node) {
|
|
730
|
+
return node.specifiers.some((specifier) => specifier.type === "ImportSpecifier");
|
|
731
|
+
}
|
|
732
|
+
function hasProblematicComments(node, sourceCode) {
|
|
733
|
+
return hasCommentBefore(node, sourceCode) || hasCommentAfter(node, sourceCode) || hasCommentInsideNonSpecifiers(node, sourceCode);
|
|
734
|
+
}
|
|
735
|
+
function hasCommentBefore(node, sourceCode) {
|
|
736
|
+
return sourceCode.getCommentsBefore(node).some((comment) => comment.loc.end.line >= node.loc.start.line - 1);
|
|
737
|
+
}
|
|
738
|
+
function hasCommentAfter(node, sourceCode) {
|
|
739
|
+
return sourceCode.getCommentsAfter(node).some((comment) => comment.loc.start.line === node.loc.end.line);
|
|
740
|
+
}
|
|
741
|
+
function hasCommentInsideNonSpecifiers(node, sourceCode) {
|
|
742
|
+
const tokens = sourceCode.getTokens(node);
|
|
743
|
+
const openBraceIndex = tokens.findIndex((token) => isPunctuator(token, "{"));
|
|
744
|
+
const closeBraceIndex = tokens.findIndex((token) => isPunctuator(token, "}"));
|
|
745
|
+
return (openBraceIndex !== -1 && closeBraceIndex !== -1 ? [...tokens.slice(1, openBraceIndex + 1), ...tokens.slice(closeBraceIndex + 1)] : tokens.slice(1)).some((token) => sourceCode.getCommentsBefore(token).length > 0);
|
|
746
|
+
}
|
|
747
|
+
var no_duplicates_default = createRule({
|
|
748
|
+
name: "no-duplicates",
|
|
749
|
+
meta: {
|
|
750
|
+
type: "problem",
|
|
751
|
+
docs: {
|
|
752
|
+
recommended: true,
|
|
753
|
+
description: "Forbid repeated import of the same module in multiple places."
|
|
754
|
+
},
|
|
755
|
+
fixable: "code",
|
|
756
|
+
schema: [{
|
|
757
|
+
type: "object",
|
|
758
|
+
properties: { "prefer-inline": { type: "boolean" } },
|
|
759
|
+
additionalProperties: false
|
|
760
|
+
}],
|
|
761
|
+
messages: { duplicate: "'{{module}}' imported multiple times." }
|
|
762
|
+
},
|
|
763
|
+
defaultOptions: [],
|
|
764
|
+
create(context) {
|
|
765
|
+
const preferInline = context.options[0]?.["prefer-inline"];
|
|
766
|
+
const moduleMaps = /* @__PURE__ */ new Map();
|
|
767
|
+
function getImportMap(n) {
|
|
768
|
+
const parent = n.parent;
|
|
769
|
+
let map;
|
|
770
|
+
if (moduleMaps.has(parent)) map = moduleMaps.get(parent);
|
|
771
|
+
else {
|
|
772
|
+
map = {
|
|
773
|
+
imported: /* @__PURE__ */ new Map(),
|
|
774
|
+
nsImported: /* @__PURE__ */ new Map(),
|
|
775
|
+
defaultTypesImported: /* @__PURE__ */ new Map(),
|
|
776
|
+
namespaceTypesImported: /* @__PURE__ */ new Map(),
|
|
777
|
+
namedTypesImported: /* @__PURE__ */ new Map()
|
|
778
|
+
};
|
|
779
|
+
moduleMaps.set(parent, map);
|
|
780
|
+
}
|
|
781
|
+
if (n.importKind === "type") {
|
|
782
|
+
if (n.specifiers.length > 0 && n.specifiers[0].type === "ImportDefaultSpecifier") return map.defaultTypesImported;
|
|
783
|
+
if (n.specifiers.length > 0 && n.specifiers[0].type === "ImportNamespaceSpecifier") return map.namespaceTypesImported;
|
|
784
|
+
if (!preferInline) return map.namedTypesImported;
|
|
785
|
+
}
|
|
786
|
+
if (!preferInline && n.specifiers.some((spec) => "importKind" in spec && spec.importKind === "type")) return map.namedTypesImported;
|
|
787
|
+
return hasNamespace(n) ? map.nsImported : map.imported;
|
|
788
|
+
}
|
|
789
|
+
return {
|
|
790
|
+
ImportDeclaration(n) {
|
|
791
|
+
const resolvedPath = resolve(n.source.value);
|
|
792
|
+
const importMap = getImportMap(n);
|
|
793
|
+
if (importMap.has(resolvedPath)) importMap.get(resolvedPath).push(n);
|
|
794
|
+
else importMap.set(resolvedPath, [n]);
|
|
795
|
+
},
|
|
796
|
+
"Program:exit": function() {
|
|
797
|
+
for (const map of moduleMaps.values()) {
|
|
798
|
+
checkImports(map.imported, context);
|
|
799
|
+
checkImports(map.nsImported, context);
|
|
800
|
+
checkImports(map.defaultTypesImported, context);
|
|
801
|
+
checkImports(map.namedTypesImported, context);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
//#region src/rules/no-mutable-exports/no-mutable-exports.ts
|
|
809
|
+
var no_mutable_exports_default = createRule({
|
|
810
|
+
name: "no-mutable-exports",
|
|
811
|
+
meta: {
|
|
812
|
+
type: "suggestion",
|
|
813
|
+
docs: { description: "Forbid the use of mutable exports with `var` or `let`." },
|
|
814
|
+
schema: [],
|
|
815
|
+
messages: { noMutable: "Exporting mutable '{{kind}}' binding, use 'const' instead." }
|
|
816
|
+
},
|
|
817
|
+
defaultOptions: [],
|
|
818
|
+
create(context) {
|
|
819
|
+
function checkDeclaration(node) {
|
|
820
|
+
if ("kind" in node && (node.kind === "var" || node.kind === "let")) context.report({
|
|
821
|
+
node,
|
|
822
|
+
messageId: "noMutable",
|
|
823
|
+
data: { kind: node.kind }
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
function checkDeclarationsInScope({ variables }, name) {
|
|
827
|
+
for (const variable of variables) if (variable.name === name) {
|
|
828
|
+
for (const def of variable.defs) if (def.type === "Variable" && def.parent) checkDeclaration(def.parent);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
return {
|
|
832
|
+
ExportDefaultDeclaration(node) {
|
|
833
|
+
const scope = context.sourceCode.getScope(node);
|
|
834
|
+
if ("name" in node.declaration) checkDeclarationsInScope(scope, node.declaration.name);
|
|
835
|
+
},
|
|
836
|
+
ExportNamedDeclaration(node) {
|
|
837
|
+
const scope = context.sourceCode.getScope(node);
|
|
838
|
+
if (node.declaration) checkDeclaration(node.declaration);
|
|
839
|
+
else if (!node.source) for (const specifier of node.specifiers) checkDeclarationsInScope(scope, specifier.local.name);
|
|
840
|
+
}
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
//#region src/rules/no-named-default/no-named-default.ts
|
|
846
|
+
var no_named_default_default = createRule({
|
|
847
|
+
name: "no-named-default",
|
|
848
|
+
meta: {
|
|
849
|
+
type: "suggestion",
|
|
850
|
+
docs: { description: "Forbid named default exports." },
|
|
851
|
+
schema: [],
|
|
852
|
+
messages: { default: `Use default import syntax to import '{{importName}}'.` }
|
|
853
|
+
},
|
|
854
|
+
defaultOptions: [],
|
|
855
|
+
create(context) {
|
|
856
|
+
return { ImportDeclaration(node) {
|
|
857
|
+
for (const im of node.specifiers) {
|
|
858
|
+
if ("importKind" in im && im.importKind === "type") continue;
|
|
859
|
+
if (im.type === "ImportSpecifier" && getValue(im.imported) === "default") context.report({
|
|
860
|
+
node: im.local,
|
|
861
|
+
messageId: "default",
|
|
862
|
+
data: { importName: im.local.name }
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
} };
|
|
866
|
+
}
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
//#region src/rules/prefer-default-export/prefer-default-export.ts
|
|
870
|
+
var prefer_default_export_default = createRule({
|
|
871
|
+
name: "prefer-default-export",
|
|
872
|
+
meta: {
|
|
873
|
+
type: "suggestion",
|
|
874
|
+
docs: { description: "Prefer a default export if module exports a single name or multiple names." },
|
|
875
|
+
schema: [{
|
|
876
|
+
type: "object",
|
|
877
|
+
properties: { target: {
|
|
878
|
+
type: "string",
|
|
879
|
+
enum: ["single", "any"],
|
|
880
|
+
default: "single"
|
|
881
|
+
} },
|
|
882
|
+
additionalProperties: false
|
|
883
|
+
}],
|
|
884
|
+
messages: {
|
|
885
|
+
single: "Prefer default export on a file with single export.",
|
|
886
|
+
any: "Prefer default export to be present on every file that has export."
|
|
887
|
+
}
|
|
888
|
+
},
|
|
889
|
+
defaultOptions: [{ target: "single" }],
|
|
890
|
+
create(context, [options]) {
|
|
891
|
+
let specifierExportCount = 0;
|
|
892
|
+
let hasDefaultExport = false;
|
|
893
|
+
let hasStarExport = false;
|
|
894
|
+
let hasTypeExport = false;
|
|
895
|
+
let namedExportNode;
|
|
896
|
+
const { target } = options;
|
|
897
|
+
function captureDeclaration(identifierOrPattern) {
|
|
898
|
+
if (identifierOrPattern?.type === "ObjectPattern") for (const property of identifierOrPattern.properties) captureDeclaration(property.value);
|
|
899
|
+
else if (identifierOrPattern?.type === "ArrayPattern") for (const el of identifierOrPattern.elements) captureDeclaration(el);
|
|
900
|
+
else specifierExportCount++;
|
|
901
|
+
}
|
|
902
|
+
return {
|
|
903
|
+
ExportDefaultSpecifier() {
|
|
904
|
+
hasDefaultExport = true;
|
|
905
|
+
},
|
|
906
|
+
ExportSpecifier(node) {
|
|
907
|
+
if (getValue(node.exported) === "default") hasDefaultExport = true;
|
|
908
|
+
else {
|
|
909
|
+
specifierExportCount++;
|
|
910
|
+
namedExportNode = node;
|
|
911
|
+
}
|
|
912
|
+
},
|
|
913
|
+
ExportNamedDeclaration(node) {
|
|
914
|
+
if (!node.declaration) return;
|
|
915
|
+
const { type } = node.declaration;
|
|
916
|
+
if (type === "TSTypeAliasDeclaration" || type === "TSInterfaceDeclaration") {
|
|
917
|
+
specifierExportCount++;
|
|
918
|
+
hasTypeExport = true;
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
if ("declarations" in node.declaration && node.declaration.declarations) for (const declaration of node.declaration.declarations) captureDeclaration(declaration.id);
|
|
922
|
+
else specifierExportCount++;
|
|
923
|
+
namedExportNode = node;
|
|
924
|
+
},
|
|
925
|
+
ExportDefaultDeclaration() {
|
|
926
|
+
hasDefaultExport = true;
|
|
927
|
+
},
|
|
928
|
+
ExportAllDeclaration() {
|
|
929
|
+
hasStarExport = true;
|
|
930
|
+
},
|
|
931
|
+
"Program:exit": function() {
|
|
932
|
+
if (hasDefaultExport || hasStarExport || hasTypeExport) return;
|
|
933
|
+
if (target === "single" && specifierExportCount === 1) context.report({
|
|
934
|
+
node: namedExportNode,
|
|
935
|
+
messageId: "single"
|
|
936
|
+
});
|
|
937
|
+
else if (target === "any" && specifierExportCount > 0) context.report({
|
|
938
|
+
node: namedExportNode,
|
|
939
|
+
messageId: "any"
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
//#region src/rules/index.ts
|
|
947
|
+
const rules = {
|
|
948
|
+
"consistent-type-specifier-style": consistent_type_specifier_style_default,
|
|
949
|
+
"exports-last": exports_last_default,
|
|
950
|
+
"first": first_default,
|
|
951
|
+
"newline-after-import": newline_after_import_default,
|
|
952
|
+
"no-default-export": no_default_export_default,
|
|
953
|
+
"no-duplicates": no_duplicates_default,
|
|
954
|
+
"no-mutable-exports": no_mutable_exports_default,
|
|
955
|
+
"no-named-default": no_named_default_default,
|
|
956
|
+
"prefer-default-export": prefer_default_export_default
|
|
957
|
+
};
|
|
958
|
+
|
|
959
|
+
//#endregion
|
|
960
|
+
//#region src/index.ts
|
|
961
|
+
const pluginName = "import-lite";
|
|
962
|
+
function generateConfig(name, filter = () => true) {
|
|
963
|
+
const ruleMeta = Object.entries(rules).filter(([ruleName, rule]) => !rule.meta?.deprecated && filter(ruleName, rule));
|
|
964
|
+
return {
|
|
965
|
+
name: `${pluginName}/${name}`,
|
|
966
|
+
plugins: { [pluginName]: {
|
|
967
|
+
name: pluginName,
|
|
968
|
+
rules
|
|
969
|
+
} },
|
|
970
|
+
rules: Object.fromEntries(ruleMeta.map(([ruleName]) => [`${pluginName}/${ruleName}`, "error"]))
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
var src_default = {
|
|
974
|
+
rules,
|
|
975
|
+
configs: {
|
|
976
|
+
recommended: generateConfig("recommended", (_, rule) => !!rule.meta?.docs?.recommended),
|
|
977
|
+
all: generateConfig("all")
|
|
978
|
+
}
|
|
979
|
+
};
|
|
980
|
+
|
|
981
|
+
exports.default = src_default;
|
|
982
|
+
exports.pluginName = pluginName;
|