@monorepolint/rules 0.5.0-alpha.10 → 0.5.0-alpha.106
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 +4 -0
- package/.turbo/turbo-compile-typescript.log +4 -0
- package/.turbo/turbo-lint.log +110 -0
- package/.turbo/turbo-test.log +638 -0
- package/.turbo/turbo-transpile-typescript.log +14 -0
- package/build/js/index.js +1417 -0
- package/build/js/index.js.map +1 -0
- package/build/tsconfig.tsbuildinfo +1 -0
- package/{lib/__tests__/utils.d.ts → build/types/__tests__/alphabeticalScripts.spec.d.ts} +2 -2
- package/build/types/__tests__/alphabeticalScripts.spec.d.ts.map +1 -0
- package/build/types/__tests__/bannedDependencies.spec.d.ts +2 -0
- package/build/types/__tests__/bannedDependencies.spec.d.ts.map +1 -0
- package/build/types/__tests__/consistentDependencies.spec.d.ts.map +1 -0
- package/build/types/__tests__/consistentVersions.spec.d.ts +8 -0
- package/build/types/__tests__/consistentVersions.spec.d.ts.map +1 -0
- package/build/types/__tests__/fileContents.spec.d.ts +8 -0
- package/build/types/__tests__/fileContents.spec.d.ts.map +1 -0
- package/build/types/__tests__/mustSatisfyPeerDependencies.spec.d.ts +8 -0
- package/build/types/__tests__/mustSatisfyPeerDependencies.spec.d.ts.map +1 -0
- package/build/types/__tests__/nestedWorkspaces.spec.d.ts +2 -0
- package/build/types/__tests__/nestedWorkspaces.spec.d.ts.map +1 -0
- package/build/types/__tests__/packageEntry.spec.d.ts.map +1 -0
- package/build/types/__tests__/packageOrder.spec.d.ts.map +1 -0
- package/build/types/__tests__/packageScript.spec.d.ts.map +1 -0
- package/build/types/__tests__/requireDependency.spec.d.ts +2 -0
- package/build/types/__tests__/requireDependency.spec.d.ts.map +1 -0
- package/build/types/__tests__/utils.d.ts +81 -0
- package/build/types/__tests__/utils.d.ts.map +1 -0
- package/build/types/alphabeticalDependencies.d.ts +9 -0
- package/build/types/alphabeticalDependencies.d.ts.map +1 -0
- package/build/types/alphabeticalScripts.d.ts +9 -0
- package/build/types/alphabeticalScripts.d.ts.map +1 -0
- package/build/types/bannedDependencies.d.ts +66 -0
- package/build/types/bannedDependencies.d.ts.map +1 -0
- package/build/types/consistentDependencies.d.ts +18 -0
- package/build/types/consistentDependencies.d.ts.map +1 -0
- package/build/types/consistentVersions.d.ts +21 -0
- package/build/types/consistentVersions.d.ts.map +1 -0
- package/build/types/fileContents.d.ts +39 -0
- package/build/types/fileContents.d.ts.map +1 -0
- package/build/types/index.d.ts +20 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/mustSatisfyPeerDependencies.d.ts +427 -0
- package/build/types/mustSatisfyPeerDependencies.d.ts.map +1 -0
- package/build/types/nestedWorkspaces.d.ts +10 -0
- package/build/types/nestedWorkspaces.d.ts.map +1 -0
- package/build/types/packageEntry.d.ts +54 -0
- package/build/types/packageEntry.d.ts.map +1 -0
- package/build/types/packageOrder.d.ts +13 -0
- package/build/types/packageOrder.d.ts.map +1 -0
- package/build/types/packageScript.d.ts +37 -0
- package/build/types/packageScript.d.ts.map +1 -0
- package/build/types/public/util.d.ts +2 -0
- package/build/types/public/util.d.ts.map +1 -0
- package/build/types/requireDependency.d.ts +35 -0
- package/build/types/requireDependency.d.ts.map +1 -0
- package/build/types/standardTsconfig.d.ts +53 -0
- package/build/types/standardTsconfig.d.ts.map +1 -0
- package/build/types/util/checkAlpha.d.ts +10 -0
- package/build/types/util/checkAlpha.d.ts.map +1 -0
- package/build/types/util/makeDirectory.d.ts +8 -0
- package/build/types/util/makeDirectory.d.ts.map +1 -0
- package/build/types/util/makeRule.d.ts +13 -0
- package/build/types/util/makeRule.d.ts.map +1 -0
- package/build/types/util/packageDependencyGraphService.d.ts +37 -0
- package/build/types/util/packageDependencyGraphService.d.ts.map +1 -0
- package/package.json +45 -20
- package/src/__tests__/alphabeticalScripts.spec.ts +76 -0
- package/src/__tests__/bannedDependencies.spec.ts +189 -0
- package/src/__tests__/consistentDependencies.spec.ts +42 -28
- package/src/__tests__/consistentVersions.spec.ts +224 -0
- package/src/__tests__/fileContents.spec.ts +79 -0
- package/src/__tests__/mustSatisfyPeerDependencies.spec.ts +1189 -0
- package/src/__tests__/nestedWorkspaces.spec.ts +153 -0
- package/src/__tests__/packageEntry.spec.ts +127 -49
- package/src/__tests__/packageOrder.spec.ts +68 -53
- package/src/__tests__/packageScript.spec.ts +124 -98
- package/src/__tests__/requireDependency.spec.ts +152 -0
- package/src/__tests__/utils.ts +115 -11
- package/src/alphabeticalDependencies.ts +6 -50
- package/src/alphabeticalScripts.ts +19 -0
- package/src/bannedDependencies.ts +134 -45
- package/src/consistentDependencies.ts +39 -16
- package/src/consistentVersions.ts +141 -0
- package/src/fileContents.ts +39 -35
- package/src/index.ts +13 -8
- package/src/mustSatisfyPeerDependencies.ts +744 -0
- package/src/nestedWorkspaces.ts +60 -0
- package/src/packageEntry.ts +71 -27
- package/src/packageOrder.ts +15 -12
- package/src/packageScript.ts +14 -18
- package/src/public/util.ts +1 -0
- package/src/requireDependency.ts +71 -0
- package/src/standardTsconfig.ts +49 -26
- package/src/util/checkAlpha.ts +59 -0
- package/src/util/makeDirectory.ts +24 -0
- package/src/util/makeRule.ts +29 -0
- package/src/util/packageDependencyGraphService.ts +114 -0
- package/tsconfig.json +10 -2
- package/lib/__tests__/consistentDependencies.spec.d.ts.map +0 -1
- package/lib/__tests__/consistentDependencies.spec.js +0 -108
- package/lib/__tests__/consistentDependencies.spec.js.map +0 -1
- package/lib/__tests__/packageEntry.spec.d.ts.map +0 -1
- package/lib/__tests__/packageEntry.spec.js +0 -99
- package/lib/__tests__/packageEntry.spec.js.map +0 -1
- package/lib/__tests__/packageOrder.spec.d.ts.map +0 -1
- package/lib/__tests__/packageOrder.spec.js +0 -115
- package/lib/__tests__/packageOrder.spec.js.map +0 -1
- package/lib/__tests__/packageScript.spec.d.ts.map +0 -1
- package/lib/__tests__/packageScript.spec.js +0 -172
- package/lib/__tests__/packageScript.spec.js.map +0 -1
- package/lib/__tests__/utils.d.ts.map +0 -1
- package/lib/__tests__/utils.js +0 -23
- package/lib/__tests__/utils.js.map +0 -1
- package/lib/alphabeticalDependencies.d.ts +0 -10
- package/lib/alphabeticalDependencies.d.ts.map +0 -1
- package/lib/alphabeticalDependencies.js +0 -56
- package/lib/alphabeticalDependencies.js.map +0 -1
- package/lib/bannedDependencies.d.ts +0 -15
- package/lib/bannedDependencies.d.ts.map +0 -1
- package/lib/bannedDependencies.js +0 -57
- package/lib/bannedDependencies.js.map +0 -1
- package/lib/consistentDependencies.d.ts +0 -10
- package/lib/consistentDependencies.d.ts.map +0 -1
- package/lib/consistentDependencies.js +0 -57
- package/lib/consistentDependencies.js.map +0 -1
- package/lib/fileContents.d.ts +0 -25
- package/lib/fileContents.d.ts.map +0 -1
- package/lib/fileContents.js +0 -77
- package/lib/fileContents.js.map +0 -1
- package/lib/index.d.ts +0 -15
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js +0 -25
- package/lib/index.js.map +0 -1
- package/lib/packageEntry.d.ts +0 -16
- package/lib/packageEntry.d.ts.map +0 -1
- package/lib/packageEntry.js +0 -40
- package/lib/packageEntry.js.map +0 -1
- package/lib/packageOrder.d.ts +0 -12
- package/lib/packageOrder.d.ts.map +0 -1
- package/lib/packageOrder.js +0 -103
- package/lib/packageOrder.js.map +0 -1
- package/lib/packageScript.d.ts +0 -25
- package/lib/packageScript.d.ts.map +0 -1
- package/lib/packageScript.js +0 -89
- package/lib/packageScript.js.map +0 -1
- package/lib/standardTsconfig.d.ts +0 -33
- package/lib/standardTsconfig.d.ts.map +0 -1
- package/lib/standardTsconfig.js +0 -98
- package/lib/standardTsconfig.js.map +0 -1
- package/tsconfig.tsbuildinfo +0 -2439
- /package/{lib → build/types}/__tests__/consistentDependencies.spec.d.ts +0 -0
- /package/{lib → build/types}/__tests__/packageEntry.spec.d.ts +0 -0
- /package/{lib → build/types}/__tests__/packageOrder.spec.d.ts +0 -0
- /package/{lib → build/types}/__tests__/packageScript.spec.d.ts +0 -0
- /package/{jest.config.js → jest.config.cjs} +0 -0
|
@@ -6,13 +6,10 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
// tslint:disable:no-console
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import { Failure, PackageContext } from "@monorepolint/core";
|
|
15
|
-
import { packageScript } from "../packageScript";
|
|
9
|
+
import { describe, expect, it, beforeEach, jest } from "@jest/globals";
|
|
10
|
+
import { Context, Failure } from "@monorepolint/config";
|
|
11
|
+
import { packageScript } from "../packageScript.js";
|
|
12
|
+
import { AddErrorSpy, createTestingWorkspace, HOST_FACTORIES, TestingWorkspace } from "./utils.js";
|
|
16
13
|
|
|
17
14
|
const json = (a: unknown) => JSON.stringify(a, undefined, 2) + "\n";
|
|
18
15
|
|
|
@@ -33,120 +30,143 @@ const PACKAGE_WITH_SCRIPTS = json({
|
|
|
33
30
|
},
|
|
34
31
|
});
|
|
35
32
|
|
|
36
|
-
describe("expectPackageScript", () => {
|
|
37
|
-
afterEach(() => {
|
|
38
|
-
mockFiles.clear();
|
|
39
|
-
});
|
|
40
|
-
|
|
33
|
+
describe.each(HOST_FACTORIES)("expectPackageScript ($name)", (hostFactory) => {
|
|
41
34
|
describe("fix: false", () => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
fix: false,
|
|
45
|
-
verbose: false,
|
|
46
|
-
silent: true,
|
|
47
|
-
});
|
|
35
|
+
let workspace: TestingWorkspace;
|
|
36
|
+
let spy: AddErrorSpy;
|
|
48
37
|
|
|
49
|
-
|
|
38
|
+
beforeEach(async () => {
|
|
39
|
+
workspace = await createTestingWorkspace({
|
|
40
|
+
fixFlag: false,
|
|
41
|
+
host: hostFactory.make(),
|
|
42
|
+
});
|
|
50
43
|
|
|
51
|
-
|
|
52
|
-
spy.mockClear();
|
|
44
|
+
spy = jest.spyOn(workspace.context, "addError");
|
|
53
45
|
});
|
|
54
46
|
|
|
55
47
|
it("handles an empty script section", () => {
|
|
56
|
-
|
|
48
|
+
workspace.writeFile("package.json", PACKAGE_WITHOUT_SCRIPTS);
|
|
57
49
|
|
|
58
|
-
packageScript
|
|
59
|
-
|
|
60
|
-
|
|
50
|
+
packageScript({
|
|
51
|
+
options: {
|
|
52
|
+
scripts: {
|
|
53
|
+
foo: "bar",
|
|
54
|
+
},
|
|
61
55
|
},
|
|
62
|
-
});
|
|
56
|
+
}).check(workspace.context);
|
|
63
57
|
|
|
64
58
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
65
59
|
|
|
66
60
|
const failure: Failure = spy.mock.calls[0][0];
|
|
67
|
-
expect(failure
|
|
68
|
-
|
|
69
|
-
|
|
61
|
+
expect(failure).toMatchObject(
|
|
62
|
+
workspace.failureMatcher({
|
|
63
|
+
file: "package.json",
|
|
64
|
+
hasFixer: true,
|
|
65
|
+
message: "No scripts block in package.json",
|
|
66
|
+
})
|
|
67
|
+
);
|
|
70
68
|
});
|
|
71
69
|
});
|
|
72
70
|
|
|
73
71
|
describe("fix: true", () => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
72
|
+
let workspace: TestingWorkspace;
|
|
73
|
+
let spy: AddErrorSpy;
|
|
74
|
+
let context: Context;
|
|
75
|
+
|
|
76
|
+
beforeEach(async () => {
|
|
77
|
+
workspace = await createTestingWorkspace({
|
|
78
|
+
fixFlag: true,
|
|
79
|
+
host: hostFactory.make(),
|
|
80
|
+
});
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
spy = jest.spyOn(workspace.context, "addError");
|
|
83
|
+
context = workspace.context; // minimizing delta
|
|
84
84
|
});
|
|
85
85
|
|
|
86
86
|
it("fixes an empty script section", () => {
|
|
87
|
-
|
|
87
|
+
workspace.writeFile("package.json", PACKAGE_WITHOUT_SCRIPTS);
|
|
88
88
|
|
|
89
|
-
packageScript
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
packageScript({
|
|
90
|
+
options: {
|
|
91
|
+
scripts: {
|
|
92
|
+
foo: "bar",
|
|
93
|
+
},
|
|
92
94
|
},
|
|
93
|
-
});
|
|
95
|
+
}).check(context);
|
|
94
96
|
|
|
95
97
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
96
98
|
|
|
97
99
|
const failure: Failure = spy.mock.calls[0][0];
|
|
98
|
-
expect(failure
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
expect(failure).toMatchObject(
|
|
101
|
+
workspace.failureMatcher({
|
|
102
|
+
file: "package.json",
|
|
103
|
+
hasFixer: true,
|
|
104
|
+
message: "No scripts block in package.json",
|
|
105
|
+
})
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual({});
|
|
103
109
|
});
|
|
104
110
|
|
|
105
111
|
it("adds a script", () => {
|
|
106
|
-
|
|
112
|
+
workspace.writeFile("package.json", PACKAGE_WITH_SCRIPTS);
|
|
107
113
|
|
|
108
|
-
packageScript
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
packageScript({
|
|
115
|
+
options: {
|
|
116
|
+
scripts: {
|
|
117
|
+
[MISSING_SCRIPT_NAME]: MISSING_SCRIPT_VALUE,
|
|
118
|
+
},
|
|
111
119
|
},
|
|
112
|
-
});
|
|
120
|
+
}).check(context);
|
|
113
121
|
|
|
114
122
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
115
123
|
|
|
116
124
|
const failure: Failure = spy.mock.calls[0][0];
|
|
117
|
-
expect(failure
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
125
|
+
expect(failure).toMatchObject(
|
|
126
|
+
workspace.failureMatcher({
|
|
127
|
+
file: "package.json",
|
|
128
|
+
hasFixer: true,
|
|
129
|
+
message: expect.stringContaining(
|
|
130
|
+
`Expected standardized script entry for '${MISSING_SCRIPT_NAME}'`
|
|
131
|
+
) as any as string,
|
|
132
|
+
})
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
expect(JSON.parse(workspace.readFile("package.json")!).scripts[MISSING_SCRIPT_NAME]).toEqual(
|
|
136
|
+
MISSING_SCRIPT_VALUE
|
|
137
|
+
);
|
|
122
138
|
});
|
|
123
139
|
|
|
124
140
|
it("does nothing if the value exists", () => {
|
|
125
|
-
|
|
141
|
+
workspace.writeFile("package.json", PACKAGE_WITH_SCRIPTS);
|
|
126
142
|
|
|
127
|
-
packageScript
|
|
128
|
-
|
|
129
|
-
|
|
143
|
+
packageScript({
|
|
144
|
+
options: {
|
|
145
|
+
scripts: {
|
|
146
|
+
[SCRIPT_NAME]: SCRIPT_VALUE,
|
|
147
|
+
},
|
|
130
148
|
},
|
|
131
|
-
});
|
|
149
|
+
}).check(context);
|
|
132
150
|
|
|
133
151
|
expect(spy).not.toHaveBeenCalled();
|
|
134
152
|
|
|
135
|
-
expect(JSON.parse(
|
|
153
|
+
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual({
|
|
136
154
|
[SCRIPT_NAME]: SCRIPT_VALUE,
|
|
137
155
|
});
|
|
138
156
|
});
|
|
139
157
|
|
|
140
158
|
it("errors if long form is used and no value matches and there is no fixValue", () => {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
packageScript
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
159
|
+
workspace.writeFile("package.json", PACKAGE_WITH_SCRIPTS);
|
|
160
|
+
|
|
161
|
+
packageScript({
|
|
162
|
+
options: {
|
|
163
|
+
scripts: {
|
|
164
|
+
foo: {
|
|
165
|
+
options: ["a", "b"],
|
|
166
|
+
},
|
|
147
167
|
},
|
|
148
168
|
},
|
|
149
|
-
});
|
|
169
|
+
}).check(context);
|
|
150
170
|
|
|
151
171
|
const errors = spy.mock.calls;
|
|
152
172
|
|
|
@@ -155,66 +175,72 @@ describe("expectPackageScript", () => {
|
|
|
155
175
|
});
|
|
156
176
|
|
|
157
177
|
it("uses the fixValue for fixing if provided", () => {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
packageScript
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
178
|
+
workspace.writeFile("package.json", PACKAGE_WITH_SCRIPTS);
|
|
179
|
+
|
|
180
|
+
packageScript({
|
|
181
|
+
options: {
|
|
182
|
+
scripts: {
|
|
183
|
+
foo: {
|
|
184
|
+
options: ["a", "b"],
|
|
185
|
+
fixValue: "a",
|
|
186
|
+
},
|
|
165
187
|
},
|
|
166
188
|
},
|
|
167
|
-
});
|
|
189
|
+
}).check(context);
|
|
168
190
|
|
|
169
191
|
const errors = spy.mock.calls;
|
|
170
192
|
|
|
171
193
|
expect(errors.length).toBe(1);
|
|
172
194
|
expect(errors[0][0].fixer).toBeDefined();
|
|
173
195
|
|
|
174
|
-
expect(JSON.parse(
|
|
196
|
+
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual({
|
|
175
197
|
[SCRIPT_NAME]: SCRIPT_VALUE,
|
|
176
198
|
foo: "a",
|
|
177
199
|
});
|
|
178
200
|
});
|
|
179
201
|
|
|
180
202
|
it("can fix to empty", () => {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
packageScript
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
203
|
+
workspace.writeFile("package.json", PACKAGE_WITH_SCRIPTS);
|
|
204
|
+
|
|
205
|
+
packageScript({
|
|
206
|
+
options: {
|
|
207
|
+
scripts: {
|
|
208
|
+
[SCRIPT_NAME]: {
|
|
209
|
+
options: ["a", undefined],
|
|
210
|
+
fixValue: undefined,
|
|
211
|
+
},
|
|
188
212
|
},
|
|
189
213
|
},
|
|
190
|
-
});
|
|
214
|
+
}).check(context);
|
|
191
215
|
|
|
192
216
|
const errors = spy.mock.calls;
|
|
193
217
|
|
|
194
218
|
expect(errors.length).toBe(1);
|
|
195
219
|
expect(errors[0][0].fixer).toBeDefined();
|
|
196
220
|
|
|
197
|
-
expect(JSON.parse(
|
|
221
|
+
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual({});
|
|
198
222
|
});
|
|
199
223
|
|
|
200
224
|
it("can allow only empty", () => {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
packageScript
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
225
|
+
workspace.writeFile("package.json", PACKAGE_WITH_SCRIPTS);
|
|
226
|
+
|
|
227
|
+
packageScript({
|
|
228
|
+
options: {
|
|
229
|
+
scripts: {
|
|
230
|
+
[SCRIPT_NAME]: {
|
|
231
|
+
options: [undefined],
|
|
232
|
+
fixValue: undefined,
|
|
233
|
+
},
|
|
208
234
|
},
|
|
209
235
|
},
|
|
210
|
-
});
|
|
236
|
+
}).check(context);
|
|
211
237
|
|
|
212
238
|
const errors = spy.mock.calls;
|
|
213
239
|
|
|
214
240
|
expect(errors.length).toBe(1);
|
|
215
241
|
expect(errors[0][0].fixer).toBeDefined();
|
|
216
242
|
|
|
217
|
-
expect(JSON.parse(
|
|
243
|
+
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual({});
|
|
218
244
|
});
|
|
219
245
|
});
|
|
220
246
|
});
|
|
@@ -0,0 +1,152 @@
|
|
|
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
|
+
import { WorkspaceContextImpl } from "@monorepolint/core";
|
|
8
|
+
import { SimpleHost } from "@monorepolint/utils";
|
|
9
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
10
|
+
import * as path from "node:path";
|
|
11
|
+
import * as tmp from "tmp";
|
|
12
|
+
import { requireDependency } from "../requireDependency.js";
|
|
13
|
+
import { makeDirectoryRecursively } from "../util/makeDirectory.js";
|
|
14
|
+
import { jsonToString } from "./utils.js";
|
|
15
|
+
import { describe, expect, it, afterEach, jest } from "@jest/globals";
|
|
16
|
+
|
|
17
|
+
const PACKAGE_ROOT = jsonToString({
|
|
18
|
+
workspaces: {
|
|
19
|
+
packages: ["packages/*"],
|
|
20
|
+
},
|
|
21
|
+
dependencies: {
|
|
22
|
+
foo: "5",
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const PACKAGE_WITH_NO_ENTRIES = jsonToString({});
|
|
27
|
+
|
|
28
|
+
const PACKAGE_WITH_ENTRIES_MISSING = jsonToString({
|
|
29
|
+
dependencies: {},
|
|
30
|
+
devDependencies: {},
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const PACKAGE_WITH_WRONG_ENTRIES = jsonToString({
|
|
34
|
+
dependencies: {
|
|
35
|
+
foo: "0.1.0",
|
|
36
|
+
},
|
|
37
|
+
devDependencies: {
|
|
38
|
+
bar: "1.0.0",
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const PACKAGE_WITH_RIGHT_ENTRIES = jsonToString({
|
|
43
|
+
dependencies: {
|
|
44
|
+
foo: "1.0.0",
|
|
45
|
+
},
|
|
46
|
+
devDependencies: {
|
|
47
|
+
bar: "^2.0.0",
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const OPTIONS = {
|
|
52
|
+
dependencies: {
|
|
53
|
+
foo: "1.0.0",
|
|
54
|
+
},
|
|
55
|
+
devDependencies: {
|
|
56
|
+
bar: "^2.0.0",
|
|
57
|
+
},
|
|
58
|
+
} as const;
|
|
59
|
+
|
|
60
|
+
const CORRECT_OUTPUT = jsonToString(OPTIONS);
|
|
61
|
+
|
|
62
|
+
describe("requireDependency", () => {
|
|
63
|
+
tmp.setGracefulCleanup();
|
|
64
|
+
|
|
65
|
+
let cleanupJobs: Array<() => void> = [];
|
|
66
|
+
|
|
67
|
+
afterEach(() => {
|
|
68
|
+
for (const cleanupJob of cleanupJobs) {
|
|
69
|
+
cleanupJob();
|
|
70
|
+
}
|
|
71
|
+
cleanupJobs = [];
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
function makeWorkspace({ fix }: { fix: boolean }) {
|
|
75
|
+
const dir: tmp.DirResult = tmp.dirSync({ unsafeCleanup: true });
|
|
76
|
+
cleanupJobs.push(() => dir.removeCallback());
|
|
77
|
+
|
|
78
|
+
const workspaceContext = new WorkspaceContextImpl(
|
|
79
|
+
dir.name,
|
|
80
|
+
{
|
|
81
|
+
rules: [],
|
|
82
|
+
fix,
|
|
83
|
+
verbose: false,
|
|
84
|
+
silent: true,
|
|
85
|
+
},
|
|
86
|
+
new SimpleHost()
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
function checkAndSpy(q: string) {
|
|
90
|
+
const context = workspaceContext.createChildContext(path.resolve(dir.name, q));
|
|
91
|
+
const addErrorSpy = jest.spyOn(context, "addError");
|
|
92
|
+
requireDependency({ options: OPTIONS }).check(context);
|
|
93
|
+
return { context, addErrorSpy };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function addFile(filePath: string, content: string) {
|
|
97
|
+
const dirPath = path.resolve(dir.name, path.dirname(filePath));
|
|
98
|
+
const resolvedFilePath = path.resolve(dir.name, filePath);
|
|
99
|
+
|
|
100
|
+
makeDirectoryRecursively(dirPath);
|
|
101
|
+
writeFileSync(resolvedFilePath, content);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function readFile(filePath: string) {
|
|
105
|
+
return readFileSync(path.resolve(dir.name, filePath)).toString();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return { addFile, readFile, workspaceContext, checkAndSpy };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
it("checks correctly", () => {
|
|
112
|
+
const { addFile, workspaceContext, checkAndSpy } = makeWorkspace({ fix: false });
|
|
113
|
+
addFile("./package.json", PACKAGE_ROOT);
|
|
114
|
+
addFile("./packages/none/package.json", PACKAGE_WITH_NO_ENTRIES);
|
|
115
|
+
addFile("./packages/missing/package.json", PACKAGE_WITH_ENTRIES_MISSING);
|
|
116
|
+
addFile("./packages/wrong/package.json", PACKAGE_WITH_WRONG_ENTRIES);
|
|
117
|
+
addFile("./packages/right/package.json", PACKAGE_WITH_RIGHT_ENTRIES);
|
|
118
|
+
|
|
119
|
+
requireDependency({ options: OPTIONS }).check(workspaceContext);
|
|
120
|
+
|
|
121
|
+
const none = checkAndSpy("./packages/none");
|
|
122
|
+
expect(none.addErrorSpy).toHaveBeenCalledTimes(2);
|
|
123
|
+
|
|
124
|
+
const missing = checkAndSpy("./packages/missing");
|
|
125
|
+
expect(missing.addErrorSpy).toHaveBeenCalledTimes(2);
|
|
126
|
+
|
|
127
|
+
const wrong = checkAndSpy("./packages/wrong");
|
|
128
|
+
expect(wrong.addErrorSpy).toHaveBeenCalledTimes(2);
|
|
129
|
+
|
|
130
|
+
const right = checkAndSpy("./packages/right");
|
|
131
|
+
expect(right.addErrorSpy).toHaveBeenCalledTimes(0);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("fixes correctly", () => {
|
|
135
|
+
const { addFile, readFile, checkAndSpy } = makeWorkspace({ fix: true });
|
|
136
|
+
addFile("./package.json", PACKAGE_ROOT);
|
|
137
|
+
addFile("./packages/missing/package.json", PACKAGE_WITH_ENTRIES_MISSING);
|
|
138
|
+
addFile("./packages/wrong/package.json", PACKAGE_WITH_WRONG_ENTRIES);
|
|
139
|
+
|
|
140
|
+
const missing = checkAndSpy("./packages/missing");
|
|
141
|
+
expect(missing.addErrorSpy).toHaveBeenCalledTimes(2);
|
|
142
|
+
|
|
143
|
+
const wrong = checkAndSpy("./packages/wrong");
|
|
144
|
+
expect(wrong.addErrorSpy).toHaveBeenCalledTimes(2);
|
|
145
|
+
|
|
146
|
+
const missingContents = readFile("./packages/missing/package.json");
|
|
147
|
+
expect(missingContents).toEqual(CORRECT_OUTPUT);
|
|
148
|
+
|
|
149
|
+
const contents = readFile("./packages/wrong/package.json");
|
|
150
|
+
expect(contents).toEqual(CORRECT_OUTPUT);
|
|
151
|
+
});
|
|
152
|
+
});
|
package/src/__tests__/utils.ts
CHANGED
|
@@ -5,19 +5,123 @@
|
|
|
5
5
|
*
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
import { AddErrorOptions, WorkspaceContext } from "@monorepolint/config";
|
|
9
|
+
import { WorkspaceContextImpl } from "@monorepolint/core";
|
|
10
|
+
import { CachingHost, Host, SimpleHost } from "@monorepolint/utils";
|
|
11
|
+
import { expect, jest } from "@jest/globals";
|
|
12
|
+
import * as path from "node:path";
|
|
13
|
+
import * as tmp from "tmp";
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
export function jsonToString(obj: unknown) {
|
|
16
|
+
return JSON.stringify(obj, undefined, 2) + "\n";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface TestingWorkspaceOpts {
|
|
20
|
+
host: Host;
|
|
21
|
+
rootProjectName?: string;
|
|
22
|
+
fixFlag: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function createTestingWorkspace(inboundOpts: TestingWorkspaceOpts) {
|
|
26
|
+
tmp.setGracefulCleanup();
|
|
27
|
+
const tmpdir = tmp.dirSync();
|
|
28
|
+
const opts = {
|
|
29
|
+
...inboundOpts,
|
|
30
|
+
rootProjectName: inboundOpts.rootProjectName ?? "rootProject",
|
|
31
|
+
};
|
|
32
|
+
const rootPath = tmpdir.name;
|
|
33
|
+
opts.host.mkdir(rootPath, { recursive: true });
|
|
15
34
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
35
|
+
opts.host.writeJson(path.join(rootPath, "package.json"), {
|
|
36
|
+
name: opts.rootProjectName,
|
|
37
|
+
workspaces: {
|
|
38
|
+
packages: ["packages/*"],
|
|
19
39
|
},
|
|
20
|
-
})
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
await opts.host.flush();
|
|
21
43
|
|
|
22
|
-
return
|
|
44
|
+
return new DefaultTestingWorkspace(
|
|
45
|
+
{ ...opts, rootPath },
|
|
46
|
+
new WorkspaceContextImpl(rootPath, { fix: opts.fixFlag, rules: [] }, opts.host)
|
|
47
|
+
);
|
|
23
48
|
}
|
|
49
|
+
|
|
50
|
+
interface RealTestingWorkspaceOpts extends Required<TestingWorkspaceOpts> {
|
|
51
|
+
rootPath: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface TestingWorkspace {
|
|
55
|
+
/**
|
|
56
|
+
* Adds a utf8 file to `packageName` with `relativePath` to the package directory.
|
|
57
|
+
*
|
|
58
|
+
* @param packageName The child package to add to or undefined for root package
|
|
59
|
+
* @param filePath The path of the file to be written. Will be prepended with package dir
|
|
60
|
+
* @param contents the contents to be written (as utf8)
|
|
61
|
+
*/
|
|
62
|
+
writeFile(filePath: string, contents: string): void;
|
|
63
|
+
|
|
64
|
+
writeJsonFile(filePath: string, json: object): void;
|
|
65
|
+
addProject(name: string, fields: object): void;
|
|
66
|
+
getFilePath(filePath: string): string;
|
|
67
|
+
readFile(filePath: string): string;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Helper method for matching failures via jest `expect().toMatchObject
|
|
71
|
+
*
|
|
72
|
+
*/
|
|
73
|
+
failureMatcher(opts: { file: string; message: string; hasFixer: boolean }): any;
|
|
74
|
+
|
|
75
|
+
readonly context: WorkspaceContext;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
class DefaultTestingWorkspace implements TestingWorkspace {
|
|
79
|
+
constructor(private opts: RealTestingWorkspaceOpts, public readonly context: WorkspaceContext) {}
|
|
80
|
+
|
|
81
|
+
addProject(name: string, fields: object) {
|
|
82
|
+
this.writeJsonFile(path.join("packages", name, "package.json"), {
|
|
83
|
+
name,
|
|
84
|
+
...fields,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
writeJsonFile(filePath: string, json: object) {
|
|
89
|
+
this.writeFile(filePath, JSON.stringify(json, undefined, 2));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Adds a utf8 file to `packageName` with `relativePath` to the package directory.
|
|
94
|
+
*
|
|
95
|
+
* @param packageName The child package to add to or undefined for root package
|
|
96
|
+
* @param filePath The path of the file to be written. Will be prepended with package dir
|
|
97
|
+
* @param contents the contents to be written (as utf8)
|
|
98
|
+
*/
|
|
99
|
+
writeFile(filePath: string, contents: string) {
|
|
100
|
+
const fullFilePath = this.getFilePath(filePath);
|
|
101
|
+
this.opts.host.mkdir(path.dirname(fullFilePath), { recursive: true });
|
|
102
|
+
this.opts.host.writeFile(fullFilePath, contents, { encoding: "utf-8" });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
getFilePath(filePath: string) {
|
|
106
|
+
return path.join(this.opts.rootPath, filePath);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
readFile(filePath: string) {
|
|
110
|
+
return this.opts.host.readFile(this.getFilePath(filePath), { encoding: "utf-8" });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
failureMatcher(opts: { file: string; message: string; hasFixer: boolean }) {
|
|
114
|
+
return {
|
|
115
|
+
file: this.getFilePath(opts.file),
|
|
116
|
+
message: opts.message,
|
|
117
|
+
...(opts.hasFixer ? { fixer: expect.any(Function) } : {}),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export type AddErrorSpy = jest.SpiedFunction<(options: AddErrorOptions) => void>;
|
|
123
|
+
|
|
124
|
+
export const HOST_FACTORIES: Array<{ name: string; make: () => Host }> = [
|
|
125
|
+
{ name: "SimpleHost", make: () => new SimpleHost() },
|
|
126
|
+
{ name: "CachingHost", make: () => new CachingHost() },
|
|
127
|
+
];
|
|
@@ -5,61 +5,17 @@
|
|
|
5
5
|
*
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { Context, RuleModule } from "@monorepolint/core";
|
|
9
|
-
import { writeJson } from "@monorepolint/utils";
|
|
10
|
-
import diff from "jest-diff";
|
|
11
8
|
import * as r from "runtypes";
|
|
12
|
-
|
|
9
|
+
import { checkAlpha } from "./util/checkAlpha.js";
|
|
10
|
+
import { makeRule } from "./util/makeRule.js";
|
|
13
11
|
const Options = r.Undefined;
|
|
14
12
|
|
|
15
|
-
export const alphabeticalDependencies = {
|
|
16
|
-
|
|
13
|
+
export const alphabeticalDependencies = makeRule({
|
|
14
|
+
name: "alphabeticalDependencies",
|
|
15
|
+
check: (context) => {
|
|
17
16
|
checkAlpha(context, "dependencies");
|
|
18
17
|
checkAlpha(context, "devDependencies");
|
|
19
18
|
checkAlpha(context, "peerDependencies");
|
|
20
19
|
},
|
|
21
20
|
optionsRuntype: Options,
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function checkAlpha(context: Context, block: "dependencies" | "devDependencies" | "peerDependencies") {
|
|
25
|
-
const packageJson = context.getPackageJson();
|
|
26
|
-
const packagePath = context.getPackageJsonPath();
|
|
27
|
-
|
|
28
|
-
const dependencies = packageJson[block];
|
|
29
|
-
|
|
30
|
-
if (dependencies === undefined) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const actualOrder = Object.keys(dependencies);
|
|
35
|
-
const expectedOrder = actualOrder.slice().sort(); // sort mutates, so we need to copy the previous result
|
|
36
|
-
|
|
37
|
-
if (!arrayOrderCompare(actualOrder, expectedOrder)) {
|
|
38
|
-
context.addError({
|
|
39
|
-
file: packagePath,
|
|
40
|
-
message: `Incorrect order of ${block} in package.json`,
|
|
41
|
-
longMessage: diff(expectedOrder, actualOrder, { expand: true }),
|
|
42
|
-
fixer: () => {
|
|
43
|
-
const expectedDependencies: Record<string, string> = {};
|
|
44
|
-
|
|
45
|
-
expectedOrder.forEach(dep => {
|
|
46
|
-
expectedDependencies[dep] = dependencies[dep];
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
const newPackageJson = { ...packageJson };
|
|
50
|
-
newPackageJson[block] = expectedDependencies;
|
|
51
|
-
writeJson(packagePath, newPackageJson);
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function arrayOrderCompare(a: ReadonlyArray<string>, b: ReadonlyArray<string>) {
|
|
58
|
-
for (let index = 0; index < a.length; index++) {
|
|
59
|
-
if (a[index] !== b[index]) {
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
21
|
+
});
|