eslint-config-webpack 4.1.4 → 4.2.1
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/configs/browser.js +15 -1
- package/configs/index.js +2 -0
- package/configs/javascript.js +31 -24
- package/configs/jest.js +15 -0
- package/configs/markdown.js +4 -0
- package/configs/node.js +7 -5
- package/configs/package-json.js +9 -0
- package/configs/stylistic.js +1 -1
- package/configs/utils/extensions.js +1 -1
- package/configs.js +5 -1
- package/ignore-paths.js +63 -3
- package/package.json +26 -21
- package/plugins/package-json/index.js +48 -0
- package/plugins/package-json/rules/order-properties.js +187 -0
package/configs/browser.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import globals from "globals";
|
|
2
1
|
import importPlugin from "eslint-plugin-import";
|
|
2
|
+
import globals from "globals";
|
|
3
3
|
|
|
4
4
|
const recommendedBrowserConfig = {
|
|
5
5
|
languageOptions: {
|
|
@@ -11,6 +11,20 @@ const recommendedBrowserConfig = {
|
|
|
11
11
|
import: importPlugin,
|
|
12
12
|
},
|
|
13
13
|
rules: {
|
|
14
|
+
"unicorn/prefer-dom-node-append": "error",
|
|
15
|
+
|
|
16
|
+
"unicorn/prefer-dom-node-dataset": "error",
|
|
17
|
+
|
|
18
|
+
"unicorn/prefer-dom-node-remove": "error",
|
|
19
|
+
|
|
20
|
+
"unicorn/prefer-dom-node-text-content": "error",
|
|
21
|
+
|
|
22
|
+
"unicorn/prefer-modern-dom-apis": "error",
|
|
23
|
+
|
|
24
|
+
"unicorn/prefer-keyboard-event-key": "error",
|
|
25
|
+
|
|
26
|
+
"unicorn/prefer-query-selector": "error",
|
|
27
|
+
|
|
14
28
|
"import/extensions": ["error", "always", { ignorePackages: true }],
|
|
15
29
|
},
|
|
16
30
|
};
|
package/configs/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import javascriptConfig from "./javascript.js";
|
|
|
3
3
|
import jestConfig from "./jest.js";
|
|
4
4
|
import markdownConfig from "./markdown.js";
|
|
5
5
|
import nodeConfig from "./node.js";
|
|
6
|
+
import packageJSON from "./package-json.js";
|
|
6
7
|
import stylisticConfig from "./stylistic.js";
|
|
7
8
|
import typescriptConfig from "./typescript.js";
|
|
8
9
|
|
|
@@ -14,6 +15,7 @@ const configs = {
|
|
|
14
15
|
...nodeConfig,
|
|
15
16
|
...stylisticConfig,
|
|
16
17
|
...typescriptConfig,
|
|
18
|
+
...packageJSON,
|
|
17
19
|
};
|
|
18
20
|
|
|
19
21
|
export default configs;
|
package/configs/javascript.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import globals from "globals";
|
|
2
1
|
import javascriptConfig from "@eslint/js";
|
|
3
|
-
import unicornPlugin from "eslint-plugin-unicorn";
|
|
4
2
|
import importPlugin from "eslint-plugin-import";
|
|
3
|
+
import unicornPlugin from "eslint-plugin-unicorn";
|
|
4
|
+
import globals from "globals";
|
|
5
5
|
import { allExtensions } from "./utils/extensions.js";
|
|
6
6
|
|
|
7
7
|
const possibleProblems = {
|
|
@@ -885,13 +885,17 @@ const unicornRules = {
|
|
|
885
885
|
|
|
886
886
|
"unicorn/prefer-default-parameters": "error",
|
|
887
887
|
|
|
888
|
-
|
|
888
|
+
// Not here, define only for `browsers`
|
|
889
|
+
// "unicorn/prefer-dom-node-append": "error",
|
|
889
890
|
|
|
890
|
-
|
|
891
|
+
// Not here, define only for `browsers`
|
|
892
|
+
// "unicorn/prefer-dom-node-dataset": "error",
|
|
891
893
|
|
|
892
|
-
|
|
894
|
+
// Not here, define only for `browsers`
|
|
895
|
+
// "unicorn/prefer-dom-node-remove": "error",
|
|
893
896
|
|
|
894
|
-
|
|
897
|
+
// Not here, define only for `browsers`
|
|
898
|
+
// "unicorn/prefer-dom-node-text-content": "error",
|
|
895
899
|
|
|
896
900
|
"unicorn/prefer-event-target": "error",
|
|
897
901
|
|
|
@@ -907,7 +911,8 @@ const unicornRules = {
|
|
|
907
911
|
// No need
|
|
908
912
|
// "unicorn/prefer-json-parse-buffer": "off",
|
|
909
913
|
|
|
910
|
-
|
|
914
|
+
// Not here, define only for `browsers`
|
|
915
|
+
// "unicorn/prefer-keyboard-event-key": "error",
|
|
911
916
|
|
|
912
917
|
"unicorn/prefer-logical-operator-over-ternary": "error",
|
|
913
918
|
|
|
@@ -918,7 +923,8 @@ const unicornRules = {
|
|
|
918
923
|
// `| 0` is faster
|
|
919
924
|
// "unicorn/prefer-math-trunc": "off",
|
|
920
925
|
|
|
921
|
-
|
|
926
|
+
// Not here, define only for `browsers`
|
|
927
|
+
// "unicorn/prefer-modern-dom-apis": "error",
|
|
922
928
|
|
|
923
929
|
"unicorn/prefer-modern-math-apis": "error",
|
|
924
930
|
|
|
@@ -941,7 +947,8 @@ const unicornRules = {
|
|
|
941
947
|
|
|
942
948
|
"unicorn/prefer-prototype-methods": "error",
|
|
943
949
|
|
|
944
|
-
|
|
950
|
+
// Not here, define only for `browsers`
|
|
951
|
+
// "unicorn/prefer-query-selector": "error",
|
|
945
952
|
|
|
946
953
|
// No need
|
|
947
954
|
// "unicorn/prefer-reflect-apply": "off",
|
|
@@ -1141,21 +1148,20 @@ const importRules = {
|
|
|
1141
1148
|
// No need
|
|
1142
1149
|
// "import/no-unassigned-import": "off",
|
|
1143
1150
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
// ],
|
|
1151
|
+
"import/order": [
|
|
1152
|
+
"error",
|
|
1153
|
+
{
|
|
1154
|
+
named: {
|
|
1155
|
+
enabled: true,
|
|
1156
|
+
import: true,
|
|
1157
|
+
export: true,
|
|
1158
|
+
require: true,
|
|
1159
|
+
cjsExports: true,
|
|
1160
|
+
types: "mixed",
|
|
1161
|
+
},
|
|
1162
|
+
alphabetize: { order: "asc" },
|
|
1163
|
+
},
|
|
1164
|
+
],
|
|
1159
1165
|
|
|
1160
1166
|
// No need
|
|
1161
1167
|
// "import/prefer-default-export": "off",
|
|
@@ -1195,6 +1201,7 @@ function getConfig(esVersion) {
|
|
|
1195
1201
|
},
|
|
1196
1202
|
linterOptions: {
|
|
1197
1203
|
reportUnusedDisableDirectives: true,
|
|
1204
|
+
reportUnusedInlineConfigs: "error",
|
|
1198
1205
|
},
|
|
1199
1206
|
rules: {
|
|
1200
1207
|
...javascriptConfig.configs.recommended.rules,
|
package/configs/jest.js
CHANGED
|
@@ -206,6 +206,21 @@ async function getJestRecommendedConfig() {
|
|
|
206
206
|
// Allow to output information in tests
|
|
207
207
|
"no-console": "off",
|
|
208
208
|
|
|
209
|
+
// Allow to use `eval` for tests
|
|
210
|
+
"no-eval": "off",
|
|
211
|
+
|
|
212
|
+
// Allow to have any regexps in tests, useful to clean up/etc
|
|
213
|
+
"no-control-regex": "off",
|
|
214
|
+
|
|
215
|
+
// Allow to use any builtins, syntax and node API in tests
|
|
216
|
+
"n/no-unsupported-features/es-builtins": "off",
|
|
217
|
+
"n/no-unsupported-features/es-syntax": "off",
|
|
218
|
+
"n/no-unsupported-features/node-builtins": "off",
|
|
219
|
+
|
|
220
|
+
// Allow to `require` and `import` any things in tests
|
|
221
|
+
"n/no-unpublished-require": "off",
|
|
222
|
+
"n/no-unpublished-import": "off",
|
|
223
|
+
|
|
209
224
|
// Doesn't require jsdoc for tests, they are either redundant or we have a separate task for checking types of tests
|
|
210
225
|
"jsdoc/require-jsdoc": "off",
|
|
211
226
|
},
|
package/configs/markdown.js
CHANGED
package/configs/node.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import globals from "globals";
|
|
2
1
|
import importPlugin from "eslint-plugin-import";
|
|
2
|
+
import globals from "globals";
|
|
3
3
|
|
|
4
4
|
const commonRules = {
|
|
5
5
|
// No need
|
|
@@ -38,11 +38,11 @@ const commonRules = {
|
|
|
38
38
|
// Deprecated
|
|
39
39
|
// "n/no-hide-core-modules": "error",
|
|
40
40
|
|
|
41
|
-
//
|
|
42
|
-
|
|
41
|
+
// We have `import/no-unresolved` rule
|
|
42
|
+
"n/no-missing-import": "off",
|
|
43
43
|
|
|
44
|
-
//
|
|
45
|
-
|
|
44
|
+
// We have `import/no-unresolved` rule
|
|
45
|
+
"n/no-missing-require": "off",
|
|
46
46
|
|
|
47
47
|
// No need
|
|
48
48
|
// "n/no-mixed-requires": "error",
|
|
@@ -144,6 +144,7 @@ async function getCommonJSConfig() {
|
|
|
144
144
|
import: importPlugin,
|
|
145
145
|
},
|
|
146
146
|
rules: {
|
|
147
|
+
...nodeConfig.rules,
|
|
147
148
|
...commonRules,
|
|
148
149
|
"n/exports-style": "error",
|
|
149
150
|
"n/no-path-concat": "error",
|
|
@@ -200,6 +201,7 @@ async function getModuleConfig() {
|
|
|
200
201
|
import: importPlugin,
|
|
201
202
|
},
|
|
202
203
|
rules: {
|
|
204
|
+
...nodeConfig.rules,
|
|
203
205
|
...commonRules,
|
|
204
206
|
"import/extensions": [
|
|
205
207
|
"error",
|
package/configs/stylistic.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import stylisticPlugin from "@stylistic/eslint-plugin";
|
|
1
2
|
import prettierPlugin from "eslint-plugin-prettier";
|
|
2
3
|
import prettierConfig from "eslint-plugin-prettier/recommended";
|
|
3
|
-
import stylisticPlugin from "@stylistic/eslint-plugin";
|
|
4
4
|
|
|
5
5
|
const recommendedConfig = {
|
|
6
6
|
...prettierConfig,
|
|
@@ -2,4 +2,4 @@ const javascriptExtensions = [".js", ".cjs", ".mjs", ".jsx"];
|
|
|
2
2
|
const typescriptExtensions = [".ts", ".cts", ".mts", ".tsx"];
|
|
3
3
|
const allExtensions = [...javascriptExtensions, ...typescriptExtensions];
|
|
4
4
|
|
|
5
|
-
export { javascriptExtensions, typescriptExtensions
|
|
5
|
+
export { allExtensions, javascriptExtensions, typescriptExtensions };
|
package/configs.js
CHANGED
|
@@ -3,8 +3,8 @@ import path from "node:path";
|
|
|
3
3
|
import { globalIgnores } from "eslint/config";
|
|
4
4
|
import semver from "semver";
|
|
5
5
|
import configs from "./configs/index.js";
|
|
6
|
-
import ignorePaths from "./ignore-paths.js";
|
|
7
6
|
import { typescriptExtensions } from "./configs/utils/extensions.js";
|
|
7
|
+
import ignorePaths from "./ignore-paths.js";
|
|
8
8
|
|
|
9
9
|
const SKIP_TIME = 5000;
|
|
10
10
|
|
|
@@ -295,6 +295,7 @@ configs.recommended = [
|
|
|
295
295
|
jestConfig,
|
|
296
296
|
configs["markdown/recommended"],
|
|
297
297
|
configs["stylistic/recommended"],
|
|
298
|
+
configs["package-json/recommended"],
|
|
298
299
|
];
|
|
299
300
|
|
|
300
301
|
configs["recommended-module"] = [
|
|
@@ -306,6 +307,7 @@ configs["recommended-module"] = [
|
|
|
306
307
|
jestConfig,
|
|
307
308
|
configs["markdown/recommended"],
|
|
308
309
|
configs["stylistic/recommended"],
|
|
310
|
+
configs["package-json/recommended"],
|
|
309
311
|
];
|
|
310
312
|
|
|
311
313
|
configs["recommended-commonjs"] = [
|
|
@@ -317,6 +319,7 @@ configs["recommended-commonjs"] = [
|
|
|
317
319
|
jestConfig,
|
|
318
320
|
configs["markdown/recommended"],
|
|
319
321
|
configs["stylistic/recommended"],
|
|
322
|
+
configs["package-json/recommended"],
|
|
320
323
|
];
|
|
321
324
|
|
|
322
325
|
configs["recommended-dirty"] = [
|
|
@@ -328,6 +331,7 @@ configs["recommended-dirty"] = [
|
|
|
328
331
|
jestConfig,
|
|
329
332
|
configs["markdown/recommended"],
|
|
330
333
|
configs["stylistic/recommended"],
|
|
334
|
+
configs["package-json/recommended"],
|
|
331
335
|
];
|
|
332
336
|
|
|
333
337
|
export { default } from "./configs/index.js";
|
package/ignore-paths.js
CHANGED
|
@@ -1,9 +1,69 @@
|
|
|
1
1
|
export default [
|
|
2
|
-
|
|
2
|
+
// OS
|
|
3
|
+
".DS_Store",
|
|
4
|
+
"Thumbs.db",
|
|
5
|
+
|
|
6
|
+
// IDE
|
|
7
|
+
".idea",
|
|
8
|
+
"*.iml",
|
|
9
|
+
".vscode",
|
|
10
|
+
".vscode-test",
|
|
11
|
+
"*.sublime-project",
|
|
12
|
+
"*.sublime-workspace",
|
|
13
|
+
|
|
14
|
+
// Logs
|
|
15
|
+
"logs/**/*",
|
|
16
|
+
"*.log",
|
|
17
|
+
"npm-debug.log*",
|
|
18
|
+
"yarn-debug.log*",
|
|
19
|
+
"yarn-error.log*",
|
|
20
|
+
"lerna-debug.log*",
|
|
21
|
+
|
|
22
|
+
// Diagnostic reports (https://nodejs.org/api/report.html)
|
|
23
|
+
"report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json",
|
|
24
|
+
|
|
25
|
+
// Runtime data
|
|
26
|
+
"pids",
|
|
27
|
+
"*.pid",
|
|
28
|
+
"*.seed",
|
|
29
|
+
"*.pid.lock",
|
|
30
|
+
|
|
31
|
+
// Directory for instrumented libs generated by jscoverage/JSCover
|
|
32
|
+
"lib-cov/**/*",
|
|
33
|
+
|
|
34
|
+
// Coverage directory used by tools like istanbul
|
|
35
|
+
"coverage/**/*",
|
|
36
|
+
"*.lcov",
|
|
37
|
+
|
|
38
|
+
// nyc test coverage
|
|
39
|
+
".nyc_output",
|
|
40
|
+
|
|
41
|
+
// Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
42
|
+
"build/Release/**/*",
|
|
43
|
+
|
|
44
|
+
// Dependencies
|
|
3
45
|
"node_modules/**/*",
|
|
46
|
+
|
|
47
|
+
// Optional REPL history
|
|
48
|
+
".node_repl_history",
|
|
49
|
+
|
|
50
|
+
// Generated code
|
|
4
51
|
"dist/**/*",
|
|
5
|
-
|
|
52
|
+
|
|
53
|
+
// Test
|
|
6
54
|
"test/fixtures/**/*",
|
|
7
55
|
"test/outputs/**/*",
|
|
8
|
-
|
|
56
|
+
|
|
57
|
+
// Generated types
|
|
58
|
+
"types/**/*",
|
|
59
|
+
|
|
60
|
+
// Reports
|
|
61
|
+
"reports/**/*",
|
|
62
|
+
|
|
63
|
+
// Caches
|
|
64
|
+
".cache/**/*",
|
|
65
|
+
".eslintcache",
|
|
66
|
+
".stylelintcache",
|
|
67
|
+
".cspellcache",
|
|
68
|
+
"*.tsbuildinfo",
|
|
9
69
|
];
|
package/package.json
CHANGED
|
@@ -1,13 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-config-webpack",
|
|
3
|
-
"version": "4.1
|
|
4
|
-
"author": "Joshua Wiens (https://twitter.com/@d3viant0ne)",
|
|
5
|
-
"license": "MIT",
|
|
3
|
+
"version": "4.2.1",
|
|
6
4
|
"description": "Provides Webpack's eslint rules as an extensible shared config",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"eslint",
|
|
7
|
+
"eslintconfig",
|
|
8
|
+
"config",
|
|
9
|
+
"webpack",
|
|
10
|
+
"javascript",
|
|
11
|
+
"typescript"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/webpack/eslint-config-webpack#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/webpack/eslint-config-webpack/issues"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/webpack/eslint-config-webpack.git"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": "Joshua Wiens (https://twitter.com/@d3viant0ne)",
|
|
7
23
|
"type": "module",
|
|
8
24
|
"main": "index.js",
|
|
9
25
|
"files": [
|
|
10
26
|
"index.js",
|
|
27
|
+
"plugins",
|
|
11
28
|
"prettier-config.js",
|
|
12
29
|
"prettier-config-es5.js",
|
|
13
30
|
"configs.js",
|
|
@@ -16,11 +33,14 @@
|
|
|
16
33
|
],
|
|
17
34
|
"scripts": {
|
|
18
35
|
"lint": "npm run lint:code",
|
|
19
|
-
"lint:code": "
|
|
36
|
+
"lint:code": "eslint --cache .",
|
|
20
37
|
"release": "standard-version"
|
|
21
38
|
},
|
|
22
39
|
"dependencies": {
|
|
23
|
-
"
|
|
40
|
+
"detect-indent": "^7.0.1",
|
|
41
|
+
"jsonc-eslint-parser": "^2.4.0",
|
|
42
|
+
"semver": "^7.7.2",
|
|
43
|
+
"sort-package-json": "^3.3.1"
|
|
24
44
|
},
|
|
25
45
|
"devDependencies": {
|
|
26
46
|
"@eslint/js": "^9.29.0",
|
|
@@ -80,20 +100,5 @@
|
|
|
80
100
|
},
|
|
81
101
|
"engines": {
|
|
82
102
|
"node": ">= 18.20.0"
|
|
83
|
-
}
|
|
84
|
-
"repository": {
|
|
85
|
-
"type": "git",
|
|
86
|
-
"url": "git+https://github.com/webpack/eslint-config-webpack.git"
|
|
87
|
-
},
|
|
88
|
-
"keywords": [
|
|
89
|
-
"eslint",
|
|
90
|
-
"eslintconfig",
|
|
91
|
-
"config",
|
|
92
|
-
"webpack",
|
|
93
|
-
"javascirpt"
|
|
94
|
-
],
|
|
95
|
-
"bugs": {
|
|
96
|
-
"url": "https://github.com/webpack/eslint-config-webpack/issues"
|
|
97
|
-
},
|
|
98
|
-
"homepage": "https://github.com/webpack/eslint-config-webpack#readme"
|
|
103
|
+
}
|
|
99
104
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import * as parserJsonc from "jsonc-eslint-parser";
|
|
3
|
+
import { rule as orderProperties } from "./rules/order-properties.js";
|
|
4
|
+
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
|
|
7
|
+
const { version } = require("../../package.json");
|
|
8
|
+
|
|
9
|
+
const rules = {
|
|
10
|
+
"order-properties": orderProperties,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const recommendedRules = {
|
|
14
|
+
...Object.fromEntries(
|
|
15
|
+
Object.entries(rules)
|
|
16
|
+
.filter(([, rule]) => rule.meta.docs?.recommended)
|
|
17
|
+
.map(([name]) => [`package-json/${name}`, "error"]),
|
|
18
|
+
),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const configs = {
|
|
22
|
+
recommended: {
|
|
23
|
+
name: "package-json/recommended",
|
|
24
|
+
files: ["**/package.json"],
|
|
25
|
+
languageOptions: {
|
|
26
|
+
parser: parserJsonc,
|
|
27
|
+
},
|
|
28
|
+
plugins: {
|
|
29
|
+
get "package-json"() {
|
|
30
|
+
// eslint-disable-next-line no-use-before-define
|
|
31
|
+
return plugin;
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
rules: recommendedRules,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const plugin = {
|
|
39
|
+
configs,
|
|
40
|
+
meta: {
|
|
41
|
+
version,
|
|
42
|
+
},
|
|
43
|
+
rules,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export { configs, rules };
|
|
47
|
+
|
|
48
|
+
export default plugin;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import detectIndent from "detect-indent";
|
|
2
|
+
import { sortOrder } from "sort-package-json";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {string} string string
|
|
6
|
+
* @returns {"\r\n" | "\n"} detected newline
|
|
7
|
+
*/
|
|
8
|
+
function detectNewline(string) {
|
|
9
|
+
if (typeof string !== "string") {
|
|
10
|
+
throw new TypeError("Expected a string");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const newlines = string.match(/(?:\r?\n)/g) || [];
|
|
14
|
+
|
|
15
|
+
if (newlines.length === 0) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const crlf = newlines.filter((newline) => newline === "\r\n").length;
|
|
20
|
+
const lf = newlines.length - crlf;
|
|
21
|
+
|
|
22
|
+
return crlf > lf ? "\r\n" : "\n";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {string} string string
|
|
27
|
+
* @returns {string} result
|
|
28
|
+
*/
|
|
29
|
+
function detectNewlineGraceful(string) {
|
|
30
|
+
return detectNewline(string) || "\n";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// eslint-disable-next-line jsdoc/no-restricted-syntax
|
|
34
|
+
/** @typedef {Record<string, any>} ObjectToSort */
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {ObjectToSort} object object to sort
|
|
38
|
+
* @param {(a: number, b: number) => number} sortWith function to sort
|
|
39
|
+
* @returns {ObjectToSort} object with sorted properties
|
|
40
|
+
*/
|
|
41
|
+
function sortObjectKeys(object, sortWith) {
|
|
42
|
+
let keys;
|
|
43
|
+
let sortFn;
|
|
44
|
+
|
|
45
|
+
if (typeof sortWith === "function") {
|
|
46
|
+
sortFn = sortWith;
|
|
47
|
+
} else {
|
|
48
|
+
keys = sortWith;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const objectKeys = Object.keys(object);
|
|
52
|
+
|
|
53
|
+
return (keys || [...objectKeys.sort(sortFn)]).reduce((total, key) => {
|
|
54
|
+
if (Object.hasOwn(object, key)) {
|
|
55
|
+
total[key] = object[key];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return total;
|
|
59
|
+
}, Object.create(null));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param {string} filePath file path
|
|
64
|
+
* @returns {boolean} result
|
|
65
|
+
*/
|
|
66
|
+
export const isPackageJson = (filePath) =>
|
|
67
|
+
/(?:^|[/\\])package.json$/.test(filePath);
|
|
68
|
+
|
|
69
|
+
// eslint-disable-next-line jsdoc/no-restricted-syntax
|
|
70
|
+
/**
|
|
71
|
+
* @typedef {import("eslint").AST.Program} PackageJsonAst
|
|
72
|
+
* @property {[any]} body body
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @typedef {import("eslint").SourceCode} PackageJsonSourceCode
|
|
77
|
+
* @property {PackageJsonAst} ast ast
|
|
78
|
+
*/
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @template {unknown[]} [Options=unknown[]]
|
|
82
|
+
* @typedef {import("eslint").RuleContext} PackageJsonRuleContext
|
|
83
|
+
* @property {Options} options options
|
|
84
|
+
* @property {PackageJsonSourceCode} sourceCode source code
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @template {unknown[]} Options
|
|
89
|
+
* @typedef {object} PackageJsonRuleModule
|
|
90
|
+
* @property {import("eslint").Rule.RuleMetaData} meta meta
|
|
91
|
+
* @property {(context: PackageJsonRuleContext<Options>) => import("eslint").RuleListener} create function to create
|
|
92
|
+
*/
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @type {import("eslint").Rule} rule
|
|
96
|
+
*/
|
|
97
|
+
export const rule = {
|
|
98
|
+
create(context) {
|
|
99
|
+
if (!isPackageJson(context.filename)) {
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
"Program:exit"() {
|
|
105
|
+
const { ast, text } = context.sourceCode;
|
|
106
|
+
|
|
107
|
+
const options = {
|
|
108
|
+
order: "sort-package-json",
|
|
109
|
+
...context.options[0],
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const requiredOrder =
|
|
113
|
+
options.order === "sort-package-json" ? sortOrder : options.order;
|
|
114
|
+
|
|
115
|
+
const json = JSON.parse(text);
|
|
116
|
+
const orderedSource = sortObjectKeys(json, [
|
|
117
|
+
...requiredOrder,
|
|
118
|
+
...Object.keys(json),
|
|
119
|
+
]);
|
|
120
|
+
const orderedKeys = Object.keys(orderedSource);
|
|
121
|
+
|
|
122
|
+
const { properties } = ast.body[0].expression;
|
|
123
|
+
|
|
124
|
+
for (let i = 0; i < properties.length; i += 1) {
|
|
125
|
+
const property = properties[i].key;
|
|
126
|
+
const { value } = property;
|
|
127
|
+
|
|
128
|
+
if (value === orderedKeys[i]) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
context.report({
|
|
133
|
+
data: {
|
|
134
|
+
property: value,
|
|
135
|
+
},
|
|
136
|
+
fix(fixer) {
|
|
137
|
+
const { indent, type } = detectIndent(text);
|
|
138
|
+
const endCharacters = text.endsWith("\n") ? "\n" : "";
|
|
139
|
+
const newline = detectNewlineGraceful(text);
|
|
140
|
+
let result =
|
|
141
|
+
JSON.stringify(
|
|
142
|
+
orderedSource,
|
|
143
|
+
null,
|
|
144
|
+
type === "tab" ? "\t" : indent,
|
|
145
|
+
) + endCharacters;
|
|
146
|
+
if (newline === "\r\n") {
|
|
147
|
+
result = result.replaceAll("\n", newline);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return fixer.replaceText(context.sourceCode.ast, result);
|
|
151
|
+
},
|
|
152
|
+
loc: properties[i].loc,
|
|
153
|
+
messageId: "incorrectOrder",
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
},
|
|
159
|
+
meta: {
|
|
160
|
+
docs: {
|
|
161
|
+
category: "Best Practices",
|
|
162
|
+
description: "Package properties must be declared in standard order",
|
|
163
|
+
recommended: true,
|
|
164
|
+
},
|
|
165
|
+
fixable: "code",
|
|
166
|
+
messages: {
|
|
167
|
+
incorrectOrder:
|
|
168
|
+
'Package top-level property "{{property}}" is not ordered in the npm standard way. Run the ESLint auto-fixer to correct.',
|
|
169
|
+
},
|
|
170
|
+
schema: [
|
|
171
|
+
{
|
|
172
|
+
properties: {
|
|
173
|
+
order: {
|
|
174
|
+
anyOf: [
|
|
175
|
+
{
|
|
176
|
+
enum: ["sort-package-json"],
|
|
177
|
+
type: ["string"],
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
type: "object",
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
type: "layout",
|
|
186
|
+
},
|
|
187
|
+
};
|