@codefast/cli 0.3.16-canary.2 → 0.4.0-canary.4
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.
- package/README.md +254 -86
- package/dist/arrange/analyze.mjs +2 -2
- package/dist/arrange/command.mjs +51 -27
- package/dist/arrange/domain/analyze-service.mjs +2 -2
- package/dist/arrange/domain/ast/collectors-cn.mjs +1 -1
- package/dist/arrange/domain/ast/collectors-tv.mjs +2 -2
- package/dist/arrange/domain/ast/helpers.mjs +2 -2
- package/dist/arrange/domain/ast/simplify-targets.mjs +109 -0
- package/dist/arrange/domain/ast/targets.mjs +25 -10
- package/dist/arrange/domain/grouping-service.mjs +1 -1
- package/dist/arrange/domain/grouping.mjs +5 -5
- package/dist/arrange/domain/imports.mjs +50 -2
- package/dist/arrange/domain/token-classifier.mjs +12 -12
- package/dist/arrange/output.mjs +11 -3
- package/dist/arrange/process-file.mjs +1 -1
- package/dist/arrange/scan-target.mjs +10 -1
- package/dist/arrange/simplify-process-file.mjs +35 -0
- package/dist/arrange/simplify-sync.mjs +32 -0
- package/dist/arrange/suggest.mjs +1 -1
- package/dist/arrange/sync.mjs +1 -1
- package/dist/arrange/workspace.mjs +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/core/cli/result-handle.mjs +1 -1
- package/dist/core/config/schema.mjs +31 -10
- package/dist/core/source-text-edit.mjs +1 -1
- package/dist/core/workspace/resolver.mjs +3 -3
- package/dist/mirror/cli-result.mjs +2 -1
- package/dist/mirror/cli-schema.mjs +2 -1
- package/dist/mirror/command.mjs +12 -11
- package/dist/mirror/domain/exports.mjs +16 -19
- package/dist/mirror/output.mjs +3 -0
- package/dist/mirror/supplement-exports.mjs +114 -0
- package/dist/mirror/sync-reporter.mjs +5 -2
- package/dist/mirror/sync-workspace-package.mjs +35 -29
- package/dist/mirror/sync.mjs +2 -1
- package/dist/mirror/write-exports.mjs +3 -2
- package/dist/tag/command.mjs +6 -6
- package/dist/tag/output.mjs +1 -1
- package/dist/tag/sync.mjs +1 -1
- package/dist/tag/target-runner.mjs +1 -1
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -18,9 +18,13 @@ A small developer CLI for maintenance tasks in a TypeScript monorepo — Tailwin
|
|
|
18
18
|
- [Global options](#global-options)
|
|
19
19
|
- [Exit codes](#exit-codes)
|
|
20
20
|
- [`arrange`](#arrange)
|
|
21
|
-
- [`mirror
|
|
22
|
-
- [`tag`
|
|
21
|
+
- [`mirror`](#mirror)
|
|
22
|
+
- [`tag`](#tag)
|
|
23
23
|
- [Configuration (`codefast.config.*`)](#configuration-codefastconfig)
|
|
24
|
+
- [Full skeleton](#full-skeleton)
|
|
25
|
+
- [`mirror` configuration](#mirror-configuration)
|
|
26
|
+
- [`tag` configuration](#tag-configuration)
|
|
27
|
+
- [`arrange` configuration](#arrange-configuration)
|
|
24
28
|
- [Lifecycle hooks](#lifecycle-hooks)
|
|
25
29
|
- [Grouping philosophy — Render Pipeline Order](#grouping-philosophy--render-pipeline-order)
|
|
26
30
|
- [Troubleshooting](#troubleshooting)
|
|
@@ -36,7 +40,9 @@ Three recurring maintenance chores you don't want to script by hand:
|
|
|
36
40
|
|
|
37
41
|
- **`arrange`** — regroup Tailwind class strings inside `cn()` / `tv()` calls in render-pipeline order.
|
|
38
42
|
- **`mirror`** — regenerate `package.json` `exports` fields from built `dist/` trees across a pnpm workspace.
|
|
39
|
-
- **`tag`**
|
|
43
|
+
- **`tag`** — add `@since <version>` JSDoc tags to exported declarations that are missing version metadata.
|
|
44
|
+
|
|
45
|
+
Each top-level command **performs its action by default** (writing files). Pass `--dry-run` to preview without writing. `arrange` additionally exposes a read-only `inspect` report.
|
|
40
46
|
|
|
41
47
|
```mermaid
|
|
42
48
|
flowchart LR
|
|
@@ -45,19 +51,16 @@ flowchart LR
|
|
|
45
51
|
R --> M[mirror]
|
|
46
52
|
R --> T[tag]
|
|
47
53
|
|
|
48
|
-
A --> A0[
|
|
49
|
-
A --> A1[
|
|
50
|
-
A --> A2[
|
|
51
|
-
A --> A3[group]
|
|
52
|
-
|
|
53
|
-
M --> M0[sync]
|
|
54
|
+
A --> A0[inspect]
|
|
55
|
+
A --> A1[simplify]
|
|
56
|
+
A --> A2[group]
|
|
54
57
|
```
|
|
55
58
|
|
|
56
59
|
---
|
|
57
60
|
|
|
58
61
|
## Requirements
|
|
59
62
|
|
|
60
|
-
- Node.js `>=
|
|
63
|
+
- Node.js `>= 24.0.0`
|
|
61
64
|
- pnpm (recommended — the CLI discovers workspaces via `pnpm-workspace.yaml`)
|
|
62
65
|
|
|
63
66
|
---
|
|
@@ -83,17 +86,17 @@ npx @codefast/cli --help
|
|
|
83
86
|
## Quick Start
|
|
84
87
|
|
|
85
88
|
```bash
|
|
86
|
-
#
|
|
87
|
-
codefast arrange
|
|
89
|
+
# Inspect Tailwind classes in the nearest package (read-only report)
|
|
90
|
+
codefast arrange inspect
|
|
88
91
|
|
|
89
92
|
# Preview proposed rewrites — no files written
|
|
90
|
-
codefast arrange
|
|
93
|
+
codefast arrange --dry-run packages/ui/src/components
|
|
91
94
|
|
|
92
95
|
# Apply after reviewing
|
|
93
|
-
codefast arrange
|
|
96
|
+
codefast arrange packages/ui/src/components
|
|
94
97
|
|
|
95
98
|
# Regenerate every package's `exports` from built dist/
|
|
96
|
-
codefast mirror
|
|
99
|
+
codefast mirror
|
|
97
100
|
|
|
98
101
|
# Add @since <version> to exported APIs under ./src
|
|
99
102
|
codefast tag
|
|
@@ -109,15 +112,17 @@ codefast tag
|
|
|
109
112
|
| `-V`, `--version` | Print the CLI version and exit. |
|
|
110
113
|
| `-h`, `--help` | Show contextual help for the invoked command. |
|
|
111
114
|
|
|
115
|
+
> **Placement.** Global flags must come **before** the command name (git-style), e.g. `codefast --no-color mirror`. A flag after the command name binds to that command.
|
|
116
|
+
|
|
112
117
|
---
|
|
113
118
|
|
|
114
119
|
## Exit codes
|
|
115
120
|
|
|
116
|
-
| Code | Meaning
|
|
117
|
-
| ---- |
|
|
118
|
-
| `0` | Success.
|
|
119
|
-
| `1` | General failure (missing paths, infrastructure errors, partial failures in `mirror
|
|
120
|
-
| `2` | Invalid invocation or input (Zod schema validation on CLI requests — `CLI_EXIT_USAGE`).
|
|
121
|
+
| Code | Meaning |
|
|
122
|
+
| ---- | --------------------------------------------------------------------------------------------------- |
|
|
123
|
+
| `0` | Success. |
|
|
124
|
+
| `1` | General failure (missing paths, infrastructure errors, partial failures in `mirror`, failed hooks). |
|
|
125
|
+
| `2` | Invalid invocation or input (Zod schema validation on CLI requests — `CLI_EXIT_USAGE`). |
|
|
121
126
|
|
|
122
127
|
Diagnostics go to **stderr**; primary command output goes to **stdout**. When a subcommand accepts `--json`, only the JSON object is written to stdout and all human progress is suppressed, so the stream stays pipeline-safe.
|
|
123
128
|
|
|
@@ -133,25 +138,28 @@ When `[target]` is omitted, `arrange` auto-detects the **nearest package directo
|
|
|
133
138
|
|
|
134
139
|
### Workflow
|
|
135
140
|
|
|
136
|
-
| Step | Command
|
|
137
|
-
| ---- |
|
|
138
|
-
| 1 | `codefast arrange
|
|
139
|
-
| 2 | `codefast arrange
|
|
140
|
-
| 3 | `codefast arrange
|
|
141
|
+
| Step | Command | Effect |
|
|
142
|
+
| ---- | ------------------------------------- | ---------------------------------------------- |
|
|
143
|
+
| 1 | `codefast arrange inspect [target]` | Report only — no files changed |
|
|
144
|
+
| 2 | `codefast arrange --dry-run [target]` | Show exactly what a bare `arrange` would write |
|
|
145
|
+
| 3 | `codefast arrange [target]` | Write the changes |
|
|
141
146
|
|
|
142
|
-
### Flags (
|
|
147
|
+
### Flags (`arrange`)
|
|
143
148
|
|
|
144
149
|
| Flag | Description |
|
|
145
150
|
| -------------------- | --------------------------------------------------------------------------- |
|
|
151
|
+
| `--dry-run` | Preview the rewrite without writing files. |
|
|
146
152
|
| `--with-class-name` | Append `className` as the last argument when rewriting a `cn(...)` call. |
|
|
147
153
|
| `--cn-import <spec>` | Override the module specifier used when a missing `cn` import is added. |
|
|
148
154
|
| `--json` | Print a single JSON object on stdout; suppresses human progress and colors. |
|
|
149
155
|
|
|
150
|
-
`
|
|
156
|
+
`inspect` also supports `--json`. `simplify` accepts `--dry-run` and `--json`.
|
|
157
|
+
|
|
158
|
+
> **Test files are skipped.** Directory scans exclude `*.test.*` / `*.spec.*` files — a `cn(...)` inside an assertion is test data, not styling to reformat. Pass such a file explicitly to override.
|
|
151
159
|
|
|
152
160
|
### `arrange group` — one-shot classification
|
|
153
161
|
|
|
154
|
-
Groups a class string without touching the filesystem. Useful for checking how classes would be grouped before running `
|
|
162
|
+
Groups a class string without touching the filesystem. Useful for checking how classes would be grouped before running `arrange`:
|
|
155
163
|
|
|
156
164
|
```bash
|
|
157
165
|
# Quoted string
|
|
@@ -172,44 +180,47 @@ codefast arrange group --tv "flex items-center gap-2"
|
|
|
172
180
|
|
|
173
181
|
### `--json` payloads
|
|
174
182
|
|
|
175
|
-
| Subcommand
|
|
176
|
-
|
|
|
177
|
-
| `
|
|
178
|
-
| `
|
|
179
|
-
| `
|
|
183
|
+
| Subcommand | Payload highlights |
|
|
184
|
+
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
185
|
+
| `arrange` | `schemaVersion`, `write`, `ok` (`false` if the `onAfterWrite` hook failed), full `result` (`filePaths`, `modifiedFiles`, `totalFound`, …). |
|
|
186
|
+
| `inspect` | `schemaVersion`, `analyzeRootPath`, full `report` (same data as the human report). |
|
|
187
|
+
| `simplify` | `schemaVersion`, `write`, `ok`, full `result`. |
|
|
188
|
+
| `group` | `schemaVersion`, `primaryLine`, `bucketsCommentLine`. |
|
|
180
189
|
|
|
181
190
|
---
|
|
182
191
|
|
|
183
|
-
## `mirror
|
|
192
|
+
## `mirror`
|
|
184
193
|
|
|
185
194
|
Scans built `dist/` trees and regenerates the `exports` field of every workspace package. Run it from anywhere inside the monorepo — the workspace root is discovered via `pnpm-workspace.yaml`.
|
|
186
195
|
|
|
187
196
|
```bash
|
|
188
|
-
codefast mirror
|
|
189
|
-
codefast mirror
|
|
190
|
-
codefast mirror
|
|
191
|
-
codefast mirror
|
|
197
|
+
codefast mirror # all workspace packages
|
|
198
|
+
codefast mirror packages/ui # one package (path relative to repo root)
|
|
199
|
+
codefast mirror --dry-run # preview — report changes without writing
|
|
200
|
+
codefast mirror -v # verbose diagnostics
|
|
201
|
+
codefast mirror --json # JSON summary for scripts / CI
|
|
192
202
|
```
|
|
193
203
|
|
|
194
|
-
| Flag | Description
|
|
195
|
-
| ----------------- |
|
|
196
|
-
|
|
|
197
|
-
| `--
|
|
204
|
+
| Flag | Description |
|
|
205
|
+
| ----------------- | ---------------------------------------------------------------------------- |
|
|
206
|
+
| `--dry-run` | Report what would change without writing any `package.json`. |
|
|
207
|
+
| `-v`, `--verbose` | Print extra diagnostics. |
|
|
208
|
+
| `--json` | Print a single `{ schemaVersion, ok, write, elapsedSeconds, stats }` object. |
|
|
198
209
|
|
|
199
|
-
> **Build first.** `mirror
|
|
210
|
+
> **Build first.** `mirror` reads from `dist/`. Run your build before syncing or exports will reflect stale output.
|
|
200
211
|
|
|
201
212
|
Exit code is `1` when any package fails (`stats.packagesErrored > 0`), `0` otherwise.
|
|
202
213
|
|
|
203
214
|
---
|
|
204
215
|
|
|
205
|
-
## `tag`
|
|
216
|
+
## `tag`
|
|
206
217
|
|
|
207
218
|
Scans `.ts` / `.tsx` sources and adds `@since <current-package-version>` to exported declarations that don't already carry one. The version is read from the nearest `package.json` walking up from the target path.
|
|
208
219
|
|
|
209
220
|
```bash
|
|
210
221
|
codefast tag # auto-discover workspace packages from cwd
|
|
211
|
-
codefast tag packages/ui/src #
|
|
212
|
-
codefast
|
|
222
|
+
codefast tag packages/ui/src # tag a custom target
|
|
223
|
+
codefast tag --dry-run # preview only, do not write
|
|
213
224
|
codefast tag --json # JSON summary for scripts / CI
|
|
214
225
|
```
|
|
215
226
|
|
|
@@ -228,37 +239,46 @@ What it updates:
|
|
|
228
239
|
|
|
229
240
|
## Configuration (`codefast.config.*`)
|
|
230
241
|
|
|
231
|
-
Create
|
|
242
|
+
Create a config file at the **monorepo root** (next to `pnpm-workspace.yaml`). Supported names, in priority order:
|
|
243
|
+
|
|
244
|
+
| File name | Format |
|
|
245
|
+
| ---------------------- | --------------------------------------- |
|
|
246
|
+
| `codefast.config.mjs` | ES module — `export default { … }` |
|
|
247
|
+
| `codefast.config.js` | ES module (if `"type":"module"`) or CJS |
|
|
248
|
+
| `codefast.config.cjs` | CommonJS — `module.exports = { … }` |
|
|
249
|
+
| `codefast.config.json` | Plain JSON (no functions — no hooks) |
|
|
250
|
+
|
|
251
|
+
The file is found by walking up from the working directory, so running the CLI from any sub-directory still picks up the root config.
|
|
252
|
+
|
|
253
|
+
> **Security.** `.js`, `.mjs`, and `.cjs` files are executed via `import()`. Only run `codefast` inside repositories you trust.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
### Full skeleton
|
|
232
258
|
|
|
233
259
|
```javascript
|
|
234
260
|
// codefast.config.mjs
|
|
235
261
|
import { execSync } from "node:child_process";
|
|
236
262
|
|
|
237
263
|
export default {
|
|
264
|
+
// ─── mirror ────────────────────────────────────────────────────────────────
|
|
265
|
+
// Keys are package names (from package.json#name).
|
|
266
|
+
// Set a package to `false` to skip it entirely.
|
|
267
|
+
// Omit a package to process it with default settings.
|
|
238
268
|
mirror: {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
},
|
|
247
|
-
},
|
|
248
|
-
cssExports: {
|
|
249
|
-
// Shorthand: `true` enables default CSS export detection
|
|
250
|
-
"@acme/theme": true,
|
|
251
|
-
// Or configure explicitly:
|
|
252
|
-
"@acme/ui": {
|
|
253
|
-
enabled: true,
|
|
254
|
-
forceExportFiles: false,
|
|
255
|
-
customExports: {
|
|
256
|
-
"./tokens.css": "./dist/tokens.css",
|
|
257
|
-
},
|
|
258
|
-
},
|
|
269
|
+
"@acme/ui": {
|
|
270
|
+
strip: "./components/",
|
|
271
|
+
exports: { "./css/*": "./src/css/*" },
|
|
272
|
+
source: true, // default: true
|
|
273
|
+
types: true, // default: true
|
|
274
|
+
import: true, // default: true
|
|
275
|
+
css: true,
|
|
259
276
|
},
|
|
277
|
+
"@acme/internal": false,
|
|
278
|
+
"@acme/docs": false,
|
|
260
279
|
},
|
|
261
280
|
|
|
281
|
+
// ─── tag ───────────────────────────────────────────────────────────────────
|
|
262
282
|
tag: {
|
|
263
283
|
skipPackages: ["@acme/internal"],
|
|
264
284
|
onAfterWrite: ({ files }) => {
|
|
@@ -266,6 +286,7 @@ export default {
|
|
|
266
286
|
},
|
|
267
287
|
},
|
|
268
288
|
|
|
289
|
+
// ─── arrange ───────────────────────────────────────────────────────────────
|
|
269
290
|
arrange: {
|
|
270
291
|
onAfterWrite: ({ files }) => {
|
|
271
292
|
execSync(`oxfmt ${files.join(" ")}`, { stdio: "inherit" });
|
|
@@ -274,31 +295,177 @@ export default {
|
|
|
274
295
|
};
|
|
275
296
|
```
|
|
276
297
|
|
|
277
|
-
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
### `mirror` configuration
|
|
301
|
+
|
|
302
|
+
`mirror` is a record keyed by **package name** (the `name` field in the package's `package.json`, e.g. `"@acme/ui"`).
|
|
303
|
+
|
|
304
|
+
#### Skipping a package
|
|
305
|
+
|
|
306
|
+
Set a package to `false` to exclude it from `codefast mirror` entirely:
|
|
307
|
+
|
|
308
|
+
```javascript
|
|
309
|
+
mirror: {
|
|
310
|
+
"@acme/internal": false,
|
|
311
|
+
"@acme/docs": false,
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Packages not mentioned in the config are processed with default settings.
|
|
316
|
+
|
|
317
|
+
#### Per-package options
|
|
318
|
+
|
|
319
|
+
Each package entry is an object with the following fields:
|
|
320
|
+
|
|
321
|
+
| Field | Type | Default | Description |
|
|
322
|
+
| ---------- | ------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
323
|
+
| `source` | `boolean \| string` | `true` | Add a `source` condition to each export entry pointing to the original `.ts` file. `true` auto-derives the path (`./src/<module>.ts`). Pass a string to set the root-export path explicitly (`"./src/index.tsx"`). Set to `false` to omit. |
|
|
324
|
+
| `types` | `boolean` | `true` | Include the `types` condition when a `.d.ts` file is present. Set to `false` to omit. |
|
|
325
|
+
| `import` | `boolean` | `true` | Include the `import` condition. Set to `false` to omit (useful for CJS-only packages). |
|
|
326
|
+
| `strip` | `string` | — | Strip a leading path segment from generated export specifiers. See below. |
|
|
327
|
+
| `exports` | `Record<string, string>` | — | Add or override specific export specifiers. See below. |
|
|
328
|
+
| `preserve` | `boolean` | — | Keep the existing `package.json#exports` and only fill in missing conditions. |
|
|
329
|
+
| `css` | `boolean \| CssConfig` | — | Enable CSS export detection. See below. |
|
|
330
|
+
|
|
331
|
+
#### `strip`
|
|
332
|
+
|
|
333
|
+
Removes a fixed prefix from every generated export specifier. Use this when a package's `dist/` mirrors deep directory structure that you want to flatten in the public API.
|
|
334
|
+
|
|
335
|
+
```javascript
|
|
336
|
+
// Without strip, dist/components/button.mjs → "./components/button"
|
|
337
|
+
// With strip: "./components/", it becomes → "./button"
|
|
338
|
+
"@acme/ui": {
|
|
339
|
+
strip: "./components/",
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
The original file path is preserved for sorting — only the public specifier changes.
|
|
344
|
+
|
|
345
|
+
#### `exports`
|
|
346
|
+
|
|
347
|
+
Adds or overrides specific specifiers in the final export map. Keys and values are the exact strings written into `package.json#exports`.
|
|
348
|
+
|
|
349
|
+
```javascript
|
|
350
|
+
"@acme/ui": {
|
|
351
|
+
exports: {
|
|
352
|
+
"./css/*": "./src/css/*", // wildcard passthrough to sources
|
|
353
|
+
"./tokens": "./dist/tokens.js", // explicit extra entry
|
|
354
|
+
},
|
|
355
|
+
}
|
|
356
|
+
```
|
|
278
357
|
|
|
279
|
-
|
|
280
|
-
- `cssExports[pkg]` accepts a boolean shorthand or the full `{ enabled, customExports, forceExportFiles }` object.
|
|
281
|
-
- `tag.skipPackages` lists package names to skip entirely when `codefast tag` is run without an explicit target.
|
|
358
|
+
Extra entries are merged after auto-generation. They win over anything the scanner would produce for the same specifier. `./package.json` cannot be overridden.
|
|
282
359
|
|
|
283
|
-
|
|
360
|
+
#### `preserve`
|
|
361
|
+
|
|
362
|
+
Keeps the existing `package.json#exports` map exactly as-is and only fills in missing conditions (`source`, `types`, `import`) for each entry — no `dist/` scan is performed. Use this when you maintain the exports map by hand and only want the CLI to supplement missing conditions.
|
|
363
|
+
|
|
364
|
+
```javascript
|
|
365
|
+
"@acme/tailwind-variants": {
|
|
366
|
+
preserve: true,
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
#### `css`
|
|
371
|
+
|
|
372
|
+
Controls CSS file export generation. `mirror` scans `dist/` for `.css` files and writes wildcard or per-file export entries.
|
|
373
|
+
|
|
374
|
+
```javascript
|
|
375
|
+
// Shorthand: auto-detect all CSS files in dist/
|
|
376
|
+
"@acme/theme": { css: true }
|
|
377
|
+
|
|
378
|
+
// Full config:
|
|
379
|
+
"@acme/ui": {
|
|
380
|
+
css: {
|
|
381
|
+
enabled: true,
|
|
382
|
+
// Force individual file entries instead of directory wildcards:
|
|
383
|
+
forceExportFiles: false,
|
|
384
|
+
// Manually add or override individual CSS specifiers:
|
|
385
|
+
customExports: {
|
|
386
|
+
"./tokens.css": "./dist/tokens.css",
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Explicitly disable CSS exports for this package:
|
|
392
|
+
"@acme/legacy": { css: false }
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
When `css` is omitted, CSS files found in `dist/` are still exported by default.
|
|
396
|
+
|
|
397
|
+
#### What `mirror` writes
|
|
398
|
+
|
|
399
|
+
For a package with `dist/button.mjs`, `dist/button.d.ts`, and `source: true`, the generated export entry looks like:
|
|
400
|
+
|
|
401
|
+
```json
|
|
402
|
+
{
|
|
403
|
+
"./button": {
|
|
404
|
+
"source": "./src/button.ts",
|
|
405
|
+
"types": "./dist/button.d.ts",
|
|
406
|
+
"import": "./dist/button.mjs"
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
It also updates the top-level `main`, `module`, and `types` fields from the root (`.`) export, and ensures `"dist"` is listed in `files`.
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
### `tag` configuration
|
|
416
|
+
|
|
417
|
+
```javascript
|
|
418
|
+
tag: {
|
|
419
|
+
// Package names to skip when running without an explicit target
|
|
420
|
+
skipPackages: ["@acme/internal", "@acme/docs"],
|
|
421
|
+
|
|
422
|
+
// Called after files are written — use it to format or lint-fix
|
|
423
|
+
onAfterWrite: ({ files }) => {
|
|
424
|
+
execSync(`prettier --write ${files.join(" ")}`, { stdio: "inherit" });
|
|
425
|
+
},
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
| Field | Type | Description |
|
|
430
|
+
| -------------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
431
|
+
| `skipPackages` | `string[]` | Package names to skip when `codefast tag` is run without an explicit target. Has no effect when a target path is provided directly. |
|
|
432
|
+
| `onAfterWrite` | `(ctx: { files: string[] }) => void \| Promise<void>` | Lifecycle hook — runs after files are written. |
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
### `arrange` configuration
|
|
437
|
+
|
|
438
|
+
```javascript
|
|
439
|
+
arrange: {
|
|
440
|
+
// Called after files are written by `codefast arrange`
|
|
441
|
+
onAfterWrite: ({ files }) => {
|
|
442
|
+
execSync(`oxfmt ${files.join(" ")}`, { stdio: "inherit" });
|
|
443
|
+
},
|
|
444
|
+
}
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
| Field | Type | Description |
|
|
448
|
+
| -------------- | ----------------------------------------------------- | -------------------------------------------------------------------------------- |
|
|
449
|
+
| `onAfterWrite` | `(ctx: { files: string[] }) => void \| Promise<void>` | Lifecycle hook — runs after `arrange` writes files. Not called with `--dry-run`. |
|
|
284
450
|
|
|
285
451
|
---
|
|
286
452
|
|
|
287
453
|
## Lifecycle hooks
|
|
288
454
|
|
|
289
|
-
Both `tag` and `arrange
|
|
455
|
+
Both `tag` and `arrange` call `onAfterWrite` immediately after writing files to disk. The hook receives the list of written file paths and can run any synchronous or asynchronous work — formatters, linters, codegen, notifications.
|
|
290
456
|
|
|
291
457
|
```javascript
|
|
292
458
|
export default {
|
|
293
459
|
tag: {
|
|
294
460
|
onAfterWrite: async ({ files }) => {
|
|
295
|
-
|
|
296
|
-
|
|
461
|
+
// async is supported
|
|
462
|
+
await runFormatter(files);
|
|
297
463
|
},
|
|
298
464
|
},
|
|
299
465
|
arrange: {
|
|
300
466
|
onAfterWrite: ({ files }) => {
|
|
301
|
-
|
|
467
|
+
// sync is fine too
|
|
468
|
+
execSync(`oxfmt ${files.join(" ")}`, { stdio: "inherit" });
|
|
302
469
|
},
|
|
303
470
|
},
|
|
304
471
|
};
|
|
@@ -306,10 +473,11 @@ export default {
|
|
|
306
473
|
|
|
307
474
|
Contract:
|
|
308
475
|
|
|
309
|
-
- `tag.onAfterWrite
|
|
310
|
-
- `arrange.onAfterWrite
|
|
311
|
-
-
|
|
312
|
-
-
|
|
476
|
+
- `tag.onAfterWrite` fires after `codefast tag` writes JSDoc annotations.
|
|
477
|
+
- `arrange.onAfterWrite` fires after `codefast arrange` rewrites class strings.
|
|
478
|
+
- Hook is **not** called on `--dry-run`.
|
|
479
|
+
- Hooks may be synchronous or `async` (`void | Promise<void>`).
|
|
480
|
+
- If the hook throws or rejects, the command reports the error on stderr and exits with code `1`.
|
|
313
481
|
|
|
314
482
|
---
|
|
315
483
|
|
|
@@ -348,14 +516,14 @@ To change placement, extend `classifyBareUtility` in `packages/cli/src/arrange/d
|
|
|
348
516
|
**`codefast: command not found`**
|
|
349
517
|
Install globally with `pnpm add -g @codefast/cli`, or run via `pnpm dlx @codefast/cli <command>`.
|
|
350
518
|
|
|
351
|
-
**`mirror
|
|
352
|
-
Packages must be built first. Ensure `dist/` exists by running your build step, then re-run `codefast mirror
|
|
519
|
+
**`mirror` writes little or no output**
|
|
520
|
+
Packages must be built first. Ensure `dist/` exists by running your build step, then re-run `codefast mirror`.
|
|
353
521
|
|
|
354
|
-
**Unexpected class reorder after `arrange
|
|
355
|
-
Run `arrange
|
|
522
|
+
**Unexpected class reorder after `arrange`**
|
|
523
|
+
Run `arrange --dry-run` first and smoke-test the UI. Some components rely on cascade-sensitive ordering that `arrange` cannot detect automatically.
|
|
356
524
|
|
|
357
525
|
**`--json` output mixed with progress lines**
|
|
358
|
-
Some shells buffer progress writes on stderr into stdout when piping — redirect stderr explicitly: `codefast mirror
|
|
526
|
+
Some shells buffer progress writes on stderr into stdout when piping — redirect stderr explicitly: `codefast mirror --json 2>/dev/null | jq`.
|
|
359
527
|
|
|
360
528
|
---
|
|
361
529
|
|
|
@@ -377,7 +545,7 @@ A few naming conventions:
|
|
|
377
545
|
|
|
378
546
|
- **`codefast <command>`** refers to CLI commands exposed via the `bin` entry in `@codefast/cli`.
|
|
379
547
|
- **Scripts in `packages/cli/package.json`** (`build`, `test`, …) are package-local dev scripts, not CLI commands.
|
|
380
|
-
- The root `package.json` includes optional convenience wrappers (e.g. `cli:mirror
|
|
548
|
+
- The root `package.json` includes optional convenience wrappers (e.g. `cli:mirror`, `cli:arrange-inspect`) for common dev workflows.
|
|
381
549
|
|
|
382
550
|
---
|
|
383
551
|
|
package/dist/arrange/analyze.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { AppError, messageFrom } from "../core/errors.mjs";
|
|
2
|
-
import { err, ok } from "../core/result.mjs";
|
|
3
1
|
import { accumulateAnalyzeReportForSourceFile, createEmptyAnalyzeReport } from "./domain/analyze-service.mjs";
|
|
2
|
+
import { AppError, messageFrom } from "../core/errors.mjs";
|
|
4
3
|
import { scanArrangeTargets } from "./scan-target.mjs";
|
|
5
4
|
import { parseDomainSourceFile } from "./source-parse.mjs";
|
|
5
|
+
import { err, ok } from "../core/result.mjs";
|
|
6
6
|
//#region src/arrange/analyze.ts
|
|
7
7
|
/**
|
|
8
8
|
* @since 0.3.16-canary.0
|
package/dist/arrange/command.mjs
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { parseWithSchema } from "../core/schema-parse.mjs";
|
|
2
|
-
import "../core/exit-codes.mjs";
|
|
3
1
|
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
2
|
import { analyzeDirectory } from "./analyze.mjs";
|
|
9
|
-
import {
|
|
3
|
+
import { arrangeAnalyzeDirectoryRequestSchema, arrangeSuggestGroupsRequestSchema, arrangeSyncRunRequestSchema } from "./cli-schema.mjs";
|
|
4
|
+
import { printAnalyzeReport, printGroupFilePreviewFromWork, printSimplifyResult, printSyncResult } from "./output.mjs";
|
|
5
|
+
import { runArrangeSimplify } from "./simplify-sync.mjs";
|
|
10
6
|
import { suggestCnGroupsFromCli } from "./suggest.mjs";
|
|
11
|
-
import {
|
|
7
|
+
import { runArrangeSync } from "./sync.mjs";
|
|
8
|
+
import { prepareArrangeWorkspace } from "./workspace.mjs";
|
|
12
9
|
import { readOptionalPositionalArg } from "../core/cli/positional.mjs";
|
|
10
|
+
import "../core/exit-codes.mjs";
|
|
11
|
+
import { consumeCliAppError, runCliResultAsync } from "../core/cli/result-handle.mjs";
|
|
12
|
+
import { nodeFilesystem } from "../core/filesystem/node.mjs";
|
|
13
|
+
import { parseWithSchema } from "../core/schema-parse.mjs";
|
|
13
14
|
import process from "node:process";
|
|
14
15
|
import { Command } from "commander";
|
|
15
16
|
//#region src/arrange/command.ts
|
|
@@ -17,22 +18,8 @@ import { Command } from "commander";
|
|
|
17
18
|
* @since 0.3.16-canary.0
|
|
18
19
|
*/
|
|
19
20
|
function createArrangeCommand() {
|
|
20
|
-
const cmd = new Command("arrange").description("
|
|
21
|
-
|
|
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) => {
|
|
21
|
+
const cmd = new Command("arrange").description("Regroup Tailwind classes in cn() / tv() calls in render-pipeline order").enablePositionalOptions().argument("[target]", "Directory or file (default: nearest package directory from cwd)").option("--dry-run", "Preview suggested replacements without writing files", false).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(async (target, opts) => {
|
|
22
|
+
const write = !opts.dryRun;
|
|
36
23
|
const prelude = await prepareArrangeWorkspace(nodeFilesystem, {
|
|
37
24
|
currentWorkingDirectory: process.cwd(),
|
|
38
25
|
rawTarget: readOptionalPositionalArg(target)
|
|
@@ -57,9 +44,46 @@ function createArrangeCommand() {
|
|
|
57
44
|
printSyncResult(value, write);
|
|
58
45
|
return exitCodeForArrangeSyncResult(value);
|
|
59
46
|
});
|
|
60
|
-
};
|
|
61
|
-
cmd.command("
|
|
62
|
-
|
|
47
|
+
});
|
|
48
|
+
cmd.command("inspect").description("Report long strings, nested cn in tv(), and related findings (read-only)").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) => {
|
|
49
|
+
const prelude = await prepareArrangeWorkspace(nodeFilesystem, {
|
|
50
|
+
currentWorkingDirectory: process.cwd(),
|
|
51
|
+
rawTarget: readOptionalPositionalArg(target)
|
|
52
|
+
});
|
|
53
|
+
if (!consumeCliAppError(prelude)) return;
|
|
54
|
+
const { resolvedTarget } = prelude.value;
|
|
55
|
+
const parsed = parseWithSchema(arrangeAnalyzeDirectoryRequestSchema, { analyzeRootPath: resolvedTarget });
|
|
56
|
+
if (!consumeCliAppError(parsed)) return;
|
|
57
|
+
const outcome = analyzeDirectory(nodeFilesystem, parsed.value.analyzeRootPath);
|
|
58
|
+
if (!consumeCliAppError(outcome)) return;
|
|
59
|
+
if (opts.json) logger.out(formatArrangeAnalyzeJsonOutput(resolvedTarget, outcome.value));
|
|
60
|
+
else printAnalyzeReport(resolvedTarget, outcome.value);
|
|
61
|
+
});
|
|
62
|
+
cmd.command("simplify").description("Flatten grouped arrays and static-only cn() calls back to plain strings in tv() slots").argument("[target]", "Directory or file (default: nearest package directory from cwd)").option("--dry-run", "Show what simplify would change without writing files", false).option("--json", "Print one JSON object on stdout (suppresses human progress)", false).action(async (target, opts) => {
|
|
63
|
+
const write = !opts.dryRun;
|
|
64
|
+
const prelude = await prepareArrangeWorkspace(nodeFilesystem, {
|
|
65
|
+
currentWorkingDirectory: process.cwd(),
|
|
66
|
+
rawTarget: readOptionalPositionalArg(target)
|
|
67
|
+
});
|
|
68
|
+
if (!consumeCliAppError(prelude)) return;
|
|
69
|
+
const { resolvedTarget } = prelude.value;
|
|
70
|
+
await runCliResultAsync(runArrangeSimplify(nodeFilesystem, {
|
|
71
|
+
targetPath: resolvedTarget,
|
|
72
|
+
write
|
|
73
|
+
}), (value) => {
|
|
74
|
+
if (opts.json) {
|
|
75
|
+
logger.out(JSON.stringify({
|
|
76
|
+
schemaVersion: 1,
|
|
77
|
+
ok: true,
|
|
78
|
+
write,
|
|
79
|
+
result: value
|
|
80
|
+
}));
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
printSimplifyResult(value, write);
|
|
84
|
+
return 0;
|
|
85
|
+
});
|
|
86
|
+
});
|
|
63
87
|
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
88
|
const parsed = parseWithSchema(arrangeSuggestGroupsRequestSchema, {
|
|
65
89
|
inlineClasses: classTokenSeries.join(" ").trim(),
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import "./constants.mjs";
|
|
2
|
-
import { tokenizeClassString } from "./tailwind-token.mjs";
|
|
3
1
|
import { forEachDomainChild, isDomainCallExpression, isDomainJsxAttribute, isDomainObjectLiteralExpression } from "./ast/ast-node.mjs";
|
|
2
|
+
import "./constants.mjs";
|
|
4
3
|
import { forEachStringLiteralInClassExpression } from "./ast/collectors-cn.mjs";
|
|
5
4
|
import { jsxClassNameStaticLiteral } from "./ast/collectors-jsx.mjs";
|
|
6
5
|
import { buildKnownCnTvBindings, isCnOrTvIdentifier, lineOf } from "./ast/helpers.mjs";
|
|
6
|
+
import { tokenizeClassString } from "./tailwind-token.mjs";
|
|
7
7
|
import { collectCnCallsInsideTv, traverseTvObject } from "./ast/collectors-tv.mjs";
|
|
8
8
|
//#region src/arrange/domain/analyze-service.ts
|
|
9
9
|
/**
|