repopo 0.9.0 → 0.12.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 (271) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/README.md +41 -2
  3. package/THIRD-PARTY-LICENSES.txt +71 -11
  4. package/bin/dev.js +5 -1
  5. package/esm/baseCommand.d.ts +1 -1
  6. package/esm/baseCommand.d.ts.map +1 -1
  7. package/esm/baseCommand.js +6 -9
  8. package/esm/baseCommand.js.map +1 -1
  9. package/esm/commands/check-native.d.ts +25 -0
  10. package/esm/commands/check-native.d.ts.map +1 -0
  11. package/esm/commands/check-native.js +137 -0
  12. package/esm/commands/check-native.js.map +1 -0
  13. package/esm/commands/check.d.ts +8 -19
  14. package/esm/commands/check.d.ts.map +1 -1
  15. package/esm/commands/check.js +97 -169
  16. package/esm/commands/check.js.map +1 -1
  17. package/esm/commands/list.d.ts.map +1 -1
  18. package/esm/commands/list.js +5 -6
  19. package/esm/commands/list.js.map +1 -1
  20. package/esm/config.d.ts +19 -4
  21. package/esm/config.d.ts.map +1 -1
  22. package/esm/config.js +2 -3
  23. package/esm/config.js.map +1 -1
  24. package/esm/context.d.ts +13 -3
  25. package/esm/context.d.ts.map +1 -1
  26. package/esm/context.js +11 -1
  27. package/esm/context.js.map +1 -1
  28. package/esm/index.d.ts +7 -2
  29. package/esm/index.d.ts.map +1 -1
  30. package/esm/index.js +9 -1
  31. package/esm/index.js.map +1 -1
  32. package/esm/makePolicy.d.ts +77 -8
  33. package/esm/makePolicy.d.ts.map +1 -1
  34. package/esm/makePolicy.js +108 -4
  35. package/esm/makePolicy.js.map +1 -1
  36. package/esm/perf.d.ts +7 -2
  37. package/esm/perf.d.ts.map +1 -1
  38. package/esm/perf.js.map +1 -1
  39. package/esm/policies/CargoLicenceValidated.d.ts +41 -0
  40. package/esm/policies/CargoLicenceValidated.d.ts.map +1 -0
  41. package/esm/policies/CargoLicenceValidated.js +45 -0
  42. package/esm/policies/CargoLicenceValidated.js.map +1 -0
  43. package/esm/policies/CargoLintsConfigured.d.ts +30 -0
  44. package/esm/policies/CargoLintsConfigured.d.ts.map +1 -0
  45. package/esm/policies/CargoLintsConfigured.js +61 -0
  46. package/esm/policies/CargoLintsConfigured.js.map +1 -0
  47. package/esm/policies/CargoLockPolicy.d.ts +34 -0
  48. package/esm/policies/CargoLockPolicy.d.ts.map +1 -0
  49. package/esm/policies/CargoLockPolicy.js +57 -0
  50. package/esm/policies/CargoLockPolicy.js.map +1 -0
  51. package/esm/policies/CargoTomlRequired.d.ts +34 -0
  52. package/esm/policies/CargoTomlRequired.d.ts.map +1 -0
  53. package/esm/policies/CargoTomlRequired.js +77 -0
  54. package/esm/policies/CargoTomlRequired.js.map +1 -0
  55. package/esm/policies/CargoTomlSorted.d.ts +20 -0
  56. package/esm/policies/CargoTomlSorted.d.ts.map +1 -0
  57. package/esm/policies/CargoTomlSorted.js +164 -0
  58. package/esm/policies/CargoTomlSorted.js.map +1 -0
  59. package/esm/policies/ConditionalScripts.d.ts +94 -0
  60. package/esm/policies/ConditionalScripts.d.ts.map +1 -0
  61. package/esm/policies/ConditionalScripts.js +145 -0
  62. package/esm/policies/ConditionalScripts.js.map +1 -0
  63. package/esm/policies/ExactScripts.d.ts +51 -0
  64. package/esm/policies/ExactScripts.d.ts.map +1 -0
  65. package/esm/policies/ExactScripts.js +108 -0
  66. package/esm/policies/ExactScripts.js.map +1 -0
  67. package/esm/policies/GleamDepVersions.d.ts +25 -0
  68. package/esm/policies/GleamDepVersions.d.ts.map +1 -0
  69. package/esm/policies/GleamDepVersions.js +67 -0
  70. package/esm/policies/GleamDepVersions.js.map +1 -0
  71. package/esm/policies/GleamDocExists.d.ts +24 -0
  72. package/esm/policies/GleamDocExists.d.ts.map +1 -0
  73. package/esm/policies/GleamDocExists.js +39 -0
  74. package/esm/policies/GleamDocExists.js.map +1 -0
  75. package/esm/policies/GleamInternalModulesConfigured.d.ts +21 -0
  76. package/esm/policies/GleamInternalModulesConfigured.d.ts.map +1 -0
  77. package/esm/policies/GleamInternalModulesConfigured.js +30 -0
  78. package/esm/policies/GleamInternalModulesConfigured.js.map +1 -0
  79. package/esm/policies/GleamLicenceConfigured.d.ts +29 -0
  80. package/esm/policies/GleamLicenceConfigured.d.ts.map +1 -0
  81. package/esm/policies/GleamLicenceConfigured.js +34 -0
  82. package/esm/policies/GleamLicenceConfigured.js.map +1 -0
  83. package/esm/policies/GleamManifestCommitted.d.ts +9 -0
  84. package/esm/policies/GleamManifestCommitted.d.ts.map +1 -0
  85. package/esm/policies/GleamManifestCommitted.js +26 -0
  86. package/esm/policies/GleamManifestCommitted.js.map +1 -0
  87. package/esm/policies/GleamMonorepoConsistency.d.ts +30 -0
  88. package/esm/policies/GleamMonorepoConsistency.d.ts.map +1 -0
  89. package/esm/policies/GleamMonorepoConsistency.js +74 -0
  90. package/esm/policies/GleamMonorepoConsistency.js.map +1 -0
  91. package/esm/policies/GleamNameRestrictions.d.ts +25 -0
  92. package/esm/policies/GleamNameRestrictions.d.ts.map +1 -0
  93. package/esm/policies/GleamNameRestrictions.js +44 -0
  94. package/esm/policies/GleamNameRestrictions.js.map +1 -0
  95. package/esm/policies/GleamNoPathDepsInPublished.d.ts +22 -0
  96. package/esm/policies/GleamNoPathDepsInPublished.d.ts.map +1 -0
  97. package/esm/policies/GleamNoPathDepsInPublished.js +43 -0
  98. package/esm/policies/GleamNoPathDepsInPublished.js.map +1 -0
  99. package/esm/policies/GleamPathDepsValid.d.ts +9 -0
  100. package/esm/policies/GleamPathDepsValid.d.ts.map +1 -0
  101. package/esm/policies/GleamPathDepsValid.js +59 -0
  102. package/esm/policies/GleamPathDepsValid.js.map +1 -0
  103. package/esm/policies/GleamProjectStructure.d.ts +25 -0
  104. package/esm/policies/GleamProjectStructure.d.ts.map +1 -0
  105. package/esm/policies/GleamProjectStructure.js +33 -0
  106. package/esm/policies/GleamProjectStructure.js.map +1 -0
  107. package/esm/policies/GleamSharedDependencyVersions.d.ts +29 -0
  108. package/esm/policies/GleamSharedDependencyVersions.d.ts.map +1 -0
  109. package/esm/policies/GleamSharedDependencyVersions.js +101 -0
  110. package/esm/policies/GleamSharedDependencyVersions.js.map +1 -0
  111. package/esm/policies/GleamTomlRequired.d.ts +30 -0
  112. package/esm/policies/GleamTomlRequired.d.ts.map +1 -0
  113. package/esm/policies/GleamTomlRequired.js +37 -0
  114. package/esm/policies/GleamTomlRequired.js.map +1 -0
  115. package/esm/policies/GleamTomlSorted.d.ts +20 -0
  116. package/esm/policies/GleamTomlSorted.d.ts.map +1 -0
  117. package/esm/policies/GleamTomlSorted.js +153 -0
  118. package/esm/policies/GleamTomlSorted.js.map +1 -0
  119. package/esm/policies/GleamVersionConstraint.d.ts +20 -0
  120. package/esm/policies/GleamVersionConstraint.d.ts.map +1 -0
  121. package/esm/policies/GleamVersionConstraint.js +64 -0
  122. package/esm/policies/GleamVersionConstraint.js.map +1 -0
  123. package/esm/policies/HtmlFileHeaders.d.ts +1 -1
  124. package/esm/policies/HtmlFileHeaders.d.ts.map +1 -1
  125. package/esm/policies/HtmlFileHeaders.js +1 -1
  126. package/esm/policies/HtmlFileHeaders.js.map +1 -1
  127. package/esm/policies/JsTsFileHeaders.d.ts +1 -1
  128. package/esm/policies/JsTsFileHeaders.d.ts.map +1 -1
  129. package/esm/policies/MutuallyExclusiveScripts.d.ts +46 -0
  130. package/esm/policies/MutuallyExclusiveScripts.d.ts.map +1 -0
  131. package/esm/policies/MutuallyExclusiveScripts.js +52 -0
  132. package/esm/policies/MutuallyExclusiveScripts.js.map +1 -0
  133. package/esm/policies/NoBuildDirectory.d.ts +9 -0
  134. package/esm/policies/NoBuildDirectory.d.ts.map +1 -0
  135. package/esm/policies/NoBuildDirectory.js +29 -0
  136. package/esm/policies/NoBuildDirectory.js.map +1 -0
  137. package/esm/policies/NoPrivateWorkspaceDependencies.d.ts +1 -1
  138. package/esm/policies/NoPrivateWorkspaceDependencies.d.ts.map +1 -1
  139. package/esm/policies/NoTargetArtifacts.d.ts +8 -0
  140. package/esm/policies/NoTargetArtifacts.d.ts.map +1 -0
  141. package/esm/policies/NoTargetArtifacts.js +42 -0
  142. package/esm/policies/NoTargetArtifacts.js.map +1 -0
  143. package/esm/policies/NoUnsafeWithoutJustification.d.ts +24 -0
  144. package/esm/policies/NoUnsafeWithoutJustification.d.ts.map +1 -0
  145. package/esm/policies/NoUnsafeWithoutJustification.js +80 -0
  146. package/esm/policies/NoUnsafeWithoutJustification.js.map +1 -0
  147. package/esm/policies/NoWildcardDependencies.d.ts +30 -0
  148. package/esm/policies/NoWildcardDependencies.d.ts.map +1 -0
  149. package/esm/policies/NoWildcardDependencies.js +83 -0
  150. package/esm/policies/NoWildcardDependencies.js.map +1 -0
  151. package/esm/policies/PackageAllowedScopes.d.ts +1 -1
  152. package/esm/policies/PackageAllowedScopes.d.ts.map +1 -1
  153. package/esm/policies/PackageEsmType.d.ts +1 -1
  154. package/esm/policies/PackageEsmType.d.ts.map +1 -1
  155. package/esm/policies/PackageEsmType.js +7 -5
  156. package/esm/policies/PackageEsmType.js.map +1 -1
  157. package/esm/policies/PackageFolderName.d.ts +1 -1
  158. package/esm/policies/PackageFolderName.d.ts.map +1 -1
  159. package/esm/policies/PackageJsonProperties.d.ts +1 -1
  160. package/esm/policies/PackageJsonProperties.d.ts.map +1 -1
  161. package/esm/policies/PackageJsonProperties.js +12 -4
  162. package/esm/policies/PackageJsonProperties.js.map +1 -1
  163. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts +1 -1
  164. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts.map +1 -1
  165. package/esm/policies/PackageJsonRepoDirectoryProperty.js +3 -2
  166. package/esm/policies/PackageJsonRepoDirectoryProperty.js.map +1 -1
  167. package/esm/policies/PackageJsonSorted.d.ts +1 -1
  168. package/esm/policies/PackageJsonSorted.d.ts.map +1 -1
  169. package/esm/policies/PackageJsonSorted.js +42 -7
  170. package/esm/policies/PackageJsonSorted.js.map +1 -1
  171. package/esm/policies/PackageLicense.d.ts +1 -1
  172. package/esm/policies/PackageLicense.d.ts.map +1 -1
  173. package/esm/policies/PackageLicense.js +1 -2
  174. package/esm/policies/PackageLicense.js.map +1 -1
  175. package/esm/policies/PackagePrivateField.d.ts +1 -1
  176. package/esm/policies/PackagePrivateField.d.ts.map +1 -1
  177. package/esm/policies/PackagePrivateField.js +3 -2
  178. package/esm/policies/PackagePrivateField.js.map +1 -1
  179. package/esm/policies/PackageReadme.d.ts +1 -1
  180. package/esm/policies/PackageReadme.d.ts.map +1 -1
  181. package/esm/policies/PackageReadme.js +2 -2
  182. package/esm/policies/PackageReadme.js.map +1 -1
  183. package/esm/policies/PackageScripts.d.ts +1 -1
  184. package/esm/policies/PackageScripts.d.ts.map +1 -1
  185. package/esm/policies/PackageScripts.js +3 -2
  186. package/esm/policies/PackageScripts.js.map +1 -1
  187. package/esm/policies/PackageTestScripts.d.ts +1 -1
  188. package/esm/policies/PackageTestScripts.d.ts.map +1 -1
  189. package/esm/policies/PackageTestScripts.js +3 -3
  190. package/esm/policies/PackageTestScripts.js.map +1 -1
  191. package/esm/policies/PublicApiDocumented.d.ts +21 -0
  192. package/esm/policies/PublicApiDocumented.d.ts.map +1 -0
  193. package/esm/policies/PublicApiDocumented.js +36 -0
  194. package/esm/policies/PublicApiDocumented.js.map +1 -0
  195. package/esm/policies/RequiredScripts.d.ts +71 -0
  196. package/esm/policies/RequiredScripts.d.ts.map +1 -0
  197. package/esm/policies/RequiredScripts.js +121 -0
  198. package/esm/policies/RequiredScripts.js.map +1 -0
  199. package/esm/policies/RustDocExists.d.ts +24 -0
  200. package/esm/policies/RustDocExists.d.ts.map +1 -0
  201. package/esm/policies/RustDocExists.js +49 -0
  202. package/esm/policies/RustDocExists.js.map +1 -0
  203. package/esm/policies/RustToolchainExists.d.ts +20 -0
  204. package/esm/policies/RustToolchainExists.d.ts.map +1 -0
  205. package/esm/policies/RustToolchainExists.js +27 -0
  206. package/esm/policies/RustToolchainExists.js.map +1 -0
  207. package/esm/policies/RustfmtConfigExists.d.ts +20 -0
  208. package/esm/policies/RustfmtConfigExists.d.ts.map +1 -0
  209. package/esm/policies/RustfmtConfigExists.js +27 -0
  210. package/esm/policies/RustfmtConfigExists.js.map +1 -0
  211. package/esm/policies/ScriptContains.d.ts +64 -0
  212. package/esm/policies/ScriptContains.d.ts.map +1 -0
  213. package/esm/policies/ScriptContains.js +62 -0
  214. package/esm/policies/ScriptContains.js.map +1 -0
  215. package/esm/policies/SharedDependencyVersions.d.ts +24 -0
  216. package/esm/policies/SharedDependencyVersions.d.ts.map +1 -0
  217. package/esm/policies/SharedDependencyVersions.js +135 -0
  218. package/esm/policies/SharedDependencyVersions.js.map +1 -0
  219. package/esm/policies/WorkspaceInheritance.d.ts +24 -0
  220. package/esm/policies/WorkspaceInheritance.d.ts.map +1 -0
  221. package/esm/policies/WorkspaceInheritance.js +94 -0
  222. package/esm/policies/WorkspaceInheritance.js.map +1 -0
  223. package/esm/policies/WorkspaceMembersValid.d.ts +20 -0
  224. package/esm/policies/WorkspaceMembersValid.d.ts.map +1 -0
  225. package/esm/policies/WorkspaceMembersValid.js +88 -0
  226. package/esm/policies/WorkspaceMembersValid.js.map +1 -0
  227. package/esm/policies/constants.d.ts +8 -0
  228. package/esm/policies/constants.d.ts.map +1 -1
  229. package/esm/policies/constants.js +8 -0
  230. package/esm/policies/constants.js.map +1 -1
  231. package/esm/policies.d.ts +36 -1
  232. package/esm/policies.d.ts.map +1 -1
  233. package/esm/policies.js +68 -0
  234. package/esm/policies.js.map +1 -1
  235. package/esm/policy.d.ts +202 -84
  236. package/esm/policy.d.ts.map +1 -1
  237. package/esm/policy.js +103 -21
  238. package/esm/policy.js.map +1 -1
  239. package/esm/policyDefiners/defineCargoPolicy.d.ts +66 -0
  240. package/esm/policyDefiners/defineCargoPolicy.d.ts.map +1 -0
  241. package/esm/policyDefiners/defineCargoPolicy.js +60 -0
  242. package/esm/policyDefiners/defineCargoPolicy.js.map +1 -0
  243. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts +7 -2
  244. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts.map +1 -1
  245. package/esm/policyDefiners/defineFileHeaderPolicy.js +11 -7
  246. package/esm/policyDefiners/defineFileHeaderPolicy.js.map +1 -1
  247. package/esm/policyDefiners/defineGleamPolicy.d.ts +65 -0
  248. package/esm/policyDefiners/defineGleamPolicy.d.ts.map +1 -0
  249. package/esm/policyDefiners/defineGleamPolicy.js +59 -0
  250. package/esm/policyDefiners/defineGleamPolicy.js.map +1 -0
  251. package/esm/policyDefiners/definePackagePolicy.d.ts +18 -5
  252. package/esm/policyDefiners/definePackagePolicy.d.ts.map +1 -1
  253. package/esm/policyDefiners/definePackagePolicy.js +14 -4
  254. package/esm/policyDefiners/definePackagePolicy.js.map +1 -1
  255. package/esm/policyDefiners/spdxValidator.d.ts +74 -0
  256. package/esm/policyDefiners/spdxValidator.d.ts.map +1 -0
  257. package/esm/policyDefiners/spdxValidator.js +127 -0
  258. package/esm/policyDefiners/spdxValidator.js.map +1 -0
  259. package/esm/policyDefiners/tomlParser.d.ts +8 -0
  260. package/esm/policyDefiners/tomlParser.d.ts.map +1 -0
  261. package/esm/policyDefiners/tomlParser.js +17 -0
  262. package/esm/policyDefiners/tomlParser.js.map +1 -0
  263. package/esm/runner.d.ts +60 -0
  264. package/esm/runner.d.ts.map +1 -0
  265. package/esm/runner.js +174 -0
  266. package/esm/runner.js.map +1 -0
  267. package/esm/tsdoc-metadata.json +1 -1
  268. package/oclif.manifest.json +100 -3
  269. package/package.json +46 -31
  270. package/scripts/postinstall.mjs +154 -0
  271. package/sidecar/sidecar.mjs +468 -0
