@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
@@ -17,8 +17,8 @@ export const Options = r.Record({
17
17
  r.Record({
18
18
  options: r.Array(r.String.Or(r.Undefined)),
19
19
  fixValue: r.Union(r.String, r.Undefined, r.Literal(false)).optional(),
20
- })
21
- )
20
+ }),
21
+ ),
22
22
  ), // string => string
23
23
  });
24
24
 
@@ -35,10 +35,14 @@ export const packageScript = createRuleFactory<Options>({
35
35
  file: context.getPackageJsonPath(),
36
36
  message: MSG_NO_SCRIPTS_BLOCK,
37
37
  fixer: () => {
38
- mutateJson<PackageJson>(context.getPackageJsonPath(), context.host, (input) => {
39
- input.scripts = {};
40
- return input;
41
- });
38
+ mutateJson<PackageJson>(
39
+ context.getPackageJsonPath(),
40
+ context.host,
41
+ (input) => {
42
+ input.scripts = {};
43
+ return input;
44
+ },
45
+ );
42
46
  },
43
47
  });
44
48
  return;
@@ -59,26 +63,36 @@ export const packageScript = createRuleFactory<Options>({
59
63
  }
60
64
  allowedValues.add(q);
61
65
  }
62
- fixToEmpty = Object.prototype.hasOwnProperty.call(value, "fixValue") && value.fixValue === undefined;
66
+ fixToEmpty = Object.prototype.hasOwnProperty.call(value, "fixValue")
67
+ && value.fixValue === undefined;
63
68
  fixValue = value.fixValue;
64
69
  }
65
70
 
66
71
  const actualValue = packageJson.scripts[name];
67
72
 
