eslint-plugin-package-json 1.2.0 → 1.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
CHANGED
|
@@ -43,6 +43,7 @@ See [Getting Started](https://eslint-plugin-package-json.dev/getting-started) fo
|
|
|
43
43
|
| [bin-name-casing](https://eslint-plugin-package-json.dev/rules/bin-name-casing) | Enforce that names for bin properties are in kebab case. | 🎨 | | 💡 |
|
|
44
44
|
| [exports-subpaths-style](https://eslint-plugin-package-json.dev/rules/exports-subpaths-style) | Enforce consistent format for the exports field (implicit or explicit subpaths). | 🎨 | 🔧 | |
|
|
45
45
|
| [no-empty-fields](https://eslint-plugin-package-json.dev/rules/no-empty-fields) | Reports on unnecessary empty arrays and objects. | ✅ 📦 | | 💡 |
|
|
46
|
+
| [no-local-dependencies](https://eslint-plugin-package-json.dev/rules/no-local-dependencies) | Requires that dependencies do not use local file paths, which will likely result in errors when installing from a registry. | | | |
|
|
46
47
|
| [no-redundant-files](https://eslint-plugin-package-json.dev/rules/no-redundant-files) | Prevents adding unnecessary / redundant files. | ✅ 📦 | | 💡 |
|
|
47
48
|
| [no-redundant-publishConfig](https://eslint-plugin-package-json.dev/rules/no-redundant-publishConfig) | Warns when publishConfig.access is used in unscoped packages. | ✅ 📦 | | 💡 |
|
|
48
49
|
| [order-properties](https://eslint-plugin-package-json.dev/rules/order-properties) | Package properties should be declared in standard order | 🎨 | 🔧 | |
|
package/lib/plugin.mjs
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import { rule } from "./rules/bin-name-casing.mjs";
|
|
2
2
|
import { rule as rule$1 } from "./rules/exports-subpaths-style.mjs";
|
|
3
3
|
import { rule as rule$2 } from "./rules/no-empty-fields.mjs";
|
|
4
|
-
import { rule as rule$3 } from "./rules/no-
|
|
5
|
-
import { rule as rule$4 } from "./rules/no-redundant-
|
|
6
|
-
import { rule as rule$5 } from "./rules/
|
|
7
|
-
import { rule as rule$6 } from "./rules/
|
|
8
|
-
import { rule as rule$7 } from "./rules/
|
|
4
|
+
import { rule as rule$3 } from "./rules/no-local-dependencies.mjs";
|
|
5
|
+
import { rule as rule$4 } from "./rules/no-redundant-files.mjs";
|
|
6
|
+
import { rule as rule$5 } from "./rules/no-redundant-publishConfig.mjs";
|
|
7
|
+
import { rule as rule$6 } from "./rules/order-properties.mjs";
|
|
8
|
+
import { rule as rule$7 } from "./rules/repository-shorthand.mjs";
|
|
9
|
+
import { rule as rule$8 } from "./rules/require-attribution.mjs";
|
|
9
10
|
import { rules as rules$1 } from "./rules/require-properties.mjs";
|
|
10
|
-
import { rule as rule$
|
|
11
|
-
import { rule as rule$
|
|
12
|
-
import { rule as rule$
|
|
13
|
-
import { rule as rule$
|
|
14
|
-
import { rule as rule$
|
|
15
|
-
import { rule as rule$
|
|
16
|
-
import { rule as rule$
|
|
17
|
-
import { rule as rule$
|
|
11
|
+
import { rule as rule$9 } from "./rules/restrict-dependency-ranges.mjs";
|
|
12
|
+
import { rule as rule$10 } from "./rules/restrict-private-properties.mjs";
|
|
13
|
+
import { rule as rule$11 } from "./rules/restrict-top-level-properties.mjs";
|
|
14
|
+
import { rule as rule$12 } from "./rules/scripts-name-casing.mjs";
|
|
15
|
+
import { rule as rule$13 } from "./rules/sort-collections.mjs";
|
|
16
|
+
import { rule as rule$14 } from "./rules/specify-peers-locally.mjs";
|
|
17
|
+
import { rule as rule$15 } from "./rules/unique-dependencies.mjs";
|
|
18
|
+
import { rule as rule$16 } from "./rules/valid-peerDependenciesMeta-relationship.mjs";
|
|
18
19
|
import { rules as rules$2 } from "./rules/valid-properties.mjs";
|
|
19
|
-
import { rule as rule$
|
|
20
|
+
import { rule as rule$17 } from "./rules/valid-repository-directory.mjs";
|
|
20
21
|
import { createRequire } from "node:module";
|
|
21
22
|
import * as parserJsonc from "jsonc-eslint-parser";
|
|
22
23
|
//#region src/plugin.ts
|
|
@@ -25,22 +26,23 @@ const rules = {
|
|
|
25
26
|
"bin-name-casing": rule,
|
|
26
27
|
"exports-subpaths-style": rule$1,
|
|
27
28
|
"no-empty-fields": rule$2,
|
|
28
|
-
"no-
|
|
29
|
-
"no-redundant-
|
|
30
|
-
"
|
|
31
|
-
"
|
|
29
|
+
"no-local-dependencies": rule$3,
|
|
30
|
+
"no-redundant-files": rule$4,
|
|
31
|
+
"no-redundant-publishConfig": rule$5,
|
|
32
|
+
"order-properties": rule$6,
|
|
33
|
+
"require-attribution": rule$8,
|
|
32
34
|
...rules$1,
|
|
33
|
-
"repository-shorthand": rule$
|
|
34
|
-
"restrict-dependency-ranges": rule$
|
|
35
|
-
"restrict-private-properties": rule$
|
|
36
|
-
"restrict-top-level-properties": rule$
|
|
37
|
-
"scripts-name-casing": rule$
|
|
38
|
-
"sort-collections": rule$
|
|
39
|
-
"specify-peers-locally": rule$
|
|
40
|
-
"unique-dependencies": rule$
|
|
35
|
+
"repository-shorthand": rule$7,
|
|
36
|
+
"restrict-dependency-ranges": rule$9,
|
|
37
|
+
"restrict-private-properties": rule$10,
|
|
38
|
+
"restrict-top-level-properties": rule$11,
|
|
39
|
+
"scripts-name-casing": rule$12,
|
|
40
|
+
"sort-collections": rule$13,
|
|
41
|
+
"specify-peers-locally": rule$14,
|
|
42
|
+
"unique-dependencies": rule$15,
|
|
41
43
|
...rules$2,
|
|
42
|
-
"valid-peerDependenciesMeta-relationship": rule$
|
|
43
|
-
"valid-repository-directory": rule$
|
|
44
|
+
"valid-peerDependenciesMeta-relationship": rule$16,
|
|
45
|
+
"valid-repository-directory": rule$17
|
|
44
46
|
};
|
|
45
47
|
const recommendedRules = { ...Object.fromEntries(Object.entries(rules).filter(([, rule]) => rule.meta.docs?.recommended).map(([name]) => ["package-json/" + name, "error"])) };
|
|
46
48
|
const recommendedPublishableRules = {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { PackageJsonRuleModule } from "../createRule.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/rules/no-local-dependencies.d.ts
|
|
4
|
+
declare const rule: PackageJsonRuleModule<[({
|
|
5
|
+
ignorePrivate?: boolean | undefined;
|
|
6
|
+
} | undefined)?], [{
|
|
7
|
+
readonly additionalProperties: false;
|
|
8
|
+
readonly properties: {
|
|
9
|
+
readonly ignorePrivate: {
|
|
10
|
+
readonly description: "Determines if this rule should be enforced when the package's `private` property is `true`.";
|
|
11
|
+
readonly type: "boolean";
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
readonly type: "object";
|
|
15
|
+
}]>;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { rule };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createRule } from "../createRule.mjs";
|
|
2
|
+
import { isJSONStringLiteral } from "../utils/predicates.mjs";
|
|
3
|
+
//#region src/rules/no-local-dependencies.ts
|
|
4
|
+
const isLocalDependency = (value) => value.startsWith("file:") || value.startsWith("link:") || value.startsWith("./") || value.startsWith("../") || value.startsWith(".\\") || value.startsWith("..\\");
|
|
5
|
+
const rule = createRule({
|
|
6
|
+
create(context) {
|
|
7
|
+
const ignorePrivate = context.options[0]?.ignorePrivate ?? true;
|
|
8
|
+
let isPrivate = false;
|
|
9
|
+
let dependencyNodes = [];
|
|
10
|
+
return {
|
|
11
|
+
"Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.type=JSONLiteral][value.type=JSONLiteral][key.value=private]"(node) {
|
|
12
|
+
if (node.value.value === true) isPrivate = true;
|
|
13
|
+
},
|
|
14
|
+
"Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.type=JSONLiteral][value.type=JSONObjectExpression][key.value=dependencies]"(node) {
|
|
15
|
+
dependencyNodes = node.value.properties;
|
|
16
|
+
},
|
|
17
|
+
"Program:exit"() {
|
|
18
|
+
if (ignorePrivate && isPrivate) return;
|
|
19
|
+
for (const dependencyPropertyNode of dependencyNodes) {
|
|
20
|
+
const dependencyValue = dependencyPropertyNode.value;
|
|
21
|
+
if (isJSONStringLiteral(dependencyValue) && isLocalDependency(dependencyValue.value)) context.report({
|
|
22
|
+
data: { name: dependencyValue.value },
|
|
23
|
+
messageId: "localDependencyFound",
|
|
24
|
+
node: dependencyValue
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
meta: {
|
|
31
|
+
defaultOptions: [{ ignorePrivate: true }],
|
|
32
|
+
docs: { description: "Requires that dependencies do not use local file paths, which will likely result in errors when installing from a registry." },
|
|
33
|
+
messages: { localDependencyFound: "Local dependency \"{{ name }}\" is not allowed." },
|
|
34
|
+
schema: [{
|
|
35
|
+
additionalProperties: false,
|
|
36
|
+
properties: { ignorePrivate: {
|
|
37
|
+
description: "Determines if this rule should be enforced when the package's `private` property is `true`.",
|
|
38
|
+
type: "boolean"
|
|
39
|
+
} },
|
|
40
|
+
type: "object"
|
|
41
|
+
}],
|
|
42
|
+
type: "problem"
|
|
43
|
+
},
|
|
44
|
+
name: "no-local-dependencies"
|
|
45
|
+
});
|
|
46
|
+
//#endregion
|
|
47
|
+
export { rule };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createRule } from "../createRule.mjs";
|
|
2
2
|
import { findPropertyWithKeyValue } from "../utils/findPropertyWithKeyValue.mjs";
|
|
3
|
-
import { findRootSync } from "@altano/repository-tools";
|
|
4
3
|
import path from "node:path";
|
|
5
4
|
import { sep } from "node:path/posix";
|
|
5
|
+
import { findRootSync } from "@altano/repository-tools";
|
|
6
6
|
//#region src/rules/valid-repository-directory.ts
|
|
7
7
|
/**
|
|
8
8
|
* Checks if the child path appears at the end of the parent path.
|
|
@@ -11,7 +11,7 @@ import { sep } from "node:path/posix";
|
|
|
11
11
|
* @example '/a/b/c', 'b' => false
|
|
12
12
|
* @example '/a/b/c', 'd' => false
|
|
13
13
|
*/
|
|
14
|
-
|
|
14
|
+
const pathEndsWith = (parent, child) => {
|
|
15
15
|
const segments = parent.split(path.sep);
|
|
16
16
|
if (parent === child) return true;
|
|
17
17
|
let pathToCheck = "";
|
|
@@ -19,7 +19,8 @@ function pathEndsWith(parent, child) {
|
|
|
19
19
|
pathToCheck = path.join(segment, pathToCheck);
|
|
20
20
|
if (pathToCheck === child) return true;
|
|
21
21
|
});
|
|
22
|
-
}
|
|
22
|
+
};
|
|
23
|
+
let repoRootCache = null;
|
|
23
24
|
const rule = createRule({
|
|
24
25
|
create(context) {
|
|
25
26
|
return { "Program > JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=repository][value.type=JSONObjectExpression]"(node) {
|
|
@@ -27,13 +28,13 @@ const rule = createRule({
|
|
|
27
28
|
if (directoryProperty?.value.type !== "JSONLiteral" || typeof directoryProperty.value.value !== "string") return;
|
|
28
29
|
const directoryValue = directoryProperty.value.value;
|
|
29
30
|
const fileDirectory = path.normalize(path.dirname(context.filename));
|
|
30
|
-
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
let repositoryRoot;
|
|
32
|
+
if (repoRootCache && fileDirectory.startsWith(repoRootCache)) repositoryRoot = repoRootCache;
|
|
33
|
+
else {
|
|
34
|
+
repositoryRoot = findRootSync(fileDirectory);
|
|
35
|
+
if (repositoryRoot) repoRootCache = path.normalize(repositoryRoot);
|
|
36
|
+
}
|
|
37
|
+
if (repositoryRoot) {
|
|
37
38
|
const expected = path.relative(repositoryRoot, fileDirectory).replaceAll(path.sep, sep);
|
|
38
39
|
if (expected !== directoryValue) context.report({
|
|
39
40
|
messageId: "mismatched",
|
|
@@ -46,7 +47,10 @@ const rule = createRule({
|
|
|
46
47
|
messageId: "replace"
|
|
47
48
|
}]
|
|
48
49
|
});
|
|
49
|
-
}
|
|
50
|
+
} else if (!pathEndsWith(fileDirectory, path.normalize(directoryValue))) context.report({
|
|
51
|
+
messageId: "mismatched",
|
|
52
|
+
node: directoryProperty.value
|
|
53
|
+
});
|
|
50
54
|
} };
|
|
51
55
|
},
|
|
52
56
|
meta: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-package-json",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Rules for consistent, readable, and valid package.json files. 🗂️",
|
|
5
5
|
"homepage": "https://github.com/michaelfaith/eslint-plugin-package-json#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -60,14 +60,15 @@
|
|
|
60
60
|
"@catppuccin/starlight": "2.0.1",
|
|
61
61
|
"@eslint-community/eslint-plugin-eslint-comments": "4.7.0",
|
|
62
62
|
"@eslint/js": "10.0.1",
|
|
63
|
-
"@eslint/json": "
|
|
63
|
+
"@eslint/json": "2.0.0",
|
|
64
64
|
"@eslint/markdown": "8.0.1",
|
|
65
|
+
"@ianvs/prettier-plugin-sort-imports": "4.7.1",
|
|
65
66
|
"@types/estree": "1.0.8",
|
|
66
67
|
"@types/node": "24.12.0",
|
|
67
68
|
"@types/semver": "7.7.1",
|
|
68
69
|
"@vitest/coverage-v8": "4.1.0",
|
|
69
70
|
"@vitest/eslint-plugin": "1.6.1",
|
|
70
|
-
"astro": "6.
|
|
71
|
+
"astro": "6.4.2",
|
|
71
72
|
"astro-og-canvas": "0.11.1",
|
|
72
73
|
"canvaskit-wasm": "0.41.1",
|
|
73
74
|
"console-fail-test": "0.6.0",
|
|
@@ -75,13 +76,13 @@
|
|
|
75
76
|
"eslint-doc-generator": "3.6.0",
|
|
76
77
|
"eslint-plugin-eslint-plugin": "7.3.1",
|
|
77
78
|
"eslint-plugin-jsdoc": "63.0.0",
|
|
78
|
-
"eslint-plugin-jsonc": "3.
|
|
79
|
+
"eslint-plugin-jsonc": "3.2.0",
|
|
79
80
|
"eslint-plugin-n": "18.0.0",
|
|
80
81
|
"eslint-plugin-node-dependencies": "2.2.0",
|
|
81
82
|
"eslint-plugin-perfectionist": "5.9.0",
|
|
82
83
|
"eslint-plugin-regexp": "3.1.0",
|
|
83
84
|
"eslint-plugin-unicorn": "64.0.0",
|
|
84
|
-
"eslint-plugin-yml": "3.
|
|
85
|
+
"eslint-plugin-yml": "3.4.0",
|
|
85
86
|
"jiti": "2.7.0",
|
|
86
87
|
"json-schema-to-ts": "3.1.1",
|
|
87
88
|
"knip": "6.14.0",
|