@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
package/README.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  A small developer CLI for maintenance tasks in a TypeScript monorepo — Tailwind class arranging, `package.json` `exports` mirroring, and `@since` JSDoc tagging.
4
4
 
5
+ [![CI](https://github.com/codefastlabs/codefast/actions/workflows/release.yml/badge.svg)](https://github.com/codefastlabs/codefast/actions/workflows/release.yml)
6
+ [![npm version](https://img.shields.io/npm/v/@codefast/cli.svg)](https://www.npmjs.com/package/@codefast/cli)
7
+ [![npm downloads](https://img.shields.io/npm/dm/@codefast/cli.svg)](https://www.npmjs.com/package/@codefast/cli)
8
+ [![license](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
+
5
10
  ---
6
11
 
7
12
  ## Table of Contents
@@ -9,7 +14,7 @@ A small developer CLI for maintenance tasks in a TypeScript monorepo — Tailwin
9
14
  - [Why @codefast/cli](#why-codefastcli)
10
15
  - [Requirements](#requirements)
11
16
  - [Installation](#installation)
12
- - [Quick start](#quick-start)
17
+ - [Quick Start](#quick-start)
13
18
  - [Global options](#global-options)
14
19
  - [Exit codes](#exit-codes)
15
20
  - [`arrange`](#arrange)
@@ -75,7 +80,7 @@ npx @codefast/cli --help
75
80
 
76
81
  ---
77
82
 
78
- ## Quick start
83
+ ## Quick Start
79
84
 
80
85
  ```bash
81
86
  # Analyze Tailwind classes in the nearest package
@@ -334,7 +339,7 @@ Contract:
334
339
 
335
340
  Adjacent buckets may be merged into a single string literal when declared _compatible_ (e.g. Layout + Sizing), which keeps `cn()` calls readable without flattening unrelated concerns.
336
341
 
337
- To change placement, edit `classifyBareUtility` in `src/lib/arrange/domain/tokenizer.util.ts` and add a matching case in `tokenizer.util.test.ts`.
342
+ To change placement, extend `classifyBareUtility` in `packages/cli/src/arrange/domain/token-classifier.ts` (and cover the new rule with arrange tests if you introduce a new bucket).
338
343
 
339
344
  ---
340
345
 
@@ -0,0 +1,24 @@
1
+ import { AppError, messageFrom } from "../core/errors.mjs";
2
+ import { err, ok } from "../core/result.mjs";
3
+ import { accumulateAnalyzeReportForSourceFile, createEmptyAnalyzeReport } from "./domain/analyze-service.mjs";
4
+ import { scanArrangeTargets } from "./scan-target.mjs";
5
+ import { parseDomainSourceFile } from "./source-parse.mjs";
6
+ //#region src/arrange/analyze.ts
7
+ /**
8
+ * @since 0.3.16-canary.0
9
+ */
10
+ function analyzeDirectory(fs, analyzeRootPath) {
11
+ const report = createEmptyAnalyzeReport();
12
+ try {
13
+ const files = scanArrangeTargets(fs, analyzeRootPath);
14
+ for (const filePath of files) {
15
+ const sourceText = fs.readFileSync(filePath, "utf8");
16
+ accumulateAnalyzeReportForSourceFile(report, parseDomainSourceFile(filePath, sourceText), sourceText, filePath);
17
+ }
18
+ return ok(report);
19
+ } catch (caughtError) {
20
+ return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
21
+ }
22
+ }
23
+ //#endregion
24
+ export { analyzeDirectory };
@@ -1,6 +1,12 @@
1
1
  import { z } from "zod";
2
- //#region src/lib/arrange/presentation/arrange-cli.schema.ts
2
+ //#region src/arrange/cli-schema.ts
3
+ /**
4
+ * @since 0.3.16-canary.0
5
+ */
3
6
  const arrangeAnalyzeDirectoryRequestSchema = z.object({ analyzeRootPath: z.string().min(1, "analyzeRootPath is required") });
7
+ /**
8
+ * @since 0.3.16-canary.0
9
+ */
4
10
  const arrangeSyncRunRequestSchema = z.object({
5
11
  rootDir: z.string().min(1),
6
12
  targetPath: z.string().min(1),
@@ -9,6 +15,9 @@ const arrangeSyncRunRequestSchema = z.object({
9
15
  cnImport: z.string().optional(),
10
16
  config: z.unknown().optional()
11
17
  });
18
+ /**
19
+ * @since 0.3.16-canary.0
20
+ */
12
21
  const arrangeSuggestGroupsRequestSchema = z.object({
13
22
  inlineClasses: z.string().min(1, "Pass a class string. Example: codefast arrange group \"flex gap-2 text-sm rounded-md\""),
14
23
  emitTvStyleArray: z.boolean(),
@@ -0,0 +1,106 @@
1
+ import { parseWithSchema } from "../core/schema-parse.mjs";
2
+ import "../core/exit-codes.mjs";
3
+ import { logger } from "../core/logger.mjs";
4
+ import { consumeCliAppError, runCliResultAsync } from "../core/cli/result-handle.mjs";
5
+ import { nodeFilesystem } from "../core/filesystem/node.mjs";
6
+ import { arrangeAnalyzeDirectoryRequestSchema, arrangeSuggestGroupsRequestSchema, arrangeSyncRunRequestSchema } from "./cli-schema.mjs";
7
+ import { prepareArrangeWorkspace } from "./workspace.mjs";
8
+ import { analyzeDirectory } from "./analyze.mjs";
9
+ import { runArrangeSync } from "./sync.mjs";
10
+ import { suggestCnGroupsFromCli } from "./suggest.mjs";
11
+ import { printAnalyzeReport, printGroupFilePreviewFromWork, printSyncResult } from "./output.mjs";
12
+ import { readOptionalPositionalArg } from "../core/cli/positional.mjs";
13
+ import process from "node:process";
14
+ import { Command } from "commander";
15
+ //#region src/arrange/command.ts
16
+ /**
17
+ * @since 0.3.16-canary.0
18
+ */
19
+ function createArrangeCommand() {
20
+ const cmd = new Command("arrange").description("Analyze and regroup Tailwind classes in cn() / tv() calls (Tailwind v4)");
21
+ cmd.command("analyze").description("Report long strings, nested cn in tv(), and related findings").argument("[target]", "Directory or file (default: nearest package directory from cwd)").option("--json", "Print one JSON object on stdout instead of a human report", false).action(async (target, opts) => {
22
+ const prelude = await prepareArrangeWorkspace(nodeFilesystem, {
23
+ currentWorkingDirectory: process.cwd(),
24
+ rawTarget: readOptionalPositionalArg(target)
25
+ });
26
+ if (!consumeCliAppError(prelude)) return;
27
+ const { resolvedTarget } = prelude.value;
28
+ const parsed = parseWithSchema(arrangeAnalyzeDirectoryRequestSchema, { analyzeRootPath: resolvedTarget });
29
+ if (!consumeCliAppError(parsed)) return;
30
+ const outcome = analyzeDirectory(nodeFilesystem, parsed.value.analyzeRootPath);
31
+ if (!consumeCliAppError(outcome)) return;
32
+ if (opts.json) logger.out(formatArrangeAnalyzeJsonOutput(resolvedTarget, outcome.value));
33
+ else printAnalyzeReport(resolvedTarget, outcome.value);
34
+ });
35
+ const previewOrApply = (write) => async (target, opts) => {
36
+ const prelude = await prepareArrangeWorkspace(nodeFilesystem, {
37
+ currentWorkingDirectory: process.cwd(),
38
+ rawTarget: readOptionalPositionalArg(target)
39
+ });
40
+ if (!consumeCliAppError(prelude)) return;
41
+ const { resolvedTarget, rootDir, config } = prelude.value;
42
+ const parsed = parseWithSchema(arrangeSyncRunRequestSchema, {
43
+ rootDir,
44
+ targetPath: resolvedTarget,
45
+ write,
46
+ withClassName: opts.withClassName,
47
+ cnImport: opts.cnImport,
48
+ config: config.arrange ?? {}
49
+ });
50
+ if (!consumeCliAppError(parsed)) return;
51
+ await runCliResultAsync(runArrangeSync(nodeFilesystem, parsed.value), (value) => {
52
+ if (!write) for (const plan of value.previewPlans) printGroupFilePreviewFromWork(plan);
53
+ if (opts.json) {
54
+ logger.out(formatArrangeSyncJsonOutput(value, write));
55
+ return exitCodeForArrangeSyncResult(value);
56
+ }
57
+ printSyncResult(value, write);
58
+ return exitCodeForArrangeSyncResult(value);
59
+ });
60
+ };
61
+ cmd.command("preview").description("Dry-run: print suggested replacements without writing files").argument("[target]", "Directory or file (default: nearest package directory from cwd)").option("--with-classname, --with-class-name", "Append className as final cn() argument", false).option("--cn-import <spec>", "Override module specifier when adding cn import").option("--json", "Print one JSON object on stdout (suppresses human progress)", false).action(previewOrApply(false));
62
+ cmd.command("apply").description("Apply grouping and cn-in-tv unwrap edits to files").argument("[target]", "Directory or file (default: nearest package directory from cwd)").option("--with-classname, --with-class-name", "Append className as final cn() argument", false).option("--cn-import <spec>", "Override module specifier when adding cn import").option("--json", "Print one JSON object on stdout (suppresses human progress)", false).action(previewOrApply(true));
63
+ cmd.command("group").description("Try grouping on a pasted class string (stdout: cn(...) or tv array with --tv)").argument("<tokens...>", "Class tokens (quote a single string if it contains spaces)").option("--tv", "Emit tv()-style array instead of cn() call", false).option("--with-classname, --with-class-name", "Append className as final cn() argument", false).option("--json", "Print one JSON object on stdout instead of plain lines", false).action(async (classTokenSeries, opts) => {
64
+ const parsed = parseWithSchema(arrangeSuggestGroupsRequestSchema, {
65
+ inlineClasses: classTokenSeries.join(" ").trim(),
66
+ emitTvStyleArray: !!opts.tv,
67
+ trailingClassName: !!opts.withClassName
68
+ });
69
+ if (!consumeCliAppError(parsed)) return;
70
+ const output = suggestCnGroupsFromCli(parsed.value);
71
+ if (opts.json) logger.out(formatArrangeGroupJsonOutput(output));
72
+ else {
73
+ logger.out(output.primaryLine);
74
+ logger.out(output.bucketsCommentLine);
75
+ }
76
+ });
77
+ return cmd;
78
+ }
79
+ function formatArrangeAnalyzeJsonOutput(analyzeRootPath, report) {
80
+ return JSON.stringify({
81
+ schemaVersion: 1,
82
+ analyzeRootPath,
83
+ report
84
+ });
85
+ }
86
+ function formatArrangeSyncJsonOutput(result, write) {
87
+ const { previewPlans: _plans, ...serializableResult } = result;
88
+ return JSON.stringify({
89
+ schemaVersion: 1,
90
+ ok: result.hookError === null,
91
+ write,
92
+ result: serializableResult
93
+ });
94
+ }
95
+ function formatArrangeGroupJsonOutput(output) {
96
+ return JSON.stringify({
97
+ schemaVersion: 1,
98
+ primaryLine: output.primaryLine,
99
+ bucketsCommentLine: output.bucketsCommentLine
100
+ });
101
+ }
102
+ function exitCodeForArrangeSyncResult(result) {
103
+ return result.hookError !== null ? 1 : 0;
104
+ }
105
+ //#endregion
106
+ export { createArrangeCommand };
@@ -1,18 +1,22 @@
1
- import "./constants.domain.mjs";
2
- import { forEachDomainChild, isDomainCallExpression, isDomainJsxAttribute, isDomainObjectLiteralExpression } from "./ast/ast-node.model.mjs";
3
- import { buildKnownCnTvBindings, isCnOrTvIdentifier, lineOf } from "./ast/ast-helpers.helper.mjs";
4
- import { forEachStringLiteralInClassExpression } from "./ast/collectors-cn.collector.mjs";
5
- import { tokenizeClassString } from "./tailwind-token.value-object.mjs";
6
- import { collectCnCallsInsideTv, traverseTvObject } from "./ast/collectors-tv.collector.mjs";
7
- import { jsxClassNameStaticLiteral } from "./ast/collectors-jsx.collector.mjs";
8
- //#region src/lib/arrange/domain/arrange-analyze.service.ts
1
+ import "./constants.mjs";
2
+ import { tokenizeClassString } from "./tailwind-token.mjs";
3
+ import { forEachDomainChild, isDomainCallExpression, isDomainJsxAttribute, isDomainObjectLiteralExpression } from "./ast/ast-node.mjs";
4
+ import { forEachStringLiteralInClassExpression } from "./ast/collectors-cn.mjs";
5
+ import { jsxClassNameStaticLiteral } from "./ast/collectors-jsx.mjs";
6
+ import { buildKnownCnTvBindings, isCnOrTvIdentifier, lineOf } from "./ast/helpers.mjs";
7
+ import { collectCnCallsInsideTv, traverseTvObject } from "./ast/collectors-tv.mjs";
8
+ //#region src/arrange/domain/analyze-service.ts
9
9
  /**
10
10
  * Rich domain: Tailwind/cn/tv analysis rules (counts, long literals, nested cn in tv).
11
11
  * Pure orchestration of domain collectors and invariants — no I/O.
12
- */ const PREVIEW_MAX_LENGTH = 72;
12
+ */
13
+ const PREVIEW_MAX_LENGTH = 72;
13
14
  function previewText(text) {
14
15
  return text.length > PREVIEW_MAX_LENGTH ? `${text.slice(0, PREVIEW_MAX_LENGTH)}…` : text;
15
16
  }
17
+ /**
18
+ * @since 0.3.16-canary.0
19
+ */
16
20
  function createEmptyAnalyzeReport() {
17
21
  return {
18
22
  files: 0,
@@ -81,7 +85,10 @@ function visitJsxAttributeForArrangeAnalyze(jsxClassAttribute, domainSf, filePat
81
85
  }
82
86
  /**
83
87
  * Accumulates findings for one parsed source file into `report` (mutates report).
84
- */ function accumulateAnalyzeReportForSourceFile(report, domainSf, sourceText, filePath) {
88
+ *
89
+ * @since 0.3.16-canary.0
90
+ */
91
+ function accumulateAnalyzeReportForSourceFile(report, domainSf, sourceText, filePath) {
85
92
  report.files++;
86
93
  const knownBindings = buildKnownCnTvBindings(domainSf);
87
94
  const visitTypeScriptSubtree = (tsNode) => {
@@ -1,8 +1,11 @@
1
- //#region src/lib/arrange/domain/ast/ast-node.model.ts
1
+ //#region src/arrange/domain/ast/ast-node.ts
2
2
  /**
3
3
  * Pure-domain AST shapes for arrange analysis. No TypeScript compiler types.
4
4
  * Positions mirror `getStart(sourceFile)` / `getEnd()` semantics from translation.
5
- */ var DomainSyntaxKind = /* @__PURE__ */ function(DomainSyntaxKind) {
5
+ *
6
+ * @since 0.3.16-canary.0
7
+ */
8
+ let DomainSyntaxKind = /* @__PURE__ */ function(DomainSyntaxKind) {
6
9
  DomainSyntaxKind[DomainSyntaxKind["Unknown"] = 1] = "Unknown";
7
10
  DomainSyntaxKind[DomainSyntaxKind["Identifier"] = 2] = "Identifier";
8
11
  DomainSyntaxKind[DomainSyntaxKind["StringLiteral"] = 3] = "StringLiteral";
@@ -29,56 +32,104 @@
29
32
  DomainSyntaxKind[DomainSyntaxKind["JsxExpression"] = 24] = "JsxExpression";
30
33
  return DomainSyntaxKind;
31
34
  }({});
32
- var DomainBinaryOperator = /* @__PURE__ */ function(DomainBinaryOperator) {
35
+ /**
36
+ * @since 0.3.16-canary.0
37
+ */
38
+ let DomainBinaryOperator = /* @__PURE__ */ function(DomainBinaryOperator) {
33
39
  DomainBinaryOperator[DomainBinaryOperator["Plus"] = 0] = "Plus";
34
40
  DomainBinaryOperator[DomainBinaryOperator["Other"] = 1] = "Other";
35
41
  return DomainBinaryOperator;
36
42
  }({});
43
+ /**
44
+ * @since 0.3.16-canary.0
45
+ */
37
46
  function isDomainIdentifier(node) {
38
47
  return node.kind === 2;
39
48
  }
49
+ /**
50
+ * @since 0.3.16-canary.0
51
+ */
40
52
  function isDomainStringLiteral(node) {
41
53
  return node.kind === 3;
42
54
  }
43
55
  function isDomainNoSubstitutionTemplateLiteral(node) {
44
56
  return node.kind === 4;
45
57
  }
58
+ /**
59
+ * @since 0.3.16-canary.0
60
+ */
46
61
  function isDomainTailwindClassLiteral(node) {
47
62
  return isDomainStringLiteral(node) || isDomainNoSubstitutionTemplateLiteral(node);
48
63
  }
64
+ /**
65
+ * @since 0.3.16-canary.0
66
+ */
49
67
  function isDomainImportDeclaration(node) {
50
68
  return node.kind === 5;
51
69
  }
70
+ /**
71
+ * @since 0.3.16-canary.0
72
+ */
52
73
  function isDomainNamedImports(node) {
53
74
  return node.kind === 7;
54
75
  }
76
+ /**
77
+ * @since 0.3.16-canary.0
78
+ */
55
79
  function isDomainNamespaceImport(node) {
56
80
  return node.kind === 8;
57
81
  }
82
+ /**
83
+ * @since 0.3.16-canary.0
84
+ */
58
85
  function isDomainCallExpression(node) {
59
86
  return node.kind === 10;
60
87
  }
88
+ /**
89
+ * @since 0.3.16-canary.0
90
+ */
61
91
  function isDomainObjectLiteralExpression(node) {
62
92
  return node.kind === 12;
63
93
  }
94
+ /**
95
+ * @since 0.3.16-canary.0
96
+ */
64
97
  function isDomainPropertyAssignment(node) {
65
98
  return node.kind === 13;
66
99
  }
100
+ /**
101
+ * @since 0.3.16-canary.0
102
+ */
67
103
  function isDomainArrayLiteralExpression(node) {
68
104
  return node.kind === 14;
69
105
  }
106
+ /**
107
+ * @since 0.3.16-canary.0
108
+ */
70
109
  function isDomainSpreadElement(node) {
71
110
  return node.kind === 15;
72
111
  }
112
+ /**
113
+ * @since 0.3.16-canary.0
114
+ */
73
115
  function isDomainPropertyAccessExpression(node) {
74
116
  return node.kind === 11;
75
117
  }
118
+ /**
119
+ * @since 0.3.16-canary.0
120
+ */
76
121
  function isDomainJsxAttribute(node) {
77
122
  return node.kind === 23;
78
123
  }
124
+ /**
125
+ * @since 0.3.16-canary.0
126
+ */
79
127
  function isDomainJsxExpression(node) {
80
128
  return node.kind === 24;
81
129
  }
130
+ /**
131
+ * @since 0.3.16-canary.0
132
+ */
82
133
  function forEachDomainChild(node, visit) {
83
134
  switch (node.kind) {
84
135
  case 1:
@@ -151,6 +202,9 @@ function forEachDomainChild(node, visit) {
151
202
  default: return;
152
203
  }
153
204
  }
205
+ /**
206
+ * @since 0.3.16-canary.0
207
+ */
154
208
  function lineOfSourcePosition(sourceText, pos) {
155
209
  const boundedPos = Math.max(0, Math.min(pos, sourceText.length));
156
210
  let line = 1;
@@ -1,44 +1,56 @@
1
- import "../constants.domain.mjs";
2
- import { DomainBinaryOperator, DomainSyntaxKind, isDomainArrayLiteralExpression, isDomainTailwindClassLiteral } from "./ast-node.model.mjs";
3
- //#region src/lib/arrange/domain/ast/collectors-cn.collector.ts
1
+ import "../constants.mjs";
2
+ import { isDomainArrayLiteralExpression, isDomainTailwindClassLiteral } from "./ast-node.mjs";
3
+ //#region src/arrange/domain/ast/collectors-cn.ts
4
+ /**
5
+ * @since 0.3.16-canary.0
6
+ */
4
7
  function forEachStringLiteralInClassExpression(expr, sink, depth = 0, options) {
5
8
  if (depth > 12) return;
6
9
  if (isDomainTailwindClassLiteral(expr)) {
7
10
  sink(expr);
8
11
  return;
9
12
  }
10
- if (expr.kind === DomainSyntaxKind.ParenthesizedExpression) {
13
+ if (expr.kind === 16) {
11
14
  forEachStringLiteralInClassExpression(expr.expression, sink, depth + 1, options);
12
15
  return;
13
16
  }
14
- if (expr.kind === DomainSyntaxKind.AsExpression || expr.kind === DomainSyntaxKind.SatisfiesExpression) {
17
+ if (expr.kind === 17 || expr.kind === 18) {
15
18
  forEachStringLiteralInClassExpression(expr.expression, sink, depth + 1, options);
16
19
  return;
17
20
  }
18
- if (expr.kind === DomainSyntaxKind.NonNullExpression) {
21
+ if (expr.kind === 19) {
19
22
  forEachStringLiteralInClassExpression(expr.expression, sink, depth + 1, options);
20
23
  return;
21
24
  }
22
- if (expr.kind === DomainSyntaxKind.ConditionalExpression) {
25
+ if (expr.kind === 20) {
23
26
  if (options?.descendIntoConditional === false) return;
24
27
  forEachStringLiteralInClassExpression(expr.whenTrue, sink, depth + 1, options);
25
28
  forEachStringLiteralInClassExpression(expr.whenFalse, sink, depth + 1, options);
26
29
  return;
27
30
  }
28
- if (expr.kind === DomainSyntaxKind.BinaryExpression && expr.operator === DomainBinaryOperator.Plus) {
31
+ if (expr.kind === 21 && expr.operator === 0) {
29
32
  forEachStringLiteralInClassExpression(expr.left, sink, depth + 1, options);
30
33
  forEachStringLiteralInClassExpression(expr.right, sink, depth + 1, options);
31
34
  return;
32
35
  }
33
36
  if (isDomainArrayLiteralExpression(expr)) for (const arrayElement of expr.elements) {
34
- if (arrayElement.kind === DomainSyntaxKind.SpreadElement) continue;
37
+ if (arrayElement.kind === 15) continue;
35
38
  forEachStringLiteralInClassExpression(arrayElement, sink, depth + 1, options);
36
39
  }
37
40
  }
41
+ /**
42
+ * @since 0.3.16-canary.0
43
+ */
38
44
  function isUnsafeLiteralForCnStyleApplySplit(classLiteral) {
39
45
  return classLiteral.parent !== null && isDomainArrayLiteralExpression(classLiteral.parent);
40
46
  }
47
+ /**
48
+ * @since 0.3.16-canary.0
49
+ */
41
50
  const CN_APPLY_LITERAL_WALK_OPTS = { descendIntoConditional: false };
51
+ /**
52
+ * @since 0.3.16-canary.0
53
+ */
42
54
  function collectUnconditionalTailwindLiteralsFromCnArguments(args) {
43
55
  const staticLits = [];
44
56
  for (const arg of args) if (isDomainTailwindClassLiteral(arg)) {
@@ -1,5 +1,8 @@
1
- import { isDomainIdentifier, isDomainJsxExpression, isDomainTailwindClassLiteral } from "./ast-node.model.mjs";
2
- //#region src/lib/arrange/domain/ast/collectors-jsx.collector.ts
1
+ import { isDomainIdentifier, isDomainJsxExpression, isDomainTailwindClassLiteral } from "./ast-node.mjs";
2
+ //#region src/arrange/domain/ast/collectors-jsx.ts
3
+ /**
4
+ * @since 0.3.16-canary.0
5
+ */
3
6
  function jsxClassNameStaticLiteral(jsxClassNameAttribute) {
4
7
  if (!isDomainIdentifier(jsxClassNameAttribute.name) || jsxClassNameAttribute.name.text !== "className") return;
5
8
  const init = jsxClassNameAttribute.initializer;
@@ -1,9 +1,12 @@
1
- import "../constants.domain.mjs";
2
- import { forEachDomainChild, isDomainArrayLiteralExpression, isDomainCallExpression, isDomainObjectLiteralExpression, isDomainPropertyAssignment, isDomainSpreadElement, isDomainTailwindClassLiteral } from "./ast-node.model.mjs";
3
- import { buildKnownCnTvBindings, isCnOrTvIdentifier, propertyAssignmentNameText } from "./ast-helpers.helper.mjs";
4
- import { CN_APPLY_LITERAL_WALK_OPTS, collectUnconditionalTailwindLiteralsFromCnArguments, forEachStringLiteralInClassExpression, isUnsafeLiteralForCnStyleApplySplit } from "./collectors-cn.collector.mjs";
5
- import { tokenizeClassString } from "../tailwind-token.value-object.mjs";
6
- //#region src/lib/arrange/domain/ast/collectors-tv.collector.ts
1
+ import "../constants.mjs";
2
+ import { tokenizeClassString } from "../tailwind-token.mjs";
3
+ import { forEachDomainChild, isDomainArrayLiteralExpression, isDomainCallExpression, isDomainObjectLiteralExpression, isDomainPropertyAssignment, isDomainSpreadElement, isDomainTailwindClassLiteral } from "./ast-node.mjs";
4
+ import { CN_APPLY_LITERAL_WALK_OPTS, collectUnconditionalTailwindLiteralsFromCnArguments, forEachStringLiteralInClassExpression, isUnsafeLiteralForCnStyleApplySplit } from "./collectors-cn.mjs";
5
+ import { buildKnownCnTvBindings, isCnOrTvIdentifier, propertyAssignmentNameText } from "./helpers.mjs";
6
+ //#region src/arrange/domain/ast/collectors-tv.ts
7
+ /**
8
+ * @since 0.3.16-canary.0
9
+ */
7
10
  function traverseTvObject(sourceFile, obj, visitor, depth = 0, knownBindings) {
8
11
  if (depth > 12) return;
9
12
  for (const prop of obj.properties) {
@@ -37,6 +40,9 @@ function traverseTvObject(sourceFile, obj, visitor, depth = 0, knownBindings) {
37
40
  });
38
41
  }
39
42
  }
43
+ /**
44
+ * @since 0.3.16-canary.0
45
+ */
40
46
  function collectCnCallsInsideTv(sourceFile, obj, knownBindings, depth = 0) {
41
47
  if (depth > 12) return [];
42
48
  const calls = [];
@@ -59,6 +65,9 @@ function collectCnCallsInsideTv(sourceFile, obj, knownBindings, depth = 0) {
59
65
  }
60
66
  return calls;
61
67
  }
68
+ /**
69
+ * @since 0.3.16-canary.0
70
+ */
62
71
  function listAllCnCallsInsideTvInSourceFile(sourceFile, knownBindings) {
63
72
  const calls = [];
64
73
  const visitSubtree = (tsNode) => {
@@ -84,6 +93,9 @@ function makeStringNode(nodes, sourceFile, isTvContext, cnCall) {
84
93
  }
85
94
  };
86
95
  }
96
+ /**
97
+ * @since 0.3.16-canary.0
98
+ */
87
99
  function slotClassString(stringNode) {
88
100
  return stringNode.nodes.map((literal) => literal.text).join(" ");
89
101
  }
@@ -144,6 +156,9 @@ function collectTvSlots(sourceFile, obj, knownBindings, results, seenNodePos, de
144
156
  }
145
157
  }
146
158
  }
159
+ /**
160
+ * @since 0.3.16-canary.0
161
+ */
147
162
  function collectGroupableStringNodes(sourceFile) {
148
163
  const results = [];
149
164
  const seenNodePos = /* @__PURE__ */ new Set();
@@ -1,10 +1,11 @@
1
- import { EMPTY_CN_TV_BINDINGS } from "../constants.domain.mjs";
2
- import { applyEditsDescending, indentOfLineContaining } from "../../../shared/source-code/domain/text-edit.model.mjs";
3
- import { isDomainIdentifier, isDomainImportDeclaration, isDomainNamedImports, isDomainNamespaceImport, isDomainPropertyAccessExpression, isDomainStringLiteral, lineOfSourcePosition } from "./ast-node.model.mjs";
4
- //#region src/lib/arrange/domain/ast/ast-helpers.helper.ts
1
+ import { EMPTY_CN_TV_BINDINGS } from "../constants.mjs";
2
+ import { isDomainIdentifier, isDomainImportDeclaration, isDomainNamedImports, isDomainNamespaceImport, isDomainPropertyAccessExpression, isDomainStringLiteral, lineOfSourcePosition } from "./ast-node.mjs";
3
+ import { applyEditsDescending, indentOfLineContaining } from "../../../core/source-text-edit.mjs";
4
+ //#region src/arrange/domain/ast/helpers.ts
5
5
  /**
6
6
  * Known module specifiers that export `cn` / `tv`.
7
- */ const KNOWN_CN_TV_MODULES = new Set([
7
+ */
8
+ const KNOWN_CN_TV_MODULES = new Set([
8
9
  "@codefast/tailwind-variants",
9
10
  "clsx",
10
11
  "class-variance-authority",
@@ -16,7 +17,8 @@ import { isDomainIdentifier, isDomainImportDeclaration, isDomainNamedImports, is
16
17
  /**
17
18
  * True for typical shadcn-style re-exports: `./utils`, `@/lib/utils`, `…/utils/…`,
18
19
  * or a dedicated `cn.ts` / `cn.tsx` module.
19
- */ function moduleLooksLikeCnTvReexport(moduleSpecifier) {
20
+ */
21
+ function moduleLooksLikeCnTvReexport(moduleSpecifier) {
20
22
  const norm = moduleSpecifier.replace(/\\/g, "/");
21
23
  if (/(?:^|[./])utils(?:\/|$)/.test(norm)) return true;
22
24
  if (/\/utils\//.test(norm) || /\/utils$/.test(norm)) return true;
@@ -26,7 +28,10 @@ import { isDomainIdentifier, isDomainImportDeclaration, isDomainNamedImports, is
26
28
  /**
27
29
  * Build a set of local binding names that are imported from a known cn/tv
28
30
  * module in `sourceFile`.
29
- */ function buildKnownCnTvBindings(sourceFile) {
31
+ *
32
+ * @since 0.3.16-canary.0
33
+ */
34
+ function buildKnownCnTvBindings(sourceFile) {
30
35
  const bindings = /* @__PURE__ */ new Set();
31
36
  for (const stmt of sourceFile.statements) {
32
37
  if (!isDomainImportDeclaration(stmt) || !stmt.importClause) continue;
@@ -50,23 +55,35 @@ import { isDomainIdentifier, isDomainImportDeclaration, isDomainNamedImports, is
50
55
  /**
51
56
  * Returns true when `expr` is an identifier whose name matches `name` AND
52
57
  * that name is listed in `knownBindings` from a recognized import.
53
- */ function isCnOrTvIdentifier(expr, name, knownBindings = EMPTY_CN_TV_BINDINGS) {
58
+ *
59
+ * @since 0.3.16-canary.0
60
+ */
61
+ function isCnOrTvIdentifier(expr, name, knownBindings = EMPTY_CN_TV_BINDINGS) {
54
62
  if (knownBindings.size === 0) return false;
55
63
  if (isDomainIdentifier(expr) && expr.text === name) return knownBindings.has(expr.text);
56
64
  if (isDomainPropertyAccessExpression(expr) && expr.name.text === name) return isDomainIdentifier(expr.expression) && knownBindings.has(expr.expression.text);
57
65
  return false;
58
66
  }
67
+ /**
68
+ * @since 0.3.16-canary.0
69
+ */
59
70
  function propertyAssignmentNameText(prop) {
60
71
  if (isDomainIdentifier(prop.name)) return prop.name.text;
61
72
  if (isDomainStringLiteral(prop.name)) return prop.name.text;
62
73
  }
74
+ /**
75
+ * @since 0.3.16-canary.0
76
+ */
63
77
  function lineOf(sourceFile, node) {
64
78
  return lineOfSourcePosition(sourceFile.text, node.pos);
65
79
  }
66
80
  /**
67
81
  * Replace `cn(...)` nested in `tv({...})` with a plain string (one arg) or a string
68
82
  * array (multiple args). Returns undefined when there are zero arguments.
69
- */ function unwrapCnInsideTvCallReplacement(call, sourceText) {
83
+ *
84
+ * @since 0.3.16-canary.0
85
+ */
86
+ function unwrapCnInsideTvCallReplacement(call, sourceText) {
70
87
  const args = call.arguments;
71
88
  if (args.length === 0) return;
72
89
  const baseIndent = indentOfLineContaining(sourceText, call.pos);
@@ -1,13 +1,16 @@
1
- import "../constants.domain.mjs";
2
- import { endAfterOptionalCommaFollowingInSource, indentOfLineContaining, textPrefixFromLineStartToPosition } from "../../../shared/source-code/domain/text-edit.model.mjs";
3
- import { forEachDomainChild, isDomainArrayLiteralExpression, isDomainJsxAttribute, isDomainTailwindClassLiteral } from "./ast-node.model.mjs";
4
- import { isUnsafeLiteralForCnStyleApplySplit } from "./collectors-cn.collector.mjs";
5
- import { tokenizeClassString } from "../tailwind-token.value-object.mjs";
6
- import { collectGroupableStringNodes, slotClassString } from "./collectors-tv.collector.mjs";
7
- import { areCnTailwindPartitionsEquivalent, suggestCnGroups, summarizeGroupBucketLabels } from "../grouping.domain.mjs";
8
- import { escapeTsStringLiteralContent, formatArray, formatArrayElementsAsSiblingLines, formatJsxCnAttributeValue } from "../source-text-formatters.formatter.mjs";
9
- import { jsxClassNameStaticLiteral } from "./collectors-jsx.collector.mjs";
10
- //#region src/lib/arrange/domain/ast/targets.model.ts
1
+ import "../constants.mjs";
2
+ import { tokenizeClassString } from "../tailwind-token.mjs";
3
+ import { forEachDomainChild, isDomainArrayLiteralExpression, isDomainJsxAttribute, isDomainTailwindClassLiteral } from "./ast-node.mjs";
4
+ import { isUnsafeLiteralForCnStyleApplySplit } from "./collectors-cn.mjs";
5
+ import { jsxClassNameStaticLiteral } from "./collectors-jsx.mjs";
6
+ import { endAfterOptionalCommaFollowingInSource, indentOfLineContaining, textPrefixFromLineStartToPosition } from "../../../core/source-text-edit.mjs";
7
+ import { collectGroupableStringNodes, slotClassString } from "./collectors-tv.mjs";
8
+ import { areCnTailwindPartitionsEquivalent, suggestCnGroups, summarizeGroupBucketLabels } from "../grouping.mjs";
9
+ import { escapeTsStringLiteralContent, formatArray, formatArrayElementsAsSiblingLines, formatJsxCnAttributeValue } from "../source-text-formatters.mjs";
10
+ //#region src/arrange/domain/ast/targets.ts
11
+ /**
12
+ * @since 0.3.16-canary.0
13
+ */
11
14
  function targetReplaceStart(target) {
12
15
  if (target.kind === "cnArg") return target.item.cnCall ? target.item.cnCall.pos : target.item.primaryClassLiteral.pos;
13
16
  return target.valueNode.pos;
@@ -29,6 +32,9 @@ function collectLongJsxClassNameTargets(sourceFile) {
29
32
  for (const stmt of sourceFile.statements) visitTypeScriptSubtree(stmt);
30
33
  return results;
31
34
  }
35
+ /**
36
+ * @since 0.3.16-canary.0
37
+ */
32
38
  function collectGroupTargets(sourceFile, filePath) {
33
39
  const cnPart = collectGroupableStringNodes(sourceFile).map((stringNode) => ({
34
40
  kind: "cnArg",
@@ -58,6 +64,9 @@ function formatCnCallReplacement(stringNode, sourceText, withClassName) {
58
64
  const commaAfterLastArg = allArgs.length > 1;
59
65
  return `cn(\n${allArgs.map((argLine, lineIndex) => lineIndex < allArgs.length - 1 || commaAfterLastArg ? `${argLine},` : `${argLine}`).join("\n")}\n${baseIndent})`;
60
66
  }
67
+ /**
68
+ * @since 0.3.16-canary.0
69
+ */
61
70
  function planGroupEditForTarget(target, textAfterUnwrap, withClassName) {
62
71
  if (target.kind === "jsxClassName") {
63
72
  const groups = suggestCnGroups(target.lit.text);