@homebound/truss 2.29.7 → 2.29.9

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.
@@ -56,6 +56,7 @@ function removeCssImport(ast, cssBinding) {
56
56
  ast.program.body.splice(i, 1);
57
57
  } else {
58
58
  node.specifiers.splice(cssSpecIndex, 1);
59
+ hoistTypeOnlyImportKind(node);
59
60
  }
60
61
  return;
61
62
  }
@@ -76,10 +77,10 @@ function insertAfterLeadingImports(ast, statements) {
76
77
  }
77
78
  function findNamedImportBinding(ast, importedName, source) {
78
79
  for (const node of ast.program.body) {
79
- if (!t.isImportDeclaration(node)) continue;
80
+ if (!t.isImportDeclaration(node) || node.importKind === "type") continue;
80
81
  if (source !== void 0 && node.source.value !== source) continue;
81
82
  for (const spec of node.specifiers) {
82
- if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported, { name: importedName })) {
83
+ if (t.isImportSpecifier(spec) && spec.importKind !== "type" && t.isIdentifier(spec.imported, { name: importedName })) {
83
84
  return spec.local.name;
84
85
  }
85
86
  }
@@ -109,7 +110,9 @@ function replaceCssImportWithNamedImports(ast, cssBinding, source, imports) {
109
110
  }
110
111
  function upsertNamedImports(ast, source, imports) {
111
112
  if (imports.length === 0) return;
112
- const existing = findImportDeclaration(ast, source);
113
+ const existing = ast.program.body.find(
114
+ (node) => t.isImportDeclaration(node) && node.source.value === source && node.importKind !== "type" && !node.specifiers.some((spec) => t.isImportNamespaceSpecifier(spec))
115
+ );
113
116
  if (!existing) {
114
117
  const importDecl = t.importDeclaration(imports.map(toImportSpecifier), t.stringLiteral(source));
115
118
  ast.program.body.splice(findLastImportIndex(ast) + 1, 0, importDecl);
@@ -117,7 +120,7 @@ function upsertNamedImports(ast, source, imports) {
117
120
  }
118
121
  for (const entry of imports) {
119
122
  const exists = existing.specifiers.some((spec) => {
120
- return t.isImportSpecifier(spec) && t.isIdentifier(spec.imported, { name: entry.importedName });
123
+ return t.isImportSpecifier(spec) && spec.importKind !== "type" && t.isIdentifier(spec.imported, { name: entry.importedName });
121
124
  });
122
125
  if (!exists) existing.specifiers.push(toImportSpecifier(entry));
123
126
  }
@@ -183,16 +186,23 @@ function memberPropertyName(node) {
183
186
  if (node.computed && t.isStringLiteral(node.property)) return node.property.value;
184
187
  return null;
185
188
  }
189
+ function hoistTypeOnlyImportKind(node) {
190
+ if (node.importKind === "type") return;
191
+ const typeOnly = node.specifiers.every((spec) => t.isImportSpecifier(spec) && spec.importKind === "type");
192
+ if (!typeOnly) return;
193
+ node.importKind = "type";
194
+ for (const spec of node.specifiers) {
195
+ if (t.isImportSpecifier(spec)) spec.importKind = null;
196
+ }
197
+ }
186
198
  function toImportSpecifier(entry) {
187
199
  return t.importSpecifier(t.identifier(entry.localName), t.identifier(entry.importedName));
188
200
  }
189
201
 
190
202
  // src/plugin/babel-utils.ts
191
- import _generate from "@babel/generator";
203
+ import generate from "@babel/generator";
192
204
  import { parse } from "@babel/parser";
193
- import _traverse from "@babel/traverse";
194
- var generate = _generate.default ?? _generate;
195
- var traverse = _traverse.default ?? _traverse;
205
+ import traverse from "@babel/traverse";
196
206
  function parseModule(code, filename) {
197
207
  return parse(code, {
198
208
  sourceType: "module",
@@ -2486,6 +2496,84 @@ function sortRulesByPriority(rules) {
2486
2496
  return decorated.map((d) => ({ rule: d.rule, priority: d.priority }));
2487
2497
  }
2488
2498
 
2499
+ // src/plugin/truss-css.ts
2500
+ var RULE_ANNOTATION_RE = /^\/\* @truss p:([\d.]+) c:(\S+) \*\/$/;
2501
+ var PROPERTY_ANNOTATION_RE = /^\/\* @truss @property \*\/$/;
2502
+ var ARBITRARY_START_RE = /^\/\* @truss arbitrary:start \*\/$/;
2503
+ var ARBITRARY_END_RE = /^\/\* @truss arbitrary:end \*\/$/;
2504
+ var PROPERTY_VAR_RE = /^@property\s+(--\S+)/;
2505
+ function parseTrussCss(cssText) {
2506
+ const lines = cssText.split("\n");
2507
+ const rules = [];
2508
+ const properties = [];
2509
+ const arbitraryCssBlocks = [];
2510
+ let i = 0;
2511
+ function takeAnnotatedLine() {
2512
+ i++;
2513
+ while (i < lines.length && lines[i].trim() === "") i++;
2514
+ return i < lines.length ? lines[i].trim() : null;
2515
+ }
2516
+ while (i < lines.length) {
2517
+ const line = lines[i].trim();
2518
+ const ruleMatch = RULE_ANNOTATION_RE.exec(line);
2519
+ if (ruleMatch) {
2520
+ const cssText2 = takeAnnotatedLine();
2521
+ if (cssText2 !== null) {
2522
+ rules.push({ priority: parseFloat(ruleMatch[1]), className: ruleMatch[2], cssText: cssText2 });
2523
+ }
2524
+ i++;
2525
+ continue;
2526
+ }
2527
+ if (PROPERTY_ANNOTATION_RE.test(line)) {
2528
+ const propLine = takeAnnotatedLine();
2529
+ const varMatch = propLine === null ? null : PROPERTY_VAR_RE.exec(propLine);
2530
+ if (propLine !== null && varMatch) {
2531
+ properties.push({ cssText: propLine, varName: varMatch[1] });
2532
+ }
2533
+ i++;
2534
+ continue;
2535
+ }
2536
+ if (ARBITRARY_START_RE.test(line)) {
2537
+ i++;
2538
+ const blockLines = [];
2539
+ while (i < lines.length && !ARBITRARY_END_RE.test(lines[i].trim())) {
2540
+ blockLines.push(lines[i]);
2541
+ i++;
2542
+ }
2543
+ const blockText = blockLines.join("\n").trim();
2544
+ if (blockText.length > 0) {
2545
+ arbitraryCssBlocks.push({ cssText: blockText });
2546
+ }
2547
+ if (i < lines.length && ARBITRARY_END_RE.test(lines[i].trim())) {
2548
+ i++;
2549
+ }
2550
+ continue;
2551
+ }
2552
+ i++;
2553
+ }
2554
+ return { rules, properties, arbitraryCssBlocks };
2555
+ }
2556
+ function serializeTrussCss(css) {
2557
+ const lines = [];
2558
+ for (const rule of css.rules) {
2559
+ lines.push(`/* @truss p:${rule.priority} c:${rule.className} */`, rule.cssText);
2560
+ }
2561
+ for (const prop of css.properties) {
2562
+ lines.push(`/* @truss @property */`, prop.cssText);
2563
+ }
2564
+ for (const block of css.arbitraryCssBlocks) {
2565
+ lines.push(annotateArbitraryCssBlock(block.cssText));
2566
+ }
2567
+ return lines.join("\n");
2568
+ }
2569
+ function annotateArbitraryCssBlock(cssText) {
2570
+ const trimmed = cssText.trim();
2571
+ if (trimmed.length === 0) {
2572
+ return "";
2573
+ }
2574
+ return ["/* @truss arbitrary:start */", trimmed, "/* @truss arbitrary:end */"].join("\n");
2575
+ }
2576
+
2489
2577
  // src/plugin/emit-css.ts
2490
2578
  function collectAtomicRules(chains, mapping) {
2491
2579
  const rules = /* @__PURE__ */ new Map();
@@ -2545,22 +2633,28 @@ function whenSelectorFor(whenPseudo) {
2545
2633
  pseudo: whenPseudo.pseudo
2546
2634
  };
2547
2635
  }
2548
- function generateCssText(rules) {
2636
+ function generateCssData(rules) {
2549
2637
  const sorted = sortRulesByPriority(rules.values());
2550
- const lines = [];
2551
- for (const { rule, priority } of sorted) {
2552
- lines.push(`/* @truss p:${priority} c:${rule.className} */`);
2553
- lines.push(formatRule(rule));
2554
- }
2638
+ const css = {
2639
+ rules: sorted.map((entry) => ({
2640
+ priority: entry.priority,
2641
+ className: entry.rule.className,
2642
+ cssText: formatRule(entry.rule)
2643
+ })),
2644
+ properties: [],
2645
+ arbitraryCssBlocks: []
2646
+ };
2555
2647
  for (const { rule } of sorted) {
2556
2648
  for (const declaration of rule.declarations) {
2557
2649
  if (declaration.cssVarName) {
2558
- lines.push(`/* @truss @property */`);
2559
- lines.push(`@property ${declaration.cssVarName} { syntax: "*"; inherits: false; }`);
2650
+ css.properties.push({
2651
+ varName: declaration.cssVarName,
2652
+ cssText: `@property ${declaration.cssVarName} { syntax: "*"; inherits: false; }`
2653
+ });
2560
2654
  }
2561
2655
  }
2562
2656
  }
2563
- return lines.join("\n");
2657
+ return css;
2564
2658
  }
2565
2659
  function formatRule(rule) {
2566
2660
  const duplicateClassName = !!rule.mediaQuery;
@@ -2805,6 +2899,38 @@ ${body}
2805
2899
  import * as t15 from "@babel/types";
2806
2900
  import { basename } from "path";
2807
2901
 
2902
+ // src/plugin/test-css.ts
2903
+ import { parse as parse2 } from "css-tree";
2904
+ function createTestCssPayload(css) {
2905
+ const payload = {};
2906
+ if (css.rules.length > 0) {
2907
+ payload.rules = css.rules.map((rule) => {
2908
+ const atRule = atRulePrelude(rule.cssText);
2909
+ return { ...rule, ...atRule === void 0 ? {} : { atRule } };
2910
+ });
2911
+ }
2912
+ if (css.properties.length > 0) payload.properties = css.properties;
2913
+ const arbitraryRules = css.arbitraryCssBlocks.flatMap((block) => splitArbitraryCss(block.cssText));
2914
+ if (arbitraryRules.length > 0) payload.arbitraryRules = arbitraryRules;
2915
+ return payload;
2916
+ }
2917
+ function splitArbitraryCss(cssText) {
2918
+ const root = parse2(cssText, {
2919
+ context: "stylesheet",
2920
+ positions: true,
2921
+ parseRulePrelude: false,
2922
+ parseAtrulePrelude: false,
2923
+ parseValue: false
2924
+ });
2925
+ const rules = [];
2926
+ root.children.forEach((node) => {
2927
+ if (node.type === "Rule" || node.type === "Atrule") {
2928
+ rules.push(cssText.slice(node.loc.start.offset, node.loc.end.offset));
2929
+ }
2930
+ });
2931
+ return rules;
2932
+ }
2933
+
2808
2934
  // src/plugin/emit-style-hash.ts
2809
2935
  import * as t13 from "@babel/types";
2810
2936
  function buildStyleHashProperties(segments, mapping, maybeIncHelperName, maybeCssVarHelperName) {
@@ -3271,7 +3397,8 @@ function transformTruss(code, filename, mapping, options = {}) {
3271
3397
  if (sites.length === 0 && !hasCssPropsCall && !hasBuildtimeJsxCssAttribute) return null;
3272
3398
  const chains = sites.map((s) => s.resolvedChain);
3273
3399
  const { rules, needsMaybeInc, needsMaybeCssVar } = collectAtomicRules(chains, mapping);
3274
- const cssText = generateCssText(rules);
3400
+ const cssData = generateCssData(rules);
3401
+ const cssText = serializeTrussCss(cssData);
3275
3402
  const runtime = createRuntimeHelpers(ast, usedTopLevelNames);
3276
3403
  const maybeIncHelperName = needsMaybeInc ? reservePreferredName(usedTopLevelNames, "__maybeInc") : null;
3277
3404
  const maybeCssVarHelperName = needsMaybeCssVar ? runtime.use("maybeCssVar") : null;
@@ -3317,7 +3444,9 @@ function transformTruss(code, filename, mapping, options = {}) {
3317
3444
  }
3318
3445
  if (options.injectCss && cssText.length > 0) {
3319
3446
  declarationsToInsert.push(
3320
- t15.expressionStatement(t15.callExpression(t15.identifier("__injectTrussCSS"), [t15.stringLiteral(cssText)]))
3447
+ t15.expressionStatement(
3448
+ t15.callExpression(t15.identifier("__injectTrussCSS"), [t15.valueToNode(createTestCssPayload(cssData))])
3449
+ )
3321
3450
  );
3322
3451
  }
3323
3452
  for (const { message, line } of errorMessages) {
@@ -3436,78 +3565,11 @@ function findLastImportLine(lines) {
3436
3565
 
3437
3566
  // src/plugin/merge-css.ts
3438
3567
  import { readFileSync as readFileSync2 } from "fs";
3439
-
3440
- // src/truss-css.ts
3441
- var RULE_ANNOTATION_RE = /^\/\* @truss p:([\d.]+) c:(\S+) \*\/$/;
3442
- var PROPERTY_ANNOTATION_RE = /^\/\* @truss @property \*\/$/;
3443
- var ARBITRARY_START_RE = /^\/\* @truss arbitrary:start \*\/$/;
3444
- var ARBITRARY_END_RE = /^\/\* @truss arbitrary:end \*\/$/;
3445
- var PROPERTY_VAR_RE = /^@property\s+(--\S+)/;
3446
- function parseTrussCss(cssText) {
3447
- const lines = cssText.split("\n");
3448
- const rules = [];
3449
- const properties = [];
3450
- const arbitraryCssBlocks = [];
3451
- let i = 0;
3452
- function takeAnnotatedLine() {
3453
- i++;
3454
- while (i < lines.length && lines[i].trim() === "") i++;
3455
- return i < lines.length ? lines[i].trim() : null;
3456
- }
3457
- while (i < lines.length) {
3458
- const line = lines[i].trim();
3459
- const ruleMatch = RULE_ANNOTATION_RE.exec(line);
3460
- if (ruleMatch) {
3461
- const cssText2 = takeAnnotatedLine();
3462
- if (cssText2 !== null) {
3463
- rules.push({ priority: parseFloat(ruleMatch[1]), className: ruleMatch[2], cssText: cssText2 });
3464
- }
3465
- i++;
3466
- continue;
3467
- }
3468
- if (PROPERTY_ANNOTATION_RE.test(line)) {
3469
- const propLine = takeAnnotatedLine();
3470
- const varMatch = propLine === null ? null : PROPERTY_VAR_RE.exec(propLine);
3471
- if (propLine !== null && varMatch) {
3472
- properties.push({ cssText: propLine, varName: varMatch[1] });
3473
- }
3474
- i++;
3475
- continue;
3476
- }
3477
- if (ARBITRARY_START_RE.test(line)) {
3478
- i++;
3479
- const blockLines = [];
3480
- while (i < lines.length && !ARBITRARY_END_RE.test(lines[i].trim())) {
3481
- blockLines.push(lines[i]);
3482
- i++;
3483
- }
3484
- const blockText = blockLines.join("\n").trim();
3485
- if (blockText.length > 0) {
3486
- arbitraryCssBlocks.push({ cssText: blockText });
3487
- }
3488
- if (i < lines.length && ARBITRARY_END_RE.test(lines[i].trim())) {
3489
- i++;
3490
- }
3491
- continue;
3492
- }
3493
- i++;
3494
- }
3495
- return { rules, properties, arbitraryCssBlocks };
3496
- }
3497
- function annotateArbitraryCssBlock(cssText) {
3498
- const trimmed = cssText.trim();
3499
- if (trimmed.length === 0) {
3500
- return "";
3501
- }
3502
- return ["/* @truss arbitrary:start */", trimmed, "/* @truss arbitrary:end */"].join("\n");
3503
- }
3504
-
3505
- // src/plugin/merge-css.ts
3506
3568
  function readTrussCss(filePath) {
3507
3569
  const content = readFileSync2(filePath, "utf8");
3508
3570
  return parseTrussCss(content);
3509
3571
  }
3510
- function mergeTrussCss(sources) {
3572
+ function mergeTrussCssData(sources) {
3511
3573
  const seenClasses = /* @__PURE__ */ new Set();
3512
3574
  const allRules = [];
3513
3575
  const seenProperties = /* @__PURE__ */ new Set();
@@ -3532,19 +3594,11 @@ function mergeTrussCss(sources) {
3532
3594
  return { rule, key: ruleSortKey(rule.priority, rule.className, atRulePrelude(rule.cssText)) };
3533
3595
  });
3534
3596
  decorated.sort((a, b) => compareRuleSortKeys(a.key, b.key));
3535
- const lines = [];
3536
- for (const entry of decorated) {
3537
- lines.push(`/* @truss p:${entry.rule.priority} c:${entry.rule.className} */`);
3538
- lines.push(entry.rule.cssText);
3539
- }
3540
- for (const prop of allProperties) {
3541
- lines.push(`/* @truss @property */`);
3542
- lines.push(prop.cssText);
3543
- }
3544
- for (const block of allArbitraryCssBlocks) {
3545
- lines.push(annotateArbitraryCssBlock(block.cssText));
3546
- }
3547
- return lines.join("\n");
3597
+ return {
3598
+ rules: decorated.map((entry) => entry.rule),
3599
+ properties: allProperties,
3600
+ arbitraryCssBlocks: allArbitraryCssBlocks
3601
+ };
3548
3602
  }
3549
3603
 
3550
3604
  // src/plugin/transform-session.ts
@@ -3604,12 +3658,11 @@ function createTrussTransformSession(options) {
3604
3658
  }
3605
3659
  function collectCss() {
3606
3660
  const mapping2 = ensureMapping();
3607
- const appCssParts = [generateCssText(cssRegistry)];
3661
+ const appCss = generateCssData(cssRegistry);
3608
3662
  const allArbitrary = Array.from(arbitraryCssRegistry.entries()).sort((a, b) => compareClassNames(a[0], b[0])).map((entry) => entry[1]).join("\n\n");
3609
- appCssParts.push(annotateArbitraryCssBlock(allArbitrary));
3610
- const appCss = appCssParts.filter((part) => part.length > 0).join("\n");
3663
+ if (allArbitrary.length > 0) appCss.arbitraryCssBlocks.push({ cssText: allArbitrary });
3611
3664
  const libs = loadLibraries();
3612
- const body = libs.length === 0 ? appCss : mergeTrussCss([...libs, parseTrussCss(appCss)]);
3665
+ const body = serializeTrussCss(libs.length === 0 ? appCss : mergeTrussCssData([...libs, appCss]));
3613
3666
  if (body.length === 0) return "";
3614
3667
  return `${rootSpacingPreludeCss(mapping2.increment)}
3615
3668
  ${body}`;
@@ -3618,7 +3671,7 @@ ${body}`;
3618
3671
  return cssRegistry.size > 0 || arbitraryCssRegistry.size > 0 || libraryPaths.length > 0;
3619
3672
  }
3620
3673
  function collectTestCss() {
3621
- return mergeTrussCss(loadLibraries());
3674
+ return createTestCssPayload(mergeTrussCssData(loadLibraries()));
3622
3675
  }
3623
3676
  function getArbitraryCss(sourcePath) {
3624
3677
  return arbitraryCssRegistry.get(resolve2(sourcePath).replace(/\\/g, "/")) ?? "";
@@ -3687,6 +3740,8 @@ function loaderForPath(filePath) {
3687
3740
  var VIRTUAL_CSS_PREFIX = "\0truss-css:";
3688
3741
  var VIRTUAL_TEST_CSS_PREFIX = "\0truss-test-css:";
3689
3742
  var CSS_TS_QUERY = "?truss-css";
3743
+ var RUNTIME_MODULE2 = "@homebound/truss/runtime";
3744
+ var INJECT_CSS_HELPER = "__injectTrussCSS";
3690
3745
  var TRUSS_CSS_PLACEHOLDER = "__TRUSS_CSS_HASH__";
3691
3746
  var VIRTUAL_CSS_ENDPOINT = "/virtual:truss.css";
3692
3747
  var VIRTUAL_RUNTIME_ID = "virtual:truss:runtime";
@@ -3809,8 +3864,8 @@ function trussPlugin(opts) {
3809
3864
  `;
3810
3865
  }
3811
3866
  if (id === RESOLVED_VIRTUAL_TEST_CSS_ID) {
3812
- const css = session.collectTestCss();
3813
- const options = {
3867
+ const payload = {
3868
+ ...session.collectTestCss(),
3814
3869
  source: "libraries",
3815
3870
  order: 0,
3816
3871
  prelude: rootSpacingPreludeCss(session.ensureMapping().increment)
@@ -3818,18 +3873,21 @@ function trussPlugin(opts) {
3818
3873
  return `
3819
3874
  import { __injectTrussCSS } from "@homebound/truss/runtime";
3820
3875
 
3821
- __injectTrussCSS(${JSON.stringify(css)}, ${JSON.stringify(options)});
3876
+ __injectTrussCSS(${JSON.stringify(payload)});
3822
3877
  `;
3823
3878
  }
3824
3879
  if (id.startsWith(VIRTUAL_TEST_CSS_PREFIX)) {
3825
- const sourcePath2 = resolve4(id.slice(VIRTUAL_TEST_CSS_PREFIX.length)).replace(/\\/g, "/");
3880
+ const sourcePath2 = canonicalSourcePath(id.slice(VIRTUAL_TEST_CSS_PREFIX.length));
3826
3881
  session.updateArbitraryCssRegistry(sourcePath2, readFileSync4(sourcePath2, "utf8"));
3827
- const css = annotateArbitraryCssBlock(session.getArbitraryCss(sourcePath2));
3882
+ const payload = {
3883
+ arbitraryRules: splitArbitraryCss(session.getArbitraryCss(sourcePath2)),
3884
+ source: sourcePath2
3885
+ };
3828
3886
  return `
3829
3887
  import "${VIRTUAL_TEST_CSS_ID}";
3830
3888
  import { __injectTrussCSS } from "@homebound/truss/runtime";
3831
3889
 
3832
- __injectTrussCSS(${JSON.stringify(css)}, ${JSON.stringify({ source: sourcePath2 })});
3890
+ __injectTrussCSS(${JSON.stringify(payload)});
3833
3891
  `;
3834
3892
  }
3835
3893
  if (!id.startsWith(VIRTUAL_CSS_PREFIX)) return null;
@@ -3851,32 +3909,8 @@ import "${VIRTUAL_TEST_CSS_ID}";` : rewrittenImports.code;
3851
3909
  if (fileId.endsWith(".css.ts")) {
3852
3910
  session.updateArbitraryCssRegistry(fileId, code);
3853
3911
  if (isTest) {
3854
- const css = annotateArbitraryCssBlock(session.getArbitraryCss(fileId));
3855
- const ast = parseModule(transformedCode, fileId);
3856
- traverse(ast, {
3857
- Program(path) {
3858
- const inject = path.scope.generateUidIdentifier("injectTrussCSS");
3859
- path.unshiftContainer(
3860
- "body",
3861
- t16.importDeclaration(
3862
- [t16.importSpecifier(inject, t16.identifier("__injectTrussCSS"))],
3863
- t16.stringLiteral("@homebound/truss/runtime")
3864
- )
3865
- );
3866
- path.pushContainer(
3867
- "body",
3868
- t16.expressionStatement(
3869
- t16.callExpression(inject, [
3870
- t16.stringLiteral(css),
3871
- t16.objectExpression([
3872
- t16.objectProperty(t16.identifier("source"), t16.stringLiteral(resolve4(fileId).replace(/\\/g, "/")))
3873
- ])
3874
- ])
3875
- )
3876
- );
3877
- }
3878
- });
3879
- return { code: generate(ast, { sourceFileName: fileId }).code, map: null };
3912
+ const css = session.getArbitraryCss(fileId);
3913
+ return { code: appendTestCssInjection(transformedCode, fileId, css), map: null };
3880
3914
  }
3881
3915
  return importsOnlyResult;
3882
3916
  }
@@ -3938,6 +3972,30 @@ function stripQueryAndHash(id) {
3938
3972
  function isNodeModulesFile(filePath) {
3939
3973
  return filePath.replace(/\\/g, "/").includes("/node_modules/");
3940
3974
  }
3975
+ function canonicalSourcePath(filePath) {
3976
+ return resolve4(filePath).replace(/\\/g, "/");
3977
+ }
3978
+ function appendTestCssInjection(code, fileId, css) {
3979
+ const ast = parseModule(code, fileId);
3980
+ let usedTopLevelNames = /* @__PURE__ */ new Set();
3981
+ traverse(ast, {
3982
+ Program(path) {
3983
+ usedTopLevelNames = new Set(Object.keys(path.scope.bindings));
3984
+ path.stop();
3985
+ }
3986
+ });
3987
+ const existing = findNamedImportBinding(ast, INJECT_CSS_HELPER, RUNTIME_MODULE2);
3988
+ const localName = existing ?? reservePreferredName(usedTopLevelNames, INJECT_CSS_HELPER);
3989
+ if (!existing) upsertNamedImports(ast, RUNTIME_MODULE2, [{ importedName: INJECT_CSS_HELPER, localName }]);
3990
+ ast.program.body.push(
3991
+ t16.expressionStatement(
3992
+ t16.callExpression(t16.identifier(localName), [
3993
+ t16.valueToNode({ arbitraryRules: splitArbitraryCss(css), source: canonicalSourcePath(fileId) })
3994
+ ])
3995
+ )
3996
+ );
3997
+ return generate(ast, { sourceFileName: fileId }).code;
3998
+ }
3941
3999
  export {
3942
4000
  loadMapping,
3943
4001
  trussEsbuildPlugin,