@monorepolint/rules 0.6.0-alpha.2 → 0.6.0-alpha.3
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 +160 -100
- package/.turbo/turbo-transpile-typescript.log +4 -4
- package/CHANGELOG.md +9 -0
- package/build/js/index.js +399 -246
- 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/index.d.ts +3 -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/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 +1159 -818
- package/coverage/coverage-final.json +18 -18
- package/coverage/index.html +20 -20
- package/coverage/src/alphabeticalDependencies.ts.html +8 -8
- package/coverage/src/alphabeticalScripts.ts.html +5 -5
- package/coverage/src/bannedDependencies.ts.html +77 -26
- package/coverage/src/consistentDependencies.ts.html +58 -19
- package/coverage/src/consistentVersions.ts.html +169 -58
- package/coverage/src/fileContents.ts.html +47 -23
- package/coverage/src/index.html +67 -67
- package/coverage/src/index.ts.html +32 -32
- package/coverage/src/mustSatisfyPeerDependencies.ts.html +373 -85
- package/coverage/src/nestedWorkspaces.ts.html +59 -20
- 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 +83 -32
- package/coverage/src/standardTsconfig.ts.html +81 -18
- 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 +101 -20
- 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 +9 -5
- package/src/__tests__/mustSatisfyPeerDependencies.spec.ts +191 -76
- package/src/__tests__/nestedWorkspaces.spec.ts +10 -6
- package/src/__tests__/packageEntry.spec.ts +54 -48
- package/src/__tests__/packageOrder.spec.ts +77 -71
- package/src/__tests__/packageScript.spec.ts +25 -11
- package/src/__tests__/requireDependency.spec.ts +12 -6
- package/src/__tests__/utils.ts +16 -7
- package/src/bannedDependencies.ts +32 -15
- package/src/consistentDependencies.ts +22 -9
- package/src/consistentVersions.ts +84 -47
- package/src/fileContents.ts +19 -11
- package/src/index.ts +3 -3
- package/src/mustSatisfyPeerDependencies.ts +162 -66
- package/src/nestedWorkspaces.ts +23 -10
- package/src/packageEntry.ts +18 -11
- package/src/packageOrder.ts +9 -3
- package/src/packageScript.ts +37 -19
- package/src/requireDependency.ts +28 -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 +41 -14
- package/vitest.config.mjs +10 -7
|
@@ -8,50 +8,56 @@
|
|
|
8
8
|
// tslint:disable:no-console
|
|
9
9
|
|
|
10
10
|
import { Context, Failure } from "@monorepolint/config";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
12
|
+
import {
|
|
13
|
+
createExpectedEntryErrorMessage,
|
|
14
|
+
createStandardizedEntryErrorMessage,
|
|
15
|
+
packageEntry,
|
|
16
|
+
} from "../packageEntry.js";
|
|
17
|
+
import {
|
|
18
|
+
AddErrorSpy,
|
|
19
|
+
createTestingWorkspace,
|
|
20
|
+
HOST_FACTORIES,
|
|
21
|
+
TestingWorkspace,
|
|
22
|
+
} from "./utils.js";
|
|
23
|
+
|
|
24
|
+
const PACKAGE_MISSING_ENTRY = JSON.stringify(
|
|
25
|
+
{
|
|
26
|
+
name: "package",
|
|
27
|
+
version: {},
|
|
28
|
+
scripts: {},
|
|
29
|
+
dependencies: {},
|
|
30
|
+
},
|
|
31
|
+
undefined,
|
|
32
|
+
2,
|
|
33
|
+
) + "\n";
|
|
34
|
+
|
|
35
|
+
const PACKAGE_LICENSE = JSON.stringify(
|
|
36
|
+
{
|
|
37
|
+
name: "package",
|
|
38
|
+
version: {},
|
|
39
|
+
scripts: {},
|
|
40
|
+
dependencies: {},
|
|
41
|
+
license: "UNLICENSED",
|
|
42
|
+
},
|
|
43
|
+
undefined,
|
|
44
|
+
2,
|
|
45
|
+
) + "\n";
|
|
46
|
+
|
|
47
|
+
const PACKAGE_REPOSITORY = JSON.stringify(
|
|
48
|
+
{
|
|
49
|
+
name: "package",
|
|
50
|
+
version: {},
|
|
51
|
+
scripts: {},
|
|
52
|
+
dependencies: {},
|
|
53
|
+
repository: {
|
|
54
|
+
type: "git",
|
|
55
|
+
url: "https://github.com:foo/foo",
|
|
22
56
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const PACKAGE_LICENSE =
|
|
28
|
-
JSON.stringify(
|
|
29
|
-
{
|
|
30
|
-
name: "package",
|
|
31
|
-
version: {},
|
|
32
|
-
scripts: {},
|
|
33
|
-
dependencies: {},
|
|
34
|
-
license: "UNLICENSED",
|
|
35
|
-
},
|
|
36
|
-
undefined,
|
|
37
|
-
2
|
|
38
|
-
) + "\n";
|
|
39
|
-
|
|
40
|
-
const PACKAGE_REPOSITORY =
|
|
41
|
-
JSON.stringify(
|
|
42
|
-
{
|
|
43
|
-
name: "package",
|
|
44
|
-
version: {},
|
|
45
|
-
scripts: {},
|
|
46
|
-
dependencies: {},
|
|
47
|
-
repository: {
|
|
48
|
-
type: "git",
|
|
49
|
-
url: "https://github.com:foo/foo",
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
undefined,
|
|
53
|
-
2
|
|
54
|
-
) + "\n";
|
|
57
|
+
},
|
|
58
|
+
undefined,
|
|
59
|
+
2,
|
|
60
|
+
) + "\n";
|
|
55
61
|
|
|
56
62
|
describe.each(HOST_FACTORIES)("expectPackageEntries ($name)", (hostFactory) => {
|
|
57
63
|
describe("fix: true", () => {
|
|
@@ -93,7 +99,7 @@ describe.each(HOST_FACTORIES)("expectPackageEntries ($name)", (hostFactory) => {
|
|
|
93
99
|
file: "package.json",
|
|
94
100
|
hasFixer: true,
|
|
95
101
|
message: createStandardizedEntryErrorMessage("license"),
|
|
96
|
-
})
|
|
102
|
+
}),
|
|
97
103
|
);
|
|
98
104
|
|
|
99
105
|
expect(workspace.readFile("package.json")).toEqual(PACKAGE_LICENSE);
|
|
@@ -122,7 +128,7 @@ describe.each(HOST_FACTORIES)("expectPackageEntries ($name)", (hostFactory) => {
|
|
|
122
128
|
file: "package.json",
|
|
123
129
|
hasFixer: true,
|
|
124
130
|
message: createStandardizedEntryErrorMessage("repository"),
|
|
125
|
-
})
|
|
131
|
+
}),
|
|
126
132
|
);
|
|
127
133
|
|
|
128
134
|
expect(workspace.readFile("package.json")).toEqual(PACKAGE_REPOSITORY);
|
|
@@ -165,7 +171,7 @@ describe.each(HOST_FACTORIES)("expectPackageEntries ($name)", (hostFactory) => {
|
|
|
165
171
|
file: "package.json",
|
|
166
172
|
hasFixer: false,
|
|
167
173
|
message: createExpectedEntryErrorMessage("bugs"),
|
|
168
|
-
})
|
|
174
|
+
}),
|
|
169
175
|
);
|
|
170
176
|
expect(workspace.readFile("package.json")).toEqual(PACKAGE_REPOSITORY);
|
|
171
177
|
});
|
|
@@ -193,7 +199,7 @@ describe.each(HOST_FACTORIES)("expectPackageEntries ($name)", (hostFactory) => {
|
|
|
193
199
|
file: "package.json",
|
|
194
200
|
hasFixer: true,
|
|
195
201
|
message: createStandardizedEntryErrorMessage("repository"),
|
|
196
|
-
})
|
|
202
|
+
}),
|
|
197
203
|
);
|
|
198
204
|
|
|
199
205
|
const failure2: Failure = spy.mock.calls[1][0];
|
|
@@ -202,7 +208,7 @@ describe.each(HOST_FACTORIES)("expectPackageEntries ($name)", (hostFactory) => {
|
|
|
202
208
|
file: "package.json",
|
|
203
209
|
hasFixer: false,
|
|
204
210
|
message: createExpectedEntryErrorMessage("bugs"),
|
|
205
|
-
})
|
|
211
|
+
}),
|
|
206
212
|
);
|
|
207
213
|
|
|
208
214
|
expect(workspace.readFile("package.json")).toEqual(PACKAGE_REPOSITORY);
|
|
@@ -6,36 +6,39 @@
|
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
},
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
},
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
12
|
+
import {
|
|
13
|
+
AddErrorSpy,
|
|
14
|
+
createTestingWorkspace,
|
|
15
|
+
HOST_FACTORIES,
|
|
16
|
+
TestingWorkspace,
|
|
17
|
+
} from "./utils.js";
|
|
18
|
+
|
|
19
|
+
const PACKAGE_UNORDERED = JSON.stringify(
|
|
20
|
+
{
|
|
21
|
+
scripts: {},
|
|
22
|
+
dependencies: {},
|
|
23
|
+
version: {},
|
|
24
|
+
name: "package",
|
|
25
|
+
},
|
|
26
|
+
undefined,
|
|
27
|
+
2,
|
|
28
|
+
) + "\n";
|
|
29
|
+
|
|
30
|
+
const PACKAGE_UNORDERED_UNKOWN_KEYS = JSON.stringify(
|
|
31
|
+
{
|
|
32
|
+
butter: false,
|
|
33
|
+
apple: false,
|
|
34
|
+
scripts: {},
|
|
35
|
+
dependencies: {},
|
|
36
|
+
version: {},
|
|
37
|
+
name: "package-unknown-keys",
|
|
38
|
+
},
|
|
39
|
+
undefined,
|
|
40
|
+
2,
|
|
41
|
+
) + "\n";
|
|
39
42
|
|
|
40
43
|
const orderArray = ["name", "version", "scripts", "dependencies"];
|
|
41
44
|
|
|
@@ -44,43 +47,40 @@ const orderFunction = (_context: Context) => (a: string, b: string) => {
|
|
|
44
47
|
return b.length - a.length || a.localeCompare(b);
|
|
45
48
|
};
|
|
46
49
|
|
|
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";
|
|
50
|
+
const PACKAGE_ORDERED = JSON.stringify(
|
|
51
|
+
{
|
|
52
|
+
name: "package",
|
|
53
|
+
version: {},
|
|
54
|
+
scripts: {},
|
|
55
|
+
dependencies: {},
|
|
56
|
+
},
|
|
57
|
+
undefined,
|
|
58
|
+
2,
|
|
59
|
+
) + "\n";
|
|
60
|
+
|
|
61
|
+
const PACKAGE_ORDERED_BY_LENGTH = JSON.stringify(
|
|
62
|
+
{
|
|
63
|
+
dependencies: {},
|
|
64
|
+
scripts: {},
|
|
65
|
+
version: {},
|
|
66
|
+
name: "package",
|
|
67
|
+
},
|
|
68
|
+
undefined,
|
|
69
|
+
2,
|
|
70
|
+
) + "\n";
|
|
71
|
+
|
|
72
|
+
const PACKAGE_ORDERED_UNKOWN_KEYS = JSON.stringify(
|
|
73
|
+
{
|
|
74
|
+
name: "package-unknown-keys",
|
|
75
|
+
version: {},
|
|
76
|
+
scripts: {},
|
|
77
|
+
dependencies: {},
|
|
78
|
+
apple: false,
|
|
79
|
+
butter: false,
|
|
80
|
+
},
|
|
81
|
+
undefined,
|
|
82
|
+
2,
|
|
83
|
+
) + "\n";
|
|
84
84
|
|
|
85
85
|
describe.each(HOST_FACTORIES)("expectPackageOrder ($name)", (hostFactory) => {
|
|
86
86
|
describe("fix: true", () => {
|
|
@@ -115,7 +115,7 @@ describe.each(HOST_FACTORIES)("expectPackageOrder ($name)", (hostFactory) => {
|
|
|
115
115
|
file: "package.json",
|
|
116
116
|
hasFixer: true,
|
|
117
117
|
message: "Incorrect order of fields in package.json",
|
|
118
|
-
})
|
|
118
|
+
}),
|
|
119
119
|
);
|
|
120
120
|
|
|
121
121
|
expect(workspace.readFile("package.json")).toEqual(PACKAGE_ORDERED);
|
|
@@ -138,10 +138,12 @@ describe.each(HOST_FACTORIES)("expectPackageOrder ($name)", (hostFactory) => {
|
|
|
138
138
|
file: "package.json",
|
|
139
139
|
hasFixer: true,
|
|
140
140
|
message: "Incorrect order of fields in package.json",
|
|
141
|
-
})
|
|
141
|
+
}),
|
|
142
142
|
);
|
|
143
143
|
|
|
144
|
-
expect(workspace.readFile("package.json")).toEqual(
|
|
144
|
+
expect(workspace.readFile("package.json")).toEqual(
|
|
145
|
+
PACKAGE_ORDERED_UNKOWN_KEYS,
|
|
146
|
+
);
|
|
145
147
|
});
|
|
146
148
|
|
|
147
149
|
it("fixes order using function", () => {
|
|
@@ -161,10 +163,12 @@ describe.each(HOST_FACTORIES)("expectPackageOrder ($name)", (hostFactory) => {
|
|
|
161
163
|
file: "package.json",
|
|
162
164
|
hasFixer: true,
|
|
163
165
|
message: "Incorrect order of fields in package.json",
|
|
164
|
-
})
|
|
166
|
+
}),
|
|
165
167
|
);
|
|
166
168
|
|
|
167
|
-
expect(workspace.readFile("package.json")).toEqual(
|
|
169
|
+
expect(workspace.readFile("package.json")).toEqual(
|
|
170
|
+
PACKAGE_ORDERED_BY_LENGTH,
|
|
171
|
+
);
|
|
168
172
|
});
|
|
169
173
|
|
|
170
174
|
it("does nothing if already order", () => {
|
|
@@ -178,7 +182,9 @@ describe.each(HOST_FACTORIES)("expectPackageOrder ($name)", (hostFactory) => {
|
|
|
178
182
|
|
|
179
183
|
expect(spy).not.toHaveBeenCalled();
|
|
180
184
|
|
|
181
|
-
expect(workspace.readFile("package.json")).toEqual(
|
|
185
|
+
expect(workspace.readFile("package.json")).toEqual(
|
|
186
|
+
PACKAGE_ORDERED_UNKOWN_KEYS,
|
|
187
|
+
);
|
|
182
188
|
});
|
|
183
189
|
});
|
|
184
190
|
});
|
|
@@ -6,10 +6,15 @@
|
|
|
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
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
AddErrorSpy,
|
|
14
|
+
createTestingWorkspace,
|
|
15
|
+
HOST_FACTORIES,
|
|
16
|
+
TestingWorkspace,
|
|
17
|
+
} from "./utils.js";
|
|
13
18
|
|
|
14
19
|
const json = (a: unknown) => JSON.stringify(a, undefined, 2) + "\n";
|
|
15
20
|
|
|
@@ -63,7 +68,7 @@ describe.each(HOST_FACTORIES)("expectPackageScript ($name)", (hostFactory) => {
|
|
|
63
68
|
file: "package.json",
|
|
64
69
|
hasFixer: true,
|
|
65
70
|
message: "No scripts block in package.json",
|
|
66
|
-
})
|
|
71
|
+
}),
|
|
67
72
|
);
|
|
68
73
|
});
|
|
69
74
|
});
|
|
@@ -102,10 +107,12 @@ describe.each(HOST_FACTORIES)("expectPackageScript ($name)", (hostFactory) => {
|
|
|
102
107
|
file: "package.json",
|
|
103
108
|
hasFixer: true,
|
|
104
109
|
message: "No scripts block in package.json",
|
|
105
|
-
})
|
|
110
|
+
}),
|
|
106
111
|
);
|
|
107
112
|
|
|
108
|
-
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual(
|
|
113
|
+
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual(
|
|
114
|
+
{},
|
|
115
|
+
);
|
|
109
116
|
});
|
|
110
117
|
|
|
111
118
|
it("adds a script", () => {
|
|
@@ -127,13 +134,16 @@ describe.each(HOST_FACTORIES)("expectPackageScript ($name)", (hostFactory) => {
|
|
|
127
134
|
file: "package.json",
|
|
128
135
|
hasFixer: true,
|
|
129
136
|
message: expect.stringContaining(
|
|
130
|
-
`Expected standardized script entry for '${MISSING_SCRIPT_NAME}'
|
|
137
|
+
`Expected standardized script entry for '${MISSING_SCRIPT_NAME}'`,
|
|
131
138
|
) as unknown as string,
|
|
132
|
-
})
|
|
139
|
+
}),
|
|
133
140
|
);
|
|
134
141
|
|
|
135
|
-
expect(
|
|
136
|
-
|
|
142
|
+
expect(
|
|
143
|
+
JSON.parse(workspace.readFile("package.json")!)
|
|
144
|
+
.scripts[MISSING_SCRIPT_NAME],
|
|
145
|
+
).toEqual(
|
|
146
|
+
MISSING_SCRIPT_VALUE,
|
|
137
147
|
);
|
|
138
148
|
});
|
|
139
149
|
|
|
@@ -218,7 +228,9 @@ describe.each(HOST_FACTORIES)("expectPackageScript ($name)", (hostFactory) => {
|
|
|
218
228
|
expect(errors.length).toBe(1);
|
|
219
229
|
expect(errors[0][0].fixer).toBeDefined();
|
|
220
230
|
|
|
221
|
-
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual(
|
|
231
|
+
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual(
|
|
232
|
+
{},
|
|
233
|
+
);
|
|
222
234
|
});
|
|
223
235
|
|
|
224
236
|
it("can allow only empty", () => {
|
|
@@ -240,7 +252,9 @@ describe.each(HOST_FACTORIES)("expectPackageScript ($name)", (hostFactory) => {
|
|
|
240
252
|
expect(errors.length).toBe(1);
|
|
241
253
|
expect(errors[0][0].fixer).toBeDefined();
|
|
242
254
|
|
|
243
|
-
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual(
|
|
255
|
+
expect(JSON.parse(workspace.readFile("package.json")!).scripts).toEqual(
|
|
256
|
+
{},
|
|
257
|
+
);
|
|
244
258
|
});
|
|
245
259
|
});
|
|
246
260
|
});
|
|
@@ -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);
|
|
@@ -89,8 +96,8 @@ export const bannedDependencies = createRuleFactory<Options>({
|
|
|
89
96
|
context.addError({
|
|
90
97
|
file: packagePath,
|
|
91
98
|
message:
|
|
92
|
-
`Found ${violations.size} banned dependencies of package.json:\n\t`
|
|
93
|
-
Array.from(violations)
|
|
99
|
+
`Found ${violations.size} banned dependencies of package.json:\n\t`
|
|
100
|
+
+ Array.from(violations)
|
|
94
101
|
.map((v) => `'${v}'`)
|
|
95
102
|
.join(", "),
|
|
96
103
|
});
|
|
@@ -113,7 +120,11 @@ export const bannedDependencies = createRuleFactory<Options>({
|
|
|
113
120
|
},
|
|
114
121
|
});
|
|
115
122
|
|
|
116
|
-
function populateProblemsExact(
|
|
123
|
+
function populateProblemsExact(
|
|
124
|
+
banned: Set<string>,
|
|
125
|
+
dependencies: ReadonlyArray<string>,
|
|
126
|
+
violations: Set<string>,
|
|
127
|
+
) {
|
|
117
128
|
for (const dependency of dependencies) {
|
|
118
129
|
if (banned.has(dependency)) {
|
|
119
130
|
violations.add(dependency);
|
|
@@ -124,7 +135,7 @@ function populateProblemsExact(banned: Set<string>, dependencies: ReadonlyArray<
|
|
|
124
135
|
function populateProblemsGlobs(
|
|
125
136
|
bannedDependencyGlobs: ReadonlyArray<string>,
|
|
126
137
|
dependencies: ReadonlyArray<string>,
|
|
127
|
-
violations: Set<string
|
|
138
|
+
violations: Set<string>,
|
|
128
139
|
) {
|
|
129
140
|
for (const dependency of dependencies) {
|
|
130
141
|
if (matchesAnyGlob(dependency, bannedDependencyGlobs)) {
|
|
@@ -136,13 +147,19 @@ function populateProblemsGlobs(
|
|
|
136
147
|
// This function is slow. God help you if you use this on a big repo
|
|
137
148
|
function checkTransitives(context: Context, banned: Set<string>) {
|
|
138
149
|
const graphService = new PackageDependencyGraphService();
|
|
139
|
-
const root = graphService.buildDependencyGraph(
|
|
150
|
+
const root = graphService.buildDependencyGraph(
|
|
151
|
+
path.resolve(context.getPackageJsonPath()),
|
|
152
|
+
context.host,
|
|
153
|
+
);
|
|
140
154
|
for (const { dependencies, importPath } of graphService.traverse(root)) {
|
|
141
155
|
for (const [dependency] of dependencies) {
|
|
142
156
|
if (banned.has(dependency)) {
|
|
143
157
|
// Remove the starting package since it's obvious in CLI output.
|
|
144
158
|
const [, ...importPathWithoutRoot] = importPath;
|
|
145
|
-
const pathing = [
|
|
159
|
+
const pathing = [
|
|
160
|
+
...importPathWithoutRoot.map(nameOrPackageJsonPath),
|
|
161
|
+
dependency,
|
|
162
|
+
].join(" -> ");
|
|
146
163
|
|
|
147
164
|
context.addError({
|
|
148
165
|
file: root.paths.packageJsonPath,
|