Skip to content

Commit 2af10da

Browse files
authored
feat(valid-exports): add new rule for validating exports (#1220)
<!-- πŸ‘‹ Hi, thanks for sending a PR to eslint-plugin-package-json! πŸ—‚ Please fill out all fields below and make sure each item is true and [x] checked. Otherwise we may not be able to review your PR. --> ## PR Checklist - [x] Addresses an existing open issue: fixes #1033 - [x] That issue was marked as [`status: accepting prs`](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22) - [x] Steps in [CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/blob/main/.github/CONTRIBUTING.md) were taken ## Overview This change adds a new `valid-exports` rule that uses `exports` from package-json-validator to identify errors. It's included in the `recommended` config.
1 parent e9a090f commit 2af10da

File tree

7 files changed

+179
-7
lines changed

7 files changed

+179
-7
lines changed

β€Ž.vscode/settings.jsonβ€Ž

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@
1414
"yaml"
1515
],
1616
"eslint.rules.customizations": [{ "rule": "*", "severity": "warn" }],
17-
"typescript.tsdk": "node_modules/typescript/lib"
17+
"typescript.tsdk": "node_modules/typescript/lib",
18+
"npm.packageManager": "pnpm"
1819
}

β€ŽREADME.mdβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ The default settings don't conflict, and Prettier plugins can quickly fix up ord
185185
| [valid-dependencies](docs/rules/valid-dependencies.md) | Enforce that the `dependencies` property is valid. | βœ”οΈ βœ… | | | |
186186
| [valid-description](docs/rules/valid-description.md) | Enforce that the `description` property is valid. | βœ”οΈ βœ… | | | |
187187
| [valid-devDependencies](docs/rules/valid-devDependencies.md) | Enforce that the `devDependencies` property is valid. | βœ”οΈ βœ… | | | |
188+
| [valid-exports](docs/rules/valid-exports.md) | Enforce that the `exports` property is valid. | βœ”οΈ βœ… | | | |
188189
| [valid-license](docs/rules/valid-license.md) | Enforce that the `license` property is valid. | βœ”οΈ βœ… | | | |
189190
| [valid-local-dependency](docs/rules/valid-local-dependency.md) | Checks existence of local dependencies in the package.json | | | | ❌ |
190191
| [valid-name](docs/rules/valid-name.md) | Enforce that package names are valid npm package names | βœ”οΈ βœ… | | | |

β€Ždocs/rules/valid-exports.mdβ€Ž

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# valid-exports
2+
3+
πŸ’Ό This rule is enabled in the following configs: βœ”οΈ `legacy-recommended`, βœ… `recommended`.
4+
5+
<!-- end auto-generated rule header -->
6+
7+
The rule checks that, if present, the `exports` property is a validated according the following criteria:
8+
9+
- It should be of type `string` or `object`.
10+
- If it's a `string`, it should be a path to an entry point.
11+
- If it's an export condition object, its properties should have values that are either a path to an entry point, or another exports condition object.
12+
13+
Example of **incorrect** code for this rule:
14+
15+
```json
16+
{
17+
"exports": {
18+
"import": true
19+
}
20+
}
21+
```
22+
23+
Example of **correct** code for this rule:
24+
25+
```json
26+
{
27+
"exports": "./index.js"
28+
}
29+
```
30+
31+
```json
32+
{
33+
"exports": {
34+
".": "./index.js",
35+
"./secondary": "./secondary.js"
36+
}
37+
}
38+
```
39+
40+
```json
41+
{
42+
"exports": {
43+
".": {
44+
"import": {
45+
"types": "./esm/index.d.mts",
46+
"default": "./esm/index.mjs"
47+
},
48+
"require": {
49+
"types": "./cjs/index.d.cts",
50+
"default": "./cjs/index.cjs"
51+
}
52+
}
53+
}
54+
}
55+
```

β€Žpackage.jsonβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"detect-indent": "^7.0.1",
5050
"detect-newline": "^4.0.1",
5151
"eslint-fix-utils": "~0.4.0",
52-
"package-json-validator": "~0.27.0",
52+
"package-json-validator": "~0.29.0",
5353
"semver": "^7.5.4",
5454
"sort-object-keys": "^1.1.3",
5555
"sort-package-json": "^3.3.0",

β€Žpnpm-lock.yamlβ€Ž

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žsrc/rules/valid-properties.tsβ€Ž

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
validateCpu,
66
validateDependencies,
77
validateDescription,
8+
validateExports,
89
validateLicense,
910
validateScripts,
1011
validateType,
@@ -36,6 +37,7 @@ const properties = [
3637
["dependencies", validateDependencies],
3738
["description", validateDescription],
3839
["devDependencies", validateDependencies],
40+
["exports", validateExports],
3941
["license", validateLicense],
4042
["optionalDependencies", validateDependencies],
4143
["peerDependencies", validateDependencies],
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { rules } from "../../rules/valid-properties.ts";
2+
import { ruleTester } from "./ruleTester.ts";
3+
4+
ruleTester.run("valid-exports", rules["valid-exports"], {
5+
invalid: [
6+
{
7+
code: `{
8+
"exports": null
9+
}
10+
`,
11+
errors: [
12+
{
13+
data: {
14+
errors: "the field is `null`, but should be an `object` or `string`",
15+
},
16+
messageId: "validationError",
17+
},
18+
],
19+
},
20+
{
21+
code: `{
22+
"exports": 123
23+
}
24+
`,
25+
errors: [
26+
{
27+
data: {
28+
errors: "the type should be `object` or `string`, not `number`",
29+
},
30+
messageId: "validationError",
31+
},
32+
],
33+
},
34+
{
35+
code: `{
36+
"exports": ""
37+
}
38+
`,
39+
errors: [
40+
{
41+
data: {
42+
errors: "the value is empty, but should be an entry point path",
43+
},
44+
messageId: "validationError",
45+
},
46+
],
47+
},
48+
{
49+
code: `{
50+
"exports": { "./invalid": 123 }
51+
}
52+
`,
53+
errors: [
54+
{
55+
data: {
56+
errors: 'the value of "./invalid" should be either an entry point path or an object of export conditions',
57+
},
58+
messageId: "validationError",
59+
},
60+
],
61+
},
62+
{
63+
code: `{
64+
"exports": { "./invalid": "" }
65+
}
66+
`,
67+
errors: [
68+
{
69+
data: {
70+
errors: 'the value of "./invalid" is empty, but should be an entry point path',
71+
},
72+
messageId: "validationError",
73+
},
74+
],
75+
},
76+
{
77+
code: `{
78+
"exports": { "": "invalid" }
79+
}
80+
`,
81+
errors: [
82+
{
83+
data: {
84+
errors: "property 0 has an empty key, but should be an export condition",
85+
},
86+
messageId: "validationError",
87+
},
88+
],
89+
},
90+
{
91+
code: `{
92+
"exports": { "": "invalid", " ": "invalid" }
93+
}
94+
`,
95+
errors: [
96+
{
97+
data: {
98+
errors: `
99+
- property 0 has an empty key, but should be an export condition
100+
- property 1 has an empty key, but should be an export condition`,
101+
},
102+
messageId: "validationError",
103+
},
104+
],
105+
},
106+
],
107+
valid: [
108+
"{}",
109+
`{ "exports": "./index.js" }`,
110+
`{ "exports": { ".": "./index.js", "./secondary": "./secondary.js" } }`,
111+
`{ "exports": { ".": { "types": "./index.d.ts", "default": "./index.js" } } }`,
112+
],
113+
});

0 commit comments

Comments
Β (0)