@menapo/vicss 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2942 @@
1
+ import { $ as keepAtom, A as getProperty, At as splitClasses, Ct as makeClassName, F as markerId, Ft as stableStringify, I as markerLabel, K as placeholder, L as markerSites, M as numberKind, Mt as toRecord, Nt as valueLabel, Ot as propertyKey, P as MarkerValue, Pt as hash, Tt as mergeClassNames, _t as VicssError, at as SPACING_STEP, b as hasPrivateAccess, ct as cssVarName, dt as isScaleName, ft as lookupToken, g as normalizeStyle, h as compileKeyframes, ht as suggestTokens, it as SCALE_NAMESPACES, jt as styleLiteral, k as PROPERTIES, kt as readableClass, lt as didYouMean, mt as scaleTokens, nt as typedPaletteNames, ot as closestNames, rt as SCALES, ut as isPlainObject, vt as classAttribute, x as privateTokenError, xt as fromRecord, yt as compareStrings } from "./print-Ds6fkgio.js";
2
+ import { C as createLocator, _ as evaluate, a as buildRecipe, c as resolveRecipe, h as NOT_HANDLED, i as RecipeValue, m as shadowedByEarlier, n as compileTheme, o as printTable, p as isBaseClass, r as analyzeScopes, s as recipeKey, v as evaluateBinding, y as isDynamic } from "./theme-C-0LpsJx.js";
3
+ import { createRequire } from "node:module";
4
+ import { existsSync, readFileSync } from "node:fs";
5
+ import path from "node:path";
6
+ import { availableParallelism } from "node:os";
7
+ import { Worker } from "node:worker_threads";
8
+ //#region src/core/edits.ts
9
+ /**
10
+ * Source edits with a source map (PLAN D20): the few operations the rewrite
11
+ * step needs, without a dependency. Offsets always refer to the original
12
+ * string, so edits can be recorded in any order.
13
+ */
14
+ var SourceEdits = class {
15
+ original;
16
+ /** Sorted by start, never overlapping. */
17
+ #replacements = [];
18
+ #inserts = /* @__PURE__ */ new Map();
19
+ #prefix = "";
20
+ #keepLines;
21
+ constructor(original, options = {}) {
22
+ this.original = original;
23
+ this.#keepLines = options.keepLines === true;
24
+ }
25
+ overwrite(start, end, content) {
26
+ this.#checkRange(start, end);
27
+ if (start === end) throw new RangeError(`SourceEdits: empty range at ${start}; use insert()`);
28
+ let index = this.#replacements.findIndex((r) => r.start >= start);
29
+ if (index === -1) index = this.#replacements.length;
30
+ const before = this.#replacements[index - 1];
31
+ const after = this.#replacements[index];
32
+ const clash = before && before.end > start ? before : after && after.start < end ? after : null;
33
+ if (clash) throw new Error(`SourceEdits: [${start}, ${end}) overlaps the overwrite of [${clash.start}, ${clash.end})`);
34
+ for (const offset of this.#inserts.keys()) if (offset > start && offset < end) throw new Error(`SourceEdits: [${start}, ${end}) would drop the insert at ${offset}`);
35
+ if (this.#keepLines) content += "\n".repeat(Math.max(0, lineBreaks(this.original, start, end) - lineBreaks(content)));
36
+ this.#replacements.splice(index, 0, {
37
+ start,
38
+ end,
39
+ content
40
+ });
41
+ return this;
42
+ }
43
+ /** Inserts before the original character at `offset`; inserts at one offset keep call order. */
44
+ insert(offset, content) {
45
+ this.#checkRange(offset, offset);
46
+ const inside = this.#replacements.find((r) => offset > r.start && offset < r.end);
47
+ if (inside) throw new Error(`SourceEdits: insert at ${offset} falls inside the overwrite of [${inside.start}, ${inside.end})`);
48
+ const list = this.#inserts.get(offset);
49
+ if (list) list.push(content);
50
+ else this.#inserts.set(offset, [content]);
51
+ return this;
52
+ }
53
+ /** Adds `content` at the very start of the output, before earlier prepends and inserts. */
54
+ prepend(content) {
55
+ this.#prefix = content + this.#prefix;
56
+ return this;
57
+ }
58
+ remove(start, end) {
59
+ this.#checkRange(start, end);
60
+ return start === end ? this : this.overwrite(start, end, "");
61
+ }
62
+ hasChanged() {
63
+ return this.toString() !== this.original;
64
+ }
65
+ toString() {
66
+ let out = "";
67
+ for (const chunk of this.#chunks()) out += chunk.text;
68
+ return out;
69
+ }
70
+ /**
71
+ * Segments start every output line and every edit boundary. Unchanged text
72
+ * maps 1:1; replaced and inserted text maps to the start of the range it
73
+ * replaced or to its insertion point.
74
+ */
75
+ generateMap(options) {
76
+ const locate = createLocator(this.original);
77
+ let mappings = "";
78
+ let column = 0;
79
+ let lineHasSegment = false;
80
+ let prevColumn = 0;
81
+ let prevSourceLine = 0;
82
+ let prevSourceColumn = 0;
83
+ const add = (offset) => {
84
+ const { line, column: sourceColumn } = locate(offset);
85
+ if (lineHasSegment) mappings += ",";
86
+ mappings += vlq(column - prevColumn) + "A" + vlq(line - 1 - prevSourceLine) + vlq(sourceColumn - prevSourceColumn);
87
+ lineHasSegment = true;
88
+ prevColumn = column;
89
+ prevSourceLine = line - 1;
90
+ prevSourceColumn = sourceColumn;
91
+ };
92
+ for (const { text, origin, copied } of this.#chunks()) {
93
+ add(origin);
94
+ for (let i = 0; i < text.length; i++) {
95
+ if (text.charCodeAt(i) === 10) {
96
+ mappings += ";";
97
+ column = 0;
98
+ prevColumn = 0;
99
+ lineHasSegment = false;
100
+ } else column++;
101
+ const next = i + 1;
102
+ if (next === text.length) continue;
103
+ if (column === 0 || options.hires && copied && isWordStart(text, next)) add(copied ? origin + next : origin);
104
+ }
105
+ }
106
+ return {
107
+ version: 3,
108
+ ...options.file === void 0 ? {} : { file: options.file },
109
+ sources: [options.source],
110
+ ...options.includeContent ? { sourcesContent: [this.original] } : {},
111
+ names: [],
112
+ mappings
113
+ };
114
+ }
115
+ #checkRange(start, end) {
116
+ if (!Number.isInteger(start) || !Number.isInteger(end) || start < 0 || end < start || end > this.original.length) throw new RangeError(`SourceEdits: invalid range [${start}, ${end}) for a string of length ${this.original.length}`);
117
+ }
118
+ #chunks() {
119
+ const chunks = [];
120
+ const push = (text, origin, copied) => {
121
+ if (text !== "") chunks.push({
122
+ text,
123
+ origin,
124
+ copied
125
+ });
126
+ };
127
+ let pos = 0;
128
+ const copyTo = (end) => {
129
+ if (end > pos) push(this.original.slice(pos, end), pos, true);
130
+ pos = end;
131
+ };
132
+ const replacements = this.#replacements;
133
+ let r = 0;
134
+ const replaceBefore = (limit) => {
135
+ for (let next = replacements[r]; next && next.start < limit; next = replacements[++r]) {
136
+ copyTo(next.start);
137
+ push(next.content, next.start, false);
138
+ pos = next.end;
139
+ }
140
+ };
141
+ push(this.#prefix, 0, false);
142
+ for (const offset of [...this.#inserts.keys()].sort((a, b) => a - b)) {
143
+ replaceBefore(offset);
144
+ copyTo(offset);
145
+ for (const text of this.#inserts.get(offset)) push(text, offset, false);
146
+ }
147
+ replaceBefore(Infinity);
148
+ copyTo(this.original.length);
149
+ return chunks;
150
+ }
151
+ };
152
+ const WORD = /[\w$]/;
153
+ function isWordStart(text, i) {
154
+ return WORD.test(text[i]) && !WORD.test(text[i - 1]);
155
+ }
156
+ const BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
157
+ /** Base64 VLQ: sign in the lowest bit, then 5-bit groups, least significant first. */
158
+ function vlq(value) {
159
+ let rest = value < 0 ? -value << 1 | 1 : value << 1;
160
+ let out = "";
161
+ do {
162
+ let digit = rest & 31;
163
+ rest >>>= 5;
164
+ if (rest > 0) digit |= 32;
165
+ out += BASE64[digit];
166
+ } while (rest > 0);
167
+ return out;
168
+ }
169
+ /**
170
+ * Reads a map back: the 1-based line of the original source a generated
171
+ * position (1-based line, 0-based column) came from, or undefined where the
172
+ * map says nothing or names another source. For `data-vx-src` in a
173
+ * framework file (PLAN §5.14), whose compiler moved its lines before vicss
174
+ * compiles its output: the map Vite combined says where each line was.
175
+ */
176
+ function originalLines(map, isSource) {
177
+ const lines = [];
178
+ let source = 0;
179
+ let sourceLine = 0;
180
+ for (const text of map.mappings.split(";")) {
181
+ const segments = [];
182
+ let column = 0;
183
+ for (const part of text.split(",")) {
184
+ if (!part) continue;
185
+ const fields = decodeVlq(part);
186
+ column += fields[0] ?? 0;
187
+ if (fields.length < 4) continue;
188
+ source += fields[1];
189
+ sourceLine += fields[2];
190
+ segments.push([
191
+ column,
192
+ source,
193
+ sourceLine
194
+ ]);
195
+ }
196
+ lines.push(segments);
197
+ }
198
+ const own = map.sources.map((name) => name !== null && isSource(name));
199
+ return (line, column) => {
200
+ const segments = lines[line - 1] ?? [];
201
+ let found = segments[0];
202
+ for (const segment of segments) {
203
+ if (segment[0] > column) break;
204
+ found = segment;
205
+ }
206
+ return found && own[found[1]] ? found[2] + 1 : void 0;
207
+ };
208
+ }
209
+ /** The `\n`s in `text`, or in its range `[start, end)`. */
210
+ function lineBreaks(text, start = 0, end = text.length) {
211
+ let count = 0;
212
+ for (let i = text.indexOf("\n", start); i !== -1 && i < end; i = text.indexOf("\n", i + 1)) count++;
213
+ return count;
214
+ }
215
+ /** The values of one segment's Base64 VLQ fields. */
216
+ function decodeVlq(text) {
217
+ const out = [];
218
+ let value = 0;
219
+ let shift = 0;
220
+ for (const char of text) {
221
+ const digit = BASE64.indexOf(char);
222
+ if (digit === -1) return out;
223
+ value += (digit & 31) << shift;
224
+ if (digit & 32) {
225
+ shift += 5;
226
+ continue;
227
+ }
228
+ out.push(value & 1 ? -(value >>> 1) : value >>> 1);
229
+ value = 0;
230
+ shift = 0;
231
+ }
232
+ return out;
233
+ }
234
+ //#endregion
235
+ //#region src/core/parser.ts
236
+ let parser;
237
+ let loading;
238
+ /** Installs the parser before the first compile (a worker that loaded it itself). */
239
+ function setParser(parse) {
240
+ parser = parse;
241
+ }
242
+ /** The parser, loading Vite once if nothing installed one. */
243
+ function loadParser() {
244
+ if (parser) return parser;
245
+ return loading ??= import("vite").then((vite) => parser = vite.parseSync);
246
+ }
247
+ //#endregion
248
+ //#region src/core/compile.ts
249
+ /** One entry per module id: an edited module replaces its stale parse. */
250
+ function createModuleCache() {
251
+ return {
252
+ parsed: /* @__PURE__ */ new Map(),
253
+ recipes: /* @__PURE__ */ new WeakMap()
254
+ };
255
+ }
256
+ /** Distinct recipe definitions a cache keeps per system before it starts over. */
257
+ const RECIPE_CACHE_SIZE = 1e3;
258
+ /** Compiles one module. Throws VicssError, with a location, for anything it refuses. */
259
+ async function compileModule(code, options) {
260
+ const sources = [.../* @__PURE__ */ new Set([RUNTIME_PACKAGE, ...options.importSources ?? []])];
261
+ if (!sources.some((source) => code.includes(source))) return unchanged(code);
262
+ const compiler = new Compiler(code, options, sources, await loadParser());
263
+ if (compiler.root.runtime.size === 0) return unchanged(code);
264
+ for (;;) try {
265
+ return compiler.run();
266
+ } catch (error) {
267
+ if (!(error instanceof PendingImport)) throw error;
268
+ await Promise.all(error.requests.map(([importer, source]) => compiler.load(importer, source, error.probes.has(requestKey(importer, source)))));
269
+ }
270
+ }
271
+ const RUNTIME_PACKAGE = "@menapo/vicss";
272
+ const RUNTIME_EXPORTS = /* @__PURE__ */ new Set([
273
+ "css",
274
+ "sx",
275
+ "token",
276
+ "recipe",
277
+ "theme",
278
+ "group",
279
+ "peer",
280
+ "keyframes"
281
+ ]);
282
+ /**
283
+ * What `sx()` returns per framework (PLAN §5.12): the class attribute a
284
+ * folded call sets, the runtime export an `sx` import is pointed at
285
+ * (React's shape is `sx` itself), and the dev variant a runtime call becomes
286
+ * so the element names its source line (runtime/dev.ts). Every shape's
287
+ * `style` is what its framework accepts: an object, or a `a:b;c:d` string.
288
+ * `data-vx-src` is a plain attribute name, which every framework passes
289
+ * through from a spread object as it is.
290
+ */
291
+ const SX_SHAPES = {
292
+ react: {
293
+ attribute: "className",
294
+ dev: "__vxSxDev"
295
+ },
296
+ preact: {
297
+ attribute: "className",
298
+ dev: "__vxSxDev"
299
+ },
300
+ solid: {
301
+ attribute: "class",
302
+ target: "__vxSxClass",
303
+ dev: "__vxSxDevClass"
304
+ },
305
+ vue: {
306
+ attribute: "class",
307
+ target: "__vxSxClass",
308
+ dev: "__vxSxDevClass"
309
+ },
310
+ svelte: {
311
+ attribute: "class",
312
+ target: "__vxSxString",
313
+ dev: "__vxSxDevString"
314
+ },
315
+ astro: {
316
+ attribute: "class",
317
+ target: "__vxSxString",
318
+ dev: "__vxSxDevString"
319
+ },
320
+ vanilla: {
321
+ attribute: "class",
322
+ target: "__vxSxString",
323
+ dev: "__vxSxDevString"
324
+ }
325
+ };
326
+ /** D18: a folded `sx()` precomputes 2^n strings for n conditional arguments. */
327
+ const MAX_FOLD_CONDITIONS = 2;
328
+ /** Stands for a runtime value while the normaliser checks the rest of a function style. */
329
+ const PLACEHOLDER = "\0vx";
330
+ const WRAPPERS = /* @__PURE__ */ new Set([
331
+ "ParenthesizedExpression",
332
+ "TSAsExpression",
333
+ "TSSatisfiesExpression",
334
+ "TSNonNullExpression",
335
+ "TSTypeAssertion",
336
+ "TSInstantiationExpression"
337
+ ]);
338
+ /** Keys that hold types or metadata: no runtime call lives below them. */
339
+ const SKIPPED_KEYS = /* @__PURE__ */ new Set([
340
+ "parent",
341
+ "range",
342
+ "typeAnnotation",
343
+ "typeArguments",
344
+ "typeParameters",
345
+ "returnType",
346
+ "superTypeArguments",
347
+ "implements"
348
+ ]);
349
+ /** Tests that read the same without parentheses in front of `?`. */
350
+ const BARE_TESTS = /* @__PURE__ */ new Set([
351
+ "Identifier",
352
+ "MemberExpression",
353
+ "ChainExpression",
354
+ "CallExpression",
355
+ "ParenthesizedExpression",
356
+ "UnaryExpression",
357
+ "Literal",
358
+ "ThisExpression"
359
+ ]);
360
+ const LANGS = {
361
+ js: "js",
362
+ mjs: "js",
363
+ cjs: "js",
364
+ jsx: "jsx",
365
+ ts: "ts",
366
+ mts: "ts",
367
+ cts: "ts",
368
+ tsx: "tsx",
369
+ vue: "js",
370
+ svelte: "js",
371
+ astro: "js"
372
+ };
373
+ /** What a `css()` call is inside another static expression: its classes, as a class list. */
374
+ var CompiledStyle = class {
375
+ __vxSpecial = "style";
376
+ classes;
377
+ constructor(classes) {
378
+ this.classes = classes;
379
+ }
380
+ };
381
+ /** A function style inside another expression: never a constant. */
382
+ const FUNCTION_STYLE = { __vxSpecial: "functionStyle" };
383
+ /**
384
+ * Thrown through the evaluator when a constant lives in a module that is not
385
+ * loaded yet. A VicssError, so the evaluator passes it on untouched.
386
+ */
387
+ var PendingImport = class extends VicssError {
388
+ /** `[importer, source]` pairs, each once. */
389
+ requests;
390
+ /** Keys of the requests only a recipe probe made (`Compiler.probe`). */
391
+ probes;
392
+ constructor(requests, probes = false) {
393
+ super("PENDING_IMPORT", `${requests.map(([, source]) => `"${source}"`).join(", ")} not loaded yet`);
394
+ this.requests = requests;
395
+ this.probes = probes === true ? new Set(requests.map((request) => requestKey(...request))) : probes || /* @__PURE__ */ new Set();
396
+ }
397
+ };
398
+ var Compiler = class {
399
+ options;
400
+ system;
401
+ sources;
402
+ root;
403
+ modules = /* @__PURE__ */ new Map();
404
+ /** `importer\0source` → the module it loads, or why it cannot be loaded. */
405
+ requests = /* @__PURE__ */ new Map();
406
+ dependencies = /* @__PURE__ */ new Set();
407
+ /** Requests a recipe probe made for a package's module, which was not read (`load`). */
408
+ skipped = /* @__PURE__ */ new Set();
409
+ /** Above 0 while a callee that may be a recipe is evaluated (`probe`). */
410
+ probing = 0;
411
+ /** Exports being resolved, to stop re-export cycles that the evaluator never sees. */
412
+ resolving = /* @__PURE__ */ new Set();
413
+ /**
414
+ * `css()` calls being compiled: a function style evaluates in a context of
415
+ * its own, where the evaluator cannot see that it reads its own result.
416
+ */
417
+ compiling = /* @__PURE__ */ new Set();
418
+ /** Every atom compiled in any module, by class name: folded classes report theirs. */
419
+ atomIndex = /* @__PURE__ */ new Map();
420
+ /** Every rule compiled in any module, by id. */
421
+ rules = /* @__PURE__ */ new Map();
422
+ /**
423
+ * This module's values outside their scales, by where they are written:
424
+ * a style evaluated in several passes counts once.
425
+ */
426
+ arbitrary = /* @__PURE__ */ new Set();
427
+ /** The app's own class names this module's calls write (`CompileResult.names`). */
428
+ names = /* @__PURE__ */ new Set();
429
+ /** Module id → whether `privateAccess` lists it (PLAN §4.1). */
430
+ access = /* @__PURE__ */ new Map();
431
+ /** Every module's markers by family and id, as messages name them (`[row.hover]`). */
432
+ markerLabels = /* @__PURE__ */ new Map();
433
+ parseSync;
434
+ /** What `sx()` returns in this module, and the runtime functions of that shape. */
435
+ shape;
436
+ /** How a class is written into the output: readable, or a build's placeholder. */
437
+ emit;
438
+ pass;
439
+ constructor(code, options, sources, parseSync) {
440
+ this.options = options;
441
+ this.system = options.system;
442
+ this.sources = sources;
443
+ this.parseSync = parseSync;
444
+ this.shape = SX_SHAPES[options.framework ?? "react"];
445
+ this.emit = options.placeholders ? placeholder : readableClass;
446
+ this.root = this.createModule(options.id, code, options.lang, options.functionBody);
447
+ this.modules.set(options.id, this.root);
448
+ this.pass = newPass(code, options.keepLines === true);
449
+ }
450
+ run() {
451
+ const { root } = this;
452
+ this.pass = newPass(root.code, this.options.keepLines === true);
453
+ this.rewrite(root.program, this.pass.edits);
454
+ if (this.pass.pending.size > 0) throw new PendingImport([...this.pass.pending.values()], this.pass.probes);
455
+ for (const error of this.pass.errors) this.options.onError?.(error);
456
+ this.pruneImports();
457
+ const { edits, tokens, folded } = this.pass;
458
+ if (this.pass.devSx) edits.insert(root.code.length, `\nimport { ${this.shape.dev} } from "${RUNTIME_PACKAGE}";\n`);
459
+ const names = this.names.size > 0 && { names: [...this.names].sort(compareStrings) };
460
+ if (!edits.hasChanged()) return {
461
+ ...unchanged(root.code),
462
+ arbitrary: this.arbitrary.size,
463
+ ...names
464
+ };
465
+ const atoms = /* @__PURE__ */ new Map();
466
+ for (const style of root.styles.values()) for (const atom of style.atoms) keepAtom(atoms, atom);
467
+ for (const recipe of root.recipes.values()) for (const atom of recipe.atoms) keepAtom(atoms, atom);
468
+ const own = {
469
+ classes: [...atoms.keys()].sort(compareStrings),
470
+ rules: [.../* @__PURE__ */ new Set([...[...root.rules.values()].map((rule) => rule.id), ...[...root.recipes.values()].flatMap((recipe) => recipe.rules.map((rule) => rule.id))])].sort(compareStrings)
471
+ };
472
+ for (const cls of folded) {
473
+ const atom = this.atomIndex.get(cls);
474
+ if (atom && !atoms.has(cls)) atoms.set(cls, atom);
475
+ }
476
+ const file = root.id.replace(/[?#].*$/, "");
477
+ return {
478
+ code: edits.toString(),
479
+ map: this.options.sourceMap === false ? null : edits.generateMap({
480
+ source: file,
481
+ file,
482
+ includeContent: true,
483
+ hires: true
484
+ }),
485
+ atoms: [...atoms.values()].sort((a, b) => compareStrings(a.className, b.className)),
486
+ dependencies: [...this.dependencies],
487
+ tokens: [...tokens.values()],
488
+ rules: [...this.rules.values()].sort((a, b) => compareStrings(a.id, b.id)),
489
+ arbitrary: this.arbitrary.size,
490
+ ...names,
491
+ own,
492
+ changed: true
493
+ };
494
+ }
495
+ /**
496
+ * Reads a module the evaluation needs. For a `probe`, a module under
497
+ * `node_modules` is not parsed or recorded as a dependency: any call of an
498
+ * import (`useState()`, `useQuery({ … })`) is probed for a recipe, and a
499
+ * package's barrel would otherwise load its whole graph on every compile.
500
+ * Packages hold compiled code, which never yields a recipe to fold.
501
+ */
502
+ async load(importer, source, probe = false) {
503
+ const key = requestKey(importer, source);
504
+ if (this.requests.has(key) || probe && this.skipped.has(key)) return;
505
+ let loaded = null;
506
+ let reason = `"${source}" cannot be loaded from ${importer}`;
507
+ try {
508
+ loaded = await this.options.loadModule(source, importer);
509
+ } catch (error) {
510
+ reason = `"${source}" cannot be loaded from ${importer}: ${error instanceof Error ? error.message : String(error)}`;
511
+ }
512
+ if (!loaded) {
513
+ this.requests.set(key, reason);
514
+ return;
515
+ }
516
+ if (probe && /[\\/]node_modules[\\/]/.test(loaded.id)) {
517
+ this.skipped.add(key);
518
+ return;
519
+ }
520
+ let target = this.modules.get(loaded.id);
521
+ if (!target) {
522
+ try {
523
+ target = this.createModule(loaded.id, loaded.code);
524
+ } catch (error) {
525
+ if (!(error instanceof VicssError)) throw error;
526
+ this.requests.set(key, `"${source}" (${loaded.id}) cannot be parsed: ${error.message}`);
527
+ return;
528
+ }
529
+ this.modules.set(loaded.id, target);
530
+ }
531
+ this.requests.set(key, target);
532
+ if (target !== this.root) this.dependencies.add(loaded.id);
533
+ }
534
+ createModule(id, code, lang, functionBody = false) {
535
+ const parsedAs = isJson(id) ? "js" : lang ?? langOf(id);
536
+ const { program, scopes } = this.parse(id, code, parsedAs, functionBody);
537
+ const ctx = {
538
+ file: id,
539
+ code,
540
+ scopes,
541
+ resolveImport: (binding) => this.resolveImport(mod, binding),
542
+ callHandler: (callee, _binding, args, evaluateNode) => this.evaluateCall(mod, callee, args, evaluateNode),
543
+ isHarmlessCall: (call) => runtimeName(mod, call.callee) !== void 0 || isUnref(mod, call.callee, call.arguments)
544
+ };
545
+ const mod = {
546
+ id,
547
+ code,
548
+ program,
549
+ scopes,
550
+ runtime: runtimeBindings(program, scopes, this.sources),
551
+ vue: this.options.framework === "vue" && id === this.options.id,
552
+ lang: parsedAs,
553
+ ctx,
554
+ styles: /* @__PURE__ */ new Map(),
555
+ rules: /* @__PURE__ */ new Map(),
556
+ recipes: /* @__PURE__ */ new Map(),
557
+ markers: /* @__PURE__ */ new Map(),
558
+ markerKeys: /* @__PURE__ */ new Map(),
559
+ markerSites: void 0,
560
+ locate: createLocator(code)
561
+ };
562
+ return mod;
563
+ }
564
+ /** A parse from the shared cache, or a new one. JSON modules read as their exports. */
565
+ parse(id, code, lang, functionBody = false) {
566
+ const key = `${lang === langOf(id) ? id : `${id}\0${lang}`}${functionBody ? "\0body" : ""}`;
567
+ const cached = this.options.cache?.parsed.get(key);
568
+ if (cached?.code === code) return cached;
569
+ const source = isJson(id) ? jsonModule(id, code) : code;
570
+ const program = parse(this.parseSync, id, source, lang, functionBody);
571
+ const parsed = {
572
+ code,
573
+ program,
574
+ scopes: analyzeScopes(program)
575
+ };
576
+ this.options.cache?.parsed.set(key, parsed);
577
+ return parsed;
578
+ }
579
+ /** Rewrites the runtime calls under `node`. */
580
+ rewrite(node, editor) {
581
+ walk(this.root, node, (child) => {
582
+ if (child.type !== "CallExpression") return true;
583
+ const name = runtimeName(this.root, child.callee);
584
+ try {
585
+ if (name === void 0) return !this.foldRecipeCall(child, editor);
586
+ return !this.rewriteCall(child, name, editor);
587
+ } catch (error) {
588
+ if (error instanceof VicssError && !(error instanceof PendingImport) && this.options.onError) {
589
+ this.pass.errors.push(error);
590
+ return false;
591
+ }
592
+ if (!(error instanceof PendingImport)) throw error;
593
+ const { pending, probes } = this.pass;
594
+ for (const request of error.requests) {
595
+ const key = requestKey(...request);
596
+ if (!error.probes.has(key)) probes.delete(key);
597
+ else if (!pending.has(key)) probes.add(key);
598
+ pending.set(key, request);
599
+ }
600
+ return false;
601
+ }
602
+ });
603
+ }
604
+ /** Returns whether the call was replaced; otherwise its arguments are rewritten in place. */
605
+ rewriteCall(call, name, editor) {
606
+ const { root } = this;
607
+ const evaluateHere = (node) => evaluate(node, root.ctx);
608
+ switch (name) {
609
+ case "css":
610
+ this.rewriteStyle(call, editor);
611
+ return true;
612
+ case "token": {
613
+ const token = this.tokenOf(root, call.callee, call.arguments, evaluateHere);
614
+ this.pass.tokens.set(`${token.scale}:${token.path}`, {
615
+ scale: token.scale,
616
+ path: token.path
617
+ });
618
+ this.replace(editor, call.start, call.end, JSON.stringify(`var(${token.cssVar})`));
619
+ return true;
620
+ }
621
+ case "sx":
622
+ if (this.fold(call, editor)) return true;
623
+ if (this.options.dev) this.devCall(call, editor);
624
+ return false;
625
+ case "keyframes":
626
+ case "theme": {
627
+ const rule = this.compileRule(root, name, call.callee, call.arguments, evaluateHere);
628
+ const text = name === "theme" ? `(${styleLiteral(rule.id, this.emit)})` : JSON.stringify(rule.id);
629
+ this.replace(editor, call.start, call.end, text);
630
+ return true;
631
+ }
632
+ case "recipe": {
633
+ const recipe = this.compileRecipe(root, call.callee, call.arguments, evaluateHere);
634
+ const helper = this.helper("__vxRecipe");
635
+ const extra = recipe.table.q ? `, ${this.helper("__vxResponsive")}` : "";
636
+ const table = this.options.dev && recipe.rules.length > 0 ? {
637
+ ...recipe.table,
638
+ f: Object.fromEntries(recipe.rules.map((rule) => [rule.id, toRecord((rule.atoms ?? []).map((atom) => atom.className).join(" "))]))
639
+ } : recipe.table;
640
+ const text = `/*#__PURE__*/${helper}(${printTable(table, this.emit)}${extra})`;
641
+ const imports = root.program.body.filter((node) => node.type === "ImportDeclaration");
642
+ if (editor === this.pass.edits && imports.length > 0 && this.inFunction(call.start)) {
643
+ const local = this.hoistName();
644
+ this.pass.edits.insert(imports.at(-1).end, this.options.keepLines ? `;const ${local} = ${text};` : `\nconst ${local} = ${text};`);
645
+ this.replace(editor, call.start, call.end, local);
646
+ } else this.replace(editor, call.start, call.end, text);
647
+ return true;
648
+ }
649
+ case "group":
650
+ case "peer": {
651
+ const marker = this.markerOf(root, name, call.callee, call.arguments, evaluateHere);
652
+ this.replace(editor, call.start, call.end, `(${styleLiteral(marker.className, this.emit)})`);
653
+ return true;
654
+ }
655
+ default: return false;
656
+ }
657
+ }
658
+ /** Whether `offset` lies in a function (or a class field), which may run many times. */
659
+ inFunction(offset) {
660
+ const { root } = this;
661
+ if (!root.functions) {
662
+ const ranges = [];
663
+ walk(root, root.program, (node) => {
664
+ if (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression" || node.type === "PropertyDefinition" && !node.static) {
665
+ ranges.push([node.start, node.end]);
666
+ return false;
667
+ }
668
+ return true;
669
+ });
670
+ root.functions = ranges;
671
+ }
672
+ return root.functions.some(([start, end]) => offset > start && offset < end);
673
+ }
674
+ /** A module-level name for a hoisted recipe, unused in the module. */
675
+ hoistName() {
676
+ const { code } = this.root;
677
+ let name;
678
+ do
679
+ name = `__vxRecipeTable${++this.pass.hoisted}`;
680
+ while (code.includes(name));
681
+ return name;
682
+ }
683
+ /** The local name of a runtime export the output calls; `pruneImports` adds the import. */
684
+ helper(name) {
685
+ const { helpers } = this.pass;
686
+ const known = helpers.get(name);
687
+ if (known) return known.local;
688
+ const { root } = this;
689
+ for (const binding of root.scopes.moduleBindings.values()) if (binding.kind === "import" && binding.source === RUNTIME_PACKAGE && binding.imported === name) {
690
+ helpers.set(name, {
691
+ local: binding.name,
692
+ add: false
693
+ });
694
+ return binding.name;
695
+ }
696
+ let local = name;
697
+ for (let i = 1; root.code.includes(local); i++) local = `${name}${i}`;
698
+ helpers.set(name, {
699
+ local,
700
+ add: true
701
+ });
702
+ return local;
703
+ }
704
+ /**
705
+ * `button({ size: "sm" })` with a recipe the compiler knows and literal props
706
+ * becomes its classes (an object of them for slots), with up to D18's two
707
+ * runtime tests among the props. Returns whether the call was replaced.
708
+ */
709
+ foldRecipeCall(call, editor) {
710
+ if (!this.mayBeRecipeCall(call)) return false;
711
+ const { root } = this;
712
+ const target = this.probe(() => attempt(() => evaluate(call.callee, root.ctx)));
713
+ if (!(target?.result instanceof RecipeValue)) return false;
714
+ const { recipe } = target.result;
715
+ const [arg] = call.arguments;
716
+ const props = arg ? this.foldProps(arg) : {
717
+ tests: [],
718
+ build: () => void 0
719
+ };
720
+ if (!props || props.tests.length > MAX_FOLD_CONDITIONS) return false;
721
+ const fail = this.propsError(root, call, arg);
722
+ const n = props.tests.length;
723
+ const slots = recipe.table.s;
724
+ const leaves = [];
725
+ for (let i = 0; i < 2 ** n; i++) {
726
+ const picks = props.tests.map((_, j) => (i >> n - 1 - j & 1) === 0);
727
+ const classes = resolveRecipe(recipe, props.build(picks), fail);
728
+ const styles = slots ? Object.values(classes) : [classes];
729
+ for (const style of styles) for (const cls of Object.values(style)) this.pass.folded.add(cls);
730
+ leaves.push(slots ? Object.fromEntries(slots.map((slot) => [slot, styleLiteral(classes[slot], this.emit)])) : { "": styleLiteral(classes, this.emit) });
731
+ }
732
+ const tests = props.tests.map((test) => this.testText(test));
733
+ const choose = (texts, depth = 0, at = 0) => {
734
+ if (depth === n) return texts[at];
735
+ const yes = choose(texts, depth + 1, at);
736
+ const no = choose(texts, depth + 1, at + 2 ** (n - depth - 1));
737
+ return yes === no ? yes : `${tests[depth]} ? ${yes} : ${no}`;
738
+ };
739
+ let text;
740
+ if (!slots) text = `(${choose(leaves.map((leaf) => leaf[""]))})`;
741
+ else text = `({ ${slots.map((slot) => {
742
+ const value = choose(leaves.map((leaf) => leaf[slot]));
743
+ return `${propertyKey(slot)}: ${value}`;
744
+ }).join(", ")} })`;
745
+ this.replace(editor, call.start, call.end, text);
746
+ return true;
747
+ }
748
+ /** Evaluates a callee that may be a recipe: packages it imports are not read (`load`). */
749
+ probe(evaluateCallee) {
750
+ this.probing++;
751
+ try {
752
+ return evaluateCallee();
753
+ } finally {
754
+ this.probing--;
755
+ }
756
+ }
757
+ /**
758
+ * A call that could be a recipe's: its callee is a binding that can hold
759
+ * one (a `const` or an import, or a member of one), and it passes nothing
760
+ * or an object literal. Only these callees are evaluated.
761
+ */
762
+ mayBeRecipeCall(call) {
763
+ const args = call.arguments;
764
+ if (args.length > 1 || args[0] && unwrap(args[0]).type !== "ObjectExpression") return false;
765
+ let target = unwrap(call.callee);
766
+ if (target.type === "CallExpression" && isUnref(this.root, target.callee, target.arguments)) target = unwrap(target.arguments[0]);
767
+ if (target.type === "MemberExpression") {
768
+ if (target.computed && target.property.type !== "Literal") return false;
769
+ target = unwrap(target.object);
770
+ }
771
+ if (target.type !== "Identifier") return false;
772
+ const binding = this.root.scopes.bindingOf(target);
773
+ if (!binding) return false;
774
+ if (binding.kind === "import") return binding.source !== RUNTIME_PACKAGE && !(this.sources.includes(binding.source) && RUNTIME_EXPORTS.has(binding.imported));
775
+ if (binding.kind !== "const" || !binding.init) return false;
776
+ const init = unwrap(binding.init).type;
777
+ return init !== "ArrowFunctionExpression" && init !== "FunctionExpression";
778
+ }
779
+ /** Static props, or an object literal of them with runtime tests between static values. */
780
+ foldProps(node) {
781
+ const known = attempt(() => evaluate(node, this.root.ctx));
782
+ if (known) return {
783
+ tests: [],
784
+ build: () => known.result
785
+ };
786
+ const tests = [];
787
+ const build = this.propsShape(unwrap(node), tests);
788
+ return build && {
789
+ tests,
790
+ build
791
+ };
792
+ }
793
+ propsShape(node, tests) {
794
+ if (node.type !== "ObjectExpression") return void 0;
795
+ const entries = [];
796
+ for (const property of node.properties) {
797
+ if (property.type === "SpreadElement" || property.method || property.kind !== "init") return;
798
+ let key = staticKey(property);
799
+ if (property.computed) {
800
+ const value = attempt(() => evaluate(property.key, this.root.ctx))?.result;
801
+ key = typeof value === "string" || typeof value === "number" ? String(value) : void 0;
802
+ }
803
+ const value = key === void 0 ? void 0 : this.propValue(property.value, tests);
804
+ if (key === void 0 || !value) return void 0;
805
+ entries.push([key, value]);
806
+ }
807
+ return (picks) => Object.fromEntries(entries.map(([key, value]) => [key, value(picks)]));
808
+ }
809
+ propValue(node, tests) {
810
+ const known = attempt(() => evaluate(node, this.root.ctx));
811
+ if (known) return () => known.result;
812
+ const inner = unwrap(node);
813
+ if (inner.type === "ObjectExpression") return this.propsShape(inner, tests);
814
+ if (inner.type !== "ConditionalExpression") return void 0;
815
+ const index = tests.push(inner.test) - 1;
816
+ const yes = this.propValue(inner.consequent, tests);
817
+ const no = yes && this.propValue(inner.alternate, tests);
818
+ return yes && no && ((picks) => picks[index] ? yes(picks) : no(picks));
819
+ }
820
+ /** Errors in a recipe call's props, located at the prop. */
821
+ propsError(mod, at, arg) {
822
+ return (path, message, hint) => new VicssError("BAD_VARIANT", path ? `${path}: ${message}` : message, {
823
+ loc: arg ? this.locateStyle(mod, arg, path) : this.loc(mod, at),
824
+ hint
825
+ });
826
+ }
827
+ rewriteStyle(call, editor) {
828
+ const style = this.compileStyle(this.root, call.callee, call.arguments);
829
+ const { fn, vars } = style;
830
+ if (!fn || !vars) {
831
+ this.replace(editor, call.start, call.end, `(${styleLiteral(style.classes, this.emit)})`);
832
+ return;
833
+ }
834
+ const constant = this.localName("__vxStyle");
835
+ const memo = this.localName("__vxStyles");
836
+ const palettes = style.palettes ?? [];
837
+ this.replace(editor, call.start, fn.start, palettes.length === 0 ? `((${constant}) => ` : `((${constant}, ${memo} = {}) => `);
838
+ for (const param of fn.params) this.rewrite(param, editor);
839
+ const entries = [...new Map(vars.map((v) => [v.variable, v])).values()].map((v) => `${JSON.stringify(v.variable)}: ${this.runtimeValue(v.value, v.property)}`);
840
+ let classes = constant;
841
+ let body;
842
+ if (palettes.length === 0) body = entries.length > 0 ? `({ $c: ${classes}, $s: { ${entries.join(", ")} } })` : `({ $c: ${classes} })`;
843
+ else {
844
+ const picks = palettes.map((_, i) => `${memo}${i}`);
845
+ const add = palettes.map((p, i) => `...(${picks[i]} && { ${JSON.stringify(p.prefix.slice(0, -1))}: ${picks[i]} })`).join(", ");
846
+ classes = `(${memo}[${picks.join(" + \" \" + ")}] ??= { ...${constant}, ${add} })`;
847
+ const style$ = entries.length > 0 ? `{ $c: ${classes}, $s: { ${entries.join(", ")} } }` : `{ $c: ${classes} }`;
848
+ body = `((${picks.join(", ")}) => (${style$}))(${palettes.map((p) => this.paletteClass(p.prefix, p.value)).join(", ")})`;
849
+ }
850
+ this.replace(editor, fn.body.start, fn.body.end, body);
851
+ this.replace(editor, fn.end, call.end, `)(${styleLiteral(style.classes, this.emit)})`);
852
+ }
853
+ /** A name for a binding the output adds, unused in the module. */
854
+ localName(base) {
855
+ const { code } = this.root;
856
+ let name = base;
857
+ for (let i = 1; code.includes(name); i++) name = `${base}${i}`;
858
+ return name;
859
+ }
860
+ /** The class a runtime `colorPalette` picks (`"md:palette_" + tone`), or `""` for none. */
861
+ paletteClass(prefix, value) {
862
+ const named = JSON.stringify(this.emit(prefix));
863
+ if (isDynamic(value)) {
864
+ const { choice } = value;
865
+ if (choice) return `(${`${this.testText(choice.test)}${choice.nullish ? " != null" : ""}`} ? ${this.paletteClass(prefix, choice.consequent)} : ${this.paletteClass(prefix, choice.alternate)})`;
866
+ const { node } = value;
867
+ if (node.type === "Identifier") {
868
+ const name = node.name;
869
+ return `(${name} == null ? "" : ${named} + ${name})`;
870
+ }
871
+ return `((v) => v == null ? "" : ${named} + v)(${this.copy(node)})`;
872
+ }
873
+ return typeof value === "string" ? JSON.stringify(this.emit(prefix + value)) : "\"\"";
874
+ }
875
+ /**
876
+ * The expression that sets a custom property for `property`: tests run,
877
+ * numbers map like S9 at build time. In dev, a value the browser would
878
+ * drop warns once (runtime/dev.ts).
879
+ */
880
+ runtimeValue(value, property) {
881
+ switch (value.kind) {
882
+ case "static": return value.css === void 0 ? "undefined" : JSON.stringify(value.css);
883
+ case "choice": return `(${`${this.testText(value.test)}${value.nullish ? " != null" : ""}`} ? ${this.runtimeValue(value.consequent, property)} : ${this.runtimeValue(value.alternate, property)})`;
884
+ case "token":
885
+ if (!this.options.dev) return tokenExpression(value.name, value.param);
886
+ return `${this.helper("__vxDevToken")}(${JSON.stringify(property)}, ${JSON.stringify(value.param.prefix)}, ${value.name})`;
887
+ case "runtime": {
888
+ const { node, numbers } = value;
889
+ const bare = node.type === "Identifier";
890
+ const text = bare ? node.name : this.copy(node, value.tokens);
891
+ const checked = (x) => this.options.dev ? `${this.helper("__vxDevValue")}(${JSON.stringify(property)}, ${x})` : x;
892
+ if (node.type === "TemplateLiteral") return checked(text);
893
+ const step = cssVarName(this.system.cssVarPrefix, "spacing", SPACING_STEP);
894
+ const map = (x) => {
895
+ const lookup = Object.keys(numbers.lookup).length > 0;
896
+ const fallback = {
897
+ calc: `"calc(var(${step}) * " + ${x} + ")"`,
898
+ px: `${x} + "px"`,
899
+ ms: `${x} + "ms"`,
900
+ deg: `${x} + "deg"`,
901
+ plain: `String(${x})`,
902
+ unset: "undefined"
903
+ }[numbers.fallback];
904
+ return `typeof ${x} === "number" ? ${lookup ? `${JSON.stringify(numbers.lookup)}[${x}] ?? ` : ""}${fallback} : ${x}`;
905
+ };
906
+ return checked(bare ? map(text) : `((v) => ${map("v")})(${text})`);
907
+ }
908
+ }
909
+ }
910
+ /**
911
+ * `sx(a, cond && b, x ? c : d)` with every style known at build time
912
+ * becomes its merged result, one string per combination of the tests.
913
+ */
914
+ fold(call, editor) {
915
+ for (const arg of call.arguments) this.noteNames(arg);
916
+ const parts = [];
917
+ let conditions = 0;
918
+ for (const arg of call.arguments) {
919
+ if (arg.type === "SpreadElement") return false;
920
+ const known = this.known(arg);
921
+ if (known !== void 0) {
922
+ parts.push({ classes: known });
923
+ continue;
924
+ }
925
+ const node = unwrap(arg);
926
+ let part;
927
+ if (node.type === "LogicalExpression" && node.operator === "&&") part = {
928
+ test: node.left,
929
+ ifTrue: this.known(node.right),
930
+ ifFalse: ""
931
+ };
932
+ else if (node.type === "ConditionalExpression") part = {
933
+ test: node.test,
934
+ ifTrue: this.known(node.consequent),
935
+ ifFalse: this.known(node.alternate)
936
+ };
937
+ else return false;
938
+ if (part.ifTrue === void 0 || part.ifFalse === void 0) return false;
939
+ parts.push({
940
+ test: part.test,
941
+ ifTrue: part.ifTrue,
942
+ ifFalse: part.ifFalse
943
+ });
944
+ conditions++;
945
+ }
946
+ if (conditions > MAX_FOLD_CONDITIONS) return false;
947
+ const tests = parts.flatMap((part) => "test" in part ? [this.testText(part.test)] : []);
948
+ let dropped = false;
949
+ let flattened = false;
950
+ const leaf = (picks) => {
951
+ let i = 0;
952
+ const chosen = parts.map((part) => "test" in part ? picks[i++] ? part.ifTrue : part.ifFalse : part.classes);
953
+ if (!dropped) dropped = this.warnDroppedThemes(call, chosen);
954
+ if (!flattened) flattened = this.warnFlattenedBases(call, chosen);
955
+ const merged = mergeClassNames(chosen);
956
+ for (const cls of merged) if (cls.startsWith("!")) this.names.add(cls.slice(1));
957
+ else this.pass.folded.add(cls);
958
+ return classAttribute(merged.join(" "), this.emit);
959
+ };
960
+ const choose = (picks) => picks.length === tests.length ? leaf(picks) : `${tests[picks.length]} ? ${choose([...picks, true])} : ${choose([...picks, false])}`;
961
+ const value = choose([]);
962
+ const src = this.options.dev ? `, "data-vx-src": ${this.sourceOf(call)}` : "";
963
+ this.replace(editor, call.start, call.end, `({ ${this.shape.attribute}: ${value}${src} })`);
964
+ return true;
965
+ }
966
+ /**
967
+ * A theme is one class with one merge key, so `sx(brand, round)` keeps
968
+ * `round` alone, as it keeps the last value of a property: two themes on
969
+ * one element could set the same custom properties (a token, or a token
970
+ * both re-declare as an alias), and the sheet's order, not the call's,
971
+ * would pick the winner. Folding sees the arguments, so it says so.
972
+ * Returns whether it warned.
973
+ */
974
+ warnDroppedThemes(call, chosen) {
975
+ const seen = /* @__PURE__ */ new Set();
976
+ for (const cls of chosen.flatMap((classes) => classes.split(" "))) {
977
+ if (!cls.startsWith(`vx-theme_`)) continue;
978
+ seen.delete(cls);
979
+ seen.add(cls);
980
+ }
981
+ const themes = [...seen];
982
+ if (themes.length < 2) return false;
983
+ const kept = themes.at(-1);
984
+ const lost = themes.slice(0, -1).map((theme) => `\`${theme}\``);
985
+ const hint = "Write one theme() with every override, or apply the themes to nested elements.";
986
+ this.options.warn?.(`sx() keeps one theme per element, the last (\`${kept}\`): ${lost.join(", ")} ${lost.length === 1 ? "is" : "are"} dropped. ${hint}`, {
987
+ code: "DROPPED_THEME",
988
+ loc: {
989
+ file: this.root.id,
990
+ ...this.root.locate(call.start)
991
+ },
992
+ hint
993
+ });
994
+ return true;
995
+ }
996
+ /**
997
+ * Flattened recipe bases (core/flatten.ts) share one merge key, so an
998
+ * element keeps the last, as with themes; and a flattened base applies
999
+ * under every atom of its element, so an earlier argument's class it
1000
+ * would have cleared atomically stays. Folding sees both. Returns
1001
+ * whether it warned.
1002
+ */
1003
+ warnFlattenedBases(call, chosen) {
1004
+ const seen = /* @__PURE__ */ new Set();
1005
+ for (const cls of chosen.flatMap((classes) => classes.split(" "))) {
1006
+ if (!isBaseClass(cls)) continue;
1007
+ seen.delete(cls);
1008
+ seen.add(cls);
1009
+ }
1010
+ if (seen.size === 0) return false;
1011
+ const loc = {
1012
+ file: this.root.id,
1013
+ ...this.root.locate(call.start)
1014
+ };
1015
+ const bases = [...seen];
1016
+ if (bases.length > 1) {
1017
+ const kept = bases.at(-1);
1018
+ const lost = bases.slice(0, -1).map((base) => `\`${base}\``);
1019
+ const hint = "Flatten one of the recipes only (`flatten: false` on the other), or apply them to nested elements.";
1020
+ this.options.warn?.(`sx() keeps one flattened recipe base per element, the last (\`${kept}\`): ${lost.join(", ")} ${lost.length === 1 ? "is" : "are"} dropped. ${hint}`, {
1021
+ code: "DROPPED_BASE",
1022
+ loc,
1023
+ hint
1024
+ });
1025
+ return true;
1026
+ }
1027
+ const shadowed = shadowedByEarlier(chosen, (base) => this.rules.get(base)?.atoms?.map((atom) => atom.className));
1028
+ if (!shadowed) return false;
1029
+ const classes = shadowed.classes.map((cls) => `\`${cls}\``).join(", ");
1030
+ const hint = "Pass the recipe's result first (sx(recipe(…), …)), or leave its base atomic (`flatten: false`).";
1031
+ this.options.warn?.(`sx() applies the flattened recipe base \`${shadowed.base}\` under every class of the element: ${classes}, from an earlier argument, ${shadowed.classes.length === 1 ? "wins" : "win"} over what the base sets, which an atomic base would override. ${hint}`, {
1032
+ code: "BASE_ORDER",
1033
+ loc,
1034
+ hint
1035
+ });
1036
+ return true;
1037
+ }
1038
+ /**
1039
+ * `sx(a, b)` → `__vxSxDev("src/Card.tsx:12", a, b)`, in dev, for a call
1040
+ * that stays a runtime call: the variant of the module's shape.
1041
+ */
1042
+ devCall(call, editor) {
1043
+ const { code } = this.root;
1044
+ const open = skipTrivia(code, Math.max(call.callee.end, call.typeArguments?.end ?? 0));
1045
+ if (call.optional || code[open] !== "(") return;
1046
+ const rest = call.arguments.length > 0 ? ", " : "";
1047
+ const dev = `${this.shape.dev}(${this.sourceOf(call)}${rest}`;
1048
+ this.replace(editor, call.callee.start, open + 1, dev);
1049
+ this.pass.devSx = true;
1050
+ }
1051
+ /** `"src/Card.tsx:12"`: where a call is, for `data-vx-src`. */
1052
+ sourceOf(call) {
1053
+ const file = this.root.id.replace(/[?#].*$/, "");
1054
+ const root = this.options.root?.replace(/\/+$/, "");
1055
+ const name = root && file.startsWith(`${root}/`) ? file.slice(root.length + 1) : file;
1056
+ const { line, column } = this.root.locate(call.start);
1057
+ const at = this.options.sourceLine ? this.options.sourceLine(line, column) : line;
1058
+ return JSON.stringify(at === void 0 ? name : `${name}:${at}`);
1059
+ }
1060
+ /** The classes an `sx()` argument adds, when the compiler knows them. */
1061
+ /** The classes a string written in an `sx()` argument names, through `&&` and `?:`. */
1062
+ noteNames(node) {
1063
+ const inner = unwrap(node);
1064
+ if (inner.type === "Literal" && typeof inner.value === "string") for (const cls of splitClasses(inner.value)) this.names.add(cls);
1065
+ else if (inner.type === "TemplateLiteral") inner.quasis.forEach((quasi, i) => {
1066
+ const text = quasi.value.cooked ?? "";
1067
+ const words = splitClasses(text);
1068
+ if (i > 0 && /^\S/.test(text)) words.shift();
1069
+ if (i < inner.quasis.length - 1 && /\S$/.test(text)) words.pop();
1070
+ for (const cls of words) this.names.add(cls);
1071
+ });
1072
+ else if (inner.type === "LogicalExpression") this.noteNames(inner.right);
1073
+ else if (inner.type === "ConditionalExpression") {
1074
+ this.noteNames(inner.consequent);
1075
+ this.noteNames(inner.alternate);
1076
+ }
1077
+ }
1078
+ known(node) {
1079
+ const value = attempt(() => evaluate(node, this.root.ctx));
1080
+ return value ? classesOf(value.result) : void 0;
1081
+ }
1082
+ testText(test) {
1083
+ const text = this.copy(test);
1084
+ return BARE_TESTS.has(test.type) ? text : `(${text})`;
1085
+ }
1086
+ /**
1087
+ * Source text moved into generated code, with the runtime calls inside it
1088
+ * rewritten, and token-typed parameters read as their `var(--…)`.
1089
+ */
1090
+ copy(node, tokens) {
1091
+ this.pass.spans.push({
1092
+ start: node.start,
1093
+ end: node.end,
1094
+ live: true
1095
+ });
1096
+ const splice = new Splice(this.root.code, node.start, node.end);
1097
+ this.rewrite(node, splice);
1098
+ if (tokens && tokens.size > 0) {
1099
+ const { scopes } = this.root;
1100
+ const paramOf = (id) => {
1101
+ if (id.type !== "Identifier") return void 0;
1102
+ const binding = scopes.bindingOf(id);
1103
+ return binding && binding.id !== id ? tokens.get(binding) : void 0;
1104
+ };
1105
+ walk(this.root, node, (child) => {
1106
+ if (splice.touches(child.start, child.end)) return false;
1107
+ if (child.type === "Property" && child.shorthand) {
1108
+ const param = paramOf(child.value);
1109
+ if (!param) return true;
1110
+ const name = child.value.name;
1111
+ splice.overwrite(child.start, child.end, `${name}: ${tokenExpression(name, param)}`);
1112
+ return false;
1113
+ }
1114
+ const param = paramOf(child);
1115
+ if (param) {
1116
+ const name = child.name;
1117
+ const text = tokenExpression(name, param);
1118
+ splice.overwrite(child.start, child.end, param.nullable ? text : `(${text})`);
1119
+ }
1120
+ return true;
1121
+ });
1122
+ }
1123
+ return splice.toString();
1124
+ }
1125
+ replace(editor, start, end, content) {
1126
+ this.pass.spans.push({
1127
+ start,
1128
+ end,
1129
+ live: false
1130
+ });
1131
+ if (content === "") editor.remove(start, end);
1132
+ else editor.overwrite(start, end, content);
1133
+ }
1134
+ /**
1135
+ * Drops import specifiers that only rewritten code referenced, and
1136
+ * declarations left empty. Specifiers that were never referenced as values
1137
+ * (types, side effects, JSX the scope analysis does not see) stay. An `sx`
1138
+ * the output still calls is pointed at the framework's shape (PLAN §5.12):
1139
+ * renamed in an import of the runtime, imported from the runtime instead of
1140
+ * a wrapper module (whose re-exports need not include the shapes).
1141
+ */
1142
+ pruneImports() {
1143
+ const { root } = this;
1144
+ const references = [];
1145
+ const jsx = /* @__PURE__ */ new Set();
1146
+ /** `ns.sx` where `ns` is a namespace import of a runtime source. */
1147
+ const members = [];
1148
+ walk(root, root.program, (node) => {
1149
+ if (node.type === "JSXIdentifier") jsx.add(node.name);
1150
+ if (node.type === "MemberExpression" && memberKey(node) === "sx") {
1151
+ const binding = namespaceOf(root, node.object);
1152
+ if (binding) members.push({
1153
+ node,
1154
+ binding
1155
+ });
1156
+ }
1157
+ if (node.type !== "Identifier") return true;
1158
+ const binding = root.scopes.bindingOf(node);
1159
+ if (binding?.kind === "import" && binding.id !== node) references.push({
1160
+ binding,
1161
+ offset: node.start
1162
+ });
1163
+ return true;
1164
+ });
1165
+ const live = this.liveness(references.map((reference) => reference.offset));
1166
+ const referenced = /* @__PURE__ */ new Set();
1167
+ const kept = /* @__PURE__ */ new Set();
1168
+ references.forEach(({ binding }, i) => {
1169
+ referenced.add(binding);
1170
+ if (live[i]) kept.add(binding);
1171
+ });
1172
+ const { code } = root;
1173
+ const edits = this.pass.edits;
1174
+ const target = this.shape.target;
1175
+ const direct = (locals) => ` import { ${locals.map((local) => `${target} as ${local}`).join(", ")} } from "${RUNTIME_PACKAGE}";`;
1176
+ const renamed = /* @__PURE__ */ new Map();
1177
+ const slice = (node) => renamed.get(node) ?? code.slice(node.start, node.end);
1178
+ const added = [...this.pass.helpers].filter(([, helper]) => helper.add).map(([name, { local }]) => local === name ? name : `${name} as ${local}`);
1179
+ const host = added.length === 0 ? void 0 : root.program.body.find((node) => node.type === "ImportDeclaration" && node.importKind !== "type" && node.source.value === RUNTIME_PACKAGE && node.specifiers.some((s) => s.type === "ImportSpecifier"));
1180
+ if (added.length > 0 && !host) {
1181
+ const first = root.program.body.find((node) => !(node.type === "ExpressionStatement" && typeof node.directive === "string"));
1182
+ const statement = `import { ${added.join(", ")} } from "${RUNTIME_PACKAGE}";`;
1183
+ if (first) edits.insert(first.start, `${statement}${this.options.keepLines ? " " : "\n"}`);
1184
+ else edits.insert(code.length, `\n${statement}\n`);
1185
+ }
1186
+ for (const declaration of root.program.body) {
1187
+ if (declaration.type !== "ImportDeclaration" || declaration.importKind === "type") continue;
1188
+ const remaining = new Set(declaration.specifiers.filter((specifier) => {
1189
+ const binding = root.scopes.bindingOf(specifier.local);
1190
+ return !binding || !referenced.has(binding) || kept.has(binding) || jsx.has(binding.name);
1191
+ }));
1192
+ const moved = [];
1193
+ for (const specifier of target ? remaining : []) {
1194
+ const binding = root.scopes.bindingOf(specifier.local);
1195
+ if (!binding || !kept.has(binding) || root.runtime.get(binding) !== "sx") continue;
1196
+ if (declaration.source.value === RUNTIME_PACKAGE) renamed.set(specifier, `${target} as ${specifier.local.name}`);
1197
+ else {
1198
+ remaining.delete(specifier);
1199
+ moved.push(specifier.local.name);
1200
+ }
1201
+ }
1202
+ if (moved.length > 0) edits.insert(declaration.end, direct(moved));
1203
+ if (declaration === host) {
1204
+ this.addHelpers(declaration, remaining, added, slice);
1205
+ continue;
1206
+ }
1207
+ const named = declaration.specifiers.filter((s) => s.type === "ImportSpecifier");
1208
+ if (named.some((s) => renamed.has(s)) && remaining.size === declaration.specifiers.length) {
1209
+ edits.overwrite(named[0].start, named.at(-1).end, named.map(slice).join(", "));
1210
+ continue;
1211
+ }
1212
+ if (remaining.size === declaration.specifiers.length) continue;
1213
+ if (remaining.size === 0) {
1214
+ if (declaration.source.value !== RUNTIME_PACKAGE) {
1215
+ edits.overwrite(declaration.start, declaration.end, `import ${code.slice(declaration.source.start, declaration.end)}`);
1216
+ continue;
1217
+ }
1218
+ const end = code.startsWith("\r\n", declaration.end) ? declaration.end + 2 : code[declaration.end] === "\n" ? declaration.end + 1 : declaration.end;
1219
+ edits.remove(declaration.start, end);
1220
+ continue;
1221
+ }
1222
+ const clause = declaration.specifiers.find((s) => s.type !== "ImportSpecifier");
1223
+ const namespace = declaration.specifiers.find((s) => s.type === "ImportNamespaceSpecifier");
1224
+ const keptNamed = named.filter((s) => remaining.has(s));
1225
+ if (named.length > 0 && keptNamed.length === 0) {
1226
+ const close = skipTrivia(code, named.at(-1).end);
1227
+ const brace = code[close] === "," ? skipTrivia(code, close + 1) : close;
1228
+ edits.remove(clause.end, brace + 1);
1229
+ } else if (keptNamed.length < named.length || keptNamed.some((s) => renamed.has(s))) edits.overwrite(named[0].start, named.at(-1).end, keptNamed.map(slice).join(", "));
1230
+ const defaulted = declaration.specifiers.find((s) => s.type === "ImportDefaultSpecifier");
1231
+ if (defaulted && !remaining.has(defaulted)) {
1232
+ const next = namespace ?? named[0];
1233
+ edits.remove(defaulted.start, next === namespace ? next.start : openBrace(code, defaulted.end));
1234
+ } else if (namespace && !remaining.has(namespace) && defaulted) edits.remove(defaulted.end, namespace.end);
1235
+ }
1236
+ if (!target) return;
1237
+ let alias = false;
1238
+ for (const { node, binding } of members) {
1239
+ if (this.pass.spans.some((s) => !s.live && s.start <= node.start && node.end <= s.end)) continue;
1240
+ if (binding.source === RUNTIME_PACKAGE) {
1241
+ const property = node.property;
1242
+ edits.overwrite(property.start, property.end, node.computed ? JSON.stringify(target) : target);
1243
+ } else {
1244
+ edits.overwrite(node.start, node.end, "__vxSx");
1245
+ const declaration = root.program.body.find((d) => d.type === "ImportDeclaration" && d.specifiers.some((s) => s === binding.node));
1246
+ if (!alias && declaration) edits.insert(declaration.end, direct(["__vxSx"]));
1247
+ alias = true;
1248
+ }
1249
+ }
1250
+ }
1251
+ /**
1252
+ * Prunes the runtime import that takes the helpers, which has named
1253
+ * specifiers and no namespace: `import { recipe, sx }` → `import { sx, __vxRecipe }`.
1254
+ * `slice` gives a kept specifier's text, an `sx` pointed at its shape included.
1255
+ */
1256
+ addHelpers(declaration, remaining, added, slice) {
1257
+ const { code } = this.root;
1258
+ const edits = this.pass.edits;
1259
+ const named = declaration.specifiers.filter((s) => s.type === "ImportSpecifier");
1260
+ if (remaining.size === 0) {
1261
+ const from = code.slice(declaration.source.start, declaration.end);
1262
+ edits.overwrite(declaration.start, declaration.end, `import { ${added.join(", ")} } from ${from}`);
1263
+ return;
1264
+ }
1265
+ const keptNamed = named.filter((s) => remaining.has(s)).map(slice);
1266
+ if (keptNamed.length === named.length && named.every((s, i) => keptNamed[i] === code.slice(s.start, s.end))) edits.insert(named.at(-1).end, `, ${added.join(", ")}`);
1267
+ else edits.overwrite(named[0].start, named.at(-1).end, [...keptNamed, ...added].join(", "));
1268
+ const defaulted = declaration.specifiers.find((s) => s.type === "ImportDefaultSpecifier");
1269
+ if (defaulted && !remaining.has(defaulted)) edits.remove(defaulted.start, openBrace(code, defaulted.end));
1270
+ }
1271
+ /**
1272
+ * Whether the output still holds the original code at each offset: the
1273
+ * innermost span around it decides. Spans nest or are disjoint, so one
1274
+ * sweep with a stack of open spans answers every offset.
1275
+ */
1276
+ liveness(offsets) {
1277
+ const spans = this.pass.spans.map((span, index) => ({
1278
+ span,
1279
+ index
1280
+ })).sort((a, b) => a.span.start - b.span.start || b.span.end - a.span.end || a.index - b.index).map((entry) => entry.span);
1281
+ const order = offsets.map((_, i) => i).sort((a, b) => offsets[a] - offsets[b]);
1282
+ const open = [];
1283
+ const out = [];
1284
+ let next = 0;
1285
+ for (const i of order) {
1286
+ const offset = offsets[i];
1287
+ for (let span = spans[next]; span && span.start <= offset; span = spans[++next]) {
1288
+ while (open.length > 0 && open.at(-1).end <= span.start) open.pop();
1289
+ open.push(span);
1290
+ }
1291
+ while (open.length > 0 && open.at(-1).end <= offset) open.pop();
1292
+ out[i] = open.at(-1)?.live ?? true;
1293
+ }
1294
+ return out;
1295
+ }
1296
+ /** Gives runtime calls their compile-time value inside a static expression. */
1297
+ evaluateCall(mod, callee, args, evaluateNode) {
1298
+ if (isUnref(mod, callee, args)) return evaluateNode(args[0]);
1299
+ const name = runtimeName(mod, callee);
1300
+ if (name === void 0) return this.evaluateRecipeCall(mod, callee, args, evaluateNode);
1301
+ switch (name) {
1302
+ case "css": {
1303
+ const style = this.compileStyle(mod, callee, args);
1304
+ return style.vars ? FUNCTION_STYLE : new CompiledStyle(style.classes);
1305
+ }
1306
+ case "recipe": return new RecipeValue(this.compileRecipe(mod, callee, args, evaluateNode));
1307
+ case "group":
1308
+ case "peer": return this.markerOf(mod, name, callee, args, evaluateNode);
1309
+ case "token": {
1310
+ const token = this.tokenOf(mod, callee, args, evaluateNode);
1311
+ return `{${token.scale}.${token.path}}`;
1312
+ }
1313
+ case "keyframes": return this.compileRule(mod, "keyframes", callee, args, evaluateNode).id;
1314
+ case "theme": return new CompiledStyle(this.compileRule(mod, "theme", callee, args, evaluateNode).id);
1315
+ default: return NOT_HANDLED;
1316
+ }
1317
+ }
1318
+ /**
1319
+ * A call of a recipe with static props, inside a static expression: its
1320
+ * classes, as a compiled style or an object of them per slot. Any other
1321
+ * call is not handled, and the evaluator reports it.
1322
+ */
1323
+ evaluateRecipeCall(mod, callee, args, evaluateNode) {
1324
+ const [arg] = args;
1325
+ if (args.length > 1 || arg?.type === "SpreadElement") return NOT_HANDLED;
1326
+ const target = this.probe(() => attempt(() => evaluateNode(callee)));
1327
+ if (!(target?.result instanceof RecipeValue)) return NOT_HANDLED;
1328
+ const props = arg ? evaluateNode(arg) : void 0;
1329
+ const { recipe } = target.result;
1330
+ const classes = resolveRecipe(recipe, props, this.propsError(mod, callee, arg));
1331
+ if (!recipe.table.s) return new CompiledStyle(fromRecord(classes));
1332
+ return Object.fromEntries(Object.entries(classes).map(([slot, style]) => [slot, new CompiledStyle(fromRecord(style))]));
1333
+ }
1334
+ /** A `recipe()` call: its table and atoms (PLAN §5.7). */
1335
+ compileRecipe(mod, callee, args, evaluateNode) {
1336
+ const cached = mod.recipes.get(args);
1337
+ if (cached) return cached;
1338
+ const [arg] = args;
1339
+ if (args.length !== 1 || !arg || arg.type === "SpreadElement") throw this.error(mod, callee, "BAD_CALL", "recipe() takes one definition object", RECIPE_HINT);
1340
+ const definition = evaluateNode(arg);
1341
+ const { cache } = this.options;
1342
+ const key = cache?.recipes && (mod !== this.root || !this.options.warn) ? `${recipeKey(definition)}${this.privateAccess(mod) ? "\0private" : ""}` : void 0;
1343
+ let shared = key === void 0 ? void 0 : cache.recipes.get(this.system);
1344
+ if (key !== void 0 && !shared) cache.recipes.set(this.system, shared = /* @__PURE__ */ new Map());
1345
+ const hit = key === void 0 ? void 0 : shared.get(key);
1346
+ const recipe = hit ?? buildRecipe(definition, {
1347
+ system: this.system,
1348
+ normalize: (style, path) => {
1349
+ if (containsCompiled(style)) throw new VicssError("BAD_STYLE", `${path}: a compiled style is used inside a recipe; recipes take style objects`, {
1350
+ loc: this.locateStyle(mod, arg, path),
1351
+ hint: "Write the style object itself."
1352
+ });
1353
+ return normalizeStyle(style, {
1354
+ ...this.normalizeContext(mod, arg),
1355
+ root: path
1356
+ });
1357
+ },
1358
+ error: (path, code, message, hint) => new VicssError(code, message, {
1359
+ loc: this.locateStyle(mod, arg, path),
1360
+ hint
1361
+ })
1362
+ });
1363
+ if (key !== void 0 && !hit) {
1364
+ if (shared.size >= RECIPE_CACHE_SIZE) shared.clear();
1365
+ shared.set(key, recipe);
1366
+ }
1367
+ mod.recipes.set(args, recipe);
1368
+ for (const atom of recipe.atoms) if (!this.atomIndex.has(atom.className)) this.atomIndex.set(atom.className, atom);
1369
+ for (const rule of recipe.rules) if (!this.rules.has(rule.id)) this.rules.set(rule.id, rule);
1370
+ return recipe;
1371
+ }
1372
+ /**
1373
+ * A `group()` or `peer()` call. Its key in the module is the name it is
1374
+ * given, else the const it initialises, else its position among the
1375
+ * module's marker calls; the id hashes the key with the module's path.
1376
+ */
1377
+ markerOf(mod, kind, callee, args, evaluateNode) {
1378
+ const cached = mod.markers.get(args);
1379
+ if (cached) return cached;
1380
+ const [arg] = args;
1381
+ const hint = `Write const row = ${kind}(), or ${kind}("row") to name it.`;
1382
+ if (args.length > 1 || arg?.type === "SpreadElement") throw this.error(mod, callee, "BAD_CALL", `${kind}() takes an optional name`, hint);
1383
+ let name;
1384
+ if (arg) {
1385
+ const value = evaluateNode(arg);
1386
+ if (typeof value !== "string" || !/^[\w$-]+$/.test(value)) throw this.error(mod, arg, "BAD_CALL", `a ${kind}() name is a string of letters, digits, \`_\`, \`$\` or \`-\``, hint);
1387
+ name = value;
1388
+ }
1389
+ mod.markerSites ??= markerSites(mod.program, (call) => {
1390
+ const callName = runtimeName(mod, call.callee);
1391
+ return callName === "group" || callName === "peer";
1392
+ });
1393
+ const site = mod.markerSites.get(args);
1394
+ const key = name ?? site?.binding ?? `#${site?.index ?? 0}`;
1395
+ const family = kind === "group" ? "g" : "p";
1396
+ const claimed = mod.markerKeys.get(`${family}:${key}`);
1397
+ if (claimed && claimed !== args) throw this.error(mod, callee, "DUPLICATE_MARKER", `another ${kind}() in this module is also called \`${key}\`, so the two would mark elements with one class`, `Name one of them: ${kind}("${key}2").`);
1398
+ mod.markerKeys.set(`${family}:${key}`, args);
1399
+ const marker = new MarkerValue(family, markerId(mod.id, this.options.root ?? process.cwd(), key, this.options.package), this.system);
1400
+ mod.markers.set(args, marker);
1401
+ this.markerLabels.set(`${family}:${marker.id}`, markerLabel(family, key));
1402
+ return marker;
1403
+ }
1404
+ /** A `keyframes()` or `theme()` call: its rule, which names the call's result. */
1405
+ compileRule(mod, kind, callee, args, evaluateNode) {
1406
+ const cached = mod.rules.get(args);
1407
+ if (cached) return cached;
1408
+ const [arg] = args;
1409
+ if (args.length !== 1 || !arg || arg.type === "SpreadElement") throw this.error(mod, callee, "BAD_CALL", kind === "theme" ? "theme() takes one object of token overrides" : "keyframes() takes one object of frames", kind === "theme" ? THEME_HINT : KEYFRAMES_HINT);
1410
+ const value = evaluateNode(arg);
1411
+ const rule = kind === "theme" ? compileTheme(value, this.system, { locate: (path) => this.locateStyle(mod, arg, path) }) : compileKeyframes(value, this.normalizeContext(mod, arg));
1412
+ mod.rules.set(args, rule);
1413
+ if (!this.rules.has(rule.id)) this.rules.set(rule.id, rule);
1414
+ return rule;
1415
+ }
1416
+ compileStyle(mod, callee, args) {
1417
+ const cached = mod.styles.get(args);
1418
+ if (cached) return cached;
1419
+ if (this.compiling.has(args)) throw this.error(mod, callee, "NOT_STATIC", "this style reads its own result", "A style cannot depend on the value it compiles to.");
1420
+ this.compiling.add(args);
1421
+ try {
1422
+ return this.compileStyleOnce(mod, callee, args);
1423
+ } finally {
1424
+ this.compiling.delete(args);
1425
+ }
1426
+ }
1427
+ compileStyleOnce(mod, callee, args) {
1428
+ const [arg, options] = args;
1429
+ if (args.length < 1 || args.length > 2 || !arg || arg.type === "SpreadElement" || options?.type === "SpreadElement") throw this.error(mod, callee, "BAD_CALL", "css() takes one style object, and its options", CSS_HINT);
1430
+ const inner = unwrap(arg);
1431
+ if (inner.type === "FunctionExpression") throw this.error(mod, inner, "BAD_STYLE", "a function style is an arrow function", CSS_HINT);
1432
+ const name = options && this.styleName(mod, options);
1433
+ let style = inner.type === "ArrowFunctionExpression" ? this.compileFunctionStyle(mod, inner) : this.compileStaticStyle(mod, arg);
1434
+ if (name) style = {
1435
+ ...style,
1436
+ classes: `!${name} ${style.classes}`.trim()
1437
+ };
1438
+ mod.styles.set(args, style);
1439
+ for (const atom of style.atoms) if (!this.atomIndex.has(atom.className)) this.atomIndex.set(atom.className, atom);
1440
+ return style;
1441
+ }
1442
+ /** `css(style, { name: "card" })`: the class the style adds as it is. */
1443
+ styleName(mod, node) {
1444
+ const value = evaluate(node, mod.ctx);
1445
+ const keys = isPlainObject(value) ? Object.keys(value) : void 0;
1446
+ const name = isPlainObject(value) ? value.name : void 0;
1447
+ const bad = keys?.find((key) => key !== "name");
1448
+ if (!keys || bad !== void 0) throw this.error(mod, node, "BAD_CALL", bad === void 0 ? "css() takes its options as an object: { name }" : `\`${bad}\` is not an option of css(): it takes \`name\``, "Write css({ … }, { name: \"card\" }).");
1449
+ if (name === void 0) return void 0;
1450
+ if (typeof name !== "string" || !CLASS_NAME.test(name) || name.startsWith("vx-")) throw this.error(mod, node, "BAD_CALL", typeof name === "string" && name.startsWith("vx-") ? "class names starting with `vx-` are reserved for vicss" : "a style's `name` is one class name: letters, digits, `-` and `_`, not starting with a digit", "Write css({ … }, { name: \"card\" }).");
1451
+ this.names.add(name);
1452
+ return name;
1453
+ }
1454
+ compileStaticStyle(mod, arg) {
1455
+ const value = evaluate(arg, mod.ctx);
1456
+ this.checkComposition(mod, arg, value, mod.ctx);
1457
+ const atoms = normalizeStyle(value, this.normalizeContext(mod, arg));
1458
+ return {
1459
+ classes: classString(atoms),
1460
+ atoms
1461
+ };
1462
+ }
1463
+ /**
1464
+ * PLAN §5.8: parameters are runtime values. Every property they reach
1465
+ * becomes an atom reading `var(--vx-<hash>)`; the rest compiles statically.
1466
+ */
1467
+ compileFunctionStyle(mod, fn) {
1468
+ if (fn.async) throw this.error(mod, fn, "BAD_STYLE", "a function style cannot be async");
1469
+ const body = unwrap(fn.body);
1470
+ if (body.type !== "ObjectExpression") throw this.error(mod, fn.body, "BAD_STYLE", "a function style must return an object literal", "Write css((value) => ({ width: value })).");
1471
+ const params = /* @__PURE__ */ new Map();
1472
+ for (const param of fn.params) for (const id of bindingIds(param)) {
1473
+ const binding = mod.scopes.bindingOf(id);
1474
+ if (binding) params.set(binding, {
1475
+ __vxSpecial: "dynamic",
1476
+ node: id
1477
+ });
1478
+ }
1479
+ const tokenParams = this.tokenParams(mod, fn);
1480
+ const ctx = {
1481
+ ...mod.ctx,
1482
+ params
1483
+ };
1484
+ const value = evaluate(body, ctx);
1485
+ this.checkComposition(mod, body, value, ctx);
1486
+ const found = [];
1487
+ const normalize = this.normalizeContext(mod, body);
1488
+ const { style: withoutPalettes, palettes, paletteAtoms } = this.runtimePalettes(mod, value, normalize);
1489
+ const style = withPlaceholders(withoutPalettes, found);
1490
+ this.checkRuntimeTargets(mod, body, style, "");
1491
+ const vars = [];
1492
+ const atoms = normalizeStyle(style, normalize).map((atom) => {
1493
+ const index = placeholderIndex(atom.value);
1494
+ if (index === void 0) {
1495
+ if (atom.value.includes(PLACEHOLDER)) throw this.error(mod, body, "BAD_STYLE", `\`${atom.property}\` cannot take a runtime value`);
1496
+ return atom;
1497
+ }
1498
+ const dynamic = found[index];
1499
+ const label = valueLabel({
1500
+ kind: "dynamic",
1501
+ property: atom.property,
1502
+ value: `${atom.chain.join(":")}:${sourceText(mod, dynamic.node)}`
1503
+ });
1504
+ const variable = `--vx-${label.slice(1)}`;
1505
+ const tokens = /* @__PURE__ */ new Map();
1506
+ const scales = /* @__PURE__ */ new Set();
1507
+ const info = propertyByCss(atom.property);
1508
+ vars.push({
1509
+ variable,
1510
+ property: atom.property,
1511
+ value: this.describe(mod, body, info, dynamic, {
1512
+ tokens,
1513
+ scales
1514
+ }, tokenParams)
1515
+ });
1516
+ const labels = atom.chain.map((name) => this.system.conditions.get(name).label);
1517
+ return {
1518
+ ...atom,
1519
+ className: makeClassName(labels, atom.key, label),
1520
+ value: `var(${variable})`,
1521
+ variable,
1522
+ tokens: [...tokens.values()],
1523
+ ...scales.size > 0 ? { scales: [...scales].sort(compareStrings) } : {}
1524
+ };
1525
+ });
1526
+ atoms.sort((a, b) => compareStrings(a.className, b.className));
1527
+ if (palettes.length === 0) return {
1528
+ classes: classString(atoms),
1529
+ atoms,
1530
+ fn,
1531
+ vars
1532
+ };
1533
+ const all = [...atoms, ...paletteAtoms].sort((a, b) => compareStrings(a.className, b.className));
1534
+ return {
1535
+ classes: classString(atoms),
1536
+ atoms: all,
1537
+ fn,
1538
+ vars,
1539
+ palettes
1540
+ };
1541
+ }
1542
+ /**
1543
+ * The `colorPalette` values of a function style that runtime values
1544
+ * choose, taken out of `value`: each becomes a class the function adds
1545
+ * (`RuntimePalette`), and every palette it may name an atom. A parameter
1546
+ * typed as a union of names (`tone: "red" | "blue"`) may name those; any
1547
+ * other runtime value, every palette.
1548
+ */
1549
+ runtimePalettes(mod, value, normalize) {
1550
+ const palettes = [];
1551
+ const paletteAtoms = /* @__PURE__ */ new Map();
1552
+ const names = [...this.system.palettes?.groups.keys() ?? []];
1553
+ /**
1554
+ * `name` as the style would hold it statically, under the condition
1555
+ * blocks and the value per condition's keys it is written in: anything
1556
+ * but a palette's name fails here, with the path a static value has.
1557
+ */
1558
+ const compileOne = (blocks, conditions, name, any = false) => {
1559
+ let value = name;
1560
+ for (const key of [...conditions].reverse()) value = { [key]: value };
1561
+ let style = { colorPalette: value };
1562
+ for (const key of [...blocks].reverse()) style = { [key]: style };
1563
+ const [compiled] = normalizeStyle(style, normalize);
1564
+ const atom = any ? {
1565
+ ...compiled,
1566
+ anyPalette: true
1567
+ } : compiled;
1568
+ keepAtom(paletteAtoms, atom);
1569
+ return atom;
1570
+ };
1571
+ /** Each palette name `v` may hold at runtime, compiled where it is written; its class prefix. */
1572
+ const candidates = (v, blocks, conditions) => {
1573
+ let prefix;
1574
+ const add = (name, any = false) => {
1575
+ const atom = compileOne(blocks, conditions, name, any);
1576
+ prefix ??= atom.className.slice(0, -name.length);
1577
+ };
1578
+ const visit = (x) => {
1579
+ if (isDynamic(x)) {
1580
+ if (x.choice) {
1581
+ visit(x.choice.consequent);
1582
+ visit(x.choice.alternate);
1583
+ return;
1584
+ }
1585
+ if (names.length === 0) compileOne(blocks, conditions, "");
1586
+ const typed = typedPaletteNames(mod.scopes, x.node);
1587
+ for (const name of typed ?? names) add(name, typed === void 0);
1588
+ return;
1589
+ }
1590
+ if (typeof x === "string") add(x);
1591
+ else if (x !== void 0 && x !== null && x !== false) compileOne(blocks, conditions, x);
1592
+ };
1593
+ visit(v);
1594
+ return prefix;
1595
+ };
1596
+ const take = (node, blocks) => {
1597
+ if (!isPlainObject(node) || isDynamic(node)) return node;
1598
+ const out = {};
1599
+ for (const [key, inner] of Object.entries(node)) {
1600
+ if (key === "colorPalette" && containsDynamic(inner)) {
1601
+ const leaves = (v, conditions) => {
1602
+ if (isPlainObject(v) && !isDynamic(v)) {
1603
+ const kept = {};
1604
+ for (const [k, x] of Object.entries(v)) {
1605
+ const rest = leaves(x, [...conditions, k]);
1606
+ if (rest !== void 0) kept[k] = rest;
1607
+ }
1608
+ return Object.keys(kept).length > 0 ? kept : void 0;
1609
+ }
1610
+ if (!containsDynamic(v)) return v;
1611
+ const prefix = candidates(v, blocks, conditions);
1612
+ if (prefix !== void 0) palettes.push({
1613
+ prefix,
1614
+ value: v
1615
+ });
1616
+ };
1617
+ const rest = leaves(inner, []);
1618
+ if (rest !== void 0) out[key] = rest;
1619
+ continue;
1620
+ }
1621
+ out[key] = key.startsWith("_") ? take(inner, [...blocks, key]) : inner;
1622
+ }
1623
+ return out;
1624
+ };
1625
+ return {
1626
+ style: take(value, []),
1627
+ palettes,
1628
+ paletteAtoms: [...paletteAtoms.values()]
1629
+ };
1630
+ }
1631
+ /**
1632
+ * How a runtime value reaches `info`: the branches of a runtime test are
1633
+ * compiled now, with the token check and S9, so `on ? "accent" : 4` sets
1634
+ * `var(--color-accent)` or `calc(var(--spacing) * 4)`. `named` collects
1635
+ * the tokens the value may name, and the scales a Token-typed parameter
1636
+ * may name any token of: those stay scales, so an app that prints a
1637
+ * library's atom counts its own tokens of them, not the library's.
1638
+ */
1639
+ describe(mod, root, info, value, named, tokenParams) {
1640
+ const use = (refs) => {
1641
+ for (const ref of refs) named.tokens.set(`${ref.scale}:${ref.path}`, ref);
1642
+ };
1643
+ if (isDynamic(value)) {
1644
+ const { choice } = value;
1645
+ if (!choice) {
1646
+ const { node } = value;
1647
+ const binding = node.type === "Identifier" ? mod.scopes.bindingOf(node) : void 0;
1648
+ const param = binding && tokenParams.get(binding);
1649
+ if (param) {
1650
+ this.checkTokenTarget(mod, root, info, binding.name, param);
1651
+ named.scales.add(param.scale);
1652
+ return {
1653
+ kind: "token",
1654
+ name: binding.name,
1655
+ param
1656
+ };
1657
+ }
1658
+ const read = /* @__PURE__ */ new Map();
1659
+ if (tokenParams.size > 0) walk(mod, node, (child) => {
1660
+ const ref = child.type === "Identifier" ? mod.scopes.bindingOf(child) : void 0;
1661
+ const token = ref && tokenParams.get(ref);
1662
+ if (token) read.set(ref, token);
1663
+ return true;
1664
+ });
1665
+ for (const token of read.values()) named.scales.add(token.scale);
1666
+ const numbers = this.numberMapping(info);
1667
+ if (node.type !== "TemplateLiteral") use(numbers.tokens);
1668
+ return {
1669
+ kind: "runtime",
1670
+ node,
1671
+ numbers: numbers.mapping,
1672
+ ...read.size > 0 ? { tokens: read } : {}
1673
+ };
1674
+ }
1675
+ return {
1676
+ kind: "choice",
1677
+ test: choice.test,
1678
+ nullish: choice.nullish ?? false,
1679
+ consequent: this.describe(mod, root, info, choice.consequent, named, tokenParams),
1680
+ alternate: this.describe(mod, root, info, choice.alternate, named, tokenParams)
1681
+ };
1682
+ }
1683
+ if (value === void 0 || value === null || value === false) return {
1684
+ kind: "static",
1685
+ css: void 0
1686
+ };
1687
+ if (isPlainObject(value)) throw this.error(mod, root, "BAD_STYLE", `\`${info.name}\`: a runtime test chooses between values, not between values per condition`, "Put the test inside each condition: { base: on ? a : b, _md: on ? c : d }.");
1688
+ const atom = normalizeStyle({ [info.name]: value }, this.normalizeContext(mod, root)).find((a) => a.property === info.css);
1689
+ if (!atom) throw this.error(mod, root, "BAD_STYLE", `\`${info.name}\` cannot take this value`);
1690
+ use(atom.tokens);
1691
+ return {
1692
+ kind: "static",
1693
+ css: atom.value
1694
+ };
1695
+ }
1696
+ /**
1697
+ * Parameters typed `Token<"scale">`, with `Token` imported from a vicss
1698
+ * import source under any name (`T<"colors">`, `vx.Token<"colors">`),
1699
+ * plain, defaulted or destructured from a type literal.
1700
+ */
1701
+ tokenParams(mod, fn) {
1702
+ const out = /* @__PURE__ */ new Map();
1703
+ const types = /* @__PURE__ */ new Set();
1704
+ const namespaces = /* @__PURE__ */ new Set();
1705
+ for (const node of mod.program.body) {
1706
+ if (node.type !== "ImportDeclaration" || !this.sources.includes(node.source.value)) continue;
1707
+ for (const specifier of node.specifiers) if (specifier.type === "ImportNamespaceSpecifier") namespaces.add(specifier.local.name);
1708
+ else if (specifier.type === "ImportSpecifier" && importedName(specifier) === "Token") types.add(specifier.local.name);
1709
+ }
1710
+ if (types.size === 0 && namespaces.size === 0) return out;
1711
+ const isToken = (name) => name.type === "Identifier" ? types.has(name.name) : name.type === "TSQualifiedName" && name.left.type === "Identifier" && namespaces.has(name.left.name) && name.right.name === "Token";
1712
+ const visit = (pattern, type, optional) => {
1713
+ const annotation = pattern.typeAnnotation?.typeAnnotation ?? type;
1714
+ switch (pattern.type) {
1715
+ case "Identifier": {
1716
+ const param = annotation && this.tokenParam(mod, annotation, isToken, optional || pattern.optional === true);
1717
+ const binding = param && mod.scopes.bindingOf(pattern);
1718
+ if (param && binding) out.set(binding, param);
1719
+ return;
1720
+ }
1721
+ case "AssignmentPattern":
1722
+ visit(pattern.left, annotation, optional);
1723
+ return;
1724
+ case "ObjectPattern":
1725
+ if (annotation?.type !== "TSTypeLiteral") return;
1726
+ for (const property of pattern.properties) {
1727
+ if (property.type === "RestElement") continue;
1728
+ const key = patternKey(property);
1729
+ const member = annotation.members.find((m) => m.type === "TSPropertySignature" && !m.computed && (m.key.type === "Identifier" ? m.key.name : String(m.key.value)) === key);
1730
+ if (member) visit(property.value, member.typeAnnotation?.typeAnnotation, member.optional);
1731
+ }
1732
+ return;
1733
+ }
1734
+ };
1735
+ for (const param of fn.params) visit(param, void 0, false);
1736
+ return out;
1737
+ }
1738
+ /** `Token<"colors">`, alone or with undefined or null: the scale and how to read it. */
1739
+ tokenParam(mod, annotation, isToken, optional) {
1740
+ let type = annotation;
1741
+ let nullable = optional;
1742
+ if (type.type === "TSUnionType") {
1743
+ const rest = type.types.filter((t) => t.type !== "TSUndefinedKeyword" && t.type !== "TSNullKeyword");
1744
+ if (rest.length !== 1) return void 0;
1745
+ nullable ||= rest.length < type.types.length;
1746
+ type = rest[0];
1747
+ }
1748
+ if (type.type !== "TSTypeReference" || !isToken(type.typeName)) return void 0;
1749
+ const [arg, ...more] = type.typeArguments?.params ?? [];
1750
+ const value = arg?.type === "TSLiteralType" && arg.literal.type === "Literal" && more.length === 0 ? arg.literal.value : void 0;
1751
+ const literal = typeof value === "string" ? value : void 0;
1752
+ const hint = "Name the scale as a literal: (tone: Token<\"colors\">) => ({ background: tone }).";
1753
+ if (literal === void 0) throw this.error(mod, type, "BAD_STYLE", "Token<…> takes one scale name", hint);
1754
+ if (!isScaleName(literal)) throw this.error(mod, type, "UNKNOWN_TOKEN", `\`${literal}\` is not a scale`, didYouMean(closestNames(literal, SCALES)) ?? hint);
1755
+ const scale = literal;
1756
+ if (scaleTokens(this.system, scale).length === 0) throw this.error(mod, type, "NOT_A_TOKEN", `the ${scale} scale has no tokens to name`, scale === "spacing" && this.system.spacingStep !== void 0 ? "The spacing scale is a step: type the parameter as a number, which counts steps." : `Add ${scale} tokens to the config, or type the parameter as a string.`);
1757
+ return {
1758
+ scale,
1759
+ prefix: `--${this.system.cssVarPrefix}${SCALE_NAMESPACES[scale]}-`,
1760
+ nullable
1761
+ };
1762
+ }
1763
+ /** A token of one scale on a property that draws from another is a mistake, not a value. */
1764
+ checkTokenTarget(mod, root, info, name, param) {
1765
+ const { scale } = info;
1766
+ if (!scale || scale === param.scale || scale === "sizes" && param.scale === "spacing") return;
1767
+ throw new VicssError("BAD_STYLE", `\`${info.name}\` takes ${scale} tokens, and \`${name}\` names ${param.scale} tokens`, {
1768
+ loc: this.locateStyle(mod, root, info.name),
1769
+ hint: `Type the parameter Token<"${scale}">.`
1770
+ });
1771
+ }
1772
+ /** S9 at runtime for `info`, and the tokens it may name. */
1773
+ numberMapping(info) {
1774
+ const lookup = {};
1775
+ const tokens = [];
1776
+ const named = (scale) => {
1777
+ for (const token of this.system.tokens.get(scale)?.values() ?? []) {
1778
+ if (token.path in lookup || String(Number(token.path)) !== token.path) continue;
1779
+ lookup[token.path] = `var(${token.cssVar})`;
1780
+ tokens.push({
1781
+ scale,
1782
+ path: token.path
1783
+ });
1784
+ }
1785
+ };
1786
+ if (info.scale) named(info.scale);
1787
+ const kind = numberKind(info);
1788
+ let fallback;
1789
+ if (kind === "spacing" || kind === "sizes") {
1790
+ if (this.system.spacingStep !== void 0) {
1791
+ fallback = "calc";
1792
+ tokens.push({
1793
+ scale: "spacing",
1794
+ path: SPACING_STEP
1795
+ });
1796
+ } else {
1797
+ if (kind === "sizes") named("spacing");
1798
+ fallback = "unset";
1799
+ }
1800
+ } else fallback = kind === "length" ? "px" : kind === "time" ? "ms" : kind === "angle" ? "deg" : "plain";
1801
+ return {
1802
+ mapping: {
1803
+ lookup,
1804
+ fallback
1805
+ },
1806
+ tokens
1807
+ };
1808
+ }
1809
+ /** Runtime values only reach properties that keep their value whole. */
1810
+ checkRuntimeTargets(mod, root, style, path) {
1811
+ if (!isPlainObject(style)) return;
1812
+ for (const [key, value] of Object.entries(style)) {
1813
+ if (!hasPlaceholder(value)) continue;
1814
+ const here = path ? `${path}.${key}` : key;
1815
+ if (key.startsWith("_")) {
1816
+ this.checkRuntimeTargets(mod, root, value, here);
1817
+ continue;
1818
+ }
1819
+ if (this.system.utilities.has(key)) continue;
1820
+ if (key === "textStyle" || getProperty(key)?.expand) throw new VicssError("BAD_STYLE", `${here}: \`${key}\` cannot take a runtime value`, {
1821
+ loc: this.locateStyle(mod, root, here),
1822
+ hint: key === "textStyle" ? "Text styles are chosen at build time." : "It is split into longhands at build time; set the longhands instead."
1823
+ });
1824
+ }
1825
+ }
1826
+ /** A compiled style is a class string: it composes through sx(), never inside a style object. */
1827
+ checkComposition(mod, arg, value, ctx) {
1828
+ if (value instanceof CompiledStyle) throw this.error(mod, arg, "BAD_STYLE", "this style is already compiled; css() takes a style object", "Combine compiled styles with sx(): sx(base, css({ … })).");
1829
+ const spreads = [];
1830
+ collectSpreads(arg, spreads);
1831
+ for (const spread of spreads) {
1832
+ const result = attempt(() => evaluate(spread.argument, ctx))?.result;
1833
+ if (result instanceof MarkerValue) throw this.error(mod, spread, "BAD_STYLE", `\`${excerpt(mod.code, spread)}\` spreads a marker: a marker is applied with sx(), and its states are condition keys`, "sx(row, css({ opacity: { base: 0, [row.hover]: 1 } })).");
1834
+ if (result instanceof CompiledStyle || typeof result === "string") throw this.error(mod, spread, "BAD_STYLE", `\`${excerpt(mod.code, spread)}\` spreads a compiled style: compose compiled styles with sx(), not with spread`, "sx(base, css({ … })) merges them, last value wins.");
1835
+ }
1836
+ if (containsCompiled(value)) throw this.error(mod, arg, "BAD_STYLE", "a compiled style is used inside a style object: compose compiled styles with sx(), not with spread", "sx(base, css({ … })) merges them, last value wins.");
1837
+ }
1838
+ /** Whether styles written in `mod` may name private tokens: `privateAccess` lists it. */
1839
+ privateAccess(mod) {
1840
+ let access = this.access.get(mod.id);
1841
+ if (access === void 0) {
1842
+ access = hasPrivateAccess(this.system, this.options.root ?? process.cwd(), mod.id);
1843
+ this.access.set(mod.id, access);
1844
+ }
1845
+ return access;
1846
+ }
1847
+ normalizeContext(mod, root) {
1848
+ const { options } = this;
1849
+ return {
1850
+ system: this.system,
1851
+ privateAccess: this.privateAccess(mod),
1852
+ locate: (path) => this.locateStyle(mod, root, path),
1853
+ markerLabels: this.markerLabels,
1854
+ ...options.warn && mod === this.root ? { warn: (message, warning) => options.warn?.(message, warning) } : {},
1855
+ ...mod === this.root && { arbitrary: ({ value, path }) => this.arbitrary.add(`${root.start}:${path}:${value}`) }
1856
+ };
1857
+ }
1858
+ /** Where a style path (`padding._md`) was written: its property, or the closest enclosing one. */
1859
+ locateStyle(mod, root, path) {
1860
+ let at = root;
1861
+ let value = root;
1862
+ for (const key of path === "" ? [] : path.split(".")) {
1863
+ const property = findProperty(mod, value, key);
1864
+ if (!property) break;
1865
+ at = property;
1866
+ value = property.value;
1867
+ }
1868
+ return this.loc(mod, at);
1869
+ }
1870
+ tokenOf(mod, callee, args, evaluateNode) {
1871
+ const [arg] = args;
1872
+ if (args.length !== 1 || !arg || arg.type === "SpreadElement") throw this.error(mod, callee, "BAD_CALL", "token() takes one token path", TOKEN_HINT);
1873
+ const path = evaluateNode(arg);
1874
+ if (typeof path !== "string") throw this.error(mod, arg, "BAD_CALL", "token() takes a token path string", TOKEN_HINT);
1875
+ const dot = path.indexOf(".");
1876
+ const scale = dot === -1 ? path : path.slice(0, dot);
1877
+ if (dot === -1 || !isScaleName(scale)) throw this.error(mod, arg, "UNKNOWN_TOKEN", `\`${path}\` does not start with a scale`, didYouMean(closestNames(scale, SCALES).map((s) => `${s}.…`)) ?? TOKEN_HINT);
1878
+ const rest = path.slice(dot + 1);
1879
+ const token = lookupToken(this.system, scale, rest);
1880
+ if (!token) throw this.error(mod, arg, "UNKNOWN_TOKEN", `\`${path}\` names no token`, didYouMean(suggestTokens(this.system, scale, rest).map((p) => `${scale}.${p}`)));
1881
+ if (token.private && !this.privateAccess(mod)) {
1882
+ const e = privateTokenError(this.system, token);
1883
+ throw this.error(mod, arg, e.code, e.message, e.hint);
1884
+ }
1885
+ return token;
1886
+ }
1887
+ resolveImport(mod, binding) {
1888
+ const source = binding.source;
1889
+ const name = binding.imported;
1890
+ if (this.sources.includes(source) && (name === "*" || RUNTIME_EXPORTS.has(name))) throw new Error("it is part of the vicss runtime, not a value");
1891
+ if (!this.options.loadModule) throw new Error("the compiler was given no module loader");
1892
+ return this.exportValue(this.target(mod.id, source), name);
1893
+ }
1894
+ target(importer, source) {
1895
+ const key = requestKey(importer, source);
1896
+ const entry = this.requests.get(key);
1897
+ if (entry === void 0) {
1898
+ if (this.probing > 0 && this.skipped.has(key)) throw new Error(notSearched(source));
1899
+ throw new PendingImport([[importer, source]], this.probing > 0);
1900
+ }
1901
+ if (typeof entry === "string") throw new Error(entry);
1902
+ return entry;
1903
+ }
1904
+ /**
1905
+ * The modules `mod` star-exports, loaded or failed. A barrel of a hundred
1906
+ * `export *` loads its targets together rather than one per pass.
1907
+ */
1908
+ stars(mod) {
1909
+ const probing = this.probing > 0;
1910
+ const missing = mod.scopes.starExports.filter((star) => {
1911
+ const key = requestKey(mod.id, star);
1912
+ return !this.requests.has(key) && !(probing && this.skipped.has(key));
1913
+ });
1914
+ if (missing.length > 0) throw new PendingImport(missing.map((star) => [mod.id, star]), probing);
1915
+ return mod.scopes.starExports.map((star) => this.requests.get(requestKey(mod.id, star)) ?? notSearched(star));
1916
+ }
1917
+ exportValue(mod, name) {
1918
+ const key = requestKey(mod.id, name);
1919
+ if (this.resolving.has(key)) throw new Error(`\`${name}\` of ${mod.id} depends on itself through an import cycle`);
1920
+ this.resolving.add(key);
1921
+ try {
1922
+ if (name === "*") return this.namespace(mod);
1923
+ const entry = mod.scopes.exports.get(name);
1924
+ if (entry?.local !== void 0) {
1925
+ const binding = mod.scopes.moduleBindings.get(entry.local);
1926
+ if (!binding) throw new Error(`${mod.id} exports \`${name}\` without declaring it`);
1927
+ return evaluateBinding(binding, mod.ctx);
1928
+ }
1929
+ if (entry?.source !== void 0) return this.exportValue(this.target(mod.id, entry.source), entry.imported);
1930
+ const unread = [];
1931
+ for (const inner of this.stars(mod)) if (typeof inner === "string") unread.push(inner);
1932
+ else if (this.exportsName(inner, name, /* @__PURE__ */ new Set(), unread)) return this.exportValue(inner, name);
1933
+ throw new Error(`${mod.id} has no export \`${name}\`${unread.length > 0 ? `; ${unread.join("; ")}` : ""}`);
1934
+ } finally {
1935
+ this.resolving.delete(key);
1936
+ }
1937
+ }
1938
+ exportsName(mod, name, seen, unread) {
1939
+ if (seen.has(mod)) return false;
1940
+ seen.add(mod);
1941
+ if (mod.scopes.exports.has(name)) return true;
1942
+ return this.stars(mod).some((inner) => {
1943
+ if (typeof inner !== "string") return this.exportsName(inner, name, seen, unread);
1944
+ unread.push(inner);
1945
+ return false;
1946
+ });
1947
+ }
1948
+ /** Every name `mod` exports, its `export *` targets' included (never their default). */
1949
+ exportNames(mod, seen = /* @__PURE__ */ new Set()) {
1950
+ const names = new Set(mod.scopes.exports.keys());
1951
+ if (seen.has(mod)) return names;
1952
+ seen.add(mod);
1953
+ for (const inner of this.stars(mod)) {
1954
+ if (typeof inner === "string") continue;
1955
+ for (const name of this.exportNames(inner, seen)) if (name !== "default") names.add(name);
1956
+ }
1957
+ return names;
1958
+ }
1959
+ /** `import * as ns`: exports are evaluated when read, so non-static siblings do not matter. */
1960
+ namespace(mod) {
1961
+ const { exports } = mod.scopes;
1962
+ const has = (key) => typeof key === "string" && (exports.has(key) || key !== "default" && this.exportsName(mod, key, /* @__PURE__ */ new Set(), []));
1963
+ return new Proxy({}, {
1964
+ ownKeys: () => [...this.exportNames(mod)],
1965
+ has: (_, key) => has(key),
1966
+ get: (_, key) => has(key) ? this.exportValue(mod, key) : void 0,
1967
+ getOwnPropertyDescriptor: (_, key) => has(key) ? {
1968
+ value: this.exportValue(mod, key),
1969
+ enumerable: true,
1970
+ configurable: true
1971
+ } : void 0
1972
+ });
1973
+ }
1974
+ loc(mod, node) {
1975
+ return {
1976
+ file: mod.id,
1977
+ ...mod.locate(node.start)
1978
+ };
1979
+ }
1980
+ error(mod, node, code, message, hint) {
1981
+ return new VicssError(code, message, {
1982
+ loc: this.loc(mod, node),
1983
+ hint
1984
+ });
1985
+ }
1986
+ };
1987
+ /** A class an app names: what `css(style, { name })` takes. */
1988
+ const CLASS_NAME = /^-?[A-Za-z_][\w-]*$/;
1989
+ const CSS_HINT = "Write css({ padding: 4 }), or css((value) => ({ width: value })) for runtime values.";
1990
+ const TOKEN_HINT = "Write token(\"colors.accent\"): a scale, then the token path.";
1991
+ const THEME_HINT = "Write theme({ colors: { accent: \"{colors.red.600}\" } }).";
1992
+ const KEYFRAMES_HINT = "Write keyframes({ from: { opacity: 0 }, to: { opacity: 1 } }).";
1993
+ const RECIPE_HINT = "Write recipe({ base: { … }, variants: { size: { sm: { … } } } }).";
1994
+ /** The first position at or after `pos` that is not whitespace or a comment. */
1995
+ function skipTrivia(code, pos) {
1996
+ for (let i = pos; i < code.length;) if (/\s/.test(code[i])) i++;
1997
+ else if (code.startsWith("//", i)) i = code.includes("\n", i) ? code.indexOf("\n", i) : code.length;
1998
+ else if (code.startsWith("/*", i)) i = code.indexOf("*/", i + 2) + 2;
1999
+ else return i;
2000
+ return code.length;
2001
+ }
2002
+ /** After a default import specifier: the `{` that opens the named ones. */
2003
+ function openBrace(code, pos) {
2004
+ const comma = skipTrivia(code, pos);
2005
+ return skipTrivia(code, code[comma] === "," ? comma + 1 : comma);
2006
+ }
2007
+ function unchanged(code) {
2008
+ return {
2009
+ code,
2010
+ map: null,
2011
+ atoms: [],
2012
+ dependencies: [],
2013
+ tokens: [],
2014
+ rules: [],
2015
+ arbitrary: 0,
2016
+ changed: false
2017
+ };
2018
+ }
2019
+ function newPass(code, keepLines) {
2020
+ return {
2021
+ edits: new SourceEdits(code, { keepLines }),
2022
+ spans: [],
2023
+ tokens: /* @__PURE__ */ new Map(),
2024
+ folded: /* @__PURE__ */ new Set(),
2025
+ pending: /* @__PURE__ */ new Map(),
2026
+ probes: /* @__PURE__ */ new Set(),
2027
+ helpers: /* @__PURE__ */ new Map(),
2028
+ hoisted: 0,
2029
+ devSx: false,
2030
+ errors: []
2031
+ };
2032
+ }
2033
+ function notSearched(source) {
2034
+ return `"${source}" is a package, which is not searched for recipes`;
2035
+ }
2036
+ function requestKey(a, b) {
2037
+ return `${a}\0${b}`;
2038
+ }
2039
+ const isJson = (id) => /\.json$/i.test(id.replace(/[?#].*$/, ""));
2040
+ const RESERVED = new Set("await break case catch class const continue debugger default delete do else enum export extends false finally for function if implements import in instanceof interface let new null package private protected public return static super switch this throw true try typeof var void while with yield".split(" "));
2041
+ /**
2042
+ * A JSON module as the JS module bundlers make of it: the value as the
2043
+ * default export, and its top-level keys that are identifiers as named ones.
2044
+ */
2045
+ function jsonModule(id, code) {
2046
+ let value;
2047
+ try {
2048
+ value = JSON.parse(code);
2049
+ } catch (error) {
2050
+ throw new VicssError("PARSE_ERROR", error instanceof Error ? error.message : String(error), { loc: {
2051
+ file: id,
2052
+ line: 1,
2053
+ column: 0
2054
+ } });
2055
+ }
2056
+ let out = `export default ${JSON.stringify(value)};\n`;
2057
+ if (isPlainObject(value)) {
2058
+ for (const [key, item] of Object.entries(value)) if (/^[A-Za-z_$][\w$]*$/.test(key) && !RESERVED.has(key)) out += `export const ${key} = ${JSON.stringify(item)};\n`;
2059
+ }
2060
+ return out;
2061
+ }
2062
+ function langOf(id) {
2063
+ const ext = /\.([a-z]+)$/i.exec(id.replace(/[?#].*$/, ""))?.[1]?.toLowerCase();
2064
+ return ext !== void 0 && LANGS[ext] || "tsx";
2065
+ }
2066
+ function parse(parseSync, id, code, lang, functionBody) {
2067
+ const { program, errors } = parseSync(id, code, {
2068
+ lang,
2069
+ sourceType: "module"
2070
+ });
2071
+ const returns = functionBody && errors.length > 0 ? topLevelReturns(program) : void 0;
2072
+ const error = errors.find((e) => e.severity === "Error" && !(returns && e.labels.length === 1 && returns.has(e.labels[0].start)));
2073
+ if (error) {
2074
+ const start = error.labels[0]?.start;
2075
+ throw new VicssError("PARSE_ERROR", error.message, {
2076
+ loc: start === void 0 ? void 0 : {
2077
+ file: id,
2078
+ ...createLocator(code)(start)
2079
+ },
2080
+ hint: error.helpMessage ?? void 0
2081
+ });
2082
+ }
2083
+ return program;
2084
+ }
2085
+ /** Where the `return` statements outside any function start. */
2086
+ function topLevelReturns(program) {
2087
+ const out = /* @__PURE__ */ new Set();
2088
+ const visit = (value) => {
2089
+ if (Array.isArray(value)) return value.forEach(visit);
2090
+ if (!isNode(value)) return;
2091
+ if (FUNCTIONS.has(value.type)) return;
2092
+ if (value.type === "ReturnStatement") out.add(value.start);
2093
+ for (const key in value) if (key !== "type") visit(value[key]);
2094
+ };
2095
+ visit(program.body);
2096
+ return out;
2097
+ }
2098
+ const FUNCTIONS = /* @__PURE__ */ new Set([
2099
+ "FunctionDeclaration",
2100
+ "FunctionExpression",
2101
+ "ArrowFunctionExpression",
2102
+ "ClassDeclaration",
2103
+ "ClassExpression"
2104
+ ]);
2105
+ function runtimeBindings(program, scopes, sources) {
2106
+ const out = /* @__PURE__ */ new Map();
2107
+ for (const node of program.body) {
2108
+ if (node.type !== "ImportDeclaration" || node.importKind === "type") continue;
2109
+ if (!sources.includes(node.source.value)) continue;
2110
+ for (const specifier of node.specifiers) {
2111
+ const binding = scopes.bindingOf(specifier.local);
2112
+ const name = binding?.imported;
2113
+ if (binding && name && (name === "*" || RUNTIME_EXPORTS.has(name))) out.set(binding, name);
2114
+ }
2115
+ }
2116
+ return out;
2117
+ }
2118
+ /**
2119
+ * The runtime function a callee names: `css`, an alias of it, or `ns.css` —
2120
+ * shadowing respected. In a Vue component's output, a template reaches the
2121
+ * script's `css` as `_unref(css)`, `$setup.css` or `_ctx.css` too.
2122
+ */
2123
+ function runtimeName(mod, callee) {
2124
+ const target = unwrap(callee);
2125
+ if (target.type === "Identifier") {
2126
+ const binding = mod.scopes.bindingOf(target);
2127
+ const name = binding && mod.runtime.get(binding);
2128
+ return name === "*" ? void 0 : name;
2129
+ }
2130
+ if (target.type === "CallExpression") {
2131
+ const [arg] = target.arguments;
2132
+ return arg && isUnref(mod, target.callee, target.arguments) ? runtimeName(mod, arg) : void 0;
2133
+ }
2134
+ if (target.type !== "MemberExpression") return void 0;
2135
+ const key = memberKey(target);
2136
+ if (key === void 0) return void 0;
2137
+ const setup = vueBinding(mod, target);
2138
+ if (setup) {
2139
+ const imported = mod.runtime.get(setup);
2140
+ return imported === "*" ? void 0 : imported;
2141
+ }
2142
+ return namespaceOf(mod, target.object) && RUNTIME_EXPORTS.has(key) ? key : void 0;
2143
+ }
2144
+ /**
2145
+ * The namespace import of a runtime source that `node` reads: `ns`, or in a
2146
+ * Vue component's output `_unref(ns)`, `$setup.ns` and `_ctx.ns`.
2147
+ */
2148
+ function namespaceOf(mod, node) {
2149
+ const target = unwrap(node);
2150
+ let binding;
2151
+ if (target.type === "Identifier") binding = mod.scopes.bindingOf(target);
2152
+ else if (target.type === "CallExpression") {
2153
+ const [arg] = target.arguments;
2154
+ return arg && isUnref(mod, target.callee, target.arguments) ? namespaceOf(mod, arg) : void 0;
2155
+ } else if (target.type === "MemberExpression") binding = vueBinding(mod, target);
2156
+ return binding && mod.runtime.get(binding) === "*" ? binding : void 0;
2157
+ }
2158
+ /**
2159
+ * The script binding a Vue render function reads as `$setup.x` or `_ctx.x`:
2160
+ * those hold the script's bindings by name.
2161
+ */
2162
+ function vueBinding(mod, node) {
2163
+ if (!mod.vue) return void 0;
2164
+ const object = unwrap(node.object);
2165
+ const key = memberKey(node);
2166
+ if (object.type !== "Identifier" || key === void 0) return void 0;
2167
+ const { name } = object;
2168
+ if (name !== "$setup" && name !== "_ctx") return void 0;
2169
+ const own = mod.scopes.bindingOf(object);
2170
+ if (own && own.kind !== "param") return void 0;
2171
+ return mod.scopes.moduleBindings.get(key);
2172
+ }
2173
+ /** `ns.name` or `ns["name"]`: the name. */
2174
+ function memberKey(node) {
2175
+ if (!node.computed) return node.property.name;
2176
+ const property = node.property;
2177
+ return property.type === "Literal" && typeof property.value === "string" ? property.value : void 0;
2178
+ }
2179
+ /** A call of Vue's `unref` (`_unref(x)` in compiled templates): x itself for a constant. */
2180
+ function isUnref(mod, callee, args) {
2181
+ const target = unwrap(callee);
2182
+ if (target.type !== "Identifier" || args.length !== 1 || args[0].type === "SpreadElement") return false;
2183
+ const binding = mod.scopes.bindingOf(target);
2184
+ return binding?.kind === "import" && binding.source === "vue" && binding.imported === "unref";
2185
+ }
2186
+ function unwrap(node) {
2187
+ let inner = node;
2188
+ while (WRAPPERS.has(inner.type)) inner = inner.expression;
2189
+ return inner;
2190
+ }
2191
+ function isNode(value) {
2192
+ return typeof value === "object" && value !== null && typeof value.type === "string";
2193
+ }
2194
+ const CHILD_KEYS = {
2195
+ js: /* @__PURE__ */ new Map(),
2196
+ ts: /* @__PURE__ */ new Map()
2197
+ };
2198
+ function childKeys(node, cache) {
2199
+ let keys = cache.get(node.type);
2200
+ if (!keys) {
2201
+ const record = node;
2202
+ keys = Object.keys(record).filter((key) => {
2203
+ if (SKIPPED_KEYS.has(key)) return false;
2204
+ const value = record[key];
2205
+ return value === null || value === void 0 || typeof value === "object";
2206
+ });
2207
+ cache.set(node.type, keys);
2208
+ }
2209
+ return keys;
2210
+ }
2211
+ /** Depth-first, `node` first; children are skipped when `enter` returns false. */
2212
+ function walk(mod, node, enter) {
2213
+ const cache = CHILD_KEYS[mod.lang === "ts" || mod.lang === "tsx" ? "ts" : "js"];
2214
+ const visit = (current) => {
2215
+ if (!enter(current)) return;
2216
+ const record = current;
2217
+ for (const key of childKeys(current, cache)) {
2218
+ const value = record[key];
2219
+ if (Array.isArray(value)) {
2220
+ for (const item of value) if (isNode(item)) visit(item);
2221
+ } else if (isNode(value)) visit(value);
2222
+ }
2223
+ };
2224
+ visit(node);
2225
+ }
2226
+ /** Identifiers a parameter pattern declares. */
2227
+ function bindingIds(pattern, out = []) {
2228
+ switch (pattern.type) {
2229
+ case "Identifier":
2230
+ out.push(pattern);
2231
+ break;
2232
+ case "AssignmentPattern":
2233
+ bindingIds(pattern.left, out);
2234
+ break;
2235
+ case "RestElement":
2236
+ bindingIds(pattern.argument, out);
2237
+ break;
2238
+ case "ObjectPattern":
2239
+ for (const p of pattern.properties) bindingIds(p.type === "RestElement" ? p : p.value, out);
2240
+ break;
2241
+ case "ArrayPattern":
2242
+ for (const element of pattern.elements) if (element) bindingIds(element, out);
2243
+ break;
2244
+ case "TSParameterProperty": bindingIds(pattern.parameter, out);
2245
+ }
2246
+ return out;
2247
+ }
2248
+ /** Spreads inside a style literal, where a compiled style would be flattened into keys. */
2249
+ function collectSpreads(node, out) {
2250
+ const inner = unwrap(node);
2251
+ if (inner.type === "ObjectExpression") for (const property of inner.properties) if (property.type === "SpreadElement") out.push(property);
2252
+ else collectSpreads(property.value, out);
2253
+ else if (inner.type === "ConditionalExpression") {
2254
+ collectSpreads(inner.consequent, out);
2255
+ collectSpreads(inner.alternate, out);
2256
+ } else if (inner.type === "LogicalExpression") collectSpreads(inner.right, out);
2257
+ }
2258
+ function containsCompiled(value) {
2259
+ if (value instanceof CompiledStyle) return true;
2260
+ if (Array.isArray(value)) return value.some(containsCompiled);
2261
+ if (!isPlainObject(value)) return false;
2262
+ if (value.__vxSpecial === "style") return true;
2263
+ if (Object.hasOwn(value, "__vxSpecial")) return false;
2264
+ return Object.values(value).some(containsCompiled);
2265
+ }
2266
+ /** The class string a value adds to `sx()`: falsy values add nothing. Undefined when unknown. */
2267
+ function classesOf(value) {
2268
+ if (value === false || value === null || value === void 0 || value === 0 || value === "") return "";
2269
+ if (typeof value === "string") return splitClasses(value).map((cls) => "!" + cls).join(" ");
2270
+ if (value instanceof CompiledStyle) return value.classes;
2271
+ if (value instanceof MarkerValue) return value.className;
2272
+ if (Array.isArray(value)) {
2273
+ const parts = value.map(classesOf);
2274
+ return parts.every((part) => part !== void 0) ? mergeClassNames(parts).join(" ") : void 0;
2275
+ }
2276
+ }
2277
+ function classString(atoms) {
2278
+ return atoms.map((atom) => atom.className).join(" ");
2279
+ }
2280
+ /** Runs `fn`; a VicssError (other than a pending import) means "not known". */
2281
+ function attempt(fn) {
2282
+ try {
2283
+ return { result: fn() };
2284
+ } catch (error) {
2285
+ if (error instanceof PendingImport || !(error instanceof VicssError)) throw error;
2286
+ return;
2287
+ }
2288
+ }
2289
+ function withPlaceholders(value, found) {
2290
+ if (isDynamic(value)) {
2291
+ found.push(value);
2292
+ return `${PLACEHOLDER}${found.length - 1}`;
2293
+ }
2294
+ if (Array.isArray(value)) return value.map((item) => withPlaceholders(item, found));
2295
+ if (!isPlainObject(value) || Object.hasOwn(value, "__vxSpecial")) return value;
2296
+ const out = {};
2297
+ for (const [key, item] of Object.entries(value)) out[key] = withPlaceholders(item, found);
2298
+ return out;
2299
+ }
2300
+ /** Whether a runtime value sits in `value`, at any depth. */
2301
+ function containsDynamic(value) {
2302
+ if (isDynamic(value)) return true;
2303
+ if (Array.isArray(value)) return value.some(containsDynamic);
2304
+ return isPlainObject(value) && Object.values(value).some(containsDynamic);
2305
+ }
2306
+ function hasPlaceholder(value) {
2307
+ if (typeof value === "string") return value.startsWith(PLACEHOLDER);
2308
+ if (Array.isArray(value)) return value.some(hasPlaceholder);
2309
+ return isPlainObject(value) && Object.values(value).some(hasPlaceholder);
2310
+ }
2311
+ function placeholderIndex(value) {
2312
+ if (!value.startsWith(PLACEHOLDER)) return void 0;
2313
+ const index = value.slice(3);
2314
+ return /^\d+$/.test(index) ? Number(index) : void 0;
2315
+ }
2316
+ let byCss;
2317
+ function propertyByCss(css) {
2318
+ byCss ??= new Map([...PROPERTIES.values()].map((info) => [info.css, info]));
2319
+ return byCss.get(css);
2320
+ }
2321
+ /** The text a runtime value hashes by: a parameter by its name, without its type annotation. */
2322
+ function sourceText(mod, node) {
2323
+ return node.type === "Identifier" ? node.name : mod.code.slice(node.start, node.end);
2324
+ }
2325
+ /** The property written last under `key` in the object `node` is, or is bound to in this module. */
2326
+ function findProperty(mod, node, key) {
2327
+ let target = unwrap(node);
2328
+ if (target.type === "Identifier") {
2329
+ const binding = mod.scopes.bindingOf(target);
2330
+ if (binding?.kind !== "const" || !binding.init || binding.path) return void 0;
2331
+ target = unwrap(binding.init);
2332
+ }
2333
+ if (target.type !== "ObjectExpression") return void 0;
2334
+ for (let i = target.properties.length - 1; i >= 0; i--) {
2335
+ const property = target.properties[i];
2336
+ if (property.type === "Property" && staticKey(property) === key) return property;
2337
+ }
2338
+ }
2339
+ function staticKey(property) {
2340
+ const { key } = property;
2341
+ if (key.type === "Identifier" && !property.computed) return key.name;
2342
+ if (key.type === "Literal" && (typeof key.value === "string" || typeof key.value === "number")) return String(key.value);
2343
+ }
2344
+ /**
2345
+ * A token-typed parameter's custom property: a string transform, so no
2346
+ * token table ships to the browser (PLAN §4.6). A value that names no
2347
+ * token is written as it is (D33), which `var()`'s fallback does with no
2348
+ * table either: no token declares the property it reads. A value that
2349
+ * cannot be part of a property's name is the value itself.
2350
+ */
2351
+ function tokenExpression(name, param) {
2352
+ const read = `((v) => /^[\\w.-]+$/.test(v) ? "var(${param.prefix}" + v.replace(/\\./g, "-") + ", " + v + ")" : v)(String(${name}))`;
2353
+ return param.nullable ? `(${name} == null ? undefined : ${read})` : read;
2354
+ }
2355
+ /** The name an import specifier takes from its module (`Token` in `{ Token as T }`). */
2356
+ function importedName(specifier) {
2357
+ const { imported } = specifier;
2358
+ return imported.type === "Identifier" ? imported.name : String(imported.value);
2359
+ }
2360
+ /** The key a destructuring property reads, when it is written out. */
2361
+ function patternKey(property) {
2362
+ const { key } = property;
2363
+ if (key.type === "Identifier" && !property.computed) return key.name;
2364
+ if (key.type === "Literal" && (typeof key.value === "string" || typeof key.value === "number")) return String(key.value);
2365
+ }
2366
+ function excerpt(code, node) {
2367
+ const text = code.slice(node.start, node.end).replace(/\s+/g, " ");
2368
+ return text.length > 60 ? `${text.slice(0, 59)}…` : text;
2369
+ }
2370
+ /** An editor over one range of the source, for code copied into generated text. */
2371
+ var Splice = class {
2372
+ #code;
2373
+ #start;
2374
+ #end;
2375
+ #edits = [];
2376
+ constructor(code, start, end) {
2377
+ this.#code = code;
2378
+ this.#start = start;
2379
+ this.#end = end;
2380
+ }
2381
+ overwrite(start, end, content) {
2382
+ this.#edits.push({
2383
+ start,
2384
+ end,
2385
+ content
2386
+ });
2387
+ return this;
2388
+ }
2389
+ remove(start, end) {
2390
+ return start === end ? this : this.overwrite(start, end, "");
2391
+ }
2392
+ /** Whether an edit overlaps `[start, end)`. */
2393
+ touches(start, end) {
2394
+ return this.#edits.some((edit) => edit.start < end && start < edit.end);
2395
+ }
2396
+ toString() {
2397
+ let out = "";
2398
+ let pos = this.#start;
2399
+ for (const edit of [...this.#edits].sort((a, b) => a.start - b.start)) {
2400
+ out += this.#code.slice(pos, edit.start) + edit.content;
2401
+ pos = edit.end;
2402
+ }
2403
+ return out + this.#code.slice(pos, this.#end);
2404
+ }
2405
+ };
2406
+ //#endregion
2407
+ //#region src/vite/framework.ts
2408
+ /**
2409
+ * Which framework a module belongs to (PLAN §5.12), which decides the shape
2410
+ * `sx()` returns, and the framework files (`.vue`, `.svelte`, `.astro`) the
2411
+ * plugin compiles after their own compiler and pre-scans by their scripts
2412
+ * (§5.4). Plain data in, plain data out: the scan's workers use it too.
2413
+ */
2414
+ const FRAMEWORKS = [
2415
+ "react",
2416
+ "preact",
2417
+ "solid",
2418
+ "vue",
2419
+ "svelte",
2420
+ "astro",
2421
+ "vanilla"
2422
+ ];
2423
+ /** Root dependencies that name a project's framework, the first found winning. */
2424
+ const DEPENDENCIES = [
2425
+ ["vue", "vue"],
2426
+ ["svelte", "svelte"],
2427
+ ["solid-js", "solid"],
2428
+ ["preact", "preact"],
2429
+ ["react", "react"],
2430
+ ["astro", "astro"]
2431
+ ];
2432
+ /** Extensions whose files a framework compiler turns into JS first; the patterns below list them. */
2433
+ const SFC_EXTENSIONS = [
2434
+ "vue",
2435
+ "svelte",
2436
+ "astro"
2437
+ ];
2438
+ const SFC_EXTENSION = `(?:${SFC_EXTENSIONS.join("|")})`;
2439
+ /** `X.vue`, `X.svelte`, `X.astro`, with or without a query. */
2440
+ const SFC_FILE = new RegExp(`\\.${SFC_EXTENSION}(?:[?#]|$)`);
2441
+ /**
2442
+ * The modules of a framework file that hold its compiled scripts: the file
2443
+ * itself, or a script sub-module (`X.vue?vue&type=script&setup=true&lang.ts`,
2444
+ * `X.astro?astro&type=script&index=0&lang.ts`). Styles, templates and other
2445
+ * sub-modules are left alone.
2446
+ */
2447
+ const SFC_SCRIPT_ID = new RegExp(`\\.${SFC_EXTENSION}(?:$|\\?(?:[^#]*&)?type=script(?:[&#]|$))`);
2448
+ function isSfc(id) {
2449
+ return SFC_FILE.test(id);
2450
+ }
2451
+ /** The framework of a module, from its id, its code and the project's settings. */
2452
+ function frameworkOf(id, code, settings) {
2453
+ const file = id.replace(/[?#].*$/, "");
2454
+ const ext = /\.([a-z]+)$/i.exec(file)?.[1]?.toLowerCase();
2455
+ if (SFC_EXTENSIONS.includes(ext ?? "")) return ext;
2456
+ if (ext === "jsx" || ext === "tsx") {
2457
+ const pragma = /@jsxImportSource\s+([^\s*]+)/.exec(code)?.[1];
2458
+ return jsxFramework(pragma ?? settings.jsxImportSource ?? "react");
2459
+ }
2460
+ return settings.scripts;
2461
+ }
2462
+ /** `preact`, `solid-js`, `vue` (and their subpaths) by name; anything else takes React's props. */
2463
+ function jsxFramework(source) {
2464
+ const name = source.startsWith("@") ? source.split("/", 2).join("/") : source.split("/")[0];
2465
+ if (name === "preact") return "preact";
2466
+ if (name === "solid-js") return "solid";
2467
+ if (name === "vue") return "vue";
2468
+ return "react";
2469
+ }
2470
+ /** The framework the root `package.json` depends on, if one of the known ones. */
2471
+ function detectFramework(root) {
2472
+ const pkg = readJson(path.join(root, "package.json"));
2473
+ if (!pkg) return void 0;
2474
+ const names = /* @__PURE__ */ new Set([...Object.keys(deps(pkg.dependencies)), ...Object.keys(deps(pkg.devDependencies))]);
2475
+ return DEPENDENCIES.find(([name]) => names.has(name))?.[1];
2476
+ }
2477
+ /**
2478
+ * The project's JSX import source: the Vite config's (`oxc.jsx.importSource`,
2479
+ * or esbuild's `jsxImportSource`), else the root tsconfig's, following
2480
+ * `extends` and, for a solution file, its `references`.
2481
+ */
2482
+ function configuredJsxSource(config, root) {
2483
+ const jsx = record(record(config.oxc)?.jsx);
2484
+ const esbuild = record(config.esbuild);
2485
+ return string(jsx?.importSource) ?? string(esbuild?.jsxImportSource) ?? tsconfigJsxSource(path.join(root, "tsconfig.json"), /* @__PURE__ */ new Set());
2486
+ }
2487
+ function tsconfigJsxSource(file, seen) {
2488
+ if (seen.has(file)) return void 0;
2489
+ seen.add(file);
2490
+ const tsconfig = readJson(file, true);
2491
+ if (!tsconfig) return void 0;
2492
+ const own = string(record(tsconfig.compilerOptions)?.jsxImportSource);
2493
+ if (own) return own;
2494
+ const dir = path.dirname(file);
2495
+ const parents = Array.isArray(tsconfig.extends) ? tsconfig.extends : [tsconfig.extends];
2496
+ for (const parent of parents.toReversed()) {
2497
+ const resolved = typeof parent === "string" ? resolveExtends(parent, dir) : void 0;
2498
+ const found = resolved && tsconfigJsxSource(resolved, seen);
2499
+ if (found) return found;
2500
+ }
2501
+ for (const reference of Array.isArray(tsconfig.references) ? tsconfig.references : []) {
2502
+ const target = string(record(reference)?.path);
2503
+ if (!target) continue;
2504
+ const full = path.resolve(dir, target);
2505
+ const found = tsconfigJsxSource(full.endsWith(".json") ? full : path.join(full, "tsconfig.json"), seen);
2506
+ if (found) return found;
2507
+ }
2508
+ }
2509
+ function resolveExtends(specifier, dir) {
2510
+ if (specifier.startsWith(".") || path.isAbsolute(specifier)) {
2511
+ const full = path.resolve(dir, specifier);
2512
+ return existsSync(full) ? full : `${full}.json`;
2513
+ }
2514
+ try {
2515
+ return createRequire(path.join(dir, "tsconfig.json")).resolve(specifier.endsWith(".json") ? specifier : `${specifier}.json`);
2516
+ } catch {
2517
+ try {
2518
+ return createRequire(path.join(dir, "tsconfig.json")).resolve(specifier);
2519
+ } catch {
2520
+ return;
2521
+ }
2522
+ }
2523
+ }
2524
+ /**
2525
+ * An opening `<script>` tag and the element's text. Attribute values are
2526
+ * matched whole, so a `>` inside quotes (Vue's `generic="T extends
2527
+ * Record<K, V>"`, Svelte's `generics`) does not end the tag.
2528
+ */
2529
+ const SCRIPT_ELEMENT = /<script\b((?:\s+[^\s"'>/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'>]+))?)*)\s*>([\s\S]*?)<\/script\s*>/dgi;
2530
+ const ATTRIBUTE = /([^\s"'>/=]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>]+)))?/g;
2531
+ /**
2532
+ * The scripts of a `.vue` (`<script>` and `<script setup>`, one module as
2533
+ * Vue merges them), `.svelte` (instance and module scripts, one module) or
2534
+ * `.astro` file (the frontmatter, and each `<script>` Astro bundles, each a
2535
+ * module of its own). A script with `src` is a file of its own, scanned as
2536
+ * one if `include` has it.
2537
+ */
2538
+ function extractScripts(id, code) {
2539
+ const ext = /\.([a-z]+)(?:[?#].*)?$/i.exec(id)?.[1]?.toLowerCase();
2540
+ const markup = code.replace(/<!--[\s\S]*?-->/g, blank);
2541
+ const blocks = [];
2542
+ for (const match of markup.matchAll(SCRIPT_ELEMENT)) {
2543
+ const [start, end] = match.indices[2];
2544
+ blocks.push({
2545
+ start,
2546
+ end,
2547
+ attributes: attributesOf(match[1])
2548
+ });
2549
+ }
2550
+ if (ext === "astro") {
2551
+ const units = [];
2552
+ const fence = /^(\s*)---[^\S\r\n]*\r?\n([\s\S]*?)\r?\n---/.exec(code);
2553
+ if (fence) {
2554
+ const start = fence[0].indexOf("\n", fence[1].length) + 1;
2555
+ units.push({
2556
+ code: keep(code, [[start, start + fence[2].length]]),
2557
+ lang: "ts",
2558
+ functionBody: true
2559
+ });
2560
+ }
2561
+ const after = fence ? fence.index + fence[0].length : 0;
2562
+ for (const block of blocks) {
2563
+ if (block.start < after || block.attributes.size > 0) continue;
2564
+ units.push({
2565
+ code: keep(code, [[block.start, block.end]]),
2566
+ lang: "ts"
2567
+ });
2568
+ }
2569
+ return units;
2570
+ }
2571
+ const scripts = blocks.filter(({ attributes }) => {
2572
+ const type = attributes.get("type");
2573
+ return !attributes.has("src") && (type === void 0 || type === "module" || /^(?:text|application)\/(?:java|type)script$/.test(type));
2574
+ });
2575
+ if (scripts.length === 0) return [];
2576
+ const lang = scripts.map((block) => block.attributes.get("lang")).some((l) => l === "tsx" || l === "jsx") ? "tsx" : "ts";
2577
+ return [{
2578
+ code: keep(code, scripts.map((block) => [block.start, block.end])),
2579
+ lang
2580
+ }];
2581
+ }
2582
+ /** A tag's attributes by lower-cased name, `""` for a bare one; the first of a name wins. */
2583
+ function attributesOf(text) {
2584
+ const out = /* @__PURE__ */ new Map();
2585
+ for (const match of text.matchAll(ATTRIBUTE)) {
2586
+ const name = match[1].toLowerCase();
2587
+ if (!out.has(name)) out.set(name, match[2] ?? match[3] ?? match[4] ?? "");
2588
+ }
2589
+ return out;
2590
+ }
2591
+ /** `code` with everything outside `ranges` blanked, line breaks kept. */
2592
+ function keep(code, ranges) {
2593
+ let out = "";
2594
+ let at = 0;
2595
+ for (const [start, end] of ranges) {
2596
+ out += blank(code.slice(at, start)) + code.slice(start, end);
2597
+ at = end;
2598
+ }
2599
+ return out + blank(code.slice(at));
2600
+ }
2601
+ const blank = (text) => text.replace(/[^\r\n]/g, " ");
2602
+ function readJson(file, comments = false) {
2603
+ let text;
2604
+ try {
2605
+ text = readFileSync(file, "utf8");
2606
+ } catch {
2607
+ return;
2608
+ }
2609
+ try {
2610
+ return record(JSON.parse(comments ? stripJsonComments(text) : text));
2611
+ } catch {
2612
+ return;
2613
+ }
2614
+ }
2615
+ /** JSONC as tsconfig files use it: comments and trailing commas. */
2616
+ function stripJsonComments(text) {
2617
+ let out = "";
2618
+ for (let i = 0; i < text.length; i++) {
2619
+ const c = text[i];
2620
+ if (c === "\"") {
2621
+ const end = /"(?:[^"\\]|\\.)*"/y;
2622
+ end.lastIndex = i;
2623
+ const literal = end.exec(text)?.[0] ?? text.slice(i);
2624
+ out += literal;
2625
+ i += literal.length - 1;
2626
+ } else if (text.startsWith("//", i)) {
2627
+ const next = text.indexOf("\n", i);
2628
+ i = next === -1 ? text.length : next - 1;
2629
+ } else if (text.startsWith("/*", i)) {
2630
+ const close = text.indexOf("*/", i + 2);
2631
+ i = close === -1 ? text.length : close + 1;
2632
+ } else out += c;
2633
+ }
2634
+ return out.replace(/,(\s*[}\]])/g, "$1");
2635
+ }
2636
+ function record(value) {
2637
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
2638
+ }
2639
+ const string = (value) => typeof value === "string" && value ? value : void 0;
2640
+ const deps = (value) => record(value) ?? {};
2641
+ //#endregion
2642
+ //#region src/vite/compile.ts
2643
+ /**
2644
+ * The plugin's side of compiling one module: imported constants are found
2645
+ * through Vite's resolver, read from disk and reported as dependencies, so
2646
+ * tsconfig paths, aliases and workspaces work as they do for the app.
2647
+ */
2648
+ const REACT = {
2649
+ scripts: "react",
2650
+ jsxImportSource: void 0
2651
+ };
2652
+ /** The file the compiler reads for an import, or "" when it reads none. */
2653
+ async function resolveFile(resolve, source, importer) {
2654
+ const resolved = await resolve(source, importer);
2655
+ if (!resolved || resolved.external || resolved.id.startsWith("\0")) return "";
2656
+ return resolved.id.replace(/[?#].*$/, "");
2657
+ }
2658
+ /** Whether every recorded import resolves to the same file through `resolve`. */
2659
+ async function resolvesAlike(resolutions, resolve) {
2660
+ for (const [request, file] of Object.entries(resolutions)) {
2661
+ const at = request.indexOf("\0");
2662
+ if (await resolve(request.slice(at + 1), request.slice(0, at)) !== file) return false;
2663
+ }
2664
+ return true;
2665
+ }
2666
+ /** `this.resolve` without our own `resolveId`, as a module loader for the compiler. */
2667
+ function moduleLoader(resolve, resolutions = {}) {
2668
+ return async (source, importer) => {
2669
+ const id = await resolveFile(resolve, source, importer);
2670
+ resolutions[`${importer}\0${source}`] = id;
2671
+ if (!id) return null;
2672
+ try {
2673
+ return {
2674
+ id,
2675
+ code: readFileSync(id, "utf8")
2676
+ };
2677
+ } catch {
2678
+ return null;
2679
+ }
2680
+ };
2681
+ }
2682
+ /**
2683
+ * Compiles one module. `script` is set for a script the pre-scan extracted
2684
+ * from a framework file, whose id names the file rather than how it parses;
2685
+ * `sourceLine`, in dev, for a framework's output, whose lines its compiler
2686
+ * moved (`CompileOptions.sourceLine`).
2687
+ */
2688
+ async function compile(ctx, id, code, resolve, script, sourceLine) {
2689
+ const resolutions = {};
2690
+ const warnings = [];
2691
+ return {
2692
+ ...await compileModule(code, {
2693
+ system: ctx.system,
2694
+ id,
2695
+ importSources: ctx.importSources,
2696
+ loadModule: moduleLoader(resolve, resolutions),
2697
+ framework: frameworkOf(id, code, ctx.frameworks ?? REACT),
2698
+ ...script ? {
2699
+ lang: script.lang,
2700
+ functionBody: script.functionBody === true
2701
+ } : {},
2702
+ sourceMap: ctx.sourceMap,
2703
+ cache: ctx.parsed,
2704
+ dev: ctx.dev === true,
2705
+ placeholders: ctx.placeholders === true,
2706
+ keepLines: ctx.keepLines === true,
2707
+ ...ctx.root === void 0 ? {} : { root: ctx.root },
2708
+ ...ctx.package ? { package: ctx.package } : {},
2709
+ ...sourceLine ? { sourceLine } : {},
2710
+ warn: (message) => warnings.push(message)
2711
+ }),
2712
+ resolutions,
2713
+ warnings
2714
+ };
2715
+ }
2716
+ /**
2717
+ * Parsed modules, most recently used last. A design system's barrel is read
2718
+ * by most styled modules, so it stays; the ASTs of the modules themselves
2719
+ * (about 20 times their source size) are not all kept for the server's life.
2720
+ */
2721
+ function createParseCache(limit = 256) {
2722
+ return { parsed: new LruMap(limit) };
2723
+ }
2724
+ var LruMap = class extends Map {
2725
+ #limit;
2726
+ constructor(limit) {
2727
+ super();
2728
+ this.#limit = limit;
2729
+ }
2730
+ get(key) {
2731
+ const value = super.get(key);
2732
+ if (value !== void 0) {
2733
+ super.delete(key);
2734
+ super.set(key, value);
2735
+ }
2736
+ return value;
2737
+ }
2738
+ set(key, value) {
2739
+ super.delete(key);
2740
+ super.set(key, value);
2741
+ if (this.size > this.#limit) super.delete(this.keys().next().value);
2742
+ return this;
2743
+ }
2744
+ };
2745
+ //#endregion
2746
+ //#region src/vite/pool.ts
2747
+ /**
2748
+ * The pre-scan's worker threads (PLAN D17). A cold scan is CPU-bound: every
2749
+ * module is parsed, evaluated and normalised. With more than `POOL_MIN`
2750
+ * modules to compile, worker threads run the same compiler on the files'
2751
+ * contents next to the main thread. The main thread keeps what must stay
2752
+ * one: resolution through Vite's plugins, the cache and the order results
2753
+ * are combined in. Only plain data crosses: jobs, resolution requests and
2754
+ * results, and errors as their fields.
2755
+ */
2756
+ /** Jobs a worker holds at once, so one waiting for a resolution leaves it busy. */
2757
+ const IN_FLIGHT = 16;
2758
+ /**
2759
+ * A config's hash with its functions counted rather than read: the main
2760
+ * thread loads a TypeScript config through Vite, which prints a function's
2761
+ * source otherwise than Node's type stripping does in a worker.
2762
+ */
2763
+ function configShape(config) {
2764
+ return hash(stableStringify(config, () => "\0function"), 8);
2765
+ }
2766
+ function toErrorData(error) {
2767
+ if (error instanceof VicssError) return {
2768
+ name: error.name,
2769
+ message: error.message,
2770
+ code: error.code,
2771
+ ...error.hint === void 0 ? {} : { hint: error.hint },
2772
+ ...error.loc === void 0 ? {} : { loc: error.loc }
2773
+ };
2774
+ const e = error instanceof Error ? error : new Error(String(error));
2775
+ return {
2776
+ name: e.name,
2777
+ message: e.message,
2778
+ ...e.stack ? { stack: e.stack } : {}
2779
+ };
2780
+ }
2781
+ function fromErrorData(data) {
2782
+ if (data.name === "VicssError" && data.code !== void 0) return new VicssError(data.code, data.message, {
2783
+ ...data.loc ? { loc: data.loc } : {},
2784
+ ...data.hint === void 0 ? {} : { hint: data.hint }
2785
+ });
2786
+ const error = new Error(data.message);
2787
+ error.name = data.name;
2788
+ if (data.stack) error.stack = data.stack;
2789
+ return error;
2790
+ }
2791
+ /** A job a worker took and could not finish: the thread died. The caller runs it itself. */
2792
+ var WorkerLost = class extends Error {};
2793
+ /**
2794
+ * Threads for this many compiles: one per 100 modules, leaving a core to the
2795
+ * main thread (which compiles too) and one to Rolldown's own threads. On
2796
+ * four cores, three workers were no faster than two.
2797
+ */
2798
+ function poolSize(jobs) {
2799
+ return Math.max(0, Math.min(availableParallelism() - 2, Math.ceil(jobs / 100), 7));
2800
+ }
2801
+ var CompilePool = class CompilePool {
2802
+ workers;
2803
+ #threads;
2804
+ #use;
2805
+ #used = false;
2806
+ constructor(workers, threads, use) {
2807
+ this.workers = workers;
2808
+ this.#threads = threads;
2809
+ this.#use = use;
2810
+ }
2811
+ /**
2812
+ * Starts `size` threads, which load the compiler and wait for `use()`; a
2813
+ * build spawns them before its config is loaded, which takes as long as
2814
+ * their start. Unreferenced until used, so a config resolved for a build
2815
+ * that never runs leaves nothing alive. Undefined when threads cannot start.
2816
+ */
2817
+ static spawn(size) {
2818
+ if (size < 1) return void 0;
2819
+ const threads = [];
2820
+ try {
2821
+ for (let i = 0; i < size; i++) threads.push(new Worker(WORKER_URL));
2822
+ } catch {
2823
+ for (const thread of threads) thread.terminate();
2824
+ return;
2825
+ }
2826
+ for (const thread of threads) thread.unref();
2827
+ let current;
2828
+ let warned = false;
2829
+ const warn = (message) => {
2830
+ if (warned) return;
2831
+ warned = true;
2832
+ current?.warn?.(message);
2833
+ };
2834
+ const resolve = (source, importer) => current ? current.resolve(source, importer) : Promise.resolve("");
2835
+ const workers = threads.map((thread) => connect(thread, resolve, warn));
2836
+ return new CompilePool(workers, threads, (use) => {
2837
+ current = use;
2838
+ for (const thread of threads) {
2839
+ thread.ref();
2840
+ try {
2841
+ thread.postMessage({
2842
+ type: "setup",
2843
+ setup: use.setup
2844
+ });
2845
+ } catch (error) {
2846
+ warn(`the scan runs on one thread: ${error instanceof Error ? error.message : String(error)}`);
2847
+ thread.terminate();
2848
+ }
2849
+ }
2850
+ });
2851
+ }
2852
+ /** Sends the scan's setup; the workers report ready once they built the compiler. */
2853
+ use(use) {
2854
+ if (this.#used) throw new Error("vicss: a scan pool serves one scan");
2855
+ this.#used = true;
2856
+ this.#use(use);
2857
+ return this;
2858
+ }
2859
+ /** Ends the threads; a pool is closed once, whoever closes it. */
2860
+ async close() {
2861
+ await Promise.all(this.#threads.map((thread) => thread.terminate()));
2862
+ }
2863
+ };
2864
+ /** `src/vite/worker.ts` next to this file, or `dist/worker.js` next to the bundled plugin. */
2865
+ const WORKER_URL = new URL(import.meta.url.endsWith(".ts") ? "./worker.ts" : "./worker.js", import.meta.url);
2866
+ function connect(thread, resolve, warn) {
2867
+ const jobs = /* @__PURE__ */ new Map();
2868
+ let next = 0;
2869
+ let alive = true;
2870
+ let settle;
2871
+ const ready = new Promise((resolve) => settle = resolve);
2872
+ const lost = (why) => {
2873
+ if (!alive) return;
2874
+ alive = false;
2875
+ settle(false);
2876
+ for (const job of jobs.values()) job.reject(new WorkerLost(why));
2877
+ jobs.clear();
2878
+ };
2879
+ thread.on("message", (message) => {
2880
+ switch (message.type) {
2881
+ case "ready":
2882
+ settle(true);
2883
+ return;
2884
+ case "unavailable":
2885
+ warn(`a scan worker could not start, so the main thread compiles more: ${message.message}`);
2886
+ lost(message.message);
2887
+ thread.terminate();
2888
+ return;
2889
+ case "resolve":
2890
+ resolve(message.source, message.importer).then((file) => post({
2891
+ type: "resolved",
2892
+ request: message.request,
2893
+ file
2894
+ }), () => post({
2895
+ type: "resolved",
2896
+ request: message.request,
2897
+ file: ""
2898
+ }));
2899
+ return;
2900
+ case "done":
2901
+ case "failed": {
2902
+ const job = jobs.get(message.job);
2903
+ jobs.delete(message.job);
2904
+ if (message.type === "done") job?.resolve(message.result);
2905
+ else job?.reject(fromErrorData(message.error));
2906
+ return;
2907
+ }
2908
+ }
2909
+ });
2910
+ thread.on("error", (error) => {
2911
+ const why = error instanceof Error ? error.message : String(error);
2912
+ warn(`a scan worker stopped, so the main thread compiles more: ${why}`);
2913
+ lost(why);
2914
+ });
2915
+ thread.on("exit", () => lost("the worker exited"));
2916
+ const post = (message) => {
2917
+ if (alive) thread.postMessage(message);
2918
+ };
2919
+ return {
2920
+ ready,
2921
+ capacity: IN_FLIGHT,
2922
+ compile(job) {
2923
+ if (!alive) return Promise.reject(new WorkerLost("the worker exited"));
2924
+ const id = next++;
2925
+ return new Promise((resolve, reject) => {
2926
+ jobs.set(id, {
2927
+ resolve,
2928
+ reject
2929
+ });
2930
+ post({
2931
+ type: "compile",
2932
+ job: id,
2933
+ id: job.id,
2934
+ code: job.code,
2935
+ ...job.script ? { script: job.script } : {}
2936
+ });
2937
+ });
2938
+ }
2939
+ };
2940
+ }
2941
+ //#endregion
2942
+ export { originalLines as S, isSfc as _, toErrorData as a, setParser as b, moduleLoader as c, FRAMEWORKS as d, SFC_SCRIPT_ID as f, frameworkOf as g, extractScripts as h, poolSize as i, resolveFile as l, detectFramework as m, WorkerLost as n, compile as o, configuredJsxSource as p, configShape as r, createParseCache as s, CompilePool as t, resolvesAlike as u, compileModule as v, SourceEdits as x, createModuleCache as y };