@codefast/cli 0.3.15 → 0.3.16-canary.1

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 (209) hide show
  1. package/README.md +1 -1
  2. package/dist/arrange/analyze.mjs +24 -0
  3. package/dist/{domains/arrange/presentation/presenters/arrange-cli.schema.mjs → arrange/cli-schema.mjs} +10 -1
  4. package/dist/arrange/command.mjs +106 -0
  5. package/dist/{domains/arrange/domain/arrange-analyze.domain-service.mjs → arrange/domain/analyze-service.mjs} +17 -10
  6. package/dist/{domains/arrange/domain/ast/ast-node.model.mjs → arrange/domain/ast/ast-node.mjs} +57 -3
  7. package/dist/{domains/arrange/domain/ast/collectors-cn.collector.mjs → arrange/domain/ast/collectors-cn.mjs} +21 -9
  8. package/dist/{domains/arrange/domain/ast/collectors-jsx.collector.mjs → arrange/domain/ast/collectors-jsx.mjs} +5 -2
  9. package/dist/{domains/arrange/domain/ast/collectors-tv.collector.mjs → arrange/domain/ast/collectors-tv.mjs} +21 -6
  10. package/dist/{domains/arrange/domain/ast/ast-helpers.helper.mjs → arrange/domain/ast/helpers.mjs} +26 -9
  11. package/dist/{domains/arrange/domain/ast/targets.model.mjs → arrange/domain/ast/targets.mjs} +19 -10
  12. package/dist/{domains/arrange/domain/constants.domain.mjs → arrange/domain/constants.mjs} +61 -16
  13. package/dist/{domains/arrange/domain/arrange-grouping.domain-service.mjs → arrange/domain/grouping-service.mjs} +31 -10
  14. package/dist/{domains/arrange/domain/grouping.domain.mjs → arrange/domain/grouping.mjs} +39 -18
  15. package/dist/{domains/arrange/domain/imports.domain.mjs → arrange/domain/imports.mjs} +7 -3
  16. package/dist/{domains/arrange/domain/source-text-formatters.formatter.mjs → arrange/domain/source-text-formatters.mjs} +22 -5
  17. package/dist/{domains/arrange/domain/tailwind-token.value-object.mjs → arrange/domain/tailwind-token.mjs} +12 -3
  18. package/dist/{domains/arrange/domain/tailwind-token-classifier.domain-service.mjs → arrange/domain/token-classifier.mjs} +39 -14
  19. package/dist/arrange/output.mjs +79 -0
  20. package/dist/arrange/process-file.mjs +42 -0
  21. package/dist/arrange/resolve-target.mjs +24 -0
  22. package/dist/arrange/scan-target.mjs +20 -0
  23. package/dist/arrange/source-parse.mjs +18 -0
  24. package/dist/arrange/suggest.mjs +15 -0
  25. package/dist/arrange/sync.mjs +51 -0
  26. package/dist/arrange/typescript-ast-translator.mjs +354 -0
  27. package/dist/arrange/workspace.mjs +31 -0
  28. package/dist/bin.mjs +1 -1
  29. package/dist/{program.mjs → cli.mjs} +14 -20
  30. package/dist/core/cli/format-error.mjs +15 -0
  31. package/dist/core/cli/global-options.mjs +10 -0
  32. package/dist/core/cli/positional.mjs +11 -0
  33. package/dist/core/cli/result-handle.mjs +51 -0
  34. package/dist/core/config/loader.mjs +79 -0
  35. package/dist/{domains/config/domain/codefast-config.schema.mjs → core/config/schema.mjs} +16 -2
  36. package/dist/core/config/warnings.mjs +12 -0
  37. package/dist/core/config.mjs +19 -0
  38. package/dist/{shell/domain/caught-unknown-message.value-object.mjs → core/errors.mjs} +20 -4
  39. package/dist/core/exit-codes.mjs +17 -0
  40. package/dist/core/filesystem/node.mjs +32 -0
  41. package/dist/core/logger.mjs +15 -0
  42. package/dist/{shell/domain/result.model.mjs → core/result.mjs} +7 -3
  43. package/dist/core/schema-parse.mjs +18 -0
  44. package/dist/{shell/domain/source-text-edit.support.mjs → core/source-text-edit.mjs} +14 -13
  45. package/dist/core/verbose-diagnostics.mjs +11 -0
  46. package/dist/core/workspace/resolver.mjs +177 -0
  47. package/dist/core/workspace/typescript-walk.mjs +36 -0
  48. package/dist/{domains/mirror/application/mirror-sync-cli-result.mjs → mirror/cli-result.mjs} +8 -2
  49. package/dist/{domains/mirror/presentation/presenters/mirror-cli.schema.mjs → mirror/cli-schema.mjs} +4 -1
  50. package/dist/mirror/command.mjs +57 -0
  51. package/dist/mirror/dist-filesystem-impl.mjs +42 -0
  52. package/dist/{domains/mirror/domain/constants.domain.mjs → mirror/domain/constants.mjs} +16 -1
  53. package/dist/{domains/mirror/infrastructure/guards/dirent-list.guard.mjs → mirror/domain/dirent-guard.mjs} +5 -2
  54. package/dist/{domains/mirror/domain/errors.domain.mjs → mirror/domain/errors.mjs} +7 -1
  55. package/dist/{domains/mirror/domain/generate-mirror-exports.domain-service.mjs → mirror/domain/exports.mjs} +17 -10
  56. package/dist/{domains/mirror/domain/package-display-name.policy.mjs → mirror/domain/package-display-name.mjs} +5 -2
  57. package/dist/{domains/mirror/domain/path-normalizer.value-object.mjs → mirror/domain/path-normalizer.mjs} +4 -1
  58. package/dist/mirror/output.mjs +45 -0
  59. package/dist/mirror/package-path.mjs +32 -0
  60. package/dist/mirror/prepare.mjs +33 -0
  61. package/dist/mirror/sync-reporter.mjs +104 -0
  62. package/dist/mirror/sync-workspace-package.mjs +103 -0
  63. package/dist/mirror/sync.mjs +87 -0
  64. package/dist/{domains/mirror/infrastructure/package-json-exports.repository.mjs → mirror/write-exports.mjs} +11 -7
  65. package/dist/tag/cli-result.mjs +11 -0
  66. package/dist/{domains/tag/presentation/presenters/tag-cli.schema.mjs → tag/cli-schema.mjs} +4 -1
  67. package/dist/tag/command.mjs +56 -0
  68. package/dist/tag/output.mjs +87 -0
  69. package/dist/tag/prepare.mjs +29 -0
  70. package/dist/tag/resolve-target-path.mjs +12 -0
  71. package/dist/tag/since-writer.mjs +131 -0
  72. package/dist/tag/sync.mjs +141 -0
  73. package/dist/tag/target-candidates.mjs +68 -0
  74. package/dist/tag/target-runner.mjs +26 -0
  75. package/dist/tag/version-resolver.mjs +25 -0
  76. package/package.json +11 -11
  77. package/dist/bootstrap/cli-application.module.mjs +0 -18
  78. package/dist/bootstrap/composition-root.mjs +0 -14
  79. package/dist/bootstrap/register-cli-command-trees.mjs +0 -7
  80. package/dist/domains/arrange/application/ports/outbound/arrange-target-scanner.port.mjs +0 -1
  81. package/dist/domains/arrange/application/ports/outbound/domain-source-parser.port.mjs +0 -1
  82. package/dist/domains/arrange/application/ports/outbound/file-walker.port.mjs +0 -1
  83. package/dist/domains/arrange/application/ports/presenting/present-analyze-report.presenter.mjs +0 -1
  84. package/dist/domains/arrange/application/ports/presenting/present-arrange-sync-result.presenter.mjs +0 -1
  85. package/dist/domains/arrange/application/ports/presenting/present-group-file-preview.presenter.mjs +0 -1
  86. package/dist/domains/arrange/application/requests/analyze-directory.request.mjs +0 -1
  87. package/dist/domains/arrange/application/requests/arrange-sync.request.mjs +0 -1
  88. package/dist/domains/arrange/application/requests/suggest-groups.request.mjs +0 -1
  89. package/dist/domains/arrange/application/use-cases/analyze-directory.use-case.mjs +0 -255
  90. package/dist/domains/arrange/application/use-cases/prepare-arrange-workspace.use-case.mjs +0 -264
  91. package/dist/domains/arrange/application/use-cases/run-arrange-sync.use-case.mjs +0 -274
  92. package/dist/domains/arrange/application/use-cases/suggest-cn-groups.use-case.mjs +0 -237
  93. package/dist/domains/arrange/arrange.module.mjs +0 -38
  94. package/dist/domains/arrange/composition/tokens.mjs +0 -17
  95. package/dist/domains/arrange/contracts/models.mjs +0 -1
  96. package/dist/domains/arrange/domain/tailwind-grouping.domain-service.mjs +0 -231
  97. package/dist/domains/arrange/domain/types.domain.mjs +0 -1
  98. package/dist/domains/arrange/infrastructure/adapters/arrange-file-processor.adapter.mjs +0 -267
  99. package/dist/domains/arrange/infrastructure/adapters/arrange-target-path-resolver.adapter.mjs +0 -247
  100. package/dist/domains/arrange/infrastructure/adapters/arrange-target-scanner.adapter.mjs +0 -243
  101. package/dist/domains/arrange/infrastructure/adapters/domain-source-parser.adapter.mjs +0 -241
  102. package/dist/domains/arrange/infrastructure/adapters/file-walker.adapter.mjs +0 -240
  103. package/dist/domains/arrange/infrastructure/typescript-ast-translator.mjs +0 -580
  104. package/dist/domains/arrange/presentation/cli/arrange.command.mjs +0 -465
  105. package/dist/domains/arrange/presentation/presenters/arrange-analyze.presenter.mjs +0 -252
  106. package/dist/domains/arrange/presentation/presenters/arrange-sync.presenter.mjs +0 -236
  107. package/dist/domains/arrange/presentation/presenters/group-file-preview.presenter.mjs +0 -271
  108. package/dist/domains/config/application/ports/outbound/codefast-config-schema.port.mjs +0 -1
  109. package/dist/domains/config/application/ports/outbound/config-loader.port.mjs +0 -1
  110. package/dist/domains/config/application/ports/outbound/config-warning-reporter.port.mjs +0 -1
  111. package/dist/domains/config/composition/tokens.mjs +0 -7
  112. package/dist/domains/config/domain/schema.domain.mjs +0 -1
  113. package/dist/domains/config/infrastructure/adapters/config-loader.adapter.mjs +0 -305
  114. package/dist/domains/config/infrastructure/adapters/config-warning-reporter.adapter.mjs +0 -234
  115. package/dist/domains/config/infrastructure/adapters/zod-codefast-config-schema.adapter.mjs +0 -236
  116. package/dist/domains/mirror/application/ports/inbound/prepare-mirror-sync.port.mjs +0 -1
  117. package/dist/domains/mirror/application/ports/inbound/run-mirror-sync.port.mjs +0 -1
  118. package/dist/domains/mirror/application/ports/outbound/file-system-service.port.mjs +0 -1
  119. package/dist/domains/mirror/application/ports/outbound/mirror-package-path.port.mjs +0 -1
  120. package/dist/domains/mirror/application/ports/outbound/mirror-sync-reporter.port.mjs +0 -1
  121. package/dist/domains/mirror/application/ports/outbound/package-repository.port.mjs +0 -1
  122. package/dist/domains/mirror/application/ports/outbound/sync-workspace-package.port.mjs +0 -1
  123. package/dist/domains/mirror/application/ports/presenting/present-mirror-sync-progress.presenter.mjs +0 -1
  124. package/dist/domains/mirror/application/requests/mirror-sync-execution-input.mjs +0 -1
  125. package/dist/domains/mirror/application/requests/mirror-sync.request.mjs +0 -1
  126. package/dist/domains/mirror/application/use-cases/prepare-mirror-sync.use-case.mjs +0 -263
  127. package/dist/domains/mirror/application/use-cases/run-mirror-sync.use-case.mjs +0 -317
  128. package/dist/domains/mirror/composition/tokens.mjs +0 -12
  129. package/dist/domains/mirror/contracts/models.mjs +0 -1
  130. package/dist/domains/mirror/domain/types.domain.mjs +0 -1
  131. package/dist/domains/mirror/infrastructure/adapters/file-system-service.adapter.mjs +0 -261
  132. package/dist/domains/mirror/infrastructure/adapters/mirror-package-path-resolver.adapter.mjs +0 -252
  133. package/dist/domains/mirror/infrastructure/adapters/mirror-sync-reporter.adapter.mjs +0 -322
  134. package/dist/domains/mirror/infrastructure/adapters/package-repository.adapter.mjs +0 -241
  135. package/dist/domains/mirror/infrastructure/adapters/sync-workspace-package.adapter.mjs +0 -328
  136. package/dist/domains/mirror/mirror.module.mjs +0 -26
  137. package/dist/domains/mirror/presentation/cli/mirror.command.mjs +0 -328
  138. package/dist/domains/mirror/presentation/presenters/present-mirror-sync-progress.presenter.mjs +0 -265
  139. package/dist/domains/tag/application/ports/inbound/prepare-tag-sync.port.mjs +0 -1
  140. package/dist/domains/tag/application/ports/inbound/run-tag-sync.port.mjs +0 -1
  141. package/dist/domains/tag/application/ports/outbound/tag-eligible-workspace-paths.port.mjs +0 -1
  142. package/dist/domains/tag/application/ports/outbound/tag-since-writer.port.mjs +0 -1
  143. package/dist/domains/tag/application/ports/outbound/tag-target-path-resolver.port.mjs +0 -1
  144. package/dist/domains/tag/application/ports/outbound/tag-target-runner.port.mjs +0 -1
  145. package/dist/domains/tag/application/ports/outbound/tag-version-resolver.port.mjs +0 -1
  146. package/dist/domains/tag/application/ports/presenting/present-tag-sync-progress.presenter.mjs +0 -1
  147. package/dist/domains/tag/application/ports/presenting/present-tag-sync-result.presenter.mjs +0 -1
  148. package/dist/domains/tag/application/requests/tag-sync-execution-input.mjs +0 -1
  149. package/dist/domains/tag/application/requests/tag-sync.request.mjs +0 -1
  150. package/dist/domains/tag/application/tag-sync-cli-result.mjs +0 -11
  151. package/dist/domains/tag/application/use-cases/prepare-tag-sync.use-case.mjs +0 -260
  152. package/dist/domains/tag/application/use-cases/run-tag-sync.use-case.mjs +0 -375
  153. package/dist/domains/tag/composition/tokens.mjs +0 -13
  154. package/dist/domains/tag/contracts/models.mjs +0 -1
  155. package/dist/domains/tag/domain/types.domain.mjs +0 -1
  156. package/dist/domains/tag/infrastructure/adapters/tag-since-writer.adapter.mjs +0 -348
  157. package/dist/domains/tag/infrastructure/adapters/tag-target-path-resolver.adapter.mjs +0 -235
  158. package/dist/domains/tag/infrastructure/adapters/tag-target-resolver.adapter.mjs +0 -302
  159. package/dist/domains/tag/infrastructure/adapters/tag-target-runner.adapter.mjs +0 -259
  160. package/dist/domains/tag/infrastructure/adapters/tag-version-resolver.adapter.mjs +0 -249
  161. package/dist/domains/tag/presentation/cli/tag.command.mjs +0 -325
  162. package/dist/domains/tag/presentation/presenters/present-tag-sync-progress.presenter.mjs +0 -248
  163. package/dist/domains/tag/presentation/presenters/present-tag-sync-result.presenter.mjs +0 -290
  164. package/dist/domains/tag/tag.module.mjs +0 -28
  165. package/dist/shell/application/cli-runtime.tokens.mjs +0 -18
  166. package/dist/shell/application/coordination/cli-executor.coordination.mjs +0 -1
  167. package/dist/shell/application/coordination/cli-schema-parsing.coordination.mjs +0 -1
  168. package/dist/shell/application/global-cli-options.model.mjs +0 -5
  169. package/dist/shell/application/ports/inbound/load-codefast-config.port.mjs +0 -1
  170. package/dist/shell/application/ports/outbound/cli-fs.port.mjs +0 -1
  171. package/dist/shell/application/ports/outbound/cli-logger.port.mjs +0 -1
  172. package/dist/shell/application/ports/outbound/cli-path.port.mjs +0 -1
  173. package/dist/shell/application/ports/outbound/cli-runtime.port.mjs +0 -1
  174. package/dist/shell/application/ports/outbound/cli-telemetry.port.mjs +0 -1
  175. package/dist/shell/application/ports/outbound/cli-verbose-diagnostics.port.mjs +0 -1
  176. package/dist/shell/application/ports/outbound/format-app-error.port.mjs +0 -1
  177. package/dist/shell/application/ports/outbound/global-cli-options-parse.port.mjs +0 -1
  178. package/dist/shell/application/ports/outbound/repo-root-resolver.port.mjs +0 -1
  179. package/dist/shell/application/ports/outbound/typescript-source-file-walker.port.mjs +0 -1
  180. package/dist/shell/application/ports/outbound/workspace-package-layout.port.mjs +0 -1
  181. package/dist/shell/application/ports/primary/command.port.mjs +0 -1
  182. package/dist/shell/application/services/cli-executor.service.mjs +0 -267
  183. package/dist/shell/application/services/schema-validator.service.mjs +0 -236
  184. package/dist/shell/application/use-cases/load-codefast-config.use-case.mjs +0 -243
  185. package/dist/shell/composition/tokens.mjs +0 -5
  186. package/dist/shell/contracts/cli-command-slots.mjs +0 -11
  187. package/dist/shell/domain/cli-exit-codes.domain.mjs +0 -11
  188. package/dist/shell/domain/cli-positional-arg.value-object.mjs +0 -6
  189. package/dist/shell/domain/errors.domain.mjs +0 -17
  190. package/dist/shell/infrastructure/adapters/cli-verbose-diagnostics.adapter.mjs +0 -228
  191. package/dist/shell/infrastructure/adapters/format-app-error.adapter.mjs +0 -236
  192. package/dist/shell/infrastructure/adapters/global-cli-options-parser.adapter.mjs +0 -233
  193. package/dist/shell/infrastructure/adapters/repo-root-resolver.adapter.mjs +0 -244
  194. package/dist/shell/infrastructure/adapters/typescript-source-file-walker.adapter.mjs +0 -259
  195. package/dist/shell/infrastructure/commander/commander-cli-host.adapter.mjs +0 -69
  196. package/dist/shell/infrastructure/node/node-cli-fs.adapter.mjs +0 -249
  197. package/dist/shell/infrastructure/node/node-cli-logger.adapter.mjs +0 -231
  198. package/dist/shell/infrastructure/node/node-cli-path.adapter.mjs +0 -246
  199. package/dist/shell/infrastructure/node/node-cli-runtime.adapter.mjs +0 -234
  200. package/dist/shell/infrastructure/telemetry/cli-telemetry.adapter.mjs +0 -280
  201. package/dist/shell/infrastructure/workspace/node-pnpm-workspace-package-layout.adapter.mjs +0 -385
  202. package/dist/shell/shell.module.mjs +0 -43
  203. package/dist/shell/wiring/optional-cli-port-telemetry-activation.mjs +0 -13
  204. /package/dist/{domains/arrange/application/ports/inbound/analyze-directory.port.mjs → arrange/domain/types.mjs} +0 -0
  205. /package/dist/{domains/arrange/application/ports/inbound/prepare-arrange-workspace.port.mjs → core/filesystem/port.mjs} +0 -0
  206. /package/dist/{domains/arrange/application/ports/inbound/run-arrange-sync.port.mjs → mirror/domain/dist-filesystem.mjs} +0 -0
  207. /package/dist/{domains/arrange/application/ports/inbound/suggest-cn-groups.port.mjs → mirror/domain/types.mjs} +0 -0
  208. /package/dist/{domains/arrange/application/ports/outbound/arrange-file-processor.port.mjs → mirror/sync-types.mjs} +0 -0
  209. /package/dist/{domains/arrange/application/ports/outbound/arrange-target-path-resolver.port.mjs → tag/domain/types.mjs} +0 -0
