tw-migrate 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +121 -0
- package/bin/tw-migrate.js +46 -0
- package/html.js +153 -0
- package/index.d.ts +46 -0
- package/index.js +1254 -0
- package/native.js +34 -0
- package/package.json +90 -0
- package/rfcs/batch-css-migration.md +297 -0
- package/rfcs/browser-ecosystem-e2e.md +338 -0
- package/rfcs/css-to-tailwind-migration-cli.md +521 -0
- package/rfcs/preprocessor-and-html-migration.md +497 -0
- package/style-compiler.js +125 -0
package/native.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
|
|
3
|
+
const require = createRequire(import.meta.url);
|
|
4
|
+
const targets = {
|
|
5
|
+
'darwin-arm64': 'darwin-arm64',
|
|
6
|
+
'darwin-x64': 'darwin-x64',
|
|
7
|
+
'linux-arm64': 'linux-arm64-gnu',
|
|
8
|
+
'linux-x64': 'linux-x64-gnu',
|
|
9
|
+
'win32-x64': 'win32-x64-msvc',
|
|
10
|
+
};
|
|
11
|
+
const target = targets[`${process.platform}-${process.arch}`];
|
|
12
|
+
|
|
13
|
+
if (!target) throw new Error(`Unsupported platform: ${process.platform}-${process.arch}`);
|
|
14
|
+
|
|
15
|
+
let binding;
|
|
16
|
+
for (const load of [
|
|
17
|
+
() => require(`./tw-migrate.${target}.node`),
|
|
18
|
+
() => require(`tw-migrate-${target}`),
|
|
19
|
+
]) {
|
|
20
|
+
try {
|
|
21
|
+
binding = load();
|
|
22
|
+
break;
|
|
23
|
+
} catch (error) {
|
|
24
|
+
if (error.code !== 'MODULE_NOT_FOUND') throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!binding) {
|
|
29
|
+
throw new Error(`No tw-migrate native addon was found for ${target}. Reinstall the package or build it locally.`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const decodeSourceMap = binding.decodeSourceMap;
|
|
33
|
+
export const planBatchMigration = binding.planBatchMigration;
|
|
34
|
+
export const validateCss = binding.validateCss;
|
package/package.json
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tw-migrate",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "Preview and migrate React CSS to Tailwind utilities",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"codemod",
|
|
7
|
+
"css",
|
|
8
|
+
"css-modules",
|
|
9
|
+
"migration",
|
|
10
|
+
"napi-rs",
|
|
11
|
+
"react",
|
|
12
|
+
"tailwind",
|
|
13
|
+
"tailwindcss"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://github.com/jong-kyung/tw-migrate#readme",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/jong-kyung/tw-migrate/issues"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "JongKyung Lee",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/jong-kyung/tw-migrate.git"
|
|
24
|
+
},
|
|
25
|
+
"bin": {
|
|
26
|
+
"tw-migrate": "bin/tw-migrate.js"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"bin",
|
|
30
|
+
"html.js",
|
|
31
|
+
"index.js",
|
|
32
|
+
"index.d.ts",
|
|
33
|
+
"native.js",
|
|
34
|
+
"rfcs",
|
|
35
|
+
"style-compiler.js"
|
|
36
|
+
],
|
|
37
|
+
"type": "module",
|
|
38
|
+
"main": "index.js",
|
|
39
|
+
"types": "index.d.ts",
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "napi build --manifest-path crates/tw_migrate/Cargo.toml --package-json-path package.json --output-dir . --platform --release --no-js --dts binding.d.ts",
|
|
42
|
+
"build:debug": "napi build --manifest-path crates/tw_migrate/Cargo.toml --package-json-path package.json --output-dir . --platform --no-js --dts binding.d.ts",
|
|
43
|
+
"artifacts": "napi artifacts --output-dir . --npm-dir npm",
|
|
44
|
+
"test": "cargo test && pnpm build:debug && node --test",
|
|
45
|
+
"test:ecosystem": "node ecosystem-ci/run.ts",
|
|
46
|
+
"test:rust": "cargo test",
|
|
47
|
+
"typecheck": "tsc --noEmit",
|
|
48
|
+
"snapshots:prepare": "node -e \"const fs=require('node:fs'); for(const dir of fs.readdirSync('npm')) for(const file of fs.readdirSync('npm/'+dir)) if(file.endsWith('.node')) fs.rmSync('npm/'+dir+'/'+file)\" && pnpm build && pnpm artifacts",
|
|
49
|
+
"test:snapshots": "pnpm snapshots:prepare && cargo test -p tw-migrate-snapshots",
|
|
50
|
+
"prepare": "vp config"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"parse5": "7.3.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@napi-rs/cli": "3.7.3",
|
|
57
|
+
"@types/node": "22.20.1",
|
|
58
|
+
"@vitest/browser-playwright": "catalog:",
|
|
59
|
+
"less": "4.7.0",
|
|
60
|
+
"playwright": "1.61.1",
|
|
61
|
+
"sass": "1.101.3",
|
|
62
|
+
"tailwindcss": "4.3.3",
|
|
63
|
+
"typescript": "7.0.2",
|
|
64
|
+
"verdaccio": "6.8.0",
|
|
65
|
+
"vite": "catalog:",
|
|
66
|
+
"vite-plus": "catalog:",
|
|
67
|
+
"vitest": "catalog:"
|
|
68
|
+
},
|
|
69
|
+
"optionalDependencies": {
|
|
70
|
+
"tw-migrate-darwin-arm64": "0.1.0-alpha.0",
|
|
71
|
+
"tw-migrate-darwin-x64": "0.1.0-alpha.0",
|
|
72
|
+
"tw-migrate-linux-arm64-gnu": "0.1.0-alpha.0",
|
|
73
|
+
"tw-migrate-linux-x64-gnu": "0.1.0-alpha.0",
|
|
74
|
+
"tw-migrate-win32-x64-msvc": "0.1.0-alpha.0"
|
|
75
|
+
},
|
|
76
|
+
"napi": {
|
|
77
|
+
"binaryName": "tw-migrate",
|
|
78
|
+
"targets": [
|
|
79
|
+
"aarch64-apple-darwin",
|
|
80
|
+
"x86_64-apple-darwin",
|
|
81
|
+
"aarch64-unknown-linux-gnu",
|
|
82
|
+
"x86_64-unknown-linux-gnu",
|
|
83
|
+
"x86_64-pc-windows-msvc"
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
"engines": {
|
|
87
|
+
"node": ">=22.18.0"
|
|
88
|
+
},
|
|
89
|
+
"packageManager": "pnpm@11.15.1"
|
|
90
|
+
}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
# RFC: Batch CSS Migration
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Accepted
|
|
6
|
+
|
|
7
|
+
## Summary
|
|
8
|
+
|
|
9
|
+
`tw-migrate` currently requires one CSS file per invocation. This RFC extends it so an invocation without a CSS path discovers and migrates every eligible CSS file in the current package. A supplied CSS path continues to scope conversion to that file. Workspace-wide migration is explicit through `--workspaces`.
|
|
10
|
+
|
|
11
|
+
The batch operation reads the project once, builds one deterministic edit plan, validates the complete result, and applies it atomically. Independent per-CSS migrations are not written one after another because they can edit the same JavaScript or Tailwind entry from stale source.
|
|
12
|
+
|
|
13
|
+
## Goals
|
|
14
|
+
|
|
15
|
+
1. Migrate every eligible `.css` file in the current package when no CSS path is supplied.
|
|
16
|
+
2. Preserve single-file migration when a CSS path is supplied.
|
|
17
|
+
3. Find every supported JavaScript/TypeScript reference to each selected stylesheet.
|
|
18
|
+
4. Group migration by the nearest package boundary and that package's Tailwind v4 entry.
|
|
19
|
+
5. Support an explicit `--workspaces` mode for all packages below the workspace root.
|
|
20
|
+
6. Respect `.gitignore` during automatic discovery.
|
|
21
|
+
7. Produce one deterministic preview and one validated write transaction.
|
|
22
|
+
8. Retain only conflicting rules while continuing independent conversions.
|
|
23
|
+
9. Allow `--force` to skip failed package groups without weakening edit, Tailwind, or write validation.
|
|
24
|
+
10. Establish a measurable baseline before adding parallel parsing.
|
|
25
|
+
|
|
26
|
+
## Non-Goals
|
|
27
|
+
|
|
28
|
+
1. SCSS, Sass, and Less parsing or migration in this release.
|
|
29
|
+
2. Emotion or styled-components discovery.
|
|
30
|
+
3. Selecting migration scope from a JavaScript or TypeScript positional path.
|
|
31
|
+
4. Directory, glob, or include/exclude configuration beyond current package and workspace scope.
|
|
32
|
+
5. Guessing ownership across package boundaries when a package has no unique Tailwind entry.
|
|
33
|
+
6. Parallel analysis in the initial implementation.
|
|
34
|
+
7. Automatic deletion of global CSS rules.
|
|
35
|
+
|
|
36
|
+
Preprocessor extensions must not be treated as CSS merely because they are discovered. They will be added only with parsers and source-editing rules that preserve their original syntax.
|
|
37
|
+
|
|
38
|
+
## User Experience
|
|
39
|
+
|
|
40
|
+
### CLI
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Preview every eligible CSS file in the current package.
|
|
44
|
+
tw-migrate
|
|
45
|
+
|
|
46
|
+
# Preview one CSS file while scanning all relevant source references.
|
|
47
|
+
tw-migrate src/components/Button.module.css
|
|
48
|
+
|
|
49
|
+
# Apply the current package migration.
|
|
50
|
+
tw-migrate --write
|
|
51
|
+
|
|
52
|
+
# Apply every discovered workspace package.
|
|
53
|
+
tw-migrate --workspaces --write
|
|
54
|
+
|
|
55
|
+
# Skip recoverably failed package groups and apply successful groups.
|
|
56
|
+
tw-migrate --workspaces --write --force
|
|
57
|
+
|
|
58
|
+
# Resolve a package with an ambiguous Tailwind entry.
|
|
59
|
+
tw-migrate --tailwind-css src/app/globals.css --write
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The command accepts at most one positional CSS file. `--workspaces` cannot be combined with a positional CSS file because the positional path already defines the requested scope.
|
|
63
|
+
|
|
64
|
+
Preview remains the default. `--force` has no effect on unsupported rules that are already represented as warnings; those rules remain unchanged in every mode.
|
|
65
|
+
|
|
66
|
+
### Node.js API
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
interface MigrateOptions {
|
|
70
|
+
cssFile?: string;
|
|
71
|
+
cwd?: string;
|
|
72
|
+
write?: boolean;
|
|
73
|
+
tailwindCss?: string;
|
|
74
|
+
workspaces?: boolean;
|
|
75
|
+
force?: boolean;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`migrate()` with no `cssFile` processes the current package. `workspaces: true` processes all package groups below the workspace root. Supplying both `cssFile` and `workspaces: true` is an error.
|
|
80
|
+
|
|
81
|
+
The existing aggregate report fields remain. Package failures skipped by `force` are returned separately:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
interface MigrationFailure {
|
|
85
|
+
package: string;
|
|
86
|
+
message: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface MigrationReport {
|
|
90
|
+
changedFiles: string[];
|
|
91
|
+
diff: string;
|
|
92
|
+
convertedRules: number;
|
|
93
|
+
retainedRules: number;
|
|
94
|
+
rules: RuleReport[];
|
|
95
|
+
candidates: string[];
|
|
96
|
+
warnings: MigrationWarning[];
|
|
97
|
+
failures: MigrationFailure[];
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Scope Discovery
|
|
102
|
+
|
|
103
|
+
### Package Boundaries
|
|
104
|
+
|
|
105
|
+
The current package is the nearest ancestor containing `package.json`. The workspace root is the Git root when available, otherwise the current package root.
|
|
106
|
+
|
|
107
|
+
In default mode only the current package contributes migration targets. In `--workspaces` mode, package directories below the workspace root are discovered from non-ignored `package.json` files. Every selected CSS file belongs to its nearest package boundary.
|
|
108
|
+
|
|
109
|
+
A package group must resolve exactly one Tailwind v4 CSS entry unless `tailwindCss` explicitly selects one for a single-package invocation. Tailwind entry files are inputs and possible edit destinations, never migration targets.
|
|
110
|
+
|
|
111
|
+
A package with no Tailwind entry or multiple entries fails before planning. In default mode this prevents every write. With `--force`, the package group is skipped.
|
|
112
|
+
|
|
113
|
+
### CSS Targets
|
|
114
|
+
|
|
115
|
+
Automatic discovery selects `.css` files within the requested package groups after excluding:
|
|
116
|
+
|
|
117
|
+
- Tailwind entry files;
|
|
118
|
+
- `.git`, `.next`, `build`, `dist`, and `node_modules`;
|
|
119
|
+
- paths ignored by Git.
|
|
120
|
+
|
|
121
|
+
A positional CSS path overrides ignore rules and selects exactly that file. It must end in `.css` and belong to the current package.
|
|
122
|
+
|
|
123
|
+
### Source References
|
|
124
|
+
|
|
125
|
+
Migration targets and writable sources are scoped separately:
|
|
126
|
+
|
|
127
|
+
- default mode writes CSS and supported JS/TS files in the current package;
|
|
128
|
+
- workspace mode writes files in all selected package groups;
|
|
129
|
+
- safety analysis scans supported JS/TS and CSS references throughout the workspace root.
|
|
130
|
+
|
|
131
|
+
If a selected CSS Module has a consumer outside the writable scope, the affected module rule and import are retained with a warning. The external consumer is not modified. This permits safe current-package migration without silently expanding its write scope.
|
|
132
|
+
|
|
133
|
+
## Batch Architecture
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
resolve scope
|
|
137
|
+
-> discover non-ignored files once
|
|
138
|
+
-> snapshot CSS, JS/TS, package manifests, and Tailwind entries
|
|
139
|
+
-> group targets by package and Tailwind entry
|
|
140
|
+
-> plan every group against the immutable snapshot
|
|
141
|
+
-> merge edits by absolute path and original byte span
|
|
142
|
+
-> retain cross-stylesheet conflicts
|
|
143
|
+
-> validate edited syntax and Tailwind candidates
|
|
144
|
+
-> verify inputs still match the snapshot
|
|
145
|
+
-> print preview or atomically write
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### One Snapshot
|
|
149
|
+
|
|
150
|
+
Every relevant file is read once before planning. The planner never reads a source file after another CSS plan has modified it. All edits target the same immutable source snapshot.
|
|
151
|
+
|
|
152
|
+
Before writing, every destination is read again and compared with its snapshot. A concurrent user or tool edit aborts the operation instead of being overwritten.
|
|
153
|
+
|
|
154
|
+
### One Combined Plan
|
|
155
|
+
|
|
156
|
+
The native planner receives all CSS targets for a package group together. It resolves all CSS Module bindings and global selector candidates before producing JS edits. This avoids these unsafe patterns:
|
|
157
|
+
|
|
158
|
+
- two CSS files replacing the same `className` from different source versions;
|
|
159
|
+
- one CSS plan deleting an import needed by another stylesheet;
|
|
160
|
+
- multiple plans independently appending to the same Tailwind entry;
|
|
161
|
+
- the last file write silently discarding an earlier migration.
|
|
162
|
+
|
|
163
|
+
Edits are sorted deterministically by path and descending byte offset. Overlapping edits remaining after conflict handling are an internal planning error and abort the requested operation.
|
|
164
|
+
|
|
165
|
+
### Cross-Stylesheet Conflicts
|
|
166
|
+
|
|
167
|
+
If different selected stylesheets generate utilities that affect the same Tailwind property and variant on the same JSX element, class attribute order cannot preserve the original cascade.
|
|
168
|
+
|
|
169
|
+
The planner therefore:
|
|
170
|
+
|
|
171
|
+
1. identifies every contributing CSS rule;
|
|
172
|
+
2. retains those rules in their original stylesheets;
|
|
173
|
+
3. leaves their JS references unchanged;
|
|
174
|
+
4. emits a stable warning naming the conflicting candidates;
|
|
175
|
+
5. continues planning unrelated rules.
|
|
176
|
+
|
|
177
|
+
A retained conflict is a warning, not a package failure.
|
|
178
|
+
|
|
179
|
+
### Tailwind Validation
|
|
180
|
+
|
|
181
|
+
Each package group loads its Tailwind installation and design system once. All candidates in that group are validated against that group's prefix, theme, config, and plugins.
|
|
182
|
+
|
|
183
|
+
A candidate validation failure is an integrity failure, not a recoverable unsupported rule. It aborts the complete requested operation even with `--force` because it indicates that the generated edit plan cannot be trusted.
|
|
184
|
+
|
|
185
|
+
## Failure and Transaction Policy
|
|
186
|
+
|
|
187
|
+
### Default
|
|
188
|
+
|
|
189
|
+
Without `--force`, the requested scope is one transaction. Discovery, parsing, planning, candidate validation, source validation, or pre-write snapshot failure causes no file changes.
|
|
190
|
+
|
|
191
|
+
### Force
|
|
192
|
+
|
|
193
|
+
`--force` changes only package-group admission. A group with a recoverable discovery or parse failure is reported and excluded. Successful groups are then merged and written through one transaction.
|
|
194
|
+
|
|
195
|
+
`--force` never ignores:
|
|
196
|
+
|
|
197
|
+
- overlapping final edit ranges;
|
|
198
|
+
- invalid generated JavaScript, TypeScript, or CSS;
|
|
199
|
+
- invalid Tailwind candidates;
|
|
200
|
+
- changed inputs detected before commit;
|
|
201
|
+
- staging, rename, or rollback failures.
|
|
202
|
+
|
|
203
|
+
The package group is the minimum failure-isolation unit. CSS-file-level isolation is deferred because files in a group can share JS destinations and a Tailwind entry.
|
|
204
|
+
|
|
205
|
+
### Atomic Write
|
|
206
|
+
|
|
207
|
+
All final files are staged before any destination is replaced. Existing files are renamed to backups, staged files are installed, deletions remain represented by backups, and backups are removed only after the complete operation succeeds. A failure restores every available backup.
|
|
208
|
+
|
|
209
|
+
File permissions are preserved. Leftover staging or backup files continue to block a later run until the user restores or removes them.
|
|
210
|
+
|
|
211
|
+
## Git Ignore Behavior
|
|
212
|
+
|
|
213
|
+
Automatic discovery uses Git's ignore semantics when the workspace is a Git repository. Explicit CSS paths bypass ignore filtering. Outside Git, the fixed ignored-directory list still applies.
|
|
214
|
+
|
|
215
|
+
No new ignore-pattern parser or glob dependency is introduced for the initial implementation.
|
|
216
|
+
|
|
217
|
+
## Determinism
|
|
218
|
+
|
|
219
|
+
Package groups, CSS targets, source files, warnings, candidates, and output operations are sorted by normalized path and stable secondary keys. Repeated previews from the same snapshot must be byte-for-byte identical.
|
|
220
|
+
|
|
221
|
+
The preview and write paths consume the same final plan. A successful second invocation must produce no additional changes.
|
|
222
|
+
|
|
223
|
+
## Parallelism
|
|
224
|
+
|
|
225
|
+
Initial implementation is sequential after eliminating repeated project scans and repeated Tailwind loads. This provides the performance baseline and keeps the planner deterministic.
|
|
226
|
+
|
|
227
|
+
If benchmarks show CSS parsing is material, a later implementation may use a bounded worker pool for immutable CSS reads, parsing, and candidate extraction. Module resolution, edit merging, conflict handling, validation, and commit remain coordinated stages. Running complete per-CSS migrations concurrently is explicitly disallowed.
|
|
228
|
+
|
|
229
|
+
## Testing Strategy
|
|
230
|
+
|
|
231
|
+
### Discovery
|
|
232
|
+
|
|
233
|
+
- no positional path discovers all non-ignored CSS in the current package;
|
|
234
|
+
- a positional ignored CSS file is still processed;
|
|
235
|
+
- Tailwind entries and fixed generated directories are excluded;
|
|
236
|
+
- `--workspaces` discovers nested package groups;
|
|
237
|
+
- default mode does not write another package;
|
|
238
|
+
- workspace references outside writable scope prevent unsafe module cleanup.
|
|
239
|
+
|
|
240
|
+
### Grouping
|
|
241
|
+
|
|
242
|
+
- one package entry is selected automatically;
|
|
243
|
+
- missing and duplicate entries fail deterministically;
|
|
244
|
+
- workspace packages use their own Tailwind installations and entries;
|
|
245
|
+
- a shared package without a unique entry is skipped only with `--force`.
|
|
246
|
+
|
|
247
|
+
### Planning
|
|
248
|
+
|
|
249
|
+
- two CSS Modules can update different references in one JS file without lost edits;
|
|
250
|
+
- multiple selected rules can update one static `className`;
|
|
251
|
+
- cross-stylesheet utility conflicts retain only contributing rules;
|
|
252
|
+
- imports and CSS Module files are deleted only after all batch references are safe;
|
|
253
|
+
- candidates and warnings are deterministically ordered.
|
|
254
|
+
|
|
255
|
+
### Transactions
|
|
256
|
+
|
|
257
|
+
- preview writes nothing;
|
|
258
|
+
- default failure writes nothing;
|
|
259
|
+
- `--force` excludes a failed package group and applies successful groups;
|
|
260
|
+
- candidate or edit-integrity failure aborts even with `--force`;
|
|
261
|
+
- a source changed after planning aborts the write;
|
|
262
|
+
- an interrupted write restores prior content;
|
|
263
|
+
- a second run is a no-op.
|
|
264
|
+
|
|
265
|
+
## Implementation Sequence
|
|
266
|
+
|
|
267
|
+
1. Extend CLI and API options while preserving single-file behavior.
|
|
268
|
+
2. Add package-aware, Git-ignore-aware discovery and Tailwind grouping.
|
|
269
|
+
3. Replace the single-CSS native request with a package batch request.
|
|
270
|
+
4. Resolve all batch CSS Module and global candidates before planning source edits.
|
|
271
|
+
5. Add cross-stylesheet conflict retention and combined edit validation.
|
|
272
|
+
6. Aggregate package reports and implement `--force` package admission.
|
|
273
|
+
7. Add pre-write snapshot checks and retain the existing atomic writer.
|
|
274
|
+
8. Benchmark representative repositories before deciding whether to parallelize parsing.
|
|
275
|
+
|
|
276
|
+
## Success Criteria
|
|
277
|
+
|
|
278
|
+
1. `tw-migrate` previews every eligible CSS target in the current package.
|
|
279
|
+
2. `tw-migrate <file>` preserves exact single-file scope.
|
|
280
|
+
3. `--workspaces` processes package groups with their own Tailwind entries.
|
|
281
|
+
4. No batch edit can overwrite another edit produced from a different source version.
|
|
282
|
+
5. Cross-stylesheet conflicts retain their contributing rules without blocking independent work.
|
|
283
|
+
6. Default writes are all-or-nothing for the requested scope.
|
|
284
|
+
7. `--force` skips only recoverably failed package groups.
|
|
285
|
+
8. Automatic discovery respects Git ignore rules.
|
|
286
|
+
9. External workspace references prevent unsafe CSS Module deletion.
|
|
287
|
+
10. Preview, write, and repeated-run behavior are deterministic.
|
|
288
|
+
|
|
289
|
+
## Deferred Work
|
|
290
|
+
|
|
291
|
+
- SCSS, Sass, and Less parsers and source-preserving edits;
|
|
292
|
+
- Emotion and styled-components discovery from JS/TS inputs;
|
|
293
|
+
- JavaScript positional scope;
|
|
294
|
+
- configurable include/exclude globs;
|
|
295
|
+
- CSS-file-level failure isolation;
|
|
296
|
+
- dependency-graph ownership for shared CSS across multiple Tailwind applications;
|
|
297
|
+
- bounded parallel CSS parsing after benchmarks justify it.
|