repopo 0.12.0 → 0.14.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 (345) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/README.md +57 -90
  3. package/THIRD-PARTY-LICENSES.txt +169 -11
  4. package/bin/dev.js +0 -0
  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 +66 -1
  10. package/esm/api.d.ts.map +1 -1
  11. package/esm/api.js +18 -1
  12. package/esm/api.js.map +1 -1
  13. package/esm/baseCommand.d.ts.map +1 -1
  14. package/esm/baseCommand.js +2 -2
  15. package/esm/baseCommand.js.map +1 -1
  16. package/esm/commands/check-native.d.ts +5 -3
  17. package/esm/commands/check-native.d.ts.map +1 -1
  18. package/esm/commands/check-native.js +35 -7
  19. package/esm/commands/check-native.js.map +1 -1
  20. package/esm/commands/check.d.ts +8 -21
  21. package/esm/commands/check.d.ts.map +1 -1
  22. package/esm/commands/check.js +98 -154
  23. package/esm/commands/check.js.map +1 -1
  24. package/esm/commands/list.d.ts.map +1 -1
  25. package/esm/commands/list.js +1 -0
  26. package/esm/commands/list.js.map +1 -1
  27. package/esm/concurrency.d.ts +3 -0
  28. package/esm/concurrency.d.ts.map +1 -0
  29. package/esm/concurrency.js +8 -0
  30. package/esm/concurrency.js.map +1 -0
  31. package/esm/config.d.ts +10 -39
  32. package/esm/config.d.ts.map +1 -1
  33. package/esm/config.js +3 -7
  34. package/esm/config.js.map +1 -1
  35. package/esm/context.d.ts +10 -1
  36. package/esm/context.d.ts.map +1 -1
  37. package/esm/context.js +19 -1
  38. package/esm/context.js.map +1 -1
  39. package/esm/executionContractError.d.ts +4 -0
  40. package/esm/executionContractError.d.ts.map +1 -0
  41. package/esm/executionContractError.js +4 -0
  42. package/esm/executionContractError.js.map +1 -0
  43. package/esm/fileCache.d.ts +12 -0
  44. package/esm/fileCache.d.ts.map +1 -0
  45. package/esm/fileCache.js +37 -0
  46. package/esm/fileCache.js.map +1 -0
  47. package/esm/filePaths.d.ts +2 -0
  48. package/esm/filePaths.d.ts.map +1 -0
  49. package/esm/filePaths.js +9 -0
  50. package/esm/filePaths.js.map +1 -0
  51. package/esm/generators.d.ts +0 -20
  52. package/esm/generators.d.ts.map +1 -1
  53. package/esm/generators.js.map +1 -1
  54. package/esm/index.d.ts +3 -16
  55. package/esm/index.d.ts.map +1 -1
  56. package/esm/index.js +3 -17
  57. package/esm/index.js.map +1 -1
  58. package/esm/makePolicy.d.ts +20 -100
  59. package/esm/makePolicy.d.ts.map +1 -1
  60. package/esm/makePolicy.js +46 -132
  61. package/esm/makePolicy.js.map +1 -1
  62. package/esm/perf.d.ts +5 -2
  63. package/esm/perf.d.ts.map +1 -1
  64. package/esm/perf.js +10 -9
  65. package/esm/perf.js.map +1 -1
  66. package/esm/policies/CargoLicenceValidated.d.ts +4 -4
  67. package/esm/policies/CargoLicenceValidated.d.ts.map +1 -1
  68. package/esm/policies/CargoLicenceValidated.js +9 -7
  69. package/esm/policies/CargoLicenceValidated.js.map +1 -1
  70. package/esm/policies/CargoLintsConfigured.d.ts +4 -4
  71. package/esm/policies/CargoLintsConfigured.d.ts.map +1 -1
  72. package/esm/policies/CargoLintsConfigured.js +19 -15
  73. package/esm/policies/CargoLintsConfigured.js.map +1 -1
  74. package/esm/policies/CargoLockPolicy.d.ts +4 -4
  75. package/esm/policies/CargoLockPolicy.d.ts.map +1 -1
  76. package/esm/policies/CargoLockPolicy.js +15 -11
  77. package/esm/policies/CargoLockPolicy.js.map +1 -1
  78. package/esm/policies/CargoTomlRequired.d.ts +5 -5
  79. package/esm/policies/CargoTomlRequired.d.ts.map +1 -1
  80. package/esm/policies/CargoTomlRequired.js +7 -7
  81. package/esm/policies/CargoTomlRequired.js.map +1 -1
  82. package/esm/policies/CargoTomlSorted.d.ts +4 -4
  83. package/esm/policies/CargoTomlSorted.d.ts.map +1 -1
  84. package/esm/policies/CargoTomlSorted.js +21 -17
  85. package/esm/policies/CargoTomlSorted.js.map +1 -1
  86. package/esm/policies/ConditionalScripts.d.ts +10 -8
  87. package/esm/policies/ConditionalScripts.d.ts.map +1 -1
  88. package/esm/policies/ConditionalScripts.js +24 -22
  89. package/esm/policies/ConditionalScripts.js.map +1 -1
  90. package/esm/policies/ExactScripts.d.ts +8 -6
  91. package/esm/policies/ExactScripts.d.ts.map +1 -1
  92. package/esm/policies/ExactScripts.js +15 -18
  93. package/esm/policies/ExactScripts.js.map +1 -1
  94. package/esm/policies/GleamDepVersions.d.ts +5 -5
  95. package/esm/policies/GleamDepVersions.d.ts.map +1 -1
  96. package/esm/policies/GleamDepVersions.js +5 -5
  97. package/esm/policies/GleamDepVersions.js.map +1 -1
  98. package/esm/policies/GleamDocExists.d.ts +4 -4
  99. package/esm/policies/GleamDocExists.d.ts.map +1 -1
  100. package/esm/policies/GleamDocExists.js +6 -6
  101. package/esm/policies/GleamDocExists.js.map +1 -1
  102. package/esm/policies/GleamInternalModulesConfigured.d.ts +4 -4
  103. package/esm/policies/GleamInternalModulesConfigured.d.ts.map +1 -1
  104. package/esm/policies/GleamInternalModulesConfigured.js +8 -6
  105. package/esm/policies/GleamInternalModulesConfigured.js.map +1 -1
  106. package/esm/policies/GleamLicenceConfigured.d.ts +4 -4
  107. package/esm/policies/GleamLicenceConfigured.d.ts.map +1 -1
  108. package/esm/policies/GleamLicenceConfigured.js +8 -6
  109. package/esm/policies/GleamLicenceConfigured.js.map +1 -1
  110. package/esm/policies/GleamManifestCommitted.d.ts +10 -3
  111. package/esm/policies/GleamManifestCommitted.d.ts.map +1 -1
  112. package/esm/policies/GleamManifestCommitted.js +10 -9
  113. package/esm/policies/GleamManifestCommitted.js.map +1 -1
  114. package/esm/policies/GleamMonorepoConsistency.d.ts +13 -5
  115. package/esm/policies/GleamMonorepoConsistency.d.ts.map +1 -1
  116. package/esm/policies/GleamMonorepoConsistency.js +10 -10
  117. package/esm/policies/GleamMonorepoConsistency.js.map +1 -1
  118. package/esm/policies/GleamNameRestrictions.d.ts +4 -4
  119. package/esm/policies/GleamNameRestrictions.d.ts.map +1 -1
  120. package/esm/policies/GleamNameRestrictions.js +6 -6
  121. package/esm/policies/GleamNameRestrictions.js.map +1 -1
  122. package/esm/policies/GleamNoPathDepsInPublished.d.ts +4 -4
  123. package/esm/policies/GleamNoPathDepsInPublished.d.ts.map +1 -1
  124. package/esm/policies/GleamNoPathDepsInPublished.js +6 -6
  125. package/esm/policies/GleamNoPathDepsInPublished.js.map +1 -1
  126. package/esm/policies/GleamPathDepsValid.d.ts +3 -3
  127. package/esm/policies/GleamPathDepsValid.d.ts.map +1 -1
  128. package/esm/policies/GleamPathDepsValid.js +5 -5
  129. package/esm/policies/GleamPathDepsValid.js.map +1 -1
  130. package/esm/policies/GleamProjectStructure.d.ts +11 -4
  131. package/esm/policies/GleamProjectStructure.d.ts.map +1 -1
  132. package/esm/policies/GleamProjectStructure.js +7 -8
  133. package/esm/policies/GleamProjectStructure.js.map +1 -1
  134. package/esm/policies/GleamSharedDependencyVersions.d.ts +12 -4
  135. package/esm/policies/GleamSharedDependencyVersions.d.ts.map +1 -1
  136. package/esm/policies/GleamSharedDependencyVersions.js +10 -10
  137. package/esm/policies/GleamSharedDependencyVersions.js.map +1 -1
  138. package/esm/policies/GleamTomlRequired.d.ts +4 -4
  139. package/esm/policies/GleamTomlRequired.d.ts.map +1 -1
  140. package/esm/policies/GleamTomlRequired.js +5 -5
  141. package/esm/policies/GleamTomlRequired.js.map +1 -1
  142. package/esm/policies/GleamTomlSorted.d.ts +4 -4
  143. package/esm/policies/GleamTomlSorted.d.ts.map +1 -1
  144. package/esm/policies/GleamTomlSorted.js +21 -17
  145. package/esm/policies/GleamTomlSorted.js.map +1 -1
  146. package/esm/policies/GleamVersionConstraint.d.ts +4 -4
  147. package/esm/policies/GleamVersionConstraint.d.ts.map +1 -1
  148. package/esm/policies/GleamVersionConstraint.js +14 -10
  149. package/esm/policies/GleamVersionConstraint.js.map +1 -1
  150. package/esm/policies/HtmlFileHeaders.d.ts +4 -2
  151. package/esm/policies/HtmlFileHeaders.d.ts.map +1 -1
  152. package/esm/policies/HtmlFileHeaders.js +1 -1
  153. package/esm/policies/HtmlFileHeaders.js.map +1 -1
  154. package/esm/policies/JsTsFileHeaders.d.ts +4 -2
  155. package/esm/policies/JsTsFileHeaders.d.ts.map +1 -1
  156. package/esm/policies/JsTsFileHeaders.js +1 -1
  157. package/esm/policies/JsTsFileHeaders.js.map +1 -1
  158. package/esm/policies/LicenseFileExists.d.ts +10 -4
  159. package/esm/policies/LicenseFileExists.d.ts.map +1 -1
  160. package/esm/policies/LicenseFileExists.js +27 -20
  161. package/esm/policies/LicenseFileExists.js.map +1 -1
  162. package/esm/policies/MaxChangedFiles.d.ts +17 -0
  163. package/esm/policies/MaxChangedFiles.d.ts.map +1 -0
  164. package/esm/policies/MaxChangedFiles.js +22 -0
  165. package/esm/policies/MaxChangedFiles.js.map +1 -0
  166. package/esm/policies/MutuallyExclusiveScripts.d.ts +8 -6
  167. package/esm/policies/MutuallyExclusiveScripts.d.ts.map +1 -1
  168. package/esm/policies/MutuallyExclusiveScripts.js +9 -13
  169. package/esm/policies/MutuallyExclusiveScripts.js.map +1 -1
  170. package/esm/policies/NoBuildDirectory.d.ts +9 -3
  171. package/esm/policies/NoBuildDirectory.d.ts.map +1 -1
  172. package/esm/policies/NoBuildDirectory.js +8 -13
  173. package/esm/policies/NoBuildDirectory.js.map +1 -1
  174. package/esm/policies/NoJsFileExtensions.d.ts +9 -3
  175. package/esm/policies/NoJsFileExtensions.d.ts.map +1 -1
  176. package/esm/policies/NoJsFileExtensions.js +9 -14
  177. package/esm/policies/NoJsFileExtensions.js.map +1 -1
  178. package/esm/policies/NoLargeBinaryFiles.d.ts +9 -4
  179. package/esm/policies/NoLargeBinaryFiles.d.ts.map +1 -1
  180. package/esm/policies/NoLargeBinaryFiles.js +10 -16
  181. package/esm/policies/NoLargeBinaryFiles.js.map +1 -1
  182. package/esm/policies/NoPrivateWorkspaceDependencies.d.ts +10 -6
  183. package/esm/policies/NoPrivateWorkspaceDependencies.d.ts.map +1 -1
  184. package/esm/policies/NoPrivateWorkspaceDependencies.js +12 -14
  185. package/esm/policies/NoPrivateWorkspaceDependencies.js.map +1 -1
  186. package/esm/policies/NoTargetArtifacts.d.ts +9 -3
  187. package/esm/policies/NoTargetArtifacts.d.ts.map +1 -1
  188. package/esm/policies/NoTargetArtifacts.js +9 -14
  189. package/esm/policies/NoTargetArtifacts.js.map +1 -1
  190. package/esm/policies/NoUnsafeWithoutJustification.d.ts +11 -4
  191. package/esm/policies/NoUnsafeWithoutJustification.d.ts.map +1 -1
  192. package/esm/policies/NoUnsafeWithoutJustification.js +8 -9
  193. package/esm/policies/NoUnsafeWithoutJustification.js.map +1 -1
  194. package/esm/policies/NoWildcardDependencies.d.ts +5 -5
  195. package/esm/policies/NoWildcardDependencies.d.ts.map +1 -1
  196. package/esm/policies/NoWildcardDependencies.js +6 -6
  197. package/esm/policies/NoWildcardDependencies.js.map +1 -1
  198. package/esm/policies/PackageAllowedScopes.d.ts +9 -5
  199. package/esm/policies/PackageAllowedScopes.d.ts.map +1 -1
  200. package/esm/policies/PackageAllowedScopes.js +15 -16
  201. package/esm/policies/PackageAllowedScopes.js.map +1 -1
  202. package/esm/policies/PackageEsmType.d.ts +7 -5
  203. package/esm/policies/PackageEsmType.d.ts.map +1 -1
  204. package/esm/policies/PackageEsmType.js +31 -31
  205. package/esm/policies/PackageEsmType.js.map +1 -1
  206. package/esm/policies/PackageFolderName.d.ts +8 -6
  207. package/esm/policies/PackageFolderName.d.ts.map +1 -1
  208. package/esm/policies/PackageFolderName.js +13 -16
  209. package/esm/policies/PackageFolderName.js.map +1 -1
  210. package/esm/policies/PackageJsonProperties.d.ts +5 -3
  211. package/esm/policies/PackageJsonProperties.d.ts.map +1 -1
  212. package/esm/policies/PackageJsonProperties.js +6 -17
  213. package/esm/policies/PackageJsonProperties.js.map +1 -1
  214. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts +2 -7
  215. package/esm/policies/PackageJsonRepoDirectoryProperty.d.ts.map +1 -1
  216. package/esm/policies/PackageJsonRepoDirectoryProperty.js +28 -42
  217. package/esm/policies/PackageJsonRepoDirectoryProperty.js.map +1 -1
  218. package/esm/policies/PackageJsonSorted.d.ts +2 -2
  219. package/esm/policies/PackageJsonSorted.d.ts.map +1 -1
  220. package/esm/policies/PackageJsonSorted.js +15 -30
  221. package/esm/policies/PackageJsonSorted.js.map +1 -1
  222. package/esm/policies/PackageLicense.d.ts +4 -4
  223. package/esm/policies/PackageLicense.d.ts.map +1 -1
  224. package/esm/policies/PackageLicense.js +31 -52
  225. package/esm/policies/PackageLicense.js.map +1 -1
  226. package/esm/policies/PackagePrivateField.d.ts +12 -8
  227. package/esm/policies/PackagePrivateField.d.ts.map +1 -1
  228. package/esm/policies/PackagePrivateField.js +31 -23
  229. package/esm/policies/PackagePrivateField.js.map +1 -1
  230. package/esm/policies/PackageReadme.d.ts +6 -5
  231. package/esm/policies/PackageReadme.d.ts.map +1 -1
  232. package/esm/policies/PackageReadme.js +22 -59
  233. package/esm/policies/PackageReadme.js.map +1 -1
  234. package/esm/policies/PackageScripts.d.ts +26 -22
  235. package/esm/policies/PackageScripts.d.ts.map +1 -1
  236. package/esm/policies/PackageScripts.js +39 -36
  237. package/esm/policies/PackageScripts.js.map +1 -1
  238. package/esm/policies/PackageTestScripts.d.ts +10 -6
  239. package/esm/policies/PackageTestScripts.d.ts.map +1 -1
  240. package/esm/policies/PackageTestScripts.js +14 -16
  241. package/esm/policies/PackageTestScripts.js.map +1 -1
  242. package/esm/policies/PublicApiDocumented.d.ts +4 -4
  243. package/esm/policies/PublicApiDocumented.d.ts.map +1 -1
  244. package/esm/policies/PublicApiDocumented.js +10 -8
  245. package/esm/policies/PublicApiDocumented.js.map +1 -1
  246. package/esm/policies/RequireCompanionChanges.d.ts +16 -0
  247. package/esm/policies/RequireCompanionChanges.d.ts.map +1 -0
  248. package/esm/policies/RequireCompanionChanges.js +42 -0
  249. package/esm/policies/RequireCompanionChanges.js.map +1 -0
  250. package/esm/policies/RequiredGitignorePatterns.d.ts +11 -4
  251. package/esm/policies/RequiredGitignorePatterns.d.ts.map +1 -1
  252. package/esm/policies/RequiredGitignorePatterns.js +29 -36
  253. package/esm/policies/RequiredGitignorePatterns.js.map +1 -1
  254. package/esm/policies/RequiredScripts.d.ts +9 -7
  255. package/esm/policies/RequiredScripts.d.ts.map +1 -1
  256. package/esm/policies/RequiredScripts.js +24 -24
  257. package/esm/policies/RequiredScripts.js.map +1 -1
  258. package/esm/policies/RustDocExists.d.ts +4 -4
  259. package/esm/policies/RustDocExists.d.ts.map +1 -1
  260. package/esm/policies/RustDocExists.js +6 -6
  261. package/esm/policies/RustDocExists.js.map +1 -1
  262. package/esm/policies/RustToolchainExists.d.ts +11 -4
  263. package/esm/policies/RustToolchainExists.d.ts.map +1 -1
  264. package/esm/policies/RustToolchainExists.js +10 -9
  265. package/esm/policies/RustToolchainExists.js.map +1 -1
  266. package/esm/policies/RustfmtConfigExists.d.ts +11 -4
  267. package/esm/policies/RustfmtConfigExists.d.ts.map +1 -1
  268. package/esm/policies/RustfmtConfigExists.js +10 -9
  269. package/esm/policies/RustfmtConfigExists.js.map +1 -1
  270. package/esm/policies/ScriptContains.d.ts +9 -7
  271. package/esm/policies/ScriptContains.d.ts.map +1 -1
  272. package/esm/policies/ScriptContains.js +9 -13
  273. package/esm/policies/ScriptContains.js.map +1 -1
  274. package/esm/policies/SharedDependencyVersions.d.ts +9 -4
  275. package/esm/policies/SharedDependencyVersions.d.ts.map +1 -1
  276. package/esm/policies/SharedDependencyVersions.js +28 -20
  277. package/esm/policies/SharedDependencyVersions.js.map +1 -1
  278. package/esm/policies/WorkspaceInheritance.d.ts +11 -4
  279. package/esm/policies/WorkspaceInheritance.d.ts.map +1 -1
  280. package/esm/policies/WorkspaceInheritance.js +10 -11
  281. package/esm/policies/WorkspaceInheritance.js.map +1 -1
  282. package/esm/policies/WorkspaceMembersValid.d.ts +11 -4
  283. package/esm/policies/WorkspaceMembersValid.d.ts.map +1 -1
  284. package/esm/policies/WorkspaceMembersValid.js +10 -11
  285. package/esm/policies/WorkspaceMembersValid.js.map +1 -1
  286. package/esm/policies/constants.d.ts.map +1 -1
  287. package/esm/policies/constants.js +1 -1
  288. package/esm/policies/constants.js.map +1 -1
  289. package/esm/policies.d.ts +15 -5
  290. package/esm/policies.d.ts.map +1 -1
  291. package/esm/policies.js +14 -5
  292. package/esm/policies.js.map +1 -1
  293. package/esm/policy.d.ts +67 -289
  294. package/esm/policy.d.ts.map +1 -1
  295. package/esm/policy.js +1 -122
  296. package/esm/policy.js.map +1 -1
  297. package/esm/policyDefiners/defineCargoPolicy.d.ts +25 -9
  298. package/esm/policyDefiners/defineCargoPolicy.d.ts.map +1 -1
  299. package/esm/policyDefiners/defineCargoPolicy.js +10 -28
  300. package/esm/policyDefiners/defineCargoPolicy.js.map +1 -1
  301. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts +27 -14
  302. package/esm/policyDefiners/defineFileHeaderPolicy.d.ts.map +1 -1
  303. package/esm/policyDefiners/defineFileHeaderPolicy.js +16 -35
  304. package/esm/policyDefiners/defineFileHeaderPolicy.js.map +1 -1
  305. package/esm/policyDefiners/defineGleamPolicy.d.ts +25 -9
  306. package/esm/policyDefiners/defineGleamPolicy.d.ts.map +1 -1
  307. package/esm/policyDefiners/defineGleamPolicy.js +10 -27
  308. package/esm/policyDefiners/defineGleamPolicy.js.map +1 -1
  309. package/esm/policyDefiners/definePackagePolicy.d.ts +24 -13
  310. package/esm/policyDefiners/definePackagePolicy.d.ts.map +1 -1
  311. package/esm/policyDefiners/definePackagePolicy.js +9 -32
  312. package/esm/policyDefiners/definePackagePolicy.js.map +1 -1
  313. package/esm/policyDefiners/spdxValidator.d.ts +4 -12
  314. package/esm/policyDefiners/spdxValidator.d.ts.map +1 -1
  315. package/esm/policyDefiners/spdxValidator.js +26 -14
  316. package/esm/policyDefiners/spdxValidator.js.map +1 -1
  317. package/esm/policyExecution.d.ts +20 -0
  318. package/esm/policyExecution.d.ts.map +1 -0
  319. package/esm/policyExecution.js +234 -0
  320. package/esm/policyExecution.js.map +1 -0
  321. package/esm/repositoryChanges.d.ts +26 -0
  322. package/esm/repositoryChanges.d.ts.map +1 -0
  323. package/esm/repositoryChanges.js +172 -0
  324. package/esm/repositoryChanges.js.map +1 -0
  325. package/esm/repositoryFiles.d.ts +6 -0
  326. package/esm/repositoryFiles.d.ts.map +1 -0
  327. package/esm/repositoryFiles.js +11 -0
  328. package/esm/repositoryFiles.js.map +1 -0
  329. package/esm/runner.d.ts +73 -47
  330. package/esm/runner.d.ts.map +1 -1
  331. package/esm/runner.js +158 -144
  332. package/esm/runner.js.map +1 -1
  333. package/esm/settlePolicyPromise.d.ts +4 -0
  334. package/esm/settlePolicyPromise.d.ts.map +1 -0
  335. package/esm/settlePolicyPromise.js +10 -0
  336. package/esm/settlePolicyPromise.js.map +1 -0
  337. package/esm/tsdoc-metadata.json +1 -1
  338. package/esm/utils/safePaths.d.ts +9 -0
  339. package/esm/utils/safePaths.d.ts.map +1 -0
  340. package/esm/utils/safePaths.js +40 -0
  341. package/esm/utils/safePaths.js.map +1 -0
  342. package/oclif.manifest.json +57 -2
  343. package/package.json +42 -27
  344. package/scripts/benchmark.mjs +341 -0
  345. package/sidecar/sidecar.mjs +388 -417
