@monorepolint/rules 0.6.0-alpha.2 → 0.6.0-alpha.4
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 +161 -102
- package/.turbo/turbo-transpile-typescript.log +4 -4
- package/CHANGELOG.md +19 -0
- package/build/js/index.js +429 -241
- package/build/js/index.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/__tests__/utils.d.ts +0 -1
- package/build/types/__tests__/utils.d.ts.map +1 -1
- package/build/types/bannedDependencies.d.ts.map +1 -1
- package/build/types/fileContents.d.ts.map +1 -1
- package/build/types/forceError.d.ts +4 -0
- package/build/types/forceError.d.ts.map +1 -0
- package/build/types/index.d.ts +5 -3
- package/build/types/index.d.ts.map +1 -1
- package/build/types/mustSatisfyPeerDependencies.d.ts.map +1 -1
- package/build/types/nestedWorkspaces.d.ts.map +1 -1
- package/build/types/oncePerPackage.d.ts +11 -0
- package/build/types/oncePerPackage.d.ts.map +1 -0
- package/build/types/packageEntry.d.ts.map +1 -1
- package/build/types/packageOrder.d.ts.map +1 -1
- package/build/types/packageScript.d.ts.map +1 -1
- package/build/types/requireDependency.d.ts +12 -12
- package/build/types/requireDependency.d.ts.map +1 -1
- package/build/types/util/checkAlpha.d.ts.map +1 -1
- package/build/types/util/createRuleFactory.d.ts.map +1 -1
- package/build/types/util/packageDependencyGraphService.d.ts.map +1 -1
- package/coverage/clover.xml +1201 -813
- package/coverage/coverage-final.json +20 -18
- package/coverage/index.html +20 -20
- package/coverage/src/alphabeticalDependencies.ts.html +11 -11
- package/coverage/src/alphabeticalScripts.ts.html +5 -5
- package/coverage/src/bannedDependencies.ts.html +76 -28
- package/coverage/src/consistentDependencies.ts.html +51 -18
- package/coverage/src/consistentVersions.ts.html +144 -48
- package/coverage/src/fileContents.ts.html +47 -23
- package/coverage/src/forceError.ts.html +184 -0
- package/coverage/src/index.html +96 -66
- package/coverage/src/index.ts.html +39 -33
- package/coverage/src/mustSatisfyPeerDependencies.ts.html +323 -80
- package/coverage/src/nestedWorkspaces.ts.html +47 -20
- package/coverage/src/oncePerPackage.ts.html +181 -0
- package/coverage/src/packageEntry.ts.html +40 -19
- package/coverage/src/packageOrder.ts.html +30 -12
- package/coverage/src/packageScript.ts.html +81 -27
- package/coverage/src/requireDependency.ts.html +77 -32
- package/coverage/src/standardTsconfig.ts.html +84 -21
- package/coverage/src/util/checkAlpha.ts.html +18 -9
- package/coverage/src/util/createRuleFactory.ts.html +16 -4
- package/coverage/src/util/index.html +17 -17
- package/coverage/src/util/makeDirectory.ts.html +5 -5
- package/coverage/src/util/packageDependencyGraphService.ts.html +94 -19
- package/package.json +4 -5
- package/src/__tests__/alphabeticalScripts.spec.ts +12 -4
- package/src/__tests__/bannedDependencies.spec.ts +45 -16
- package/src/__tests__/consistentDependencies.spec.ts +11 -5
- package/src/__tests__/consistentVersions.spec.ts +72 -18
- package/src/__tests__/fileContents.spec.ts +5 -5
- package/src/__tests__/mustSatisfyPeerDependencies.spec.ts +191 -76
- package/src/__tests__/nestedWorkspaces.spec.ts +10 -7
- package/src/__tests__/packageEntry.spec.ts +48 -47
- package/src/__tests__/packageOrder.spec.ts +72 -71
- package/src/__tests__/packageScript.spec.ts +19 -10
- package/src/__tests__/requireDependency.spec.ts +12 -6
- package/src/__tests__/utils.ts +16 -7
- package/src/bannedDependencies.ts +32 -16
- package/src/consistentDependencies.ts +19 -8
- package/src/consistentVersions.ts +70 -38
- package/src/fileContents.ts +19 -11
- package/src/forceError.ts +33 -0
- package/src/index.ts +5 -3
- package/src/mustSatisfyPeerDependencies.ts +141 -60
- package/src/nestedWorkspaces.ts +19 -10
- package/src/oncePerPackage.ts +32 -0
- package/src/packageEntry.ts +18 -11
- package/src/packageOrder.ts +9 -3
- package/src/packageScript.ts +37 -19
- package/src/requireDependency.ts +26 -11
- package/src/standardTsconfig.ts +31 -10
- package/src/util/checkAlpha.ts +5 -2
- package/src/util/createRuleFactory.ts +6 -2
- package/src/util/packageDependencyGraphService.ts +38 -13
- package/vitest.config.mjs +6 -7
|
@@ -8,50 +8,51 @@
|
|
|
8
8
|
// tslint:disable:no-console
|
|
9
9
|
|
|
10
10
|
import { Context, Failure } from "@monorepolint/config";
|
|
11
|
-
import {
|
|
11
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
12
|
+
import {
|
|
13
|
+
createExpectedEntryErrorMessage,
|
|
14
|
+
createStandardizedEntryErrorMessage,
|
|
15
|
+
packageEntry,
|
|
16
|
+
} from "../packageEntry.js";
|
|
12
17
|
import { AddErrorSpy, createTestingWorkspace, HOST_FACTORIES, TestingWorkspace } from "./utils.js";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
{
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
{
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
dependencies: {},
|
|
47
|
-
repository: {
|
|
48
|
-
type: "git",
|
|
49
|
-
url: "https://github.com:foo/foo",
|
|
50
|
-
},
|
|
18
|
+
|
|
19
|
+
const PACKAGE_MISSING_ENTRY = JSON.stringify(
|
|
20
|
+
{
|
|
21
|
+
name: "package",
|
|
22
|
+
version: {},
|
|
23
|
+
scripts: {},
|
|
24
|
+
dependencies: {},
|
|
25
|
+
},
|
|
26
|
+
undefined,
|
|
27
|
+
2,
|
|
28
|
+
) + "\n";
|
|
29
|
+
|
|
30
|
+
const PACKAGE_LICENSE = JSON.stringify(
|
|
31
|
+
{
|
|
32
|
+
name: "package",
|
|
33
|
+
version: {},
|
|
34
|
+
scripts: {},
|
|
35
|
+
dependencies: {},
|
|
36
|
+
license: "UNLICENSED",
|
|
37
|
+
},
|
|
38
|
+
undefined,
|
|
39
|
+
2,
|
|
40
|
+
) + "\n";
|
|
41
|
+
|
|
42
|
+
const PACKAGE_REPOSITORY = JSON.stringify(
|
|
43
|
+
{
|
|
44
|
+
name: "package",
|
|
45
|
+
version: {},
|
|
46
|
+
scripts: {},
|
|
47
|
+
dependencies: {},
|
|
48
|
+
repository: {
|
|
49
|
+
type: "git",
|
|
50
|
+
url: "https://github.com:foo/foo",
|
|
51
51
|
},
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
},
|
|
53
|
+
undefined,
|
|
54
|
+
2,
|
|
55
|
+
) + "\n";
|
|
55
56
|
|
|
56
57
|
describe.each(HOST_FACTORIES)("expectPackageEntries ($name)", (hostFactory) => {
|
|
57
58
|
describe("fix: true", () => {
|
|
@@ -93,7 +94,7 @@ describe.each(HOST_FACTORIES)("expectPackageEntries ($name)", (hostFactory) => {
|
|
|
93
94
|
file: "package.json",
|
|
94
95
|
hasFixer: true,
|
|
95
96
|
message: createStandardizedEntryErrorMessage("license"),
|
|
96
|
-
})
|
|
97
|
+
}),
|
|
97
98
|
);
|
|
98
99
|
|
|
99
100
|
expect(workspace.readFile("package.json")).toEqual(PACKAGE_LICENSE);
|
|
@@ -122,7 +123,7 @@ describe.each(HOST_FACTORIES)("expectPackageEntries ($name)", (hostFactory) => {
|
|
|
122
123
|
file: "package.json",
|
|
123
124
|
hasFixer: true,
|
|
124
125
|
message: createStandardizedEntryErrorMessage("repository"),
|
|
125
|
-
})
|
|
126
|
+
}),
|
|
126
127
|
);
|
|
127
128
|
|
|
128
129
|
expect(workspace.readFile("package.json")).toEqual(PACKAGE_REPOSITORY);
|
|
@@ -165,7 +166,7 @@ describe.each(HOST_FACTORIES)("expectPackageEntries ($name)", (hostFactory) => {
|
|
|
165
166
|
file: "package.json",
|
|
166
167
|
hasFixer: false,
|
|
167
168
|
message: createExpectedEntryErrorMessage("bugs"),
|
|
168
|
-
})
|
|
169
|
+
}),
|
|
169
170
|
);
|
|
170
171
|
expect(workspace.readFile("package.json")).toEqual(PACKAGE_REPOSITORY);
|
|
171
172
|
});
|
|
@@ -193,7 +194,7 @@ describe.each(HOST_FACTORIES)("expectPackageEntries ($name)", (hostFactory) => {
|
|
|
193
194
|
file: "package.json",
|
|
194
195
|
hasFixer: true,
|
|
195
196
|
message: createStandardizedEntryErrorMessage("repository"),
|
|
196
|
-
})
|
|
197
|
+
}),
|
|
197
198
|
);
|
|
198
199
|
|
|
199
200
|
const failure2: Failure = spy.mock.calls[1][0];
|
|
@@ -202,7 +203,7 @@ describe.each(HOST_FACTORIES)("expectPackageEntries ($name)", (hostFactory) => {
|
|
|
202
203
|
file: "package.json",
|
|
203
204
|
hasFixer: false,
|
|
204
205
|
message: createExpectedEntryErrorMessage("bugs"),
|
|
205
|
-
})
|
|
206
|
+
}),
|
|
206
207
|
);
|
|
207
208
|
|
|
208
209
|
expect(workspace.readFile("package.json")).toEqual(PACKAGE_REPOSITORY);
|
|
@@ -6,36 +6,34 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
// tslint:disable:no-console
|
|
9
|
-
import { AddErrorSpy, createTestingWorkspace, HOST_FACTORIES, TestingWorkspace } from "./utils.js";
|
|
10
9
|
import { Context, Failure } from "@monorepolint/config";
|
|
10
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
11
11
|
import { packageOrder } from "../packageOrder.js";
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
const PACKAGE_UNORDERED =
|
|
15
|
-
|
|
16
|
-
{
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
2
|
|
38
|
-
) + "\n";
|
|
12
|
+
import { AddErrorSpy, createTestingWorkspace, HOST_FACTORIES, TestingWorkspace } from "./utils.js";
|
|
13
|
+
|
|
14
|
+
const PACKAGE_UNORDERED = JSON.stringify(
|
|
15
|
+
{
|
|
16
|
+
scripts: {},
|
|
17
|
+
dependencies: {},
|
|
18
|
+
version: {},
|
|
19
|
+
name: "package",
|
|
20
|
+
},
|
|
21
|
+
undefined,
|
|
22
|
+
2,
|
|
23
|
+
) + "\n";
|
|
24
|
+
|
|
25
|
+
const PACKAGE_UNORDERED_UNKOWN_KEYS = JSON.stringify(
|
|
26
|
+
{
|
|
27
|
+
butter: false,
|
|
28
|
+
apple: false,
|
|
29
|
+
scripts: {},
|
|
30
|
+
dependencies: {},
|
|
31
|
+
version: {},
|
|
32
|
+
name: "package-unknown-keys",
|
|
33
|
+
},
|
|
34
|
+
undefined,
|
|
35
|
+
2,
|
|
36
|
+
) + "\n";
|
|
39
37
|
|
|
40
38
|
const orderArray = ["name", "version", "scripts", "dependencies"];
|
|
41
39
|
|
|
@@ -44,43 +42,40 @@ const orderFunction = (_context: Context) => (a: string, b: string) => {
|
|
|
44
42
|
return b.length - a.length || a.localeCompare(b);
|
|
45
43
|
};
|
|
46
44
|
|
|
47
|
-
const PACKAGE_ORDERED =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
{
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
undefined,
|
|
82
|
-
2
|
|
83
|
-
) + "\n";
|
|
45
|
+
const PACKAGE_ORDERED = JSON.stringify(
|
|
46
|
+
{
|
|
47
|
+
name: "package",
|
|
48
|
+
version: {},
|
|
49
|
+
scripts: {},
|
|
50
|
+
dependencies: {},
|
|
51
|
+
},
|
|
52
|
+
undefined,
|
|
53
|
+
2,
|
|
54
|
+
) + "\n";
|
|
55
|
+
|
|
56
|
+
const PACKAGE_ORDERED_BY_LENGTH = JSON.stringify(
|
|
57
|
+
{
|
|
58
|
+
dependencies: {},
|
|
59
|
+
scripts: {},
|
|
60
|
+
version: {},
|
|
61
|
+
name: "package",
|
|
62
|
+
},
|
|
63
|
+
undefined,
|
|
64
|
+
2,
|
|
65
|
+
) + "\n";
|
|
66
|
+
|
|
67
|
+
const PACKAGE_ORDERED_UNKOWN_KEYS = JSON.stringify(
|
|
68
|
+
{
|
|
69
|
+
name: "package-unknown-keys",
|
|
70
|
+
version: {},
|
|
71
|
+
scripts: {},
|
|
72
|
+
dependencies: {},
|
|
73
|
+
apple: false,
|
|
74
|
+
butter: false,
|
|
75
|
+
},
|
|
76
|
+
undefined,
|
|
77
|
+
2,
|
|
78
|
+
) + "\n";
|
|
84
79
|
|
|
85
80
|
describe.each(HOST_FACTORIES)("expectPackageOrder ($name)", (hostFactory) => {
|
|
86
81
|
describe("fix: true", () => {
|
|
@@ -115,7 +110,7 @@ describe.each(HOST_FACTORIES)("expectPackageOrder ($name)", (hostFactory) => {
|
|
|
115
110
|
file: "package.json",
|
|
116
111
|
hasFixer: true,
|
|
117
112
|
message: "Incorrect order of fields in package.json",
|
|
118
|
-
})
|
|
113
|
+
}),
|
|
119
114
|
);
|
|
120
115
|
|
|
121
116
|
expect(workspace.readFile("package.json")).toEqual(PACKAGE_ORDERED);
|
|
@@ -138,10 +133,12 @@ describe.each(HOST_FACTORIES)("expectPackageOrder ($name)", (hostFactory) => {
|
|
|
138
133
|
file: "package.json",
|
|
139
134
|
hasFixer: true,
|
|
140
135
|
message: "Incorrect order of fields in package.json",
|
|
141
|
-
})
|
|
136
|
+
}),
|
|
142
137
|
);
|
|
143
138
|
|
|
144
|
-
expect(workspace.readFile("package.json")).toEqual(
|
|
139
|
+
expect(workspace.readFile("package.json")).toEqual(
|
|
140
|
+
PACKAGE_ORDERED_UNKOWN_KEYS,
|
|
141
|
+
);
|
|
145
142
|
});
|
|
146
143
|
|
|
147
144
|
it("fixes order using function", () => {
|
|
@@ -161,10 +158,12 @@ describe.each(HOST_FACTORIES)("expectPackageOrder ($name)", (hostFactory) => {
|
|
|
161
158
|
file: "package.json",
|
|
162
159
|
hasFixer: true,
|
|
163
160
|
message: "Incorrect order of fields in package.json",
|
|
164
|
-
})
|
|
161
|
+
}),
|
|
165
162
|
);
|
|
166
163
|
|
|
167
|
-
expect(workspace.readFile("package.json")).toEqual(
|
|
164
|
+
expect(workspace.readFile("package.json")).toEqual(
|
|
165
|
+
PACKAGE_ORDERED_BY_LENGTH,
|
|
166
|
+
);
|
|
168
167
|
});
|
|
169
168
|
|
|
170
169
|
it("does nothing if already order", () => {
|
|
@@ -178,7 +177,9 @@ describe.each(HOST_FACTORIES)("expectPackageOrder ($name)", (hostFactory) => {
|
|
|
178
177
|
|
|
179
178
|
expect(spy).not.toHaveBeenCalled();
|
|
180
179
|
|
|
181
|
-
expect(workspace.readFile("package.json")).toEqual(
|
|
180
|
+
expect(workspace.readFile("package.json")).toEqual(
|
|
181
|
+
PACKAGE_ORDERED_UNKOWN_KEYS,
|
|
182
|
+
);
|
|
182
183
|
});
|
|
183
184
|
});
|
|
184
185
|
});
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
// tslint:disable:no-console
|
|
9
|
-
import { describe, expect, it, beforeEach, vi } from "vitest";
|
|
10
9
|
import { Context, Failure } from "@monorepolint/config";
|
|
10
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
11
11
|
import { packageScript } from "../packageScript.js";
|
|
12
12
|
import { AddErrorSpy, createTestingWorkspace, HOST_FACTORIES, TestingWorkspace } from "./utils.js";
|
|
13
13
|
|
|
@@ -63,7 +63,7 @@ describe.each(HOST_FACTORIES)("expectPackageScript ($name)", (hostFactory) => {
|
|
|
63
63
|
file: "package.json",
|
|
64
64
|
hasFixer: true,
|
|
65
65
|
message: "No scripts block in package.json",
|
|
66
|
-
})
|
|
66
|
+
}),
|
|
67
67
|
);
|
|
68
68
|
});
|
|
69
69
|
});
|
|
@@ -102,10 +102,12 @@ describe.each(HOST_FACTORIES)("expectPackageScript ($name)", (hostFactory) => {
|
|
|
102
102
|
file: "package.json",
|
|
103
103
|
hasFixer: true,
|
|
104
104
|
message: "No scripts block in package.json",
|
|
105
|
-
})
|
|
105
|
+
}),
|
|
106
106
|
);
|
|
107
107
|
|
|
108
|
-
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual(
|
|
108
|
+
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual(
|
|
109
|
+
{},
|
|
110
|
+
);
|
|
109
111
|
});
|
|
110
112
|
|
|
111
113
|
it("adds a script", () => {
|
|
@@ -127,13 +129,16 @@ describe.each(HOST_FACTORIES)("expectPackageScript ($name)", (hostFactory) => {
|
|
|
127
129
|
file: "package.json",
|
|
128
130
|
hasFixer: true,
|
|
129
131
|
message: expect.stringContaining(
|
|
130
|
-
`Expected standardized script entry for '${MISSING_SCRIPT_NAME}'
|
|
132
|
+
`Expected standardized script entry for '${MISSING_SCRIPT_NAME}'`,
|
|
131
133
|
) as unknown as string,
|
|
132
|
-
})
|
|
134
|
+
}),
|
|
133
135
|
);
|
|
134
136
|
|
|
135
|
-
expect(
|
|
136
|
-
|
|
137
|
+
expect(
|
|
138
|
+
JSON.parse(workspace.readFile("package.json")!)
|
|
139
|
+
.scripts[MISSING_SCRIPT_NAME],
|
|
140
|
+
).toEqual(
|
|
141
|
+
MISSING_SCRIPT_VALUE,
|
|
137
142
|
);
|
|
138
143
|
});
|
|
139
144
|
|
|
@@ -218,7 +223,9 @@ describe.each(HOST_FACTORIES)("expectPackageScript ($name)", (hostFactory) => {
|
|
|
218
223
|
expect(errors.length).toBe(1);
|
|
219
224
|
expect(errors[0][0].fixer).toBeDefined();
|
|
220
225
|
|
|
221
|
-
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual(
|
|
226
|
+
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual(
|
|
227
|
+
{},
|
|
228
|
+
);
|
|
222
229
|
});
|
|
223
230
|
|
|
224
231
|
it("can allow only empty", () => {
|
|
@@ -240,7 +247,9 @@ describe.each(HOST_FACTORIES)("expectPackageScript ($name)", (hostFactory) => {
|
|
|
240
247
|
expect(errors.length).toBe(1);
|
|
241
248
|
expect(errors[0][0].fixer).toBeDefined();
|
|
242
249
|
|
|
243
|
-
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual(
|
|
250
|
+
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual(
|
|
251
|
+
{},
|
|
252
|
+
);
|
|
244
253
|
});
|
|
245
254
|
});
|
|
246
255
|
});
|
|
@@ -9,10 +9,10 @@ import { SimpleHost } from "@monorepolint/utils";
|
|
|
9
9
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
10
10
|
import * as path from "node:path";
|
|
11
11
|
import * as tmp from "tmp";
|
|
12
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
12
13
|
import { requireDependency } from "../requireDependency.js";
|
|
13
14
|
import { makeDirectoryRecursively } from "../util/makeDirectory.js";
|
|
14
15
|
import { jsonToString } from "./utils.js";
|
|
15
|
-
import { describe, expect, it, afterEach, vi } from "vitest";
|
|
16
16
|
|
|
17
17
|
const PACKAGE_ROOT = jsonToString({
|
|
18
18
|
workspaces: {
|
|
@@ -36,6 +36,7 @@ const PACKAGE_WITH_WRONG_ENTRIES = jsonToString({
|
|
|
36
36
|
},
|
|
37
37
|
devDependencies: {
|
|
38
38
|
bar: "1.0.0",
|
|
39
|
+
baz: "1.0.0",
|
|
39
40
|
},
|
|
40
41
|
});
|
|
41
42
|
|
|
@@ -54,6 +55,7 @@ const OPTIONS = {
|
|
|
54
55
|
},
|
|
55
56
|
devDependencies: {
|
|
56
57
|
bar: "^2.0.0",
|
|
58
|
+
baz: undefined,
|
|
57
59
|
},
|
|
58
60
|
} as const;
|
|
59
61
|
|
|
@@ -83,11 +85,13 @@ describe("requireDependency", () => {
|
|
|
83
85
|
verbose: false,
|
|
84
86
|
silent: true,
|
|
85
87
|
},
|
|
86
|
-
new SimpleHost()
|
|
88
|
+
new SimpleHost(),
|
|
87
89
|
);
|
|
88
90
|
|
|
89
91
|
function checkAndSpy(q: string) {
|
|
90
|
-
const context = workspaceContext.createChildContext(
|
|
92
|
+
const context = workspaceContext.createChildContext(
|
|
93
|
+
path.resolve(dir.name, q),
|
|
94
|
+
);
|
|
91
95
|
const addErrorSpy = vi.spyOn(context, "addError");
|
|
92
96
|
requireDependency({ options: OPTIONS }).check(context);
|
|
93
97
|
return { context, addErrorSpy };
|
|
@@ -109,7 +113,9 @@ describe("requireDependency", () => {
|
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
it("checks correctly", () => {
|
|
112
|
-
const { addFile, workspaceContext, checkAndSpy } = makeWorkspace({
|
|
116
|
+
const { addFile, workspaceContext, checkAndSpy } = makeWorkspace({
|
|
117
|
+
fix: false,
|
|
118
|
+
});
|
|
113
119
|
addFile("./package.json", PACKAGE_ROOT);
|
|
114
120
|
addFile("./packages/none/package.json", PACKAGE_WITH_NO_ENTRIES);
|
|
115
121
|
addFile("./packages/missing/package.json", PACKAGE_WITH_ENTRIES_MISSING);
|
|
@@ -125,7 +131,7 @@ describe("requireDependency", () => {
|
|
|
125
131
|
expect(missing.addErrorSpy).toHaveBeenCalledTimes(2);
|
|
126
132
|
|
|
127
133
|
const wrong = checkAndSpy("./packages/wrong");
|
|
128
|
-
expect(wrong.addErrorSpy).toHaveBeenCalledTimes(
|
|
134
|
+
expect(wrong.addErrorSpy).toHaveBeenCalledTimes(3);
|
|
129
135
|
|
|
130
136
|
const right = checkAndSpy("./packages/right");
|
|
131
137
|
expect(right.addErrorSpy).toHaveBeenCalledTimes(0);
|
|
@@ -141,7 +147,7 @@ describe("requireDependency", () => {
|
|
|
141
147
|
expect(missing.addErrorSpy).toHaveBeenCalledTimes(2);
|
|
142
148
|
|
|
143
149
|
const wrong = checkAndSpy("./packages/wrong");
|
|
144
|
-
expect(wrong.addErrorSpy).toHaveBeenCalledTimes(
|
|
150
|
+
expect(wrong.addErrorSpy).toHaveBeenCalledTimes(3);
|
|
145
151
|
|
|
146
152
|
const missingContents = readFile("./packages/missing/package.json");
|
|
147
153
|
expect(missingContents).toEqual(CORRECT_OUTPUT);
|
package/src/__tests__/utils.ts
CHANGED
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
import { AddErrorOptions, WorkspaceContext } from "@monorepolint/config";
|
|
9
9
|
import { WorkspaceContextImpl } from "@monorepolint/core";
|
|
10
10
|
import { CachingHost, Host, SimpleHost } from "@monorepolint/utils";
|
|
11
|
-
import { expect, MockInstance } from "vitest";
|
|
12
11
|
import * as path from "node:path";
|
|
13
12
|
import * as tmp from "tmp";
|
|
13
|
+
import { expect, MockInstance } from "vitest";
|
|
14
14
|
|
|
15
15
|
export function jsonToString(obj: unknown) {
|
|
16
16
|
return JSON.stringify(obj, undefined, 2) + "\n";
|
|
@@ -22,7 +22,9 @@ interface TestingWorkspaceOpts {
|
|
|
22
22
|
fixFlag: boolean;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export async function createTestingWorkspace(
|
|
25
|
+
export async function createTestingWorkspace(
|
|
26
|
+
inboundOpts: TestingWorkspaceOpts,
|
|
27
|
+
) {
|
|
26
28
|
tmp.setGracefulCleanup();
|
|
27
29
|
const tmpdir = tmp.dirSync();
|
|
28
30
|
const opts = {
|
|
@@ -43,7 +45,11 @@ export async function createTestingWorkspace(inboundOpts: TestingWorkspaceOpts)
|
|
|
43
45
|
|
|
44
46
|
return new DefaultTestingWorkspace(
|
|
45
47
|
{ ...opts, rootPath },
|
|
46
|
-
new WorkspaceContextImpl(
|
|
48
|
+
new WorkspaceContextImpl(
|
|
49
|
+
rootPath,
|
|
50
|
+
{ fix: opts.fixFlag, rules: [] },
|
|
51
|
+
opts.host,
|
|
52
|
+
),
|
|
47
53
|
);
|
|
48
54
|
}
|
|
49
55
|
|
|
@@ -68,9 +74,10 @@ export interface TestingWorkspace {
|
|
|
68
74
|
|
|
69
75
|
/**
|
|
70
76
|
* Helper method for matching failures via vi `expect().toMatchObject
|
|
71
|
-
*
|
|
72
77
|
*/
|
|
73
|
-
failureMatcher(
|
|
78
|
+
failureMatcher(
|
|
79
|
+
opts: { file: string; message: string; hasFixer: boolean },
|
|
80
|
+
): any;
|
|
74
81
|
|
|
75
82
|
readonly context: WorkspaceContext;
|
|
76
83
|
}
|
|
@@ -78,7 +85,7 @@ export interface TestingWorkspace {
|
|
|
78
85
|
class DefaultTestingWorkspace implements TestingWorkspace {
|
|
79
86
|
constructor(
|
|
80
87
|
private opts: RealTestingWorkspaceOpts,
|
|
81
|
-
public readonly context: WorkspaceContext
|
|
88
|
+
public readonly context: WorkspaceContext,
|
|
82
89
|
) {}
|
|
83
90
|
|
|
84
91
|
addProject(name: string, fields: object) {
|
|
@@ -110,7 +117,9 @@ class DefaultTestingWorkspace implements TestingWorkspace {
|
|
|
110
117
|
}
|
|
111
118
|
|
|
112
119
|
readFile(filePath: string) {
|
|
113
|
-
return this.opts.host.readFile(this.getFilePath(filePath), {
|
|
120
|
+
return this.opts.host.readFile(this.getFilePath(filePath), {
|
|
121
|
+
encoding: "utf-8",
|
|
122
|
+
});
|
|
114
123
|
}
|
|
115
124
|
|
|
116
125
|
failureMatcher(opts: { file: string; message: string; hasFixer: boolean }) {
|
|
@@ -11,7 +11,10 @@ import { AggregateTiming } from "@monorepolint/utils";
|
|
|
11
11
|
import * as path from "node:path";
|
|
12
12
|
import * as r from "runtypes";
|
|
13
13
|
import { createRuleFactory } from "./util/createRuleFactory.js";
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
IPackageDependencyGraphNode,
|
|
16
|
+
PackageDependencyGraphService,
|
|
17
|
+
} from "./util/packageDependencyGraphService.js";
|
|
15
18
|
// FIXME: This rule is messed. bannedTransitiveDependencies doesnt glob
|
|
16
19
|
|
|
17
20
|
const bannedDepGlobsField = r.Union(
|
|
@@ -19,7 +22,7 @@ const bannedDepGlobsField = r.Union(
|
|
|
19
22
|
r.Record({
|
|
20
23
|
glob: r.Array(r.String).optional(),
|
|
21
24
|
exact: r.Array(r.String).optional(),
|
|
22
|
-
})
|
|
25
|
+
}),
|
|
23
26
|
);
|
|
24
27
|
|
|
25
28
|
const Options = r.Union(
|
|
@@ -27,16 +30,14 @@ const Options = r.Union(
|
|
|
27
30
|
bannedDependencies: bannedDepGlobsField,
|
|
28
31
|
bannedTransitiveDependencies: r.Undefined.optional(),
|
|
29
32
|
}),
|
|
30
|
-
|
|
31
33
|
r.Record({
|
|
32
34
|
bannedDependencies: bannedDepGlobsField.optional(),
|
|
33
35
|
bannedTransitiveDependencies: r.Array(r.String),
|
|
34
36
|
}),
|
|
35
|
-
|
|
36
37
|
r.Record({
|
|
37
38
|
bannedDependencies: bannedDepGlobsField.optional(),
|
|
38
39
|
bannedTransitiveDependencies: r.Array(r.String).optional(),
|
|
39
|
-
})
|
|
40
|
+
}),
|
|
40
41
|
);
|
|
41
42
|
|
|
42
43
|
export type Options = r.Static<typeof Options>;
|
|
@@ -57,11 +58,17 @@ export const bannedDependencies = createRuleFactory<Options>({
|
|
|
57
58
|
const packageJson = context.getPackageJson();
|
|
58
59
|
const packagePath = context.getPackageJsonPath();
|
|
59
60
|
|
|
60
|
-
const curDeps = packageJson.dependencies
|
|
61
|
-
|
|
62
|
-
const
|
|
61
|
+
const curDeps = packageJson.dependencies
|
|
62
|
+
&& Object.keys(packageJson.dependencies);
|
|
63
|
+
const curDevDeps = packageJson.devDependencies
|
|
64
|
+
&& Object.keys(packageJson.devDependencies);
|
|
65
|
+
const curPeerDeps = packageJson.peerDependencies
|
|
66
|
+
&& Object.keys(packageJson.peerDependencies);
|
|
63
67
|
|
|
64
|
-
const {
|
|
68
|
+
const {
|
|
69
|
+
bannedDependencies: banned,
|
|
70
|
+
bannedTransitiveDependencies: transitives,
|
|
71
|
+
} = opts;
|
|
65
72
|
|
|
66
73
|
const globs = banned && (Array.isArray(banned) ? banned : banned.glob);
|
|
67
74
|
const exacts = banned && (Array.isArray(banned) ? undefined : banned.exact);
|
|
@@ -88,9 +95,8 @@ export const bannedDependencies = createRuleFactory<Options>({
|
|
|
88
95
|
if (violations.size > 0) {
|
|
89
96
|
context.addError({
|
|
90
97
|
file: packagePath,
|
|
91
|
-
message:
|
|
92
|
-
|
|
93
|
-
Array.from(violations)
|
|
98
|
+
message: `Found ${violations.size} banned dependencies of package.json:\n\t`
|
|
99
|
+
+ Array.from(violations)
|
|
94
100
|
.map((v) => `'${v}'`)
|
|
95
101
|
.join(", "),
|
|
96
102
|
});
|
|
@@ -113,7 +119,11 @@ export const bannedDependencies = createRuleFactory<Options>({
|
|
|
113
119
|
},
|
|
114
120
|
});
|
|
115
121
|
|
|
116
|
-
function populateProblemsExact(
|
|
122
|
+
function populateProblemsExact(
|
|
123
|
+
banned: Set<string>,
|
|
124
|
+
dependencies: ReadonlyArray<string>,
|
|
125
|
+
violations: Set<string>,
|
|
126
|
+
) {
|
|
117
127
|
for (const dependency of dependencies) {
|
|
118
128
|
if (banned.has(dependency)) {
|
|
119
129
|
violations.add(dependency);
|
|
@@ -124,7 +134,7 @@ function populateProblemsExact(banned: Set<string>, dependencies: ReadonlyArray<
|
|
|
124
134
|
function populateProblemsGlobs(
|
|
125
135
|
bannedDependencyGlobs: ReadonlyArray<string>,
|
|
126
136
|
dependencies: ReadonlyArray<string>,
|
|
127
|
-
violations: Set<string
|
|
137
|
+
violations: Set<string>,
|
|
128
138
|
) {
|
|
129
139
|
for (const dependency of dependencies) {
|
|
130
140
|
if (matchesAnyGlob(dependency, bannedDependencyGlobs)) {
|
|
@@ -136,13 +146,19 @@ function populateProblemsGlobs(
|
|
|
136
146
|
// This function is slow. God help you if you use this on a big repo
|
|
137
147
|
function checkTransitives(context: Context, banned: Set<string>) {
|
|
138
148
|
const graphService = new PackageDependencyGraphService();
|
|
139
|
-
const root = graphService.buildDependencyGraph(
|
|
149
|
+
const root = graphService.buildDependencyGraph(
|
|
150
|
+
path.resolve(context.getPackageJsonPath()),
|
|
151
|
+
context.host,
|
|
152
|
+
);
|
|
140
153
|
for (const { dependencies, importPath } of graphService.traverse(root)) {
|
|
141
154
|
for (const [dependency] of dependencies) {
|
|
142
155
|
if (banned.has(dependency)) {
|
|
143
156
|
// Remove the starting package since it's obvious in CLI output.
|
|
144
157
|
const [, ...importPathWithoutRoot] = importPath;
|
|
145
|
-
const pathing = [
|
|
158
|
+
const pathing = [
|
|
159
|
+
...importPathWithoutRoot.map(nameOrPackageJsonPath),
|
|
160
|
+
dependency,
|
|
161
|
+
].join(" -> ");
|
|
146
162
|
|
|
147
163
|
context.addError({
|
|
148
164
|
file: root.paths.packageJsonPath,
|