@@ -0,0 +1,87 @@
1
+ import { AppError, messageFrom } from "../core/errors.mjs";
2
+ import { err, ok } from "../core/result.mjs";
3
+ import { listWorkspacePackageDirectories } from "../core/workspace/resolver.mjs";
4
+ import { normalizePath } from "./domain/path-normalizer.mjs";
5
+ import { resolvePackageFilterUnderRoot } from "./package-path.mjs";
6
+ import { syncExportsForWorkspacePackage } from "./sync-workspace-package.mjs";
7
+ import path from "node:path";
8
+ //#region src/mirror/sync.ts
9
+ /**
10
+ * @since 0.3.16-canary.0
11
+ */
12
+ async function runMirrorSync(fs, input) {
13
+ const config = input.config ?? {};
14
+ const { listener } = input;
15
+ listener?.onBanner();
16
+ const startTime = performance.now();
17
+ try {
18
+ let targetPackages = [];
19
+ if (input.packageFilter) {
20
+ const filterOutcome = resolvePackageFilterUnderRoot(fs, input.rootDir, input.packageFilter);
21
+ if (!filterOutcome.ok) return filterOutcome;
22
+ targetPackages = [filterOutcome.value];
23
+ listener?.onProcessingMode({ kind: "single" });
24
+ } else {
25
+ const layoutOutcome = await listWorkspacePackageDirectories(input.rootDir, fs, false);
26
+ const { relPaths, multiSource } = mirrorTargetsFromWorkspaceLayout(input.rootDir, layoutOutcome);
27
+ targetPackages = relPaths;
28
+ listener?.onProcessingMode({
29
+ kind: "multi",
30
+ source: multiSource
31
+ });
32
+ }
33
+ const stats = {
34
+ packagesFound: targetPackages.length,
35
+ packagesProcessed: 0,
36
+ packagesSkipped: 0,
37
+ packagesErrored: 0,
38
+ totalExports: 0,
39
+ totalJsModules: 0,
40
+ totalCssExports: 0,
41
+ packageDetails: []
42
+ };
43
+ if (targetPackages.length === 0) {
44
+ listener?.onNoPackages();
45
+ listener?.onComplete(stats, (performance.now() - startTime) / 1e3);
46
+ return ok(stats);
47
+ }
48
+ let ordinal = 1;
49
+ for (const pkgPath of targetPackages) {
50
+ const pkgStats = await syncExportsForWorkspacePackage(fs, input.rootDir, pkgPath, config);
51
+ stats.packageDetails.push(pkgStats);
52
+ listener?.onPackageComplete(pkgStats, ordinal, targetPackages.length);
53
+ ordinal++;
54
+ accumulateStats(stats, pkgStats);
55
+ }
56
+ const elapsed = (performance.now() - startTime) / 1e3;
57
+ listener?.onComplete(stats, elapsed);
58
+ return ok(stats);
59
+ } catch (caughtError) {
60
+ return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
61
+ }
62
+ }
63
+ function accumulateStats(stats, pkgStats) {
64
+ if (pkgStats.skipped) stats.packagesSkipped++;
65
+ else if (pkgStats.error !== null) stats.packagesErrored++;
66
+ else {
67
+ stats.packagesProcessed++;
68
+ stats.totalExports += pkgStats.totalExports;
69
+ stats.totalJsModules += pkgStats.jsModules;
70
+ stats.totalCssExports += pkgStats.cssExports;
71
+ }
72
+ }
73
+ function mirrorTargetsFromWorkspaceLayout(rootDir, layoutOutcome) {
74
+ if (layoutOutcome.layoutSource === "declared-empty") return {
75
+ relPaths: [],
76
+ multiSource: "declared-empty"
77
+ };
78
+ const multiSource = layoutOutcome.layoutSource;
79
+ const relPaths = layoutOutcome.packageDirectoryPathsAbsolute.map((absolutePath) => normalizePath(path.relative(rootDir, absolutePath))).filter((relativePath) => relativePath.length > 0);
80
+ relPaths.sort((left, right) => left.localeCompare(right));
81
+ return {
82
+ relPaths,
83
+ multiSource
84
+ };
85
+ }
86
+ //#endregion
87
+ export { runMirrorSync };
@@ -1,11 +1,14 @@
1
- import { messageFromCaughtUnknown } from "../../../shell/domain/caught-unknown-message.value-object.mjs";
2
- import { MirrorError, MirrorErrorCode } from "../domain/errors.domain.mjs";
3
- import { PACKAGE_JSON_EXPORT } from "../domain/constants.domain.mjs";
4
- //#region src/domains/mirror/infrastructure/package-json-exports.repository.ts
1
+ import { messageFrom } from "../core/errors.mjs";
2
+ import { PACKAGE_JSON_EXPORT } from "./domain/constants.mjs";
3
+ import { MirrorError, MirrorErrorCode } from "./domain/errors.mjs";
4
+ //#region src/mirror/write-exports.ts
5
5
  /**
6
6
  * Writes `exports` into `package.json` via a temp file + rename (atomic on same volume).
7
7
  * Preserves a trailing newline after JSON.
8
- */ async function writePackageJsonExportsAtomic(fs, packageJsonPath, mergeInput) {
8
+ *
9
+ * @since 0.3.16-canary.0
10
+ */
11
+ async function writePackageJsonExportsAtomic(fs, packageJsonPath, mergeInput) {
9
12
  function containsDistTarget(value) {
10
13
  if (typeof value === "string") return value.startsWith("./dist/");
11
14
  if (Array.isArray(value)) return value.some((entryValue) => containsDistTarget(entryValue));
@@ -15,7 +18,8 @@ import { PACKAGE_JSON_EXPORT } from "../domain/constants.domain.mjs";
15
18
  /**
16
19
  * Keep `./package.json` at the very end for aesthetics by default.
17
20
  * If a catch-all `./*` exists, move `./package.json` before wildcards so it remains reachable.
18
- */ function exportSpecifierRank(exportSpecifier, hasCatchAllWildcard) {
21
+ */
22
+ function exportSpecifierRank(exportSpecifier, hasCatchAllWildcard) {
19
23
  if (exportSpecifier === ".") return 0;
20
24
  if (exportSpecifier === "./package.json") return hasCatchAllWildcard ? 2 : 4;
21
25
  if (exportSpecifier.includes("*")) return 3;
@@ -81,7 +85,7 @@ import { PACKAGE_JSON_EXPORT } from "../domain/constants.domain.mjs";
81
85
  await fs.rename(tmpPath, packageJsonPath);
82
86
  } catch (caughtRenameError) {
83
87
  await fs.unlink(tmpPath).catch(() => {});
84
- throw new MirrorError(MirrorErrorCode.PACKAGE_WRITE, `Failed to atomically update ${packageJsonPath}: ${messageFromCaughtUnknown(caughtRenameError)}`, caughtRenameError instanceof Error ? { cause: caughtRenameError } : void 0);
88
+ throw new MirrorError(MirrorErrorCode.PACKAGE_WRITE, `Failed to atomically update ${packageJsonPath}: ${messageFrom(caughtRenameError)}`, caughtRenameError instanceof Error ? { cause: caughtRenameError } : void 0);
85
89
  }
86
90
  return { prunedKeys };
87
91
  }
@@ -0,0 +1,11 @@
1
+ import "../core/exit-codes.mjs";
2
+ //#region src/tag/cli-result.ts
3
+ /**
4
+ * @since 0.3.16-canary.0
5
+ */
6
+ function exitCodeForTagSyncResult(result) {
7
+ if (result.selectedTargets.length === 0) return 1;
8
+ return result.targetResults.some((targetResult) => targetResult.runError !== null) || result.hookError !== null ? 1 : 0;
9
+ }
10
+ //#endregion
11
+ export { exitCodeForTagSyncResult };
@@ -1,5 +1,8 @@
1
1
  import { z } from "zod";
2
- //#region src/domains/tag/presentation/presenters/tag-cli.schema.ts
2
+ //#region src/tag/cli-schema.ts
3
+ /**
4
+ * @since 0.3.16-canary.0
5
+ */
3
6
  const tagSyncRunRequestSchema = z.object({
4
7
  rootDir: z.string().min(1),
5
8
  write: z.boolean(),
@@ -0,0 +1,56 @@
1
+ import { parseWithSchema } from "../core/schema-parse.mjs";
2
+ import { logger } from "../core/logger.mjs";
3
+ import { consumeCliAppError } from "../core/cli/result-handle.mjs";
4
+ import { nodeFilesystem } from "../core/filesystem/node.mjs";
5
+ import { readOptionalPositionalArg } from "../core/cli/positional.mjs";
6
+ import { prepareTagSync } from "./prepare.mjs";
7
+ import { runTagSync } from "./sync.mjs";
8
+ import { tagSyncRunRequestSchema } from "./cli-schema.mjs";
9
+ import { exitCodeForTagSyncResult } from "./cli-result.mjs";
10
+ import { TagSyncProgressPresenter, presentTagSyncResult } from "./output.mjs";
11
+ import process from "node:process";
12
+ import { Command } from "commander";
13
+ //#region src/tag/command.ts
14
+ /**
15
+ * @since 0.3.16-canary.0
16
+ */
17
+ function createTagCommand() {
18
+ return new Command("tag").description("Add @since <version> JSDoc tags to exported declarations").alias("annotate").argument("[target]", "Directory or file to annotate (default: auto-discover workspace packages)").option("--dry-run", "Show summary without writing files", false).option("--json", "Print one JSON summary on stdout (suppresses human progress)", false).action(async (target, opts) => {
19
+ const prelude = await prepareTagSync(nodeFilesystem, {
20
+ currentWorkingDirectory: process.cwd(),
21
+ rawTarget: readOptionalPositionalArg(target)
22
+ });
23
+ if (!consumeCliAppError(prelude)) return;
24
+ const { rootDir, config, resolvedTargetPath } = prelude.value;
25
+ const tagConfig = config.tag ?? {};
26
+ const parsed = parseWithSchema(tagSyncRunRequestSchema, {
27
+ rootDir,
28
+ write: !opts.dryRun,
29
+ json: opts.json,
30
+ targetPath: resolvedTargetPath,
31
+ skipPackages: tagConfig.skipPackages,
32
+ config: tagConfig
33
+ });
34
+ if (!consumeCliAppError(parsed)) return;
35
+ const progressPresenter = new TagSyncProgressPresenter();
36
+ const tagOutcome = await runTagSync(nodeFilesystem, {
37
+ ...parsed.value,
38
+ listener: parsed.value.json ? void 0 : progressPresenter
39
+ });
40
+ if (!consumeCliAppError(tagOutcome)) return;
41
+ if (parsed.value.json) {
42
+ logger.out(formatTagSyncJsonOutput(tagOutcome.value, rootDir));
43
+ process.exitCode = exitCodeForTagSyncResult(tagOutcome.value);
44
+ } else process.exitCode = presentTagSyncResult(tagOutcome.value, rootDir);
45
+ });
46
+ }
47
+ function formatTagSyncJsonOutput(result, rootDir) {
48
+ return JSON.stringify({
49
+ schemaVersion: 1,
50
+ ok: result.hookError === null,
51
+ cwd: rootDir,
52
+ result
53
+ });
54
+ }
55
+ //#endregion
56
+ export { createTagCommand };
@@ -0,0 +1,87 @@
1
+ import "../core/exit-codes.mjs";
2
+ import { logger } from "../core/logger.mjs";
3
+ import { exitCodeForTagSyncResult } from "./cli-result.mjs";
4
+ //#region src/tag/output.ts
5
+ /**
6
+ * @since 0.3.16-canary.0
7
+ */
8
+ var TagSyncProgressPresenter = class TagSyncProgressPresenter {
9
+ onTargetStarted(target) {
10
+ logger.out(TagSyncProgressPresenter.formatProgress({
11
+ type: "target-started",
12
+ target
13
+ }));
14
+ }
15
+ onTargetCompleted(target, result) {
16
+ logger.out(TagSyncProgressPresenter.formatProgress({
17
+ type: "target-completed",
18
+ target,
19
+ result
20
+ }));
21
+ }
22
+ static formatProgress(event) {
23
+ const targetDisplayName = (target) => target.packageName ?? target.rootRelativeTargetPath;
24
+ if (event.type === "target-started") return `[tag] Processing ${targetDisplayName(event.target)}...`;
25
+ const changedFiles = event.result.result?.filesChanged ?? 0;
26
+ return `[tag] Done ${targetDisplayName(event.target)} (${changedFiles} changes)`;
27
+ }
28
+ };
29
+ const colorReset = "\x1B[0m";
30
+ const colors = {
31
+ red: "\x1B[31m",
32
+ green: "\x1B[32m",
33
+ yellow: "\x1B[33m"
34
+ };
35
+ /**
36
+ * @since 0.3.16-canary.0
37
+ */
38
+ function presentTagSyncResult(result, rootDir) {
39
+ logger.out(formatTargetTable(result.selectedTargets, rootDir));
40
+ if (result.selectedTargets.length === 0) {
41
+ logger.err("No packages found in workspace. Check your pnpm-workspace.yaml or provide an explicit target path.");
42
+ return 1;
43
+ }
44
+ const warningsAndErrorsSection = formatWarningsAndErrors(result);
45
+ if (warningsAndErrorsSection) logger.err(warningsAndErrorsSection);
46
+ logger.out(formatSummary(result));
47
+ return exitCodeForTagSyncResult(result);
48
+ }
49
+ function withColorizedLine(line, colorCode) {
50
+ return `${colorCode}${line}${colorReset}`;
51
+ }
52
+ function warningsAndErrorsFromResult(result) {
53
+ const entries = [];
54
+ for (const targetResult of result.targetResults) if (targetResult.runError) entries.push(targetResult.runError);
55
+ if (result.hookError) entries.push(result.hookError);
56
+ return entries;
57
+ }
58
+ function formatTargetTable(targets, rootDir) {
59
+ const packageColumnWidth = Math.max(7, ...targets.map((target) => (target.packageName ?? "-").length));
60
+ const pathColumnWidth = Math.max(4, ...targets.map((target) => target.rootRelativeTargetPath.length));
61
+ const lines = [];
62
+ lines.push(`[tag] Root: ${rootDir}`);
63
+ lines.push(`[tag] Resolved targets: ${targets.length}`);
64
+ lines.push("[tag] Targets:");
65
+ lines.push(` ${"package".padEnd(packageColumnWidth)} ${"path".padEnd(pathColumnWidth)} source`);
66
+ lines.push(` ${"-".repeat(packageColumnWidth)} ${"-".repeat(pathColumnWidth)} ${"-".repeat(6)}`);
67
+ for (const target of targets) lines.push(` ${(target.packageName ?? "-").padEnd(packageColumnWidth)} ${target.rootRelativeTargetPath.padEnd(pathColumnWidth)} ${target.source}`);
68
+ return lines.join("\n");
69
+ }
70
+ function formatWarningsAndErrors(result) {
71
+ const entries = warningsAndErrorsFromResult(result);
72
+ if (entries.length === 0) return null;
73
+ const lines = [withColorizedLine("⚠️ Warnings & Errors", colors.yellow)];
74
+ for (const entry of entries) lines.push(withColorizedLine(`- ${entry}`, colors.red));
75
+ return lines.join("\n");
76
+ }
77
+ function formatSummary(result) {
78
+ const isDryRun = result.mode === "dry-run";
79
+ const summaryPrefix = isDryRun ? "[tag:dry-run]" : "[tag]";
80
+ const versionSuffix = result.versionSummary === "mixed" && result.distinctVersions.length > 0 ? ` [${result.distinctVersions.join(", ")}]` : "";
81
+ const summaryColor = result.targetResults.some((targetResult) => targetResult.runError !== null) || result.hookError !== null ? colors.red : isDryRun ? colors.yellow : colors.green;
82
+ const lines = [withColorizedLine(`${summaryPrefix} version=${result.versionSummary}${versionSuffix} files=${result.filesChanged}/${result.filesScanned} declarations=${result.taggedDeclarations}`, summaryColor)];
83
+ if (result.skippedPackages.length > 0) lines.push(`[tag] Skipped: ${result.skippedPackages.length} package(s)`);
84
+ return lines.join("\n");
85
+ }
86
+ //#endregion
87
+ export { TagSyncProgressPresenter, presentTagSyncResult };
@@ -0,0 +1,29 @@
1
+ import { ok } from "../core/result.mjs";
2
+ import { loadCodefastConfig } from "../core/config.mjs";
3
+ import { findRepoRoot } from "../core/workspace/resolver.mjs";
4
+ import { resolveProvidedTagTargetPath } from "./resolve-target-path.mjs";
5
+ //#region src/tag/prepare.ts
6
+ /**
7
+ * @since 0.3.16-canary.0
8
+ */
9
+ async function prepareTagSync(fs, args) {
10
+ let rootDir;
11
+ try {
12
+ rootDir = findRepoRoot(args.currentWorkingDirectory, fs);
13
+ } catch {
14
+ rootDir = args.currentWorkingDirectory;
15
+ }
16
+ const loadedOutcome = await loadCodefastConfig(rootDir, fs);
17
+ if (!loadedOutcome.ok) return loadedOutcome;
18
+ const resolvedTargetPath = resolveProvidedTagTargetPath(fs, {
19
+ currentWorkingDirectory: args.currentWorkingDirectory,
20
+ rawTarget: args.rawTarget
21
+ });
22
+ return ok({
23
+ rootDir,
24
+ config: loadedOutcome.value.config,
25
+ resolvedTargetPath
26
+ });
27
+ }
28
+ //#endregion
29
+ export { prepareTagSync };
@@ -0,0 +1,12 @@
1
+ import path from "node:path";
2
+ //#region src/tag/resolve-target-path.ts
3
+ /**
4
+ * @since 0.3.16-canary.0
5
+ */
6
+ function resolveProvidedTagTargetPath(fs, args) {
7
+ if (args.rawTarget === void 0) return;
8
+ const candidate = path.isAbsolute(args.rawTarget) ? path.resolve(args.rawTarget) : path.resolve(args.currentWorkingDirectory, args.rawTarget);
9
+ return fs.canonicalPathSync(candidate);
10
+ }
11
+ //#endregion
12
+ export { resolveProvidedTagTargetPath };
@@ -0,0 +1,131 @@
1
+ import { applyEditsDescending, indentOfLineContaining } from "../core/source-text-edit.mjs";
2
+ import ts from "typescript";
3
+ //#region src/tag/since-writer.ts
4
+ /**
5
+ * @since 0.3.16-canary.0
6
+ */
7
+ var TagSinceWriter = class {
8
+ fs;
9
+ sinceDocumentationTag = "@since";
10
+ constructor(fs) {
11
+ this.fs = fs;
12
+ }
13
+ applySinceTagsToFile(filePath, version, write) {
14
+ const sourceText = this.fs.readFileSync(filePath, "utf8");
15
+ const sf = ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true, filePath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
16
+ const edits = [];
17
+ for (const declaration of this.collectExportedDeclarations(sf)) {
18
+ const edit = this.makeDeclarationSinceLine(declaration, sf, sourceText, version);
19
+ if (edit) edits.push(edit);
20
+ }
21
+ if (edits.length > 0 && write) {
22
+ const updated = applyEditsDescending(sourceText, edits);
23
+ this.fs.writeFileSync(filePath, updated, "utf8");
24
+ }
25
+ return {
26
+ filePath,
27
+ taggedDeclarations: edits.length,
28
+ changed: edits.length > 0
29
+ };
30
+ }
31
+ hasExportModifier(node) {
32
+ return (ts.canHaveModifiers(node) ? ts.getModifiers(node) : void 0)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ?? false;
33
+ }
34
+ isTaggableDeclaration(node) {
35
+ return ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isEnumDeclaration(node) || ts.isVariableStatement(node);
36
+ }
37
+ addDeclarationName(registry, name, declaration) {
38
+ if (!registry.has(name)) {
39
+ registry.set(name, new Set([declaration]));
40
+ return;
41
+ }
42
+ const bucket = registry.get(name);
43
+ if (bucket === void 0) throw new Error(`declaration registry missing set for ${name}`);
44
+ bucket.add(declaration);
45
+ }
46
+ collectLocalNamedDeclarations(sf) {
47
+ const declarations = /* @__PURE__ */ new Map();
48
+ for (const statement of sf.statements) {
49
+ if (ts.isFunctionDeclaration(statement) && statement.name) {
50
+ this.addDeclarationName(declarations, statement.name.text, statement);
51
+ continue;
52
+ }
53
+ if (ts.isClassDeclaration(statement) && statement.name) {
54
+ this.addDeclarationName(declarations, statement.name.text, statement);
55
+ continue;
56
+ }
57
+ if (ts.isInterfaceDeclaration(statement)) {
58
+ this.addDeclarationName(declarations, statement.name.text, statement);
59
+ continue;
60
+ }
61
+ if (ts.isTypeAliasDeclaration(statement)) {
62
+ this.addDeclarationName(declarations, statement.name.text, statement);
63
+ continue;
64
+ }
65
+ if (ts.isEnumDeclaration(statement)) {
66
+ this.addDeclarationName(declarations, statement.name.text, statement);
67
+ continue;
68
+ }
69
+ if (!ts.isVariableStatement(statement)) continue;
70
+ for (const declaration of statement.declarationList.declarations) if (ts.isIdentifier(declaration.name)) this.addDeclarationName(declarations, declaration.name.text, statement);
71
+ }
72
+ return declarations;
73
+ }
74
+ collectExportedDeclarations(sf) {
75
+ const exported = /* @__PURE__ */ new Set();
76
+ const localNamed = this.collectLocalNamedDeclarations(sf);
77
+ for (const statement of sf.statements) {
78
+ if (this.isTaggableDeclaration(statement) && this.hasExportModifier(statement)) {
79
+ exported.add(statement);
80
+ continue;
81
+ }
82
+ if (ts.isExportDeclaration(statement) && !statement.moduleSpecifier && statement.exportClause && ts.isNamedExports(statement.exportClause)) {
83
+ for (const element of statement.exportClause.elements) {
84
+ const localName = element.propertyName?.text ?? element.name.text;
85
+ const declarations = localNamed.get(localName);
86
+ if (!declarations) continue;
87
+ for (const declaration of declarations) exported.add(declaration);
88
+ }
89
+ continue;
90
+ }
91
+ if (!ts.isExportAssignment(statement) || !ts.isIdentifier(statement.expression)) continue;
92
+ const declarations = localNamed.get(statement.expression.text);
93
+ if (!declarations) continue;
94
+ for (const declaration of declarations) exported.add(declaration);
95
+ }
96
+ return exported;
97
+ }
98
+ makeJSDocSinceLine(existingComment, sourceText, version) {
99
+ const commentText = sourceText.slice(existingComment.pos, existingComment.end);
100
+ const baseIndent = indentOfLineContaining(sourceText, existingComment.pos);
101
+ const normalizedBodyLines = commentText.replace(/^\/\*\*\s?/, "").replace(/\s*\*\/$/, "").split("\n").map((line) => line.replace(/^\s*\*\s?/, "").replace(/\s+$/, "")).filter((line, lineIndex, lines) => {
102
+ if (line.length > 0) return true;
103
+ const hasNonEmptyBefore = lines.slice(0, lineIndex).some((value) => value.length > 0);
104
+ const hasNonEmptyAfter = lines.slice(lineIndex + 1).some((value) => value.length > 0);
105
+ return hasNonEmptyBefore && hasNonEmptyAfter;
106
+ });
107
+ const replacement = `/**\n${normalizedBodyLines.length > 0 ? `${normalizedBodyLines.map((line) => line.length > 0 ? `${baseIndent} * ${line}` : `${baseIndent} *`).join("\n")}\n${baseIndent} *\n` : ""}${baseIndent} * ${this.sinceDocumentationTag} ${version}\n${baseIndent} */`;
108
+ return {
109
+ start: existingComment.pos,
110
+ end: existingComment.end,
111
+ replacement
112
+ };
113
+ }
114
+ makeSinceOnlyJSDocBlock(declarationIndent, version) {
115
+ return `/**\n${declarationIndent} * ${this.sinceDocumentationTag} ${version}\n${declarationIndent} */`;
116
+ }
117
+ makeDeclarationSinceLine(declaration, sf, sourceText, version) {
118
+ if (ts.getJSDocTags(declaration).some((tag) => tag.tagName.text === "since")) return;
119
+ const lastJsDoc = ts.getJSDocCommentsAndTags(declaration).filter(ts.isJSDoc).at(-1);
120
+ if (lastJsDoc) return this.makeJSDocSinceLine(lastJsDoc, sourceText, version);
121
+ const start = declaration.getStart(sf);
122
+ const indent = indentOfLineContaining(sourceText, start);
123
+ return {
124
+ start,
125
+ end: start,
126
+ replacement: `${indent}${this.makeSinceOnlyJSDocBlock(indent, version)}\n${indent}`
127
+ };
128
+ }
129
+ };
130
+ //#endregion
131
+ export { TagSinceWriter };
@@ -0,0 +1,141 @@
1
+ import { AppError, messageFrom } from "../core/errors.mjs";
2
+ import { err, ok } from "../core/result.mjs";
3
+ import { resolveTagTargetCandidates } from "./target-candidates.mjs";
4
+ import { runTagOnTarget } from "./target-runner.mjs";
5
+ import path from "node:path";
6
+ //#region src/tag/sync.ts
7
+ /**
8
+ * @since 0.3.16-canary.0
9
+ */
10
+ async function runTagSync(fs, input) {
11
+ try {
12
+ const tagConfig = input.config;
13
+ const { includedCandidates, skippedPackages } = filterSkippedCandidates(await resolveTagTargetCandidates(fs, input.rootDir, input.targetPath), input.skipPackages);
14
+ const selectedTargets = includedCandidates.map((candidate) => resolveTargetSelection(fs, candidate, input.rootDir));
15
+ const targetExecutionResults = await Promise.all(selectedTargets.map((resolvedTarget) => runOnResolvedTarget(fs, resolvedTarget, input.write, input.listener)));
16
+ const allFileResults = targetExecutionResults.flatMap((targetResult) => targetResult.result?.fileResults ?? []);
17
+ const filesScanned = targetExecutionResults.reduce((sum, targetResult) => sum + (targetResult.result?.filesScanned ?? 0), 0);
18
+ const filesChanged = targetExecutionResults.reduce((sum, targetResult) => sum + (targetResult.result?.filesChanged ?? 0), 0);
19
+ const taggedDeclarations = targetExecutionResults.reduce((sum, targetResult) => sum + (targetResult.result?.taggedDeclarations ?? 0), 0);
20
+ const modifiedFiles = allFileResults.filter((entry) => entry.changed).map((entry) => entry.filePath);
21
+ const hookError = input.write && modifiedFiles.length > 0 ? await runTagOnAfterWriteHook(tagConfig?.onAfterWrite, modifiedFiles) : null;
22
+ const versionsSet = extractDistinctVersions(targetExecutionResults);
23
+ const distinctVersions = [...versionsSet].sort((left, right) => left.localeCompare(right));
24
+ return ok({
25
+ mode: input.write ? "applied" : "dry-run",
26
+ selectedTargets,
27
+ skippedPackages,
28
+ targetResults: targetExecutionResults,
29
+ filesScanned,
30
+ filesChanged,
31
+ taggedDeclarations,
32
+ versionSummary: summarizeVersions(versionsSet),
33
+ distinctVersions,
34
+ modifiedFiles,
35
+ hookError
36
+ });
37
+ } catch (caughtError) {
38
+ return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
39
+ }
40
+ }
41
+ async function runTagOnAfterWriteHook(hook, modifiedFiles) {
42
+ if (!hook || modifiedFiles.length === 0) return null;
43
+ try {
44
+ await hook({ files: modifiedFiles });
45
+ return null;
46
+ } catch (caughtHookError) {
47
+ return `[tag] onAfterWrite hook failed: ${messageFrom(caughtHookError)}`;
48
+ }
49
+ }
50
+ function summarizeVersions(distinctVersions) {
51
+ if (distinctVersions.size === 0) return "none";
52
+ if (distinctVersions.size > 1) return "mixed";
53
+ return distinctVersions.values().next().value ?? "none";
54
+ }
55
+ function extractDistinctVersions(targetResults) {
56
+ return new Set(targetResults.map((targetResult) => targetResult.result?.version).filter((version) => typeof version === "string" && version.length > 0));
57
+ }
58
+ function chooseWorkspacePackageTargetPath(fs, candidate) {
59
+ if (candidate.source !== "workspace-package") return {
60
+ targetPath: candidate.candidatePath,
61
+ source: candidate.source
62
+ };
63
+ const preferredSourceDir = path.join(candidate.candidatePath, "src");
64
+ try {
65
+ if (fs.statSync(preferredSourceDir).isDirectory()) return {
66
+ targetPath: preferredSourceDir,
67
+ source: "workspace-package-selected-src"
68
+ };
69
+ } catch {}
70
+ return {
71
+ targetPath: candidate.candidatePath,
72
+ source: "workspace-package-selected-root"
73
+ };
74
+ }
75
+ function resolveTargetSelection(fs, candidate, rootDir) {
76
+ const selectedTarget = chooseWorkspacePackageTargetPath(fs, candidate);
77
+ const rootRelativeTargetPath = path.relative(rootDir, selectedTarget.targetPath).split(path.sep).join("/");
78
+ return {
79
+ targetPath: selectedTarget.targetPath,
80
+ rootRelativeTargetPath: rootRelativeTargetPath || ".",
81
+ source: selectedTarget.source,
82
+ packageDir: candidate.packageDir,
83
+ packageName: candidate.packageName
84
+ };
85
+ }
86
+ function filterSkippedCandidates(targetCandidates, skipPackages) {
87
+ if (!skipPackages || skipPackages.length === 0) return {
88
+ includedCandidates: targetCandidates,
89
+ skippedPackages: []
90
+ };
91
+ const skipPackageSet = new Set(skipPackages);
92
+ const includedCandidates = [];
93
+ const skippedPackages = [];
94
+ for (const candidate of targetCandidates) {
95
+ const packageName = candidate.packageName;
96
+ if (packageName && skipPackageSet.has(packageName)) {
97
+ skippedPackages.push(packageName);
98
+ continue;
99
+ }
100
+ includedCandidates.push(candidate);
101
+ }
102
+ return {
103
+ includedCandidates,
104
+ skippedPackages
105
+ };
106
+ }
107
+ async function runOnResolvedTarget(fs, resolvedTarget, write, listener) {
108
+ listener?.onTargetStarted(resolvedTarget);
109
+ const absoluteTargetPath = path.resolve(resolvedTarget.targetPath);
110
+ if (!fs.existsSync(absoluteTargetPath)) {
111
+ const missingTargetResult = {
112
+ target: resolvedTarget,
113
+ targetExists: false,
114
+ runError: `Not found: ${absoluteTargetPath}`,
115
+ result: null
116
+ };
117
+ listener?.onTargetCompleted(resolvedTarget, missingTargetResult);
118
+ return missingTargetResult;
119
+ }
120
+ try {
121
+ const targetRunResult = {
122
+ target: resolvedTarget,
123
+ targetExists: true,
124
+ runError: null,
125
+ result: runTagOnTarget(fs, absoluteTargetPath, { write })
126
+ };
127
+ listener?.onTargetCompleted(resolvedTarget, targetRunResult);
128
+ return targetRunResult;
129
+ } catch (caughtRunError) {
130
+ const failedTargetRunResult = {
131
+ target: resolvedTarget,
132
+ targetExists: true,
133
+ runError: messageFrom(caughtRunError),
134
+ result: null
135
+ };
136
+ listener?.onTargetCompleted(resolvedTarget, failedTargetRunResult);
137
+ return failedTargetRunResult;
138
+ }
139
+ }
140
+ //#endregion
141
+ export { runTagSync };
@@ -0,0 +1,68 @@
1
+ import { listWorkspacePackageDirectories } from "../core/workspace/resolver.mjs";
2
+ import path from "node:path";
3
+ import { z } from "zod";
4
+ //#region src/tag/target-candidates.ts
5
+ const packageJsonFileName = "package.json";
6
+ const packageJsonNameSchema = z.looseObject({ name: z.string().min(1).optional() });
7
+ function toPosix(filePath) {
8
+ return filePath.split(path.sep).join("/");
9
+ }
10
+ function readPackageName(fs, packageDir) {
11
+ const packageJsonPath = path.join(packageDir, packageJsonFileName);
12
+ if (!fs.existsSync(packageJsonPath)) return null;
13
+ try {
14
+ const rawPackageJson = fs.readFileSync(packageJsonPath, "utf8");
15
+ const parsedPackageJson = JSON.parse(rawPackageJson);
16
+ const parsedPackageName = packageJsonNameSchema.safeParse(parsedPackageJson);
17
+ if (!parsedPackageName.success) return null;
18
+ return parsedPackageName.data.name ?? null;
19
+ } catch {
20
+ return null;
21
+ }
22
+ }
23
+ function toRootRelativePath(rootDir, absolutePath) {
24
+ const relativePath = path.relative(rootDir, absolutePath);
25
+ return relativePath ? toPosix(relativePath) : ".";
26
+ }
27
+ function toPackageTargetCandidate(fs, rootDir, packageDir) {
28
+ const packageName = readPackageName(fs, packageDir);
29
+ return {
30
+ candidatePath: packageDir,
31
+ rootRelativeCandidatePath: toRootRelativePath(rootDir, packageDir),
32
+ source: "workspace-package",
33
+ packageDir,
34
+ packageName
35
+ };
36
+ }
37
+ /**
38
+ * @since 0.3.16-canary.0
39
+ */
40
+ async function resolveTagTargetCandidates(fs, rootDir, explicitTarget) {
41
+ if (explicitTarget) {
42
+ const resolvedExplicitTarget = path.resolve(explicitTarget);
43
+ return [{
44
+ candidatePath: resolvedExplicitTarget,
45
+ rootRelativeCandidatePath: toRootRelativePath(rootDir, resolvedExplicitTarget),
46
+ source: "explicit-target",
47
+ packageDir: null,
48
+ packageName: null
49
+ }];
50
+ }
51
+ const outcome = await listWorkspacePackageDirectories(rootDir, fs, true);
52
+ const packageDirs = [...outcome.packageDirectoryPathsAbsolute];
53
+ const hasWorkspaceFile = outcome.hasPnpmWorkspaceYamlFile;
54
+ if (packageDirs.length === 0) {
55
+ if (hasWorkspaceFile) return [];
56
+ const repoSourceDir = path.join(rootDir, "src");
57
+ return [{
58
+ candidatePath: repoSourceDir,
59
+ rootRelativeCandidatePath: toRootRelativePath(rootDir, repoSourceDir),
60
+ source: "repo-src-fallback",
61
+ packageDir: null,
62
+ packageName: null
63
+ }];
64
+ }
65
+ return packageDirs.map((packageDir) => toPackageTargetCandidate(fs, rootDir, packageDir));
66
+ }
67
+ //#endregion
68
+ export { resolveTagTargetCandidates };