@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.
Files changed (85) hide show
  1. package/.turbo/turbo-clean.log +1 -1
  2. package/.turbo/turbo-compile-typescript.log +1 -1
  3. package/.turbo/turbo-lint.log +1 -1
  4. package/.turbo/turbo-test.log +161 -102
  5. package/.turbo/turbo-transpile-typescript.log +4 -4
  6. package/CHANGELOG.md +19 -0
  7. package/build/js/index.js +429 -241
  8. package/build/js/index.js.map +1 -1
  9. package/build/tsconfig.tsbuildinfo +1 -1
  10. package/build/types/__tests__/utils.d.ts +0 -1
  11. package/build/types/__tests__/utils.d.ts.map +1 -1
  12. package/build/types/bannedDependencies.d.ts.map +1 -1
  13. package/build/types/fileContents.d.ts.map +1 -1
  14. package/build/types/forceError.d.ts +4 -0
  15. package/build/types/forceError.d.ts.map +1 -0
  16. package/build/types/index.d.ts +5 -3
  17. package/build/types/index.d.ts.map +1 -1
  18. package/build/types/mustSatisfyPeerDependencies.d.ts.map +1 -1
  19. package/build/types/nestedWorkspaces.d.ts.map +1 -1
  20. package/build/types/oncePerPackage.d.ts +11 -0
  21. package/build/types/oncePerPackage.d.ts.map +1 -0
  22. package/build/types/packageEntry.d.ts.map +1 -1
  23. package/build/types/packageOrder.d.ts.map +1 -1
  24. package/build/types/packageScript.d.ts.map +1 -1
  25. package/build/types/requireDependency.d.ts +12 -12
  26. package/build/types/requireDependency.d.ts.map +1 -1
  27. package/build/types/util/checkAlpha.d.ts.map +1 -1
  28. package/build/types/util/createRuleFactory.d.ts.map +1 -1
  29. package/build/types/util/packageDependencyGraphService.d.ts.map +1 -1
  30. package/coverage/clover.xml +1201 -813
  31. package/coverage/coverage-final.json +20 -18
  32. package/coverage/index.html +20 -20
  33. package/coverage/src/alphabeticalDependencies.ts.html +11 -11
  34. package/coverage/src/alphabeticalScripts.ts.html +5 -5
  35. package/coverage/src/bannedDependencies.ts.html +76 -28
  36. package/coverage/src/consistentDependencies.ts.html +51 -18
  37. package/coverage/src/consistentVersions.ts.html +144 -48
  38. package/coverage/src/fileContents.ts.html +47 -23
  39. package/coverage/src/forceError.ts.html +184 -0
  40. package/coverage/src/index.html +96 -66
  41. package/coverage/src/index.ts.html +39 -33
  42. package/coverage/src/mustSatisfyPeerDependencies.ts.html +323 -80
  43. package/coverage/src/nestedWorkspaces.ts.html +47 -20
  44. package/coverage/src/oncePerPackage.ts.html +181 -0
  45. package/coverage/src/packageEntry.ts.html +40 -19
  46. package/coverage/src/packageOrder.ts.html +30 -12
  47. package/coverage/src/packageScript.ts.html +81 -27
  48. package/coverage/src/requireDependency.ts.html +77 -32
  49. package/coverage/src/standardTsconfig.ts.html +84 -21
  50. package/coverage/src/util/checkAlpha.ts.html +18 -9
  51. package/coverage/src/util/createRuleFactory.ts.html +16 -4
  52. package/coverage/src/util/index.html +17 -17
  53. package/coverage/src/util/makeDirectory.ts.html +5 -5
  54. package/coverage/src/util/packageDependencyGraphService.ts.html +94 -19
  55. package/package.json +4 -5
  56. package/src/__tests__/alphabeticalScripts.spec.ts +12 -4
  57. package/src/__tests__/bannedDependencies.spec.ts +45 -16
  58. package/src/__tests__/consistentDependencies.spec.ts +11 -5
  59. package/src/__tests__/consistentVersions.spec.ts +72 -18
  60. package/src/__tests__/fileContents.spec.ts +5 -5
  61. package/src/__tests__/mustSatisfyPeerDependencies.spec.ts +191 -76
  62. package/src/__tests__/nestedWorkspaces.spec.ts +10 -7
  63. package/src/__tests__/packageEntry.spec.ts +48 -47
  64. package/src/__tests__/packageOrder.spec.ts +72 -71
  65. package/src/__tests__/packageScript.spec.ts +19 -10
  66. package/src/__tests__/requireDependency.spec.ts +12 -6
  67. package/src/__tests__/utils.ts +16 -7
  68. package/src/bannedDependencies.ts +32 -16
  69. package/src/consistentDependencies.ts +19 -8
  70. package/src/consistentVersions.ts +70 -38
  71. package/src/fileContents.ts +19 -11
  72. package/src/forceError.ts +33 -0
  73. package/src/index.ts +5 -3
  74. package/src/mustSatisfyPeerDependencies.ts +141 -60
  75. package/src/nestedWorkspaces.ts +19 -10
  76. package/src/oncePerPackage.ts +32 -0
  77. package/src/packageEntry.ts +18 -11
  78. package/src/packageOrder.ts +9 -3
  79. package/src/packageScript.ts +37 -19
  80. package/src/requireDependency.ts +26 -11
  81. package/src/standardTsconfig.ts +31 -10
  82. package/src/util/checkAlpha.ts +5 -2
  83. package/src/util/createRuleFactory.ts +6 -2
  84. package/src/util/packageDependencyGraphService.ts +38 -13
  85. package/vitest.config.mjs +6 -7
