@monorepolint/rules 0.6.0-alpha.1 → 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 +272 -667
- package/.turbo/turbo-transpile-typescript.log +5 -5
- package/CHANGELOG.md +42 -0
- package/build/js/index.js +411 -263
- package/build/js/index.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/__tests__/utils.d.ts +4 -10
- 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 +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/standardTsconfig.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/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +1887 -0
- package/coverage/coverage-final.json +19 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +131 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +196 -0
- package/coverage/src/alphabeticalDependencies.ts.html +142 -0
- package/coverage/src/alphabeticalScripts.ts.html +136 -0
- package/coverage/src/bannedDependencies.ts.html +610 -0
- package/coverage/src/consistentDependencies.ts.html +394 -0
- package/coverage/src/consistentVersions.ts.html +619 -0
- package/coverage/src/fileContents.ts.html +409 -0
- package/coverage/src/index.html +311 -0
- package/coverage/src/index.ts.html +169 -0
- package/coverage/src/mustSatisfyPeerDependencies.ts.html +2605 -0
- package/coverage/src/nestedWorkspaces.ts.html +304 -0
- package/coverage/src/packageEntry.ts.html +376 -0
- package/coverage/src/packageOrder.ts.html +472 -0
- package/coverage/src/packageScript.ts.html +436 -0
- package/coverage/src/requireDependency.ts.html +349 -0
- package/coverage/src/standardTsconfig.ts.html +553 -0
- package/coverage/src/util/checkAlpha.ts.html +271 -0
- package/coverage/src/util/createRuleFactory.ts.html +196 -0
- package/coverage/src/util/index.html +161 -0
- package/coverage/src/util/makeDirectory.ts.html +157 -0
- package/coverage/src/util/packageDependencyGraphService.ts.html +508 -0
- package/package.json +15 -20
- package/src/__tests__/alphabeticalScripts.spec.ts +13 -5
- package/src/__tests__/bannedDependencies.spec.ts +47 -18
- package/src/__tests__/consistentDependencies.spec.ts +12 -6
- package/src/__tests__/consistentVersions.spec.ts +74 -20
- package/src/__tests__/fileContents.spec.ts +11 -7
- package/src/__tests__/mustSatisfyPeerDependencies.spec.ts +193 -78
- package/src/__tests__/nestedWorkspaces.spec.ts +12 -8
- package/src/__tests__/packageEntry.spec.ts +55 -49
- package/src/__tests__/packageOrder.spec.ts +78 -72
- package/src/__tests__/packageScript.spec.ts +27 -13
- package/src/__tests__/requireDependency.spec.ts +13 -7
- package/src/__tests__/utils.ts +18 -9
- package/src/bannedDependencies.ts +32 -15
- package/src/consistentDependencies.ts +22 -9
- package/src/consistentVersions.ts +84 -47
- package/src/fileContents.ts +24 -10
- 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 +32 -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 +17 -0
- package/jest.config.cjs +0 -4
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
import { Context } from "@monorepolint/config";
|
|
9
9
|
import { Host, mutateJson, PackageJson } from "@monorepolint/utils";
|
|
10
10
|
import * as path from "node:path";
|
|
11
|
+
import resolvePackagePath from "resolve-package-path";
|
|
11
12
|
import * as r from "runtypes";
|
|
12
13
|
import { coerce } from "semver";
|
|
13
|
-
import resolvePackagePath from "resolve-package-path";
|
|
14
14
|
import { createRuleFactory } from "./util/createRuleFactory.js";
|
|
15
15
|
|
|
16
16
|
const Options = r.Union(
|
|
@@ -29,7 +29,7 @@ const Options = r.Union(
|
|
|
29
29
|
dependencyWhitelist: r.Undefined,
|
|
30
30
|
dependencyBlacklist: r.Undefined,
|
|
31
31
|
enforceForDevDependencies: r.Undefined,
|
|
32
|
-
})
|
|
32
|
+
}),
|
|
33
33
|
),
|
|
34
34
|
r
|
|
35
35
|
.Record({
|
|
@@ -40,7 +40,7 @@ const Options = r.Union(
|
|
|
40
40
|
skipUnparseableRanges: r.Undefined,
|
|
41
41
|
dependencyBlacklist: r.Undefined,
|
|
42
42
|
enforceForDevDependencies: r.Undefined,
|
|
43
|
-
})
|
|
43
|
+
}),
|
|
44
44
|
),
|
|
45
45
|
r
|
|
46
46
|
.Record({
|
|
@@ -51,7 +51,7 @@ const Options = r.Union(
|
|
|
51
51
|
skipUnparseableRanges: r.Undefined,
|
|
52
52
|
dependencyWhitelist: r.Undefined,
|
|
53
53
|
enforceForDevDependencies: r.Undefined,
|
|
54
|
-
})
|
|
54
|
+
}),
|
|
55
55
|
),
|
|
56
56
|
r
|
|
57
57
|
.Record({
|
|
@@ -62,7 +62,7 @@ const Options = r.Union(
|
|
|
62
62
|
skipUnparseableRanges: r.Undefined,
|
|
63
63
|
dependencyWhitelist: r.Undefined,
|
|
64
64
|
dependencyBlacklist: r.Undefined,
|
|
65
|
-
})
|
|
65
|
+
}),
|
|
66
66
|
),
|
|
67
67
|
r
|
|
68
68
|
.Record({
|
|
@@ -73,7 +73,7 @@ const Options = r.Union(
|
|
|
73
73
|
r.Partial({
|
|
74
74
|
dependencyBlacklist: r.Undefined,
|
|
75
75
|
enforceForDevDependencies: r.Undefined,
|
|
76
|
-
})
|
|
76
|
+
}),
|
|
77
77
|
),
|
|
78
78
|
r
|
|
79
79
|
.Record({
|
|
@@ -84,7 +84,7 @@ const Options = r.Union(
|
|
|
84
84
|
r.Partial({
|
|
85
85
|
dependencyWhitelist: r.Undefined,
|
|
86
86
|
enforceForDevDependencies: r.Undefined,
|
|
87
|
-
})
|
|
87
|
+
}),
|
|
88
88
|
),
|
|
89
89
|
r
|
|
90
90
|
.Record({
|
|
@@ -95,7 +95,7 @@ const Options = r.Union(
|
|
|
95
95
|
r.Partial({
|
|
96
96
|
dependencyWhitelist: r.Undefined,
|
|
97
97
|
dependencyBlacklist: r.Undefined,
|
|
98
|
-
})
|
|
98
|
+
}),
|
|
99
99
|
),
|
|
100
100
|
r
|
|
101
101
|
.Record({
|
|
@@ -106,7 +106,7 @@ const Options = r.Union(
|
|
|
106
106
|
r.Partial({
|
|
107
107
|
skipUnparseableRanges: r.Undefined,
|
|
108
108
|
enforceForDevDependencies: r.Undefined,
|
|
109
|
-
})
|
|
109
|
+
}),
|
|
110
110
|
),
|
|
111
111
|
r
|
|
112
112
|
.Record({
|
|
@@ -117,7 +117,7 @@ const Options = r.Union(
|
|
|
117
117
|
r.Partial({
|
|
118
118
|
skipUnparseableRanges: r.Undefined,
|
|
119
119
|
dependencyBlacklist: r.Undefined,
|
|
120
|
-
})
|
|
120
|
+
}),
|
|
121
121
|
),
|
|
122
122
|
r
|
|
123
123
|
.Record({
|
|
@@ -128,7 +128,7 @@ const Options = r.Union(
|
|
|
128
128
|
r.Partial({
|
|
129
129
|
skipUnparseableRanges: r.Undefined,
|
|
130
130
|
dependencyWhitelist: r.Undefined,
|
|
131
|
-
})
|
|
131
|
+
}),
|
|
132
132
|
),
|
|
133
133
|
r
|
|
134
134
|
.Record({
|
|
@@ -139,7 +139,7 @@ const Options = r.Union(
|
|
|
139
139
|
.And(
|
|
140
140
|
r.Partial({
|
|
141
141
|
enforceForDevDependencies: r.Undefined,
|
|
142
|
-
})
|
|
142
|
+
}),
|
|
143
143
|
),
|
|
144
144
|
r
|
|
145
145
|
.Record({
|
|
@@ -150,7 +150,7 @@ const Options = r.Union(
|
|
|
150
150
|
.And(
|
|
151
151
|
r.Partial({
|
|
152
152
|
dependencyBlacklist: r.Undefined,
|
|
153
|
-
})
|
|
153
|
+
}),
|
|
154
154
|
),
|
|
155
155
|
r
|
|
156
156
|
.Record({
|
|
@@ -161,7 +161,7 @@ const Options = r.Union(
|
|
|
161
161
|
.And(
|
|
162
162
|
r.Partial({
|
|
163
163
|
dependencyWhitelist: r.Undefined,
|
|
164
|
-
})
|
|
164
|
+
}),
|
|
165
165
|
),
|
|
166
166
|
r
|
|
167
167
|
.Record({
|
|
@@ -172,14 +172,14 @@ const Options = r.Union(
|
|
|
172
172
|
.And(
|
|
173
173
|
r.Partial({
|
|
174
174
|
skipUnparseableRanges: r.Undefined,
|
|
175
|
-
})
|
|
175
|
+
}),
|
|
176
176
|
),
|
|
177
177
|
r.Record({
|
|
178
178
|
skipUnparseableRanges: r.Boolean,
|
|
179
179
|
dependencyWhitelist: r.Array(r.String),
|
|
180
180
|
dependencyBlacklist: r.Array(r.String),
|
|
181
181
|
enforceForDevDependencies: r.Boolean,
|
|
182
|
-
})
|
|
182
|
+
}),
|
|
183
183
|
);
|
|
184
184
|
|
|
185
185
|
export type Options = r.Static<typeof Options>;
|
|
@@ -270,7 +270,12 @@ interface IResolvedPeerDependencyRequirement {
|
|
|
270
270
|
}
|
|
271
271
|
|
|
272
272
|
function checkSatisfyPeerDependencies(context: Context, opts: Options) {
|
|
273
|
-
const {
|
|
273
|
+
const {
|
|
274
|
+
dependencyBlacklist,
|
|
275
|
+
dependencyWhitelist,
|
|
276
|
+
enforceForDevDependencies,
|
|
277
|
+
skipUnparseableRanges,
|
|
278
|
+
} = opts;
|
|
274
279
|
const packageJsonPath = path.resolve(context.getPackageJsonPath());
|
|
275
280
|
const packageJson = context.host.readJson(packageJsonPath) as PackageJson;
|
|
276
281
|
const packageDependencies = packageJson.dependencies || {};
|
|
@@ -279,8 +284,18 @@ function checkSatisfyPeerDependencies(context: Context, opts: Options) {
|
|
|
279
284
|
const packageName = packageJson.name || packageJsonPath;
|
|
280
285
|
|
|
281
286
|
// check that no peer dependencies are also declared as regular dependencies
|
|
282
|
-
for (
|
|
283
|
-
|
|
287
|
+
for (
|
|
288
|
+
const [peerDependencyName, peerDependencyRange] of Object.entries(
|
|
289
|
+
packagePeerDependencies,
|
|
290
|
+
)
|
|
291
|
+
) {
|
|
292
|
+
if (
|
|
293
|
+
shouldSkipPackage({
|
|
294
|
+
dependencyBlacklist,
|
|
295
|
+
dependencyWhitelist,
|
|
296
|
+
packageName: peerDependencyName,
|
|
297
|
+
})
|
|
298
|
+
) {
|
|
284
299
|
continue;
|
|
285
300
|
}
|
|
286
301
|
|
|
@@ -289,36 +304,59 @@ function checkSatisfyPeerDependencies(context: Context, opts: Options) {
|
|
|
289
304
|
context.addError({
|
|
290
305
|
file: packageJsonPath,
|
|
291
306
|
message:
|
|
292
|
-
`[0] Package ${packageName} has overloaded ${peerDependencyName} dependencies.\n\t`
|
|
293
|
-
`Peer dependency '${peerDependencyRange}' and regular dependency '${dependencyRange}'.`,
|
|
307
|
+
`[0] Package ${packageName} has overloaded ${peerDependencyName} dependencies.\n\t`
|
|
308
|
+
+ `Peer dependency '${peerDependencyRange}' and regular dependency '${dependencyRange}'.`,
|
|
294
309
|
});
|
|
295
310
|
}
|
|
296
311
|
}
|
|
297
312
|
|
|
298
313
|
// map of all inherited peer dependency requirements
|
|
299
|
-
const allRequiredPeerDependencies: {
|
|
314
|
+
const allRequiredPeerDependencies: {
|
|
315
|
+
[peerDependencyName: string]: IPeerDependencyRequirement[];
|
|
316
|
+
} = {};
|
|
300
317
|
|
|
301
318
|
// for each of this package's dependencies, add the dependency's peer requirements into `allRequiredPeerDependencies`
|
|
302
319
|
const allDependencies = enforceForDevDependencies
|
|
303
|
-
? [
|
|
320
|
+
? [
|
|
321
|
+
...Object.keys(packageDependencies),
|
|
322
|
+
...Object.keys(packageDevDependencies),
|
|
323
|
+
]
|
|
304
324
|
: Object.keys(packageDependencies);
|
|
305
325
|
for (const dependency of allDependencies) {
|
|
306
|
-
const dependencyPackageJsonPath = resolvePackagePath(
|
|
326
|
+
const dependencyPackageJsonPath = resolvePackagePath(
|
|
327
|
+
dependency,
|
|
328
|
+
path.dirname(packageJsonPath),
|
|
329
|
+
);
|
|
307
330
|
if (dependencyPackageJsonPath == null) {
|
|
308
|
-
throw new Error(
|
|
331
|
+
throw new Error(
|
|
332
|
+
`Could not resolve ${dependency} from ${path.dirname(packageJsonPath)}`,
|
|
333
|
+
);
|
|
309
334
|
}
|
|
310
|
-
const dependencyPackageJson = context.host.readJson(
|
|
335
|
+
const dependencyPackageJson = context.host.readJson(
|
|
336
|
+
dependencyPackageJsonPath,
|
|
337
|
+
) as PackageJson;
|
|
311
338
|
const requiredPeerDependencies = dependencyPackageJson.peerDependencies;
|
|
312
339
|
if (requiredPeerDependencies == null) {
|
|
313
340
|
continue;
|
|
314
341
|
}
|
|
315
|
-
for (
|
|
316
|
-
|
|
342
|
+
for (
|
|
343
|
+
const [peerDependencyName, range] of Object.entries(
|
|
344
|
+
requiredPeerDependencies,
|
|
345
|
+
)
|
|
346
|
+
) {
|
|
347
|
+
if (
|
|
348
|
+
shouldSkipPackage({
|
|
349
|
+
dependencyBlacklist,
|
|
350
|
+
dependencyWhitelist,
|
|
351
|
+
packageName: peerDependencyName,
|
|
352
|
+
})
|
|
353
|
+
) {
|
|
317
354
|
continue;
|
|
318
355
|
}
|
|
319
356
|
|
|
320
357
|
if (!isValidRange(range)) {
|
|
321
|
-
const message =
|
|
358
|
+
const message =
|
|
359
|
+
`Unable to parse ${dependencyPackageJson.name}'s ${peerDependencyName} peer dependency range '${range}'.`;
|
|
322
360
|
if (skipUnparseableRanges) {
|
|
323
361
|
context.addWarning({ file: dependencyPackageJsonPath, message });
|
|
324
362
|
continue;
|
|
@@ -328,26 +366,40 @@ function checkSatisfyPeerDependencies(context: Context, opts: Options) {
|
|
|
328
366
|
if (allRequiredPeerDependencies[peerDependencyName] == null) {
|
|
329
367
|
allRequiredPeerDependencies[peerDependencyName] = [];
|
|
330
368
|
}
|
|
331
|
-
allRequiredPeerDependencies[peerDependencyName].push({
|
|
369
|
+
allRequiredPeerDependencies[peerDependencyName].push({
|
|
370
|
+
fromPackageName: dependencyPackageJson.name!,
|
|
371
|
+
range,
|
|
372
|
+
});
|
|
332
373
|
}
|
|
333
374
|
}
|
|
334
375
|
|
|
335
|
-
for (
|
|
376
|
+
for (
|
|
377
|
+
const [peerDependencyName, peerDependencyRequirements] of Object.entries(
|
|
378
|
+
allRequiredPeerDependencies,
|
|
379
|
+
)
|
|
380
|
+
) {
|
|
336
381
|
// for each inherited peer dependency, determine the strictest range
|
|
337
382
|
let mostStrictPeerRequirement: IResolvedPeerDependencyRequirement = {
|
|
338
383
|
fromPeerDependencyRequirements: [peerDependencyRequirements[0]],
|
|
339
384
|
range: peerDependencyRequirements[0].range,
|
|
340
385
|
};
|
|
341
386
|
for (const peerRequirement of peerDependencyRequirements) {
|
|
342
|
-
if (
|
|
387
|
+
if (
|
|
388
|
+
doesASatisfyB(mostStrictPeerRequirement.range, peerRequirement.range)
|
|
389
|
+
) {
|
|
343
390
|
continue;
|
|
344
|
-
} else if (
|
|
391
|
+
} else if (
|
|
392
|
+
doesASatisfyB(peerRequirement.range, mostStrictPeerRequirement.range)
|
|
393
|
+
) {
|
|
345
394
|
mostStrictPeerRequirement = {
|
|
346
395
|
fromPeerDependencyRequirements: [peerRequirement],
|
|
347
396
|
range: peerRequirement.range,
|
|
348
397
|
};
|
|
349
398
|
} else {
|
|
350
|
-
const maybeIntersection = findIntersection(
|
|
399
|
+
const maybeIntersection = findIntersection(
|
|
400
|
+
peerRequirement.range,
|
|
401
|
+
mostStrictPeerRequirement.range,
|
|
402
|
+
);
|
|
351
403
|
if (maybeIntersection !== undefined) {
|
|
352
404
|
mostStrictPeerRequirement = {
|
|
353
405
|
fromPeerDependencyRequirements: [
|
|
@@ -360,9 +412,9 @@ function checkSatisfyPeerDependencies(context: Context, opts: Options) {
|
|
|
360
412
|
context.addError({
|
|
361
413
|
file: packageJsonPath,
|
|
362
414
|
message:
|
|
363
|
-
`[1] Package ${packageName} has conflicting inherited ${peerDependencyName} peer dependencies.\n\t`
|
|
364
|
-
`Dependency ${peerRequirement.fromPackageName} requires '${peerRequirement.range}' but\n\t`
|
|
365
|
-
getMostStrictStatement(mostStrictPeerRequirement),
|
|
415
|
+
`[1] Package ${packageName} has conflicting inherited ${peerDependencyName} peer dependencies.\n\t`
|
|
416
|
+
+ `Dependency ${peerRequirement.fromPackageName} requires '${peerRequirement.range}' but\n\t`
|
|
417
|
+
+ getMostStrictStatement(mostStrictPeerRequirement),
|
|
366
418
|
});
|
|
367
419
|
}
|
|
368
420
|
}
|
|
@@ -373,31 +425,35 @@ function checkSatisfyPeerDependencies(context: Context, opts: Options) {
|
|
|
373
425
|
const packageDependencyRange = packageDependencies[peerDependencyName];
|
|
374
426
|
if (packageDependencyRange != null) {
|
|
375
427
|
if (!isValidRange(packageDependencyRange)) {
|
|
376
|
-
const message =
|
|
428
|
+
const message =
|
|
429
|
+
`Unable to parse ${packageName}'s ${peerDependencyName} dependency range '${packageDependencyRange}'.`;
|
|
377
430
|
if (skipUnparseableRanges) {
|
|
378
431
|
context.addWarning({ file: packageJsonPath, message });
|
|
379
432
|
} else {
|
|
380
433
|
throw new Error(message);
|
|
381
434
|
}
|
|
382
|
-
} else if (
|
|
435
|
+
} else if (
|
|
436
|
+
!doesASatisfyB(packageDependencyRange, mostStrictPeerRequirement.range)
|
|
437
|
+
) {
|
|
383
438
|
context.addError({
|
|
384
439
|
file: packageJsonPath,
|
|
385
440
|
message:
|
|
386
|
-
`[2] Package ${packageName} dependency on ${peerDependencyName} '${packageDependencyRange}' does not satisfy inherited peer dependencies.\n\t`
|
|
387
|
-
getMostStrictStatement(mostStrictPeerRequirement),
|
|
441
|
+
`[2] Package ${packageName} dependency on ${peerDependencyName} '${packageDependencyRange}' does not satisfy inherited peer dependencies.\n\t`
|
|
442
|
+
+ getMostStrictStatement(mostStrictPeerRequirement),
|
|
388
443
|
});
|
|
389
444
|
}
|
|
390
445
|
}
|
|
391
446
|
|
|
392
447
|
// for every inherited peer dependency, this package must declare a dependency or peer dependency
|
|
393
448
|
// equal to or stricter than `mostStrictPeerRequirement`
|
|
394
|
-
const packagePeerDependencyRange =
|
|
449
|
+
const packagePeerDependencyRange =
|
|
450
|
+
packagePeerDependencies[peerDependencyName];
|
|
395
451
|
if (packageDependencyRange == null && packagePeerDependencyRange == null) {
|
|
396
452
|
context.addError({
|
|
397
453
|
file: packageJsonPath,
|
|
398
454
|
message:
|
|
399
|
-
`[3] Package ${packageName} is missing required ${peerDependencyName} dependency.\n\t`
|
|
400
|
-
getMostStrictStatement(mostStrictPeerRequirement),
|
|
455
|
+
`[3] Package ${packageName} is missing required ${peerDependencyName} dependency.\n\t`
|
|
456
|
+
+ getMostStrictStatement(mostStrictPeerRequirement),
|
|
401
457
|
fixer: getAddDependencyTypeFixer({
|
|
402
458
|
packageJsonPath,
|
|
403
459
|
dependencyType: "peerDependencies",
|
|
@@ -412,18 +468,24 @@ function checkSatisfyPeerDependencies(context: Context, opts: Options) {
|
|
|
412
468
|
// the range must be equal to or stricter than `mostStrictPeerRequirement`
|
|
413
469
|
if (packagePeerDependencyRange != null) {
|
|
414
470
|
if (!isValidRange(packagePeerDependencyRange)) {
|
|
415
|
-
const message =
|
|
471
|
+
const message =
|
|
472
|
+
`Unable to parse ${packageName}'s ${peerDependencyName} peer dependency range '${packagePeerDependencyRange}'.`;
|
|
416
473
|
if (skipUnparseableRanges) {
|
|
417
474
|
context.addWarning({ file: packageJsonPath, message });
|
|
418
475
|
} else {
|
|
419
476
|
throw new Error(message);
|
|
420
477
|
}
|
|
421
|
-
} else if (
|
|
478
|
+
} else if (
|
|
479
|
+
!doesASatisfyB(
|
|
480
|
+
packagePeerDependencyRange,
|
|
481
|
+
mostStrictPeerRequirement.range,
|
|
482
|
+
)
|
|
483
|
+
) {
|
|
422
484
|
context.addError({
|
|
423
485
|
file: packageJsonPath,
|
|
424
486
|
message:
|
|
425
|
-
`[4] Package ${packageName} peer dependency on ${peerDependencyName} '${packagePeerDependencyRange}' is not strict enough.\n\t`
|
|
426
|
-
getMostStrictStatement(mostStrictPeerRequirement),
|
|
487
|
+
`[4] Package ${packageName} peer dependency on ${peerDependencyName} '${packagePeerDependencyRange}' is not strict enough.\n\t`
|
|
488
|
+
+ getMostStrictStatement(mostStrictPeerRequirement),
|
|
427
489
|
fixer: getAddDependencyTypeFixer({
|
|
428
490
|
packageJsonPath,
|
|
429
491
|
dependencyType: "peerDependencies",
|
|
@@ -448,28 +510,39 @@ function shouldSkipPackage({
|
|
|
448
510
|
}) {
|
|
449
511
|
// blacklist should take precedance
|
|
450
512
|
if (
|
|
451
|
-
(dependencyBlacklist != null && dependencyBlacklist.includes(packageName))
|
|
452
|
-
(dependencyWhitelist != null
|
|
513
|
+
(dependencyBlacklist != null && dependencyBlacklist.includes(packageName))
|
|
514
|
+
|| (dependencyWhitelist != null
|
|
515
|
+
&& !dependencyWhitelist.includes(packageName))
|
|
453
516
|
) {
|
|
454
517
|
return true;
|
|
455
518
|
}
|
|
456
519
|
return false;
|
|
457
520
|
}
|
|
458
521
|
|
|
459
|
-
function getMostStrictStatement(
|
|
522
|
+
function getMostStrictStatement(
|
|
523
|
+
mostStrictPeerRequirement: IResolvedPeerDependencyRequirement,
|
|
524
|
+
) {
|
|
460
525
|
if (mostStrictPeerRequirement.fromPeerDependencyRequirements.length === 1) {
|
|
461
|
-
const dependencyName =
|
|
526
|
+
const dependencyName =
|
|
527
|
+
mostStrictPeerRequirement.fromPeerDependencyRequirements[0]
|
|
528
|
+
.fromPackageName;
|
|
462
529
|
return `Dependency ${dependencyName} requires '${mostStrictPeerRequirement.range}'.`;
|
|
463
530
|
} else {
|
|
464
|
-
const dependencyNames = mostStrictPeerRequirement
|
|
465
|
-
.
|
|
531
|
+
const dependencyNames = mostStrictPeerRequirement
|
|
532
|
+
.fromPeerDependencyRequirements
|
|
533
|
+
.map((peerDependencyRequirement) =>
|
|
534
|
+
peerDependencyRequirement.fromPackageName
|
|
535
|
+
)
|
|
466
536
|
.join(", ");
|
|
467
|
-
const dependencyRequirements = mostStrictPeerRequirement
|
|
468
|
-
.
|
|
537
|
+
const dependencyRequirements = mostStrictPeerRequirement
|
|
538
|
+
.fromPeerDependencyRequirements
|
|
539
|
+
.map((peerDependencyRequirement) =>
|
|
540
|
+
`'${peerDependencyRequirement.range}'`
|
|
541
|
+
)
|
|
469
542
|
.join(", ");
|
|
470
543
|
return (
|
|
471
|
-
`Dependencies [${dependencyNames}] require [${dependencyRequirements}] respectively, `
|
|
472
|
-
`resolving to '${mostStrictPeerRequirement.range}'.`
|
|
544
|
+
`Dependencies [${dependencyNames}] require [${dependencyRequirements}] respectively, `
|
|
545
|
+
+ `resolving to '${mostStrictPeerRequirement.range}'.`
|
|
473
546
|
);
|
|
474
547
|
}
|
|
475
548
|
}
|
|
@@ -503,7 +576,10 @@ function getMostStrictStatement(mostStrictPeerRequirement: IResolvedPeerDependen
|
|
|
503
576
|
* @param b version range that matches `RANGE_REGEX`
|
|
504
577
|
* @returns the maximum intersecting `ValidRange`, or `undefined` if there is no intersection
|
|
505
578
|
*/
|
|
506
|
-
export function findIntersection(
|
|
579
|
+
export function findIntersection(
|
|
580
|
+
a: ValidRange,
|
|
581
|
+
b: ValidRange,
|
|
582
|
+
): ValidRange | undefined {
|
|
507
583
|
if (doesASatisfyB(a, b)) {
|
|
508
584
|
return a;
|
|
509
585
|
} else if (doesASatisfyB(b, a)) {
|
|
@@ -536,7 +612,9 @@ export function findIntersection(a: ValidRange, b: ValidRange): ValidRange | und
|
|
|
536
612
|
.map((bVersion) => {
|
|
537
613
|
const bSemVer = coerce(bVersion)!;
|
|
538
614
|
if (bVersion.startsWith("^") && bSemVer.major >= aSemVer.major) {
|
|
539
|
-
return `^${
|
|
615
|
+
return `^${
|
|
616
|
+
bSemVer.compare(aSemVer) >= 0 ? bSemVer.raw : aSemVer.raw
|
|
617
|
+
}`;
|
|
540
618
|
}
|
|
541
619
|
return bSemVer.compare(aSemVer) !== -1 ? bVersion : undefined;
|
|
542
620
|
})
|
|
@@ -555,7 +633,9 @@ export function findIntersection(a: ValidRange, b: ValidRange): ValidRange | und
|
|
|
555
633
|
.map((aVersion) => {
|
|
556
634
|
const aSemVer = coerce(aVersion)!;
|
|
557
635
|
if (aVersion.startsWith("^") && aSemVer.major >= bSemVer.major) {
|
|
558
|
-
return `^${
|
|
636
|
+
return `^${
|
|
637
|
+
aSemVer.compare(bSemVer) >= 0 ? aSemVer.raw : bSemVer.raw
|
|
638
|
+
}`;
|
|
559
639
|
}
|
|
560
640
|
return aSemVer.compare(bSemVer) !== -1 ? aVersion : undefined;
|
|
561
641
|
})
|
|
@@ -569,14 +649,26 @@ export function findIntersection(a: ValidRange, b: ValidRange): ValidRange | und
|
|
|
569
649
|
const compatibleVersions = aVersions
|
|
570
650
|
.map((aVersion) => {
|
|
571
651
|
const aSemVer = coerce(aVersion)!;
|
|
572
|
-
const majorMatchingBVersion = bVersions.find((m) =>
|
|
652
|
+
const majorMatchingBVersion = bVersions.find((m) =>
|
|
653
|
+
coerce(m)!.major === aSemVer.major
|
|
654
|
+
);
|
|
573
655
|
if (majorMatchingBVersion === undefined) {
|
|
574
656
|
// there is no intersecting `b` major version for this `a` major version
|
|
575
657
|
return undefined;
|
|
576
658
|
}
|
|
577
|
-
if (
|
|
659
|
+
if (
|
|
660
|
+
doesASatisfyB(
|
|
661
|
+
aVersion as ValidRange,
|
|
662
|
+
majorMatchingBVersion as ValidRange,
|
|
663
|
+
)
|
|
664
|
+
) {
|
|
578
665
|
return aVersion;
|
|
579
|
-
} else if (
|
|
666
|
+
} else if (
|
|
667
|
+
doesASatisfyB(
|
|
668
|
+
majorMatchingBVersion as ValidRange,
|
|
669
|
+
aVersion as ValidRange,
|
|
670
|
+
)
|
|
671
|
+
) {
|
|
580
672
|
return majorMatchingBVersion;
|
|
581
673
|
} else {
|
|
582
674
|
return undefined;
|
|
@@ -665,7 +757,9 @@ export function doesASatisfyB(a: ValidRange, b: ValidRange): boolean {
|
|
|
665
757
|
|
|
666
758
|
return aVersions.every((aVersion) => {
|
|
667
759
|
const aSemVer = coerce(aVersion)!;
|
|
668
|
-
const majorMatchingBVersion = bVersions.find((m) =>
|
|
760
|
+
const majorMatchingBVersion = bVersions.find((m) =>
|
|
761
|
+
coerce(m)!.major === aSemVer.major
|
|
762
|
+
);
|
|
669
763
|
if (majorMatchingBVersion === undefined) {
|
|
670
764
|
// `a` permits a major version that is not permitted by `b`, therefore `a` is "less strict"
|
|
671
765
|
return false;
|
|
@@ -673,7 +767,9 @@ export function doesASatisfyB(a: ValidRange, b: ValidRange): boolean {
|
|
|
673
767
|
|
|
674
768
|
const aVersionIsRange = isMajorVersionRange(aVersion);
|
|
675
769
|
const majorMatchingBSemVer = coerce(majorMatchingBVersion)!;
|
|
676
|
-
const majorMatchingBVersionIsRange = isMajorVersionRange(
|
|
770
|
+
const majorMatchingBVersionIsRange = isMajorVersionRange(
|
|
771
|
+
majorMatchingBVersion,
|
|
772
|
+
);
|
|
677
773
|
|
|
678
774
|
if (majorMatchingBVersionIsRange) {
|
|
679
775
|
// `a` satisfies `b` so long as `aSemVer` is greater than or equal to `majorMatchingBSemVer`
|
package/src/nestedWorkspaces.ts
CHANGED
|
@@ -21,38 +21,51 @@ export const nestedWorkspaces = createRuleFactory({
|
|
|
21
21
|
const rootPackageJson = context.getWorkspaceContext().getPackageJson();
|
|
22
22
|
|
|
23
23
|
// Expand a set of globs covering all package.json files in the entire repo (except the root)
|
|
24
|
-
const packageJsonPaths = globby.globbySync([
|
|
24
|
+
const packageJsonPaths = globby.globbySync([
|
|
25
|
+
"*/**/package.json",
|
|
26
|
+
"!**/node_modules/**",
|
|
27
|
+
]);
|
|
25
28
|
|
|
26
29
|
const workspaces = Array.isArray(rootPackageJson.workspaces)
|
|
27
30
|
? rootPackageJson.workspaces
|
|
28
31
|
: rootPackageJson.workspaces !== undefined
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
? rootPackageJson.workspaces.packages
|
|
33
|
+
: undefined;
|
|
31
34
|
|
|
32
35
|
if (workspaces === undefined && packageJsonPaths.length > 0) {
|
|
33
36
|
context.addError({
|
|
34
37
|
file: context.getPackageJsonPath(),
|
|
35
|
-
message:
|
|
38
|
+
message:
|
|
39
|
+
"The \"workspace\" field is missing, even though there are workspaces in the repository.",
|
|
36
40
|
});
|
|
37
41
|
return;
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
// Build a set of globs for each package.json that exists in packages specified by a workspace.
|
|
41
|
-
const workspacePackageJsons = (workspaces || []).map((item) =>
|
|
45
|
+
const workspacePackageJsons = (workspaces || []).map((item) =>
|
|
46
|
+
`${item}/package.json`
|
|
47
|
+
);
|
|
42
48
|
|
|
43
49
|
// Expand the globs to get an array of all package.json files that are in packages specified by a workspace.
|
|
44
|
-
const expandedWorkspacesGlobs = globby.globbySync([
|
|
50
|
+
const expandedWorkspacesGlobs = globby.globbySync([
|
|
51
|
+
...workspacePackageJsons,
|
|
52
|
+
"!**/node_modules/**",
|
|
53
|
+
]);
|
|
45
54
|
|
|
46
55
|
// Ensure there are no package.jsons which are not included in the globbed workspaces set
|
|
47
|
-
const difference = packageJsonPaths.filter((packageJsonPath) =>
|
|
56
|
+
const difference = packageJsonPaths.filter((packageJsonPath) =>
|
|
57
|
+
!expandedWorkspacesGlobs.includes(packageJsonPath)
|
|
58
|
+
);
|
|
48
59
|
|
|
49
60
|
if (difference.length !== 0) {
|
|
50
|
-
const differencesList = difference.map((packageJsonPath) =>
|
|
61
|
+
const differencesList = difference.map((packageJsonPath) =>
|
|
62
|
+
path.dirname(packageJsonPath)
|
|
63
|
+
).join(", ");
|
|
51
64
|
context.addError({
|
|
52
65
|
file: context.getPackageJsonPath(),
|
|
53
66
|
message:
|
|
54
|
-
`The "workspace" field is missing one or more values: ${differencesList}. `
|
|
55
|
-
|
|
67
|
+
`The "workspace" field is missing one or more values: ${differencesList}. `
|
|
68
|
+
+ "You may be able to use a glob to avoid listing each workspace individually, e.g. \"packages/nested-workspace/*\".",
|
|
56
69
|
});
|
|
57
70
|
}
|
|
58
71
|
},
|
package/src/packageEntry.ts
CHANGED
|
@@ -18,7 +18,7 @@ export const Options = r.Union(
|
|
|
18
18
|
.And(
|
|
19
19
|
r.Partial({
|
|
20
20
|
entriesExist: r.Undefined,
|
|
21
|
-
})
|
|
21
|
+
}),
|
|
22
22
|
),
|
|
23
23
|
r
|
|
24
24
|
.Record({
|
|
@@ -27,12 +27,12 @@ export const Options = r.Union(
|
|
|
27
27
|
.And(
|
|
28
28
|
r.Partial({
|
|
29
29
|
entries: r.Undefined,
|
|
30
|
-
})
|
|
30
|
+
}),
|
|
31
31
|
),
|
|
32
32
|
r.Record({
|
|
33
33
|
entries: r.Dictionary(r.Unknown), // string => unknown, enforces existence of keys and their values
|
|
34
34
|
entriesExist: r.Array(r.String),
|
|
35
|
-
})
|
|
35
|
+
}),
|
|
36
36
|
);
|
|
37
37
|
|
|
38
38
|
export type Options = r.Static<typeof Options>;
|
|
@@ -46,21 +46,28 @@ export const packageEntry = createRuleFactory<Options>({
|
|
|
46
46
|
for (const key of Object.keys(options.entries)) {
|
|
47
47
|
const value = options.entries[key];
|
|
48
48
|
|
|
49
|
-
const entryDiff = diff(
|
|
49
|
+
const entryDiff = diff(
|
|
50
|
+
JSON.stringify(value) + "\n",
|
|
51
|
+
(JSON.stringify(packageJson[key]) || "") + "\n",
|
|
52
|
+
);
|
|
50
53
|
if (
|
|
51
|
-
(typeof value !== "object" && value !== packageJson[key])
|
|
52
|
-
entryDiff == null
|
|
53
|
-
!entryDiff.includes("Compared values have no visual difference")
|
|
54
|
+
(typeof value !== "object" && value !== packageJson[key])
|
|
55
|
+
|| entryDiff == null
|
|
56
|
+
|| !entryDiff.includes("Compared values have no visual difference")
|
|
54
57
|
) {
|
|
55
58
|
context.addError({
|
|
56
59
|
file: context.getPackageJsonPath(),
|
|
57
60
|
message: createStandardizedEntryErrorMessage(key),
|
|
58
61
|
longMessage: entryDiff,
|
|
59
62
|
fixer: () => {
|
|
60
|
-
mutateJson<PackageJson>(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
mutateJson<PackageJson>(
|
|
64
|
+
context.getPackageJsonPath(),
|
|
65
|
+
context.host,
|
|
66
|
+
(input) => {
|
|
67
|
+
input[key] = value;
|
|
68
|
+
return input;
|
|
69
|
+
},
|
|
70
|
+
);
|
|
64
71
|
},
|
|
65
72
|
});
|
|
66
73
|
}
|
package/src/packageOrder.ts
CHANGED
|
@@ -57,9 +57,13 @@ export const packageOrder = createRuleFactory<Options>({
|
|
|
57
57
|
const packageJson = context.getPackageJson();
|
|
58
58
|
const packagePath = context.getPackageJsonPath();
|
|
59
59
|
|
|
60
|
-
const order: string[] | OrderFunction = opts === undefined
|
|
60
|
+
const order: string[] | OrderFunction = opts === undefined
|
|
61
|
+
? defaultKeyOrder
|
|
62
|
+
: opts.order;
|
|
61
63
|
|
|
62
|
-
const comparator = isOrderFunction(order)
|
|
64
|
+
const comparator = isOrderFunction(order)
|
|
65
|
+
? order(context)
|
|
66
|
+
: createComparator(order);
|
|
63
67
|
|
|
64
68
|
const actualOrder = Object.keys(packageJson);
|
|
65
69
|
const expectedOrder = actualOrder.slice().sort(comparator); // sort mutates, so we need to copy the previous result
|
|
@@ -118,6 +122,8 @@ function createComparator(order: ReadonlyArray<string>) {
|
|
|
118
122
|
};
|
|
119
123
|
}
|
|
120
124
|
|
|
121
|
-
function isOrderFunction(
|
|
125
|
+
function isOrderFunction(
|
|
126
|
+
order: ReadonlyArray<string> | OrderFunction,
|
|
127
|
+
): order is OrderFunction {
|
|
122
128
|
return !Array.isArray(order);
|
|
123
129
|
}
|