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
@@ -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":"AAIA;;;;;;;;;;;;;;;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"}
@@ -1,4 +1,5 @@
1
1
  import jsonfile from "jsonfile";
2
+ import { resolve as resolvePath } from "pathe";
2
3
  import { definePackagePolicy } from "../policyDefiners/definePackagePolicy.js";
3
4
  const POLICY_NAME = "RequiredScripts";
4
5
  /**
@@ -60,61 +61,61 @@ async function fixMissingScripts(json, file, missingWithDefaults, existingScript
60
61
  *
61
62
  * @example
62
63
  * ```typescript
63
- * import { policy } from "repopo";
64
+ * import { makePolicy } from "repopo";
64
65
  * import { RequiredScripts } from "repopo/policies";
65
66
  *
66
- * policy(RequiredScripts, {
67
+ * makePolicy(RequiredScripts, { config: {
67
68
  * scripts: [
68
69
  * "test", // Must exist, no auto-fix
69
70
  * { lint: "biome lint ." }, // Must exist, auto-fix adds default if missing
70
71
  * { clean: "rimraf dist esm" }, // Must exist, auto-fix adds default if missing
71
72
  * ],
72
- * })
73
+ * } })
73
74
  * ```
74
75
  *
75
- * @alpha
76
+ * @public
76
77
  */
