@monorepolint/rules 0.6.0-alpha.2 → 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 (77) 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 +160 -100
  5. package/.turbo/turbo-transpile-typescript.log +4 -4
  6. package/CHANGELOG.md +9 -0
  7. package/build/js/index.js +399 -246
  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/index.d.ts +3 -3
  15. package/build/types/index.d.ts.map +1 -1
  16. package/build/types/mustSatisfyPeerDependencies.d.ts.map +1 -1
  17. package/build/types/nestedWorkspaces.d.ts.map +1 -1
  18. package/build/types/packageEntry.d.ts.map +1 -1
  19. package/build/types/packageOrder.d.ts.map +1 -1
  20. package/build/types/packageScript.d.ts.map +1 -1
  21. package/build/types/requireDependency.d.ts +12 -12
  22. package/build/types/requireDependency.d.ts.map +1 -1
  23. package/build/types/util/checkAlpha.d.ts.map +1 -1
  24. package/build/types/util/createRuleFactory.d.ts.map +1 -1
  25. package/build/types/util/packageDependencyGraphService.d.ts.map +1 -1
  26. package/coverage/clover.xml +1159 -818
  27. package/coverage/coverage-final.json +18 -18
  28. package/coverage/index.html +20 -20
  29. package/coverage/src/alphabeticalDependencies.ts.html +8 -8
  30. package/coverage/src/alphabeticalScripts.ts.html +5 -5
  31. package/coverage/src/bannedDependencies.ts.html +77 -26
  32. package/coverage/src/consistentDependencies.ts.html +58 -19
  33. package/coverage/src/consistentVersions.ts.html +169 -58
  34. package/coverage/src/fileContents.ts.html +47 -23
  35. package/coverage/src/index.html +67 -67
  36. package/coverage/src/index.ts.html +32 -32
  37. package/coverage/src/mustSatisfyPeerDependencies.ts.html +373 -85
  38. package/coverage/src/nestedWorkspaces.ts.html +59 -20
  39. package/coverage/src/packageEntry.ts.html +40 -19
  40. package/coverage/src/packageOrder.ts.html +30 -12
  41. package/coverage/src/packageScript.ts.html +81 -27
  42. package/coverage/src/requireDependency.ts.html +83 -32
  43. package/coverage/src/standardTsconfig.ts.html +81 -18
  44. package/coverage/src/util/checkAlpha.ts.html +18 -9
  45. package/coverage/src/util/createRuleFactory.ts.html +16 -4
  46. package/coverage/src/util/index.html +17 -17
  47. package/coverage/src/util/makeDirectory.ts.html +5 -5
  48. package/coverage/src/util/packageDependencyGraphService.ts.html +101 -20
  49. package/package.json +4 -5
  50. package/src/__tests__/alphabeticalScripts.spec.ts +12 -4
  51. package/src/__tests__/bannedDependencies.spec.ts +45 -16
  52. package/src/__tests__/consistentDependencies.spec.ts +11 -5
  53. package/src/__tests__/consistentVersions.spec.ts +72 -18
  54. package/src/__tests__/fileContents.spec.ts +9 -5
  55. package/src/__tests__/mustSatisfyPeerDependencies.spec.ts +191 -76
  56. package/src/__tests__/nestedWorkspaces.spec.ts +10 -6
  57. package/src/__tests__/packageEntry.spec.ts +54 -48
  58. package/src/__tests__/packageOrder.spec.ts +77 -71
  59. package/src/__tests__/packageScript.spec.ts +25 -11
  60. package/src/__tests__/requireDependency.spec.ts +12 -6
  61. package/src/__tests__/utils.ts +16 -7
  62. package/src/bannedDependencies.ts +32 -15
  63. package/src/consistentDependencies.ts +22 -9
  64. package/src/consistentVersions.ts +84 -47
  65. package/src/fileContents.ts +19 -11
  66. package/src/index.ts +3 -3
  67. package/src/mustSatisfyPeerDependencies.ts +162 -66
  68. package/src/nestedWorkspaces.ts +23 -10
  69. package/src/packageEntry.ts +18 -11
  70. package/src/packageOrder.ts +9 -3
  71. package/src/packageScript.ts +37 -19
  72. package/src/requireDependency.ts +28 -11
  73. package/src/standardTsconfig.ts +31 -10
  74. package/src/util/checkAlpha.ts +5 -2
  75. package/src/util/createRuleFactory.ts +6 -2
  76. package/src/util/packageDependencyGraphService.ts +41 -14
  77. package/vitest.config.mjs +10 -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,11 @@ 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]) =>
48
+ v !== undefined
49
+ ),
50
+ ) as Record<string, string>;
46
51
  return input;
47
52
  });
48
53
  },
