repopo 0.10.0 → 0.13.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 (340) hide show
  1. package/CHANGELOG.md +113 -0
  2. package/README.md +76 -77
  3. package/THIRD-PARTY-LICENSES.txt +232 -14
  4. package/bin/dev.js +5 -1
  5. package/esm/adapters/fluidFramework.d.ts +13 -9
  6. package/esm/adapters/fluidFramework.d.ts.map +1 -1
  7. package/esm/adapters/fluidFramework.js +20 -43
  8. package/esm/adapters/fluidFramework.js.map +1 -1
  9. package/esm/api.d.ts +64 -1
  10. package/esm/api.d.ts.map +1 -1
  11. package/esm/api.js +17 -1
  12. package/esm/api.js.map +1 -1
  13. package/esm/baseCommand.d.ts +1 -1
  14. package/esm/baseCommand.d.ts.map +1 -1
  15. package/esm/baseCommand.js +7 -10
  16. package/esm/baseCommand.js.map +1 -1
  17. package/esm/commands/check-native.d.ts +25 -0
  18. package/esm/commands/check-native.d.ts.map +1 -0
  19. package/esm/commands/check-native.js +156 -0
  20. package/esm/commands/check-native.js.map +1 -0
  21. package/esm/commands/check.d.ts +7 -34
  22. package/esm/commands/check.d.ts.map +1 -1
  23. package/esm/commands/check.js +76 -265
  24. package/esm/commands/check.js.map +1 -1
  25. package/esm/commands/list.d.ts.map +1 -1
  26. package/esm/commands/list.js +6 -6
  27. package/esm/commands/list.js.map +1 -1
  28. package/esm/concurrency.d.ts +3 -0
  29. package/esm/concurrency.d.ts.map +1 -0
  30. package/esm/concurrency.js +8 -0
  31. package/esm/concurrency.js.map +1 -0
  32. package/esm/config.d.ts +5 -39
  33. package/esm/config.d.ts.map +1 -1
  34. package/esm/config.js +3 -7
  35. package/esm/config.js.map +1 -1
  36. package/esm/context.d.ts +20 -3
  37. package/esm/context.d.ts.map +1 -1
  38. package/esm/context.js +18 -1
  39. package/esm/context.js.map +1 -1
  40. package/esm/executionContractError.d.ts +4 -0
  41. package/esm/executionContractError.d.ts.map +1 -0
  42. package/esm/executionContractError.js +4 -0
  43. package/esm/executionContractError.js.map +1 -0
  44. package/esm/fileCache.d.ts +12 -0
  45. package/esm/fileCache.d.ts.map +1 -0
  46. package/esm/fileCache.js +37 -0
  47. package/esm/fileCache.js.map +1 -0
  48. package/esm/filePaths.d.ts +2 -0
  49. package/esm/filePaths.d.ts.map +1 -0
  50. package/esm/filePaths.js +9 -0
  51. package/esm/filePaths.js.map +1 -0
  52. package/esm/generators.d.ts +0 -20
  53. package/esm/generators.d.ts.map +1 -1
  54. package/esm/generators.js.map +1 -1
  55. package/esm/index.d.ts +3 -11
  56. package/esm/index.d.ts.map +1 -1
  57. package/esm/index.js +3 -14
  58. package/esm/index.js.map +1 -1
  59. package/esm/makePolicy.d.ts +26 -79
  60. package/esm/makePolicy.d.ts.map +1 -1
  61. package/esm/makePolicy.js +51 -95
  62. package/esm/makePolicy.js.map +1 -1
  63. package/esm/perf.d.ts +10 -2
  64. package/esm/perf.d.ts.map +1 -1
  65. package/esm/perf.js +10 -9
  66. package/esm/perf.js.map +1 -1
  67. package/esm/policies/CargoLicenceValidated.d.ts +41 -0
  68. package/esm/policies/CargoLicenceValidated.d.ts.map +1 -0
  69. package/esm/policies/CargoLicenceValidated.js +47 -0
  70. package/esm/policies/CargoLicenceValidated.js.map +1 -0
  71. package/esm/policies/CargoLintsConfigured.d.ts +30 -0
  72. package/esm/policies/CargoLintsConfigured.d.ts.map +1 -0
  73. package/esm/policies/CargoLintsConfigured.js +65 -0
  74. package/esm/policies/CargoLintsConfigured.js.map +1 -0
  75. package/esm/policies/CargoLockPolicy.d.ts +34 -0
  76. package/esm/policies/CargoLockPolicy.d.ts.map +1 -0
  77. package/esm/policies/CargoLockPolicy.js +61 -0
  78. package/esm/policies/CargoLockPolicy.js.map +1 -0
  79. package/esm/policies/CargoTomlRequired.d.ts +34 -0
  80. package/esm/policies/CargoTomlRequired.d.ts.map +1 -0
  81. package/esm/policies/CargoTomlRequired.js +77 -0
  82. package/esm/policies/CargoTomlRequired.js.map +1 -0
  83. package/esm/policies/CargoTomlSorted.d.ts +20 -0
  84. package/esm/policies/CargoTomlSorted.d.ts.map +1 -0
  85. package/esm/policies/CargoTomlSorted.js +168 -0
  86. package/esm/policies/CargoTomlSorted.js.map +1 -0
  87. package/esm/policies/ConditionalScripts.d.ts +10 -8
  88. package/esm/policies/ConditionalScripts.d.ts.map +1 -1
  89. package/esm/policies/ConditionalScripts.js +27 -24
  90. package/esm/policies/ConditionalScripts.js.map +1 -1
  91. package/esm/policies/ExactScripts.d.ts +8 -6
  92. package/esm/policies/ExactScripts.d.ts.map +1 -1
  93. package/esm/policies/ExactScripts.js +18 -20
  94. package/esm/policies/ExactScripts.js.map +1 -1
  95. package/esm/policies/GleamDepVersions.d.ts +25 -0
  96. package/esm/policies/GleamDepVersions.d.ts.map +1 -0
  97. package/esm/policies/GleamDepVersions.js +67 -0
  98. package/esm/policies/GleamDepVersions.js.map +1 -0
  99. package/esm/policies/GleamDocExists.d.ts +24 -0
  100. package/esm/policies/GleamDocExists.d.ts.map +1 -0
  101. package/esm/policies/GleamDocExists.js +39 -0
  102. package/esm/policies/GleamDocExists.js.map +1 -0
  103. package/esm/policies/GleamInternalModulesConfigured.d.ts +21 -0
  104. package/esm/policies/GleamInternalModulesConfigured.d.ts.map +1 -0
  105. package/esm/policies/GleamInternalModulesConfigured.js +32 -0
  106. package/esm/policies/GleamInternalModulesConfigured.js.map +1 -0
  107. package/esm/policies/GleamLicenceConfigured.d.ts +29 -0
  108. package/esm/policies/GleamLicenceConfigured.d.ts.map +1 -0
  109. package/esm/policies/GleamLicenceConfigured.js +36 -0
  110. package/esm/policies/GleamLicenceConfigured.js.map +1 -0
  111. package/esm/policies/GleamManifestCommitted.d.ts +16 -0
  112. package/esm/policies/GleamManifestCommitted.d.ts.map +1 -0
  113. package/esm/policies/GleamManifestCommitted.js +27 -0
  114. package/esm/policies/GleamManifestCommitted.js.map +1 -0
  115. package/esm/policies/GleamMonorepoConsistency.d.ts +38 -0
  116. package/esm/policies/GleamMonorepoConsistency.d.ts.map +1 -0
  117. package/esm/policies/GleamMonorepoConsistency.js +74 -0
  118. package/esm/policies/GleamMonorepoConsistency.js.map +1 -0
  119. package/esm/policies/GleamNameRestrictions.d.ts +25 -0
  120. package/esm/policies/GleamNameRestrictions.d.ts.map +1 -0
  121. package/esm/policies/GleamNameRestrictions.js +44 -0
  122. package/esm/policies/GleamNameRestrictions.js.map +1 -0
  123. package/esm/policies/GleamNoPathDepsInPublished.d.ts +22 -0
  124. package/esm/policies/GleamNoPathDepsInPublished.d.ts.map +1 -0
  125. package/esm/policies/GleamNoPathDepsInPublished.js +43 -0
  126. package/esm/policies/GleamNoPathDepsInPublished.js.map +1 -0
  127. package/esm/policies/GleamPathDepsValid.d.ts +9 -0
  128. package/esm/policies/GleamPathDepsValid.d.ts.map +1 -0
  129. package/esm/policies/GleamPathDepsValid.js +59 -0
  130. package/esm/policies/GleamPathDepsValid.js.map +1 -0
  131. package/esm/policies/GleamProjectStructure.d.ts +32 -0
  132. package/esm/policies/GleamProjectStructure.d.ts.map +1 -0
  133. package/esm/policies/GleamProjectStructure.js +32 -0
  134. package/esm/policies/GleamProjectStructure.js.map +1 -0
  135. package/esm/policies/GleamSharedDependencyVersions.d.ts +37 -0
  136. package/esm/policies/GleamSharedDependencyVersions.d.ts.map +1 -0
  137. package/esm/policies/GleamSharedDependencyVersions.js +101 -0
  138. package/esm/policies/GleamSharedDependencyVersions.js.map +1 -0
  139. package/esm/policies/GleamTomlRequired.d.ts +30 -0
  140. package/esm/policies/GleamTomlRequired.d.ts.map +1 -0
  141. package/esm/policies/GleamTomlRequired.js +37 -0
  142. package/esm/policies/GleamTomlRequired.js.map +1 -0
  143. package/esm/policies/GleamTomlSorted.d.ts +20 -0
  144. package/esm/policies/GleamTomlSorted.d.ts.map +1 -0
  145. package/esm/policies/GleamTomlSorted.js +157 -0
  146. package/esm/policies/GleamTomlSorted.js.map +1 -0
  147. package/esm/policies/GleamVersionConstraint.d.ts +20 -0
  148. package/esm/policies/GleamVersionConstraint.d.ts.map +1 -0
  149. package/esm/policies/GleamVersionConstraint.js +68 -0
  150. package/esm/policies/GleamVersionConstraint.js.map +1 -0
  151. package/esm/policies/HtmlFileHeaders.d.ts +4 -2
  152. package/esm/policies/HtmlFileHeaders.d.ts.map +1 -1
  153. package/esm/policies/HtmlFileHeaders.js +2 -2
  154. package/esm/policies/HtmlFileHeaders.js.map +1 -1
  155. package/esm/policies/JsTsFileHeaders.d.ts +4 -2
  156. package/esm/policies/JsTsFileHeaders.d.ts.map +1 -1
  157. package/esm/policies/JsTsFileHeaders.js +1 -1
  158. package/esm/policies/JsTsFileHeaders.js.map +1 -1
  159. package/esm/policies/LicenseFileExists.d.ts +10 -4
  160. package/esm/policies/LicenseFileExists.d.ts.map +1 -1
  161. package/esm/policies/LicenseFileExists.js +27 -20
  162. package/esm/policies/LicenseFileExists.js.map +1 -1
  163. package/esm/policies/MutuallyExclusiveScripts.d.ts +8 -6
  164. package/esm/policies/MutuallyExclusiveScripts.d.ts.map +1 -1
  165. package/esm/policies/MutuallyExclusiveScripts.js +9 -13
  166. package/esm/policies/MutuallyExclusiveScripts.js.map +1 -1
  167. package/esm/policies/NoBuildDirectory.d.ts +15 -0
  168. package/esm/policies/NoBuildDirectory.d.ts.map +1 -0
  169. package/esm/policies/NoBuildDirectory.js +24 -0
  170. package/esm/policies/NoBuildDirectory.js.map +1 -0
  171. package/esm/policies/NoJsFileExtensions.d.ts +9 -3
  172. package/esm/policies/NoJsFileExtensions.d.ts.map +1 -1
  173. package/esm/policies/NoJsFileExtensions.js +9 -14
  174. package/esm/policies/NoJsFileExtensions.js.map +1 -1
  175. package/esm/policies/NoLargeBinaryFiles.d.ts +9 -4
  176. package/esm/policies/NoLargeBinaryFiles.d.ts.map +1 -1
  177. package/esm/policies/NoLargeBinaryFiles.js +10 -16
  178. package/esm/policies/NoLargeBinaryFiles.js.map +1 -1
  179. package/esm/policies/NoPrivateWorkspaceDependencies.d.ts +10 -6
  180. package/esm/policies/NoPrivateWorkspaceDependencies.d.ts.map +1 -1
  181. package/esm/policies/NoPrivateWorkspaceDependencies.js +12 -14
  182. package/esm/policies/NoPrivateWorkspaceDependencies.js.map +1 -1
  183. package/esm/policies/NoTargetArtifacts.d.ts +14 -0
  184. package/esm/policies/NoTargetArtifacts.d.ts.map +1 -0
  185. package/esm/policies/NoTargetArtifacts.js +37 -0
  186. package/esm/policies/NoTargetArtifacts.js.map +1 -0
  187. package/esm/policies/NoUnsafeWithoutJustification.d.ts +31 -0
  188. package/esm/policies/NoUnsafeWithoutJustification.d.ts.map +1 -0
  189. package/esm/policies/NoUnsafeWithoutJustification.js +79 -0
  190. package/esm/policies/NoUnsafeWithoutJustification.js.map +1 -0
  191. package/esm/policies/NoWildcardDependencies.d.ts +30 -0
  192. package/esm/policies/NoWildcardDependencies.d.ts.map +1 -0
  193. package/esm/policies/NoWildcardDependencies.js +83 -0
  194. package/esm/policies/NoWildcardDependencies.js.map +1 -0
  195. package/esm/policies/PackageAllowedScopes.d.ts +9 -5
  196. package/esm/policies/PackageAllowedScopes.d.ts.map +1 -1
  197. package/esm/policies/PackageAllowedScopes.js +15 -16
  198. package/esm/policies/PackageAllowedScopes.js.map +1 -1
  199. package/esm/policies/PackageEsmType.d.ts +7 -5
  200. package/esm/policies/PackageEsmType.d.ts.map +1 -1
  201. package/esm/policies/PackageEsmType.js +38 -36
  202. package/esm/policies/PackageEsmType.js.map +1 -1
  203. package/esm/policies/PackageFolderName.d.ts +8 -6
  204. package/esm/policies/PackageFolderName.d.ts.map +1 -1
  205. package/esm/policies/PackageFolderName.js +13 -16
  206. package/esm/policies/PackageFolderName.js.map +1 -1
  207. package/esm/policies/PackageJsonProperties.d.ts +5 -3
  208. package/esm/policies/PackageJsonProperties.d.ts.map +1 -1
  209. package/esm/policies/PackageJsonProperties.js +18 -21
  210. package/esm/policies/PackageJsonProperties.js.map +1 -1
  211. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts +2 -7
  212. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts.map +1 -1
  213. package/esm/policies/PackageJsonRepoDirectoryProperty.js +29 -42
  214. package/esm/policies/PackageJsonRepoDirectoryProperty.js.map +1 -1
  215. package/esm/policies/PackageJsonSorted.d.ts +2 -2
  216. package/esm/policies/PackageJsonSorted.d.ts.map +1 -1
  217. package/esm/policies/PackageJsonSorted.js +51 -31
  218. package/esm/policies/PackageJsonSorted.js.map +1 -1
  219. package/esm/policies/PackageLicense.d.ts +4 -4
  220. package/esm/policies/PackageLicense.d.ts.map +1 -1
  221. package/esm/policies/PackageLicense.js +32 -54
  222. package/esm/policies/PackageLicense.js.map +1 -1
  223. package/esm/policies/PackagePrivateField.d.ts +12 -8
  224. package/esm/policies/PackagePrivateField.d.ts.map +1 -1
  225. package/esm/policies/PackagePrivateField.js +34 -25
  226. package/esm/policies/PackagePrivateField.js.map +1 -1
  227. package/esm/policies/PackageReadme.d.ts +6 -5
  228. package/esm/policies/PackageReadme.d.ts.map +1 -1
  229. package/esm/policies/PackageReadme.js +24 -61
  230. package/esm/policies/PackageReadme.js.map +1 -1
  231. package/esm/policies/PackageScripts.d.ts +26 -22
  232. package/esm/policies/PackageScripts.d.ts.map +1 -1
  233. package/esm/policies/PackageScripts.js +42 -38
  234. package/esm/policies/PackageScripts.js.map +1 -1
  235. package/esm/policies/PackageTestScripts.d.ts +10 -6
  236. package/esm/policies/PackageTestScripts.d.ts.map +1 -1
  237. package/esm/policies/PackageTestScripts.js +17 -19
  238. package/esm/policies/PackageTestScripts.js.map +1 -1
  239. package/esm/policies/PublicApiDocumented.d.ts +21 -0
  240. package/esm/policies/PublicApiDocumented.d.ts.map +1 -0
  241. package/esm/policies/PublicApiDocumented.js +38 -0
  242. package/esm/policies/PublicApiDocumented.js.map +1 -0
  243. package/esm/policies/RequiredGitignorePatterns.d.ts +11 -4
  244. package/esm/policies/RequiredGitignorePatterns.d.ts.map +1 -1
  245. package/esm/policies/RequiredGitignorePatterns.js +29 -36
  246. package/esm/policies/RequiredGitignorePatterns.js.map +1 -1
  247. package/esm/policies/RequiredScripts.d.ts +9 -7
  248. package/esm/policies/RequiredScripts.d.ts.map +1 -1
  249. package/esm/policies/RequiredScripts.js +27 -26
  250. package/esm/policies/RequiredScripts.js.map +1 -1
  251. package/esm/policies/RustDocExists.d.ts +24 -0
  252. package/esm/policies/RustDocExists.d.ts.map +1 -0
  253. package/esm/policies/RustDocExists.js +49 -0
  254. package/esm/policies/RustDocExists.js.map +1 -0
  255. package/esm/policies/RustToolchainExists.d.ts +27 -0
  256. package/esm/policies/RustToolchainExists.d.ts.map +1 -0
  257. package/esm/policies/RustToolchainExists.js +28 -0
  258. package/esm/policies/RustToolchainExists.js.map +1 -0
  259. package/esm/policies/RustfmtConfigExists.d.ts +27 -0
  260. package/esm/policies/RustfmtConfigExists.d.ts.map +1 -0
  261. package/esm/policies/RustfmtConfigExists.js +28 -0
  262. package/esm/policies/RustfmtConfigExists.js.map +1 -0
  263. package/esm/policies/ScriptContains.d.ts +9 -7
  264. package/esm/policies/ScriptContains.d.ts.map +1 -1
  265. package/esm/policies/ScriptContains.js +9 -13
  266. package/esm/policies/ScriptContains.js.map +1 -1
  267. package/esm/policies/SharedDependencyVersions.d.ts +29 -0
  268. package/esm/policies/SharedDependencyVersions.d.ts.map +1 -0
  269. package/esm/policies/SharedDependencyVersions.js +143 -0
  270. package/esm/policies/SharedDependencyVersions.js.map +1 -0
  271. package/esm/policies/WorkspaceInheritance.d.ts +31 -0
  272. package/esm/policies/WorkspaceInheritance.d.ts.map +1 -0
  273. package/esm/policies/WorkspaceInheritance.js +93 -0
  274. package/esm/policies/WorkspaceInheritance.js.map +1 -0
  275. package/esm/policies/WorkspaceMembersValid.d.ts +27 -0
  276. package/esm/policies/WorkspaceMembersValid.d.ts.map +1 -0
  277. package/esm/policies/WorkspaceMembersValid.js +87 -0
  278. package/esm/policies/WorkspaceMembersValid.js.map +1 -0
  279. package/esm/policies/constants.d.ts +8 -0
  280. package/esm/policies/constants.d.ts.map +1 -1
  281. package/esm/policies/constants.js +9 -1
  282. package/esm/policies/constants.js.map +1 -1
  283. package/esm/policies.d.ts +43 -5
  284. package/esm/policies.d.ts.map +1 -1
  285. package/esm/policies.js +63 -6
  286. package/esm/policies.js.map +1 -1
  287. package/esm/policy.d.ts +65 -269
  288. package/esm/policy.d.ts.map +1 -1
  289. package/esm/policy.js +1 -122
  290. package/esm/policy.js.map +1 -1
  291. package/esm/policyDefiners/defineCargoPolicy.d.ts +82 -0
  292. package/esm/policyDefiners/defineCargoPolicy.d.ts.map +1 -0
  293. package/esm/policyDefiners/defineCargoPolicy.js +42 -0
  294. package/esm/policyDefiners/defineCargoPolicy.js.map +1 -0
  295. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts +27 -14
  296. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts.map +1 -1
  297. package/esm/policyDefiners/defineFileHeaderPolicy.js +19 -39
  298. package/esm/policyDefiners/defineFileHeaderPolicy.js.map +1 -1
  299. package/esm/policyDefiners/defineGleamPolicy.d.ts +81 -0
  300. package/esm/policyDefiners/defineGleamPolicy.d.ts.map +1 -0
  301. package/esm/policyDefiners/defineGleamPolicy.js +42 -0
  302. package/esm/policyDefiners/defineGleamPolicy.js.map +1 -0
  303. package/esm/policyDefiners/definePackagePolicy.d.ts +24 -13
  304. package/esm/policyDefiners/definePackagePolicy.d.ts.map +1 -1
  305. package/esm/policyDefiners/definePackagePolicy.js +9 -32
  306. package/esm/policyDefiners/definePackagePolicy.js.map +1 -1
  307. package/esm/policyDefiners/spdxValidator.d.ts +66 -0
  308. package/esm/policyDefiners/spdxValidator.d.ts.map +1 -0
  309. package/esm/policyDefiners/spdxValidator.js +139 -0
  310. package/esm/policyDefiners/spdxValidator.js.map +1 -0
  311. package/esm/policyDefiners/tomlParser.d.ts +8 -0
  312. package/esm/policyDefiners/tomlParser.d.ts.map +1 -0
  313. package/esm/policyDefiners/tomlParser.js +17 -0
  314. package/esm/policyDefiners/tomlParser.js.map +1 -0
  315. package/esm/policyExecution.d.ts +19 -0
  316. package/esm/policyExecution.d.ts.map +1 -0
  317. package/esm/policyExecution.js +224 -0
  318. package/esm/policyExecution.js.map +1 -0
  319. package/esm/repositoryFiles.d.ts +4 -0
  320. package/esm/repositoryFiles.d.ts.map +1 -0
  321. package/esm/repositoryFiles.js +8 -0
  322. package/esm/repositoryFiles.js.map +1 -0
  323. package/esm/runner.d.ts +85 -0
  324. package/esm/runner.d.ts.map +1 -0
  325. package/esm/runner.js +189 -0
  326. package/esm/runner.js.map +1 -0
  327. package/esm/settlePolicyPromise.d.ts +4 -0
  328. package/esm/settlePolicyPromise.d.ts.map +1 -0
  329. package/esm/settlePolicyPromise.js +10 -0
  330. package/esm/settlePolicyPromise.js.map +1 -0
  331. package/esm/tsdoc-metadata.json +1 -1
  332. package/esm/utils/safePaths.d.ts +9 -0
  333. package/esm/utils/safePaths.d.ts.map +1 -0
  334. package/esm/utils/safePaths.js +40 -0
  335. package/esm/utils/safePaths.js.map +1 -0
  336. package/oclif.manifest.json +117 -3
  337. package/package.json +66 -36
  338. package/scripts/benchmark.mjs +341 -0
  339. package/scripts/postinstall.mjs +154 -0
  340. package/sidecar/sidecar.mjs +399 -0
