tailwind-styled-v4 1.0.1 → 4.0.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/dist/animate.cjs +252 -0
- package/dist/animate.cjs.map +1 -0
- package/dist/animate.d.cts +117 -0
- package/dist/animate.d.ts +117 -0
- package/dist/animate.js +245 -0
- package/dist/animate.js.map +1 -0
- package/dist/astTransform-ua-eapqs.d.cts +41 -0
- package/dist/astTransform-ua-eapqs.d.ts +41 -0
- package/dist/compiler.cjs +3594 -0
- package/dist/compiler.cjs.map +1 -0
- package/dist/compiler.d.cts +716 -0
- package/dist/compiler.d.ts +716 -0
- package/dist/compiler.js +3535 -0
- package/dist/compiler.js.map +1 -0
- package/dist/css.cjs +71 -0
- package/dist/css.cjs.map +1 -0
- package/dist/css.d.cts +45 -0
- package/dist/css.d.ts +45 -0
- package/dist/css.js +62 -0
- package/dist/css.js.map +1 -0
- package/dist/devtools.cjs +959 -0
- package/dist/devtools.cjs.map +1 -0
- package/dist/devtools.d.cts +22 -0
- package/dist/devtools.d.ts +22 -0
- package/dist/devtools.js +952 -0
- package/dist/devtools.js.map +1 -0
- package/dist/index.cjs +1058 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +584 -0
- package/dist/index.d.ts +449 -980
- package/dist/index.js +1021 -3
- package/dist/index.js.map +1 -1
- package/dist/next.cjs +268 -0
- package/dist/next.cjs.map +1 -0
- package/dist/next.d.cts +45 -0
- package/dist/next.d.ts +45 -0
- package/dist/next.js +261 -0
- package/dist/next.js.map +1 -0
- package/dist/plugins.cjs +396 -0
- package/dist/plugins.cjs.map +1 -0
- package/dist/plugins.d.cts +231 -0
- package/dist/plugins.d.ts +231 -0
- package/dist/plugins.js +381 -0
- package/dist/plugins.js.map +1 -0
- package/dist/preset.cjs +129 -0
- package/dist/preset.cjs.map +1 -0
- package/dist/preset.d.cts +249 -0
- package/dist/preset.d.ts +249 -0
- package/dist/preset.js +124 -0
- package/dist/preset.js.map +1 -0
- package/dist/theme.cjs +154 -0
- package/dist/theme.cjs.map +1 -0
- package/dist/theme.d.cts +181 -0
- package/dist/theme.d.ts +181 -0
- package/dist/theme.js +148 -0
- package/dist/theme.js.map +1 -0
- package/dist/turbopackLoader.cjs +2689 -0
- package/dist/turbopackLoader.cjs.map +1 -0
- package/dist/turbopackLoader.d.cts +22 -0
- package/dist/turbopackLoader.d.ts +22 -0
- package/dist/turbopackLoader.js +2681 -0
- package/dist/turbopackLoader.js.map +1 -0
- package/dist/vite.cjs +105 -0
- package/dist/vite.cjs.map +1 -0
- package/dist/vite.d.cts +22 -0
- package/dist/vite.d.ts +22 -0
- package/dist/vite.js +96 -0
- package/dist/vite.js.map +1 -0
- package/dist/webpackLoader.cjs +2670 -0
- package/dist/webpackLoader.cjs.map +1 -0
- package/dist/webpackLoader.d.cts +24 -0
- package/dist/webpackLoader.d.ts +24 -0
- package/dist/webpackLoader.js +2662 -0
- package/dist/webpackLoader.js.map +1 -0
- package/package.json +62 -32
- package/CHANGELOG.md +0 -75
- package/LICENSE +0 -21
- package/README.md +0 -608
- package/dist/cli/init.js +0 -208
- package/dist/compiler/index.d.mts +0 -214
- package/dist/compiler/index.d.ts +0 -214
- package/dist/compiler/index.js +0 -546
- package/dist/compiler/index.js.map +0 -1
- package/dist/compiler/index.mjs +0 -504
- package/dist/compiler/index.mjs.map +0 -1
- package/dist/index.d.mts +0 -1115
- package/dist/index.mjs +0 -4
- package/dist/index.mjs.map +0 -1
- package/dist/turbopack-loader.js +0 -232
- package/dist/webpack-loader.js +0 -213
package/dist/compiler/index.mjs
DELETED
|
@@ -1,504 +0,0 @@
|
|
|
1
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
-
}) : x)(function(x) {
|
|
4
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
// src/utils/classParser.ts
|
|
9
|
-
function parseClassString(cls) {
|
|
10
|
-
return Array.from(
|
|
11
|
-
new Set(
|
|
12
|
-
cls.split(/\s+/).map((c) => c.trim()).filter(Boolean)
|
|
13
|
-
)
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
function normalizeClasses(cls) {
|
|
17
|
-
return parseClassString(cls).sort().join(" ");
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// src/utils/hash.ts
|
|
21
|
-
function djb2(str) {
|
|
22
|
-
let hash = 5381;
|
|
23
|
-
for (let i = 0; i < str.length; i++) {
|
|
24
|
-
hash = (hash << 5) + hash ^ str.charCodeAt(i);
|
|
25
|
-
hash = hash >>> 0;
|
|
26
|
-
}
|
|
27
|
-
return hash;
|
|
28
|
-
}
|
|
29
|
-
function hashClass(input) {
|
|
30
|
-
const n = djb2(input);
|
|
31
|
-
return "tw-" + n.toString(16).slice(0, 5).padStart(5, "0");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// src/compiler/astTransform.ts
|
|
35
|
-
var TEMPLATE_LITERAL_RE = /\btw\.(\w+)`((?:[^`\\]|\\.)*)`/g;
|
|
36
|
-
var OBJECT_CONFIG_RE = /\btw\.(\w+)\(\s*(\{[\s\S]*?\})\s*\)/g;
|
|
37
|
-
var EXTEND_CALL_RE = /(\w+)\.extend`((?:[^`\\]|\\.)*)`/g;
|
|
38
|
-
var IMPORT_RE = /import\s*\{[^}]*\btw\b[^}]*\}\s*from\s*["']tailwind-styled-v4["']/;
|
|
39
|
-
function cleanTemplateLiteral(raw) {
|
|
40
|
-
return raw.split("\n").map((l) => l.trim()).filter(Boolean).join(" ").replace(/\s+/g, " ").trim();
|
|
41
|
-
}
|
|
42
|
-
function isDynamic(raw) {
|
|
43
|
-
return raw.includes("${");
|
|
44
|
-
}
|
|
45
|
-
function extractBaseFromObjectConfig(objectStr) {
|
|
46
|
-
const baseMatch = objectStr.match(/base\s*:\s*["'`]([^"'`]+)["'`]/);
|
|
47
|
-
return baseMatch ? baseMatch[1].trim() : null;
|
|
48
|
-
}
|
|
49
|
-
function extractVariantsFromObjectConfig(objectStr) {
|
|
50
|
-
const variants = {};
|
|
51
|
-
const variantsBlockMatch = objectStr.match(/variants\s*:\s*\{([\s\S]*?)\}\s*[,}]/);
|
|
52
|
-
if (!variantsBlockMatch) return variants;
|
|
53
|
-
const block = variantsBlockMatch[1];
|
|
54
|
-
const variantKeyRe = /(\w+)\s*:\s*\{([^}]+)\}/g;
|
|
55
|
-
let km;
|
|
56
|
-
while ((km = variantKeyRe.exec(block)) !== null) {
|
|
57
|
-
const variantName = km[1];
|
|
58
|
-
const innerBlock = km[2];
|
|
59
|
-
variants[variantName] = {};
|
|
60
|
-
const valueRe = /(\w+)\s*:\s*["'`]([^"'`]+)["'`]/g;
|
|
61
|
-
let vm;
|
|
62
|
-
while ((vm = valueRe.exec(innerBlock)) !== null) {
|
|
63
|
-
variants[variantName][vm[1]] = vm[2].trim();
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return variants;
|
|
67
|
-
}
|
|
68
|
-
function buildStaticAttrs(classes, opts, tag, hash) {
|
|
69
|
-
const dataAttr = opts.addDataAttr && hash ? `, "data-tw": "${hash}"` : "";
|
|
70
|
-
return `styled.${tag}.attrs(() => ({ className: "${classes}"${dataAttr} }))\`\``;
|
|
71
|
-
}
|
|
72
|
-
function buildStyledTagWithVariants(tag, base, _variants, opts) {
|
|
73
|
-
const dataAttr = opts.addDataAttr ? `, "data-tw": "${tag}"` : "";
|
|
74
|
-
const normalizedBase = normalizeClasses(base);
|
|
75
|
-
return `styled.${tag}.attrs((p) => ({
|
|
76
|
-
className: [
|
|
77
|
-
"${normalizedBase}",
|
|
78
|
-
p.className
|
|
79
|
-
].filter(Boolean).join(" ")${dataAttr}
|
|
80
|
-
}))\`\``;
|
|
81
|
-
}
|
|
82
|
-
function transformSource(source, opts = {}) {
|
|
83
|
-
const { mode = "zero-runtime", addDataAttr = false, generateHash = true } = opts;
|
|
84
|
-
if (!IMPORT_RE.test(source) && !source.includes("tw.")) {
|
|
85
|
-
return { code: source, classes: [], changed: false };
|
|
86
|
-
}
|
|
87
|
-
let code = source;
|
|
88
|
-
let changed = false;
|
|
89
|
-
const allClasses = [];
|
|
90
|
-
if (mode === "extract-only") {
|
|
91
|
-
const classes = extractAllClasses(source);
|
|
92
|
-
return { code: source, classes, changed: false };
|
|
93
|
-
}
|
|
94
|
-
if (mode === "runtime") {
|
|
95
|
-
return { code: source, classes: extractAllClasses(source), changed: false };
|
|
96
|
-
}
|
|
97
|
-
code = code.replace(
|
|
98
|
-
TEMPLATE_LITERAL_RE,
|
|
99
|
-
(_match, tag, content) => {
|
|
100
|
-
if (isDynamic(content)) {
|
|
101
|
-
return _match;
|
|
102
|
-
}
|
|
103
|
-
const classes = cleanTemplateLiteral(content);
|
|
104
|
-
const hash = generateHash ? hashClass(`${tag}:${classes}`) : void 0;
|
|
105
|
-
allClasses.push(...classes.split(/\s+/).filter(Boolean));
|
|
106
|
-
changed = true;
|
|
107
|
-
return buildStaticAttrs(classes, { addDataAttr }, tag, hash);
|
|
108
|
-
}
|
|
109
|
-
);
|
|
110
|
-
code = code.replace(
|
|
111
|
-
OBJECT_CONFIG_RE,
|
|
112
|
-
(_match, tag, objectStr) => {
|
|
113
|
-
const base = extractBaseFromObjectConfig(objectStr);
|
|
114
|
-
const variants = extractVariantsFromObjectConfig(objectStr);
|
|
115
|
-
if (!base) return _match;
|
|
116
|
-
const baseClasses = normalizeClasses(base);
|
|
117
|
-
allClasses.push(...baseClasses.split(/\s+/).filter(Boolean));
|
|
118
|
-
for (const vMap of Object.values(variants)) {
|
|
119
|
-
for (const cls of Object.values(vMap)) {
|
|
120
|
-
allClasses.push(...cls.split(/\s+/).filter(Boolean));
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
changed = true;
|
|
124
|
-
if (Object.keys(variants).length === 0) {
|
|
125
|
-
const hash = generateHash ? hashClass(`${tag}:${baseClasses}`) : void 0;
|
|
126
|
-
return buildStaticAttrs(baseClasses, { addDataAttr }, tag, hash);
|
|
127
|
-
}
|
|
128
|
-
return buildStyledTagWithVariants(tag, baseClasses, variants, { addDataAttr });
|
|
129
|
-
}
|
|
130
|
-
);
|
|
131
|
-
code = code.replace(
|
|
132
|
-
EXTEND_CALL_RE,
|
|
133
|
-
(_match, componentName, content) => {
|
|
134
|
-
if (isDynamic(content)) return _match;
|
|
135
|
-
const classes = cleanTemplateLiteral(content);
|
|
136
|
-
allClasses.push(...classes.split(/\s+/).filter(Boolean));
|
|
137
|
-
changed = true;
|
|
138
|
-
return `styled(${componentName}).attrs((p) => ({
|
|
139
|
-
className: [p.className, "${classes}"].filter(Boolean).join(" ")
|
|
140
|
-
}))\`\``;
|
|
141
|
-
}
|
|
142
|
-
);
|
|
143
|
-
if (changed && !source.includes("import styled from")) {
|
|
144
|
-
code = `import styled from "styled-components"
|
|
145
|
-
${code}`;
|
|
146
|
-
}
|
|
147
|
-
return {
|
|
148
|
-
code,
|
|
149
|
-
classes: Array.from(new Set(allClasses)),
|
|
150
|
-
changed
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
function extractAllClasses(source) {
|
|
154
|
-
const classes = /* @__PURE__ */ new Set();
|
|
155
|
-
const addClasses = (str) => {
|
|
156
|
-
str.split(/\s+/).map((c) => c.trim()).filter((c) => c.length > 0 && /^[-a-z0-9:/[\]!.]+$/.test(c)).forEach((c) => classes.add(c));
|
|
157
|
-
};
|
|
158
|
-
let m;
|
|
159
|
-
const re1 = new RegExp(TEMPLATE_LITERAL_RE.source, "g");
|
|
160
|
-
while ((m = re1.exec(source)) !== null) addClasses(m[2]);
|
|
161
|
-
const re2 = new RegExp(OBJECT_CONFIG_RE.source, "g");
|
|
162
|
-
while ((m = re2.exec(source)) !== null) {
|
|
163
|
-
const base = extractBaseFromObjectConfig(m[2]);
|
|
164
|
-
if (base) addClasses(base);
|
|
165
|
-
const variants = extractVariantsFromObjectConfig(m[2]);
|
|
166
|
-
for (const vMap of Object.values(variants)) {
|
|
167
|
-
for (const cls of Object.values(vMap)) addClasses(cls);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
const re3 = new RegExp(EXTEND_CALL_RE.source, "g");
|
|
171
|
-
while ((m = re3.exec(source)) !== null) addClasses(m[2]);
|
|
172
|
-
const classNameRe = /className\s*=\s*["']([^"']+)["']/g;
|
|
173
|
-
while ((m = classNameRe.exec(source)) !== null) addClasses(m[1]);
|
|
174
|
-
const cnRe = /(?:cn|clsx|twMerge|mergeClasses)\s*\(([^)]+)\)/g;
|
|
175
|
-
while ((m = cnRe.exec(source)) !== null) {
|
|
176
|
-
const inner = m[1].replace(/["'`]/g, " ");
|
|
177
|
-
addClasses(inner);
|
|
178
|
-
}
|
|
179
|
-
return Array.from(classes).sort();
|
|
180
|
-
}
|
|
181
|
-
function transformBatch(files, opts = {}) {
|
|
182
|
-
const allClasses = /* @__PURE__ */ new Set();
|
|
183
|
-
const results = files.map(({ path: path4, source }) => {
|
|
184
|
-
const result = transformSource(source, { ...opts, filename: path4 });
|
|
185
|
-
result.classes.forEach((c) => allClasses.add(c));
|
|
186
|
-
return { ...result, path: path4 };
|
|
187
|
-
});
|
|
188
|
-
return {
|
|
189
|
-
results,
|
|
190
|
-
allClasses: Array.from(allClasses).sort()
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// src/compiler/transformTw.ts
|
|
195
|
-
var PROCESSABLE_EXTS = /\.(tsx|ts|jsx|js|mts|mjs)$/;
|
|
196
|
-
function transformTw(source, opts = {}) {
|
|
197
|
-
const { filepath = "" } = opts;
|
|
198
|
-
if (filepath && !PROCESSABLE_EXTS.test(filepath)) {
|
|
199
|
-
return { code: source, classes: [], changed: false };
|
|
200
|
-
}
|
|
201
|
-
if (!source.includes("tw") && !source.includes("tailwind-styled")) {
|
|
202
|
-
return { code: source, classes: [], changed: false };
|
|
203
|
-
}
|
|
204
|
-
return transformSource(source, opts);
|
|
205
|
-
}
|
|
206
|
-
function extractTwClasses(source) {
|
|
207
|
-
return extractAllClasses(source);
|
|
208
|
-
}
|
|
209
|
-
function shouldProcess(filepath) {
|
|
210
|
-
if (!PROCESSABLE_EXTS.test(filepath)) return false;
|
|
211
|
-
if (filepath.includes("node_modules")) return false;
|
|
212
|
-
if (filepath.includes(".d.ts")) return false;
|
|
213
|
-
return true;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// src/compiler/swcPlugin.ts
|
|
217
|
-
import fs from "fs";
|
|
218
|
-
import path from "path";
|
|
219
|
-
function turbopackTransform(source, resourcePath, opts = {}) {
|
|
220
|
-
if (!shouldProcess(resourcePath)) return { code: source };
|
|
221
|
-
const result = transformTw(source, { ...opts, filepath: resourcePath });
|
|
222
|
-
return { code: result.code };
|
|
223
|
-
}
|
|
224
|
-
function buildTurbopackRules(opts) {
|
|
225
|
-
const loaderPath = __require.resolve("./turbopackLoader");
|
|
226
|
-
const rule = {
|
|
227
|
-
loaders: [
|
|
228
|
-
{
|
|
229
|
-
loader: loaderPath,
|
|
230
|
-
options: opts
|
|
231
|
-
}
|
|
232
|
-
],
|
|
233
|
-
as: "*.tsx"
|
|
234
|
-
};
|
|
235
|
-
return {
|
|
236
|
-
"*.{ts,tsx,js,jsx}": rule
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
function withTailwindStyled(pluginOpts = {}) {
|
|
240
|
-
const {
|
|
241
|
-
mode = process.env.NODE_ENV === "production" ? "zero-runtime" : "runtime",
|
|
242
|
-
addDataAttr = process.env.NODE_ENV !== "production",
|
|
243
|
-
generateHash = true,
|
|
244
|
-
generateSafelist: generateSafelist2 = true,
|
|
245
|
-
safelistOutput = "tailwind.safelist.json",
|
|
246
|
-
scanDirs = ["src", "app", "pages", "components"],
|
|
247
|
-
...transformOpts
|
|
248
|
-
} = pluginOpts;
|
|
249
|
-
const loaderOpts = { mode, addDataAttr, generateHash, ...transformOpts };
|
|
250
|
-
return function(nextConfig = {}) {
|
|
251
|
-
const existingTurbopack = nextConfig.experimental?.turbopack ?? {};
|
|
252
|
-
const existingRules = existingTurbopack.rules ?? {};
|
|
253
|
-
const turboRules = buildTurbopackRules(loaderOpts);
|
|
254
|
-
const merged = {
|
|
255
|
-
...nextConfig,
|
|
256
|
-
experimental: {
|
|
257
|
-
...nextConfig.experimental,
|
|
258
|
-
turbopack: {
|
|
259
|
-
...existingTurbopack,
|
|
260
|
-
rules: {
|
|
261
|
-
...existingRules,
|
|
262
|
-
...turboRules
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
},
|
|
266
|
-
// ── Webpack (fallback for non-turbopack builds) ──────────────────
|
|
267
|
-
webpack(webpackConfig, context) {
|
|
268
|
-
webpackConfig.module.rules.push({
|
|
269
|
-
test: /\.(tsx|ts|jsx|js)$/,
|
|
270
|
-
exclude: /node_modules/,
|
|
271
|
-
use: [
|
|
272
|
-
{
|
|
273
|
-
loader: __require.resolve("./webpackLoader"),
|
|
274
|
-
options: loaderOpts
|
|
275
|
-
}
|
|
276
|
-
]
|
|
277
|
-
});
|
|
278
|
-
if (generateSafelist2 && !context.dev) {
|
|
279
|
-
runSafelistGeneration({
|
|
280
|
-
scanDirs,
|
|
281
|
-
outputPath: safelistOutput,
|
|
282
|
-
cwd: context.dir ?? process.cwd()
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
if (typeof nextConfig.webpack === "function") {
|
|
286
|
-
return nextConfig.webpack(webpackConfig, context);
|
|
287
|
-
}
|
|
288
|
-
return webpackConfig;
|
|
289
|
-
}
|
|
290
|
-
};
|
|
291
|
-
return merged;
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
function swcTransformFile(source, filepath, opts = {}) {
|
|
295
|
-
if (!shouldProcess(filepath)) return source;
|
|
296
|
-
const result = transformTw(source, { ...opts, filepath });
|
|
297
|
-
return result.code;
|
|
298
|
-
}
|
|
299
|
-
function scanDirectory(dir) {
|
|
300
|
-
if (!fs.existsSync(dir)) return [];
|
|
301
|
-
const results = [];
|
|
302
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
303
|
-
for (const entry of entries) {
|
|
304
|
-
const fullPath = path.join(dir, entry.name);
|
|
305
|
-
if (entry.isDirectory()) {
|
|
306
|
-
if (!["node_modules", ".next", ".git", "dist"].includes(entry.name)) {
|
|
307
|
-
results.push(...scanDirectory(fullPath));
|
|
308
|
-
}
|
|
309
|
-
} else if (/\.(tsx|ts|jsx|js)$/.test(entry.name)) {
|
|
310
|
-
results.push(fullPath);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
return results;
|
|
314
|
-
}
|
|
315
|
-
function runSafelistGeneration(opts) {
|
|
316
|
-
const { scanDirs, outputPath, cwd } = opts;
|
|
317
|
-
const allClasses = /* @__PURE__ */ new Set();
|
|
318
|
-
for (const dir of scanDirs) {
|
|
319
|
-
const absDir = path.resolve(cwd, dir);
|
|
320
|
-
const files = scanDirectory(absDir);
|
|
321
|
-
for (const file of files) {
|
|
322
|
-
try {
|
|
323
|
-
const source = fs.readFileSync(file, "utf-8");
|
|
324
|
-
const classes = extractTwClasses(source);
|
|
325
|
-
classes.forEach((c) => allClasses.add(c));
|
|
326
|
-
} catch {
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
const sorted = Array.from(allClasses).sort();
|
|
331
|
-
const absOutput = path.resolve(cwd, outputPath);
|
|
332
|
-
fs.writeFileSync(
|
|
333
|
-
absOutput,
|
|
334
|
-
JSON.stringify({ safelist: sorted, count: sorted.length, generatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
|
|
335
|
-
);
|
|
336
|
-
console.log(`[tailwind-styled-v4] \u2713 Safelist: ${sorted.length} classes \u2192 ${absOutput}`);
|
|
337
|
-
}
|
|
338
|
-
function swcPlugin(source, opts = {}) {
|
|
339
|
-
const result = transformTw(source, opts);
|
|
340
|
-
return result.code;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// src/compiler/vitePlugin.ts
|
|
344
|
-
import path2 from "path";
|
|
345
|
-
function tailwindStyledPlugin(opts = {}) {
|
|
346
|
-
const {
|
|
347
|
-
include = /\.(tsx|ts|jsx|js)$/,
|
|
348
|
-
exclude = /node_modules/,
|
|
349
|
-
scanDirs = ["src"],
|
|
350
|
-
safelistOutput = "tailwind.safelist.json",
|
|
351
|
-
generateSafelist: generateSafelist2 = true,
|
|
352
|
-
mode,
|
|
353
|
-
...transformOpts
|
|
354
|
-
} = opts;
|
|
355
|
-
let root = process.cwd();
|
|
356
|
-
let isDev = true;
|
|
357
|
-
let resolvedMode;
|
|
358
|
-
return {
|
|
359
|
-
name: "tailwind-styled-v4",
|
|
360
|
-
enforce: "pre",
|
|
361
|
-
configResolved(config) {
|
|
362
|
-
root = config.root;
|
|
363
|
-
isDev = config.command === "serve";
|
|
364
|
-
resolvedMode = mode ?? (isDev ? "runtime" : "zero-runtime");
|
|
365
|
-
},
|
|
366
|
-
transform(source, id) {
|
|
367
|
-
const filepath = id.split("?")[0];
|
|
368
|
-
if (!include.test(filepath)) return null;
|
|
369
|
-
if (exclude.test(filepath)) return null;
|
|
370
|
-
if (!shouldProcess(filepath)) return null;
|
|
371
|
-
const result = transformTw(source, {
|
|
372
|
-
...transformOpts,
|
|
373
|
-
mode: resolvedMode,
|
|
374
|
-
filename: filepath,
|
|
375
|
-
addDataAttr: transformOpts.addDataAttr ?? isDev
|
|
376
|
-
});
|
|
377
|
-
if (!result.changed) return null;
|
|
378
|
-
return {
|
|
379
|
-
code: result.code,
|
|
380
|
-
map: null
|
|
381
|
-
// source maps: future enhancement
|
|
382
|
-
};
|
|
383
|
-
},
|
|
384
|
-
buildEnd() {
|
|
385
|
-
if (!generateSafelist2 || isDev) return;
|
|
386
|
-
runSafelistGeneration({
|
|
387
|
-
scanDirs: scanDirs.map((d) => path2.resolve(root, d)),
|
|
388
|
-
outputPath: path2.resolve(root, safelistOutput),
|
|
389
|
-
cwd: root
|
|
390
|
-
});
|
|
391
|
-
},
|
|
392
|
-
// HMR: re-transform on save
|
|
393
|
-
handleHotUpdate({ file, server }) {
|
|
394
|
-
if (!include.test(file)) return;
|
|
395
|
-
server.ws.send({ type: "full-reload" });
|
|
396
|
-
}
|
|
397
|
-
};
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
// src/build/generateSafelist.ts
|
|
401
|
-
import fs2 from "fs";
|
|
402
|
-
import path3 from "path";
|
|
403
|
-
var DEFAULT_CONFIG = {
|
|
404
|
-
cwd: process.cwd(),
|
|
405
|
-
scanDirs: ["src", "app", "pages", "components", "features", "lib"],
|
|
406
|
-
extensions: /\.(tsx|ts|jsx|js|mdx|md)$/,
|
|
407
|
-
excludeDirs: ["node_modules", ".next", ".git", "dist", "build", ".turbo", "coverage"],
|
|
408
|
-
outputPath: "tailwind.safelist.json",
|
|
409
|
-
verbose: true
|
|
410
|
-
};
|
|
411
|
-
function walkDir(dir, config) {
|
|
412
|
-
if (!fs2.existsSync(dir)) return [];
|
|
413
|
-
const results = [];
|
|
414
|
-
try {
|
|
415
|
-
const entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
416
|
-
for (const entry of entries) {
|
|
417
|
-
if (config.excludeDirs.includes(entry.name)) continue;
|
|
418
|
-
const fullPath = path3.join(dir, entry.name);
|
|
419
|
-
if (entry.isDirectory()) {
|
|
420
|
-
results.push(...walkDir(fullPath, config));
|
|
421
|
-
} else if (config.extensions.test(entry.name)) {
|
|
422
|
-
results.push(fullPath);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
} catch {
|
|
426
|
-
}
|
|
427
|
-
return results;
|
|
428
|
-
}
|
|
429
|
-
function extractFromFiles(files, config) {
|
|
430
|
-
const allClasses = /* @__PURE__ */ new Set();
|
|
431
|
-
const byFile = {};
|
|
432
|
-
let errorCount = 0;
|
|
433
|
-
for (const file of files) {
|
|
434
|
-
try {
|
|
435
|
-
const source = fs2.readFileSync(file, "utf-8");
|
|
436
|
-
const classes = extractAllClasses(source);
|
|
437
|
-
if (classes.length > 0) {
|
|
438
|
-
classes.forEach((c) => allClasses.add(c));
|
|
439
|
-
const relPath = path3.relative(config.cwd, file);
|
|
440
|
-
byFile[relPath] = classes;
|
|
441
|
-
}
|
|
442
|
-
} catch {
|
|
443
|
-
errorCount++;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
return {
|
|
447
|
-
classes: Array.from(allClasses).sort(),
|
|
448
|
-
fileCount: files.length,
|
|
449
|
-
errorCount,
|
|
450
|
-
byFile
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
|
-
function writeSafelist(result, config) {
|
|
454
|
-
const absOutput = path3.resolve(config.cwd, config.outputPath);
|
|
455
|
-
const output = {
|
|
456
|
-
safelist: result.classes,
|
|
457
|
-
count: result.classes.length,
|
|
458
|
-
fileCount: result.fileCount,
|
|
459
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
460
|
-
generator: "tailwind-styled-v4",
|
|
461
|
-
...config.verbose ? { byFile: result.byFile } : {}
|
|
462
|
-
};
|
|
463
|
-
fs2.writeFileSync(absOutput, JSON.stringify(output, null, 2));
|
|
464
|
-
if (config.verbose) {
|
|
465
|
-
console.log(`[tailwind-styled-v4] \u2713 Safelist generated`);
|
|
466
|
-
console.log(` Classes: ${result.classes.length.toLocaleString()}`);
|
|
467
|
-
console.log(` Files: ${result.fileCount}`);
|
|
468
|
-
console.log(` Errors: ${result.errorCount}`);
|
|
469
|
-
console.log(` Output: ${absOutput}`);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
function generateSafelist(userConfig = {}) {
|
|
473
|
-
const config = { ...DEFAULT_CONFIG, ...userConfig };
|
|
474
|
-
const files = [];
|
|
475
|
-
for (const dir of config.scanDirs) {
|
|
476
|
-
const absDir = path3.resolve(config.cwd, dir);
|
|
477
|
-
files.push(...walkDir(absDir, config));
|
|
478
|
-
}
|
|
479
|
-
const uniqueFiles = Array.from(new Set(files));
|
|
480
|
-
if (config.verbose) {
|
|
481
|
-
console.log(`[tailwind-styled-v4] Scanning ${uniqueFiles.length} files...`);
|
|
482
|
-
}
|
|
483
|
-
const result = extractFromFiles(uniqueFiles, config);
|
|
484
|
-
writeSafelist(result, config);
|
|
485
|
-
}
|
|
486
|
-
if (__require.main === module) {
|
|
487
|
-
generateSafelist();
|
|
488
|
-
}
|
|
489
|
-
export {
|
|
490
|
-
extractAllClasses,
|
|
491
|
-
extractTwClasses,
|
|
492
|
-
generateSafelist,
|
|
493
|
-
runSafelistGeneration,
|
|
494
|
-
shouldProcess,
|
|
495
|
-
swcPlugin,
|
|
496
|
-
swcTransformFile,
|
|
497
|
-
tailwindStyledPlugin,
|
|
498
|
-
transformBatch,
|
|
499
|
-
transformSource,
|
|
500
|
-
transformTw,
|
|
501
|
-
turbopackTransform,
|
|
502
|
-
withTailwindStyled
|
|
503
|
-
};
|
|
504
|
-
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/classParser.ts","../../src/utils/hash.ts","../../src/compiler/astTransform.ts","../../src/compiler/transformTw.ts","../../src/compiler/swcPlugin.ts","../../src/compiler/vitePlugin.ts","../../src/build/generateSafelist.ts"],"sourcesContent":["/**\n * tailwind-styled-v4 — Class Parser Utilities\n */\n\n/**\n * Parse a Tailwind class string into a deduplicated sorted array.\n *\n * @example\n * parseClassString(\"p-4 bg-zinc-900 p-4\") → [\"bg-zinc-900\", \"p-4\"]\n */\nexport function parseClassString(cls: string): string[] {\n return Array.from(\n new Set(\n cls\n .split(/\\s+/)\n .map(c => c.trim())\n .filter(Boolean)\n )\n )\n}\n\n/**\n * Normalize a class string: trim, deduplicate, sort, collapse whitespace.\n *\n * @example\n * normalizeClasses(\" p-4 bg-zinc-900 p-4 \") → \"bg-zinc-900 p-4\"\n */\nexport function normalizeClasses(cls: string): string {\n return parseClassString(cls).sort().join(\" \")\n}\n\n/**\n * Split a class string into groups: base classes vs modifier classes.\n *\n * @example\n * splitModifiers(\"p-4 hover:bg-blue-500 md:p-8\")\n * → { base: [\"p-4\"], modifiers: [\"hover:bg-blue-500\", \"md:p-8\"] }\n */\nexport function splitModifiers(cls: string): {\n base: string[]\n modifiers: string[]\n} {\n const classes = parseClassString(cls)\n const base: string[] = []\n const modifiers: string[] = []\n\n for (const c of classes) {\n if (c.includes(\":\")) modifiers.push(c)\n else base.push(c)\n }\n\n return { base, modifiers }\n}\n\n/**\n * Check if a string looks like a valid Tailwind class token.\n *\n * @example\n * isValidClass(\"bg-blue-500\") → true\n * isValidClass(\"not a class\") → false\n */\nexport function isValidClass(cls: string): boolean {\n return /^!?[-a-z0-9]+(?:[:/[\\]().#,]+[-a-z0-9_]+)*$/.test(cls)\n}\n\n/**\n * Extract modifier prefix from a class.\n *\n * @example\n * getModifier(\"hover:bg-blue-500\") → \"hover\"\n * getModifier(\"md:p-4\") → \"md\"\n * getModifier(\"p-4\") → null\n */\nexport function getModifier(cls: string): string | null {\n const idx = cls.indexOf(\":\")\n return idx > -1 ? cls.slice(0, idx) : null\n}\n\n/**\n * Strip modifier prefix from a class.\n *\n * @example\n * stripModifier(\"hover:bg-blue-500\") → \"bg-blue-500\"\n * stripModifier(\"p-4\") → \"p-4\"\n */\nexport function stripModifier(cls: string): string {\n const idx = cls.indexOf(\":\")\n return idx > -1 ? cls.slice(idx + 1) : cls\n}\n\n/**\n * Group classes by their modifier prefix.\n *\n * @example\n * groupByModifier(\"p-4 hover:bg-blue-500 hover:text-white md:p-8\")\n * → { \"\": [\"p-4\"], hover: [\"bg-blue-500\", \"text-white\"], md: [\"p-8\"] }\n */\nexport function groupByModifier(cls: string): Record<string, string[]> {\n const classes = parseClassString(cls)\n const groups: Record<string, string[]> = {}\n\n for (const c of classes) {\n const mod = getModifier(c) ?? \"\"\n const base = stripModifier(c)\n if (!groups[mod]) groups[mod] = []\n groups[mod].push(base)\n }\n\n return groups\n}\n","/**\n * tailwind-styled-v4 — Deterministic Hash Utility\n *\n * Generates a short stable hash from a string.\n * Used for:\n * - data-tw attribute values in dev tools\n * - CSS @layer naming\n * - Component deduplication\n *\n * Algorithm: djb2 — fast, collision-resistant enough for our use case.\n *\n * @example\n * hashClass(\"div:p-4 bg-zinc-900\") → \"tw-3f2a1b\"\n */\n\n/**\n * djb2 hash — produces a 32-bit signed integer\n */\nfunction djb2(str: string): number {\n let hash = 5381\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) + hash) ^ str.charCodeAt(i)\n hash = hash >>> 0 // convert to unsigned 32-bit\n }\n return hash\n}\n\n/**\n * Returns a short hex hash string prefixed with \"tw-\".\n * Output is always 8 characters (tw- + 5 hex chars).\n *\n * @example\n * hashClass(\"div:p-4\") → \"tw-3f2a1\"\n * hashClass(\"button:bg-blue\") → \"tw-8c4d2\"\n */\nexport function hashClass(input: string): string {\n const n = djb2(input)\n return \"tw-\" + n.toString(16).slice(0, 5).padStart(5, \"0\")\n}\n\n/**\n * Returns a numeric hash — useful for CSS layer ordering.\n */\nexport function hashNumber(input: string): number {\n return djb2(input)\n}\n\n/**\n * Generates a stable component display name from tag + classes.\n * Used as the styled-components displayName for better DevTools experience.\n *\n * @example\n * componentName(\"div\", \"p-4 bg-zinc-900\") → \"Tw-div-3f2a1\"\n */\nexport function componentName(tag: string, classes: string): string {\n const hash = hashClass(`${tag}:${classes}`)\n const tagCap = tag.charAt(0).toUpperCase() + tag.slice(1)\n return `Tw${tagCap}-${hash.replace(\"tw-\", \"\")}`\n}\n","/**\n * tailwind-styled-v4 — AST Transform Core\n *\n * Pure-string AST-like transformer yang menganalisis source code dan\n * mengubah semua tw.tag`...` / tw.tag({...}) calls menjadi static\n * className strings (zero-runtime output).\n *\n * Dipakai oleh:\n * - swcPlugin.ts → SWC/Next.js transform\n * - vitePlugin.ts → Vite/Rollup transform\n * - nextPlugin.ts → Next.js webpack loader\n * - postcssPlugin.ts → PostCSS safelist generation\n *\n * Zero-runtime berarti output akhirnya adalah:\n * BEFORE: const Box = tw.div`p-4 bg-zinc-900`\n * AFTER: const Box = styled.div``.attrs(()=>({className:\"p-4 bg-zinc-900\"}))``)\n *\n * Untuk kasus yang pure static (tidak ada dynamic expr),\n * output bisa di-inline langsung sebagai string literal:\n * AFTER: const Box = styled.div.attrs(()=>({className:\"p-4 bg-zinc-900\"}))``)\n */\n\nimport { normalizeClasses } from \"../utils/classParser\"\nimport { hashClass } from \"../utils/hash\"\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TransformOptions {\n /**\n * \"runtime\" → keep tw.tag, resolve at runtime (default dev mode)\n * \"zero-runtime\"→ transform to styled.tag with static className\n * \"extract-only\"→ do not transform, only extract class names\n */\n mode?: \"runtime\" | \"zero-runtime\" | \"extract-only\"\n\n /** Add data-tw attribute for debugging in dev tools */\n addDataAttr?: boolean\n\n /** Generate unique stable hash per component for CSS layer naming */\n generateHash?: boolean\n\n /** Tailwind prefix (if configured in tailwind.config.ts) */\n prefix?: string\n\n /** Filename being transformed — used for source maps */\n filename?: string\n}\n\nexport interface TransformResult {\n code: string\n classes: string[]\n map?: string\n changed: boolean\n}\n\nexport interface ExtractedComponent {\n tag: string\n classes: string[]\n variants: Record<string, Record<string, string>>\n isStatic: boolean\n line: number\n col: number\n hash: string\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Regex patterns\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** tw.div`classes` */\nconst TEMPLATE_LITERAL_RE = /\\btw\\.(\\w+)`((?:[^`\\\\]|\\\\.)*)`/g\n\n/** tw.div({ base: \"...\", variants: {...} }) */\nconst OBJECT_CONFIG_RE = /\\btw\\.(\\w+)\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)/g\n\n/** tw(Component)`classes` */\nconst _WRAP_COMPONENT_RE = /\\btw\\((\\w+)\\)`((?:[^`\\\\]|\\\\.)*)`/g\n\n/** Card.extend`extra-classes` */\nconst EXTEND_CALL_RE = /(\\w+)\\.extend`((?:[^`\\\\]|\\\\.)*)`/g\n\n/** import { tw } from \"tailwind-styled-v4\" */\nconst IMPORT_RE = /import\\s*\\{[^}]*\\btw\\b[^}]*\\}\\s*from\\s*[\"']tailwind-styled-v4[\"']/\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction cleanTemplateLiteral(raw: string): string {\n return raw\n .split(\"\\n\")\n .map(l => l.trim())\n .filter(Boolean)\n .join(\" \")\n .replace(/\\s+/g, \" \")\n .trim()\n}\n\nfunction isDynamic(raw: string): boolean {\n return raw.includes(\"${\")\n}\n\nfunction extractBaseFromObjectConfig(objectStr: string): string | null {\n const baseMatch = objectStr.match(/base\\s*:\\s*[\"'`]([^\"'`]+)[\"'`]/)\n return baseMatch ? baseMatch[1].trim() : null\n}\n\nfunction extractVariantsFromObjectConfig(\n objectStr: string\n): Record<string, Record<string, string>> {\n const variants: Record<string, Record<string, string>> = {}\n\n const variantsBlockMatch = objectStr.match(/variants\\s*:\\s*\\{([\\s\\S]*?)\\}\\s*[,}]/)\n if (!variantsBlockMatch) return variants\n\n const block = variantsBlockMatch[1]\n\n // Match each variant key: { value: \"classes\", ... }\n const variantKeyRe = /(\\w+)\\s*:\\s*\\{([^}]+)\\}/g\n let km: RegExpExecArray | null\n\n while ((km = variantKeyRe.exec(block)) !== null) {\n const variantName = km[1]\n const innerBlock = km[2]\n variants[variantName] = {}\n\n const valueRe = /(\\w+)\\s*:\\s*[\"'`]([^\"'`]+)[\"'`]/g\n let vm: RegExpExecArray | null\n while ((vm = valueRe.exec(innerBlock)) !== null) {\n variants[variantName][vm[1]] = vm[2].trim()\n }\n }\n\n return variants\n}\n\nfunction buildStaticAttrs(\n classes: string,\n opts: TransformOptions,\n tag: string,\n hash?: string\n): string {\n const dataAttr = opts.addDataAttr && hash\n ? `, \"data-tw\": \"${hash}\"`\n : \"\"\n return `styled.${tag}.attrs(() => ({ className: \"${classes}\"${dataAttr} }))\\`\\``\n}\n\nfunction buildStyledTagWithVariants(\n tag: string,\n base: string,\n _variants: Record<string, Record<string, string>>,\n opts: TransformOptions\n): string {\n // For variant configs, we keep a slim runtime resolver but pre-extract base\n const dataAttr = opts.addDataAttr ? `, \"data-tw\": \"${tag}\"` : \"\"\n const normalizedBase = normalizeClasses(base)\n return `styled.${tag}.attrs((p) => ({\n className: [\n \"${normalizedBase}\",\n p.className\n ].filter(Boolean).join(\" \")${dataAttr}\n }))\\`\\``\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Main transform\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function transformSource(\n source: string,\n opts: TransformOptions = {}\n): TransformResult {\n const { mode = \"zero-runtime\", addDataAttr = false, generateHash = true } = opts\n\n // Short-circuit: if file doesn't use tw, skip\n if (!IMPORT_RE.test(source) && !source.includes(\"tw.\")) {\n return { code: source, classes: [], changed: false }\n }\n\n let code = source\n let changed = false\n const allClasses: string[] = []\n\n if (mode === \"extract-only\") {\n const classes = extractAllClasses(source)\n return { code: source, classes, changed: false }\n }\n\n if (mode === \"runtime\") {\n // In runtime mode, still extract for safelist but don't transform\n return { code: source, classes: extractAllClasses(source), changed: false }\n }\n\n // ── zero-runtime mode ───────────────────────────────────────────────────\n\n // 1. Transform tw.tag`classes` → styled.tag.attrs(...)``\n code = code.replace(\n TEMPLATE_LITERAL_RE,\n (_match, tag: string, content: string) => {\n if (isDynamic(content)) {\n // Cannot statically resolve dynamic expressions — fall through to runtime\n return _match\n }\n\n const classes = cleanTemplateLiteral(content)\n const hash = generateHash ? hashClass(`${tag}:${classes}`) : undefined\n\n allClasses.push(...classes.split(/\\s+/).filter(Boolean))\n changed = true\n\n return buildStaticAttrs(classes, { addDataAttr }, tag, hash)\n }\n )\n\n // 2. Transform tw.tag({ base, variants }) → styled.tag.attrs(...)``\n code = code.replace(\n OBJECT_CONFIG_RE,\n (_match, tag: string, objectStr: string) => {\n const base = extractBaseFromObjectConfig(objectStr)\n const variants = extractVariantsFromObjectConfig(objectStr)\n\n if (!base) return _match\n\n const baseClasses = normalizeClasses(base)\n allClasses.push(...baseClasses.split(/\\s+/).filter(Boolean))\n\n // Collect all variant classes too\n for (const vMap of Object.values(variants)) {\n for (const cls of Object.values(vMap)) {\n allClasses.push(...cls.split(/\\s+/).filter(Boolean))\n }\n }\n\n changed = true\n\n if (Object.keys(variants).length === 0) {\n const hash = generateHash ? hashClass(`${tag}:${baseClasses}`) : undefined\n return buildStaticAttrs(baseClasses, { addDataAttr }, tag, hash)\n }\n\n return buildStyledTagWithVariants(tag, baseClasses, variants, { addDataAttr })\n }\n )\n\n // 3. Transform Component.extend`classes` → Component with merged attrs\n code = code.replace(\n EXTEND_CALL_RE,\n (_match, componentName: string, content: string) => {\n if (isDynamic(content)) return _match\n\n const classes = cleanTemplateLiteral(content)\n allClasses.push(...classes.split(/\\s+/).filter(Boolean))\n changed = true\n\n return `styled(${componentName}).attrs((p) => ({\n className: [p.className, \"${classes}\"].filter(Boolean).join(\" \")\n}))\\`\\``\n }\n )\n\n // 4. Add styled import if not present\n if (changed && !source.includes(\"import styled from\")) {\n code = `import styled from \"styled-components\"\\n${code}`\n }\n\n return {\n code,\n classes: Array.from(new Set(allClasses)),\n changed,\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Class extractor (used separately for safelist generation)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function extractAllClasses(source: string): string[] {\n const classes = new Set<string>()\n\n const addClasses = (str: string) => {\n str\n .split(/\\s+/)\n .map(c => c.trim())\n .filter(c => c.length > 0 && /^[-a-z0-9:/[\\]!.]+$/.test(c))\n .forEach(c => classes.add(c))\n }\n\n // Template literals\n let m: RegExpExecArray | null\n const re1 = new RegExp(TEMPLATE_LITERAL_RE.source, \"g\")\n while ((m = re1.exec(source)) !== null) addClasses(m[2])\n\n // Object base\n const re2 = new RegExp(OBJECT_CONFIG_RE.source, \"g\")\n while ((m = re2.exec(source)) !== null) {\n const base = extractBaseFromObjectConfig(m[2])\n if (base) addClasses(base)\n\n const variants = extractVariantsFromObjectConfig(m[2])\n for (const vMap of Object.values(variants)) {\n for (const cls of Object.values(vMap)) addClasses(cls)\n }\n }\n\n // extend\n const re3 = new RegExp(EXTEND_CALL_RE.source, \"g\")\n while ((m = re3.exec(source)) !== null) addClasses(m[2])\n\n // className=\"...\"\n const classNameRe = /className\\s*=\\s*[\"']([^\"']+)[\"']/g\n while ((m = classNameRe.exec(source)) !== null) addClasses(m[1])\n\n // cn / clsx / twMerge\n const cnRe = /(?:cn|clsx|twMerge|mergeClasses)\\s*\\(([^)]+)\\)/g\n while ((m = cnRe.exec(source)) !== null) {\n const inner = m[1].replace(/[\"'`]/g, \" \")\n addClasses(inner)\n }\n\n return Array.from(classes).sort()\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Batch transform (for build plugins)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function transformBatch(\n files: Array<{ path: string; source: string }>,\n opts: TransformOptions = {}\n): {\n results: Array<TransformResult & { path: string }>\n allClasses: string[]\n} {\n const allClasses = new Set<string>()\n\n const results = files.map(({ path, source }) => {\n const result = transformSource(source, { ...opts, filename: path })\n result.classes.forEach(c => allClasses.add(c))\n return { ...result, path }\n })\n\n return {\n results,\n allClasses: Array.from(allClasses).sort(),\n }\n}\n","/**\n * tailwind-styled-v4 — transformTw\n *\n * Low-level transform used by all build plugins.\n * Wraps astTransform with file-type filtering and source-map passthrough.\n */\n\nimport { transformSource, extractAllClasses } from \"./astTransform\"\nimport type { TransformOptions, TransformResult } from \"./astTransform\"\n\nexport type { TransformOptions, TransformResult }\n\n// File extensions we process\nconst PROCESSABLE_EXTS = /\\.(tsx|ts|jsx|js|mts|mjs)$/\n\n/**\n * Transform a single file's source code.\n * Returns unchanged code for non-JS/TS files.\n */\nexport function transformTw(\n source: string,\n opts: TransformOptions & { filepath?: string } = {}\n): TransformResult {\n const { filepath = \"\" } = opts\n\n // Skip non-JS/TS files\n if (filepath && !PROCESSABLE_EXTS.test(filepath)) {\n return { code: source, classes: [], changed: false }\n }\n\n // Skip files that clearly don't use tw\n if (!source.includes(\"tw\") && !source.includes(\"tailwind-styled\")) {\n return { code: source, classes: [], changed: false }\n }\n\n return transformSource(source, opts)\n}\n\n/**\n * Extract all Tailwind classes from source without transforming.\n * Used for safelist generation.\n */\nexport function extractTwClasses(source: string): string[] {\n return extractAllClasses(source)\n}\n\n/**\n * Check whether a file should be processed by the transform.\n */\nexport function shouldProcess(filepath: string): boolean {\n if (!PROCESSABLE_EXTS.test(filepath)) return false\n if (filepath.includes(\"node_modules\")) return false\n if (filepath.includes(\".d.ts\")) return false\n return true\n}\n","/**\n * tailwind-styled-v4 — SWC Plugin / Next.js Transform\n *\n * Integrates with Next.js compiler (SWC-based) via next.config.ts.\n * Supports both Webpack and Turbopack (Next.js 15.3+).\n *\n * Usage in next.config.ts:\n * ─────────────────────────────────────────────────────────────\n * import { withTailwindStyled } from \"tailwind-styled-v4/compiler\"\n *\n * const nextConfig = withTailwindStyled({\n * mode: \"zero-runtime\",\n * addDataAttr: true,\n * generateHash: true,\n * })({\n * // ...your Next.js config\n * })\n *\n * export default nextConfig\n * ─────────────────────────────────────────────────────────────\n *\n * What it does at build time:\n * BEFORE: const Box = tw.div`p-4 bg-zinc-900 rounded-xl`\n * AFTER: const Box = styled.div.attrs(()=>({className:\"p-4 bg-zinc-900 rounded-xl\"}))`\n *\n * Turbopack support (Next.js 15.3+):\n * ─────────────────────────────────────────────────────────────\n * Turbopack does not support webpack loaders. Instead it uses\n * experimental.turbopack.rules. withTailwindStyled automatically\n * detects and configures both bundlers.\n */\n\nimport { transformTw, shouldProcess } from \"./transformTw\"\nimport type { TransformOptions } from \"./transformTw\"\nimport { extractTwClasses } from \"./transformTw\"\nimport fs from \"fs\"\nimport path from \"path\"\n\nexport interface SwcPluginOptions extends TransformOptions {\n /**\n * Directories to scan for class extraction (safelist generation).\n * Defaults to [\"src\", \"app\", \"pages\", \"components\"]\n */\n scanDirs?: string[]\n\n /**\n * Output path for generated safelist JSON.\n * Defaults to \"tailwind.safelist.json\"\n */\n safelistOutput?: string\n\n /**\n * Whether to generate the safelist file on each build.\n * Defaults to true\n */\n generateSafelist?: boolean\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Turbopack loader handler (Next.js 15.3+)\n// Called by Turbopack via experimental.turbopack.rules as a Node.js module.\n// The exported function receives { source, resourcePath } and returns { code }.\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function turbopackTransform(\n source: string,\n resourcePath: string,\n opts: TransformOptions = {}\n): { code: string } {\n if (!shouldProcess(resourcePath)) return { code: source }\n const result = transformTw(source, { ...opts, filepath: resourcePath })\n return { code: result.code }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Build Turbopack rules config\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction buildTurbopackRules(opts: TransformOptions): Record<string, any> {\n const loaderPath = require.resolve(\"./turbopackLoader\")\n const rule = {\n loaders: [\n {\n loader: loaderPath,\n options: opts,\n },\n ],\n as: \"*.tsx\",\n }\n\n return {\n \"*.{ts,tsx,js,jsx}\": rule,\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Next.js higher-order config wrapper\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function withTailwindStyled(pluginOpts: SwcPluginOptions = {}) {\n const {\n mode = process.env.NODE_ENV === \"production\" ? \"zero-runtime\" : \"runtime\",\n addDataAttr = process.env.NODE_ENV !== \"production\",\n generateHash = true,\n generateSafelist = true,\n safelistOutput = \"tailwind.safelist.json\",\n scanDirs = [\"src\", \"app\", \"pages\", \"components\"],\n ...transformOpts\n } = pluginOpts\n\n const loaderOpts: TransformOptions = { mode, addDataAttr, generateHash, ...transformOpts }\n\n return function (nextConfig: Record<string, any> = {}) {\n // ── Turbopack rules (Next.js 15.3+) ─────────────────────────────────\n const existingTurbopack = nextConfig.experimental?.turbopack ?? {}\n const existingRules = existingTurbopack.rules ?? {}\n const turboRules = buildTurbopackRules(loaderOpts)\n\n const merged: Record<string, any> = {\n ...nextConfig,\n\n experimental: {\n ...nextConfig.experimental,\n turbopack: {\n ...existingTurbopack,\n rules: {\n ...existingRules,\n ...turboRules,\n },\n },\n },\n\n // ── Webpack (fallback for non-turbopack builds) ──────────────────\n webpack(webpackConfig: any, context: any) {\n webpackConfig.module.rules.push({\n test: /\\.(tsx|ts|jsx|js)$/,\n exclude: /node_modules/,\n use: [\n {\n loader: require.resolve(\"./webpackLoader\"),\n options: loaderOpts,\n },\n ],\n })\n\n if (generateSafelist && !context.dev) {\n runSafelistGeneration({\n scanDirs,\n outputPath: safelistOutput,\n cwd: context.dir ?? process.cwd(),\n })\n }\n\n if (typeof nextConfig.webpack === \"function\") {\n return nextConfig.webpack(webpackConfig, context)\n }\n\n return webpackConfig\n },\n }\n\n return merged\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Standalone file transform (used by webpack loader + CLI)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function swcTransformFile(\n source: string,\n filepath: string,\n opts: TransformOptions = {}\n): string {\n if (!shouldProcess(filepath)) return source\n\n const result = transformTw(source, { ...opts, filepath })\n return result.code\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Safelist generation\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface SafelistOptions {\n scanDirs: string[]\n outputPath: string\n cwd: string\n}\n\nfunction scanDirectory(dir: string): string[] {\n if (!fs.existsSync(dir)) return []\n\n const results: string[] = []\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name)\n if (entry.isDirectory()) {\n if (![\"node_modules\", \".next\", \".git\", \"dist\"].includes(entry.name)) {\n results.push(...scanDirectory(fullPath))\n }\n } else if (/\\.(tsx|ts|jsx|js)$/.test(entry.name)) {\n results.push(fullPath)\n }\n }\n\n return results\n}\n\nexport function runSafelistGeneration(opts: SafelistOptions): void {\n const { scanDirs, outputPath, cwd } = opts\n\n const allClasses = new Set<string>()\n\n for (const dir of scanDirs) {\n const absDir = path.resolve(cwd, dir)\n const files = scanDirectory(absDir)\n\n for (const file of files) {\n try {\n const source = fs.readFileSync(file, \"utf-8\")\n const classes = extractTwClasses(source)\n classes.forEach(c => allClasses.add(c))\n } catch {\n // Skip unreadable files\n }\n }\n }\n\n const sorted = Array.from(allClasses).sort()\n const absOutput = path.resolve(cwd, outputPath)\n\n fs.writeFileSync(\n absOutput,\n JSON.stringify({ safelist: sorted, count: sorted.length, generatedAt: new Date().toISOString() }, null, 2)\n )\n\n console.log(`[tailwind-styled-v4] ✓ Safelist: ${sorted.length} classes → ${absOutput}`)\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Direct transform function (backward compat + testing)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function swcPlugin(source: string, opts: TransformOptions = {}): string {\n const result = transformTw(source, opts)\n return result.code\n}\n","/**\n * tailwind-styled-v4 — Vite Plugin\n *\n * Usage in vite.config.ts:\n * ─────────────────────────────────────────────────────────────\n * import { tailwindStyledPlugin } from \"tailwind-styled-v4/compiler\"\n *\n * export default defineConfig({\n * plugins: [\n * react(),\n * tailwindStyledPlugin({\n * mode: \"zero-runtime\",\n * addDataAttr: true,\n * }),\n * ],\n * })\n * ─────────────────────────────────────────────────────────────\n *\n * Compatible with: Vite 4+, Remix, SvelteKit (JS files only)\n */\n\nimport { transformTw, shouldProcess } from \"./transformTw\"\nimport type { TransformOptions } from \"./transformTw\"\nimport { runSafelistGeneration } from \"./swcPlugin\"\nimport path from \"path\"\n\nexport interface VitePluginOptions extends TransformOptions {\n /** Include patterns. Default: all .tsx/.ts/.jsx/.js */\n include?: RegExp\n /** Exclude patterns. Default: node_modules */\n exclude?: RegExp\n /** Directories to scan for safelist generation */\n scanDirs?: string[]\n /** Output path for safelist JSON */\n safelistOutput?: string\n /** Generate safelist on build end */\n generateSafelist?: boolean\n}\n\nexport function tailwindStyledPlugin(opts: VitePluginOptions = {}): any {\n const {\n include = /\\.(tsx|ts|jsx|js)$/,\n exclude = /node_modules/,\n scanDirs = [\"src\"],\n safelistOutput = \"tailwind.safelist.json\",\n generateSafelist = true,\n mode,\n ...transformOpts\n } = opts\n\n let root = process.cwd()\n let isDev = true\n let resolvedMode: TransformOptions[\"mode\"]\n\n return {\n name: \"tailwind-styled-v4\",\n enforce: \"pre\" as const,\n\n configResolved(config: any) {\n root = config.root\n isDev = config.command === \"serve\"\n resolvedMode = mode ?? (isDev ? \"runtime\" : \"zero-runtime\")\n },\n\n transform(source: string, id: string) {\n // Strip query strings (e.g. ?t=timestamp from Vite HMR)\n const filepath = id.split(\"?\")[0]\n\n if (!include.test(filepath)) return null\n if (exclude.test(filepath)) return null\n if (!shouldProcess(filepath)) return null\n\n const result = transformTw(source, {\n ...transformOpts,\n mode: resolvedMode,\n filename: filepath,\n addDataAttr: transformOpts.addDataAttr ?? isDev,\n })\n\n if (!result.changed) return null\n\n return {\n code: result.code,\n map: null, // source maps: future enhancement\n }\n },\n\n buildEnd() {\n if (!generateSafelist || isDev) return\n\n runSafelistGeneration({\n scanDirs: scanDirs.map(d => path.resolve(root, d)),\n outputPath: path.resolve(root, safelistOutput),\n cwd: root,\n })\n },\n\n // HMR: re-transform on save\n handleHotUpdate({ file, server }: any) {\n if (!include.test(file)) return\n server.ws.send({ type: \"full-reload\" })\n },\n }\n}\n","/**\n * tailwind-styled-v4 — Safelist Generator\n *\n * Scans your entire src/ directory and extracts every Tailwind class\n * used via tw.tag`...`, className=\"...\", cn(), etc.\n *\n * The output JSON can be referenced in your tailwind.config.ts:\n *\n * ─────────────────────────────────────────────────────────────\n * // tailwind.config.ts\n * import safelist from \"./tailwind.safelist.json\"\n *\n * export default {\n * safelist: safelist.safelist,\n * // ...\n * }\n * ─────────────────────────────────────────────────────────────\n *\n * Run manually: npx ts-node src/build/generateSafelist.ts\n * Or via script: npm run build:safelist\n */\n\nimport fs from \"fs\"\nimport path from \"path\"\nimport { extractAllClasses } from \"../compiler/astTransform\"\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Config\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface SafelistConfig {\n /** Root directory of your project */\n cwd: string\n /** Directories to scan (relative to cwd) */\n scanDirs: string[]\n /** File extensions to scan */\n extensions: RegExp\n /** Directories to skip */\n excludeDirs: string[]\n /** Output file path (relative to cwd) */\n outputPath: string\n /** Include Tailwind pattern annotations in output */\n verbose: boolean\n}\n\nconst DEFAULT_CONFIG: SafelistConfig = {\n cwd: process.cwd(),\n scanDirs: [\"src\", \"app\", \"pages\", \"components\", \"features\", \"lib\"],\n extensions: /\\.(tsx|ts|jsx|js|mdx|md)$/,\n excludeDirs: [\"node_modules\", \".next\", \".git\", \"dist\", \"build\", \".turbo\", \"coverage\"],\n outputPath: \"tailwind.safelist.json\",\n verbose: true,\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// File scanner\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction walkDir(dir: string, config: SafelistConfig): string[] {\n if (!fs.existsSync(dir)) return []\n\n const results: string[] = []\n\n try {\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n if (config.excludeDirs.includes(entry.name)) continue\n\n const fullPath = path.join(dir, entry.name)\n\n if (entry.isDirectory()) {\n results.push(...walkDir(fullPath, config))\n } else if (config.extensions.test(entry.name)) {\n results.push(fullPath)\n }\n }\n } catch {\n // Skip unreadable directories\n }\n\n return results\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Class extraction\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface ExtractionResult {\n classes: string[]\n fileCount: number\n errorCount: number\n byFile: Record<string, string[]>\n}\n\nfunction extractFromFiles(\n files: string[],\n config: SafelistConfig\n): ExtractionResult {\n const allClasses = new Set<string>()\n const byFile: Record<string, string[]> = {}\n let errorCount = 0\n\n for (const file of files) {\n try {\n const source = fs.readFileSync(file, \"utf-8\")\n const classes = extractAllClasses(source)\n\n if (classes.length > 0) {\n classes.forEach(c => allClasses.add(c))\n const relPath = path.relative(config.cwd, file)\n byFile[relPath] = classes\n }\n } catch {\n errorCount++\n }\n }\n\n return {\n classes: Array.from(allClasses).sort(),\n fileCount: files.length,\n errorCount,\n byFile,\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Output writers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction writeSafelist(result: ExtractionResult, config: SafelistConfig): void {\n const absOutput = path.resolve(config.cwd, config.outputPath)\n\n const output = {\n safelist: result.classes,\n count: result.classes.length,\n fileCount: result.fileCount,\n generatedAt: new Date().toISOString(),\n generator: \"tailwind-styled-v4\",\n ...(config.verbose ? { byFile: result.byFile } : {}),\n }\n\n fs.writeFileSync(absOutput, JSON.stringify(output, null, 2))\n\n if (config.verbose) {\n console.log(`[tailwind-styled-v4] ✓ Safelist generated`)\n console.log(` Classes: ${result.classes.length.toLocaleString()}`)\n console.log(` Files: ${result.fileCount}`)\n console.log(` Errors: ${result.errorCount}`)\n console.log(` Output: ${absOutput}`)\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Main\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function generateSafelist(userConfig: Partial<SafelistConfig> = {}): void {\n const config = { ...DEFAULT_CONFIG, ...userConfig }\n\n // Scan all configured directories\n const files: string[] = []\n for (const dir of config.scanDirs) {\n const absDir = path.resolve(config.cwd, dir)\n files.push(...walkDir(absDir, config))\n }\n\n // Deduplicate file list\n const uniqueFiles = Array.from(new Set(files))\n\n if (config.verbose) {\n console.log(`[tailwind-styled-v4] Scanning ${uniqueFiles.length} files...`)\n }\n\n const result = extractFromFiles(uniqueFiles, config)\n writeSafelist(result, config)\n}\n\n// Run when called directly (ts-node src/build/generateSafelist.ts)\nif (require.main === module) {\n generateSafelist()\n}\n"],"mappings":"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","names":["path","generateSafelist","path","generateSafelist","fs","path","fs","path"]}
|