77
78
  export const RequiredScripts = definePackagePolicy({
79
+ requiresConfig: true,
78
80
  name: POLICY_NAME,
79
81
  description: "Validates that required scripts exist in package.json.",
80
- handler: async (json, { file, resolve, config }) => {
82
+ handler: async (json, { file, root, resolve, config }) => {
81
83
  if (config === undefined || config.scripts.length === 0) {
82
- return true;
84
+ return [];
83
85
  }
84
86
  const scripts = json.scripts ?? {};
85
87
  const validation = validateRequiredScripts(scripts, config.scripts);
86
88
  if (validation.missingScripts.length === 0) {
87
- return true;
89
+ return [];
88
90
  }
89
91
  const hasAutoFixableErrors = validation.missingWithDefaults.length > 0;
90
92
  if (resolve && hasAutoFixableErrors) {
91
93
  try {
92
- const fixedScripts = await fixMissingScripts(json, file, validation.missingWithDefaults, scripts);
94
+ const fixedScripts = await fixMissingScripts(json, resolvePath(root, file), validation.missingWithDefaults, scripts);
93
95
  // Check if there are still missing scripts (those without defaults)
94
96
  const stillMissing = validation.missingScripts.filter((name) => !fixedScripts.includes(name));
95
- return {
96
- name: POLICY_NAME,
97
- file,
98
- resolved: stillMissing.length === 0,
99
- errorMessages: stillMissing.length > 0
100
- ? [
101
- `Fixed scripts: ${fixedScripts.join(", ")}. Still missing: ${stillMissing.join(", ")}`,
102
- ]
103
- : [`Fixed scripts: ${fixedScripts.join(", ")}`],
104
- };
97
+ return [
98
+ ...fixedScripts.map((name) => ({
99
+ message: `Fixed scripts: ${name}`,
100
+ fixStatus: "fixed",
101
+ })),
102
+ ...stillMissing.map((name) => ({
103
+ message: `Still missing: ${name}`,
104
+ })),
105
+ ];
105
106
  }
106
107
  catch {
107
108
  // Fall through to return regular failure
108
109
  }
109
110
  }
110
- return {
111
- name: POLICY_NAME,
112
- file,
113
- autoFixable: hasAutoFixableErrors,
114
- errorMessages: [
115
- `Missing required scripts:\n\t${validation.missingScripts.join("\n\t")}`,
116
- ],
117
- };
111
+ return validation.missingScripts.map((name) => ({
112
+ message: `Missing required scripts:\n\t${name}`,
113
+ fixStatus: validation.missingWithDefaults.some((entry) => entry.name === name)
114
+ ? resolve
115
+ ? "failed"
116
+ : "available"
117
+ : undefined,
118
+ }));
118
119
  },
119
120
  });
120
121
  //# sourceMappingURL=RequiredScripts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RequiredScripts.js","sourceRoot":"","sources":["../../src/policies/RequiredScripts.ts"],"names":[],"mappings":"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","sourcesContent":["import jsonfile from \"jsonfile\";\nimport type { PackageJson } from \"type-fest\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\n/**\n * A required script entry. Can be either:\n * - A string (script name only, no default value)\n * - An object with a single key-value pair (script name → default value for auto-fix)\n *\n * @example\n * ```typescript\n * // Script must exist, no auto-fix available\n * \"test\"\n *\n * // Script must exist, auto-fix will add this value if missing\n * { lint: \"biome lint .\" }\n * ```\n *\n * @alpha\n */\nexport type RequiredScriptEntry = string | Record<string, string>;\n\n/**\n * Configuration for the RequiredScripts policy.\n *\n * @alpha\n */\nexport interface RequiredScriptsConfig {\n\t/**\n\t * Scripts that must be present in package.json.\n\t *\n\t * @remarks\n\t * Each entry can be:\n\t * - A string: Script must exist, no auto-fix available, content not validated\n\t * - An object `{ scriptName: \"default value\" }`: Script must exist, auto-fix adds the\n\t * default value if missing, but existing scripts with different content still pass\n\t *\n\t * @example\n\t * ```typescript\n\t * scripts: [\n\t * \"test\", // Must exist, no auto-fix\n\t * { lint: \"biome lint .\" }, // Must exist, auto-fix available\n\t * { clean: \"rimraf dist esm\" }, // Must exist, auto-fix available\n\t * ]\n\t * ```\n\t */\n\tscripts: RequiredScriptEntry[];\n}\n\nconst POLICY_NAME = \"RequiredScripts\";\n\ninterface ParsedEntry {\n\tname: string;\n\tdefaultValue?: string;\n}\n\n/**\n * Extracts script name and optional default value from a RequiredScriptEntry.\n */\nfunction parseRequiredEntry(entry: RequiredScriptEntry): ParsedEntry {\n\tif (typeof entry === \"string\") {\n\t\treturn { name: entry };\n\t}\n\tconst keys = Object.keys(entry);\n\tif (keys.length !== 1) {\n\t\tthrow new Error(\n\t\t\t`Invalid required script entry: expected single key-value pair, got ${keys.length} keys`,\n\t\t);\n\t}\n\t// biome-ignore lint/style/noNonNullAssertion: we verified length is 1\n\tconst name = keys[0]!;\n\tconst defaultValue = entry[name];\n\treturn defaultValue !== undefined ? { name, defaultValue } : { name };\n}\n\ninterface ValidationResult {\n\tmissingScripts: string[];\n\tmissingWithDefaults: Array<{ name: string; defaultValue: string }>;\n}\n\nfunction validateRequiredScripts(\n\tscripts: Record<string, string | undefined>,\n\trequiredEntries: RequiredScriptEntry[],\n): ValidationResult {\n\tconst missingScripts: string[] = [];\n\tconst missingWithDefaults: Array<{ name: string; defaultValue: string }> = [];\n\n\tfor (const entry of requiredEntries) {\n\t\tconst { name, defaultValue } = parseRequiredEntry(entry);\n\t\tif (!Object.hasOwn(scripts, name)) {\n\t\t\tmissingScripts.push(name);\n\t\t\tif (defaultValue !== undefined) {\n\t\t\t\tmissingWithDefaults.push({ name, defaultValue });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { missingScripts, missingWithDefaults };\n}\n\nasync function fixMissingScripts(\n\tjson: PackageJson,\n\tfile: string,\n\tmissingWithDefaults: Array<{ name: string; defaultValue: string }>,\n\texistingScripts: Record<string, string | undefined>,\n): Promise<string[]> {\n\tconst updatedScripts: Record<string, string> = {};\n\n\t// Copy existing scripts\n\tfor (const [key, value] of Object.entries(existingScripts)) {\n\t\tif (value !== undefined) {\n\t\t\tupdatedScripts[key] = value;\n\t\t}\n\t}\n\n\t// Add missing scripts with defaults\n\tconst fixedScripts: string[] = [];\n\tfor (const { name, defaultValue } of missingWithDefaults) {\n\t\tupdatedScripts[name] = defaultValue;\n\t\tfixedScripts.push(name);\n\t}\n\n\tawait jsonfile.writeFile(\n\t\tfile,\n\t\t{ ...json, scripts: updatedScripts },\n\t\t{ spaces: 2 },\n\t);\n\n\treturn fixedScripts;\n}\n\n/**\n * A policy that validates required scripts exist in package.json.\n *\n * @remarks\n * Use this policy when you want to ensure specific scripts are present.\n * Scripts can be specified with optional default values that enable auto-fix.\n *\n * Note: This policy only checks for script presence. It does NOT validate\n * the script's content. Use ExactScripts for content validation.\n *\n * @example\n * ```typescript\n * import { policy } from \"repopo\";\n * import { RequiredScripts } from \"repopo/policies\";\n *\n * policy(RequiredScripts, {\n * scripts: [\n * \"test\", // Must exist, no auto-fix\n * { lint: \"biome lint .\" }, // Must exist, auto-fix adds default if missing\n * { clean: \"rimraf dist esm\" }, // Must exist, auto-fix adds default if missing\n * ],\n * })\n * ```\n *\n * @alpha\n */\nexport const RequiredScripts = definePackagePolicy<\n\tPackageJson,\n\tRequiredScriptsConfig | undefined\n>({\n\tname: POLICY_NAME,\n\tdescription: \"Validates that required scripts exist in package.json.\",\n\thandler: async (json, { file, resolve, config }) => {\n\t\tif (config === undefined || config.scripts.length === 0) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst scripts = json.scripts ?? {};\n\t\tconst validation = validateRequiredScripts(scripts, config.scripts);\n\n\t\tif (validation.missingScripts.length === 0) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst hasAutoFixableErrors = validation.missingWithDefaults.length > 0;\n\n\t\tif (resolve && hasAutoFixableErrors) {\n\t\t\ttry {\n\t\t\t\tconst fixedScripts = await fixMissingScripts(\n\t\t\t\t\tjson,\n\t\t\t\t\tfile,\n\t\t\t\t\tvalidation.missingWithDefaults,\n\t\t\t\t\tscripts,\n\t\t\t\t);\n\n\t\t\t\t// Check if there are still missing scripts (those without defaults)\n\t\t\t\tconst stillMissing = validation.missingScripts.filter(\n\t\t\t\t\t(name) => !fixedScripts.includes(name),\n\t\t\t\t);\n\n\t\t\t\treturn {\n\t\t\t\t\tname: POLICY_NAME,\n\t\t\t\t\tfile,\n\t\t\t\t\tresolved: stillMissing.length === 0,\n\t\t\t\t\terrorMessages:\n\t\t\t\t\t\tstillMissing.length > 0\n\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t`Fixed scripts: ${fixedScripts.join(\", \")}. Still missing: ${stillMissing.join(\", \")}`,\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t: [`Fixed scripts: ${fixedScripts.join(\", \")}`],\n\t\t\t\t};\n\t\t\t} catch {\n\t\t\t\t// Fall through to return regular failure\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tname: POLICY_NAME,\n\t\t\tfile,\n\t\t\tautoFixable: hasAutoFixableErrors,\n\t\t\terrorMessages: [\n\t\t\t\t`Missing required scripts:\\n\\t${validation.missingScripts.join(\"\\n\\t\")}`,\n\t\t\t],\n\t\t};\n\t},\n});\n"]}
1
+ {"version":3,"file":"RequiredScripts.js","sourceRoot":"","sources":["../../src/policies/RequiredScripts.ts"],"names":[],"mappings":"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","sourcesContent":["import jsonfile from \"jsonfile\";\nimport { resolve as resolvePath } from \"pathe\";\nimport type { PackageJson } from \"type-fest\";\nimport { definePackagePolicy } from \"../policyDefiners/definePackagePolicy.js\";\n\n/**\n * A required script entry. Can be either:\n * - A string (script name only, no default value)\n * - An object with a single key-value pair (script name → default value for auto-fix)\n *\n * @example\n * ```typescript\n * // Script must exist, no auto-fix available\n * \"test\"\n *\n * // Script must exist, auto-fix will add this value if missing\n * { lint: \"biome lint .\" }\n * ```\n *\n * @public\n */\nexport type RequiredScriptEntry = string | Record<string, string>;\n\n/**\n * Configuration for the RequiredScripts policy.\n *\n * @public\n */\nexport interface RequiredScriptsConfig {\n\t/**\n\t * Scripts that must be present in package.json.\n\t *\n\t * @remarks\n\t * Each entry can be:\n\t * - A string: Script must exist, no auto-fix available, content not validated\n\t * - An object `{ scriptName: \"default value\" }`: Script must exist, auto-fix adds the\n\t * default value if missing, but existing scripts with different content still pass\n\t *\n\t * @example\n\t * ```typescript\n\t * scripts: [\n\t * \"test\", // Must exist, no auto-fix\n\t * { lint: \"biome lint .\" }, // Must exist, auto-fix available\n\t * { clean: \"rimraf dist esm\" }, // Must exist, auto-fix available\n\t * ]\n\t * ```\n\t */\n\tscripts: RequiredScriptEntry[];\n}\n\nconst POLICY_NAME = \"RequiredScripts\";\n\ninterface ParsedEntry {\n\tname: string;\n\tdefaultValue?: string;\n}\n\n/**\n * Extracts script name and optional default value from a RequiredScriptEntry.\n */\nfunction parseRequiredEntry(entry: RequiredScriptEntry): ParsedEntry {\n\tif (typeof entry === \"string\") {\n\t\treturn { name: entry };\n\t}\n\tconst keys = Object.keys(entry);\n\tif (keys.length !== 1) {\n\t\tthrow new Error(\n\t\t\t`Invalid required script entry: expected single key-value pair, got ${keys.length} keys`,\n\t\t);\n\t}\n\t// biome-ignore lint/style/noNonNullAssertion: we verified length is 1\n\tconst name = keys[0]!;\n\tconst defaultValue = entry[name];\n\treturn defaultValue !== undefined ? { name, defaultValue } : { name };\n}\n\ninterface ValidationResult {\n\tmissingScripts: string[];\n\tmissingWithDefaults: Array<{\n\t\tname: string;\n\t\tdefaultValue: string;\n\t}>;\n}\n\nfunction validateRequiredScripts(\n\tscripts: Record<string, string | undefined>,\n\trequiredEntries: RequiredScriptEntry[],\n): ValidationResult {\n\tconst missingScripts: string[] = [];\n\tconst missingWithDefaults: Array<{\n\t\tname: string;\n\t\tdefaultValue: string;\n\t}> = [];\n\tfor (const entry of requiredEntries) {\n\t\tconst { name, defaultValue } = parseRequiredEntry(entry);\n\t\tif (!Object.hasOwn(scripts, name)) {\n\t\t\tmissingScripts.push(name);\n\t\t\tif (defaultValue !== undefined) {\n\t\t\t\tmissingWithDefaults.push({ name, defaultValue });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { missingScripts, missingWithDefaults };\n}\n\nasync function fixMissingScripts(\n\tjson: PackageJson,\n\tfile: string,\n\tmissingWithDefaults: Array<{\n\t\tname: string;\n\t\tdefaultValue: string;\n\t}>,\n\texistingScripts: Record<string, string | undefined>,\n): Promise<string[]> {\n\tconst updatedScripts: Record<string, string> = {};\n\n\t// Copy existing scripts\n\tfor (const [key, value] of Object.entries(existingScripts)) {\n\t\tif (value !== undefined) {\n\t\t\tupdatedScripts[key] = value;\n\t\t}\n\t}\n\n\t// Add missing scripts with defaults\n\tconst fixedScripts: string[] = [];\n\tfor (const { name, defaultValue } of missingWithDefaults) {\n\t\tupdatedScripts[name] = defaultValue;\n\t\tfixedScripts.push(name);\n\t}\n\n\tawait jsonfile.writeFile(\n\t\tfile,\n\t\t{ ...json, scripts: updatedScripts },\n\t\t{ spaces: 2 },\n\t);\n\n\treturn fixedScripts;\n}\n\n/**\n * A policy that validates required scripts exist in package.json.\n *\n * @remarks\n * Use this policy when you want to ensure specific scripts are present.\n * Scripts can be specified with optional default values that enable auto-fix.\n *\n * Note: This policy only checks for script presence. It does NOT validate\n * the script's content. Use ExactScripts for content validation.\n *\n * @example\n * ```typescript\n * import { makePolicy } from \"repopo\";\n * import { RequiredScripts } from \"repopo/policies\";\n *\n * makePolicy(RequiredScripts, { config: {\n * scripts: [\n * \"test\", // Must exist, no auto-fix\n * { lint: \"biome lint .\" }, // Must exist, auto-fix adds default if missing\n * { clean: \"rimraf dist esm\" }, // Must exist, auto-fix adds default if missing\n * ],\n * } })\n * ```\n *\n * @public\n */\nexport const RequiredScripts = definePackagePolicy<\n\tPackageJson,\n\tRequiredScriptsConfig | undefined\n>({\n\trequiresConfig: true,\n\tname: POLICY_NAME,\n\tdescription: \"Validates that required scripts exist in package.json.\",\n\thandler: async (json, { file, root, resolve, config }) => {\n\t\tif (config === undefined || config.scripts.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst scripts = json.scripts ?? {};\n\t\tconst validation = validateRequiredScripts(scripts, config.scripts);\n\n\t\tif (validation.missingScripts.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst hasAutoFixableErrors = validation.missingWithDefaults.length > 0;\n\n\t\tif (resolve && hasAutoFixableErrors) {\n\t\t\ttry {\n\t\t\t\tconst fixedScripts = await fixMissingScripts(\n\t\t\t\t\tjson,\n\t\t\t\t\tresolvePath(root, file),\n\t\t\t\t\tvalidation.missingWithDefaults,\n\t\t\t\t\tscripts,\n\t\t\t\t);\n\n\t\t\t\t// Check if there are still missing scripts (those without defaults)\n\t\t\t\tconst stillMissing = validation.missingScripts.filter(\n\t\t\t\t\t(name) => !fixedScripts.includes(name),\n\t\t\t\t);\n\t\t\t\treturn [\n\t\t\t\t\t...fixedScripts.map((name) => ({\n\t\t\t\t\t\tmessage: `Fixed scripts: ${name}`,\n\t\t\t\t\t\tfixStatus: \"fixed\" as const,\n\t\t\t\t\t})),\n\t\t\t\t\t...stillMissing.map((name) => ({\n\t\t\t\t\t\tmessage: `Still missing: ${name}`,\n\t\t\t\t\t})),\n\t\t\t\t];\n\t\t\t} catch {\n\t\t\t\t// Fall through to return regular failure\n\t\t\t}\n\t\t}\n\t\treturn validation.missingScripts.map((name) => ({\n\t\t\tmessage: `Missing required scripts:\\n\\t${name}`,\n\t\t\tfixStatus: validation.missingWithDefaults.some(\n\t\t\t\t(entry) => entry.name === name,\n\t\t\t)\n\t\t\t\t? resolve\n\t\t\t\t\t? \"failed\"\n\t\t\t\t\t: \"available\"\n\t\t\t\t: undefined,\n\t\t}));\n\t},\n});\n"]}
@@ -0,0 +1,24 @@
1
+ import type { FilePolicyDefinition } from "../policy.js";
2
+ /**
3
+ * Configuration for the RustDocExists policy.
4
+ *
5
+ * @public
6
+ */
7
+ export interface RustDocExistsConfig {
8
+ /**
9
+ * Files that must exist alongside the Cargo.toml.
10
+ * @defaultValue ["README.md"]
11
+ */
12
+ required?: string[];
13
+ /**
14
+ * Files that are recommended but not required. Missing ones produce warnings.
15
+ */
16
+ recommended?: string[];
17
+ }
18
+ /**
19
+ * A policy that validates documentation files exist for Rust crates.
20
+ *
21
+ * @public
22
+ */
23
+ export declare const RustDocExists: FilePolicyDefinition<RustDocExistsConfig>;
24
+ //# sourceMappingURL=RustDocExists.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RustDocExists.d.ts","sourceRoot":"","sources":["../../src/policies/RustDocExists.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAMzD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAID;;;;GAIG;AACH,eAAO,MAAM,aAAa,2CAkD4B,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { existsSync } from "node:fs";
2
+ import path from "pathe";
3
+ import { defineCargoPolicy, } from "../policyDefiners/defineCargoPolicy.js";
4
+ const DEFAULT_REQUIRED = ["README.md"];
5
+ /**
6
+ * A policy that validates documentation files exist for Rust crates.
7
+ *
8
+ * @public
9
+ */
10
+ export const RustDocExists = defineCargoPolicy({
11
+ name: "RustDocExists",
12
+ description: "Validates that documentation files (README.md, etc.) exist for Rust crates.",
13
+ handler: async (toml, { file, root, config }) => {
14
+ // Skip workspace root
15
+ if (toml.workspace !== undefined && toml.package === undefined) {
16
+ return [];
17
+ }
18
+ const dir = path.dirname(path.resolve(root, file));
19
+ const required = config?.required ?? DEFAULT_REQUIRED;
20
+ const recommended = config?.recommended ?? [];
21
+ const missingRequired = [];
22
+ const missingRecommended = [];
23
+ for (const fileName of required) {
24
+ if (!existsSync(path.join(dir, fileName))) {
25
+ missingRequired.push(fileName);
26
+ }
27
+ }
28
+ for (const fileName of recommended) {
29
+ if (!existsSync(path.join(dir, fileName))) {
30
+ missingRecommended.push(fileName);
31
+ }
32
+ }
33
+ const errors = [];
34
+ if (missingRequired.length > 0) {
35
+ errors.push(`Missing required documentation: ${missingRequired.join(", ")}`);
36
+ }
37
+ if (missingRecommended.length > 0) {
38
+ errors.push(`Missing recommended documentation: ${missingRecommended.join(", ")}`);
39
+ }
40
+ if (errors.length > 0) {
41
+ return errors.map((message) => ({
42
+ message,
43
+ manualFix: "Create the missing documentation files alongside Cargo.toml.",
44
+ }));
45
+ }
46
+ return [];
47
+ },
48
+ });
49
+ //# sourceMappingURL=RustDocExists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RustDocExists.js","sourceRoot":"","sources":["../../src/policies/RustDocExists.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,IAAI,MAAM,OAAO,CAAC;AAEzB,OAAO,EAEN,iBAAiB,GACjB,MAAM,wCAAwC,CAAC;AAoBhD,MAAM,gBAAgB,GAAG,CAAC,WAAW,CAAC,CAAC;AAEvC;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,iBAAiB,CAAC;IAC9C,IAAI,EAAE,eAAe;IACrB,WAAW,EACV,6EAA6E;IAC9E,OAAO,EAAE,KAAK,EAAE,IAAe,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;QAC1D,sBAAsB;QACtB,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAChE,OAAO,EAAE,CAAC;QACX,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAG,MAAM,EAAE,QAAQ,IAAI,gBAAgB,CAAC;QACtD,MAAM,WAAW,GAAG,MAAM,EAAE,WAAW,IAAI,EAAE,CAAC;QAE9C,MAAM,eAAe,GAAa,EAAE,CAAC;QACrC,MAAM,kBAAkB,GAAa,EAAE,CAAC;QAExC,KAAK,MAAM,QAAQ,IAAI,QAAQ,EAAE,CAAC;YACjC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;gBAC3C,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAChC,CAAC;QACF,CAAC;QAED,KAAK,MAAM,QAAQ,IAAI,WAAW,EAAE,CAAC;YACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;gBAC3C,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACnC,CAAC;QACF,CAAC;QAED,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,MAAM,CAAC,IAAI,CACV,mCAAmC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC/D,CAAC;QACH,CAAC;QACD,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,CACV,sCAAsC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACrE,CAAC;QACH,CAAC;QAED,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,8DAA8D;aAC/D,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,EAAE,CAAC;IACX,CAAC;CACD,CAAqD,CAAC","sourcesContent":["import { existsSync } from \"node:fs\";\nimport path from \"pathe\";\nimport type { FilePolicyDefinition } from \"../policy.js\";\nimport {\n\ttype CargoToml,\n\tdefineCargoPolicy,\n} from \"../policyDefiners/defineCargoPolicy.js\";\n\n/**\n * Configuration for the RustDocExists policy.\n *\n * @public\n */\nexport interface RustDocExistsConfig {\n\t/**\n\t * Files that must exist alongside the Cargo.toml.\n\t * @defaultValue [\"README.md\"]\n\t */\n\trequired?: string[];\n\n\t/**\n\t * Files that are recommended but not required. Missing ones produce warnings.\n\t */\n\trecommended?: string[];\n}\n\nconst DEFAULT_REQUIRED = [\"README.md\"];\n\n/**\n * A policy that validates documentation files exist for Rust crates.\n *\n * @public\n */\nexport const RustDocExists = defineCargoPolicy({\n\tname: \"RustDocExists\",\n\tdescription:\n\t\t\"Validates that documentation files (README.md, etc.) exist for Rust crates.\",\n\thandler: async (toml: CargoToml, { file, root, 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 dir = path.dirname(path.resolve(root, file));\n\t\tconst required = config?.required ?? DEFAULT_REQUIRED;\n\t\tconst recommended = config?.recommended ?? [];\n\n\t\tconst missingRequired: string[] = [];\n\t\tconst missingRecommended: string[] = [];\n\n\t\tfor (const fileName of required) {\n\t\t\tif (!existsSync(path.join(dir, fileName))) {\n\t\t\t\tmissingRequired.push(fileName);\n\t\t\t}\n\t\t}\n\n\t\tfor (const fileName of recommended) {\n\t\t\tif (!existsSync(path.join(dir, fileName))) {\n\t\t\t\tmissingRecommended.push(fileName);\n\t\t\t}\n\t\t}\n\n\t\tconst errors: string[] = [];\n\t\tif (missingRequired.length > 0) {\n\t\t\terrors.push(\n\t\t\t\t`Missing required documentation: ${missingRequired.join(\", \")}`,\n\t\t\t);\n\t\t}\n\t\tif (missingRecommended.length > 0) {\n\t\t\terrors.push(\n\t\t\t\t`Missing recommended documentation: ${missingRecommended.join(\", \")}`,\n\t\t\t);\n\t\t}\n\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\"Create the missing documentation files alongside Cargo.toml.\",\n\t\t\t}));\n\t\t}\n\t\treturn [];\n\t},\n}) satisfies FilePolicyDefinition<RustDocExistsConfig>;\n"]}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Configuration for the RustToolchainExists policy.
3
+ *
4
+ * @public
5
+ */
6
+ export interface RustToolchainExistsConfig {
7
+ /**
8
+ * Accepted file names for the toolchain file.
9
+ * @defaultValue ["rust-toolchain.toml", "rust-toolchain"]
10
+ */
11
+ acceptedNames?: string[];
12
+ }
13
+ /**
14
+ * A policy that requires a rust-toolchain.toml file for reproducible Rust builds.
15
+ *
16
+ * @public
17
+ */
18
+ export declare const RustToolchainExists: {
19
+ name: string;
20
+ description: string;
21
+ match: RegExp;
22
+ handler: ({ root, config }: import("../policy.js").PolicyArgs<RustToolchainExistsConfig>) => Promise<{
23
+ message: string;
24
+ manualFix: string;
25
+ }[]>;
26
+ };
27
+ //# sourceMappingURL=RustToolchainExists.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RustToolchainExists.d.ts","sourceRoot":"","sources":["../../src/policies/RustToolchainExists.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACzC;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAID;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;CAuB2B,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { existsSync } from "node:fs";
2
+ import path from "pathe";
3
+ const DEFAULT_NAMES = ["rust-toolchain.toml", "rust-toolchain"];
4
+ /**
5
+ * A policy that requires a rust-toolchain.toml file for reproducible Rust builds.
6
+ *
7
+ * @public
8
+ */
9
+ export const RustToolchainExists = {
10
+ name: "RustToolchainExists",
11
+ description: "Ensures a rust-toolchain.toml file exists for reproducible Rust builds.",
12
+ // Trigger on Cargo.toml to check once per project
13
+ match: /^Cargo\.toml$/,
14
+ handler: async ({ root, config }) => {
15
+ const names = config?.acceptedNames ?? DEFAULT_NAMES;
16
+ const hasToolchain = names.some((name) => existsSync(path.join(root, name)));
17
+ if (hasToolchain) {
18
+ return [];
19
+ }
20
+ return [
21
+ {
22
+ message: `No rust-toolchain file found. Expected one of: ${names.join(", ")}`,
23
+ manualFix: "Create a rust-toolchain.toml file specifying the Rust toolchain version.",
24
+ },
25
+ ];
26
+ },
27
+ };
28
+ //# sourceMappingURL=RustToolchainExists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RustToolchainExists.js","sourceRoot":"","sources":["../../src/policies/RustToolchainExists.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,IAAI,MAAM,OAAO,CAAC;AAezB,MAAM,aAAa,GAAG,CAAC,qBAAqB,EAAE,gBAAgB,CAAC,CAAC;AAEhE;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IAClC,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EACV,yEAAyE;IAC1E,kDAAkD;IAClD,KAAK,EAAE,eAAe;IACtB,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;QACnC,MAAM,KAAK,GAAG,MAAM,EAAE,aAAa,IAAI,aAAa,CAAC;QACrD,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CACxC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CACjC,CAAC;QAEF,IAAI,YAAY,EAAE,CAAC;YAClB,OAAO,EAAE,CAAC;QACX,CAAC;QACD,OAAO;YACN;gBACC,OAAO,EAAE,kDAAkD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBAC7E,SAAS,EACR,0EAA0E;aAC3E;SACD,CAAC;IACH,CAAC;CACyD,CAAC","sourcesContent":["import { existsSync } from \"node:fs\";\nimport path from \"pathe\";\nimport type { FilePolicyDefinition } from \"../policy.js\";\n/**\n * Configuration for the RustToolchainExists policy.\n *\n * @public\n */\nexport interface RustToolchainExistsConfig {\n\t/**\n\t * Accepted file names for the toolchain file.\n\t * @defaultValue [\"rust-toolchain.toml\", \"rust-toolchain\"]\n\t */\n\tacceptedNames?: string[];\n}\n\nconst DEFAULT_NAMES = [\"rust-toolchain.toml\", \"rust-toolchain\"];\n\n/**\n * A policy that requires a rust-toolchain.toml file for reproducible Rust builds.\n *\n * @public\n */\nexport const RustToolchainExists = {\n\tname: \"RustToolchainExists\",\n\tdescription:\n\t\t\"Ensures a rust-toolchain.toml file exists for reproducible Rust builds.\",\n\t// Trigger on Cargo.toml to check once per project\n\tmatch: /^Cargo\\.toml$/,\n\thandler: async ({ root, config }) => {\n\t\tconst names = config?.acceptedNames ?? DEFAULT_NAMES;\n\t\tconst hasToolchain = names.some((name) =>\n\t\t\texistsSync(path.join(root, name)),\n\t\t);\n\n\t\tif (hasToolchain) {\n\t\t\treturn [];\n\t\t}\n\t\treturn [\n\t\t\t{\n\t\t\t\tmessage: `No rust-toolchain file found. Expected one of: ${names.join(\", \")}`,\n\t\t\t\tmanualFix:\n\t\t\t\t\t\"Create a rust-toolchain.toml file specifying the Rust toolchain version.\",\n\t\t\t},\n\t\t];\n\t},\n} satisfies FilePolicyDefinition<RustToolchainExistsConfig>;\n"]}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Configuration for the RustfmtConfigExists policy.
3
+ *
4
+ * @public
5
+ */
6
+ export interface RustfmtConfigExistsConfig {
7
+ /**
8
+ * Accepted file names for the rustfmt config.
9
+ * @defaultValue ["rustfmt.toml", ".rustfmt.toml"]
10
+ */
11
+ acceptedNames?: string[];
12
+ }
13
+ /**
14
+ * A policy that requires a rustfmt.toml file for consistent Rust formatting.
15
+ *
16
+ * @public
17
+ */
18
+ export declare const RustfmtConfigExists: {
19
+ name: string;
20
+ description: string;
21
+ match: RegExp;
22
+ handler: ({ root, config }: import("../policy.js").PolicyArgs<RustfmtConfigExistsConfig>) => Promise<{
23
+ message: string;
24
+ manualFix: string;
25
+ }[]>;
26
+ };
27
+ //# sourceMappingURL=RustfmtConfigExists.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RustfmtConfigExists.d.ts","sourceRoot":"","sources":["../../src/policies/RustfmtConfigExists.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACzC;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAID;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;CAoB2B,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { existsSync } from "node:fs";
2
+ import path from "pathe";
3
+ const DEFAULT_NAMES = ["rustfmt.toml", ".rustfmt.toml"];
4
+ /**
5
+ * A policy that requires a rustfmt.toml file for consistent Rust formatting.
6
+ *
7
+ * @public
8
+ */
9
+ export const RustfmtConfigExists = {
10
+ name: "RustfmtConfigExists",
11
+ description: "Ensures a rustfmt.toml file exists for consistent Rust formatting.",
12
+ // Trigger on Cargo.toml to check once per project
13
+ match: /^Cargo\.toml$/,
14
+ handler: async ({ root, config }) => {
15
+ const names = config?.acceptedNames ?? DEFAULT_NAMES;
16
+ const hasConfig = names.some((name) => existsSync(path.join(root, name)));
17
+ if (hasConfig) {
18
+ return [];
19
+ }
20
+ return [
21
+ {
22
+ message: `No rustfmt config found. Expected one of: ${names.join(", ")}`,
23
+ manualFix: "Create a rustfmt.toml file to configure Rust formatting.",
24
+ },
25
+ ];
26
+ },
27
+ };
28
+ //# sourceMappingURL=RustfmtConfigExists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RustfmtConfigExists.js","sourceRoot":"","sources":["../../src/policies/RustfmtConfigExists.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,IAAI,MAAM,OAAO,CAAC;AAezB,MAAM,aAAa,GAAG,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;AAExD;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IAClC,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EACV,oEAAoE;IACrE,kDAAkD;IAClD,KAAK,EAAE,eAAe;IACtB,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;QACnC,MAAM,KAAK,GAAG,MAAM,EAAE,aAAa,IAAI,aAAa,CAAC;QACrD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAE1E,IAAI,SAAS,EAAE,CAAC;YACf,OAAO,EAAE,CAAC;QACX,CAAC;QACD,OAAO;YACN;gBACC,OAAO,EAAE,6CAA6C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBACxE,SAAS,EAAE,0DAA0D;aACrE;SACD,CAAC;IACH,CAAC;CACyD,CAAC","sourcesContent":["import { existsSync } from \"node:fs\";\nimport path from \"pathe\";\nimport type { FilePolicyDefinition } from \"../policy.js\";\n/**\n * Configuration for the RustfmtConfigExists policy.\n *\n * @public\n */\nexport interface RustfmtConfigExistsConfig {\n\t/**\n\t * Accepted file names for the rustfmt config.\n\t * @defaultValue [\"rustfmt.toml\", \".rustfmt.toml\"]\n\t */\n\tacceptedNames?: string[];\n}\n\nconst DEFAULT_NAMES = [\"rustfmt.toml\", \".rustfmt.toml\"];\n\n/**\n * A policy that requires a rustfmt.toml file for consistent Rust formatting.\n *\n * @public\n */\nexport const RustfmtConfigExists = {\n\tname: \"RustfmtConfigExists\",\n\tdescription:\n\t\t\"Ensures a rustfmt.toml file exists for consistent Rust formatting.\",\n\t// Trigger on Cargo.toml to check once per project\n\tmatch: /^Cargo\\.toml$/,\n\thandler: async ({ root, config }) => {\n\t\tconst names = config?.acceptedNames ?? DEFAULT_NAMES;\n\t\tconst hasConfig = names.some((name) => existsSync(path.join(root, name)));\n\n\t\tif (hasConfig) {\n\t\t\treturn [];\n\t\t}\n\t\treturn [\n\t\t\t{\n\t\t\t\tmessage: `No rustfmt config found. Expected one of: ${names.join(\", \")}`,\n\t\t\t\tmanualFix: \"Create a rustfmt.toml file to configure Rust formatting.\",\n\t\t\t},\n\t\t];\n\t},\n} satisfies FilePolicyDefinition<RustfmtConfigExistsConfig>;\n"]}