galaxy-design 0.2.73 → 0.2.74
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 +113 -95
- package/dist/bin.js +17 -1
- package/dist/bin.js.map +1 -1
- package/dist/commands/add.js +59 -99
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/init.js +120 -611
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/migrate-tailwind.js +90 -0
- package/dist/commands/migrate-tailwind.js.map +1 -0
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/registries/registry-angular.json +145 -537
- package/dist/registry-angular.json +145 -537
- package/dist/schemas/components-schema.json +66 -11
- package/dist/schemas/registry-framework-schema.json +17 -7
- package/dist/utils/angular-provider-manager.js +1 -1
- package/dist/utils/angular-provider-manager.js.map +1 -1
- package/dist/utils/component-copier.js +102 -62
- package/dist/utils/component-copier.js.map +1 -1
- package/dist/utils/component-transformer.js +86 -16
- package/dist/utils/component-transformer.js.map +1 -1
- package/dist/utils/config-schema.js +160 -9
- package/dist/utils/config-schema.js.map +1 -1
- package/dist/utils/framework-registry-service.js +181 -0
- package/dist/utils/framework-registry-service.js.map +1 -0
- package/dist/utils/framework-registry.js +1 -138
- package/dist/utils/framework-registry.js.map +1 -1
- package/dist/utils/github-fetcher.js +55 -27
- package/dist/utils/github-fetcher.js.map +1 -1
- package/dist/utils/index.js +4 -3
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/init-runtime.js +477 -0
- package/dist/utils/init-runtime.js.map +1 -0
- package/dist/utils/init-scaffold.js +115 -0
- package/dist/utils/init-scaffold.js.map +1 -0
- package/dist/utils/init-workflow.js +189 -0
- package/dist/utils/init-workflow.js.map +1 -0
- package/dist/utils/package-manager.js +77 -2
- package/dist/utils/package-manager.js.map +1 -1
- package/dist/utils/platform-detector.js +12 -8
- package/dist/utils/platform-detector.js.map +1 -1
- package/dist/utils/registry-loader.js +20 -41
- package/dist/utils/registry-loader.js.map +1 -1
- package/dist/utils/tailwind-detector.js +162 -0
- package/dist/utils/tailwind-detector.js.map +1 -0
- package/dist/utils/tailwind-migration.js +401 -0
- package/dist/utils/tailwind-migration.js.map +1 -0
- package/dist/utils/tailwind-scaffold.js +398 -0
- package/dist/utils/tailwind-scaffold.js.map +1 -0
- package/package.json +20 -2
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
import { existsSync, readFileSync } from 'fs';
|
|
3
|
+
import { resolve } from 'path';
|
|
4
|
+
const POSTCSS_CONFIG_FILES = [
|
|
5
|
+
'postcss.config.mjs',
|
|
6
|
+
'postcss.config.js',
|
|
7
|
+
'postcss.config.cjs'
|
|
8
|
+
];
|
|
9
|
+
const TAILWIND_CONFIG_FILES = [
|
|
10
|
+
'tailwind.config.ts',
|
|
11
|
+
'tailwind.config.js',
|
|
12
|
+
'tailwind.config.mjs',
|
|
13
|
+
'tailwind.config.cjs'
|
|
14
|
+
];
|
|
15
|
+
const COMMON_CSS_FILES = [
|
|
16
|
+
'app/globals.css',
|
|
17
|
+
'src/app/globals.css',
|
|
18
|
+
'src/index.css',
|
|
19
|
+
'src/styles.css',
|
|
20
|
+
'src/style.css',
|
|
21
|
+
'assets/css/main.css',
|
|
22
|
+
'global.css'
|
|
23
|
+
];
|
|
24
|
+
function readTextIfExists(filePath) {
|
|
25
|
+
if (!existsSync(filePath)) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
return readFileSync(filePath, 'utf-8');
|
|
30
|
+
} catch (e) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function detectTailwindMajorFromRange(versionRange) {
|
|
35
|
+
if (!versionRange) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const match = versionRange.match(/(\d+)/);
|
|
39
|
+
if (!match) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const major = Number(match[1]);
|
|
43
|
+
if (major === 3 || major === 4) {
|
|
44
|
+
return major;
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
function findFirstExistingFile(cwd, candidates) {
|
|
49
|
+
for (const candidate of candidates){
|
|
50
|
+
if (existsSync(resolve(cwd, candidate))) {
|
|
51
|
+
return candidate;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
function uniquePaths(paths) {
|
|
57
|
+
return Array.from(new Set(paths.filter(Boolean)));
|
|
58
|
+
}
|
|
59
|
+
export function detectTailwindVersion(cwd, cssPathHints = []) {
|
|
60
|
+
const packageJsonPath = resolve(cwd, 'package.json');
|
|
61
|
+
const postcssConfigPath = findFirstExistingFile(cwd, POSTCSS_CONFIG_FILES);
|
|
62
|
+
const configPath = findFirstExistingFile(cwd, TAILWIND_CONFIG_FILES);
|
|
63
|
+
if (existsSync(packageJsonPath)) {
|
|
64
|
+
try {
|
|
65
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
66
|
+
const dependencies = _extends({}, packageJson.dependencies, packageJson.devDependencies);
|
|
67
|
+
if (dependencies['@tailwindcss/postcss']) {
|
|
68
|
+
return {
|
|
69
|
+
installed: true,
|
|
70
|
+
version: 4,
|
|
71
|
+
source: 'package-json',
|
|
72
|
+
postcssConfigPath,
|
|
73
|
+
configPath
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const packageVersion = detectTailwindMajorFromRange(dependencies.tailwindcss);
|
|
77
|
+
if (packageVersion) {
|
|
78
|
+
return {
|
|
79
|
+
installed: true,
|
|
80
|
+
version: packageVersion,
|
|
81
|
+
source: 'package-json',
|
|
82
|
+
postcssConfigPath,
|
|
83
|
+
configPath
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
} catch (e) {
|
|
87
|
+
// Fall through to content-based detection.
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (postcssConfigPath) {
|
|
91
|
+
const postcssContent = readTextIfExists(resolve(cwd, postcssConfigPath));
|
|
92
|
+
if (postcssContent == null ? void 0 : postcssContent.includes('@tailwindcss/postcss')) {
|
|
93
|
+
return {
|
|
94
|
+
installed: true,
|
|
95
|
+
version: 4,
|
|
96
|
+
source: 'postcss-config',
|
|
97
|
+
postcssConfigPath,
|
|
98
|
+
configPath
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (postcssContent && /tailwindcss/.test(postcssContent)) {
|
|
102
|
+
return {
|
|
103
|
+
installed: true,
|
|
104
|
+
version: 3,
|
|
105
|
+
source: 'postcss-config',
|
|
106
|
+
postcssConfigPath,
|
|
107
|
+
configPath
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const cssCandidates = uniquePaths([
|
|
112
|
+
...cssPathHints,
|
|
113
|
+
...COMMON_CSS_FILES
|
|
114
|
+
]);
|
|
115
|
+
for (const cssPath of cssCandidates){
|
|
116
|
+
const cssContent = readTextIfExists(resolve(cwd, cssPath));
|
|
117
|
+
if (!cssContent) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (/[@]import\s+['\"]tailwindcss['\"]/.test(cssContent)) {
|
|
121
|
+
return {
|
|
122
|
+
installed: true,
|
|
123
|
+
version: 4,
|
|
124
|
+
source: 'css-import',
|
|
125
|
+
cssPath,
|
|
126
|
+
postcssConfigPath,
|
|
127
|
+
configPath
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (/[@]tailwind\s+(base|components|utilities)/.test(cssContent)) {
|
|
131
|
+
return {
|
|
132
|
+
installed: true,
|
|
133
|
+
version: 3,
|
|
134
|
+
source: 'css-import',
|
|
135
|
+
cssPath,
|
|
136
|
+
postcssConfigPath,
|
|
137
|
+
configPath
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
installed: Boolean(postcssConfigPath || configPath),
|
|
143
|
+
version: null,
|
|
144
|
+
source: 'unknown',
|
|
145
|
+
postcssConfigPath,
|
|
146
|
+
configPath
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
export function resolveTailwindMode(detection, requestedVersion) {
|
|
150
|
+
if (requestedVersion === 3) {
|
|
151
|
+
return 'v3';
|
|
152
|
+
}
|
|
153
|
+
if (requestedVersion === 4) {
|
|
154
|
+
return 'v4';
|
|
155
|
+
}
|
|
156
|
+
if (detection.version === 3) {
|
|
157
|
+
return 'v3';
|
|
158
|
+
}
|
|
159
|
+
return 'v4';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
//# sourceMappingURL=tailwind-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/tailwind-detector.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'fs';\nimport { resolve } from 'path';\n\nexport type TailwindMajor = 3 | 4 | null;\n\nexport interface TailwindDetectionResult {\n installed: boolean;\n version: TailwindMajor;\n source: 'package-json' | 'postcss-config' | 'css-import' | 'unknown';\n cssPath?: string;\n postcssConfigPath?: string;\n configPath?: string;\n}\n\nconst POSTCSS_CONFIG_FILES = [\n 'postcss.config.mjs',\n 'postcss.config.js',\n 'postcss.config.cjs',\n];\n\nconst TAILWIND_CONFIG_FILES = [\n 'tailwind.config.ts',\n 'tailwind.config.js',\n 'tailwind.config.mjs',\n 'tailwind.config.cjs',\n];\n\nconst COMMON_CSS_FILES = [\n 'app/globals.css',\n 'src/app/globals.css',\n 'src/index.css',\n 'src/styles.css',\n 'src/style.css',\n 'assets/css/main.css',\n 'global.css',\n];\n\nfunction readTextIfExists(filePath: string): string | null {\n if (!existsSync(filePath)) {\n return null;\n }\n\n try {\n return readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\nfunction detectTailwindMajorFromRange(versionRange?: string): TailwindMajor {\n if (!versionRange) {\n return null;\n }\n\n const match = versionRange.match(/(\\d+)/);\n if (!match) {\n return null;\n }\n\n const major = Number(match[1]);\n if (major === 3 || major === 4) {\n return major;\n }\n\n return null;\n}\n\nfunction findFirstExistingFile(\n cwd: string,\n candidates: string[],\n): string | undefined {\n for (const candidate of candidates) {\n if (existsSync(resolve(cwd, candidate))) {\n return candidate;\n }\n }\n\n return undefined;\n}\n\nfunction uniquePaths(paths: string[]): string[] {\n return Array.from(new Set(paths.filter(Boolean)));\n}\n\nexport function detectTailwindVersion(\n cwd: string,\n cssPathHints: string[] = [],\n): TailwindDetectionResult {\n const packageJsonPath = resolve(cwd, 'package.json');\n const postcssConfigPath = findFirstExistingFile(cwd, POSTCSS_CONFIG_FILES);\n const configPath = findFirstExistingFile(cwd, TAILWIND_CONFIG_FILES);\n\n if (existsSync(packageJsonPath)) {\n try {\n const packageJson = JSON.parse(\n readFileSync(packageJsonPath, 'utf-8'),\n ) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const dependencies = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n if (dependencies['@tailwindcss/postcss']) {\n return {\n installed: true,\n version: 4,\n source: 'package-json',\n postcssConfigPath,\n configPath,\n };\n }\n\n const packageVersion = detectTailwindMajorFromRange(\n dependencies.tailwindcss,\n );\n if (packageVersion) {\n return {\n installed: true,\n version: packageVersion,\n source: 'package-json',\n postcssConfigPath,\n configPath,\n };\n }\n } catch {\n // Fall through to content-based detection.\n }\n }\n\n if (postcssConfigPath) {\n const postcssContent = readTextIfExists(resolve(cwd, postcssConfigPath));\n if (postcssContent?.includes('@tailwindcss/postcss')) {\n return {\n installed: true,\n version: 4,\n source: 'postcss-config',\n postcssConfigPath,\n configPath,\n };\n }\n\n if (postcssContent && /tailwindcss/.test(postcssContent)) {\n return {\n installed: true,\n version: 3,\n source: 'postcss-config',\n postcssConfigPath,\n configPath,\n };\n }\n }\n\n const cssCandidates = uniquePaths([...cssPathHints, ...COMMON_CSS_FILES]);\n for (const cssPath of cssCandidates) {\n const cssContent = readTextIfExists(resolve(cwd, cssPath));\n if (!cssContent) {\n continue;\n }\n\n if (/[@]import\\s+['\\\"]tailwindcss['\\\"]/.test(cssContent)) {\n return {\n installed: true,\n version: 4,\n source: 'css-import',\n cssPath,\n postcssConfigPath,\n configPath,\n };\n }\n\n if (/[@]tailwind\\s+(base|components|utilities)/.test(cssContent)) {\n return {\n installed: true,\n version: 3,\n source: 'css-import',\n cssPath,\n postcssConfigPath,\n configPath,\n };\n }\n }\n\n return {\n installed: Boolean(postcssConfigPath || configPath),\n version: null,\n source: 'unknown',\n postcssConfigPath,\n configPath,\n };\n}\n\nexport function resolveTailwindMode(\n detection: TailwindDetectionResult,\n requestedVersion?: TailwindMajor,\n): 'v3' | 'v4' {\n if (requestedVersion === 3) {\n return 'v3';\n }\n\n if (requestedVersion === 4) {\n return 'v4';\n }\n\n if (detection.version === 3) {\n return 'v3';\n }\n\n return 'v4';\n}\n"],"names":["existsSync","readFileSync","resolve","POSTCSS_CONFIG_FILES","TAILWIND_CONFIG_FILES","COMMON_CSS_FILES","readTextIfExists","filePath","detectTailwindMajorFromRange","versionRange","match","major","Number","findFirstExistingFile","cwd","candidates","candidate","undefined","uniquePaths","paths","Array","from","Set","filter","Boolean","detectTailwindVersion","cssPathHints","packageJsonPath","postcssConfigPath","configPath","packageJson","JSON","parse","dependencies","devDependencies","installed","version","source","packageVersion","tailwindcss","postcssContent","includes","test","cssCandidates","cssPath","cssContent","resolveTailwindMode","detection","requestedVersion"],"mappings":"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"}
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'fs';
|
|
3
|
+
import { resolve, join, extname, relative, dirname } from 'path';
|
|
4
|
+
import { detectFramework } from './detect.js';
|
|
5
|
+
import { detectTailwindVersion } from './tailwind-detector.js';
|
|
6
|
+
import { loadComponentsConfig, saveComponentsConfig } from './components-config.js';
|
|
7
|
+
const TAILWIND_V4_RANGE = '^4.1.16';
|
|
8
|
+
const AUDIT_PATTERNS = [
|
|
9
|
+
{
|
|
10
|
+
name: 'outline-none',
|
|
11
|
+
matcher: /\boutline-none\b/g,
|
|
12
|
+
message: 'Tailwind v4 often expects outline-hidden instead of outline-none.'
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'ring',
|
|
16
|
+
matcher: /\bring\b/g,
|
|
17
|
+
message: 'Bare ring now maps differently in v4; review whether ring-3 or another explicit width is intended.'
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'shadow-sm',
|
|
21
|
+
matcher: /\bshadow-sm\b/g,
|
|
22
|
+
message: 'Review shadow-sm because Tailwind v4 changed parts of the size scale.'
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'rounded-sm',
|
|
26
|
+
matcher: /\brounded-sm\b/g,
|
|
27
|
+
message: 'Review rounded-sm because Tailwind v4 changed parts of the size scale.'
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'blur-sm',
|
|
31
|
+
matcher: /\bblur-sm\b/g,
|
|
32
|
+
message: 'Review blur-sm because Tailwind v4 changed parts of the size scale.'
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'bg-opacity-*',
|
|
36
|
+
matcher: /\bbg-opacity-\d+\b/g,
|
|
37
|
+
message: 'Opacity utility shorthands were removed; prefer slash opacity syntax in v4.'
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'text-opacity-*',
|
|
41
|
+
matcher: /\btext-opacity-\d+\b/g,
|
|
42
|
+
message: 'Opacity utility shorthands were removed; prefer slash opacity syntax in v4.'
|
|
43
|
+
}
|
|
44
|
+
];
|
|
45
|
+
const SCAN_EXTENSIONS = new Set([
|
|
46
|
+
'.js',
|
|
47
|
+
'.jsx',
|
|
48
|
+
'.ts',
|
|
49
|
+
'.tsx',
|
|
50
|
+
'.vue',
|
|
51
|
+
'.html',
|
|
52
|
+
'.css',
|
|
53
|
+
'.mdx'
|
|
54
|
+
]);
|
|
55
|
+
const IGNORE_DIRS = new Set([
|
|
56
|
+
'node_modules',
|
|
57
|
+
'.git',
|
|
58
|
+
'dist',
|
|
59
|
+
'build',
|
|
60
|
+
'.next',
|
|
61
|
+
'.nuxt',
|
|
62
|
+
'.angular',
|
|
63
|
+
'coverage'
|
|
64
|
+
]);
|
|
65
|
+
const CONFIG_FILE_CANDIDATES = [
|
|
66
|
+
'tailwind.config.js',
|
|
67
|
+
'tailwind.config.cjs',
|
|
68
|
+
'tailwind.config.mjs',
|
|
69
|
+
'tailwind.config.ts',
|
|
70
|
+
'tailwind.config.cts',
|
|
71
|
+
'tailwind.config.mts',
|
|
72
|
+
'postcss.config.js',
|
|
73
|
+
'postcss.config.cjs',
|
|
74
|
+
'postcss.config.mjs',
|
|
75
|
+
'postcss.config.ts'
|
|
76
|
+
];
|
|
77
|
+
const CONFIG_AUDIT_PATTERNS = [
|
|
78
|
+
{
|
|
79
|
+
name: '@layer utilities',
|
|
80
|
+
matcher: /@layer\s+utilities\b/g,
|
|
81
|
+
message: 'Custom utilities declared with @layer utilities may depend on pre-v4 behavior and should be reviewed manually.'
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: 'corePlugins',
|
|
85
|
+
matcher: /\bcorePlugins\b/g,
|
|
86
|
+
message: 'corePlugins in JS config can behave differently in Tailwind v4 and may need a CSS-first replacement.'
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: 'safelist',
|
|
90
|
+
matcher: /\bsafelist\b/g,
|
|
91
|
+
message: 'safelist in JS config should be reviewed because Tailwind v4 encourages different content/config patterns.'
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'separator',
|
|
95
|
+
matcher: /\bseparator\b/g,
|
|
96
|
+
message: 'separator in JS config is legacy configuration and should be reviewed for Tailwind v4 compatibility.'
|
|
97
|
+
}
|
|
98
|
+
];
|
|
99
|
+
function getPackageJson(cwd) {
|
|
100
|
+
const packageJsonPath = resolve(cwd, 'package.json');
|
|
101
|
+
if (!existsSync(packageJsonPath)) {
|
|
102
|
+
throw new Error('package.json not found in the target project');
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
path: packageJsonPath,
|
|
106
|
+
data: JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function getDefaultCssPath(framework) {
|
|
110
|
+
switch(framework){
|
|
111
|
+
case 'nextjs':
|
|
112
|
+
return 'app/globals.css';
|
|
113
|
+
case 'angular':
|
|
114
|
+
return 'src/styles.css';
|
|
115
|
+
default:
|
|
116
|
+
return 'src/index.css';
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function resolveMigrationFramework(cwd) {
|
|
120
|
+
const config = loadComponentsConfig(cwd);
|
|
121
|
+
if (config) {
|
|
122
|
+
return config.framework;
|
|
123
|
+
}
|
|
124
|
+
const framework = detectFramework(cwd);
|
|
125
|
+
if (framework === 'unknown') {
|
|
126
|
+
throw new Error('Could not detect a supported framework for Tailwind migration');
|
|
127
|
+
}
|
|
128
|
+
return framework;
|
|
129
|
+
}
|
|
130
|
+
function resolveCssPath(cwd, framework) {
|
|
131
|
+
const config = loadComponentsConfig(cwd);
|
|
132
|
+
const preferred = (config == null ? void 0 : config.tailwind.css) || getDefaultCssPath(framework);
|
|
133
|
+
if (existsSync(resolve(cwd, preferred))) {
|
|
134
|
+
return preferred;
|
|
135
|
+
}
|
|
136
|
+
const detection = detectTailwindVersion(cwd, [
|
|
137
|
+
preferred
|
|
138
|
+
]);
|
|
139
|
+
return detection.cssPath || preferred;
|
|
140
|
+
}
|
|
141
|
+
function determinePostcssConfigPath(cwd, detection) {
|
|
142
|
+
if (detection.postcssConfigPath) {
|
|
143
|
+
return detection.postcssConfigPath;
|
|
144
|
+
}
|
|
145
|
+
const { data } = getPackageJson(cwd);
|
|
146
|
+
return data.type === 'module' ? 'postcss.config.mjs' : 'postcss.config.js';
|
|
147
|
+
}
|
|
148
|
+
function getPostcssV4Content(cwd, configPath) {
|
|
149
|
+
const extension = extname(configPath);
|
|
150
|
+
const { data } = getPackageJson(cwd);
|
|
151
|
+
const useEsm = extension === '.mjs' || extension === '.js' && data.type === 'module';
|
|
152
|
+
if (useEsm) {
|
|
153
|
+
return `export default {
|
|
154
|
+
plugins: {
|
|
155
|
+
"@tailwindcss/postcss": {},
|
|
156
|
+
},
|
|
157
|
+
}
|
|
158
|
+
`;
|
|
159
|
+
}
|
|
160
|
+
return `module.exports = {
|
|
161
|
+
plugins: {
|
|
162
|
+
"@tailwindcss/postcss": {},
|
|
163
|
+
},
|
|
164
|
+
}
|
|
165
|
+
`;
|
|
166
|
+
}
|
|
167
|
+
function rewriteCssToV4(content) {
|
|
168
|
+
if (/[@]import\s+['"]tailwindcss['"]/.test(content)) {
|
|
169
|
+
return content;
|
|
170
|
+
}
|
|
171
|
+
const lines = content.split('\n');
|
|
172
|
+
const rewritten = [];
|
|
173
|
+
let insertedImport = false;
|
|
174
|
+
for (const line of lines){
|
|
175
|
+
if (/^\s*[@]tailwind\s+(base|components|utilities);?\s*$/.test(line)) {
|
|
176
|
+
if (!insertedImport) {
|
|
177
|
+
rewritten.push('@import "tailwindcss";');
|
|
178
|
+
insertedImport = true;
|
|
179
|
+
}
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
rewritten.push(line);
|
|
183
|
+
}
|
|
184
|
+
if (!insertedImport) {
|
|
185
|
+
rewritten.unshift('@import "tailwindcss";');
|
|
186
|
+
}
|
|
187
|
+
return `${rewritten.join('\n').replace(/^\n+/, '').trimEnd()}\n`;
|
|
188
|
+
}
|
|
189
|
+
function collectFiles(root) {
|
|
190
|
+
if (!existsSync(root)) {
|
|
191
|
+
return [];
|
|
192
|
+
}
|
|
193
|
+
const entries = readdirSync(root, {
|
|
194
|
+
withFileTypes: true
|
|
195
|
+
});
|
|
196
|
+
const files = [];
|
|
197
|
+
for (const entry of entries){
|
|
198
|
+
const fullPath = join(root, entry.name);
|
|
199
|
+
if (entry.isDirectory()) {
|
|
200
|
+
if (!IGNORE_DIRS.has(entry.name)) {
|
|
201
|
+
files.push(...collectFiles(fullPath));
|
|
202
|
+
}
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if (SCAN_EXTENSIONS.has(extname(entry.name))) {
|
|
206
|
+
files.push(fullPath);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return files;
|
|
210
|
+
}
|
|
211
|
+
function collectAuditTargets(cwd) {
|
|
212
|
+
const candidateRoots = [
|
|
213
|
+
'src',
|
|
214
|
+
'app',
|
|
215
|
+
'components'
|
|
216
|
+
].map((dir)=>resolve(cwd, dir));
|
|
217
|
+
const targets = [];
|
|
218
|
+
const visited = new Set();
|
|
219
|
+
for (const root of candidateRoots){
|
|
220
|
+
for (const filePath of collectFiles(root)){
|
|
221
|
+
if (visited.has(filePath)) {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
visited.add(filePath);
|
|
225
|
+
targets.push({
|
|
226
|
+
filePath,
|
|
227
|
+
content: readFileSync(filePath, 'utf-8')
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
for (const relativePath of CONFIG_FILE_CANDIDATES){
|
|
232
|
+
const filePath = resolve(cwd, relativePath);
|
|
233
|
+
if (!existsSync(filePath) || visited.has(filePath)) {
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
visited.add(filePath);
|
|
237
|
+
targets.push({
|
|
238
|
+
filePath,
|
|
239
|
+
content: readFileSync(filePath, 'utf-8')
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
return targets;
|
|
243
|
+
}
|
|
244
|
+
export function auditTailwindV4Risks(cwd) {
|
|
245
|
+
const findings = [];
|
|
246
|
+
const targets = collectAuditTargets(cwd);
|
|
247
|
+
for (const target of targets){
|
|
248
|
+
const applicablePatterns = target.filePath.endsWith('.css') || target.filePath.endsWith('.scss') ? [
|
|
249
|
+
...AUDIT_PATTERNS,
|
|
250
|
+
...CONFIG_AUDIT_PATTERNS
|
|
251
|
+
] : target.filePath.includes('tailwind.config.') || target.filePath.includes('postcss.config.') ? CONFIG_AUDIT_PATTERNS : AUDIT_PATTERNS;
|
|
252
|
+
for (const pattern of applicablePatterns){
|
|
253
|
+
const matches = target.content.match(pattern.matcher);
|
|
254
|
+
if (matches && matches.length > 0) {
|
|
255
|
+
findings.push({
|
|
256
|
+
filePath: relative(cwd, target.filePath),
|
|
257
|
+
pattern: pattern.name,
|
|
258
|
+
matches: [
|
|
259
|
+
...new Set(matches)
|
|
260
|
+
],
|
|
261
|
+
message: pattern.message
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return findings;
|
|
267
|
+
}
|
|
268
|
+
function computePackageChanges(packageJson) {
|
|
269
|
+
var _updated_dependencies, _updated_dependencies1, _updated_devDependencies, _updated_devDependencies1;
|
|
270
|
+
const updated = _extends({}, packageJson, {
|
|
271
|
+
dependencies: _extends({}, packageJson.dependencies || {}),
|
|
272
|
+
devDependencies: _extends({}, packageJson.devDependencies || {})
|
|
273
|
+
});
|
|
274
|
+
const addedDevDependencies = [];
|
|
275
|
+
const removedPackages = [];
|
|
276
|
+
if ((_updated_dependencies = updated.dependencies) == null ? void 0 : _updated_dependencies.tailwindcss) {
|
|
277
|
+
delete updated.dependencies.tailwindcss;
|
|
278
|
+
}
|
|
279
|
+
if ((_updated_dependencies1 = updated.dependencies) == null ? void 0 : _updated_dependencies1['@tailwindcss/postcss']) {
|
|
280
|
+
delete updated.dependencies['@tailwindcss/postcss'];
|
|
281
|
+
}
|
|
282
|
+
if (((_updated_devDependencies = updated.devDependencies) == null ? void 0 : _updated_devDependencies.tailwindcss) !== TAILWIND_V4_RANGE) {
|
|
283
|
+
updated.devDependencies = updated.devDependencies || {};
|
|
284
|
+
updated.devDependencies.tailwindcss = TAILWIND_V4_RANGE;
|
|
285
|
+
addedDevDependencies.push(`tailwindcss@${TAILWIND_V4_RANGE}`);
|
|
286
|
+
}
|
|
287
|
+
if (((_updated_devDependencies1 = updated.devDependencies) == null ? void 0 : _updated_devDependencies1['@tailwindcss/postcss']) !== TAILWIND_V4_RANGE) {
|
|
288
|
+
updated.devDependencies = updated.devDependencies || {};
|
|
289
|
+
updated.devDependencies['@tailwindcss/postcss'] = TAILWIND_V4_RANGE;
|
|
290
|
+
addedDevDependencies.push(`@tailwindcss/postcss@${TAILWIND_V4_RANGE}`);
|
|
291
|
+
}
|
|
292
|
+
for (const dependencySection of [
|
|
293
|
+
'dependencies',
|
|
294
|
+
'devDependencies'
|
|
295
|
+
]){
|
|
296
|
+
const bucket = updated[dependencySection];
|
|
297
|
+
if (bucket == null ? void 0 : bucket.autoprefixer) {
|
|
298
|
+
delete bucket.autoprefixer;
|
|
299
|
+
removedPackages.push('autoprefixer');
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return {
|
|
303
|
+
updated,
|
|
304
|
+
addedDevDependencies: [
|
|
305
|
+
...new Set(addedDevDependencies)
|
|
306
|
+
],
|
|
307
|
+
removedPackages: [
|
|
308
|
+
...new Set(removedPackages)
|
|
309
|
+
]
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function updateComponentsConfigVersion(cwd) {
|
|
313
|
+
const config = loadComponentsConfig(cwd);
|
|
314
|
+
if (!config) {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
const updatedConfig = _extends({}, config, {
|
|
318
|
+
tailwind: _extends({}, config.tailwind, {
|
|
319
|
+
version: 4
|
|
320
|
+
})
|
|
321
|
+
});
|
|
322
|
+
saveComponentsConfig(cwd, updatedConfig);
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
export function planTailwindMigration(cwd) {
|
|
326
|
+
const framework = resolveMigrationFramework(cwd);
|
|
327
|
+
if (framework === 'react-native' || framework === 'flutter') {
|
|
328
|
+
throw new Error('Tailwind migration currently supports web frameworks only');
|
|
329
|
+
}
|
|
330
|
+
const cssPath = resolveCssPath(cwd, framework);
|
|
331
|
+
const detection = detectTailwindVersion(cwd, [
|
|
332
|
+
cssPath
|
|
333
|
+
]);
|
|
334
|
+
const postcssConfigPath = determinePostcssConfigPath(cwd, detection);
|
|
335
|
+
const { data: packageJson } = getPackageJson(cwd);
|
|
336
|
+
const packageChanges = computePackageChanges(packageJson);
|
|
337
|
+
const auditFindings = auditTailwindV4Risks(cwd);
|
|
338
|
+
const notes = [];
|
|
339
|
+
if (detection.version !== 3) {
|
|
340
|
+
notes.push(detection.version === 4 ? 'Project already appears to use Tailwind v4.' : 'Tailwind v3 was not detected; migration will not be applied automatically.');
|
|
341
|
+
}
|
|
342
|
+
if (auditFindings.some((finding)=>[
|
|
343
|
+
'@layer utilities',
|
|
344
|
+
'corePlugins',
|
|
345
|
+
'safelist',
|
|
346
|
+
'separator'
|
|
347
|
+
].includes(finding.pattern))) {
|
|
348
|
+
notes.push('Custom utility layers or legacy JS config options were detected; review those findings before treating the Tailwind v4 migration as complete.');
|
|
349
|
+
}
|
|
350
|
+
const filesToUpdate = [
|
|
351
|
+
postcssConfigPath,
|
|
352
|
+
cssPath,
|
|
353
|
+
'package.json'
|
|
354
|
+
];
|
|
355
|
+
const hasComponentsConfig = Boolean(loadComponentsConfig(cwd));
|
|
356
|
+
if (hasComponentsConfig) {
|
|
357
|
+
filesToUpdate.push('components.json');
|
|
358
|
+
}
|
|
359
|
+
return {
|
|
360
|
+
framework,
|
|
361
|
+
cssPath,
|
|
362
|
+
postcssConfigPath,
|
|
363
|
+
detection,
|
|
364
|
+
addedDevDependencies: packageChanges.addedDevDependencies,
|
|
365
|
+
removedPackages: packageChanges.removedPackages,
|
|
366
|
+
filesToUpdate,
|
|
367
|
+
notes,
|
|
368
|
+
auditFindings,
|
|
369
|
+
willUpdateComponentsConfig: hasComponentsConfig
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
export function applyTailwindMigration(cwd) {
|
|
373
|
+
const plan = planTailwindMigration(cwd);
|
|
374
|
+
if (plan.detection.version !== 3) {
|
|
375
|
+
throw new Error(plan.notes[0] || 'Tailwind v3 was not detected; nothing to migrate.');
|
|
376
|
+
}
|
|
377
|
+
const { path: packageJsonPath, data: packageJson } = getPackageJson(cwd);
|
|
378
|
+
const packageChanges = computePackageChanges(packageJson);
|
|
379
|
+
writeFileSync(packageJsonPath, `${JSON.stringify(packageChanges.updated, null, 2)}\n`, 'utf-8');
|
|
380
|
+
const cssFullPath = resolve(cwd, plan.cssPath);
|
|
381
|
+
mkdirSync(dirname(cssFullPath), {
|
|
382
|
+
recursive: true
|
|
383
|
+
});
|
|
384
|
+
const existingCss = existsSync(cssFullPath) ? readFileSync(cssFullPath, 'utf-8') : '';
|
|
385
|
+
writeFileSync(cssFullPath, rewriteCssToV4(existingCss), 'utf-8');
|
|
386
|
+
const postcssFullPath = resolve(cwd, plan.postcssConfigPath);
|
|
387
|
+
mkdirSync(dirname(postcssFullPath), {
|
|
388
|
+
recursive: true
|
|
389
|
+
});
|
|
390
|
+
writeFileSync(postcssFullPath, getPostcssV4Content(cwd, plan.postcssConfigPath), 'utf-8');
|
|
391
|
+
const componentsConfigUpdated = updateComponentsConfigVersion(cwd);
|
|
392
|
+
return {
|
|
393
|
+
filesUpdated: plan.filesToUpdate,
|
|
394
|
+
addedDevDependencies: plan.addedDevDependencies,
|
|
395
|
+
removedPackages: plan.removedPackages,
|
|
396
|
+
auditFindings: plan.auditFindings,
|
|
397
|
+
componentsConfigUpdated
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
//# sourceMappingURL=tailwind-migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/tailwind-migration.ts"],"sourcesContent":["import {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n writeFileSync,\n} from 'fs';\nimport { resolve, join, extname, relative, dirname } from 'path';\nimport type { Framework, ComponentsConfig } from './config-schema.js';\nimport { detectFramework } from './detect.js';\nimport {\n detectTailwindVersion,\n type TailwindDetectionResult,\n} from './tailwind-detector.js';\nimport {\n loadComponentsConfig,\n saveComponentsConfig,\n} from './components-config.js';\n\nconst TAILWIND_V4_RANGE = '^4.1.16';\n\nexport interface TailwindAuditFinding {\n filePath: string;\n pattern: string;\n matches: string[];\n message: string;\n}\n\nexport interface TailwindMigrationPlan {\n framework: Framework;\n cssPath: string;\n postcssConfigPath: string;\n detection: TailwindDetectionResult;\n addedDevDependencies: string[];\n removedPackages: string[];\n filesToUpdate: string[];\n notes: string[];\n auditFindings: TailwindAuditFinding[];\n willUpdateComponentsConfig: boolean;\n}\n\nexport interface TailwindMigrationResult {\n filesUpdated: string[];\n addedDevDependencies: string[];\n removedPackages: string[];\n auditFindings: TailwindAuditFinding[];\n componentsConfigUpdated: boolean;\n}\n\ninterface PackageJsonShape {\n type?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\ninterface AuditPattern {\n name: string;\n matcher: RegExp;\n message: string;\n}\n\ninterface AuditTarget {\n filePath: string;\n content: string;\n}\n\nconst AUDIT_PATTERNS: AuditPattern[] = [\n {\n name: 'outline-none',\n matcher: /\\boutline-none\\b/g,\n message:\n 'Tailwind v4 often expects outline-hidden instead of outline-none.',\n },\n {\n name: 'ring',\n matcher: /\\bring\\b/g,\n message:\n 'Bare ring now maps differently in v4; review whether ring-3 or another explicit width is intended.',\n },\n {\n name: 'shadow-sm',\n matcher: /\\bshadow-sm\\b/g,\n message:\n 'Review shadow-sm because Tailwind v4 changed parts of the size scale.',\n },\n {\n name: 'rounded-sm',\n matcher: /\\brounded-sm\\b/g,\n message:\n 'Review rounded-sm because Tailwind v4 changed parts of the size scale.',\n },\n {\n name: 'blur-sm',\n matcher: /\\bblur-sm\\b/g,\n message:\n 'Review blur-sm because Tailwind v4 changed parts of the size scale.',\n },\n {\n name: 'bg-opacity-*',\n matcher: /\\bbg-opacity-\\d+\\b/g,\n message:\n 'Opacity utility shorthands were removed; prefer slash opacity syntax in v4.',\n },\n {\n name: 'text-opacity-*',\n matcher: /\\btext-opacity-\\d+\\b/g,\n message:\n 'Opacity utility shorthands were removed; prefer slash opacity syntax in v4.',\n },\n];\n\nconst SCAN_EXTENSIONS = new Set([\n '.js',\n '.jsx',\n '.ts',\n '.tsx',\n '.vue',\n '.html',\n '.css',\n '.mdx',\n]);\n\nconst IGNORE_DIRS = new Set([\n 'node_modules',\n '.git',\n 'dist',\n 'build',\n '.next',\n '.nuxt',\n '.angular',\n 'coverage',\n]);\n\nconst CONFIG_FILE_CANDIDATES = [\n 'tailwind.config.js',\n 'tailwind.config.cjs',\n 'tailwind.config.mjs',\n 'tailwind.config.ts',\n 'tailwind.config.cts',\n 'tailwind.config.mts',\n 'postcss.config.js',\n 'postcss.config.cjs',\n 'postcss.config.mjs',\n 'postcss.config.ts',\n];\n\nconst CONFIG_AUDIT_PATTERNS: AuditPattern[] = [\n {\n name: '@layer utilities',\n matcher: /@layer\\s+utilities\\b/g,\n message:\n 'Custom utilities declared with @layer utilities may depend on pre-v4 behavior and should be reviewed manually.',\n },\n {\n name: 'corePlugins',\n matcher: /\\bcorePlugins\\b/g,\n message:\n 'corePlugins in JS config can behave differently in Tailwind v4 and may need a CSS-first replacement.',\n },\n {\n name: 'safelist',\n matcher: /\\bsafelist\\b/g,\n message:\n 'safelist in JS config should be reviewed because Tailwind v4 encourages different content/config patterns.',\n },\n {\n name: 'separator',\n matcher: /\\bseparator\\b/g,\n message:\n 'separator in JS config is legacy configuration and should be reviewed for Tailwind v4 compatibility.',\n },\n];\n\nfunction getPackageJson(cwd: string): { path: string; data: PackageJsonShape } {\n const packageJsonPath = resolve(cwd, 'package.json');\n if (!existsSync(packageJsonPath)) {\n throw new Error('package.json not found in the target project');\n }\n\n return {\n path: packageJsonPath,\n data: JSON.parse(\n readFileSync(packageJsonPath, 'utf-8'),\n ) as PackageJsonShape,\n };\n}\n\nfunction getDefaultCssPath(framework: Framework): string {\n switch (framework) {\n case 'nextjs':\n return 'app/globals.css';\n case 'angular':\n return 'src/styles.css';\n default:\n return 'src/index.css';\n }\n}\n\nfunction resolveMigrationFramework(cwd: string): Framework {\n const config = loadComponentsConfig(cwd);\n if (config) {\n return config.framework;\n }\n\n const framework = detectFramework(cwd);\n if (framework === 'unknown') {\n throw new Error(\n 'Could not detect a supported framework for Tailwind migration',\n );\n }\n\n return framework;\n}\n\nfunction resolveCssPath(cwd: string, framework: Framework): string {\n const config = loadComponentsConfig(cwd);\n const preferred = config?.tailwind.css || getDefaultCssPath(framework);\n\n if (existsSync(resolve(cwd, preferred))) {\n return preferred;\n }\n\n const detection = detectTailwindVersion(cwd, [preferred]);\n return detection.cssPath || preferred;\n}\n\nfunction determinePostcssConfigPath(\n cwd: string,\n detection: TailwindDetectionResult,\n): string {\n if (detection.postcssConfigPath) {\n return detection.postcssConfigPath;\n }\n\n const { data } = getPackageJson(cwd);\n return data.type === 'module' ? 'postcss.config.mjs' : 'postcss.config.js';\n}\n\nfunction getPostcssV4Content(cwd: string, configPath: string): string {\n const extension = extname(configPath);\n const { data } = getPackageJson(cwd);\n const useEsm =\n extension === '.mjs' || (extension === '.js' && data.type === 'module');\n\n if (useEsm) {\n return `export default {\n plugins: {\n \"@tailwindcss/postcss\": {},\n },\n}\n`;\n }\n\n return `module.exports = {\n plugins: {\n \"@tailwindcss/postcss\": {},\n },\n}\n`;\n}\n\nfunction rewriteCssToV4(content: string): string {\n if (/[@]import\\s+['\"]tailwindcss['\"]/.test(content)) {\n return content;\n }\n\n const lines = content.split('\\n');\n const rewritten: string[] = [];\n let insertedImport = false;\n\n for (const line of lines) {\n if (/^\\s*[@]tailwind\\s+(base|components|utilities);?\\s*$/.test(line)) {\n if (!insertedImport) {\n rewritten.push('@import \"tailwindcss\";');\n insertedImport = true;\n }\n continue;\n }\n\n rewritten.push(line);\n }\n\n if (!insertedImport) {\n rewritten.unshift('@import \"tailwindcss\";');\n }\n\n return `${rewritten.join('\\n').replace(/^\\n+/, '').trimEnd()}\\n`;\n}\n\nfunction collectFiles(root: string): string[] {\n if (!existsSync(root)) {\n return [];\n }\n\n const entries = readdirSync(root, { withFileTypes: true });\n const files: string[] = [];\n\n for (const entry of entries) {\n const fullPath = join(root, entry.name);\n\n if (entry.isDirectory()) {\n if (!IGNORE_DIRS.has(entry.name)) {\n files.push(...collectFiles(fullPath));\n }\n continue;\n }\n\n if (SCAN_EXTENSIONS.has(extname(entry.name))) {\n files.push(fullPath);\n }\n }\n\n return files;\n}\n\nfunction collectAuditTargets(cwd: string): AuditTarget[] {\n const candidateRoots = ['src', 'app', 'components'].map((dir) =>\n resolve(cwd, dir),\n );\n const targets: AuditTarget[] = [];\n const visited = new Set<string>();\n\n for (const root of candidateRoots) {\n for (const filePath of collectFiles(root)) {\n if (visited.has(filePath)) {\n continue;\n }\n visited.add(filePath);\n targets.push({\n filePath,\n content: readFileSync(filePath, 'utf-8'),\n });\n }\n }\n\n for (const relativePath of CONFIG_FILE_CANDIDATES) {\n const filePath = resolve(cwd, relativePath);\n if (!existsSync(filePath) || visited.has(filePath)) {\n continue;\n }\n\n visited.add(filePath);\n targets.push({\n filePath,\n content: readFileSync(filePath, 'utf-8'),\n });\n }\n\n return targets;\n}\n\nexport function auditTailwindV4Risks(cwd: string): TailwindAuditFinding[] {\n const findings: TailwindAuditFinding[] = [];\n const targets = collectAuditTargets(cwd);\n\n for (const target of targets) {\n const applicablePatterns =\n target.filePath.endsWith('.css') || target.filePath.endsWith('.scss')\n ? [...AUDIT_PATTERNS, ...CONFIG_AUDIT_PATTERNS]\n : target.filePath.includes('tailwind.config.') ||\n target.filePath.includes('postcss.config.')\n ? CONFIG_AUDIT_PATTERNS\n : AUDIT_PATTERNS;\n\n for (const pattern of applicablePatterns) {\n const matches = target.content.match(pattern.matcher);\n if (matches && matches.length > 0) {\n findings.push({\n filePath: relative(cwd, target.filePath),\n pattern: pattern.name,\n matches: [...new Set(matches)],\n message: pattern.message,\n });\n }\n }\n }\n\n return findings;\n}\n\nfunction computePackageChanges(packageJson: PackageJsonShape): {\n updated: PackageJsonShape;\n addedDevDependencies: string[];\n removedPackages: string[];\n} {\n const updated: PackageJsonShape = {\n ...packageJson,\n dependencies: { ...(packageJson.dependencies || {}) },\n devDependencies: { ...(packageJson.devDependencies || {}) },\n };\n\n const addedDevDependencies: string[] = [];\n const removedPackages: string[] = [];\n\n if (updated.dependencies?.tailwindcss) {\n delete updated.dependencies.tailwindcss;\n }\n if (updated.dependencies?.['@tailwindcss/postcss']) {\n delete updated.dependencies['@tailwindcss/postcss'];\n }\n\n if (updated.devDependencies?.tailwindcss !== TAILWIND_V4_RANGE) {\n updated.devDependencies = updated.devDependencies || {};\n updated.devDependencies.tailwindcss = TAILWIND_V4_RANGE;\n addedDevDependencies.push(`tailwindcss@${TAILWIND_V4_RANGE}`);\n }\n\n if (updated.devDependencies?.['@tailwindcss/postcss'] !== TAILWIND_V4_RANGE) {\n updated.devDependencies = updated.devDependencies || {};\n updated.devDependencies['@tailwindcss/postcss'] = TAILWIND_V4_RANGE;\n addedDevDependencies.push(`@tailwindcss/postcss@${TAILWIND_V4_RANGE}`);\n }\n\n for (const dependencySection of [\n 'dependencies',\n 'devDependencies',\n ] as const) {\n const bucket = updated[dependencySection];\n if (bucket?.autoprefixer) {\n delete bucket.autoprefixer;\n removedPackages.push('autoprefixer');\n }\n }\n\n return {\n updated,\n addedDevDependencies: [...new Set(addedDevDependencies)],\n removedPackages: [...new Set(removedPackages)],\n };\n}\n\nfunction updateComponentsConfigVersion(cwd: string): boolean {\n const config = loadComponentsConfig(cwd);\n if (!config) {\n return false;\n }\n\n const updatedConfig: ComponentsConfig = {\n ...config,\n tailwind: {\n ...config.tailwind,\n version: 4,\n },\n };\n saveComponentsConfig(cwd, updatedConfig);\n return true;\n}\n\nexport function planTailwindMigration(cwd: string): TailwindMigrationPlan {\n const framework = resolveMigrationFramework(cwd);\n\n if (framework === 'react-native' || framework === 'flutter') {\n throw new Error(\n 'Tailwind migration currently supports web frameworks only',\n );\n }\n\n const cssPath = resolveCssPath(cwd, framework);\n const detection = detectTailwindVersion(cwd, [cssPath]);\n const postcssConfigPath = determinePostcssConfigPath(cwd, detection);\n const { data: packageJson } = getPackageJson(cwd);\n const packageChanges = computePackageChanges(packageJson);\n const auditFindings = auditTailwindV4Risks(cwd);\n const notes: string[] = [];\n\n if (detection.version !== 3) {\n notes.push(\n detection.version === 4\n ? 'Project already appears to use Tailwind v4.'\n : 'Tailwind v3 was not detected; migration will not be applied automatically.',\n );\n }\n\n if (\n auditFindings.some((finding) =>\n ['@layer utilities', 'corePlugins', 'safelist', 'separator'].includes(\n finding.pattern,\n ),\n )\n ) {\n notes.push(\n 'Custom utility layers or legacy JS config options were detected; review those findings before treating the Tailwind v4 migration as complete.',\n );\n }\n\n const filesToUpdate = [postcssConfigPath, cssPath, 'package.json'];\n const hasComponentsConfig = Boolean(loadComponentsConfig(cwd));\n if (hasComponentsConfig) {\n filesToUpdate.push('components.json');\n }\n\n return {\n framework,\n cssPath,\n postcssConfigPath,\n detection,\n addedDevDependencies: packageChanges.addedDevDependencies,\n removedPackages: packageChanges.removedPackages,\n filesToUpdate,\n notes,\n auditFindings,\n willUpdateComponentsConfig: hasComponentsConfig,\n };\n}\n\nexport function applyTailwindMigration(cwd: string): TailwindMigrationResult {\n const plan = planTailwindMigration(cwd);\n\n if (plan.detection.version !== 3) {\n throw new Error(\n plan.notes[0] || 'Tailwind v3 was not detected; nothing to migrate.',\n );\n }\n\n const { path: packageJsonPath, data: packageJson } = getPackageJson(cwd);\n const packageChanges = computePackageChanges(packageJson);\n writeFileSync(\n packageJsonPath,\n `${JSON.stringify(packageChanges.updated, null, 2)}\\n`,\n 'utf-8',\n );\n\n const cssFullPath = resolve(cwd, plan.cssPath);\n mkdirSync(dirname(cssFullPath), { recursive: true });\n const existingCss = existsSync(cssFullPath)\n ? readFileSync(cssFullPath, 'utf-8')\n : '';\n writeFileSync(cssFullPath, rewriteCssToV4(existingCss), 'utf-8');\n\n const postcssFullPath = resolve(cwd, plan.postcssConfigPath);\n mkdirSync(dirname(postcssFullPath), { recursive: true });\n writeFileSync(\n postcssFullPath,\n getPostcssV4Content(cwd, plan.postcssConfigPath),\n 'utf-8',\n );\n\n const componentsConfigUpdated = updateComponentsConfigVersion(cwd);\n\n return {\n filesUpdated: plan.filesToUpdate,\n addedDevDependencies: plan.addedDevDependencies,\n removedPackages: plan.removedPackages,\n auditFindings: plan.auditFindings,\n componentsConfigUpdated,\n };\n}\n"],"names":["existsSync","mkdirSync","readdirSync","readFileSync","writeFileSync","resolve","join","extname","relative","dirname","detectFramework","detectTailwindVersion","loadComponentsConfig","saveComponentsConfig","TAILWIND_V4_RANGE","AUDIT_PATTERNS","name","matcher","message","SCAN_EXTENSIONS","Set","IGNORE_DIRS","CONFIG_FILE_CANDIDATES","CONFIG_AUDIT_PATTERNS","getPackageJson","cwd","packageJsonPath","Error","path","data","JSON","parse","getDefaultCssPath","framework","resolveMigrationFramework","config","resolveCssPath","preferred","tailwind","css","detection","cssPath","determinePostcssConfigPath","postcssConfigPath","type","getPostcssV4Content","configPath","extension","useEsm","rewriteCssToV4","content","test","lines","split","rewritten","insertedImport","line","push","unshift","replace","trimEnd","collectFiles","root","entries","withFileTypes","files","entry","fullPath","isDirectory","has","collectAuditTargets","candidateRoots","map","dir","targets","visited","filePath","add","relativePath","auditTailwindV4Risks","findings","target","applicablePatterns","endsWith","includes","pattern","matches","match","length","computePackageChanges","packageJson","updated","dependencies","devDependencies","addedDevDependencies","removedPackages","tailwindcss","dependencySection","bucket","autoprefixer","updateComponentsConfigVersion","updatedConfig","version","planTailwindMigration","packageChanges","auditFindings","notes","some","finding","filesToUpdate","hasComponentsConfig","Boolean","willUpdateComponentsConfig","applyTailwindMigration","plan","stringify","cssFullPath","recursive","existingCss","postcssFullPath","componentsConfigUpdated","filesUpdated"],"mappings":";AAAA,SACEA,UAAU,EACVC,SAAS,EACTC,WAAW,EACXC,YAAY,EACZC,aAAa,QACR,KAAK;AACZ,SAASC,OAAO,EAAEC,IAAI,EAAEC,OAAO,EAAEC,QAAQ,EAAEC,OAAO,QAAQ,OAAO;AAEjE,SAASC,eAAe,QAAQ,cAAc;AAC9C,SACEC,qBAAqB,QAEhB,yBAAyB;AAChC,SACEC,oBAAoB,EACpBC,oBAAoB,QACf,yBAAyB;AAEhC,MAAMC,oBAAoB;AA+C1B,MAAMC,iBAAiC;IACrC;QACEC,MAAM;QACNC,SAAS;QACTC,SACE;IACJ;IACA;QACEF,MAAM;QACNC,SAAS;QACTC,SACE;IACJ;IACA;QACEF,MAAM;QACNC,SAAS;QACTC,SACE;IACJ;IACA;QACEF,MAAM;QACNC,SAAS;QACTC,SACE;IACJ;IACA;QACEF,MAAM;QACNC,SAAS;QACTC,SACE;IACJ;IACA;QACEF,MAAM;QACNC,SAAS;QACTC,SACE;IACJ;IACA;QACEF,MAAM;QACNC,SAAS;QACTC,SACE;IACJ;CACD;AAED,MAAMC,kBAAkB,IAAIC,IAAI;IAC9B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD;AAED,MAAMC,cAAc,IAAID,IAAI;IAC1B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD;AAED,MAAME,yBAAyB;IAC7B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD;AAED,MAAMC,wBAAwC;IAC5C;QACEP,MAAM;QACNC,SAAS;QACTC,SACE;IACJ;IACA;QACEF,MAAM;QACNC,SAAS;QACTC,SACE;IACJ;IACA;QACEF,MAAM;QACNC,SAAS;QACTC,SACE;IACJ;IACA;QACEF,MAAM;QACNC,SAAS;QACTC,SACE;IACJ;CACD;AAED,SAASM,eAAeC,GAAW;IACjC,MAAMC,kBAAkBrB,QAAQoB,KAAK;IACrC,IAAI,CAACzB,WAAW0B,kBAAkB;QAChC,MAAM,IAAIC,MAAM;IAClB;IAEA,OAAO;QACLC,MAAMF;QACNG,MAAMC,KAAKC,KAAK,CACd5B,aAAauB,iBAAiB;IAElC;AACF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"}
|