repopo 0.8.0 → 0.10.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 (141) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/THIRD-PARTY-LICENSES.txt +4 -3
  3. package/esm/adapters/fluidFramework.js +8 -3
  4. package/esm/adapters/fluidFramework.js.map +1 -1
  5. package/esm/baseCommand.d.ts.map +1 -1
  6. package/esm/baseCommand.js +2 -1
  7. package/esm/baseCommand.js.map +1 -1
  8. package/esm/commands/check.d.ts +1 -0
  9. package/esm/commands/check.d.ts.map +1 -1
  10. package/esm/commands/check.js +114 -52
  11. package/esm/commands/check.js.map +1 -1
  12. package/esm/commands/list.d.ts.map +1 -1
  13. package/esm/commands/list.js +3 -1
  14. package/esm/commands/list.js.map +1 -1
  15. package/esm/config.d.ts +19 -4
  16. package/esm/config.d.ts.map +1 -1
  17. package/esm/config.js +2 -3
  18. package/esm/config.js.map +1 -1
  19. package/esm/generators.d.ts +30 -2
  20. package/esm/generators.d.ts.map +1 -1
  21. package/esm/generators.js +31 -1
  22. package/esm/generators.js.map +1 -1
  23. package/esm/index.d.ts +14 -4
  24. package/esm/index.d.ts.map +1 -1
  25. package/esm/index.js +17 -2
  26. package/esm/index.js.map +1 -1
  27. package/esm/makePolicy.d.ts +74 -3
  28. package/esm/makePolicy.d.ts.map +1 -1
  29. package/esm/makePolicy.js +87 -13
  30. package/esm/makePolicy.js.map +1 -1
  31. package/esm/perf.d.ts +3 -2
  32. package/esm/perf.d.ts.map +1 -1
  33. package/esm/perf.js +2 -2
  34. package/esm/perf.js.map +1 -1
  35. package/esm/policies/ConditionalScripts.d.ts +94 -0
  36. package/esm/policies/ConditionalScripts.d.ts.map +1 -0
  37. package/esm/policies/ConditionalScripts.js +144 -0
  38. package/esm/policies/ConditionalScripts.js.map +1 -0
  39. package/esm/policies/ExactScripts.d.ts +51 -0
  40. package/esm/policies/ExactScripts.d.ts.map +1 -0
  41. package/esm/policies/ExactScripts.js +107 -0
  42. package/esm/policies/ExactScripts.js.map +1 -0
  43. package/esm/policies/HtmlFileHeaders.d.ts +1 -1
  44. package/esm/policies/HtmlFileHeaders.d.ts.map +1 -1
  45. package/esm/policies/HtmlFileHeaders.js +11 -7
  46. package/esm/policies/HtmlFileHeaders.js.map +1 -1
  47. package/esm/policies/JsTsFileHeaders.d.ts +1 -1
  48. package/esm/policies/JsTsFileHeaders.d.ts.map +1 -1
  49. package/esm/policies/JsTsFileHeaders.js +11 -7
  50. package/esm/policies/JsTsFileHeaders.js.map +1 -1
  51. package/esm/policies/LicenseFileExists.d.ts.map +1 -1
  52. package/esm/policies/LicenseFileExists.js +22 -18
  53. package/esm/policies/LicenseFileExists.js.map +1 -1
  54. package/esm/policies/MutuallyExclusiveScripts.d.ts +46 -0
  55. package/esm/policies/MutuallyExclusiveScripts.d.ts.map +1 -0
  56. package/esm/policies/MutuallyExclusiveScripts.js +52 -0
  57. package/esm/policies/MutuallyExclusiveScripts.js.map +1 -0
  58. package/esm/policies/NoJsFileExtensions.d.ts.map +1 -1
  59. package/esm/policies/NoJsFileExtensions.js +16 -12
  60. package/esm/policies/NoJsFileExtensions.js.map +1 -1
  61. package/esm/policies/NoLargeBinaryFiles.d.ts.map +1 -1
  62. package/esm/policies/NoLargeBinaryFiles.js +35 -31
  63. package/esm/policies/NoLargeBinaryFiles.js.map +1 -1
  64. package/esm/policies/NoPrivateWorkspaceDependencies.d.ts +1 -1
  65. package/esm/policies/NoPrivateWorkspaceDependencies.d.ts.map +1 -1
  66. package/esm/policies/NoPrivateWorkspaceDependencies.js +53 -45
  67. package/esm/policies/NoPrivateWorkspaceDependencies.js.map +1 -1
  68. package/esm/policies/PackageAllowedScopes.d.ts +1 -1
  69. package/esm/policies/PackageAllowedScopes.d.ts.map +1 -1
  70. package/esm/policies/PackageAllowedScopes.js +45 -40
  71. package/esm/policies/PackageAllowedScopes.js.map +1 -1
  72. package/esm/policies/PackageEsmType.d.ts +1 -1
  73. package/esm/policies/PackageEsmType.d.ts.map +1 -1
  74. package/esm/policies/PackageEsmType.js +48 -44
  75. package/esm/policies/PackageEsmType.js.map +1 -1
  76. package/esm/policies/PackageFolderName.d.ts +1 -1
  77. package/esm/policies/PackageFolderName.d.ts.map +1 -1
  78. package/esm/policies/PackageFolderName.js +38 -34
  79. package/esm/policies/PackageFolderName.js.map +1 -1
  80. package/esm/policies/PackageJsonProperties.d.ts +1 -1
  81. package/esm/policies/PackageJsonProperties.d.ts.map +1 -1
  82. package/esm/policies/PackageJsonProperties.js +36 -31
  83. package/esm/policies/PackageJsonProperties.js.map +1 -1
  84. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts +1 -1
  85. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts.map +1 -1
  86. package/esm/policies/PackageJsonRepoDirectoryProperty.js +41 -38
  87. package/esm/policies/PackageJsonRepoDirectoryProperty.js.map +1 -1
  88. package/esm/policies/PackageJsonSorted.d.ts +1 -1
  89. package/esm/policies/PackageJsonSorted.d.ts.map +1 -1
  90. package/esm/policies/PackageJsonSorted.js +40 -36
  91. package/esm/policies/PackageJsonSorted.js.map +1 -1
  92. package/esm/policies/PackageLicense.d.ts +1 -1
  93. package/esm/policies/PackageLicense.d.ts.map +1 -1
  94. package/esm/policies/PackageLicense.js +58 -54
  95. package/esm/policies/PackageLicense.js.map +1 -1
  96. package/esm/policies/PackagePrivateField.d.ts +1 -1
  97. package/esm/policies/PackagePrivateField.d.ts.map +1 -1
  98. package/esm/policies/PackagePrivateField.js +58 -54
  99. package/esm/policies/PackagePrivateField.js.map +1 -1
  100. package/esm/policies/PackageReadme.d.ts +1 -1
  101. package/esm/policies/PackageReadme.d.ts.map +1 -1
  102. package/esm/policies/PackageReadme.js +30 -26
  103. package/esm/policies/PackageReadme.js.map +1 -1
  104. package/esm/policies/PackageScripts.d.ts +1 -1
  105. package/esm/policies/PackageScripts.d.ts.map +1 -1
  106. package/esm/policies/PackageScripts.js +39 -35
  107. package/esm/policies/PackageScripts.js.map +1 -1
  108. package/esm/policies/PackageTestScripts.d.ts +1 -1
  109. package/esm/policies/PackageTestScripts.d.ts.map +1 -1
  110. package/esm/policies/PackageTestScripts.js +46 -40
  111. package/esm/policies/PackageTestScripts.js.map +1 -1
  112. package/esm/policies/RequiredGitignorePatterns.d.ts.map +1 -1
  113. package/esm/policies/RequiredGitignorePatterns.js +20 -15
  114. package/esm/policies/RequiredGitignorePatterns.js.map +1 -1
  115. package/esm/policies/RequiredScripts.d.ts +71 -0
  116. package/esm/policies/RequiredScripts.d.ts.map +1 -0
  117. package/esm/policies/RequiredScripts.js +120 -0
  118. package/esm/policies/RequiredScripts.js.map +1 -0
  119. package/esm/policies/ScriptContains.d.ts +64 -0
  120. package/esm/policies/ScriptContains.d.ts.map +1 -0
  121. package/esm/policies/ScriptContains.js +62 -0
  122. package/esm/policies/ScriptContains.js.map +1 -0
  123. package/esm/policies.d.ts +6 -1
  124. package/esm/policies.d.ts.map +1 -1
  125. package/esm/policies.js +18 -0
  126. package/esm/policies.js.map +1 -1
  127. package/esm/policy.d.ts +193 -74
  128. package/esm/policy.d.ts.map +1 -1
  129. package/esm/policy.js +110 -19
  130. package/esm/policy.js.map +1 -1
  131. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts +49 -2
  132. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts.map +1 -1
  133. package/esm/policyDefiners/defineFileHeaderPolicy.js +21 -4
  134. package/esm/policyDefiners/defineFileHeaderPolicy.js.map +1 -1
  135. package/esm/policyDefiners/definePackagePolicy.d.ts +57 -3
  136. package/esm/policyDefiners/definePackagePolicy.d.ts.map +1 -1
  137. package/esm/policyDefiners/definePackagePolicy.js +50 -5
  138. package/esm/policyDefiners/definePackagePolicy.js.map +1 -1
  139. package/esm/tsdoc-metadata.json +1 -1
  140. package/oclif.manifest.json +1 -1
  141. package/package.json +6 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,72 @@
1
1
  # repopo
2
2
 
