@codefast/cli 0.10.0 → 0.11.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 (220) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +16 -2
  3. package/dist/arrange/command.js +96 -132
  4. package/dist/arrange/domain/ast/simplify-targets.js +18 -23
  5. package/dist/arrange/{typescript-ast-translator.d.ts → domain/ast/translator.d.ts} +5 -4
  6. package/dist/arrange/{typescript-ast-translator.js → domain/ast/translator.js} +19 -22
  7. package/dist/arrange/group/cli-result.d.ts +7 -0
  8. package/dist/arrange/group/cli-result.js +12 -0
  9. package/dist/arrange/group/cli-schema.d.ts +17 -0
  10. package/dist/arrange/group/cli-schema.js +13 -0
  11. package/dist/arrange/group/output.d.ts +7 -0
  12. package/dist/arrange/group/output.js +10 -0
  13. package/dist/arrange/{suggest.d.ts → group/suggest.d.ts} +1 -1
  14. package/dist/arrange/inspect/cli-result.d.ts +7 -0
  15. package/dist/arrange/inspect/cli-result.js +8 -0
  16. package/dist/arrange/inspect/cli-schema.d.ts +15 -0
  17. package/dist/arrange/inspect/cli-schema.js +9 -0
  18. package/dist/arrange/inspect/output.d.ts +7 -0
  19. package/dist/arrange/inspect/output.js +42 -0
  20. package/dist/arrange/{analyze.d.ts → inspect/run.d.ts} +2 -2
  21. package/dist/arrange/{analyze.js → inspect/run.js} +2 -2
  22. package/dist/arrange/{workspace.d.ts → prepare.d.ts} +2 -2
  23. package/dist/arrange/{workspace.js → prepare.js} +5 -8
  24. package/dist/arrange/regroup/cli-result.d.ts +13 -0
  25. package/dist/arrange/regroup/cli-result.js +23 -0
  26. package/dist/arrange/regroup/cli-schema.d.ts +20 -0
  27. package/dist/arrange/regroup/cli-schema.js +14 -0
  28. package/dist/arrange/regroup/output.d.ts +14 -0
  29. package/dist/arrange/regroup/output.js +72 -0
  30. package/dist/arrange/{process-file.d.ts → regroup/process-file.d.ts} +2 -2
  31. package/dist/arrange/{sync.d.ts → regroup/run.d.ts} +3 -3
  32. package/dist/arrange/{sync.js → regroup/run.js} +2 -2
  33. package/dist/arrange/resolve-target.d.ts +2 -2
  34. package/dist/arrange/scan-target.d.ts +2 -2
  35. package/dist/arrange/simplify/cli-result.d.ts +7 -0
  36. package/dist/arrange/simplify/cli-result.js +8 -0
  37. package/dist/arrange/simplify/cli-schema.d.ts +17 -0
  38. package/dist/arrange/simplify/cli-schema.js +11 -0
  39. package/dist/arrange/simplify/fold-targets.d.ts +13 -0
  40. package/dist/arrange/simplify/fold-targets.js +139 -0
  41. package/dist/arrange/simplify/output.d.ts +7 -0
  42. package/dist/arrange/simplify/output.js +15 -0
  43. package/dist/arrange/{simplify-process-file.d.ts → simplify/process-file.d.ts} +4 -2
  44. package/dist/arrange/simplify/process-file.js +49 -0
  45. package/dist/arrange/{simplify-sync.d.ts → simplify/run.d.ts} +3 -2
  46. package/dist/arrange/simplify/run.js +38 -0
  47. package/dist/arrange/simplify/variant-classname-probe.d.ts +35 -0
  48. package/dist/arrange/simplify/variant-classname-probe.js +95 -0
  49. package/dist/arrange/source-parse.js +1 -1
  50. package/dist/audit/command.js +134 -211
  51. package/dist/audit/comments/cli-result.d.ts +13 -0
  52. package/dist/audit/comments/cli-result.js +22 -0
  53. package/dist/audit/comments/cli-schema.d.ts +19 -0
  54. package/dist/audit/comments/cli-schema.js +13 -0
  55. package/dist/audit/comments/output.d.ts +7 -0
  56. package/dist/audit/comments/output.js +27 -0
  57. package/dist/audit/comments/prepare.d.ts +16 -0
  58. package/dist/audit/comments/prepare.js +12 -0
  59. package/dist/audit/{run-comments.d.ts → comments/run.d.ts} +2 -2
  60. package/dist/audit/{run-comments.js → comments/run.js} +5 -5
  61. package/dist/audit/display-names/cli-result.d.ts +13 -0
  62. package/dist/audit/display-names/cli-result.js +22 -0
  63. package/dist/audit/display-names/cli-schema.d.ts +18 -0
  64. package/dist/audit/display-names/cli-schema.js +12 -0
  65. package/dist/audit/display-names/output.d.ts +7 -0
  66. package/dist/audit/display-names/output.js +21 -0
  67. package/dist/audit/display-names/prepare.d.ts +16 -0
  68. package/dist/audit/display-names/prepare.js +12 -0
  69. package/dist/audit/{run-display-names.d.ts → display-names/run.d.ts} +2 -2
  70. package/dist/audit/{run-display-names.js → display-names/run.js} +1 -1
  71. package/dist/audit/imports/cli-result.d.ts +13 -0
  72. package/dist/audit/imports/cli-result.js +22 -0
  73. package/dist/audit/imports/cli-schema.d.ts +18 -0
  74. package/dist/audit/imports/cli-schema.js +12 -0
  75. package/dist/audit/{domain → imports/domain}/import-policy.d.ts +2 -2
  76. package/dist/audit/{domain → imports/domain}/import-policy.js +4 -11
  77. package/dist/audit/imports/output.d.ts +7 -0
  78. package/dist/audit/imports/output.js +21 -0
  79. package/dist/audit/imports/prepare.d.ts +16 -0
  80. package/dist/audit/imports/prepare.js +12 -0
  81. package/dist/audit/{run-imports.d.ts → imports/run.d.ts} +2 -2
  82. package/dist/audit/{run-imports.js → imports/run.js} +2 -2
  83. package/dist/audit/links/cli-result.d.ts +13 -0
  84. package/dist/audit/links/cli-result.js +22 -0
  85. package/dist/audit/links/cli-schema.d.ts +18 -0
  86. package/dist/audit/links/cli-schema.js +12 -0
  87. package/dist/audit/links/output.d.ts +7 -0
  88. package/dist/audit/links/output.js +21 -0
  89. package/dist/audit/links/prepare.d.ts +16 -0
  90. package/dist/audit/links/prepare.js +12 -0
  91. package/dist/audit/{run-links.d.ts → links/run.d.ts} +2 -2
  92. package/dist/audit/{run-links.js → links/run.js} +1 -1
  93. package/dist/audit/prepare.d.ts +11 -50
  94. package/dist/audit/prepare.js +9 -132
  95. package/dist/audit/rtl/cli-result.d.ts +13 -0
  96. package/dist/audit/rtl/cli-result.js +22 -0
  97. package/dist/audit/rtl/cli-schema.d.ts +18 -0
  98. package/dist/audit/rtl/cli-schema.js +12 -0
  99. package/dist/audit/{domain → rtl/domain}/audit-file.js +2 -2
  100. package/dist/audit/rtl/output.d.ts +7 -0
  101. package/dist/audit/rtl/output.js +21 -0
  102. package/dist/audit/rtl/prepare.d.ts +13 -0
  103. package/dist/audit/rtl/prepare.js +41 -0
  104. package/dist/audit/{run.d.ts → rtl/run.d.ts} +2 -2
  105. package/dist/audit/{run.js → rtl/run.js} +1 -1
  106. package/dist/core/cli/command-pipeline.d.ts +91 -0
  107. package/dist/core/cli/command-pipeline.js +83 -0
  108. package/dist/core/cli/global-options.d.ts +1 -1
  109. package/dist/core/cli/global-options.js +1 -1
  110. package/dist/core/cli/resolve-root.d.ts +9 -0
  111. package/dist/core/cli/resolve-root.js +16 -0
  112. package/dist/core/cli/result-handle.d.ts +1 -7
  113. package/dist/core/cli/result-handle.js +0 -13
  114. package/dist/core/config/loader.d.ts +2 -2
  115. package/dist/core/config/schema.d.ts +1 -1
  116. package/dist/core/config/schema.js +1 -1
  117. package/dist/core/config.d.ts +2 -2
  118. package/dist/core/filesystem/{port.d.ts → filesystem.d.ts} +1 -1
  119. package/dist/core/filesystem/node.d.ts +3 -3
  120. package/dist/core/filesystem/node.js +1 -1
  121. package/dist/core/source-text-edit.d.ts +14 -0
  122. package/dist/core/source-text-edit.js +22 -0
  123. package/dist/core/workspace/markdown-walk.d.ts +2 -2
  124. package/dist/core/workspace/package-version.d.ts +2 -2
  125. package/dist/core/workspace/resolver.d.ts +3 -3
  126. package/dist/core/workspace/source-walk.d.ts +2 -2
  127. package/dist/core/workspace/typescript-walk.d.ts +2 -2
  128. package/dist/core/workspace/walk-files.d.ts +2 -2
  129. package/dist/mirror/cli-schema.d.ts +2 -2
  130. package/dist/mirror/cli-schema.js +1 -1
  131. package/dist/mirror/command.js +31 -60
  132. package/dist/mirror/{dist-filesystem-impl.d.ts → dist-filesystem-node.d.ts} +3 -3
  133. package/dist/mirror/{dist-filesystem-impl.js → dist-filesystem-node.js} +1 -1
  134. package/dist/mirror/domain/dirent-guard.d.ts +1 -1
  135. package/dist/mirror/domain/types.d.ts +57 -0
  136. package/dist/mirror/output.d.ts +1 -3
  137. package/dist/mirror/output.js +126 -1
  138. package/dist/mirror/package-path.d.ts +3 -3
  139. package/dist/mirror/prepare.d.ts +3 -3
  140. package/dist/mirror/prepare.js +6 -10
  141. package/dist/mirror/run.d.ts +12 -0
  142. package/dist/mirror/supplement-exports.d.ts +3 -3
  143. package/dist/mirror/sync-workspace-package.d.ts +2 -2
  144. package/dist/mirror/sync-workspace-package.js +1 -1
  145. package/dist/mirror/write-exports.d.ts +2 -2
  146. package/dist/pack-slim/cli-schema.d.ts +1 -1
  147. package/dist/pack-slim/cli-schema.js +1 -1
  148. package/dist/pack-slim/command.js +31 -66
  149. package/dist/pack-slim/prepare.d.ts +21 -0
  150. package/dist/pack-slim/prepare.js +14 -0
  151. package/dist/pack-slim/{sync.d.ts → run.d.ts} +2 -2
  152. package/dist/tag/cli-result.d.ts +8 -2
  153. package/dist/tag/cli-result.js +14 -1
  154. package/dist/tag/cli-schema.d.ts +4 -4
  155. package/dist/tag/cli-schema.js +3 -4
  156. package/dist/tag/command.js +33 -60
  157. package/dist/tag/domain/skip-filter.d.ts +13 -0
  158. package/dist/tag/domain/skip-filter.js +29 -0
  159. package/dist/tag/domain/types.d.ts +21 -1
  160. package/dist/tag/domain/version-summary.d.ts +13 -0
  161. package/dist/tag/domain/version-summary.js +24 -0
  162. package/dist/tag/output.d.ts +4 -4
  163. package/dist/tag/output.js +6 -9
  164. package/dist/tag/prepare.d.ts +2 -2
  165. package/dist/tag/prepare.js +2 -2
  166. package/dist/tag/run.d.ts +10 -0
  167. package/dist/tag/{sync.js → run.js} +20 -50
  168. package/dist/tag/{target-candidates.d.ts → target/candidates.d.ts} +2 -2
  169. package/dist/tag/{target-candidates.js → target/candidates.js} +1 -1
  170. package/dist/tag/{resolve-target-path.d.ts → target/resolve-path.d.ts} +2 -2
  171. package/dist/tag/{target-runner.d.ts → target/runner.d.ts} +2 -2
  172. package/dist/tag/{target-runner.js → target/runner.js} +2 -2
  173. package/dist/tag/{since-writer.d.ts → writer/since-writer.d.ts} +2 -2
  174. package/dist/tag/{version-resolver.d.ts → writer/version-resolver.d.ts} +2 -2
  175. package/package.json +10 -2
  176. package/dist/arrange/cli-schema.d.ts +0 -50
  177. package/dist/arrange/cli-schema.js +0 -34
  178. package/dist/arrange/output.d.ts +0 -26
  179. package/dist/arrange/output.js +0 -127
  180. package/dist/arrange/simplify-process-file.js +0 -30
  181. package/dist/arrange/simplify-sync.js +0 -30
  182. package/dist/audit/cli-schema.d.ts +0 -93
  183. package/dist/audit/cli-schema.js +0 -66
  184. package/dist/audit/output.d.ts +0 -91
  185. package/dist/audit/output.js +0 -213
  186. package/dist/mirror/sync-reporter.d.ts +0 -60
  187. package/dist/mirror/sync-reporter.js +0 -128
  188. package/dist/mirror/sync-types.d.ts +0 -43
  189. package/dist/mirror/sync-types.js +0 -1
  190. package/dist/mirror/sync.d.ts +0 -12
  191. package/dist/tag/sync.d.ts +0 -42
  192. /package/dist/arrange/{suggest.js → group/suggest.js} +0 -0
  193. /package/dist/arrange/{domain → inspect/domain}/analyze-service.d.ts +0 -0
  194. /package/dist/arrange/{domain → inspect/domain}/analyze-service.js +0 -0
  195. /package/dist/arrange/{process-file.js → regroup/process-file.js} +0 -0
  196. /package/dist/audit/{domain → comments/domain}/comment-content.d.ts +0 -0
  197. /package/dist/audit/{domain → comments/domain}/comment-content.js +0 -0
  198. /package/dist/audit/{domain → comments/domain}/comment-dividers.d.ts +0 -0
  199. /package/dist/audit/{domain → comments/domain}/comment-dividers.js +0 -0
  200. /package/dist/audit/{domain → comments/domain}/link-references.d.ts +0 -0
  201. /package/dist/audit/{domain → comments/domain}/link-references.js +0 -0
  202. /package/dist/audit/{domain → comments/domain}/since-versions.d.ts +0 -0
  203. /package/dist/audit/{domain → comments/domain}/since-versions.js +0 -0
  204. /package/dist/audit/{domain → comments/domain}/tsdoc-syntax.d.ts +0 -0
  205. /package/dist/audit/{domain → comments/domain}/tsdoc-syntax.js +0 -0
  206. /package/dist/audit/{domain → display-names/domain}/display-names.d.ts +0 -0
  207. /package/dist/audit/{domain → display-names/domain}/display-names.js +0 -0
  208. /package/dist/audit/{domain → links/domain}/markdown-links.d.ts +0 -0
  209. /package/dist/audit/{domain → links/domain}/markdown-links.js +0 -0
  210. /package/dist/audit/{domain → rtl/domain}/audit-file.d.ts +0 -0
  211. /package/dist/audit/{domain → rtl/domain}/mappings.d.ts +0 -0
  212. /package/dist/audit/{domain → rtl/domain}/mappings.js +0 -0
  213. /package/dist/audit/{domain → rtl/domain}/tokenize.d.ts +0 -0
  214. /package/dist/audit/{domain → rtl/domain}/tokenize.js +0 -0
  215. /package/dist/core/filesystem/{port.js → filesystem.js} +0 -0
  216. /package/dist/mirror/{sync.js → run.js} +0 -0
  217. /package/dist/pack-slim/{sync.js → run.js} +0 -0
  218. /package/dist/tag/{resolve-target-path.js → target/resolve-path.js} +0 -0
  219. /package/dist/tag/{since-writer.js → writer/since-writer.js} +0 -0
  220. /package/dist/tag/{version-resolver.js → writer/version-resolver.js} +0 -0
