@codefast/cli 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/README.md +66 -41
  3. package/dist/arrange/command.js +99 -136
  4. package/dist/arrange/domain/ast/collectors-cn.d.ts +2 -2
  5. package/dist/arrange/domain/ast/collectors-cn.js +2 -2
  6. package/dist/arrange/domain/ast/collectors-jsx.d.ts +2 -2
  7. package/dist/arrange/domain/ast/collectors-jsx.js +1 -1
  8. package/dist/arrange/domain/ast/collectors-tv.d.ts +2 -2
  9. package/dist/arrange/domain/ast/collectors-tv.js +5 -5
  10. package/dist/arrange/domain/ast/helpers.d.ts +2 -2
  11. package/dist/arrange/domain/ast/helpers.js +3 -4
  12. package/dist/arrange/domain/ast/simplify-targets.d.ts +1 -1
  13. package/dist/arrange/domain/ast/simplify-targets.js +23 -28
  14. package/dist/arrange/domain/ast/targets.d.ts +2 -2
  15. package/dist/arrange/domain/ast/targets.js +9 -9
  16. package/dist/arrange/{typescript-ast-translator.d.ts → domain/ast/translator.d.ts} +6 -5
  17. package/dist/arrange/{typescript-ast-translator.js → domain/ast/translator.js} +20 -23
  18. package/dist/arrange/domain/constants.d.ts +1 -1
  19. package/dist/arrange/domain/grouping-service.d.ts +2 -2
  20. package/dist/arrange/domain/grouping-service.js +3 -3
  21. package/dist/arrange/domain/grouping.js +3 -3
  22. package/dist/arrange/domain/imports.d.ts +1 -1
  23. package/dist/arrange/domain/imports.js +2 -2
  24. package/dist/arrange/domain/source-text-formatters.js +1 -1
  25. package/dist/arrange/domain/tailwind-token.js +1 -1
  26. package/dist/arrange/domain/token-classifier.d.ts +1 -1
  27. package/dist/arrange/domain/token-classifier.js +2 -2
  28. package/dist/arrange/domain/types.d.ts +3 -3
  29. package/dist/arrange/group/cli-result.d.ts +7 -0
  30. package/dist/arrange/group/cli-result.js +12 -0
  31. package/dist/arrange/group/cli-schema.d.ts +17 -0
  32. package/dist/arrange/group/cli-schema.js +13 -0
  33. package/dist/arrange/group/output.d.ts +7 -0
  34. package/dist/arrange/group/output.js +10 -0
  35. package/dist/arrange/group/suggest.d.ts +8 -0
  36. package/dist/arrange/{suggest.js → group/suggest.js} +2 -2
  37. package/dist/arrange/inspect/cli-result.d.ts +7 -0
  38. package/dist/arrange/inspect/cli-result.js +8 -0
  39. package/dist/arrange/inspect/cli-schema.d.ts +15 -0
  40. package/dist/arrange/inspect/cli-schema.js +9 -0
  41. package/dist/arrange/{domain → inspect/domain}/analyze-service.d.ts +2 -2
  42. package/dist/arrange/{domain → inspect/domain}/analyze-service.js +7 -7
  43. package/dist/arrange/inspect/output.d.ts +7 -0
  44. package/dist/arrange/inspect/output.js +42 -0
  45. package/dist/arrange/inspect/run.d.ts +10 -0
  46. package/dist/arrange/{analyze.js → inspect/run.js} +7 -7
  47. package/dist/arrange/prepare.d.ts +13 -0
  48. package/dist/arrange/{workspace.js → prepare.js} +9 -12
  49. package/dist/arrange/regroup/cli-result.d.ts +13 -0
  50. package/dist/arrange/regroup/cli-result.js +23 -0
  51. package/dist/arrange/regroup/cli-schema.d.ts +20 -0
  52. package/dist/arrange/regroup/cli-schema.js +14 -0
  53. package/dist/arrange/regroup/output.d.ts +14 -0
  54. package/dist/arrange/regroup/output.js +72 -0
  55. package/dist/arrange/{process-file.d.ts → regroup/process-file.d.ts} +3 -3
  56. package/dist/arrange/{process-file.js → regroup/process-file.js} +3 -3
  57. package/dist/arrange/regroup/run.d.ts +11 -0
  58. package/dist/arrange/{sync.js → regroup/run.js} +5 -5
  59. package/dist/arrange/resolve-target.d.ts +2 -2
  60. package/dist/arrange/resolve-target.js +2 -2
  61. package/dist/arrange/scan-target.d.ts +2 -2
  62. package/dist/arrange/scan-target.js +3 -3
  63. package/dist/arrange/simplify/cli-result.d.ts +7 -0
  64. package/dist/arrange/simplify/cli-result.js +8 -0
  65. package/dist/arrange/simplify/cli-schema.d.ts +17 -0
  66. package/dist/arrange/simplify/cli-schema.js +11 -0
  67. package/dist/arrange/simplify/fold-targets.d.ts +13 -0
  68. package/dist/arrange/simplify/fold-targets.js +139 -0
  69. package/dist/arrange/simplify/output.d.ts +7 -0
  70. package/dist/arrange/simplify/output.js +15 -0
  71. package/dist/arrange/simplify/process-file.d.ts +13 -0
  72. package/dist/arrange/simplify/process-file.js +49 -0
  73. package/dist/arrange/simplify/run.d.ts +14 -0
  74. package/dist/arrange/simplify/run.js +38 -0
  75. package/dist/arrange/simplify/variant-classname-probe.d.ts +35 -0
  76. package/dist/arrange/simplify/variant-classname-probe.js +95 -0
  77. package/dist/arrange/source-parse.d.ts +1 -1
  78. package/dist/arrange/source-parse.js +3 -3
  79. package/dist/audit/command.js +152 -212
  80. package/dist/audit/comments/cli-result.d.ts +13 -0
  81. package/dist/audit/comments/cli-result.js +22 -0
  82. package/dist/audit/comments/cli-schema.d.ts +19 -0
  83. package/dist/audit/comments/cli-schema.js +13 -0
  84. package/dist/audit/comments/output.d.ts +7 -0
  85. package/dist/audit/comments/output.js +27 -0
  86. package/dist/audit/comments/prepare.d.ts +16 -0
  87. package/dist/audit/comments/prepare.js +12 -0
  88. package/dist/audit/{run-comments.d.ts → comments/run.d.ts} +5 -5
  89. package/dist/audit/{run-comments.js → comments/run.js} +9 -9
  90. package/dist/audit/display-names/cli-result.d.ts +13 -0
  91. package/dist/audit/display-names/cli-result.js +22 -0
  92. package/dist/audit/display-names/cli-schema.d.ts +18 -0
  93. package/dist/audit/display-names/cli-schema.js +12 -0
  94. package/dist/audit/{domain → display-names/domain}/display-names.d.ts +1 -1
  95. package/dist/audit/display-names/output.d.ts +7 -0
  96. package/dist/audit/display-names/output.js +21 -0
  97. package/dist/audit/display-names/prepare.d.ts +16 -0
  98. package/dist/audit/display-names/prepare.js +12 -0
  99. package/dist/audit/display-names/run.d.ts +14 -0
  100. package/dist/audit/{run-display-names.js → display-names/run.js} +5 -5
  101. package/dist/audit/domain/types.d.ts +43 -0
  102. package/dist/audit/imports/cli-result.d.ts +13 -0
  103. package/dist/audit/imports/cli-result.js +22 -0
  104. package/dist/audit/imports/cli-schema.d.ts +18 -0
  105. package/dist/audit/imports/cli-schema.js +12 -0
  106. package/dist/audit/{domain → imports/domain}/import-policy.d.ts +3 -3
  107. package/dist/audit/{domain → imports/domain}/import-policy.js +4 -11
  108. package/dist/audit/imports/output.d.ts +7 -0
  109. package/dist/audit/imports/output.js +21 -0
  110. package/dist/audit/imports/prepare.d.ts +16 -0
  111. package/dist/audit/imports/prepare.js +12 -0
  112. package/dist/audit/imports/run.d.ts +14 -0
  113. package/dist/audit/{run-imports.js → imports/run.js} +6 -6
  114. package/dist/audit/links/cli-result.d.ts +13 -0
  115. package/dist/audit/links/cli-result.js +22 -0
  116. package/dist/audit/links/cli-schema.d.ts +18 -0
  117. package/dist/audit/links/cli-schema.js +12 -0
  118. package/dist/audit/{domain → links/domain}/markdown-links.d.ts +3 -3
  119. package/dist/audit/{domain → links/domain}/markdown-links.js +22 -8
  120. package/dist/audit/links/output.d.ts +7 -0
  121. package/dist/audit/links/output.js +21 -0
  122. package/dist/audit/links/prepare.d.ts +16 -0
  123. package/dist/audit/links/prepare.js +12 -0
  124. package/dist/audit/links/run.d.ts +14 -0
  125. package/dist/audit/{run-links.js → links/run.js} +4 -4
  126. package/dist/audit/prepare.d.ts +13 -52
  127. package/dist/audit/prepare.js +13 -136
  128. package/dist/audit/publish/cli-result.d.ts +13 -0
  129. package/dist/audit/publish/cli-result.js +22 -0
  130. package/dist/audit/publish/cli-schema.d.ts +18 -0
  131. package/dist/audit/publish/cli-schema.js +12 -0
  132. package/dist/audit/publish/domain/legacy-subpath.d.ts +8 -0
  133. package/dist/audit/publish/domain/legacy-subpath.js +22 -0
  134. package/dist/audit/publish/output.d.ts +7 -0
  135. package/dist/audit/publish/output.js +24 -0
  136. package/dist/audit/publish/prepare.d.ts +16 -0
  137. package/dist/audit/publish/prepare.js +12 -0
  138. package/dist/audit/publish/run.d.ts +14 -0
  139. package/dist/audit/publish/run.js +62 -0
  140. package/dist/audit/rtl/cli-result.d.ts +13 -0
  141. package/dist/audit/rtl/cli-result.js +22 -0
  142. package/dist/audit/rtl/cli-schema.d.ts +18 -0
  143. package/dist/audit/rtl/cli-schema.js +12 -0
  144. package/dist/audit/{domain → rtl/domain}/audit-file.d.ts +1 -1
  145. package/dist/audit/{domain → rtl/domain}/audit-file.js +2 -2
  146. package/dist/audit/{domain → rtl/domain}/tokenize.d.ts +1 -1
  147. package/dist/audit/rtl/output.d.ts +7 -0
  148. package/dist/audit/rtl/output.js +21 -0
  149. package/dist/audit/rtl/prepare.d.ts +13 -0
  150. package/dist/audit/rtl/prepare.js +41 -0
  151. package/dist/audit/rtl/run.d.ts +14 -0
  152. package/dist/audit/{run.js → rtl/run.js} +4 -4
  153. package/dist/bin.js +1 -1
  154. package/dist/cli.js +5 -5
  155. package/dist/core/cli/command-pipeline.d.ts +90 -0
  156. package/dist/core/cli/command-pipeline.js +83 -0
  157. package/dist/core/cli/format-error.d.ts +1 -1
  158. package/dist/core/cli/global-options.d.ts +1 -1
  159. package/dist/core/cli/global-options.js +1 -1
  160. package/dist/core/cli/resolve-root.d.ts +9 -0
  161. package/dist/core/cli/resolve-root.js +16 -0
  162. package/dist/core/cli/result-handle.d.ts +3 -9
  163. package/dist/core/cli/result-handle.js +4 -17
  164. package/dist/core/config/define-config.d.ts +1 -1
  165. package/dist/core/config/loader.d.ts +3 -3
  166. package/dist/core/config/loader.js +2 -2
  167. package/dist/core/config/schema.d.ts +1 -1
  168. package/dist/core/config/schema.js +1 -1
  169. package/dist/core/config/warnings.js +1 -1
  170. package/dist/core/config.d.ts +5 -5
  171. package/dist/core/config.js +4 -4
  172. package/dist/core/filesystem/{port.d.ts → filesystem.d.ts} +1 -1
  173. package/dist/core/filesystem/node.d.ts +3 -3
  174. package/dist/core/filesystem/node.js +1 -1
  175. package/dist/core/schema-parse.d.ts +2 -2
  176. package/dist/core/schema-parse.js +2 -2
  177. package/dist/core/source-text-edit.d.ts +14 -0
  178. package/dist/core/source-text-edit.js +22 -0
  179. package/dist/core/workspace/markdown-walk.d.ts +2 -2
  180. package/dist/core/workspace/markdown-walk.js +1 -1
  181. package/dist/core/workspace/package-version.d.ts +2 -2
  182. package/dist/core/workspace/package-version.js +2 -2
  183. package/dist/core/workspace/resolver.d.ts +3 -3
  184. package/dist/core/workspace/resolver.js +5 -5
  185. package/dist/core/workspace/source-walk.d.ts +2 -2
  186. package/dist/core/workspace/source-walk.js +1 -1
  187. package/dist/core/workspace/typescript-walk.d.ts +2 -2
  188. package/dist/core/workspace/typescript-walk.js +1 -1
  189. package/dist/core/workspace/walk-files.d.ts +2 -2
  190. package/dist/core/workspace/walk-files.js +1 -1
  191. package/dist/index.d.ts +3 -3
  192. package/dist/index.js +2 -2
  193. package/dist/mirror/cli-result.d.ts +1 -1
  194. package/dist/mirror/cli-result.js +1 -1
  195. package/dist/mirror/cli-schema.d.ts +2 -2
  196. package/dist/mirror/cli-schema.js +1 -1
  197. package/dist/mirror/command.js +36 -65
  198. package/dist/mirror/dist-filesystem-node.d.ts +8 -0
  199. package/dist/mirror/{dist-filesystem-impl.js → dist-filesystem-node.js} +3 -3
  200. package/dist/mirror/domain/dirent-guard.d.ts +1 -1
  201. package/dist/mirror/domain/exports.d.ts +2 -2
  202. package/dist/mirror/domain/exports.js +1 -1
  203. package/dist/mirror/domain/types.d.ts +59 -2
  204. package/dist/mirror/output.d.ts +1 -3
  205. package/dist/mirror/output.js +127 -2
  206. package/dist/mirror/package-path.d.ts +5 -5
  207. package/dist/mirror/package-path.js +3 -3
  208. package/dist/mirror/prepare.d.ts +6 -6
  209. package/dist/mirror/prepare.js +8 -12
  210. package/dist/mirror/run.d.ts +12 -0
  211. package/dist/mirror/{sync.js → run.js} +7 -7
  212. package/dist/mirror/supplement-exports.d.ts +3 -3
  213. package/dist/mirror/supplement-exports.js +2 -2
  214. package/dist/mirror/sync-workspace-package.d.ts +4 -4
  215. package/dist/mirror/sync-workspace-package.js +11 -14
  216. package/dist/mirror/write-exports.d.ts +3 -3
  217. package/dist/mirror/write-exports.js +3 -3
  218. package/dist/pack-slim/cli-result.d.ts +1 -1
  219. package/dist/pack-slim/cli-result.js +1 -1
  220. package/dist/pack-slim/cli-schema.d.ts +1 -1
  221. package/dist/pack-slim/cli-schema.js +1 -1
  222. package/dist/pack-slim/command.js +36 -71
  223. package/dist/pack-slim/domain/transform.d.ts +22 -1
  224. package/dist/pack-slim/domain/transform.js +65 -8
  225. package/dist/pack-slim/output.d.ts +1 -1
  226. package/dist/pack-slim/output.js +1 -1
  227. package/dist/pack-slim/prepare.d.ts +21 -0
  228. package/dist/pack-slim/prepare.js +14 -0
  229. package/dist/pack-slim/{sync.d.ts → run.d.ts} +6 -6
  230. package/dist/pack-slim/{sync.js → run.js} +5 -5
  231. package/dist/pack-slim/working-tree.d.ts +2 -2
  232. package/dist/pack-slim/working-tree.js +2 -2
  233. package/dist/tag/cli-result.d.ts +8 -2
  234. package/dist/tag/cli-result.js +15 -2
  235. package/dist/tag/cli-schema.d.ts +4 -4
  236. package/dist/tag/cli-schema.js +3 -4
  237. package/dist/tag/command.js +34 -61
  238. package/dist/tag/domain/skip-filter.d.ts +13 -0
  239. package/dist/tag/domain/skip-filter.js +29 -0
  240. package/dist/tag/domain/types.d.ts +22 -2
  241. package/dist/tag/domain/version-summary.d.ts +13 -0
  242. package/dist/tag/domain/version-summary.js +24 -0
  243. package/dist/tag/output.d.ts +4 -4
  244. package/dist/tag/output.js +7 -10
  245. package/dist/tag/prepare.d.ts +5 -5
  246. package/dist/tag/prepare.js +5 -5
  247. package/dist/tag/run.d.ts +10 -0
  248. package/dist/tag/{sync.js → run.js} +23 -53
  249. package/dist/tag/target/candidates.d.ts +8 -0
  250. package/dist/tag/{target-candidates.js → target/candidates.js} +3 -3
  251. package/dist/tag/{resolve-target-path.d.ts → target/resolve-path.d.ts} +2 -2
  252. package/dist/tag/target/runner.d.ts +8 -0
  253. package/dist/tag/{target-runner.js → target/runner.js} +3 -3
  254. package/dist/tag/{since-writer.d.ts → writer/since-writer.d.ts} +3 -3
  255. package/dist/tag/{since-writer.js → writer/since-writer.js} +1 -1
  256. package/dist/tag/{version-resolver.d.ts → writer/version-resolver.d.ts} +2 -2
  257. package/dist/tag/{version-resolver.js → writer/version-resolver.js} +1 -1
  258. package/package.json +15 -7
  259. package/dist/arrange/analyze.d.ts +0 -10
  260. package/dist/arrange/cli-schema.d.ts +0 -50
  261. package/dist/arrange/cli-schema.js +0 -34
  262. package/dist/arrange/output.d.ts +0 -26
  263. package/dist/arrange/output.js +0 -127
  264. package/dist/arrange/simplify-process-file.d.ts +0 -11
  265. package/dist/arrange/simplify-process-file.js +0 -30
  266. package/dist/arrange/simplify-sync.d.ts +0 -13
  267. package/dist/arrange/simplify-sync.js +0 -30
  268. package/dist/arrange/suggest.d.ts +0 -8
  269. package/dist/arrange/sync.d.ts +0 -11
  270. package/dist/arrange/workspace.d.ts +0 -13
  271. package/dist/audit/cli-schema.d.ts +0 -93
  272. package/dist/audit/cli-schema.js +0 -66
  273. package/dist/audit/output.d.ts +0 -91
  274. package/dist/audit/output.js +0 -213
  275. package/dist/audit/run-display-names.d.ts +0 -14
  276. package/dist/audit/run-imports.d.ts +0 -14
  277. package/dist/audit/run-links.d.ts +0 -14
  278. package/dist/audit/run.d.ts +0 -14
  279. package/dist/mirror/dist-filesystem-impl.d.ts +0 -8
  280. package/dist/mirror/sync-reporter.d.ts +0 -60
  281. package/dist/mirror/sync-reporter.js +0 -128
  282. package/dist/mirror/sync-types.d.ts +0 -43
  283. package/dist/mirror/sync-types.js +0 -1
  284. package/dist/mirror/sync.d.ts +0 -12
  285. package/dist/tag/sync.d.ts +0 -42
  286. package/dist/tag/target-candidates.d.ts +0 -8
  287. package/dist/tag/target-runner.d.ts +0 -8
  288. /package/dist/audit/{domain → comments/domain}/comment-content.d.ts +0 -0
  289. /package/dist/audit/{domain → comments/domain}/comment-content.js +0 -0
  290. /package/dist/audit/{domain → comments/domain}/comment-dividers.d.ts +0 -0
  291. /package/dist/audit/{domain → comments/domain}/comment-dividers.js +0 -0
  292. /package/dist/audit/{domain → comments/domain}/link-references.d.ts +0 -0
  293. /package/dist/audit/{domain → comments/domain}/link-references.js +0 -0
  294. /package/dist/audit/{domain → comments/domain}/since-versions.d.ts +0 -0
  295. /package/dist/audit/{domain → comments/domain}/since-versions.js +0 -0
  296. /package/dist/audit/{domain → comments/domain}/tsdoc-syntax.d.ts +0 -0
  297. /package/dist/audit/{domain → comments/domain}/tsdoc-syntax.js +0 -0
  298. /package/dist/audit/{domain → display-names/domain}/display-names.js +0 -0
  299. /package/dist/audit/{domain → rtl/domain}/mappings.d.ts +0 -0
  300. /package/dist/audit/{domain → rtl/domain}/mappings.js +0 -0
  301. /package/dist/audit/{domain → rtl/domain}/tokenize.js +0 -0
  302. /package/dist/core/filesystem/{port.js → filesystem.js} +0 -0
  303. /package/dist/tag/{resolve-target-path.js → target/resolve-path.js} +0 -0
