@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
@@ -28,7 +28,11 @@ export const consistentDependencies = createRuleFactory<Options>({
28
28
  validateOptions: Options.check,
29
29
  });
30
30
 
31
- function checkDeps(context: Context, args: Options, block: "dependencies" | "devDependencies" | "peerDependencies") {
31
+ function checkDeps(
32
+ context: Context,
33
+ args: Options,
34
+ block: "dependencies" | "devDependencies" | "peerDependencies",
35
+ ) {
32
36
  const packageJson = context.getPackageJson();
33
37
  const packagePath = context.getPackageJsonPath();
34
38
  const dependencies = packageJson[block];
@@ -37,10 +41,9 @@ function checkDeps(context: Context, args: Options, block: "dependencies" | "dev
37
41
  const workspaceDependencies = workspacePackageJson[block];
38
42
 
39
43
  const ignoredDeps = args?.ignoredDependencies ?? [];
40
- const depsToCheck =
41
- workspaceDependencies == null || ignoredDeps.length === 0
42
- ? workspaceDependencies
43
- : omit(workspaceDependencies, ignoredDeps);
44
+ const depsToCheck = workspaceDependencies == null || ignoredDeps.length === 0
45
+ ? workspaceDependencies
46
+ : omit(workspaceDependencies, ignoredDeps);
44
47
 
45
48
  if (dependencies === undefined || depsToCheck === undefined) {
46
49
  return;
@@ -65,12 +68,17 @@ function checkDeps(context: Context, args: Options, block: "dependencies" | "dev
65
68
  }
66
69
  }
67
70
 
68
- function filterKeys(ob: Record<string, string>, filterOb: Record<string, string>) {
71
+ function filterKeys(
72
+ ob: Record<string, string>,
73
+ filterOb: Record<string, string>,
74
+ ) {
69
75
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
70
76
  const newOb: Record<string, any> = {};
71
77
 
72
78
  for (const key of Object.keys(filterOb)) {
73
- if (ob[key] !== undefined && skippedVersions.indexOf(filterOb[key]) === -1) {
79
+ if (
80
+ ob[key] !== undefined && skippedVersions.indexOf(filterOb[key]) === -1
81
+ ) {
74
82
  newOb[key] = ob[key];
75
83
  }
76
84
  }
@@ -78,7 +86,10 @@ function filterKeys(ob: Record<string, string>, filterOb: Record<string, string>
78
86
  return newOb;
79
87
  }
80
88
 
81
- function omit<T>(obj: Record<string, T>, keysToOmit: readonly string[]): Record<string, T> {
89
+ function omit<T>(
90
+ obj: Record<string, T>,
91
+ keysToOmit: readonly string[],
92
+ ): Record<string, T> {
82
93
  const newObj: Record<string, T> = {};
83
94
 
84
95
  const filtered = Object.entries(obj).filter(([key]) => !keysToOmit.includes(key));
@@ -23,13 +23,24 @@ export const consistentVersions = createRuleFactory({
23
23
  });
24
24
 
25
25
  function checkConsistentVersions(context: Context, options: Options) {
26
- for (const [dependencyPackageName, expectedPackageDependencyValue] of Object.entries(
27
- options.matchDependencyVersions
28
- )) {
26
+ for (
27
+ const [dependencyPackageName, expectedPackageDependencyValue] of Object
28
+ .entries(
29
+ options.matchDependencyVersions,
30
+ )
31
+ ) {
29
32
  if (Array.isArray(expectedPackageDependencyValue)) {
30
- ensurePackageMatchesSomeVersion(context, dependencyPackageName, expectedPackageDependencyValue);
33
+ ensurePackageMatchesSomeVersion(
34
+ context,
35
+ dependencyPackageName,
36
+ expectedPackageDependencyValue,
37
+ );
31
38
  } else {
32
- ensurePackageIsCorrectVersion(context, dependencyPackageName, expectedPackageDependencyValue);
39
+ ensurePackageIsCorrectVersion(
40
+ context,
41
+ dependencyPackageName,
42
+ expectedPackageDependencyValue,
43
+ );
33
44
  }
34
45
  }
35
46
  }
@@ -37,27 +48,32 @@ function checkConsistentVersions(context: Context, options: Options) {
37
48
  const ensurePackageIsCorrectVersion = (
38
49
  context: Context,
39
50
  dependencyPackageName: string,
40
- expectedPackageDependencyValue: string
51
+ expectedPackageDependencyValue: string,
41
52
  ) => {
42
53
  const packageJson = context.getPackageJson();
43
54
  const packageJsonPath = context.getPackageJsonPath();
44
55
 
45
- const expectedPackageDependencyVersion = coerce(expectedPackageDependencyValue);
56
+ const expectedPackageDependencyVersion = coerce(
57
+ expectedPackageDependencyValue,
58
+ );
46
59
  if (expectedPackageDependencyVersion == null) {
47
60
  throw new Error(
48
- `Malformed expected package dependency version defined in monorepolint configuration: ${dependencyPackageName} @ '${expectedPackageDependencyValue}'`
61
+ `Malformed expected package dependency version defined in monorepolint configuration: ${dependencyPackageName} @ '${expectedPackageDependencyValue}'`,
49
62
  );
50
63
  }
51
64
 
52
- const actualPackageDependencyValue = packageJson.dependencies && packageJson.dependencies[dependencyPackageName];
65
+ const actualPackageDependencyValue = packageJson.dependencies
66
+ && packageJson.dependencies[dependencyPackageName];
53
67
  const actualPackageDependencyVersion = coerce(actualPackageDependencyValue);
54
68
  if (
55
- actualPackageDependencyVersion != null &&
56
- actualPackageDependencyVersion.raw !== expectedPackageDependencyVersion.raw
69
+ actualPackageDependencyVersion != null
70
+ && actualPackageDependencyVersion.raw
71
+ !== expectedPackageDependencyVersion.raw
57
72
  ) {
58
73
  context.addError({
59
74
  file: packageJsonPath,
60
- message: `Expected dependency on ${dependencyPackageName} to match version defined in monorepolint configuration '${expectedPackageDependencyValue}', got '${actualPackageDependencyValue}' instead.`,
75
+ message:
76
+ `Expected dependency on ${dependencyPackageName} to match version defined in monorepolint configuration '${expectedPackageDependencyValue}', got '${actualPackageDependencyValue}' instead.`,
61
77
  fixer: () =>
62
78
  mutateJson<PackageJson>(packageJsonPath, context.host, (input) => {
63
79
  input.dependencies![dependencyPackageName] = expectedPackageDependencyValue;
@@ -66,16 +82,20 @@ const ensurePackageIsCorrectVersion = (
66
82
  });
67
83
  }
68
84
 
69
- const actualPackageDevDependencyValue =
70
- packageJson.devDependencies && packageJson.devDependencies[dependencyPackageName];
71
- const actualPackageDevDependencyVersion = coerce(actualPackageDevDependencyValue);
85
+ const actualPackageDevDependencyValue = packageJson.devDependencies
86
+ && packageJson.devDependencies[dependencyPackageName];
87
+ const actualPackageDevDependencyVersion = coerce(
88
+ actualPackageDevDependencyValue,
89
+ );
72
90
  if (
73
- actualPackageDevDependencyVersion != null &&
74
- actualPackageDevDependencyVersion.raw !== expectedPackageDependencyVersion.raw
91
+ actualPackageDevDependencyVersion != null
92
+ && actualPackageDevDependencyVersion.raw
93
+ !== expectedPackageDependencyVersion.raw
75
94
  ) {
76
95
  context.addError({
77
96
  file: packageJsonPath,
78
- message: `Expected devDependency on ${dependencyPackageName} to match version defined in monorepolint configuration '${expectedPackageDependencyValue}', got '${actualPackageDevDependencyValue}' instead`,
97
+ message:
98
+ `Expected devDependency on ${dependencyPackageName} to match version defined in monorepolint configuration '${expectedPackageDependencyValue}', got '${actualPackageDevDependencyValue}' instead`,
79
99
  fixer: () =>
80
100
  mutateJson<PackageJson>(packageJsonPath, context.host, (input) => {
81
101
  input.devDependencies![dependencyPackageName] = expectedPackageDependencyValue;
@@ -88,54 +108,66 @@ const ensurePackageIsCorrectVersion = (
88
108
  const ensurePackageMatchesSomeVersion = (
89
109
  context: Context,
90
110
  dependencyPackageName: string,
91
- acceptedPackageDependencyValues: string[]
111
+ acceptedPackageDependencyValues: string[],
92
112
  ) => {
93
113
  const packageJson = context.getPackageJson();
94
114
  const packageJsonPath = context.getPackageJsonPath();
95
115
 
96
116
  const acceptedPackageDependencyVersions: SemVer[] = acceptedPackageDependencyValues.map(
97
117
  (acceptedPackageDependencyValue) => {
98
- const acceptedPackageDependencyVersion = coerce(acceptedPackageDependencyValue);
118
+ const acceptedPackageDependencyVersion = coerce(
119
+ acceptedPackageDependencyValue,
120
+ );
99
121
  if (acceptedPackageDependencyVersion == null) {
100
122
  throw new Error(
101
- `Malformed accepted package dependency version defined in monorepolint configuration: ${dependencyPackageName} @ '${acceptedPackageDependencyValue}'`
123
+ `Malformed accepted package dependency version defined in monorepolint configuration: ${dependencyPackageName} @ '${acceptedPackageDependencyValue}'`,
102
124
  );
103
125
  }
104
126
  return acceptedPackageDependencyVersion;
105
- }
127
+ },
106
128
  );
107
129
 
108
- const actualPackageDependencyValue = packageJson.dependencies && packageJson.dependencies[dependencyPackageName];
130
+ const actualPackageDependencyValue = packageJson.dependencies
131
+ && packageJson.dependencies[dependencyPackageName];
109
132
  const actualPackageDependencyVersion = coerce(actualPackageDependencyValue);
110
133
  if (
111
- actualPackageDependencyVersion != null &&
112
- acceptedPackageDependencyVersions.every(
113
- (acceptedPackageDependencyVersion) => actualPackageDependencyVersion.raw !== acceptedPackageDependencyVersion.raw
134
+ actualPackageDependencyVersion != null
135
+ && acceptedPackageDependencyVersions.every(
136
+ (acceptedPackageDependencyVersion) =>
137
+ actualPackageDependencyVersion.raw
138
+ !== acceptedPackageDependencyVersion.raw,
114
139
  )
115
140
  ) {
116
141
  context.addError({
117
142
  file: packageJsonPath,
118
- message: `Expected dependency on ${dependencyPackageName} to match one of '${JSON.stringify(
119
- acceptedPackageDependencyValues
120
- )}', got '${actualPackageDependencyValue}' instead.`,
143
+ message: `Expected dependency on ${dependencyPackageName} to match one of '${
144
+ JSON.stringify(
145
+ acceptedPackageDependencyValues,
146
+ )
147
+ }', got '${actualPackageDependencyValue}' instead.`,
121
148
  });
122
149
  }
123
150
 
124
- const actualPackageDevDependencyValue =
125
- packageJson.devDependencies && packageJson.devDependencies[dependencyPackageName];
126
- const actualPackageDevDependencyVersion = coerce(actualPackageDevDependencyValue);
151
+ const actualPackageDevDependencyValue = packageJson.devDependencies
152
+ && packageJson.devDependencies[dependencyPackageName];
153
+ const actualPackageDevDependencyVersion = coerce(
154
+ actualPackageDevDependencyValue,
155
+ );
127
156
  if (
128
- actualPackageDevDependencyVersion != null &&
129
- acceptedPackageDependencyVersions.every(
157
+ actualPackageDevDependencyVersion != null
158
+ && acceptedPackageDependencyVersions.every(
130
159
  (acceptedPackageDependencyVersion) =>
131
- actualPackageDevDependencyVersion.raw !== acceptedPackageDependencyVersion.raw
160
+ actualPackageDevDependencyVersion.raw
161
+ !== acceptedPackageDependencyVersion.raw,
132
162
  )
133
163
  ) {
134
164
  context.addError({
135
165
  file: packageJsonPath,
136
- message: `Expected devDependency on ${dependencyPackageName} to match one of '${JSON.stringify(
137
- acceptedPackageDependencyValues
138
- )}', got '${actualPackageDevDependencyValue}' instead.`,
166
+ message: `Expected devDependency on ${dependencyPackageName} to match one of '${
167
+ JSON.stringify(
168
+ acceptedPackageDependencyValues,
169
+ )
170
+ }', got '${actualPackageDevDependencyValue}' instead.`,
139
171
  });
140
172
  }
141
173
  };
@@ -13,24 +13,24 @@ import { createRuleFactory } from "./util/createRuleFactory.js";
13
13
  const Options = r.Union(
14
14
  r.Record({
15
15
  file: r.String,
16
- generator: r.Function.withGuard((x): x is (context: Context) => string | Promise<string> => x != undefined),
16
+ generator: r.Function.withGuard((
17
+ x,
18
+ ): x is (context: Context) => string | Promise<string> => x != undefined),
17
19
  template: r.Undefined.optional(),
18
20
  templateFile: r.Undefined.optional(),
19
21
  }),
20
-
21
22
  r.Record({
22
23
  file: r.String,
23
24
  generator: r.Undefined.optional(),
24
25
  template: r.String.Or(r.Undefined),
25
26
  templateFile: r.Undefined.optional(),
26
27
  }),
27
-
28
28
  r.Record({
29
29
  file: r.String,
30
30
  generator: r.Undefined.optional(),
31
31
  template: r.Undefined.optional(),
32
32
  templateFile: r.String,
33
- })
33
+ }),
34
34
  );
35
35
 
36
36
  type Options = r.Static<typeof Options>;
@@ -42,13 +42,17 @@ export const fileContents = createRuleFactory<Options>({
42
42
  const expectedContent = await getExpectedContents(context, opts);
43
43
 
44
44
  const pathExists = context.host.exists(fullPath);
45
- const actualContent = pathExists ? context.host.readFile(fullPath, { encoding: "utf-8" }) : undefined;
45
+ const actualContent = pathExists
46
+ ? context.host.readFile(fullPath, { encoding: "utf-8" })
47
+ : undefined;
46
48
  if (actualContent !== expectedContent) {
47
- const longMessage =
48
- pathExists && expectedContent == undefined ? undefined : diff(expectedContent, actualContent, { expand: true });
49
+ const longMessage = pathExists && expectedContent == undefined
50
+ ? undefined
51
+ : diff(expectedContent, actualContent, { expand: true });
49
52
 
50
- const message =
51
- pathExists && expectedContent == undefined ? "File should not exist" : "Expect file contents to match";
53
+ const message = pathExists && expectedContent == undefined
54
+ ? "File should not exist"
55
+ : "Expect file contents to match";
52
56
 
53
57
  context.addError({
54
58
  file: fullPath,
@@ -59,7 +63,9 @@ export const fileContents = createRuleFactory<Options>({
59
63
  if (pathExists) context.host.deleteFile(fullPath);
60
64
  } else {
61
65
  context.host.mkdir(path.dirname(fullPath), { recursive: true });
62
- context.host.writeFile(fullPath, expectedContent, { encoding: "utf-8" });
66
+ context.host.writeFile(fullPath, expectedContent, {
67
+ encoding: "utf-8",
68
+ });
63
69
  }
64
70
  },
65
71
  });
@@ -70,7 +76,9 @@ export const fileContents = createRuleFactory<Options>({
70
76
 
71
77
  const optionsCache = new Map<
72
78
  Options,
73
- ((context: Context) => Promise<string> | string | undefined) | string | undefined
79
+ | ((context: Context) => Promise<string> | string | undefined)
80
+ | string
81
+ | undefined
74
82
  >();
75
83
 
76
84
  async function getExpectedContents(context: Context, opts: Options) {
@@ -0,0 +1,33 @@
1
+ import { createRuleFactory } from "./util/createRuleFactory.js";
2
+
3
+ export const forceError = createRuleFactory<{ customMessage?: string }>({
4
+ name: "forceError",
5
+
6
+ check: async (context, opts) => {
7
+ context.addError({
8
+ message: opts?.customMessage
9
+ ?? "Forced error (often used to debug package selection)",
10
+ file: context.getPackageJsonPath(),
11
+ });
12
+ },
13
+
14
+ validateOptions: (opts): asserts opts is null | { customMessage: string } => {
15
+ if (opts == null) return;
16
+
17
+ if (typeof opts !== "object") {
18
+ throw new Error("options must be an object if provided");
19
+ }
20
+
21
+ const numKeys = Object.keys(opts).length;
22
+
23
+ if (numKeys === 0) return;
24
+
25
+ if (Object.keys(opts).length > 1 || !("customMessage" in opts)) {
26
+ throw new Error("options must only have `customMessage` property");
27
+ }
28
+
29
+ if (typeof opts.customMessage !== "string") {
30
+ throw new Error("customMessage must be a string");
31
+ }
32
+ },
33
+ });
package/src/index.ts CHANGED
@@ -11,13 +11,15 @@ export { bannedDependencies } from "./bannedDependencies.js";
11
11
  export { consistentDependencies } from "./consistentDependencies.js";
12
12
  export { consistentVersions } from "./consistentVersions.js";
13
13
  export { fileContents } from "./fileContents.js";
14
+ export { forceError } from "./forceError.js";
14
15
  export { mustSatisfyPeerDependencies } from "./mustSatisfyPeerDependencies.js";
15
- export { packageOrder } from "./packageOrder.js";
16
+ export { nestedWorkspaces } from "./nestedWorkspaces.js";
17
+ export { oncePerPackage } from "./oncePerPackage.js";
16
18
  export { packageEntry } from "./packageEntry.js";
19
+ export { packageOrder } from "./packageOrder.js";
17
20
  export { packageScript } from "./packageScript.js";
18
- export { standardTsconfig } from "./standardTsconfig.js";
19
- export { nestedWorkspaces } from "./nestedWorkspaces.js";
20
21
  export { requireDependency } from "./requireDependency.js";
22
+ export { standardTsconfig } from "./standardTsconfig.js";
21
23
 
22
24
  export {
23
25
  createRuleFactory,