repopo 0.5.0 → 0.7.0

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 (96) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/README.md +3 -5
  3. package/THIRD-PARTY-LICENSES.txt +6 -6
  4. package/esm/baseCommand.d.ts.map +1 -1
  5. package/esm/baseCommand.js +7 -9
  6. package/esm/baseCommand.js.map +1 -1
  7. package/esm/commands/check.d.ts +17 -6
  8. package/esm/commands/check.d.ts.map +1 -1
  9. package/esm/commands/check.js +162 -110
  10. package/esm/commands/check.js.map +1 -1
  11. package/esm/commands/list.d.ts.map +1 -1
  12. package/esm/commands/list.js +0 -1
  13. package/esm/commands/list.js.map +1 -1
  14. package/esm/config.d.ts +4 -15
  15. package/esm/config.d.ts.map +1 -1
  16. package/esm/config.js +3 -2
  17. package/esm/config.js.map +1 -1
  18. package/esm/context.d.ts +3 -3
  19. package/esm/context.d.ts.map +1 -1
  20. package/esm/context.js.map +1 -1
  21. package/esm/generators.d.ts +21 -0
  22. package/esm/generators.d.ts.map +1 -0
  23. package/esm/generators.js +2 -0
  24. package/esm/generators.js.map +1 -0
  25. package/esm/index.d.ts +5 -11
  26. package/esm/index.d.ts.map +1 -1
  27. package/esm/index.js +3 -9
  28. package/esm/index.js.map +1 -1
  29. package/esm/makePolicy.d.ts +9 -0
  30. package/esm/makePolicy.d.ts.map +1 -0
  31. package/esm/makePolicy.js +28 -0
  32. package/esm/makePolicy.js.map +1 -0
  33. package/esm/policies/HtmlFileHeaders.d.ts +2 -2
  34. package/esm/policies/HtmlFileHeaders.d.ts.map +1 -1
  35. package/esm/policies/HtmlFileHeaders.js +2 -2
  36. package/esm/policies/HtmlFileHeaders.js.map +1 -1
  37. package/esm/policies/JsTsFileHeaders.d.ts +2 -2
  38. package/esm/policies/JsTsFileHeaders.d.ts.map +1 -1
  39. package/esm/policies/JsTsFileHeaders.js +2 -2
  40. package/esm/policies/JsTsFileHeaders.js.map +1 -1
  41. package/esm/policies/LicenseFileExists.d.ts +20 -0
  42. package/esm/policies/LicenseFileExists.d.ts.map +1 -0
  43. package/esm/policies/LicenseFileExists.js +40 -0
  44. package/esm/policies/LicenseFileExists.js.map +1 -0
  45. package/esm/policies/NoJsFileExtensions.d.ts +2 -2
  46. package/esm/policies/NoJsFileExtensions.d.ts.map +1 -1
  47. package/esm/policies/NoJsFileExtensions.js +11 -15
  48. package/esm/policies/NoJsFileExtensions.js.map +1 -1
  49. package/esm/policies/NoLargeBinaryFiles.d.ts +30 -0
  50. package/esm/policies/NoLargeBinaryFiles.d.ts.map +1 -0
  51. package/esm/policies/NoLargeBinaryFiles.js +118 -0
  52. package/esm/policies/NoLargeBinaryFiles.js.map +1 -0
  53. package/esm/policies/PackageJsonProperties.d.ts +1 -1
  54. package/esm/policies/PackageJsonProperties.d.ts.map +1 -1
  55. package/esm/policies/PackageJsonProperties.js +3 -3
  56. package/esm/policies/PackageJsonProperties.js.map +1 -1
  57. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts +1 -1
  58. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts.map +1 -1
  59. package/esm/policies/PackageJsonRepoDirectoryProperty.js +24 -25
  60. package/esm/policies/PackageJsonRepoDirectoryProperty.js.map +1 -1
  61. package/esm/policies/PackageJsonSorted.d.ts +1 -1
  62. package/esm/policies/PackageJsonSorted.d.ts.map +1 -1
  63. package/esm/policies/PackageJsonSorted.js +3 -2
  64. package/esm/policies/PackageJsonSorted.js.map +1 -1
  65. package/esm/policies/PackageScripts.d.ts +25 -2
  66. package/esm/policies/PackageScripts.d.ts.map +1 -1
  67. package/esm/policies/PackageScripts.js +47 -10
  68. package/esm/policies/PackageScripts.js.map +1 -1
  69. package/esm/policies/RequiredGitignorePatterns.d.ts +24 -0
  70. package/esm/policies/RequiredGitignorePatterns.d.ts.map +1 -0
  71. package/esm/policies/RequiredGitignorePatterns.js +166 -0
  72. package/esm/policies/RequiredGitignorePatterns.js.map +1 -0
  73. package/esm/policies.d.ts +8 -3
  74. package/esm/policies.d.ts.map +1 -1
  75. package/esm/policies.js +8 -3
  76. package/esm/policies.js.map +1 -1
  77. package/esm/policy.d.ts +40 -13
  78. package/esm/policy.d.ts.map +1 -1
  79. package/esm/policy.js +18 -7
  80. package/esm/policy.js.map +1 -1
  81. package/esm/{policyGenerators/generateFileHeaderPolicy.d.ts → policyDefiners/defineFileHeaderPolicy.d.ts} +4 -4
  82. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts.map +1 -0
  83. package/esm/{policyGenerators/generateFileHeaderPolicy.js → policyDefiners/defineFileHeaderPolicy.js} +3 -3
  84. package/esm/policyDefiners/defineFileHeaderPolicy.js.map +1 -0
  85. package/esm/policyDefiners/definePackagePolicy.d.ts +15 -0
  86. package/esm/policyDefiners/definePackagePolicy.d.ts.map +1 -0
  87. package/esm/{policyGenerators/generatePackagePolicy.js → policyDefiners/definePackagePolicy.js} +2 -2
  88. package/esm/policyDefiners/definePackagePolicy.js.map +1 -0
  89. package/esm/tsdoc-metadata.json +1 -1
  90. package/oclif.manifest.json +1 -1
  91. package/package.json +36 -31
  92. package/esm/policyGenerators/generateFileHeaderPolicy.d.ts.map +0 -1
  93. package/esm/policyGenerators/generateFileHeaderPolicy.js.map +0 -1
  94. package/esm/policyGenerators/generatePackagePolicy.d.ts +0 -9
  95. package/esm/policyGenerators/generatePackagePolicy.d.ts.map +0 -1
  96. package/esm/policyGenerators/generatePackagePolicy.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,92 @@
