@weapp-tailwindcss/engine 0.1.0 → 0.1.1
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/{index-BKLDGE3a.d.cts → index-BnvpPg0y.d.cts} +16 -13
- package/dist/{index-CJQBHKch.d.ts → index-CHGSHPWB.d.ts} +17 -14
- package/dist/index.cjs +53 -99
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -87
- package/dist/v4/index.cjs +50 -9
- package/dist/v4/index.d.cts +1 -1
- package/dist/v4/index.d.ts +1 -1
- package/dist/v4/index.js +1 -1
- package/dist/{v4-BdeIFyye.js → v4-D46xWjyQ.js} +343 -243
- package/dist/{v4-CUw9Iuc5.cjs → v4-DVqsqn8b.cjs} +349 -304
- package/package.json +2 -2
|
@@ -1,11 +1,173 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
import { promises,
|
|
1
|
+
import { createRequire, findPackageJSON } from "node:module";
|
|
2
|
+
import { promises, readFileSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import process from "node:process";
|
|
5
|
-
import { pathToFileURL } from "node:url";
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
import { clearRequireCache } from "@tailwindcss/node/require-cache";
|
|
9
|
+
import { createSourceScanPlan, expandSourceEntries as expandTailwindV4SourceEntries, expandSourceEntryBraces, expandSourceEntryBraces as expandTailwindV4SourceEntryBraces, groupSourceEntriesByBase as groupTailwindV4SourceEntriesByBase, isFileExcludedByTailwindSourceEntries, isFileExcludedByTailwindSourceEntries as isFileExcludedByTailwindV4SourceEntries, isFileMatchedByTailwindSourceEntries, mergeSourceEntries as mergeTailwindV4SourceEntries, normalizeGlobPattern, resolveSourceScanPath, resolveSourceScanPath as resolveSourceScanPath$1, resolveTailwindSourceEntry, toPosixPath } from "@weapp-tailwindcss/source-scan";
|
|
8
10
|
import postcss from "postcss";
|
|
11
|
+
import { readFile } from "node:fs/promises";
|
|
12
|
+
//#region src/v4/module-cache.ts
|
|
13
|
+
const context = new AsyncLocalStorage();
|
|
14
|
+
const caches = /* @__PURE__ */ new WeakMap();
|
|
15
|
+
let revision = 0;
|
|
16
|
+
const hooks = globalThis;
|
|
17
|
+
let installedHook;
|
|
18
|
+
let activeContexts = 0;
|
|
19
|
+
const MODULE_CACHE_LIMIT = 128;
|
|
20
|
+
const require = createRequire(import.meta.url);
|
|
21
|
+
function canUseCommonJsGraph(file) {
|
|
22
|
+
const extension = path.extname(file);
|
|
23
|
+
if (extension === ".cjs" || extension === ".cts") return true;
|
|
24
|
+
if (extension !== ".js") return false;
|
|
25
|
+
const manifest = findPackageJSON(pathToFileURL(file).href);
|
|
26
|
+
return !manifest || path.basename(manifest) !== "package.json" || JSON.parse(readFileSync(manifest, "utf8")).type !== "module";
|
|
27
|
+
}
|
|
28
|
+
function collectCommonJsDependencies(file, dependencies) {
|
|
29
|
+
const module = require.cache[file];
|
|
30
|
+
if (!module?.loaded) return false;
|
|
31
|
+
const visited = /* @__PURE__ */ new Set();
|
|
32
|
+
const packageRoot = path.dirname(findPackageJSON(pathToFileURL(file).href) ?? file);
|
|
33
|
+
function visit(current) {
|
|
34
|
+
if (visited.has(current) || !current.filename) return;
|
|
35
|
+
visited.add(current);
|
|
36
|
+
let directory = path.dirname(current.filename);
|
|
37
|
+
const relative = path.relative(packageRoot, current.filename);
|
|
38
|
+
while (path.dirname(directory) !== directory) {
|
|
39
|
+
if (path.basename(directory) === "node_modules" && (relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))) return;
|
|
40
|
+
directory = path.dirname(directory);
|
|
41
|
+
}
|
|
42
|
+
dependencies.add(current.filename);
|
|
43
|
+
for (const child of current.children) visit(child);
|
|
44
|
+
}
|
|
45
|
+
visit(module);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
function fingerprint(files) {
|
|
49
|
+
const hash = createHash("sha256");
|
|
50
|
+
for (const file of files) {
|
|
51
|
+
hash.update(file);
|
|
52
|
+
hash.update(readFileSync(file));
|
|
53
|
+
}
|
|
54
|
+
return hash.digest("hex");
|
|
55
|
+
}
|
|
56
|
+
async function loadCachedModule(loader, file) {
|
|
57
|
+
let state = caches.get(loader);
|
|
58
|
+
if (!state || state.revision !== revision) {
|
|
59
|
+
state = {
|
|
60
|
+
revision,
|
|
61
|
+
entries: /* @__PURE__ */ new Map()
|
|
62
|
+
};
|
|
63
|
+
caches.set(loader, state);
|
|
64
|
+
}
|
|
65
|
+
const cache = state.entries;
|
|
66
|
+
const previous = cache.get(file);
|
|
67
|
+
if (previous) {
|
|
68
|
+
const entry = await previous;
|
|
69
|
+
try {
|
|
70
|
+
if (fingerprint(entry.dependencies) === entry.fingerprint) return entry;
|
|
71
|
+
} catch {}
|
|
72
|
+
if (cache.get(file) !== previous) return loadCachedModule(loader, file);
|
|
73
|
+
clearRequireCache(entry.dependencies);
|
|
74
|
+
}
|
|
75
|
+
const pending = context.run(void 0, async () => {
|
|
76
|
+
const dependencies = /* @__PURE__ */ new Set([file]);
|
|
77
|
+
const base = path.dirname(file);
|
|
78
|
+
const onDependency = (dependency) => {
|
|
79
|
+
dependencies.add(dependency);
|
|
80
|
+
};
|
|
81
|
+
let loaded = previous || !canUseCommonJsGraph(file) ? void 0 : await loader.loadModule(file, base, onDependency);
|
|
82
|
+
if (!loaded || !collectCommonJsDependencies(file, dependencies)) loaded = await loader.loadModule(`./${path.basename(file)}`, base, onDependency);
|
|
83
|
+
const files = [...dependencies].sort();
|
|
84
|
+
return {
|
|
85
|
+
dependencies: files,
|
|
86
|
+
fingerprint: fingerprint(files),
|
|
87
|
+
value: { default: loaded.module }
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
cache.set(file, pending);
|
|
91
|
+
while (cache.size > MODULE_CACHE_LIMIT) cache.delete(cache.keys().next().value);
|
|
92
|
+
try {
|
|
93
|
+
return await pending;
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (cache.get(file) === pending) cache.delete(file);
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function installHook() {
|
|
100
|
+
if (installedHook && hooks.__tw_load === installedHook) return;
|
|
101
|
+
const previous = hooks.__tw_load;
|
|
102
|
+
installedHook = async (url) => {
|
|
103
|
+
const overridden = await previous?.(url);
|
|
104
|
+
if (overridden) return overridden;
|
|
105
|
+
const active = context.getStore();
|
|
106
|
+
if (!active?.loader.loadModule || !url.startsWith("file:")) return;
|
|
107
|
+
const parsed = new URL(url);
|
|
108
|
+
const file = resolveSourceScanPath(fileURLToPath(parsed));
|
|
109
|
+
if (!parsed.searchParams.has("id") && !active.files.has(file)) return;
|
|
110
|
+
const entry = await loadCachedModule(active.loader, file);
|
|
111
|
+
for (const dependency of entry.dependencies) active.onDependency?.(dependency);
|
|
112
|
+
return entry.value;
|
|
113
|
+
};
|
|
114
|
+
hooks.__tw_load = installedHook;
|
|
115
|
+
}
|
|
116
|
+
function invalidateGenerationModuleCache() {
|
|
117
|
+
revision += 1;
|
|
118
|
+
}
|
|
119
|
+
/** 仅在本引擎调用内复用本地模块;Tailwind 仍负责解析与依赖跟踪。 */
|
|
120
|
+
async function withGenerationModuleCache(loader, run, files = [], onDependency) {
|
|
121
|
+
installHook();
|
|
122
|
+
const resolved = files.map((file) => {
|
|
123
|
+
for (const candidate of [
|
|
124
|
+
file,
|
|
125
|
+
`${file}.ts`,
|
|
126
|
+
path.join(file, "index.ts")
|
|
127
|
+
]) try {
|
|
128
|
+
return resolveSourceScanPath(require.resolve(candidate));
|
|
129
|
+
} catch {}
|
|
130
|
+
return resolveSourceScanPath(file);
|
|
131
|
+
});
|
|
132
|
+
activeContexts += 1;
|
|
133
|
+
try {
|
|
134
|
+
return await context.run({
|
|
135
|
+
loader,
|
|
136
|
+
files: new Set(resolved),
|
|
137
|
+
onDependency
|
|
138
|
+
}, run);
|
|
139
|
+
} finally {
|
|
140
|
+
activeContexts -= 1;
|
|
141
|
+
if (activeContexts === 0) context.disable();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
//#region src/v4/module-requests.ts
|
|
146
|
+
/** 固定本地模块身份,依赖跟踪与刷新由生成模块缓存负责。 */
|
|
147
|
+
function prepareGenerationModuleRequests(css, base) {
|
|
148
|
+
const files = [];
|
|
149
|
+
if (!css.includes("@config") && !css.includes("@plugin")) return {
|
|
150
|
+
css,
|
|
151
|
+
files
|
|
152
|
+
};
|
|
153
|
+
const root = postcss.parse(css);
|
|
154
|
+
root.walkAtRules((rule) => {
|
|
155
|
+
if (rule.name !== "config" && rule.name !== "plugin") return;
|
|
156
|
+
const match = /^(["'])(.*)\1$/.exec(rule.params.trim());
|
|
157
|
+
if (!match) return;
|
|
158
|
+
const request = match[2];
|
|
159
|
+
const pathApi = /^[a-z]:[\\/]/i.test(base) || base.includes("\\") ? path.win32 : path;
|
|
160
|
+
if (!pathApi.isAbsolute(request) && !request.startsWith(".")) return;
|
|
161
|
+
const file = pathApi.resolve(base, request);
|
|
162
|
+
files.push(file);
|
|
163
|
+
rule.params = JSON.stringify(file.replaceAll("\\", "/"));
|
|
164
|
+
});
|
|
165
|
+
return {
|
|
166
|
+
css: root.toString(),
|
|
167
|
+
files
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//#endregion
|
|
9
171
|
//#region src/v4/node-adapter.ts
|
|
10
172
|
const nodeModulePromiseCache = /* @__PURE__ */ new Map();
|
|
11
173
|
const designSystemPromiseCache = /* @__PURE__ */ new Map();
|
|
@@ -86,7 +248,8 @@ async function createTailwindV4DesignSystem(source) {
|
|
|
86
248
|
const node = await loadTailwindV4NodeModule([source.projectRoot, ...bases]);
|
|
87
249
|
let lastError;
|
|
88
250
|
for (const base of bases) try {
|
|
89
|
-
|
|
251
|
+
const prepared = prepareGenerationModuleRequests(source.css, base);
|
|
252
|
+
return await withGenerationModuleCache(node, () => node.__unstable__loadDesignSystem(prepared.css, { base }), prepared.files);
|
|
90
253
|
} catch (error) {
|
|
91
254
|
lastError = error;
|
|
92
255
|
}
|
|
@@ -113,14 +276,14 @@ async function compileTailwindV4Source(source) {
|
|
|
113
276
|
for (const base of bases) {
|
|
114
277
|
const dependencies = new Set(source.dependencies);
|
|
115
278
|
try {
|
|
279
|
+
const prepared = prepareGenerationModuleRequests(source.css, base);
|
|
280
|
+
const onDependency = (dependency) => dependencies.add(path.resolve(dependency));
|
|
116
281
|
return {
|
|
117
|
-
compiled: await node.compile(
|
|
282
|
+
compiled: await withGenerationModuleCache(node, () => node.compile(prepared.css, {
|
|
118
283
|
base,
|
|
119
284
|
customCssResolver: createFallbackCssResolver([source.projectRoot, ...bases]),
|
|
120
|
-
onDependency
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
}),
|
|
285
|
+
onDependency
|
|
286
|
+
}), prepared.files, onDependency),
|
|
124
287
|
dependencies
|
|
125
288
|
};
|
|
126
289
|
} catch (error) {
|
|
@@ -131,6 +294,17 @@ async function compileTailwindV4Source(source) {
|
|
|
131
294
|
throw new Error("Failed to compile Tailwind CSS v4 source.");
|
|
132
295
|
}
|
|
133
296
|
//#endregion
|
|
297
|
+
//#region src/v4/source-scan/matcher.ts
|
|
298
|
+
function isFileMatchedByTailwindV4SourceEntries(file, entries) {
|
|
299
|
+
return isFileMatchedByTailwindSourceEntries(file, entries, { requirePositive: true });
|
|
300
|
+
}
|
|
301
|
+
function createTailwindV4SourceEntryMatcher(entries) {
|
|
302
|
+
return entries?.length ? (file) => isFileMatchedByTailwindV4SourceEntries(file, entries) : void 0;
|
|
303
|
+
}
|
|
304
|
+
function createTailwindV4SourceExclusionMatcher(entries) {
|
|
305
|
+
return entries?.length ? (file) => isFileExcludedByTailwindSourceEntries(file, entries) : void 0;
|
|
306
|
+
}
|
|
307
|
+
//#endregion
|
|
134
308
|
//#region src/v4/source-scan/sources.ts
|
|
135
309
|
const TAILWIND_V4_IGNORED_CONTENT_DIRS = [
|
|
136
310
|
".git",
|
|
@@ -175,48 +349,6 @@ function uniqueResolvedPaths(values) {
|
|
|
175
349
|
}
|
|
176
350
|
return result;
|
|
177
351
|
}
|
|
178
|
-
function toPosixPath(value) {
|
|
179
|
-
return value.replaceAll(path.sep, "/");
|
|
180
|
-
}
|
|
181
|
-
function resolveSourceScanPath(value) {
|
|
182
|
-
const resolved = path.resolve(value);
|
|
183
|
-
try {
|
|
184
|
-
return realpathSync.native(resolved);
|
|
185
|
-
} catch {
|
|
186
|
-
return resolved;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
function normalizeGlobPattern(pattern) {
|
|
190
|
-
return pattern.startsWith("./") ? pattern.slice(2) : pattern;
|
|
191
|
-
}
|
|
192
|
-
function hasGlobMagic(value) {
|
|
193
|
-
return /[*?[\]{}()!+@]/.test(value);
|
|
194
|
-
}
|
|
195
|
-
function splitStaticGlobPrefix(pattern) {
|
|
196
|
-
const segments = normalizeGlobPattern(pattern).split(/[\\/]+/);
|
|
197
|
-
const prefix = [];
|
|
198
|
-
const rest = [];
|
|
199
|
-
let reachedGlob = false;
|
|
200
|
-
for (const segment of segments) {
|
|
201
|
-
if (!reachedGlob && segment && !hasGlobMagic(segment)) {
|
|
202
|
-
prefix.push(segment);
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
reachedGlob = true;
|
|
206
|
-
rest.push(segment);
|
|
207
|
-
}
|
|
208
|
-
return {
|
|
209
|
-
prefix,
|
|
210
|
-
rest
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
async function pathExistsAsDirectory(file) {
|
|
214
|
-
try {
|
|
215
|
-
return (await stat(file)).isDirectory();
|
|
216
|
-
} catch {
|
|
217
|
-
return false;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
352
|
function createTailwindV4DefaultIgnoreSources(base) {
|
|
221
353
|
return [
|
|
222
354
|
...TAILWIND_V4_IGNORED_CONTENT_DIRS.map((pattern) => ({
|
|
@@ -237,117 +369,32 @@ function createTailwindV4DefaultIgnoreSources(base) {
|
|
|
237
369
|
];
|
|
238
370
|
}
|
|
239
371
|
function createTailwindV4RootSources(root, fallbackBase) {
|
|
240
|
-
|
|
241
|
-
if (root === null) return [{
|
|
372
|
+
return createSourceScanPlan({
|
|
242
373
|
base: fallbackBase,
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}];
|
|
374
|
+
mode: root === "none" ? "disabled" : root === null ? "auto" : "explicit",
|
|
375
|
+
entries: root && root !== "none" ? [{
|
|
376
|
+
...root,
|
|
377
|
+
negated: false
|
|
378
|
+
}] : []
|
|
379
|
+
});
|
|
250
380
|
}
|
|
251
381
|
function createTailwindV4CompiledSourceEntries(root, sources, fallbackBase) {
|
|
252
382
|
return [...createTailwindV4RootSources(root, fallbackBase), ...sources];
|
|
253
383
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (await pathExistsAsDirectory(absoluteSource)) return {
|
|
257
|
-
base: absoluteSource,
|
|
258
|
-
negated,
|
|
259
|
-
pattern: normalizeGlobPattern(defaultPattern)
|
|
260
|
-
};
|
|
261
|
-
if (path.isAbsolute(sourcePath)) return {
|
|
262
|
-
base: path.dirname(absoluteSource),
|
|
263
|
-
negated,
|
|
264
|
-
pattern: normalizeGlobPattern(path.basename(absoluteSource))
|
|
265
|
-
};
|
|
266
|
-
const { prefix, rest } = splitStaticGlobPrefix(sourcePath);
|
|
267
|
-
if (prefix.length > 0 && rest.length > 0) return {
|
|
268
|
-
base: path.resolve(base, ...prefix),
|
|
269
|
-
negated,
|
|
270
|
-
pattern: normalizeGlobPattern(rest.join("/"))
|
|
271
|
-
};
|
|
272
|
-
return {
|
|
273
|
-
base,
|
|
274
|
-
negated,
|
|
275
|
-
pattern: normalizeGlobPattern(sourcePath)
|
|
276
|
-
};
|
|
384
|
+
function resolveTailwindV4SourceEntry(sourcePath, base, negated, defaultPattern = TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN) {
|
|
385
|
+
return resolveTailwindSourceEntry(sourcePath, base, negated, defaultPattern);
|
|
277
386
|
}
|
|
278
387
|
async function normalizeTailwindV4SourceEntries(sources, options = {}) {
|
|
279
388
|
const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd();
|
|
280
389
|
return Promise.all(sources.map((source) => resolveTailwindV4SourceEntry(source.pattern, source.base ? path.resolve(source.base) : cwd, source.negated, options.defaultPattern)));
|
|
281
390
|
}
|
|
282
|
-
function expandBracePattern(pattern) {
|
|
283
|
-
const index = pattern.indexOf("{");
|
|
284
|
-
if (index === -1) return [pattern];
|
|
285
|
-
const rest = pattern.slice(index);
|
|
286
|
-
let depth = 0;
|
|
287
|
-
let endIndex = -1;
|
|
288
|
-
for (let i = 0; i < rest.length; i++) {
|
|
289
|
-
const char = rest[i];
|
|
290
|
-
if (char === "\\") {
|
|
291
|
-
i += 1;
|
|
292
|
-
continue;
|
|
293
|
-
}
|
|
294
|
-
if (char === "{") {
|
|
295
|
-
depth += 1;
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
if (char === "}") {
|
|
299
|
-
depth -= 1;
|
|
300
|
-
if (depth === 0) {
|
|
301
|
-
endIndex = i;
|
|
302
|
-
break;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
if (endIndex === -1) return [pattern];
|
|
307
|
-
const prefix = pattern.slice(0, index);
|
|
308
|
-
const inner = rest.slice(1, endIndex);
|
|
309
|
-
const suffix = rest.slice(endIndex + 1);
|
|
310
|
-
const parts = [];
|
|
311
|
-
const stack = [];
|
|
312
|
-
let lastPos = 0;
|
|
313
|
-
for (let i = 0; i < inner.length; i++) {
|
|
314
|
-
const char = inner[i];
|
|
315
|
-
if (char === "\\") {
|
|
316
|
-
i += 1;
|
|
317
|
-
continue;
|
|
318
|
-
}
|
|
319
|
-
if (char === "{") {
|
|
320
|
-
stack.push("}");
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
|
-
if (char === "}" && stack[stack.length - 1] === "}") {
|
|
324
|
-
stack.pop();
|
|
325
|
-
continue;
|
|
326
|
-
}
|
|
327
|
-
if (char === "," && stack.length === 0) {
|
|
328
|
-
parts.push(inner.slice(lastPos, i));
|
|
329
|
-
lastPos = i + 1;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
parts.push(inner.slice(lastPos));
|
|
333
|
-
return parts.flatMap((part) => expandBracePattern(`${prefix}${part}${suffix}`));
|
|
334
|
-
}
|
|
335
|
-
function expandTailwindV4SourceEntryBraces(sources) {
|
|
336
|
-
return sources.flatMap((source) => {
|
|
337
|
-
const base = path.resolve(source.base);
|
|
338
|
-
return expandBracePattern(source.pattern).map((pattern) => ({
|
|
339
|
-
base,
|
|
340
|
-
pattern,
|
|
341
|
-
negated: source.negated
|
|
342
|
-
}));
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
391
|
function normalizeTailwindV4ScannerSources(sources, cwd, ignoredSources = []) {
|
|
346
|
-
|
|
392
|
+
const baseSources = sources?.length ? sources : [{
|
|
347
393
|
base: cwd,
|
|
348
394
|
pattern: TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN,
|
|
349
395
|
negated: false
|
|
350
|
-
}]
|
|
396
|
+
}];
|
|
397
|
+
return expandSourceEntryBraces([...baseSources, ...ignoredSources]);
|
|
351
398
|
}
|
|
352
399
|
function resolveTailwindV4SourceBaseCandidates(projectRoot, base, baseFallbacks) {
|
|
353
400
|
return uniqueResolvedPaths([
|
|
@@ -357,79 +404,6 @@ function resolveTailwindV4SourceBaseCandidates(projectRoot, base, baseFallbacks)
|
|
|
357
404
|
]);
|
|
358
405
|
}
|
|
359
406
|
//#endregion
|
|
360
|
-
//#region src/v4/source-scan/matcher.ts
|
|
361
|
-
function normalizeEntryPattern(entry) {
|
|
362
|
-
return path.isAbsolute(entry.pattern) ? toPosixPath(path.relative(resolveSourceScanPath(entry.base), entry.pattern)) : normalizeGlobPattern(entry.pattern);
|
|
363
|
-
}
|
|
364
|
-
function isFileMatchedByTailwindV4SourceEntry(file, entry) {
|
|
365
|
-
const relative = toPosixPath(path.relative(resolveSourceScanPath(entry.base), file));
|
|
366
|
-
return Boolean(relative) && !relative.startsWith("../") && !path.isAbsolute(relative) && micromatch.isMatch(relative, normalizeEntryPattern(entry));
|
|
367
|
-
}
|
|
368
|
-
function isFileExcludedByTailwindV4SourceEntries(file, entries) {
|
|
369
|
-
if (!entries?.length) return false;
|
|
370
|
-
const resolvedFile = resolveSourceScanPath(file);
|
|
371
|
-
return entries.some((entry) => entry.negated && isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry));
|
|
372
|
-
}
|
|
373
|
-
function isFileMatchedByTailwindV4SourceEntries(file, entries) {
|
|
374
|
-
if (!entries?.length) return true;
|
|
375
|
-
const positiveEntries = entries.filter((entry) => !entry.negated);
|
|
376
|
-
const negativeEntries = entries.filter((entry) => entry.negated);
|
|
377
|
-
if (positiveEntries.length === 0) return false;
|
|
378
|
-
const resolvedFile = resolveSourceScanPath(file);
|
|
379
|
-
if (!positiveEntries.some((entry) => isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry))) return false;
|
|
380
|
-
return !negativeEntries.some((entry) => isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry));
|
|
381
|
-
}
|
|
382
|
-
function createTailwindV4SourceEntryMatcher(entries) {
|
|
383
|
-
if (!entries?.length) return;
|
|
384
|
-
return (file) => isFileMatchedByTailwindV4SourceEntries(file, entries);
|
|
385
|
-
}
|
|
386
|
-
function createTailwindV4SourceExclusionMatcher(entries) {
|
|
387
|
-
if (!entries?.length) return;
|
|
388
|
-
return (file) => isFileExcludedByTailwindV4SourceEntries(file, entries);
|
|
389
|
-
}
|
|
390
|
-
function groupTailwindV4SourceEntriesByBase(entries) {
|
|
391
|
-
const entriesByBase = /* @__PURE__ */ new Map();
|
|
392
|
-
for (const entry of entries) {
|
|
393
|
-
const base = path.resolve(entry.base);
|
|
394
|
-
const group = entriesByBase.get(base) ?? [];
|
|
395
|
-
group.push({
|
|
396
|
-
...entry,
|
|
397
|
-
base,
|
|
398
|
-
pattern: normalizeGlobPattern(entry.pattern)
|
|
399
|
-
});
|
|
400
|
-
entriesByBase.set(base, group);
|
|
401
|
-
}
|
|
402
|
-
return entriesByBase;
|
|
403
|
-
}
|
|
404
|
-
async function expandTailwindV4SourceEntries(entries, resolveFiles) {
|
|
405
|
-
if (entries.length === 0) return [];
|
|
406
|
-
const files = /* @__PURE__ */ new Set();
|
|
407
|
-
await Promise.all([...groupTailwindV4SourceEntriesByBase(entries).entries()].map(async ([base, group]) => {
|
|
408
|
-
const matched = await resolveFiles({
|
|
409
|
-
cwd: base,
|
|
410
|
-
sources: group
|
|
411
|
-
});
|
|
412
|
-
for (const file of matched) files.add(path.resolve(file));
|
|
413
|
-
}));
|
|
414
|
-
return [...files].filter((file) => !isFileExcludedByTailwindV4SourceEntries(file, entries));
|
|
415
|
-
}
|
|
416
|
-
function mergeTailwindV4SourceEntries(...entries) {
|
|
417
|
-
const result = [];
|
|
418
|
-
const seen = /* @__PURE__ */ new Set();
|
|
419
|
-
for (const group of entries) for (const entry of group ?? []) {
|
|
420
|
-
const normalized = {
|
|
421
|
-
base: path.resolve(entry.base),
|
|
422
|
-
pattern: normalizeGlobPattern(entry.pattern),
|
|
423
|
-
negated: entry.negated
|
|
424
|
-
};
|
|
425
|
-
const key = JSON.stringify(normalized);
|
|
426
|
-
if (seen.has(key)) continue;
|
|
427
|
-
seen.add(key);
|
|
428
|
-
result.push(normalized);
|
|
429
|
-
}
|
|
430
|
-
return result;
|
|
431
|
-
}
|
|
432
|
-
//#endregion
|
|
433
407
|
//#region src/extraction/oxide.ts
|
|
434
408
|
let oxideImportPromise;
|
|
435
409
|
function createOxideRuntimeDependencyError(cause) {
|
|
@@ -517,6 +491,94 @@ function createTokenLocation(input) {
|
|
|
517
491
|
};
|
|
518
492
|
}
|
|
519
493
|
//#endregion
|
|
494
|
+
//#region src/extraction/candidate-extractor/project.ts
|
|
495
|
+
async function resolveScannerSources(options) {
|
|
496
|
+
const cwd = options?.cwd ? path.resolve(options.cwd) : process.cwd();
|
|
497
|
+
if (options?.sources?.length || options?.css === void 0) return {
|
|
498
|
+
cwd,
|
|
499
|
+
sources: normalizeTailwindV4ScannerSources(options?.sources, cwd, options?.ignoredSources)
|
|
500
|
+
};
|
|
501
|
+
const base = options.base ? path.resolve(options.base) : cwd;
|
|
502
|
+
const { compiled } = await compileTailwindV4Source({
|
|
503
|
+
projectRoot: cwd,
|
|
504
|
+
base,
|
|
505
|
+
baseFallbacks: options.baseFallbacks?.map((baseFallback) => path.resolve(baseFallback)) ?? [],
|
|
506
|
+
css: options.css,
|
|
507
|
+
dependencies: []
|
|
508
|
+
});
|
|
509
|
+
return {
|
|
510
|
+
cwd,
|
|
511
|
+
sources: normalizeTailwindV4ScannerSources(createTailwindV4CompiledSourceEntries(compiled.root, compiled.sources, base), cwd, options.ignoredSources)
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
async function resolveProjectSourceFiles(options) {
|
|
515
|
+
const { sources } = await resolveScannerSources(options);
|
|
516
|
+
const { Scanner } = await getOxideModule();
|
|
517
|
+
const files = new Scanner({ sources }).files ?? [];
|
|
518
|
+
return options?.filter ? files.filter(options.filter) : files;
|
|
519
|
+
}
|
|
520
|
+
async function extractProjectCandidatesWithPositions(options) {
|
|
521
|
+
const { cwd, sources } = await resolveScannerSources(options);
|
|
522
|
+
const { Scanner } = await getOxideModule();
|
|
523
|
+
const scanner = new Scanner({ sources });
|
|
524
|
+
const files = scanner.files ?? [];
|
|
525
|
+
const entries = [];
|
|
526
|
+
const skipped = [];
|
|
527
|
+
const batchSize = 32;
|
|
528
|
+
for (let start = 0; start < files.length; start += batchSize) {
|
|
529
|
+
const batch = files.slice(start, start + batchSize);
|
|
530
|
+
const contents = await Promise.allSettled(batch.map((file) => promises.readFile(file, "utf8")));
|
|
531
|
+
for (const [index, file] of batch.entries()) {
|
|
532
|
+
const result = contents[index];
|
|
533
|
+
if (result.status === "rejected") {
|
|
534
|
+
skipped.push({
|
|
535
|
+
file,
|
|
536
|
+
reason: result.reason instanceof Error ? result.reason.message : "Unknown error"
|
|
537
|
+
});
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
const content = result.value;
|
|
541
|
+
const extension = toExtension(file);
|
|
542
|
+
const matches = scanner.getCandidatesWithPositions({
|
|
543
|
+
file,
|
|
544
|
+
content,
|
|
545
|
+
extension
|
|
546
|
+
});
|
|
547
|
+
if (!matches.length) continue;
|
|
548
|
+
const offsets = buildLineOffsets(content);
|
|
549
|
+
for (const match of matches) entries.push(createTokenLocation({
|
|
550
|
+
cwd,
|
|
551
|
+
file,
|
|
552
|
+
content,
|
|
553
|
+
extension,
|
|
554
|
+
candidate: match.candidate,
|
|
555
|
+
position: match.position,
|
|
556
|
+
offsets
|
|
557
|
+
}));
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
return {
|
|
561
|
+
entries,
|
|
562
|
+
filesScanned: files.length,
|
|
563
|
+
skippedFiles: skipped,
|
|
564
|
+
sources
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
function groupTokensByFile(report, options) {
|
|
568
|
+
const key = options?.key ?? "relative";
|
|
569
|
+
const stripAbsolute = options?.stripAbsolutePaths ?? key !== "absolute";
|
|
570
|
+
return report.entries.reduce((acc, entry) => {
|
|
571
|
+
const bucketKey = key === "absolute" ? entry.file : entry.relativeFile;
|
|
572
|
+
const bucket = acc[bucketKey] ?? (acc[bucketKey] = []);
|
|
573
|
+
const value = stripAbsolute ? {
|
|
574
|
+
...entry,
|
|
575
|
+
file: entry.relativeFile
|
|
576
|
+
} : entry;
|
|
577
|
+
bucket.push(value);
|
|
578
|
+
return acc;
|
|
579
|
+
}, {});
|
|
580
|
+
}
|
|
581
|
+
//#endregion
|
|
520
582
|
//#region src/v4/bare-arbitrary-values/escape.ts
|
|
521
583
|
function escapeCssClassName(value) {
|
|
522
584
|
let result = "";
|
|
@@ -3533,6 +3595,7 @@ function createTailwindGenerationArtifact(css, source, request, classSet, rawCan
|
|
|
3533
3595
|
//#region src/v4/generation-request.ts
|
|
3534
3596
|
function toGenerationRequest(options) {
|
|
3535
3597
|
return {
|
|
3598
|
+
...options?.excludeFiles === void 0 ? {} : { excludeFiles: options.excludeFiles },
|
|
3536
3599
|
...options?.candidates === void 0 ? {} : { candidates: options.candidates },
|
|
3537
3600
|
...options?.sources === void 0 ? {} : { sourceEntries: options.sources.map((sourceEntry, index) => ({
|
|
3538
3601
|
id: `source:${index}`,
|
|
@@ -3544,6 +3607,7 @@ function toGenerationRequest(options) {
|
|
|
3544
3607
|
}
|
|
3545
3608
|
function toGenerateOptions(request) {
|
|
3546
3609
|
return {
|
|
3610
|
+
...request.excludeFiles === void 0 ? {} : { excludeFiles: request.excludeFiles },
|
|
3547
3611
|
...request.candidates === void 0 ? {} : { candidates: request.candidates },
|
|
3548
3612
|
...request.sourceEntries === void 0 ? {} : { sources: request.sourceEntries },
|
|
3549
3613
|
...request.bareArbitraryValues === void 0 ? {} : { bareArbitraryValues: request.bareArbitraryValues },
|
|
@@ -3582,7 +3646,7 @@ function stripCompiledSourceEntries(source) {
|
|
|
3582
3646
|
return source;
|
|
3583
3647
|
}
|
|
3584
3648
|
}
|
|
3585
|
-
async function collectRawCandidates(source, options, compiledRoot, compiledSources = []) {
|
|
3649
|
+
async function collectRawCandidates(source, options, compiledRoot, compiledSources = [], onFiles) {
|
|
3586
3650
|
const rawCandidates = /* @__PURE__ */ new Set();
|
|
3587
3651
|
const extractOptions = options?.bareArbitraryValues === void 0 ? void 0 : { bareArbitraryValues: options.bareArbitraryValues };
|
|
3588
3652
|
for (const candidate of options?.candidates ?? []) rawCandidates.add(candidate);
|
|
@@ -3591,7 +3655,25 @@ async function collectRawCandidates(source, options, compiledRoot, compiledSourc
|
|
|
3591
3655
|
for (const candidate of candidates) rawCandidates.add(candidate.rawCandidate);
|
|
3592
3656
|
}
|
|
3593
3657
|
const filesystemSources = resolveScanSources(options, source, compiledRoot, compiledSources);
|
|
3594
|
-
if (filesystemSources.
|
|
3658
|
+
if (filesystemSources.some((entry) => !entry.negated)) {
|
|
3659
|
+
const excluded = new Set((options?.excludeFiles ?? []).map(resolveSourceScanPath));
|
|
3660
|
+
const files = await resolveProjectSourceFiles({
|
|
3661
|
+
sources: filesystemSources,
|
|
3662
|
+
filter: (file) => !excluded.has(resolveSourceScanPath(file))
|
|
3663
|
+
});
|
|
3664
|
+
onFiles?.(files);
|
|
3665
|
+
for (const file of files) {
|
|
3666
|
+
let content;
|
|
3667
|
+
try {
|
|
3668
|
+
content = await readFile(file, "utf8");
|
|
3669
|
+
} catch (error) {
|
|
3670
|
+
const code = error?.code;
|
|
3671
|
+
if (code === "ENOENT" || code === "ENOTDIR") continue;
|
|
3672
|
+
throw error;
|
|
3673
|
+
}
|
|
3674
|
+
for (const candidate of await extractRawCandidatesWithPositions(content, path.extname(file).slice(1), extractOptions)) rawCandidates.add(candidate.rawCandidate);
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3595
3677
|
const inlineSources = extractTailwindV4InlineSourceCandidates(source.css);
|
|
3596
3678
|
for (const candidate of inlineSources.included) rawCandidates.add(candidate);
|
|
3597
3679
|
for (const candidate of inlineSources.excluded) rawCandidates.delete(candidate);
|
|
@@ -3604,6 +3686,7 @@ var TailwindGenerationSessionImpl = class {
|
|
|
3604
3686
|
runtimes = /* @__PURE__ */ new Map();
|
|
3605
3687
|
designSystemPromise;
|
|
3606
3688
|
disposed = false;
|
|
3689
|
+
moduleDependencies = /* @__PURE__ */ new Set();
|
|
3607
3690
|
constructor(source) {
|
|
3608
3691
|
this.currentSource = source;
|
|
3609
3692
|
}
|
|
@@ -3636,10 +3719,15 @@ var TailwindGenerationSessionImpl = class {
|
|
|
3636
3719
|
invalidate(change) {
|
|
3637
3720
|
if (this.disposed) return;
|
|
3638
3721
|
if (change.type === "source") this.currentSource = change.source;
|
|
3722
|
+
clearRequireCache([...this.moduleDependencies]);
|
|
3723
|
+
invalidateGenerationModuleCache();
|
|
3724
|
+
this.moduleDependencies.clear();
|
|
3639
3725
|
this.runtimes.clear();
|
|
3640
3726
|
this.designSystemPromise = void 0;
|
|
3641
3727
|
}
|
|
3642
3728
|
dispose() {
|
|
3729
|
+
clearRequireCache([...this.moduleDependencies]);
|
|
3730
|
+
this.moduleDependencies.clear();
|
|
3643
3731
|
this.runtimes.clear();
|
|
3644
3732
|
this.designSystemPromise = void 0;
|
|
3645
3733
|
this.disposed = true;
|
|
@@ -3647,12 +3735,12 @@ var TailwindGenerationSessionImpl = class {
|
|
|
3647
3735
|
assertActive() {
|
|
3648
3736
|
if (this.disposed) throw new Error("Tailwind generation session has been disposed.");
|
|
3649
3737
|
}
|
|
3650
|
-
getRuntime(compileSourceEntries) {
|
|
3738
|
+
getRuntime(compileSourceEntries, designSystem) {
|
|
3651
3739
|
this.assertActive();
|
|
3652
3740
|
const cached = this.runtimes.get(compileSourceEntries);
|
|
3653
3741
|
if (cached) return cached;
|
|
3654
3742
|
const source = compileSourceEntries ? this.currentSource : stripCompiledSourceEntries(this.currentSource);
|
|
3655
|
-
const promise = Promise.all([compileTailwindV4Source(source), loadTailwindV4DesignSystem(source, { cache: false })]).then(([compiledSource, designSystem]) => ({
|
|
3743
|
+
const promise = Promise.all([compileTailwindV4Source(source), designSystem ?? loadTailwindV4DesignSystem(source, { cache: false })]).then(([compiledSource, designSystem]) => ({
|
|
3656
3744
|
compiled: compiledSource.compiled,
|
|
3657
3745
|
dependencies: compiledSource.dependencies,
|
|
3658
3746
|
designSystem,
|
|
@@ -3664,28 +3752,32 @@ var TailwindGenerationSessionImpl = class {
|
|
|
3664
3752
|
});
|
|
3665
3753
|
return promise;
|
|
3666
3754
|
}
|
|
3667
|
-
async resetRuntime(compileSourceEntries) {
|
|
3755
|
+
async resetRuntime(compileSourceEntries, designSystem) {
|
|
3668
3756
|
this.runtimes.delete(compileSourceEntries);
|
|
3669
|
-
return this.getRuntime(compileSourceEntries);
|
|
3757
|
+
return this.getRuntime(compileSourceEntries, designSystem);
|
|
3670
3758
|
}
|
|
3671
3759
|
async generateInternal(request) {
|
|
3672
3760
|
this.assertActive();
|
|
3673
3761
|
const options = toGenerateOptions(request);
|
|
3674
3762
|
const compileSourceEntries = shouldCompileSourceEntries(options);
|
|
3675
3763
|
let runtime = await this.getRuntime(compileSourceEntries);
|
|
3676
|
-
const
|
|
3764
|
+
const sourceFiles = [];
|
|
3765
|
+
let rawCandidates = await collectRawCandidates(this.currentSource, options, runtime.compiled.root, runtime.compiled.sources, (files) => sourceFiles.push(...files));
|
|
3766
|
+
if (request.prepareCandidates) rawCandidates = new Set(request.prepareCandidates(rawCandidates));
|
|
3677
3767
|
const classSet = resolveValidTailwindV4Candidates(runtime.designSystem, rawCandidates, { ...options.bareArbitraryValues === void 0 ? {} : { bareArbitraryValues: options.bareArbitraryValues } });
|
|
3678
3768
|
const inlineSources = extractTailwindV4InlineSourceCandidates(this.currentSource.css);
|
|
3679
3769
|
for (const candidate of inlineSources.excluded) classSet.delete(candidate);
|
|
3680
3770
|
const buildCandidates = new Set(canonicalizeBareArbitraryValueCandidates(classSet, options.bareArbitraryValues));
|
|
3681
|
-
if ([...runtime.builtCandidates].some((candidate) => !buildCandidates.has(candidate))) runtime = await this.resetRuntime(compileSourceEntries);
|
|
3771
|
+
if ([...runtime.builtCandidates].some((candidate) => !buildCandidates.has(candidate))) runtime = await this.resetRuntime(compileSourceEntries, runtime.designSystem);
|
|
3682
3772
|
const css = replaceBareArbitraryValueSelectors(runtime.compiled.build([...buildCandidates]), classSet, options.bareArbitraryValues);
|
|
3683
3773
|
runtime.builtCandidates = new Set(buildCandidates);
|
|
3774
|
+
for (const dependency of runtime.dependencies) this.moduleDependencies.add(dependency);
|
|
3775
|
+
const dependencies = [.../* @__PURE__ */ new Set([...runtime.dependencies, ...sourceFiles])];
|
|
3684
3776
|
return {
|
|
3685
3777
|
css,
|
|
3686
3778
|
classSet,
|
|
3687
3779
|
rawCandidates,
|
|
3688
|
-
dependencies
|
|
3780
|
+
dependencies,
|
|
3689
3781
|
sources: runtime.compiled.sources,
|
|
3690
3782
|
root: runtime.compiled.root
|
|
3691
3783
|
};
|
|
@@ -3703,6 +3795,9 @@ function createTailwindV4Engine(source) {
|
|
|
3703
3795
|
const session = createTailwindV4EngineGenerationSession(source);
|
|
3704
3796
|
return {
|
|
3705
3797
|
source,
|
|
3798
|
+
dispose() {
|
|
3799
|
+
session.dispose();
|
|
3800
|
+
},
|
|
3706
3801
|
loadDesignSystem() {
|
|
3707
3802
|
return session.loadDesignSystem();
|
|
3708
3803
|
},
|
|
@@ -3859,16 +3954,21 @@ async function collectTailwindV4StyleCandidates(options) {
|
|
|
3859
3954
|
async function generateTailwindV4Style(options = {}) {
|
|
3860
3955
|
const source = options.source ?? await resolveTailwindV4Source(createSourceOptions(options));
|
|
3861
3956
|
const candidates = await collectTailwindV4StyleCandidates(options);
|
|
3862
|
-
const
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3957
|
+
const engine = createTailwindV4Engine(source);
|
|
3958
|
+
try {
|
|
3959
|
+
const result = await engine.generate({
|
|
3960
|
+
candidates,
|
|
3961
|
+
...options.bareArbitraryValues === void 0 ? {} : { bareArbitraryValues: options.bareArbitraryValues },
|
|
3962
|
+
...options.scanSources === void 0 ? {} : { scanSources: options.scanSources }
|
|
3963
|
+
});
|
|
3964
|
+
return {
|
|
3965
|
+
...result,
|
|
3966
|
+
tokens: result.rawCandidates,
|
|
3967
|
+
source
|
|
3968
|
+
};
|
|
3969
|
+
} finally {
|
|
3970
|
+
engine.dispose?.();
|
|
3971
|
+
}
|
|
3872
3972
|
}
|
|
3873
3973
|
//#endregion
|
|
3874
|
-
export {
|
|
3974
|
+
export { expandTailwindV4SourceEntryBraces as A, expandTailwindV4SourceEntries as B, TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN as C, createTailwindV4CompiledSourceEntries as D, TAILWIND_V4_IGNORED_FILES as E, resolveTailwindV4SourceBaseCandidates as F, compileTailwindV4Source as G, isFileExcludedByTailwindV4SourceEntries as H, resolveTailwindV4SourceEntry as I, loadTailwindV4NodeModule as J, getTailwindV4DesignSystemCacheKey as K, toPosixPath as L, normalizeTailwindV4ScannerSources as M, normalizeTailwindV4SourceEntries as N, createTailwindV4DefaultIgnoreSources as O, resolveSourceScanPath$1 as P, createTailwindV4SourceEntryMatcher as R, resolveProjectSourceFiles as S, TAILWIND_V4_IGNORED_EXTENSIONS as T, isFileMatchedByTailwindV4SourceEntries as U, groupTailwindV4SourceEntriesByBase as V, mergeTailwindV4SourceEntries as W, isBareArbitraryValuesEnabled as _, createTailwindGenerationSession as a, extractProjectCandidatesWithPositions as b, replaceBareArbitraryValueSelectors as c, extractRawCandidates as d, extractRawCandidatesWithPositions as f, extractBareArbitraryValueSourceCandidatesWithPositions as g, extractBareArbitraryValueSourceCandidates as h, createTailwindV4Engine as i, normalizeGlobPattern as j, createTailwindV4RootSources as k, resolveValidTailwindV4Candidates as l, extractSourceCandidatesWithPositions as m, generateTailwindV4Style as n, collectTailwindStyleCandidates as o, extractSourceCandidates as p, loadTailwindV4DesignSystem as q, resolveTailwindV4Source as r, canonicalizeBareArbitraryValueCandidates as s, collectTailwindV4StyleCandidates as t, extractTailwindV4InlineSourceCandidates as u, resolveBareArbitraryValueCandidate as v, TAILWIND_V4_IGNORED_CONTENT_DIRS as w, groupTokensByFile as x, escapeCssClassName as y, createTailwindV4SourceExclusionMatcher as z };
|