@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.
Files changed (87) 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 +272 -667
  5. package/.turbo/turbo-transpile-typescript.log +5 -5
  6. package/CHANGELOG.md +42 -0
  7. package/build/js/index.js +411 -263
  8. package/build/js/index.js.map +1 -1
  9. package/build/tsconfig.tsbuildinfo +1 -1
  10. package/build/types/__tests__/utils.d.ts +4 -10
  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 +1 -1
  14. package/build/types/fileContents.d.ts.map +1 -1
  15. package/build/types/index.d.ts +3 -3
  16. package/build/types/index.d.ts.map +1 -1
  17. package/build/types/mustSatisfyPeerDependencies.d.ts.map +1 -1
  18. package/build/types/nestedWorkspaces.d.ts.map +1 -1
  19. package/build/types/packageEntry.d.ts.map +1 -1
  20. package/build/types/packageOrder.d.ts.map +1 -1
  21. package/build/types/packageScript.d.ts.map +1 -1
  22. package/build/types/requireDependency.d.ts +12 -12
  23. package/build/types/requireDependency.d.ts.map +1 -1
  24. package/build/types/standardTsconfig.d.ts.map +1 -1
  25. package/build/types/util/checkAlpha.d.ts.map +1 -1
  26. package/build/types/util/createRuleFactory.d.ts.map +1 -1
  27. package/build/types/util/packageDependencyGraphService.d.ts.map +1 -1
  28. package/coverage/base.css +224 -0
  29. package/coverage/block-navigation.js +87 -0
  30. package/coverage/clover.xml +1887 -0
  31. package/coverage/coverage-final.json +19 -0
  32. package/coverage/favicon.png +0 -0
  33. package/coverage/index.html +131 -0
  34. package/coverage/prettify.css +1 -0
  35. package/coverage/prettify.js +2 -0
  36. package/coverage/sort-arrow-sprite.png +0 -0
  37. package/coverage/sorter.js +196 -0
  38. package/coverage/src/alphabeticalDependencies.ts.html +142 -0
  39. package/coverage/src/alphabeticalScripts.ts.html +136 -0
  40. package/coverage/src/bannedDependencies.ts.html +610 -0
  41. package/coverage/src/consistentDependencies.ts.html +394 -0
  42. package/coverage/src/consistentVersions.ts.html +619 -0
  43. package/coverage/src/fileContents.ts.html +409 -0
  44. package/coverage/src/index.html +311 -0
  45. package/coverage/src/index.ts.html +169 -0
  46. package/coverage/src/mustSatisfyPeerDependencies.ts.html +2605 -0
  47. package/coverage/src/nestedWorkspaces.ts.html +304 -0
  48. package/coverage/src/packageEntry.ts.html +376 -0
  49. package/coverage/src/packageOrder.ts.html +472 -0
  50. package/coverage/src/packageScript.ts.html +436 -0
  51. package/coverage/src/requireDependency.ts.html +349 -0
  52. package/coverage/src/standardTsconfig.ts.html +553 -0
  53. package/coverage/src/util/checkAlpha.ts.html +271 -0
  54. package/coverage/src/util/createRuleFactory.ts.html +196 -0
  55. package/coverage/src/util/index.html +161 -0
  56. package/coverage/src/util/makeDirectory.ts.html +157 -0
  57. package/coverage/src/util/packageDependencyGraphService.ts.html +508 -0
  58. package/package.json +15 -20
  59. package/src/__tests__/alphabeticalScripts.spec.ts +13 -5
  60. package/src/__tests__/bannedDependencies.spec.ts +47 -18
  61. package/src/__tests__/consistentDependencies.spec.ts +12 -6
  62. package/src/__tests__/consistentVersions.spec.ts +74 -20
  63. package/src/__tests__/fileContents.spec.ts +11 -7
  64. package/src/__tests__/mustSatisfyPeerDependencies.spec.ts +193 -78
  65. package/src/__tests__/nestedWorkspaces.spec.ts +12 -8
  66. package/src/__tests__/packageEntry.spec.ts +55 -49
  67. package/src/__tests__/packageOrder.spec.ts +78 -72
  68. package/src/__tests__/packageScript.spec.ts +27 -13
  69. package/src/__tests__/requireDependency.spec.ts +13 -7
  70. package/src/__tests__/utils.ts +18 -9
  71. package/src/bannedDependencies.ts +32 -15
  72. package/src/consistentDependencies.ts +22 -9
  73. package/src/consistentVersions.ts +84 -47
  74. package/src/fileContents.ts +24 -10
  75. package/src/index.ts +3 -3
  76. package/src/mustSatisfyPeerDependencies.ts +162 -66
  77. package/src/nestedWorkspaces.ts +23 -10
  78. package/src/packageEntry.ts +18 -11
  79. package/src/packageOrder.ts +9 -3
  80. package/src/packageScript.ts +37 -19
  81. package/src/requireDependency.ts +28 -11
  82. package/src/standardTsconfig.ts +32 -10
  83. package/src/util/checkAlpha.ts +5 -2
  84. package/src/util/createRuleFactory.ts +6 -2
  85. package/src/util/packageDependencyGraphService.ts +41 -14
  86. package/vitest.config.mjs +17 -0
  87. package/jest.config.cjs +0 -4
