@monorepolint/rules 0.6.0-alpha.4 → 0.6.0-alpha.6
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/.turbo/turbo-clean.log +1 -1
- package/.turbo/turbo-compile-typescript.log +1 -1
- package/.turbo/turbo-lint.log +1 -1
- package/.turbo/turbo-test.log +443 -92
- package/.turbo/turbo-transpile-typescript.log +5 -5
- package/CHANGELOG.md +112 -0
- package/build/js/index.js +413 -368
- package/build/js/index.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/REMOVE.d.ts +2 -0
- package/build/types/REMOVE.d.ts.map +1 -0
- package/build/types/__tests__/alphabeticalDependencies.spec.d.ts +8 -0
- package/build/types/__tests__/alphabeticalDependencies.spec.d.ts.map +1 -0
- package/build/types/__tests__/forceError.spec.d.ts +8 -0
- package/build/types/__tests__/forceError.spec.d.ts.map +1 -0
- package/build/types/__tests__/oncePerPackage.spec.d.ts +8 -0
- package/build/types/__tests__/oncePerPackage.spec.d.ts.map +1 -0
- package/build/types/__tests__/standardTsconfig.spec.d.ts +8 -0
- package/build/types/__tests__/standardTsconfig.spec.d.ts.map +1 -0
- package/build/types/bannedDependencies.d.ts +9 -33
- package/build/types/bannedDependencies.d.ts.map +1 -1
- package/build/types/consistentDependencies.d.ts +6 -6
- package/build/types/consistentDependencies.d.ts.map +1 -1
- package/build/types/consistentVersions.d.ts +6 -10
- package/build/types/consistentVersions.d.ts.map +1 -1
- package/build/types/fileContents.d.ts +3 -2
- package/build/types/fileContents.d.ts.map +1 -1
- package/build/types/index.d.ts +1 -0
- package/build/types/index.d.ts.map +1 -1
- package/build/types/mustSatisfyPeerDependencies.d.ts +12 -190
- package/build/types/mustSatisfyPeerDependencies.d.ts.map +1 -1
- package/build/types/nestedWorkspaces.d.ts +2 -2
- package/build/types/nestedWorkspaces.d.ts.map +1 -1
- package/build/types/oncePerPackage.d.ts +6 -6
- package/build/types/oncePerPackage.d.ts.map +1 -1
- package/build/types/packageEntry.d.ts +11 -33
- package/build/types/packageEntry.d.ts.map +1 -1
- package/build/types/packageOrder.d.ts +2 -1
- package/build/types/packageOrder.d.ts.map +1 -1
- package/build/types/packageScript.d.ts +13 -22
- package/build/types/packageScript.d.ts.map +1 -1
- package/build/types/requireDependency.d.ts +5 -20
- package/build/types/requireDependency.d.ts.map +1 -1
- package/build/types/standardTsconfig.d.ts +12 -19
- package/build/types/standardTsconfig.d.ts.map +1 -1
- package/build/types/util/zodSchemas.d.ts +14 -0
- package/build/types/util/zodSchemas.d.ts.map +1 -0
- package/coverage/block-navigation.js +1 -1
- package/coverage/clover.xml +1420 -1452
- package/coverage/coverage-final.json +21 -19
- package/coverage/index.html +27 -27
- package/coverage/sorter.js +21 -7
- package/coverage/src/REMOVE.ts.html +88 -0
- package/coverage/src/alphabeticalDependencies.ts.html +15 -15
- package/coverage/src/alphabeticalScripts.ts.html +5 -5
- package/coverage/src/bannedDependencies.ts.html +20 -53
- package/coverage/src/consistentDependencies.ts.html +20 -14
- package/coverage/src/consistentVersions.ts.html +330 -183
- package/coverage/src/fileContents.ts.html +223 -88
- package/coverage/src/forceError.ts.html +31 -31
- package/coverage/src/index.html +104 -89
- package/coverage/src/index.ts.html +11 -5
- package/coverage/src/mustSatisfyPeerDependencies.ts.html +15 -501
- package/coverage/src/nestedWorkspaces.ts.html +5 -5
- package/coverage/src/oncePerPackage.ts.html +31 -31
- package/coverage/src/packageEntry.ts.html +121 -91
- package/coverage/src/packageOrder.ts.html +44 -14
- package/coverage/src/packageScript.ts.html +235 -88
- package/coverage/src/requireDependency.ts.html +241 -82
- package/coverage/src/standardTsconfig.ts.html +212 -212
- package/coverage/src/util/checkAlpha.ts.html +40 -40
- package/coverage/src/util/createRuleFactory.ts.html +19 -19
- package/coverage/src/util/index.html +30 -15
- package/coverage/src/util/makeDirectory.ts.html +11 -11
- package/coverage/src/util/packageDependencyGraphService.ts.html +1 -1
- package/coverage/src/util/zodSchemas.ts.html +130 -0
- package/package.json +15 -15
- package/src/REMOVE.ts +1 -0
- package/src/__tests__/alphabeticalDependencies.spec.ts +102 -0
- package/src/__tests__/alphabeticalScripts.spec.ts +18 -0
- package/src/__tests__/bannedDependencies.spec.ts +49 -0
- package/src/__tests__/consistentDependencies.spec.ts +23 -0
- package/src/__tests__/consistentVersions.spec.ts +142 -0
- package/src/__tests__/fileContents.spec.ts +348 -0
- package/src/__tests__/forceError.spec.ts +70 -0
- package/src/__tests__/mustSatisfyPeerDependencies.spec.ts +44 -0
- package/src/__tests__/nestedWorkspaces.spec.ts +14 -0
- package/src/__tests__/oncePerPackage.spec.ts +75 -0
- package/src/__tests__/packageEntry.spec.ts +177 -0
- package/src/__tests__/packageOrder.spec.ts +22 -0
- package/src/__tests__/packageScript.spec.ts +549 -0
- package/src/__tests__/requireDependency.spec.ts +259 -2
- package/src/__tests__/standardTsconfig.spec.ts +91 -0
- package/src/bannedDependencies.ts +14 -25
- package/src/consistentDependencies.ts +10 -8
- package/src/consistentVersions.ts +132 -83
- package/src/fileContents.ts +80 -35
- package/src/index.ts +2 -0
- package/src/mustSatisfyPeerDependencies.ts +10 -172
- package/src/nestedWorkspaces.ts +4 -4
- package/src/oncePerPackage.ts +6 -6
- package/src/packageEntry.ts +60 -50
- package/src/packageOrder.ts +19 -9
- package/src/packageScript.ts +67 -18
- package/src/requireDependency.ts +84 -31
- package/src/standardTsconfig.ts +26 -26
- package/src/util/zodSchemas.ts +15 -0
package/src/oncePerPackage.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { z } from "zod";
|
|
2
2
|
import { createRuleFactory } from "./util/createRuleFactory.js";
|
|
3
3
|
|
|
4
|
-
export const Options =
|
|
5
|
-
singletonKey:
|
|
6
|
-
customMessage:
|
|
4
|
+
export const Options = z.object({
|
|
5
|
+
singletonKey: z.union([z.string(), z.symbol()]),
|
|
6
|
+
customMessage: z.string().optional(),
|
|
7
7
|
});
|
|
8
8
|
|
|
9
|
-
export type Options =
|
|
9
|
+
export type Options = z.infer<typeof Options>;
|
|
10
10
|
|
|
11
11
|
const visitedMap = new Map<string | symbol, Set<string>>();
|
|
12
12
|
|
|
@@ -28,5 +28,5 @@ export const oncePerPackage = createRuleFactory<Options>({
|
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
30
|
|
|
31
|
-
validateOptions: Options.
|
|
31
|
+
validateOptions: Options.parse,
|
|
32
32
|
});
|
package/src/packageEntry.ts
CHANGED
|
@@ -7,35 +7,20 @@
|
|
|
7
7
|
|
|
8
8
|
import { mutateJson, PackageJson } from "@monorepolint/utils";
|
|
9
9
|
import { diff } from "jest-diff";
|
|
10
|
-
import
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { REMOVE } from "./REMOVE.js";
|
|
11
12
|
import { createRuleFactory } from "./util/createRuleFactory.js";
|
|
13
|
+
import { ZodRemove } from "./util/zodSchemas.js";
|
|
12
14
|
|
|
13
|
-
export const Options =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
r.Partial({
|
|
20
|
-
entriesExist: r.Undefined,
|
|
21
|
-
}),
|
|
22
|
-
),
|
|
23
|
-
r
|
|
24
|
-
.Record({
|
|
25
|
-
entriesExist: r.Array(r.String), // enforces existence of keys, but not values
|
|
26
|
-
})
|
|
27
|
-
.And(
|
|
28
|
-
r.Partial({
|
|
29
|
-
entries: r.Undefined,
|
|
30
|
-
}),
|
|
31
|
-
),
|
|
32
|
-
r.Record({
|
|
33
|
-
entries: r.Dictionary(r.Unknown), // string => unknown, enforces existence of keys and their values
|
|
34
|
-
entriesExist: r.Array(r.String),
|
|
35
|
-
}),
|
|
15
|
+
export const Options = z.object({
|
|
16
|
+
entries: z.record(z.string(), z.union([z.unknown(), ZodRemove])).optional(), // string => unknown | REMOVE, enforces existence of keys and their values or removal
|
|
17
|
+
entriesExist: z.array(z.string()).optional(), // enforces existence of keys, but not values
|
|
18
|
+
}).refine(
|
|
19
|
+
(data) => data.entries !== undefined || data.entriesExist !== undefined,
|
|
20
|
+
{ message: "At least one of 'entries' or 'entriesExist' must be provided" },
|
|
36
21
|
);
|
|
37
22
|
|
|
38
|
-
export type Options =
|
|
23
|
+
export type Options = z.infer<typeof Options>;
|
|
39
24
|
|
|
40
25
|
export const packageEntry = createRuleFactory<Options>({
|
|
41
26
|
name: "packageEntry",
|
|
@@ -46,30 +31,51 @@ export const packageEntry = createRuleFactory<Options>({
|
|
|
46
31
|
for (const key of Object.keys(options.entries)) {
|
|
47
32
|
const value = options.entries[key];
|
|
48
33
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
34
|
+
if (value === REMOVE) {
|
|
35
|
+
// Handle removal: only add error if key exists
|
|
36
|
+
if (packageJson[key] !== undefined) {
|
|
37
|
+
context.addError({
|
|
38
|
+
file: context.getPackageJsonPath(),
|
|
39
|
+
message: createRemovalEntryErrorMessage(key),
|
|
40
|
+
fixer: () => {
|
|
41
|
+
mutateJson<PackageJson>(
|
|
42
|
+
context.getPackageJsonPath(),
|
|
43
|
+
context.host,
|
|
44
|
+
(input) => {
|
|
45
|
+
delete input[key];
|
|
46
|
+
return input;
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
// Handle regular value checking
|
|
54
|
+
const entryDiff = diff(
|
|
55
|
+
JSON.stringify(value) + "\n",
|
|
56
|
+
(JSON.stringify(packageJson[key]) || "") + "\n",
|
|
57
|
+
);
|
|
58
|
+
if (
|
|
59
|
+
(typeof value !== "object" && value !== packageJson[key])
|
|
60
|
+
|| entryDiff == null
|
|
61
|
+
|| !entryDiff.includes("Compared values have no visual difference")
|
|
62
|
+
) {
|
|
63
|
+
context.addError({
|
|
64
|
+
file: context.getPackageJsonPath(),
|
|
65
|
+
message: createStandardizedEntryErrorMessage(key),
|
|
66
|
+
longMessage: entryDiff,
|
|
67
|
+
fixer: () => {
|
|
68
|
+
mutateJson<PackageJson>(
|
|
69
|
+
context.getPackageJsonPath(),
|
|
70
|
+
context.host,
|
|
71
|
+
(input) => {
|
|
72
|
+
input[key] = value;
|
|
73
|
+
return input;
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
73
79
|
}
|
|
74
80
|
}
|
|
75
81
|
}
|
|
@@ -85,7 +91,7 @@ export const packageEntry = createRuleFactory<Options>({
|
|
|
85
91
|
}
|
|
86
92
|
}
|
|
87
93
|
},
|
|
88
|
-
validateOptions: Options.
|
|
94
|
+
validateOptions: Options.parse,
|
|
89
95
|
});
|
|
90
96
|
|
|
91
97
|
export function createStandardizedEntryErrorMessage(key: string) {
|
|
@@ -95,3 +101,7 @@ export function createStandardizedEntryErrorMessage(key: string) {
|
|
|
95
101
|
export function createExpectedEntryErrorMessage(key: string) {
|
|
96
102
|
return `Expected entry for '${key}' to exist`;
|
|
97
103
|
}
|
|
104
|
+
|
|
105
|
+
export function createRemovalEntryErrorMessage(key: string) {
|
|
106
|
+
return `Entry '${key}' should be removed`;
|
|
107
|
+
}
|
package/src/packageOrder.ts
CHANGED
|
@@ -7,17 +7,27 @@
|
|
|
7
7
|
|
|
8
8
|
import { Context } from "@monorepolint/config";
|
|
9
9
|
import { diff } from "jest-diff";
|
|
10
|
-
import
|
|
10
|
+
import { z } from "zod";
|
|
11
11
|
import { createRuleFactory } from "./util/createRuleFactory.js";
|
|
12
12
|
type OrderFunction = (context: Context) => (a: string, b: string) => number;
|
|
13
13
|
|
|
14
|
-
const Options =
|
|
15
|
-
.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
const Options = z.union([
|
|
15
|
+
z.undefined(),
|
|
16
|
+
z.object({
|
|
17
|
+
order: z.union([
|
|
18
|
+
z.array(z.string()),
|
|
19
|
+
z.function({
|
|
20
|
+
input: [z.any()],
|
|
21
|
+
output: z.function({
|
|
22
|
+
input: [z.string(), z.string()],
|
|
23
|
+
output: z.number(),
|
|
24
|
+
}),
|
|
25
|
+
}),
|
|
26
|
+
]),
|
|
27
|
+
}),
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
type Options = z.infer<typeof Options>;
|
|
21
31
|
|
|
22
32
|
const defaultKeyOrder = [
|
|
23
33
|
"name",
|
|
@@ -86,7 +96,7 @@ export const packageOrder = createRuleFactory<Options>({
|
|
|
86
96
|
});
|
|
87
97
|
}
|
|
88
98
|
},
|
|
89
|
-
validateOptions: Options.
|
|
99
|
+
validateOptions: Options.parse,
|
|
90
100
|
});
|
|
91
101
|
|
|
92
102
|
function arrayOrderCompare(a: ReadonlyArray<string>, b: ReadonlyArray<string>) {
|
package/src/packageScript.ts
CHANGED
|
@@ -7,22 +7,35 @@
|
|
|
7
7
|
|
|
8
8
|
import { mutateJson, PackageJson } from "@monorepolint/utils";
|
|
9
9
|
import { diff } from "jest-diff";
|
|
10
|
-
import
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { REMOVE } from "./REMOVE.js";
|
|
11
12
|
import { createRuleFactory } from "./util/createRuleFactory.js";
|
|
13
|
+
import { ZodRemove } from "./util/zodSchemas.js";
|
|
12
14
|
|
|
13
|
-
export const Options =
|
|
14
|
-
scripts:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
export const Options = z.object({
|
|
16
|
+
scripts: z.record(
|
|
17
|
+
z.string(),
|
|
18
|
+
z.union([
|
|
19
|
+
z.string(),
|
|
20
|
+
ZodRemove, // Allow direct REMOVE values like { "build": REMOVE }
|
|
21
|
+
z.object({
|
|
22
|
+
options: z.array(z.union([
|
|
23
|
+
z.string(),
|
|
24
|
+
z.undefined(),
|
|
25
|
+
ZodRemove,
|
|
26
|
+
])),
|
|
27
|
+
fixValue: z.union([
|
|
28
|
+
z.string(),
|
|
29
|
+
z.undefined(),
|
|
30
|
+
z.literal(false),
|
|
31
|
+
ZodRemove,
|
|
32
|
+
]).optional(),
|
|
20
33
|
}),
|
|
21
|
-
),
|
|
22
|
-
), // string => string
|
|
34
|
+
]),
|
|
35
|
+
), // string => string | REMOVE | object
|
|
23
36
|
});
|
|
24
37
|
|
|
25
|
-
export type Options =
|
|
38
|
+
export type Options = z.infer<typeof Options>;
|
|
26
39
|
|
|
27
40
|
export const MSG_NO_SCRIPTS_BLOCK = "No scripts block in package.json";
|
|
28
41
|
|
|
@@ -48,28 +61,63 @@ export const packageScript = createRuleFactory<Options>({
|
|
|
48
61
|
return;
|
|
49
62
|
}
|
|
50
63
|
for (const [name, value] of Object.entries(options.scripts)) {
|
|
51
|
-
const allowedValues = new Set<string | undefined>();
|
|
52
|
-
let fixValue: string | undefined | false;
|
|
64
|
+
const allowedValues = new Set<string | undefined | typeof REMOVE>();
|
|
65
|
+
let fixValue: string | undefined | false | typeof REMOVE;
|
|
53
66
|
let allowEmpty = false;
|
|
54
67
|
let fixToEmpty = false;
|
|
68
|
+
let fixToRemove = false;
|
|
55
69
|
|
|
56
70
|
if (typeof value === "string") {
|
|
57
71
|
allowedValues.add(value);
|
|
58
72
|
fixValue = value;
|
|
73
|
+
} else if (value === REMOVE) {
|
|
74
|
+
// Handle direct REMOVE value: script should be removed
|
|
75
|
+
allowedValues.add(REMOVE);
|
|
76
|
+
fixValue = REMOVE;
|
|
77
|
+
fixToRemove = true;
|
|
59
78
|
} else {
|
|
60
79
|
for (const q of value.options) {
|
|
61
80
|
if (q === undefined) {
|
|
62
81
|
allowEmpty = true;
|
|
82
|
+
} else if (q === REMOVE) {
|
|
83
|
+
allowEmpty = true;
|
|
63
84
|
}
|
|
64
85
|
allowedValues.add(q);
|
|
65
86
|
}
|
|
66
87
|
fixToEmpty = Object.prototype.hasOwnProperty.call(value, "fixValue")
|
|
67
88
|
&& value.fixValue === undefined;
|
|
89
|
+
fixToRemove = Object.prototype.hasOwnProperty.call(value, "fixValue")
|
|
90
|
+
&& value.fixValue === REMOVE;
|
|
68
91
|
fixValue = value.fixValue;
|
|
69
92
|
}
|
|
70
93
|
|
|
71
94
|
const actualValue = packageJson.scripts[name];
|
|
72
95
|
|
|
96
|
+
// Special handling for direct REMOVE: only error if script exists
|
|
97
|
+
if (value === REMOVE) {
|
|
98
|
+
if (actualValue !== undefined) {
|
|
99
|
+
// Script exists but should be removed
|
|
100
|
+
const fixer = () => {
|
|
101
|
+
mutateJson<PackageJson>(
|
|
102
|
+
context.getPackageJsonPath(),
|
|
103
|
+
context.host,
|
|
104
|
+
(input) => {
|
|
105
|
+
delete input.scripts![name];
|
|
106
|
+
return input;
|
|
107
|
+
},
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
context.addError({
|
|
112
|
+
file: context.getPackageJsonPath(),
|
|
113
|
+
message: `Script '${name}' should be removed`,
|
|
114
|
+
fixer,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
// If script doesn't exist, no error needed
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
|
|
73
121
|
if (
|
|
74
122
|
!allowedValues.has(actualValue)
|
|
75
123
|
&& !(allowEmpty === true && actualValue === undefined)
|
|
@@ -77,7 +125,8 @@ export const packageScript = createRuleFactory<Options>({
|
|
|
77
125
|
let fixer;
|
|
78
126
|
|
|
79
127
|
if (
|
|
80
|
-
fixValue !== false
|
|
128
|
+
fixValue !== false
|
|
129
|
+
&& (fixValue !== undefined || fixToEmpty === true || fixToRemove === true)
|
|
81
130
|
) {
|
|
82
131
|
const q = fixValue;
|
|
83
132
|
fixer = () => {
|
|
@@ -85,10 +134,10 @@ export const packageScript = createRuleFactory<Options>({
|
|
|
85
134
|
context.getPackageJsonPath(),
|
|
86
135
|
context.host,
|
|
87
136
|
(input) => {
|
|
88
|
-
if (fixToEmpty && q === undefined) {
|
|
137
|
+
if ((fixToEmpty && q === undefined) || (fixToRemove && q === REMOVE)) {
|
|
89
138
|
delete input.scripts![name];
|
|
90
139
|
} else {
|
|
91
|
-
input.scripts![name] = q
|
|
140
|
+
input.scripts![name] = q as string;
|
|
92
141
|
}
|
|
93
142
|
return input;
|
|
94
143
|
},
|
|
@@ -97,7 +146,7 @@ export const packageScript = createRuleFactory<Options>({
|
|
|
97
146
|
}
|
|
98
147
|
|
|
99
148
|
const validOptionsString = Array.from(allowedValues.values())
|
|
100
|
-
.map((a) => (a === undefined ? "(empty)" : `'${a}'`))
|
|
149
|
+
.map((a) => (a === undefined || a === REMOVE ? "(empty)" : `'${a}'`))
|
|
101
150
|
.join(", ");
|
|
102
151
|
|
|
103
152
|
context.addError({
|
|
@@ -113,5 +162,5 @@ export const packageScript = createRuleFactory<Options>({
|
|
|
113
162
|
}
|
|
114
163
|
}
|
|
115
164
|
},
|
|
116
|
-
validateOptions: Options.
|
|
165
|
+
validateOptions: Options.parse,
|
|
117
166
|
});
|
package/src/requireDependency.ts
CHANGED
|
@@ -8,17 +8,43 @@
|
|
|
8
8
|
import { Context } from "@monorepolint/config";
|
|
9
9
|
import { mutateJson, PackageJson } from "@monorepolint/utils";
|
|
10
10
|
import { diff } from "jest-diff";
|
|
11
|
-
import
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import { REMOVE } from "./REMOVE.js";
|
|
12
13
|
import { createRuleFactory } from "./util/createRuleFactory.js";
|
|
14
|
+
import { ZodRemove } from "./util/zodSchemas.js";
|
|
13
15
|
|
|
14
|
-
const Options =
|
|
15
|
-
dependencies:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
const Options = z.object({
|
|
17
|
+
dependencies: z.record(
|
|
18
|
+
z.string(),
|
|
19
|
+
z.union([
|
|
20
|
+
z.string(),
|
|
21
|
+
ZodRemove,
|
|
22
|
+
]).optional(),
|
|
23
|
+
).optional(),
|
|
24
|
+
devDependencies: z.record(
|
|
25
|
+
z.string(),
|
|
26
|
+
z.union([
|
|
27
|
+
z.string(),
|
|
28
|
+
ZodRemove,
|
|
29
|
+
]).optional(),
|
|
30
|
+
).optional(),
|
|
31
|
+
peerDependencies: z.record(
|
|
32
|
+
z.string(),
|
|
33
|
+
z.union([
|
|
34
|
+
z.string(),
|
|
35
|
+
ZodRemove,
|
|
36
|
+
]).optional(),
|
|
37
|
+
).optional(),
|
|
38
|
+
optionalDependencies: z.record(
|
|
39
|
+
z.string(),
|
|
40
|
+
z.union([
|
|
41
|
+
z.string(),
|
|
42
|
+
ZodRemove,
|
|
43
|
+
]).optional(),
|
|
44
|
+
).optional(),
|
|
45
|
+
}).partial();
|
|
20
46
|
|
|
21
|
-
type Options =
|
|
47
|
+
type Options = z.infer<typeof Options>;
|
|
22
48
|
|
|
23
49
|
export const requireDependency = createRuleFactory({
|
|
24
50
|
name: "requireDependency",
|
|
@@ -37,29 +63,40 @@ export const requireDependency = createRuleFactory({
|
|
|
37
63
|
return;
|
|
38
64
|
}
|
|
39
65
|
|
|
66
|
+
// Separate additions from removals upfront
|
|
67
|
+
const dependenciesToAdd = Object.entries(expectedEntries).filter(
|
|
68
|
+
([, version]) => version !== REMOVE && version !== undefined,
|
|
69
|
+
);
|
|
70
|
+
const dependenciesToRemove = Object.entries(expectedEntries).filter(
|
|
71
|
+
([, version]) => version === REMOVE,
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
// Handle missing dependency block
|
|
40
75
|
if (packageJson[type] === undefined) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
76
|
+
// Only create block if there are dependencies to add (REMOVE entries shouldn't create blocks)
|
|
77
|
+
if (dependenciesToAdd.length > 0) {
|
|
78
|
+
context.addError({
|
|
79
|
+
file: packageJsonPath,
|
|
80
|
+
message: `No ${type} block, cannot add required ${type}.`,
|
|
81
|
+
fixer: () => {
|
|
82
|
+
mutateJson<PackageJson>(packageJsonPath, context.host, (input) => {
|
|
83
|
+
input[type] = Object.fromEntries(dependenciesToAdd) as Record<string, string>;
|
|
84
|
+
return input;
|
|
85
|
+
});
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return; // Can't remove from non-existent block
|
|
54
90
|
}
|
|
55
91
|
|
|
56
|
-
|
|
92
|
+
// Process additions
|
|
93
|
+
for (const [dep, version] of dependenciesToAdd) {
|
|
57
94
|
if (packageJson[type]?.[dep] !== version) {
|
|
58
95
|
context.addError({
|
|
59
96
|
file: packageJsonPath,
|
|
60
|
-
message: `Expected dependency ${dep}@${version}`,
|
|
97
|
+
message: `Expected dependency ${dep}@${version as string}`,
|
|
61
98
|
longMessage: diff(
|
|
62
|
-
`${dep}@${version}\n`,
|
|
99
|
+
`${dep}@${version as string}\n`,
|
|
63
100
|
`${dep}@${packageJson[type]![dep] || "missing"}\n`,
|
|
64
101
|
)!,
|
|
65
102
|
fixer: () => {
|
|
@@ -67,12 +104,28 @@ export const requireDependency = createRuleFactory({
|
|
|
67
104
|
packageJsonPath,
|
|
68
105
|
context.host,
|
|
69
106
|
(input) => {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
107
|
+
input[type] = { ...input[type], [dep]: version as string };
|
|
108
|
+
return input;
|
|
109
|
+
},
|
|
110
|
+
);
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Process removals
|
|
117
|
+
for (const [dep] of dependenciesToRemove) {
|
|
118
|
+
if (packageJson[type]?.[dep] !== undefined) {
|
|
119
|
+
context.addError({
|
|
120
|
+
file: packageJsonPath,
|
|
121
|
+
message: `Dependency ${dep} should be removed`,
|
|
122
|
+
fixer: () => {
|
|
123
|
+
mutateJson<PackageJson>(
|
|
124
|
+
packageJsonPath,
|
|
125
|
+
context.host,
|
|
126
|
+
(input) => {
|
|
127
|
+
input[type] = { ...input[type] };
|
|
128
|
+
delete input[type][dep];
|
|
76
129
|
return input;
|
|
77
130
|
},
|
|
78
131
|
);
|
|
@@ -82,5 +135,5 @@ export const requireDependency = createRuleFactory({
|
|
|
82
135
|
}
|
|
83
136
|
});
|
|
84
137
|
},
|
|
85
|
-
validateOptions: Options.
|
|
138
|
+
validateOptions: Options.parse,
|
|
86
139
|
});
|
package/src/standardTsconfig.ts
CHANGED
|
@@ -9,38 +9,38 @@ import { Context } from "@monorepolint/config";
|
|
|
9
9
|
import { matchesAnyGlob } from "@monorepolint/utils";
|
|
10
10
|
import { diff } from "jest-diff";
|
|
11
11
|
import * as path from "path";
|
|
12
|
-
import
|
|
12
|
+
import { z } from "zod";
|
|
13
13
|
import { createRuleFactory } from "./util/createRuleFactory.js";
|
|
14
14
|
|
|
15
15
|
const DEFAULT_TSCONFIG_FILENAME = "tsconfig.json";
|
|
16
16
|
|
|
17
|
-
const Options =
|
|
18
|
-
.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
count++;
|
|
37
|
-
}
|
|
17
|
+
const Options = z.object({
|
|
18
|
+
file: z.string().optional(),
|
|
19
|
+
generator: z.custom<(context: Context) => Promise<string> | string>().optional(),
|
|
20
|
+
tsconfigReferenceFile: z.string().optional(),
|
|
21
|
+
template: z.record(z.string(), z.unknown()).optional(),
|
|
22
|
+
templateFile: z.string().optional(),
|
|
23
|
+
excludedReferences: z.array(z.string()).optional(),
|
|
24
|
+
additionalReferences: z.array(z.string()).optional(),
|
|
25
|
+
}).partial().refine(({ generator, template, templateFile }) => {
|
|
26
|
+
let count = 0;
|
|
27
|
+
if (generator) {
|
|
28
|
+
count++;
|
|
29
|
+
}
|
|
30
|
+
if (template) {
|
|
31
|
+
count++;
|
|
32
|
+
}
|
|
33
|
+
if (templateFile) {
|
|
34
|
+
count++;
|
|
35
|
+
}
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
return count === 1;
|
|
38
|
+
}, {
|
|
39
|
+
message: "Expect one of { generator, template, templateFile }",
|
|
40
|
+
});
|
|
41
41
|
|
|
42
42
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
43
|
-
export interface Options extends
|
|
43
|
+
export interface Options extends z.infer<typeof Options> {}
|
|
44
44
|
|
|
45
45
|
export const standardTsconfig = createRuleFactory<Options>({
|
|
46
46
|
name: "standardTsconfig",
|
|
@@ -75,7 +75,7 @@ export const standardTsconfig = createRuleFactory<Options>({
|
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
77
|
},
|
|
78
|
-
validateOptions: Options.
|
|
78
|
+
validateOptions: Options.parse,
|
|
79
79
|
});
|
|
80
80
|
|
|
81
81
|
function getGenerator(context: Context, opts: Options) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright 2019 Palantir Technologies, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the MIT license. See LICENSE file in the project root for details.
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { REMOVE } from "../REMOVE.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Reusable Zod schema for the REMOVE symbol.
|
|
13
|
+
* This schema validates that a value is exactly the REMOVE symbol.
|
|
14
|
+
*/
|
|
15
|
+
export const ZodRemove = z.custom<typeof REMOVE>((x) => x === REMOVE);
|