@@ -55,12 +60,24 @@ export const requireDependency = createRuleFactory({
55
60
  context.addError({
56
61
  file: packageJsonPath,
57
62
  message: `Expected dependency ${dep}@${version}`,
58
- longMessage: diff(`${dep}@${version}\n`, `${dep}@${packageJson[type]![dep] || "missing"}\n`)!,
63
+ longMessage: diff(
64
+ `${dep}@${version}\n`,
65
+ `${dep}@${packageJson[type]![dep] || "missing"}\n`,
66
+ )!,
59
67
  fixer: () => {
60
- mutateJson<PackageJson>(packageJsonPath, context.host, (input) => {
61
- input[type] = { ...input[type], [dep]: version };
62
- return input;
63
- });
68
+ mutateJson<PackageJson>(
69
+ packageJsonPath,
70
+ context.host,
71
+ (input) => {
72
+ if (version === undefined) {
73
+ input[type] = { ...input[type] };
74
+ delete input[type][dep];
75
+ } else {
76
+ input[type] = { ...input[type], [dep]: version };
77
+ }
78
+ return input;
79
+ },
80
+ );
64
81
  },
65
82
  });
66
83
  }
@@ -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,20 +31,27 @@ 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. */
35
- export class PackageDependencyGraphService implements IPackageDependencyGraphService {
41
+ export class PackageDependencyGraphService
42
+ implements IPackageDependencyGraphService
43
+ {
36
44
  /** Construct a graph of package dependencies and return the root node. */
37
45
  public buildDependencyGraph(
38
46
  startPackageJsonPath: string,
39
47
  host: Host,
40
- maxDepth?: number
48
+ maxDepth?: number,
41
49
  ): IPackageDependencyGraphNode {
42
50
  const nodes = new Map<string, IPackageDependencyGraphNode>();
43
- const visit = (packageJsonPath: string, currentDepth: number): IPackageDependencyGraphNode => {
51
+ const visit = (
52
+ packageJsonPath: string,
53
+ currentDepth: number,
54
+ ): IPackageDependencyGraphNode => {
44
55
  if (nodes.has(packageJsonPath)) {
45
56
  return nodes.get(packageJsonPath)!;
46
57
  }
@@ -60,14 +71,24 @@ export class PackageDependencyGraphService implements IPackageDependencyGraphSer
60
71
 
61
72
  const nextDepth = currentDepth + 1;
62
73
  if (maxDepth == null || nextDepth <= maxDepth) {
63
- const dependencies = packageJson.dependencies != null ? Object.keys(packageJson.dependencies) : [];
74
+ const dependencies = packageJson.dependencies != null
75
+ ? Object.keys(packageJson.dependencies)
76
+ : [];
64
77
  for (const dependency of dependencies) {
65
- const dependencyPackageJsonPath = resolvePackagePath(dependency, node.paths.rootDirectory);
78
+ const dependencyPackageJsonPath = resolvePackagePath(
79
+ dependency,
80
+ node.paths.rootDirectory,
81
+ );
66
82
  if (dependencyPackageJsonPath == null) {
67
- throw new Error(`Could not resolve ${dependency} from ${node.paths.rootDirectory}`);
83
+ throw new Error(
84
+ `Could not resolve ${dependency} from ${node.paths.rootDirectory}`,
85
+ );
68
86
  }
69
87
 
70
- node.dependencies.set(dependency, visit(dependencyPackageJsonPath, nextDepth));
88
+ node.dependencies.set(
89
+ dependency,
90
+ visit(dependencyPackageJsonPath, nextDepth),
91
+ );
71
92
  }
72
93
  }
73
94
 
@@ -80,14 +101,20 @@ export class PackageDependencyGraphService implements IPackageDependencyGraphSer
80
101
  /** Traverse a package dependency graph with an iterator. */
81
102
  public *traverse(
82
103
  root: IPackageDependencyGraphNode,
83
- opts = { traverseAllPaths: false }
84
- ): IterableIterator<IPackageDependencyGraphNode & { importPath: IPackageDependencyGraphNode[] }> {
104
+ opts = { traverseAllPaths: false },
105
+ ): IterableIterator<
106
+ IPackageDependencyGraphNode & { importPath: IPackageDependencyGraphNode[] }
107
+ > {
85
108
  const visited = new Set<IPackageDependencyGraphNode>();
86
109
 
87
110
  function* visit(
88
111
  node: IPackageDependencyGraphNode,
89
- importPath: IPackageDependencyGraphNode[] = []
90
- ): IterableIterator<IPackageDependencyGraphNode & { importPath: IPackageDependencyGraphNode[] }> {
112
+ importPath: IPackageDependencyGraphNode[] = [],
113
+ ): IterableIterator<
114
+ IPackageDependencyGraphNode & {
115
+ importPath: IPackageDependencyGraphNode[];
116
+ }
117
+ > {
91
118
  // Don't visit a package more than once unless explicitly asked to traverse all paths
92
119
  if (!opts.traverseAllPaths && visited.has(node)) {
93
120
  return;
package/vitest.config.mjs CHANGED
@@ -1,14 +1,17 @@
1
-
2
- import { coverageConfigDefaults, defineProject, defaultExclude } from 'vitest/config'
1
+ import {
2
+ coverageConfigDefaults,
3
+ defaultExclude,
4
+ defineProject,
5
+ } from "vitest/config";
3
6
 
4
7
  export default defineProject({
5
8
  test: {
6
- exclude: [...defaultExclude, "**/build/**"],
9
+ exclude: [...defaultExclude, "**/build/**"],
7
10
  coverage: {
8
11
  provider: "v8",
9
12
  enabled: true,
10
- exclude: [...coverageConfigDefaults.exclude, "vitest.config.*"]
11
- }
13
+ pool: "forks",
14
+ exclude: [...coverageConfigDefaults.exclude, "vitest.config.*"],
15
+ },
12
16
  },
13
- })
14
-
17
+ });