@@ -0,0 +1,21 @@
1
+ import { logger } from "#core/logger";
2
+ /**
3
+ * Human-readable link audit report.
4
+ *
5
+ * @since 0.5.0
6
+ */
7
+ export function presentLinkAuditResult(result) {
8
+ for (const file of result.files) {
9
+ logger.out(`\n${file.relativePath}`);
10
+ for (const { line, raw, reason } of file.breakages) {
11
+ logger.out(` ${line}: ${raw} → ${reason}`);
12
+ }
13
+ }
14
+ const allowlistSuffix = result.allowlistedCount > 0 ? ` (${result.allowlistedCount} allowlisted)` : "";
15
+ if (result.breakageCount > 0) {
16
+ logger.out(`\n✖ ${result.breakageCount} broken link(s)${allowlistSuffix}`);
17
+ }
18
+ else {
19
+ logger.out(`✓ ${result.linkCount} repo-local link(s) across ${result.scannedFileCount} document(s) all resolve${allowlistSuffix}`);
20
+ }
21
+ }
@@ -0,0 +1,16 @@
1
+ import type { AuditCommandPrelude } from "#audit/prepare";
2
+ import type { AppError } from "#core/errors";
3
+ import type { Filesystem } from "#core/filesystem/filesystem";
4
+ import type { Result } from "#core/result";
5
+ /**
6
+ * Loads config and resolves the scan target for `audit links`.
7
+ *
8
+ * @remarks Defaults to the repo root rather than a configured path: a link audit that only covers one
9
+ * package cannot see the cross-package references that are the ones most likely to rot.
10
+ *
11
+ * @since 0.5.0
12
+ */
13
+ export declare function prepareLinkAudit(fs: Filesystem, args: {
14
+ readonly currentWorkingDirectory: string;
15
+ readonly rawTarget: string | undefined;
16
+ }): Promise<Result<AuditCommandPrelude, AppError>>;
@@ -0,0 +1,12 @@
1
+ import { prepareRepoRootAudit } from "#audit/prepare";
2
+ /**
3
+ * Loads config and resolves the scan target for `audit links`.
4
+ *
5
+ * @remarks Defaults to the repo root rather than a configured path: a link audit that only covers one
6
+ * package cannot see the cross-package references that are the ones most likely to rot.
7
+ *
8
+ * @since 0.5.0
9
+ */
10
+ export async function prepareLinkAudit(fs, args) {
11
+ return prepareRepoRootAudit(fs, args, (config) => config.audit?.links?.allowlist ?? []);
12
+ }
@@ -0,0 +1,14 @@
1
+ import type { LinkAuditResult } from "#audit/domain/types";
2
+ import { AppError } from "#core/errors";
3
+ import type { Filesystem } from "#core/filesystem/filesystem";
4
+ import type { Result } from "#core/result";
5
+ /**
6
+ * Reports markdown links that point at nothing — a missing path, or an anchor the target does not offer.
7
+ *
8
+ * @since 0.5.0
9
+ */
10
+ export declare function runLinkAudit(fs: Filesystem, args: {
11
+ readonly rootDir: string;
12
+ readonly targetPath: string;
13
+ readonly allowlist: ReadonlyArray<string>;
14
+ }): Result<LinkAuditResult, AppError>;
@@ -1,8 +1,8 @@
1
1
  import path from "node:path";