package/build/js/index.js CHANGED
@@ -113,11 +113,19 @@ var PackageDependencyGraphService = class {
113
113
  if (maxDepth == null || nextDepth <= maxDepth) {
114
114
  const dependencies = packageJson.dependencies != null ? Object.keys(packageJson.dependencies) : [];
115
115
  for (const dependency of dependencies) {
116
- const dependencyPackageJsonPath = resolvePackagePath(dependency, node.paths.rootDirectory);
116
+ const dependencyPackageJsonPath = resolvePackagePath(
117
+ dependency,
118
+ node.paths.rootDirectory
119
+ );
117
120
  if (dependencyPackageJsonPath == null) {
118
- throw new Error(`Could not resolve ${dependency} from ${node.paths.rootDirectory}`);
121
+ throw new Error(
122
+ `Could not resolve ${dependency} from ${node.paths.rootDirectory}`
123
+ );
119
124
  }
120
- node.dependencies.set(dependency, visit(dependencyPackageJsonPath, nextDepth));
125
+ node.dependencies.set(
126
+ dependency,
127
+ visit(dependencyPackageJsonPath, nextDepth)
128
+ );
121
129
  }
122
130
  }
123
131
  return node;
@@ -178,7 +186,10 @@ var bannedDependencies = createRuleFactory({
178
186
  const curDeps = packageJson.dependencies && Object.keys(packageJson.dependencies);
179
187
  const curDevDeps = packageJson.devDependencies && Object.keys(packageJson.devDependencies);
180
188
  const curPeerDeps = packageJson.peerDependencies && Object.keys(packageJson.peerDependencies);
181
- const { bannedDependencies: banned, bannedTransitiveDependencies: transitives } = opts;
189
+ const {
190
+ bannedDependencies: banned,
191
+ bannedTransitiveDependencies: transitives
192
+ } = opts;
182
193
  const globs = banned && (Array.isArray(banned) ? banned : banned.glob);
183
194
  const exacts = banned && (Array.isArray(banned) ? void 0 : banned.exact);
184
195
  const violations = /* @__PURE__ */ new Set();
@@ -235,12 +246,18 @@ function populateProblemsGlobs(bannedDependencyGlobs, dependencies, violations)
235
246
  }
236
247
  function checkTransitives(context, banned) {
237
248
  const graphService = new PackageDependencyGraphService();
238
- const root = graphService.buildDependencyGraph(path2.resolve(context.getPackageJsonPath()), context.host);
249
+ const root = graphService.buildDependencyGraph(
250
+ path2.resolve(context.getPackageJsonPath()),
251
+ context.host
252
+ );
239
253
  for (const { dependencies, importPath } of graphService.traverse(root)) {
240
254
  for (const [dependency] of dependencies) {
241
255
  if (banned.has(dependency)) {
242
256
  const [, ...importPathWithoutRoot] = importPath;
243
- const pathing = [...importPathWithoutRoot.map(nameOrPackageJsonPath), dependency].join(" -> ");
257
+ const pathing = [
258
+ ...importPathWithoutRoot.map(nameOrPackageJsonPath),
259
+ dependency
260
+ ].join(" -> ");
244
261
  context.addError({
245
262
  file: root.paths.packageJsonPath,
246
263
  message: `Banned transitive dependencies in repo: ${pathing}`
@@ -331,16 +348,26 @@ function checkConsistentVersions(context, options) {
331
348
  options.matchDependencyVersions
332
349
  )) {
333
350
  if (Array.isArray(expectedPackageDependencyValue)) {
334
- ensurePackageMatchesSomeVersion(context, dependencyPackageName, expectedPackageDependencyValue);
351
+ ensurePackageMatchesSomeVersion(
352
+ context,
353
+ dependencyPackageName,
354
+ expectedPackageDependencyValue
355
+ );
335
356
  } else {
336
- ensurePackageIsCorrectVersion(context, dependencyPackageName, expectedPackageDependencyValue);
357
+ ensurePackageIsCorrectVersion(
358
+ context,
359
+ dependencyPackageName,
360
+ expectedPackageDependencyValue
361
+ );
337
362
  }
338
363
  }
339
364
  }
340
365
  var ensurePackageIsCorrectVersion = (context, dependencyPackageName, expectedPackageDependencyValue) => {
341
366
  const packageJson = context.getPackageJson();
342
367
  const packageJsonPath = context.getPackageJsonPath();
343
- const expectedPackageDependencyVersion = coerce(expectedPackageDependencyValue);
368
+ const expectedPackageDependencyVersion = coerce(
369
+ expectedPackageDependencyValue
370
+ );
344
371
  if (expectedPackageDependencyVersion == null) {
345
372
  throw new Error(
346
373
  `Malformed expected package dependency version defined in monorepolint configuration: ${dependencyPackageName} @ '${expectedPackageDependencyValue}'`
@@ -359,7 +386,9 @@ var ensurePackageIsCorrectVersion = (context, dependencyPackageName, expectedPac
359
386
  });
360
387
  }
361
388
  const actualPackageDevDependencyValue = packageJson.devDependencies && packageJson.devDependencies[dependencyPackageName];
362
- const actualPackageDevDependencyVersion = coerce(actualPackageDevDependencyValue);
389
+ const actualPackageDevDependencyVersion = coerce(
390
+ actualPackageDevDependencyValue
391
+ );
363
392
  if (actualPackageDevDependencyVersion != null && actualPackageDevDependencyVersion.raw !== expectedPackageDependencyVersion.raw) {
364
393
  context.addError({
365
394
  file: packageJsonPath,
@@ -376,7 +405,9 @@ var ensurePackageMatchesSomeVersion = (context, dependencyPackageName, acceptedP
376
405
  const packageJsonPath = context.getPackageJsonPath();
377
406
  const acceptedPackageDependencyVersions = acceptedPackageDependencyValues.map(
378
407
  (acceptedPackageDependencyValue) => {
379
- const acceptedPackageDependencyVersion = coerce(acceptedPackageDependencyValue);
408
+ const acceptedPackageDependencyVersion = coerce(
409
+ acceptedPackageDependencyValue
410
+ );
380
411
  if (acceptedPackageDependencyVersion == null) {
381
412
  throw new Error(
382
413
  `Malformed accepted package dependency version defined in monorepolint configuration: ${dependencyPackageName} @ '${acceptedPackageDependencyValue}'`
@@ -398,7 +429,9 @@ var ensurePackageMatchesSomeVersion = (context, dependencyPackageName, acceptedP
398
429
  });
399
430
  }
400
431
  const actualPackageDevDependencyValue = packageJson.devDependencies && packageJson.devDependencies[dependencyPackageName];
401
- const actualPackageDevDependencyVersion = coerce(actualPackageDevDependencyValue);
432
+ const actualPackageDevDependencyVersion = coerce(
433
+ actualPackageDevDependencyValue
434
+ );
402
435
  if (actualPackageDevDependencyVersion != null && acceptedPackageDependencyVersions.every(
403
436
  (acceptedPackageDependencyVersion) => actualPackageDevDependencyVersion.raw !== acceptedPackageDependencyVersion.raw
404
437
  )) {
@@ -454,7 +487,9 @@ var fileContents = createRuleFactory({
454
487
  if (pathExists) context.host.deleteFile(fullPath);
455
488
  } else {
456
489
  context.host.mkdir(path3.dirname(fullPath), { recursive: true });
457
- context.host.writeFile(fullPath, expectedContent, { encoding: "utf-8" });
490
+ context.host.writeFile(fullPath, expectedContent, {
491
+ encoding: "utf-8"
492
+ });
458
493
  }
459
494
  }
460
495
  });
@@ -486,12 +521,37 @@ async function getExpectedContents(context, opts) {
486
521
  }
487
522
  }
488
523
 
524
+ // src/forceError.ts
525
+ var forceError = createRuleFactory({
526
+ name: "forceError",
527
+ check: async (context, opts) => {
528
+ context.addError({
529
+ message: (opts == null ? void 0 : opts.customMessage) ?? "Forced error (often used to debug package selection)",
530
+ file: context.getPackageJsonPath()
531
+ });
532
+ },
533
+ validateOptions: (opts) => {
534
+ if (opts == null) return;
535
+ if (typeof opts !== "object") {
536
+ throw new Error("options must be an object if provided");
537
+ }
538
+ const numKeys = Object.keys(opts).length;
539
+ if (numKeys === 0) return;
540
+ if (Object.keys(opts).length > 1 || !("customMessage" in opts)) {
541
+ throw new Error("options must only have `customMessage` property");
542
+ }
543
+ if (typeof opts.customMessage !== "string") {
544
+ throw new Error("customMessage must be a string");
545
+ }
546
+ }
547
+ });
548
+
489
549
  // src/mustSatisfyPeerDependencies.ts
490
550
  import { mutateJson as mutateJson2 } from "@monorepolint/utils";
491
551
  import * as path4 from "node:path";
552
+ import resolvePackagePath2 from "resolve-package-path";
492
553
  import * as r5 from "runtypes";
493
554
  import { coerce as coerce2 } from "semver";
494
- import resolvePackagePath2 from "resolve-package-path";
495
555
  var Options5 = r5.Union(
496
556
  r5.Partial({
497
557
  skipUnparseableRanges: r5.Undefined,
@@ -642,15 +702,26 @@ var MATCH_GREATER_OR_EQUAL_VERSION_RANGE = /^>= ?\d+(?:\.\d+|\.\d+\.\d+(?:-((?:0
642
702
  var MATCH_MAJOR_VERSION_RANGE = /^(?:\^?\d+|\^?\d+\.x|\^?\d+\.x\.x|\^\d+\.\d+|\^\d+\.\d+\.x|\^\d+\.\d+\.\d+(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)$/;
643
703
  var RANGE_REGEX = /^(\*|x|>= ?\d+(?:\.\d+|\.\d+\.\d+(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)?|\^?\d+(\.x|\.x\.x|\.\d+|\.\d+\.x|\.\d+\.\d+(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)?( \|\| \^?\d+(\.x|\.x\.x|\.\d+|\.\d+\.x|\.\d+\.\d+(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)?)*)$/;
644
704
  function checkSatisfyPeerDependencies(context, opts) {
645
- const { dependencyBlacklist, dependencyWhitelist, enforceForDevDependencies, skipUnparseableRanges } = opts;
705
+ const {
706
+ dependencyBlacklist,
707
+ dependencyWhitelist,
708
+ enforceForDevDependencies,
709
+ skipUnparseableRanges
710
+ } = opts;
646
711
  const packageJsonPath = path4.resolve(context.getPackageJsonPath());
647
712
  const packageJson = context.host.readJson(packageJsonPath);
648
713
  const packageDependencies = packageJson.dependencies || {};
649
714
  const packageDevDependencies = packageJson.devDependencies || {};
650
715
  const packagePeerDependencies = packageJson.peerDependencies || {};
651
716
  const packageName = packageJson.name || packageJsonPath;
652
- for (const [peerDependencyName, peerDependencyRange] of Object.entries(packagePeerDependencies)) {
653
- if (shouldSkipPackage({ dependencyBlacklist, dependencyWhitelist, packageName: peerDependencyName })) {
717
+ for (const [peerDependencyName, peerDependencyRange] of Object.entries(
718
+ packagePeerDependencies
719
+ )) {
720
+ if (shouldSkipPackage({
721
+ dependencyBlacklist,
722
+ dependencyWhitelist,
723
+ packageName: peerDependencyName
724
+ })) {
654
725
  continue;
655
726
  }
656
727
  const dependencyRange = packageDependencies[peerDependencyName];
@@ -663,19 +734,35 @@ function checkSatisfyPeerDependencies(context, opts) {
663
734
  }
664
735
  }
665
736
  const allRequiredPeerDependencies = {};
666
- const allDependencies = enforceForDevDependencies ? [...Object.keys(packageDependencies), ...Object.keys(packageDevDependencies)] : Object.keys(packageDependencies);
737
+ const allDependencies = enforceForDevDependencies ? [
738
+ ...Object.keys(packageDependencies),
739
+ ...Object.keys(packageDevDependencies)
740
+ ] : Object.keys(packageDependencies);
667
741
  for (const dependency of allDependencies) {
668
- const dependencyPackageJsonPath = resolvePackagePath2(dependency, path4.dirname(packageJsonPath));
742
+ const dependencyPackageJsonPath = resolvePackagePath2(
743
+ dependency,
744
+ path4.dirname(packageJsonPath)
745
+ );
669
746
  if (dependencyPackageJsonPath == null) {
670
- throw new Error(`Could not resolve ${dependency} from ${path4.dirname(packageJsonPath)}`);
747
+ throw new Error(
748
+ `Could not resolve ${dependency} from ${path4.dirname(packageJsonPath)}`
749
+ );
671
750
  }
672
- const dependencyPackageJson = context.host.readJson(dependencyPackageJsonPath);
751
+ const dependencyPackageJson = context.host.readJson(
752
+ dependencyPackageJsonPath
753
+ );
673
754
  const requiredPeerDependencies = dependencyPackageJson.peerDependencies;
674
755
  if (requiredPeerDependencies == null) {
675
756
  continue;
676
757
  }
677
- for (const [peerDependencyName, range] of Object.entries(requiredPeerDependencies)) {
678
- if (shouldSkipPackage({ dependencyBlacklist, dependencyWhitelist, packageName: peerDependencyName })) {
758
+ for (const [peerDependencyName, range] of Object.entries(
759
+ requiredPeerDependencies
760
+ )) {
761
+ if (shouldSkipPackage({
762
+ dependencyBlacklist,
763
+ dependencyWhitelist,
764
+ packageName: peerDependencyName
765
+ })) {
679
766
  continue;
680
767
  }
681
768
  if (!isValidRange(range)) {
@@ -689,10 +776,15 @@ function checkSatisfyPeerDependencies(context, opts) {
689
776
  if (allRequiredPeerDependencies[peerDependencyName] == null) {
690
777
  allRequiredPeerDependencies[peerDependencyName] = [];
691
778
  }
692
- allRequiredPeerDependencies[peerDependencyName].push({ fromPackageName: dependencyPackageJson.name, range });
779
+ allRequiredPeerDependencies[peerDependencyName].push({
780
+ fromPackageName: dependencyPackageJson.name,
781
+ range
782
+ });
693
783
  }
694
784
  }
695
- for (const [peerDependencyName, peerDependencyRequirements] of Object.entries(allRequiredPeerDependencies)) {
785
+ for (const [peerDependencyName, peerDependencyRequirements] of Object.entries(
786
+ allRequiredPeerDependencies
787
+ )) {
696
788
  let mostStrictPeerRequirement = {
697
789
  fromPeerDependencyRequirements: [peerDependencyRequirements[0]],
698
790
  range: peerDependencyRequirements[0].range
@@ -706,7 +798,10 @@ function checkSatisfyPeerDependencies(context, opts) {
706
798
  range: peerRequirement.range
707
799
  };
708
800
  } else {
709
- const maybeIntersection = findIntersection(peerRequirement.range, mostStrictPeerRequirement.range);
801
+ const maybeIntersection = findIntersection(
802
+ peerRequirement.range,
803
+ mostStrictPeerRequirement.range
804
+ );
710
805
  if (maybeIntersection !== void 0) {
711
806
  mostStrictPeerRequirement = {
712
807
  fromPeerDependencyRequirements: [
@@ -765,7 +860,10 @@ function checkSatisfyPeerDependencies(context, opts) {
765
860
  } else {
766
861
  throw new Error(message);
767
862
  }
768
- } else if (!doesASatisfyB(packagePeerDependencyRange, mostStrictPeerRequirement.range)) {
863
+ } else if (!doesASatisfyB(
864
+ packagePeerDependencyRange,
865
+ mostStrictPeerRequirement.range
866
+ )) {
769
867
  context.addError({
770
868
  file: packageJsonPath,
771
869
  message: `[4] Package ${packageName} peer dependency on ${peerDependencyName} '${packagePeerDependencyRange}' is not strict enough.
@@ -852,9 +950,15 @@ function findIntersection(a, b) {
852
950
  if (majorMatchingBVersion === void 0) {
853
951
  return void 0;
854
952
  }
855
- if (doesASatisfyB(aVersion, majorMatchingBVersion)) {
953
+ if (doesASatisfyB(
954
+ aVersion,
955
+ majorMatchingBVersion
956
+ )) {
856
957
  return aVersion;
857
- } else if (doesASatisfyB(majorMatchingBVersion, aVersion)) {
958
+ } else if (doesASatisfyB(
959
+ majorMatchingBVersion,
960
+ aVersion
961
+ )) {
858
962
  return majorMatchingBVersion;
859
963
  } else {
860
964
  return void 0;
@@ -901,7 +1005,9 @@ function doesASatisfyB(a, b) {
901
1005
  }
902
1006
  const aVersionIsRange = isMajorVersionRange(aVersion);
903
1007
  const majorMatchingBSemVer = coerce2(majorMatchingBVersion);
904
- const majorMatchingBVersionIsRange = isMajorVersionRange(majorMatchingBVersion);
1008
+ const majorMatchingBVersionIsRange = isMajorVersionRange(
1009
+ majorMatchingBVersion
1010
+ );
905
1011
  if (majorMatchingBVersionIsRange) {
906
1012
  return aSemVer.compare(majorMatchingBSemVer) !== -1;
907
1013
  } else {
@@ -943,12 +1049,153 @@ function getAddDependencyTypeFixer({
943
1049
  };
944
1050
  }
945
1051
 
946
- // src/packageOrder.ts
947
- import { diff as diff4 } from "jest-diff";
1052
+ // src/nestedWorkspaces.ts
1053
+ import * as globby from "globby";
1054
+ import * as path5 from "node:path";
948
1055
  import * as r6 from "runtypes";
949
- var Options6 = r6.Record({
950
- order: r6.Union(r6.Array(r6.String), r6.Function)
951
- }).Or(r6.Undefined);
1056
+ var Options6 = r6.Undefined;
1057
+ var nestedWorkspaces = createRuleFactory({
1058
+ name: "nestedWorkspaces",
1059
+ check: (context) => {
1060
+ const rootPackageJson = context.getWorkspaceContext().getPackageJson();
1061
+ const packageJsonPaths = globby.globbySync([
1062
+ "*/**/package.json",
1063
+ "!**/node_modules/**"
1064
+ ]);
1065
+ const workspaces = Array.isArray(rootPackageJson.workspaces) ? rootPackageJson.workspaces : rootPackageJson.workspaces !== void 0 ? rootPackageJson.workspaces.packages : void 0;
1066
+ if (workspaces === void 0 && packageJsonPaths.length > 0) {
1067
+ context.addError({
1068
+ file: context.getPackageJsonPath(),
1069
+ message: 'The "workspace" field is missing, even though there are workspaces in the repository.'
1070
+ });
1071
+ return;
1072
+ }
1073
+ const workspacePackageJsons = (workspaces || []).map((item) => `${item}/package.json`);
1074
+ const expandedWorkspacesGlobs = globby.globbySync([
1075
+ ...workspacePackageJsons,
1076
+ "!**/node_modules/**"
1077
+ ]);
1078
+ const difference = packageJsonPaths.filter(
1079
+ (packageJsonPath) => !expandedWorkspacesGlobs.includes(packageJsonPath)
1080
+ );
1081
+ if (difference.length !== 0) {
1082
+ const differencesList = difference.map((packageJsonPath) => path5.dirname(packageJsonPath)).join(", ");
1083
+ context.addError({
1084
+ file: context.getPackageJsonPath(),
1085
+ message: `The "workspace" field is missing one or more values: ${differencesList}. You may be able to use a glob to avoid listing each workspace individually, e.g. "packages/nested-workspace/*".`
1086
+ });
1087
+ }
1088
+ },
1089
+ validateOptions: Options6.check
1090
+ });
1091
+
1092
+ // src/oncePerPackage.ts
1093
+ import * as r7 from "runtypes";
1094
+ var Options7 = r7.Record({
1095
+ singletonKey: r7.String.Or(r7.Symbol),
1096
+ customMessage: r7.String.optional()
1097
+ });
1098
+ var visitedMap = /* @__PURE__ */ new Map();
1099
+ var oncePerPackage = createRuleFactory({
1100
+ name: "oncePerPackage",
1101
+ check: async (context, options) => {
1102
+ const visited = visitedMap.get(options.singletonKey) ?? /* @__PURE__ */ new Set();
1103
+ visitedMap.set(options.singletonKey, visited);
1104
+ if (visited.has(context.getName())) {
1105
+ context.addError({
1106
+ message: "This package has already been visited for this key: " + options.singletonKey.toString(),
1107
+ file: context.getPackageJsonPath()
1108
+ });
1109
+ } else {
1110
+ visited.add(context.getName());
1111
+ }
1112
+ },
1113
+ validateOptions: Options7.assert
1114
+ });
1115
+
1116
+ // src/packageEntry.ts
1117
+ import { mutateJson as mutateJson3 } from "@monorepolint/utils";
1118
+ import { diff as diff4 } from "jest-diff";
1119
+ import * as r8 from "runtypes";
1120
+ var Options8 = r8.Union(
1121
+ r8.Record({
1122
+ entries: r8.Dictionary(r8.Unknown)
1123
+ // string => unknown, enforces existence of keys and their values
1124
+ }).And(
1125
+ r8.Partial({
1126
+ entriesExist: r8.Undefined
1127
+ })
1128
+ ),
1129
+ r8.Record({
1130
+ entriesExist: r8.Array(r8.String)
1131
+ // enforces existence of keys, but not values
1132
+ }).And(
1133
+ r8.Partial({
1134
+ entries: r8.Undefined
1135
+ })
1136
+ ),
1137
+ r8.Record({
1138
+ entries: r8.Dictionary(r8.Unknown),
1139
+ // string => unknown, enforces existence of keys and their values
1140
+ entriesExist: r8.Array(r8.String)
1141
+ })
1142
+ );
1143
+ var packageEntry = createRuleFactory({
1144
+ name: "packageEntry",
1145
+ check: (context, options) => {
1146
+ const packageJson = context.getPackageJson();
1147
+ if (options.entries) {
1148
+ for (const key of Object.keys(options.entries)) {
1149
+ const value = options.entries[key];
1150
+ const entryDiff = diff4(
1151
+ JSON.stringify(value) + "\n",
1152
+ (JSON.stringify(packageJson[key]) || "") + "\n"
1153
+ );
1154
+ if (typeof value !== "object" && value !== packageJson[key] || entryDiff == null || !entryDiff.includes("Compared values have no visual difference")) {
1155
+ context.addError({
1156
+ file: context.getPackageJsonPath(),
1157
+ message: createStandardizedEntryErrorMessage(key),
1158
+ longMessage: entryDiff,
1159
+ fixer: () => {
1160
+ mutateJson3(
1161
+ context.getPackageJsonPath(),
1162
+ context.host,
1163
+ (input) => {
1164
+ input[key] = value;
1165
+ return input;
1166
+ }
1167
+ );
1168
+ }
1169
+ });
1170
+ }
1171
+ }
1172
+ }
1173
+ if (options.entriesExist) {
1174
+ for (const key of options.entriesExist) {
1175
+ if (packageJson[key] === void 0) {
1176
+ context.addError({
1177
+ file: context.getPackageJsonPath(),
1178
+ message: createExpectedEntryErrorMessage(key)
1179
+ });
1180
+ }
1181
+ }
1182
+ }
1183
+ },
1184
+ validateOptions: Options8.check
1185
+ });
1186
+ function createStandardizedEntryErrorMessage(key) {
1187
+ return `Expected standardized entry for '${key}'`;
1188
+ }
1189
+ function createExpectedEntryErrorMessage(key) {
1190
+ return `Expected entry for '${key}' to exist`;
1191
+ }
1192
+
1193
+ // src/packageOrder.ts
1194
+ import { diff as diff5 } from "jest-diff";
1195
+ import * as r9 from "runtypes";
1196
+ var Options9 = r9.Record({
1197
+ order: r9.Union(r9.Array(r9.String), r9.Function)
1198
+ }).Or(r9.Undefined);
952
1199
  var defaultKeyOrder = [
953
1200
  "name",
954
1201
  "version",
@@ -993,7 +1240,7 @@ var packageOrder = createRuleFactory({
993
1240
  context.addError({
994
1241
  file: packagePath,
995
1242
  message: "Incorrect order of fields in package.json",
996
- longMessage: diff4(expectedOrder, actualOrder, { expand: true }),
1243
+ longMessage: diff5(expectedOrder, actualOrder, { expand: true }),
997
1244
  fixer: () => {
998
1245
  const expectedPackageJson = {};
999
1246
  expectedOrder.forEach((key) => {
@@ -1004,7 +1251,7 @@ var packageOrder = createRuleFactory({
1004
1251
  });
1005
1252
  }
1006
1253
  },
1007
- validateOptions: Options6.check
1254
+ validateOptions: Options9.check
1008
1255
  });
1009
1256
  function arrayOrderCompare2(a, b) {
1010
1257
  for (let index = 0; index < a.length; index++) {
@@ -1035,87 +1282,17 @@ function isOrderFunction(order) {
1035
1282
  return !Array.isArray(order);
1036
1283
  }
1037
1284
 
1038
- // src/packageEntry.ts
1039
- import { mutateJson as mutateJson3 } from "@monorepolint/utils";
1040
- import { diff as diff5 } from "jest-diff";
1041
- import * as r7 from "runtypes";
1042
- var Options7 = r7.Union(
1043
- r7.Record({
1044
- entries: r7.Dictionary(r7.Unknown)
1045
- // string => unknown, enforces existence of keys and their values
1046
- }).And(
1047
- r7.Partial({
1048
- entriesExist: r7.Undefined
1049
- })
1050
- ),
1051
- r7.Record({
1052
- entriesExist: r7.Array(r7.String)
1053
- // enforces existence of keys, but not values
1054
- }).And(
1055
- r7.Partial({
1056
- entries: r7.Undefined
1057
- })
1058
- ),
1059
- r7.Record({
1060
- entries: r7.Dictionary(r7.Unknown),
1061
- // string => unknown, enforces existence of keys and their values
1062
- entriesExist: r7.Array(r7.String)
1063
- })
1064
- );
1065
- var packageEntry = createRuleFactory({
1066
- name: "packageEntry",
1067
- check: (context, options) => {
1068
- const packageJson = context.getPackageJson();
1069
- if (options.entries) {
1070
- for (const key of Object.keys(options.entries)) {
1071
- const value = options.entries[key];
1072
- const entryDiff = diff5(JSON.stringify(value) + "\n", (JSON.stringify(packageJson[key]) || "") + "\n");
1073
- if (typeof value !== "object" && value !== packageJson[key] || entryDiff == null || !entryDiff.includes("Compared values have no visual difference")) {
1074
- context.addError({
1075
- file: context.getPackageJsonPath(),
1076
- message: createStandardizedEntryErrorMessage(key),
1077
- longMessage: entryDiff,
1078
- fixer: () => {
1079
- mutateJson3(context.getPackageJsonPath(), context.host, (input) => {
1080
- input[key] = value;
1081
- return input;
1082
- });
1083
- }
1084
- });
1085
- }
1086
- }
1087
- }
1088
- if (options.entriesExist) {
1089
- for (const key of options.entriesExist) {
1090
- if (packageJson[key] === void 0) {
1091
- context.addError({
1092
- file: context.getPackageJsonPath(),
1093
- message: createExpectedEntryErrorMessage(key)
1094
- });
1095
- }
1096
- }
1097
- }
1098
- },
1099
- validateOptions: Options7.check
1100
- });
1101
- function createStandardizedEntryErrorMessage(key) {
1102
- return `Expected standardized entry for '${key}'`;
1103
- }
1104
- function createExpectedEntryErrorMessage(key) {
1105
- return `Expected entry for '${key}' to exist`;
1106
- }
1107
-
1108
1285
  // src/packageScript.ts
1109
1286
  import { mutateJson as mutateJson4 } from "@monorepolint/utils";
1110
1287
  import { diff as diff6 } from "jest-diff";
1111
- import * as r8 from "runtypes";
1112
- var Options8 = r8.Record({
1113
- scripts: r8.Dictionary(
1114
- r8.Union(
1115
- r8.String,
1116
- r8.Record({
1117
- options: r8.Array(r8.String.Or(r8.Undefined)),
1118
- fixValue: r8.Union(r8.String, r8.Undefined, r8.Literal(false)).optional()
1288
+ import * as r10 from "runtypes";
1289
+ var Options10 = r10.Record({
1290
+ scripts: r10.Dictionary(
1291
+ r10.Union(
1292
+ r10.String,
1293
+ r10.Record({
1294
+ options: r10.Array(r10.String.Or(r10.Undefined)),
1295
+ fixValue: r10.Union(r10.String, r10.Undefined, r10.Literal(false)).optional()
1119
1296
  })
1120
1297
  )
1121
1298
  )
@@ -1131,10 +1308,14 @@ var packageScript = createRuleFactory({
1131
1308
  file: context.getPackageJsonPath(),
1132
1309
  message: MSG_NO_SCRIPTS_BLOCK,
1133
1310
  fixer: () => {
1134
- mutateJson4(context.getPackageJsonPath(), context.host, (input) => {
1135
- input.scripts = {};
1136
- return input;
1137
- });
1311
+ mutateJson4(
1312
+ context.getPackageJsonPath(),
1313
+ context.host,
1314
+ (input) => {
1315
+ input.scripts = {};
1316
+ return input;
1317
+ }
1318
+ );
1138
1319
  }
1139
1320
  });
1140
1321
  return;
@@ -1163,43 +1344,125 @@ var packageScript = createRuleFactory({
1163
1344
  if (fixValue !== false && (fixValue !== void 0 || fixToEmpty === true)) {
1164
1345
  const q = fixValue;
1165
1346
  fixer = () => {
1166
- mutateJson4(context.getPackageJsonPath(), context.host, (input) => {
1167
- if (fixToEmpty && q === void 0) {
1168
- delete input.scripts[name];
1169
- } else {
1170
- input.scripts[name] = q;
1347
+ mutateJson4(
1348
+ context.getPackageJsonPath(),
1349
+ context.host,
1350
+ (input) => {
1351
+ if (fixToEmpty && q === void 0) {
1352
+ delete input.scripts[name];
1353
+ } else {
1354
+ input.scripts[name] = q;
1355
+ }
1356
+ return input;
1171
1357
  }
1172
- return input;
1173
- });
1358
+ );
1174
1359
  };
1175
1360
  }
1176
1361
  const validOptionsString = Array.from(allowedValues.values()).map((a) => a === void 0 ? "(empty)" : `'${a}'`).join(", ");
1177
1362
  context.addError({
1178
1363
  file: context.getPackageJsonPath(),
1179
1364
  message: `Expected standardized script entry for '${name}'. Valid options: ${validOptionsString}`,
1180
- longMessage: diff6(validOptionsString + "\n", (packageJson.scripts[name] || "") + "\n"),
1365
+ longMessage: diff6(
1366
+ validOptionsString + "\n",
1367
+ (packageJson.scripts[name] || "") + "\n"
1368
+ ),
1181
1369
  fixer
1182
1370
  });
1183
1371
  }
1184
1372
  }
1185
1373
  },
1186
- validateOptions: Options8.check
1374
+ validateOptions: Options10.check
1375
+ });
1376
+
1377
+ // src/requireDependency.ts
1378
+ import { mutateJson as mutateJson5 } from "@monorepolint/utils";
1379
+ import { diff as diff7 } from "jest-diff";
1380
+ import * as r11 from "runtypes";
1381
+ var Options11 = r11.Partial({
1382
+ dependencies: r11.Dictionary(r11.String.optional()),
1383
+ devDependencies: r11.Dictionary(r11.String.optional()),
1384
+ peerDependencies: r11.Dictionary(r11.String.optional()),
1385
+ optionalDependencies: r11.Dictionary(r11.String.optional())
1386
+ });
1387
+ var requireDependency = createRuleFactory({
1388
+ name: "requireDependency",
1389
+ check: function expectPackageEntry(context, options) {
1390
+ const packageJson = context.getPackageJson();
1391
+ const packageJsonPath = context.getPackageJsonPath();
1392
+ [
1393
+ "dependencies",
1394
+ "devDependencies",
1395
+ "peerDependencies",
1396
+ "optionalDependencies"
1397
+ ].forEach((type) => {
1398
+ var _a;
1399
+ const expectedEntries = options[type];
1400
+ if (!expectedEntries) {
1401
+ return;
1402
+ }
1403
+ if (packageJson[type] === void 0) {
1404
+ context.addError({
1405
+ file: packageJsonPath,
1406
+ message: `No ${type} block, cannot add required ${type}.`,
1407
+ fixer: () => {
1408
+ mutateJson5(packageJsonPath, context.host, (input) => {
1409
+ input[type] = Object.fromEntries(
1410
+ Object.entries(expectedEntries).filter(([, v]) => v !== void 0)
1411
+ );
1412
+ return input;
1413
+ });
1414
+ }
1415
+ });
1416
+ return;
1417
+ }
1418
+ for (const [dep, version] of Object.entries(options[type])) {
1419
+ if (((_a = packageJson[type]) == null ? void 0 : _a[dep]) !== version) {
1420
+ context.addError({
1421
+ file: packageJsonPath,
1422
+ message: `Expected dependency ${dep}@${version}`,
1423
+ longMessage: diff7(
1424
+ `${dep}@${version}
1425
+ `,
1426
+ `${dep}@${packageJson[type][dep] || "missing"}
1427
+ `
1428
+ ),
1429
+ fixer: () => {
1430
+ mutateJson5(
1431
+ packageJsonPath,
1432
+ context.host,
1433
+ (input) => {
1434
+ if (version === void 0) {
1435
+ input[type] = { ...input[type] };
1436
+ delete input[type][dep];
1437
+ } else {
1438
+ input[type] = { ...input[type], [dep]: version };
1439
+ }
1440
+ return input;
1441
+ }
1442
+ );
1443
+ }
1444
+ });
1445
+ }
1446
+ }
1447
+ });
1448
+ },
1449
+ validateOptions: Options11.check
1187
1450
  });
1188
1451
 
1189
1452
  // src/standardTsconfig.ts
1190
1453
  import { matchesAnyGlob as matchesAnyGlob2 } from "@monorepolint/utils";
1191
- import { diff as diff7 } from "jest-diff";
1192
- import * as path5 from "path";
1193
- import * as r9 from "runtypes";
1454
+ import { diff as diff8 } from "jest-diff";
1455
+ import * as path6 from "path";
1456
+ import * as r12 from "runtypes";
1194
1457
  var DEFAULT_TSCONFIG_FILENAME = "tsconfig.json";
1195
- var Options9 = r9.Partial({
1196
- file: r9.String,
1197
- generator: r9.Function,
1198
- tsconfigReferenceFile: r9.String,
1199
- template: r9.Record({}).Or(r9.String),
1200
- templateFile: r9.String,
1201
- excludedReferences: r9.Array(r9.String).Or(r9.Undefined),
1202
- additionalReferences: r9.Array(r9.String).Or(r9.Undefined)
1458
+ var Options12 = r12.Partial({
1459
+ file: r12.String,
1460
+ generator: r12.Function,
1461
+ tsconfigReferenceFile: r12.String,
1462
+ template: r12.Record({}).Or(r12.String),
1463
+ templateFile: r12.String,
1464
+ excludedReferences: r12.Array(r12.String).Or(r12.Undefined),
1465
+ additionalReferences: r12.Array(r12.String).Or(r12.Undefined)
1203
1466
  }).withConstraint(({ generator, template, templateFile }) => {
1204
1467
  let count = 0;
1205
1468
  if (generator) {
@@ -1217,7 +1480,7 @@ var standardTsconfig = createRuleFactory({
1217
1480
  name: "standardTsconfig",
1218
1481
  check: async (context, opts) => {
1219
1482
  const tsconfigFileName = opts.file ?? DEFAULT_TSCONFIG_FILENAME;
1220
- const fullPath = path5.resolve(context.packageDir, tsconfigFileName);
1483
+ const fullPath = path6.resolve(context.packageDir, tsconfigFileName);
1221
1484
  const generator = getGenerator(context, opts);
1222
1485
  const expectedContent = await generator(context);
1223
1486
  const actualContent = context.host.exists(fullPath) ? context.host.readFile(fullPath, { encoding: "utf-8" }) : void 0;
@@ -1232,7 +1495,7 @@ var standardTsconfig = createRuleFactory({
1232
1495
  context.addError({
1233
1496
  file: fullPath,
1234
1497
  message: "Expect file contents to match",
1235
- longMessage: diff7(expectedContent, actualContent, { expand: true }),
1498
+ longMessage: diff8(expectedContent, actualContent, { expand: true }),
1236
1499
  fixer: () => {
1237
1500
  context.host.writeFile(fullPath, expectedContent, {
1238
1501
  encoding: "utf-8"
@@ -1241,18 +1504,30 @@ var standardTsconfig = createRuleFactory({
1241
1504
  });
1242
1505
  }
1243
1506
  },
1244
- validateOptions: Options9.check
1507
+ validateOptions: Options12.check
1245
1508
  });
1246
1509
  function getGenerator(context, opts) {
1247
1510
  if (opts.generator) {
1248
1511
  return opts.generator;
1249
1512
  } else if (opts.templateFile) {
1250
1513
  const { packageDir: workspacePackageDir } = context.getWorkspaceContext();
1251
- const fullPath = path5.resolve(workspacePackageDir, opts.templateFile);
1252
- const template = JSON.parse(context.host.readFile(fullPath, { encoding: "utf-8" }));
1253
- return makeGenerator(template, opts.excludedReferences, opts.additionalReferences, opts.tsconfigReferenceFile);
1514
+ const fullPath = path6.resolve(workspacePackageDir, opts.templateFile);
1515
+ const template = JSON.parse(
1516
+ context.host.readFile(fullPath, { encoding: "utf-8" })
1517
+ );
1518
+ return makeGenerator(
1519
+ template,
1520
+ opts.excludedReferences,
1521
+ opts.additionalReferences,
1522
+ opts.tsconfigReferenceFile
1523
+ );
1254
1524
  } else if (opts.template) {
1255
- return makeGenerator(opts.template, opts.excludedReferences, opts.additionalReferences, opts.tsconfigReferenceFile);
1525
+ return makeGenerator(
1526
+ opts.template,
1527
+ opts.excludedReferences,
1528
+ opts.additionalReferences,
1529
+ opts.tsconfigReferenceFile
1530
+ );
1256
1531
  } else {
1257
1532
  throw new Error("Unable to make generator");
1258
1533
  }
@@ -1265,13 +1540,16 @@ function makeGenerator(template, excludedReferences, additionalReferences, tscon
1265
1540
  };
1266
1541
  const nameToDirectory = await context.getWorkspaceContext().getPackageNameToDir();
1267
1542
  const packageJson = context.getPackageJson();
1268
- const deps = [...Object.keys(packageJson.dependencies || {}), ...Object.keys(packageJson.devDependencies || {})];
1543
+ const deps = [
1544
+ ...Object.keys(packageJson.dependencies || {}),
1545
+ ...Object.keys(packageJson.devDependencies || {})
1546
+ ];
1269
1547
  for (const dep of deps) {
1270
1548
  const packageDir = nameToDirectory.get(dep);
1271
1549
  if (packageDir !== void 0 && (excludedReferences === void 0 || !matchesAnyGlob2(dep, excludedReferences))) {
1272
- const absoluteReferencePath = tsconfigReferenceFile !== void 0 ? path5.join(packageDir, tsconfigReferenceFile) : packageDir;
1550
+ const absoluteReferencePath = tsconfigReferenceFile !== void 0 ? path6.join(packageDir, tsconfigReferenceFile) : packageDir;
1273
1551
  template.references.push({
1274
- path: path5.relative(context.packageDir, absoluteReferencePath)
1552
+ path: path6.relative(context.packageDir, absoluteReferencePath)
1275
1553
  });
1276
1554
  }
1277
1555
  }
@@ -1285,98 +1563,6 @@ function makeGenerator(template, excludedReferences, additionalReferences, tscon
1285
1563
  return JSON.stringify(template, void 0, 2) + "\n";
1286
1564
  };
1287
1565
  }
1288
-
1289
- // src/nestedWorkspaces.ts
1290
- import * as globby from "globby";
1291
- import * as path6 from "node:path";
1292
- import * as r10 from "runtypes";
1293
- var Options10 = r10.Undefined;
1294
- var nestedWorkspaces = createRuleFactory({
1295
- name: "nestedWorkspaces",
1296
- check: (context) => {
1297
- const rootPackageJson = context.getWorkspaceContext().getPackageJson();
1298
- const packageJsonPaths = globby.globbySync(["*/**/package.json", "!**/node_modules/**"]);
1299
- const workspaces = Array.isArray(rootPackageJson.workspaces) ? rootPackageJson.workspaces : rootPackageJson.workspaces !== void 0 ? rootPackageJson.workspaces.packages : void 0;
1300
- if (workspaces === void 0 && packageJsonPaths.length > 0) {
1301
- context.addError({
1302
- file: context.getPackageJsonPath(),
1303
- message: 'The "workspace" field is missing, even though there are workspaces in the repository.'
1304
- });
1305
- return;
1306
- }
1307
- const workspacePackageJsons = (workspaces || []).map((item) => `${item}/package.json`);
1308
- const expandedWorkspacesGlobs = globby.globbySync([...workspacePackageJsons, "!**/node_modules/**"]);
1309
- const difference = packageJsonPaths.filter((packageJsonPath) => !expandedWorkspacesGlobs.includes(packageJsonPath));
1310
- if (difference.length !== 0) {
1311
- const differencesList = difference.map((packageJsonPath) => path6.dirname(packageJsonPath)).join(", ");
1312
- context.addError({
1313
- file: context.getPackageJsonPath(),
1314
- message: `The "workspace" field is missing one or more values: ${differencesList}. You may be able to use a glob to avoid listing each workspace individually, e.g. "packages/nested-workspace/*".`
1315
- });
1316
- }
1317
- },
1318
- validateOptions: Options10.check
1319
- });
1320
-
1321
- // src/requireDependency.ts
1322
- import { mutateJson as mutateJson5 } from "@monorepolint/utils";
1323
- import { diff as diff8 } from "jest-diff";
1324
- import * as r11 from "runtypes";
1325
- var Options11 = r11.Partial({
1326
- dependencies: r11.Dictionary(r11.String),
1327
- devDependencies: r11.Dictionary(r11.String),
1328
- peerDependencies: r11.Dictionary(r11.String),
1329
- optionalDependencies: r11.Dictionary(r11.String)
1330
- });
1331
- var requireDependency = createRuleFactory({
1332
- name: "requireDependency",
1333
- check: function expectPackageEntry(context, options) {
1334
- const packageJson = context.getPackageJson();
1335
- const packageJsonPath = context.getPackageJsonPath();
1336
- [
1337
- "dependencies",
1338
- "devDependencies",
1339
- "peerDependencies",
1340
- "optionalDependencies"
1341
- ].forEach((type) => {
1342
- var _a;
1343
- if (!options[type]) {
1344
- return;
1345
- }
1346
- if (packageJson[type] === void 0) {
1347
- context.addError({
1348
- file: packageJsonPath,
1349
- message: `No ${type} block, cannot add required ${type}.`,
1350
- fixer: () => {
1351
- mutateJson5(packageJsonPath, context.host, (input) => {
1352
- input[type] = options[type];
1353
- return input;
1354
- });
1355
- }
1356
- });
1357
- return;
1358
- }
1359
- for (const [dep, version] of Object.entries(options[type])) {
1360
- if (((_a = packageJson[type]) == null ? void 0 : _a[dep]) !== version) {
1361
- context.addError({
1362
- file: packageJsonPath,
1363
- message: `Expected dependency ${dep}@${version}`,
1364
- longMessage: diff8(`${dep}@${version}
1365
- `, `${dep}@${packageJson[type][dep] || "missing"}
1366
- `),
1367
- fixer: () => {
1368
- mutateJson5(packageJsonPath, context.host, (input) => {
1369
- input[type] = { ...input[type], [dep]: version };
1370
- return input;
1371
- });
1372
- }
1373
- });
1374
- }
1375
- }
1376
- });
1377
- },
1378
- validateOptions: Options11.check
1379
- });
1380
1566
  export {
1381
1567
  alphabeticalDependencies,
1382
1568
  alphabeticalScripts,
@@ -1385,8 +1571,10 @@ export {
1385
1571
  consistentVersions,
1386
1572
  createRuleFactory,
1387
1573
  fileContents,
1574
+ forceError,
1388
1575
  mustSatisfyPeerDependencies,
1389
1576
  nestedWorkspaces,
1577
+ oncePerPackage,
1390
1578
  packageEntry,
1391
1579
  packageOrder,
1392
1580
  packageScript,