@@ -1 +1 @@
1
- {"version":3,"file":"PackageTestScripts.d.ts","sourceRoot":"","sources":["../../src/policies/PackageTestScripts.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,wBAAwB;IACxC;;;;;;;;;;;;OAYG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE5B;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AA0GD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,kBAAkB,0EA4D7B,CAAC"}
1
+ {"version":3,"file":"PackageTestScripts.d.ts","sourceRoot":"","sources":["../../src/policies/PackageTestScripts.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,wBAAwB;IACxC;;;;;;;;;;;;OAYG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE5B;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AA0GD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,eAAO,MAAM,kBAAkB;;CAuD7B,CAAC"}
@@ -95,27 +95,30 @@ function shouldSkipValidation(json, config) {
95
95
  * const config: RepopoConfig = {
96
96
  * policies: [
97
97
  * makePolicy(PackageTestScripts, {
98
- * testDirectories: ["test", "tests"],
99
- * testDependencies: ["vitest", "jest"],
100
- * requiredScripts: ["test"],
98
+ * config: {
99
+ * testDirectories: ["test", "tests"],
100
+ * testDependencies: ["vitest", "jest"],
101
+ * requiredScripts: ["test"],
102
+ * },
101
103
  * }),
102
104
  * ],
103
105
  * };
104
106
  * ```
105
107
  *
106
- * @alpha
108
+ * @public
107
109
  */
108
110
  export const PackageTestScripts = definePackagePolicy({
109
111
  name: "PackageTestScripts",
112
+ requiresConfig: true,
110
113
  description: "Ensures packages have test scripts when test directories or test framework dependencies exist.",
111
114
  handler: async (json, { file, root, config }) => {
112
115
  // If no config provided, skip validation
113
116
  if (config === undefined) {
114
- return true;
117
+ return [];
115
118
  }
116
119
  // Skip validation based on package properties and config
117
120
  if (shouldSkipValidation(json, config)) {
118
- return true;
121
+ return [];
119
122
  }
120
123
  // Get config values
121
124
  const testDirectories = config.testDirectories ?? [];
@@ -130,25 +133,20 @@ export const PackageTestScripts = definePackagePolicy({
130
133
  hasTestDependency(devDeps, testDependencies);
131
134
  // If no tests expected based on configured checks, pass
132
135
  if (!(hasTestDir || hasTestDep)) {
133
- return true;
136
+ return [];
134
137
  }
135
138
  // Tests are expected - check for required scripts
136
139
  const missingScripts = findMissingScripts(json.scripts, requiredScripts);
137
140
  if (missingScripts.length === 0) {
138
- return true;
141
+ return [];
139
142
  }
140
143
  // Build error message
141
144
  const reason = hasTestDir
142
145
  ? "test directory exists"
143
146
  : `test dependencies found (${getPresentTestDependencies(devDeps, testDependencies).join(", ")})`;
144
- const failResult = {
145
- name: PackageTestScripts.name,
146
- file,
147
- autoFixable: false,
148
- errorMessages: [
149
- `Package "${json.name}" has ${reason} but is missing test scripts: ${missingScripts.join(", ")}`,
150
- ],
151
- };
147
+ const failResult = [
148
+ `Package "${json.name}" has ${reason} but is missing test scripts: ${missingScripts.join(", ")}`,
149
+ ].map((message) => ({ message }));
152
150
  return failResult;
153
151
  },
154
152
  });
@@ -1 +1 @@
1
- {"version":3,"file":"PackageTestScripts.js","sourceRoot":"","sources":["../../src/policies/PackageTestScripts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,OAAO,CAAC;AAG9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAuE/E;;GAEG;AACH,SAAS,UAAU,CAClB,WAAmB,EACnB,eAAqC;IAErC,IAAI,eAAe,KAAK,SAAS,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnE,OAAO,KAAK,CAAC;IACd,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;QACvC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,WAAW,CAAC,UAAU,CAAC,GAAG,OAAO,GAAG,CAAC,EAAE,CAAC;YACtE,OAAO,IAAI,CAAC;QACb,CAAC;QACD,IAAI,WAAW,KAAK,OAAO,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CACxB,UAAkB,EAClB,eAAyB;IAEzB,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC3C,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CACzB,eAAmD,EACnD,gBAA0B;IAE1B,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC;IACd,CAAC;IAED,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC,CAAC;AAC3E,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAC1B,OAA+B,EAC/B,eAAyB;IAEzB,OAAO,eAAe,CAAC,MAAM,CAC5B,CAAC,UAAU,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,KAAK,SAAS,CACnD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,0BAA0B,CAClC,eAAmD,EACnD,gBAA0B;IAE1B,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QACnC,OAAO,EAAE,CAAC;IACX,CAAC;IACD,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;AACzE,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAC5B,IAAiB,EACjB,MAAgC;IAEhC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC;IAE9B,+CAA+C;IAC/C,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,MAAM,EAAE,CAAC;QACzD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,mBAAmB;IACnB,IAAI,UAAU,CAAC,WAAW,EAAE,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC;QACrD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,8DAA8D;IAC9D,MAAM,eAAe,GAAG,MAAM,CAAC,eAAe,IAAI,EAAE,CAAC;IACrD,MAAM,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,IAAI,EAAE,CAAC;IAEvD,OAAO,eAAe,CAAC,MAAM,KAAK,CAAC,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,CAAC;AACtE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,mBAAmB,CAGnD;IACD,IAAI,EAAE,oBAAoB;IAC1B,WAAW,EACV,gGAAgG;IACjG,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;QAC/C,yCAAyC;QACzC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC;QACb,CAAC;QAED,yDAAyD;QACzD,IAAI,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;YACxC,OAAO,IAAI,CAAC;QACb,CAAC;QAED,oBAAoB;QACpB,MAAM,eAAe,GAAG,MAAM,CAAC,eAAe,IAAI,EAAE,CAAC;QACrD,MAAM,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,IAAI,EAAE,CAAC;QACvD,MAAM,eAAe,GAAG,MAAM,CAAC,eAAe,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3D,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACpD,MAAM,OAAO,GAAG,IAAI,CAAC,eAAqD,CAAC;QAE3E,yDAAyD;QACzD,MAAM,UAAU,GACf,eAAe,CAAC,MAAM,GAAG,CAAC;YAC1B,gBAAgB,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;QAC/C,MAAM,UAAU,GACf,gBAAgB,CAAC,MAAM,GAAG,CAAC;YAC3B,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;QAE9C,wDAAwD;QACxD,IAAI,CAAC,CAAC,UAAU,IAAI,UAAU,CAAC,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC;QACb,CAAC;QAED,kDAAkD;QAClD,MAAM,cAAc,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QAEzE,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC;QACb,CAAC;QAED,sBAAsB;QACtB,MAAM,MAAM,GAAG,UAAU;YACxB,CAAC,CAAC,uBAAuB;YACzB,CAAC,CAAC,4BAA4B,0BAA0B,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;QAEnG,MAAM,UAAU,GAAkB;YACjC,IAAI,EAAE,kBAAkB,CAAC,IAAI;YAC7B,IAAI;YACJ,WAAW,EAAE,KAAK;YAClB,aAAa,EAAE;gBACd,YAAY,IAAI,CAAC,IAAI,SAAS,MAAM,iCAAiC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;aAChG;SACD,CAAC;QACF,OAAO,UAAU,CAAC;IACnB,CAAC;CACD,CAAC,CAAC","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { dirname, join, resolve as resolvePath } from \"pathe\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFailure } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\n/**\n * Configuration for the PackageTestScripts policy.\n *\n * This policy ensures that packages have appropriate test scripts when they\n * contain test files or have test-related dependencies.\n *\n * The policy automatically determines what to check based on what's configured:\n * - If `testDirectories` is set, checks for test directories\n * - If `testDependencies` is set, checks for test dependencies\n * - If both are set, a package triggers validation if either condition is met\n *\n * @example\n * ```typescript\n * const config: PackageTestScriptsConfig = {\n * // Check for these test directories\n * testDirectories: [\"test\", \"tests\", \"__tests__\"],\n * // Require test script if these devDependencies exist\n * testDependencies: [\"vitest\", \"jest\", \"mocha\"],\n * // Required test script names\n * requiredScripts: [\"test\"],\n * };\n * ```\n *\n * @alpha\n */\nexport interface PackageTestScriptsConfig {\n\t/**\n\t * Directory names that indicate test files are present.\n\t *\n\t * If any of these directories exist relative to the package.json,\n\t * the policy will require test scripts to be present.\n\t *\n\t * If not set or empty, directory checking is skipped.\n\t *\n\t * @example\n\t * ```typescript\n\t * testDirectories: [\"test\", \"tests\", \"__tests__\"]\n\t * ```\n\t */\n\ttestDirectories?: string[];\n\n\t/**\n\t * Test framework dependencies that indicate tests are expected.\n\t *\n\t * If any of these appear in devDependencies, the policy will require\n\t * test scripts to be present.\n\t *\n\t * If not set or empty, dependency checking is skipped.\n\t *\n\t * @example\n\t * ```typescript\n\t * testDependencies: [\"vitest\", \"jest\", \"mocha\", \"@jest/globals\"]\n\t * ```\n\t */\n\ttestDependencies?: string[];\n\n\t/**\n\t * Script names that must exist when tests are detected.\n\t *\n\t * @defaultValue [\"test\"]\n\t */\n\trequiredScripts?: string[];\n\n\t/**\n\t * Package names or scopes to exclude from validation.\n\t */\n\texcludePackages?: string[];\n}\n\n/**\n * Check if a package should be excluded from validation.\n */\nfunction isExcluded(\n\tpackageName: string,\n\texcludePackages: string[] | undefined,\n): boolean {\n\tif (excludePackages === undefined || excludePackages.length === 0) {\n\t\treturn false;\n\t}\n\n\tfor (const pattern of excludePackages) {\n\t\tif (pattern.startsWith(\"@\") && packageName.startsWith(`${pattern}/`)) {\n\t\t\treturn true;\n\t\t}\n\t\tif (packageName === pattern) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Check if any test directories exist.\n */\nfunction hasTestDirectory(\n\tpackageDir: string,\n\ttestDirectories: string[],\n): boolean {\n\tfor (const testDir of testDirectories) {\n\t\tconst testPath = join(packageDir, testDir);\n\t\tif (existsSync(testPath)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Check if any test dependencies are present.\n */\nfunction hasTestDependency(\n\tdevDependencies: Record<string, string> | undefined,\n\ttestDependencies: string[],\n): boolean {\n\tif (devDependencies === undefined) {\n\t\treturn false;\n\t}\n\n\treturn testDependencies.some((dep) => devDependencies[dep] !== undefined);\n}\n\n/**\n * Find missing scripts from the required list.\n */\nfunction findMissingScripts(\n\tscripts: PackageJson[\"scripts\"],\n\trequiredScripts: string[],\n): string[] {\n\treturn requiredScripts.filter(\n\t\t(scriptName) => scripts?.[scriptName] === undefined,\n\t);\n}\n\n/**\n * Get the list of test dependencies that are present in devDependencies.\n */\nfunction getPresentTestDependencies(\n\tdevDependencies: Record<string, string> | undefined,\n\ttestDependencies: string[],\n): string[] {\n\tif (devDependencies === undefined) {\n\t\treturn [];\n\t}\n\treturn testDependencies.filter((d) => devDependencies[d] !== undefined);\n}\n\n/**\n * Check if a package should be validated based on config and package properties.\n */\nfunction shouldSkipValidation(\n\tjson: PackageJson,\n\tconfig: PackageTestScriptsConfig,\n): boolean {\n\tconst packageName = json.name;\n\n\t// Skip packages without a name or root package\n\tif (packageName === undefined || packageName === \"root\") {\n\t\treturn true;\n\t}\n\n\t// Check exclusions\n\tif (isExcluded(packageName, config.excludePackages)) {\n\t\treturn true;\n\t}\n\n\t// Skip if neither directories nor dependencies are configured\n\tconst testDirectories = config.testDirectories ?? [];\n\tconst testDependencies = config.testDependencies ?? [];\n\n\treturn testDirectories.length === 0 && testDependencies.length === 0;\n}\n\n/**\n * A policy that ensures packages have test scripts when test files exist.\n *\n * This policy helps maintain testing discipline by requiring test scripts\n * for packages that have test directories or test framework dependencies.\n *\n * @remarks\n *\n * The policy detects that tests are expected based on:\n *\n * 1. **Test directories**: If `test/`, `tests/`, or `__tests__/` exists\n * 2. **Test dependencies**: If vitest, jest, mocha, etc. are in devDependencies\n *\n * When tests are detected, the policy requires specified test scripts to exist.\n *\n * @example\n * ```typescript\n * import { makePolicy } from \"repopo\";\n * import { PackageTestScripts } from \"repopo/policies\";\n *\n * const config: RepopoConfig = {\n * policies: [\n * makePolicy(PackageTestScripts, {\n * testDirectories: [\"test\", \"tests\"],\n * testDependencies: [\"vitest\", \"jest\"],\n * requiredScripts: [\"test\"],\n * }),\n * ],\n * };\n * ```\n *\n * @alpha\n */\nexport const PackageTestScripts = definePackagePolicy<\n\tPackageJson,\n\tPackageTestScriptsConfig | undefined\n>({\n\tname: \"PackageTestScripts\",\n\tdescription:\n\t\t\"Ensures packages have test scripts when test directories or test framework dependencies exist.\",\n\thandler: async (json, { file, root, config }) => {\n\t\t// If no config provided, skip validation\n\t\tif (config === undefined) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Skip validation based on package properties and config\n\t\tif (shouldSkipValidation(json, config)) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Get config values\n\t\tconst testDirectories = config.testDirectories ?? [];\n\t\tconst testDependencies = config.testDependencies ?? [];\n\t\tconst requiredScripts = config.requiredScripts ?? [\"test\"];\n\t\tconst packageDir = dirname(resolvePath(root, file));\n\t\tconst devDeps = json.devDependencies as Record<string, string> | undefined;\n\n\t\t// Check if tests are expected based on what's configured\n\t\tconst hasTestDir =\n\t\t\ttestDirectories.length > 0 &&\n\t\t\thasTestDirectory(packageDir, testDirectories);\n\t\tconst hasTestDep =\n\t\t\ttestDependencies.length > 0 &&\n\t\t\thasTestDependency(devDeps, testDependencies);\n\n\t\t// If no tests expected based on configured checks, pass\n\t\tif (!(hasTestDir || hasTestDep)) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Tests are expected - check for required scripts\n\t\tconst missingScripts = findMissingScripts(json.scripts, requiredScripts);\n\n\t\tif (missingScripts.length === 0) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Build error message\n\t\tconst reason = hasTestDir\n\t\t\t? \"test directory exists\"\n\t\t\t: `test dependencies found (${getPresentTestDependencies(devDeps, testDependencies).join(\", \")})`;\n\n\t\tconst failResult: PolicyFailure = {\n\t\t\tname: PackageTestScripts.name,\n\t\t\tfile,\n\t\t\tautoFixable: false,\n\t\t\terrorMessages: [\n\t\t\t\t`Package \"${json.name}\" has ${reason} but is missing test scripts: ${missingScripts.join(\", \")}`,\n\t\t\t],\n\t\t};\n\t\treturn failResult;\n\t},\n});\n"]}
1
+ {"version":3,"file":"PackageTestScripts.js","sourceRoot":"","sources":["../../src/policies/PackageTestScripts.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { dirname, join, resolve as resolvePath } from \"pathe\";\nimport type { PackageJson } from \"type-fest\";\nimport type { PolicyFinding } from \"../policy.js\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\n/**\n * Configuration for the PackageTestScripts policy.\n *\n * This policy ensures that packages have appropriate test scripts when they\n * contain test files or have test-related dependencies.\n *\n * The policy automatically determines what to check based on what's configured:\n * - If `testDirectories` is set, checks for test directories\n * - If `testDependencies` is set, checks for test dependencies\n * - If both are set, a package triggers validation if either condition is met\n *\n * @example\n * ```typescript\n * const config: PackageTestScriptsConfig = {\n * // Check for these test directories\n * testDirectories: [\"test\", \"tests\", \"__tests__\"],\n * // Require test script if these devDependencies exist\n * testDependencies: [\"vitest\", \"jest\", \"mocha\"],\n * // Required test script names\n * requiredScripts: [\"test\"],\n * };\n * ```\n *\n * @public\n */\nexport interface PackageTestScriptsConfig {\n\t/**\n\t * Directory names that indicate test files are present.\n\t *\n\t * If any of these directories exist relative to the package.json,\n\t * the policy will require test scripts to be present.\n\t *\n\t * If not set or empty, directory checking is skipped.\n\t *\n\t * @example\n\t * ```typescript\n\t * testDirectories: [\"test\", \"tests\", \"__tests__\"]\n\t * ```\n\t */\n\ttestDirectories?: string[];\n\n\t/**\n\t * Test framework dependencies that indicate tests are expected.\n\t *\n\t * If any of these appear in devDependencies, the policy will require\n\t * test scripts to be present.\n\t *\n\t * If not set or empty, dependency checking is skipped.\n\t *\n\t * @example\n\t * ```typescript\n\t * testDependencies: [\"vitest\", \"jest\", \"mocha\", \"@jest/globals\"]\n\t * ```\n\t */\n\ttestDependencies?: string[];\n\n\t/**\n\t * Script names that must exist when tests are detected.\n\t *\n\t * @defaultValue [\"test\"]\n\t */\n\trequiredScripts?: string[];\n\n\t/**\n\t * Package names or scopes to exclude from validation.\n\t */\n\texcludePackages?: string[];\n}\n\n/**\n * Check if a package should be excluded from validation.\n */\nfunction isExcluded(\n\tpackageName: string,\n\texcludePackages: string[] | undefined,\n): boolean {\n\tif (excludePackages === undefined || excludePackages.length === 0) {\n\t\treturn false;\n\t}\n\n\tfor (const pattern of excludePackages) {\n\t\tif (pattern.startsWith(\"@\") && packageName.startsWith(`${pattern}/`)) {\n\t\t\treturn true;\n\t\t}\n\t\tif (packageName === pattern) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Check if any test directories exist.\n */\nfunction hasTestDirectory(\n\tpackageDir: string,\n\ttestDirectories: string[],\n): boolean {\n\tfor (const testDir of testDirectories) {\n\t\tconst testPath = join(packageDir, testDir);\n\t\tif (existsSync(testPath)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Check if any test dependencies are present.\n */\nfunction hasTestDependency(\n\tdevDependencies: Record<string, string> | undefined,\n\ttestDependencies: string[],\n): boolean {\n\tif (devDependencies === undefined) {\n\t\treturn false;\n\t}\n\n\treturn testDependencies.some((dep) => devDependencies[dep] !== undefined);\n}\n\n/**\n * Find missing scripts from the required list.\n */\nfunction findMissingScripts(\n\tscripts: PackageJson[\"scripts\"],\n\trequiredScripts: string[],\n): string[] {\n\treturn requiredScripts.filter(\n\t\t(scriptName) => scripts?.[scriptName] === undefined,\n\t);\n}\n\n/**\n * Get the list of test dependencies that are present in devDependencies.\n */\nfunction getPresentTestDependencies(\n\tdevDependencies: Record<string, string> | undefined,\n\ttestDependencies: string[],\n): string[] {\n\tif (devDependencies === undefined) {\n\t\treturn [];\n\t}\n\treturn testDependencies.filter((d) => devDependencies[d] !== undefined);\n}\n\n/**\n * Check if a package should be validated based on config and package properties.\n */\nfunction shouldSkipValidation(\n\tjson: PackageJson,\n\tconfig: PackageTestScriptsConfig,\n): boolean {\n\tconst packageName = json.name;\n\n\t// Skip packages without a name or root package\n\tif (packageName === undefined || packageName === \"root\") {\n\t\treturn true;\n\t}\n\n\t// Check exclusions\n\tif (isExcluded(packageName, config.excludePackages)) {\n\t\treturn true;\n\t}\n\n\t// Skip if neither directories nor dependencies are configured\n\tconst testDirectories = config.testDirectories ?? [];\n\tconst testDependencies = config.testDependencies ?? [];\n\n\treturn testDirectories.length === 0 && testDependencies.length === 0;\n}\n\n/**\n * A policy that ensures packages have test scripts when test files exist.\n *\n * This policy helps maintain testing discipline by requiring test scripts\n * for packages that have test directories or test framework dependencies.\n *\n * @remarks\n *\n * The policy detects that tests are expected based on:\n *\n * 1. **Test directories**: If `test/`, `tests/`, or `__tests__/` exists\n * 2. **Test dependencies**: If vitest, jest, mocha, etc. are in devDependencies\n *\n * When tests are detected, the policy requires specified test scripts to exist.\n *\n * @example\n * ```typescript\n * import { makePolicy } from \"repopo\";\n * import { PackageTestScripts } from \"repopo/policies\";\n *\n * const config: RepopoConfig = {\n * policies: [\n * makePolicy(PackageTestScripts, {\n * config: {\n * testDirectories: [\"test\", \"tests\"],\n * testDependencies: [\"vitest\", \"jest\"],\n * requiredScripts: [\"test\"],\n * },\n * }),\n * ],\n * };\n * ```\n *\n * @public\n */\nexport const PackageTestScripts = definePackagePolicy<\n\tPackageJson,\n\tPackageTestScriptsConfig | undefined\n>({\n\tname: \"PackageTestScripts\",\n\trequiresConfig: true,\n\tdescription:\n\t\t\"Ensures packages have test scripts when test directories or test framework dependencies exist.\",\n\thandler: async (json, { file, root, config }) => {\n\t\t// If no config provided, skip validation\n\t\tif (config === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Skip validation based on package properties and config\n\t\tif (shouldSkipValidation(json, config)) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Get config values\n\t\tconst testDirectories = config.testDirectories ?? [];\n\t\tconst testDependencies = config.testDependencies ?? [];\n\t\tconst requiredScripts = config.requiredScripts ?? [\"test\"];\n\t\tconst packageDir = dirname(resolvePath(root, file));\n\t\tconst devDeps = json.devDependencies as Record<string, string> | undefined;\n\n\t\t// Check if tests are expected based on what's configured\n\t\tconst hasTestDir =\n\t\t\ttestDirectories.length > 0 &&\n\t\t\thasTestDirectory(packageDir, testDirectories);\n\t\tconst hasTestDep =\n\t\t\ttestDependencies.length > 0 &&\n\t\t\thasTestDependency(devDeps, testDependencies);\n\n\t\t// If no tests expected based on configured checks, pass\n\t\tif (!(hasTestDir || hasTestDep)) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Tests are expected - check for required scripts\n\t\tconst missingScripts = findMissingScripts(json.scripts, requiredScripts);\n\n\t\tif (missingScripts.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Build error message\n\t\tconst reason = hasTestDir\n\t\t\t? \"test directory exists\"\n\t\t\t: `test dependencies found (${getPresentTestDependencies(devDeps, testDependencies).join(\", \")})`;\n\t\tconst failResult: PolicyFinding[] = [\n\t\t\t`Package \"${json.name}\" has ${reason} but is missing test scripts: ${missingScripts.join(\", \")}`,\n\t\t].map((message) => ({ message }));\n\t\treturn failResult;\n\t},\n});\n"]}
@@ -1,8 +1,8 @@
1
- import type { PolicyShape } from "../policy.js";
1
+ import type { FilePolicyDefinition } from "../policy.js";
2
2
  /**
3
3
  * Configuration for the PublicApiDocumented policy.
4
4
  *
5
- * @alpha
5
+ * @public
6
6
  */
7
7
  export interface PublicApiDocumentedConfig {
8
8
  /**
@@ -15,7 +15,7 @@ export interface PublicApiDocumentedConfig {
15
15
  * A policy that ensures public API documentation is enforced in Rust crates
16
16
  * via the `missing_docs` lint configured in Cargo.toml.
17
17
  *
18
- * @alpha
18
+ * @public
19
19
  */
20
- export declare const PublicApiDocumented: PolicyShape<PublicApiDocumentedConfig>;
20
+ export declare const PublicApiDocumented: FilePolicyDefinition<PublicApiDocumentedConfig>;
21
21
  //# sourceMappingURL=PublicApiDocumented.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PublicApiDocumented.d.ts","sourceRoot":"","sources":["../../src/policies/PublicApiDocumented.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAMhD;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACzC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,yBAAyB,CAsCpE,CAAC"}
1
+ {"version":3,"file":"PublicApiDocumented.d.ts","sourceRoot":"","sources":["../../src/policies/PublicApiDocumented.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAMzD;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACzC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,iDAoC4B,CAAC"}
@@ -3,7 +3,7 @@ import { defineCargoPolicy, } from "../policyDefiners/defineCargoPolicy.js";
3
3
  * A policy that ensures public API documentation is enforced in Rust crates
4
4
  * via the `missing_docs` lint configured in Cargo.toml.
5
5
  *
6
- * @alpha
6
+ * @public
7
7
  */
8
8
  export const PublicApiDocumented = defineCargoPolicy({
9
9
  name: "PublicApiDocumented",
@@ -11,7 +11,7 @@ export const PublicApiDocumented = defineCargoPolicy({
11
11
  handler: async (toml, { config }) => {
12
12
  // Skip workspace root
13
13
  if (toml.workspace !== undefined && toml.package === undefined) {
14
- return true;
14
+ return [];
15
15
  }
16
16
  const checkCargoLints = config?.checkCargoLints ?? true;
17
17
  if (checkCargoLints) {
@@ -22,15 +22,17 @@ export const PublicApiDocumented = defineCargoPolicy({
22
22
  if (missingDocs === "deny" ||
23
23
  missingDocs === "warn" ||
24
24
  missingDocs === "forbid") {
25
- return true;
25
+ return [];
26
26
  }
27
27
  }
28
- return {
29
- error: 'missing_docs lint is not configured. Set [lints.rust] missing_docs = "warn" or "deny" in Cargo.toml.',
30
- manualFix: 'Add to Cargo.toml:\n[lints.rust]\nmissing_docs = "warn"',
31
- };
28
+ return [
29
+ {
30
+ message: 'missing_docs lint is not configured. Set [lints.rust] missing_docs = "warn" or "deny" in Cargo.toml.',
31
+ manualFix: 'Add to Cargo.toml:\n[lints.rust]\nmissing_docs = "warn"',
32
+ },
33
+ ];
32
34
  }
33
- return true;
35
+ return [];
34
36
  },
35
37
  });
36
38
  //# sourceMappingURL=PublicApiDocumented.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PublicApiDocumented.js","sourceRoot":"","sources":["../../src/policies/PublicApiDocumented.ts"],"names":[],"mappings":"AACA,OAAO,EAEN,iBAAiB,GACjB,MAAM,wCAAwC,CAAC;AAehD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAC/B,iBAAiB,CAAC;IACjB,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EACV,gGAAgG;IACjG,OAAO,EAAE,KAAK,EAAE,IAAe,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QAC9C,sBAAsB;QACtB,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAChE,OAAO,IAAI,CAAC;QACb,CAAC;QAED,MAAM,eAAe,GAAG,MAAM,EAAE,eAAe,IAAI,IAAI,CAAC;QAExD,IAAI,eAAe,EAAE,CAAC;YACrB,MAAM,KAAK,GAAG,IAAI,CAAC,KAA4C,CAAC;YAChE,MAAM,SAAS,GAAG,KAAK,EAAE,IAA2C,CAAC;YAErE,IAAI,SAAS,EAAE,CAAC;gBACf,MAAM,WAAW,GAChB,SAAS,CAAC,YAAY,IAAI,SAAS,CAAC,cAAc,CAAC,CAAC;gBACrD,IACC,WAAW,KAAK,MAAM;oBACtB,WAAW,KAAK,MAAM;oBACtB,WAAW,KAAK,QAAQ,EACvB,CAAC;oBACF,OAAO,IAAI,CAAC;gBACb,CAAC;YACF,CAAC;YAED,OAAO;gBACN,KAAK,EACJ,sGAAsG;gBACvG,SAAS,EAAE,yDAAyD;aACpE,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;CACD,CAAC,CAAC","sourcesContent":["import type { PolicyShape } from \"../policy.js\";\nimport {\n\ttype CargoToml,\n\tdefineCargoPolicy,\n} from \"../policyDefiners/defineCargoPolicy.js\";\n\n/**\n * Configuration for the PublicApiDocumented policy.\n *\n * @alpha\n */\nexport interface PublicApiDocumentedConfig {\n\t/**\n\t * If true, check for `#![deny(missing_docs)]` directive via [lints.rust] in Cargo.toml.\n\t * @defaultValue true\n\t */\n\tcheckCargoLints?: boolean;\n}\n\n/**\n * A policy that ensures public API documentation is enforced in Rust crates\n * via the `missing_docs` lint configured in Cargo.toml.\n *\n * @alpha\n */\nexport const PublicApiDocumented: PolicyShape<PublicApiDocumentedConfig> =\n\tdefineCargoPolicy({\n\t\tname: \"PublicApiDocumented\",\n\t\tdescription:\n\t\t\t\"Ensures the missing_docs lint is configured in Cargo.toml to enforce public API documentation.\",\n\t\thandler: async (toml: CargoToml, { config }) => {\n\t\t\t// Skip workspace root\n\t\t\tif (toml.workspace !== undefined && toml.package === undefined) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst checkCargoLints = config?.checkCargoLints ?? true;\n\n\t\t\tif (checkCargoLints) {\n\t\t\t\tconst lints = toml.lints as Record<string, unknown> | undefined;\n\t\t\t\tconst rustLints = lints?.rust as Record<string, unknown> | undefined;\n\n\t\t\t\tif (rustLints) {\n\t\t\t\t\tconst missingDocs =\n\t\t\t\t\t\trustLints.missing_docs ?? rustLints[\"missing-docs\"];\n\t\t\t\t\tif (\n\t\t\t\t\t\tmissingDocs === \"deny\" ||\n\t\t\t\t\t\tmissingDocs === \"warn\" ||\n\t\t\t\t\t\tmissingDocs === \"forbid\"\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\terror:\n\t\t\t\t\t\t'missing_docs lint is not configured. Set [lints.rust] missing_docs = \"warn\" or \"deny\" in Cargo.toml.',\n\t\t\t\t\tmanualFix: 'Add to Cargo.toml:\\n[lints.rust]\\nmissing_docs = \"warn\"',\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn true;\n\t\t},\n\t});\n"]}
1
+ {"version":3,"file":"PublicApiDocumented.js","sourceRoot":"","sources":["../../src/policies/PublicApiDocumented.ts"],"names":[],"mappings":"AACA,OAAO,EAEN,iBAAiB,GACjB,MAAM,wCAAwC,CAAC;AAehD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;IACpD,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EACV,gGAAgG;IACjG,OAAO,EAAE,KAAK,EAAE,IAAe,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QAC9C,sBAAsB;QACtB,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAChE,OAAO,EAAE,CAAC;QACX,CAAC;QAED,MAAM,eAAe,GAAG,MAAM,EAAE,eAAe,IAAI,IAAI,CAAC;QAExD,IAAI,eAAe,EAAE,CAAC;YACrB,MAAM,KAAK,GAAG,IAAI,CAAC,KAA4C,CAAC;YAChE,MAAM,SAAS,GAAG,KAAK,EAAE,IAA2C,CAAC;YAErE,IAAI,SAAS,EAAE,CAAC;gBACf,MAAM,WAAW,GAAG,SAAS,CAAC,YAAY,IAAI,SAAS,CAAC,cAAc,CAAC,CAAC;gBACxE,IACC,WAAW,KAAK,MAAM;oBACtB,WAAW,KAAK,MAAM;oBACtB,WAAW,KAAK,QAAQ,EACvB,CAAC;oBACF,OAAO,EAAE,CAAC;gBACX,CAAC;YACF,CAAC;YACD,OAAO;gBACN;oBACC,OAAO,EACN,sGAAsG;oBACvG,SAAS,EAAE,yDAAyD;iBACpE;aACD,CAAC;QACH,CAAC;QACD,OAAO,EAAE,CAAC;IACX,CAAC;CACD,CAA2D,CAAC","sourcesContent":["import type { FilePolicyDefinition } from \"../policy.js\";\nimport {\n\ttype CargoToml,\n\tdefineCargoPolicy,\n} from \"../policyDefiners/defineCargoPolicy.js\";\n\n/**\n * Configuration for the PublicApiDocumented policy.\n *\n * @public\n */\nexport interface PublicApiDocumentedConfig {\n\t/**\n\t * If true, check for `#![deny(missing_docs)]` directive via [lints.rust] in Cargo.toml.\n\t * @defaultValue true\n\t */\n\tcheckCargoLints?: boolean;\n}\n\n/**\n * A policy that ensures public API documentation is enforced in Rust crates\n * via the `missing_docs` lint configured in Cargo.toml.\n *\n * @public\n */\nexport const PublicApiDocumented = defineCargoPolicy({\n\tname: \"PublicApiDocumented\",\n\tdescription:\n\t\t\"Ensures the missing_docs lint is configured in Cargo.toml to enforce public API documentation.\",\n\thandler: async (toml: CargoToml, { config }) => {\n\t\t// Skip workspace root\n\t\tif (toml.workspace !== undefined && toml.package === undefined) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst checkCargoLints = config?.checkCargoLints ?? true;\n\n\t\tif (checkCargoLints) {\n\t\t\tconst lints = toml.lints as Record<string, unknown> | undefined;\n\t\t\tconst rustLints = lints?.rust as Record<string, unknown> | undefined;\n\n\t\t\tif (rustLints) {\n\t\t\t\tconst missingDocs = rustLints.missing_docs ?? rustLints[\"missing-docs\"];\n\t\t\t\tif (\n\t\t\t\t\tmissingDocs === \"deny\" ||\n\t\t\t\t\tmissingDocs === \"warn\" ||\n\t\t\t\t\tmissingDocs === \"forbid\"\n\t\t\t\t) {\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t'missing_docs lint is not configured. Set [lints.rust] missing_docs = \"warn\" or \"deny\" in Cargo.toml.',\n\t\t\t\t\tmanualFix: 'Add to Cargo.toml:\\n[lints.rust]\\nmissing_docs = \"warn\"',\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\t\treturn [];\n\t},\n}) satisfies FilePolicyDefinition<PublicApiDocumentedConfig>;\n"]}
@@ -0,0 +1,16 @@
1
+ /** Require a related update when trigger paths change. @public */
2
+ export declare const RequireCompanionChanges: {
3
+ name: string;
4
+ description: string;
5
+ scope: "changes";
6
+ requiresConfig: true;
7
+ handler: ({ entries, config }: import("../policy.js").RepositoryPolicyArgs<{
8
+ trigger: string | RegExp;
9
+ companion: string | RegExp;
10
+ }>) => Promise<{
11
+ message: string;
12
+ files: string[];
13
+ manualFix: string;
14
+ }[]>;
15
+ };
16
+ //# sourceMappingURL=RequireCompanionChanges.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequireCompanionChanges.d.ts","sourceRoot":"","sources":["../../src/policies/RequireCompanionChanges.ts"],"names":[],"mappings":"AAYA,kEAAkE;AAClE,eAAO,MAAM,uBAAuB;;;;;;iBA4C1B,MAAM,GAAG,MAAM;mBACb,MAAM,GAAG,MAAM;;;;;;CACzB,CAAC"}
@@ -0,0 +1,42 @@
1
+ import { exclusionRegex, matchesPath } from "../context.js";
2
+ function compilePattern(value) {
3
+ if (typeof value !== "string" && !(value instanceof RegExp)) {
4
+ throw new TypeError("Trigger and companion must be regex strings or RegExp values.");
5
+ }
6
+ return exclusionRegex(value);
7
+ }
8
+ /** Require a related update when trigger paths change. @public */
9
+ export const RequireCompanionChanges = {
10
+ name: "RequireCompanionChanges",
11
+ description: "Requires a related file change when trigger paths change.",
12
+ scope: "changes",
13
+ requiresConfig: true,
14
+ handler: async ({ entries, config }) => {
15
+ if (!config) {
16
+ throw new TypeError("RequireCompanionChanges requires config.");
17
+ }
18
+ const trigger = compilePattern(config.trigger);
19
+ const companion = compilePattern(config.companion);
20
+ const triggers = [
21
+ ...new Set(entries
22
+ .filter((entry) => entry.status !== "unchanged")
23
+ .flatMap((entry) => (entry.status === "renamed"
24
+ ? [entry.previousPath, entry.path]
25
+ : [entry.path]).filter((path) => matchesPath(trigger, path)))),
26
+ ];
27
+ if (triggers.length === 0 ||
28
+ entries.some((entry) => entry.status !== "unchanged" &&
29
+ entry.status !== "deleted" &&
30
+ matchesPath(companion, entry.path))) {
31
+ return [];
32
+ }
33
+ return [
34
+ {
35
+ message: `Changes matching ${trigger} require a companion change matching ${companion}.`,
36
+ files: triggers,
37
+ manualFix: "Add, update, or rename a file into the companion pattern in the same change set. Deletions do not satisfy this rule.",
38
+ },
39
+ ];
40
+ },
41
+ };
42
+ //# sourceMappingURL=RequireCompanionChanges.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequireCompanionChanges.js","sourceRoot":"","sources":["../../src/policies/RequireCompanionChanges.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5D,SAAS,cAAc,CAAC,KAAc;IACrC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,YAAY,MAAM,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,SAAS,CAClB,+DAA+D,CAC/D,CAAC;IACH,CAAC;IACD,OAAO,cAAc,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,kEAAkE;AAClE,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACtC,IAAI,EAAE,yBAAyB;IAC/B,WAAW,EAAE,2DAA2D;IACxE,KAAK,EAAE,SAAS;IAChB,cAAc,EAAE,IAAI;IACpB,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE;QACtC,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAC;QACjE,CAAC;QACD,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAG;YAChB,GAAG,IAAI,GAAG,CACT,OAAO;iBACL,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,WAAW,CAAC;iBAC/C,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAClB,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS;gBAC1B,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC;gBAClC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CACd,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAC9C,CACF;SACD,CAAC;QACF,IACC,QAAQ,CAAC,MAAM,KAAK,CAAC;YACrB,OAAO,CAAC,IAAI,CACX,CAAC,KAAK,EAAE,EAAE,CACT,KAAK,CAAC,MAAM,KAAK,WAAW;gBAC5B,KAAK,CAAC,MAAM,KAAK,SAAS;gBAC1B,WAAW,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CACnC,EACA,CAAC;YACF,OAAO,EAAE,CAAC;QACX,CAAC;QACD,OAAO;YACN;gBACC,OAAO,EAAE,oBAAoB,OAAO,wCAAwC,SAAS,GAAG;gBACxF,KAAK,EAAE,QAAQ;gBACf,SAAS,EACR,sHAAsH;aACvH;SACD,CAAC;IACH,CAAC;CAIA,CAAC","sourcesContent":["import { exclusionRegex, matchesPath } from \"../context.js\";\nimport type { RepositoryPolicyDefinition } from \"../policy.js\";\n\nfunction compilePattern(value: unknown): RegExp {\n\tif (typeof value !== \"string\" && !(value instanceof RegExp)) {\n\t\tthrow new TypeError(\n\t\t\t\"Trigger and companion must be regex strings or RegExp values.\",\n\t\t);\n\t}\n\treturn exclusionRegex(value);\n}\n\n/** Require a related update when trigger paths change. @public */\nexport const RequireCompanionChanges = {\n\tname: \"RequireCompanionChanges\",\n\tdescription: \"Requires a related file change when trigger paths change.\",\n\tscope: \"changes\",\n\trequiresConfig: true,\n\thandler: async ({ entries, config }) => {\n\t\tif (!config) {\n\t\t\tthrow new TypeError(\"RequireCompanionChanges requires config.\");\n\t\t}\n\t\tconst trigger = compilePattern(config.trigger);\n\t\tconst companion = compilePattern(config.companion);\n\t\tconst triggers = [\n\t\t\t...new Set(\n\t\t\t\tentries\n\t\t\t\t\t.filter((entry) => entry.status !== \"unchanged\")\n\t\t\t\t\t.flatMap((entry) =>\n\t\t\t\t\t\t(entry.status === \"renamed\"\n\t\t\t\t\t\t\t? [entry.previousPath, entry.path]\n\t\t\t\t\t\t\t: [entry.path]\n\t\t\t\t\t\t).filter((path) => matchesPath(trigger, path)),\n\t\t\t\t\t),\n\t\t\t),\n\t\t];\n\t\tif (\n\t\t\ttriggers.length === 0 ||\n\t\t\tentries.some(\n\t\t\t\t(entry) =>\n\t\t\t\t\tentry.status !== \"unchanged\" &&\n\t\t\t\t\tentry.status !== \"deleted\" &&\n\t\t\t\t\tmatchesPath(companion, entry.path),\n\t\t\t)\n\t\t) {\n\t\t\treturn [];\n\t\t}\n\t\treturn [\n\t\t\t{\n\t\t\t\tmessage: `Changes matching ${trigger} require a companion change matching ${companion}.`,\n\t\t\t\tfiles: triggers,\n\t\t\t\tmanualFix:\n\t\t\t\t\t\"Add, update, or rename a file into the companion pattern in the same change set. Deletions do not satisfy this rule.\",\n\t\t\t},\n\t\t];\n\t},\n} satisfies RepositoryPolicyDefinition<{\n\ttrigger: string | RegExp;\n\tcompanion: string | RegExp;\n}>;\n"]}
@@ -1,8 +1,8 @@
1
- import type { PolicyDefinition } from "../policy.js";
1
+ import type { PolicyFinding } from "../policy.js";
2
2
  /**
3
3
  * Policy settings for the RequiredGitignorePatterns repo policy.
4
4
  *
5
- * @alpha
5
+ * @public
6
6
  */
7
7
  export interface RequiredGitignorePatternsSettings {
8
8
  /**
@@ -10,7 +10,9 @@ export interface RequiredGitignorePatternsSettings {
10
10
  * Each pattern can be a string or an object with pattern and comment.
11
11
  */
12
12
  patterns: Array<string | {
13
+ /** Literal .gitignore entry to require. */
13
14
  pattern: string;
15
+ /** Comment inserted before the entry when fixing the file. */
14
16
  comment?: string;
15
17
  }>;
16
18
  }
@@ -18,7 +20,12 @@ export interface RequiredGitignorePatternsSettings {
18
20
  * A repo policy that ensures .gitignore contains required patterns to prevent
19
21
  * committing sensitive files, dependencies, and build artifacts.
20
22
  *
21
- * @alpha
23
+ * @public
22
24
  */
23
- export declare const RequiredGitignorePatterns: PolicyDefinition<RequiredGitignorePatternsSettings>;
25
+ export declare const RequiredGitignorePatterns: {
26
+ name: string;
27
+ description: string;
28
+ match: RegExp;
29
+ handler: ({ file, root, resolve, config }: import("../policy.js").PolicyArgs<RequiredGitignorePatternsSettings>) => Promise<PolicyFinding[]>;
30
+ };
24
31
  //# sourceMappingURL=RequiredGitignorePatterns.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RequiredGitignorePatterns.d.ts","sourceRoot":"","sources":["../../src/policies/RequiredGitignorePatterns.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACX,gBAAgB,EAGhB,MAAM,cAAc,CAAC;AAEtB;;;;GAIG;AACH,MAAM,WAAW,iCAAiC;IACjD;;;OAGG;IACH,QAAQ,EAAE,KAAK,CAAC,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChE;AAyMD;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,EAAE,gBAAgB,CAAC,iCAAiC,CAgBvF,CAAC"}
1
+ {"version":3,"file":"RequiredGitignorePatterns.d.ts","sourceRoot":"","sources":["../../src/policies/RequiredGitignorePatterns.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAwB,aAAa,EAAE,MAAM,cAAc,CAAC;AACxE;;;;GAIG;AACH,MAAM,WAAW,iCAAiC;IACjD;;;OAGG;IACH,QAAQ,EAAE,KAAK,CACZ,MAAM,GACN;QACA,2CAA2C;QAC3C,OAAO,EAAE,MAAM,CAAC;QAChB,8DAA8D;QAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;KAChB,CACH,CAAC;CACF;AAgPD;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB;;;;;CAe6B,CAAC"}
@@ -1,6 +1,5 @@
1
1
  import { readFile, writeFile } from "node:fs/promises";
2
2
  import path from "pathe";
3
- import { makePolicyDefinition } from "../makePolicy.js";
4
3
  /**
5
4
  * Default patterns that should typically be in .gitignore files.
6
5
  */
@@ -90,35 +89,30 @@ function createGitignoreContent(patterns) {
90
89
  /**
91
90
  * Handle the case when .gitignore exists.
92
91
  */
93
- async function handleExistingGitignore(filePath, patterns, file, resolve) {
92
+ async function handleExistingGitignore(filePath, patterns, _file, resolve) {
94
93
  const gitignoreContent = await readFile(filePath, "utf-8");
95
94
  const lines = gitignoreContent.split("\n");
96
95
  const missingPatterns = findMissingPatterns(patterns, lines);
97
96
  if (missingPatterns.length === 0) {
98
- return true;
97
+ return [];
99
98
  }
100
- const result = {
101
- name: RequiredGitignorePatterns.name,
102
- file,
103
- autoFixable: true,
104
- errorMessages: [
105
- `Missing required .gitignore patterns: ${missingPatterns.map((p) => (typeof p === "string" ? p : p.pattern)).join(", ")}`,
106
- ],
107
- };
99
+ const result = [
100
+ `Missing required .gitignore patterns: ${missingPatterns.map((p) => (typeof p === "string" ? p : p.pattern)).join(", ")}`,
101
+ ].map((message) => ({ message, fixStatus: "available" }));
108
102
  if (resolve) {
109
- const fixResult = {
110
- ...result,
111
- resolved: false,
112
- };
103
+ const fixResult = result.map((finding) => ({
104
+ ...finding,
105
+ fixStatus: "failed",
106
+ }));
113
107
  try {
114
108
  const newContent = addPatternsToContent(gitignoreContent, missingPatterns);
115
109
  await writeFile(filePath, newContent);
116
- fixResult.resolved = true;
110
+ for (const finding of fixResult) {
111
+ finding.fixStatus = "fixed";
112
+ }
117
113
  }
118
114
  catch (error) {
119
- fixResult.errorMessages = [
120
- `Failed to update .gitignore: ${error.message}`,
121
- ];
115
+ fixResult.splice(0, fixResult.length, ...[`Failed to update .gitignore: ${error.message}`].map((message) => ({ ...fixResult[0], message })));
122
116
  }
123
117
  return fixResult;
124
118
  }
@@ -127,27 +121,26 @@ async function handleExistingGitignore(filePath, patterns, file, resolve) {
127
121
  /**
128
122
  * Handle the case when .gitignore doesn't exist.
129
123
  */
130
- async function handleMissingGitignore(filePath, patterns, file, resolve) {
131
- const result = {
132
- name: RequiredGitignorePatterns.name,
133
- file,
134
- autoFixable: true,
135
- errorMessages: ["No .gitignore file found in repository root"],
136
- };
124
+ async function handleMissingGitignore(filePath, patterns, _file, resolve) {
125
+ const result = [
126
+ "No .gitignore file found in repository root",
127
+ ].map((message) => ({ message, fixStatus: "available" }));
137
128
  if (resolve) {
138
- const fixResult = {
139
- ...result,
140
- resolved: false,
141
- };
129
+ const fixResult = result.map((finding) => ({
130
+ ...finding,
131
+ fixStatus: "failed",
132
+ }));
142
133
  try {
143
134
  const content = createGitignoreContent(patterns);
144
135
  await writeFile(filePath, content);
145
- fixResult.resolved = true;
136
+ for (const finding of fixResult) {
137
+ finding.fixStatus = "fixed";
138
+ }
146
139
  }
147
140
  catch (writeError) {
148
- fixResult.errorMessages = [
141
+ fixResult.splice(0, fixResult.length, ...[
149
142
  `Failed to create .gitignore: ${writeError.message}`,
150
- ];
143
+ ].map((message) => ({ ...fixResult[0], message })));
151
144
  }
152
145
  return fixResult;
153
146
  }
@@ -157,9 +150,9 @@ async function handleMissingGitignore(filePath, patterns, file, resolve) {
157
150
  * A repo policy that ensures .gitignore contains required patterns to prevent
158
151
  * committing sensitive files, dependencies, and build artifacts.
159
152
  *
160
- * @alpha
153
+ * @public
161
154
  */
162
- export const RequiredGitignorePatterns = makePolicyDefinition({
155
+ export const RequiredGitignorePatterns = {
163
156
  name: "RequiredGitignorePatterns",
164
157
  description: "Ensures .gitignore contains required patterns to prevent committing sensitive files, dependencies, and build artifacts.",
165
158
  match: /^\.gitignore$/,
@@ -173,5 +166,5 @@ export const RequiredGitignorePatterns = makePolicyDefinition({
173
166
  return await handleMissingGitignore(filePath, patterns, file, resolve);
174
167
  }
175
168
  },
176
- });
169
+ };
177
170
  //# sourceMappingURL=RequiredGitignorePatterns.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RequiredGitignorePatterns.js","sourceRoot":"","sources":["../../src/policies/RequiredGitignorePatterns.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"pathe\";\nimport { makePolicyDefinition } from \"../makePolicy.js\";\nimport type {\n\tPolicyDefinition,\n\tPolicyFailure,\n\tPolicyFixResult,\n} from \"../policy.js\";\n\n/**\n * Policy settings for the RequiredGitignorePatterns repo policy.\n *\n * @alpha\n */\nexport interface RequiredGitignorePatternsSettings {\n\t/**\n\t * Array of patterns that must be present in .gitignore.\n\t * Each pattern can be a string or an object with pattern and comment.\n\t */\n\tpatterns: Array<string | { pattern: string; comment?: string }>;\n}\n\n/**\n * Default patterns that should typically be in .gitignore files.\n */\nconst DEFAULT_PATTERNS = [\n\t{ pattern: \"node_modules/\", comment: \"Dependencies\" },\n\t{ pattern: \".env\", comment: \"Environment files\" },\n\t{ pattern: \".env.*\", comment: \"Environment files\" },\n\t{ pattern: \"!.env.example\", comment: \"Allow example env file\" },\n\t{ pattern: \"dist/\", comment: \"Build output\" },\n\t{ pattern: \"build/\", comment: \"Build output\" },\n\t{ pattern: \".DS_Store\", comment: \"macOS system files\" },\n\t{ pattern: \"Thumbs.db\", comment: \"Windows system files\" },\n];\n\n/**\n * Check if a pattern exists in gitignore content.\n * Handles patterns with inline comments (e.g., \"node_modules/ # comment\").\n */\nfunction patternExists(lines: string[], pattern: string): boolean {\n\treturn lines.some((line) => {\n\t\tconst trimmed = line.trim();\n\t\t// Remove inline comments (everything after # that's not escaped)\n\t\tconst withoutComment = trimmed.split(\"#\")[0]?.trim() ?? \"\";\n\t\treturn (\n\t\t\twithoutComment === pattern ||\n\t\t\ttrimmed === pattern ||\n\t\t\ttrimmed.startsWith(`${pattern} `) ||\n\t\t\ttrimmed.startsWith(`${pattern}\\t`)\n\t\t);\n\t});\n}\n\n/**\n * Find missing patterns in gitignore content.\n */\nfunction findMissingPatterns(\n\tpatterns: Array<string | { pattern: string; comment?: string }>,\n\tlines: string[],\n): Array<string | { pattern: string; comment?: string }> {\n\tconst missingPatterns: Array<string | { pattern: string; comment?: string }> =\n\t\t[];\n\n\tfor (const patternConfig of patterns) {\n\t\tconst pattern =\n\t\t\ttypeof patternConfig === \"string\" ? patternConfig : patternConfig.pattern;\n\n\t\tif (!patternExists(lines, pattern)) {\n\t\t\tmissingPatterns.push(patternConfig);\n\t\t}\n\t}\n\n\treturn missingPatterns;\n}\n\n/**\n * Add patterns to gitignore content.\n */\nfunction addPatternsToContent(\n\tcontent: string,\n\tmissingPatterns: Array<string | { pattern: string; comment?: string }>,\n): string {\n\tlet newContent = content;\n\n\t// Ensure file ends with newline\n\tif (!newContent.endsWith(\"\\n\")) {\n\t\tnewContent += \"\\n\";\n\t}\n\n\t// Add a section header if we're adding patterns\n\tif (missingPatterns.length > 0) {\n\t\tnewContent += \"\\n# Added by repopo RequiredGitignorePatterns policy\\n\";\n\t}\n\n\t// Add each missing pattern\n\tfor (const patternConfig of missingPatterns) {\n\t\tif (typeof patternConfig === \"string\") {\n\t\t\tnewContent += `${patternConfig}\\n`;\n\t\t} else {\n\t\t\tif (patternConfig.comment) {\n\t\t\t\tnewContent += `# ${patternConfig.comment}\\n`;\n\t\t\t}\n\t\t\tnewContent += `${patternConfig.pattern}\\n`;\n\t\t}\n\t}\n\n\treturn newContent;\n}\n\n/**\n * Create gitignore content from scratch.\n */\nfunction createGitignoreContent(\n\tpatterns: Array<string | { pattern: string; comment?: string }>,\n): string {\n\tlet content = \"# Generated by repopo RequiredGitignorePatterns policy\\n\\n\";\n\n\tfor (const patternConfig of patterns) {\n\t\tif (typeof patternConfig === \"string\") {\n\t\t\tcontent += `${patternConfig}\\n`;\n\t\t} else {\n\t\t\tif (patternConfig.comment) {\n\t\t\t\tcontent += `# ${patternConfig.comment}\\n`;\n\t\t\t}\n\t\t\tcontent += `${patternConfig.pattern}\\n`;\n\t\t}\n\t}\n\n\treturn content;\n}\n\n/**\n * Handle the case when .gitignore exists.\n */\nasync function handleExistingGitignore(\n\tfilePath: string,\n\tpatterns: Array<string | { pattern: string; comment?: string }>,\n\tfile: string,\n\tresolve: boolean,\n): Promise<true | PolicyFailure | PolicyFixResult> {\n\tconst gitignoreContent = await readFile(filePath, \"utf-8\");\n\tconst lines = gitignoreContent.split(\"\\n\");\n\tconst missingPatterns = findMissingPatterns(patterns, lines);\n\n\tif (missingPatterns.length === 0) {\n\t\treturn true;\n\t}\n\n\tconst result: PolicyFailure = {\n\t\tname: RequiredGitignorePatterns.name,\n\t\tfile,\n\t\tautoFixable: true,\n\t\terrorMessages: [\n\t\t\t`Missing required .gitignore patterns: ${missingPatterns.map((p) => (typeof p === \"string\" ? p : p.pattern)).join(\", \")}`,\n\t\t],\n\t};\n\n\tif (resolve) {\n\t\tconst fixResult: PolicyFixResult = {\n\t\t\t...result,\n\t\t\tresolved: false,\n\t\t};\n\n\t\ttry {\n\t\t\tconst newContent = addPatternsToContent(\n\t\t\t\tgitignoreContent,\n\t\t\t\tmissingPatterns,\n\t\t\t);\n\t\t\tawait writeFile(filePath, newContent);\n\t\t\tfixResult.resolved = true;\n\t\t} catch (error: unknown) {\n\t\t\tfixResult.errorMessages = [\n\t\t\t\t`Failed to update .gitignore: ${(error as Error).message}`,\n\t\t\t];\n\t\t}\n\n\t\treturn fixResult;\n\t}\n\n\treturn result;\n}\n\n/**\n * Handle the case when .gitignore doesn't exist.\n */\nasync function handleMissingGitignore(\n\tfilePath: string,\n\tpatterns: Array<string | { pattern: string; comment?: string }>,\n\tfile: string,\n\tresolve: boolean,\n): Promise<PolicyFailure | PolicyFixResult> {\n\tconst result: PolicyFailure = {\n\t\tname: RequiredGitignorePatterns.name,\n\t\tfile,\n\t\tautoFixable: true,\n\t\terrorMessages: [\"No .gitignore file found in repository root\"],\n\t};\n\n\tif (resolve) {\n\t\tconst fixResult: PolicyFixResult = {\n\t\t\t...result,\n\t\t\tresolved: false,\n\t\t};\n\n\t\ttry {\n\t\t\tconst content = createGitignoreContent(patterns);\n\t\t\tawait writeFile(filePath, content);\n\t\t\tfixResult.resolved = true;\n\t\t} catch (writeError: unknown) {\n\t\t\tfixResult.errorMessages = [\n\t\t\t\t`Failed to create .gitignore: ${(writeError as Error).message}`,\n\t\t\t];\n\t\t}\n\n\t\treturn fixResult;\n\t}\n\n\treturn result;\n}\n\n/**\n * A repo policy that ensures .gitignore contains required patterns to prevent\n * committing sensitive files, dependencies, and build artifacts.\n *\n * @alpha\n */\nexport const RequiredGitignorePatterns: PolicyDefinition<RequiredGitignorePatternsSettings> =\n\tmakePolicyDefinition({\n\t\tname: \"RequiredGitignorePatterns\",\n\t\tdescription:\n\t\t\t\"Ensures .gitignore contains required patterns to prevent committing sensitive files, dependencies, and build artifacts.\",\n\t\tmatch: /^\\.gitignore$/,\n\t\thandler: async ({ file, root, resolve, config }) => {\n\t\t\tconst patterns = config?.patterns ?? DEFAULT_PATTERNS;\n\t\t\tconst filePath = path.join(root, file);\n\n\t\t\ttry {\n\t\t\t\treturn await handleExistingGitignore(filePath, patterns, file, resolve);\n\t\t\t} catch (_error: unknown) {\n\t\t\t\treturn await handleMissingGitignore(filePath, patterns, file, resolve);\n\t\t\t}\n\t\t},\n\t});\n"]}
1
+ {"version":3,"file":"RequiredGitignorePatterns.js","sourceRoot":"","sources":["../../src/policies/RequiredGitignorePatterns.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"pathe\";\nimport type { FilePolicyDefinition, PolicyFinding } from \"../policy.js\";\n/**\n * Policy settings for the RequiredGitignorePatterns repo policy.\n *\n * @public\n */\nexport interface RequiredGitignorePatternsSettings {\n\t/**\n\t * Array of patterns that must be present in .gitignore.\n\t * Each pattern can be a string or an object with pattern and comment.\n\t */\n\tpatterns: Array<\n\t\t| string\n\t\t| {\n\t\t\t\t/** Literal .gitignore entry to require. */\n\t\t\t\tpattern: string;\n\t\t\t\t/** Comment inserted before the entry when fixing the file. */\n\t\t\t\tcomment?: string;\n\t\t }\n\t>;\n}\n\n/**\n * Default patterns that should typically be in .gitignore files.\n */\nconst DEFAULT_PATTERNS = [\n\t{ pattern: \"node_modules/\", comment: \"Dependencies\" },\n\t{ pattern: \".env\", comment: \"Environment files\" },\n\t{ pattern: \".env.*\", comment: \"Environment files\" },\n\t{ pattern: \"!.env.example\", comment: \"Allow example env file\" },\n\t{ pattern: \"dist/\", comment: \"Build output\" },\n\t{ pattern: \"build/\", comment: \"Build output\" },\n\t{ pattern: \".DS_Store\", comment: \"macOS system files\" },\n\t{ pattern: \"Thumbs.db\", comment: \"Windows system files\" },\n];\n\n/**\n * Check if a pattern exists in gitignore content.\n * Handles patterns with inline comments (e.g., \"node_modules/ # comment\").\n */\nfunction patternExists(lines: string[], pattern: string): boolean {\n\treturn lines.some((line) => {\n\t\tconst trimmed = line.trim();\n\t\t// Remove inline comments (everything after # that's not escaped)\n\t\tconst withoutComment = trimmed.split(\"#\")[0]?.trim() ?? \"\";\n\t\treturn (\n\t\t\twithoutComment === pattern ||\n\t\t\ttrimmed === pattern ||\n\t\t\ttrimmed.startsWith(`${pattern} `) ||\n\t\t\ttrimmed.startsWith(`${pattern}\\t`)\n\t\t);\n\t});\n}\n\n/**\n * Find missing patterns in gitignore content.\n */\nfunction findMissingPatterns(\n\tpatterns: Array<\n\t\t| string\n\t\t| {\n\t\t\t\tpattern: string;\n\t\t\t\tcomment?: string;\n\t\t }\n\t>,\n\tlines: string[],\n): Array<\n\t| string\n\t| {\n\t\t\tpattern: string;\n\t\t\tcomment?: string;\n\t }\n> {\n\tconst missingPatterns: Array<\n\t\t| string\n\t\t| {\n\t\t\t\tpattern: string;\n\t\t\t\tcomment?: string;\n\t\t }\n\t> = [];\n\tfor (const patternConfig of patterns) {\n\t\tconst pattern =\n\t\t\ttypeof patternConfig === \"string\" ? patternConfig : patternConfig.pattern;\n\n\t\tif (!patternExists(lines, pattern)) {\n\t\t\tmissingPatterns.push(patternConfig);\n\t\t}\n\t}\n\n\treturn missingPatterns;\n}\n\n/**\n * Add patterns to gitignore content.\n */\nfunction addPatternsToContent(\n\tcontent: string,\n\tmissingPatterns: Array<\n\t\t| string\n\t\t| {\n\t\t\t\tpattern: string;\n\t\t\t\tcomment?: string;\n\t\t }\n\t>,\n): string {\n\tlet newContent = content;\n\n\t// Ensure file ends with newline\n\tif (!newContent.endsWith(\"\\n\")) {\n\t\tnewContent += \"\\n\";\n\t}\n\n\t// Add a section header if we're adding patterns\n\tif (missingPatterns.length > 0) {\n\t\tnewContent += \"\\n# Added by repopo RequiredGitignorePatterns policy\\n\";\n\t}\n\n\t// Add each missing pattern\n\tfor (const patternConfig of missingPatterns) {\n\t\tif (typeof patternConfig === \"string\") {\n\t\t\tnewContent += `${patternConfig}\\n`;\n\t\t} else {\n\t\t\tif (patternConfig.comment) {\n\t\t\t\tnewContent += `# ${patternConfig.comment}\\n`;\n\t\t\t}\n\t\t\tnewContent += `${patternConfig.pattern}\\n`;\n\t\t}\n\t}\n\n\treturn newContent;\n}\n\n/**\n * Create gitignore content from scratch.\n */\nfunction createGitignoreContent(\n\tpatterns: Array<\n\t\t| string\n\t\t| {\n\t\t\t\tpattern: string;\n\t\t\t\tcomment?: string;\n\t\t }\n\t>,\n): string {\n\tlet content = \"# Generated by repopo RequiredGitignorePatterns policy\\n\\n\";\n\n\tfor (const patternConfig of patterns) {\n\t\tif (typeof patternConfig === \"string\") {\n\t\t\tcontent += `${patternConfig}\\n`;\n\t\t} else {\n\t\t\tif (patternConfig.comment) {\n\t\t\t\tcontent += `# ${patternConfig.comment}\\n`;\n\t\t\t}\n\t\t\tcontent += `${patternConfig.pattern}\\n`;\n\t\t}\n\t}\n\n\treturn content;\n}\n\n/**\n * Handle the case when .gitignore exists.\n */\nasync function handleExistingGitignore(\n\tfilePath: string,\n\tpatterns: Array<\n\t\t| string\n\t\t| {\n\t\t\t\tpattern: string;\n\t\t\t\tcomment?: string;\n\t\t }\n\t>,\n\t_file: string,\n\tresolve: boolean,\n): Promise<PolicyFinding[]> {\n\tconst gitignoreContent = await readFile(filePath, \"utf-8\");\n\tconst lines = gitignoreContent.split(\"\\n\");\n\tconst missingPatterns = findMissingPatterns(patterns, lines);\n\n\tif (missingPatterns.length === 0) {\n\t\treturn [];\n\t}\n\tconst result: PolicyFinding[] = [\n\t\t`Missing required .gitignore patterns: ${missingPatterns.map((p) => (typeof p === \"string\" ? p : p.pattern)).join(\", \")}`,\n\t].map((message) => ({ message, fixStatus: \"available\" }));\n\tif (resolve) {\n\t\tconst fixResult: PolicyFinding[] = result.map((finding) => ({\n\t\t\t...finding,\n\t\t\tfixStatus: \"failed\",\n\t\t}));\n\t\ttry {\n\t\t\tconst newContent = addPatternsToContent(\n\t\t\t\tgitignoreContent,\n\t\t\t\tmissingPatterns,\n\t\t\t);\n\t\t\tawait writeFile(filePath, newContent);\n\t\t\tfor (const finding of fixResult) {\n\t\t\t\tfinding.fixStatus = \"fixed\";\n\t\t\t}\n\t\t} catch (error: unknown) {\n\t\t\tfixResult.splice(\n\t\t\t\t0,\n\t\t\t\tfixResult.length,\n\t\t\t\t...[`Failed to update .gitignore: ${(error as Error).message}`].map(\n\t\t\t\t\t(message) => ({ ...fixResult[0], message }),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\treturn fixResult;\n\t}\n\n\treturn result;\n}\n\n/**\n * Handle the case when .gitignore doesn't exist.\n */\nasync function handleMissingGitignore(\n\tfilePath: string,\n\tpatterns: Array<\n\t\t| string\n\t\t| {\n\t\t\t\tpattern: string;\n\t\t\t\tcomment?: string;\n\t\t }\n\t>,\n\t_file: string,\n\tresolve: boolean,\n): Promise<PolicyFinding[]> {\n\tconst result: PolicyFinding[] = [\n\t\t\"No .gitignore file found in repository root\",\n\t].map((message) => ({ message, fixStatus: \"available\" }));\n\tif (resolve) {\n\t\tconst fixResult: PolicyFinding[] = result.map((finding) => ({\n\t\t\t...finding,\n\t\t\tfixStatus: \"failed\",\n\t\t}));\n\t\ttry {\n\t\t\tconst content = createGitignoreContent(patterns);\n\t\t\tawait writeFile(filePath, content);\n\t\t\tfor (const finding of fixResult) {\n\t\t\t\tfinding.fixStatus = \"fixed\";\n\t\t\t}\n\t\t} catch (writeError: unknown) {\n\t\t\tfixResult.splice(\n\t\t\t\t0,\n\t\t\t\tfixResult.length,\n\t\t\t\t...[\n\t\t\t\t\t`Failed to create .gitignore: ${(writeError as Error).message}`,\n\t\t\t\t].map((message) => ({ ...fixResult[0], message })),\n\t\t\t);\n\t\t}\n\n\t\treturn fixResult;\n\t}\n\n\treturn result;\n}\n\n/**\n * A repo policy that ensures .gitignore contains required patterns to prevent\n * committing sensitive files, dependencies, and build artifacts.\n *\n * @public\n */\nexport const RequiredGitignorePatterns = {\n\tname: \"RequiredGitignorePatterns\",\n\tdescription:\n\t\t\"Ensures .gitignore contains required patterns to prevent committing sensitive files, dependencies, and build artifacts.\",\n\tmatch: /^\\.gitignore$/,\n\thandler: async ({ file, root, resolve, config }) => {\n\t\tconst patterns = config?.patterns ?? DEFAULT_PATTERNS;\n\t\tconst filePath = path.join(root, file);\n\n\t\ttry {\n\t\t\treturn await handleExistingGitignore(filePath, patterns, file, resolve);\n\t\t} catch (_error: unknown) {\n\t\t\treturn await handleMissingGitignore(filePath, patterns, file, resolve);\n\t\t}\n\t},\n} satisfies FilePolicyDefinition<RequiredGitignorePatternsSettings>;\n"]}
@@ -12,13 +12,13 @@
12
12
  * { lint: "biome lint ." }
13
13
  * ```
14
14
  *
15
- * @alpha
15
+ * @public
16
16
  */
17
17
  export type RequiredScriptEntry = string | Record<string, string>;
18
18
  /**
19
19
  * Configuration for the RequiredScripts policy.
20
20
  *
21
- * @alpha
21
+ * @public
22
22
  */
23
23
  export interface RequiredScriptsConfig {
24
24
  /**
@@ -53,19 +53,21 @@ export interface RequiredScriptsConfig {
53
53
  *
54
54
  * @example
55
55
  * ```typescript
56
- * import { policy } from "repopo";
56
+ * import { makePolicy } from "repopo";
57
57
  * import { RequiredScripts } from "repopo/policies";
58
58
  *
59
- * policy(RequiredScripts, {
59
+ * makePolicy(RequiredScripts, { config: {
60
60
  * scripts: [
61
61
  * "test", // Must exist, no auto-fix
62
62
  * { lint: "biome lint ." }, // Must exist, auto-fix adds default if missing
63
63
  * { clean: "rimraf dist esm" }, // Must exist, auto-fix adds default if missing
64
64
  * ],
65
- * })
65
+ * } })
66
66
  * ```
67
67
  *
68
- * @alpha
68
+ * @public
69
69
  */
70
- export declare const RequiredScripts: import("../policy.js").PolicyShape<RequiredScriptsConfig | undefined>;
70
+ export declare const RequiredScripts: import("../policy.js").FilePolicyDefinition<RequiredScriptsConfig | undefined> & {
71
+ requiresConfig: true;
72
+ };
71
73
  //# sourceMappingURL=RequiredScripts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RequiredScripts.d.ts","sourceRoot":"","sources":["../../src/policies/RequiredScripts.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAElE;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACrC;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,EAAE,mBAAmB,EAAE,CAAC;CAC/B;AAoFD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,eAAe,uEA2D1B,CAAC"}
1
+ {"version":3,"file":"RequiredScripts.d.ts","sourceRoot":"","sources":["../../src/policies/RequiredScripts.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAElE;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACrC;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,EAAE,mBAAmB,EAAE,CAAC;CAC/B;AA4FD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,eAAe;;CA0D1B,CAAC"}