@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.
@@ -27,11 +27,172 @@ let node_process = require("node:process");
27
27
  node_process = __toESM(node_process, 1);
28
28
  let node_module = require("node:module");
29
29
  let node_url = require("node:url");
30
- let micromatch = require("micromatch");
31
- micromatch = __toESM(micromatch, 1);
32
- let node_fs_promises = require("node:fs/promises");
30
+ let node_async_hooks = require("node:async_hooks");
31
+ let node_crypto = require("node:crypto");
32
+ let _tailwindcss_node_require_cache = require("@tailwindcss/node/require-cache");
33
+ let _weapp_tailwindcss_source_scan = require("@weapp-tailwindcss/source-scan");
33
34
  let postcss = require("postcss");
34
35
  postcss = __toESM(postcss, 1);
36
+ let node_fs_promises = require("node:fs/promises");
37
+ //#region src/v4/module-cache.ts
38
+ const context = new node_async_hooks.AsyncLocalStorage();
39
+ const caches = /* @__PURE__ */ new WeakMap();
40
+ let revision = 0;
41
+ const hooks = globalThis;
42
+ let installedHook;
43
+ let activeContexts = 0;
44
+ const MODULE_CACHE_LIMIT = 128;
45
+ const require$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
46
+ function canUseCommonJsGraph(file) {
47
+ const extension = node_path.default.extname(file);
48
+ if (extension === ".cjs" || extension === ".cts") return true;
49
+ if (extension !== ".js") return false;
50
+ const manifest = (0, node_module.findPackageJSON)((0, node_url.pathToFileURL)(file).href);
51
+ return !manifest || node_path.default.basename(manifest) !== "package.json" || JSON.parse((0, node_fs.readFileSync)(manifest, "utf8")).type !== "module";
52
+ }
53
+ function collectCommonJsDependencies(file, dependencies) {
54
+ const module = require$1.cache[file];
55
+ if (!module?.loaded) return false;
56
+ const visited = /* @__PURE__ */ new Set();
57
+ const packageRoot = node_path.default.dirname((0, node_module.findPackageJSON)((0, node_url.pathToFileURL)(file).href) ?? file);
58
+ function visit(current) {
59
+ if (visited.has(current) || !current.filename) return;
60
+ visited.add(current);
61
+ let directory = node_path.default.dirname(current.filename);
62
+ const relative = node_path.default.relative(packageRoot, current.filename);
63
+ while (node_path.default.dirname(directory) !== directory) {
64
+ if (node_path.default.basename(directory) === "node_modules" && (relative.startsWith(`..${node_path.default.sep}`) || node_path.default.isAbsolute(relative))) return;
65
+ directory = node_path.default.dirname(directory);
66
+ }
67
+ dependencies.add(current.filename);
68
+ for (const child of current.children) visit(child);
69
+ }
70
+ visit(module);
71
+ return true;
72
+ }
73
+ function fingerprint(files) {
74
+ const hash = (0, node_crypto.createHash)("sha256");
75
+ for (const file of files) {
76
+ hash.update(file);
77
+ hash.update((0, node_fs.readFileSync)(file));
78
+ }
79
+ return hash.digest("hex");
80
+ }
81
+ async function loadCachedModule(loader, file) {
82
+ let state = caches.get(loader);
83
+ if (!state || state.revision !== revision) {
84
+ state = {
85
+ revision,
86
+ entries: /* @__PURE__ */ new Map()
87
+ };
88
+ caches.set(loader, state);
89
+ }
90
+ const cache = state.entries;
91
+ const previous = cache.get(file);
92
+ if (previous) {
93
+ const entry = await previous;
94
+ try {
95
+ if (fingerprint(entry.dependencies) === entry.fingerprint) return entry;
96
+ } catch {}
97
+ if (cache.get(file) !== previous) return loadCachedModule(loader, file);
98
+ (0, _tailwindcss_node_require_cache.clearRequireCache)(entry.dependencies);
99
+ }
100
+ const pending = context.run(void 0, async () => {
101
+ const dependencies = /* @__PURE__ */ new Set([file]);
102
+ const base = node_path.default.dirname(file);
103
+ const onDependency = (dependency) => {
104
+ dependencies.add(dependency);
105
+ };
106
+ let loaded = previous || !canUseCommonJsGraph(file) ? void 0 : await loader.loadModule(file, base, onDependency);
107
+ if (!loaded || !collectCommonJsDependencies(file, dependencies)) loaded = await loader.loadModule(`./${node_path.default.basename(file)}`, base, onDependency);
108
+ const files = [...dependencies].sort();
109
+ return {
110
+ dependencies: files,
111
+ fingerprint: fingerprint(files),
112
+ value: { default: loaded.module }
113
+ };
114
+ });
115
+ cache.set(file, pending);
116
+ while (cache.size > MODULE_CACHE_LIMIT) cache.delete(cache.keys().next().value);
117
+ try {
118
+ return await pending;
119
+ } catch (error) {
120
+ if (cache.get(file) === pending) cache.delete(file);
121
+ throw error;
122
+ }
123
+ }
124
+ function installHook() {
125
+ if (installedHook && hooks.__tw_load === installedHook) return;
126
+ const previous = hooks.__tw_load;
127
+ installedHook = async (url) => {
128
+ const overridden = await previous?.(url);
129
+ if (overridden) return overridden;
130
+ const active = context.getStore();
131
+ if (!active?.loader.loadModule || !url.startsWith("file:")) return;
132
+ const parsed = new URL(url);
133
+ const file = (0, _weapp_tailwindcss_source_scan.resolveSourceScanPath)((0, node_url.fileURLToPath)(parsed));
134
+ if (!parsed.searchParams.has("id") && !active.files.has(file)) return;
135
+ const entry = await loadCachedModule(active.loader, file);
136
+ for (const dependency of entry.dependencies) active.onDependency?.(dependency);
137
+ return entry.value;
138
+ };
139
+ hooks.__tw_load = installedHook;
140
+ }
141
+ function invalidateGenerationModuleCache() {
142
+ revision += 1;
143
+ }
144
+ /** 仅在本引擎调用内复用本地模块;Tailwind 仍负责解析与依赖跟踪。 */
145
+ async function withGenerationModuleCache(loader, run, files = [], onDependency) {
146
+ installHook();
147
+ const resolved = files.map((file) => {
148
+ for (const candidate of [
149
+ file,
150
+ `${file}.ts`,
151
+ node_path.default.join(file, "index.ts")
152
+ ]) try {
153
+ return (0, _weapp_tailwindcss_source_scan.resolveSourceScanPath)(require$1.resolve(candidate));
154
+ } catch {}
155
+ return (0, _weapp_tailwindcss_source_scan.resolveSourceScanPath)(file);
156
+ });
157
+ activeContexts += 1;
158
+ try {
159
+ return await context.run({
160
+ loader,
161
+ files: new Set(resolved),
162
+ onDependency
163
+ }, run);
164
+ } finally {
165
+ activeContexts -= 1;
166
+ if (activeContexts === 0) context.disable();
167
+ }
168
+ }
169
+ //#endregion
170
+ //#region src/v4/module-requests.ts
171
+ /** 固定本地模块身份,依赖跟踪与刷新由生成模块缓存负责。 */
172
+ function prepareGenerationModuleRequests(css, base) {
173
+ const files = [];
174
+ if (!css.includes("@config") && !css.includes("@plugin")) return {
175
+ css,
176
+ files
177
+ };
178
+ const root = postcss.default.parse(css);
179
+ root.walkAtRules((rule) => {
180
+ if (rule.name !== "config" && rule.name !== "plugin") return;
181
+ const match = /^(["'])(.*)\1$/.exec(rule.params.trim());
182
+ if (!match) return;
183
+ const request = match[2];
184
+ const pathApi = /^[a-z]:[\\/]/i.test(base) || base.includes("\\") ? node_path.default.win32 : node_path.default;
185
+ if (!pathApi.isAbsolute(request) && !request.startsWith(".")) return;
186
+ const file = pathApi.resolve(base, request);
187
+ files.push(file);
188
+ rule.params = JSON.stringify(file.replaceAll("\\", "/"));
189
+ });
190
+ return {
191
+ css: root.toString(),
192
+ files
193
+ };
194
+ }
195
+ //#endregion
35
196
  //#region src/v4/node-adapter.ts
36
197
  const nodeModulePromiseCache = /* @__PURE__ */ new Map();
37
198
  const designSystemPromiseCache = /* @__PURE__ */ new Map();
@@ -112,7 +273,8 @@ async function createTailwindV4DesignSystem(source) {
112
273
  const node = await loadTailwindV4NodeModule([source.projectRoot, ...bases]);
113
274
  let lastError;
114
275
  for (const base of bases) try {
115
- return await node.__unstable__loadDesignSystem(source.css, { base });
276
+ const prepared = prepareGenerationModuleRequests(source.css, base);
277
+ return await withGenerationModuleCache(node, () => node.__unstable__loadDesignSystem(prepared.css, { base }), prepared.files);
116
278
  } catch (error) {
117
279
  lastError = error;
118
280
  }
@@ -139,14 +301,14 @@ async function compileTailwindV4Source(source) {
139
301
  for (const base of bases) {
140
302
  const dependencies = new Set(source.dependencies);
141
303
  try {
304
+ const prepared = prepareGenerationModuleRequests(source.css, base);
305
+ const onDependency = (dependency) => dependencies.add(node_path.default.resolve(dependency));
142
306
  return {
143
- compiled: await node.compile(source.css, {
307
+ compiled: await withGenerationModuleCache(node, () => node.compile(prepared.css, {
144
308
  base,
145
309
  customCssResolver: createFallbackCssResolver([source.projectRoot, ...bases]),
146
- onDependency(dependency) {
147
- dependencies.add(node_path.default.resolve(dependency));
148
- }
149
- }),
310
+ onDependency
311
+ }), prepared.files, onDependency),
150
312
  dependencies
151
313
  };
152
314
  } catch (error) {
@@ -157,6 +319,17 @@ async function compileTailwindV4Source(source) {
157
319
  throw new Error("Failed to compile Tailwind CSS v4 source.");
158
320
  }
159
321
  //#endregion
322
+ //#region src/v4/source-scan/matcher.ts
323
+ function isFileMatchedByTailwindV4SourceEntries(file, entries) {
324
+ return (0, _weapp_tailwindcss_source_scan.isFileMatchedByTailwindSourceEntries)(file, entries, { requirePositive: true });
325
+ }
326
+ function createTailwindV4SourceEntryMatcher(entries) {
327
+ return entries?.length ? (file) => isFileMatchedByTailwindV4SourceEntries(file, entries) : void 0;
328
+ }
329
+ function createTailwindV4SourceExclusionMatcher(entries) {
330
+ return entries?.length ? (file) => (0, _weapp_tailwindcss_source_scan.isFileExcludedByTailwindSourceEntries)(file, entries) : void 0;
331
+ }
332
+ //#endregion
160
333
  //#region src/v4/source-scan/sources.ts
161
334
  const TAILWIND_V4_IGNORED_CONTENT_DIRS = [
162
335
  ".git",
@@ -201,48 +374,6 @@ function uniqueResolvedPaths(values) {
201
374
  }
202
375
  return result;
203
376
  }
204
- function toPosixPath(value) {
205
- return value.replaceAll(node_path.default.sep, "/");
206
- }
207
- function resolveSourceScanPath(value) {
208
- const resolved = node_path.default.resolve(value);
209
- try {
210
- return node_fs.realpathSync.native(resolved);
211
- } catch {
212
- return resolved;
213
- }
214
- }
215
- function normalizeGlobPattern(pattern) {
216
- return pattern.startsWith("./") ? pattern.slice(2) : pattern;
217
- }
218
- function hasGlobMagic(value) {
219
- return /[*?[\]{}()!+@]/.test(value);
220
- }
221
- function splitStaticGlobPrefix(pattern) {
222
- const segments = normalizeGlobPattern(pattern).split(/[\\/]+/);
223
- const prefix = [];
224
- const rest = [];
225
- let reachedGlob = false;
226
- for (const segment of segments) {
227
- if (!reachedGlob && segment && !hasGlobMagic(segment)) {
228
- prefix.push(segment);
229
- continue;
230
- }
231
- reachedGlob = true;
232
- rest.push(segment);
233
- }
234
- return {
235
- prefix,
236
- rest
237
- };
238
- }
239
- async function pathExistsAsDirectory(file) {
240
- try {
241
- return (await (0, node_fs_promises.stat)(file)).isDirectory();
242
- } catch {
243
- return false;
244
- }
245
- }
246
377
  function createTailwindV4DefaultIgnoreSources(base) {
247
378
  return [
248
379
  ...TAILWIND_V4_IGNORED_CONTENT_DIRS.map((pattern) => ({
@@ -263,117 +394,32 @@ function createTailwindV4DefaultIgnoreSources(base) {
263
394
  ];
264
395
  }
265
396
  function createTailwindV4RootSources(root, fallbackBase) {
266
- if (root === "none") return [];
267
- if (root === null) return [{
397
+ return (0, _weapp_tailwindcss_source_scan.createSourceScanPlan)({
268
398
  base: fallbackBase,
269
- pattern: TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN,
270
- negated: false
271
- }];
272
- return [{
273
- ...root,
274
- negated: false
275
- }];
399
+ mode: root === "none" ? "disabled" : root === null ? "auto" : "explicit",
400
+ entries: root && root !== "none" ? [{
401
+ ...root,
402
+ negated: false
403
+ }] : []
404
+ });
276
405
  }
277
406
  function createTailwindV4CompiledSourceEntries(root, sources, fallbackBase) {
278
407
  return [...createTailwindV4RootSources(root, fallbackBase), ...sources];
279
408
  }
280
- async function resolveTailwindV4SourceEntry(sourcePath, base, negated, defaultPattern = TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN) {
281
- const absoluteSource = node_path.default.isAbsolute(sourcePath) ? node_path.default.resolve(sourcePath) : node_path.default.resolve(base, sourcePath);
282
- if (await pathExistsAsDirectory(absoluteSource)) return {
283
- base: absoluteSource,
284
- negated,
285
- pattern: normalizeGlobPattern(defaultPattern)
286
- };
287
- if (node_path.default.isAbsolute(sourcePath)) return {
288
- base: node_path.default.dirname(absoluteSource),
289
- negated,
290
- pattern: normalizeGlobPattern(node_path.default.basename(absoluteSource))
291
- };
292
- const { prefix, rest } = splitStaticGlobPrefix(sourcePath);
293
- if (prefix.length > 0 && rest.length > 0) return {
294
- base: node_path.default.resolve(base, ...prefix),
295
- negated,
296
- pattern: normalizeGlobPattern(rest.join("/"))
297
- };
298
- return {
299
- base,
300
- negated,
301
- pattern: normalizeGlobPattern(sourcePath)
302
- };
409
+ function resolveTailwindV4SourceEntry(sourcePath, base, negated, defaultPattern = TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN) {
410
+ return (0, _weapp_tailwindcss_source_scan.resolveTailwindSourceEntry)(sourcePath, base, negated, defaultPattern);
303
411
  }
304
412
  async function normalizeTailwindV4SourceEntries(sources, options = {}) {
305
413
  const cwd = options.cwd ? node_path.default.resolve(options.cwd) : node_process.default.cwd();
306
414
  return Promise.all(sources.map((source) => resolveTailwindV4SourceEntry(source.pattern, source.base ? node_path.default.resolve(source.base) : cwd, source.negated, options.defaultPattern)));
307
415
  }
308
- function expandBracePattern(pattern) {
309
- const index = pattern.indexOf("{");
310
- if (index === -1) return [pattern];
311
- const rest = pattern.slice(index);
312
- let depth = 0;
313
- let endIndex = -1;
314
- for (let i = 0; i < rest.length; i++) {
315
- const char = rest[i];
316
- if (char === "\\") {
317
- i += 1;
318
- continue;
319
- }
320
- if (char === "{") {
321
- depth += 1;
322
- continue;
323
- }
324
- if (char === "}") {
325
- depth -= 1;
326
- if (depth === 0) {
327
- endIndex = i;
328
- break;
329
- }
330
- }
331
- }
332
- if (endIndex === -1) return [pattern];
333
- const prefix = pattern.slice(0, index);
334
- const inner = rest.slice(1, endIndex);
335
- const suffix = rest.slice(endIndex + 1);
336
- const parts = [];
337
- const stack = [];
338
- let lastPos = 0;
339
- for (let i = 0; i < inner.length; i++) {
340
- const char = inner[i];
341
- if (char === "\\") {
342
- i += 1;
343
- continue;
344
- }
345
- if (char === "{") {
346
- stack.push("}");
347
- continue;
348
- }
349
- if (char === "}" && stack[stack.length - 1] === "}") {
350
- stack.pop();
351
- continue;
352
- }
353
- if (char === "," && stack.length === 0) {
354
- parts.push(inner.slice(lastPos, i));
355
- lastPos = i + 1;
356
- }
357
- }
358
- parts.push(inner.slice(lastPos));
359
- return parts.flatMap((part) => expandBracePattern(`${prefix}${part}${suffix}`));
360
- }
361
- function expandTailwindV4SourceEntryBraces(sources) {
362
- return sources.flatMap((source) => {
363
- const base = node_path.default.resolve(source.base);
364
- return expandBracePattern(source.pattern).map((pattern) => ({
365
- base,
366
- pattern,
367
- negated: source.negated
368
- }));
369
- });
370
- }
371
416
  function normalizeTailwindV4ScannerSources(sources, cwd, ignoredSources = []) {
372
- return expandTailwindV4SourceEntryBraces([...sources?.length ? sources : [{
417
+ const baseSources = sources?.length ? sources : [{
373
418
  base: cwd,
374
419
  pattern: TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN,
375
420
  negated: false
376
- }], ...ignoredSources]);
421
+ }];
422
+ return (0, _weapp_tailwindcss_source_scan.expandSourceEntryBraces)([...baseSources, ...ignoredSources]);
377
423
  }
378
424
  function resolveTailwindV4SourceBaseCandidates(projectRoot, base, baseFallbacks) {
379
425
  return uniqueResolvedPaths([
@@ -383,79 +429,6 @@ function resolveTailwindV4SourceBaseCandidates(projectRoot, base, baseFallbacks)
383
429
  ]);
384
430
  }
385
431
  //#endregion
386
- //#region src/v4/source-scan/matcher.ts
387
- function normalizeEntryPattern(entry) {
388
- return node_path.default.isAbsolute(entry.pattern) ? toPosixPath(node_path.default.relative(resolveSourceScanPath(entry.base), entry.pattern)) : normalizeGlobPattern(entry.pattern);
389
- }
390
- function isFileMatchedByTailwindV4SourceEntry(file, entry) {
391
- const relative = toPosixPath(node_path.default.relative(resolveSourceScanPath(entry.base), file));
392
- return Boolean(relative) && !relative.startsWith("../") && !node_path.default.isAbsolute(relative) && micromatch.default.isMatch(relative, normalizeEntryPattern(entry));
393
- }
394
- function isFileExcludedByTailwindV4SourceEntries(file, entries) {
395
- if (!entries?.length) return false;
396
- const resolvedFile = resolveSourceScanPath(file);
397
- return entries.some((entry) => entry.negated && isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry));
398
- }
399
- function isFileMatchedByTailwindV4SourceEntries(file, entries) {
400
- if (!entries?.length) return true;
401
- const positiveEntries = entries.filter((entry) => !entry.negated);
402
- const negativeEntries = entries.filter((entry) => entry.negated);
403
- if (positiveEntries.length === 0) return false;
404
- const resolvedFile = resolveSourceScanPath(file);
405
- if (!positiveEntries.some((entry) => isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry))) return false;
406
- return !negativeEntries.some((entry) => isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry));
407
- }
408
- function createTailwindV4SourceEntryMatcher(entries) {
409
- if (!entries?.length) return;
410
- return (file) => isFileMatchedByTailwindV4SourceEntries(file, entries);
411
- }
412
- function createTailwindV4SourceExclusionMatcher(entries) {
413
- if (!entries?.length) return;
414
- return (file) => isFileExcludedByTailwindV4SourceEntries(file, entries);
415
- }
416
- function groupTailwindV4SourceEntriesByBase(entries) {
417
- const entriesByBase = /* @__PURE__ */ new Map();
418
- for (const entry of entries) {
419
- const base = node_path.default.resolve(entry.base);
420
- const group = entriesByBase.get(base) ?? [];
421
- group.push({
422
- ...entry,
423
- base,
424
- pattern: normalizeGlobPattern(entry.pattern)
425
- });
426
- entriesByBase.set(base, group);
427
- }
428
- return entriesByBase;
429
- }
430
- async function expandTailwindV4SourceEntries(entries, resolveFiles) {
431
- if (entries.length === 0) return [];
432
- const files = /* @__PURE__ */ new Set();
433
- await Promise.all([...groupTailwindV4SourceEntriesByBase(entries).entries()].map(async ([base, group]) => {
434
- const matched = await resolveFiles({
435
- cwd: base,
436
- sources: group
437
- });
438
- for (const file of matched) files.add(node_path.default.resolve(file));
439
- }));
440
- return [...files].filter((file) => !isFileExcludedByTailwindV4SourceEntries(file, entries));
441
- }
442
- function mergeTailwindV4SourceEntries(...entries) {
443
- const result = [];
444
- const seen = /* @__PURE__ */ new Set();
445
- for (const group of entries) for (const entry of group ?? []) {
446
- const normalized = {
447
- base: node_path.default.resolve(entry.base),
448
- pattern: normalizeGlobPattern(entry.pattern),
449
- negated: entry.negated
450
- };
451
- const key = JSON.stringify(normalized);
452
- if (seen.has(key)) continue;
453
- seen.add(key);
454
- result.push(normalized);
455
- }
456
- return result;
457
- }
458
- //#endregion
459
432
  //#region src/extraction/oxide.ts
460
433
  let oxideImportPromise;
461
434
  function createOxideRuntimeDependencyError(cause) {
@@ -543,6 +516,94 @@ function createTokenLocation(input) {
543
516
  };
544
517
  }
545
518
  //#endregion
519
+ //#region src/extraction/candidate-extractor/project.ts
520
+ async function resolveScannerSources(options) {
521
+ const cwd = options?.cwd ? node_path.default.resolve(options.cwd) : node_process.default.cwd();
522
+ if (options?.sources?.length || options?.css === void 0) return {
523
+ cwd,
524
+ sources: normalizeTailwindV4ScannerSources(options?.sources, cwd, options?.ignoredSources)
525
+ };
526
+ const base = options.base ? node_path.default.resolve(options.base) : cwd;
527
+ const { compiled } = await compileTailwindV4Source({
528
+ projectRoot: cwd,
529
+ base,
530
+ baseFallbacks: options.baseFallbacks?.map((baseFallback) => node_path.default.resolve(baseFallback)) ?? [],
531
+ css: options.css,
532
+ dependencies: []
533
+ });
534
+ return {
535
+ cwd,
536
+ sources: normalizeTailwindV4ScannerSources(createTailwindV4CompiledSourceEntries(compiled.root, compiled.sources, base), cwd, options.ignoredSources)
537
+ };
538
+ }
539
+ async function resolveProjectSourceFiles(options) {
540
+ const { sources } = await resolveScannerSources(options);
541
+ const { Scanner } = await getOxideModule();
542
+ const files = new Scanner({ sources }).files ?? [];
543
+ return options?.filter ? files.filter(options.filter) : files;
544
+ }
545
+ async function extractProjectCandidatesWithPositions(options) {
546
+ const { cwd, sources } = await resolveScannerSources(options);
547
+ const { Scanner } = await getOxideModule();
548
+ const scanner = new Scanner({ sources });
549
+ const files = scanner.files ?? [];
550
+ const entries = [];
551
+ const skipped = [];
552
+ const batchSize = 32;
553
+ for (let start = 0; start < files.length; start += batchSize) {
554
+ const batch = files.slice(start, start + batchSize);
555
+ const contents = await Promise.allSettled(batch.map((file) => node_fs.promises.readFile(file, "utf8")));
556
+ for (const [index, file] of batch.entries()) {
557
+ const result = contents[index];
558
+ if (result.status === "rejected") {
559
+ skipped.push({
560
+ file,
561
+ reason: result.reason instanceof Error ? result.reason.message : "Unknown error"
562
+ });
563
+ continue;
564
+ }
565
+ const content = result.value;
566
+ const extension = toExtension(file);
567
+ const matches = scanner.getCandidatesWithPositions({
568
+ file,
569
+ content,
570
+ extension
571
+ });
572
+ if (!matches.length) continue;
573
+ const offsets = buildLineOffsets(content);
574
+ for (const match of matches) entries.push(createTokenLocation({
575
+ cwd,
576
+ file,
577
+ content,
578
+ extension,
579
+ candidate: match.candidate,
580
+ position: match.position,
581
+ offsets
582
+ }));
583
+ }
584
+ }
585
+ return {
586
+ entries,
587
+ filesScanned: files.length,
588
+ skippedFiles: skipped,
589
+ sources
590
+ };
591
+ }
592
+ function groupTokensByFile(report, options) {
593
+ const key = options?.key ?? "relative";
594
+ const stripAbsolute = options?.stripAbsolutePaths ?? key !== "absolute";
595
+ return report.entries.reduce((acc, entry) => {
596
+ const bucketKey = key === "absolute" ? entry.file : entry.relativeFile;
597
+ const bucket = acc[bucketKey] ?? (acc[bucketKey] = []);
598
+ const value = stripAbsolute ? {
599
+ ...entry,
600
+ file: entry.relativeFile
601
+ } : entry;
602
+ bucket.push(value);
603
+ return acc;
604
+ }, {});
605
+ }
606
+ //#endregion
546
607
  //#region src/v4/bare-arbitrary-values/escape.ts
547
608
  function escapeCssClassName(value) {
548
609
  let result = "";
@@ -3559,6 +3620,7 @@ function createTailwindGenerationArtifact(css, source, request, classSet, rawCan
3559
3620
  //#region src/v4/generation-request.ts
3560
3621
  function toGenerationRequest(options) {
3561
3622
  return {
3623
+ ...options?.excludeFiles === void 0 ? {} : { excludeFiles: options.excludeFiles },
3562
3624
  ...options?.candidates === void 0 ? {} : { candidates: options.candidates },
3563
3625
  ...options?.sources === void 0 ? {} : { sourceEntries: options.sources.map((sourceEntry, index) => ({
3564
3626
  id: `source:${index}`,
@@ -3570,6 +3632,7 @@ function toGenerationRequest(options) {
3570
3632
  }
3571
3633
  function toGenerateOptions(request) {
3572
3634
  return {
3635
+ ...request.excludeFiles === void 0 ? {} : { excludeFiles: request.excludeFiles },
3573
3636
  ...request.candidates === void 0 ? {} : { candidates: request.candidates },
3574
3637
  ...request.sourceEntries === void 0 ? {} : { sources: request.sourceEntries },
3575
3638
  ...request.bareArbitraryValues === void 0 ? {} : { bareArbitraryValues: request.bareArbitraryValues },
@@ -3608,7 +3671,7 @@ function stripCompiledSourceEntries(source) {
3608
3671
  return source;
3609
3672
  }
3610
3673
  }
3611
- async function collectRawCandidates(source, options, compiledRoot, compiledSources = []) {
3674
+ async function collectRawCandidates(source, options, compiledRoot, compiledSources = [], onFiles) {
3612
3675
  const rawCandidates = /* @__PURE__ */ new Set();
3613
3676
  const extractOptions = options?.bareArbitraryValues === void 0 ? void 0 : { bareArbitraryValues: options.bareArbitraryValues };
3614
3677
  for (const candidate of options?.candidates ?? []) rawCandidates.add(candidate);
@@ -3617,7 +3680,25 @@ async function collectRawCandidates(source, options, compiledRoot, compiledSourc
3617
3680
  for (const candidate of candidates) rawCandidates.add(candidate.rawCandidate);
3618
3681
  }
3619
3682
  const filesystemSources = resolveScanSources(options, source, compiledRoot, compiledSources);
3620
- if (filesystemSources.length > 0) for (const candidate of await extractRawCandidates(filesystemSources, extractOptions)) rawCandidates.add(candidate);
3683
+ if (filesystemSources.some((entry) => !entry.negated)) {
3684
+ const excluded = new Set((options?.excludeFiles ?? []).map(_weapp_tailwindcss_source_scan.resolveSourceScanPath));
3685
+ const files = await resolveProjectSourceFiles({
3686
+ sources: filesystemSources,
3687
+ filter: (file) => !excluded.has((0, _weapp_tailwindcss_source_scan.resolveSourceScanPath)(file))
3688
+ });
3689
+ onFiles?.(files);
3690
+ for (const file of files) {
3691
+ let content;
3692
+ try {
3693
+ content = await (0, node_fs_promises.readFile)(file, "utf8");
3694
+ } catch (error) {
3695
+ const code = error?.code;
3696
+ if (code === "ENOENT" || code === "ENOTDIR") continue;
3697
+ throw error;
3698
+ }
3699
+ for (const candidate of await extractRawCandidatesWithPositions(content, node_path.default.extname(file).slice(1), extractOptions)) rawCandidates.add(candidate.rawCandidate);
3700
+ }
3701
+ }
3621
3702
  const inlineSources = extractTailwindV4InlineSourceCandidates(source.css);
3622
3703
  for (const candidate of inlineSources.included) rawCandidates.add(candidate);
3623
3704
  for (const candidate of inlineSources.excluded) rawCandidates.delete(candidate);
@@ -3630,6 +3711,7 @@ var TailwindGenerationSessionImpl = class {
3630
3711
  runtimes = /* @__PURE__ */ new Map();
3631
3712
  designSystemPromise;
3632
3713
  disposed = false;
3714
+ moduleDependencies = /* @__PURE__ */ new Set();
3633
3715
  constructor(source) {
3634
3716
  this.currentSource = source;
3635
3717
  }
@@ -3662,10 +3744,15 @@ var TailwindGenerationSessionImpl = class {
3662
3744
  invalidate(change) {
3663
3745
  if (this.disposed) return;
3664
3746
  if (change.type === "source") this.currentSource = change.source;
3747
+ (0, _tailwindcss_node_require_cache.clearRequireCache)([...this.moduleDependencies]);
3748
+ invalidateGenerationModuleCache();
3749
+ this.moduleDependencies.clear();
3665
3750
  this.runtimes.clear();
3666
3751
  this.designSystemPromise = void 0;
3667
3752
  }
3668
3753
  dispose() {
3754
+ (0, _tailwindcss_node_require_cache.clearRequireCache)([...this.moduleDependencies]);
3755
+ this.moduleDependencies.clear();
3669
3756
  this.runtimes.clear();
3670
3757
  this.designSystemPromise = void 0;
3671
3758
  this.disposed = true;
@@ -3673,12 +3760,12 @@ var TailwindGenerationSessionImpl = class {
3673
3760
  assertActive() {
3674
3761
  if (this.disposed) throw new Error("Tailwind generation session has been disposed.");
3675
3762
  }
3676
- getRuntime(compileSourceEntries) {
3763
+ getRuntime(compileSourceEntries, designSystem) {
3677
3764
  this.assertActive();
3678
3765
  const cached = this.runtimes.get(compileSourceEntries);
3679
3766
  if (cached) return cached;
3680
3767
  const source = compileSourceEntries ? this.currentSource : stripCompiledSourceEntries(this.currentSource);
3681
- const promise = Promise.all([compileTailwindV4Source(source), loadTailwindV4DesignSystem(source, { cache: false })]).then(([compiledSource, designSystem]) => ({
3768
+ const promise = Promise.all([compileTailwindV4Source(source), designSystem ?? loadTailwindV4DesignSystem(source, { cache: false })]).then(([compiledSource, designSystem]) => ({
3682
3769
  compiled: compiledSource.compiled,
3683
3770
  dependencies: compiledSource.dependencies,
3684
3771
  designSystem,
@@ -3690,28 +3777,32 @@ var TailwindGenerationSessionImpl = class {
3690
3777
  });
3691
3778
  return promise;
3692
3779
  }
3693
- async resetRuntime(compileSourceEntries) {
3780
+ async resetRuntime(compileSourceEntries, designSystem) {
3694
3781
  this.runtimes.delete(compileSourceEntries);
3695
- return this.getRuntime(compileSourceEntries);
3782
+ return this.getRuntime(compileSourceEntries, designSystem);
3696
3783
  }
3697
3784
  async generateInternal(request) {
3698
3785
  this.assertActive();
3699
3786
  const options = toGenerateOptions(request);
3700
3787
  const compileSourceEntries = shouldCompileSourceEntries(options);
3701
3788
  let runtime = await this.getRuntime(compileSourceEntries);
3702
- const rawCandidates = await collectRawCandidates(this.currentSource, options, runtime.compiled.root, runtime.compiled.sources);
3789
+ const sourceFiles = [];
3790
+ let rawCandidates = await collectRawCandidates(this.currentSource, options, runtime.compiled.root, runtime.compiled.sources, (files) => sourceFiles.push(...files));
3791
+ if (request.prepareCandidates) rawCandidates = new Set(request.prepareCandidates(rawCandidates));
3703
3792
  const classSet = resolveValidTailwindV4Candidates(runtime.designSystem, rawCandidates, { ...options.bareArbitraryValues === void 0 ? {} : { bareArbitraryValues: options.bareArbitraryValues } });
3704
3793
  const inlineSources = extractTailwindV4InlineSourceCandidates(this.currentSource.css);
3705
3794
  for (const candidate of inlineSources.excluded) classSet.delete(candidate);
3706
3795
  const buildCandidates = new Set(canonicalizeBareArbitraryValueCandidates(classSet, options.bareArbitraryValues));
3707
- if ([...runtime.builtCandidates].some((candidate) => !buildCandidates.has(candidate))) runtime = await this.resetRuntime(compileSourceEntries);
3796
+ if ([...runtime.builtCandidates].some((candidate) => !buildCandidates.has(candidate))) runtime = await this.resetRuntime(compileSourceEntries, runtime.designSystem);
3708
3797
  const css = replaceBareArbitraryValueSelectors(runtime.compiled.build([...buildCandidates]), classSet, options.bareArbitraryValues);
3709
3798
  runtime.builtCandidates = new Set(buildCandidates);
3799
+ for (const dependency of runtime.dependencies) this.moduleDependencies.add(dependency);
3800
+ const dependencies = [.../* @__PURE__ */ new Set([...runtime.dependencies, ...sourceFiles])];
3710
3801
  return {
3711
3802
  css,
3712
3803
  classSet,
3713
3804
  rawCandidates,
3714
- dependencies: Array.from(runtime.dependencies),
3805
+ dependencies,
3715
3806
  sources: runtime.compiled.sources,
3716
3807
  root: runtime.compiled.root
3717
3808
  };
@@ -3729,6 +3820,9 @@ function createTailwindV4Engine(source) {
3729
3820
  const session = createTailwindV4EngineGenerationSession(source);
3730
3821
  return {
3731
3822
  source,
3823
+ dispose() {
3824
+ session.dispose();
3825
+ },
3732
3826
  loadDesignSystem() {
3733
3827
  return session.loadDesignSystem();
3734
3828
  },
@@ -3885,16 +3979,21 @@ async function collectTailwindV4StyleCandidates(options) {
3885
3979
  async function generateTailwindV4Style(options = {}) {
3886
3980
  const source = options.source ?? await resolveTailwindV4Source(createSourceOptions(options));
3887
3981
  const candidates = await collectTailwindV4StyleCandidates(options);
3888
- const result = await createTailwindV4Engine(source).generate({
3889
- candidates,
3890
- ...options.bareArbitraryValues === void 0 ? {} : { bareArbitraryValues: options.bareArbitraryValues },
3891
- ...options.scanSources === void 0 ? {} : { scanSources: options.scanSources }
3892
- });
3893
- return {
3894
- ...result,
3895
- tokens: result.rawCandidates,
3896
- source
3897
- };
3982
+ const engine = createTailwindV4Engine(source);
3983
+ try {
3984
+ const result = await engine.generate({
3985
+ candidates,
3986
+ ...options.bareArbitraryValues === void 0 ? {} : { bareArbitraryValues: options.bareArbitraryValues },
3987
+ ...options.scanSources === void 0 ? {} : { scanSources: options.scanSources }
3988
+ });
3989
+ return {
3990
+ ...result,
3991
+ tokens: result.rawCandidates,
3992
+ source
3993
+ };
3994
+ } finally {
3995
+ engine.dispose?.();
3996
+ }
3898
3997
  }
3899
3998
  //#endregion
3900
3999
  Object.defineProperty(exports, "TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN", {
@@ -3927,12 +4026,6 @@ Object.defineProperty(exports, "__toESM", {
3927
4026
  return __toESM;
3928
4027
  }
3929
4028
  });
3930
- Object.defineProperty(exports, "buildLineOffsets", {
3931
- enumerable: true,
3932
- get: function() {
3933
- return buildLineOffsets;
3934
- }
3935
- });
3936
4029
  Object.defineProperty(exports, "canonicalizeBareArbitraryValueCandidates", {
3937
4030
  enumerable: true,
3938
4031
  get: function() {
@@ -3999,30 +4092,12 @@ Object.defineProperty(exports, "createTailwindV4SourceExclusionMatcher", {
3999
4092
  return createTailwindV4SourceExclusionMatcher;
4000
4093
  }
4001
4094
  });
4002
- Object.defineProperty(exports, "createTokenLocation", {
4003
- enumerable: true,
4004
- get: function() {
4005
- return createTokenLocation;
4006
- }
4007
- });
4008
4095
  Object.defineProperty(exports, "escapeCssClassName", {
4009
4096
  enumerable: true,
4010
4097
  get: function() {
4011
4098
  return escapeCssClassName;
4012
4099
  }
4013
4100
  });
4014
- Object.defineProperty(exports, "expandTailwindV4SourceEntries", {
4015
- enumerable: true,
4016
- get: function() {
4017
- return expandTailwindV4SourceEntries;
4018
- }
4019
- });
4020
- Object.defineProperty(exports, "expandTailwindV4SourceEntryBraces", {
4021
- enumerable: true,
4022
- get: function() {
4023
- return expandTailwindV4SourceEntryBraces;
4024
- }
4025
- });
4026
4101
  Object.defineProperty(exports, "extractBareArbitraryValueSourceCandidates", {
4027
4102
  enumerable: true,
4028
4103
  get: function() {
@@ -4035,6 +4110,12 @@ Object.defineProperty(exports, "extractBareArbitraryValueSourceCandidatesWithPos
4035
4110
  return extractBareArbitraryValueSourceCandidatesWithPositions;
4036
4111
  }
4037
4112
  });
4113
+ Object.defineProperty(exports, "extractProjectCandidatesWithPositions", {
4114
+ enumerable: true,
4115
+ get: function() {
4116
+ return extractProjectCandidatesWithPositions;
4117
+ }
4118
+ });
4038
4119
  Object.defineProperty(exports, "extractRawCandidates", {
4039
4120
  enumerable: true,
4040
4121
  get: function() {
@@ -4071,22 +4152,16 @@ Object.defineProperty(exports, "generateTailwindV4Style", {
4071
4152
  return generateTailwindV4Style;
4072
4153
  }
4073
4154
  });
4074
- Object.defineProperty(exports, "getOxideModule", {
4075
- enumerable: true,
4076
- get: function() {
4077
- return getOxideModule;
4078
- }
4079
- });
4080
4155
  Object.defineProperty(exports, "getTailwindV4DesignSystemCacheKey", {
4081
4156
  enumerable: true,
4082
4157
  get: function() {
4083
4158
  return getTailwindV4DesignSystemCacheKey;
4084
4159
  }
4085
4160
  });
4086
- Object.defineProperty(exports, "groupTailwindV4SourceEntriesByBase", {
4161
+ Object.defineProperty(exports, "groupTokensByFile", {
4087
4162
  enumerable: true,
4088
4163
  get: function() {
4089
- return groupTailwindV4SourceEntriesByBase;
4164
+ return groupTokensByFile;
4090
4165
  }
4091
4166
  });
4092
4167
  Object.defineProperty(exports, "isBareArbitraryValuesEnabled", {
@@ -4095,12 +4170,6 @@ Object.defineProperty(exports, "isBareArbitraryValuesEnabled", {
4095
4170
  return isBareArbitraryValuesEnabled;
4096
4171
  }
4097
4172
  });
4098
- Object.defineProperty(exports, "isFileExcludedByTailwindV4SourceEntries", {
4099
- enumerable: true,
4100
- get: function() {
4101
- return isFileExcludedByTailwindV4SourceEntries;
4102
- }
4103
- });
4104
4173
  Object.defineProperty(exports, "isFileMatchedByTailwindV4SourceEntries", {
4105
4174
  enumerable: true,
4106
4175
  get: function() {
@@ -4119,18 +4188,6 @@ Object.defineProperty(exports, "loadTailwindV4NodeModule", {
4119
4188
  return loadTailwindV4NodeModule;
4120
4189
  }
4121
4190
  });
4122
- Object.defineProperty(exports, "mergeTailwindV4SourceEntries", {
4123
- enumerable: true,
4124
- get: function() {
4125
- return mergeTailwindV4SourceEntries;
4126
- }
4127
- });
4128
- Object.defineProperty(exports, "normalizeGlobPattern", {
4129
- enumerable: true,
4130
- get: function() {
4131
- return normalizeGlobPattern;
4132
- }
4133
- });
4134
4191
  Object.defineProperty(exports, "normalizeTailwindV4ScannerSources", {
4135
4192
  enumerable: true,
4136
4193
  get: function() {
@@ -4155,10 +4212,10 @@ Object.defineProperty(exports, "resolveBareArbitraryValueCandidate", {
4155
4212
  return resolveBareArbitraryValueCandidate;
4156
4213
  }
4157
4214
  });
4158
- Object.defineProperty(exports, "resolveSourceScanPath", {
4215
+ Object.defineProperty(exports, "resolveProjectSourceFiles", {
4159
4216
  enumerable: true,
4160
4217
  get: function() {
4161
- return resolveSourceScanPath;
4218
+ return resolveProjectSourceFiles;
4162
4219
  }
4163
4220
  });
4164
4221
  Object.defineProperty(exports, "resolveTailwindV4Source", {
@@ -4185,15 +4242,3 @@ Object.defineProperty(exports, "resolveValidTailwindV4Candidates", {
4185
4242
  return resolveValidTailwindV4Candidates;
4186
4243
  }
4187
4244
  });
4188
- Object.defineProperty(exports, "toExtension", {
4189
- enumerable: true,
4190
- get: function() {
4191
- return toExtension;
4192
- }
4193
- });
4194
- Object.defineProperty(exports, "toPosixPath", {
4195
- enumerable: true,
4196
- get: function() {
4197
- return toPosixPath;
4198
- }
4199
- });