tailwindcss-patch 8.6.0 → 8.7.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.
package/README.md CHANGED
@@ -40,6 +40,15 @@ pnpm dlx tw-patch tokens --format lines
40
40
 
41
41
  # Check which patches are applied
42
42
  pnpm dlx tw-patch status --json
43
+
44
+ # Migrate deprecated config fields to modern keys
45
+ pnpm dlx tw-patch migrate --dry-run
46
+
47
+ # Restore configs from a migration report backup snapshot
48
+ pnpm dlx tw-patch restore --report-file .tw-patch/migrate-report.json --dry-run
49
+
50
+ # Validate migration report compatibility without modifying files
51
+ pnpm dlx tw-patch validate --report-file .tw-patch/migrate-report.json --json
43
52
  ```
44
53
 
45
54
  ### Embed into another CLI
@@ -108,6 +117,128 @@ Skip `next()` to fully replace a command (e.g. custom `init` or cache clearing b
108
117
 
109
118
  The CLI loads `tailwindcss-patch.config.ts` via `@tailwindcss-mangle/config`. Legacy configs continue to work; see the [migration guide](./MIGRATION.md) for hints on the new fields.
110
119
 
120
+ ### Migrate options
121
+
122
+ | Flag | Description |
123
+ | ---------------- | ---------------------------------------------------------------------------- |
124
+ | `--cwd <dir>` | Working directory used to locate config files. |
125
+ | `--config <file>`| Migrate only one specific config file path. |
126
+ | `--workspace` | Recursively scan the workspace for supported config filenames. |
127
+ | `--max-depth <n>`| Maximum recursion depth for `--workspace` mode (default: `6`). |
128
+ | `--include <glob>` | Only migrate files matching this glob pattern (repeatable). |
129
+ | `--exclude <glob>` | Skip files matching this glob pattern (repeatable). |
130
+ | `--report-file <file>` | Write the migration report JSON to this file. |
131
+ | `--backup-dir <dir>` | Store pre-migration file backups in this directory. |
132
+ | `--check` | Check mode for CI. Exits with an error if files still need migration. |
133
+ | `--json` | Print the migration report as JSON. |
134
+ | `--dry-run` | Preview planned changes without writing files. |
135
+
136
+ `tw-patch migrate` scans `tailwindcss-patch.config.*` and `tailwindcss-mangle.config.*` in the target directory. With `--workspace`, it recursively scans sub-projects (excluding folders like `node_modules`, `.git`, and `dist`). Use `--include` / `--exclude` to control monorepo scanning ranges. It rewrites deprecated keys (for example `registry.output` -> `registry.extract`, `registry.tailwind` -> `registry.tailwindcss`) and prints a per-file change summary.
137
+
138
+ When writing files, migration uses a transactional strategy by default: if a later file write fails, already written migration files are rolled back to avoid partial updates. Use `--backup-dir` if you want explicit backup snapshots for audit/manual recovery. Use `--report-file` to keep a machine-readable migration artifact.
139
+
140
+ Migration reports now include envelope metadata: `reportKind`, `schemaVersion`, `generatedAt`, and `tool` (`name` / `version`). This metadata helps restore tooling validate report compatibility.
141
+
142
+ ### Restore options
143
+
144
+ | Flag | Description |
145
+ | --------------------- | ----------------------------------------------------------------- |
146
+ | `--cwd <dir>` | Working directory used to resolve report and target paths. |
147
+ | `--report-file <file>`| Migration report file path (defaults to `.tw-patch/migrate-report.json`). |
148
+ | `--dry-run` | Preview restore targets without writing files. |
149
+ | `--strict` | Fail when any backup file in the report is missing. |
150
+ | `--json` | Print restore summary as JSON. |
151
+
152
+ `tw-patch restore` validates report schema metadata when available. Reports with unsupported `reportKind` or newer `schemaVersion` are rejected to avoid unsafe restores. Legacy reports without metadata are still supported.
153
+ With `--json`, restore output includes `reportKind` / `reportSchemaVersion` when report metadata is present.
154
+
155
+ ### Validate options
156
+
157
+ | Flag | Description |
158
+ | --------------------- | ----------------------------------------------------------------- |
159
+ | `--cwd <dir>` | Working directory used to resolve report paths. |
160
+ | `--report-file <file>`| Migration report file path (defaults to `.tw-patch/migrate-report.json`). |
161
+ | `--strict` | Fail when any backup file in the report is missing. |
162
+ | `--json` | Print validation result as JSON. |
163
+
164
+ `tw-patch validate` performs migration report compatibility checks without writing restored files. It runs report schema validation and scans backup references in dry-run mode.
165
+ On failure, validate uses dedicated exit codes for CI:
166
+ `21` report incompatibility, `22` strict missing backups, `23` I/O errors, `24` unknown errors.
167
+ With `--json`, validate emits a stable payload:
168
+ success => `{ ok: true, ...restoreFields }`, failure => `{ ok: false, reason, exitCode, message }`.
169
+
170
+ Schemas are published at package subpaths:
171
+ `tailwindcss-patch/migration-report.schema.json`,
172
+ `tailwindcss-patch/restore-result.schema.json`,
173
+ `tailwindcss-patch/validate-result.schema.json`.
174
+ Programmatic consumers can also import report helpers/types from package entry:
175
+ `migrateConfigFiles`, `restoreConfigFiles`, `MIGRATION_REPORT_KIND`, `MIGRATION_REPORT_SCHEMA_VERSION`, `ConfigFileMigrationReport`, `VALIDATE_EXIT_CODES`.
176
+
177
+ ### CI recipe
178
+
179
+ ```bash
180
+ # 1) fail fast when workspace configs still need migration
181
+ pnpm dlx tw-patch migrate --workspace --check --report-file .tw-patch/migrate-report.json
182
+
183
+ # 2) validate report schema/backup references and keep machine-readable output
184
+ set +e
185
+ pnpm dlx tw-patch validate --report-file .tw-patch/migrate-report.json --strict --json > .tw-patch/validate-result.json
186
+ status=$?
187
+ set -e
188
+
189
+ case "$status" in
190
+ 0) echo "validate ok" ;;
191
+ 21) echo "report schema/kind incompatible"; exit 1 ;;
192
+ 22) echo "missing backups under --strict"; exit 1 ;;
193
+ 23) echo "I/O failure while reading report/backups"; exit 1 ;;
194
+ *) echo "unknown validate failure"; exit "$status" ;;
195
+ esac
196
+ ```
197
+
198
+ GitHub Actions templates:
199
+ - single job: `packages/tailwindcss-patch/examples/github-actions/validate-migration-report.yml`
200
+ - monorepo matrix shards (`root/apps/packages`): `packages/tailwindcss-patch/examples/github-actions/validate-migration-report-matrix.yml`
201
+ - monorepo affected shards (PR diff-aware): `packages/tailwindcss-patch/examples/github-actions/validate-migration-report-affected.yml`
202
+ - shared composite action (used by all templates): `packages/tailwindcss-patch/examples/github-actions/actions/validate-migration-report/action.yml`
203
+ - affected-shard resolver script: `packages/tailwindcss-patch/examples/github-actions/scripts/resolve-shards.mjs`
204
+ - resolver JSON contract schema: `packages/tailwindcss-patch/examples/github-actions/resolve-shards-result.schema.json`
205
+ - resolver dispatch snapshot fixture: `packages/tailwindcss-patch/examples/github-actions/resolve-shards-result.dispatch.snapshot.json`
206
+
207
+ For the affected-shards template, you can customize shard matching and run-all triggers by adding `.tw-patch/ci-shards.json` in your repo.
208
+ A sample config is available at `packages/tailwindcss-patch/examples/github-actions/ci-shards.example.json`.
209
+
210
+ The shared composite action now supports optional environment bootstrap inputs:
211
+ `setup-pnpm`, `setup-node`, `node-version`, `cache-dependency-path`, `install-deps`, and `install-command`.
212
+ This lets you choose between action-managed setup or workflow-managed setup depending on your CI strategy.
213
+
214
+ ### CI copy checklist
215
+
216
+ 1. Pick one workflow template based on your repository shape:
217
+ `validate-migration-report.yml` (single job), `validate-migration-report-matrix.yml` (fixed shards), or `validate-migration-report-affected.yml` (PR diff-aware shards).
218
+ 2. Always copy the shared composite action:
219
+ `packages/tailwindcss-patch/examples/github-actions/actions/validate-migration-report/action.yml`.
220
+ 3. If you use the affected-shards template, also copy:
221
+ `packages/tailwindcss-patch/examples/github-actions/scripts/resolve-shards.mjs`,
222
+ `packages/tailwindcss-patch/examples/github-actions/resolve-shards-result.schema.json`,
223
+ `packages/tailwindcss-patch/examples/github-actions/resolve-shards-result.dispatch.snapshot.json`.
224
+ 4. If your workspace paths differ from defaults, add `.tw-patch/ci-shards.json` (based on `ci-shards.example.json`) and adjust shard patterns/report files.
225
+ 5. Confirm the composite action inputs match your runner setup:
226
+ action-managed setup (`setup-pnpm/setup-node/install-deps`) or pre-provisioned setup (`false` + custom install command).
227
+ 6. Keep `permissions.contents: read` and ensure `pnpm-lock.yaml` path matches `cache-dependency-path`.
228
+
229
+ ### CI troubleshooting
230
+
231
+ - `uses: ./.../validate-migration-report` not found:
232
+ the workflow references a local action path; copy the action directory with the workflow file.
233
+ - `No affected shards for migration report validation.` in PR:
234
+ either files are outside configured shard patterns or base diff resolution returned empty; verify `.tw-patch/ci-shards.json` and PR base branch.
235
+ - `Unknown scope` in composite action:
236
+ `scope` currently accepts only `all`, `root`, `apps`, `packages` unless you customize action logic.
237
+ - `validate` exits `21/22/23`:
238
+ `21` incompatible report schema/kind, `22` missing backups under `--strict`, `23` report/backup I/O failure.
239
+ - Resolver snapshot diff failure in `workflow-lint`:
240
+ you changed resolver contract behavior; update both schema/snapshot fixtures and corresponding tests in one commit.
241
+
111
242
  ### Token report options
112
243
 
113
244
  | Flag | Description |
@@ -124,24 +255,26 @@ The CLI loads `tailwindcss-patch.config.ts` via `@tailwindcss-mangle/config`. Le
124
255
  import { TailwindcssPatcher } from 'tailwindcss-patch'
125
256
 
126
257
  const patcher = new TailwindcssPatcher({
127
- overwrite: true,
258
+ projectRoot: process.cwd(),
128
259
  cache: {
129
260
  enabled: true,
130
261
  dir: '.tw-patch/cache',
131
262
  strategy: 'merge',
132
263
  driver: 'file',
133
264
  },
134
- output: {
265
+ extract: {
266
+ write: true,
135
267
  file: '.tw-patch/tw-class-list.json',
136
268
  format: 'json',
137
269
  },
138
- features: {
270
+ apply: {
271
+ overwrite: true,
139
272
  exposeContext: { refProperty: 'runtimeContexts' },
140
273
  extendLengthUnits: {
141
274
  units: ['rpx'],
142
275
  },
143
276
  },
144
- tailwind: {
277
+ tailwindcss: {
145
278
  version: 4,
146
279
  v4: {
147
280
  base: './src',
@@ -162,10 +295,57 @@ const patchStatus = await patcher.getPatchStatus()
162
295
  console.log(patchStatus.entries)
163
296
  ```