@@ -1,6 +1,6 @@
1
1
  import { type Operation } from "effection";
2
2
  import type { PackageJson } from "type-fest";
3
- import type { PolicyDefinition, PolicyFunctionArguments, PolicyHandlerResult } from "../policy.js";
3
+ import type { PolicyArgs, PolicyHandlerResult, PolicyShape } from "../policy.js";
4
4
  /**
5
5
  * A policy handler especially for policies that target package.json.
6
6
  *
@@ -13,7 +13,7 @@ import type { PolicyDefinition, PolicyFunctionArguments, PolicyHandlerResult } f
13
13
  *
14
14
  * @alpha
15
15
  */
16
- export type PackageJsonHandler<J, C> = (json: J, args: PolicyFunctionArguments<C>) => Operation<PolicyHandlerResult> | Promise<PolicyHandlerResult>;
16
+ export type PackageJsonHandler<J, C> = (json: J, args: PolicyArgs<C>) => Operation<PolicyHandlerResult> | Promise<PolicyHandlerResult>;
17
17
  /**
18
18
  * Input arguments for defining a package.json policy.
19
19
  *
@@ -32,18 +32,26 @@ export interface DefinePackagePolicyArgs<J, C> {
32
32
  * The handler function that receives the parsed package.json and policy arguments.
33
33
  */