68
- if (!allowedValues.has(actualValue) && !(allowEmpty === true && actualValue === undefined)) {
73
+ if (
74
+ !allowedValues.has(actualValue)
75
+ && !(allowEmpty === true && actualValue === undefined)
76
+ ) {
69
77
  let fixer;
70
78
 
71
- if (fixValue !== false && (fixValue !== undefined || fixToEmpty === true)) {
79
+ if (
80
+ fixValue !== false && (fixValue !== undefined || fixToEmpty === true)
81
+ ) {
72
82
  const q = fixValue;
73
83
  fixer = () => {
74
- mutateJson<PackageJson>(context.getPackageJsonPath(), context.host, (input) => {
75
- if (fixToEmpty && q === undefined) {
76
- delete input.scripts![name];
77
- } else {
78
- input.scripts![name] = q!;
79
- }
80
- return input;
81
- });
84
+ mutateJson<PackageJson>(
85
+ context.getPackageJsonPath(),
86
+ context.host,
87
+ (input) => {
88
+ if (fixToEmpty && q === undefined) {
89
+ delete input.scripts![name];
90
+ } else {
91
+ input.scripts![name] = q!;
92
+ }
93
+ return input;
94
+ },
95
+ );
82
96
  };
83
97
  }
84
98
 
@@ -88,8 +102,12 @@ export const packageScript = createRuleFactory<Options>({
88
102
 
89
103
  context.addError({
90
104
  file: context.getPackageJsonPath(),
91
- message: `Expected standardized script entry for '${name}'. Valid options: ${validOptionsString}`,
92
- longMessage: diff(validOptionsString + "\n", (packageJson.scripts[name] || "") + "\n"),
105
+ message:
106
+ `Expected standardized script entry for '${name}'. Valid options: ${validOptionsString}`,
107
+ longMessage: diff(
108
+ validOptionsString + "\n",
109
+ (packageJson.scripts[name] || "") + "\n",
110
+ ),
93
111
  fixer,
94
112
  });
95
113
  }
@@ -12,10 +12,10 @@ import * as r from "runtypes";
12
12
  import { createRuleFactory } from "./util/createRuleFactory.js";
13
13
 
14
14
  const Options = r.Partial({
15
- dependencies: r.Dictionary(r.String),
16
- devDependencies: r.Dictionary(r.String),
17
- peerDependencies: r.Dictionary(r.String),
18
- optionalDependencies: r.Dictionary(r.String),
15
+ dependencies: r.Dictionary(r.String.optional()),
16
+ devDependencies: r.Dictionary(r.String.optional()),
17
+ peerDependencies: r.Dictionary(r.String.optional()),
18
+ optionalDependencies: r.Dictionary(r.String.optional()),
19
19
  });
20
20
 
21
21
  type Options = r.Static<typeof Options>;
@@ -32,7 +32,8 @@ export const requireDependency = createRuleFactory({
32
32
  "peerDependencies" as const,
33
33
  "optionalDependencies" as const,
34
34
  ].forEach((type) => {
35
- if (!options[type]) {
35
+ const expectedEntries = options[type];
36
+ if (!expectedEntries) {
36
37
  return;
37
38
  }
38
39
 
@@ -42,7 +43,9 @@ export const requireDependency = createRuleFactory({
42
43
  message: `No ${type} block, cannot add required ${type}.`,
43
44
  fixer: () => {
44
45
  mutateJson<PackageJson>(packageJsonPath, context.host, (input) => {
45
- input[type] = options[type];
46
+ input[type] = Object.fromEntries(
47
+ Object.entries(expectedEntries).filter(([, v]) => v !== undefined),
48
+ ) as Record<string, string>;
46
49
  return input;
47
50
  });
48
51
  },
@@ -55,12 +58,24 @@ export const requireDependency = createRuleFactory({
55
58
  context.addError({
56
59
  file: packageJsonPath,
57
60
  message: `Expected dependency ${dep}@${version}`,
58
- longMessage: diff(`${dep}@${version}\n`, `${dep}@${packageJson[type]![dep] || "missing"}\n`)!,
61
+ longMessage: diff(
62
+ `${dep}@${version}\n`,
63
+ `${dep}@${packageJson[type]![dep] || "missing"}\n`,
64
+ )!,
59
65
  fixer: () => {
60
- mutateJson<PackageJson>(packageJsonPath, context.host, (input) => {
61
- input[type] = { ...input[type], [dep]: version };
62
- return input;
63
- });
66
+ mutateJson<PackageJson>(
67
+ packageJsonPath,
68
+ context.host,
69
+ (input) => {
70
+ if (version === undefined) {
71
+ input[type] = { ...input[type] };
72
+ delete input[type][dep];
73
+ } else {
74
+ input[type] = { ...input[type], [dep]: version };
75
+ }
76
+ return input;
77
+ },
78
+ );
64
79
  },
65
80
  });
66
81
  }
@@ -84,11 +84,23 @@ function getGenerator(context: Context, opts: Options) {
84
84
  } else if (opts.templateFile) {
85
85
  const { packageDir: workspacePackageDir } = context.getWorkspaceContext();
86
86
  const fullPath = path.resolve(workspacePackageDir, opts.templateFile);
87
- const template = JSON.parse(context.host.readFile(fullPath, { encoding: "utf-8" }));
88
-
89
- return makeGenerator(template, opts.excludedReferences, opts.additionalReferences, opts.tsconfigReferenceFile);
87
+ const template = JSON.parse(
88
+ context.host.readFile(fullPath, { encoding: "utf-8" }),
89
+ );
90
+
91
+ return makeGenerator(
92
+ template,
93
+ opts.excludedReferences,
94
+ opts.additionalReferences,
95
+ opts.tsconfigReferenceFile,
96
+ );
90
97
  } else if (opts.template) {
91
- return makeGenerator(opts.template, opts.excludedReferences, opts.additionalReferences, opts.tsconfigReferenceFile);
98
+ return makeGenerator(
99
+ opts.template,
100
+ opts.excludedReferences,
101
+ opts.additionalReferences,
102
+ opts.tsconfigReferenceFile,
103
+ );
92
104
  } else {
93
105
  throw new Error("Unable to make generator");
94
106
  }
@@ -99,7 +111,7 @@ function makeGenerator(
99
111
  template: any,
100
112
  excludedReferences: ReadonlyArray<string> | undefined,
101
113
  additionalReferences: ReadonlyArray<string> | undefined,
102
- tsconfigReferenceFile?: string
114
+ tsconfigReferenceFile?: string,
103
115
  ) {
104
116
  return async function generator(context: Context) {
105
117
  template = {
@@ -107,15 +119,24 @@ function makeGenerator(
107
119
  references: [],
108
120
  }; // make a copy and ensure we have a references array
109
121
 
110
- const nameToDirectory = await context.getWorkspaceContext().getPackageNameToDir();
122
+ const nameToDirectory = await context.getWorkspaceContext()
123
+ .getPackageNameToDir();
111
124
 
112
125
  const packageJson = context.getPackageJson();
113
- const deps = [...Object.keys(packageJson.dependencies || {}), ...Object.keys(packageJson.devDependencies || {})];
126
+ const deps = [
127
+ ...Object.keys(packageJson.dependencies || {}),
128
+ ...Object.keys(packageJson.devDependencies || {}),
129
+ ];
114
130
  for (const dep of deps) {
115
131
  const packageDir = nameToDirectory.get(dep);
116
- if (packageDir !== undefined && (excludedReferences === undefined || !matchesAnyGlob(dep, excludedReferences))) {
117
- const absoluteReferencePath =
118
- tsconfigReferenceFile !== undefined ? path.join(packageDir, tsconfigReferenceFile) : packageDir;
132
+ if (
133
+ packageDir !== undefined
134
+ && (excludedReferences === undefined
135
+ || !matchesAnyGlob(dep, excludedReferences))
136
+ ) {
137
+ const absoluteReferencePath = tsconfigReferenceFile !== undefined
138
+ ? path.join(packageDir, tsconfigReferenceFile)
139
+ : packageDir;
119
140
  template.references.push({
120
141
  path: path.relative(context.packageDir, absoluteReferencePath),
121
142
  });
@@ -10,7 +10,7 @@ import { diff } from "jest-diff";
10
10
 
11
11
  export function checkAlpha(
12
12
  context: Context,
13
- block: "dependencies" | "devDependencies" | "peerDependencies" | "scripts"
13
+ block: "dependencies" | "devDependencies" | "peerDependencies" | "scripts",
14
14
  ) {
15
15
  const packageJson = context.getPackageJson();
16
16
  const packagePath = context.getPackageJsonPath();
@@ -54,6 +54,9 @@ function arrayOrderCompare(a: ReadonlyArray<string>, b: ReadonlyArray<string>) {
54
54
  return true;
55
55
  }
56
56
 
57
- export function createIncorrectOrderErrorMessage(block: string, packageName: string) {
57
+ export function createIncorrectOrderErrorMessage(
58
+ block: string,
59
+ packageName: string,
60
+ ) {
58
61
  return `Incorrect order of ${block} in ${packageName}'s package.json`;
59
62
  }
@@ -2,7 +2,11 @@ import { Context, RuleEntry, RuleModule } from "@monorepolint/config";
2
2
 
3
3
  export type ValidateOptionsFn<X> = (options: unknown) => asserts options is X;
4
4
  export type RuleFactoryFn<T> = (ruleEntry: RuleEntry<T>) => RuleModule<T>;
5
- export type RuleCheckFn<O> = (context: Context, options: O, extra: { id: string }) => Promise<unknown> | unknown;
5
+ export type RuleCheckFn<O> = (
6
+ context: Context,
7
+ options: O,
8
+ extra: { id: string },
9
+ ) => Promise<unknown> | unknown;
6
10
 
7
11
  export interface RuleFactoryOptions<X> {
8
12
  name: string;
@@ -18,7 +22,7 @@ export function createRuleFactory<X>({
18
22
  validateOptions,
19
23
  printStats,
20
24
  }: RuleFactoryOptions<X>): RuleFactoryFn<X> {
21
- return function (ruleEntry) {
25
+ return function(ruleEntry) {
22
26
  const id = ruleEntry.id ?? `${name} :: ${globalId++}`;
23
27
  return {
24
28
  id,
@@ -19,7 +19,11 @@ export interface IPackageDependencyGraphNode {
19
19
  /** Service abstraction for constructing and traversing package dependency graphs. */
20
20
  export interface IPackageDependencyGraphService {
21
21
  /** Construct a graph of package dependencies. */
22
- buildDependencyGraph(packageJsonPath: string, host: Host, maxDepth?: number): IPackageDependencyGraphNode;
22
+ buildDependencyGraph(
23
+ packageJsonPath: string,
24
+ host: Host,
25
+ maxDepth?: number,
26
+ ): IPackageDependencyGraphNode;
23
27
 
24
28
  /** Traverse a package dependency graph. */
25
29
  traverse(
@@ -27,8 +31,10 @@ export interface IPackageDependencyGraphService {
27
31
  opts?: {
28
32
  /** Traverse each unique path to a given package (potentially slow). */
29
33
  traverseAllPaths?: boolean;
30
- }
31
- ): IterableIterator<IPackageDependencyGraphNode & { importPath: IPackageDependencyGraphNode[] }>;
34
+ },
35
+ ): IterableIterator<
36
+ IPackageDependencyGraphNode & { importPath: IPackageDependencyGraphNode[] }
37
+ >;
32
38
  }
33
39
 
34
40
  /** Default implementation of the package dependency graph service. */
@@ -37,10 +43,13 @@ export class PackageDependencyGraphService implements IPackageDependencyGraphSer
37
43
  public buildDependencyGraph(
38
44
  startPackageJsonPath: string,
39
45
  host: Host,
40
- maxDepth?: number
46
+ maxDepth?: number,
41
47
  ): IPackageDependencyGraphNode {
42
48
  const nodes = new Map<string, IPackageDependencyGraphNode>();
43
- const visit = (packageJsonPath: string, currentDepth: number): IPackageDependencyGraphNode => {
49
+ const visit = (
50
+ packageJsonPath: string,
51
+ currentDepth: number,
52
+ ): IPackageDependencyGraphNode => {
44
53
  if (nodes.has(packageJsonPath)) {
45
54
  return nodes.get(packageJsonPath)!;
46
55
  }
@@ -60,14 +69,24 @@ export class PackageDependencyGraphService implements IPackageDependencyGraphSer
60
69
 
61
70
  const nextDepth = currentDepth + 1;
62
71
  if (maxDepth == null || nextDepth <= maxDepth) {
63
- const dependencies = packageJson.dependencies != null ? Object.keys(packageJson.dependencies) : [];
72
+ const dependencies = packageJson.dependencies != null
73
+ ? Object.keys(packageJson.dependencies)
74
+ : [];
64
75
  for (const dependency of dependencies) {
65
- const dependencyPackageJsonPath = resolvePackagePath(dependency, node.paths.rootDirectory);
76
+ const dependencyPackageJsonPath = resolvePackagePath(
77
+ dependency,
78
+ node.paths.rootDirectory,
79
+ );
66
80
  if (dependencyPackageJsonPath == null) {
67
- throw new Error(`Could not resolve ${dependency} from ${node.paths.rootDirectory}`);
81
+ throw new Error(
82
+ `Could not resolve ${dependency} from ${node.paths.rootDirectory}`,
83
+ );
68
84
  }
69
85
 
70
- node.dependencies.set(dependency, visit(dependencyPackageJsonPath, nextDepth));
86
+ node.dependencies.set(
87
+ dependency,
88
+ visit(dependencyPackageJsonPath, nextDepth),
89
+ );
71
90
  }
72
91
  }
73
92
 
@@ -80,14 +99,20 @@ export class PackageDependencyGraphService implements IPackageDependencyGraphSer
80
99
  /** Traverse a package dependency graph with an iterator. */
81
100
  public *traverse(
82
101
  root: IPackageDependencyGraphNode,
83
- opts = { traverseAllPaths: false }
84
- ): IterableIterator<IPackageDependencyGraphNode & { importPath: IPackageDependencyGraphNode[] }> {
102
+ opts = { traverseAllPaths: false },
103
+ ): IterableIterator<
104
+ IPackageDependencyGraphNode & { importPath: IPackageDependencyGraphNode[] }
105
+ > {
85
106
  const visited = new Set<IPackageDependencyGraphNode>();
86
107
 
87
108
  function* visit(
88
109
  node: IPackageDependencyGraphNode,
89
- importPath: IPackageDependencyGraphNode[] = []
90
- ): IterableIterator<IPackageDependencyGraphNode & { importPath: IPackageDependencyGraphNode[] }> {
110
+ importPath: IPackageDependencyGraphNode[] = [],
111
+ ): IterableIterator<
112
+ IPackageDependencyGraphNode & {
113
+ importPath: IPackageDependencyGraphNode[];
114
+ }
115
+ > {
91
116
  // Don't visit a package more than once unless explicitly asked to traverse all paths
92
117
  if (!opts.traverseAllPaths && visited.has(node)) {
93
118
  return;
package/vitest.config.mjs CHANGED
@@ -1,14 +1,13 @@
1
-
2
- import { coverageConfigDefaults, defineProject, defaultExclude } from 'vitest/config'
1
+ import { coverageConfigDefaults, defaultExclude, defineProject } from "vitest/config";
3
2
 
4
3
  export default defineProject({
5
4
  test: {
6
- exclude: [...defaultExclude, "**/build/**"],
5
+ exclude: [...defaultExclude, "**/build/**"],
7
6
  coverage: {
8
7
  provider: "v8",
9
8
  enabled: true,
10
- exclude: [...coverageConfigDefaults.exclude, "vitest.config.*"]
11
- }
9
+ pool: "forks",
10
+ exclude: [...coverageConfigDefaults.exclude, "vitest.config.*"],
11
+ },
12
12
  },
13
- })
14
-
13
+ });