@animus-ui/vite-plugin 0.1.0-next.v7 → 0.1.1-beta.2

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.cjs ADDED
@@ -0,0 +1,872 @@
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ //#region \0rolldown/runtime.js
6
+ var __create = Object.create;
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
+ var __getOwnPropNames = Object.getOwnPropertyNames;
10
+ var __getProtoOf = Object.getPrototypeOf;
11
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
14
+ key = keys[i];
15
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
16
+ get: ((k) => from[k]).bind(null, key),
17
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
18
+ });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
23
+ value: mod,
24
+ enumerable: true
25
+ }) : target, mod));
26
+ //#endregion
27
+ let _animus_ui_extract_pipeline = require("@animus-ui/extract/pipeline");
28
+ let browserslist = require("browserslist");
29
+ browserslist = __toESM(browserslist);
30
+ let crypto = require("crypto");
31
+ let fs = require("fs");
32
+ let lightningcss = require("lightningcss");
33
+ let path = require("path");
34
+ //#region src/analyze-project-args.ts
35
+ /** @internal */
36
+ function buildAnalyzeProjectArgs(inputs) {
37
+ return [
38
+ inputs.filesJson,
39
+ inputs.scalesJson,
40
+ inputs.variableMapJson,
41
+ inputs.contextualVarsJson,
42
+ inputs.propConfigJson,
43
+ inputs.groupRegistryJson,
44
+ inputs.packageResolutionJson,
45
+ inputs.devMode,
46
+ inputs.emitterConfigJson,
47
+ inputs.selectorAliasesJson,
48
+ null,
49
+ inputs.globalStyleBlocksJson,
50
+ inputs.pathAliasesJson,
51
+ inputs.keyframesJson
52
+ ];
53
+ }
54
+ //#endregion
55
+ //#region src/manifest-diagnostics.ts
56
+ function surfaceManifestDiagnostics(manifest, warn) {
57
+ for (const diagnostic of manifest.diagnostics ?? []) if (diagnostic.kind === "bail") warn(`⚠ ${diagnostic.component} not extracted: ${diagnostic.message}`);
58
+ else if (diagnostic.kind === "skip") warn(`⚠ ${diagnostic.component}: skipped ${diagnostic.message}`);
59
+ else if (diagnostic.kind === "warn") warn(`⚠ ${diagnostic.file}: ${diagnostic.component}: ${diagnostic.message}`);
60
+ }
61
+ //#endregion
62
+ //#region src/index.ts
63
+ const VIRTUAL_CSS_ID = "virtual:animus/styles.css";
64
+ const RESOLVED_CSS_ID = "\0virtual:animus/styles.css";
65
+ const VIRTUAL_COMPONENTS_ID = "virtual:animus/components.js";
66
+ const RESOLVED_COMPONENTS_ID = "\0virtual:animus/components.js";
67
+ const VIRTUAL_BRIDGE_ID = "virtual:animus/hmr-bridge.js";
68
+ const RESOLVED_BRIDGE_ID = "\0virtual:animus/hmr-bridge.js";
69
+ const VIRTUAL_SYSTEM_PROPS_ID = "virtual:animus/system-props";
70
+ const RESOLVED_SYSTEM_PROPS_ID = "\0virtual:animus/system-props";
71
+ const DEFAULT_EXCLUDE = [
72
+ "node_modules",
73
+ "dist",
74
+ ".test.",
75
+ ".spec."
76
+ ];
77
+ function discoverFiles(dir, rootDir, excludePatterns, extensionsSet) {
78
+ const results = [];
79
+ let entries;
80
+ try {
81
+ entries = (0, fs.readdirSync)(dir, { encoding: "utf8" });
82
+ } catch {
83
+ return results;
84
+ }
85
+ for (const entry of entries) {
86
+ const fullPath = (0, path.join)(dir, entry);
87
+ const relativePath = (0, path.relative)(rootDir, fullPath);
88
+ if (excludePatterns.some((pattern) => fullPath.includes(pattern) || relativePath.includes(pattern))) continue;
89
+ let stat;
90
+ try {
91
+ stat = (0, fs.statSync)(fullPath);
92
+ } catch {
93
+ continue;
94
+ }
95
+ if (stat.isDirectory()) results.push(...discoverFiles(fullPath, rootDir, excludePatterns, extensionsSet));
96
+ else if (extensionsSet.has((0, path.extname)(entry))) results.push(fullPath);
97
+ }
98
+ return results;
99
+ }
100
+ /**
101
+ * Resolve browser targets for Lightning CSS.
102
+ * Priority: explicit config → project browserslist → 'defaults' fallback.
103
+ */
104
+ function resolveLightningTargets(explicitTargets, rootDir) {
105
+ let queries;
106
+ if (explicitTargets) queries = Array.isArray(explicitTargets) ? explicitTargets : [explicitTargets];
107
+ else {
108
+ const detected = (0, browserslist.default)(void 0, { path: rootDir });
109
+ queries = detected.length > 0 ? detected : (0, browserslist.default)("defaults");
110
+ }
111
+ return (0, lightningcss.browserslistToTargets)(Array.isArray(queries) && typeof queries[0] === "string" && queries[0].includes(" ") ? (0, browserslist.default)(queries) : queries);
112
+ }
113
+ /**
114
+ * Post-process CSS with Lightning CSS: autoprefixing + optional minification.
115
+ * On failure, returns the original CSS and logs a warning.
116
+ */
117
+ function postProcessCss(css, opts) {
118
+ if (!css) return css;
119
+ try {
120
+ return (0, lightningcss.transform)({
121
+ filename: "animus-extracted.css",
122
+ code: Buffer.from(css),
123
+ minify: opts.minify,
124
+ targets: opts.targets
125
+ }).code.toString();
126
+ } catch (e) {
127
+ const msg = e instanceof Error ? e.message : String(e);
128
+ (opts.warnFn ?? console.warn)(`[animus] Lightning CSS post-processing failed: ${msg}`);
129
+ return css;
130
+ }
131
+ }
132
+ /** Compute MD5 content hash for a string. */
133
+ function contentHash(source) {
134
+ return (0, crypto.createHash)("md5").update(source).digest("hex");
135
+ }
136
+ /**
137
+ * Reconstruct file entries from cache, including content hashes.
138
+ * For unchanged files (hash matches changedPath), sends empty source
139
+ * to avoid serializing full source text across the NAPI boundary.
140
+ * Rust cache-hit path never reads file.source, so empty string is safe.
141
+ */
142
+ function buildFileEntriesFromCache(cache, changedPath) {
143
+ const entries = [];
144
+ for (const [path$1, { hash, source }] of cache) entries.push({
145
+ path: path$1,
146
+ source: path$1 === changedPath ? source : "",
147
+ hash
148
+ });
149
+ return entries;
150
+ }
151
+ function animusExtract(options) {
152
+ const resolvedEngine = options.engine ?? "v2";
153
+ const engineModuleId = resolvedEngine === "v2" ? "@animus-ui/extract/engine-v2" : "@animus-ui/extract";
154
+ const requireEngine = () => require(engineModuleId);
155
+ let v2Engine = null;
156
+ const v2SentSources = /* @__PURE__ */ new Map();
157
+ let v2DriftWarned = false;
158
+ const engineApi = () => {
159
+ if (resolvedEngine !== "v2") return requireEngine();
160
+ const native = requireEngine();
161
+ return {
162
+ loadSystemModule: (...args) => native.loadSystemModule(...args),
163
+ analyzeProject: (filesJsonRaw, themeJson_, variableMapJson_, contextualVarsJson_, configJson_, groupRegistryJson_, packageResolutionJson_, devMode, emitterConfigJson, selectorAliasesJson_, _selectorOrderJson, globalStyleBlocksJson_, pathAliasesJson_, keyframesJson_) => {
164
+ let filesJson = filesJsonRaw;
165
+ if (filesJsonRaw.includes("\"source\":\"\"")) {
166
+ const entries = JSON.parse(filesJsonRaw);
167
+ for (const entry of entries) if (entry.source === "") entry.source = fileCache.get(entry.path)?.source ?? "";
168
+ filesJson = JSON.stringify(entries);
169
+ }
170
+ v2SentSources.clear();
171
+ for (const entry of JSON.parse(filesJson)) v2SentSources.set(entry.path, entry.source);
172
+ const emitterConfig = emitterConfigJson ? JSON.parse(emitterConfigJson) : {};
173
+ v2Engine = null;
174
+ const engine = new native.ExtractEngine({
175
+ runtimeImport: emitterConfig.runtime_import ?? void 0,
176
+ cssModuleId: emitterConfig.css_module_id ?? void 0,
177
+ systemPropsModuleId: emitterConfig.system_props_module_id ?? void 0,
178
+ themeJson: themeJson_,
179
+ variableMapJson: variableMapJson_,
180
+ contextualVarsJson: contextualVarsJson_ ?? void 0,
181
+ configJson: configJson_,
182
+ groupRegistryJson: groupRegistryJson_,
183
+ selectorAliasesJson: selectorAliasesJson_ ?? void 0,
184
+ globalStyleBlocksJson: globalStyleBlocksJson_ ?? void 0,
185
+ keyframesJson: keyframesJson_ ?? void 0,
186
+ packageResolutionJson: packageResolutionJson_ ?? void 0,
187
+ pathAliasesJson: pathAliasesJson_ ?? void 0,
188
+ devMode
189
+ });
190
+ v2Engine = engine;
191
+ return engine.analyze(filesJson);
192
+ },
193
+ transformFile: (source, path$2, _manifest) => {
194
+ if (!v2Engine) throw new Error("[animus-extract] v2 transform before analyze — engine state is per-instance");
195
+ const sent = v2SentSources.get(path$2);
196
+ if (sent !== void 0 && sent !== source && !v2DriftWarned) {
197
+ v2DriftWarned = true;
198
+ console.warn(`[animus-extract] v2: transform-time source for ${path$2} differs from analyze-time source — an upstream plugin transform may be reverted (engine v2 emits from analyzed sources)`);
199
+ }
200
+ return JSON.parse(v2Engine.transformFile(path$2));
201
+ },
202
+ clearAnalysisCache: () => {
203
+ if (v2Engine) v2Engine.clearCache();
204
+ v2Engine = null;
205
+ }
206
+ };
207
+ };
208
+ let themeJson = "{}";
209
+ let variableMapJson = "{}";
210
+ let contextualVarsJson = "{}";
211
+ let configJson = "{}";
212
+ let groupRegistryJson = "{}";
213
+ let selectorAliasesJson = null;
214
+ let isProd = false;
215
+ let rootDir = "";
216
+ const verbose = options.verbose || process.env.ANIMUS_DEBUG === "1" || process.env.ANIMUS_DEBUG === "true";
217
+ let logger = null;
218
+ function log(msg) {
219
+ if (verbose) (logger ?? console).info(`[animus] ${msg}`);
220
+ }
221
+ function warn(msg) {
222
+ (logger ?? console).warn(`[animus] ${msg}`);
223
+ }
224
+ function logTimingWaterfall(timing) {
225
+ if (!verbose) return;
226
+ for (const [key, label] of [
227
+ ["parseAndWalk", "parse+walk"],
228
+ ["importResolution", "imports"],
229
+ ["extensionProvenance", "provenance"],
230
+ ["topologicalSort", "topo-sort"],
231
+ ["chainEvaluation", "chains"],
232
+ ["jsxScanning", "jsx-scan"],
233
+ ["systemPropAggregation", "sys-props"],
234
+ ["usageLedger", "usage"],
235
+ ["reconciliation", "reconcile"],
236
+ ["cssGeneration", "css-gen"],
237
+ ["manifestSerialization", "serialize"]
238
+ ]) {
239
+ const ms = timing[key] ?? 0;
240
+ const pad = " ".repeat(Math.max(0, 15 - label.length));
241
+ const extra = key === "parseAndWalk" ? ` (${timing.fileCount ?? 0} files, ${timing.cacheHits ?? 0} cached)` : "";
242
+ log(` ${label}${pad}${String(ms).padStart(5)}ms${extra}`);
243
+ }
244
+ }
245
+ let lcssTargets = {};
246
+ let variableCss = "";
247
+ let globalCss = "";
248
+ let globalStyleBlocksJson = null;
249
+ let keyframesBlocksJson = null;
250
+ let pathAliasesJson = null;
251
+ let extensionsSet = new Set(options.extensions ?? _animus_ui_extract_pipeline.DEFAULT_EXTENSIONS);
252
+ let storedManifest = null;
253
+ let storedManifestJson = "";
254
+ let resolvedComponentCss = "";
255
+ let storedSheets = null;
256
+ let layerDeclaration = "";
257
+ let fragmentCache = /* @__PURE__ */ new Map();
258
+ let reverseProvenance = {};
259
+ let storedSystemPropMapJson = "{}";
260
+ let storedDynamicPropsJson = "{}";
261
+ let storedTransformsSource = "{}";
262
+ const fileCache = /* @__PURE__ */ new Map();
263
+ let packageMap = {};
264
+ let externalPackageDirs = [];
265
+ const externalSourceEntries = /* @__PURE__ */ new Map();
266
+ let devServer;
267
+ let bridgeInjected = false;
268
+ let resolvedSystemPath = null;
269
+ /**
270
+ * Load a SystemInstance via Rust NAPI (rquickjs bundled eval).
271
+ * The Rust crate reads the system file, strips TS types via OXC, resolves
272
+ * workspace package dependencies, bundles all modules, evaluates with
273
+ * rquickjs, and returns serialized config directly — no subprocess needed.
274
+ */
275
+ function loadSystem() {
276
+ resolvedSystemPath = (0, path.resolve)(rootDir, options.system);
277
+ try {
278
+ const { loadSystemModule } = engineApi();
279
+ const config = loadSystemModule(resolvedSystemPath, rootDir);
280
+ configJson = config.propConfig;
281
+ groupRegistryJson = config.groupRegistry;
282
+ selectorAliasesJson = config.selectorAliases || null;
283
+ themeJson = config.scalesJson;
284
+ variableMapJson = config.variableMapJson;
285
+ variableCss = config.variableCss;
286
+ contextualVarsJson = config.contextualVarsJson;
287
+ globalStyleBlocksJson = config.globalStyleBlocks || null;
288
+ keyframesBlocksJson = config.keyframesBlocks || null;
289
+ } catch (e) {
290
+ if (options.strict) throw new Error(`[animus-extract] Failed to load system from ${resolvedSystemPath}: ${e}`, { cause: e });
291
+ console.warn(`[animus-extract] Failed to load system from ${resolvedSystemPath}:`, e);
292
+ }
293
+ }
294
+ /**
295
+ * Run project analysis and update the manifest.
296
+ *
297
+ * Pipeline: NAPI analyzeProject → unit fallback.
298
+ * Transforms are resolved in-process via boa_engine during Rust extraction.
299
+ * No subprocess needed.
300
+ */
301
+ function runAnalysis(fileEntries) {
302
+ try {
303
+ const { analyzeProject } = engineApi();
304
+ const emitterConfig = JSON.stringify({
305
+ runtime_import: "@animus-ui/system",
306
+ css_module_id: "virtual:animus/styles.css"
307
+ });
308
+ const manifestJson = analyzeProject(...buildAnalyzeProjectArgs({
309
+ filesJson: JSON.stringify(fileEntries),
310
+ scalesJson: themeJson,
311
+ variableMapJson,
312
+ contextualVarsJson: contextualVarsJson || null,
313
+ propConfigJson: configJson,
314
+ groupRegistryJson,
315
+ packageResolutionJson: JSON.stringify(packageMap),
316
+ devMode: !isProd,
317
+ emitterConfigJson: emitterConfig,
318
+ selectorAliasesJson,
319
+ globalStyleBlocksJson,
320
+ pathAliasesJson,
321
+ keyframesJson: keyframesBlocksJson
322
+ }));
323
+ storedManifest = JSON.parse(manifestJson);
324
+ storedManifestJson = manifestJson;
325
+ surfaceManifestDiagnostics(storedManifest, warn);
326
+ storedSystemPropMapJson = JSON.stringify(storedManifest?.system_prop_map ?? {});
327
+ const dynamicProps = storedManifest?.dynamic_props ?? {};
328
+ const newDynamicPropsJson = JSON.stringify(dynamicProps);
329
+ if (newDynamicPropsJson !== storedDynamicPropsJson) {
330
+ storedDynamicPropsJson = newDynamicPropsJson;
331
+ const usedTransformNames = /* @__PURE__ */ new Set();
332
+ for (const meta of Object.values(dynamicProps)) if (meta.transform_name) usedTransformNames.add(meta.transform_name);
333
+ if (storedManifest?.components) {
334
+ for (const comp of Object.values(storedManifest.components)) if (comp.replacement) {
335
+ const matches = comp.replacement.matchAll(/transforms\.(\w+)/g);
336
+ for (const match of matches) usedTransformNames.add(match[1]);
337
+ }
338
+ }
339
+ storedTransformsSource = "{}";
340
+ }
341
+ bridgeInjected = false;
342
+ const newFragments = storedManifest?.component_fragments;
343
+ if (newFragments && typeof newFragments === "object") {
344
+ fragmentCache.clear();
345
+ for (const [id, sheets] of Object.entries(newFragments)) fragmentCache.set(id, sheets);
346
+ }
347
+ reverseProvenance = storedManifest?.reverse_provenance ?? {};
348
+ storedSheets = storedManifest?.sheets ?? null;
349
+ globalCss = storedManifest?.sheets?.global || "";
350
+ resolvedComponentCss = storedManifest?.css || "";
351
+ resolvedComponentCss = (0, _animus_ui_extract_pipeline.applyUnitFallback)(resolvedComponentCss);
352
+ } catch (e) {
353
+ if (options.strict) throw new Error(`[animus-extract] analyzeProject failed: ${e}`, { cause: e });
354
+ console.warn("[animus-extract] analyzeProject failed:", e);
355
+ }
356
+ }
357
+ function runSelfVerify() {
358
+ const failures = [];
359
+ if (resolvedComponentCss.trim().length === 0) failures.push("No component CSS produced — check system file and include patterns");
360
+ if (!variableCss.includes(":root")) failures.push("No :root variable block found in variable CSS");
361
+ if (`${variableCss}\n${globalCss}\n${resolvedComponentCss}`.includes("__TRANSFORM__")) failures.push("Unresolved __TRANSFORM__ placeholders found in CSS output");
362
+ if (storedManifest && resolvedComponentCss.length > 0) {
363
+ const assembled = (0, _animus_ui_extract_pipeline.assembleStylesheet)({
364
+ layers: options.layers,
365
+ variableCss,
366
+ globalCss,
367
+ componentCss: resolvedComponentCss
368
+ });
369
+ const baseIdx = assembled.search(/@layer\s+anm-base\s*\{/);
370
+ const variantsIdx = assembled.search(/@layer\s+anm-variants\s*\{/);
371
+ if (baseIdx !== -1 && variantsIdx !== -1 && baseIdx >= variantsIdx) failures.push(`CSS layer ordering violated — @layer anm-base (offset ${baseIdx}) must precede @layer anm-variants (offset ${variantsIdx})`);
372
+ }
373
+ for (const message of failures) {
374
+ const line = `[animus:verify] ${message}`;
375
+ if (options.strict) throw new Error(line);
376
+ if (logger) logger.warn(line, { timestamp: true });
377
+ else console.warn(line);
378
+ }
379
+ if (failures.length === 0) log("[animus:verify] structural self-check passed");
380
+ }
381
+ return {
382
+ name: "animus-extract",
383
+ enforce: "pre",
384
+ configureServer(server) {
385
+ devServer = server;
386
+ },
387
+ configResolved(config) {
388
+ isProd = config.command === "build";
389
+ rootDir = config.root;
390
+ logger = config.logger;
391
+ lcssTargets = resolveLightningTargets(options.targets, rootDir);
392
+ log(`Lightning CSS targets resolved (${Object.keys(lcssTargets).length} browsers)`);
393
+ const rawAlias = config.resolve?.alias;
394
+ if (rawAlias) {
395
+ const entries = [];
396
+ if (Array.isArray(rawAlias)) {
397
+ for (const entry of rawAlias) if (typeof entry.find === "string" && typeof entry.replacement === "string") {
398
+ const replacement = entry.replacement.startsWith(rootDir) ? entry.replacement.slice(rootDir.length + 1) : entry.replacement;
399
+ entries.push({
400
+ pattern: entry.find.endsWith("/") ? entry.find : entry.find + "/",
401
+ replacement: replacement.endsWith("/") ? replacement : replacement + "/",
402
+ type: "prefix"
403
+ });
404
+ }
405
+ } else if (typeof rawAlias === "object" && rawAlias !== null) {
406
+ for (const [key, value] of Object.entries(rawAlias)) if (typeof value === "string") {
407
+ const replacement = value.startsWith(rootDir) ? value.slice(rootDir.length + 1) : value;
408
+ if (/\.\w+$/.test(replacement)) entries.push({
409
+ pattern: key,
410
+ replacement,
411
+ type: "exact"
412
+ });
413
+ else entries.push({
414
+ pattern: key.endsWith("/") ? key : key + "/",
415
+ replacement: replacement.endsWith("/") ? replacement : replacement + "/",
416
+ type: "prefix"
417
+ });
418
+ }
419
+ }
420
+ entries.sort((a, b) => b.pattern.length - a.pattern.length);
421
+ if (entries.length > 0) {
422
+ pathAliasesJson = JSON.stringify({ aliases: entries });
423
+ log(`Path aliases forwarded: ${entries.length} entries`);
424
+ }
425
+ }
426
+ },
427
+ async buildStart() {
428
+ try {
429
+ const { clearAnalysisCache } = engineApi();
430
+ clearAnalysisCache();
431
+ } catch {}
432
+ let t0 = performance.now();
433
+ loadSystem();
434
+ if (options.layers) {
435
+ (0, _animus_ui_extract_pipeline.validateLayerOrder)(options.layers);
436
+ log(`Custom layers: [${options.layers.join(", ")}]`);
437
+ }
438
+ if (verbose) {
439
+ const propCount = Object.keys(JSON.parse(configJson)).length;
440
+ const groupCount = Object.keys(JSON.parse(groupRegistryJson)).length;
441
+ log(`System loaded: ${propCount} props, ${groupCount} groups (${Math.round(performance.now() - t0)}ms)`);
442
+ }
443
+ t0 = performance.now();
444
+ const excludePatterns = options.exclude ?? DEFAULT_EXCLUDE;
445
+ extensionsSet = new Set(options.extensions ?? _animus_ui_extract_pipeline.DEFAULT_EXTENSIONS);
446
+ const shouldHandleMdx = extensionsSet.has(".mdx");
447
+ let mdxMissingDepWarned = false;
448
+ const filePaths = discoverFiles(rootDir, rootDir, excludePatterns, extensionsSet);
449
+ const fileEntries = [];
450
+ for (const filePath of filePaths) try {
451
+ let source = (0, fs.readFileSync)(filePath, "utf-8");
452
+ let relPath = (0, path.relative)(rootDir, filePath);
453
+ if (shouldHandleMdx && (0, path.extname)(filePath) === ".mdx") {
454
+ const result = await (0, _animus_ui_extract_pipeline.preprocessMdx)(source, relPath);
455
+ if (result.kind === "missing-dep") {
456
+ if (!mdxMissingDepWarned) {
457
+ warn("⚠ .mdx in extensions but @mdx-js/mdx not installed; MDX files skipped");
458
+ mdxMissingDepWarned = true;
459
+ }
460
+ continue;
461
+ }
462
+ if (result.kind === "error") {
463
+ warn(`⚠ MDX preprocessing failed for ${relPath}: ${result.error}`);
464
+ continue;
465
+ }
466
+ source = result.source;
467
+ relPath = relPath + ".tsx";
468
+ }
469
+ const hash = !isProd ? contentHash(source) : void 0;
470
+ fileEntries.push({
471
+ path: relPath,
472
+ source,
473
+ hash
474
+ });
475
+ if (!isProd && hash) fileCache.set(relPath, {
476
+ hash,
477
+ source
478
+ });
479
+ } catch {}
480
+ const localFileCount = fileEntries.length;
481
+ const packageSpecifiers = (0, _animus_ui_extract_pipeline.extractSystemFilePackages)(resolvedSystemPath);
482
+ packageMap = {};
483
+ externalSourceEntries.clear();
484
+ const collectedPkgDirs = [];
485
+ for (const specifier of packageSpecifiers) try {
486
+ const resolved = await this.resolve(specifier);
487
+ if (resolved && resolved.id) {
488
+ const absPath = resolved.id;
489
+ let pkgRoot = (0, path.dirname)(absPath);
490
+ while (pkgRoot !== (0, path.dirname)(pkgRoot) && !(0, fs.existsSync)((0, path.join)(pkgRoot, "package.json"))) pkgRoot = (0, path.dirname)(pkgRoot);
491
+ const srcDir = (0, path.join)(pkgRoot, "src");
492
+ if ((0, fs.existsSync)(srcDir)) {
493
+ collectedPkgDirs.push(srcDir);
494
+ const pkgFiles = discoverFiles(srcDir, rootDir, excludePatterns, extensionsSet);
495
+ for (const pkgFile of pkgFiles) {
496
+ let pkgRelPath = (0, path.relative)(rootDir, pkgFile);
497
+ if (!fileEntries.some((e) => e.path === pkgRelPath)) {
498
+ let pkgSource = (0, fs.readFileSync)(pkgFile, "utf-8");
499
+ if (shouldHandleMdx && (0, path.extname)(pkgFile) === ".mdx") {
500
+ const result = await (0, _animus_ui_extract_pipeline.preprocessMdx)(pkgSource, pkgRelPath);
501
+ if (result.kind === "missing-dep") {
502
+ if (!mdxMissingDepWarned) {
503
+ warn("⚠ .mdx in extensions but @mdx-js/mdx not installed; MDX files skipped");
504
+ mdxMissingDepWarned = true;
505
+ }
506
+ continue;
507
+ }
508
+ if (result.kind === "error") {
509
+ warn(`⚠ MDX preprocessing failed for ${pkgRelPath}: ${result.error}`);
510
+ continue;
511
+ }
512
+ pkgSource = result.source;
513
+ pkgRelPath = pkgRelPath + ".tsx";
514
+ }
515
+ const pkgHash = !isProd ? contentHash(pkgSource) : void 0;
516
+ fileEntries.push({
517
+ path: pkgRelPath,
518
+ source: pkgSource,
519
+ hash: pkgHash
520
+ });
521
+ if (!isProd && pkgHash) fileCache.set(pkgRelPath, {
522
+ hash: pkgHash,
523
+ source: pkgSource
524
+ });
525
+ }
526
+ }
527
+ const srcEntry = (0, path.join)(srcDir, "index.ts");
528
+ if ((0, fs.existsSync)(srcEntry)) {
529
+ packageMap[specifier] = (0, path.relative)(rootDir, srcEntry);
530
+ externalSourceEntries.set(specifier, srcEntry);
531
+ } else packageMap[specifier] = (0, path.relative)(rootDir, absPath);
532
+ } else {
533
+ const relPath = (0, path.relative)(rootDir, absPath);
534
+ if (!fileEntries.some((e) => e.path === relPath)) {
535
+ const entrySource = (0, fs.readFileSync)(absPath, "utf-8");
536
+ const entryHash = !isProd ? contentHash(entrySource) : void 0;
537
+ fileEntries.push({
538
+ path: relPath,
539
+ source: entrySource,
540
+ hash: entryHash
541
+ });
542
+ if (!isProd && entryHash) fileCache.set(relPath, {
543
+ hash: entryHash,
544
+ source: entrySource
545
+ });
546
+ }
547
+ collectedPkgDirs.push((0, path.dirname)(absPath));
548
+ packageMap[specifier] = relPath;
549
+ }
550
+ }
551
+ } catch {}
552
+ externalPackageDirs = collectedPkgDirs;
553
+ const packageFileCount = fileEntries.length - localFileCount;
554
+ log(`Discovered ${fileEntries.length} files (${packageFileCount} from packages) (${Math.round(performance.now() - t0)}ms)`);
555
+ t0 = performance.now();
556
+ runAnalysis(fileEntries);
557
+ if (storedManifest) {
558
+ const report = storedManifest.report;
559
+ if (report) {
560
+ log(`Extracted ${report.components_extracted}/${report.components_total} components (${Math.round(performance.now() - t0)}ms)`);
561
+ logTimingWaterfall(storedManifest.timing ?? {});
562
+ log(`Reconciliation: ${report.components_extracted} kept, ${report.variants_eliminated} variants pruned, ${report.states_eliminated} states pruned`);
563
+ const details = report.eliminated_details || [];
564
+ for (const d of details) if (d.kind === "component") warn(`⚠ ${d.component} eliminated: ${d.reason}`);
565
+ else if (d.kind === "prospective_component") warn(`⚠ ${d.component} would be eliminated in production: ${d.reason}`);
566
+ else if (d.kind === "variant") warn(`⚠ ${d.component} variant '${d.name}' pruned: ${d.reason}`);
567
+ else if (d.kind === "state") warn(`⚠ ${d.component} state '${d.name}' pruned: ${d.reason}`);
568
+ }
569
+ log(`CSS: ${resolvedComponentCss.length} bytes (${Object.keys(storedManifest.components || {}).length} components)`);
570
+ if (!isProd && storedSheets) {
571
+ const staticSize = (0, _animus_ui_extract_pipeline.assembleStylesheet)({
572
+ layers: options.layers,
573
+ variableCss,
574
+ globalCss
575
+ }).length;
576
+ const componentSize = resolvedComponentCss.length;
577
+ log(`Delivery: split mode — static ${staticSize} bytes, components ${componentSize} bytes (adopted stylesheet)`);
578
+ } else log("Delivery: single file mode (production)");
579
+ }
580
+ const { declaration } = (0, _animus_ui_extract_pipeline.assembleStylesheet)({
581
+ layers: options.layers,
582
+ variableCss: "",
583
+ globalCss: "",
584
+ split: true
585
+ });
586
+ layerDeclaration = declaration;
587
+ if (options.verify) runSelfVerify();
588
+ },
589
+ resolveId(id) {
590
+ if (id === VIRTUAL_CSS_ID) return RESOLVED_CSS_ID;
591
+ if (id === VIRTUAL_COMPONENTS_ID) return RESOLVED_COMPONENTS_ID;
592
+ if (id === VIRTUAL_BRIDGE_ID) return RESOLVED_BRIDGE_ID;
593
+ if (id === VIRTUAL_SYSTEM_PROPS_ID) return RESOLVED_SYSTEM_PROPS_ID;
594
+ const srcEntry = externalSourceEntries.get(id);
595
+ if (srcEntry) return srcEntry;
596
+ return null;
597
+ },
598
+ load(id) {
599
+ const lcssOpts = {
600
+ minify: options.minify ?? isProd,
601
+ targets: lcssTargets,
602
+ warnFn: warn
603
+ };
604
+ if (id === RESOLVED_CSS_ID) {
605
+ if (!isProd && storedSheets) {
606
+ const { variables, body } = (0, _animus_ui_extract_pipeline.assembleStylesheet)({
607
+ layers: options.layers,
608
+ variableCss,
609
+ globalCss,
610
+ split: true
611
+ });
612
+ return [variables, postProcessCss(body, {
613
+ ...lcssOpts,
614
+ minify: false
615
+ })].filter(Boolean).join("\n");
616
+ }
617
+ const { variables, body } = (0, _animus_ui_extract_pipeline.assembleStylesheet)({
618
+ layers: options.layers,
619
+ variableCss,
620
+ globalCss,
621
+ componentCss: resolvedComponentCss,
622
+ split: true
623
+ });
624
+ return [variables, postProcessCss(body, lcssOpts)].filter(Boolean).join("\n");
625
+ }
626
+ if (id === RESOLVED_COMPONENTS_ID) return `export default \`${postProcessCss((0, _animus_ui_extract_pipeline.stripLeadingLayerDeclaration)(resolvedComponentCss || ""), {
627
+ ...lcssOpts,
628
+ minify: false
629
+ }).replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$")}\`;`;
630
+ if (id === RESOLVED_BRIDGE_ID) return `
631
+ import css from '${VIRTUAL_COMPONENTS_ID}';
632
+
633
+ const GLOBAL_KEY = '__animus_sheet_${(0, crypto.createHash)("md5").update(options.system).digest("hex").slice(0, 8)}__';
634
+ let sheet = globalThis[GLOBAL_KEY] || null;
635
+
636
+ if (typeof CSSStyleSheet !== 'undefined' && 'adoptedStyleSheets' in document) {
637
+ if (!sheet) {
638
+ sheet = new CSSStyleSheet();
639
+ globalThis[GLOBAL_KEY] = sheet;
640
+ document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
641
+ }
642
+ sheet.replaceSync(css);
643
+ } else {
644
+ // Fallback: inject or update <style> tag
645
+ let el = document.querySelector('style[data-animus-components]');
646
+ if (!el) {
647
+ el = document.createElement('style');
648
+ el.setAttribute('data-animus-components', '');
649
+ document.head.appendChild(el);
650
+ }
651
+ el.textContent = css;
652
+ }
653
+
654
+ if (import.meta.hot) {
655
+ import.meta.hot.accept('${VIRTUAL_COMPONENTS_ID}', (newModule) => {
656
+ if (sheet) {
657
+ sheet.replaceSync(newModule.default);
658
+ } else {
659
+ const el = document.querySelector('style[data-animus-components]');
660
+ if (el) el.textContent = newModule.default;
661
+ }
662
+ });
663
+ }
664
+ `;
665
+ if (id === RESOLVED_SYSTEM_PROPS_ID) {
666
+ let moduleSource = `export const systemPropMap = ${storedSystemPropMapJson};\nexport const systemPropGroups = ${groupRegistryJson};`;
667
+ if (storedDynamicPropsJson !== "{}") {
668
+ const dynamicProps = JSON.parse(storedDynamicPropsJson);
669
+ const configEntries = {};
670
+ for (const [propName, meta] of Object.entries(dynamicProps)) configEntries[propName] = {
671
+ varName: meta.var_name,
672
+ slotClass: meta.slot_class,
673
+ ...meta.transform_name ? { transformName: meta.transform_name } : {},
674
+ ...meta.scale_values && Object.keys(meta.scale_values).length > 0 ? { scaleValues: meta.scale_values } : {}
675
+ };
676
+ moduleSource += `\nexport const dynamicPropConfig = ${JSON.stringify(configEntries)};`;
677
+ } else moduleSource += `\nexport const dynamicPropConfig = {};`;
678
+ moduleSource += `\nexport const transforms = ${storedTransformsSource};`;
679
+ return moduleSource;
680
+ }
681
+ return null;
682
+ },
683
+ transform(code, id) {
684
+ if (!storedManifest) return null;
685
+ if (!externalPackageDirs.some((dir) => id.startsWith(dir))) {
686
+ if (!/\.[jt]sx?$/.test(id)) return null;
687
+ if (id.includes("node_modules")) return null;
688
+ }
689
+ const relativePath = (0, path.relative)(rootDir, id);
690
+ if (!storedManifest.files?.[relativePath]?.length) {
691
+ if (!isProd && !fileCache.has(relativePath)) {
692
+ const hash = contentHash(code);
693
+ fileCache.set(relativePath, {
694
+ hash,
695
+ source: code
696
+ });
697
+ runAnalysis(buildFileEntriesFromCache(fileCache, relativePath));
698
+ const compCount = storedManifest.files?.[relativePath]?.length ?? 0;
699
+ log(`New file detected: ${relativePath} — ${compCount ? `${compCount} components extracted` : "no components"}`);
700
+ if (compCount && devServer) {
701
+ const compModule = devServer.moduleGraph.getModuleById(RESOLVED_COMPONENTS_ID);
702
+ if (compModule) devServer.moduleGraph.invalidateModule(compModule);
703
+ const sysPropModule = devServer.moduleGraph.getModuleById(RESOLVED_SYSTEM_PROPS_ID);
704
+ if (sysPropModule) devServer.moduleGraph.invalidateModule(sysPropModule);
705
+ setTimeout(() => {
706
+ devServer.hot.send({ type: "full-reload" });
707
+ }, 100);
708
+ }
709
+ }
710
+ if (!storedManifest.files?.[relativePath]?.length) return null;
711
+ }
712
+ try {
713
+ const { transformFile } = engineApi();
714
+ const result = transformFile(code, relativePath, storedManifestJson);
715
+ if (!result.hasComponents) return null;
716
+ let transformedCode = result.code;
717
+ if (!isProd && !bridgeInjected && storedSheets) {
718
+ transformedCode = `import '${VIRTUAL_BRIDGE_ID}';\n${transformedCode}`;
719
+ bridgeInjected = true;
720
+ log("HMR bridge injected via transform");
721
+ }
722
+ if (verbose) log(`transform ${relativePath}: ${storedManifest.files?.[relativePath]?.length ?? 0} components`);
723
+ return {
724
+ code: transformedCode,
725
+ map: null
726
+ };
727
+ } catch (e) {
728
+ if (options.strict) throw new Error(`[animus-extract] Failed to transform ${id}: ${e}`, { cause: e });
729
+ console.warn(`[animus-extract] Failed to transform ${id}:`, e);
730
+ return null;
731
+ }
732
+ },
733
+ transformIndexHtml: {
734
+ order: "pre",
735
+ handler() {
736
+ if (!layerDeclaration) return [];
737
+ return [{
738
+ tag: "style",
739
+ attrs: { "data-animus-layers": "" },
740
+ children: layerDeclaration,
741
+ injectTo: "head-prepend"
742
+ }];
743
+ }
744
+ },
745
+ async handleHotUpdate({ file, server: hmrServer, modules }) {
746
+ if (isProd) return;
747
+ const ext = (0, path.extname)(file);
748
+ if (!extensionsSet.has(ext)) return;
749
+ const excludePatterns = options.exclude ?? DEFAULT_EXCLUDE;
750
+ if (!externalPackageDirs.some((dir) => file.startsWith(dir)) && excludePatterns.some((pattern) => file.includes(pattern) || (0, path.relative)(rootDir, file).includes(pattern))) return;
751
+ const absFile = (0, path.resolve)(file);
752
+ const relPath = (0, path.relative)(rootDir, absFile);
753
+ if (resolvedSystemPath && absFile === (0, path.resolve)(resolvedSystemPath)) {
754
+ const resetStart = performance.now();
755
+ log(`HMR geological reset: ${relPath}`);
756
+ loadSystem();
757
+ try {
758
+ const { clearAnalysisCache } = engineApi();
759
+ clearAnalysisCache();
760
+ } catch {}
761
+ const fileEntries = [];
762
+ for (const [path$3, { hash, source }] of fileCache) fileEntries.push({
763
+ path: path$3,
764
+ source,
765
+ hash
766
+ });
767
+ runAnalysis(fileEntries);
768
+ log(`HMR geological reset complete: ${Math.round(performance.now() - resetStart)}ms`);
769
+ const geologicalModules = [...modules];
770
+ const cssModule = hmrServer.moduleGraph.getModuleById(RESOLVED_CSS_ID);
771
+ if (cssModule) {
772
+ hmrServer.moduleGraph.invalidateModule(cssModule);
773
+ geologicalModules.push(cssModule);
774
+ }
775
+ const compModule = hmrServer.moduleGraph.getModuleById(RESOLVED_COMPONENTS_ID);
776
+ if (compModule) {
777
+ hmrServer.moduleGraph.invalidateModule(compModule);
778
+ geologicalModules.push(compModule);
779
+ }
780
+ const sysPropModule = hmrServer.moduleGraph.getModuleById(RESOLVED_SYSTEM_PROPS_ID);
781
+ if (sysPropModule) {
782
+ hmrServer.moduleGraph.invalidateModule(sysPropModule);
783
+ geologicalModules.push(sysPropModule);
784
+ }
785
+ return geologicalModules;
786
+ }
787
+ let source;
788
+ try {
789
+ source = (0, fs.readFileSync)(absFile, "utf-8");
790
+ } catch {
791
+ return;
792
+ }
793
+ let scannerRelPath = relPath;
794
+ if (ext === ".mdx") {
795
+ const result = await (0, _animus_ui_extract_pipeline.preprocessMdx)(source, relPath);
796
+ if (result.kind === "missing-dep") {
797
+ warn("⚠ .mdx HMR skipped: @mdx-js/mdx not installed; restart dev server after installing");
798
+ return;
799
+ }
800
+ if (result.kind === "error") {
801
+ warn(`⚠ MDX preprocessing failed for ${relPath}: ${result.error}`);
802
+ return;
803
+ }
804
+ source = result.source;
805
+ scannerRelPath = relPath + ".tsx";
806
+ }
807
+ const hash = contentHash(source);
808
+ const cached = fileCache.get(scannerRelPath);
809
+ if (cached && cached.hash === hash) {
810
+ log(`HMR skip: ${scannerRelPath} (unchanged)`);
811
+ return [];
812
+ }
813
+ fileCache.set(scannerRelPath, {
814
+ hash,
815
+ source
816
+ });
817
+ const hmrStart = performance.now();
818
+ const prevReplacements = /* @__PURE__ */ new Map();
819
+ if (storedManifest?.components) for (const [id, desc] of Object.entries(storedManifest.components)) prevReplacements.set(id, desc.replacement ?? "");
820
+ const directComponentIds = storedManifest?.files?.[scannerRelPath] ?? [];
821
+ const invalidatedIds = new Set(directComponentIds);
822
+ const queue = [...directComponentIds];
823
+ while (queue.length > 0) {
824
+ const parentId = queue.shift();
825
+ const children = reverseProvenance[parentId];
826
+ if (children) {
827
+ for (const childId of children) if (!invalidatedIds.has(childId)) {
828
+ invalidatedIds.add(childId);
829
+ queue.push(childId);
830
+ }
831
+ }
832
+ }
833
+ if (verbose && invalidatedIds.size > directComponentIds.length) log(`HMR: ${directComponentIds.length} direct + ${invalidatedIds.size - directComponentIds.length} transitive components invalidated`);
834
+ const analysisStart = performance.now();
835
+ runAnalysis(buildFileEntriesFromCache(fileCache, relPath));
836
+ const analysisMs = Math.round(performance.now() - analysisStart);
837
+ const modulesToUpdate = [...modules];
838
+ const compModule = hmrServer.moduleGraph.getModuleById(RESOLVED_COMPONENTS_ID);
839
+ if (compModule) {
840
+ hmrServer.moduleGraph.invalidateModule(compModule);
841
+ modulesToUpdate.push(compModule);
842
+ }
843
+ const sysPropModule = hmrServer.moduleGraph.getModuleById(RESOLVED_SYSTEM_PROPS_ID);
844
+ if (sysPropModule) {
845
+ hmrServer.moduleGraph.invalidateModule(sysPropModule);
846
+ modulesToUpdate.push(sysPropModule);
847
+ }
848
+ if (storedManifest?.components) {
849
+ const staleFiles = /* @__PURE__ */ new Set();
850
+ for (const [id, desc] of Object.entries(storedManifest.components)) if ((desc.replacement ?? "") !== (prevReplacements.get(id) ?? "")) staleFiles.add(desc.file);
851
+ for (const defFile of staleFiles) {
852
+ const absDefPath = (0, path.resolve)(rootDir, defFile);
853
+ if (absDefPath === absFile) continue;
854
+ const defModule = hmrServer.moduleGraph.getModuleById(absDefPath) ?? hmrServer.moduleGraph.getModulesByFile(absDefPath)?.values().next().value;
855
+ if (defModule) {
856
+ log(`HMR invalidate: ${defFile} (replacement changed)`);
857
+ hmrServer.moduleGraph.invalidateModule(defModule);
858
+ modulesToUpdate.push(defModule);
859
+ }
860
+ }
861
+ }
862
+ const hmrMs = Math.round(performance.now() - hmrStart);
863
+ log(`HMR update: ${relPath} — analysis ${analysisMs}ms, ${modulesToUpdate.length - modules.length} modules invalidated, total ${hmrMs}ms`);
864
+ logTimingWaterfall(storedManifest?.timing ?? {});
865
+ if (modulesToUpdate.length > modules.length) return modulesToUpdate;
866
+ }
867
+ };
868
+ }
869
+ //#endregion
870
+ exports.animusExtract = animusExtract;
871
+ exports.default = animusExtract;
872
+ exports.discoverFiles = discoverFiles;