@@ -11,7 +11,10 @@ import { AggregateTiming } from "@monorepolint/utils";
11
11
  import * as path from "node:path";
12
12
  import * as r from "runtypes";
13
13
  import { createRuleFactory } from "./util/createRuleFactory.js";
14
- import { IPackageDependencyGraphNode, PackageDependencyGraphService } from "./util/packageDependencyGraphService.js";
14
+ import {
15
+ IPackageDependencyGraphNode,
16
+ PackageDependencyGraphService,
17
+ } from "./util/packageDependencyGraphService.js";
15
18
  // FIXME: This rule is messed. bannedTransitiveDependencies doesnt glob
16
19
 
17
20
  const bannedDepGlobsField = r.Union(
@@ -19,7 +22,7 @@ const bannedDepGlobsField = r.Union(
19
22
  r.Record({
20
23
  glob: r.Array(r.String).optional(),
21
24
  exact: r.Array(r.String).optional(),
22
- })
25
+ }),
23
26
  );
24
27
 
25
28
  const Options = r.Union(
@@ -27,16 +30,14 @@ const Options = r.Union(
27
30
  bannedDependencies: bannedDepGlobsField,
28
31
  bannedTransitiveDependencies: r.Undefined.optional(),
29
32
  }),
30
-
31
33
  r.Record({
32
34
  bannedDependencies: bannedDepGlobsField.optional(),
33
35
  bannedTransitiveDependencies: r.Array(r.String),
34
36
  }),
35
-
36
37
  r.Record({
37
38
  bannedDependencies: bannedDepGlobsField.optional(),
38
39
  bannedTransitiveDependencies: r.Array(r.String).optional(),
39
- })
40
+ }),
40
41
  );
41
42
 
42
43
  export type Options = r.Static<typeof Options>;
