eslint-plugin-package-json 0.3.1 → 0.3.2

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.
@@ -0,0 +1,16 @@
1
+ jobs:
2
+ tsc:
3
+ runs-on: ubuntu-latest
4
+ steps:
5
+ - uses: actions/checkout@v4
6
+ - uses: ./.github/actions/prepare
7
+ - run: npm run tsc
8
+ - run: npm run lint:eslint-docs
9
+
10
+ name: Lint ESLint Docs
11
+
12
+ on:
13
+ pull_request: ~
14
+ push:
15
+ branches:
16
+ - main
package/README.md CHANGED
@@ -52,10 +52,18 @@ module.exports = {
52
52
 
53
53
  ## Supported Rules
54
54
 
55
- - [`package-json/order-properties`](docs/rules/order-properties.md): Require top-level properties to be in a conventional order (`"name"`first, etc.).
56
- - [`package-json/sort-collections`](docs/rules/sort-collections.md): Keep sub-collections like `"dependencies"` and `"scripts"` in alphabetical order.
57
- - [`package-json/valid-package-def`](docs/rules/valid-package-def.md): Validate `package.json` files against the NPM specification.
58
- - [`package-json/valid-local-dependency`](docs/rules/valid-local-dependency.md): Validates the casing for `file:` and `link:` dependencies in the `package.json` files.
55
+ <!-- begin auto-generated rules list -->
56
+
57
+ 🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).
58
+
59
+ | Name                   | Description | 🔧 |
60
+ | :------------------------------------------------------------- | :-------------------------------------------------------------------------------------- | :- |
61
+ | [order-properties](docs/rules/order-properties.md) | Package properties must be declared in standard order | 🔧 |
62
+ | [sort-collections](docs/rules/sort-collections.md) | Dependencies, scripts, and configuration values must be declared in alphabetical order. | 🔧 |
63
+ | [valid-local-dependency](docs/rules/valid-local-dependency.md) | Checks existence of local dependencies in the package.json | |
64
+ | [valid-package-def](docs/rules/valid-package-def.md) | Enforce that package.json has all properties required by NPM spec | |
65
+
66
+ <!-- end auto-generated rules list -->
59
67
 
60
68
  These rules only run on `package.json` files; they will ignore all other files being linted. They lint `package.json` files at project root, and in any subfolder of the project, making this plugin great for monorepos.
61
69
 
@@ -1,4 +1,8 @@
1
- # Package properties must be declared in standard order (order-properties)
1
+ # Package properties must be declared in standard order (`package-json/order-properties`)
2
+
3
+ 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
4
+
5
+ <!-- end auto-generated rule header -->
2
6
 
3
7
  A conventional order exists for `package.json` top-level properties. NPM does
4
8
  not enforce this order, but for consistency and readability, this rule can
@@ -1,4 +1,8 @@
1
- # Dependencies, scripts, and configuration values must be declared in alphabetical order. (sort-collections)
1
+ # Dependencies, scripts, and configuration values must be declared in alphabetical order (`package-json/sort-collections`)
2
+
3
+ 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
4
+
5
+ <!-- end auto-generated rule header -->
2
6
 
3
7
  Whenever NPM changes package dependencies through `npm install`, it lexically sorts (that is, alphabetizes by package name) all dependencies in `package.json`. Nevertheless, sometimes a developer will manually update `package.json` and leave dependencies out of order, leading to "noise" in changesets when a later change re-sorts the packages. This rule aims to keep the dependency collections sorted in every commit.
4
8
 
@@ -1,4 +1,6 @@
1
- # Ensures that local dependencies specified in a package.json exist
1
+ # Checks existence of local dependencies in the package.json (`package-json/valid-local-dependency`)
2
+
3
+ <!-- end auto-generated rule header -->
2
4
 
3
5
  ## Rule Details
4
6
 
@@ -19,7 +21,3 @@ Examples of **correct** code for this rule:
19
21
  "some-package": "link:../folder",
20
22
  }
21
23
  ```
22
-
23
- ### Options
24
-
25
- This rule has no options.
@@ -1,4 +1,6 @@
1
- # Enforce that package.json has all properties required by NPM spec (valid-package-def)
1
+ # Enforce that package.json has all properties required by NPM spec (`package-json/valid-package-def`)
2
+
3
+ <!-- end auto-generated rule header -->
2
4
 
3
5
  NPM issues warnings after install if the `package.json` has a missing or
4
6
  invalid required property. This rule uses [`package-json-validator`][pjv] to
@@ -43,10 +45,6 @@ Examples of **correct** code for this rule:
43
45
  }
44
46
  ```