164
297
 
165
- The constructor accepts either the new object shown above or the historical `patch`/`cache` shape. Conversions happen internally so existing configs remain backwards compatible.
298
+ The constructor accepts either the new object shown above or historical shapes. Conversions happen internally so existing configs remain backwards compatible.
299
+
300
+ Deprecated fields kept temporarily (to be removed in the next major): `cwd`, `overwrite`, `tailwind`, `features`, `output`.
301
+
302
+ Migration mapping:
303
+ - `cwd` -> `projectRoot`
304
+ - `overwrite` -> `apply.overwrite`
305
+ - `tailwind` -> `tailwindcss`
306
+ - `features` -> `apply`
307
+ - `output` -> `extract`
308
+
309
+ When deprecated fields are detected at runtime, `normalizeOptions` logs a one-time warning to help migration.
166
310
 
167
311
  Use cache.driver to switch between the default file-backed cache, an in-memory cache (memory), or a no-op cache (noop) when filesystem permissions are restricted.
168
312
 
313
+ ### Cache governance (schema v2)
314
+
315
+ `tailwindcss-patch` now isolates cache entries by **context fingerprint** to prevent cross-project pollution in monorepos.
316
+
317
+ - Cache file format uses an indexed schema (`schemaVersion: 2`) with per-context entries.
318
+ - A cache hit requires both fingerprint and metadata consistency.
319
+ - Legacy array caches are read safely and treated as misses, then lazily rebuilt on write.
320
+ - Writes are protected by lock file + atomic temp-file rename to avoid concurrent corruption.
321
+
322
+ Fingerprint components:
323
+
324
+ - realpath-normalized `process.cwd()`
325
+ - realpath-normalized project root / cache cwd
326
+ - Tailwind config absolute path (if found) + config mtime
327
+ - Tailwind package root + version
328
+ - `tailwindcss-patch` package version
329
+ - deterministic hash of key patch options (stable key ordering)
330
+
331
+ The fingerprint is computed once in the patcher constructor and reused during all cache operations.
332
+
333
+ ### Clearing cache explicitly
334
+
335
+ ```ts
336
+ // default: clear current context only
337
+ const current = await patcher.clearCache()
338
+ // => { scope: 'current', filesRemoved, entriesRemoved, contextsRemoved }
339
+
340
+ // clear all contexts from the cache index
341
+ const all = await patcher.clearCache({ scope: 'all' })
342
+ ```
343
+
344
+ Debug observability:
345
+
346
+ - cache hit logs include fingerprint + schema
347
+ - cache miss logs include miss reason and mismatch details (config/version/path/options)
348
+
169
349
  ### Helper utilities