34
34
  handler: PackageJsonHandler<J, C>;
35
+ /**
36
+ * Optional default configuration for the policy.
37
+ */
38
+ defaultConfig?: C;
35
39
  }
36
40
  /**
37
41
  * Define a repo policy for package.json files.
38
42
  *
43
+ * @remarks
44
+ * This is a helper function that creates a policy pre-configured to match
45
+ * package.json files. The handler receives the parsed JSON content.
46
+ *
39
47
  * @example
40
48
  * ```typescript
41
49
  * const MyPackagePolicy = definePackagePolicy({
42
50
  * name: "MyPackagePolicy",
43
51
  * description: "Ensures package.json has required fields",
44
- * handler: function* (json, { file }) {
52
+ * handler: async (json, { file }) => {
45
53
  * if (!json.name) {
46
- * return { name: "MyPackagePolicy", file, errorMessages: ["Missing name"] };
54
+ * return { error: "Missing name", fixable: false };
47
55
  * }
48
56
  * return true;
49
57
  * },
@@ -52,5 +60,10 @@ export interface DefinePackagePolicyArgs<J, C> {
52
60
  *
53
61
  * @alpha
54
62
  */
55
- export declare function definePackagePolicy<J = PackageJson, C = undefined>(args: DefinePackagePolicyArgs<J, C>): PolicyDefinition<C>;
63
+ export declare function definePackagePolicy<J = PackageJson, C = undefined>(args: DefinePackagePolicyArgs<J, C>): PolicyShape<C>;
64
+ /**
65
+ * Alias for definePackagePolicy.
66
+ * @alpha
67
+ */
68
+ export declare const packagePolicy: typeof definePackagePolicy;
56
69
  //# sourceMappingURL=definePackagePolicy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"definePackagePolicy.d.ts","sourceRoot":"","sources":["../../src/policyDefiners/definePackagePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAGjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,KAAK,EACX,gBAAgB,EAChB,uBAAuB,EACvB,mBAAmB,EACnB,MAAM,cAAc,CAAC;AAItB;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,EAAE,CAAC,IAAI,CACtC,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,uBAAuB,CAAC,CAAC,CAAC,KAC5B,SAAS,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAcnE;;;;GAIG;AACH,MAAM,WAAW,uBAAuB,CAAC,CAAC,EAAE,CAAC;IAC5C;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,OAAO,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,GAAG,WAAW,EAAE,CAAC,GAAG,SAAS,EACjE,IAAI,EAAE,uBAAuB,CAAC,CAAC,EAAE,CAAC,CAAC,GACjC,gBAAgB,CAAC,CAAC,CAAC,CAwBrB"}