@@ -1,8 +1,6 @@
1
+ import { resolveProjectRootResult } from "#/core/cli/resolve-root";
1
2
  import { loadCodefastConfig } from "#/core/config";
2
- import { AppError } from "#/core/errors";
3
- import { messageFrom } from "#/core/errors";
4
- import { err, ok } from "#/core/result";
5
- import { resolveProjectRoot } from "#/core/workspace/resolver";
3
+ import { ok } from "#/core/result";
6
4
  import { resolveMirrorPackageFromCliArg } from "#/mirror/package-path";
7
5
  /**
8
6
  * Resolves the repo root, config, and package filter into the prelude a mirror run starts from.
@@ -10,13 +8,11 @@ import { resolveMirrorPackageFromCliArg } from "#/mirror/package-path";
10
8
  * @since 0.3.16-canary.0
11
9
  */
12
10
  export async function prepareMirrorSync(fs, args) {
13
- let rootDir;
14
- try {
15
- rootDir = resolveProjectRoot(args.currentWorkingDirectory, fs).rootDir;
16
- }
17
- catch (caughtError) {
18
- return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
11
+ const rootOutcome = resolveProjectRootResult(fs, args.currentWorkingDirectory);
12
+ if (!rootOutcome.ok) {
13
+ return rootOutcome;
19
14
  }
15
+ const rootDir = rootOutcome.value;
20
16
  const filterOutcome = resolveMirrorPackageFromCliArg(fs, {
21
17
  rootDir,
22
18
  packageArg: args.packageArg,
@@ -0,0 +1,12 @@
1
+ import { AppError } from "#/core/errors";
2
+ import type { Filesystem } from "#/core/filesystem/filesystem";
3
+ import type { Result } from "#/core/result";
4
+ import type { GlobalStats } from "#/mirror/domain/types";
5
+ import type { MirrorSyncExecutionInput } from "#/mirror/domain/types";
6
+ export type { MirrorSyncExecutionInput } from "#/mirror/domain/types";
7
+ /**
8
+ * Runs the mirror sync across the targeted packages and returns the aggregate stats.
9
+ *
10
+ * @since 0.3.16-canary.0
11
+ */
12
+ export declare function runMirrorSync(fs: Filesystem, input: MirrorSyncExecutionInput): Promise<Result<GlobalStats, AppError>>;
@@ -1,4 +1,4 @@
1
- import type { FilesystemPort } from "#/core/filesystem/port";
1
+ import type { Filesystem } from "#/core/filesystem/filesystem";
2
2
  /**
3
3
  * The export specifiers a preserve-mode run added conditions to.
4
4
  *
@@ -12,7 +12,7 @@ export type SupplementResult = {
12
12
  *
13
13
  * @since 0.3.16-canary.0
14
14
  */
15
- export declare function supplementExportsInPackageJson(fs: FilesystemPort, packageJsonPath: string, packageDir: string, options: {
15
+ export declare function supplementExportsInPackageJson(fs: Filesystem, packageJsonPath: string, packageDir: string, options: {
16
16
  source: boolean | string;
17
17
  types: boolean;
18
18
  import: boolean;
@@ -24,4 +24,4 @@ export declare function supplementExportsInPackageJson(fs: FilesystemPort, packa
24
24
  *
25
25
  * @since 0.3.16-canary.0
26
26
  */
27
- export declare function buildSourcePathResolver(fs: FilesystemPort, packageDir: string): (modulePath: string) => string;
27
+ export declare function buildSourcePathResolver(fs: Filesystem, packageDir: string): (modulePath: string) => string;
@@ -1,9 +1,9 @@
1
1
  import type { MirrorConfig } from "#/core/config/schema";
2
- import type { FilesystemPort } from "#/core/filesystem/port";
2
+ import type { Filesystem } from "#/core/filesystem/filesystem";
3
3
  import type { PackageStats } from "#/mirror/domain/types";
4
4
  /**
5
5
  * Regenerates one package's `package.json#exports` from its `dist/` and returns the package's stats.
6
6
  *
7
7
  * @since 0.3.16-canary.0
8
8
  */
9
- export declare function syncExportsForWorkspacePackage(fs: FilesystemPort, rootDir: string, packagePathStr: string, config: MirrorConfig, write?: boolean): Promise<PackageStats>;
9
+ export declare function syncExportsForWorkspacePackage(fs: Filesystem, rootDir: string, packagePathStr: string, config: MirrorConfig, write?: boolean): Promise<PackageStats>;
@@ -1,7 +1,7 @@
1
1
  import path from "node:path";
2
2
  import { messageFrom } from "#/core/errors";
3
3
  import { distDirName, packageJsonFileName } from "#/core/workspace/well-known-files";
4
- import { createMirrorDistFilesystem } from "#/mirror/dist-filesystem-impl";
4
+ import { createMirrorDistFilesystem } from "#/mirror/dist-filesystem-node";
5
5
  import { createPathTransform, generateExports } from "#/mirror/domain/exports";
6
6
  import { resolvePackageDisplayName } from "#/mirror/domain/package-display-name";
7
7
  import { buildSourcePathResolver, supplementExportsInPackageJson } from "#/mirror/supplement-exports";
@@ -1,4 +1,4 @@
1
- import type { FilesystemPort } from "#/core/filesystem/port";
1
+ import type { Filesystem } from "#/core/filesystem/filesystem";
2
2
  import type { ExportMapData, ExportOriginalPathBySpecifier } from "#/mirror/domain/types";
3
3
  /**
4
4
  * Writes `exports` into `package.json` via a temp file + rename (atomic on same volume).
@@ -6,7 +6,7 @@ import type { ExportMapData, ExportOriginalPathBySpecifier } from "#/mirror/doma
6
6
  *
7
7
  * @since 0.3.16-canary.0
8
8
  */
9
- export declare function writePackageJsonExportsAtomic(fs: FilesystemPort, packageJsonPath: string, mergeInput: {
9
+ export declare function writePackageJsonExportsAtomic(fs: Filesystem, packageJsonPath: string, mergeInput: {
10
10
  generatedExports: ExportMapData;
11
11
  managedExportSpecifiers: Array<string>;
12
12
  originalPathBySpecifier: ExportOriginalPathBySpecifier;
@@ -1,4 +1,4 @@
1
- import { z } from "zod";
1
+ import * as z from "zod";
2
2
  /**
3
3
  * The validated serializable inputs of a pack-slim run.
4
4
  *
@@ -1,4 +1,4 @@
1
- import { z } from "zod";
1
+ import * as z from "zod";
2
2
  /**
3
3
  * Zod schema validating the serializable inputs of a pack-slim run.
4
4
  *
@@ -1,80 +1,45 @@
1
- import process from "node:process";
2
1
  import { Command } from "commander";
3
- import { globalCliCommanderOptionsSchema } from "#/core/cli/global-options";
4
- import { readOptionalPositionalArg } from "#/core/cli/positional";
5
- import { consumeCliAppError } from "#/core/cli/result-handle";
6
- import { AppError, messageFrom } from "#/core/errors";
2
+ import { applyCommandPipeline } from "#/core/cli/command-pipeline";
7
3
  import { nodeFilesystem } from "#/core/filesystem/node";
8
- import { logger } from "#/core/logger";
9
- import { err } from "#/core/result";
10
- import { parseWithSchema } from "#/core/schema-parse";
11
- import { resolveProjectRoot } from "#/core/workspace/resolver";
4
+ import { ok } from "#/core/result";
12
5
  import { exitCodeForPackSlimResult, formatPackSlimJsonOutput } from "#/pack-slim/cli-result";
13
6
  import { packSlimRunRequestSchema } from "#/pack-slim/cli-schema";
14
7
  import { PackSlimProgressPresenter } from "#/pack-slim/output";
15
- import { runPackSlim } from "#/pack-slim/sync";
8
+ import { preparePackSlim } from "#/pack-slim/prepare";
9
+ import { runPackSlim } from "#/pack-slim/run";
16
10
  import { ensureWorkingTreeClean } from "#/pack-slim/working-tree";
11
+ const packSlimPipeline = {
12
+ positional: { name: "[package]", help: "Optional package path relative to repo root (e.g. packages/ui)" },
13
+ schema: packSlimRunRequestSchema,
14
+ configureArgv: (command) => {
15
+ command.option("--dry-run", "Report what would change without touching any file", false);
16
+ command.option("--force", "Run even if the git working tree has uncommitted tracked changes", false);
17
+ },
18
+ prepare: (fs, input) => preparePackSlim(fs, { currentWorkingDirectory: input.currentWorkingDirectory, packageArg: input.rawArg }),
19
+ // A destructive slim must never land on uncommitted work; --dry-run writes nothing, so it is exempt.
20
+ guard: async ({ prelude, opts }) => !opts.dryRun && !opts.force ? ensureWorkingTreeClean(prelude.rootDir) : ok(undefined),
21
+ buildRequest: ({ prelude, opts }) => ({
22
+ rootDir: prelude.rootDir,
23
+ packageFilter: prelude.packageFilter,
24
+ write: !opts.dryRun,
25
+ }),
26
+ createPresenter: ({ opts }) => {
27
+ const presenter = new PackSlimProgressPresenter();
28
+ presenter.configure({ dryRun: !!opts.dryRun });
29
+ return presenter;
30
+ },
31
+ run: (fs, request, presenter) => runPackSlim(fs, { ...request, listener: presenter }),
32
+ formatJson: ({ result, opts, elapsedSeconds }) => formatPackSlimJsonOutput(result, elapsedSeconds, !opts.dryRun),
33
+ exitCode: exitCodeForPackSlimResult,
34
+ };
17
35
  /**
18
36
  * Creates the `pack-slim` subcommand, which slims published packages down to what a consumer reads before publish.
19
37
  *
20
38
  * @since 0.8.1
21
39
  */
22
40
  export function createPackSlimCommand() {
23
- const cmd = new Command("pack-slim")
24
- .description("Strip src, source conditions, unshipped imports, dev-only scripts, devDependencies, and dist source maps from " +
25
- "published packages before publish")
26
- .argument("[package]", "Optional package path relative to repo root (e.g. packages/ui)")
27
- .option("--dry-run", "Report what would change without touching any file", false)
28
- .option("--force", "Run even if the git working tree has uncommitted tracked changes", false)
29
- .option("--json", "Print one JSON summary on stdout (suppresses human progress)", false)
30
- .action(async (packageArg, opts, command) => {
31
- const globalsOptionCarrier = command.optsWithGlobals?.() ??
32
- command.opts();
33
- const globalOptionsOutcome = parseWithSchema(globalCliCommanderOptionsSchema, globalsOptionCarrier);
34
- if (!consumeCliAppError(globalOptionsOutcome)) {
35
- return;
36
- }
37
- let rootDir;
38
- try {
39
- rootDir = resolveProjectRoot(process.cwd(), nodeFilesystem).rootDir;
40
- }
41
- catch (caughtError) {
42
- consumeCliAppError(err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError)));
43
- return;
44
- }
45
- const write = !opts.dryRun;
46
- // A destructive slim must never land on a developer's uncommitted work; --dry-run writes nothing, so it is exempt.
47
- if (write && !opts.force) {
48
- const cleanCheck = ensureWorkingTreeClean(rootDir);
49
- if (!consumeCliAppError(cleanCheck)) {
50
- return;
51
- }
52
- }
53
- const parsed = parseWithSchema(packSlimRunRequestSchema, {
54
- rootDir,
55
- packageFilter: readOptionalPositionalArg(packageArg),
56
- write,
57
- });
58
- if (!consumeCliAppError(parsed)) {
59
- return;
60
- }
61
- const json = !!opts.json;
62
- const presenter = new PackSlimProgressPresenter();
63
- if (!json) {
64
- presenter.configure({ dryRun: !write });
65
- }
66
- const startTime = performance.now();
67
- const outcome = await runPackSlim(nodeFilesystem, {
68
- ...parsed.value,
69
- listener: json ? undefined : presenter,
70
- });
71
- if (!consumeCliAppError(outcome)) {
72
- return;
73
- }
74
- if (json) {
75
- logger.out(formatPackSlimJsonOutput(outcome.value, (performance.now() - startTime) / 1000, write));
76
- }
77
- process.exitCode = exitCodeForPackSlimResult(outcome.value);
78
- });
41
+ const cmd = new Command("pack-slim").description("Strip src, source conditions, unshipped imports, dev-only scripts, devDependencies, and dist source maps from " +
42
+ "published packages before publish");
43
+ applyCommandPipeline(cmd, nodeFilesystem, packSlimPipeline);
79
44
  return cmd;
80
45
  }
@@ -0,0 +1,21 @@
1
+ import type { AppError } from "#/core/errors";
2
+ import type { Filesystem } from "#/core/filesystem/filesystem";
3
+ import type { Result } from "#/core/result";
4
+ /**
5
+ * The repo root and package filter a pack-slim run starts from.
6
+ *
7
+ * @since 0.8.1
8
+ */
9
+ export interface PackSlimCommandPrelude {
10
+ readonly rootDir: string;
11
+ readonly packageFilter: string | undefined;
12
+ }
13
+ /**
14
+ * Resolves the repo root and optional package filter into the prelude a pack-slim run starts from.
15
+ *
16
+ * @since 0.8.1
17
+ */
18
+ export declare function preparePackSlim(fs: Filesystem, args: {
19
+ readonly currentWorkingDirectory: string;
20
+ readonly packageArg: string | undefined;
21
+ }): Promise<Result<PackSlimCommandPrelude, AppError>>;
@@ -0,0 +1,14 @@
1
+ import { resolveProjectRootResult } from "#/core/cli/resolve-root";
2
+ import { ok } from "#/core/result";
3
+ /**
4
+ * Resolves the repo root and optional package filter into the prelude a pack-slim run starts from.
5
+ *
6
+ * @since 0.8.1
7
+ */
8
+ export async function preparePackSlim(fs, args) {
9
+ const rootOutcome = resolveProjectRootResult(fs, args.currentWorkingDirectory);
10
+ if (!rootOutcome.ok) {
11
+ return rootOutcome;
12
+ }
13
+ return ok({ rootDir: rootOutcome.value, packageFilter: args.packageArg });
14
+ }
@@ -1,5 +1,5 @@
1
1
  import { AppError } from "#/core/errors";
2
- import type { FilesystemPort } from "#/core/filesystem/port";
2
+ import type { Filesystem } from "#/core/filesystem/filesystem";
3
3
  import type { Result } from "#/core/result";
4
4
  import type { PackSlimRunRequest } from "#/pack-slim/cli-schema";
5
5
  import type { PackSlimProgressListener, PackSlimRunStats } from "#/pack-slim/domain/types";
@@ -20,4 +20,4 @@ export type PackSlimRunInput = PackSlimRunRequest & {
20
20
  *
21
21
  * @since 0.8.1
22
22
  */
23
- export declare function runPackSlim(fs: FilesystemPort, input: PackSlimRunInput): Promise<Result<PackSlimRunStats, AppError>>;
23
+ export declare function runPackSlim(fs: Filesystem, input: PackSlimRunInput): Promise<Result<PackSlimRunStats, AppError>>;
@@ -1,7 +1,13 @@
1
- import type { TagSyncResult } from "#/tag/domain/types";
1
+ import type { TagResult } from "#/tag/domain/types";
2
2
  /**
3
3
  * Maps a tag run's result to the process exit code.
4
4
  *
5
5
  * @since 0.3.16-canary.0
6
6
  */
7
- export declare function exitCodeForTagSyncResult(result: TagSyncResult): number;
7
+ export declare function exitCodeForTagResult(result: TagResult): number;
8
+ /**
9
+ * Serializes a tag run's result as the `--json` output string.
10
+ *
11
+ * @since 0.11.0
12
+ */
13
+ export declare function formatTagJsonOutput(result: TagResult, rootDir: string): string;
@@ -4,10 +4,23 @@ import { CLI_EXIT_GENERAL_ERROR, CLI_EXIT_SUCCESS } from "#/core/exit-codes";
4
4
  *
5
5
  * @since 0.3.16-canary.0
6
6
  */
7
- export function exitCodeForTagSyncResult(result) {
7
+ export function exitCodeForTagResult(result) {
8
8
  if (result.selectedTargets.length === 0) {
9
9
  return CLI_EXIT_GENERAL_ERROR;
10
10
  }
11
11
  const hasRunErrors = result.targetResults.some((targetResult) => targetResult.runError !== null);
12
12
  return hasRunErrors || result.hookError !== null ? CLI_EXIT_GENERAL_ERROR : CLI_EXIT_SUCCESS;
13
+ }
14
+ /**
15
+ * Serializes a tag run's result as the `--json` output string.
16
+ *
17
+ * @since 0.11.0
18
+ */
19
+ export function formatTagJsonOutput(result, rootDir) {
20
+ return JSON.stringify({
21
+ schemaVersion: 1,
22
+ ok: result.hookError === null,
23
+ cwd: rootDir,
24
+ result,
25
+ });
13
26
  }
@@ -1,8 +1,8 @@
1
- import { z } from "zod";
2
- import type { TagSyncRunRequest } from "#/tag/sync";
1
+ import * as z from "zod";
2
+ import type { TagRunRequest } from "#/tag/domain/types";
3
3
  /**
4
- * Zod schema validating a `TagSyncRunRequest`.
4
+ * Zod schema validating a `TagRunRequest`.
5
5
  *
6
6
  * @since 0.3.16-canary.0
7
7
  */
8
- export declare const tagSyncRunRequestSchema: z.ZodType<TagSyncRunRequest>;
8
+ export declare const tagRunRequestSchema: z.ZodType<TagRunRequest>;
@@ -1,13 +1,12 @@
1
- import { z } from "zod";
1
+ import * as z from "zod";
2
2
  /**
3
- * Zod schema validating a `TagSyncRunRequest`.
3
+ * Zod schema validating a `TagRunRequest`.
4
4
  *
5
5
  * @since 0.3.16-canary.0
6
6
  */
7
- export const tagSyncRunRequestSchema = z.object({
7
+ export const tagRunRequestSchema = z.object({
8
8
  rootDir: z.string().min(1),
9
9
  write: z.boolean(),
10
- json: z.boolean().optional(),
11
10
  targetPath: z.string().optional(),
12
11
  skipPackages: z.array(z.string()).optional(),
13
12
  config: z.unknown().optional(),
@@ -1,70 +1,43 @@
1
- import process from "node:process";
2
1
  import { Command } from "commander";
3
- import { readOptionalPositionalArg } from "#/core/cli/positional";
4
- import { consumeCliAppError } from "#/core/cli/result-handle";
2
+ import { applyCommandPipeline } from "#/core/cli/command-pipeline";
5
3
  import { nodeFilesystem } from "#/core/filesystem/node";
6
- import { logger } from "#/core/logger";
7
- import { parseWithSchema } from "#/core/schema-parse";
8
- import { exitCodeForTagSyncResult } from "#/tag/cli-result";
9
- import { tagSyncRunRequestSchema } from "#/tag/cli-schema";
10
- import { presentTagSyncResult, TagSyncProgressPresenter } from "#/tag/output";
11
- import { prepareTagSync } from "#/tag/prepare";
12
- import { runTagSync } from "#/tag/sync";
4
+ import { exitCodeForTagResult, formatTagJsonOutput } from "#/tag/cli-result";
5
+ import { tagRunRequestSchema } from "#/tag/cli-schema";
6
+ import { presentTagResult, TagProgressPresenter } from "#/tag/output";
7
+ import { prepareTag } from "#/tag/prepare";
8
+ import { runTag } from "#/tag/run";
9
+ const tagPipeline = {
10
+ positional: { name: "[target]", help: "Directory or file to tag (default: auto-discover workspace packages)" },
11
+ schema: tagRunRequestSchema,
12
+ configureArgv: (command) => {
13
+ command.option("--dry-run", "Show summary without writing files", false);
14
+ },
15
+ prepare: (fs, input) => prepareTag(fs, { currentWorkingDirectory: input.currentWorkingDirectory, rawTarget: input.rawArg }),
16
+ buildRequest: ({ prelude, opts }) => {
17
+ const tagConfig = prelude.config.tag ?? {};
18
+ return {
19
+ rootDir: prelude.rootDir,
20
+ write: !opts.dryRun,
21
+ targetPath: prelude.resolvedTargetPath,
22
+ skipPackages: tagConfig.skipPackages,
23
+ config: tagConfig,
24
+ };
25
+ },
26
+ createPresenter: () => new TagProgressPresenter(),
27
+ run: (fs, request, presenter) => runTag(fs, { ...request, listener: presenter }),
28
+ presentHuman: ({ result, prelude }) => {
29
+ presentTagResult(result, prelude.rootDir);
30
+ },
31
+ formatJson: ({ result, prelude }) => formatTagJsonOutput(result, prelude.rootDir),
32
+ exitCode: exitCodeForTagResult,
33
+ };
13
34
  /**
14
35
  * Creates the `tag` subcommand, which stamps `@since` tags on exported declarations.
15
36
  *
16
37
  * @since 0.3.16-canary.0
17
38
  */
18
39
  export function createTagCommand() {
19
- const cmd = new Command("tag")
20
- .description("Add @since <version> JSDoc tags to exported declarations")
21
- .argument("[target]", "Directory or file to tag (default: auto-discover workspace packages)")
22
- .option("--dry-run", "Show summary without writing files", false)
23
- .option("--json", "Print one JSON summary on stdout (suppresses human progress)", false)
24
- .action(async (target, opts) => {
25
- const prelude = await prepareTagSync(nodeFilesystem, {
26
- currentWorkingDirectory: process.cwd(),
27
- rawTarget: readOptionalPositionalArg(target),
28
- });
29
- if (!consumeCliAppError(prelude)) {
30
- return;
31
- }
32
- const { rootDir, config, resolvedTargetPath } = prelude.value;
33
- const tagConfig = config.tag ?? {};
34
- const parsed = parseWithSchema(tagSyncRunRequestSchema, {
35
- rootDir,
36
- write: !opts.dryRun,
37
- json: opts.json,
38
- targetPath: resolvedTargetPath,
39
- skipPackages: tagConfig.skipPackages,
40
- config: tagConfig,
41
- });
42
- if (!consumeCliAppError(parsed)) {
43
- return;
44
- }
45
- const progressPresenter = new TagSyncProgressPresenter();
46
- const tagOutcome = await runTagSync(nodeFilesystem, {
47
- ...parsed.value,
48
- listener: parsed.value.json ? undefined : progressPresenter,
49
- });
50
- if (!consumeCliAppError(tagOutcome)) {
51
- return;
52
- }
53
- if (parsed.value.json) {
54
- logger.out(formatTagSyncJsonOutput(tagOutcome.value, rootDir));
55
- process.exitCode = exitCodeForTagSyncResult(tagOutcome.value);
56
- }
57
- else {
58
- process.exitCode = presentTagSyncResult(tagOutcome.value, rootDir);
59
- }
60
- });
40
+ const cmd = new Command("tag").description("Add @since <version> JSDoc tags to exported declarations");
41
+ applyCommandPipeline(cmd, nodeFilesystem, tagPipeline);
61
42
  return cmd;
62
- }
63
- function formatTagSyncJsonOutput(result, rootDir) {
64
- return JSON.stringify({
65
- schemaVersion: 1,
66
- ok: result.hookError === null,
67
- cwd: rootDir,
68
- result,
69
- });
70
43
  }
@@ -0,0 +1,13 @@
1
+ import type { TagTargetCandidate } from "#/tag/domain/types";
2
+ /**
3
+ * Partitions tag target candidates into those to tag and those to skip, matching each candidate's
4
+ * package name against `skipPackages` as glob patterns.
5
+ *
6
+ * @remarks Candidates without a package name (e.g. an explicit-target path) are never skipped.
7
+ *
8
+ * @since 0.5.0-canary.0
9
+ */
10
+ export declare function filterSkippedCandidates(targetCandidates: Array<TagTargetCandidate>, skipPackages: ReadonlyArray<string> | undefined): {
11
+ includedCandidates: Array<TagTargetCandidate>;
12
+ skippedPackages: Array<string>;
13
+ };
@@ -0,0 +1,29 @@
1
+ import { createAnyGlobMatcher } from "#/core/glob";
2
+ /**
3
+ * Partitions tag target candidates into those to tag and those to skip, matching each candidate's
4
+ * package name against `skipPackages` as glob patterns.
5
+ *
6
+ * @remarks Candidates without a package name (e.g. an explicit-target path) are never skipped.
7
+ *
8
+ * @since 0.5.0-canary.0
9
+ */
10
+ export function filterSkippedCandidates(targetCandidates, skipPackages) {
11
+ if (!skipPackages || skipPackages.length === 0) {
12
+ return {
13
+ includedCandidates: targetCandidates,
14
+ skippedPackages: [],
15
+ };
16
+ }
17
+ const isSkipped = createAnyGlobMatcher(skipPackages);
18
+ const includedCandidates = [];
19
+ const skippedPackages = [];
20
+ for (const candidate of targetCandidates) {
21
+ const packageName = candidate.packageName;
22
+ if (packageName && isSkipped(packageName)) {
23
+ skippedPackages.push(packageName);
24
+ continue;
25
+ }
26
+ includedCandidates.push(candidate);
27
+ }
28
+ return { includedCandidates, skippedPackages };
29
+ }
@@ -85,7 +85,7 @@ export interface TagProgressListener {
85
85
  *
86
86
  * @since 0.3.16-canary.0
87
87
  */
88
- export type TagSyncResult = {
88
+ export type TagResult = {
89
89
  mode: "applied" | "dry-run";
90
90
  selectedTargets: Array<TagResolvedTarget>;
91
91
  skippedPackages: Array<string>;
@@ -108,4 +108,24 @@ export interface TagCommandPrelude {
108
108
  readonly config: CodefastConfig;
109
109
  readonly resolvedTargetPath: string | undefined;
110
110
  }
111
+ /**
112
+ * The inputs a tag run is invoked with.
113
+ *
114
+ * @since 0.3.16-canary.0
115
+ */
116
+ export type TagRunRequest = {
117
+ rootDir: string;
118
+ write: boolean;
119
+ targetPath?: string | undefined;
120
+ skipPackages?: Array<string> | undefined;
121
+ config?: unknown;
122
+ };
123
+ /**
124
+ * A run request paired with an optional progress listener.
125
+ *
126
+ * @since 0.3.16-canary.0
127
+ */
128
+ export type TagExecutionInput = TagRunRequest & {
129
+ readonly listener?: TagProgressListener | undefined;
130
+ };
111
131
  export {};
@@ -0,0 +1,13 @@
1
+ import type { TagTargetExecutionResult } from "#/tag/domain/types";
2
+ /**
3
+ * Collects the distinct, non-empty package versions stamped across a run's target results.
4
+ *
5
+ * @since 0.11.0
6
+ */
7
+ export declare function extractDistinctVersions(targetResults: Array<TagTargetExecutionResult>): Set<string>;
8
+ /**
9
+ * Summarizes a set of versions as `"none"`, the single version, or `"mixed"`.
10
+ *
11
+ * @since 0.11.0
12
+ */
13
+ export declare function summarizeVersions(distinctVersions: Set<string>): string;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Collects the distinct, non-empty package versions stamped across a run's target results.
3
+ *
4
+ * @since 0.11.0
5
+ */
6
+ export function extractDistinctVersions(targetResults) {
7
+ return new Set(targetResults
8
+ .map((targetResult) => targetResult.result?.version)
9
+ .filter((version) => typeof version === "string" && version.length > 0));
10
+ }
11
+ /**
12
+ * Summarizes a set of versions as `"none"`, the single version, or `"mixed"`.
13
+ *
14
+ * @since 0.11.0
15
+ */
16
+ export function summarizeVersions(distinctVersions) {
17
+ if (distinctVersions.size === 0) {
18
+ return "none";
19
+ }
20
+ if (distinctVersions.size > 1) {
21
+ return "mixed";
22
+ }
23
+ return distinctVersions.values().next().value ?? "none";
24
+ }
@@ -1,17 +1,17 @@
1
- import type { TagProgressListener, TagResolvedTarget, TagSyncResult, TagTargetExecutionResult } from "#/tag/domain/types";
1
+ import type { TagProgressListener, TagResolvedTarget, TagResult, TagTargetExecutionResult } from "#/tag/domain/types";
2
2
  /**
3
3
  * A progress listener that prints a line as each tag target starts and completes.
4
4
  *
5
5
  * @since 0.3.16-canary.0
6
6
  */
7
- export declare class TagSyncProgressPresenter implements TagProgressListener {
7
+ export declare class TagProgressPresenter implements TagProgressListener {
8
8
  onTargetStarted(target: TagResolvedTarget): void;
9
9
  onTargetCompleted(target: TagResolvedTarget, result: TagTargetExecutionResult): void;
10
10
  private static formatProgress;
11
11
  }
12
12
  /**
13
- * Prints a tag run's target table, warnings, and summary, and returns the exit code.
13
+ * Prints a tag run's target table, warnings, and summary to the human reader.
14
14
  *
15
15
  * @since 0.3.16-canary.0
16
16
  */
17
- export declare function presentTagSyncResult(result: TagSyncResult, rootDir: string): number;
17
+ export declare function presentTagResult(result: TagResult, rootDir: string): void;
@@ -1,17 +1,15 @@
1
- import { CLI_EXIT_GENERAL_ERROR } from "#/core/exit-codes";
2
1
  import { logger } from "#/core/logger";
3
- import { exitCodeForTagSyncResult } from "#/tag/cli-result";
4
2
  /**
5
3
  * A progress listener that prints a line as each tag target starts and completes.
6
4
  *
7
5
  * @since 0.3.16-canary.0
8
6
  */
9
- export class TagSyncProgressPresenter {
7
+ export class TagProgressPresenter {
10
8
  onTargetStarted(target) {
11
- logger.out(TagSyncProgressPresenter.formatProgress({ type: "target-started", target }));
9
+ logger.out(TagProgressPresenter.formatProgress({ type: "target-started", target }));
12
10
  }
13
11
  onTargetCompleted(target, result) {
14
- logger.out(TagSyncProgressPresenter.formatProgress({ type: "target-completed", target, result }));
12
+ logger.out(TagProgressPresenter.formatProgress({ type: "target-completed", target, result }));
15
13
  }
16
14
  static formatProgress(event) {
17
15
  const targetDisplayName = (target) => target.packageName ?? target.rootRelativeTargetPath;
@@ -29,22 +27,21 @@ const colors = {
29
27
  yellow: "\x1b[33m",
30
28
  };
31
29
  /**
32
- * Prints a tag run's target table, warnings, and summary, and returns the exit code.
30
+ * Prints a tag run's target table, warnings, and summary to the human reader.
33
31
  *
34
32
  * @since 0.3.16-canary.0
35
33
  */
36
- export function presentTagSyncResult(result, rootDir) {
34
+ export function presentTagResult(result, rootDir) {
37
35
  logger.out(formatTargetTable(result.selectedTargets, rootDir));
38
36
  if (result.selectedTargets.length === 0) {
39
37
  logger.err("No packages found in workspace. Check your pnpm-workspace.yaml or provide an explicit target path.");
40
- return CLI_EXIT_GENERAL_ERROR;
38
+ return;
41
39
  }
42
40
  const warningsAndErrorsSection = formatWarningsAndErrors(result);
43
41
  if (warningsAndErrorsSection) {
44
42
  logger.err(warningsAndErrorsSection);
45
43
  }
46
44
  logger.out(formatSummary(result));
47
- return exitCodeForTagSyncResult(result);
48
45
  }
49
46
  function withColorizedLine(line, colorCode) {
50
47
  return `${colorCode}${line}${colorReset}`;