package/esm/makePolicy.js CHANGED
@@ -1,102 +1,58 @@
1
- import { call } from "effection";
2
- import { isGeneratorFunction } from "./generators.js";
3
- /**
4
- * Normalizes a handler to always return an Effection Operation.
5
- * Detection happens once at registration time, not per-invocation.
6
- */
7
- function normalizeHandler(handler) {
8
- if (isGeneratorFunction(handler)) {
9
- // Already a generator, return as-is
10
- return handler;
1
+ import { exclusionRegex } from "./context.js";
2
+ export function makePolicy(definition, options, ...extra) {
3
+ const guidance = "Use makePolicy(definition, { config, exclude, instanceId }); positional config, third arguments and excludeFiles are no longer supported.";
4
+ if (extra.length > 0 ||
5
+ (options !== undefined &&
6
+ (typeof options !== "object" ||
7
+ options === null ||
8
+ Array.isArray(options) ||
9
+ Object.keys(options).some((key) => !["config", "exclude", "instanceId"].includes(key))))) {
10
+ throw new TypeError(guidance);
11
11
  }
12
- // Async function - wrap with call()
13
- return function* (args) {
14
- const asyncHandler = handler;
15
- return yield* call(() => asyncHandler(args));
16
- };
12
+ if (definition.scope === "repository" && definition.resolver !== undefined) {
13
+ throw new TypeError("Repository policies support inline fixes only; remove resolver.");
14
+ }
15
+ if (options?.exclude !== undefined &&
16
+ !(Array.isArray(options.exclude) &&
17
+ options.exclude.every((value) => typeof value === "string" || value instanceof RegExp))) {
18
+ throw new TypeError(guidance);
19
+ }
20
+ if (options?.instanceId !== undefined &&
21
+ (typeof options.instanceId !== "string" || options.instanceId.length === 0)) {
22
+ throw new TypeError("instanceId must be a nonempty string.");
23
+ }
24
+ options?.exclude?.forEach(exclusionRegex);
25
+ const config = options?.config === undefined ? definition.defaultConfig : options.config;
26
+ if (definition.requiresConfig && config === undefined) {
27
+ throw new TypeError(`Policy '${definition.name}' requires config. ${guidance}`);
28
+ }
29
+ return { ...definition, ...options, config };
17
30
  }
18
- /** @alpha */
19
- export function policy(policyDef, configOrOptions, maybeOptions) {
20
- // Determine if the second argument is config or options
21
- let config;
22
- let options;
23
- if (maybeOptions !== undefined) {
24
- // Three-argument form: policy(def, config, options)
25
- config = configOrOptions;
26
- options = maybeOptions;
31
+ /** Assign stable IDs, rejecting ambiguous duplicates. @internal */
32
+ export function identifyPolicyInstances(policies) {
33
+ const names = new Map();
34
+ const ids = new Set();
35
+ for (const policy of policies) {
36
+ names.set(policy.name, (names.get(policy.name) ?? 0) + 1);
37
+ if (policy.instanceId !== undefined) {
38
+ if (ids.has(policy.instanceId)) {
39
+ throw new Error(`Duplicate policy instance ID: ${policy.instanceId}`);
40
+ }
41
+ ids.add(policy.instanceId);
42
+ }
27
43
  }
28
- else if (configOrOptions !== undefined) {
29
- // Two-argument form: need to determine if it's config or options
30
- // PolicyOptions has a specific shape with 'exclude' property
31
- if (typeof configOrOptions === "object" &&
32
- configOrOptions !== null &&
33
- "exclude" in configOrOptions &&
34
- !("name" in configOrOptions) &&
35
- Object.keys(configOrOptions).every((k) => k === "exclude")) {
36
- // It's options (has only 'exclude')
37
- options = configOrOptions;
44
+ return policies.map((policy) => {
45
+ if (policy.instanceId !== undefined) {
46
+ return { ...policy, instanceId: policy.instanceId };
38
47
  }
39
- else {
40
- // It's config
41
- config = configOrOptions;
48
+ if ((names.get(policy.name) ?? 0) > 1) {
49
+ throw new Error(`Policy '${policy.name}' is configured multiple times. Set a unique instanceId for each instance.`);
42
50
  }
43
- }
44
- // Merge with default config if available
45
- const effectiveConfig = config ?? policyDef.defaultConfig;
46
- // Support both 'exclude' and 'excludeFiles' for backward compatibility
47
- const excludePatterns = options?.exclude;
48
- return {
49
- ...policyDef,
50
- config: effectiveConfig,
51
- exclude: excludePatterns,
52
- excludeFiles: excludePatterns,
53
- _internalHandler: normalizeHandler(policyDef.handler),
54
- };
55
- }
56
- /**
57
- * Creates a {@link PolicyDefinition} from the provided arguments.
58
- *
59
- * @deprecated Define policies as object literals satisfying {@link PolicyShape} instead.
60
- *
61
- * @example
62
- * ```typescript
63
- * const MyPolicy = makePolicyDefinition({
64
- * name: "MyPolicy",
65
- * description: "Ensures files follow conventions",
66
- * match: /\.ts$/,
67
- * handler: async ({ file }) => true,
68
- * });
69
- * ```
70
- *
71
- * @alpha
72
- */
73
- export function makePolicyDefinition(args) {
74
- return {
75
- name: args.name,
76
- description: args.description,
77
- match: args.match,
78
- handler: args.handler,
79
- defaultConfig: args.defaultConfig,
80
- resolver: args.resolver,
81
- };
82
- }
83
- /**
84
- * Combine a {@link PolicyDefinition} with a policy-specific config and other settings.
85
- *
86
- * @deprecated Use the `policy` function instead, which has a simpler API.
87
- *
88
- * @example
89
- * ```typescript
90
- * makePolicy(NoJsFileExtensions, undefined, { excludeFiles: ["bin/*"] })
91
- * ```
92
- *
93
- * @alpha
94
- */
95
- export function makePolicy(definition, config, settings) {
96
- return {
97
- ...definition,
98
- ...settings,
99
- config,
100
- };
51
+ if (ids.has(policy.name)) {
52
+ throw new Error(`Policy instance ID '${policy.name}' conflicts with another configured policy. Set an explicit unique instanceId.`);
53
+ }
54
+ ids.add(policy.name);
55
+ return { ...policy, instanceId: policy.name };
56
+ });
101
57
  }
102
58
  //# sourceMappingURL=makePolicy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"makePolicy.js","sourceRoot":"","sources":["../src/makePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAkB,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AA6BtD;;;GAGG;AACH,SAAS,gBAAgB,CACxB,OAAyB;IAEzB,IAAI,mBAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;QAClC,oCAAoC;QACpC,OAAO,OAAkE,CAAC;IAC3E,CAAC;IAED,oCAAoC;IACpC,OAAO,QAAQ,CAAC,EAAE,IAAmB;QACpC,MAAM,YAAY,GAAG,OAEY,CAAC;QAClC,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC;AACH,CAAC;AAoCD,aAAa;AACb,MAAM,UAAU,MAAM,CACrB,SAAyB,EACzB,eAAmC,EACnC,YAA4B;IAE5B,wDAAwD;IACxD,IAAI,MAAqB,CAAC;IAC1B,IAAI,OAAkC,CAAC;IAEvC,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAChC,oDAAoD;QACpD,MAAM,GAAG,eAAoB,CAAC;QAC9B,OAAO,GAAG,YAAY,CAAC;IACxB,CAAC;SAAM,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QAC1C,iEAAiE;QACjE,6DAA6D;QAC7D,IACC,OAAO,eAAe,KAAK,QAAQ;YACnC,eAAe,KAAK,IAAI;YACxB,SAAS,IAAI,eAAe;YAC5B,CAAC,CAAC,MAAM,IAAI,eAAe,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,EACzD,CAAC;YACF,oCAAoC;YACpC,OAAO,GAAG,eAAgC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACP,cAAc;YACd,MAAM,GAAG,eAAoB,CAAC;QAC/B,CAAC;IACF,CAAC;IAED,yCAAyC;IACzC,MAAM,eAAe,GAAG,MAAM,IAAK,SAAS,CAAC,aAA+B,CAAC;IAE7E,uEAAuE;IACvE,MAAM,eAAe,GAAG,OAAO,EAAE,OAAO,CAAC;IAEzC,OAAO;QACN,GAAG,SAAS;QACZ,MAAM,EAAE,eAAe;QACvB,OAAO,EAAE,eAAe;QACxB,YAAY,EAAE,eAAe;QAC7B,gBAAgB,EAAE,gBAAgB,CAAC,SAAS,CAAC,OAAO,CAAC;KACrD,CAAC;AACH,CAAC;AAeD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,oBAAoB,CACnC,IAA8B;IAE9B,OAAO;QACN,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,QAAQ,EAAE,IAAI,CAAC,QAAQ;KACvB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CACzB,UAA+B,EAC/B,MAAU,EACV,QAAoC;IAEpC,OAAO;QACN,GAAG,UAAU;QACb,GAAG,QAAQ;QACX,MAAM;KACsB,CAAC;AAC/B,CAAC","sourcesContent":["import { call, type Operation } from \"effection\";\nimport { isGeneratorFunction } from \"./generators.js\";\nimport type {\n\tConfiguredPolicy,\n\tPolicyArgs,\n\tPolicyDefinition,\n\tPolicyHandler,\n\tPolicyHandlerResult,\n\tPolicyInstance,\n\tPolicyInstanceSettings,\n\tPolicyShape,\n} from \"./policy.js\";\n\n// ============================================================================\n// New API: policy() function\n// ============================================================================\n\n/**\n * Options for configuring a policy instance.\n *\n * @alpha\n */\nexport interface PolicyOptions {\n\t/**\n\t * File paths matching these patterns will be excluded from this policy.\n\t * Patterns are matched against repo-relative paths.\n\t */\n\texclude?: (string | RegExp)[];\n}\n\n/**\n * Normalizes a handler to always return an Effection Operation.\n * Detection happens once at registration time, not per-invocation.\n */\nfunction normalizeHandler<C>(\n\thandler: PolicyHandler<C>,\n): (args: PolicyArgs<C>) => Operation<PolicyHandlerResult> {\n\tif (isGeneratorFunction(handler)) {\n\t\t// Already a generator, return as-is\n\t\treturn handler as (args: PolicyArgs<C>) => Operation<PolicyHandlerResult>;\n\t}\n\n\t// Async function - wrap with call()\n\treturn function* (args: PolicyArgs<C>): Operation<PolicyHandlerResult> {\n\t\tconst asyncHandler = handler as (\n\t\t\tpolicyArgs: PolicyArgs<C>,\n\t\t) => Promise<PolicyHandlerResult>;\n\t\treturn yield* call(() => asyncHandler(args));\n\t};\n}\n\n/**\n * Configure a policy for use in repopo.\n *\n * @remarks\n * This function takes a policy definition and returns a configured policy instance\n * that can be added to the `policies` array in `repopo.config.ts`.\n *\n * Handlers are automatically normalized: async functions are wrapped for Effection\n * compatibility, while generator functions are used directly.\n *\n * @example\n * ```typescript\n * // Policy with no config, just options\n * policy(NoJsFileExtensions, { exclude: [\"bin/*\"] })\n *\n * // Policy with config\n * policy(PackageJsonProperties, { verbatim: { license: \"MIT\" } })\n *\n * // Policy with config and options\n * policy(PackageJsonProperties, { verbatim: { license: \"MIT\" } }, { exclude: [\"vendor/*\"] })\n * ```\n *\n * @alpha\n */\nexport function policy<C = void>(\n\tpolicyDef: PolicyShape<C>,\n\toptions?: PolicyOptions,\n): ConfiguredPolicy<C>;\n/** @alpha */\nexport function policy<C>(\n\tpolicyDef: PolicyShape<C>,\n\tconfig: C,\n\toptions?: PolicyOptions,\n): ConfiguredPolicy<C>;\n/** @alpha */\nexport function policy<C>(\n\tpolicyDef: PolicyShape<C>,\n\tconfigOrOptions?: C | PolicyOptions,\n\tmaybeOptions?: PolicyOptions,\n): ConfiguredPolicy<C> {\n\t// Determine if the second argument is config or options\n\tlet config: C | undefined;\n\tlet options: PolicyOptions | undefined;\n\n\tif (maybeOptions !== undefined) {\n\t\t// Three-argument form: policy(def, config, options)\n\t\tconfig = configOrOptions as C;\n\t\toptions = maybeOptions;\n\t} else if (configOrOptions !== undefined) {\n\t\t// Two-argument form: need to determine if it's config or options\n\t\t// PolicyOptions has a specific shape with 'exclude' property\n\t\tif (\n\t\t\ttypeof configOrOptions === \"object\" &&\n\t\t\tconfigOrOptions !== null &&\n\t\t\t\"exclude\" in configOrOptions &&\n\t\t\t!(\"name\" in configOrOptions) &&\n\t\t\tObject.keys(configOrOptions).every((k) => k === \"exclude\")\n\t\t) {\n\t\t\t// It's options (has only 'exclude')\n\t\t\toptions = configOrOptions as PolicyOptions;\n\t\t} else {\n\t\t\t// It's config\n\t\t\tconfig = configOrOptions as C;\n\t\t}\n\t}\n\n\t// Merge with default config if available\n\tconst effectiveConfig = config ?? (policyDef.defaultConfig as C | undefined);\n\n\t// Support both 'exclude' and 'excludeFiles' for backward compatibility\n\tconst excludePatterns = options?.exclude;\n\n\treturn {\n\t\t...policyDef,\n\t\tconfig: effectiveConfig,\n\t\texclude: excludePatterns,\n\t\texcludeFiles: excludePatterns,\n\t\t_internalHandler: normalizeHandler(policyDef.handler),\n\t};\n}\n\n// ============================================================================\n// Legacy API (Still supported for backward compatibility)\n// ============================================================================\n\n/**\n * Input arguments for creating a policy definition.\n *\n * @deprecated Use {@link PolicyShape} directly instead.\n *\n * @alpha\n */\nexport type PolicyDefinitionInput<C = undefined> = PolicyDefinition<C>;\n\n/**\n * Creates a {@link PolicyDefinition} from the provided arguments.\n *\n * @deprecated Define policies as object literals satisfying {@link PolicyShape} instead.\n *\n * @example\n * ```typescript\n * const MyPolicy = makePolicyDefinition({\n * name: \"MyPolicy\",\n * description: \"Ensures files follow conventions\",\n * match: /\\.ts$/,\n * handler: async ({ file }) => true,\n * });\n * ```\n *\n * @alpha\n */\nexport function makePolicyDefinition<C = undefined>(\n\targs: PolicyDefinitionInput<C>,\n): PolicyDefinition<C> {\n\treturn {\n\t\tname: args.name,\n\t\tdescription: args.description,\n\t\tmatch: args.match,\n\t\thandler: args.handler,\n\t\tdefaultConfig: args.defaultConfig,\n\t\tresolver: args.resolver,\n\t};\n}\n\n/**\n * Combine a {@link PolicyDefinition} with a policy-specific config and other settings.\n *\n * @deprecated Use the `policy` function instead, which has a simpler API.\n *\n * @example\n * ```typescript\n * makePolicy(NoJsFileExtensions, undefined, { excludeFiles: [\"bin/*\"] })\n * ```\n *\n * @alpha\n */\nexport function makePolicy<C>(\n\tdefinition: PolicyDefinition<C>,\n\tconfig?: C,\n\tsettings?: PolicyInstanceSettings<C>,\n): PolicyInstance<C> {\n\treturn {\n\t\t...definition,\n\t\t...settings,\n\t\tconfig,\n\t} satisfies PolicyInstance<C>;\n}\n"]}
1
+ {"version":3,"file":"makePolicy.js","sourceRoot":"","sources":["../src/makePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AA6C9C,MAAM,UAAU,UAAU,CACzB,UAAqC,EACrC,OAAgC,EAChC,GAAG,KAAgB;IAEnB,MAAM,QAAQ,GACb,2IAA2I,CAAC;IAC7I,IACC,KAAK,CAAC,MAAM,GAAG,CAAC;QAChB,CAAC,OAAO,KAAK,SAAS;YACrB,CAAC,OAAO,OAAO,KAAK,QAAQ;gBAC3B,OAAO,KAAK,IAAI;gBAChB,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;gBACtB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CACxB,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAC3D,CAAC,CAAC,EACJ,CAAC;QACF,MAAM,IAAI,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,UAAU,CAAC,KAAK,KAAK,YAAY,IAAI,UAAU,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC5E,MAAM,IAAI,SAAS,CAClB,iEAAiE,CACjE,CAAC;IACH,CAAC;IACD,IACC,OAAO,EAAE,OAAO,KAAK,SAAS;QAC9B,CAAC,CACA,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;YAC9B,OAAO,CAAC,OAAO,CAAC,KAAK,CACpB,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,YAAY,MAAM,CAC/D,CACD,EACA,CAAC;QACF,MAAM,IAAI,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IACD,IACC,OAAO,EAAE,UAAU,KAAK,SAAS;QACjC,CAAC,OAAO,OAAO,CAAC,UAAU,KAAK,QAAQ,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,EAC1E,CAAC;QACF,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IAC1C,MAAM,MAAM,GACX,OAAO,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAC3E,IAAI,UAAU,CAAC,cAAc,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACvD,MAAM,IAAI,SAAS,CAClB,WAAW,UAAU,CAAC,IAAI,sBAAsB,QAAQ,EAAE,CAC1D,CAAC;IACH,CAAC;IACD,OAAO,EAAE,GAAG,UAAU,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,CAAC;AAC9C,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,uBAAuB,CAErC,QAAsB;IACvB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC/B,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1D,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACrC,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CAAC,iCAAiC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACvE,CAAC;YACD,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC5B,CAAC;IACF,CAAC;IACD,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QAC9B,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACrC,OAAO,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;QACrD,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CACd,WAAW,MAAM,CAAC,IAAI,4EAA4E,CAClG,CAAC;QACH,CAAC;QACD,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CACd,uBAAuB,MAAM,CAAC,IAAI,gFAAgF,CAClH,CAAC;QACH,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACrB,OAAO,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;IAC/C,CAAC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { exclusionRegex } from \"./context.js\";\nimport type {\n\tConfiguredFilePolicy,\n\tConfiguredPolicy,\n\tConfiguredRepositoryPolicy,\n\tDefinedConfig,\n\tFilePolicyDefinition,\n\tPolicyDefinition,\n\tPolicyInstanceId,\n\tPolicyName,\n\tPolicyOptions,\n\tRepositoryPolicyDefinition,\n} from \"./policy.js\";\n\ntype ConfigOf<D> = D extends PolicyDefinition<infer C> ? C : never;\ntype RequiredConfigDefinitions<D> = D extends { requiresConfig: true }\n\t? D extends { defaultConfig: infer Default }\n\t\t? undefined extends Default\n\t\t\t? D\n\t\t\t: never\n\t\t: D\n\t: never;\ntype OptionsFor<D> = [RequiredConfigDefinitions<D>] extends [never]\n\t? [options?: PolicyOptions<ConfigOf<D>>]\n\t: [\n\t\t\toptions: PolicyOptions<ConfigOf<D>> & {\n\t\t\t\tconfig: DefinedConfig<ConfigOf<RequiredConfigDefinitions<D>>>;\n\t\t\t},\n\t\t];\n\n/** Configure a file definition using a single options object. @public */\nexport function makePolicy<D extends FilePolicyDefinition<unknown>>(\n\tdefinition: D,\n\t...options: OptionsFor<D>\n): ConfiguredFilePolicy<ConfigOf<D>>;\n/** Configure a repository definition using a single options object. @public */\nexport function makePolicy<D extends RepositoryPolicyDefinition<unknown>>(\n\tdefinition: D,\n\t...options: OptionsFor<D>\n): ConfiguredRepositoryPolicy<ConfigOf<D>>;\n/** Configure a common-union definition without losing scope discrimination. @public */\nexport function makePolicy<D extends PolicyDefinition<unknown>>(\n\tdefinition: D,\n\t...options: OptionsFor<D>\n): ConfiguredPolicy<ConfigOf<D>>;\nexport function makePolicy(\n\tdefinition: PolicyDefinition<unknown>,\n\toptions?: PolicyOptions<unknown>,\n\t...extra: unknown[]\n): ConfiguredPolicy<unknown> {\n\tconst guidance =\n\t\t\"Use makePolicy(definition, { config, exclude, instanceId }); positional config, third arguments and excludeFiles are no longer supported.\";\n\tif (\n\t\textra.length > 0 ||\n\t\t(options !== undefined &&\n\t\t\t(typeof options !== \"object\" ||\n\t\t\t\toptions === null ||\n\t\t\t\tArray.isArray(options) ||\n\t\t\t\tObject.keys(options).some(\n\t\t\t\t\t(key) => ![\"config\", \"exclude\", \"instanceId\"].includes(key),\n\t\t\t\t)))\n\t) {\n\t\tthrow new TypeError(guidance);\n\t}\n\tif (definition.scope === \"repository\" && definition.resolver !== undefined) {\n\t\tthrow new TypeError(\n\t\t\t\"Repository policies support inline fixes only; remove resolver.\",\n\t\t);\n\t}\n\tif (\n\t\toptions?.exclude !== undefined &&\n\t\t!(\n\t\t\tArray.isArray(options.exclude) &&\n\t\t\toptions.exclude.every(\n\t\t\t\t(value) => typeof value === \"string\" || value instanceof RegExp,\n\t\t\t)\n\t\t)\n\t) {\n\t\tthrow new TypeError(guidance);\n\t}\n\tif (\n\t\toptions?.instanceId !== undefined &&\n\t\t(typeof options.instanceId !== \"string\" || options.instanceId.length === 0)\n\t) {\n\t\tthrow new TypeError(\"instanceId must be a nonempty string.\");\n\t}\n\toptions?.exclude?.forEach(exclusionRegex);\n\tconst config =\n\t\toptions?.config === undefined ? definition.defaultConfig : options.config;\n\tif (definition.requiresConfig && config === undefined) {\n\t\tthrow new TypeError(\n\t\t\t`Policy '${definition.name}' requires config. ${guidance}`,\n\t\t);\n\t}\n\treturn { ...definition, ...options, config };\n}\n\n/** Assign stable IDs, rejecting ambiguous duplicates. @internal */\nexport function identifyPolicyInstances<\n\tT extends { name: PolicyName; instanceId?: PolicyInstanceId | undefined },\n>(policies: readonly T[]): (T & { instanceId: PolicyInstanceId })[] {\n\tconst names = new Map<string, number>();\n\tconst ids = new Set<string>();\n\tfor (const policy of policies) {\n\t\tnames.set(policy.name, (names.get(policy.name) ?? 0) + 1);\n\t\tif (policy.instanceId !== undefined) {\n\t\t\tif (ids.has(policy.instanceId)) {\n\t\t\t\tthrow new Error(`Duplicate policy instance ID: ${policy.instanceId}`);\n\t\t\t}\n\t\t\tids.add(policy.instanceId);\n\t\t}\n\t}\n\treturn policies.map((policy) => {\n\t\tif (policy.instanceId !== undefined) {\n\t\t\treturn { ...policy, instanceId: policy.instanceId };\n\t\t}\n\t\tif ((names.get(policy.name) ?? 0) > 1) {\n\t\t\tthrow new Error(\n\t\t\t\t`Policy '${policy.name}' is configured multiple times. Set a unique instanceId for each instance.`,\n\t\t\t);\n\t\t}\n\t\tif (ids.has(policy.name)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Policy instance ID '${policy.name}' conflicts with another configured policy. Set an explicit unique instanceId.`,\n\t\t\t);\n\t\t}\n\t\tids.add(policy.name);\n\t\treturn { ...policy, instanceId: policy.name };\n\t});\n}\n"]}
package/esm/perf.d.ts CHANGED
@@ -1,14 +1,22 @@
1
1
  import type { Logger } from "@tylerbu/cli-api";
2
2
  import type { Operation } from "effection";
3
- import type { PolicyName } from "./policy.js";
3
+ import type { PolicyInstanceId } from "./policy.js";
4
+ /**
5
+ * The type of action a policy can perform.
6
+ * @public
7
+ */
4
8
  export type PolicyAction = "check" | "resolve" | "handle";
5
9
  /**
6
10
  * Stores performance data for each handler. Used to collect and display performance stats.
11
+ * @public
7
12
  */
8
13
  export interface PolicyHandlerPerfStats {
14
+ /** Number of candidate file paths supplied to the runner. */
9
15
  count: number;
16
+ /** Number of candidate files admitted past global exclusions. */
10
17
  processed: number;
11
- data: Map<PolicyAction, Map<PolicyName, number>>;
18
+ /** Total elapsed milliseconds per action and configured policy instance. */
19
+ data: Map<PolicyAction, Map<PolicyInstanceId, number>>;
12
20
  }
13
21
  export declare function newPerfStats(): PolicyHandlerPerfStats;
14
22
  export declare function runWithPerf<T>(name: string, action: PolicyAction, stats: PolicyHandlerPerfStats, run: () => Operation<T>): Operation<T>;
package/esm/perf.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"perf.d.ts","sourceRoot":"","sources":["../src/perf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;CACjD;AAED,wBAAgB,YAAY,IAAI,sBAAsB,CAMrD;AAED,wBAAiB,WAAW,CAAC,CAAC,EAC7B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,sBAAsB,EAC7B,GAAG,EAAE,MAAM,SAAS,CAAC,CAAC,CAAC,GACrB,SAAS,CAAC,CAAC,CAAC,CAWd;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,sBAAsB,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAWzE"}
1
+ {"version":3,"file":"perf.d.ts","sourceRoot":"","sources":["../src/perf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE1D;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACtC,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,IAAI,EAAE,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC;CACvD;AAED,wBAAgB,YAAY,IAAI,sBAAsB,CAMrD;AAED,wBAAiB,WAAW,CAAC,CAAC,EAC7B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,sBAAsB,EAC7B,GAAG,EAAE,MAAM,SAAS,CAAC,CAAC,CAAC,GACrB,SAAS,CAAC,CAAC,CAAC,CASd;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,sBAAsB,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAWzE"}
package/esm/perf.js CHANGED
@@ -6,14 +6,15 @@ export function newPerfStats() {
6
6
  };
7
7
  }
8
8
  export function* runWithPerf(name, action, stats, run) {
9
- const actionMap = stats.data.get(action) ?? new Map();
10
- let dur = actionMap.get(name) ?? 0;
11
- const start = Date.now();
12
- const result = yield* run();
13
- dur += Date.now() - start;
14
- actionMap.set(name, dur);
15
- stats.data.set(action, actionMap);
16
- return result;
9
+ const start = performance.now();
10
+ try {
11
+ return yield* run();
12
+ }
13
+ finally {
14
+ const actionMap = stats.data.get(action) ?? new Map();
15
+ actionMap.set(name, (actionMap.get(name) ?? 0) + performance.now() - start);
16
+ stats.data.set(action, actionMap);
17
+ }
17
18
  }
18
19
  export function logStats(stats, log) {
19
20
  log.log(`Statistics: ${stats.processed} files processed, ` +
@@ -21,7 +22,7 @@ export function logStats(stats, log) {
21
22
  for (const [action, handlerPerf] of stats.data.entries()) {
22
23
  log.log(`Performance for "${action}":`);
23
24
  for (const [handler, dur] of handlerPerf.entries()) {
24
- log.log(` ${handler}: ${dur}ms`);
25
+ log.log(` ${handler}: ${Math.round(dur * 10) / 10}ms`);
25
26
  }
26
27
  }
27
28
  }
package/esm/perf.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"perf.js","sourceRoot":"","sources":["../src/perf.ts"],"names":[],"mappings":"AAeA,MAAM,UAAU,YAAY;IAC3B,OAAO;QACN,KAAK,EAAE,CAAC;QACR,SAAS,EAAE,CAAC;QACZ,IAAI,EAAE,IAAI,GAAG,EAAyC;KACtD,CAAC;AACH,CAAC;AAED,MAAM,SAAS,CAAC,CAAC,WAAW,CAC3B,IAAY,EACZ,MAAoB,EACpB,KAA6B,EAC7B,GAAuB;IAEvB,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAkB,CAAC;IACtE,IAAI,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEnC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC;IAC5B,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;IAE1B,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACzB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC;AACf,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAA6B,EAAE,GAAW;IAClE,GAAG,CAAC,GAAG,CACN,eAAe,KAAK,CAAC,SAAS,oBAAoB;QACjD,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,SAAS,cAAc,KAAK,CAAC,KAAK,QAAQ,CAClE,CAAC;IACF,KAAK,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;QAC1D,GAAG,CAAC,GAAG,CAAC,oBAAoB,MAAM,IAAI,CAAC,CAAC;QACxC,KAAK,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;YACpD,GAAG,CAAC,GAAG,CAAC,OAAO,OAAO,KAAK,GAAG,IAAI,CAAC,CAAC;QACrC,CAAC;IACF,CAAC;AACF,CAAC","sourcesContent":["import type { Logger } from \"@tylerbu/cli-api\";\nimport type { Operation } from \"effection\";\nimport type { PolicyName } from \"./policy.js\";\n\nexport type PolicyAction = \"check\" | \"resolve\" | \"handle\";\n\n/**\n * Stores performance data for each handler. Used to collect and display performance stats.\n */\nexport interface PolicyHandlerPerfStats {\n\tcount: number;\n\tprocessed: number;\n\tdata: Map<PolicyAction, Map<PolicyName, number>>;\n}\n\nexport function newPerfStats(): PolicyHandlerPerfStats {\n\treturn {\n\t\tcount: 0,\n\t\tprocessed: 0,\n\t\tdata: new Map<PolicyAction, Map<PolicyName, number>>(),\n\t};\n}\n\nexport function* runWithPerf<T>(\n\tname: string,\n\taction: PolicyAction,\n\tstats: PolicyHandlerPerfStats,\n\trun: () => Operation<T>,\n): Operation<T> {\n\tconst actionMap = stats.data.get(action) ?? new Map<string, number>();\n\tlet dur = actionMap.get(name) ?? 0;\n\n\tconst start = Date.now();\n\tconst result = yield* run();\n\tdur += Date.now() - start;\n\n\tactionMap.set(name, dur);\n\tstats.data.set(action, actionMap);\n\treturn result;\n}\n\nexport function logStats(stats: PolicyHandlerPerfStats, log: Logger): void {\n\tlog.log(\n\t\t`Statistics: ${stats.processed} files processed, ` +\n\t\t\t`${stats.count - stats.processed} excluded, ${stats.count} total`,\n\t);\n\tfor (const [action, handlerPerf] of stats.data.entries()) {\n\t\tlog.log(`Performance for \"${action}\":`);\n\t\tfor (const [handler, dur] of handlerPerf.entries()) {\n\t\t\tlog.log(` ${handler}: ${dur}ms`);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"perf.js","sourceRoot":"","sources":["../src/perf.ts"],"names":[],"mappings":"AAuBA,MAAM,UAAU,YAAY;IAC3B,OAAO;QACN,KAAK,EAAE,CAAC;QACR,SAAS,EAAE,CAAC;QACZ,IAAI,EAAE,IAAI,GAAG,EAA+C;KAC5D,CAAC;AACH,CAAC;AAED,MAAM,SAAS,CAAC,CAAC,WAAW,CAC3B,IAAY,EACZ,MAAoB,EACpB,KAA6B,EAC7B,GAAuB;IAEvB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAChC,IAAI,CAAC;QACJ,OAAO,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC;IACrB,CAAC;YAAS,CAAC;QACV,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAkB,CAAC;QACtE,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC;QAC5E,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACnC,CAAC;AACF,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAA6B,EAAE,GAAW;IAClE,GAAG,CAAC,GAAG,CACN,eAAe,KAAK,CAAC,SAAS,oBAAoB;QACjD,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,SAAS,cAAc,KAAK,CAAC,KAAK,QAAQ,CAClE,CAAC;IACF,KAAK,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;QAC1D,GAAG,CAAC,GAAG,CAAC,oBAAoB,MAAM,IAAI,CAAC,CAAC;QACxC,KAAK,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;YACpD,GAAG,CAAC,GAAG,CAAC,OAAO,OAAO,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC3D,CAAC;IACF,CAAC;AACF,CAAC","sourcesContent":["import type { Logger } from \"@tylerbu/cli-api\";\nimport type { Operation } from \"effection\";\nimport type { PolicyInstanceId } from \"./policy.js\";\n\n/**\n * The type of action a policy can perform.\n * @public\n */\nexport type PolicyAction = \"check\" | \"resolve\" | \"handle\";\n\n/**\n * Stores performance data for each handler. Used to collect and display performance stats.\n * @public\n */\nexport interface PolicyHandlerPerfStats {\n\t/** Number of candidate file paths supplied to the runner. */\n\tcount: number;\n\t/** Number of candidate files admitted past global exclusions. */\n\tprocessed: number;\n\t/** Total elapsed milliseconds per action and configured policy instance. */\n\tdata: Map<PolicyAction, Map<PolicyInstanceId, number>>;\n}\n\nexport function newPerfStats(): PolicyHandlerPerfStats {\n\treturn {\n\t\tcount: 0,\n\t\tprocessed: 0,\n\t\tdata: new Map<PolicyAction, Map<PolicyInstanceId, number>>(),\n\t};\n}\n\nexport function* runWithPerf<T>(\n\tname: string,\n\taction: PolicyAction,\n\tstats: PolicyHandlerPerfStats,\n\trun: () => Operation<T>,\n): Operation<T> {\n\tconst start = performance.now();\n\ttry {\n\t\treturn yield* run();\n\t} finally {\n\t\tconst actionMap = stats.data.get(action) ?? new Map<string, number>();\n\t\tactionMap.set(name, (actionMap.get(name) ?? 0) + performance.now() - start);\n\t\tstats.data.set(action, actionMap);\n\t}\n}\n\nexport function logStats(stats: PolicyHandlerPerfStats, log: Logger): void {\n\tlog.log(\n\t\t`Statistics: ${stats.processed} files processed, ` +\n\t\t\t`${stats.count - stats.processed} excluded, ${stats.count} total`,\n\t);\n\tfor (const [action, handlerPerf] of stats.data.entries()) {\n\t\tlog.log(`Performance for \"${action}\":`);\n\t\tfor (const [handler, dur] of handlerPerf.entries()) {\n\t\t\tlog.log(` ${handler}: ${Math.round(dur * 10) / 10}ms`);\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,41 @@
1
+ import type { FilePolicyDefinition } from "../policy.js";
2
+ /**
3
+ * Configuration for the CargoLicenceValidated policy.
4
+ *
5
+ * @public
6
+ */
7
+ export interface CargoLicenceValidatedConfig {
8
+ /**
9
+ * Allowed SPDX licence identifiers. If set, only these are accepted.
10
+ */
11
+ allowedLicences?: string[];
12
+ /**
13
+ * If true, validate the licence value against the SPDX licence list
14
+ * using `spdx-correct`. When enabled, typos like "MIIT" are detected
15
+ * and can be auto-fixed to the correct identifier ("MIT").
16
+ *
17
+ * Requires the optional peer dependency `spdx-correct` to be installed.
18
+ *
19
+ * @defaultValue true
20
+ */
21
+ validateSpdx?: boolean;
22
+ /**
23
+ * If true, skip workspace-only Cargo.toml files (those without a [package] section).
24
+ *
25
+ * @defaultValue true
26
+ */
27
+ skipWorkspace?: boolean;
28
+ }
29
+ /**
30
+ * A policy that validates the `license` field in Cargo.toml against the SPDX
31
+ * licence list. Supports auto-fixing correctable identifiers.
32
+ *
33
+ * @remarks
34
+ * Cargo.toml uses a single `license` string field (not an array like Gleam's
35
+ * `licences`). This policy validates that the value is a recognized SPDX
36
+ * identifier and can auto-fix common mistakes like wrong casing.
37
+ *
38
+ * @public
39
+ */
40
+ export declare const CargoLicenceValidated: FilePolicyDefinition<CargoLicenceValidatedConfig>;
41
+ //# sourceMappingURL=CargoLicenceValidated.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CargoLicenceValidated.d.ts","sourceRoot":"","sources":["../../src/policies/CargoLicenceValidated.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAOzD;;;;GAIG;AACH,MAAM,WAAW,2BAA2B;IAC3C;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAKD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,mDAsC4B,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { resolve } from "pathe";
2
+ import { defineCargoPolicy, } from "../policyDefiners/defineCargoPolicy.js";
3
+ import { validateLicenceField } from "../policyDefiners/spdxValidator.js";
4
+ const MANUAL_FIX = "Use a valid SPDX licence identifier (e.g., MIT, Apache-2.0, MPL-2.0).";
5
+ /**
6
+ * A policy that validates the `license` field in Cargo.toml against the SPDX
7
+ * licence list. Supports auto-fixing correctable identifiers.
8
+ *
9
+ * @remarks
10
+ * Cargo.toml uses a single `license` string field (not an array like Gleam's
11
+ * `licences`). This policy validates that the value is a recognized SPDX
12
+ * identifier and can auto-fix common mistakes like wrong casing.
13
+ *
14
+ * @public
15
+ */
16
+ export const CargoLicenceValidated = defineCargoPolicy({
17
+ name: "CargoLicenceValidated",
18
+ description: "Validates that Cargo.toml has a valid SPDX licence identifier.",
19
+ handler: async (toml, { file, root, resolve: shouldResolve, config }) => {
20
+ const skipWorkspace = config?.skipWorkspace ?? true;
21
+ const pkg = toml.package;
22
+ if (!pkg && skipWorkspace) {
23
+ return [];
24
+ }
25
+ const licence = pkg?.license;
26
+ if (!licence || licence.trim() === "") {
27
+ return [
28
+ {
29
+ message: "Missing or empty license field in [package] section.",
30
+ manualFix: 'Add license = "MIT" (or appropriate SPDX identifier) to [package] in Cargo.toml.',
31
+ },
32
+ ];
33
+ }
34
+ const result = await validateLicenceField({
35
+ licences: [licence],
36
+ ...(config?.allowedLicences !== undefined && {
37
+ allowedLicences: config.allowedLicences,
38
+ }),
39
+ validateSpdx: config?.validateSpdx ?? true,
40
+ shouldResolve,
41
+ filePath: resolve(root, file),
42
+ manualFixMessage: MANUAL_FIX,
43
+ });
44
+ return result;
45
+ },
46
+ });
47
+ //# sourceMappingURL=CargoLicenceValidated.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CargoLicenceValidated.js","sourceRoot":"","sources":["../../src/policies/CargoLicenceValidated.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,EAEN,iBAAiB,GACjB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAgC1E,MAAM,UAAU,GACf,uEAAuE,CAAC;AAEzE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,iBAAiB,CAAC;IACtD,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EAAE,gEAAgE;IAC7E,OAAO,EAAE,KAAK,EACb,IAAe,EACf,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,EAC7C,EAAE;QACH,MAAM,aAAa,GAAG,MAAM,EAAE,aAAa,IAAI,IAAI,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,OAA8C,CAAC;QAEhE,IAAI,CAAC,GAAG,IAAI,aAAa,EAAE,CAAC;YAC3B,OAAO,EAAE,CAAC;QACX,CAAC;QAED,MAAM,OAAO,GAAG,GAAG,EAAE,OAA6B,CAAC;QAEnD,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACvC,OAAO;gBACN;oBACC,OAAO,EAAE,sDAAsD;oBAC/D,SAAS,EACR,kFAAkF;iBACnF;aACD,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC;YACzC,QAAQ,EAAE,CAAC,OAAO,CAAC;YACnB,GAAG,CAAC,MAAM,EAAE,eAAe,KAAK,SAAS,IAAI;gBAC5C,eAAe,EAAE,MAAM,CAAC,eAAe;aACvC,CAAC;YACF,YAAY,EAAE,MAAM,EAAE,YAAY,IAAI,IAAI;YAC1C,aAAa;YACb,QAAQ,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC;YAC7B,gBAAgB,EAAE,UAAU;SAC5B,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IACf,CAAC;CACD,CAA6D,CAAC","sourcesContent":["import { resolve } from \"pathe\";\nimport type { FilePolicyDefinition } from \"../policy.js\";\nimport {\n\ttype CargoToml,\n\tdefineCargoPolicy,\n} from \"../policyDefiners/defineCargoPolicy.js\";\nimport { validateLicenceField } from \"../policyDefiners/spdxValidator.js\";\n\n/**\n * Configuration for the CargoLicenceValidated policy.\n *\n * @public\n */\nexport interface CargoLicenceValidatedConfig {\n\t/**\n\t * Allowed SPDX licence identifiers. If set, only these are accepted.\n\t */\n\tallowedLicences?: string[];\n\n\t/**\n\t * If true, validate the licence value against the SPDX licence list\n\t * using `spdx-correct`. When enabled, typos like \"MIIT\" are detected\n\t * and can be auto-fixed to the correct identifier (\"MIT\").\n\t *\n\t * Requires the optional peer dependency `spdx-correct` to be installed.\n\t *\n\t * @defaultValue true\n\t */\n\tvalidateSpdx?: boolean;\n\n\t/**\n\t * If true, skip workspace-only Cargo.toml files (those without a [package] section).\n\t *\n\t * @defaultValue true\n\t */\n\tskipWorkspace?: boolean;\n}\n\nconst MANUAL_FIX =\n\t\"Use a valid SPDX licence identifier (e.g., MIT, Apache-2.0, MPL-2.0).\";\n\n/**\n * A policy that validates the `license` field in Cargo.toml against the SPDX\n * licence list. Supports auto-fixing correctable identifiers.\n *\n * @remarks\n * Cargo.toml uses a single `license` string field (not an array like Gleam's\n * `licences`). This policy validates that the value is a recognized SPDX\n * identifier and can auto-fix common mistakes like wrong casing.\n *\n * @public\n */\nexport const CargoLicenceValidated = defineCargoPolicy({\n\tname: \"CargoLicenceValidated\",\n\tdescription: \"Validates that Cargo.toml has a valid SPDX licence identifier.\",\n\thandler: async (\n\t\ttoml: CargoToml,\n\t\t{ file, root, resolve: shouldResolve, config },\n\t) => {\n\t\tconst skipWorkspace = config?.skipWorkspace ?? true;\n\t\tconst pkg = toml.package as Record<string, unknown> | undefined;\n\n\t\tif (!pkg && skipWorkspace) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst licence = pkg?.license as string | undefined;\n\n\t\tif (!licence || licence.trim() === \"\") {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tmessage: \"Missing or empty license field in [package] section.\",\n\t\t\t\t\tmanualFix:\n\t\t\t\t\t\t'Add license = \"MIT\" (or appropriate SPDX identifier) to [package] in Cargo.toml.',\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\n\t\tconst result = await validateLicenceField({\n\t\t\tlicences: [licence],\n\t\t\t...(config?.allowedLicences !== undefined && {\n\t\t\t\tallowedLicences: config.allowedLicences,\n\t\t\t}),\n\t\t\tvalidateSpdx: config?.validateSpdx ?? true,\n\t\t\tshouldResolve,\n\t\t\tfilePath: resolve(root, file),\n\t\t\tmanualFixMessage: MANUAL_FIX,\n\t\t});\n\t\treturn result;\n\t},\n}) satisfies FilePolicyDefinition<CargoLicenceValidatedConfig>;\n"]}
@@ -0,0 +1,30 @@
1
+ import type { FilePolicyDefinition } from "../policy.js";
2
+ /**
3
+ * Configuration for the CargoLintsConfigured policy.
4
+ *
5
+ * @public
6
+ */
7
+ export interface CargoLintsConfiguredConfig {
8
+ /**
9
+ * Required clippy lint levels. Keys are lint names (without the `clippy::` prefix),
10
+ * values are the minimum level ("warn" or "deny").
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * { pedantic: "warn", nursery: "warn" }
15
+ * ```
16
+ */
17
+ required?: Record<string, string>;
18
+ /**
19
+ * If true, just require that a [lints.clippy] section exists (without checking specific lints).
20
+ * @defaultValue true
21
+ */
22
+ requireSection?: boolean;
23
+ }
24
+ /**
25
+ * A policy that ensures Cargo.toml has a [lints.clippy] section configured.
26
+ *
27
+ * @public
28
+ */
29
+ export declare const CargoLintsConfigured: FilePolicyDefinition<CargoLintsConfiguredConfig>;
30
+ //# sourceMappingURL=CargoLintsConfigured.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CargoLintsConfigured.d.ts","sourceRoot":"","sources":["../../src/policies/CargoLintsConfigured.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAgB,MAAM,cAAc,CAAC;AAMvE;;;;GAIG;AACH,MAAM,WAAW,0BAA0B;IAC1C;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAElC;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAmED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,kDAY4B,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { defineCargoPolicy, } from "../policyDefiners/defineCargoPolicy.js";
2
+ function checkClippyLints(clippy, required) {
3
+ const errors = [];
4
+ for (const [lint, expectedLevel] of Object.entries(required)) {
5
+ const actual = clippy[lint];
6
+ if (actual === undefined) {
7
+ errors.push(`Missing clippy lint: ${lint} (expected level: "${expectedLevel}")`);
8
+ }
9
+ else if (String(actual) !== expectedLevel) {
10
+ errors.push(`Clippy lint ${lint} = "${String(actual)}", expected "${expectedLevel}"`);
11
+ }
12
+ }
13
+ return errors;
14
+ }
15
+ function checkLintsSection(toml, config) {
16
+ const lints = toml.lints;
17
+ const requireSection = config?.requireSection ?? true;
18
+ if (requireSection && lints === undefined) {
19
+ return [
20
+ {
21
+ message: "Missing [lints] section in Cargo.toml.",
22
+ manualFix: 'Add a [lints.clippy] section, e.g.:\n[lints.clippy]\npedantic = "warn"',
23
+ },
24
+ ];
25
+ }
26
+ if (lints === undefined) {
27
+ return [];
28
+ }
29
+ const clippy = lints.clippy;
30
+ if (requireSection && clippy === undefined) {
31
+ return [
32
+ {
33
+ message: "Missing [lints.clippy] section in Cargo.toml.",
34
+ manualFix: 'Add a [lints.clippy] section, e.g.:\n[lints.clippy]\npedantic = "warn"',
35
+ },
36
+ ];
37
+ }
38
+ if (config?.required && clippy) {
39
+ const errors = checkClippyLints(clippy, config.required);
40
+ if (errors.length > 0) {
41
+ return errors.map((message) => ({
42
+ message,
43
+ manualFix: "Update the [lints.clippy] section with the required lint levels.",
44
+ }));
45
+ }
46
+ }
47
+ return [];
48
+ }
49
+ /**
50
+ * A policy that ensures Cargo.toml has a [lints.clippy] section configured.
51
+ *
52
+ * @public
53
+ */
54
+ export const CargoLintsConfigured = defineCargoPolicy({
55
+ name: "CargoLintsConfigured",
56
+ description: "Ensures Cargo.toml has clippy lints configured in the [lints] section.",
57
+ handler: async (toml, { config }) => {
58
+ // Skip workspace root Cargo.toml files
59
+ if (toml.workspace !== undefined && toml.package === undefined) {
60
+ return [];
61
+ }
62
+ return checkLintsSection(toml, config);
63
+ },
64
+ });
65
+ //# sourceMappingURL=CargoLintsConfigured.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CargoLintsConfigured.js","sourceRoot":"","sources":["../../src/policies/CargoLintsConfigured.ts"],"names":[],"mappings":"AACA,OAAO,EAEN,iBAAiB,GACjB,MAAM,wCAAwC,CAAC;AA0BhD,SAAS,gBAAgB,CACxB,MAA+B,EAC/B,QAAgC;IAEhC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9D,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CACV,wBAAwB,IAAI,sBAAsB,aAAa,IAAI,CACnE,CAAC;QACH,CAAC;aAAM,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,aAAa,EAAE,CAAC;YAC7C,MAAM,CAAC,IAAI,CACV,eAAe,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,gBAAgB,aAAa,GAAG,CACxE,CAAC;QACH,CAAC;IACF,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAED,SAAS,iBAAiB,CACzB,IAAe,EACf,MAA8C;IAE9C,MAAM,KAAK,GAAG,IAAI,CAAC,KAA4C,CAAC;IAChE,MAAM,cAAc,GAAG,MAAM,EAAE,cAAc,IAAI,IAAI,CAAC;IAEtD,IAAI,cAAc,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC3C,OAAO;YACN;gBACC,OAAO,EAAE,wCAAwC;gBACjD,SAAS,EACR,wEAAwE;aACzE;SACD,CAAC;IACH,CAAC;IAED,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,EAAE,CAAC;IACX,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,MAA6C,CAAC;IACnE,IAAI,cAAc,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QAC5C,OAAO;YACN;gBACC,OAAO,EAAE,+CAA+C;gBACxD,SAAS,EACR,wEAAwE;aACzE;SACD,CAAC;IACH,CAAC;IAED,IAAI,MAAM,EAAE,QAAQ,IAAI,MAAM,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBAC/B,OAAO;gBACP,SAAS,EACR,kEAAkE;aACnE,CAAC,CAAC,CAAC;QACL,CAAC;IACF,CAAC;IACD,OAAO,EAAE,CAAC;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,iBAAiB,CAAC;IACrD,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EACV,wEAAwE;IACzE,OAAO,EAAE,KAAK,EAAE,IAAe,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QAC9C,uCAAuC;QACvC,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAChE,OAAO,EAAE,CAAC;QACX,CAAC;QAED,OAAO,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;CACD,CAA4D,CAAC","sourcesContent":["import type { FilePolicyDefinition, PolicyResult } from \"../policy.js\";\nimport {\n\ttype CargoToml,\n\tdefineCargoPolicy,\n} from \"../policyDefiners/defineCargoPolicy.js\";\n\n/**\n * Configuration for the CargoLintsConfigured policy.\n *\n * @public\n */\nexport interface CargoLintsConfiguredConfig {\n\t/**\n\t * Required clippy lint levels. Keys are lint names (without the `clippy::` prefix),\n\t * values are the minimum level (\"warn\" or \"deny\").\n\t *\n\t * @example\n\t * ```typescript\n\t * { pedantic: \"warn\", nursery: \"warn\" }\n\t * ```\n\t */\n\trequired?: Record<string, string>;\n\n\t/**\n\t * If true, just require that a [lints.clippy] section exists (without checking specific lints).\n\t * @defaultValue true\n\t */\n\trequireSection?: boolean;\n}\n\nfunction checkClippyLints(\n\tclippy: Record<string, unknown>,\n\trequired: Record<string, string>,\n): string[] {\n\tconst errors: string[] = [];\n\tfor (const [lint, expectedLevel] of Object.entries(required)) {\n\t\tconst actual = clippy[lint];\n\t\tif (actual === undefined) {\n\t\t\terrors.push(\n\t\t\t\t`Missing clippy lint: ${lint} (expected level: \"${expectedLevel}\")`,\n\t\t\t);\n\t\t} else if (String(actual) !== expectedLevel) {\n\t\t\terrors.push(\n\t\t\t\t`Clippy lint ${lint} = \"${String(actual)}\", expected \"${expectedLevel}\"`,\n\t\t\t);\n\t\t}\n\t}\n\treturn errors;\n}\n\nfunction checkLintsSection(\n\ttoml: CargoToml,\n\tconfig: CargoLintsConfiguredConfig | undefined,\n): PolicyResult {\n\tconst lints = toml.lints as Record<string, unknown> | undefined;\n\tconst requireSection = config?.requireSection ?? true;\n\n\tif (requireSection && lints === undefined) {\n\t\treturn [\n\t\t\t{\n\t\t\t\tmessage: \"Missing [lints] section in Cargo.toml.\",\n\t\t\t\tmanualFix:\n\t\t\t\t\t'Add a [lints.clippy] section, e.g.:\\n[lints.clippy]\\npedantic = \"warn\"',\n\t\t\t},\n\t\t];\n\t}\n\n\tif (lints === undefined) {\n\t\treturn [];\n\t}\n\n\tconst clippy = lints.clippy as Record<string, unknown> | undefined;\n\tif (requireSection && clippy === undefined) {\n\t\treturn [\n\t\t\t{\n\t\t\t\tmessage: \"Missing [lints.clippy] section in Cargo.toml.\",\n\t\t\t\tmanualFix:\n\t\t\t\t\t'Add a [lints.clippy] section, e.g.:\\n[lints.clippy]\\npedantic = \"warn\"',\n\t\t\t},\n\t\t];\n\t}\n\n\tif (config?.required && clippy) {\n\t\tconst errors = checkClippyLints(clippy, config.required);\n\t\tif (errors.length > 0) {\n\t\t\treturn errors.map((message) => ({\n\t\t\t\tmessage,\n\t\t\t\tmanualFix:\n\t\t\t\t\t\"Update the [lints.clippy] section with the required lint levels.\",\n\t\t\t}));\n\t\t}\n\t}\n\treturn [];\n}\n\n/**\n * A policy that ensures Cargo.toml has a [lints.clippy] section configured.\n *\n * @public\n */\nexport const CargoLintsConfigured = defineCargoPolicy({\n\tname: \"CargoLintsConfigured\",\n\tdescription:\n\t\t\"Ensures Cargo.toml has clippy lints configured in the [lints] section.\",\n\thandler: async (toml: CargoToml, { config }) => {\n\t\t// Skip workspace root Cargo.toml files\n\t\tif (toml.workspace !== undefined && toml.package === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn checkLintsSection(toml, config);\n\t},\n}) satisfies FilePolicyDefinition<CargoLintsConfiguredConfig>;\n"]}
@@ -0,0 +1,34 @@
1
+ import type { FilePolicyDefinition } from "../policy.js";
2
+ /**
3
+ * Configuration for the CargoLockPolicy.
4
+ *
5
+ * @public
6
+ */
7
+ export interface CargoLockPolicyConfig {
8
+ /**
9
+ * Policy for binary crates.
10
+ * - "require": Cargo.lock must be committed (default for binaries)
11
+ * - "warn": Emit a warning if missing
12
+ * - "ignore": Skip check
13
+ *
14
+ * @defaultValue "require"
15
+ */
16
+ binaries?: "require" | "warn" | "ignore";
17
+ /**
18
+ * Policy for library crates.
19
+ * - "require": Cargo.lock must be committed
20
+ * - "warn": Emit a warning if committed (default for libraries)
21
+ * - "ignore": Skip check
22
+ *
23
+ * @defaultValue "ignore"
24
+ */
25
+ libraries?: "require" | "warn" | "ignore";
26
+ }
27
+ /**
28
+ * A context-aware policy for Cargo.lock files.
29
+ * Binary crates should commit Cargo.lock; library crates typically shouldn't.
30
+ *
31
+ * @public
32
+ */
33
+ export declare const CargoLockPolicy: FilePolicyDefinition<CargoLockPolicyConfig>;
34
+ //# sourceMappingURL=CargoLockPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CargoLockPolicy.d.ts","sourceRoot":"","sources":["../../src/policies/CargoLockPolicy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAMzD;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACrC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;IAEzC;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;CAC1C;AAsBD;;;;;GAKG;AACH,eAAO,MAAM,eAAe,6CAyC4B,CAAC"}
@@ -0,0 +1,61 @@
1
+ import { existsSync } from "node:fs";
2
+ import path from "pathe";
3
+ import { defineCargoPolicy, } from "../policyDefiners/defineCargoPolicy.js";
4
+ function isBinaryCrate(toml) {
5
+ // Has [[bin]] entries
6
+ if (Array.isArray(toml.bin) && toml.bin.length > 0) {
7
+ return true;
8
+ }
9
+ // Has a default binary (src/main.rs is handled by Cargo implicitly)
10
+ const pkg = toml.package;
11
+ if (pkg) {
12
+ // If there's no explicit lib section and no [[bin]], Cargo assumes binary
13
+ // if src/main.rs exists, but we can't check filesystem here.
14
+ // Best heuristic: if there's no [lib] section, it could be a binary.
15
+ return toml.lib === undefined;
16
+ }
17
+ return false;
18
+ }
19
+ function isLibraryCrate(toml) {
20
+ return toml.lib !== undefined;
21
+ }
22
+ /**
23
+ * A context-aware policy for Cargo.lock files.
24
+ * Binary crates should commit Cargo.lock; library crates typically shouldn't.
25
+ *
26
+ * @public
27
+ */
28
+ export const CargoLockPolicy = defineCargoPolicy({
29
+ name: "CargoLockPolicy",
30
+ description: "Context-aware Cargo.lock validation: binaries should commit it, libraries typically should not.",
31
+ handler: async (toml, { root, file, config }) => {
32
+ // Skip workspace root Cargo.toml
33
+ if (toml.workspace !== undefined && toml.package === undefined) {
34
+ return [];
35
+ }
36
+ const dir = path.dirname(path.resolve(root, file));
37
+ const lockExists = existsSync(path.join(dir, "Cargo.lock"));
38
+ const isBinary = isBinaryCrate(toml);
39
+ const isLib = isLibraryCrate(toml);
40
+ const binaryPolicy = config?.binaries ?? "require";
41
+ const libraryPolicy = config?.libraries ?? "ignore";
42
+ if (isBinary && binaryPolicy === "require" && !lockExists) {
43
+ return [
44
+ {
45
+ message: "Binary crate is missing Cargo.lock. Binary crates should commit their lockfile for reproducible builds.",
46
+ manualFix: "Run `cargo generate-lockfile` and commit the Cargo.lock file.",
47
+ },
48
+ ];
49
+ }
50
+ if (isLib && !isBinary && libraryPolicy === "warn" && lockExists) {
51
+ return [
52
+ {
53
+ message: "Library crate has Cargo.lock committed. Library crates typically should not commit their lockfile.",
54
+ manualFix: "Consider adding Cargo.lock to .gitignore for library crates.",
55
+ },
56
+ ];
57
+ }
58
+ return [];
59
+ },
60
+ });
61
+ //# sourceMappingURL=CargoLockPolicy.js.map