@homebound/truss 2.3.4 → 2.4.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.
@@ -37,8 +37,8 @@ type TrussMappingEntry =
37
37
  interface TrussPluginOptions {
38
38
  /** Path to the Css.json mapping file used for transforming files (relative to project root or absolute). */
39
39
  mapping: string;
40
- /** Packages in `node_modules` that should also be transformed, all other `node_modules` files are skipped. */
41
- externalPackages?: string[];
40
+ /** Paths to pre-compiled truss.css files from libraries to merge into the app's CSS. */
41
+ libraries?: string[];
42
42
  }
43
43
  interface TrussVitePlugin {
44
44
  name: string;
@@ -1,5 +1,5 @@
1
1
  // src/plugin/index.ts
2
- import { readFileSync, writeFileSync, existsSync } from "fs";
2
+ import { readFileSync as readFileSync2, writeFileSync, existsSync } from "fs";
3
3
  import { resolve, dirname, isAbsolute, join } from "path";
4
4
 
5
5
  // src/plugin/emit-truss.ts
@@ -565,18 +565,22 @@ function computeRulePriority(rule) {
565
565
  }
566
566
  function isVariableRule(rule) {
567
567
  if (rule.declarations) {
568
- return rule.declarations.some(function(d) {
569
- return d.cssVarName !== void 0;
570
- });
568
+ return rule.declarations.some((d) => d.cssVarName !== void 0);
571
569
  }
572
570
  return rule.cssVarName !== void 0;
573
571
  }
574
572
  function sortRulesByPriority(rules) {
575
- rules.sort(function(a, b) {
576
- const diff = computeRulePriority(a) - computeRulePriority(b);
573
+ const decorated = rules.map((rule, i) => {
574
+ return { rule, priority: computeRulePriority(rule), index: i };
575
+ });
576
+ decorated.sort((a, b) => {
577
+ const diff = a.priority - b.priority;
577
578
  if (diff !== 0) return diff;
578
- return a.className < b.className ? -1 : a.className > b.className ? 1 : 0;
579
+ return a.rule.className < b.rule.className ? -1 : a.rule.className > b.rule.className ? 1 : 0;
579
580
  });
581
+ for (let i = 0; i < decorated.length; i++) {
582
+ rules[i] = decorated[i].rule;
583
+ }
580
584
  }
581
585
 
582
586
  // src/plugin/emit-truss.ts
@@ -834,13 +838,18 @@ function collectVariableRules(rules, seg, mapping) {
834
838
  function generateCssText(rules) {
835
839
  const allRules = Array.from(rules.values());
836
840
  sortRulesByPriority(allRules);
841
+ const priorities = allRules.map(computeRulePriority);
837
842
  const lines = [];
838
- for (const rule of allRules) {
843
+ for (let i = 0; i < allRules.length; i++) {
844
+ const rule = allRules[i];
845
+ const priority = priorities[i];
846
+ lines.push(`/* @truss p:${priority} c:${rule.className} */`);
839
847
  lines.push(formatRule(rule));
840
848
  }
841
849
  for (const rule of allRules) {
842
850
  for (const declaration of getRuleDeclarations(rule)) {
843
851
  if (declaration.cssVarName) {
852
+ lines.push(`/* @truss @property */`);
844
853
  lines.push(`@property ${declaration.cssVarName} { syntax: "*"; inherits: false; }`);
845
854
  }
846
855
  }
@@ -2787,6 +2796,87 @@ function toVirtualCssSpecifier(source) {
2787
2796
  return `${source}?truss-css`;
2788
2797
  }
2789
2798
 
2799
+ // src/plugin/merge-css.ts
2800
+ import { readFileSync } from "fs";
2801
+ var RULE_ANNOTATION_RE = /^\/\* @truss p:([\d.]+) c:(\S+) \*\/$/;
2802
+ var PROPERTY_ANNOTATION_RE = /^\/\* @truss @property \*\/$/;
2803
+ var PROPERTY_VAR_RE = /^@property\s+(--\S+)/;
2804
+ function parseTrussCss(cssText) {
2805
+ const lines = cssText.split("\n");
2806
+ const rules = [];
2807
+ const properties = [];
2808
+ let i = 0;
2809
+ while (i < lines.length) {
2810
+ const line = lines[i].trim();
2811
+ const ruleMatch = RULE_ANNOTATION_RE.exec(line);
2812
+ if (ruleMatch) {
2813
+ const priority = parseFloat(ruleMatch[1]);
2814
+ const className = ruleMatch[2];
2815
+ i++;
2816
+ while (i < lines.length && lines[i].trim() === "") i++;
2817
+ if (i < lines.length) {
2818
+ rules.push({ priority, className, cssText: lines[i].trim() });
2819
+ }
2820
+ i++;
2821
+ continue;
2822
+ }
2823
+ if (PROPERTY_ANNOTATION_RE.test(line)) {
2824
+ i++;
2825
+ while (i < lines.length && lines[i].trim() === "") i++;
2826
+ if (i < lines.length) {
2827
+ const propLine = lines[i].trim();
2828
+ const varMatch = PROPERTY_VAR_RE.exec(propLine);
2829
+ if (varMatch) {
2830
+ properties.push({ cssText: propLine, varName: varMatch[1] });
2831
+ }
2832
+ }
2833
+ i++;
2834
+ continue;
2835
+ }
2836
+ i++;
2837
+ }
2838
+ return { rules, properties };
2839
+ }
2840
+ function readTrussCss(filePath) {
2841
+ const content = readFileSync(filePath, "utf8");
2842
+ return parseTrussCss(content);
2843
+ }
2844
+ function mergeTrussCss(sources) {
2845
+ const seenClasses = /* @__PURE__ */ new Set();
2846
+ const allRules = [];
2847
+ const seenProperties = /* @__PURE__ */ new Set();
2848
+ const allProperties = [];
2849
+ for (const source of sources) {
2850
+ for (const rule of source.rules) {
2851
+ if (!seenClasses.has(rule.className)) {
2852
+ seenClasses.add(rule.className);
2853
+ allRules.push(rule);
2854
+ }
2855
+ }
2856
+ for (const prop of source.properties) {
2857
+ if (!seenProperties.has(prop.varName)) {
2858
+ seenProperties.add(prop.varName);
2859
+ allProperties.push(prop);
2860
+ }
2861
+ }
2862
+ }
2863
+ allRules.sort(function(a, b) {
2864
+ const diff = a.priority - b.priority;
2865
+ if (diff !== 0) return diff;
2866
+ return a.className < b.className ? -1 : a.className > b.className ? 1 : 0;
2867
+ });
2868
+ const lines = [];
2869
+ for (const rule of allRules) {
2870
+ lines.push(`/* @truss p:${rule.priority} c:${rule.className} */`);
2871
+ lines.push(rule.cssText);
2872
+ }
2873
+ for (const prop of allProperties) {
2874
+ lines.push(`/* @truss @property */`);
2875
+ lines.push(prop.cssText);
2876
+ }
2877
+ return lines.join("\n");
2878
+ }
2879
+
2790
2880
  // src/plugin/index.ts
2791
2881
  var VIRTUAL_CSS_PREFIX = "\0truss-css:";
2792
2882
  var CSS_TS_QUERY = "?truss-css";
@@ -2799,7 +2889,7 @@ function trussPlugin(opts) {
2799
2889
  let debug = false;
2800
2890
  let isTest = false;
2801
2891
  let isBuild = false;
2802
- const externalPackages = opts.externalPackages ?? [];
2892
+ const libraryPaths = opts.libraries ?? [];
2803
2893
  const cssRegistry = /* @__PURE__ */ new Map();
2804
2894
  let cssVersion = 0;
2805
2895
  let lastSentVersion = 0;
@@ -2812,8 +2902,22 @@ function trussPlugin(opts) {
2812
2902
  }
2813
2903
  return mapping;
2814
2904
  }
2905
+ let libraryCache = null;
2906
+ function loadLibraries() {
2907
+ if (!libraryCache) {
2908
+ libraryCache = libraryPaths.map(function(libPath) {
2909
+ const resolved = resolve(projectRoot || process.cwd(), libPath);
2910
+ return readTrussCss(resolved);
2911
+ });
2912
+ }
2913
+ return libraryCache;
2914
+ }
2815
2915
  function collectCss() {
2816
- return generateCssText(cssRegistry);
2916
+ const appCss = generateCssText(cssRegistry);
2917
+ const libs = loadLibraries();
2918
+ if (libs.length === 0) return appCss;
2919
+ const appParsed = parseTrussCss(appCss);
2920
+ return mergeTrussCss([...libs, appParsed]);
2817
2921
  }
2818
2922
  return {
2819
2923
  name: "truss",
@@ -2827,6 +2931,7 @@ function trussPlugin(opts) {
2827
2931
  buildStart() {
2828
2932
  ensureMapping();
2829
2933
  cssRegistry.clear();
2934
+ libraryCache = null;
2830
2935
  cssVersion = 0;
2831
2936
  lastSentVersion = 0;
2832
2937
  },
@@ -2903,7 +3008,7 @@ function trussPlugin(opts) {
2903
3008
  }
2904
3009
  if (!id.startsWith(VIRTUAL_CSS_PREFIX)) return null;
2905
3010
  const sourcePath = id.slice(VIRTUAL_CSS_PREFIX.length) + ".ts";
2906
- const sourceCode = readFileSync(sourcePath, "utf8");
3011
+ const sourceCode = readFileSync2(sourcePath, "utf8");
2907
3012
  return transformCssTs(sourceCode, sourcePath, ensureMapping());
2908
3013
  },
2909
3014
  transform(code, id) {
@@ -2913,7 +3018,7 @@ function trussPlugin(opts) {
2913
3018
  const hasCssDsl = rewrittenCode.includes("Css");
2914
3019
  if (!hasCssDsl && !rewrittenImports.changed) return null;
2915
3020
  const fileId = stripQueryAndHash(id);
2916
- if (isNodeModulesFile(fileId) && !isWhitelistedExternalPackageFile(fileId, externalPackages)) {
3021
+ if (isNodeModulesFile(fileId)) {
2917
3022
  return null;
2918
3023
  }
2919
3024
  if (fileId.endsWith(".css.ts")) {
@@ -3003,19 +3108,10 @@ function stripQueryAndHash(id) {
3003
3108
  return cleanId;
3004
3109
  }
3005
3110
  function isNodeModulesFile(filePath) {
3006
- return normalizePath(filePath).includes("/node_modules/");
3007
- }
3008
- function isWhitelistedExternalPackageFile(filePath, externalPackages) {
3009
- const normalizedPath = normalizePath(filePath);
3010
- return externalPackages.some(function(pkg) {
3011
- return normalizedPath.includes(`/node_modules/${pkg}/`);
3012
- });
3013
- }
3014
- function normalizePath(path) {
3015
- return path.replace(/\\/g, "/");
3111
+ return filePath.replace(/\\/g, "/").includes("/node_modules/");
3016
3112
  }
3017
3113
  function loadMapping(path) {
3018
- const raw = readFileSync(path, "utf8");
3114
+ const raw = readFileSync2(path, "utf8");
3019
3115
  return JSON.parse(raw);
3020
3116
  }
3021
3117
  export {