@@ -57,11 +58,17 @@ export const bannedDependencies = createRuleFactory<Options>({
57
58
  const packageJson = context.getPackageJson();
58
59
  const packagePath = context.getPackageJsonPath();
59
60
 
60
- const curDeps = packageJson.dependencies && Object.keys(packageJson.dependencies);
61
- const curDevDeps = packageJson.devDependencies && Object.keys(packageJson.devDependencies);
62
- const curPeerDeps = packageJson.peerDependencies && Object.keys(packageJson.peerDependencies);
61
+ const curDeps = packageJson.dependencies
62
+ && Object.keys(packageJson.dependencies);
63
+ const curDevDeps = packageJson.devDependencies
64
+ && Object.keys(packageJson.devDependencies);
65
+ const curPeerDeps = packageJson.peerDependencies
66
+ && Object.keys(packageJson.peerDependencies);
63
67
 
64
- const { bannedDependencies: banned, bannedTransitiveDependencies: transitives } = opts;
68
+ const {
69
+ bannedDependencies: banned,
70
+ bannedTransitiveDependencies: transitives,
71
+ } = opts;
65
72
 
66
73
  const globs = banned && (Array.isArray(banned) ? banned : banned.glob);
67
74
  const exacts = banned && (Array.isArray(banned) ? undefined : banned.exact);
@@ -89,8 +96,8 @@ export const bannedDependencies = createRuleFactory<Options>({
89
96
  context.addError({
90
97
  file: packagePath,
91
98
  message:
92
- `Found ${violations.size} banned dependencies of package.json:\n\t` +
93
- Array.from(violations)
99
+ `Found ${violations.size} banned dependencies of package.json:\n\t`
100
+ + Array.from(violations)
94
101
  .map((v) => `'${v}'`)
95
102
  .join(", "),
96
103
  });
@@ -113,7 +120,11 @@ export const bannedDependencies = createRuleFactory<Options>({
113
120
  },
114
121
  });
115
122
 
116
- function populateProblemsExact(banned: Set<string>, dependencies: ReadonlyArray<string>, violations: Set<string>) {
123
+ function populateProblemsExact(
124
+ banned: Set<string>,
125
+ dependencies: ReadonlyArray<string>,
126
+ violations: Set<string>,
127
+ ) {
117
128
  for (const dependency of dependencies) {
118
129
  if (banned.has(dependency)) {
119
130
  violations.add(dependency);
@@ -124,7 +135,7 @@ function populateProblemsExact(banned: Set<string>, dependencies: ReadonlyArray<
124
135
  function populateProblemsGlobs(
125
136
  bannedDependencyGlobs: ReadonlyArray<string>,
126
137
  dependencies: ReadonlyArray<string>,
127
- violations: Set<string>
138
+ violations: Set<string>,
128
139
  ) {
129
140
  for (const dependency of dependencies) {
130
141
  if (matchesAnyGlob(dependency, bannedDependencyGlobs)) {
@@ -136,13 +147,19 @@ function populateProblemsGlobs(
136
147
  // This function is slow. God help you if you use this on a big repo
137
148
  function checkTransitives(context: Context, banned: Set<string>) {
138
149
  const graphService = new PackageDependencyGraphService();
139
- const root = graphService.buildDependencyGraph(path.resolve(context.getPackageJsonPath()), context.host);
150
+ const root = graphService.buildDependencyGraph(
151
+ path.resolve(context.getPackageJsonPath()),
152
+ context.host,
153
+ );
140
154
  for (const { dependencies, importPath } of graphService.traverse(root)) {
141
155
  for (const [dependency] of dependencies) {
142
156
  if (banned.has(dependency)) {
143
157
  // Remove the starting package since it's obvious in CLI output.
144
158
  const [, ...importPathWithoutRoot] = importPath;
145
- const pathing = [...importPathWithoutRoot.map(nameOrPackageJsonPath), dependency].join(" -> ");
159
+ const pathing = [
160
+ ...importPathWithoutRoot.map(nameOrPackageJsonPath),
161
+ dependency,
162
+ ].join(" -> ");
146
163
 
147
164
  context.addError({
148
165
  file: root.paths.packageJsonPath,
@@ -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,10 +86,15 @@ 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
- const filtered = Object.entries(obj).filter(([key]) => !keysToOmit.includes(key));
95
+ const filtered = Object.entries(obj).filter(([key]) =>
96
+ !keysToOmit.includes(key)
97
+ );
85
98
  for (const [key, value] of filtered) {
86
99
  newObj[key] = value;
87
100
  }
@@ -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,48 +48,59 @@ 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
- input.dependencies![dependencyPackageName] = expectedPackageDependencyValue;
79
+ input.dependencies![dependencyPackageName] =
80
+ expectedPackageDependencyValue;
64
81
  return input;
65
82
  }),
66
83
  });
67
84
  }
68
85
 
69
- const actualPackageDevDependencyValue =
70
- packageJson.devDependencies && packageJson.devDependencies[dependencyPackageName];
71
- const actualPackageDevDependencyVersion = coerce(actualPackageDevDependencyValue);
86
+ const actualPackageDevDependencyValue = packageJson.devDependencies
87
+ && packageJson.devDependencies[dependencyPackageName];
88
+ const actualPackageDevDependencyVersion = coerce(
89
+ actualPackageDevDependencyValue,
90
+ );
72
91
  if (
73
- actualPackageDevDependencyVersion != null &&
74
- actualPackageDevDependencyVersion.raw !== expectedPackageDependencyVersion.raw
92
+ actualPackageDevDependencyVersion != null
93
+ && actualPackageDevDependencyVersion.raw
94
+ !== expectedPackageDependencyVersion.raw
75
95
  ) {
76
96
  context.addError({
77
97
  file: packageJsonPath,
78
- message: `Expected devDependency on ${dependencyPackageName} to match version defined in monorepolint configuration '${expectedPackageDependencyValue}', got '${actualPackageDevDependencyValue}' instead`,
98
+ message:
99
+ `Expected devDependency on ${dependencyPackageName} to match version defined in monorepolint configuration '${expectedPackageDependencyValue}', got '${actualPackageDevDependencyValue}' instead`,
79
100
  fixer: () =>
80
101
  mutateJson<PackageJson>(packageJsonPath, context.host, (input) => {
81
- input.devDependencies![dependencyPackageName] = expectedPackageDependencyValue;
102
+ input.devDependencies![dependencyPackageName] =
103
+ expectedPackageDependencyValue;
82
104
  return input;
83
105
  }),
84
106
  });
@@ -88,54 +110,69 @@ const ensurePackageIsCorrectVersion = (
88
110
  const ensurePackageMatchesSomeVersion = (
89
111
  context: Context,
90
112
  dependencyPackageName: string,
91
- acceptedPackageDependencyValues: string[]
113
+ acceptedPackageDependencyValues: string[],
92
114
  ) => {
93
115
  const packageJson = context.getPackageJson();
94
116
  const packageJsonPath = context.getPackageJsonPath();
95
117
 
96
- const acceptedPackageDependencyVersions: SemVer[] = acceptedPackageDependencyValues.map(
97
- (acceptedPackageDependencyValue) => {
98
- const acceptedPackageDependencyVersion = coerce(acceptedPackageDependencyValue);
99
- if (acceptedPackageDependencyVersion == null) {
100
- throw new Error(
101
- `Malformed accepted package dependency version defined in monorepolint configuration: ${dependencyPackageName} @ '${acceptedPackageDependencyValue}'`
118
+ const acceptedPackageDependencyVersions: SemVer[] =
119
+ acceptedPackageDependencyValues.map(
120
+ (acceptedPackageDependencyValue) => {
121
+ const acceptedPackageDependencyVersion = coerce(
122
+ acceptedPackageDependencyValue,
102
123
  );
103
- }
104
- return acceptedPackageDependencyVersion;
105
- }
106
- );
124
+ if (acceptedPackageDependencyVersion == null) {
125
+ throw new Error(
126
+ `Malformed accepted package dependency version defined in monorepolint configuration: ${dependencyPackageName} @ '${acceptedPackageDependencyValue}'`,
127
+ );
128
+ }
129
+ return acceptedPackageDependencyVersion;
130
+ },
131
+ );
107
132
 
108
- const actualPackageDependencyValue = packageJson.dependencies && packageJson.dependencies[dependencyPackageName];
133
+ const actualPackageDependencyValue = packageJson.dependencies
134
+ && packageJson.dependencies[dependencyPackageName];
109
135
  const actualPackageDependencyVersion = coerce(actualPackageDependencyValue);
110
136
  if (
111
- actualPackageDependencyVersion != null &&
112
- acceptedPackageDependencyVersions.every(
113
- (acceptedPackageDependencyVersion) => actualPackageDependencyVersion.raw !== acceptedPackageDependencyVersion.raw
137
+ actualPackageDependencyVersion != null
138
+ && acceptedPackageDependencyVersions.every(
139
+ (acceptedPackageDependencyVersion) =>
140
+ actualPackageDependencyVersion.raw
141
+ !== acceptedPackageDependencyVersion.raw,
114
142
  )
115
143
  ) {
116
144
  context.addError({
117
145
  file: packageJsonPath,
118
- message: `Expected dependency on ${dependencyPackageName} to match one of '${JSON.stringify(
119
- acceptedPackageDependencyValues
120
- )}', got '${actualPackageDependencyValue}' instead.`,
146
+ message:
147
+ `Expected dependency on ${dependencyPackageName} to match one of '${
148
+ JSON.stringify(
149
+ acceptedPackageDependencyValues,
150
+ )
151
+ }', got '${actualPackageDependencyValue}' instead.`,
121
152
  });
122
153
  }
123
154
 
124
- const actualPackageDevDependencyValue =
125
- packageJson.devDependencies && packageJson.devDependencies[dependencyPackageName];
126
- const actualPackageDevDependencyVersion = coerce(actualPackageDevDependencyValue);
155
+ const actualPackageDevDependencyValue = packageJson.devDependencies
156
+ && packageJson.devDependencies[dependencyPackageName];
157
+ const actualPackageDevDependencyVersion = coerce(
158
+ actualPackageDevDependencyValue,
159
+ );
127
160
  if (
128
- actualPackageDevDependencyVersion != null &&
129
- acceptedPackageDependencyVersions.every(
161
+ actualPackageDevDependencyVersion != null
162
+ && acceptedPackageDependencyVersions.every(
130
163
  (acceptedPackageDependencyVersion) =>
131
- actualPackageDevDependencyVersion.raw !== acceptedPackageDependencyVersion.raw
164
+ actualPackageDevDependencyVersion.raw
165
+ !== acceptedPackageDependencyVersion.raw,
132
166
  )
133
167
  ) {
134
168
  context.addError({
135
169
  file: packageJsonPath,
136
- message: `Expected devDependency on ${dependencyPackageName} to match one of '${JSON.stringify(
137
- acceptedPackageDependencyValues
138
- )}', got '${actualPackageDevDependencyValue}' instead.`,
170
+ message:
171
+ `Expected devDependency on ${dependencyPackageName} to match one of '${
172
+ JSON.stringify(
173
+ acceptedPackageDependencyValues,
174
+ )
175
+ }', got '${actualPackageDevDependencyValue}' instead.`,
139
176
  });
140
177
  }
141
178
  };
@@ -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
- template: r.String,
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,18 +42,30 @@ 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) {
49
+ const longMessage = pathExists && expectedContent == undefined
50
+ ? undefined
51
+ : diff(expectedContent, actualContent, { expand: true });
52
+
53
+ const message = pathExists && expectedContent == undefined
54
+ ? "File should not exist"
55
+ : "Expect file contents to match";
56
+
47
57
  context.addError({
48
58
  file: fullPath,
49
- message: "Expect file contents to match",
50
- longMessage: diff(expectedContent, actualContent, { expand: true }),
59
+ message,
60
+ longMessage,
51
61
  fixer: () => {
52
62
  if (expectedContent === undefined) {
53
63
  if (pathExists) context.host.deleteFile(fullPath);
54
64
  } else {
55
65
  context.host.mkdir(path.dirname(fullPath), { recursive: true });
56
- context.host.writeFile(fullPath, expectedContent, { encoding: "utf-8" });
66
+ context.host.writeFile(fullPath, expectedContent, {
67
+ encoding: "utf-8",
68
+ });
57
69
  }
58
70
  },
59
71
  });
@@ -64,7 +76,9 @@ export const fileContents = createRuleFactory<Options>({
64
76
 
65
77
  const optionsCache = new Map<
66
78
  Options,
67
- ((context: Context) => Promise<string> | string | undefined) | string | undefined
79
+ | ((context: Context) => Promise<string> | string | undefined)
80
+ | string
81
+ | undefined
68
82
  >();
69
83
 
70
84
  async function getExpectedContents(context: Context, opts: Options) {
package/src/index.ts CHANGED
@@ -12,12 +12,12 @@ export { consistentDependencies } from "./consistentDependencies.js";
12
12
  export { consistentVersions } from "./consistentVersions.js";
13
13
  export { fileContents } from "./fileContents.js";
14
14
  export { mustSatisfyPeerDependencies } from "./mustSatisfyPeerDependencies.js";
15
- export { packageOrder } from "./packageOrder.js";
15
+ export { nestedWorkspaces } from "./nestedWorkspaces.js";
16
16
  export { packageEntry } from "./packageEntry.js";
17
+ export { packageOrder } from "./packageOrder.js";
17
18
  export { packageScript } from "./packageScript.js";
18
- export { standardTsconfig } from "./standardTsconfig.js";
19
- export { nestedWorkspaces } from "./nestedWorkspaces.js";
20
19
  export { requireDependency } from "./requireDependency.js";
20
+ export { standardTsconfig } from "./standardTsconfig.js";
21
21
 
22
22
  export {
23
23
  createRuleFactory,