1
+ {"version":3,"file":"definePackagePolicy.d.ts","sourceRoot":"","sources":["../../src/policyDefiners/definePackagePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAGjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,KAAK,EACX,UAAU,EACV,mBAAmB,EACnB,WAAW,EACX,MAAM,cAAc,CAAC;AAItB;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,EAAE,CAAC,IAAI,CACtC,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KACf,SAAS,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAcnE;;;;GAIG;AACH,MAAM,WAAW,uBAAuB,CAAC,CAAC,EAAE,CAAC;IAC5C;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,OAAO,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAElC;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,GAAG,WAAW,EAAE,CAAC,GAAG,SAAS,EACjE,IAAI,EAAE,uBAAuB,CAAC,CAAC,EAAE,CAAC,CAAC,GACjC,WAAW,CAAC,CAAC,CAAC,CAyBhB;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,4BAAsB,CAAC"}
@@ -15,14 +15,18 @@ function isOperation(value) {
15
15
  /**
16
16
  * Define a repo policy for package.json files.
17
17
  *
18
+ * @remarks
19
+ * This is a helper function that creates a policy pre-configured to match
20
+ * package.json files. The handler receives the parsed JSON content.
21
+ *
18
22
  * @example
19
23
  * ```typescript
20
24
  * const MyPackagePolicy = definePackagePolicy({
21
25
  * name: "MyPackagePolicy",
22
26
  * description: "Ensures package.json has required fields",
23
- * handler: function* (json, { file }) {
27
+ * handler: async (json, { file }) => {
24
28
  * if (!json.name) {
25
- * return { name: "MyPackagePolicy", file, errorMessages: ["Missing name"] };
29
+ * return { error: "Missing name", fixable: false };
26
30
  * }
27
31
  * return true;
28
32
  * },
@@ -32,14 +36,15 @@ function isOperation(value) {
32
36
  * @alpha
33
37
  */
34
38
  export function definePackagePolicy(args) {
35
- const { name, description, handler: packagePolicy } = args;
39
+ const { name, description, handler: packageHandler, defaultConfig } = args;
36
40
  return {
37
41
  name,
38
42
  description,
39
43
  match: PackageJsonRegexMatch,
44
+ defaultConfig,
40
45
  handler: function* (innerArgs) {
41
46
  const json = yield* call(() => readJson(resolve(innerArgs.root, innerArgs.file)));
42
- const result = packagePolicy(json, innerArgs);
47
+ const result = packageHandler(json, innerArgs);
43
48
  // Handle both Operation (generator) and Promise return types
44
49
  if (result instanceof Promise) {
45
50
  return yield* call(() => result);
@@ -53,4 +58,9 @@ export function definePackagePolicy(args) {
53
58
  },
54
59
  };
55
60
  }
61
+ /**
62
+ * Alias for definePackagePolicy.
63
+ * @alpha
64
+ */
65
+ export const packagePolicy = definePackagePolicy;
56
66
  //# sourceMappingURL=definePackagePolicy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"definePackagePolicy.js","sourceRoot":"","sources":["../../src/policyDefiners/definePackagePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAkB,MAAM,WAAW,CAAC;AACjD,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAOjE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC;AAmBxC;;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;AAwBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,mBAAmB,CAClC,IAAmC;IAEnC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;IAC3D,OAAO;QACN,IAAI;QACJ,WAAW;QACX,KAAK,EAAE,qBAAqB;QAC5B,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS;YAC5B,MAAM,IAAI,GAAM,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAChC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CACjD,CAAC;YACF,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAE9C,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,CAAsB,MAAM,CAAC,EAAE,CAAC;gBAC9C,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC;YACtB,CAAC;YACD,sDAAsD;YACtD,MAAM,IAAI,KAAK,CAAC,mCAAmC,OAAO,MAAM,EAAE,CAAC,CAAC;QACrE,CAAC;KACD,CAAC;AACH,CAAC","sourcesContent":["import { call, type Operation } from \"effection\";\nimport jsonfile from \"jsonfile\";\nimport { resolve } from \"pathe\";\nimport type { PackageJson } from \"type-fest\";\nimport { PackageJsonRegexMatch } from \"../policies/constants.js\";\nimport type {\n\tPolicyDefinition,\n\tPolicyFunctionArguments,\n\tPolicyHandlerResult,\n} from \"../policy.js\";\n\nconst { readFile: readJson } = jsonfile;\n\n/**\n * A policy handler especially for policies that target package.json.\n *\n * @remarks\n * Package JSON handlers can be implemented in two ways:\n * - As an async function returning a Promise\n * - As an Effection generator function returning an Operation\n *\n * Both styles are supported to allow gradual migration and flexibility.\n *\n * @alpha\n */\nexport type PackageJsonHandler<J, C> = (\n\tjson: J,\n\targs: PolicyFunctionArguments<C>,\n) => Operation<PolicyHandlerResult> | Promise<PolicyHandlerResult>;\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\n/**\n * Input arguments for defining a package.json policy.\n *\n * @alpha\n */\nexport interface DefinePackagePolicyArgs<J, C> {\n\t/**\n\t * The name of the policy.\n\t */\n\tname: string;\n\n\t/**\n\t * A description of the policy's purpose.\n\t */\n\tdescription: string;\n\n\t/**\n\t * The handler function that receives the parsed package.json and policy arguments.\n\t */\n\thandler: PackageJsonHandler<J, C>;\n}\n\n/**\n * Define a repo policy for package.json files.\n *\n * @example\n * ```typescript\n * const MyPackagePolicy = definePackagePolicy({\n * name: \"MyPackagePolicy\",\n * description: \"Ensures package.json has required fields\",\n * handler: function* (json, { file }) {\n * if (!json.name) {\n * return { name: \"MyPackagePolicy\", file, errorMessages: [\"Missing name\"] };\n * }\n * return true;\n * },\n * });\n * ```\n *\n * @alpha\n */\nexport function definePackagePolicy<J = PackageJson, C = undefined>(\n\targs: DefinePackagePolicyArgs<J, C>,\n): PolicyDefinition<C> {\n\tconst { name, description, handler: packagePolicy } = args;\n\treturn {\n\t\tname,\n\t\tdescription,\n\t\tmatch: PackageJsonRegexMatch,\n\t\thandler: function* (innerArgs) {\n\t\t\tconst json: J = yield* call(() =>\n\t\t\t\treadJson(resolve(innerArgs.root, innerArgs.file)),\n\t\t\t);\n\t\t\tconst result = packagePolicy(json, innerArgs);\n\n\t\t\t// Handle both Operation (generator) and Promise return types\n\t\t\tif (result instanceof Promise) {\n\t\t\t\treturn yield* call(() => result);\n\t\t\t}\n\t\t\t// Check if it's an Effection Operation (generator)\n\t\t\tif (isOperation<PolicyHandlerResult>(result)) {\n\t\t\t\treturn yield* result;\n\t\t\t}\n\t\t\t// This should never happen with proper handler typing\n\t\t\tthrow new Error(`Unexpected handler result type: ${typeof result}`);\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"definePackagePolicy.js","sourceRoot":"","sources":["../../src/policyDefiners/definePackagePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAkB,MAAM,WAAW,CAAC;AACjD,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAOjE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC;AAmBxC;;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;AA6BD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,mBAAmB,CAClC,IAAmC;IAEnC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;IAC3E,OAAO;QACN,IAAI;QACJ,WAAW;QACX,KAAK,EAAE,qBAAqB;QAC5B,aAAa;QACb,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS;YAC5B,MAAM,IAAI,GAAM,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAChC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CACjD,CAAC;YACF,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAE/C,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,CAAsB,MAAM,CAAC,EAAE,CAAC;gBAC9C,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC;YACtB,CAAC;YACD,sDAAsD;YACtD,MAAM,IAAI,KAAK,CAAC,mCAAmC,OAAO,MAAM,EAAE,CAAC,CAAC;QACrE,CAAC;KACD,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,mBAAmB,CAAC","sourcesContent":["import { call, type Operation } from \"effection\";\nimport jsonfile from \"jsonfile\";\nimport { resolve } from \"pathe\";\nimport type { PackageJson } from \"type-fest\";\nimport { PackageJsonRegexMatch } from \"../policies/constants.js\";\nimport type {\n\tPolicyArgs,\n\tPolicyHandlerResult,\n\tPolicyShape,\n} from \"../policy.js\";\n\nconst { readFile: readJson } = jsonfile;\n\n/**\n * A policy handler especially for policies that target package.json.\n *\n * @remarks\n * Package JSON handlers can be implemented in two ways:\n * - As an async function returning a Promise\n * - As an Effection generator function returning an Operation\n *\n * Both styles are supported to allow gradual migration and flexibility.\n *\n * @alpha\n */\nexport type PackageJsonHandler<J, C> = (\n\tjson: J,\n\targs: PolicyArgs<C>,\n) => Operation<PolicyHandlerResult> | Promise<PolicyHandlerResult>;\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\n/**\n * Input arguments for defining a package.json policy.\n *\n * @alpha\n */\nexport interface DefinePackagePolicyArgs<J, C> {\n\t/**\n\t * The name of the policy.\n\t */\n\tname: string;\n\n\t/**\n\t * A description of the policy's purpose.\n\t */\n\tdescription: string;\n\n\t/**\n\t * The handler function that receives the parsed package.json and policy arguments.\n\t */\n\thandler: PackageJsonHandler<J, C>;\n\n\t/**\n\t * Optional default configuration for the policy.\n\t */\n\tdefaultConfig?: C;\n}\n\n/**\n * Define a repo policy for package.json files.\n *\n * @remarks\n * This is a helper function that creates a policy pre-configured to match\n * package.json files. The handler receives the parsed JSON content.\n *\n * @example\n * ```typescript\n * const MyPackagePolicy = definePackagePolicy({\n * name: \"MyPackagePolicy\",\n * description: \"Ensures package.json has required fields\",\n * handler: async (json, { file }) => {\n * if (!json.name) {\n * return { error: \"Missing name\", fixable: false };\n * }\n * return true;\n * },\n * });\n * ```\n *\n * @alpha\n */\nexport function definePackagePolicy<J = PackageJson, C = undefined>(\n\targs: DefinePackagePolicyArgs<J, C>,\n): PolicyShape<C> {\n\tconst { name, description, handler: packageHandler, defaultConfig } = args;\n\treturn {\n\t\tname,\n\t\tdescription,\n\t\tmatch: PackageJsonRegexMatch,\n\t\tdefaultConfig,\n\t\thandler: function* (innerArgs) {\n\t\t\tconst json: J = yield* call(() =>\n\t\t\t\treadJson(resolve(innerArgs.root, innerArgs.file)),\n\t\t\t);\n\t\t\tconst result = packageHandler(json, innerArgs);\n\n\t\t\t// Handle both Operation (generator) and Promise return types\n\t\t\tif (result instanceof Promise) {\n\t\t\t\treturn yield* call(() => result);\n\t\t\t}\n\t\t\t// Check if it's an Effection Operation (generator)\n\t\t\tif (isOperation<PolicyHandlerResult>(result)) {\n\t\t\t\treturn yield* result;\n\t\t\t}\n\t\t\t// This should never happen with proper handler typing\n\t\t\tthrow new Error(`Unexpected handler result type: ${typeof result}`);\n\t\t},\n\t};\n}\n\n/**\n * Alias for definePackagePolicy.\n * @alpha\n */\nexport const packagePolicy = definePackagePolicy;\n"]}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Lazily load spdx-correct. It's an optional peer dependency.
3
+ *
4
+ * @returns The corrected identifier, `null` if unrecognized, or `undefined` if
5
+ * spdx-correct is not installed.
6
+ *
7
+ * @internal
8
+ */
9
+ export declare function tryCorrectLicence(licence: string): Promise<string | null | undefined>;
10
+ /**
11
+ * Result of validating licence identifiers with spdx-correct.
12
+ *
13
+ * @internal
14
+ */
15
+ export interface LicenceValidationResult {
16
+ /** Human-readable error messages. */
17
+ errors: string[];
18
+ /** Map from original identifier to its corrected form. */
19
+ corrections: Map<string, string>;
20
+ }
21
+ /**
22
+ * Validate an array of licence identifiers using spdx-correct.
23
+ *
24
+ * @internal
25
+ */
26
+ export declare function validateWithSpdxCorrect(licences: string[]): Promise<LicenceValidationResult>;
27
+ /**
28
+ * Check that all licence identifiers are in the allowed list.
29
+ *
30
+ * @internal
31
+ */
32
+ export declare function validateAllowlist(licences: string[], allowedLicences: string[]): string[];
33
+ /**
34
+ * Replace quoted licence strings in TOML/text content with their corrected forms.
35
+ *
36
+ * @internal
37
+ */
38
+ export declare function applyCorrections(content: string, corrections: Map<string, string>): string;
39
+ /**
40
+ * Read a file, apply licence corrections, and write it back.
41
+ *
42
+ * @internal
43
+ */
44
+ export declare function tryAutoFix(filePath: string, corrections: Map<string, string>, errors: string[]): Promise<{
45
+ error: string;
46
+ fixable: boolean;
47
+ fixed: boolean;
48
+ }>;
49
+ /**
50
+ * Validate licence identifiers and optionally auto-fix them.
51
+ *
52
+ * Combines spdx-correct validation with allowlist checking and auto-fix
53
+ * into a single helper used by both Cargo and Gleam licence policies.
54
+ *
55
+ * @returns `true` if valid, or a PolicyError-compatible object on failure.
56
+ * Returns `undefined` if no validation was requested (both allowlist and
57
+ * validateSpdx are empty/false).
58
+ *
59
+ * @internal
60
+ */
61
+ export declare function validateLicenceField(options: {
62
+ licences: string[];
63
+ allowedLicences?: string[];
64
+ validateSpdx: boolean;
65
+ shouldResolve: boolean;
66
+ filePath: string;
67
+ manualFixMessage: string;
68
+ }): Promise<true | {
69
+ error: string;
70
+ fixable?: boolean;
71
+ fixed?: boolean;
72
+ manualFix?: string;
73
+ } | undefined>;
74
+ //# sourceMappingURL=spdxValidator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spdxValidator.d.ts","sourceRoot":"","sources":["../../src/policyDefiners/spdxValidator.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACtC,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAWpC;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACvC,qCAAqC;IACrC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,0DAA0D;IAC1D,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC5C,QAAQ,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,uBAAuB,CAAC,CAqBlC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAChC,QAAQ,EAAE,MAAM,EAAE,EAClB,eAAe,EAAE,MAAM,EAAE,GACvB,MAAM,EAAE,CAUV;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC/B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,MAAM,CAMR;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC/B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,MAAM,EAAE,MAAM,EAAE,GACd,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,CAa9D;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IACnD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;CACzB,GAAG,OAAO,CACR,IAAI,GACJ;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACzE,SAAS,CACX,CAkCA"}
@@ -0,0 +1,127 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ /**
3
+ * Lazily load spdx-correct. It's an optional peer dependency.
4
+ *
5
+ * @returns The corrected identifier, `null` if unrecognized, or `undefined` if
6
+ * spdx-correct is not installed.
7
+ *
8
+ * @internal
9
+ */
10
+ export async function tryCorrectLicence(licence) {
11
+ try {
12
+ const mod = (await import("spdx-correct"));
13
+ const correct = mod.default ?? mod;
14
+ return correct(licence);
15
+ }
16
+ catch {
17
+ return undefined;
18
+ }
19
+ }
20
+ /**
21
+ * Validate an array of licence identifiers using spdx-correct.
22
+ *
23
+ * @internal
24
+ */
25
+ export async function validateWithSpdxCorrect(licences) {
26
+ const errors = [];
27
+ const corrections = new Map();
28
+ for (const licence of licences) {
29
+ const corrected = await tryCorrectLicence(licence);
30
+ if (corrected === undefined) {
31
+ errors.push(`Cannot validate "${licence}": spdx-correct is not installed. Install it with: pnpm add spdx-correct`);
32
+ break;
33
+ }
34
+ if (corrected === null) {
35
+ errors.push(`Licence "${licence}" is not a recognized SPDX identifier`);
36
+ }
37
+ else if (corrected !== licence) {
38
+ corrections.set(licence, corrected);
39
+ errors.push(`Licence "${licence}" should be "${corrected}"`);
40
+ }
41
+ }
42
+ return { errors, corrections };
43
+ }
44
+ /**
45
+ * Check that all licence identifiers are in the allowed list.
46
+ *
47
+ * @internal
48
+ */
49
+ export function validateAllowlist(licences, allowedLicences) {
50
+ const errors = [];
51
+ for (const licence of licences) {
52
+ if (!allowedLicences.includes(licence)) {
53
+ errors.push(`Licence "${licence}" is not in the allowed list: ${allowedLicences.join(", ")}`);
54
+ }
55
+ }
56
+ return errors;
57
+ }
58
+ /**
59
+ * Replace quoted licence strings in TOML/text content with their corrected forms.
60
+ *
61
+ * @internal
62
+ */
63
+ export function applyCorrections(content, corrections) {
64
+ let result = content;
65
+ for (const [original, corrected] of corrections) {
66
+ result = result.replace(`"${original}"`, `"${corrected}"`);
67
+ }
68
+ return result;
69
+ }
70
+ /**
71
+ * Read a file, apply licence corrections, and write it back.
72
+ *
73
+ * @internal
74
+ */
75
+ export async function tryAutoFix(filePath, corrections, errors) {
76
+ try {
77
+ const content = await readFile(filePath, "utf-8");
78
+ const fixed = applyCorrections(content, corrections);
79
+ await writeFile(filePath, fixed);
80
+ return { error: errors.join("; "), fixable: true, fixed: true };
81
+ }
82
+ catch {
83
+ return {
84
+ error: `${errors.join("; ")}. Auto-fix failed.`,
85
+ fixable: true,
86
+ fixed: false,
87
+ };
88
+ }
89
+ }
90
+ /**
91
+ * Validate licence identifiers and optionally auto-fix them.
92
+ *
93
+ * Combines spdx-correct validation with allowlist checking and auto-fix
94
+ * into a single helper used by both Cargo and Gleam licence policies.
95
+ *
96
+ * @returns `true` if valid, or a PolicyError-compatible object on failure.
97
+ * Returns `undefined` if no validation was requested (both allowlist and
98
+ * validateSpdx are empty/false).
99
+ *
100
+ * @internal
101
+ */
102
+ export async function validateLicenceField(options) {
103
+ const { licences, allowedLicences, validateSpdx, shouldResolve, filePath, manualFixMessage, } = options;
104
+ // Check allowlist first (takes priority)
105
+ if (allowedLicences) {
106
+ const errors = validateAllowlist(licences, allowedLicences);
107
+ if (errors.length > 0) {
108
+ return { error: errors.join("; "), manualFix: manualFixMessage };
109
+ }
110
+ }
111
+ // Validate with spdx-correct
112
+ if (validateSpdx) {
113
+ const { errors, corrections } = await validateWithSpdxCorrect(licences);
114
+ if (errors.length > 0) {
115
+ if (shouldResolve && corrections.size > 0) {
116
+ return tryAutoFix(filePath, corrections, errors);
117
+ }
118
+ return {
119
+ error: errors.join("; "),
120
+ fixable: corrections.size > 0,
121
+ manualFix: manualFixMessage,
122
+ };
123
+ }
124
+ }
125
+ return undefined;
126
+ }
127
+ //# sourceMappingURL=spdxValidator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spdxValidator.js","sourceRoot":"","sources":["../../src/policyDefiners/spdxValidator.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile, writeFile } from \"node:fs/promises\";\n\n/**\n * Lazily load spdx-correct. It's an optional peer dependency.\n *\n * @returns The corrected identifier, `null` if unrecognized, or `undefined` if\n * spdx-correct is not installed.\n *\n * @internal\n */\nexport async function tryCorrectLicence(\n\tlicence: string,\n): Promise<string | null | undefined> {\n\ttry {\n\t\tconst mod = (await import(\"spdx-correct\")) as {\n\t\t\tdefault?: (id: string) => string | null;\n\t\t};\n\t\tconst correct =\n\t\t\tmod.default ?? (mod as unknown as (id: string) => string | null);\n\t\treturn correct(licence);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Result of validating licence identifiers with spdx-correct.\n *\n * @internal\n */\nexport interface LicenceValidationResult {\n\t/** Human-readable error messages. */\n\terrors: string[];\n\t/** Map from original identifier to its corrected form. */\n\tcorrections: Map<string, string>;\n}\n\n/**\n * Validate an array of licence identifiers using spdx-correct.\n *\n * @internal\n */\nexport async function validateWithSpdxCorrect(\n\tlicences: string[],\n): Promise<LicenceValidationResult> {\n\tconst errors: string[] = [];\n\tconst corrections = new Map<string, string>();\n\n\tfor (const licence of licences) {\n\t\tconst corrected = await tryCorrectLicence(licence);\n\t\tif (corrected === undefined) {\n\t\t\terrors.push(\n\t\t\t\t`Cannot validate \"${licence}\": spdx-correct is not installed. Install it with: pnpm add spdx-correct`,\n\t\t\t);\n\t\t\tbreak;\n\t\t}\n\t\tif (corrected === null) {\n\t\t\terrors.push(`Licence \"${licence}\" is not a recognized SPDX identifier`);\n\t\t} else if (corrected !== licence) {\n\t\t\tcorrections.set(licence, corrected);\n\t\t\terrors.push(`Licence \"${licence}\" should be \"${corrected}\"`);\n\t\t}\n\t}\n\n\treturn { errors, corrections };\n}\n\n/**\n * Check that all licence identifiers are in the allowed list.\n *\n * @internal\n */\nexport function validateAllowlist(\n\tlicences: string[],\n\tallowedLicences: string[],\n): string[] {\n\tconst errors: string[] = [];\n\tfor (const licence of licences) {\n\t\tif (!allowedLicences.includes(licence)) {\n\t\t\terrors.push(\n\t\t\t\t`Licence \"${licence}\" is not in the allowed list: ${allowedLicences.join(\", \")}`,\n\t\t\t);\n\t\t}\n\t}\n\treturn errors;\n}\n\n/**\n * Replace quoted licence strings in TOML/text content with their corrected forms.\n *\n * @internal\n */\nexport function applyCorrections(\n\tcontent: string,\n\tcorrections: Map<string, string>,\n): string {\n\tlet result = content;\n\tfor (const [original, corrected] of corrections) {\n\t\tresult = result.replace(`\"${original}\"`, `\"${corrected}\"`);\n\t}\n\treturn result;\n}\n\n/**\n * Read a file, apply licence corrections, and write it back.\n *\n * @internal\n */\nexport async function tryAutoFix(\n\tfilePath: string,\n\tcorrections: Map<string, string>,\n\terrors: string[],\n): Promise<{ error: string; fixable: boolean; fixed: boolean }> {\n\ttry {\n\t\tconst content = await readFile(filePath, \"utf-8\");\n\t\tconst fixed = applyCorrections(content, corrections);\n\t\tawait writeFile(filePath, fixed);\n\t\treturn { error: errors.join(\"; \"), fixable: true, fixed: true };\n\t} catch {\n\t\treturn {\n\t\t\terror: `${errors.join(\"; \")}. Auto-fix failed.`,\n\t\t\tfixable: true,\n\t\t\tfixed: false,\n\t\t};\n\t}\n}\n\n/**\n * Validate licence identifiers and optionally auto-fix them.\n *\n * Combines spdx-correct validation with allowlist checking and auto-fix\n * into a single helper used by both Cargo and Gleam licence policies.\n *\n * @returns `true` if valid, or a PolicyError-compatible object on failure.\n * Returns `undefined` if no validation was requested (both allowlist and\n * validateSpdx are empty/false).\n *\n * @internal\n */\nexport async function validateLicenceField(options: {\n\tlicences: string[];\n\tallowedLicences?: string[];\n\tvalidateSpdx: boolean;\n\tshouldResolve: boolean;\n\tfilePath: string;\n\tmanualFixMessage: string;\n}): Promise<\n\t| true\n\t| { error: string; fixable?: boolean; fixed?: boolean; manualFix?: string }\n\t| undefined\n> {\n\tconst {\n\t\tlicences,\n\t\tallowedLicences,\n\t\tvalidateSpdx,\n\t\tshouldResolve,\n\t\tfilePath,\n\t\tmanualFixMessage,\n\t} = options;\n\n\t// Check allowlist first (takes priority)\n\tif (allowedLicences) {\n\t\tconst errors = validateAllowlist(licences, allowedLicences);\n\t\tif (errors.length > 0) {\n\t\t\treturn { error: errors.join(\"; \"), manualFix: manualFixMessage };\n\t\t}\n\t}\n\n\t// Validate with spdx-correct\n\tif (validateSpdx) {\n\t\tconst { errors, corrections } = await validateWithSpdxCorrect(licences);\n\t\tif (errors.length > 0) {\n\t\t\tif (shouldResolve && corrections.size > 0) {\n\t\t\t\treturn tryAutoFix(filePath, corrections, errors);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\terror: errors.join(\"; \"),\n\t\t\t\tfixable: corrections.size > 0,\n\t\t\t\tmanualFix: manualFixMessage,\n\t\t\t};\n\t\t}\n\t}\n\n\treturn undefined;\n}\n"]}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Lazily load smol-toml. It's an optional peer dependency, so we import
3
+ * dynamically and surface a clear error when it isn't installed.
4
+ *
5
+ * @internal
6
+ */
7
+ export declare function parseToml(content: string): Promise<Record<string, unknown>>;
8
+ //# sourceMappingURL=tomlParser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tomlParser.d.ts","sourceRoot":"","sources":["../../src/policyDefiners/tomlParser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAsB,SAAS,CAC9B,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAUlC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Lazily load smol-toml. It's an optional peer dependency, so we import
3
+ * dynamically and surface a clear error when it isn't installed.
4
+ *
5
+ * @internal
6
+ */
7
+ export async function parseToml(content) {
8
+ try {
9
+ const { parse } = await import("smol-toml");
10
+ return parse(content);
11
+ }
12
+ catch {
13
+ throw new Error("smol-toml is required for TOML-based policies but is not installed. " +
14
+ "Install it with: pnpm add smol-toml");
15
+ }
16
+ }
17
+ //# sourceMappingURL=tomlParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tomlParser.js","sourceRoot":"","sources":["../../src/policyDefiners/tomlParser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC9B,OAAe;IAEf,IAAI,CAAC;QACJ,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAC5C,OAAO,KAAK,CAAC,OAAO,CAA4B,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,KAAK,CACd,sEAAsE;YACrE,qCAAqC,CACtC,CAAC;IACH,CAAC;AACF,CAAC","sourcesContent":["/**\n * Lazily load smol-toml. It's an optional peer dependency, so we import\n * dynamically and surface a clear error when it isn't installed.\n *\n * @internal\n */\nexport async function parseToml(\n\tcontent: string,\n): Promise<Record<string, unknown>> {\n\ttry {\n\t\tconst { parse } = await import(\"smol-toml\");\n\t\treturn parse(content) as Record<string, unknown>;\n\t} catch {\n\t\tthrow new Error(\n\t\t\t\"smol-toml is required for TOML-based policies but is not installed. \" +\n\t\t\t\t\"Install it with: pnpm add smol-toml\",\n\t\t);\n\t}\n}\n"]}
@@ -0,0 +1,60 @@
1
+ import type { Logger } from "@tylerbu/cli-api";
2
+ import { type Operation } from "effection";
3
+ import { type ExcludedPolicyFileMap } from "./context.js";
4
+ import { type PolicyHandlerPerfStats } from "./perf.js";
5
+ import type { PolicyFixResult, PolicyHandlerResult, PolicyInstance, PolicyInstanceId, PolicyName } from "./policy.js";
6
+ /**
7
+ * Result of running a single policy on a single file.
8
+ * @alpha
9
+ */
10
+ export interface PolicyFileResult {
11
+ file: string;
12
+ policy: PolicyName;
13
+ /** Stable identity of the configured policy instance */
14
+ policyId: PolicyInstanceId;
15
+ /** The raw result from the policy handler */
16
+ outcome: PolicyHandlerResult;
17
+ /** Set when a standalone resolver was attempted (legacy resolver path) */
18
+ resolution?: PolicyFixResult;
19
+ }
20
+ /**
21
+ * Aggregated results from a full policy run.
22
+ * @alpha
23
+ */
24
+ export interface PolicyRunResults {
25
+ results: PolicyFileResult[];
26
+ perfStats: PolicyHandlerPerfStats;
27
+ }
28
+ /**
29
+ * Options for configuring a {@link PolicyRunner}.
30
+ * @alpha
31
+ */
32
+ export interface PolicyRunnerOptions {
33
+ policies: PolicyInstance[];
34
+ excludeFromAll: RegExp[];
35
+ excludePoliciesForFiles: ExcludedPolicyFileMap;
36
+ gitRoot: string;
37
+ resolve: boolean;
38
+ logger?: Pick<Logger, "verbose">;
39
+ }
40
+ /**
41
+ * Runs configured policies against files and collects results.
42
+ * @alpha
43
+ */
44
+ export declare class PolicyRunner {
45
+ private readonly policies;
46
+ private readonly excludeFromAll;
47
+ private readonly excludePoliciesForFiles;
48
+ private readonly gitRoot;
49
+ private readonly resolve;
50
+ private readonly logger;
51
+ constructor(options: PolicyRunnerOptions);
52
+ run(filePaths: string[]): Operation<PolicyRunResults>;
53
+ private checkOrExcludeFile;
54
+ private routeToPolicies;
55
+ private runPolicyOnFile;
56
+ private isPolicyExcluded;
57
+ private executePolicyHandler;
58
+ private attemptResolution;
59
+ }
60
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtD,OAAO,EAEN,KAAK,qBAAqB,EAC1B,MAAM,cAAc,CAAC;AAEtB,OAAO,EAEN,KAAK,sBAAsB,EAE3B,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAEX,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,UAAU,EAEV,MAAM,aAAa,CAAC;AA0BrB;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;IACnB,wDAAwD;IACxD,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,6CAA6C;IAC7C,OAAO,EAAE,mBAAmB,CAAC;IAC7B,0EAA0E;IAC1E,UAAU,CAAC,EAAE,eAAe,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,SAAS,EAAE,sBAAsB,CAAC;CAClC;AAOD;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IACnC,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,uBAAuB,EAAE,qBAAqB,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACjC;AAED;;;GAGG;AACH,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAW;IAC1C,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAwB;IAChE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsC;gBAE1C,OAAO,EAAE,mBAAmB;IAYvC,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,gBAAgB,CAAC;IAgB7D,OAAO,CAAE,kBAAkB;IAc3B,OAAO,CAAE,eAAe;IA2BxB,OAAO,CAAE,eAAe;IAyDxB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAE,oBAAoB;IA2C7B,OAAO,CAAE,iBAAiB;CA4B1B"}
package/esm/runner.js ADDED
@@ -0,0 +1,174 @@
1
+ import { all, call } from "effection";
2
+ import { createExcludedPolicyFileMap, } from "./context.js";
3
+ import { identifyPolicyInstances } from "./makePolicy.js";
4
+ import { newPerfStats, runWithPerf, } from "./perf.js";
5
+ import { isPolicyError, isPolicyFixResult } from "./policy.js";
6
+ function isOperation(value) {
7
+ return (typeof value === "object" &&
8
+ value !== null &&
9
+ "next" in value &&
10
+ typeof value.next === "function");
11
+ }
12
+ function matches(regex, value) {
13
+ if (!(regex.global || regex.sticky)) {
14
+ return regex.test(value);
15
+ }
16
+ const savedLastIndex = regex.lastIndex;
17
+ try {
18
+ regex.lastIndex = 0;
19
+ return regex.test(value);
20
+ }
21
+ finally {
22
+ regex.lastIndex = savedLastIndex;
23
+ }
24
+ }
25
+ /**
26
+ * Runs configured policies against files and collects results.
27
+ * @alpha
28
+ */
29
+ export class PolicyRunner {
30
+ policies;
31
+ excludeFromAll;
32
+ excludePoliciesForFiles;
33
+ gitRoot;
34
+ resolve;
35
+ logger;
36
+ constructor(options) {
37
+ this.policies = identifyPolicyInstances(options.policies);
38
+ this.excludeFromAll = options.excludeFromAll;
39
+ this.excludePoliciesForFiles = createExcludedPolicyFileMap(this.policies);
40
+ for (const [instanceId, exclusions] of options.excludePoliciesForFiles) {
41
+ this.excludePoliciesForFiles.set(instanceId, exclusions);
42
+ }
43
+ this.gitRoot = options.gitRoot;
44
+ this.resolve = options.resolve;
45
+ this.logger = options.logger;
46
+ }
47
+ *run(filePaths) {
48
+ const state = {
49
+ results: [],
50
+ perfStats: newPerfStats(),
51
+ };
52
+ for (const filePath of filePaths) {
53
+ yield* this.checkOrExcludeFile(filePath, state);
54
+ }
55
+ return {
56
+ results: state.results,
57
+ perfStats: state.perfStats,
58
+ };
59
+ }
60
+ *checkOrExcludeFile(relPath, state) {
61
+ state.perfStats.count++;
62
+ try {
63
+ yield* this.routeToPolicies(relPath, state);
64
+ }
65
+ catch (error) {
66
+ throw new Error(`Error routing ${relPath} to handler: ${error}\nStack:\n${error.stack}`);
67
+ }
68
+ }
69
+ *routeToPolicies(relPath, state) {
70
+ if (this.excludeFromAll.some((regex) => matches(regex, relPath))) {
71
+ this.logger?.verbose(`Excluded all handlers: ${relPath}`);
72
+ return;
73
+ }
74
+ const matchingPolicies = this.policies.filter((policy) => matches(policy.match, relPath));
75
+ if (this.resolve) {
76
+ // Fixers can read and rewrite the same file.
77
+ for (const policy of matchingPolicies) {
78
+ yield* this.runPolicyOnFile(relPath, policy, state);
79
+ }
80
+ return;
81
+ }
82
+ yield* all(matchingPolicies.map((policy) => {
83
+ return this.runPolicyOnFile(relPath, policy, state);
84
+ }));
85
+ }
86
+ *runPolicyOnFile(relPath, policy, state) {
87
+ if (this.isPolicyExcluded(relPath, policy)) {
88
+ this.logger?.verbose(`Excluded from '${policy.instanceId}' policy: ${relPath}`);
89
+ return;
90
+ }
91
+ try {
92
+ const result = yield* this.executePolicyHandler(relPath, policy, state);
93
+ // Success — nothing to report
94
+ if (result === true) {
95
+ return;
96
+ }
97
+ const fileResult = {
98
+ file: relPath,
99
+ policy: policy.name,
100
+ policyId: policy.instanceId,
101
+ outcome: result,
102
+ };
103
+ // Check if resolution should be attempted: result is a failure that
104
+ // wasn't already fixed, resolve mode is on, and a standalone resolver exists.
105
+ const alreadyFixed = isPolicyFixResult(result) ||
106
+ (isPolicyError(result) && result.fixed !== undefined);
107
+ if (!alreadyFixed && this.resolve && policy.resolver) {
108
+ const resolution = yield* this.attemptResolution(relPath, policy, policy.resolver, state);
109
+ fileResult.resolution = resolution;
110
+ }
111
+ state.results.push(fileResult);
112
+ }
113
+ catch (error) {
114
+ const message = error instanceof Error ? error.message : String(error);
115
+ state.results.push({
116
+ file: relPath,
117
+ policy: policy.name,
118
+ policyId: policy.instanceId,
119
+ outcome: {
120
+ error: `System Error: Error executing policy '${policy.instanceId}' for file '${relPath}': ${message}`,
121
+ },
122
+ });
123
+ }
124
+ }
125
+ isPolicyExcluded(relPath, policy) {
126
+ return (this.excludePoliciesForFiles
127
+ .get(policy.instanceId)
128
+ ?.some((regex) => matches(regex, relPath)) ?? false);
129
+ }
130
+ *executePolicyHandler(relPath, policy, state) {
131
+ const { resolve, gitRoot } = this;
132
+ const result = yield* runWithPerf(policy.instanceId, "handle", state.perfStats, function* () {
133
+ const args = {
134
+ file: relPath,
135
+ root: gitRoot,
136
+ resolve,
137
+ config: policy.config,
138
+ };
139
+ if (policy._internalHandler) {
140
+ return yield* policy._internalHandler(args);
141
+ }
142
+ const handlerResult = policy.handler(args);
143
+ if (handlerResult instanceof Promise) {
144
+ return yield* call(() => handlerResult);
145
+ }
146
+ if (isOperation(handlerResult)) {
147
+ return yield* handlerResult;
148
+ }
149
+ throw new Error(`Unexpected handler result type: ${typeof handlerResult}`);
150
+ });
151
+ if (result === undefined) {
152
+ throw new Error("Policy result was undefined.");
153
+ }
154
+ return result;
155
+ }
156
+ *attemptResolution(relPath, policy, resolver, state) {
157
+ const { gitRoot } = this;
158
+ return yield* runWithPerf(policy.instanceId, "resolve", state.perfStats, function* () {
159
+ const result = resolver({
160
+ file: relPath,
161
+ root: gitRoot,
162
+ config: policy.config,
163
+ });
164
+ if (result instanceof Promise) {
165
+ return yield* call(() => result);
166
+ }
167
+ if (isOperation(result)) {
168
+ return yield* result;
169
+ }
170
+ throw new Error(`Unexpected resolver result type: ${typeof result}`);
171
+ });
172
+ }
173
+ }
174
+ //# sourceMappingURL=runner.js.map