170
350
 
171
351
  - `normalizeOptions` – normalise raw user input to the runtime shape.
@@ -184,9 +364,10 @@ All helpers are exported from the package root for direct consumption in custom
184
364
  import { defineConfig } from 'tailwindcss-patch'
185
365
 
186
366
  export default defineConfig({
187
- patch: {
188
- output: {
189
- filename: '.tw-patch/tw-class-list.json',
367
+ registry: {
368
+ projectRoot: '.',
369
+ extract: {
370
+ file: '.tw-patch/tw-class-list.json',
190
371
  removeUniversalSelector: true,
191
372
  format: 'json',
192
373
  },
@@ -197,8 +378,9 @@ export default defineConfig({
197
378
  sources: [{ base: 'src', pattern: '**/*.{html,tsx}', negated: false }],
198
379
  },
199
380
  },
200
- applyPatches: {
201
- exportContext: true,
381
+ apply: {
382
+ overwrite: true,
383
+ exposeContext: true,
202
384
  extendLengthUnits: {
203
385
  units: ['rpx'],
204
386
  },
@@ -207,7 +389,7 @@ export default defineConfig({
207
389
  })
208
390
  ```
209
391
 
210
- Even though `defineConfig` still exposes the historical shape, every new option is supported and will be normalised automatically.
392
+ `defineConfig` supports both modern `registry` fields (`projectRoot`, `tailwindcss`, `apply`, `extract`) and historical keys. The patcher normalizer handles both and always prefers modern fields when both are present.
211
393
 
212
394
  ## Migration
213
395