2
- import { collectMarkdownAnchors, scanMarkdownLinks } from "#/audit/domain/markdown-links";
3
- import { AppError, messageFrom } from "#/core/errors";
4
- import { err, ok } from "#/core/result";
5
- import { walkMarkdownFiles } from "#/core/workspace/markdown-walk";
2
+ import { collectMarkdownAnchors, scanMarkdownLinks } from "#audit/links/domain/markdown-links";
3
+ import { AppError, messageFrom } from "#core/errors";
4
+ import { err, ok } from "#core/result";
5
+ import { walkMarkdownFiles } from "#core/workspace/markdown-walk";
6
6
  /**
7
7
  * Reports markdown links that point at nothing — a missing path, or an anchor the target does not offer.
8
8
  *
@@ -1,70 +1,31 @@
1
- import { AppError } from "#/core/errors";
2
- import type { FilesystemPort } from "#/core/filesystem/port";
3
- import type { Result } from "#/core/result";
1
+ import type { CodefastConfig } from "#core/config/schema";
2
+ import { AppError } from "#core/errors";
3
+ import type { Filesystem } from "#core/filesystem/filesystem";
4
+ import type { Result } from "#core/result";
4
5
  /**
5
- * Shared prelude for `audit rtl`: repo root and the canonicalized scan target with its allowlist.
6
+ * Shared prelude for an audit: repo root and the canonicalized scan target with its allowlist.
6
7
  *
7
8
  * @since 0.5.0-canary.6
8
9
  */
