@codefast/cli 0.3.14 → 0.3.16-canary.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 (189) hide show
  1. package/README.md +8 -3
  2. package/dist/arrange/analyze.mjs +24 -0
  3. package/dist/{lib/arrange/presentation/arrange-cli.schema.mjs → arrange/cli-schema.mjs} +10 -1
  4. package/dist/arrange/command.mjs +106 -0
  5. package/dist/{lib/arrange/domain/arrange-analyze.service.mjs → arrange/domain/analyze-service.mjs} +17 -10
  6. package/dist/{lib/arrange/domain/ast/ast-node.model.mjs → arrange/domain/ast/ast-node.mjs} +57 -3
  7. package/dist/{lib/arrange/domain/ast/collectors-cn.collector.mjs → arrange/domain/ast/collectors-cn.mjs} +21 -9
  8. package/dist/{lib/arrange/domain/ast/collectors-jsx.collector.mjs → arrange/domain/ast/collectors-jsx.mjs} +5 -2
  9. package/dist/{lib/arrange/domain/ast/collectors-tv.collector.mjs → arrange/domain/ast/collectors-tv.mjs} +21 -6
  10. package/dist/{lib/arrange/domain/ast/ast-helpers.helper.mjs → arrange/domain/ast/helpers.mjs} +26 -9
  11. package/dist/{lib/arrange/domain/ast/targets.model.mjs → arrange/domain/ast/targets.mjs} +19 -10
  12. package/dist/{lib/arrange/domain/constants.domain.mjs → arrange/domain/constants.mjs} +63 -18
  13. package/dist/{lib/arrange/domain/arrange-grouping.service.mjs → arrange/domain/grouping-service.mjs} +31 -10
  14. package/dist/{lib/arrange/domain/grouping.domain.mjs → arrange/domain/grouping.mjs} +39 -18
  15. package/dist/{lib/arrange/domain/imports.domain.mjs → arrange/domain/imports.mjs} +7 -3
  16. package/dist/{lib/arrange/domain/source-text-formatters.formatter.mjs → arrange/domain/source-text-formatters.mjs} +22 -5
  17. package/dist/{lib/arrange/domain/tailwind-token.value-object.mjs → arrange/domain/tailwind-token.mjs} +12 -3
  18. package/dist/{lib/arrange/domain/tailwind-token-classifier.domain-service.mjs → arrange/domain/token-classifier.mjs} +40 -15
  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 -19
  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/{lib/config/infrastructure/config-schema.adapter.mjs → core/config/schema.mjs} +20 -6
  36. package/dist/core/config/warnings.mjs +12 -0
  37. package/dist/core/config.mjs +19 -0
  38. package/dist/{lib/core/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/{lib/core/domain/result.model.mjs → core/result.mjs} +7 -3
  43. package/dist/{lib/core/application/services/schema-validator.service.mjs → core/schema-parse.mjs} +6 -5
  44. package/dist/{lib/shared/source-code/domain/text-edit.model.mjs → core/source-text-edit.mjs} +15 -14
  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/mirror/cli-result.mjs +21 -0
  49. package/dist/{lib/mirror/presentation/mirror-cli.schema.mjs → mirror/cli-schema.mjs} +4 -4
  50. package/dist/mirror/command.mjs +57 -0
  51. package/dist/mirror/dist-filesystem-impl.mjs +42 -0
  52. package/dist/{lib/mirror/domain/constants.domain.mjs → mirror/domain/constants.mjs} +16 -1
  53. package/dist/{lib/mirror/infrastructure/dirent-list.guard.mjs → mirror/domain/dirent-guard.mjs} +5 -2
  54. package/dist/{lib/mirror/domain/errors.domain.mjs → mirror/domain/errors.mjs} +7 -1
  55. package/dist/{lib/mirror/application/services/generate-mirror-exports.service.mjs → mirror/domain/exports.mjs} +17 -10
  56. package/dist/{lib/mirror/domain/package-display-name.policy.mjs → mirror/domain/package-display-name.mjs} +5 -2
  57. package/dist/{lib/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/{lib/mirror/infrastructure/package-json-exports.repository.mjs → mirror/write-exports.mjs} +35 -31
  65. package/dist/tag/cli-result.mjs +11 -0
  66. package/dist/{lib/tag/presentation/tag-cli.schema.mjs → tag/cli-schema.mjs} +4 -1
  67. package/dist/tag/command.mjs +56 -0
  68. package/dist/{lib/tag/presentation/tag-sync.presenter.mjs → tag/output.mjs} +54 -28
  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 +130 -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 +8 -9
  77. package/dist/lib/arrange/adapters/primary/cli/arrange.command.mjs +0 -324
  78. package/dist/lib/arrange/adapters/primary/cli/arrange.presentation.module.mjs +0 -14
  79. package/dist/lib/arrange/adapters/primary/cli/presentation.tokens.mjs +0 -5
  80. package/dist/lib/arrange/adapters/secondary/domain-source-parser.adapter.mjs +0 -239
  81. package/dist/lib/arrange/adapters/secondary/file-walker.adapter.mjs +0 -241
  82. package/dist/lib/arrange/adapters/secondary/workspace-resolver.adapter.mjs +0 -233
  83. package/dist/lib/arrange/application/requests/suggest-groups.request.mjs +0 -1
  84. package/dist/lib/arrange/application/services/arrange-file-processor.service.mjs +0 -267
  85. package/dist/lib/arrange/application/services/arrange-target-path-resolver.service.mjs +0 -21
  86. package/dist/lib/arrange/application/services/arrange-target-scanner.service.mjs +0 -243
  87. package/dist/lib/arrange/application/use-cases/analyze-directory.use-case.mjs +0 -255
  88. package/dist/lib/arrange/application/use-cases/prepare-arrange-workspace.use-case.mjs +0 -263
  89. package/dist/lib/arrange/application/use-cases/run-arrange-sync.use-case.mjs +0 -274
  90. package/dist/lib/arrange/application/use-cases/suggest-cn-groups.use-case.mjs +0 -237
  91. package/dist/lib/arrange/arrange.module.mjs +0 -31
  92. package/dist/lib/arrange/contracts/analyze-report-presenter.contract.mjs +0 -1
  93. package/dist/lib/arrange/contracts/models.mjs +0 -1
  94. package/dist/lib/arrange/contracts/services.contract.mjs +0 -1
  95. package/dist/lib/arrange/contracts/tokens.mjs +0 -15
  96. package/dist/lib/arrange/domain/tailwind-grouping.service.mjs +0 -231
  97. package/dist/lib/arrange/domain/types.domain.mjs +0 -1
  98. package/dist/lib/arrange/infrastructure/typescript-ast-translator.adapter.mjs +0 -355
  99. package/dist/lib/arrange/presentation/arrange-analyze.presenter.mjs +0 -259
  100. package/dist/lib/arrange/presentation/arrange-sync.presenter.mjs +0 -33
  101. package/dist/lib/arrange/presentation/group-file-preview.presenter.mjs +0 -271
  102. package/dist/lib/bootstrap/composition-root.mjs +0 -33
  103. package/dist/lib/config/application/ports/config-loader.port.mjs +0 -1
  104. package/dist/lib/config/application/ports/config-warning-reporter.port.mjs +0 -1
  105. package/dist/lib/config/application/services/load-config.service.mjs +0 -17
  106. package/dist/lib/config/contracts/tokens.mjs +0 -6
  107. package/dist/lib/config/domain/schema.domain.mjs +0 -1
  108. package/dist/lib/config/infrastructure/config-loader.adapter.mjs +0 -306
  109. package/dist/lib/config/infrastructure/config-warning-reporter.adapter.mjs +0 -234
  110. package/dist/lib/core/application/load-codefast-config.use-case.mjs +0 -245
  111. package/dist/lib/core/application/ports/cli-io.port.mjs +0 -1
  112. package/dist/lib/core/application/ports/path.port.mjs +0 -1
  113. package/dist/lib/core/application/ports/repo-root-resolver.port.mjs +0 -1
  114. package/dist/lib/core/application/ports/runtime.port.mjs +0 -1
  115. package/dist/lib/core/application/services/global-cli-options-parser.service.mjs +0 -9
  116. package/dist/lib/core/contracts/tokens.mjs +0 -10
  117. package/dist/lib/core/core.module.mjs +0 -9
  118. package/dist/lib/core/domain/cli-exit-codes.domain.mjs +0 -11
  119. package/dist/lib/core/domain/errors.domain.mjs +0 -17
  120. package/dist/lib/core/infrastructure/infrastructure.module.mjs +0 -30
  121. package/dist/lib/core/infrastructure/path.adapter.mjs +0 -246
  122. package/dist/lib/core/infrastructure/port-telemetry.decorator.mjs +0 -62
  123. package/dist/lib/core/infrastructure/repo-root-resolver.adapter.mjs +0 -233
  124. package/dist/lib/core/infrastructure/verbose-diagnostics.policy.mjs +0 -9
  125. package/dist/lib/core/presentation/cli-executor.presenter.mjs +0 -42
  126. package/dist/lib/core/presentation/cli-schema.parser.mjs +0 -7
  127. package/dist/lib/core/presentation/format-app-error.presenter.mjs +0 -17
  128. package/dist/lib/core/presentation/presentation.module.mjs +0 -5
  129. package/dist/lib/infrastructure/node-io.adapter.mjs +0 -285
  130. package/dist/lib/infrastructure/workspace/repo-root-resolver.service.mjs +0 -21
  131. package/dist/lib/kernel/contracts/cli-command.contract.mjs +0 -1
  132. package/dist/lib/kernel/contracts/tokens.mjs +0 -5
  133. package/dist/lib/mirror/adapters/primary/cli/mirror.command.mjs +0 -272
  134. package/dist/lib/mirror/adapters/secondary/file-system-service.adapter.mjs +0 -261
  135. package/dist/lib/mirror/adapters/secondary/mirror-sync-reporter.adapter.mjs +0 -243
  136. package/dist/lib/mirror/adapters/secondary/package-repository.adapter.mjs +0 -241
  137. package/dist/lib/mirror/adapters/secondary/sync-workspace-package.adapter.mjs +0 -351
  138. package/dist/lib/mirror/adapters/secondary/workspace-service.adapter.mjs +0 -237
  139. package/dist/lib/mirror/application/mirror-sync-json.format.mjs +0 -12
  140. package/dist/lib/mirror/application/ports/file-system-service.port.mjs +0 -1
  141. package/dist/lib/mirror/application/ports/mirror-sync-reporter.port.mjs +0 -1
  142. package/dist/lib/mirror/application/ports/package-repository.port.mjs +0 -1
  143. package/dist/lib/mirror/application/ports/sync-workspace-package.port.mjs +0 -1
  144. package/dist/lib/mirror/application/ports/workspace-service.port.mjs +0 -1
  145. package/dist/lib/mirror/application/requests/mirror-sync.request.mjs +0 -1
  146. package/dist/lib/mirror/application/services/mirror-package-arg-resolver.service.mjs +0 -20
  147. package/dist/lib/mirror/application/use-cases/prepare-mirror-sync.use-case.mjs +0 -264
  148. package/dist/lib/mirror/application/use-cases/run-mirror-sync.use-case.mjs +0 -302
  149. package/dist/lib/mirror/contracts/models.mjs +0 -1
  150. package/dist/lib/mirror/contracts/tokens.mjs +0 -11
  151. package/dist/lib/mirror/domain/types.domain.mjs +0 -1
  152. package/dist/lib/mirror/infrastructure/mirror-console-reporter.presenter.mjs +0 -99
  153. package/dist/lib/mirror/infrastructure/package-filter-resolver.service.mjs +0 -25
  154. package/dist/lib/mirror/infrastructure/workspace-packages.service.mjs +0 -158
  155. package/dist/lib/mirror/mirror.module.mjs +0 -25
  156. package/dist/lib/shared/source-code/infrastructure/typescript-source-file-walker.service.mjs +0 -33
  157. package/dist/lib/tag/adapters/primary/cli/presentation.tokens.mjs +0 -6
  158. package/dist/lib/tag/adapters/primary/cli/tag.command.mjs +0 -285
  159. package/dist/lib/tag/adapters/primary/cli/tag.presentation.module.mjs +0 -13
  160. package/dist/lib/tag/adapters/secondary/tag-since-writer.adapter.mjs +0 -348
  161. package/dist/lib/tag/adapters/secondary/tag-target-resolver.adapter.mjs +0 -233
  162. package/dist/lib/tag/adapters/secondary/tag-version-resolver.adapter.mjs +0 -249
  163. package/dist/lib/tag/adapters/secondary/typescript-tree-walk.adapter.mjs +0 -233
  164. package/dist/lib/tag/application/ports/tag-since-writer.port.mjs +0 -1
  165. package/dist/lib/tag/application/ports/tag-version-resolver.port.mjs +0 -1
  166. package/dist/lib/tag/application/ports/target-resolver.port.mjs +0 -1
  167. package/dist/lib/tag/application/ports/typescript-tree-walk.port.mjs +0 -1
  168. package/dist/lib/tag/application/requests/tag-sync.request.mjs +0 -1
  169. package/dist/lib/tag/application/services/tag-cli-target-path-resolver.service.mjs +0 -9
  170. package/dist/lib/tag/application/services/tag-target-runner.service.mjs +0 -21
  171. package/dist/lib/tag/application/tag-sync-cli-result.mjs +0 -11
  172. package/dist/lib/tag/application/tag-sync-json.format.mjs +0 -14
  173. package/dist/lib/tag/application/use-cases/prepare-tag-sync.use-case.mjs +0 -264
  174. package/dist/lib/tag/application/use-cases/run-tag-sync.use-case.mjs +0 -381
  175. package/dist/lib/tag/contracts/models.mjs +0 -1
  176. package/dist/lib/tag/contracts/tag-sync-result-presenter.contract.mjs +0 -1
  177. package/dist/lib/tag/contracts/tokens.mjs +0 -10
  178. package/dist/lib/tag/domain/types.domain.mjs +0 -1
  179. package/dist/lib/tag/infrastructure/tag-target-candidates.adapter.mjs +0 -170
  180. package/dist/lib/tag/presentation/colors.presenter.mjs +0 -12
  181. package/dist/lib/tag/presentation/present-tag-sync-result.presenter.mjs +0 -233
  182. package/dist/lib/tag/presentation/tag-sync-progress-listener.presenter.mjs +0 -243
  183. package/dist/lib/tag/tag.module.mjs +0 -23
  184. /package/dist/{lib/arrange/application/ports/domain-source-parser.port.mjs → arrange/domain/types.mjs} +0 -0
  185. /package/dist/{lib/arrange/application/ports/file-walker.port.mjs → core/filesystem/port.mjs} +0 -0
  186. /package/dist/{lib/arrange/application/ports/group-file-preview.port.mjs → mirror/domain/dist-filesystem.mjs} +0 -0
  187. /package/dist/{lib/arrange/application/ports/workspace-resolver.port.mjs → mirror/domain/types.mjs} +0 -0
  188. /package/dist/{lib/arrange/application/requests/analyze-directory.request.mjs → mirror/sync-types.mjs} +0 -0
  189. /package/dist/{lib/arrange/application/requests/arrange-sync.request.mjs → tag/domain/types.mjs} +0 -0
@@ -0,0 +1,79 @@
1
+ import { logger } from "../core/logger.mjs";
2
+ import "./domain/constants.mjs";
3
+ import { lineOf } from "./domain/ast/helpers.mjs";
4
+ import path from "node:path";
5
+ //#region src/arrange/output.ts
6
+ /**
7
+ * @since 0.3.16-canary.0
8
+ */
9
+ function printAnalyzeReport(resolvedTargetPath, report) {
10
+ logger.out(`Path: ${path.resolve(resolvedTargetPath)}`);
11
+ logger.out(`.ts/.tsx files: ${report.files}`);
12
+ logger.out(`cn(...) call sites: ${report.cnCallExpressions}`);
13
+ logger.out(`tv(...) call sites: ${report.tvCallExpressions}`);
14
+ logger.out(`\nLong cn(...) string literals (≥18 tokens — consider splitting arguments): ${report.longCnStringLiterals.length}`);
15
+ for (const findingEntry of report.longCnStringLiterals.slice(0, 40)) logger.out(` ${findingEntry.file}:${findingEntry.line} (${findingEntry.tokenCount} tokens) ${findingEntry.preview}`);
16
+ if (report.longCnStringLiterals.length > 40) logger.out(` … and ${report.longCnStringLiterals.length - 40} more`);
17
+ logger.out(`\nLong tv({...}) string literals in base/variants/… (≥18 tokens): ${report.longTvStringLiterals.length}`);
18
+ for (const findingEntry of report.longTvStringLiterals.slice(0, 40)) logger.out(` ${findingEntry.file}:${findingEntry.line} (${findingEntry.tokenCount} tokens) ${findingEntry.preview}`);
19
+ if (report.longTvStringLiterals.length > 40) logger.out(` … and ${report.longTvStringLiterals.length - 40} more`);
20
+ logger.out(`\nJSX className="..." or className={'...'} (static strings, ≥18 tokens): ${report.longJsxClassNameLiterals.length}`);
21
+ for (const findingEntry of report.longJsxClassNameLiterals.slice(0, 40)) logger.out(` ${findingEntry.file}:${findingEntry.line} (${findingEntry.tokenCount} tokens) ${findingEntry.preview}`);
22
+ if (report.longJsxClassNameLiterals.length > 40) logger.out(` … and ${report.longJsxClassNameLiterals.length - 40} more`);
23
+ logger.out(`\ncn(...) nested inside tv({...}) (prefer a string or array — preview/apply can rewrite): ${report.cnInsideTvCalls.length}`);
24
+ for (const findingEntry of report.cnInsideTvCalls.slice(0, 40)) logger.out(` ${findingEntry.file}:${findingEntry.line} (${findingEntry.argCount} args) ${findingEntry.preview}`);
25
+ if (report.cnInsideTvCalls.length > 40) logger.out(` … and ${report.cnInsideTvCalls.length - 40} more`);
26
+ }
27
+ /**
28
+ * @since 0.3.16-canary.0
29
+ */
30
+ function printSyncResult(result, write) {
31
+ logger.out(`\nTotal: ${result.filePaths.length} file(s), ${result.totalFound} site(s) (cn/tv/JSX className) to review.`);
32
+ if (write) logger.out(`Applied: ${result.totalChanged} site(s) updated.`);
33
+ else logger.out(`(Run "apply" to write changes, or "pnpm cli:arrange-apply" / "pnpm exec codefast arrange apply")`);
34
+ if (write ? result.totalChanged > 0 : result.totalFound > 0) logger.out("Note: class order may change across concern groups — smoke-test the UI if you rely on cascade order.");
35
+ if (result.hookError !== null) logger.err(result.hookError);
36
+ }
37
+ /**
38
+ * @since 0.3.16-canary.0
39
+ */
40
+ function printGroupFilePreviewFromWork(work) {
41
+ printGroupFilePreviewBody({
42
+ filePath: work.filePath,
43
+ reportTotal: work.reportTotal,
44
+ cnInTvNoReplacement: work.cnInTvNoReplacement,
45
+ cnInTvCalls: work.cnInTvCalls,
46
+ unwrapReplacementByCall: work.unwrapReplacementByCall,
47
+ sourceText: work.sourceText,
48
+ domainSf: work.domainSfForLineNumbers,
49
+ unwrapEdits: work.unwrapEdits,
50
+ plannedGroupEdits: work.plannedGroupEdits
51
+ });
52
+ }
53
+ function printGroupFilePreviewBody(args) {
54
+ const { filePath, reportTotal, cnInTvNoReplacement, cnInTvCalls, unwrapReplacementByCall, sourceText, domainSf, unwrapEdits, plannedGroupEdits } = args;
55
+ let header = `\n── ${filePath} (${reportTotal} site(s)`;
56
+ if (cnInTvNoReplacement > 0) header += `; plus ${cnInTvNoReplacement} cn() inside tv left unchanged (0 args)`;
57
+ header += `) ──`;
58
+ logger.out(header);
59
+ for (const call of cnInTvCalls) {
60
+ const replacement = unwrapReplacementByCall.get(call);
61
+ if (replacement === void 0) {
62
+ logger.out(` Line ${lineOf(domainSf, call)} [tv ⊃ cn]: cn(...) has no arguments — skipped`);
63
+ continue;
64
+ }
65
+ const start = call.pos;
66
+ const end = call.end;
67
+ if (sourceText.slice(start, end) === replacement) continue;
68
+ logger.out(` Line ${lineOf(domainSf, call)} [tv ⊃ cn → string/array]:`);
69
+ logger.out(` ${replacement.split("\n").join("\n ")}`);
70
+ }
71
+ if (unwrapEdits.length > 0 && plannedGroupEdits.length > 0) logger.out(" ([cn] / [tv] / [JSX className] lines below reflect content after unwrap of cn inside tv.)");
72
+ for (const plan of plannedGroupEdits) {
73
+ logger.out(` Line ${lineOf(plan.lineSf, plan.reportNode)} [${plan.label}]:`);
74
+ logger.out(` ${plan.replacement.split("\n").join("\n ")}`);
75
+ logger.out(` // Buckets: ${JSON.stringify(plan.bucketSummary)}`);
76
+ }
77
+ }
78
+ //#endregion
79
+ export { printAnalyzeReport, printGroupFilePreviewFromWork, printSyncResult };
@@ -0,0 +1,42 @@
1
+ import { parseDomainSourceFile } from "./source-parse.mjs";
2
+ import { buildGroupFileUnwrapState, countPersistedGroupFileEdits, groupFileDryRunNoEdits, groupFileEditsTouchJsxCn, groupFilePreviewTotals, groupFileWorkHasNothingToReport, mergeGroupFileBodyText, tryBuildGroupFileWorkPlan } from "./domain/grouping-service.mjs";
3
+ import { ensureCnImport } from "./domain/imports.mjs";
4
+ //#region src/arrange/process-file.ts
5
+ /**
6
+ * @since 0.3.16-canary.0
7
+ */
8
+ function processArrangeGroupFile(fs, args) {
9
+ const { filePath, options } = args;
10
+ const sourceText = fs.readFileSync(filePath, "utf8");
11
+ const domainSfInitial = parseDomainSourceFile(filePath, sourceText);
12
+ const unwrap = buildGroupFileUnwrapState(domainSfInitial, sourceText);
13
+ const work = tryBuildGroupFileWorkPlan({
14
+ filePath,
15
+ sourceText,
16
+ domainSfInitial,
17
+ domainSfGrouped: parseDomainSourceFile(filePath, unwrap.textAfterUnwrap),
18
+ withClassName: options.withClassName,
19
+ unwrap
20
+ });
21
+ if (work === null) return groupFileDryRunNoEdits(filePath);
22
+ if (!options.write) {
23
+ if (groupFileWorkHasNothingToReport(work)) return groupFileDryRunNoEdits(filePath);
24
+ return {
25
+ ...groupFilePreviewTotals(work),
26
+ workPlan: work
27
+ };
28
+ }
29
+ const persistedEditCount = countPersistedGroupFileEdits(work);
30
+ let newText = mergeGroupFileBodyText(work);
31
+ if (persistedEditCount > 0) {
32
+ if (groupFileEditsTouchJsxCn(work)) newText = ensureCnImport(parseDomainSourceFile(filePath, newText), options.cnImport);
33
+ fs.writeFileSync(filePath, newText, "utf8");
34
+ }
35
+ return {
36
+ filePath,
37
+ totalFound: persistedEditCount + work.cnInTvNoReplacement,
38
+ changed: persistedEditCount
39
+ };
40
+ }
41
+ //#endregion
42
+ export { processArrangeGroupFile };
@@ -0,0 +1,24 @@
1
+ import path from "node:path";
2
+ //#region src/arrange/resolve-target.ts
3
+ const packageJsonFileName = "package.json";
4
+ /**
5
+ * @since 0.3.16-canary.0
6
+ */
7
+ function resolveArrangeTargetPath(fs, args) {
8
+ const explicitTargetPath = args.rawTarget ? path.isAbsolute(args.rawTarget) ? path.resolve(args.rawTarget) : path.resolve(args.currentWorkingDirectory, args.rawTarget) : void 0;
9
+ if (explicitTargetPath) return fs.canonicalPathSync(explicitTargetPath);
10
+ const resolvedDefaultTarget = findNearestPackageDirectory(fs, args.currentWorkingDirectory) ?? args.currentWorkingDirectory;
11
+ return fs.canonicalPathSync(resolvedDefaultTarget);
12
+ }
13
+ function findNearestPackageDirectory(fs, currentWorkingDirectory) {
14
+ let currentDir = path.resolve(currentWorkingDirectory);
15
+ while (true) {
16
+ const packageJsonPath = path.join(currentDir, packageJsonFileName);
17
+ if (fs.existsSync(packageJsonPath)) return currentDir;
18
+ const parentDirectory = path.dirname(currentDir);
19
+ if (parentDirectory === currentDir) return;
20
+ currentDir = parentDirectory;
21
+ }
22
+ }
23
+ //#endregion
24
+ export { resolveArrangeTargetPath };
@@ -0,0 +1,20 @@
1
+ import { messageFrom } from "../core/errors.mjs";
2
+ import { logger } from "../core/logger.mjs";
3
+ import { walkTsxFiles } from "../core/workspace/typescript-walk.mjs";
4
+ import path from "node:path";
5
+ //#region src/arrange/scan-target.ts
6
+ /**
7
+ * @since 0.3.16-canary.0
8
+ */
9
+ function scanArrangeTargets(fs, targetPath) {
10
+ const resolvedTargetPath = path.resolve(targetPath);
11
+ if (fs.statSync(resolvedTargetPath).isDirectory()) try {
12
+ return walkTsxFiles(resolvedTargetPath, fs);
13
+ } catch (caughtError) {
14
+ logger.err(`[file-walker] ${messageFrom(caughtError)}`);
15
+ throw caughtError;
16
+ }
17
+ return [resolvedTargetPath];
18
+ }
19
+ //#endregion
20
+ export { scanArrangeTargets };
@@ -0,0 +1,18 @@
1
+ import { messageFrom } from "../core/errors.mjs";
2
+ import { logger } from "../core/logger.mjs";
3
+ import { TypeScriptAstTranslator } from "./typescript-ast-translator.mjs";
4
+ //#region src/arrange/source-parse.ts
5
+ const translator = new TypeScriptAstTranslator();
6
+ /**
7
+ * @since 0.3.16-canary.0
8
+ */
9
+ function parseDomainSourceFile(filePath, sourceText) {
10
+ try {
11
+ return translator.translateSourceFile(filePath, sourceText);
12
+ } catch (caughtError) {
13
+ logger.err(`[domain-source-parser] ${messageFrom(caughtError)}`);
14
+ throw caughtError;
15
+ }
16
+ }
17
+ //#endregion
18
+ export { parseDomainSourceFile };
@@ -0,0 +1,15 @@
1
+ import { suggestCnGroups, summarizeGroupBucketLabels } from "./domain/grouping.mjs";
2
+ import { formatArray, formatCnCall } from "./domain/source-text-formatters.mjs";
3
+ //#region src/arrange/suggest.ts
4
+ /**
5
+ * @since 0.3.16-canary.0
6
+ */
7
+ function suggestCnGroupsFromCli(request) {
8
+ const groups = suggestCnGroups(request.inlineClasses);
9
+ return {
10
+ primaryLine: request.emitTvStyleArray ? formatArray(groups) : formatCnCall(groups, { trailingClassName: request.trailingClassName }),
11
+ bucketsCommentLine: `// Buckets: ${JSON.stringify(summarizeGroupBucketLabels(groups))}`
12
+ };
13
+ }
14
+ //#endregion
15
+ export { suggestCnGroupsFromCli };
@@ -0,0 +1,51 @@
1
+ import { messageFrom } from "../core/errors.mjs";
2
+ import { ok } from "../core/result.mjs";
3
+ import { scanArrangeTargets } from "./scan-target.mjs";
4
+ import { processArrangeGroupFile } from "./process-file.mjs";
5
+ //#region src/arrange/sync.ts
6
+ async function runOnAfterWriteHook(hook, modifiedFiles) {
7
+ if (!hook || modifiedFiles.length === 0) return null;
8
+ try {
9
+ await hook({ files: modifiedFiles });
10
+ return null;
11
+ } catch (caughtHookError) {
12
+ return `[arrange] onAfterWrite hook failed: ${messageFrom(caughtHookError)}`;
13
+ }
14
+ }
15
+ /**
16
+ * @since 0.3.16-canary.0
17
+ */
18
+ async function runArrangeSync(fs, request) {
19
+ const filePaths = scanArrangeTargets(fs, request.targetPath);
20
+ const modifiedFiles = [];
21
+ const previewPlans = [];
22
+ let totalFound = 0;
23
+ let totalChanged = 0;
24
+ const groupOptions = {
25
+ write: request.write,
26
+ withClassName: !!request.withClassName,
27
+ cnImport: request.cnImport
28
+ };
29
+ for (const filePath of filePaths) {
30
+ const fileProcessResult = processArrangeGroupFile(fs, {
31
+ filePath,
32
+ options: groupOptions
33
+ });
34
+ totalFound += fileProcessResult.totalFound;
35
+ totalChanged += fileProcessResult.changed;
36
+ if (fileProcessResult.changed > 0) modifiedFiles.push(fileProcessResult.filePath);
37
+ if (fileProcessResult.workPlan) previewPlans.push(fileProcessResult.workPlan);
38
+ }
39
+ const arrangeConfig = request.config;
40
+ const hookError = request.write && modifiedFiles.length > 0 ? await runOnAfterWriteHook(arrangeConfig?.onAfterWrite, modifiedFiles) : null;
41
+ return ok({
42
+ filePaths,
43
+ modifiedFiles,
44
+ totalFound,
45
+ totalChanged,
46
+ hookError,
47
+ previewPlans
48
+ });
49
+ }
50
+ //#endregion
51
+ export { runArrangeSync };
@@ -0,0 +1,354 @@
1
+ import "./domain/ast/ast-node.mjs";
2
+ import ts from "typescript";
3
+ //#region src/arrange/typescript-ast-translator.ts
4
+ /**
5
+ * Anti-corruption layer: maps TypeScript compiler AST to arrange domain AST.
6
+ * This module is the only place that imports `typescript` for arrange AST translation.
7
+ */
8
+ /**
9
+ * @since 0.3.16-canary.0
10
+ */
11
+ var TypeScriptAstTranslator = class {
12
+ translateSourceFile(filePath, sourceText) {
13
+ return this.parseDomainSourceFile(filePath, sourceText);
14
+ }
15
+ translateUnknown(n, parent, sf) {
16
+ const self = {
17
+ kind: 1,
18
+ pos: n.getStart(sf),
19
+ end: n.getEnd(),
20
+ parent,
21
+ children: []
22
+ };
23
+ const childList = [];
24
+ ts.forEachChild(n, (child) => {
25
+ childList.push(this.translateNode(child, self, sf));
26
+ });
27
+ return {
28
+ ...self,
29
+ children: childList
30
+ };
31
+ }
32
+ mapBinaryOperator(operatorToken) {
33
+ if (operatorToken.kind === ts.SyntaxKind.PlusToken) return 0;
34
+ return 1;
35
+ }
36
+ translateNode(n, parent, sf) {
37
+ const pos = n.getStart(sf);
38
+ const end = n.getEnd();
39
+ switch (n.kind) {
40
+ case ts.SyntaxKind.Identifier: return {
41
+ kind: 2,
42
+ pos,
43
+ end,
44
+ parent,
45
+ text: n.text
46
+ };
47
+ case ts.SyntaxKind.StringLiteral: return {
48
+ kind: 3,
49
+ pos,
50
+ end,
51
+ parent,
52
+ text: n.text
53
+ };
54
+ case ts.SyntaxKind.NoSubstitutionTemplateLiteral: return {
55
+ kind: 4,
56
+ pos,
57
+ end,
58
+ parent,
59
+ text: n.text
60
+ };
61
+ case ts.SyntaxKind.ImportDeclaration: {
62
+ const decl = n;
63
+ const self = {
64
+ kind: 5,
65
+ pos,
66
+ end,
67
+ parent,
68
+ importClause: void 0,
69
+ moduleSpecifier: void 0
70
+ };
71
+ if (decl.importClause) self.importClause = this.translateNode(decl.importClause, self, sf);
72
+ self.moduleSpecifier = this.translateNode(decl.moduleSpecifier, self, sf);
73
+ return self;
74
+ }
75
+ case ts.SyntaxKind.ImportClause: {
76
+ const clause = n;
77
+ const self = {
78
+ kind: 6,
79
+ pos,
80
+ end,
81
+ parent,
82
+ isTypeOnly: clause.isTypeOnly,
83
+ name: void 0,
84
+ namedBindings: void 0
85
+ };
86
+ if (clause.name) self.name = this.translateNode(clause.name, self, sf);
87
+ if (clause.namedBindings) self.namedBindings = this.translateNode(clause.namedBindings, self, sf);
88
+ return self;
89
+ }
90
+ case ts.SyntaxKind.NamedImports: {
91
+ const named = n;
92
+ const self = {
93
+ kind: 7,
94
+ pos,
95
+ end,
96
+ parent,
97
+ elements: []
98
+ };
99
+ const elements = [];
100
+ for (const element of named.elements) elements.push(this.translateNode(element, self, sf));
101
+ return {
102
+ ...self,
103
+ elements
104
+ };
105
+ }
106
+ case ts.SyntaxKind.NamespaceImport: {
107
+ const ns = n;
108
+ const self = {
109
+ kind: 8,
110
+ pos,
111
+ end,
112
+ parent,
113
+ name: void 0
114
+ };
115
+ self.name = this.translateNode(ns.name, self, sf);
116
+ return self;
117
+ }
118
+ case ts.SyntaxKind.ImportSpecifier: {
119
+ const spec = n;
120
+ const self = {
121
+ kind: 9,
122
+ pos,
123
+ end,
124
+ parent,
125
+ propertyName: void 0,
126
+ name: void 0
127
+ };
128
+ if (spec.propertyName) self.propertyName = this.translateNode(spec.propertyName, self, sf);
129
+ self.name = this.translateNode(spec.name, self, sf);
130
+ return self;
131
+ }
132
+ case ts.SyntaxKind.CallExpression: {
133
+ const call = n;
134
+ const self = {
135
+ kind: 10,
136
+ pos,
137
+ end,
138
+ parent,
139
+ expression: void 0,
140
+ arguments: []
141
+ };
142
+ self.expression = this.translateNode(call.expression, self, sf);
143
+ self.arguments = call.arguments.map((arg) => this.translateNode(arg, self, sf));
144
+ return self;
145
+ }
146
+ case ts.SyntaxKind.PropertyAccessExpression: {
147
+ const pa = n;
148
+ const self = {
149
+ kind: 11,
150
+ pos,
151
+ end,
152
+ parent,
153
+ expression: void 0,
154
+ name: void 0
155
+ };
156
+ self.expression = this.translateNode(pa.expression, self, sf);
157
+ self.name = this.translateNode(pa.name, self, sf);
158
+ return self;
159
+ }
160
+ case ts.SyntaxKind.ObjectLiteralExpression: {
161
+ const obj = n;
162
+ const self = {
163
+ kind: 12,
164
+ pos,
165
+ end,
166
+ parent,
167
+ properties: []
168
+ };
169
+ const properties = [];
170
+ for (const prop of obj.properties) properties.push(this.translateNode(prop, self, sf));
171
+ return {
172
+ ...self,
173
+ properties
174
+ };
175
+ }
176
+ case ts.SyntaxKind.PropertyAssignment: {
177
+ const prop = n;
178
+ const self = {
179
+ kind: 13,
180
+ pos,
181
+ end,
182
+ parent,
183
+ name: void 0,
184
+ initializer: void 0
185
+ };
186
+ self.name = this.translateNode(prop.name, self, sf);
187
+ self.initializer = this.translateNode(prop.initializer, self, sf);
188
+ return self;
189
+ }
190
+ case ts.SyntaxKind.ArrayLiteralExpression: {
191
+ const arr = n;
192
+ const self = {
193
+ kind: 14,
194
+ pos,
195
+ end,
196
+ parent,
197
+ elements: []
198
+ };
199
+ const elements = [];
200
+ for (const element of arr.elements) elements.push(this.translateNode(element, self, sf));
201
+ return {
202
+ ...self,
203
+ elements
204
+ };
205
+ }
206
+ case ts.SyntaxKind.SpreadElement: {
207
+ const sp = n;
208
+ const self = {
209
+ kind: 15,
210
+ pos,
211
+ end,
212
+ parent,
213
+ expression: void 0
214
+ };
215
+ self.expression = this.translateNode(sp.expression, self, sf);
216
+ return self;
217
+ }
218
+ case ts.SyntaxKind.ParenthesizedExpression: {
219
+ const pe = n;
220
+ const self = {
221
+ kind: 16,
222
+ pos,
223
+ end,
224
+ parent,
225
+ expression: void 0
226
+ };
227
+ self.expression = this.translateNode(pe.expression, self, sf);
228
+ return self;
229
+ }
230
+ case ts.SyntaxKind.AsExpression: {
231
+ const ae = n;
232
+ const self = {
233
+ kind: 17,
234
+ pos,
235
+ end,
236
+ parent,
237
+ expression: void 0
238
+ };
239
+ self.expression = this.translateNode(ae.expression, self, sf);
240
+ return self;
241
+ }
242
+ case ts.SyntaxKind.SatisfiesExpression: {
243
+ const se = n;
244
+ const self = {
245
+ kind: 18,
246
+ pos,
247
+ end,
248
+ parent,
249
+ expression: void 0
250
+ };
251
+ self.expression = this.translateNode(se.expression, self, sf);
252
+ return self;
253
+ }
254
+ case ts.SyntaxKind.NonNullExpression: {
255
+ const nn = n;
256
+ const self = {
257
+ kind: 19,
258
+ pos,
259
+ end,
260
+ parent,
261
+ expression: void 0
262
+ };
263
+ self.expression = this.translateNode(nn.expression, self, sf);
264
+ return self;
265
+ }
266
+ case ts.SyntaxKind.ConditionalExpression: {
267
+ const ce = n;
268
+ const self = {
269
+ kind: 20,
270
+ pos,
271
+ end,
272
+ parent,
273
+ condition: void 0,
274
+ whenTrue: void 0,
275
+ whenFalse: void 0
276
+ };
277
+ self.condition = this.translateNode(ce.condition, self, sf);
278
+ self.whenTrue = this.translateNode(ce.whenTrue, self, sf);
279
+ self.whenFalse = this.translateNode(ce.whenFalse, self, sf);
280
+ return self;
281
+ }
282
+ case ts.SyntaxKind.BinaryExpression: {
283
+ const be = n;
284
+ const self = {
285
+ kind: 21,
286
+ pos,
287
+ end,
288
+ parent,
289
+ left: void 0,
290
+ operator: this.mapBinaryOperator(be.operatorToken),
291
+ right: void 0
292
+ };
293
+ self.left = this.translateNode(be.left, self, sf);
294
+ self.right = this.translateNode(be.right, self, sf);
295
+ return self;
296
+ }
297
+ case ts.SyntaxKind.ExpressionStatement: {
298
+ const es = n;
299
+ const self = {
300
+ kind: 22,
301
+ pos,
302
+ end,
303
+ parent,
304
+ expression: void 0
305
+ };
306
+ self.expression = this.translateNode(es.expression, self, sf);
307
+ return self;
308
+ }
309
+ case ts.SyntaxKind.JsxAttribute: {
310
+ const ja = n;
311
+ const self = {
312
+ kind: 23,
313
+ pos,
314
+ end,
315
+ parent,
316
+ name: void 0,
317
+ initializer: void 0
318
+ };
319
+ self.name = this.translateNode(ja.name, self, sf);
320
+ if (ja.initializer) self.initializer = this.translateNode(ja.initializer, self, sf);
321
+ return self;
322
+ }
323
+ case ts.SyntaxKind.JsxExpression: {
324
+ const je = n;
325
+ const self = {
326
+ kind: 24,
327
+ pos,
328
+ end,
329
+ parent,
330
+ expression: void 0
331
+ };
332
+ if (je.expression) self.expression = this.translateNode(je.expression, self, sf);
333
+ return self;
334
+ }
335
+ default: return this.translateUnknown(n, parent, sf);
336
+ }
337
+ }
338
+ translateTypeScriptSourceFile(tsSf) {
339
+ const text = tsSf.getFullText();
340
+ const statements = tsSf.statements.map((statement) => this.translateNode(statement, null, tsSf));
341
+ return {
342
+ fileName: tsSf.fileName,
343
+ text,
344
+ statements
345
+ };
346
+ }
347
+ parseDomainSourceFile(filePath, sourceText) {
348
+ const scriptKind = filePath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
349
+ const tsSf = ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true, scriptKind);
350
+ return this.translateTypeScriptSourceFile(tsSf);
351
+ }
352
+ };
353
+ //#endregion
354
+ export { TypeScriptAstTranslator };
@@ -0,0 +1,31 @@
1
+ import { AppError, messageFrom } from "../core/errors.mjs";
2
+ import { err, ok } from "../core/result.mjs";
3
+ import { loadCodefastConfig } from "../core/config.mjs";
4
+ import { findRepoRoot } from "../core/workspace/resolver.mjs";
5
+ import { resolveArrangeTargetPath } from "./resolve-target.mjs";
6
+ //#region src/arrange/workspace.ts
7
+ /**
8
+ * @since 0.3.16-canary.0
9
+ */
10
+ async function prepareArrangeWorkspace(fs, args) {
11
+ const resolvedTarget = resolveArrangeTargetPath(fs, {
12
+ currentWorkingDirectory: args.currentWorkingDirectory,
13
+ rawTarget: args.rawTarget
14
+ });
15
+ if (!fs.existsSync(resolvedTarget)) return err(new AppError("NOT_FOUND", `Not found: ${resolvedTarget}`));
16
+ let rootDir;
17
+ try {
18
+ rootDir = findRepoRoot(args.currentWorkingDirectory, fs);
19
+ } catch (caughtError) {
20
+ return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
21
+ }
22
+ const loadedOutcome = await loadCodefastConfig(rootDir, fs);
23
+ if (!loadedOutcome.ok) return loadedOutcome;
24
+ return ok({
25
+ resolvedTarget,
26
+ rootDir,
27
+ config: loadedOutcome.value.config
28
+ });
29
+ }
30
+ //#endregion
31
+ export { prepareArrangeWorkspace };
package/dist/bin.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { runCli } from "./program.mjs";
2
+ import { runCli } from "./cli.mjs";
3
3
  import process from "node:process";
4
4
  //#region src/bin.ts
5
5
  const code = await runCli(process.argv);