eslint-plugin-import-lite 0.1.1 → 0.3.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 +15 -6
- package/dist/index.d.ts +6 -2
- package/dist/index.js +42 -26
- package/dist/rolldown-runtime.js +40 -0
- package/dist/rules/consistent-type-specifier-style.js +105 -4
- package/dist/rules/first.js +106 -3
- package/dist/rules/newline-after-import.js +173 -3
- package/dist/rules/no-default-export.js +54 -4
- package/dist/rules/no-duplicates.js +199 -3
- package/dist/rules/no-mutable-exports.js +45 -3
- package/dist/rules/no-named-default.js +33 -4
- package/dist/utils.js +28 -3
- package/dist/vender.js +784 -0
- package/package.json +5 -3
- package/dist/ast.js +0 -13
- package/dist/index2.d.ts +0 -9
- package/dist/rules/consistent-type-specifier-style.d.ts +0 -8
- package/dist/rules/consistent-type-specifier-style2.js +0 -111
- package/dist/rules/first.d.ts +0 -8
- package/dist/rules/first2.js +0 -105
- package/dist/rules/newline-after-import.d.ts +0 -12
- package/dist/rules/newline-after-import2.js +0 -172
- package/dist/rules/no-default-export.d.ts +0 -8
- package/dist/rules/no-default-export2.js +0 -50
- package/dist/rules/no-duplicates.d.ts +0 -18
- package/dist/rules/no-duplicates2.js +0 -196
- package/dist/rules/no-mutable-exports.d.ts +0 -8
- package/dist/rules/no-mutable-exports2.js +0 -41
- package/dist/rules/no-named-default.d.ts +0 -8
- package/dist/rules/no-named-default2.js +0 -29
package/README.md
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
# eslint-plugin-import-lite
|
|
2
2
|
|
|
3
|
+
> [!WARNING]
|
|
4
|
+
>
|
|
5
|
+
> WIP
|
|
6
|
+
>
|
|
7
|
+
> This plugin is still newly born and willing to accept useful import-related rules.
|
|
8
|
+
>
|
|
9
|
+
> Feel free to open an issue to share your ideas!
|
|
10
|
+
|
|
3
11
|
[![npm version][npm-version-src]][npm-version-href]
|
|
4
12
|
[![npm bundle size][npm-bundle-size-src]][npm-bundle-size-href]
|
|
5
13
|
[![License][license-src]][license-href]
|
|
6
14
|
|
|
7
15
|
## Feature
|
|
8
16
|
|
|
9
|
-
- Port some useful rules from [`eslint-plugin-import-x`](https://github.com/un-ts/eslint-plugin-import-x).
|
|
10
|
-
- No need resolver and settings in [`eslint-plugin-import-x`](https://github.com/un-ts/eslint-plugin-import-x).
|
|
17
|
+
- Port some useful rules that don’t require a resolver from [`eslint-plugin-import-x`](https://github.com/un-ts/eslint-plugin-import-x).
|
|
18
|
+
- No need for a resolver and settings like those in [`eslint-plugin-import-x`](https://github.com/un-ts/eslint-plugin-import-x).
|
|
11
19
|
- Drop babel and flow support.
|
|
12
20
|
|
|
13
21
|
See all rules in [`src/rules`](./src/rules)
|
|
@@ -24,7 +32,8 @@ But there are some useful rules and [some people (include me) want to bring the
|
|
|
24
32
|
|
|
25
33
|
## Credits
|
|
26
34
|
|
|
27
|
-
[eslint-plugin-import-x](https://github.com/un-ts/eslint-plugin-import-x) - [MIT](https://github.com/un-ts/eslint-plugin-import-x/blob/master/LICENSE)
|
|
35
|
+
- [eslint-plugin-import-x](https://github.com/un-ts/eslint-plugin-import-x) - source codes [MIT](https://github.com/un-ts/eslint-plugin-import-x/blob/master/LICENSE)
|
|
36
|
+
- [eslint-stylistic](https://github.com/eslint-stylistic/eslint-stylistic) - project structure and scripts [MIT](https://github.com/eslint-stylistic/eslint-stylistic/blob/main/LICENSE)
|
|
28
37
|
|
|
29
38
|
## License
|
|
30
39
|
|
|
@@ -32,9 +41,9 @@ But there are some useful rules and [some people (include me) want to bring the
|
|
|
32
41
|
|
|
33
42
|
<!-- Badges -->
|
|
34
43
|
|
|
35
|
-
[npm-version-src]: https://img.shields.io/npm/v/eslint-plugin-import-lite
|
|
44
|
+
[npm-version-src]: https://img.shields.io/npm/v/eslint-plugin-import-lite?color=00a3e0
|
|
36
45
|
[npm-version-href]: https://npmjs.com/package/eslint-plugin-import-lite
|
|
37
|
-
[npm-bundle-size-src]: https://img.shields.io/npm/unpacked-size/eslint-plugin-import-lite
|
|
46
|
+
[npm-bundle-size-src]: https://img.shields.io/npm/unpacked-size/eslint-plugin-import-lite?color=00a3e0
|
|
38
47
|
[npm-bundle-size-href]: https://npmjs.com/package/eslint-plugin-import-lite
|
|
39
|
-
[license-src]: https://img.shields.io/npm/l/eslint-plugin-import-lite
|
|
48
|
+
[license-src]: https://img.shields.io/npm/l/eslint-plugin-import-lite?color=00a3e0
|
|
40
49
|
[license-href]: https://opensource.org/licenses/MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Linter } from "eslint";
|
|
1
|
+
import { Linter, Rule } from "eslint";
|
|
3
2
|
|
|
3
|
+
//#region src/utils/index.d.ts
|
|
4
|
+
interface ESLintRuleModule<T extends readonly unknown[], TMessageIds extends string> extends Rule.RuleModule {
|
|
5
|
+
defaultOptions: T;
|
|
6
|
+
}
|
|
7
|
+
//#endregion
|
|
4
8
|
//#region src/index.d.ts
|
|
5
9
|
declare const _default: {
|
|
6
10
|
rules: Record<string, ESLintRuleModule<unknown[], string>>;
|
package/dist/index.js
CHANGED
|
@@ -1,27 +1,37 @@
|
|
|
1
|
+
import { __esm } from "./rolldown-runtime.js";
|
|
2
|
+
import "./vender.js";
|
|
1
3
|
import "./utils.js";
|
|
2
|
-
import "./
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { no_named_default_default } from "./rules/no-named-default2.js";
|
|
4
|
+
import { consistent_type_specifier_style_default, init_consistent_type_specifier_style } from "./rules/consistent-type-specifier-style.js";
|
|
5
|
+
import { first_default, init_first } from "./rules/first.js";
|
|
6
|
+
import { init_newline_after_import, newline_after_import_default } from "./rules/newline-after-import.js";
|
|
7
|
+
import { init_no_default_export, no_default_export_default } from "./rules/no-default-export.js";
|
|
8
|
+
import { init_no_duplicates, no_duplicates_default } from "./rules/no-duplicates.js";
|
|
9
|
+
import { init_no_mutable_exports, no_mutable_exports_default } from "./rules/no-mutable-exports.js";
|
|
10
|
+
import { init_no_named_default, no_named_default_default } from "./rules/no-named-default.js";
|
|
10
11
|
|
|
11
12
|
//#region src/rules/index.ts
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
var rules;
|
|
14
|
+
var init_rules = __esm({ "src/rules/index.ts"() {
|
|
15
|
+
init_consistent_type_specifier_style();
|
|
16
|
+
init_first();
|
|
17
|
+
init_newline_after_import();
|
|
18
|
+
init_no_default_export();
|
|
19
|
+
init_no_duplicates();
|
|
20
|
+
init_no_mutable_exports();
|
|
21
|
+
init_no_named_default();
|
|
22
|
+
rules = {
|
|
23
|
+
"consistent-type-specifier-style": consistent_type_specifier_style_default,
|
|
24
|
+
"first": first_default,
|
|
25
|
+
"newline-after-import": newline_after_import_default,
|
|
26
|
+
"no-default-export": no_default_export_default,
|
|
27
|
+
"no-duplicates": no_duplicates_default,
|
|
28
|
+
"no-mutable-exports": no_mutable_exports_default,
|
|
29
|
+
"no-named-default": no_named_default_default
|
|
30
|
+
};
|
|
31
|
+
} });
|
|
21
32
|
|
|
22
33
|
//#endregion
|
|
23
34
|
//#region src/index.ts
|
|
24
|
-
const pluginName = "import-lite";
|
|
25
35
|
function generateConfig(name, filter) {
|
|
26
36
|
let ruleMeta = Object.entries(rules).filter(([_, rule]) => !rule.meta?.deprecated);
|
|
27
37
|
if (filter) ruleMeta = ruleMeta.filter(([ruleName, rule]) => filter(ruleName, rule));
|
|
@@ -31,16 +41,22 @@ function generateConfig(name, filter) {
|
|
|
31
41
|
name: pluginName,
|
|
32
42
|
rules
|
|
33
43
|
} },
|
|
34
|
-
rules: Object.fromEntries(ruleMeta.map((ruleName) => [`${pluginName}/${ruleName}`, "error"]))
|
|
44
|
+
rules: Object.fromEntries(ruleMeta.map(([ruleName]) => [`${pluginName}/${ruleName}`, "error"]))
|
|
35
45
|
};
|
|
36
46
|
}
|
|
37
|
-
var src_default
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
var pluginName, src_default;
|
|
48
|
+
var init_src = __esm({ "src/index.ts"() {
|
|
49
|
+
init_rules();
|
|
50
|
+
pluginName = "import-lite";
|
|
51
|
+
src_default = {
|
|
52
|
+
rules,
|
|
53
|
+
configs: {
|
|
54
|
+
recommended: generateConfig("recommended", (_, rule) => !!rule.meta?.docs?.recommended),
|
|
55
|
+
all: generateConfig("all")
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
} });
|
|
44
59
|
|
|
45
60
|
//#endregion
|
|
61
|
+
init_src();
|
|
46
62
|
export { src_default as default };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
|
|
3
|
+
//#region rolldown:runtime
|
|
4
|
+
var __create = Object.create;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
9
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
+
var __esm = (fn, res) => function() {
|
|
11
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
12
|
+
};
|
|
13
|
+
var __commonJS = (cb, mod) => function() {
|
|
14
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
15
|
+
};
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all) __defProp(target, name, {
|
|
18
|
+
get: all[name],
|
|
19
|
+
enumerable: true
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
var __copyProps = (to, from, except, desc) => {
|
|
23
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
24
|
+
key = keys[i];
|
|
25
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
26
|
+
get: ((k) => from[k]).bind(null, key),
|
|
27
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return to;
|
|
31
|
+
};
|
|
32
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
33
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
34
|
+
value: mod,
|
|
35
|
+
enumerable: true
|
|
36
|
+
}) : target, mod));
|
|
37
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
export { __commonJS, __esm, __export, __reExport, __require, __toESM };
|
|
@@ -1,5 +1,106 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import "../
|
|
3
|
-
import { consistent_type_specifier_style_default } from "./consistent-type-specifier-style2.js";
|
|
1
|
+
import { __esm } from "../rolldown-runtime.js";
|
|
2
|
+
import { ast_exports, createRule, getValue, init_ast, init_utils } from "../utils.js";
|
|
4
3
|
|
|
5
|
-
|
|
4
|
+
//#region src/rules/consistent-type-specifier-style/consistent-type-specifier-style.ts
|
|
5
|
+
function getImportText(node, sourceCode, specifiers) {
|
|
6
|
+
const sourceString = sourceCode.getText(node.source);
|
|
7
|
+
if (specifiers.length === 0) return "";
|
|
8
|
+
const names = specifiers.map((s) => {
|
|
9
|
+
const importedName = getValue(s.imported);
|
|
10
|
+
if (importedName === s.local.name) return importedName;
|
|
11
|
+
return `${importedName} as ${s.local.name}`;
|
|
12
|
+
});
|
|
13
|
+
return `import type {${names.join(", ")}} from ${sourceString};`;
|
|
14
|
+
}
|
|
15
|
+
var consistent_type_specifier_style_default;
|
|
16
|
+
var init_consistent_type_specifier_style = __esm({ "src/rules/consistent-type-specifier-style/consistent-type-specifier-style.ts"() {
|
|
17
|
+
init_utils();
|
|
18
|
+
init_ast();
|
|
19
|
+
consistent_type_specifier_style_default = createRule({
|
|
20
|
+
name: "consistent-type-specifier-style",
|
|
21
|
+
meta: {
|
|
22
|
+
type: "suggestion",
|
|
23
|
+
docs: { description: "Enforce or ban the use of inline type-only markers for named imports." },
|
|
24
|
+
fixable: "code",
|
|
25
|
+
schema: [{
|
|
26
|
+
type: "string",
|
|
27
|
+
enum: [
|
|
28
|
+
"top-level",
|
|
29
|
+
"inline",
|
|
30
|
+
"prefer-top-level"
|
|
31
|
+
],
|
|
32
|
+
default: "top-level"
|
|
33
|
+
}],
|
|
34
|
+
messages: {
|
|
35
|
+
inline: "Prefer using inline {{kind}} specifiers instead of a top-level {{kind}}-only import.",
|
|
36
|
+
topLevel: "Prefer using a top-level {{kind}}-only import instead of inline {{kind}} specifiers."
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
defaultOptions: ["top-level"],
|
|
40
|
+
create(context, [options]) {
|
|
41
|
+
const { sourceCode } = context;
|
|
42
|
+
if (options === "inline") return { ImportDeclaration(node) {
|
|
43
|
+
if (node.importKind === "value" || node.importKind == null) return;
|
|
44
|
+
if (node.specifiers.length === 0 || node.specifiers.length === 1 && (node.specifiers[0].type === "ImportDefaultSpecifier" || node.specifiers[0].type === "ImportNamespaceSpecifier")) return;
|
|
45
|
+
context.report({
|
|
46
|
+
node,
|
|
47
|
+
messageId: "inline",
|
|
48
|
+
data: { kind: node.importKind },
|
|
49
|
+
fix(fixer) {
|
|
50
|
+
const kindToken = sourceCode.getFirstToken(node, { skip: 1 });
|
|
51
|
+
return [kindToken ? fixer.remove(kindToken) : [], node.specifiers.map((specifier) => fixer.insertTextBefore(specifier, `${node.importKind} `))].flat();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
} };
|
|
55
|
+
return { ImportDeclaration(node) {
|
|
56
|
+
if (node.importKind === "type" || node.specifiers.length === 0 || node.specifiers.length === 1 && (node.specifiers[0].type === "ImportDefaultSpecifier" || node.specifiers[0].type === "ImportNamespaceSpecifier")) return;
|
|
57
|
+
const typeSpecifiers = [];
|
|
58
|
+
const valueSpecifiers = [];
|
|
59
|
+
let defaultSpecifier = null;
|
|
60
|
+
for (const specifier of node.specifiers) {
|
|
61
|
+
if (specifier.type === "ImportDefaultSpecifier") {
|
|
62
|
+
defaultSpecifier = specifier;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (!("importKind" in specifier)) continue;
|
|
66
|
+
if (specifier.importKind === "type") typeSpecifiers.push(specifier);
|
|
67
|
+
else if (specifier.importKind === "value" || specifier.importKind == null) valueSpecifiers.push(specifier);
|
|
68
|
+
}
|
|
69
|
+
const typeImport = getImportText(node, sourceCode, typeSpecifiers);
|
|
70
|
+
if (typeSpecifiers.length === node.specifiers.length) context.report({
|
|
71
|
+
node,
|
|
72
|
+
messageId: "topLevel",
|
|
73
|
+
data: { kind: "type" },
|
|
74
|
+
fix(fixer) {
|
|
75
|
+
return fixer.replaceText(node, typeImport);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
else if (options === "top-level") for (const specifier of typeSpecifiers) context.report({
|
|
79
|
+
node: specifier,
|
|
80
|
+
messageId: "topLevel",
|
|
81
|
+
data: { kind: specifier.importKind },
|
|
82
|
+
fix(fixer) {
|
|
83
|
+
const fixes = [];
|
|
84
|
+
if (valueSpecifiers.length > 0) {
|
|
85
|
+
for (const specifier$1 of typeSpecifiers) {
|
|
86
|
+
const token = sourceCode.getTokenAfter(specifier$1);
|
|
87
|
+
if (token && (0, ast_exports.isCommaToken)(token)) fixes.push(fixer.remove(token));
|
|
88
|
+
fixes.push(fixer.remove(specifier$1));
|
|
89
|
+
}
|
|
90
|
+
const maybeComma = sourceCode.getTokenAfter(valueSpecifiers[valueSpecifiers.length - 1]);
|
|
91
|
+
if ((0, ast_exports.isCommaToken)(maybeComma)) fixes.push(fixer.remove(maybeComma));
|
|
92
|
+
} else if (defaultSpecifier) {
|
|
93
|
+
const comma = sourceCode.getTokenAfter(defaultSpecifier, ast_exports.isCommaToken);
|
|
94
|
+
const closingBrace = sourceCode.getTokenAfter(node.specifiers[node.specifiers.length - 1], (token) => token.type === "Punctuator" && token.value === "}");
|
|
95
|
+
fixes.push(fixer.removeRange([comma.range[0], closingBrace.range[1]]));
|
|
96
|
+
}
|
|
97
|
+
return [...fixes, fixer.insertTextAfter(node, `\n${typeImport}`)];
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
} };
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
} });
|
|
104
|
+
|
|
105
|
+
//#endregion
|
|
106
|
+
export { consistent_type_specifier_style_default, init_consistent_type_specifier_style };
|
package/dist/rules/first.js
CHANGED
|
@@ -1,4 +1,107 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import {
|
|
1
|
+
import { __esm } from "../rolldown-runtime.js";
|
|
2
|
+
import { createRule, init_utils } from "../utils.js";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
//#region src/rules/first/first.ts
|
|
5
|
+
function getImportValue(node) {
|
|
6
|
+
return node.type === "ImportDeclaration" ? node.source.value : "moduleReference" in node && "expression" in node.moduleReference && "value" in node.moduleReference.expression && node.moduleReference.expression.value;
|
|
7
|
+
}
|
|
8
|
+
function isPossibleDirective(node) {
|
|
9
|
+
return node.type === "ExpressionStatement" && node.expression.type === "Literal" && typeof node.expression.value === "string";
|
|
10
|
+
}
|
|
11
|
+
var first_default;
|
|
12
|
+
var init_first = __esm({ "src/rules/first/first.ts"() {
|
|
13
|
+
init_utils();
|
|
14
|
+
first_default = createRule({
|
|
15
|
+
name: "first",
|
|
16
|
+
meta: {
|
|
17
|
+
type: "suggestion",
|
|
18
|
+
docs: { description: "Ensure all imports appear before other statements." },
|
|
19
|
+
fixable: "code",
|
|
20
|
+
schema: [{
|
|
21
|
+
type: "string",
|
|
22
|
+
enum: ["absolute-first", "disable-absolute-first"]
|
|
23
|
+
}],
|
|
24
|
+
messages: {
|
|
25
|
+
absolute: "Absolute imports should come before relative imports.",
|
|
26
|
+
order: "Import in body of module; reorder to top."
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
defaultOptions: [],
|
|
30
|
+
create(context, options) {
|
|
31
|
+
return { Program(n) {
|
|
32
|
+
const body = n.body;
|
|
33
|
+
if (!body?.length) return;
|
|
34
|
+
const absoluteFirst = options[0] === "absolute-first";
|
|
35
|
+
const { sourceCode } = context;
|
|
36
|
+
const originSourceCode = sourceCode.getText();
|
|
37
|
+
let nonImportCount = 0;
|
|
38
|
+
let anyExpressions = false;
|
|
39
|
+
let anyRelative = false;
|
|
40
|
+
let lastLegalImp = null;
|
|
41
|
+
const errorInfos = [];
|
|
42
|
+
let shouldSort = true;
|
|
43
|
+
let lastSortNodesIndex = 0;
|
|
44
|
+
for (const [index, node] of body.entries()) {
|
|
45
|
+
if (!anyExpressions && isPossibleDirective(node)) continue;
|
|
46
|
+
anyExpressions = true;
|
|
47
|
+
if (node.type === "ImportDeclaration" || node.type === "TSImportEqualsDeclaration") {
|
|
48
|
+
if (absoluteFirst) {
|
|
49
|
+
const importValue = getImportValue(node);
|
|
50
|
+
if (typeof importValue === "string" && /^\./.test(importValue)) anyRelative = true;
|
|
51
|
+
else if (anyRelative) context.report({
|
|
52
|
+
node: node.type === "ImportDeclaration" ? node.source : node.moduleReference,
|
|
53
|
+
messageId: "absolute"
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if (nonImportCount > 0) {
|
|
57
|
+
/** @see https://eslint.org/docs/next/use/migrate-to-9.0.0#-removed-multiple-context-methods */
|
|
58
|
+
for (const variable of sourceCode.getDeclaredVariables(node)) {
|
|
59
|
+
if (!shouldSort) break;
|
|
60
|
+
for (const reference of variable.references) if (reference.identifier.range[0] < node.range[1]) {
|
|
61
|
+
shouldSort = false;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (shouldSort) lastSortNodesIndex = errorInfos.length;
|
|
66
|
+
errorInfos.push({
|
|
67
|
+
node,
|
|
68
|
+
range: [body[index - 1].range[1], node.range[1]]
|
|
69
|
+
});
|
|
70
|
+
} else lastLegalImp = node;
|
|
71
|
+
} else nonImportCount++;
|
|
72
|
+
}
|
|
73
|
+
if (errorInfos.length === 0) return;
|
|
74
|
+
for (const [index, { node }] of errorInfos.entries()) {
|
|
75
|
+
let fix;
|
|
76
|
+
if (index < lastSortNodesIndex) fix = (fixer) => fixer.insertTextAfter(node, "");
|
|
77
|
+
else if (index === lastSortNodesIndex) {
|
|
78
|
+
const sortNodes = errorInfos.slice(0, lastSortNodesIndex + 1);
|
|
79
|
+
fix = (fixer) => {
|
|
80
|
+
const removeFixers = sortNodes.map(({ range: range$1 }) => fixer.removeRange(range$1));
|
|
81
|
+
const range = [0, removeFixers[removeFixers.length - 1].range[1]];
|
|
82
|
+
let insertSourceCode = sortNodes.map(({ range: range$1 }) => {
|
|
83
|
+
const nodeSourceCode = originSourceCode.slice(...range$1);
|
|
84
|
+
if (/\S/.test(nodeSourceCode[0])) return `\n${nodeSourceCode}`;
|
|
85
|
+
return nodeSourceCode;
|
|
86
|
+
}).join("");
|
|
87
|
+
let replaceSourceCode = "";
|
|
88
|
+
if (!lastLegalImp) insertSourceCode = insertSourceCode.trim() + insertSourceCode.match(/^(\s+)/)[0];
|
|
89
|
+
const insertFixer = lastLegalImp ? fixer.insertTextAfter(lastLegalImp, insertSourceCode) : fixer.insertTextBefore(body[0], insertSourceCode);
|
|
90
|
+
const fixers = [insertFixer, ...removeFixers];
|
|
91
|
+
for (const [i, computedFixer] of fixers.entries()) replaceSourceCode += originSourceCode.slice(fixers[i - 1] ? fixers[i - 1].range[1] : 0, computedFixer.range[0]) + computedFixer.text;
|
|
92
|
+
return fixer.replaceTextRange(range, replaceSourceCode);
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
context.report({
|
|
96
|
+
node,
|
|
97
|
+
messageId: "order",
|
|
98
|
+
fix
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
} };
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
} });
|
|
105
|
+
|
|
106
|
+
//#endregion
|
|
107
|
+
export { first_default, init_first };
|
|
@@ -1,4 +1,174 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import {
|
|
1
|
+
import { __esm } from "../rolldown-runtime.js";
|
|
2
|
+
import { createRule, init_utils } from "../utils.js";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
//#region src/rules/newline-after-import/newline-after-import.ts
|
|
5
|
+
function isStaticRequire(node) {
|
|
6
|
+
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";
|
|
7
|
+
}
|
|
8
|
+
function containsNodeOrEqual(outerNode, innerNode) {
|
|
9
|
+
return outerNode.range[0] <= innerNode.range[0] && outerNode.range[1] >= innerNode.range[1];
|
|
10
|
+
}
|
|
11
|
+
function getScopeBody(scope) {
|
|
12
|
+
if (scope.block.type === "SwitchStatement") {
|
|
13
|
+
console.log("SwitchStatement scopes not supported");
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
const body = "body" in scope.block ? scope.block.body : null;
|
|
17
|
+
if (body && "type" in body && body.type === "BlockStatement") return body.body;
|
|
18
|
+
return Array.isArray(body) ? body : [];
|
|
19
|
+
}
|
|
20
|
+
function findNodeIndexInScopeBody(body, nodeToFind) {
|
|
21
|
+
return body.findIndex((node) => containsNodeOrEqual(node, nodeToFind));
|
|
22
|
+
}
|
|
23
|
+
function getLineDifference(node, nextNode) {
|
|
24
|
+
return nextNode.loc.start.line - node.loc.end.line;
|
|
25
|
+
}
|
|
26
|
+
function isClassWithDecorator(node) {
|
|
27
|
+
return node.type === "ClassDeclaration" && !!node.decorators?.length;
|
|
28
|
+
}
|
|
29
|
+
function isExportDefaultClass(node) {
|
|
30
|
+
return node.type === "ExportDefaultDeclaration" && node.declaration.type === "ClassDeclaration";
|
|
31
|
+
}
|
|
32
|
+
function isExportNameClass(node) {
|
|
33
|
+
return node.type === "ExportNamedDeclaration" && node.declaration?.type === "ClassDeclaration";
|
|
34
|
+
}
|
|
35
|
+
var newline_after_import_default;
|
|
36
|
+
var init_newline_after_import = __esm({ "src/rules/newline-after-import/newline-after-import.ts"() {
|
|
37
|
+
init_utils();
|
|
38
|
+
newline_after_import_default = createRule({
|
|
39
|
+
name: "newline-after-import",
|
|
40
|
+
meta: {
|
|
41
|
+
type: "layout",
|
|
42
|
+
docs: { description: "Enforce a newline after import statements." },
|
|
43
|
+
fixable: "whitespace",
|
|
44
|
+
schema: [{
|
|
45
|
+
type: "object",
|
|
46
|
+
properties: {
|
|
47
|
+
count: {
|
|
48
|
+
type: "integer",
|
|
49
|
+
minimum: 1
|
|
50
|
+
},
|
|
51
|
+
exactCount: { type: "boolean" },
|
|
52
|
+
considerComments: { type: "boolean" }
|
|
53
|
+
},
|
|
54
|
+
additionalProperties: false
|
|
55
|
+
}],
|
|
56
|
+
messages: { newline: "Expected {{count}} empty line{{lineSuffix}} after {{type}} statement not followed by another {{type}}." }
|
|
57
|
+
},
|
|
58
|
+
defaultOptions: [{
|
|
59
|
+
count: 1,
|
|
60
|
+
exactCount: false,
|
|
61
|
+
considerComments: false
|
|
62
|
+
}],
|
|
63
|
+
create(context, [options]) {
|
|
64
|
+
let level = 0;
|
|
65
|
+
const requireCalls = [];
|
|
66
|
+
function checkForNewLine(node, nextNode, type) {
|
|
67
|
+
if (isExportDefaultClass(nextNode) || isExportNameClass(nextNode)) {
|
|
68
|
+
const classNode = nextNode.declaration;
|
|
69
|
+
if (isClassWithDecorator(classNode)) nextNode = classNode.decorators[0];
|
|
70
|
+
} else if (isClassWithDecorator(nextNode)) nextNode = nextNode.decorators[0];
|
|
71
|
+
const lineDifference = getLineDifference(node, nextNode);
|
|
72
|
+
const EXPECTED_LINE_DIFFERENCE = options.count + 1;
|
|
73
|
+
if (lineDifference < EXPECTED_LINE_DIFFERENCE || options.exactCount && lineDifference !== EXPECTED_LINE_DIFFERENCE) {
|
|
74
|
+
let column = node.loc.start.column;
|
|
75
|
+
if (node.loc.start.line !== node.loc.end.line) column = 0;
|
|
76
|
+
context.report({
|
|
77
|
+
loc: {
|
|
78
|
+
line: node.loc.end.line,
|
|
79
|
+
column
|
|
80
|
+
},
|
|
81
|
+
messageId: "newline",
|
|
82
|
+
data: {
|
|
83
|
+
count: options.count,
|
|
84
|
+
lineSuffix: options.count > 1 ? "s" : "",
|
|
85
|
+
type
|
|
86
|
+
},
|
|
87
|
+
fix: options.exactCount && EXPECTED_LINE_DIFFERENCE < lineDifference ? void 0 : (fixer) => fixer.insertTextAfter(node, "\n".repeat(EXPECTED_LINE_DIFFERENCE - lineDifference))
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function commentAfterImport(node, nextComment, type) {
|
|
92
|
+
const lineDifference = getLineDifference(node, nextComment);
|
|
93
|
+
const EXPECTED_LINE_DIFFERENCE = options.count + 1;
|
|
94
|
+
if (lineDifference < EXPECTED_LINE_DIFFERENCE) {
|
|
95
|
+
let column = node.loc.start.column;
|
|
96
|
+
if (node.loc.start.line !== node.loc.end.line) column = 0;
|
|
97
|
+
context.report({
|
|
98
|
+
loc: {
|
|
99
|
+
line: node.loc.end.line,
|
|
100
|
+
column
|
|
101
|
+
},
|
|
102
|
+
messageId: "newline",
|
|
103
|
+
data: {
|
|
104
|
+
count: options.count,
|
|
105
|
+
lineSuffix: options.count > 1 ? "s" : "",
|
|
106
|
+
type
|
|
107
|
+
},
|
|
108
|
+
fix: options.exactCount && EXPECTED_LINE_DIFFERENCE < lineDifference ? void 0 : (fixer) => fixer.insertTextAfter(node, "\n".repeat(EXPECTED_LINE_DIFFERENCE - lineDifference))
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function incrementLevel() {
|
|
113
|
+
level++;
|
|
114
|
+
}
|
|
115
|
+
function decrementLevel() {
|
|
116
|
+
level--;
|
|
117
|
+
}
|
|
118
|
+
function checkImport(node) {
|
|
119
|
+
const { parent } = node;
|
|
120
|
+
if (!parent || !("body" in parent) || !parent.body) return;
|
|
121
|
+
const root = parent;
|
|
122
|
+
const nodePosition = root.body.indexOf(node);
|
|
123
|
+
const nextNode = root.body[nodePosition + 1];
|
|
124
|
+
const endLine = node.loc.end.line;
|
|
125
|
+
let nextComment;
|
|
126
|
+
if (root.comments !== void 0 && options.considerComments) nextComment = root.comments.find((o) => o.loc.start.line >= endLine && o.loc.start.line <= endLine + options.count + 1);
|
|
127
|
+
if (node.type === "TSImportEqualsDeclaration" && node.isExport) return;
|
|
128
|
+
if (nextComment) commentAfterImport(node, nextComment, "import");
|
|
129
|
+
else if (nextNode && nextNode.type !== "ImportDeclaration" && (nextNode.type !== "TSImportEqualsDeclaration" || nextNode.isExport)) checkForNewLine(node, nextNode, "import");
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
"ImportDeclaration": checkImport,
|
|
133
|
+
"TSImportEqualsDeclaration": checkImport,
|
|
134
|
+
CallExpression(node) {
|
|
135
|
+
if (isStaticRequire(node) && level === 0) requireCalls.push(node);
|
|
136
|
+
},
|
|
137
|
+
"Program:exit": function(node) {
|
|
138
|
+
const scopeBody = getScopeBody(context.sourceCode.getScope(node));
|
|
139
|
+
for (const [index, node$1] of requireCalls.entries()) {
|
|
140
|
+
const nodePosition = findNodeIndexInScopeBody(scopeBody, node$1);
|
|
141
|
+
const statementWithRequireCall = scopeBody[nodePosition];
|
|
142
|
+
const nextStatement = scopeBody[nodePosition + 1];
|
|
143
|
+
const nextRequireCall = requireCalls[index + 1];
|
|
144
|
+
if (nextRequireCall && containsNodeOrEqual(statementWithRequireCall, nextRequireCall)) continue;
|
|
145
|
+
if (nextStatement && (!nextRequireCall || !containsNodeOrEqual(nextStatement, nextRequireCall))) {
|
|
146
|
+
let nextComment;
|
|
147
|
+
if ("comments" in statementWithRequireCall.parent && statementWithRequireCall.parent.comments !== void 0 && options.considerComments) {
|
|
148
|
+
const endLine = node$1.loc.end.line;
|
|
149
|
+
nextComment = statementWithRequireCall.parent.comments.find((o) => o.loc.start.line >= endLine && o.loc.start.line <= endLine + options.count + 1);
|
|
150
|
+
}
|
|
151
|
+
if (nextComment && nextComment !== void 0) commentAfterImport(statementWithRequireCall, nextComment, "require");
|
|
152
|
+
else checkForNewLine(statementWithRequireCall, nextStatement, "require");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"FunctionDeclaration": incrementLevel,
|
|
157
|
+
"FunctionExpression": incrementLevel,
|
|
158
|
+
"ArrowFunctionExpression": incrementLevel,
|
|
159
|
+
"BlockStatement": incrementLevel,
|
|
160
|
+
"ObjectExpression": incrementLevel,
|
|
161
|
+
"Decorator": incrementLevel,
|
|
162
|
+
"FunctionDeclaration:exit": decrementLevel,
|
|
163
|
+
"FunctionExpression:exit": decrementLevel,
|
|
164
|
+
"ArrowFunctionExpression:exit": decrementLevel,
|
|
165
|
+
"BlockStatement:exit": decrementLevel,
|
|
166
|
+
"ObjectExpression:exit": decrementLevel,
|
|
167
|
+
"Decorator:exit": decrementLevel
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
} });
|
|
172
|
+
|
|
173
|
+
//#endregion
|
|
174
|
+
export { init_newline_after_import, newline_after_import_default };
|
|
@@ -1,5 +1,55 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import "../
|
|
3
|
-
import { no_default_export_default } from "./no-default-export2.js";
|
|
1
|
+
import { __esm } from "../rolldown-runtime.js";
|
|
2
|
+
import { createRule, getValue, init_ast, init_utils, sourceType } from "../utils.js";
|
|
4
3
|
|
|
5
|
-
|
|
4
|
+
//#region src/rules/no-default-export/no-default-export.ts
|
|
5
|
+
var no_default_export_default;
|
|
6
|
+
var init_no_default_export = __esm({ "src/rules/no-default-export/no-default-export.ts"() {
|
|
7
|
+
init_utils();
|
|
8
|
+
init_ast();
|
|
9
|
+
no_default_export_default = createRule({
|
|
10
|
+
name: "no-default-export",
|
|
11
|
+
meta: {
|
|
12
|
+
type: "suggestion",
|
|
13
|
+
docs: { description: "Forbid default exports." },
|
|
14
|
+
schema: [],
|
|
15
|
+
messages: {
|
|
16
|
+
preferNamed: "Prefer named exports.",
|
|
17
|
+
noAliasDefault: "Do not alias `{{local}}` as `default`. Just export `{{local}}` itself instead."
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
if (sourceType(context) !== "module") return {};
|
|
23
|
+
const { sourceCode } = context;
|
|
24
|
+
return {
|
|
25
|
+
ExportDefaultDeclaration(node) {
|
|
26
|
+
const { loc } = sourceCode.getFirstTokens(node)[1] || {};
|
|
27
|
+
context.report({
|
|
28
|
+
node,
|
|
29
|
+
messageId: "preferNamed",
|
|
30
|
+
loc
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
ExportNamedDeclaration(node) {
|
|
34
|
+
for (const specifier of node.specifiers.filter((specifier$1) => getValue(specifier$1.exported) === "default")) {
|
|
35
|
+
const { loc } = sourceCode.getFirstTokens(node)[1] || {};
|
|
36
|
+
if (specifier.type === "ExportDefaultSpecifier") context.report({
|
|
37
|
+
node,
|
|
38
|
+
messageId: "preferNamed",
|
|
39
|
+
loc
|
|
40
|
+
});
|
|
41
|
+
else if (specifier.type === "ExportSpecifier") context.report({
|
|
42
|
+
node,
|
|
43
|
+
messageId: "noAliasDefault",
|
|
44
|
+
data: { local: getValue(specifier.local) },
|
|
45
|
+
loc
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
} });
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
export { init_no_default_export, no_default_export_default };
|