9
- export type RtlAuditCommandPrelude = {
10
+ export type AuditCommandPrelude = {
10
11
  readonly rootDir: string;
11
12
  readonly targetPath: string;
12
13
  readonly allowlist: ReadonlyArray<string>;
13
14
  };
14
15
  /**
15
- * Loads config and resolves the scan target for `audit rtl`.
16
+ * Resolves a path that may be absolute or relative to `rootDir`.
16
17
  *
17
18
  * @since 0.5.0-canary.6
18
19
  */
19
- export declare function prepareRtlAudit(fs: FilesystemPort, args: {
20
- readonly currentWorkingDirectory: string;
21
- readonly rawTarget: string | undefined;
22
- }): Promise<Result<RtlAuditCommandPrelude, AppError>>;
23
- /**
24
- * Loads config and resolves the scan target for `audit links`.
25
- *
26
- * @remarks Defaults to the repo root rather than a configured path: a link audit that only covers one
27
- * package cannot see the cross-package references that are the ones most likely to rot.
28
- *
29
- * @since 0.5.0
30
- */
31
- export declare function prepareLinkAudit(fs: FilesystemPort, args: {
32
- readonly currentWorkingDirectory: string;
33
- readonly rawTarget: string | undefined;
34
- }): Promise<Result<RtlAuditCommandPrelude, AppError>>;
35
- /**
36
- * Loads config and resolves the scan target for `audit imports`.
37
- *
38
- * @remarks Defaults to the repo root: the import policy is repo-wide, and generated or vendored
39
- * trees are already excluded by the shared walk.
40
- *
41
- * @since 0.10.0
42
- */
43
- export declare function prepareImportsAudit(fs: FilesystemPort, args: {
44
- readonly currentWorkingDirectory: string;
45
- readonly rawTarget: string | undefined;
46
- }): Promise<Result<RtlAuditCommandPrelude, AppError>>;
47
- /**
48
- * Loads config and resolves the scan target for `audit comments`.
49
- *
50
- * @remarks Defaults to the repo root: a divider convention that only holds inside one package
51
- * is not a convention.
52
- *
53
- * @since 0.6.0
54
- */
55
- export declare function prepareCommentAudit(fs: FilesystemPort, args: {
56
- readonly currentWorkingDirectory: string;
57
- readonly rawTarget: string | undefined;
58
- }): Promise<Result<RtlAuditCommandPrelude, AppError>>;
20
+ export declare function resolveRepoRelativePath(rootDir: string, maybeRelative: string): string;
59
21
  /**
60
- * Loads config and resolves the scan target for `audit display-names`.
22
+ * Loads config and resolves the repo root as the scan target, taking the allowlist the caller selects.
61
23
  *
62
- * @remarks Defaults to the repo root: a display name collides across packages, so the convention
63
- * has to hold across them.
24
+ * @remarks Every repo-wide audit shares this prelude; only the config key its allowlist comes from differs.
64
25
  *
65
- * @since 0.9.0
26
+ * @since 0.11.0
66
27
  */
67
- export declare function prepareDisplayNameAudit(fs: FilesystemPort, args: {
28
+ export declare function prepareRepoRootAudit(fs: Filesystem, args: {
68
29
  readonly currentWorkingDirectory: string;
69
30
  readonly rawTarget: string | undefined;
70
- }): Promise<Result<RtlAuditCommandPrelude, AppError>>;
31
+ }, selectAllowlist: (config: CodefastConfig) => ReadonlyArray<string>): Promise<Result<AuditCommandPrelude, AppError>>;
@@ -1,146 +1,24 @@
1
- import { resolveRepoRelativePath } from "#/audit/cli-schema";
2
- import { loadCodefastConfig } from "#/core/config";
3
- import { AppError, messageFrom } from "#/core/errors";
4
- import { err, ok } from "#/core/result";
5
- import { resolveProjectRoot } from "#/core/workspace/resolver";
1
+ import path from "node:path";
2
+ import { loadCodefastConfig } from "#core/config";
3
+ import { AppError, messageFrom } from "#core/errors";
4
+ import { err, ok } from "#core/result";
5
+ import { resolveProjectRoot } from "#core/workspace/resolver";
6
6
  /**
7
- * Loads config and resolves the scan target for `audit rtl`.
7
+ * Resolves a path that may be absolute or relative to `rootDir`.
8
8
  *
9
9
  * @since 0.5.0-canary.6
10
10
  */
11
- export async function prepareRtlAudit(fs, args) {
12
- let rootDir;
13
- try {
14
- // Realpath so allowlist keys (`path.relative(rootDir, file)`) stay stable when cwd is a symlink.
15
- rootDir = fs.canonicalPathSync(resolveProjectRoot(args.currentWorkingDirectory, fs).rootDir);
16
- }
17
- catch (caughtError) {
18
- return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
19
- }
20
- const loadedOutcome = await loadCodefastConfig(rootDir, fs);
21
- if (!loadedOutcome.ok) {
22
- return loadedOutcome;
23
- }
24
- const { config } = loadedOutcome.value;
25
- const rtlConfig = config.audit?.rtl ?? {};
26
- const targetFromCli = args.rawTarget;
27
- const targetFromConfig = rtlConfig.target;
28
- const resolvedTargetInput = targetFromCli ?? targetFromConfig;
29
- if (resolvedTargetInput === undefined) {
30
- return err(new AppError("VALIDATION_ERROR", "Missing scan target: pass a path argument or set audit.rtl.target in codefast.config"));
31
- }
32
- const targetPath = resolveRepoRelativePath(targetFromCli !== undefined ? args.currentWorkingDirectory : rootDir, resolvedTargetInput);
33
- if (!fs.existsSync(targetPath)) {
34
- return err(new AppError("NOT_FOUND", `Not found: ${targetPath}`));
35
- }
36
- return ok({
37
- rootDir,
38
- targetPath: fs.canonicalPathSync(targetPath),
39
- allowlist: rtlConfig.allowlist ?? [],
40
- });
41
- }
42
- /**
43
- * Loads config and resolves the scan target for `audit links`.
44
- *
45
- * @remarks Defaults to the repo root rather than a configured path: a link audit that only covers one
46
- * package cannot see the cross-package references that are the ones most likely to rot.
47
- *
48
- * @since 0.5.0
49
- */
50
- export async function prepareLinkAudit(fs, args) {
51
- let rootDir;
52
- try {
53
- rootDir = fs.canonicalPathSync(resolveProjectRoot(args.currentWorkingDirectory, fs).rootDir);
54
- }
55
- catch (caughtError) {
56
- return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
57
- }
58
- const loadedOutcome = await loadCodefastConfig(rootDir, fs);
59
- if (!loadedOutcome.ok) {
60
- return loadedOutcome;
61
- }
62
- const linksConfig = loadedOutcome.value.config.audit?.links ?? {};
63
- const targetPath = args.rawTarget === undefined ? rootDir : resolveRepoRelativePath(args.currentWorkingDirectory, args.rawTarget);
64
- if (!fs.existsSync(targetPath)) {
65
- return err(new AppError("NOT_FOUND", `Not found: ${targetPath}`));
66
- }
67
- return ok({
68
- rootDir,
69
- targetPath: fs.canonicalPathSync(targetPath),
70
- allowlist: linksConfig.allowlist ?? [],
71
- });
72
- }
73
- /**
74
- * Loads config and resolves the scan target for `audit imports`.
75
- *
76
- * @remarks Defaults to the repo root: the import policy is repo-wide, and generated or vendored
77
- * trees are already excluded by the shared walk.
78
- *
79
- * @since 0.10.0
80
- */
81
- export async function prepareImportsAudit(fs, args) {
82
- let rootDir;
83
- try {
84
- rootDir = fs.canonicalPathSync(resolveProjectRoot(args.currentWorkingDirectory, fs).rootDir);
85
- }
86
- catch (caughtError) {
87
- return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
88
- }
89
- const loadedOutcome = await loadCodefastConfig(rootDir, fs);
90
- if (!loadedOutcome.ok) {
91
- return loadedOutcome;
92
- }
93
- const importsConfig = loadedOutcome.value.config.audit?.imports ?? {};
94
- const targetPath = args.rawTarget === undefined ? rootDir : resolveRepoRelativePath(args.currentWorkingDirectory, args.rawTarget);
95
- if (!fs.existsSync(targetPath)) {
96
- return err(new AppError("NOT_FOUND", `Not found: ${targetPath}`));
97
- }
98
- return ok({
99
- rootDir,
100
- targetPath: fs.canonicalPathSync(targetPath),
101
- allowlist: importsConfig.allowlist ?? [],
102
- });
103
- }
104
- /**
105
- * Loads config and resolves the scan target for `audit comments`.
106
- *
107
- * @remarks Defaults to the repo root: a divider convention that only holds inside one package
108
- * is not a convention.
109
- *
110
- * @since 0.6.0
111
- */
112
- export async function prepareCommentAudit(fs, args) {
113
- let rootDir;
114
- try {
115
- rootDir = fs.canonicalPathSync(resolveProjectRoot(args.currentWorkingDirectory, fs).rootDir);
116
- }
117
- catch (caughtError) {
118
- return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
119
- }
120
- const loadedOutcome = await loadCodefastConfig(rootDir, fs);
121
- if (!loadedOutcome.ok) {
122
- return loadedOutcome;
123
- }
124
- const commentsConfig = loadedOutcome.value.config.audit?.comments ?? {};
125
- const targetPath = args.rawTarget === undefined ? rootDir : resolveRepoRelativePath(args.currentWorkingDirectory, args.rawTarget);
126
- if (!fs.existsSync(targetPath)) {
127
- return err(new AppError("NOT_FOUND", `Not found: ${targetPath}`));
128
- }
129
- return ok({
130
- rootDir,
131
- targetPath: fs.canonicalPathSync(targetPath),
132
- allowlist: commentsConfig.allowlist ?? [],
133
- });
11
+ export function resolveRepoRelativePath(rootDir, maybeRelative) {
12
+ return path.isAbsolute(maybeRelative) ? path.resolve(maybeRelative) : path.resolve(rootDir, maybeRelative);
134
13
  }
135
14
  /**
136
- * Loads config and resolves the scan target for `audit display-names`.
15
+ * Loads config and resolves the repo root as the scan target, taking the allowlist the caller selects.
137
16
  *
138
- * @remarks Defaults to the repo root: a display name collides across packages, so the convention
139
- * has to hold across them.
17
+ * @remarks Every repo-wide audit shares this prelude; only the config key its allowlist comes from differs.
140
18
  *
141
- * @since 0.9.0
19
+ * @since 0.11.0
142
20
  */
143
- export async function prepareDisplayNameAudit(fs, args) {
21
+ export async function prepareRepoRootAudit(fs, args, selectAllowlist) {
144
22
  let rootDir;
145
23
  try {
146
24
  rootDir = fs.canonicalPathSync(resolveProjectRoot(args.currentWorkingDirectory, fs).rootDir);
@@ -152,7 +30,6 @@ export async function prepareDisplayNameAudit(fs, args) {
152
30
  if (!loadedOutcome.ok) {
153
31
  return loadedOutcome;
154
32
  }
155
- const displayNamesConfig = loadedOutcome.value.config.audit?.displayNames ?? {};
156
33
  const targetPath = args.rawTarget === undefined ? rootDir : resolveRepoRelativePath(args.currentWorkingDirectory, args.rawTarget);
157
34
  if (!fs.existsSync(targetPath)) {
158
35
  return err(new AppError("NOT_FOUND", `Not found: ${targetPath}`));
@@ -160,6 +37,6 @@ export async function prepareDisplayNameAudit(fs, args) {
160
37
  return ok({
161
38
  rootDir,
162
39
  targetPath: fs.canonicalPathSync(targetPath),
163
- allowlist: displayNamesConfig.allowlist ?? [],
40
+ allowlist: selectAllowlist(loadedOutcome.value.config),
164
41
  });
165
42
  }
@@ -0,0 +1,13 @@
1
+ import type { PublishAuditResult } from "#audit/domain/types";
2
+ /**
3
+ * Exit `1` when any `#/` import or unshipped publish target remains.
4
+ *
5
+ * @since 0.12.0
6
+ */
7
+ export declare function exitCodeForPublishAuditResult(result: PublishAuditResult): number;
8
+ /**
9
+ * Machine-readable publish audit summary for `--json`.
10
+ *
11
+ * @since 0.12.0
12
+ */
13
+ export declare function formatPublishAuditJsonOutput(result: PublishAuditResult, rootDir: string): string;
@@ -0,0 +1,22 @@
1
+ import { CLI_EXIT_GENERAL_ERROR, CLI_EXIT_SUCCESS } from "#core/exit-codes";
2
+ /**
3
+ * Exit `1` when any `#/` import or unshipped publish target remains.
4
+ *
5
+ * @since 0.12.0
6
+ */
7
+ export function exitCodeForPublishAuditResult(result) {
8
+ return result.legacyImportCount > 0 || result.unshipped.length > 0 ? CLI_EXIT_GENERAL_ERROR : CLI_EXIT_SUCCESS;
9
+ }
10
+ /**
11
+ * Machine-readable publish audit summary for `--json`.
12
+ *
13
+ * @since 0.12.0
14
+ */
15
+ export function formatPublishAuditJsonOutput(result, rootDir) {
16
+ return JSON.stringify({
17
+ schemaVersion: 1,
18
+ ok: result.legacyImportCount === 0 && result.unshipped.length === 0,
19
+ cwd: rootDir,
20
+ result,
21
+ });
22
+ }
@@ -0,0 +1,18 @@
1
+ import * as z from "zod";
2
+ /**
3
+ * Resolved request for a single publish audit run.
4
+ *
5
+ * @since 0.12.0
6
+ */
7
+ export type PublishAuditRunRequest = {
8
+ readonly rootDir: string;
9
+ readonly targetPath: string;
10
+ readonly allowlist?: ReadonlyArray<string> | undefined;
11
+ readonly json: boolean;
12
+ };
13
+ /**
14
+ * Zod schema for {@link PublishAuditRunRequest}.
15
+ *
16
+ * @since 0.12.0
17
+ */
18
+ export declare const publishAuditRunRequestSchema: z.ZodType<PublishAuditRunRequest>;
@@ -0,0 +1,12 @@
1
+ import * as z from "zod";
2
+ /**
3
+ * Zod schema for {@link PublishAuditRunRequest}.
4
+ *
5
+ * @since 0.12.0
6
+ */
7
+ export const publishAuditRunRequestSchema = z.object({
8
+ rootDir: z.string().min(1),
9
+ targetPath: z.string().min(1),
10
+ allowlist: z.array(z.string()).optional(),
11
+ json: z.boolean(),
12
+ });
@@ -0,0 +1,8 @@
1
+ /** Detects `#/`-prefixed internal import specifiers, which Node's ESM resolver rejects on the floor. */
2
+ import type { LegacySubpathImport } from "#audit/domain/types";
3
+ /**
4
+ * Every `#/`-prefixed import specifier in a source file, with its line number.
5
+ *
6
+ * @since 0.12.0
7
+ */
8
+ export declare function scanLegacySubpathImports(content: string): Array<LegacySubpathImport>;
@@ -0,0 +1,22 @@
1
+ /** Detects `#/`-prefixed internal import specifiers, which Node's ESM resolver rejects on the floor. */
2
+ // A `#/` specifier in import position — after `from`, `import(`, or `require(`. Anchoring on the keyword
3
+ // rules out an unrelated string that merely contains `#/`, such as this rule's own diagnostic text.
4
+ const LEGACY_SUBPATH_SPECIFIER = /(?:\bfrom|\bimport|\brequire)\b\s*\(?\s*(["']#\/[^"']*["'])/g;
5
+ /**
6
+ * Every `#/`-prefixed import specifier in a source file, with its line number.
7
+ *
8
+ * @since 0.12.0
9
+ */
10
+ export function scanLegacySubpathImports(content) {
11
+ const found = [];
12
+ const lines = content.split("\n");
13
+ for (const [index, line] of lines.entries()) {
14
+ for (const match of line.matchAll(LEGACY_SUBPATH_SPECIFIER)) {
15
+ const raw = match[1];
16
+ if (raw !== undefined) {
17
+ found.push({ line: index + 1, raw });
18
+ }
19
+ }
20
+ }
21
+ return found;
22
+ }
@@ -0,0 +1,7 @@
1
+ import type { PublishAuditResult } from "#audit/domain/types";
2
+ /**
3
+ * Human-readable publish audit report.
4
+ *
5
+ * @since 0.12.0
6
+ */
7
+ export declare function presentPublishAuditResult(result: PublishAuditResult): void;
@@ -0,0 +1,24 @@
1
+ import { logger } from "#core/logger";
2
+ /**
3
+ * Human-readable publish audit report.
4
+ *
5
+ * @since 0.12.0
6
+ */
7
+ export function presentPublishAuditResult(result) {
8
+ for (const file of result.legacyImportFiles) {
9
+ logger.out(`\n${file.relativePath}`);
10
+ for (const { line, raw } of file.imports) {
11
+ logger.out(` ${line}: ${raw} → use a bare "#" prefix, not "#/"`);
12
+ }
13
+ }
14
+ for (const { packageName, field, subpath, target } of result.unshipped) {
15
+ logger.out(`\n${packageName}: ${field}["${subpath}"] → ${target} is not shipped by "files"`);
16
+ }
17
+ const problems = result.legacyImportCount + result.unshipped.length;
18
+ if (problems > 0) {
19
+ logger.out(`\n✖ ${result.legacyImportCount} legacy "#/" import(s), ${result.unshipped.length} unshipped target(s)`);
20
+ }
21
+ else {
22
+ logger.out(`✓ No "#/" imports across ${result.scannedFileCount} file(s); every publish target ships across ${result.packageCount} package(s)`);
23
+ }
24
+ }
@@ -0,0 +1,16 @@
1
+ import type { AuditCommandPrelude } from "#audit/prepare";
2
+ import type { AppError } from "#core/errors";
3
+ import type { Filesystem } from "#core/filesystem/filesystem";
4
+ import type { Result } from "#core/result";
5
+ /**
6
+ * Loads config and resolves the scan target for `audit publish`.
7
+ *
8
+ * @remarks Defaults to the repo root: the audit walks every published package's source and manifest, so
9
+ * a single-package target would miss the cross-package surface. It takes no allowlist.
10
+ *
11
+ * @since 0.12.0
12
+ */
13
+ export declare function preparePublishAudit(fs: Filesystem, args: {
14
+ readonly currentWorkingDirectory: string;
15
+ readonly rawTarget: string | undefined;
16
+ }): Promise<Result<AuditCommandPrelude, AppError>>;
@@ -0,0 +1,12 @@
1
+ import { prepareRepoRootAudit } from "#audit/prepare";
2
+ /**
3
+ * Loads config and resolves the scan target for `audit publish`.
4
+ *
5
+ * @remarks Defaults to the repo root: the audit walks every published package's source and manifest, so
6
+ * a single-package target would miss the cross-package surface. It takes no allowlist.
7
+ *
8
+ * @since 0.12.0
9
+ */
10
+ export async function preparePublishAudit(fs, args) {
11
+ return prepareRepoRootAudit(fs, args, () => []);
12
+ }
@@ -0,0 +1,14 @@
1
+ import type { PublishAuditResult } from "#audit/domain/types";
2
+ import { AppError } from "#core/errors";
3
+ import type { Filesystem } from "#core/filesystem/filesystem";
4
+ import type { Result } from "#core/result";
5
+ /**
6
+ * Reports what would break a consumer's install: a `#/`-prefixed import Node's ESM resolver rejects on
7
+ * the floor, and an `exports`/`imports` target the slimmed publish manifest does not ship.
8
+ *
9
+ * @since 0.12.0
10
+ */
11
+ export declare function runPublishAudit(fs: Filesystem, args: {
12
+ readonly rootDir: string;
13
+ readonly targetPath: string;
14
+ }): Promise<Result<PublishAuditResult, AppError>>;
@@ -0,0 +1,62 @@
1
+ import path from "node:path";
2
+ import { scanLegacySubpathImports } from "#audit/publish/domain/legacy-subpath";
3
+ import { AppError, messageFrom } from "#core/errors";
4
+ import { err, ok } from "#core/result";
5
+ import { listWorkspacePackageDirectories } from "#core/workspace/resolver";
6
+ import { sourceCommentLanguage, walkSourceFiles } from "#core/workspace/source-walk";
7
+ import { packageJsonFileName } from "#core/workspace/well-known-files";
8
+ import { unshippedPublishTargets } from "#pack-slim/domain/transform";
9
+ /**
10
+ * Reports what would break a consumer's install: a `#/`-prefixed import Node's ESM resolver rejects on
11
+ * the floor, and an `exports`/`imports` target the slimmed publish manifest does not ship.
12
+ *
13
+ * @since 0.12.0
14
+ */
15
+ export async function runPublishAudit(fs, args) {
16
+ try {
17
+ const { rootDir, targetPath } = args;
18
+ const legacyImportFiles = [];
19
+ let legacyImportCount = 0;
20
+ // Tests are not published and may hold `#/` fixtures on purpose, so the specifier scan skips them.
21
+ const sourceFiles = walkSourceFiles(targetPath, fs).filter((filePath) => sourceCommentLanguage(filePath) === "js" && !filePath.split(path.sep).includes("tests"));
22
+ for (const absolutePath of sourceFiles) {
23
+ const imports = scanLegacySubpathImports(fs.readFileSync(absolutePath, "utf8"));
24
+ if (imports.length === 0) {
25
+ continue;
26
+ }
27
+ legacyImportCount += imports.length;
28
+ legacyImportFiles.push({ relativePath: toPosixPath(path.relative(rootDir, absolutePath)), imports });
29
+ }
30
+ const layout = await listWorkspacePackageDirectories(rootDir, fs, true);
31
+ const unshipped = [];
32
+ let packageCount = 0;
33
+ for (const packageDir of layout.packageDirectoryPathsAbsolute) {
34
+ const manifestPath = path.join(packageDir, packageJsonFileName);
35
+ if (!fs.existsSync(manifestPath)) {
36
+ continue;
37
+ }
38
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
39
+ if (manifest.private === true) {
40
+ continue;
41
+ }
42
+ packageCount++;
43
+ const packageName = typeof manifest.name === "string" ? manifest.name : toPosixPath(path.relative(rootDir, packageDir));
44
+ for (const target of unshippedPublishTargets(manifest)) {
45
+ unshipped.push({ packageName, field: target.field, subpath: target.subpath, target: target.target });
46
+ }
47
+ }
48
+ return ok({
49
+ legacyImportFiles,
50
+ unshipped,
51
+ legacyImportCount,
52
+ scannedFileCount: sourceFiles.length,
53
+ packageCount,
54
+ });
55
+ }
56
+ catch (caughtError) {
57
+ return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
58
+ }
59
+ }
60
+ function toPosixPath(filePath) {
61
+ return filePath.split(path.sep).join("/");
62
+ }
@@ -0,0 +1,13 @@
1
+ import type { RtlAuditResult } from "#audit/domain/types";
2
+ /**
3
+ * Exit `1` when any non-allowlisted violation remains.
4
+ *
5
+ * @since 0.5.0-canary.6
6
+ */
7
+ export declare function exitCodeForRtlAuditResult(result: RtlAuditResult): number;
8
+ /**
9
+ * Machine-readable RTL audit summary for `--json`.
10
+ *
11
+ * @since 0.5.0-canary.6
12
+ */
13
+ export declare function formatRtlAuditJsonOutput(result: RtlAuditResult, rootDir: string): string;
@@ -0,0 +1,22 @@
1
+ import { CLI_EXIT_GENERAL_ERROR, CLI_EXIT_SUCCESS } from "#core/exit-codes";
2
+ /**
3
+ * Exit `1` when any non-allowlisted violation remains.
4
+ *
5
+ * @since 0.5.0-canary.6
6
+ */
7
+ export function exitCodeForRtlAuditResult(result) {
8
+ return result.violationCount > 0 ? CLI_EXIT_GENERAL_ERROR : CLI_EXIT_SUCCESS;
9
+ }
10
+ /**
11
+ * Machine-readable RTL audit summary for `--json`.
12
+ *
13
+ * @since 0.5.0-canary.6
14
+ */
15
+ export function formatRtlAuditJsonOutput(result, rootDir) {
16
+ return JSON.stringify({
17
+ schemaVersion: 1,
18
+ ok: result.violationCount === 0,
19
+ cwd: rootDir,
20
+ result,
21
+ });
22
+ }
@@ -0,0 +1,18 @@
1
+ import * as z from "zod";
2
+ /**
3
+ * Resolved request for a single RTL audit run.
4
+ *
5
+ * @since 0.5.0-canary.6
6
+ */
7
+ export type RtlAuditRunRequest = {
8
+ readonly rootDir: string;
9
+ readonly targetPath: string;
10
+ readonly allowlist?: ReadonlyArray<string> | undefined;
11
+ readonly json: boolean;
12
+ };
13
+ /**
14
+ * Zod schema for {@link RtlAuditRunRequest}.
15
+ *
16
+ * @since 0.5.0-canary.6
17
+ */
18
+ export declare const rtlAuditRunRequestSchema: z.ZodType<RtlAuditRunRequest>;
@@ -0,0 +1,12 @@
1
+ import * as z from "zod";
2
+ /**
3
+ * Zod schema for {@link RtlAuditRunRequest}.
4
+ *
5
+ * @since 0.5.0-canary.6
6
+ */
7
+ export const rtlAuditRunRequestSchema = z.object({
8
+ rootDir: z.string().min(1),
9
+ targetPath: z.string().min(1),
10
+ allowlist: z.array(z.string()).optional(),
11
+ json: z.boolean(),
12
+ });