45
47
 
46
- ### Options
47
-
48
- This rule has no options.
49
-
50
48
  ## When Not To Use It
51
49
 
52
50
  NPM may complain, but it works perfectly with many package files that do not
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createRule = void 0;
4
+ const isPackageJson = (filePath) => filePath.endsWith('/package.json') || filePath === 'package.json';
5
+ function createRule(rule) {
6
+ return {
7
+ ...rule,
8
+ create(context) {
9
+ if (!isPackageJson(context.filename)) {
10
+ return {};
11
+ }
12
+ return rule.create(context);
13
+ }
14
+ };
15
+ }
16
+ exports.createRule = createRule;
package/lib/index.d.ts CHANGED
@@ -1,2 +1,41 @@
1
- export {};
1
+ export declare const rules: {
2
+ 'order-properties': {
3
+ create(context: import("./createRule").PackageJsonRuleContext): import("jsonc-eslint-parser").RuleListener;
4
+ meta: import("eslint").Rule.RuleMetaData;
5
+ };
6
+ 'sort-collections': {
7
+ create(context: import("./createRule").PackageJsonRuleContext): import("jsonc-eslint-parser").RuleListener;
8
+ meta: import("eslint").Rule.RuleMetaData;
9
+ };
10
+ 'valid-local-dependency': {
11
+ create(context: import("./createRule").PackageJsonRuleContext): import("jsonc-eslint-parser").RuleListener;
12
+ meta: import("eslint").Rule.RuleMetaData;
13
+ };
14
+ 'valid-package-def': {
15
+ create(context: import("./createRule").PackageJsonRuleContext): import("jsonc-eslint-parser").RuleListener;
16
+ meta: import("eslint").Rule.RuleMetaData;
17
+ };
18
+ };
19
+ export declare const configs: {
20
+ recommended: {
21
+ rules: {
22
+ 'order-properties': {
23
+ create(context: import("./createRule").PackageJsonRuleContext): import("jsonc-eslint-parser").RuleListener;
24
+ meta: import("eslint").Rule.RuleMetaData;
25
+ };
26
+ 'sort-collections': {
27
+ create(context: import("./createRule").PackageJsonRuleContext): import("jsonc-eslint-parser").RuleListener;
28
+ meta: import("eslint").Rule.RuleMetaData;
29
+ };
30
+ 'valid-local-dependency': {
31
+ create(context: import("./createRule").PackageJsonRuleContext): import("jsonc-eslint-parser").RuleListener;
32
+ meta: import("eslint").Rule.RuleMetaData;
33
+ };
34
+ 'valid-package-def': {
35
+ create(context: import("./createRule").PackageJsonRuleContext): import("jsonc-eslint-parser").RuleListener;
36
+ meta: import("eslint").Rule.RuleMetaData;
37
+ };
38
+ };
39
+ };
40
+ };
2
41
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;CAKjB,CAAC;AAEF,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;CAInB,CAAC"}
package/lib/index.js ADDED
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.configs = exports.rules = void 0;
7
+ const order_properties_1 = __importDefault(require("./rules/order-properties"));
8
+ const sort_collections_1 = __importDefault(require("./rules/sort-collections"));
9
+ const valid_local_dependency_1 = __importDefault(require("./rules/valid-local-dependency"));
10
+ const valid_package_def_1 = __importDefault(require("./rules/valid-package-def"));
11
+ exports.rules = {
12
+ 'order-properties': order_properties_1.default,
13
+ 'sort-collections': sort_collections_1.default,
14
+ 'valid-local-dependency': valid_local_dependency_1.default,
15
+ 'valid-package-def': valid_package_def_1.default
16
+ };
17
+ exports.configs = {
18
+ recommended: {
19
+ rules: exports.rules
20
+ }
21
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"order-properties.d.ts","sourceRoot":"","sources":["../../src/rules/order-properties.ts"],"names":[],"mappings":";;;;AAmCA,wBA0EG"}
1
+ {"version":3,"file":"order-properties.d.ts","sourceRoot":"","sources":["../../src/rules/order-properties.ts"],"names":[],"mappings":";;;;AAmCA,wBAsFG"}
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const sort_package_json_1 = __importDefault(require("sort-package-json"));
7
+ const createRule_js_1 = require("../createRule.js");
8
+ const standardOrderLegacy = [
9
+ 'name',
10
+ 'version',
11
+ 'private',
12
+ 'publishConfig',
13
+ 'description',
14
+ 'main',
15
+ 'exports',
16
+ 'browser',
17
+ 'files',
18
+ 'bin',
19
+ 'directories',
20
+ 'man',
21
+ 'scripts',
22
+ 'repository',
23
+ 'keywords',
24
+ 'author',
25
+ 'license',
26
+ 'bugs',
27
+ 'homepage',
28
+ 'config',
29
+ 'dependencies',
30
+ 'devDependencies',
31
+ 'peerDependencies',
32
+ 'optionalDependencies',
33
+ 'bundledDependencies',
34
+ 'engines',
35
+ 'os',
36
+ 'cpu'
37
+ ];
38
+ exports.default = (0, createRule_js_1.createRule)({
39
+ meta: {
40
+ docs: {
41
+ description: 'Package properties must be declared in standard order',
42
+ category: 'Best Practices',
43
+ recommended: true
44
+ },
45
+ fixable: 'code',
46
+ schema: [
47
+ {
48
+ type: 'object',
49
+ properties: {
50
+ order: {
51
+ anyOf: [
52
+ {
53
+ type: ['string'],
54
+ enum: ['legacy', 'sort-package-json']
55
+ },
56
+ {
57
+ type: ['array'],
58
+ items: {
59
+ type: ['string']
60
+ }
61
+ }
62
+ ]
63
+ }
64
+ }
65
+ }
66
+ ]
67
+ },
68
+ create(context) {
69
+ return {
70
+ 'Program:exit'() {
71
+ const { ast, text } = context.sourceCode;
72
+ const options = context.options[0] || { order: 'legacy' };
73
+ const requiredOrder = options.order === 'legacy'
74
+ ? standardOrderLegacy
75
+ : options.order;
76
+ const orderedSource = (0, sort_package_json_1.default)(JSON.parse(text), requiredOrder === 'sort-package-json'
77
+ ? undefined
78
+ : {
79
+ sortOrder: requiredOrder
80
+ });
81
+ const orderedKeys = Object.keys(orderedSource);
82
+ const { properties } = ast.body[0].expression;
83
+ // console.log({ orderedSource });
84
+ for (let i = 0; i < properties.length; i += 1) {
85
+ // console.log(
86
+ // properties.map(p => p.value),
87
+ // 'vs',
88
+ // orderedKeys
89
+ // );
90
+ if (properties[i].value !== orderedKeys[i]) {
91
+ // console.log(
92
+ // 'JOSH SAYS HI',
93
+ // properties[i].value.value,
94
+ // orderedKeys[i]
95
+ // );
96
+ context.report({
97
+ node: context.sourceCode.ast,
98
+ message: 'Package top-level properties are not ordered in the npm standard way. Run the ESLint auto-fixer to correct.',
99
+ fix(fixer) {
100
+ return fixer.replaceText(context.sourceCode.ast, JSON.stringify(orderedSource, null, 2) +
101
+ `\n`);
102
+ }
103
+ });
104
+ }
105
+ break;
106
+ }
107
+ }
108
+ };
109
+ }
110
+ });
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const createRule_js_1 = require("../createRule.js");
4
+ const defaultCollections = [
5
+ 'scripts',
6
+ 'devDependencies',
7
+ 'dependencies',
8
+ 'peerDependencies',
9
+ 'config'
10
+ ];
11
+ exports.default = (0, createRule_js_1.createRule)({
12
+ meta: {
13
+ docs: {
14
+ description: 'Dependencies, scripts, and configuration values must be declared in alphabetical order.',
15
+ category: 'Best Practices',
16
+ recommended: true
17
+ },
18
+ fixable: 'code',
19
+ schema: [
20
+ {
21
+ type: 'array',
22
+ items: {
23
+ type: 'string'
24
+ }
25
+ }
26
+ ]
27
+ },
28
+ create(context) {
29
+ const toSort = context.options[0] || defaultCollections;
30
+ return {
31
+ 'JSONProperty:exit'(node) {
32
+ const { key, value } = node;
33
+ const collection = value;
34
+ if (collection.type === 'JSONObjectExpression' &&
35
+ toSort.includes(key.value)) {
36
+ const currentOrder = collection.properties;
37
+ const desiredOrder = currentOrder
38
+ .slice()
39
+ .sort((a, b) => a.key.value >
40
+ b.key.value
41
+ ? 1
42
+ : -1);
43
+ if (currentOrder.some((property, i) => desiredOrder[i] !== property)) {
44
+ context.report({
45
+ node: node,
46
+ loc: collection.loc,
47
+ message: 'Package {{ key }} are not alphabetized',
48
+ data: {
49
+ key: key.value
50
+ },
51
+ fix(fixer) {
52
+ return fixer.replaceText(collection, JSON.stringify(desiredOrder.reduce((out, property) => {
53
+ out[property.key.value] = JSON.parse(context.sourceCode.getText(property.value));
54
+ return out;
55
+ }, {}), null, 2)
56
+ .split('\n')
57
+ .join('\n ') // nest indents
58
+ );
59
+ }
60
+ });
61
+ }
62
+ }
63
+ }
64
+ };
65
+ }
66
+ });
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const path_1 = __importDefault(require("path"));
7
+ const createRule_js_1 = require("../createRule.js");
8
+ //------------------------------------------------------------------------------
9
+ // Rule Definition
10
+ //------------------------------------------------------------------------------
11
+ exports.default = (0, createRule_js_1.createRule)({
12
+ meta: {
13
+ docs: {
14
+ description: 'Checks existence of local dependencies in the package.json',
15
+ category: 'Best Practices',
16
+ recommended: true
17
+ }
18
+ },
19
+ create: function (context) {
20
+ return {
21
+ 'Program:exit'() {
22
+ const original = JSON.parse(context.sourceCode.text);
23
+ const { dependencies, peerDependencies, devDependencies } = original;
24
+ const depObjs = [
25
+ Object.entries(dependencies || {}),
26
+ Object.entries(peerDependencies || {}),
27
+ Object.entries(devDependencies || {})
28
+ ];
29
+ depObjs.forEach(obj => obj.forEach(([key, value]) => {
30
+ const response = (localPath) => {
31
+ const filePath = path_1.default.join(context.filename.replace(/package\.json/g, '/'), value.replace(new RegExp(localPath, 'g'), ''), '/package.json');
32
+ try {
33
+ if (!require.resolve(filePath)) {
34
+ context.report({
35
+ node: context.sourceCode.ast,
36
+ message: `The package ${key} does not exist given the specified path: ${value}.`
37
+ });
38
+ }
39
+ }
40
+ catch (e) {
41
+ context.report({
42
+ node: context.sourceCode.ast,
43
+ message: `The package ${key} does not exist given the specified path: ${value}.`
44
+ });
45
+ }
46
+ };
47
+ if (value.startsWith('link:')) {
48
+ response('link:');
49
+ }
50
+ if (value.startsWith('file:')) {
51
+ response('file:');
52
+ }
53
+ }));
54
+ }
55
+ };
56
+ }
57
+ });
@@ -0,0 +1,34 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const package_json_validator_1 = require("package-json-validator");
4
+ const createRule_js_1 = require("../createRule.js");
5
+ // package-json-validator does not correctly recognize shorthand for repositories and alternate dependency statements, so we discard those values.
6
+ // it also enforces a stricter code for NPM than is really appropriate,
7
+ // so we disable some other errors here.
8
+ const unusedErrorPatterns = [
9
+ /^Url not valid/i,
10
+ /^Invalid version range for .+?: file:/i,
11
+ /^author field should have name/i
12
+ ];
13
+ const isUsableError = (errorText) => unusedErrorPatterns.every(pattern => !pattern.test(errorText));
14
+ exports.default = (0, createRule_js_1.createRule)({
15
+ meta: {
16
+ docs: {
17
+ description: 'Enforce that package.json has all properties required by NPM spec',
18
+ category: 'Best Practices',
19
+ recommended: true
20
+ }
21
+ },
22
+ create: function (context) {
23
+ return {
24
+ 'Program:exit'() {
25
+ const validation = package_json_validator_1.PJV.validate(context.sourceCode.text);
26
+ validation.errors?.filter(isUsableError).forEach(message => message &&
27
+ context.report({
28
+ node: context.sourceCode.ast,
29
+ message
30
+ }));
31
+ }
32
+ };
33
+ }
34
+ });
@@ -8,7 +8,6 @@ const ruleTester_1 = require("./ruleTester");
8
8
  ruleTester_1.ruleTester.run('order-properties', order_properties_1.default, {
9
9
  invalid: [
10
10
  {
11
- only: true,
12
11
  code: `{
13
12
  "name": "invalid-top-level-property-order",
14
13
  "scripts": {
@@ -45,7 +44,6 @@ ruleTester_1.ruleTester.run('order-properties', order_properties_1.default, {
45
44
  `
46
45
  },
47
46
  {
48
- only: true,
49
47
  code: `{
50
48
  "name": "invalid-top-level-property-order",
51
49
  "scripts": {
@@ -83,7 +81,6 @@ ruleTester_1.ruleTester.run('order-properties', order_properties_1.default, {
83
81
  `
84
82
  },
85
83
  {
86
- only: true,
87
84
  code: `{
88
85
  "name": "invalid-top-level-property-order",
89
86
  "scripts": {
@@ -121,7 +118,6 @@ ruleTester_1.ruleTester.run('order-properties', order_properties_1.default, {
121
118
  `
122
119
  },
123
120
  {
124
- only: true,
125
121
  code: `{
126
122
  "name": "invalid-top-level-property-order",
127
123
  "scripts": {
@@ -160,8 +156,7 @@ ruleTester_1.ruleTester.run('order-properties', order_properties_1.default, {
160
156
  }
161
157
  ],
162
158
  valid: [
163
- {
164
- code: `{
159
+ `{
165
160
  "name": "treat-yo-self",
166
161
  "version": "1.1.1",
167
162
  "description": "Once a year.",
@@ -170,10 +165,7 @@ ruleTester_1.ruleTester.run('order-properties', order_properties_1.default, {
170
165
  "master"
171
166
  ]
172
167
  }`,
173
- filename: 'package.json'
174
- },
175
- {
176
- code: `{
168
+ `{
177
169
  "name": "treat-yo-self",
178
170
  "version": "0.1.0",
179
171
  "private": true,
@@ -183,8 +175,7 @@ ruleTester_1.ruleTester.run('order-properties', order_properties_1.default, {
183
175
  "master"
184
176
  ]
185
177
  }
186
- `
187
- },
178
+ `,
188
179
  {
189
180
  code: `{
190
181
  "version": "1.1.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-package-json",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Rules for valid, consistent, and readable package.json files",
5
5
  "keywords": [
6
6
  "eslint",
@@ -21,8 +21,10 @@
21
21
  },
22
22
  "scripts": {
23
23
  "lint": "eslint",
24
+ "lint:eslint-docs": "npm run update:eslint-docs -- --check",
24
25
  "test": "vitest",
25
26
  "tsc": "tsc",
27
+ "update:eslint-docs": "eslint-doc-generator",
26
28
  "format": "prettier --ignore-path .gitignore --write \"**/*.{js,css,md}\""
27
29
  },
28
30
  "devDependencies": {
@@ -32,6 +34,7 @@
32
34
  "@types/package-json-validator": "^0.6.0",
33
35
  "console-fail-test": "^0.2.3",
34
36
  "eslint": "^8.49.0",
37
+ "eslint-doc-generator": "^1.5.4",
35
38
  "jsonc-eslint-parser": "^2.4.0",
36
39
  "prettier": "^1.18.2",
37
40
  "typescript": "^5.2.2",
package/src/index.ts CHANGED
@@ -1,19 +1,17 @@
1
- 'use strict';
2
-
3
1
  import orderProperties from './rules/order-properties';
4
2
  import sortCollections from './rules/sort-collections';
5
3
  import validLocalDependency from './rules/valid-local-dependency';
6
4
  import validPackageDef from './rules/valid-package-def';
7
5
 
8
- module.exports = {
9
- configs: {
10
- recommended: {
11
- rules: {
12
- 'order-properties': orderProperties,
13
- 'sort-collections': sortCollections,
14
- 'valid-local-dependency': validLocalDependency,
15
- 'valid-package-def': validPackageDef
16
- }
17
- }
6
+ export const rules = {
7
+ 'order-properties': orderProperties,
8
+ 'sort-collections': sortCollections,
9
+ 'valid-local-dependency': validLocalDependency,
10
+ 'valid-package-def': validPackageDef
11
+ };
12
+
13
+ export const configs = {
14
+ recommended: {
15
+ rules
18
16
  }
19
17
  };