3
+ ## 0.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add new `policy()` function as simplified API for defining repository policies, replacing the more complex `makePolicy`/`makePolicyDefinition` workflow. _[`#617`](https://github.com/tylerbutler/tools-monorepo/pull/617) [`becd406`](https://github.com/tylerbutler/tools-monorepo/commit/becd4064e1434b2384cda991f2d0702d91ed5ed9) [@tylerbutler](https://github.com/tylerbutler)_
8
+
9
+ New features:
10
+ - `policy()` function with multiple overload signatures for defining policies concisely
11
+ - `PolicyShape` interface for object-literal policy definitions
12
+ - `ConfiguredPolicy` and `PolicyError` types for the new API surface
13
+ - Five new script-focused policies: `RequiredScripts`, `ExactScripts`, `MutuallyExclusiveScripts`, `ConditionalScripts`, and `ScriptContains`
14
+ - `isPolicyError` type guard and `convertLegacyResult`/`convertToPolicyFailure` conversion utilities
15
+
16
+ Deprecations (old APIs still work but are marked `@deprecated`):
17
+ - `makePolicy` → use `policy()` instead
18
+ - `makePolicyDefinition` → use `PolicyShape` object literals instead
19
+ - `PolicyFailure` → use `PolicyError` instead
20
+ - `PolicyInstance` → use `ConfiguredPolicy` instead
21
+ - `PolicyStandaloneResolver` → use `PolicyResolver` instead
22
+ - `isPolicyFailure` → use `isPolicyError` instead
23
+
24
+ ## 0.9.0
25
+
26
+ ### Minor Changes
27
+
28
+ - Make `description` required on PolicyDefinition _[`#594`](https://github.com/tylerbutler/tools-monorepo/pull/594) [`c3d1b65`](https://github.com/tylerbutler/tools-monorepo/commit/c3d1b65299f58b9fa605ebd18e7fb4346ae7745f) [@tylerbutler](https://github.com/tylerbutler)_
29
+
30
+ BREAKING CHANGE: `PolicyDefinition.description` is now required (was optional). All policies must include a description that explains their purpose.
31
+
32
+ All built-in policies now include descriptions.
33
+
34
+ - Use object parameters for policy factory functions and Policy class _[`#594`](https://github.com/tylerbutler/tools-monorepo/pull/594) [`c3d1b65`](https://github.com/tylerbutler/tools-monorepo/commit/c3d1b65299f58b9fa605ebd18e7fb4346ae7745f) [@tylerbutler](https://github.com/tylerbutler)_
35
+
36
+ BREAKING CHANGES:
37
+ - `makePolicyDefinition()` now takes an object argument: `{ name, description, match, handler, defaultConfig?, resolver? }`
38
+ - `definePackagePolicy()` now takes an object argument: `{ name, description, handler }`
39
+ - `defineFileHeaderPolicy()` now takes an object argument: `{ name, description, config }`
40
+ - `Policy` class constructor now takes a `PolicyDefinition` object instead of positional arguments
41
+
42
+ This change makes it easier to add new optional properties in the future without breaking changes.
43
+
44
+ New exports:
45
+ - `makePolicyDefinition` function (previously internal)
46
+ - `PolicyDefinitionInput` type
47
+ - `DefinePackagePolicyArgs` interface
48
+ - `DefineFileHeaderPolicyArgs` interface
49
+
50
+ ### Patch Changes
51
+
52
+ - Refactor to use Effection 4 for structured concurrency _[`#379`](https://github.com/tylerbutler/tools-monorepo/pull/379) [`1582ad1`](https://github.com/tylerbutler/tools-monorepo/commit/1582ad1abc79b211492dba2e5172e995c9c47fe0) [@tylerbutler](https://github.com/tylerbutler)_
53
+ - Replace manual async handling with Effection's structured concurrency primitives
54
+ - Policy handlers now support generator functions for better cancellation and resource management
55
+ - Improved internal architecture for concurrent policy execution
56
+ - Added comprehensive test coverage for async/generator patterns
57
+
58
+ <details><summary>Updated 1 dependency</summary>
59
+
60
+ <small>
61
+
62
+ [`c577266`](https://github.com/tylerbutler/tools-monorepo/commit/c577266129da545000aea343256b06129a243987)
63
+
64
+ </small>
65
+
66
+ - `@tylerbu/cli-api@0.10.1`
67
+
68
+ </details>
69
+
3
70
  ## 0.8.0
4
71
 
5
72
  ### Minor Changes
@@ -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.19.0
30
+ - @rushstack/node-core-library@5.19.1
31
31
 
32
32
  This package contains the following license:
33
33
 
@@ -142,11 +142,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
142
142
 
143
143
  -----------
144
144
 
145
- The following npm package may be included in this product:
145
+ The following npm packages may be included in this product:
146
146
 
147
+ - effection@4.0.0
147
148
  - simple-git@3.30.0
148
149
 
149
- This package contains the following license:
150
+ These packages each contain the following license:
150
151
 
151
152
  MIT
152
153
 
@@ -61,9 +61,14 @@ function fromFluidHandler(fluidHandler, options) {
61
61
  };
62
62
  };
63
63
  }
64
- return makePolicyDefinition(policyName, fluidHandler.match, handler, undefined, // no config
65
- undefined, // no description
66
- resolver);
64
+ return makePolicyDefinition({
65
+ name: policyName,
66
+ description: `FluidFramework policy: ${fluidHandler.name}`,
67
+ match: fluidHandler.match,
68
+ handler,
69
+ defaultConfig: undefined, // no config
70
+ resolver,
71
+ });
67
72
  }
68
73
  /**
69
74
  * Converts FluidFramework handlers to repopo PolicyDefinitions.
@@ -1 +1 @@
1
- {"version":3,"file":"fluidFramework.js","sourceRoot":"","sources":["../../src/adapters/fluidFramework.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,OAAO,CAAC;AACzB,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAgExD;;;;;;;;;;GAUG;AACH,SAAS,gBAAgB,CACxB,YAA0B,EAC1B,OAA6B;IAE7B,MAAM,EAAE,UAAU,GAAG,EAAE,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;IAC1C,MAAM,UAAU,GAAG,GAAG,UAAU,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;IAEvD,MAAM,OAAO,GAAkB,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;QAChE,uCAAuC;QACvC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAE3C,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAEpE,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC;QACb,CAAC;QAED,wDAAwD;QACxD,MAAM,WAAW,GAAG,YAAY,CAAC,QAAQ,KAAK,SAAS,CAAC;QAExD,6DAA6D;QAC7D,IAAI,OAAO,IAAI,YAAY,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACpD,MAAM,aAAa,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;YAEtE,OAAO;gBACN,IAAI,EAAE,UAAU;gBAChB,IAAI;gBACJ,aAAa,EAAE,CAAC,aAAa,CAAC,OAAO,IAAI,YAAY,CAAC;gBACtD,WAAW,EAAE,IAAI;gBACjB,QAAQ,EAAE,aAAa,CAAC,QAAQ;aACN,CAAC;QAC7B,CAAC;QAED,OAAO;YACN,IAAI,EAAE,UAAU;YAChB,IAAI;YACJ,aAAa,EAAE,CAAC,YAAY,CAAC;YAC7B,WAAW;SACX,CAAC;IACH,CAAC,CAAC;IAEF,sDAAsD;IACtD,IAAI,QAA8C,CAAC;IACnD,IAAI,YAAY,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACzC,QAAQ,GAAG,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;YACnC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAE3C,0CAA0C;YAC1C,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;YAEpE,+EAA+E;YAC/E,MAAM,aAAa,GAAG,MAAM,YAAY,CAAC,QAAS,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;YAEvE,OAAO;gBACN,IAAI,EAAE,UAAU;gBAChB,IAAI;gBACJ,aAAa,EAAE;oBACd,aAAa,CAAC,OAAO,IAAI,YAAY,IAAI,eAAe;iBACxD;gBACD,WAAW,EAAE,IAAI;gBACjB,QAAQ,EAAE,aAAa,CAAC,QAAQ;aAChC,CAAC;QACH,CAAC,CAAC;IACH,CAAC;IAED,OAAO,oBAAoB,CAC1B,UAAU,EACV,YAAY,CAAC,KAAK,EAClB,OAAO,EACP,SAAS,EAAE,YAAY;IACvB,SAAS,EAAE,iBAAiB;IAC5B,QAAQ,CACR,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,UAAU,iBAAiB,CAChC,aAA6B,EAC7B,OAA6B;IAE7B,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AAC/D,CAAC","sourcesContent":["import path from \"pathe\";\nimport { makePolicyDefinition } from \"../makePolicy.js\";\nimport type {\n\tPolicyDefinition,\n\tPolicyFixResult,\n\tPolicyHandler,\n\tPolicyStandaloneResolver,\n} from \"../policy.js\";\n\n/**\n * A FluidFramework build-tools policy handler interface.\n *\n * This interface matches the `Handler` interface from `@fluidframework/build-tools`.\n *\n * @alpha\n */\nexport interface FluidHandler {\n\t/**\n\t * The name of the handler, used for filtering and display.\n\t */\n\tname: string;\n\n\t/**\n\t * A regex pattern that determines which files this handler applies to.\n\t */\n\tmatch: RegExp;\n\n\t/**\n\t * The handler function that checks a file against the policy.\n\t *\n\t * @param file - Absolute path to the file.\n\t * @param root - Path to the repo root.\n\t * @returns `undefined` if the check passes, otherwise an error message string.\n\t */\n\thandler: (file: string, root: string) => Promise<string | undefined>;\n\n\t/**\n\t * Optional resolver function that attempts to fix policy violations.\n\t *\n\t * @param file - Absolute path to the file.\n\t * @param root - Path to the repo root.\n\t * @returns An object indicating whether the fix was successful.\n\t */\n\tresolver?: (\n\t\tfile: string,\n\t\troot: string,\n\t) =>\n\t\t| Promise<{ resolved: boolean; message?: string }>\n\t\t| { resolved: boolean; message?: string };\n}\n\n/**\n * Options for converting FluidFramework handlers to repopo policies.\n *\n * @alpha\n */\nexport interface FluidAdapterOptions {\n\t/**\n\t * Optional prefix to add to policy names. Useful for namespacing Fluid policies.\n\t *\n\t * @example \"Fluid:\" would result in \"Fluid:my-handler-name\"\n\t */\n\tnamePrefix?: string;\n}\n\n/**\n * Converts a FluidFramework handler to a repopo PolicyDefinition.\n *\n * This is an internal function used by {@link fromFluidHandlers}.\n *\n * @param fluidHandler - A FluidFramework Handler object to convert.\n * @param options - Optional configuration for the conversion.\n * @returns A repopo PolicyDefinition that wraps the Fluid handler.\n *\n * @internal\n */\nfunction fromFluidHandler(\n\tfluidHandler: FluidHandler,\n\toptions?: FluidAdapterOptions,\n): PolicyDefinition {\n\tconst { namePrefix = \"\" } = options ?? {};\n\tconst policyName = `${namePrefix}${fluidHandler.name}`;\n\n\tconst handler: PolicyHandler = async ({ file, root, resolve }) => {\n\t\t// Fluid handlers expect absolute paths\n\t\tconst absolutePath = path.join(root, file);\n\n\t\tconst errorMessage = await fluidHandler.handler(absolutePath, root);\n\n\t\tif (errorMessage === undefined) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check if resolver exists to determine if auto-fixable\n\t\tconst autoFixable = fluidHandler.resolver !== undefined;\n\n\t\t// If resolve is requested and we have a resolver, try to fix\n\t\tif (resolve && fluidHandler.resolver !== undefined) {\n\t\t\tconst resolveResult = await fluidHandler.resolver(absolutePath, root);\n\n\t\t\treturn {\n\t\t\t\tname: policyName,\n\t\t\t\tfile,\n\t\t\t\terrorMessages: [resolveResult.message ?? errorMessage],\n\t\t\t\tautoFixable: true,\n\t\t\t\tresolved: resolveResult.resolved,\n\t\t\t} satisfies PolicyFixResult;\n\t\t}\n\n\t\treturn {\n\t\t\tname: policyName,\n\t\t\tfile,\n\t\t\terrorMessages: [errorMessage],\n\t\t\tautoFixable,\n\t\t};\n\t};\n\n\t// Create standalone resolver if Fluid handler has one\n\tlet resolver: PolicyStandaloneResolver | undefined;\n\tif (fluidHandler.resolver !== undefined) {\n\t\tresolver = async ({ file, root }) => {\n\t\t\tconst absolutePath = path.join(root, file);\n\n\t\t\t// First get the error message for context\n\t\t\tconst errorMessage = await fluidHandler.handler(absolutePath, root);\n\n\t\t\t// biome-ignore lint/style/noNonNullAssertion: we checked this is defined above\n\t\t\tconst resolveResult = await fluidHandler.resolver!(absolutePath, root);\n\n\t\t\treturn {\n\t\t\t\tname: policyName,\n\t\t\t\tfile,\n\t\t\t\terrorMessages: [\n\t\t\t\t\tresolveResult.message ?? errorMessage ?? \"Unknown error\",\n\t\t\t\t],\n\t\t\t\tautoFixable: true,\n\t\t\t\tresolved: resolveResult.resolved,\n\t\t\t};\n\t\t};\n\t}\n\n\treturn makePolicyDefinition(\n\t\tpolicyName,\n\t\tfluidHandler.match,\n\t\thandler,\n\t\tundefined, // no config\n\t\tundefined, // no description\n\t\tresolver,\n\t);\n}\n\n/**\n * Converts FluidFramework handlers to repopo PolicyDefinitions.\n *\n * This adapter bridges the gap between FluidFramework's build-tools policy system\n * and repopo's policy system, allowing you to reuse existing Fluid policies in repopo.\n *\n * @remarks\n *\n * Key differences handled by this adapter:\n *\n * - **Handler signature**: Fluid uses `(file, root) => string | undefined`,\n * repopo uses `(args) => PolicyHandlerResult`\n *\n * - **File paths**: Fluid passes absolute paths, repopo passes repo-relative paths.\n * The adapter converts between the two.\n *\n * - **Return types**: Fluid returns `string | undefined` (error message or success),\n * repopo returns `true | PolicyFailure | PolicyFixResult`\n *\n * For a single handler, wrap it in an array: `fromFluidHandlers([handler])`.\n *\n * @example\n * ```typescript\n * import { fromFluidHandlers, makePolicy } from \"repopo\";\n * import { copyrightFileHeaderHandlers, fluidCaseHandler } from \"@fluidframework/build-tools\";\n *\n * // Convert multiple handlers with a namespace prefix\n * const FluidCopyrightPolicies = fromFluidHandlers(copyrightFileHeaderHandlers, {\n * namePrefix: \"Fluid:\",\n * });\n *\n * // For a single handler, wrap it in an array\n * const [FluidCasePolicy] = fromFluidHandlers([fluidCaseHandler]);\n *\n * const config: RepopoConfig = {\n * policies: [\n * ...FluidCopyrightPolicies.map(p => makePolicy(p)),\n * makePolicy(FluidCasePolicy),\n * ],\n * };\n * ```\n *\n * @param fluidHandlers - An array of FluidFramework Handler objects to convert.\n * @param options - Optional configuration applied to all conversions.\n * @returns An array of repopo PolicyDefinitions.\n *\n * @alpha\n */\nexport function fromFluidHandlers(\n\tfluidHandlers: FluidHandler[],\n\toptions?: FluidAdapterOptions,\n): PolicyDefinition[] {\n\treturn fluidHandlers.map((h) => fromFluidHandler(h, options));\n}\n"]}
1
+ {"version":3,"file":"fluidFramework.js","sourceRoot":"","sources":["../../src/adapters/fluidFramework.ts"],"names":[],"mappings":"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","sourcesContent":["import path from \"pathe\";\nimport { makePolicyDefinition } from \"../makePolicy.js\";\nimport type {\n\tPolicyDefinition,\n\tPolicyFixResult,\n\tPolicyHandler,\n\tPolicyStandaloneResolver,\n} from \"../policy.js\";\n\n/**\n * A FluidFramework build-tools policy handler interface.\n *\n * This interface matches the `Handler` interface from `@fluidframework/build-tools`.\n *\n * @alpha\n */\nexport interface FluidHandler {\n\t/**\n\t * The name of the handler, used for filtering and display.\n\t */\n\tname: string;\n\n\t/**\n\t * A regex pattern that determines which files this handler applies to.\n\t */\n\tmatch: RegExp;\n\n\t/**\n\t * The handler function that checks a file against the policy.\n\t *\n\t * @param file - Absolute path to the file.\n\t * @param root - Path to the repo root.\n\t * @returns `undefined` if the check passes, otherwise an error message string.\n\t */\n\thandler: (file: string, root: string) => Promise<string | undefined>;\n\n\t/**\n\t * Optional resolver function that attempts to fix policy violations.\n\t *\n\t * @param file - Absolute path to the file.\n\t * @param root - Path to the repo root.\n\t * @returns An object indicating whether the fix was successful.\n\t */\n\tresolver?: (\n\t\tfile: string,\n\t\troot: string,\n\t) =>\n\t\t| Promise<{ resolved: boolean; message?: string }>\n\t\t| { resolved: boolean; message?: string };\n}\n\n/**\n * Options for converting FluidFramework handlers to repopo policies.\n *\n * @alpha\n */\nexport interface FluidAdapterOptions {\n\t/**\n\t * Optional prefix to add to policy names. Useful for namespacing Fluid policies.\n\t *\n\t * @example \"Fluid:\" would result in \"Fluid:my-handler-name\"\n\t */\n\tnamePrefix?: string;\n}\n\n/**\n * Converts a FluidFramework handler to a repopo PolicyDefinition.\n *\n * This is an internal function used by {@link fromFluidHandlers}.\n *\n * @param fluidHandler - A FluidFramework Handler object to convert.\n * @param options - Optional configuration for the conversion.\n * @returns A repopo PolicyDefinition that wraps the Fluid handler.\n *\n * @internal\n */\nfunction fromFluidHandler(\n\tfluidHandler: FluidHandler,\n\toptions?: FluidAdapterOptions,\n): PolicyDefinition {\n\tconst { namePrefix = \"\" } = options ?? {};\n\tconst policyName = `${namePrefix}${fluidHandler.name}`;\n\n\tconst handler: PolicyHandler = async ({ file, root, resolve }) => {\n\t\t// Fluid handlers expect absolute paths\n\t\tconst absolutePath = path.join(root, file);\n\n\t\tconst errorMessage = await fluidHandler.handler(absolutePath, root);\n\n\t\tif (errorMessage === undefined) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check if resolver exists to determine if auto-fixable\n\t\tconst autoFixable = fluidHandler.resolver !== undefined;\n\n\t\t// If resolve is requested and we have a resolver, try to fix\n\t\tif (resolve && fluidHandler.resolver !== undefined) {\n\t\t\tconst resolveResult = await fluidHandler.resolver(absolutePath, root);\n\n\t\t\treturn {\n\t\t\t\tname: policyName,\n\t\t\t\tfile,\n\t\t\t\terrorMessages: [resolveResult.message ?? errorMessage],\n\t\t\t\tautoFixable: true,\n\t\t\t\tresolved: resolveResult.resolved,\n\t\t\t} satisfies PolicyFixResult;\n\t\t}\n\n\t\treturn {\n\t\t\tname: policyName,\n\t\t\tfile,\n\t\t\terrorMessages: [errorMessage],\n\t\t\tautoFixable,\n\t\t};\n\t};\n\n\t// Create standalone resolver if Fluid handler has one\n\tlet resolver: PolicyStandaloneResolver | undefined;\n\tif (fluidHandler.resolver !== undefined) {\n\t\tresolver = async ({ file, root }) => {\n\t\t\tconst absolutePath = path.join(root, file);\n\n\t\t\t// First get the error message for context\n\t\t\tconst errorMessage = await fluidHandler.handler(absolutePath, root);\n\n\t\t\t// biome-ignore lint/style/noNonNullAssertion: we checked this is defined above\n\t\t\tconst resolveResult = await fluidHandler.resolver!(absolutePath, root);\n\n\t\t\treturn {\n\t\t\t\tname: policyName,\n\t\t\t\tfile,\n\t\t\t\terrorMessages: [\n\t\t\t\t\tresolveResult.message ?? errorMessage ?? \"Unknown error\",\n\t\t\t\t],\n\t\t\t\tautoFixable: true,\n\t\t\t\tresolved: resolveResult.resolved,\n\t\t\t};\n\t\t};\n\t}\n\n\treturn makePolicyDefinition({\n\t\tname: policyName,\n\t\tdescription: `FluidFramework policy: ${fluidHandler.name}`,\n\t\tmatch: fluidHandler.match,\n\t\thandler,\n\t\tdefaultConfig: undefined, // no config\n\t\tresolver,\n\t});\n}\n\n/**\n * Converts FluidFramework handlers to repopo PolicyDefinitions.\n *\n * This adapter bridges the gap between FluidFramework's build-tools policy system\n * and repopo's policy system, allowing you to reuse existing Fluid policies in repopo.\n *\n * @remarks\n *\n * Key differences handled by this adapter:\n *\n * - **Handler signature**: Fluid uses `(file, root) => string | undefined`,\n * repopo uses `(args) => PolicyHandlerResult`\n *\n * - **File paths**: Fluid passes absolute paths, repopo passes repo-relative paths.\n * The adapter converts between the two.\n *\n * - **Return types**: Fluid returns `string | undefined` (error message or success),\n * repopo returns `true | PolicyFailure | PolicyFixResult`\n *\n * For a single handler, wrap it in an array: `fromFluidHandlers([handler])`.\n *\n * @example\n * ```typescript\n * import { fromFluidHandlers, makePolicy } from \"repopo\";\n * import { copyrightFileHeaderHandlers, fluidCaseHandler } from \"@fluidframework/build-tools\";\n *\n * // Convert multiple handlers with a namespace prefix\n * const FluidCopyrightPolicies = fromFluidHandlers(copyrightFileHeaderHandlers, {\n * namePrefix: \"Fluid:\",\n * });\n *\n * // For a single handler, wrap it in an array\n * const [FluidCasePolicy] = fromFluidHandlers([fluidCaseHandler]);\n *\n * const config: RepopoConfig = {\n * policies: [\n * ...FluidCopyrightPolicies.map(p => makePolicy(p)),\n * makePolicy(FluidCasePolicy),\n * ],\n * };\n * ```\n *\n * @param fluidHandlers - An array of FluidFramework Handler objects to convert.\n * @param options - Optional configuration applied to all conversions.\n * @returns An array of repopo PolicyDefinitions.\n *\n * @alpha\n */\nexport function fromFluidHandlers(\n\tfluidHandlers: FluidHandler[],\n\toptions?: FluidAdapterOptions,\n): PolicyDefinition[] {\n\treturn fluidHandlers.map((h) => fromFluidHandler(h, options));\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"baseCommand.d.ts","sourceRoot":"","sources":["../src/baseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,EACjB,KAAK,kBAAkB,EAEvB,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;IACvD,UAAmB,OAAO,oCAAyB;IAEnD,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"}
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;AAG1B,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;IACvD,UAAmB,OAAO,oCAAyB;IAEnD,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"}
@@ -1,4 +1,5 @@
1
- import { CommandWithConfig, createConsolaLogger, } from "@tylerbu/cli-api";
1
+ import { CommandWithConfig, } from "@tylerbu/cli-api";
2
+ import { createConsolaLogger } from "@tylerbu/cli-api/loggers/consola";
2
3
  import { findGitRootSync } from "@tylerbu/fundamentals/git";
3
4
  import { simpleGit } from "simple-git";
4
5
  import { DefaultPolicyConfig } from "./config.js";
@@ -1 +1 @@
1
- {"version":3,"file":"baseCommand.js","sourceRoot":"","sources":["../src/baseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,EAEjB,mBAAmB,GAEnB,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;IACpC,OAAO,GAAG,mBAAmB,EAAE,CAAC;IAE5C,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\tcreateConsolaLogger,\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\tprotected override _logger = createConsolaLogger();\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"]}
1
+ {"version":3,"file":"baseCommand.js","sourceRoot":"","sources":["../src/baseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,GAGjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,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;IACpC,OAAO,GAAG,mBAAmB,EAAE,CAAC;IAE5C,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 { createConsolaLogger } from \"@tylerbu/cli-api/loggers/consola\";\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\tprotected override _logger = createConsolaLogger();\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"]}
@@ -39,6 +39,7 @@ export declare class CheckPolicy<T extends typeof BaseRepopoCommand & {
39
39
  private executePolicyHandler;
40
40
  private handlePolicyResult;
41
41
  private handleFixResult;
42
+ private handlePolicyErrorFixResult;
42
43
  private handleFailureResult;
43
44
  private attemptResolution;
44
45
  private logPolicyFailure;
@@ -1 +1 @@
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;YAuBpB,kBAAkB;IAwBhC,OAAO,CAAC,eAAe;YAoBT,mBAAmB;YAyBnB,iBAAiB;IAyB/B,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,WAAW;CAOnB"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAkCtD;;;;;;;;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;IA0D1C;;;;;OAKG;IACH,OAAO,CAAE,aAAa;IAetB;;;;;OAKG;IACH,OAAO,CAAE,kBAAkB;IAgB3B,OAAO,CAAE,eAAe;IAwBxB,OAAO,CAAE,eAAe;IAsCxB,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAE,oBAAoB;IAsD7B,OAAO,CAAE,kBAAkB;IAiC3B,OAAO,CAAC,eAAe;IAoBvB,OAAO,CAAC,0BAA0B;IAsBlC,OAAO,CAAE,mBAAmB;IAyB5B,OAAO,CAAE,iBAAiB;IAsC1B,OAAO,CAAC,gBAAgB;IA4BxB,OAAO,CAAC,WAAW;CAOnB"}
@@ -2,10 +2,20 @@ import { EOL as newline } from "node:os";
2
2
  import process from "node:process";
3
3
  import { Flags } from "@oclif/core";
4
4
  import { StringBuilder } from "@rushstack/node-core-library";
5
+ import { all, call, run } from "effection";
5
6
  import chalk from "picocolors";
7
+ /**
8
+ * Type guard to check if a value is an Effection Operation (generator).
9
+ */
10
+ function isOperation(value) {
11
+ return (typeof value === "object" &&
12
+ value !== null &&
13
+ "next" in value &&
14
+ typeof value.next === "function");
15
+ }
6
16
  import { BaseRepopoCommand } from "../baseCommand.js";
7
17
  import { logStats, runWithPerf } from "../perf.js";
8
- import { isPolicyFixResult, } from "../policy.js";
18
+ import { isPolicyError, isPolicyFixResult, } from "../policy.js";
9
19
  async function readStdin() {
10
20
  return new Promise((resolve) => {
11
21
  const stdin = process.stdin;
@@ -58,8 +68,10 @@ export class CheckPolicy extends BaseRepopoCommand {
58
68
  }
59
69
  const filePathsToCheck = [];
60
70
  if (this.flags.stdin) {
61
- const stdInput = await readStdin();
62
- if (stdInput !== undefined) {
71
+ const stdInput = await run(function* () {
72
+ return yield* call(() => readStdin());
73
+ });
74
+ if (stdInput !== undefined && stdInput !== null) {
63
75
  filePathsToCheck.push(...stdInput
64
76
  .replace(
65
77
  // normalize slashes in case they're windows paths
@@ -82,7 +94,7 @@ export class CheckPolicy extends BaseRepopoCommand {
82
94
  .split("\n"));
83
95
  }
84
96
  const context = await this.getContext();
85
- await this.checkAllFiles(filePathsToCheck, context);
97
+ await run(() => this.checkAllFiles(filePathsToCheck, context));
86
98
  }
87
99
  /**
88
100
  * Executes all policies against the provided paths.
@@ -90,10 +102,10 @@ export class CheckPolicy extends BaseRepopoCommand {
90
102
  * @param pathsToCheck - All paths that should be checked. Paths should be relative to the repository root.
91
103
  * @param context - The context.
92
104
  */
93
- async checkAllFiles(pathsToCheck, context) {
105
+ *checkAllFiles(pathsToCheck, context) {
94
106
  try {
95
107
  for (const pathToCheck of pathsToCheck) {
96
- await this.checkOrExcludeFile(pathToCheck, context);
108
+ yield* this.checkOrExcludeFile(pathToCheck, context);
97
109
  }
98
110
  }
99
111
  finally {
@@ -108,91 +120,105 @@ export class CheckPolicy extends BaseRepopoCommand {
108
120
  *
109
121
  * @param relPath - A git repo-relative path to a file.
110
122
  */
111
- async checkOrExcludeFile(relPath, context) {
123
+ *checkOrExcludeFile(relPath, context) {
112
124
  const { perfStats } = context;
113
125
  perfStats.count++;
114
126
  try {
115
- const wasProcessed = await this.routeToPolicies(relPath, context);
116
- if (wasProcessed) {
117
- perfStats.processed++;
118
- }
127
+ yield* this.routeToPolicies(relPath, context);
119
128
  }
120
129
  catch (error) {
121
130
  throw new Error(`Error routing ${relPath} to handler: ${error}\nStack:\n${error.stack}`);
122
131
  }
123
132
  }
124
- async routeToPolicies(relPath, context) {
133
+ *routeToPolicies(relPath, context) {
125
134
  const { policies, excludeFromAll } = context;
126
135
  // Check exclusions
127
136
  if (excludeFromAll.some((regex) => regex.test(relPath))) {
128
137
  this.verbose(`Excluded all handlers: ${relPath}`);
129
- return false; // File was excluded from all policies
138
+ return;
130
139
  }
131
140
  // Run all matching policies
132
141
  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);
142
+ yield* all(matchingPolicies.map((policy) => {
143
+ return this.runPolicyOnFile(relPath, policy, context);
143
144
  }));
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
145
  }
148
- async runPolicyOnFile(relPath, policy, context) {
146
+ *runPolicyOnFile(relPath, policy, context) {
149
147
  const { excludePoliciesForFiles, perfStats, gitRoot } = context;
150
148
  // Check if the policy is excluded for the file
151
149
  if (this.isPolicyExcluded(relPath, policy, excludePoliciesForFiles)) {
152
150
  this.verbose(`Excluded from '${policy.name}' policy: ${relPath}`);
153
- return false; // Policy didn't run on this file
151
+ return;
154
152
  }
155
153
  try {
156
154
  // Execute the policy handler
157
- const result = await this.executePolicyHandler(relPath, policy, perfStats, gitRoot);
155
+ const result = yield* this.executePolicyHandler(relPath, policy, perfStats, gitRoot);
158
156
  // Handle the result of the policy execution
159
- await this.handlePolicyResult(result, relPath, policy, perfStats, gitRoot);
157
+ yield* this.handlePolicyResult(result, relPath, policy, perfStats, gitRoot);
160
158
  }
161
159
  catch (error) {
162
160
  // Log and rethrow the error for higher-level handling
163
161
  this.exit(`Error executing policy '${policy.name}' for file '${relPath}': ${error}`);
164
162
  }
165
- return true; // Policy ran (successfully or with error)
166
163
  }
167
164
  isPolicyExcluded(relPath, policy, excludePoliciesForFiles) {
168
165
  return (excludePoliciesForFiles
169
166
  .get(policy.name)
170
167
  ?.some((regex) => regex.test(relPath)) ?? false);
171
168
  }
172
- async executePolicyHandler(relPath, policy, perfStats, gitRoot) {
169
+ *executePolicyHandler(relPath, policy, perfStats, gitRoot) {
170
+ const resolve = this.flags.fix;
173
171
  try {
174
- const action = this.flags.fix ? "resolve" : "check";
175
- return await runWithPerf(policy.name, action, perfStats, () => policy.handler({
176
- file: relPath,
177
- root: gitRoot,
178
- resolve: this.flags.fix,
179
- config: policy.config,
180
- }));
172
+ const result = yield* runWithPerf(policy.name, "handle", perfStats, function* () {
173
+ const args = {
174
+ file: relPath,
175
+ root: gitRoot,
176
+ resolve,
177
+ config: policy.config,
178
+ };
179
+ // Use normalized _internalHandler if available (from policy() function)
180
+ // This avoids per-invocation type checking
181
+ if (policy._internalHandler) {
182
+ return yield* policy._internalHandler(args);
183
+ }
184
+ // Fallback for policies not created with policy() function
185
+ const handlerResult = policy.handler(args);
186
+ // Handle both Operation (generator) and Promise return types
187
+ if (handlerResult instanceof Promise) {
188
+ return yield* call(() => handlerResult);
189
+ }
190
+ // Check if it's an Effection Operation (generator)
191
+ if (isOperation(handlerResult)) {
192
+ return yield* handlerResult;
193
+ }
194
+ // This should never happen with proper handler typing
195
+ throw new Error(`Unexpected handler result type: ${typeof handlerResult}`);
196
+ });
197
+ if (result === undefined) {
198
+ throw new Error("Policy result was undefined.");
199
+ }
200
+ return result;
181
201
  }
182
202
  catch (error) {
183
203
  this.exit(`Error in policy handler '${policy.name}' for file '${relPath}': ${error}`);
184
204
  }
185
205
  }
186
- async handlePolicyResult(result, relPath, policy, perfStats, gitRoot) {
206
+ *handlePolicyResult(result, relPath, policy, perfStats, gitRoot) {
187
207
  if (result === true) {
188
208
  return;
189
209
  }
210
+ // Handle fix results (both legacy and new formats)
190
211
  if (isPolicyFixResult(result)) {
191
212
  this.handleFixResult(result, policy);
213
+ return;
192
214
  }
193
- else {
194
- await this.handleFailureResult(result, relPath, policy, perfStats, gitRoot);
215
+ // Handle new PolicyError with fixed property (fix was attempted)
216
+ if (isPolicyError(result) && result.fixed !== undefined) {
217
+ this.handlePolicyErrorFixResult(result, relPath, policy);
218
+ return;
195
219
  }
220
+ // Handle failure results (PolicyFailure or PolicyError without fix)
221
+ yield* this.handleFailureResult(result, relPath, policy, perfStats, gitRoot);
196
222
  }
197
223
  handleFixResult(result, policy) {
198
224
  const messages = new StringBuilder();
@@ -205,19 +231,45 @@ export class CheckPolicy extends BaseRepopoCommand {
205
231
  }
206
232
  this.logMessages(messages);
207
233
  }
208
- async handleFailureResult(result, relPath, policy, perfStats, gitRoot) {
234
+ handlePolicyErrorFixResult(result, file, policy) {
235
+ const messages = new StringBuilder();
236
+ if (result.fixed) {
237
+ messages.append(`Resolved ${policy.name} policy failure for file: ${file}`);
238
+ }
239
+ else {
240
+ messages.append(`Error fixing ${policy.name} policy failure in ${file}`);
241
+ if (result.error) {
242
+ messages.append(`${newline}\t${result.error}`);
243
+ }
244
+ process.exitCode = 1;
245
+ }
246
+ this.logMessages(messages);
247
+ }
248
+ *handleFailureResult(result, relPath, policy, perfStats, gitRoot) {
209
249
  const messages = new StringBuilder();
210
250
  if (this.flags.fix && policy.resolver) {
211
- await this.attemptResolution(relPath, policy, policy.resolver, perfStats, gitRoot, messages);
251
+ yield* this.attemptResolution(relPath, policy, policy.resolver, perfStats, gitRoot, messages);
212
252
  }
213
253
  else {
214
- this.logPolicyFailure(result, policy, messages);
254
+ this.logPolicyFailure(result, relPath, policy, messages);
215
255
  }
216
256
  this.logMessages(messages);
217
257
  }
218
- async attemptResolution(relPath, policy, resolver, perfStats, gitRoot, messages) {
258
+ *attemptResolution(relPath, policy, resolver, perfStats, gitRoot, messages) {
219
259
  messages.append(`${newline}Attempting to resolve: ${relPath}`);
220
- const resolveResult = await runWithPerf(policy.name, "resolve", perfStats, () => resolver({ file: relPath, root: gitRoot }));
260
+ const resolveResult = yield* runWithPerf(policy.name, "resolve", perfStats, function* () {
261
+ const result = resolver({ file: relPath, root: gitRoot });
262
+ // Handle both Operation (generator) and Promise return types
263
+ if (result instanceof Promise) {
264
+ return yield* call(() => result);
265
+ }
266
+ // Check if it's an Effection Operation (generator)
267
+ if (isOperation(result)) {
268
+ return yield* result;
269
+ }
270
+ // This should never happen with proper resolver typing
271
+ throw new Error(`Unexpected resolver result type: ${typeof result}`);
272
+ });
221
273
  if (!resolveResult.resolved) {
222
274
  process.exitCode = 1;
223
275
  }
@@ -225,11 +277,21 @@ export class CheckPolicy extends BaseRepopoCommand {
225
277
  messages.append(newline + resolveResult.errorMessages.join(newline));
226
278
  }
227
279
  }
228
- logPolicyFailure(result, policy, messages) {
229
- const autoFixable = result.autoFixable ? chalk.green(" (autofixable)") : "";
230
- messages.append(`'${chalk.bold(policy.name)}' policy failure${autoFixable}: ${result.file}`);
231
- if (result.errorMessages?.length > 0) {
232
- messages.append(`${newline}\t${result.errorMessages.join(`${newline}\t`)}`);
280
+ logPolicyFailure(result, file, policy, messages) {
281
+ // Handle both legacy PolicyFailure and new PolicyError formats
282
+ if (isPolicyError(result)) {
283
+ const autoFixable = result.fixable ? chalk.green(" (autofixable)") : "";
284
+ messages.append(`'${chalk.bold(policy.name)}' policy failure${autoFixable}: ${file}`);
285
+ messages.append(`${newline}\t${result.error}`);
286
+ }
287
+ else {
288
+ const autoFixable = result.autoFixable
289
+ ? chalk.green(" (autofixable)")
290
+ : "";
291
+ messages.append(`'${chalk.bold(policy.name)}' policy failure${autoFixable}: ${result.file}`);
292
+ if (result.errorMessages?.length > 0) {
293
+ messages.append(`${newline}\t${result.errorMessages.join(`${newline}\t`)}`);
294
+ }
233
295
  }
234
296
  process.exitCode = 1;
235
297
  }
@@ -1 +1 @@
1
- {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"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","sourcesContent":["import { EOL as newline } from \"node:os\";\nimport process from \"node:process\";\nimport { Flags } from \"@oclif/core\";\nimport { StringBuilder } from \"@rushstack/node-core-library\";\nimport chalk from \"picocolors\";\nimport { BaseRepopoCommand } from \"../baseCommand.js\";\nimport type { RepopoCommandContext } from \"../context.js\";\nimport { logStats, type PolicyHandlerPerfStats, runWithPerf } from \"../perf.js\";\nimport {\n\tisPolicyFixResult,\n\ttype PolicyFailure,\n\ttype PolicyFixResult,\n\ttype PolicyHandlerResult,\n\ttype PolicyInstance,\n\ttype PolicyStandaloneResolver,\n} from \"../policy.js\";\n\nasync function readStdin(): Promise<string> {\n\treturn new Promise((resolve) => {\n\t\tconst stdin = process.stdin;\n\t\tstdin.setEncoding(\"utf8\");\n\n\t\tlet data = \"\";\n\t\tstdin.on(\"data\", (chunk) => {\n\t\t\tdata += chunk;\n\t\t});\n\n\t\tstdin.on(\"end\", () => {\n\t\t\tresolve(data);\n\t\t});\n\n\t\tif (stdin.isTTY) {\n\t\t\tresolve(\"\");\n\t\t}\n\t});\n}\n\n/**\n * This tool enforces policies across the code base via a series of handler functions. The handler functions are\n * associated with a regular expression, and all files matching that expression are passed to the handler function.\n *\n * By default, the list of files to check comes from `git ls-files. You can also pipe in file names from stdin. For\n * example:\n *\n * `git ls-files -co --exclude-standard --full-name | repopo check --stdin --verbose`\n */\nexport class CheckPolicy<\n\tT extends typeof BaseRepopoCommand & {\n\t\targs: typeof CheckPolicy.args;\n\t\tflags: typeof CheckPolicy.flags;\n\t},\n> extends BaseRepopoCommand<T> {\n\tpublic static override readonly summary =\n\t\t\"Checks and applies policies to the files in the repository.\";\n\n\tpublic static override readonly flags = {\n\t\tfix: Flags.boolean({\n\t\t\taliases: [\"resolve\"],\n\t\t\tdescription: \"Fix errors if possible.\",\n\t\t\trequired: false,\n\t\t\tchar: \"f\",\n\t\t}),\n\t\tstdin: Flags.boolean({\n\t\t\tdescription: \"Read list of files from stdin.\",\n\t\t\trequired: false,\n\t\t}),\n\t\t...BaseRepopoCommand.flags,\n\t} as const;\n\n\tpublic override async run(): Promise<void> {\n\t\tif (this.flags.fix) {\n\t\t\tthis.info(\"Resolving errors if possible.\");\n\t\t}\n\n\t\tconst config = this.commandConfig;\n\t\tconst policies = config?.policies ?? [];\n\t\tthis.verbose(`${policies.length} policies loaded.`);\n\t\tfor (const h of policies) {\n\t\t\tthis.verbose(h.name);\n\t\t}\n\n\t\tconst filePathsToCheck: string[] = [];\n\n\t\tif (this.flags.stdin) {\n\t\t\tconst stdInput = await readStdin();\n\n\t\t\tif (stdInput !== undefined) {\n\t\t\t\tfilePathsToCheck.push(\n\t\t\t\t\t...stdInput\n\t\t\t\t\t\t.replace(\n\t\t\t\t\t\t\t// normalize slashes in case they're windows paths\n\t\t\t\t\t\t\t/\\\\/g,\n\t\t\t\t\t\t\t\"/\",\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.split(\"\\n\"),\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tconst gitFiles =\n\t\t\t\t(await this.git.raw(\n\t\t\t\t\t\"ls-files\",\n\t\t\t\t\t// include staged files and untracked files\n\t\t\t\t\t\"-co\",\n\t\t\t\t\t// exclude gitignored files and other standard ignore rules\n\t\t\t\t\t\"--exclude-standard\",\n\t\t\t\t\t// Outputs paths relative to the root of the repository, regardless of the current working directory.\n\t\t\t\t\t\"--full-name\",\n\t\t\t\t)) ?? \"\";\n\n\t\t\tfilePathsToCheck.push(\n\t\t\t\t...gitFiles\n\t\t\t\t\t.replace(\n\t\t\t\t\t\t// normalize slashes in case they're windows paths\n\t\t\t\t\t\t/\\\\/g,\n\t\t\t\t\t\t\"/\",\n\t\t\t\t\t)\n\t\t\t\t\t.split(\"\\n\"),\n\t\t\t);\n\t\t}\n\n\t\tconst context: RepopoCommandContext = await this.getContext();\n\n\t\tawait this.checkAllFiles(filePathsToCheck, context);\n\t}\n\n\t/**\n\t * Executes all policies against the provided paths.\n\t *\n\t * @param pathsToCheck - All paths that should be checked. Paths should be relative to the repository root.\n\t * @param context - The context.\n\t */\n\tprivate async checkAllFiles(\n\t\tpathsToCheck: string[],\n\t\tcontext: RepopoCommandContext,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tfor (const pathToCheck of pathsToCheck) {\n\t\t\t\tawait this.checkOrExcludeFile(pathToCheck, context);\n\t\t\t}\n\t\t} finally {\n\t\t\tif (!this.flags.quiet) {\n\t\t\t\tlogStats(context.perfStats, this.logger);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Given a string that represents a path to a file in the repo, determines if the file should be checked, and if so,\n\t * routes the file to the appropriate handlers.\n\t *\n\t * @param relPath - A git repo-relative path to a file.\n\t */\n\tprivate async checkOrExcludeFile(\n\t\trelPath: string,\n\t\tcontext: RepopoCommandContext,\n\t): Promise<void> {\n\t\tconst { perfStats } = context;\n\t\tperfStats.count++;\n\n\t\ttry {\n\t\t\tconst wasProcessed = await this.routeToPolicies(relPath, context);\n\t\t\tif (wasProcessed) {\n\t\t\t\tperfStats.processed++;\n\t\t\t}\n\t\t} catch (error: unknown) {\n\t\t\tthrow new Error(\n\t\t\t\t`Error routing ${relPath} to handler: ${error}\\nStack:\\n${(error as Error).stack}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async routeToPolicies(\n\t\trelPath: string,\n\t\tcontext: RepopoCommandContext,\n\t): Promise<boolean> {\n\t\tconst { policies, excludeFromAll } = context;\n\n\t\t// Check exclusions\n\t\tif (excludeFromAll.some((regex) => regex.test(relPath))) {\n\t\t\tthis.verbose(`Excluded all handlers: ${relPath}`);\n\t\t\treturn false; // File was excluded from all policies\n\t\t}\n\n\t\t// Run all matching policies\n\t\tconst matchingPolicies = policies.filter((policy) =>\n\t\t\tpolicy.match.test(relPath),\n\t\t);\n\n\t\t// for(const policy of matchingPolicies) {\n\t\t// \tbars.addFile(policy.name,\n\t\t// }\n\n\t\t// If no policies match this file, it's still considered processed\n\t\t// (we examined it and determined no policies apply)\n\t\tif (matchingPolicies.length === 0) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst results = await Promise.all(\n\t\t\tmatchingPolicies.map(async (policy) => {\n\t\t\t\treturn await this.runPolicyOnFile(relPath, policy, context);\n\t\t\t}),\n\t\t);\n\n\t\t// File is considered processed if at least one policy ran on it\n\t\t// If all matching policies excluded it, count as excluded\n\t\treturn results.some((ran) => ran);\n\t}\n\n\tprivate async runPolicyOnFile(\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\tcontext: RepopoCommandContext,\n\t): Promise<boolean> {\n\t\tconst { excludePoliciesForFiles, perfStats, gitRoot } = context;\n\n\t\t// Check if the policy is excluded for the file\n\t\tif (this.isPolicyExcluded(relPath, policy, excludePoliciesForFiles)) {\n\t\t\tthis.verbose(`Excluded from '${policy.name}' policy: ${relPath}`);\n\t\t\treturn false; // Policy didn't run on this file\n\t\t}\n\n\t\ttry {\n\t\t\t// Execute the policy handler\n\t\t\tconst result = await this.executePolicyHandler(\n\t\t\t\trelPath,\n\t\t\t\tpolicy,\n\t\t\t\tperfStats,\n\t\t\t\tgitRoot,\n\t\t\t);\n\n\t\t\t// Handle the result of the policy execution\n\t\t\tawait this.handlePolicyResult(\n\t\t\t\tresult,\n\t\t\t\trelPath,\n\t\t\t\tpolicy,\n\t\t\t\tperfStats,\n\t\t\t\tgitRoot,\n\t\t\t);\n\t\t} catch (error: unknown) {\n\t\t\t// Log and rethrow the error for higher-level handling\n\t\t\tthis.exit(\n\t\t\t\t`Error executing policy '${policy.name}' for file '${relPath}': ${error}`,\n\t\t\t);\n\t\t}\n\n\t\treturn true; // Policy ran (successfully or with error)\n\t}\n\n\tprivate isPolicyExcluded(\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\texcludePoliciesForFiles: Map<string, RegExp[]>,\n\t): boolean {\n\t\treturn (\n\t\t\texcludePoliciesForFiles\n\t\t\t\t.get(policy.name)\n\t\t\t\t?.some((regex) => regex.test(relPath)) ?? false\n\t\t);\n\t}\n\n\tprivate async executePolicyHandler(\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\tperfStats: PolicyHandlerPerfStats,\n\t\tgitRoot: string,\n\t): Promise<PolicyHandlerResult> {\n\t\ttry {\n\t\t\tconst action = this.flags.fix ? \"resolve\" : \"check\";\n\t\t\treturn await runWithPerf(policy.name, action, perfStats, () =>\n\t\t\t\tpolicy.handler({\n\t\t\t\t\tfile: relPath,\n\t\t\t\t\troot: gitRoot,\n\t\t\t\t\tresolve: this.flags.fix,\n\t\t\t\t\tconfig: policy.config,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error: unknown) {\n\t\t\tthis.exit(\n\t\t\t\t`Error in policy handler '${policy.name}' for file '${relPath}': ${error}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async handlePolicyResult(\n\t\tresult: PolicyHandlerResult,\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\tperfStats: PolicyHandlerPerfStats,\n\t\tgitRoot: string,\n\t): Promise<void> {\n\t\tif (result === true) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (isPolicyFixResult(result)) {\n\t\t\tthis.handleFixResult(result, policy);\n\t\t} else {\n\t\t\tawait this.handleFailureResult(\n\t\t\t\tresult,\n\t\t\t\trelPath,\n\t\t\t\tpolicy,\n\t\t\t\tperfStats,\n\t\t\t\tgitRoot,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate handleFixResult(\n\t\tresult: PolicyFixResult,\n\t\tpolicy: PolicyInstance,\n\t): void {\n\t\tconst messages = new StringBuilder();\n\n\t\tif (result.resolved) {\n\t\t\tmessages.append(\n\t\t\t\t`Resolved ${policy.name} policy failure for file: ${result.file}`,\n\t\t\t);\n\t\t} else {\n\t\t\tmessages.append(\n\t\t\t\t`Error fixing ${policy.name} policy failure in ${result.file}`,\n\t\t\t);\n\t\t\tprocess.exitCode = 1;\n\t\t}\n\n\t\tthis.logMessages(messages);\n\t}\n\n\tprivate async handleFailureResult(\n\t\tresult: PolicyFailure,\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\tperfStats: PolicyHandlerPerfStats,\n\t\tgitRoot: string,\n\t): Promise<void> {\n\t\tconst messages = new StringBuilder();\n\n\t\tif (this.flags.fix && policy.resolver) {\n\t\t\tawait this.attemptResolution(\n\t\t\t\trelPath,\n\t\t\t\tpolicy,\n\t\t\t\tpolicy.resolver,\n\t\t\t\tperfStats,\n\t\t\t\tgitRoot,\n\t\t\t\tmessages,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.logPolicyFailure(result, policy, messages);\n\t\t}\n\n\t\tthis.logMessages(messages);\n\t}\n\n\tprivate async attemptResolution(\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\tresolver: PolicyStandaloneResolver,\n\t\tperfStats: PolicyHandlerPerfStats,\n\t\tgitRoot: string,\n\t\tmessages: StringBuilder,\n\t): Promise<void> {\n\t\tmessages.append(`${newline}Attempting to resolve: ${relPath}`);\n\t\tconst resolveResult = await runWithPerf(\n\t\t\tpolicy.name,\n\t\t\t\"resolve\",\n\t\t\tperfStats,\n\t\t\t() => resolver({ file: relPath, root: gitRoot }),\n\t\t);\n\n\t\tif (!resolveResult.resolved) {\n\t\t\tprocess.exitCode = 1;\n\t\t}\n\n\t\tif (resolveResult.errorMessages?.length > 0) {\n\t\t\tmessages.append(newline + resolveResult.errorMessages.join(newline));\n\t\t}\n\t}\n\n\tprivate logPolicyFailure(\n\t\tresult: PolicyFailure,\n\t\tpolicy: PolicyInstance,\n\t\tmessages: StringBuilder,\n\t): void {\n\t\tconst autoFixable = result.autoFixable ? chalk.green(\" (autofixable)\") : \"\";\n\t\tmessages.append(\n\t\t\t`'${chalk.bold(policy.name)}' policy failure${autoFixable}: ${result.file}`,\n\t\t);\n\t\tif (result.errorMessages?.length > 0) {\n\t\t\tmessages.append(\n\t\t\t\t`${newline}\\t${result.errorMessages.join(`${newline}\\t`)}`,\n\t\t\t);\n\t\t}\n\t\tprocess.exitCode = 1;\n\t}\n\tprivate logMessages(messages: StringBuilder): void {\n\t\tif ((process.exitCode ?? 0) === 0) {\n\t\t\tthis.info(messages.toString());\n\t\t} else {\n\t\t\tthis.warning(messages.toString());\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,IAAI,OAAO,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,GAAG,EAAE,IAAI,EAAkB,GAAG,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B;;GAEG;AACH,SAAS,WAAW,CAAI,KAAc;IACrC,OAAO,CACN,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,MAAM,IAAI,KAAK;QACf,OAAQ,KAA2B,CAAC,IAAI,KAAK,UAAU,CACvD,CAAC;AACH,CAAC;AAED,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,OAAO,EAAE,QAAQ,EAA+B,WAAW,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EACN,aAAa,EACb,iBAAiB,GAOjB,MAAM,cAAc,CAAC;AAEtB,KAAK,UAAU,SAAS;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAE1B,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAC1B,IAAI,IAAI,KAAK,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACpB,OAAO,CAAC,IAAI,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YACjB,OAAO,CAAC,EAAE,CAAC,CAAC;QACb,CAAC;IACF,CAAC,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,WAKX,SAAQ,iBAAoB;IACtB,MAAM,CAAmB,OAAO,GACtC,6DAA6D,CAAC;IAExD,MAAM,CAAmB,KAAK,GAAG;QACvC,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC;YAClB,OAAO,EAAE,CAAC,SAAS,CAAC;YACpB,WAAW,EAAE,yBAAyB;YACtC,QAAQ,EAAE,KAAK;YACf,IAAI,EAAE,GAAG;SACT,CAAC;QACF,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC;YACpB,WAAW,EAAE,gCAAgC;YAC7C,QAAQ,EAAE,KAAK;SACf,CAAC;QACF,GAAG,iBAAiB,CAAC,KAAK;KACjB,CAAC;IAEK,KAAK,CAAC,GAAG;QACxB,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;YACpB,IAAI,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAC5C,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC;QAClC,MAAM,QAAQ,GAAG,MAAM,EAAE,QAAQ,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,mBAAmB,CAAC,CAAC;QACpD,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;QAED,MAAM,gBAAgB,GAAa,EAAE,CAAC;QAEtC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACtB,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC;gBACnC,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC;YACvC,CAAC,CAAC,CAAC;YAEH,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACjD,gBAAgB,CAAC,IAAI,CACpB,GAAG,QAAQ;qBACT,OAAO;gBACP,kDAAkD;gBAClD,KAAK,EACL,GAAG,CACH;qBACA,KAAK,CAAC,IAAI,CAAC,CACb,CAAC;YACH,CAAC;QACF,CAAC;aAAM,CAAC;YACP,MAAM,QAAQ,GACb,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAClB,UAAU;YACV,2CAA2C;YAC3C,KAAK;YACL,2DAA2D;YAC3D,oBAAoB;YACpB,qGAAqG;YACrG,aAAa,CACb,CAAC,IAAI,EAAE,CAAC;YAEV,gBAAgB,CAAC,IAAI,CACpB,GAAG,QAAQ;iBACT,OAAO;YACP,kDAAkD;YAClD,KAAK,EACL,GAAG,CACH;iBACA,KAAK,CAAC,IAAI,CAAC,CACb,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAyB,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QAE9D,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC;IAChE,CAAC;IAED;;;;;OAKG;IACK,CAAC,aAAa,CACrB,YAAsB,EACtB,OAA6B;QAE7B,IAAI,CAAC;YACJ,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;gBACxC,KAAK,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YACtD,CAAC;QACF,CAAC;gBAAS,CAAC;YACV,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;gBACvB,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YAC1C,CAAC;QACF,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACK,CAAC,kBAAkB,CAC1B,OAAe,EACf,OAA6B;QAE7B,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;QAC9B,SAAS,CAAC,KAAK,EAAE,CAAC;QAElB,IAAI,CAAC;YACJ,KAAK,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACd,iBAAiB,OAAO,gBAAgB,KAAK,aAAc,KAAe,CAAC,KAAK,EAAE,CAClF,CAAC;QACH,CAAC;IACF,CAAC;IAEO,CAAC,eAAe,CACvB,OAAe,EACf,OAA6B;QAE7B,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;QAE7C,mBAAmB;QACnB,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YACzD,IAAI,CAAC,OAAO,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAC;YAClD,OAAO;QACR,CAAC;QAED,4BAA4B;QAC5B,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CACnD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAC1B,CAAC;QAEF,KAAK,CAAC,CAAC,GAAG,CACT,gBAAgB,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YAC/B,OAAO,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC,CAAC,CACF,CAAC;IACH,CAAC;IAEO,CAAC,eAAe,CACvB,OAAe,EACf,MAAsB,EACtB,OAA6B;QAE7B,MAAM,EAAE,uBAAuB,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QAEhE,+CAA+C;QAC/C,IAAI,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,uBAAuB,CAAC,EAAE,CAAC;YACrE,IAAI,CAAC,OAAO,CAAC,kBAAkB,MAAM,CAAC,IAAI,aAAa,OAAO,EAAE,CAAC,CAAC;YAClE,OAAO;QACR,CAAC;QAED,IAAI,CAAC;YACJ,6BAA6B;YAC7B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAC9C,OAAO,EACP,MAAM,EACN,SAAS,EACT,OAAO,CACP,CAAC;YAEF,4CAA4C;YAC5C,KAAK,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAC7B,MAAM,EACN,OAAO,EACP,MAAM,EACN,SAAS,EACT,OAAO,CACP,CAAC;QACH,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACzB,sDAAsD;YACtD,IAAI,CAAC,IAAI,CACR,2BAA2B,MAAM,CAAC,IAAI,eAAe,OAAO,MAAM,KAAK,EAAE,CACzE,CAAC;QACH,CAAC;IACF,CAAC;IAEO,gBAAgB,CACvB,OAAe,EACf,MAAsB,EACtB,uBAA8C;QAE9C,OAAO,CACN,uBAAuB;aACrB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;YACjB,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,CAChD,CAAC;IACH,CAAC;IAEO,CAAC,oBAAoB,CAC5B,OAAe,EACf,MAAsB,EACtB,SAAiC,EACjC,OAAe;QAEf,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;QAC/B,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,WAAW,CAChC,MAAM,CAAC,IAAI,EACX,QAAQ,EACR,SAAS,EACT,QAAQ,CAAC;gBACR,MAAM,IAAI,GAAG;oBACZ,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,OAAO;oBACb,OAAO;oBACP,MAAM,EAAE,MAAM,CAAC,MAAM;iBACrB,CAAC;gBAEF,wEAAwE;gBACxE,2CAA2C;gBAC3C,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;oBAC7B,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;gBAC7C,CAAC;gBAED,2DAA2D;gBAC3D,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAE3C,6DAA6D;gBAC7D,IAAI,aAAa,YAAY,OAAO,EAAE,CAAC;oBACtC,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC;gBACzC,CAAC;gBACD,mDAAmD;gBACnD,IAAI,WAAW,CAAsB,aAAa,CAAC,EAAE,CAAC;oBACrD,OAAO,KAAK,CAAC,CAAC,aAAa,CAAC;gBAC7B,CAAC;gBACD,sDAAsD;gBACtD,MAAM,IAAI,KAAK,CACd,mCAAmC,OAAO,aAAa,EAAE,CACzD,CAAC;YACH,CAAC,CACD,CAAC;YACF,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;YACjD,CAAC;YACD,OAAO,MAAM,CAAC;QACf,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CACR,4BAA4B,MAAM,CAAC,IAAI,eAAe,OAAO,MAAM,KAAK,EAAE,CAC1E,CAAC;QACH,CAAC;IACF,CAAC;IAEO,CAAC,kBAAkB,CAC1B,MAA2B,EAC3B,OAAe,EACf,MAAsB,EACtB,SAAiC,EACjC,OAAe;QAEf,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACrB,OAAO;QACR,CAAC;QAED,mDAAmD;QACnD,IAAI,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACrC,OAAO;QACR,CAAC;QAED,iEAAiE;QACjE,IAAI,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YACzD,IAAI,CAAC,0BAA0B,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;YACzD,OAAO;QACR,CAAC;QAED,oEAAoE;QACpE,KAAK,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAC9B,MAAM,EACN,OAAO,EACP,MAAM,EACN,SAAS,EACT,OAAO,CACP,CAAC;IACH,CAAC;IAEO,eAAe,CACtB,MAAuB,EACvB,MAAsB;QAEtB,MAAM,QAAQ,GAAG,IAAI,aAAa,EAAE,CAAC;QAErC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrB,QAAQ,CAAC,MAAM,CACd,YAAY,MAAM,CAAC,IAAI,6BAA6B,MAAM,CAAC,IAAI,EAAE,CACjE,CAAC;QACH,CAAC;aAAM,CAAC;YACP,QAAQ,CAAC,MAAM,CACd,gBAAgB,MAAM,CAAC,IAAI,sBAAsB,MAAM,CAAC,IAAI,EAAE,CAC9D,CAAC;YACF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACtB,CAAC;QAED,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IAEO,0BAA0B,CACjC,MAAmB,EACnB,IAAY,EACZ,MAAsB;QAEtB,MAAM,QAAQ,GAAG,IAAI,aAAa,EAAE,CAAC;QAErC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,QAAQ,CAAC,MAAM,CACd,YAAY,MAAM,CAAC,IAAI,6BAA6B,IAAI,EAAE,CAC1D,CAAC;QACH,CAAC;aAAM,CAAC;YACP,QAAQ,CAAC,MAAM,CAAC,gBAAgB,MAAM,CAAC,IAAI,sBAAsB,IAAI,EAAE,CAAC,CAAC;YACzE,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBAClB,QAAQ,CAAC,MAAM,CAAC,GAAG,OAAO,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;YAChD,CAAC;YACD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACtB,CAAC;QAED,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IAEO,CAAC,mBAAmB,CAC3B,MAAmC,EACnC,OAAe,EACf,MAAsB,EACtB,SAAiC,EACjC,OAAe;QAEf,MAAM,QAAQ,GAAG,IAAI,aAAa,EAAE,CAAC;QAErC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACvC,KAAK,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAC5B,OAAO,EACP,MAAM,EACN,MAAM,CAAC,QAAQ,EACf,SAAS,EACT,OAAO,EACP,QAAQ,CACR,CAAC;QACH,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IAEO,CAAC,iBAAiB,CACzB,OAAe,EACf,MAAsB,EACtB,QAAkC,EAClC,SAAiC,EACjC,OAAe,EACf,QAAuB;QAEvB,QAAQ,CAAC,MAAM,CAAC,GAAG,OAAO,0BAA0B,OAAO,EAAE,CAAC,CAAC;QAC/D,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,WAAW,CACvC,MAAM,CAAC,IAAI,EACX,SAAS,EACT,SAAS,EACT,QAAQ,CAAC;YACR,MAAM,MAAM,GAAG,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YAE1D,6DAA6D;YAC7D,IAAI,MAAM,YAAY,OAAO,EAAE,CAAC;gBAC/B,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;YAClC,CAAC;YACD,mDAAmD;YACnD,IAAI,WAAW,CAAkB,MAAM,CAAC,EAAE,CAAC;gBAC1C,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC;YACtB,CAAC;YACD,uDAAuD;YACvD,MAAM,IAAI,KAAK,CAAC,oCAAoC,OAAO,MAAM,EAAE,CAAC,CAAC;QACtE,CAAC,CACD,CAAC;QAEF,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC;YAC7B,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACtB,CAAC;QAED,IAAI,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7C,QAAQ,CAAC,MAAM,CAAC,OAAO,GAAG,aAAa,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACtE,CAAC;IACF,CAAC;IAEO,gBAAgB,CACvB,MAAmC,EACnC,IAAY,EACZ,MAAsB,EACtB,QAAuB;QAEvB,+DAA+D;QAC/D,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACxE,QAAQ,CAAC,MAAM,CACd,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,WAAW,KAAK,IAAI,EAAE,CACpE,CAAC;YACF,QAAQ,CAAC,MAAM,CAAC,GAAG,OAAO,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACP,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW;gBACrC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC;gBAC/B,CAAC,CAAC,EAAE,CAAC;YACN,QAAQ,CAAC,MAAM,CACd,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,WAAW,KAAK,MAAM,CAAC,IAAI,EAAE,CAC3E,CAAC;YACF,IAAI,MAAM,CAAC,aAAa,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtC,QAAQ,CAAC,MAAM,CACd,GAAG,OAAO,KAAK,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,OAAO,IAAI,CAAC,EAAE,CAC1D,CAAC;YACH,CAAC;QACF,CAAC;QACD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACtB,CAAC;IACO,WAAW,CAAC,QAAuB;QAC1C,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;QAChC,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;QACnC,CAAC;IACF,CAAC","sourcesContent":["import { EOL as newline } from \"node:os\";\nimport process from \"node:process\";\nimport { Flags } from \"@oclif/core\";\nimport { StringBuilder } from \"@rushstack/node-core-library\";\nimport { all, call, type Operation, run } from \"effection\";\nimport chalk from \"picocolors\";\n\n/**\n * Type guard to check if a value is an Effection Operation (generator).\n */\nfunction isOperation<T>(value: unknown): value is Operation<T> {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"next\" in value &&\n\t\ttypeof (value as { next: unknown }).next === \"function\"\n\t);\n}\n\nimport { BaseRepopoCommand } from \"../baseCommand.js\";\nimport type { RepopoCommandContext } from \"../context.js\";\nimport { logStats, type PolicyHandlerPerfStats, runWithPerf } from \"../perf.js\";\nimport {\n\tisPolicyError,\n\tisPolicyFixResult,\n\ttype PolicyError,\n\ttype PolicyFailure,\n\ttype PolicyFixResult,\n\ttype PolicyHandlerResult,\n\ttype PolicyInstance,\n\ttype PolicyStandaloneResolver,\n} from \"../policy.js\";\n\nasync function readStdin(): Promise<string> {\n\treturn new Promise((resolve) => {\n\t\tconst stdin = process.stdin;\n\t\tstdin.setEncoding(\"utf8\");\n\n\t\tlet data = \"\";\n\t\tstdin.on(\"data\", (chunk) => {\n\t\t\tdata += chunk;\n\t\t});\n\n\t\tstdin.on(\"end\", () => {\n\t\t\tresolve(data);\n\t\t});\n\n\t\tif (stdin.isTTY) {\n\t\t\tresolve(\"\");\n\t\t}\n\t});\n}\n\n/**\n * This tool enforces policies across the code base via a series of handler functions. The handler functions are\n * associated with a regular expression, and all files matching that expression are passed to the handler function.\n *\n * By default, the list of files to check comes from `git ls-files. You can also pipe in file names from stdin. For\n * example:\n *\n * `git ls-files -co --exclude-standard --full-name | repopo check --stdin --verbose`\n */\nexport class CheckPolicy<\n\tT extends typeof BaseRepopoCommand & {\n\t\targs: typeof CheckPolicy.args;\n\t\tflags: typeof CheckPolicy.flags;\n\t},\n> extends BaseRepopoCommand<T> {\n\tpublic static override readonly summary =\n\t\t\"Checks and applies policies to the files in the repository.\";\n\n\tpublic static override readonly flags = {\n\t\tfix: Flags.boolean({\n\t\t\taliases: [\"resolve\"],\n\t\t\tdescription: \"Fix errors if possible.\",\n\t\t\trequired: false,\n\t\t\tchar: \"f\",\n\t\t}),\n\t\tstdin: Flags.boolean({\n\t\t\tdescription: \"Read list of files from stdin.\",\n\t\t\trequired: false,\n\t\t}),\n\t\t...BaseRepopoCommand.flags,\n\t} as const;\n\n\tpublic override async run(): Promise<void> {\n\t\tif (this.flags.fix) {\n\t\t\tthis.info(\"Resolving errors if possible.\");\n\t\t}\n\n\t\tconst config = this.commandConfig;\n\t\tconst policies = config?.policies ?? [];\n\t\tthis.verbose(`${policies.length} policies loaded.`);\n\t\tfor (const h of policies) {\n\t\t\tthis.verbose(h.name);\n\t\t}\n\n\t\tconst filePathsToCheck: string[] = [];\n\n\t\tif (this.flags.stdin) {\n\t\t\tconst stdInput = await run(function* () {\n\t\t\t\treturn yield* call(() => readStdin());\n\t\t\t});\n\n\t\t\tif (stdInput !== undefined && stdInput !== null) {\n\t\t\t\tfilePathsToCheck.push(\n\t\t\t\t\t...stdInput\n\t\t\t\t\t\t.replace(\n\t\t\t\t\t\t\t// normalize slashes in case they're windows paths\n\t\t\t\t\t\t\t/\\\\/g,\n\t\t\t\t\t\t\t\"/\",\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.split(\"\\n\"),\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tconst gitFiles =\n\t\t\t\t(await this.git.raw(\n\t\t\t\t\t\"ls-files\",\n\t\t\t\t\t// include staged files and untracked files\n\t\t\t\t\t\"-co\",\n\t\t\t\t\t// exclude gitignored files and other standard ignore rules\n\t\t\t\t\t\"--exclude-standard\",\n\t\t\t\t\t// Outputs paths relative to the root of the repository, regardless of the current working directory.\n\t\t\t\t\t\"--full-name\",\n\t\t\t\t)) ?? \"\";\n\n\t\t\tfilePathsToCheck.push(\n\t\t\t\t...gitFiles\n\t\t\t\t\t.replace(\n\t\t\t\t\t\t// normalize slashes in case they're windows paths\n\t\t\t\t\t\t/\\\\/g,\n\t\t\t\t\t\t\"/\",\n\t\t\t\t\t)\n\t\t\t\t\t.split(\"\\n\"),\n\t\t\t);\n\t\t}\n\n\t\tconst context: RepopoCommandContext = await this.getContext();\n\n\t\tawait run(() => this.checkAllFiles(filePathsToCheck, context));\n\t}\n\n\t/**\n\t * Executes all policies against the provided paths.\n\t *\n\t * @param pathsToCheck - All paths that should be checked. Paths should be relative to the repository root.\n\t * @param context - The context.\n\t */\n\tprivate *checkAllFiles(\n\t\tpathsToCheck: string[],\n\t\tcontext: RepopoCommandContext,\n\t): Operation<void> {\n\t\ttry {\n\t\t\tfor (const pathToCheck of pathsToCheck) {\n\t\t\t\tyield* this.checkOrExcludeFile(pathToCheck, context);\n\t\t\t}\n\t\t} finally {\n\t\t\tif (!this.flags.quiet) {\n\t\t\t\tlogStats(context.perfStats, this.logger);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Given a string that represents a path to a file in the repo, determines if the file should be checked, and if so,\n\t * routes the file to the appropriate handlers.\n\t *\n\t * @param relPath - A git repo-relative path to a file.\n\t */\n\tprivate *checkOrExcludeFile(\n\t\trelPath: string,\n\t\tcontext: RepopoCommandContext,\n\t): Operation<void> {\n\t\tconst { perfStats } = context;\n\t\tperfStats.count++;\n\n\t\ttry {\n\t\t\tyield* this.routeToPolicies(relPath, context);\n\t\t} catch (error: unknown) {\n\t\t\tthrow new Error(\n\t\t\t\t`Error routing ${relPath} to handler: ${error}\\nStack:\\n${(error as Error).stack}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate *routeToPolicies(\n\t\trelPath: string,\n\t\tcontext: RepopoCommandContext,\n\t): Operation<void> {\n\t\tconst { policies, excludeFromAll } = context;\n\n\t\t// Check exclusions\n\t\tif (excludeFromAll.some((regex) => regex.test(relPath))) {\n\t\t\tthis.verbose(`Excluded all handlers: ${relPath}`);\n\t\t\treturn;\n\t\t}\n\n\t\t// Run all matching policies\n\t\tconst matchingPolicies = policies.filter((policy) =>\n\t\t\tpolicy.match.test(relPath),\n\t\t);\n\n\t\tyield* all(\n\t\t\tmatchingPolicies.map((policy) => {\n\t\t\t\treturn this.runPolicyOnFile(relPath, policy, context);\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate *runPolicyOnFile(\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\tcontext: RepopoCommandContext,\n\t): Operation<void> {\n\t\tconst { excludePoliciesForFiles, perfStats, gitRoot } = context;\n\n\t\t// Check if the policy is excluded for the file\n\t\tif (this.isPolicyExcluded(relPath, policy, excludePoliciesForFiles)) {\n\t\t\tthis.verbose(`Excluded from '${policy.name}' policy: ${relPath}`);\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\t// Execute the policy handler\n\t\t\tconst result = yield* this.executePolicyHandler(\n\t\t\t\trelPath,\n\t\t\t\tpolicy,\n\t\t\t\tperfStats,\n\t\t\t\tgitRoot,\n\t\t\t);\n\n\t\t\t// Handle the result of the policy execution\n\t\t\tyield* this.handlePolicyResult(\n\t\t\t\tresult,\n\t\t\t\trelPath,\n\t\t\t\tpolicy,\n\t\t\t\tperfStats,\n\t\t\t\tgitRoot,\n\t\t\t);\n\t\t} catch (error: unknown) {\n\t\t\t// Log and rethrow the error for higher-level handling\n\t\t\tthis.exit(\n\t\t\t\t`Error executing policy '${policy.name}' for file '${relPath}': ${error}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate isPolicyExcluded(\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\texcludePoliciesForFiles: Map<string, RegExp[]>,\n\t): boolean {\n\t\treturn (\n\t\t\texcludePoliciesForFiles\n\t\t\t\t.get(policy.name)\n\t\t\t\t?.some((regex) => regex.test(relPath)) ?? false\n\t\t);\n\t}\n\n\tprivate *executePolicyHandler(\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\tperfStats: PolicyHandlerPerfStats,\n\t\tgitRoot: string,\n\t): Operation<PolicyHandlerResult> {\n\t\tconst resolve = this.flags.fix;\n\t\ttry {\n\t\t\tconst result = yield* runWithPerf(\n\t\t\t\tpolicy.name,\n\t\t\t\t\"handle\",\n\t\t\t\tperfStats,\n\t\t\t\tfunction* () {\n\t\t\t\t\tconst args = {\n\t\t\t\t\t\tfile: relPath,\n\t\t\t\t\t\troot: gitRoot,\n\t\t\t\t\t\tresolve,\n\t\t\t\t\t\tconfig: policy.config,\n\t\t\t\t\t};\n\n\t\t\t\t\t// Use normalized _internalHandler if available (from policy() function)\n\t\t\t\t\t// This avoids per-invocation type checking\n\t\t\t\t\tif (policy._internalHandler) {\n\t\t\t\t\t\treturn yield* policy._internalHandler(args);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fallback for policies not created with policy() function\n\t\t\t\t\tconst handlerResult = policy.handler(args);\n\n\t\t\t\t\t// Handle both Operation (generator) and Promise return types\n\t\t\t\t\tif (handlerResult instanceof Promise) {\n\t\t\t\t\t\treturn yield* call(() => handlerResult);\n\t\t\t\t\t}\n\t\t\t\t\t// Check if it's an Effection Operation (generator)\n\t\t\t\t\tif (isOperation<PolicyHandlerResult>(handlerResult)) {\n\t\t\t\t\t\treturn yield* handlerResult;\n\t\t\t\t\t}\n\t\t\t\t\t// This should never happen with proper handler typing\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Unexpected handler result type: ${typeof handlerResult}`,\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t);\n\t\t\tif (result === undefined) {\n\t\t\t\tthrow new Error(\"Policy result was undefined.\");\n\t\t\t}\n\t\t\treturn result;\n\t\t} catch (error: unknown) {\n\t\t\tthis.exit(\n\t\t\t\t`Error in policy handler '${policy.name}' for file '${relPath}': ${error}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate *handlePolicyResult(\n\t\tresult: PolicyHandlerResult,\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\tperfStats: PolicyHandlerPerfStats,\n\t\tgitRoot: string,\n\t): Operation<void> {\n\t\tif (result === true) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle fix results (both legacy and new formats)\n\t\tif (isPolicyFixResult(result)) {\n\t\t\tthis.handleFixResult(result, policy);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle new PolicyError with fixed property (fix was attempted)\n\t\tif (isPolicyError(result) && result.fixed !== undefined) {\n\t\t\tthis.handlePolicyErrorFixResult(result, relPath, policy);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle failure results (PolicyFailure or PolicyError without fix)\n\t\tyield* this.handleFailureResult(\n\t\t\tresult,\n\t\t\trelPath,\n\t\t\tpolicy,\n\t\t\tperfStats,\n\t\t\tgitRoot,\n\t\t);\n\t}\n\n\tprivate handleFixResult(\n\t\tresult: PolicyFixResult,\n\t\tpolicy: PolicyInstance,\n\t): void {\n\t\tconst messages = new StringBuilder();\n\n\t\tif (result.resolved) {\n\t\t\tmessages.append(\n\t\t\t\t`Resolved ${policy.name} policy failure for file: ${result.file}`,\n\t\t\t);\n\t\t} else {\n\t\t\tmessages.append(\n\t\t\t\t`Error fixing ${policy.name} policy failure in ${result.file}`,\n\t\t\t);\n\t\t\tprocess.exitCode = 1;\n\t\t}\n\n\t\tthis.logMessages(messages);\n\t}\n\n\tprivate handlePolicyErrorFixResult(\n\t\tresult: PolicyError,\n\t\tfile: string,\n\t\tpolicy: PolicyInstance,\n\t): void {\n\t\tconst messages = new StringBuilder();\n\n\t\tif (result.fixed) {\n\t\t\tmessages.append(\n\t\t\t\t`Resolved ${policy.name} policy failure for file: ${file}`,\n\t\t\t);\n\t\t} else {\n\t\t\tmessages.append(`Error fixing ${policy.name} policy failure in ${file}`);\n\t\t\tif (result.error) {\n\t\t\t\tmessages.append(`${newline}\\t${result.error}`);\n\t\t\t}\n\t\t\tprocess.exitCode = 1;\n\t\t}\n\n\t\tthis.logMessages(messages);\n\t}\n\n\tprivate *handleFailureResult(\n\t\tresult: PolicyFailure | PolicyError,\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\tperfStats: PolicyHandlerPerfStats,\n\t\tgitRoot: string,\n\t): Operation<void> {\n\t\tconst messages = new StringBuilder();\n\n\t\tif (this.flags.fix && policy.resolver) {\n\t\t\tyield* this.attemptResolution(\n\t\t\t\trelPath,\n\t\t\t\tpolicy,\n\t\t\t\tpolicy.resolver,\n\t\t\t\tperfStats,\n\t\t\t\tgitRoot,\n\t\t\t\tmessages,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.logPolicyFailure(result, relPath, policy, messages);\n\t\t}\n\n\t\tthis.logMessages(messages);\n\t}\n\n\tprivate *attemptResolution(\n\t\trelPath: string,\n\t\tpolicy: PolicyInstance,\n\t\tresolver: PolicyStandaloneResolver,\n\t\tperfStats: PolicyHandlerPerfStats,\n\t\tgitRoot: string,\n\t\tmessages: StringBuilder,\n\t): Operation<void> {\n\t\tmessages.append(`${newline}Attempting to resolve: ${relPath}`);\n\t\tconst resolveResult = yield* runWithPerf(\n\t\t\tpolicy.name,\n\t\t\t\"resolve\",\n\t\t\tperfStats,\n\t\t\tfunction* () {\n\t\t\t\tconst result = resolver({ file: relPath, root: gitRoot });\n\n\t\t\t\t// Handle both Operation (generator) and Promise return types\n\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\treturn yield* call(() => result);\n\t\t\t\t}\n\t\t\t\t// Check if it's an Effection Operation (generator)\n\t\t\t\tif (isOperation<PolicyFixResult>(result)) {\n\t\t\t\t\treturn yield* result;\n\t\t\t\t}\n\t\t\t\t// This should never happen with proper resolver typing\n\t\t\t\tthrow new Error(`Unexpected resolver result type: ${typeof result}`);\n\t\t\t},\n\t\t);\n\n\t\tif (!resolveResult.resolved) {\n\t\t\tprocess.exitCode = 1;\n\t\t}\n\n\t\tif (resolveResult.errorMessages?.length > 0) {\n\t\t\tmessages.append(newline + resolveResult.errorMessages.join(newline));\n\t\t}\n\t}\n\n\tprivate logPolicyFailure(\n\t\tresult: PolicyFailure | PolicyError,\n\t\tfile: string,\n\t\tpolicy: PolicyInstance,\n\t\tmessages: StringBuilder,\n\t): void {\n\t\t// Handle both legacy PolicyFailure and new PolicyError formats\n\t\tif (isPolicyError(result)) {\n\t\t\tconst autoFixable = result.fixable ? chalk.green(\" (autofixable)\") : \"\";\n\t\t\tmessages.append(\n\t\t\t\t`'${chalk.bold(policy.name)}' policy failure${autoFixable}: ${file}`,\n\t\t\t);\n\t\t\tmessages.append(`${newline}\\t${result.error}`);\n\t\t} else {\n\t\t\tconst autoFixable = result.autoFixable\n\t\t\t\t? chalk.green(\" (autofixable)\")\n\t\t\t\t: \"\";\n\t\t\tmessages.append(\n\t\t\t\t`'${chalk.bold(policy.name)}' policy failure${autoFixable}: ${result.file}`,\n\t\t\t);\n\t\t\tif (result.errorMessages?.length > 0) {\n\t\t\t\tmessages.append(\n\t\t\t\t\t`${newline}\\t${result.errorMessages.join(`${newline}\\t`)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tprocess.exitCode = 1;\n\t}\n\tprivate logMessages(messages: StringBuilder): void {\n\t\tif ((process.exitCode ?? 0) === 0) {\n\t\t\tthis.info(messages.toString());\n\t\t} else {\n\t\t\tthis.warning(messages.toString());\n\t\t}\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGtD;;GAEG;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,2CACE;IAEnB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ1C"}
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGtD;;GAEG;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,2CACE;IAEnB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAU1C"}
@@ -9,7 +9,9 @@ export class ListCommand extends BaseRepopoCommand {
9
9
  const policies = this.commandConfig?.policies ?? DefaultPolicies;
10
10
  // list the handlers then exit
11
11
  for (const h of policies) {
12
- this.log(`${h.name}\nresolver: ${h.resolver !== undefined}\n`);
12
+ this.log(`${h.name}`);
13
+ this.log(` ${h.description}`);
14
+ this.log(` resolver: ${h.resolver !== undefined}\n`);
13
15
  }
14
16
  this.log(`${policies.length} TOTAL POLICY HANDLERS`);
15
17
  }
@@ -1 +1 @@
1
- {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C;;GAEG;AACH,MAAM,OAAO,WAKX,SAAQ,iBAAoB;IACtB,MAAM,CAAmB,OAAO,GACtC,uCAAuC,CAAC;IAEzB,KAAK,CAAC,GAAG;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,EAAE,QAAQ,IAAI,eAAe,CAAC;QACjE,8BAA8B;QAC9B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC;QAChE,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,wBAAwB,CAAC,CAAC;IACtD,CAAC","sourcesContent":["import { BaseRepopoCommand } from \"../baseCommand.js\";\nimport { DefaultPolicies } from \"../policy.js\";\n\n/**\n * This command lists all the policies configured to run.\n */\nexport class ListCommand<\n\tT extends typeof BaseRepopoCommand & {\n\t\targs: typeof ListCommand.args;\n\t\tflags: typeof ListCommand.flags;\n\t},\n> extends BaseRepopoCommand<T> {\n\tpublic static override readonly summary =\n\t\t\"Lists the policies configured to run.\";\n\n\tpublic override async run(): Promise<void> {\n\t\tconst policies = this.commandConfig?.policies ?? DefaultPolicies;\n\t\t// list the handlers then exit\n\t\tfor (const h of policies) {\n\t\t\tthis.log(`${h.name}\\nresolver: ${h.resolver !== undefined}\\n`);\n\t\t}\n\t\tthis.log(`${policies.length} TOTAL POLICY HANDLERS`);\n\t}\n}\n"]}
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C;;GAEG;AACH,MAAM,OAAO,WAKX,SAAQ,iBAAoB;IACtB,MAAM,CAAmB,OAAO,GACtC,uCAAuC,CAAC;IAEzB,KAAK,CAAC,GAAG;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,EAAE,QAAQ,IAAI,eAAe,CAAC;QACjE,8BAA8B;QAC9B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACtB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YAC/B,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,wBAAwB,CAAC,CAAC;IACtD,CAAC","sourcesContent":["import { BaseRepopoCommand } from \"../baseCommand.js\";\nimport { DefaultPolicies } from \"../policy.js\";\n\n/**\n * This command lists all the policies configured to run.\n */\nexport class ListCommand<\n\tT extends typeof BaseRepopoCommand & {\n\t\targs: typeof ListCommand.args;\n\t\tflags: typeof ListCommand.flags;\n\t},\n> extends BaseRepopoCommand<T> {\n\tpublic static override readonly summary =\n\t\t\"Lists the policies configured to run.\";\n\n\tpublic override async run(): Promise<void> {\n\t\tconst policies = this.commandConfig?.policies ?? DefaultPolicies;\n\t\t// list the handlers then exit\n\t\tfor (const h of policies) {\n\t\t\tthis.log(`${h.name}`);\n\t\t\tthis.log(` ${h.description}`);\n\t\t\tthis.log(` resolver: ${h.resolver !== undefined}\\n`);\n\t\t}\n\t\tthis.log(`${policies.length} TOTAL POLICY HANDLERS`);\n\t}\n}\n"]}