1
1
  # repopo
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add configurable PackageScripts policy _[`#376`](https://github.com/tylerbutler/tools-monorepo/pull/376) [`c17462a`](https://github.com/tylerbutler/tools-monorepo/commit/c17462a8af35a8bfbb528f29825a0ef177923946) [@tylerbutler](https://github.com/tylerbutler)_
8
+
9
+ Enhances the `PackageScripts` policy with flexible configuration options to enforce package.json script requirements across your repository. The policy now supports two validation modes:
10
+
11
+ 1. **Required Scripts (`must`)**: Specify scripts that must be present in all package.json files
12
+ 2. **Mutually Exclusive Scripts (`mutuallyExclusive`)**: Define groups of scripts where exactly one from each group must exist
13
+
14
+ Example configuration:
15
+
16
+ ```typescript
17
+ makePolicy(PackageScripts, {
18
+ must: ["build", "clean"],
19
+ mutuallyExclusive: [
20
+ ["test", "test:unit"], // Either "test" or "test:unit", not both
21
+ ],
22
+ });
23
+ ```
24
+
25
+ The policy validates that:
26
+
27
+ - All scripts in the `must` array are present
28
+ - For each group in `mutuallyExclusive`, exactly one script from that group exists (not zero, not multiple)
29
+
30
+ This is useful for enforcing consistent npm script conventions across monorepo packages while allowing flexibility where needed.
31
+
32
+ - New built-in policies _[`#308`](https://github.com/tylerbutler/tools-monorepo/pull/308) [`1856d58`](https://github.com/tylerbutler/tools-monorepo/commit/1856d582fb92692447b02c89cdb45dcd3c5f7370) [@tylerbutler](https://github.com/tylerbutler)_
33
+
34
+ Added three new policies for repository quality and safety:
35
+
36
+ - **LicenseFileExists**: Ensures a LICENSE file exists in the repository root (essential for open source projects)
37
+ - **NoLargeBinaryFiles**: Prevents large binary files from being committed (default 10MB max, suggests Git LFS for large assets)
38
+ - **RequiredGitignorePatterns**: Validates .gitignore contains required patterns to prevent committing sensitive files, dependencies, and build artifacts (auto-fixable)
39
+
40
+ ### Patch Changes
41
+
42
+ <details><summary>Updated 2 dependencies</summary>
43
+
44
+ <small>
45
+
46
+ [`b0d8cb9`](https://github.com/tylerbutler/tools-monorepo/commit/b0d8cb9a9ee27a0b778ee58055bcbdd7d6d9b4eb) [`08e571f`](https://github.com/tylerbutler/tools-monorepo/commit/08e571f028e868d5db1c337e51804f5884cd2f4a) [`08e571f`](https://github.com/tylerbutler/tools-monorepo/commit/08e571f028e868d5db1c337e51804f5884cd2f4a)
47
+
48
+ </small>
49
+
50
+ - `@tylerbu/cli-api@0.8.0`
51
+ - `@tylerbu/fundamentals@0.3.0`
52
+
53
+ </details>
54
+
55
+ ## 0.6.0
56
+
57
+ ### Minor Changes
58
+
59
+ - Configuration changes _[`#224`](https://github.com/tylerbutler/tools-monorepo/pull/224) [`2b7db34`](https://github.com/tylerbutler/tools-monorepo/commit/2b7db343d74ab2e518ab2f232f47ea365ca784b8) [@tylerbutler](https://github.com/tylerbutler)_
60
+
61
+ The configuration for repopo has changed a lot in this release. The goal is to improve the typing of config and make it
62
+ easier to configure things in one place.
63
+
64
+ Policies are now declared as `PolicyDefinition`, and are then combined with a configuration (if the policy has
65
+ configuration) using `makePolicy` to form a `PolicyInstance`, which is the primary type used internally.
66
+
67
+ Generators now generate `PolicyDefinition`s, and can be used directly inline with `makePolicy`.
68
+
69
+ - Export policies from /policies entrypoint only _[`#224`](https://github.com/tylerbutler/tools-monorepo/pull/224) [`2b7db34`](https://github.com/tylerbutler/tools-monorepo/commit/2b7db343d74ab2e518ab2f232f47ea365ca784b8) [@tylerbutler](https://github.com/tylerbutler)_
70
+
71
+ Policies included with repopo are now exported from `repopo/policies`.
72
+
73
+ ### Patch Changes
74
+
75
+ - Update package metadata _[`#221`](https://github.com/tylerbutler/tools-monorepo/pull/221) [`9e5225a`](https://github.com/tylerbutler/tools-monorepo/commit/9e5225abfb67af1575af13dff60830d8da28eafd) [@tylerbutler](https://github.com/tylerbutler)_
76
+
77
+ <details><summary>Updated 2 dependencies</summary>
78
+
79
+ <small>
80
+
81
+ [`9e5225a`](https://github.com/tylerbutler/tools-monorepo/commit/9e5225abfb67af1575af13dff60830d8da28eafd)
82
+
83
+ </small>
84
+
85
+ - `@tylerbu/fundamentals@0.2.2`
86
+ - `@tylerbu/cli-api@0.7.2`
87
+
88
+ </details>
89
+
3
90
  ## 0.5.0
4
91
 
5
92
  ### Minor Changes
package/README.md CHANGED
@@ -24,14 +24,12 @@ By default, all files in the repo are checked. You can exclude files completely
24
24
  d `excludeFiles` setting. It should be an array of strings/regular expressions. Paths that match any of these
25
25
  expressions will be completely excluded from all policies.
26
26
 
27
- You can exclude files from individual policies as well. To do this, set the `excludePoliciesForFiles` setting. It should
28
- be an object with keys that match policy names. The value is an array of strings/regular expressions. Paths that match
29
- any of these expressions will be excluded from that policy only.
27
+ You can exclude files from individual policies as well by configuring the `excludeFiles` setting when calling
28
+ `makePolicy`.
30
29
 
31
30
  ## Configuring individual policies
32
31
 
33
- Individual policies can be configured using the `policySettings` setting. Use the policy name as the key, with the
34
- policy settings as the value.
32
+ Individual policies can be configured by passing configuration settings to a `PolicyDefinition` in `makePolicy`.
35
33
 
36
34
  # Included policies
37
35
 
@@ -3,7 +3,7 @@ https://www.npmjs.com/package/generate-license-file
3
3
 
4
4
  The following npm package may be included in this product:
5
5
 
6
- - jsonfile@6.1.0
6
+ - jsonfile@6.2.0
7
7
 
8
8
  This package contains the following license:
9
9
 
@@ -27,7 +27,7 @@ OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHE
27
27
 
28
28
  The following npm package may be included in this product:
29
29
 
30
- - @rushstack/node-core-library@5.13.0
30
+ - @rushstack/node-core-library@5.18.0
31
31
 
32
32
  This package contains the following license:
33
33
 
@@ -60,7 +60,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
60
60
 
61
61
  The following npm package may be included in this product:
62
62
 
63
- - @fluid-tools/build-infrastructure@0.56.0
63
+ - @fluid-tools/build-infrastructure@0.60.0
64
64
 
65
65
  This package contains the following license:
66
66
 
@@ -114,7 +114,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
114
114
 
115
115
  The following npm package may be included in this product:
116
116
 
117
- - simple-git@3.27.0
117
+ - simple-git@3.30.0
118
118
 
119
119
  This package contains the following license:
120
120
 
@@ -124,8 +124,8 @@ MIT
124
124
 
125
125
  The following npm packages may be included in this product:
126
126
 
127
- - @oclif/core@4.2.10
128
- - @oclif/plugin-help@6.2.27
127
+ - @oclif/core@4.8.0
128
+ - @oclif/plugin-help@6.2.35
129
129
 
130
130
  These packages each contain the following license:
131
131
 
@@ -1 +1 @@
1
- {"version":3,"file":"baseCommand.d.ts","sourceRoot":"","sources":["../src/baseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,KAAK,SAAS,EAAa,MAAM,YAAY,CAAC;AACvD,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAyB,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAIhF;;GAEG;AACH,8BAAsB,iBAAiB,CACrC,CAAC,SAAS,OAAO,iBAAiB,GAAG;IACpC,IAAI,EAAE,OAAO,iBAAiB,CAAC,IAAI,CAAC;IACpC,KAAK,EAAE,OAAO,iBAAiB,CAAC,KAAK,CAAC;CACtC,CAEF,SAAQ,iBAAiB,CAAC,CAAC,EAAE,YAAY,CACzC,YAAW,kBAAkB,CAAC,oBAAoB,CAAC,EAAE,WAAW;IAEhE,UAAmB,aAAa,eAAuB;IAEvD,gBAAyB,KAAK;gCAXK,wBACjB,wCACD,wBAChB;MAUU;IAEX,OAAO,CAAC,IAAI,CAAwB;IACpC,IAAW,GAAG,IAAI,SAAS,CAK1B;IAEqB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA8B3C,OAAO,CAAC,QAAQ,CAAmC;IAGtC,UAAU,IAAI,OAAO,CAAC,oBAAoB,CAAC;CAMxD"}
1
+ {"version":3,"file":"baseCommand.d.ts","sourceRoot":"","sources":["../src/baseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,KAAK,SAAS,EAAa,MAAM,YAAY,CAAC;AACvD,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAyB,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAKhF;;GAEG;AACH,8BAAsB,iBAAiB,CACrC,CAAC,SAAS,OAAO,iBAAiB,GAAG;IACpC,IAAI,EAAE,OAAO,iBAAiB,CAAC,IAAI,CAAC;IACpC,KAAK,EAAE,OAAO,iBAAiB,CAAC,KAAK,CAAC;CACtC,CAEF,SAAQ,iBAAiB,CAAC,CAAC,EAAE,YAAY,CACzC,YAAW,kBAAkB,CAAC,oBAAoB,CAAC,EAAE,WAAW;IAEhE,UAAmB,aAAa,eAAuB;IAEvD,gBAAgC,KAAK;;MAE1B;IAEX,OAAO,CAAC,IAAI,CAAwB;IACpC,IAAW,GAAG,IAAI,SAAS,CAK1B;IAEqB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB3C,OAAO,CAAC,QAAQ,CAAmC;IAEtC,UAAU,IAAI,OAAO,CAAC,oBAAoB,CAAC;CAMxD"}
@@ -2,6 +2,7 @@ import { CommandWithConfig, } from "@tylerbu/cli-api";
2
2
  import { findGitRootSync } from "@tylerbu/fundamentals/git";
3
3
  import { simpleGit } from "simple-git";
4
4
  import { DefaultPolicyConfig } from "./config.js";
5
+ import { makePolicy } from "./makePolicy.js";
5
6
  import { newPerfStats } from "./perf.js";
6
7
  import { DefaultPolicies } from "./policy.js";
7
8
  /**
@@ -22,26 +23,23 @@ export class BaseRepopoCommand extends CommandWithConfig {
22
23
  async init() {
23
24
  await super.init();
24
25
  const excludeFiles = this.commandConfig?.excludeFiles?.map((e) => new RegExp(e, "i")) ?? [];
25
- const excludePoliciesForFilesRaw = this.commandConfig?.excludePoliciesForFiles;
26
26
  const excludePoliciesForFiles = new Map();
27
- if (excludePoliciesForFilesRaw) {
28
- for (const [policyName, filters] of Object.entries(excludePoliciesForFilesRaw)) {
29
- const regexes = filters.map((e) => new RegExp(e, "i"));
30
- excludePoliciesForFiles.set(policyName, regexes);
31
- }
27
+ for (const policy of this.commandConfig?.policies ?? []) {
28
+ const regexes = policy.excludeFiles?.map((e) => new RegExp(e, "i")) ?? [];
29
+ excludePoliciesForFiles.set(policy.name, regexes);
32
30
  }
33
31
  const gitRoot = findGitRootSync();
34
32
  this._git = simpleGit({ baseDir: gitRoot });
35
33
  this._context = {
36
- excludeFiles,
37
- policies: this.commandConfig?.policies ?? DefaultPolicies,
34
+ excludeFromAll: excludeFiles,
35
+ policies: this.commandConfig?.policies ??
36
+ DefaultPolicies.map((p) => makePolicy(p)),
38
37
  excludePoliciesForFiles,
39
38
  gitRoot,
40
39
  perfStats: newPerfStats(),
41
40
  };
42
41
  }
43
42
  _context;
44
- // biome-ignore lint/suspicious/useAwait: interface defines this as async
45
43
  async getContext() {
46
44
  if (this._context === undefined) {
47
45
  throw new Error("Context not initialized.");
@@ -1 +1 @@
1
- {"version":3,"file":"baseCommand.js","sourceRoot":"","sources":["../src/baseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,GAGjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAkB,SAAS,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAqB,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;GAEG;AACH,MAAM,OAAgB,iBAMrB,SAAQ,iBAAkC;IAGvB,aAAa,GAAG,mBAAmB,CAAC;IAEvD,MAAM,CAAmB,KAAK,GAAG;QAChC,GAAG,iBAAiB,CAAC,KAAK;KACjB,CAAC;IAEH,IAAI,CAAwB;IACpC,IAAW,GAAG;QACb,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;IAEe,KAAK,CAAC,IAAI;QACzB,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QAEnB,MAAM,YAAY,GACjB,IAAI,CAAC,aAAa,EAAE,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAExE,MAAM,0BAA0B,GAC/B,IAAI,CAAC,aAAa,EAAE,uBAAuB,CAAC;QAE7C,MAAM,uBAAuB,GAA0B,IAAI,GAAG,EAAE,CAAC;QACjE,IAAI,0BAA0B,EAAE,CAAC;YAChC,KAAK,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CACjD,0BAA0B,CAC1B,EAAE,CAAC;gBACH,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;gBACvD,uBAAuB,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAClD,CAAC;QACF,CAAC;QAED,MAAM,OAAO,GAAG,eAAe,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ,GAAG;YACf,YAAY;YACZ,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,IAAI,eAAe;YACzD,uBAAuB;YACvB,OAAO;YACP,SAAS,EAAE,YAAY,EAAE;SACzB,CAAC;IACH,CAAC;IAEO,QAAQ,CAAmC;IAEnD,yEAAyE;IAClE,KAAK,CAAC,UAAU;QACtB,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC","sourcesContent":["import {\n\tCommandWithConfig,\n\ttype CommandWithContext,\n\ttype RequiresGit,\n} from \"@tylerbu/cli-api\";\nimport { findGitRootSync } from \"@tylerbu/fundamentals/git\";\nimport { type SimpleGit, simpleGit } from \"simple-git\";\nimport { DefaultPolicyConfig, type RepopoConfig } from \"./config.js\";\nimport type { ExcludedPolicyFileMap, RepopoCommandContext } from \"./context.js\";\nimport { newPerfStats } from \"./perf.js\";\nimport { DefaultPolicies } from \"./policy.js\";\n\n/**\n * This class is the base for all repopo commands. It contains common flags and config loading.\n */\nexport abstract class BaseRepopoCommand<\n\t\tT extends typeof BaseRepopoCommand & {\n\t\t\targs: typeof CommandWithConfig.args;\n\t\t\tflags: typeof CommandWithConfig.flags;\n\t\t},\n\t>\n\textends CommandWithConfig<T, RepopoConfig>\n\timplements CommandWithContext<RepopoCommandContext>, RequiresGit\n{\n\tprotected override defaultConfig = DefaultPolicyConfig;\n\n\tstatic override readonly flags = {\n\t\t...CommandWithConfig.flags,\n\t} as const;\n\n\tprivate _git: SimpleGit | undefined;\n\tpublic get git(): SimpleGit {\n\t\tif (this._git === undefined) {\n\t\t\tthrow new Error(\"git property is undefined\");\n\t\t}\n\t\treturn this._git;\n\t}\n\n\tpublic override async init(): Promise<void> {\n\t\tawait super.init();\n\n\t\tconst excludeFiles: RegExp[] =\n\t\t\tthis.commandConfig?.excludeFiles?.map((e) => new RegExp(e, \"i\")) ?? [];\n\n\t\tconst excludePoliciesForFilesRaw =\n\t\t\tthis.commandConfig?.excludePoliciesForFiles;\n\n\t\tconst excludePoliciesForFiles: ExcludedPolicyFileMap = new Map();\n\t\tif (excludePoliciesForFilesRaw) {\n\t\t\tfor (const [policyName, filters] of Object.entries(\n\t\t\t\texcludePoliciesForFilesRaw,\n\t\t\t)) {\n\t\t\t\tconst regexes = filters.map((e) => new RegExp(e, \"i\"));\n\t\t\t\texcludePoliciesForFiles.set(policyName, regexes);\n\t\t\t}\n\t\t}\n\n\t\tconst gitRoot = findGitRootSync();\n\t\tthis._git = simpleGit({ baseDir: gitRoot });\n\t\tthis._context = {\n\t\t\texcludeFiles,\n\t\t\tpolicies: this.commandConfig?.policies ?? DefaultPolicies,\n\t\t\texcludePoliciesForFiles,\n\t\t\tgitRoot,\n\t\t\tperfStats: newPerfStats(),\n\t\t};\n\t}\n\n\tprivate _context: RepopoCommandContext | undefined;\n\n\t// biome-ignore lint/suspicious/useAwait: interface defines this as async\n\tpublic async getContext(): Promise<RepopoCommandContext> {\n\t\tif (this._context === undefined) {\n\t\t\tthrow new Error(\"Context not initialized.\");\n\t\t}\n\t\treturn this._context;\n\t}\n}\n"]}
1
+ {"version":3,"file":"baseCommand.js","sourceRoot":"","sources":["../src/baseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,GAGjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAkB,SAAS,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAqB,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;GAEG;AACH,MAAM,OAAgB,iBAMrB,SAAQ,iBAAkC;IAGvB,aAAa,GAAG,mBAAmB,CAAC;IAEhD,MAAM,CAAmB,KAAK,GAAG;QACvC,GAAG,iBAAiB,CAAC,KAAK;KACjB,CAAC;IAEH,IAAI,CAAwB;IACpC,IAAW,GAAG;QACb,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;IAEe,KAAK,CAAC,IAAI;QACzB,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QAEnB,MAAM,YAAY,GACjB,IAAI,CAAC,aAAa,EAAE,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAExE,MAAM,uBAAuB,GAA0B,IAAI,GAAG,EAAE,CAAC;QACjE,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,aAAa,EAAE,QAAQ,IAAI,EAAE,EAAE,CAAC;YACzD,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;YAC1E,uBAAuB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACnD,CAAC;QAED,MAAM,OAAO,GAAG,eAAe,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ,GAAG;YACf,cAAc,EAAE,YAAY;YAC5B,QAAQ,EACP,IAAI,CAAC,aAAa,EAAE,QAAQ;gBAC5B,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC1C,uBAAuB;YACvB,OAAO;YACP,SAAS,EAAE,YAAY,EAAE;SACzB,CAAC;IACH,CAAC;IAEO,QAAQ,CAAmC;IAE5C,KAAK,CAAC,UAAU;QACtB,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC","sourcesContent":["import {\n\tCommandWithConfig,\n\ttype CommandWithContext,\n\ttype RequiresGit,\n} from \"@tylerbu/cli-api\";\nimport { findGitRootSync } from \"@tylerbu/fundamentals/git\";\nimport { type SimpleGit, simpleGit } from \"simple-git\";\nimport { DefaultPolicyConfig, type RepopoConfig } from \"./config.js\";\nimport type { ExcludedPolicyFileMap, RepopoCommandContext } from \"./context.js\";\nimport { makePolicy } from \"./makePolicy.js\";\nimport { newPerfStats } from \"./perf.js\";\nimport { DefaultPolicies } from \"./policy.js\";\n\n/**\n * This class is the base for all repopo commands. It contains common flags and config loading.\n */\nexport abstract class BaseRepopoCommand<\n\t\tT extends typeof BaseRepopoCommand & {\n\t\t\targs: typeof CommandWithConfig.args;\n\t\t\tflags: typeof CommandWithConfig.flags;\n\t\t},\n\t>\n\textends CommandWithConfig<T, RepopoConfig>\n\timplements CommandWithContext<RepopoCommandContext>, RequiresGit\n{\n\tprotected override defaultConfig = DefaultPolicyConfig;\n\n\tpublic static override readonly flags = {\n\t\t...CommandWithConfig.flags,\n\t} as const;\n\n\tprivate _git: SimpleGit | undefined;\n\tpublic get git(): SimpleGit {\n\t\tif (this._git === undefined) {\n\t\t\tthrow new Error(\"git property is undefined\");\n\t\t}\n\t\treturn this._git;\n\t}\n\n\tpublic override async init(): Promise<void> {\n\t\tawait super.init();\n\n\t\tconst excludeFiles: RegExp[] =\n\t\t\tthis.commandConfig?.excludeFiles?.map((e) => new RegExp(e, \"i\")) ?? [];\n\n\t\tconst excludePoliciesForFiles: ExcludedPolicyFileMap = new Map();\n\t\tfor (const policy of this.commandConfig?.policies ?? []) {\n\t\t\tconst regexes = policy.excludeFiles?.map((e) => new RegExp(e, \"i\")) ?? [];\n\t\t\texcludePoliciesForFiles.set(policy.name, regexes);\n\t\t}\n\n\t\tconst gitRoot = findGitRootSync();\n\t\tthis._git = simpleGit({ baseDir: gitRoot });\n\t\tthis._context = {\n\t\t\texcludeFromAll: excludeFiles,\n\t\t\tpolicies:\n\t\t\t\tthis.commandConfig?.policies ??\n\t\t\t\tDefaultPolicies.map((p) => makePolicy(p)),\n\t\t\texcludePoliciesForFiles,\n\t\t\tgitRoot,\n\t\t\tperfStats: newPerfStats(),\n\t\t};\n\t}\n\n\tprivate _context: RepopoCommandContext | undefined;\n\n\tpublic async getContext(): Promise<RepopoCommandContext> {\n\t\tif (this._context === undefined) {\n\t\t\tthrow new Error(\"Context not initialized.\");\n\t\t}\n\t\treturn this._context;\n\t}\n}\n"]}
@@ -19,18 +19,29 @@ export declare class CheckPolicy<T extends typeof BaseRepopoCommand & {
19
19
  readonly stdin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
20
20
  };
21
21
  run(): Promise<void>;
22
- private executeAllPolicies;
23
22
  /**
24
- * Routes files to their handlers and resolvers by regex testing their full paths. If a file fails a policy that has a
25
- * resolver, the resolver will be invoked as well. Synchronizes the output, exit codes, and resolve
26
- * decision for all handlers.
23
+ * Executes all policies against the provided paths.
24
+ *
25
+ * @param pathsToCheck - All paths that should be checked. Paths should be relative to the repository root.
26
+ * @param context - The context.
27
27
  */
28
- private routeToHandlers;
29
- private runPolicyOnFile;
28
+ private checkAllFiles;
30
29
  /**
31
30
  * Given a string that represents a path to a file in the repo, determines if the file should be checked, and if so,
32
31
  * routes the file to the appropriate handlers.
32
+ *
33
+ * @param relPath - A git repo-relative path to a file.
33
34
  */
34
35
  private checkOrExcludeFile;
36
+ private routeToPolicies;
37
+ private runPolicyOnFile;
38
+ private isPolicyExcluded;
39
+ private executePolicyHandler;
40
+ private handlePolicyResult;
41
+ private handleFixResult;
42
+ private handleFailureResult;
43
+ private attemptResolution;
44
+ private logPolicyFailure;
45
+ private logMessages;
35
46
  }
36
47
  //# sourceMappingURL=check.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAKtD;;;;;;;;GAQG;AACH,qBAAa,WAAW,CACvB,CAAC,SAAS,OAAO,iBAAiB,GAAG;IACpC,IAAI,EAAE,OAAO,WAAW,CAAC,IAAI,CAAC;IAC9B,KAAK,EAAE,OAAO,WAAW,CAAC,KAAK,CAAC;CAChC,CACA,SAAQ,iBAAiB,CAAC,CAAC,CAAC;IAC7B,gBAAyB,OAAO,iEAC+B;IAE/D,gBAAyB,KAAK;gCAhBkB,wBAAuB,wCAAwC,wBAE/F;;;MA0BL;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;YAmC5B,kBAAkB;IAehC;;;;OAIG;YACW,eAAe;YAwBf,eAAe;IAkG7B;;;OAGG;YACW,kBAAkB;CAwBhC"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAgCtD;;;;;;;;GAQG;AACH,qBAAa,WAAW,CACvB,CAAC,SAAS,OAAO,iBAAiB,GAAG;IACpC,IAAI,EAAE,OAAO,WAAW,CAAC,IAAI,CAAC;IAC9B,KAAK,EAAE,OAAO,WAAW,CAAC,KAAK,CAAC;CAChC,CACA,SAAQ,iBAAiB,CAAC,CAAC,CAAC;IAC7B,gBAAgC,OAAO,iEACwB;IAE/D,gBAAgC,KAAK;;;;MAY1B;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAwD1C;;;;;OAKG;YACW,aAAa;IAe3B;;;;;OAKG;YACW,kBAAkB;YAmBlB,eAAe;YAsCf,eAAe;IAwC7B,OAAO,CAAC,gBAAgB;YAYV,oBAAoB;YAsBpB,kBAAkB;IAwBhC,OAAO,CAAC,eAAe;YAoBT,mBAAmB;YAyBnB,iBAAiB;IAyB/B,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,WAAW;CAOnB"}
@@ -1,11 +1,27 @@
1
1
  import { EOL as newline } from "node:os";
2
+ import process from "node:process";
2
3
  import { Flags } from "@oclif/core";
3
4
  import { StringBuilder } from "@rushstack/node-core-library";
4
- import path from "pathe";
5
5
  import chalk from "picocolors";
6
6
  import { BaseRepopoCommand } from "../baseCommand.js";
7
7
  import { logStats, runWithPerf } from "../perf.js";
8
- import { isPolicyFixResult } from "../policy.js";
8
+ import { isPolicyFixResult, } from "../policy.js";
9
+ async function readStdin() {
10
+ return new Promise((resolve) => {
11
+ const stdin = process.stdin;
12
+ stdin.setEncoding("utf8");
13
+ let data = "";
14
+ stdin.on("data", (chunk) => {
15
+ data += chunk;
16
+ });
17
+ stdin.on("end", () => {
18
+ resolve(data);
19
+ });
20
+ if (stdin.isTTY) {
21
+ resolve("");
22
+ }
23
+ });
24
+ }
9
25
  /**
10
26
  * This tool enforces policies across the code base via a series of handler functions. The handler functions are
11
27
  * associated with a regular expression, and all files matching that expression are passed to the handler function.
@@ -44,149 +60,185 @@ export class CheckPolicy extends BaseRepopoCommand {
44
60
  if (this.flags.stdin) {
45
61
  const stdInput = await readStdin();
46
62
  if (stdInput !== undefined) {
47
- filePathsToCheck.push(...stdInput.split("\n"));
63
+ filePathsToCheck.push(...stdInput
64
+ .replace(
65
+ // normalize slashes in case they're windows paths
66
+ /\\/g, "/")
67
+ .split("\n"));
48
68
  }
49
69
  }
50
70
  else {
51
- const gitFiles = (await this.git.raw("ls-files", "-co", "--exclude-standard", "--full-name")) ?? "";
52
- filePathsToCheck.push(...gitFiles.split("\n"));
71
+ const gitFiles = (await this.git.raw("ls-files",
72
+ // include staged files and untracked files
73
+ "-co",
74
+ // exclude gitignored files and other standard ignore rules
75
+ "--exclude-standard",
76
+ // Outputs paths relative to the root of the repository, regardless of the current working directory.
77
+ "--full-name")) ?? "";
78
+ filePathsToCheck.push(...gitFiles
79
+ .replace(
80
+ // normalize slashes in case they're windows paths
81
+ /\\/g, "/")
82
+ .split("\n"));
53
83
  }
54
- await this.executeAllPolicies(filePathsToCheck);
84
+ const context = await this.getContext();
85
+ await this.checkAllFiles(filePathsToCheck, context);
55
86
  }
56
- async executeAllPolicies(pathsToCheck) {
57
- const commandContext = await this.getContext();
87
+ /**
88
+ * Executes all policies against the provided paths.
89
+ *
90
+ * @param pathsToCheck - All paths that should be checked. Paths should be relative to the repository root.
91
+ * @param context - The context.
92
+ */
93
+ async checkAllFiles(pathsToCheck, context) {
58
94
  try {
59
95
  for (const pathToCheck of pathsToCheck) {
60
- // eslint-disable-next-line no-await-in-loop
61
- await this.checkOrExcludeFile(pathToCheck, commandContext);
96
+ await this.checkOrExcludeFile(pathToCheck, context);
62
97
  }
63
98
  }
64
99
  finally {
65
100
  if (!this.flags.quiet) {
66
- logStats(commandContext.perfStats, this);
101
+ logStats(context.perfStats, this);
67
102
  }
68
103
  }
69
104
  }
70
105
  /**
71
- * Routes files to their handlers and resolvers by regex testing their full paths. If a file fails a policy that has a
72
- * resolver, the resolver will be invoked as well. Synchronizes the output, exit codes, and resolve
73
- * decision for all handlers.
106
+ * Given a string that represents a path to a file in the repo, determines if the file should be checked, and if so,
107
+ * routes the file to the appropriate handlers.
108
+ *
109
+ * @param relPath - A git repo-relative path to a file.
74
110
  */
75
- async routeToHandlers(file, commandContext) {
76
- const { policies, gitRoot } = commandContext;
77
- // Use the repo-relative path so that regexes that specify string start (^) will match repo paths.
78
- // Replace \ in result with / in case OS is Windows.
79
- const relPath = path.relative(gitRoot, file).replace(/\\/g, "/");
80
- const filteredPolicies = policies.filter((handler) => handler.match.test(relPath));
81
- const resultsP = [];
82
- for (const policy of filteredPolicies) {
83
- resultsP.push(this.runPolicyOnFile(relPath, policy));
84
- }
85
- await Promise.all(resultsP);
111
+ async checkOrExcludeFile(relPath, context) {
112
+ const { perfStats } = context;
113
+ perfStats.count++;
114
+ try {
115
+ const wasProcessed = await this.routeToPolicies(relPath, context);
116
+ if (wasProcessed) {
117
+ perfStats.processed++;
118
+ }
119
+ }
120
+ catch (error) {
121
+ throw new Error(`Error routing ${relPath} to handler: ${error}\nStack:\n${error.stack}`);
122
+ }
86
123
  }
87
- // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: FIXME
88
- async runPolicyOnFile(relPath,
89
- // policies: RepoPolicy[],
90
- policy) {
91
- const context = await this.getContext();
124
+ async routeToPolicies(relPath, context) {
125
+ const { policies, excludeFromAll } = context;
126
+ // Check exclusions
127
+ if (excludeFromAll.some((regex) => regex.test(relPath))) {
128
+ this.verbose(`Excluded all handlers: ${relPath}`);
129
+ return false; // File was excluded from all policies
130
+ }
131
+ // Run all matching policies
132
+ const matchingPolicies = policies.filter((policy) => policy.match.test(relPath));
133
+ // for(const policy of matchingPolicies) {
134
+ // bars.addFile(policy.name,
135
+ // }
136
+ // If no policies match this file, it's still considered processed
137
+ // (we examined it and determined no policies apply)
138
+ if (matchingPolicies.length === 0) {
139
+ return true;
140
+ }
141
+ const results = await Promise.all(matchingPolicies.map(async (policy) => {
142
+ return await this.runPolicyOnFile(relPath, policy, context);
143
+ }));
144
+ // File is considered processed if at least one policy ran on it
145
+ // If all matching policies excluded it, count as excluded
146
+ return results.some((ran) => ran);
147
+ }
148
+ async runPolicyOnFile(relPath, policy, context) {
92
149
  const { excludePoliciesForFiles, perfStats, gitRoot } = context;
93
- // doing exclusion per handler
94
- const exclusions = excludePoliciesForFiles.get(policy.name);
95
- if (exclusions !== undefined &&
96
- !exclusions.every((regex) => !regex.test(relPath))) {
150
+ // Check if the policy is excluded for the file
151
+ if (this.isPolicyExcluded(relPath, policy, excludePoliciesForFiles)) {
97
152
  this.verbose(`Excluded from '${policy.name}' policy: ${relPath}`);
98
- return;
153
+ return false; // Policy didn't run on this file
99
154
  }
100
- const result = await runWithPerf(policy.name, "handle", perfStats, async () => policy.handler({
101
- file: relPath,
102
- root: gitRoot,
103
- resolve: this.flags.fix,
104
- config: this.commandConfig?.perPolicyConfig?.[policy.name
105
- // biome-ignore lint/suspicious/noExplicitAny: FIXME
106
- ],
107
- }));
155
+ try {
156
+ // Execute the policy handler
157
+ const result = await this.executePolicyHandler(relPath, policy, perfStats, gitRoot);
158
+ // Handle the result of the policy execution
159
+ await this.handlePolicyResult(result, relPath, policy, perfStats, gitRoot);
160
+ }
161
+ catch (error) {
162
+ // Log and rethrow the error for higher-level handling
163
+ this.error(`Error executing policy '${policy.name}' for file '${relPath}': ${error}`);
164
+ }
165
+ return true; // Policy ran (successfully or with error)
166
+ }
167
+ isPolicyExcluded(relPath, policy, excludePoliciesForFiles) {
168
+ return (excludePoliciesForFiles
169
+ .get(policy.name)
170
+ ?.some((regex) => regex.test(relPath)) ?? false);
171
+ }
172
+ async executePolicyHandler(relPath, policy, perfStats, gitRoot) {
173
+ try {
174
+ return await runWithPerf(policy.name, "handle", perfStats, () => policy.handler({
175
+ file: relPath,
176
+ root: gitRoot,
177
+ resolve: this.flags.fix,
178
+ config: policy.config,
179
+ }));
180
+ }
181
+ catch (error) {
182
+ this.error(`Error in policy handler '${policy.name}' for file '${relPath}': ${error}`);
183
+ }
184
+ }
185
+ async handlePolicyResult(result, relPath, policy, perfStats, gitRoot) {
108
186
  if (result === true) {
109
187
  return;
110
188
  }
111
- const messages = new StringBuilder();
112
189
  if (isPolicyFixResult(result)) {
113
- if (result.resolved) {
114
- messages.append(`Resolved ${policy.name} policy failure for file: ${result.file}`);
115
- }
116
- else {
117
- messages.append(`Error when trying to fix ${policy.name} policy failure in ${result.file}`);
118
- process.exitCode = 1;
119
- }
190
+ this.handleFixResult(result, policy);
120
191
  }
121
192
  else {
122
- // result must be a PolicyFailureResult; check if there is a standalone resolver.
123
- const { resolver } = policy;
124
- if (this.flags.fix && resolver !== undefined) {
125
- // Resolve the failure
126
- messages.append(`${newline}attempting to resolve: ${relPath}`);
127
- const resolveResult = await runWithPerf(policy.name, "resolve", perfStats, async () => resolver({ file: relPath, root: gitRoot }));
128
- if (resolveResult.errorMessage !== undefined &&
129
- resolveResult.errorMessage !== "") {
130
- messages.append(newline + resolveResult.errorMessage);
131
- }
132
- if (!resolveResult.resolved) {
133
- process.exitCode = 1;
134
- }
135
- }
136
- else {
137
- // No resolver, or fix is false, so we're in the full failure case.
138
- const autoFixable = result.autoFixable
139
- ? chalk.green(" (autofixable)")
140
- : "";
141
- messages.append(`'${chalk.bold(policy.name)}' policy failure${autoFixable}: ${result.file}`);
142
- messages.append(result.errorMessage === undefined
143
- ? ""
144
- : `${newline}\t${result.errorMessage}`);
145
- process.exitCode = 1;
146
- }
193
+ await this.handleFailureResult(result, relPath, policy, perfStats, gitRoot);
147
194
  }
148
- if ((process.exitCode ?? 0) === 0) {
149
- this.info(messages.toString());
195
+ }
196
+ handleFixResult(result, policy) {
197
+ const messages = new StringBuilder();
198
+ if (result.resolved) {
199
+ messages.append(`Resolved ${policy.name} policy failure for file: ${result.file}`);
150
200
  }
151
201
  else {
152
- this.warning(messages.toString());
202
+ messages.append(`Error fixing ${policy.name} policy failure in ${result.file}`);
203
+ process.exitCode = 1;
153
204
  }
205
+ this.logMessages(messages);
154
206
  }
155
- /**
156
- * Given a string that represents a path to a file in the repo, determines if the file should be checked, and if so,
157
- * routes the file to the appropriate handlers.
158
- */
159
- async checkOrExcludeFile(inputPath, commandContext) {
160
- const { excludeFiles: exclusions, gitRoot, perfStats } = commandContext;
161
- const filePath = path.join(gitRoot, inputPath).trim().replace(/\\/g, "/");
162
- perfStats.count++;
163
- if (!exclusions.every((value) => !value.test(inputPath))) {
164
- this.verbose(`Excluded all handlers: ${inputPath}`);
165
- return;
207
+ async handleFailureResult(result, relPath, policy, perfStats, gitRoot) {
208
+ const messages = new StringBuilder();
209
+ if (this.flags.fix && policy.resolver) {
210
+ await this.attemptResolution(relPath, policy, policy.resolver, perfStats, gitRoot, messages);
166
211
  }
167
- try {
168
- await this.routeToHandlers(filePath, commandContext);
212
+ else {
213
+ this.logPolicyFailure(result, policy, messages);
169
214
  }
170
- catch (error) {
171
- throw new Error(`Error routing ${filePath} to handler: ${error}\nStack:\n${error.stack}`);
215
+ this.logMessages(messages);
216
+ }
217
+ async attemptResolution(relPath, policy, resolver, perfStats, gitRoot, messages) {
218
+ messages.append(`${newline}Attempting to resolve: ${relPath}`);
219
+ const resolveResult = await runWithPerf(policy.name, "resolve", perfStats, () => resolver({ file: relPath, root: gitRoot }));
220
+ if (!resolveResult.resolved) {
221
+ process.exitCode = 1;
222
+ }
223
+ if (resolveResult.errorMessage) {
224
+ messages.append(newline + resolveResult.errorMessage);
172
225
  }
173
- perfStats.processed++;
174
226
  }
175
- }
176
- async function readStdin() {
177
- return new Promise((resolve) => {
178
- const stdin = process.stdin;
179
- stdin.setEncoding("utf8");
180
- let data = "";
181
- stdin.on("data", (chunk) => {
182
- data += chunk;
183
- });
184
- stdin.on("end", () => {
185
- resolve(data);
186
- });
187
- if (stdin.isTTY) {
188
- resolve("");
227
+ logPolicyFailure(result, policy, messages) {
228
+ const autoFixable = result.autoFixable ? chalk.green(" (autofixable)") : "";
229
+ messages.append(`'${chalk.bold(policy.name)}' policy failure${autoFixable}: ${result.file}`);
230
+ if (result.errorMessage) {
231
+ messages.append(`${newline}\t${result.errorMessage}`);
189
232
  }
190
- });
233
+ process.exitCode = 1;
234
+ }
235
+ logMessages(messages) {
236
+ if ((process.exitCode ?? 0) === 0) {
237
+ this.info(messages.toString());
238
+ }
239
+ else {
240
+ this.warning(messages.toString());
241
+ }
242
+ }
191
243
  }
192
244
  //# sourceMappingURL=check.js.map