@fluid-app/fluid-cli-portal 0.1.33 → 0.1.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -610,7 +610,15 @@ const CONFIG_CANDIDATES = [
610
610
  const SOURCE_PACKAGE_EXTRACT_FILENAME = "extract-widget-packages.ts";
611
611
  const SOURCE_PACKAGE_OUTPUT_FILENAME = "source-widget-packages.json";
612
612
  const SOURCE_PACKAGE_OUTPUT_SENTINEL = "fluid-widget-source-packages:v1";
613
+ const FLUID_WIDGET_AUTHORING_NODE_CONDITIONS = ["--conditions=fluid-widget-authoring", "--conditions=production"];
613
614
  const TSX_CLI_PATH$1 = createRequire(import.meta.url).resolve("tsx/cli");
615
+ function withFluidWidgetAuthoringNodeCondition(nodeOptions) {
616
+ const existingOptions = nodeOptions?.trim();
617
+ const options = existingOptions ? existingOptions.split(/\s+/) : [];
618
+ const optionSet = new Set(options);
619
+ for (const condition of FLUID_WIDGET_AUTHORING_NODE_CONDITIONS) if (!optionSet.has(condition)) options.push(condition);
620
+ return options.join(" ");
621
+ }
614
622
  async function resolvePortalWidgetSourceConfig(projectDir) {
615
623
  for (const relativePath of CONFIG_CANDIDATES) {
616
624
  const candidate = path.join(projectDir, relativePath);
@@ -644,7 +652,8 @@ async function loadSourceWidgetPackages(projectDir) {
644
652
  stdio: "pipe",
645
653
  env: {
646
654
  ...process.env,
647
- NODE_ENV: "production"
655
+ NODE_ENV: "production",
656
+ NODE_OPTIONS: withFluidWidgetAuthoringNodeCondition(process.env.NODE_OPTIONS)
648
657
  }
649
658
  });
650
659
  const outputResult = await readSourcePackageExtractorOutput(outputFile);
@@ -734,12 +743,12 @@ const server = await createServer({
734
743
  logLevel: "error",
735
744
  clearScreen: false,
736
745
  resolve: {
737
- conditions: ["fluid-widget-authoring"],
746
+ conditions: ["fluid-widget-authoring", "module", "browser", "development|production"],
738
747
  },
739
748
  ssr: {
740
749
  noExternal: ["@fluid-app/portal-sdk"],
741
750
  resolve: {
742
- conditions: ["fluid-widget-authoring"],
751
+ conditions: ["fluid-widget-authoring", "module", "node", "development|production"],
743
752
  },
744
753
  },
745
754
  });
@@ -871,7 +880,8 @@ async function extractManifests(projectDir) {
871
880
  stdio: "pipe",
872
881
  env: {
873
882
  ...process.env,
874
- NODE_ENV: "production"
883
+ NODE_ENV: "production",
884
+ NODE_OPTIONS: withFluidWidgetAuthoringNodeCondition(process.env.NODE_OPTIONS)
875
885
  }
876
886
  });
877
887
  const outputResult = await readManifestExtractorOutput(outputFile);
@@ -977,6 +987,15 @@ const server = await createServer({
977
987
  appType: "custom",
978
988
  logLevel: "error",
979
989
  clearScreen: false,
990
+ resolve: {
991
+ conditions: ["fluid-widget-authoring", "module", "browser", "development|production"],
992
+ },
993
+ ssr: {
994
+ noExternal: ["@fluid-app/portal-sdk"],
995
+ resolve: {
996
+ conditions: ["fluid-widget-authoring", "module", "node", "development|production"],
997
+ },
998
+ },
980
999
  });
981
1000
 
982
1001
  try {
@@ -2527,18 +2546,10 @@ function validateCssUrl(value, cssUrlPath, errors) {
2527
2546
  });
2528
2547
  return;
2529
2548
  }
2530
- if (!isValidRuntimeDescriptorUrl(value)) {
2531
- errors.push({
2532
- code: "INVALID_SOURCE_PACKAGE",
2533
- path: cssUrlPath,
2534
- message: "Widget package cssUrls entries must be https URLs, trusted local http URLs, or relative URLs."
2535
- });
2536
- return;
2537
- }
2538
- if (!isAbsoluteRuntimeUrl(value) && !isWidgetPackageCssArtifactPath(value)) errors.push({
2549
+ if (!isWidgetPackageCssArtifactPath(value)) errors.push({
2539
2550
  code: "INVALID_SOURCE_PACKAGE",
2540
2551
  path: cssUrlPath,
2541
- message: "Widget package relative cssUrls entries must be top-level CSS artifact filenames matching [A-Za-z0-9._~-]+.css."
2552
+ message: "Widget package cssUrls entries must be top-level generated CSS artifact filenames matching [A-Za-z0-9._~-]+.css. Self-host external CSS or fonts via @font-face in widget CSS so the build can isolate them."
2542
2553
  });
2543
2554
  }
2544
2555
  function validateRuntimeDescriptorUrl(value, urlPath) {
@@ -2622,21 +2633,19 @@ function validateOptionalRecordField(record, key, path, errors) {
2622
2633
  }
2623
2634
  function mergeCssUrls(sourceCssUrls, generatedCssUrls) {
2624
2635
  const generatedCssUrlSet = new Set(generatedCssUrls ?? []);
2636
+ generatedCssUrls?.forEach((cssUrl, index) => {
2637
+ validateGeneratedCssArtifactUrl(cssUrl, `generated cssUrls[${index}]`);
2638
+ });
2625
2639
  sourceCssUrls?.forEach((cssUrl, index) => {
2626
- validateRuntimeDescriptorUrl(cssUrl, `cssUrls[${index}]`);
2627
- if (isAbsoluteRuntimeUrl(cssUrl)) return;
2628
- if (!isWidgetPackageCssArtifactPath(cssUrl)) throw new Error(`cssUrls[${index}] relative URL ${JSON.stringify(cssUrl)} must be a top-level CSS artifact filename matching [A-Za-z0-9._~-]+.css.`);
2640
+ validateGeneratedCssArtifactUrl(cssUrl, `cssUrls[${index}]`);
2629
2641
  if (generatedCssUrlSet.has(cssUrl)) return;
2630
- throw new Error(`cssUrls[${index}] relative URL ${JSON.stringify(cssUrl)} must match a generated top-level CSS artifact. Import the CSS from the widget package bundle or remove it from cssUrls.`);
2642
+ throw new Error(`cssUrls[${index}] URL ${JSON.stringify(cssUrl)} must match a generated top-level CSS artifact. Import the CSS from the widget package bundle or remove it from cssUrls.`);
2631
2643
  });
2632
- const cssUrls = Array.from(new Set([...sourceCssUrls ?? [], ...generatedCssUrls ?? []]));
2633
- cssUrls.forEach((cssUrl, index) => {
2634
- validateRuntimeDescriptorUrl(cssUrl, `cssUrls[${index}]`);
2635
- });
2636
- return cssUrls;
2644
+ return Array.from(new Set([...sourceCssUrls ?? [], ...generatedCssUrls ?? []]));
2637
2645
  }
2638
- function isAbsoluteRuntimeUrl(value) {
2639
- return /^[a-zA-Z][a-zA-Z\d+.-]*:/.test(value);
2646
+ function validateGeneratedCssArtifactUrl(value, cssUrlPath) {
2647
+ if (value.trim().length === 0) throw new Error(`${cssUrlPath} must be a non-empty string.`);
2648
+ if (!isWidgetPackageCssArtifactPath(value)) throw new Error(`${cssUrlPath} must be a top-level generated CSS artifact filename matching [A-Za-z0-9._~-]+.css. Self-host external CSS or fonts via @font-face in widget CSS so the build can isolate them.`);
2640
2649
  }
2641
2650
  function normalizePropertySchema(value, widgetType) {
2642
2651
  return {
@@ -2806,9 +2815,13 @@ async function buildSharedWidgetPackage(options) {
2806
2815
  }
2807
2816
  }
2808
2817
  function createWidgetPackageEntrySource(options) {
2818
+ const runtimePackageId = getWidgetPackageDescriptorPackageId(options.validated);
2809
2819
  return `import * as widgetConfig from ${JSON.stringify(options.configImportPath)};
2820
+ import { createElement } from "react";
2810
2821
 
2811
2822
  const SOURCE_PACKAGE_MARKER = "__fluidSourceWidgetPackage";
2823
+ const WIDGET_PACKAGE_ID = ${JSON.stringify(runtimePackageId)};
2824
+ const WIDGET_PACKAGE_VERSION = ${JSON.stringify(options.validated.version)};
2812
2825
  const descriptors = ${JSON.stringify(options.validated.widgets, null, 2)};
2813
2826
 
2814
2827
  function isSourceWidgetPackage(value) {
@@ -2832,12 +2845,31 @@ const componentsByName = new Map(
2832
2845
  sourcePackage.widgets.map((widget) => [widget.name, widget.component]),
2833
2846
  );
2834
2847
 
2848
+ function createScopedWidgetComponent(component, descriptor) {
2849
+ const wrapperTagName = descriptor.container === "inline" ? "span" : "div";
2850
+ const WrappedFluidWidgetComponent = (props) => createElement(
2851
+ wrapperTagName,
2852
+ {
2853
+ "data-fluid-widget-package": WIDGET_PACKAGE_ID,
2854
+ "data-fluid-widget-version": WIDGET_PACKAGE_VERSION,
2855
+ "data-fluid-widget-name": descriptor.name,
2856
+ },
2857
+ // PortalContainerProvider is not imported here because standalone widget packages
2858
+ // only depend on @fluid-app/portal-sdk, which does not currently expose a
2859
+ // public portal-container provider. Radix/ui-primitives portals remain a
2860
+ // residual isolation risk until a public widget-safe provider is available.
2861
+ createElement(component, props),
2862
+ );
2863
+ WrappedFluidWidgetComponent.displayName = "FluidWidgetPackage(" + WIDGET_PACKAGE_ID + "/" + descriptor.name + ")";
2864
+ return WrappedFluidWidgetComponent;
2865
+ }
2866
+
2835
2867
  const widgets = descriptors.map((descriptor) => {
2836
2868
  const component = componentsByName.get(descriptor.name);
2837
2869
  if (typeof component !== "function" && typeof component !== "object") {
2838
2870
  throw new Error("Widget package is missing component for " + descriptor.name + ".");
2839
2871
  }
2840
- return { ...descriptor, component };
2872
+ return { ...descriptor, component: createScopedWidgetComponent(component, descriptor) };
2841
2873
  });
2842
2874
 
2843
2875
  var _fluidWidgets = globalObject.FluidWidgets;
@@ -2846,7 +2878,7 @@ if (!_fluidWidgets || typeof _fluidWidgets.registerPackage !== "function") {
2846
2878
  }
2847
2879
 
2848
2880
  _fluidWidgets.registerPackage({
2849
- packageId: ${JSON.stringify(options.validated.packageId)},
2881
+ packageId: ${JSON.stringify(runtimePackageId)},
2850
2882
  version: ${JSON.stringify(options.validated.version)},
2851
2883
  widgets,
2852
2884
  });
@@ -2863,6 +2895,8 @@ async function buildWidgetScriptBundle(options) {
2863
2895
  }), "utf-8");
2864
2896
  await fs.writeFile(viteConfigPath, createViteConfigSource({
2865
2897
  entryPath,
2898
+ packageId: getWidgetPackageDescriptorPackageId(options.validated),
2899
+ packageVersion: options.validated.version,
2866
2900
  publishDir: options.publishDir,
2867
2901
  projectConfigPath: await resolveProjectViteConfigPath(options.projectDir)
2868
2902
  }), "utf-8");
@@ -2877,7 +2911,8 @@ async function buildWidgetScriptBundle(options) {
2877
2911
  stdio: "pipe",
2878
2912
  env: {
2879
2913
  ...process.env,
2880
- NODE_ENV: "production"
2914
+ NODE_ENV: "production",
2915
+ NODE_OPTIONS: withFluidWidgetAuthoringNodeCondition(process.env.NODE_OPTIONS)
2881
2916
  }
2882
2917
  });
2883
2918
  const widgetScriptPath = path.join(options.publishDir, "widget.js");
@@ -2890,13 +2925,14 @@ function wrapWidgetPackageScript(widgetScriptContent) {
2890
2925
  var runWidgetPackage = function fluidWidgetPackageFactory() {
2891
2926
  // Intentionally shadow Rollup's expected FluidShared global with the wrapper-scoped host globals.
2892
2927
  var FluidShared = globalObject.FluidShared;
2893
- if (!FluidShared) {
2894
- throw new Error("window.FluidShared is not installed.");
2928
+ if (!FluidShared || !FluidShared.PortalSdk) {
2929
+ throw new Error("window.FluidShared.PortalSdk is not installed.");
2895
2930
  }
2896
2931
  ${indentScript(widgetScriptContent, " ")}
2897
2932
  };
2933
+ runWidgetPackage.__fluidRequiresPortalSdk = true;
2898
2934
 
2899
- if (globalObject.FluidShared) {
2935
+ if (globalObject.FluidShared && globalObject.FluidShared.PortalSdk) {
2900
2936
  runWidgetPackage();
2901
2937
  return;
2902
2938
  }
@@ -2989,6 +3025,21 @@ export default defineConfig(async (configEnv) => {
2989
3025
  function createWidgetViteConfigObjectSource(options) {
2990
3026
  const configFileSource = options.disableConfigFileLookup ? " configFile: false,\n" : "";
2991
3027
  return `(() => {
3028
+ const widgetPackageId = ${JSON.stringify(options.packageId)};
3029
+ const widgetPackageVersion = ${JSON.stringify(options.packageVersion)};
3030
+ const widgetPackageScopeSelector = '[data-fluid-widget-package="' + widgetPackageId + '"][data-fluid-widget-version="' + widgetPackageVersion + '"]';
3031
+ const widgetPackageGeneratedCssFileName = "widget.css";
3032
+ const widgetPackageKeyframePrefix = "fluid-widget-" + encodeCssIdentifier(widgetPackageId) + "-" + encodeCssIdentifier(widgetPackageVersion) + "-";
3033
+ const widgetPackageLayerPrefix = widgetPackageKeyframePrefix + "layer-";
3034
+ const widgetPackageHostDefaultLayerName = widgetPackageLayerPrefix + "generated-host-defaults";
3035
+ const widgetPackageHostDefaultRule = "@layer " + widgetPackageHostDefaultLayerName + " { " + widgetPackageScopeSelector + " { display: contents; } }";
3036
+ const widgetPackageContainerPrefix = widgetPackageKeyframePrefix + "container-";
3037
+ const widgetPackageCssGlobalNamePrefix = widgetPackageKeyframePrefix + "css-name-";
3038
+ const groupingAtRules = new Set(["media", "supports", "container", "document", "starting-style"]);
3039
+ const unsafeSelectorPattern = /(^|[\\s>+~,])(:root|html|body)(?=$|[\\s.#:[>+~,)])/i;
3040
+ const universalSelectorPattern = /(^|[\\s>+~,])\\*(?=$|[\\s.#:[>+~,)])/g;
3041
+ const pseudoElementOnlySelectorPattern = /^::[A-Za-z-]+(?:\\([^)]*\\))?$/;
3042
+
2992
3043
  function createFluidWidgetBuildInvariants() {
2993
3044
  return {
2994
3045
  copyPublicDir: false,
@@ -3002,12 +3053,18 @@ function createWidgetViteConfigObjectSource(options) {
3002
3053
  fileName: () => "widget.js",
3003
3054
  },
3004
3055
  rollupOptions: {
3005
- external: ["react", "react-dom", "react/jsx-runtime"],
3056
+ external: [
3057
+ "react",
3058
+ "react-dom",
3059
+ "react/jsx-runtime",
3060
+ "@fluid-app/portal-sdk",
3061
+ ],
3006
3062
  output: {
3007
3063
  globals: {
3008
3064
  react: "FluidShared.React",
3009
3065
  "react-dom": "FluidShared.ReactDOM",
3010
3066
  "react/jsx-runtime": "FluidShared.ReactJsxRuntime",
3067
+ "@fluid-app/portal-sdk": "FluidShared.PortalSdk",
3011
3068
  },
3012
3069
  },
3013
3070
  },
@@ -3027,12 +3084,1174 @@ function createWidgetViteConfigObjectSource(options) {
3027
3084
  };
3028
3085
  }
3029
3086
 
3087
+ function fluidWidgetCssIsolationPlugin() {
3088
+ return {
3089
+ name: "fluid-widget-css-isolation",
3090
+ enforce: "post",
3091
+ generateBundle(_outputOptions, bundle) {
3092
+ let hasCssAsset = false;
3093
+ for (const asset of Object.values(bundle)) {
3094
+ if (!asset || asset.type !== "asset" || !asset.fileName.endsWith(".css")) continue;
3095
+ hasCssAsset = true;
3096
+ const source = typeof asset.source === "string" ? asset.source : new TextDecoder().decode(asset.source);
3097
+ asset.source = isolateWidgetCssAsset(source, asset.fileName);
3098
+ }
3099
+ if (!hasCssAsset) {
3100
+ this.emitFile({
3101
+ type: "asset",
3102
+ fileName: widgetPackageGeneratedCssFileName,
3103
+ source: widgetPackageHostDefaultRule + "\\n",
3104
+ });
3105
+ }
3106
+ },
3107
+ };
3108
+ }
3109
+
3110
+ function isolateWidgetCssAsset(css, assetName) {
3111
+ const keyframeNames = collectKeyframeNames(css);
3112
+ const fontFamilyNames = collectFontFamilyNames(css);
3113
+ const customPropertyNames = collectRegisteredCustomPropertyNames(css);
3114
+ const placementSensitivePrefix = readPlacementSensitiveCssPrefix(css, assetName);
3115
+ const isolatedCss = isolateCssRange(css, assetName, keyframeNames, fontFamilyNames, customPropertyNames, placementSensitivePrefix.endIndex, css.length).css;
3116
+ return placementSensitivePrefix.css + widgetPackageHostDefaultRule + "\\n" + isolatedCss;
3117
+ }
3118
+
3119
+ function collectKeyframeNames(css) {
3120
+ const names = new Map();
3121
+ visitCssAtRules(css, (atRuleName, atRule) => {
3122
+ if (!isKeyframesAtRule(atRuleName)) return false;
3123
+ const match = /^@(?:-[A-Za-z]+-)?keyframes\\s+([^\\s{]+)/i.exec(atRule.prelude);
3124
+ const name = match?.[1];
3125
+ if (name && !names.has(name)) names.set(name, widgetPackageKeyframePrefix + name);
3126
+ return atRule.blockStart !== -1;
3127
+ });
3128
+ return names;
3129
+ }
3130
+
3131
+ function collectFontFamilyNames(css) {
3132
+ const names = new Map();
3133
+ visitCssAtRules(css, (atRuleName, atRule) => {
3134
+ if (atRuleName !== "font-face" || atRule.blockStart === -1 || atRule.blockEnd === -1) return false;
3135
+ let familyName = "";
3136
+ rewriteDeclarationBlock(css.slice(atRule.blockStart + 1, atRule.blockEnd), (propertyName, rawProperty, value) => {
3137
+ if (propertyName === "font-family" && !familyName) {
3138
+ familyName = normalizeFontFamilyName(value);
3139
+ }
3140
+ return { property: rawProperty, value };
3141
+ });
3142
+ if (familyName && !names.has(familyName)) names.set(familyName, widgetPackageKeyframePrefix + familyName);
3143
+ return true;
3144
+ });
3145
+ return names;
3146
+ }
3147
+
3148
+ function collectRegisteredCustomPropertyNames(css) {
3149
+ const names = new Map();
3150
+ visitCssAtRules(css, (atRuleName, atRule) => {
3151
+ if (atRuleName !== "property") return false;
3152
+ const match = /^@property\\s+(--[A-Za-z0-9_-]+)/i.exec(atRule.prelude);
3153
+ const name = match?.[1];
3154
+ if (name && !names.has(name)) names.set(name, "--" + widgetPackageKeyframePrefix + name.slice(2));
3155
+ return atRule.blockStart !== -1;
3156
+ });
3157
+ return names;
3158
+ }
3159
+
3160
+ function visitCssAtRules(css, visitAtRule) {
3161
+ let index = 0;
3162
+ while (index < css.length) {
3163
+ if (cssStartsWithComment(css, index)) {
3164
+ const commentEnd = css.indexOf("*/", index + 2);
3165
+ index = commentEnd === -1 ? css.length : commentEnd + 2;
3166
+ continue;
3167
+ }
3168
+ const char = css[index];
3169
+ if (char === '"' || char === "'") {
3170
+ index = findCssStringEnd(css, index);
3171
+ continue;
3172
+ }
3173
+ if (char !== "@") {
3174
+ index += 1;
3175
+ continue;
3176
+ }
3177
+ const atRule = readRulePrelude(css, index, css.length);
3178
+ const blockEnd = atRule.blockStart === -1 ? -1 : findMatchingBrace(css, atRule.blockStart, css.length);
3179
+ const shouldSkipBlock = visitAtRule(readAtRuleName(atRule.prelude), { ...atRule, blockEnd });
3180
+ index = shouldSkipBlock && blockEnd !== -1 ? blockEnd + 1 : index + 1;
3181
+ }
3182
+ }
3183
+
3184
+ function isolateCssRange(css, assetName, keyframeNames, fontFamilyNames, customPropertyNames, startIndex, endIndex) {
3185
+ let output = "";
3186
+ let index = startIndex;
3187
+ while (index < endIndex) {
3188
+ if (css.startsWith("/*", index)) {
3189
+ const commentEnd = css.indexOf("*/", index + 2);
3190
+ const nextIndex = commentEnd === -1 ? endIndex : commentEnd + 2;
3191
+ output += css.slice(index, nextIndex);
3192
+ index = nextIndex;
3193
+ continue;
3194
+ }
3195
+
3196
+ if (/\\s/.test(css[index] ?? "")) {
3197
+ output += css[index];
3198
+ index += 1;
3199
+ continue;
3200
+ }
3201
+
3202
+ if (css[index] === "@") {
3203
+ const atRule = readRulePrelude(css, index, endIndex);
3204
+ const atRuleName = readAtRuleName(atRule.prelude);
3205
+ if (atRule.blockStart === -1) {
3206
+ if (atRuleName === "import") {
3207
+ throw new Error('Unsupported @import rule in CSS asset "' + assetName + '" cannot be isolated safely. Self-host external CSS or fonts via @font-face in widget CSS so the build can isolate them.');
3208
+ }
3209
+ if (atRuleName === "charset" || atRuleName === "namespace") {
3210
+ throw new Error('Unsupported @' + atRuleName + ' rule in CSS asset "' + assetName + '" cannot be isolated safely after generated host defaults. Move @' + atRuleName + ' before all non-@charset/@namespace rules.');
3211
+ }
3212
+ if (atRuleName === "layer") {
3213
+ output += rewriteLayerPrelude(atRule.prelude) + css.slice(index + atRule.prelude.length, atRule.end);
3214
+ index = atRule.end;
3215
+ continue;
3216
+ }
3217
+ output += css.slice(index, atRule.end);
3218
+ index = atRule.end;
3219
+ continue;
3220
+ }
3221
+
3222
+ const blockEnd = findMatchingBrace(css, atRule.blockStart, endIndex);
3223
+ if (blockEnd === -1) {
3224
+ output += css.slice(index, endIndex);
3225
+ index = endIndex;
3226
+ continue;
3227
+ }
3228
+
3229
+ const ruleHeader = css.slice(index, atRule.blockStart + 1);
3230
+ if (isKeyframesAtRule(atRuleName)) {
3231
+ output += rewriteKeyframesHeader(ruleHeader, keyframeNames) + namespaceKeyframesBlock(css.slice(atRule.blockStart + 1, blockEnd), keyframeNames, fontFamilyNames, customPropertyNames, assetName) + "}";
3232
+ } else if (atRuleName === "font-face") {
3233
+ output += ruleHeader + namespaceFontFaceBlock(css.slice(atRule.blockStart + 1, blockEnd), fontFamilyNames, customPropertyNames) + "}";
3234
+ } else if (atRuleName === "property") {
3235
+ output += rewritePropertyHeader(ruleHeader, customPropertyNames) + namespaceCustomPropertyReferences(css.slice(atRule.blockStart + 1, blockEnd), customPropertyNames) + "}";
3236
+ } else if (atRuleName === "layer") {
3237
+ output += rewriteLayerPrelude(atRule.prelude) + css.slice(index + atRule.prelude.length, atRule.blockStart + 1) + isolateCssRange(css, assetName, keyframeNames, fontFamilyNames, customPropertyNames, atRule.blockStart + 1, blockEnd).css + "}";
3238
+ } else if (groupingAtRules.has(atRuleName)) {
3239
+ const groupingRuleHeader = atRuleName === "container" ? rewriteContainerAtRuleHeader(ruleHeader) : ruleHeader;
3240
+ output += groupingRuleHeader + isolateCssRange(css, assetName, keyframeNames, fontFamilyNames, customPropertyNames, atRule.blockStart + 1, blockEnd).css + "}";
3241
+ } else {
3242
+ throw new Error('Unsupported @' + atRuleName + ' rule in CSS asset "' + assetName + '" cannot be isolated safely.');
3243
+ }
3244
+ index = blockEnd + 1;
3245
+ continue;
3246
+ }
3247
+
3248
+ const styleRule = readRulePrelude(css, index, endIndex);
3249
+ if (styleRule.blockStart === -1) {
3250
+ output += css.slice(index, styleRule.end);
3251
+ index = styleRule.end;
3252
+ continue;
3253
+ }
3254
+
3255
+ const styleBlockEnd = findMatchingBrace(css, styleRule.blockStart, endIndex);
3256
+ if (styleBlockEnd === -1) {
3257
+ output += css.slice(index, endIndex);
3258
+ index = endIndex;
3259
+ continue;
3260
+ }
3261
+
3262
+ output += isolateSelectorList(styleRule.prelude, assetName) + "{" + namespaceStyleBlock(css.slice(styleRule.blockStart + 1, styleBlockEnd), keyframeNames, fontFamilyNames, customPropertyNames, assetName) + "}";
3263
+ index = styleBlockEnd + 1;
3264
+ }
3265
+
3266
+ return { css: output, index };
3267
+ }
3268
+
3269
+ function readPlacementSensitiveCssPrefix(css, assetName) {
3270
+ let output = "";
3271
+ let index = 0;
3272
+ let hasNamespace = false;
3273
+ while (index < css.length) {
3274
+ const leadingStart = index;
3275
+ index = skipCssWhitespaceAndComments(css, index);
3276
+ const leading = css.slice(leadingStart, index);
3277
+ if (css[index] !== "@") {
3278
+ return { css: output + leading, endIndex: index };
3279
+ }
3280
+
3281
+ const atRule = readRulePrelude(css, index, css.length);
3282
+ const atRuleName = readAtRuleName(atRule.prelude);
3283
+ if (atRuleName !== "charset" && atRuleName !== "namespace") {
3284
+ return { css: output + leading, endIndex: index };
3285
+ }
3286
+ if (atRule.blockStart !== -1) {
3287
+ throw new Error('Unsupported @' + atRuleName + ' rule in CSS asset "' + assetName + '" cannot be isolated safely.');
3288
+ }
3289
+ if (atRuleName === "charset" && hasNamespace) {
3290
+ throw new Error('Unsupported @charset rule in CSS asset "' + assetName + '" cannot be isolated safely after @namespace. Move @charset before @namespace.');
3291
+ }
3292
+ if (atRuleName === "namespace") hasNamespace = true;
3293
+ output += leading + css.slice(index, atRule.end);
3294
+ index = atRule.end;
3295
+ }
3296
+ return { css: output, endIndex: index };
3297
+ }
3298
+
3299
+ function readRulePrelude(css, startIndex, endIndex) {
3300
+ let index = startIndex;
3301
+ let quote = "";
3302
+ let bracketDepth = 0;
3303
+ let parenDepth = 0;
3304
+ while (index < endIndex) {
3305
+ const char = css[index];
3306
+ if (quote) {
3307
+ if (char === "\\\\") index += 2;
3308
+ else {
3309
+ if (char === quote) quote = "";
3310
+ index += 1;
3311
+ }
3312
+ continue;
3313
+ }
3314
+ if (cssStartsWithComment(css, index)) {
3315
+ const commentEnd = css.indexOf("*/", index + 2);
3316
+ index = commentEnd === -1 ? endIndex : Math.min(commentEnd + 2, endIndex);
3317
+ continue;
3318
+ }
3319
+ if (char === '"' || char === "'") {
3320
+ quote = char;
3321
+ index += 1;
3322
+ continue;
3323
+ }
3324
+ if (char === "[") bracketDepth += 1;
3325
+ else if (char === "]") bracketDepth = Math.max(0, bracketDepth - 1);
3326
+ else if (char === "(") parenDepth += 1;
3327
+ else if (char === ")") parenDepth = Math.max(0, parenDepth - 1);
3328
+ else if (bracketDepth === 0 && parenDepth === 0 && char === "{") {
3329
+ return { prelude: css.slice(startIndex, index), blockStart: index, end: index + 1 };
3330
+ } else if (bracketDepth === 0 && parenDepth === 0 && char === ";") {
3331
+ return { prelude: css.slice(startIndex, index), blockStart: -1, end: index + 1 };
3332
+ }
3333
+ index += 1;
3334
+ }
3335
+ return { prelude: css.slice(startIndex, endIndex), blockStart: -1, end: endIndex };
3336
+ }
3337
+
3338
+ function findMatchingBrace(css, openBraceIndex, endIndex) {
3339
+ let depth = 1;
3340
+ let index = openBraceIndex + 1;
3341
+ let quote = "";
3342
+ while (index < endIndex) {
3343
+ const char = css[index];
3344
+ if (quote) {
3345
+ if (char === "\\\\") index += 2;
3346
+ else {
3347
+ if (char === quote) quote = "";
3348
+ index += 1;
3349
+ }
3350
+ continue;
3351
+ }
3352
+ if (char === '"' || char === "'") {
3353
+ quote = char;
3354
+ index += 1;
3355
+ continue;
3356
+ }
3357
+ if (css.startsWith("/*", index)) {
3358
+ const commentEnd = css.indexOf("*/", index + 2);
3359
+ index = commentEnd === -1 ? endIndex : commentEnd + 2;
3360
+ continue;
3361
+ }
3362
+ if (char === "{") depth += 1;
3363
+ else if (char === "}") {
3364
+ depth -= 1;
3365
+ if (depth === 0) return index;
3366
+ }
3367
+ index += 1;
3368
+ }
3369
+ return -1;
3370
+ }
3371
+
3372
+ function readAtRuleName(prelude) {
3373
+ const match = /^@([A-Za-z-]+)/.exec(prelude.trim());
3374
+ return match?.[1]?.toLowerCase() ?? "";
3375
+ }
3376
+
3377
+ function isKeyframesAtRule(atRuleName) {
3378
+ return atRuleName === "keyframes" || atRuleName.endsWith("-keyframes");
3379
+ }
3380
+
3381
+ function rewriteKeyframesHeader(header, keyframeNames) {
3382
+ return header.replace(/(@(?:-[A-Za-z]+-)?keyframes\\s+)([^\\s{]+)/, (_match, prefix, name) => prefix + (keyframeNames.get(name) ?? name));
3383
+ }
3384
+
3385
+ function splitSelectorList(selectorList) {
3386
+ const selectors = [];
3387
+ let current = "";
3388
+ let quote = "";
3389
+ let bracketDepth = 0;
3390
+ let parenDepth = 0;
3391
+ for (let index = 0; index < selectorList.length; index += 1) {
3392
+ const char = selectorList[index];
3393
+ if (quote) {
3394
+ current += char;
3395
+ if (char === "\\\\") {
3396
+ index += 1;
3397
+ current += selectorList[index] ?? "";
3398
+ } else if (char === quote) quote = "";
3399
+ continue;
3400
+ }
3401
+ if (char === '"' || char === "'") {
3402
+ quote = char;
3403
+ current += char;
3404
+ continue;
3405
+ }
3406
+ if (cssStartsWithComment(selectorList, index)) {
3407
+ const commentEnd = selectorList.indexOf("*/", index + 2);
3408
+ const nextIndex = commentEnd === -1 ? selectorList.length : commentEnd + 2;
3409
+ current += selectorList.slice(index, nextIndex);
3410
+ index = nextIndex - 1;
3411
+ continue;
3412
+ }
3413
+ if (char === "[") bracketDepth += 1;
3414
+ else if (char === "]") bracketDepth = Math.max(0, bracketDepth - 1);
3415
+ else if (char === "(") parenDepth += 1;
3416
+ else if (char === ")") parenDepth = Math.max(0, parenDepth - 1);
3417
+ if (char === "," && bracketDepth === 0 && parenDepth === 0) {
3418
+ selectors.push(current);
3419
+ current = "";
3420
+ } else current += char;
3421
+ }
3422
+ selectors.push(current);
3423
+ return selectors;
3424
+ }
3425
+
3426
+ function isolateSelectorList(selectorList, assetName) {
3427
+ return splitSelectorList(selectorList).map((selector) => isolateSelector(selector, assetName)).join(",");
3428
+ }
3429
+
3430
+ function isolateSelector(selector, assetName) {
3431
+ const leadingWhitespace = selector.match(/^\\s*/)?.[0] ?? "";
3432
+ const trailingWhitespace = selector.match(/\\s*$/)?.[0] ?? "";
3433
+ const trimmed = selector.trim();
3434
+ assertSafeSelector(trimmed, assetName);
3435
+ if (trimmed.includes(":host")) {
3436
+ return leadingWhitespace + isolateHostSelector(trimmed, assetName) + trailingWhitespace;
3437
+ }
3438
+ return leadingWhitespace + widgetPackageScopeSelector + " " + trimmed + trailingWhitespace;
3439
+ }
3440
+
3441
+ function isolateHostSelector(selector, assetName) {
3442
+ if (!selector.startsWith(":host")) {
3443
+ throw new Error('Unsupported :host selector "' + selector + '" in CSS asset "' + assetName + '" cannot be isolated safely.');
3444
+ }
3445
+ const match = /^:host(?:\\(([^()]*)\\))?($|[\\s>+~].*)/.exec(selector);
3446
+ if (!match) {
3447
+ throw new Error('Unsupported :host selector "' + selector + '" in CSS asset "' + assetName + '" cannot be isolated safely.');
3448
+ }
3449
+ const hostSelector = (match[1] ?? "").trim();
3450
+ const selectorAfterHost = match[2] ?? "";
3451
+ const firstSelectorAfterHostIndex = skipCssWhitespaceAndComments(selectorAfterHost, 0);
3452
+ const firstSelectorAfterHostChar = selectorAfterHost[firstSelectorAfterHostIndex] ?? "";
3453
+ if (hostSelector.includes(",") || hasTopLevelHostArgumentCombinator(hostSelector) || firstSelectorAfterHostChar === "+" || firstSelectorAfterHostChar === "~" || (hostSelector && (unsafeSelectorPattern.test(hostSelector) || hasUnsafeUniversalSelector(hostSelector)))) {
3454
+ throw new Error('Unsupported :host selector "' + selector + '" in CSS asset "' + assetName + '" cannot be isolated safely.');
3455
+ }
3456
+ return widgetPackageScopeSelector + hostSelector + selectorAfterHost;
3457
+ }
3458
+
3459
+ function hasTopLevelHostArgumentCombinator(value) {
3460
+ let quote = "";
3461
+ let bracketDepth = 0;
3462
+ let hasSelectorBeforeWhitespace = false;
3463
+ let index = 0;
3464
+ while (index < value.length) {
3465
+ const char = value[index];
3466
+ if (quote) {
3467
+ if (char === "\\\\") index += 2;
3468
+ else {
3469
+ if (char === quote) quote = "";
3470
+ index += 1;
3471
+ }
3472
+ continue;
3473
+ }
3474
+ if (char === '"' || char === "'") {
3475
+ quote = char;
3476
+ index += 1;
3477
+ continue;
3478
+ }
3479
+ if (char === "[") {
3480
+ bracketDepth += 1;
3481
+ hasSelectorBeforeWhitespace = true;
3482
+ } else if (char === "]") {
3483
+ bracketDepth = Math.max(0, bracketDepth - 1);
3484
+ } else if (bracketDepth === 0 && (char === "+" || char === "~" || char === ">")) {
3485
+ return true;
3486
+ } else if (bracketDepth === 0 && /\\s/.test(char)) {
3487
+ const nextIndex = skipCssWhitespaceAndComments(value, index);
3488
+ if (hasSelectorBeforeWhitespace && nextIndex < value.length) return true;
3489
+ index = nextIndex;
3490
+ continue;
3491
+ } else if (bracketDepth === 0 && cssStartsWithComment(value, index)) {
3492
+ const nextIndex = skipCssWhitespaceAndComments(value, index);
3493
+ if (hasSelectorBeforeWhitespace && nextIndex < value.length) return true;
3494
+ index = nextIndex;
3495
+ continue;
3496
+ } else if (bracketDepth === 0 && !/\\s/.test(char)) {
3497
+ hasSelectorBeforeWhitespace = true;
3498
+ }
3499
+ index += 1;
3500
+ }
3501
+ return false;
3502
+ }
3503
+
3504
+ function assertSafeSelector(selector, assetName) {
3505
+ if (!selector || unsafeSelectorPattern.test(selector) || hasUnsafeUniversalSelector(selector) || pseudoElementOnlySelectorPattern.test(selector)) {
3506
+ throw new Error('Unsafe selector "' + selector + '" in CSS asset "' + assetName + '" cannot be isolated safely.');
3507
+ }
3508
+ }
3509
+
3510
+ function hasUnsafeUniversalSelector(selector) {
3511
+ universalSelectorPattern.lastIndex = 0;
3512
+ let match;
3513
+ while ((match = universalSelectorPattern.exec(selector)) !== null) {
3514
+ const universalStart = match.index + match[1].length;
3515
+ if (!hasAnchoringSelectorBefore(selector.slice(0, universalStart))) return true;
3516
+ }
3517
+ return false;
3518
+ }
3519
+
3520
+ function hasAnchoringSelectorBefore(value) {
3521
+ return stripCssComments(value).replace(/[\\s>+~]+/g, "").length > 0;
3522
+ }
3523
+
3524
+ function namespaceKeyframesBlock(block, keyframeNames, fontFamilyNames, customPropertyNames, assetName) {
3525
+ let output = "";
3526
+ let index = 0;
3527
+ while (index < block.length) {
3528
+ if (cssStartsWithComment(block, index)) {
3529
+ const commentEnd = block.indexOf("*/", index + 2);
3530
+ const nextIndex = commentEnd === -1 ? block.length : commentEnd + 2;
3531
+ output += block.slice(index, nextIndex);
3532
+ index = nextIndex;
3533
+ continue;
3534
+ }
3535
+ if (/\\s/.test(block[index] ?? "")) {
3536
+ output += block[index];
3537
+ index += 1;
3538
+ continue;
3539
+ }
3540
+ const keyframeRule = readRulePrelude(block, index, block.length);
3541
+ if (keyframeRule.blockStart === -1) {
3542
+ output += block.slice(index, keyframeRule.end);
3543
+ index = keyframeRule.end;
3544
+ continue;
3545
+ }
3546
+ const keyframeBlockEnd = findMatchingBrace(block, keyframeRule.blockStart, block.length);
3547
+ if (keyframeBlockEnd === -1) {
3548
+ output += block.slice(index);
3549
+ index = block.length;
3550
+ continue;
3551
+ }
3552
+ output += keyframeRule.prelude + "{" + namespaceStyleBlock(block.slice(keyframeRule.blockStart + 1, keyframeBlockEnd), keyframeNames, fontFamilyNames, customPropertyNames, assetName) + "}";
3553
+ index = keyframeBlockEnd + 1;
3554
+ }
3555
+ return output;
3556
+ }
3557
+
3558
+ function namespaceStyleBlock(block, keyframeNames, fontFamilyNames, customPropertyNames, assetName) {
3559
+ assertNoNestedCssBlock(block, assetName);
3560
+ return rewriteDeclarationBlock(block, (propertyName, rawProperty, value) => {
3561
+ const nextProperty = namespaceCustomPropertyName(rawProperty, propertyName, customPropertyNames);
3562
+ let nextValue = value;
3563
+ if (propertyName === "animation" || propertyName === "-webkit-animation") {
3564
+ nextValue = namespaceAnimationShorthandValue(nextValue, keyframeNames);
3565
+ } else if (propertyName === "animation-name" || propertyName === "-webkit-animation-name") {
3566
+ nextValue = namespaceAnimationNameValue(nextValue, keyframeNames);
3567
+ } else if (propertyName === "font-family") {
3568
+ nextValue = namespaceFontFamilyValue(nextValue, fontFamilyNames);
3569
+ } else if (propertyName === "font") {
3570
+ nextValue = namespaceFontShorthandValue(nextValue, fontFamilyNames, assetName);
3571
+ }
3572
+ if (propertyName === "container-name") {
3573
+ nextValue = namespaceContainerNameValue(nextValue);
3574
+ } else if (propertyName === "container") {
3575
+ nextValue = namespaceContainerShorthandValue(nextValue);
3576
+ }
3577
+ if (propertyName === "transition" || propertyName === "transition-property" || propertyName === "will-change") {
3578
+ nextValue = namespaceCustomPropertyIdentifierValue(nextValue, customPropertyNames);
3579
+ }
3580
+ if (propertyName === "view-transition-name" || propertyName === "scroll-timeline-name" || propertyName === "animation-timeline") {
3581
+ nextValue = namespaceCssGlobalNameValue(nextValue);
3582
+ }
3583
+ nextValue = namespaceCustomPropertyReferencesValue(nextValue, customPropertyNames);
3584
+ return { property: nextProperty, value: nextValue };
3585
+ });
3586
+ }
3587
+
3588
+ function namespaceFontFaceBlock(block, fontFamilyNames, customPropertyNames) {
3589
+ return rewriteDeclarationBlock(block, (propertyName, rawProperty, value) => {
3590
+ const nextValue = propertyName === "font-family"
3591
+ ? namespaceFontFamilyValue(value, fontFamilyNames)
3592
+ : namespaceCustomPropertyReferencesValue(value, customPropertyNames);
3593
+ return { property: rawProperty, value: nextValue };
3594
+ });
3595
+ }
3596
+
3597
+ function namespaceAnimationNameValue(value, keyframeNames) {
3598
+ return replaceCssValueOutsideProtectedRanges(value, (chunk) => {
3599
+ let nextChunk = chunk;
3600
+ for (const [name, scopedName] of keyframeNames) {
3601
+ nextChunk = nextChunk.replace(new RegExp("(^|[^A-Za-z0-9_-])" + escapeRegExp(name) + "(?=$|[^A-Za-z0-9_-])", "g"), (_match, prefix) => prefix + scopedName);
3602
+ }
3603
+ return nextChunk;
3604
+ });
3605
+ }
3606
+
3607
+ function namespaceAnimationShorthandValue(value, keyframeNames) {
3608
+ if (keyframeNames.size === 0) return value;
3609
+ return splitCssCommaList(value).map((item) => rewriteAnimationShorthandItem(item, keyframeNames)).join(",");
3610
+ }
3611
+
3612
+ function rewriteAnimationShorthandItem(item, keyframeNames) {
3613
+ const tokens = readCssValueTokens(item);
3614
+ const reservedState = createAnimationShorthandReservedState();
3615
+ let output = "";
3616
+ let lastIndex = 0;
3617
+ for (const token of tokens) {
3618
+ const scopedName = keyframeNames.get(token.text);
3619
+ const isReservedToken = consumeAnimationShorthandReservedToken(token.text, reservedState);
3620
+ if (!scopedName || isReservedToken) continue;
3621
+ output += item.slice(lastIndex, token.start) + scopedName;
3622
+ lastIndex = token.end;
3623
+ }
3624
+ return output + item.slice(lastIndex);
3625
+ }
3626
+
3627
+ function createAnimationShorthandReservedState() {
3628
+ return {
3629
+ duration: false,
3630
+ delay: false,
3631
+ timingFunction: false,
3632
+ iterationCount: false,
3633
+ direction: false,
3634
+ fillMode: false,
3635
+ playState: false,
3636
+ };
3637
+ }
3638
+
3639
+ function consumeAnimationShorthandReservedToken(token, state) {
3640
+ const lower = token.toLowerCase();
3641
+ if (isAnimationTimeToken(token)) {
3642
+ if (!state.duration) {
3643
+ state.duration = true;
3644
+ return true;
3645
+ }
3646
+ if (!state.delay) {
3647
+ state.delay = true;
3648
+ return true;
3649
+ }
3650
+ return false;
3651
+ }
3652
+ if (!state.timingFunction && isAnimationTimingFunctionToken(lower)) {
3653
+ state.timingFunction = true;
3654
+ return true;
3655
+ }
3656
+ if (!state.iterationCount && isAnimationIterationCountToken(token, lower)) {
3657
+ state.iterationCount = true;
3658
+ return true;
3659
+ }
3660
+ if (!state.direction && animationDirectionKeywords.has(lower)) {
3661
+ state.direction = true;
3662
+ return true;
3663
+ }
3664
+ if (!state.fillMode && animationFillModeKeywords.has(lower)) {
3665
+ state.fillMode = true;
3666
+ return true;
3667
+ }
3668
+ if (!state.playState && animationPlayStateKeywords.has(lower)) {
3669
+ state.playState = true;
3670
+ return true;
3671
+ }
3672
+ if (animationGlobalKeywords.has(lower)) return true;
3673
+ return false;
3674
+ }
3675
+
3676
+ function isAnimationTimeToken(token) {
3677
+ return /^-?(?:\\d+|\\d*\\.\\d+)(?:ms|s)$/i.test(token);
3678
+ }
3679
+
3680
+ function isAnimationTimingFunctionToken(lowerToken) {
3681
+ return animationTimingFunctionKeywords.has(lowerToken) || lowerToken.includes("(");
3682
+ }
3683
+
3684
+ function isAnimationIterationCountToken(token, lowerToken) {
3685
+ return lowerToken === "infinite" || /^-?(?:\\d+|\\d*\\.\\d+)$/.test(token);
3686
+ }
3687
+
3688
+ const animationTimingFunctionKeywords = new Set([
3689
+ "ease",
3690
+ "ease-in",
3691
+ "ease-in-out",
3692
+ "ease-out",
3693
+ "linear",
3694
+ "step-end",
3695
+ "step-start",
3696
+ ]);
3697
+ const animationDirectionKeywords = new Set(["normal", "reverse", "alternate", "alternate-reverse"]);
3698
+ const animationFillModeKeywords = new Set(["none", "forwards", "backwards", "both"]);
3699
+ const animationPlayStateKeywords = new Set(["running", "paused"]);
3700
+ const animationGlobalKeywords = new Set(["inherit", "initial", "revert", "revert-layer", "unset"]);
3701
+
3702
+ function namespaceFontFamilyValue(value, fontFamilyNames) {
3703
+ if (fontFamilyNames.size === 0) return value;
3704
+ const important = splitCssImportantSuffix(value);
3705
+ return splitCssCommaList(important.value).map((family) => namespaceSingleFontFamily(family, fontFamilyNames)).join(",") + important.suffix;
3706
+ }
3707
+
3708
+ function namespaceFontShorthandValue(value, fontFamilyNames, assetName) {
3709
+ if (fontFamilyNames.size === 0) return value;
3710
+ const familyStart = findFontShorthandFamilyStart(value);
3711
+ if (familyStart === -1) {
3712
+ if (fontShorthandReferencesScopedFontFamily(value, fontFamilyNames)) {
3713
+ throw new Error('Unsupported font shorthand in CSS asset "' + assetName + '" cannot be isolated safely. Use font-family with font-style/font-weight/font-size longhands, or use a supported font shorthand with an explicit font-size before the family list.');
3714
+ }
3715
+ return value;
3716
+ }
3717
+ return value.slice(0, familyStart) + namespaceFontFamilyValue(value.slice(familyStart), fontFamilyNames);
3718
+ }
3719
+
3720
+ function fontShorthandReferencesScopedFontFamily(value, fontFamilyNames) {
3721
+ const tokens = readCssValueTokens(value);
3722
+ return tokens.some((token) => fontFamilyNames.has(normalizeFontFamilyName(token.text)));
3723
+ }
3724
+
3725
+ function splitCssImportantSuffix(value) {
3726
+ const match = /!\\s*important\\s*$/i.exec(value);
3727
+ if (!match) return { value, suffix: "" };
3728
+ return {
3729
+ value: value.slice(0, match.index),
3730
+ suffix: value.slice(match.index),
3731
+ };
3732
+ }
3733
+
3734
+ function namespaceSingleFontFamily(family, fontFamilyNames) {
3735
+ const leadingWhitespace = family.match(/^\\s*/)?.[0] ?? "";
3736
+ const trailingWhitespace = family.match(/\\s*$/)?.[0] ?? "";
3737
+ const trimmed = family.trim();
3738
+ const normalized = normalizeFontFamilyName(trimmed);
3739
+ const scopedName = fontFamilyNames.get(normalized);
3740
+ if (!scopedName) return family;
3741
+ const quote = trimmed[0] === '"' || trimmed[0] === "'" ? trimmed[0] : "";
3742
+ return leadingWhitespace + (quote ? quote + scopedName + quote : scopedName) + trailingWhitespace;
3743
+ }
3744
+
3745
+ function normalizeFontFamilyName(value) {
3746
+ const trimmed = value.trim();
3747
+ if ((trimmed.startsWith('"') && trimmed.endsWith('"')) || (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
3748
+ return trimmed.slice(1, -1);
3749
+ }
3750
+ return trimmed;
3751
+ }
3752
+
3753
+ function rewritePropertyHeader(header, customPropertyNames) {
3754
+ let nextHeader = header;
3755
+ for (const [name, scopedName] of customPropertyNames) {
3756
+ nextHeader = nextHeader.replace(new RegExp("(@property\\\\s+)" + escapeRegExp(name) + "(?=$|[\\\\s{])", "g"), (_match, prefix) => prefix + scopedName);
3757
+ }
3758
+ return nextHeader;
3759
+ }
3760
+
3761
+ function rewriteLayerPrelude(prelude) {
3762
+ const match = /^(@layer\\b)([\\s\\S]*)$/i.exec(prelude);
3763
+ if (!match) return prelude;
3764
+ const layerList = match[2] ?? "";
3765
+ if (!layerList.trim()) return prelude;
3766
+ return match[1] + splitCssCommaList(layerList).map(namespaceLayerName).join(",");
3767
+ }
3768
+
3769
+ function namespaceLayerName(layerName) {
3770
+ const leadingWhitespace = layerName.match(/^\\s*/)?.[0] ?? "";
3771
+ const trailingWhitespace = layerName.match(/\\s*$/)?.[0] ?? "";
3772
+ const trimmed = layerName.trim();
3773
+ return trimmed ? leadingWhitespace + widgetPackageLayerPrefix + trimmed + trailingWhitespace : layerName;
3774
+ }
3775
+
3776
+ function rewriteContainerAtRuleHeader(header) {
3777
+ if (!header.endsWith("{")) return header;
3778
+ return rewriteContainerAtRulePrelude(header.slice(0, -1)) + "{";
3779
+ }
3780
+
3781
+ function rewriteContainerAtRulePrelude(prelude) {
3782
+ const match = /^(@container\\b)([\\s\\S]*)$/i.exec(prelude);
3783
+ if (!match) return prelude;
3784
+ const condition = match[2] ?? "";
3785
+ const leadingWhitespace = condition.match(/^\\s*/)?.[0] ?? "";
3786
+ const conditionBody = condition.slice(leadingWhitespace.length);
3787
+ if (!conditionBody || conditionBody.startsWith("(") || /^(?:style|scroll-state)\\s*\\(/.test(conditionBody)) {
3788
+ return prelude;
3789
+ }
3790
+
3791
+ const tokens = readCssValueTokens(conditionBody);
3792
+ const nameToken = tokens[0];
3793
+ if (!nameToken || nameToken.start !== 0 || isContainerQueryConditionKeyword(nameToken.text) || isReservedContainerName(nameToken.text) || nameToken.text.includes("(")) {
3794
+ return prelude;
3795
+ }
3796
+ return match[1] + leadingWhitespace + namespaceContainerName(nameToken.text) + conditionBody.slice(nameToken.end);
3797
+ }
3798
+
3799
+ function namespaceContainerNameValue(value) {
3800
+ return replaceCssValueOutsideProtectedRanges(value, (chunk) => namespaceContainerNamesInChunk(chunk));
3801
+ }
3802
+
3803
+ function namespaceContainerShorthandValue(value) {
3804
+ const slashIndex = findTopLevelSlash(value);
3805
+ if (slashIndex !== -1) {
3806
+ return namespaceContainerNameValue(value.slice(0, slashIndex)) + value.slice(slashIndex);
3807
+ }
3808
+
3809
+ const trimmed = stripCssComments(value).trim().toLowerCase();
3810
+ if (isReservedContainerName(trimmed) || containerTypeKeywords.has(trimmed)) return value;
3811
+ return namespaceContainerNameValue(value);
3812
+ }
3813
+
3814
+ function namespaceContainerNamesInChunk(chunk) {
3815
+ return chunk.replace(/(^|[^A-Za-z0-9_-])([A-Za-z_][A-Za-z0-9_-]*|-[A-Za-z_][A-Za-z0-9_-]*)(?=$|[^A-Za-z0-9_-])/g, (_match, prefix, name) => {
3816
+ if (isReservedContainerName(name)) return prefix + name;
3817
+ return prefix + namespaceContainerName(name);
3818
+ });
3819
+ }
3820
+
3821
+ function namespaceContainerName(name) {
3822
+ return widgetPackageContainerPrefix + name;
3823
+ }
3824
+
3825
+ function isReservedContainerName(name) {
3826
+ return containerNameReservedKeywords.has(name.toLowerCase());
3827
+ }
3828
+
3829
+ function isContainerQueryConditionKeyword(name) {
3830
+ return containerQueryConditionKeywords.has(name.toLowerCase());
3831
+ }
3832
+
3833
+ const containerTypeKeywords = new Set(["normal", "size", "inline-size", "scroll-state"]);
3834
+ const containerQueryConditionKeywords = new Set(["not", "and", "or"]);
3835
+ const containerNameReservedKeywords = new Set(["none", "inherit", "initial", "revert", "revert-layer", "unset"]);
3836
+
3837
+ function namespaceCustomPropertyName(rawProperty, propertyName, customPropertyNames) {
3838
+ const scopedName = customPropertyNames.get(propertyName);
3839
+ if (!scopedName) return rawProperty;
3840
+ return rawProperty.replace(new RegExp(escapeRegExp(propertyName) + "(?=\\\\s*$)"), scopedName);
3841
+ }
3842
+
3843
+ function namespaceCustomPropertyReferences(block, customPropertyNames) {
3844
+ return rewriteDeclarationBlock(block, (propertyName, rawProperty, value) => ({
3845
+ property: rawProperty,
3846
+ value: namespaceCustomPropertyReferencesValue(value, customPropertyNames),
3847
+ }));
3848
+ }
3849
+
3850
+ function namespaceCustomPropertyReferencesValue(value, customPropertyNames) {
3851
+ if (customPropertyNames.size === 0) return value;
3852
+ return replaceCssValueOutsideProtectedRanges(value, (chunk) => {
3853
+ let nextChunk = chunk;
3854
+ for (const [name, scopedName] of customPropertyNames) {
3855
+ nextChunk = nextChunk.replace(new RegExp("(\\\\bvar\\\\(\\\\s*)" + escapeRegExp(name) + "(?=\\\\s*[,)])", "g"), (_match, prefix) => prefix + scopedName);
3856
+ }
3857
+ return nextChunk;
3858
+ });
3859
+ }
3860
+
3861
+ function namespaceCustomPropertyIdentifierValue(value, customPropertyNames) {
3862
+ if (customPropertyNames.size === 0) return value;
3863
+ return replaceCssValueOutsideProtectedRanges(value, (chunk) => {
3864
+ let nextChunk = chunk;
3865
+ for (const [name, scopedName] of customPropertyNames) {
3866
+ nextChunk = nextChunk.replace(new RegExp("(^|[^A-Za-z0-9_-])" + escapeRegExp(name) + "(?=$|[^A-Za-z0-9_-])", "g"), (_match, prefix) => prefix + scopedName);
3867
+ }
3868
+ return nextChunk;
3869
+ });
3870
+ }
3871
+
3872
+ function namespaceCssGlobalNameValue(value) {
3873
+ return replaceCssValueOutsideProtectedRanges(value, (chunk) => {
3874
+ return chunk.replace(/(^|[^A-Za-z0-9_-])(--[A-Za-z0-9_-]+|[A-Za-z_][A-Za-z0-9_-]*|-[A-Za-z_][A-Za-z0-9_-]*)(?=$|[^A-Za-z0-9_-])/g, (_match, prefix, name, offset, source) => {
3875
+ const nextChar = source[offset + prefix.length + name.length] ?? "";
3876
+ const beforeName = source.slice(0, offset + prefix.length);
3877
+ if (nextChar === "(" || /(?:^|[^A-Za-z0-9_-])var\\s*\\($/i.test(beforeName) || cssGlobalNameReservedKeywords.has(name.toLowerCase())) return prefix + name;
3878
+ return prefix + widgetPackageCssGlobalNamePrefix + name;
3879
+ });
3880
+ });
3881
+ }
3882
+
3883
+ const cssGlobalNameReservedKeywords = new Set(["auto", "none", "inherit", "initial", "revert", "revert-layer", "unset"]);
3884
+
3885
+ function assertNoNestedCssBlock(block, assetName) {
3886
+ let index = 0;
3887
+ let quote = "";
3888
+ let parenDepth = 0;
3889
+ while (index < block.length) {
3890
+ const char = block[index];
3891
+ if (quote) {
3892
+ if (char === "\\\\") index += 2;
3893
+ else {
3894
+ if (char === quote) quote = "";
3895
+ index += 1;
3896
+ }
3897
+ continue;
3898
+ }
3899
+ if (cssStartsWithComment(block, index)) {
3900
+ const commentEnd = block.indexOf("*/", index + 2);
3901
+ index = commentEnd === -1 ? block.length : commentEnd + 2;
3902
+ continue;
3903
+ }
3904
+ if (char === '"' || char === "'") {
3905
+ quote = char;
3906
+ index += 1;
3907
+ continue;
3908
+ }
3909
+ if (char === "(") parenDepth += 1;
3910
+ else if (char === ")") parenDepth = Math.max(0, parenDepth - 1);
3911
+ else if (char === "{" && parenDepth === 0) {
3912
+ throw new Error('Unsupported nested CSS rule in CSS asset "' + assetName + '" cannot be isolated safely. Compile nested CSS before building the widget package.');
3913
+ }
3914
+ index += 1;
3915
+ }
3916
+ }
3917
+
3918
+ function rewriteDeclarationBlock(block, rewriteDeclaration) {
3919
+ let output = "";
3920
+ let declarationStart = 0;
3921
+ let index = 0;
3922
+ let quote = "";
3923
+ let parenDepth = 0;
3924
+ while (index < block.length) {
3925
+ const char = block[index];
3926
+ if (quote) {
3927
+ if (char === "\\\\") index += 2;
3928
+ else {
3929
+ if (char === quote) quote = "";
3930
+ index += 1;
3931
+ }
3932
+ continue;
3933
+ }
3934
+ if (cssStartsWithComment(block, index)) {
3935
+ const commentEnd = block.indexOf("*/", index + 2);
3936
+ index = commentEnd === -1 ? block.length : commentEnd + 2;
3937
+ continue;
3938
+ }
3939
+ if (char === '"' || char === "'") {
3940
+ quote = char;
3941
+ index += 1;
3942
+ continue;
3943
+ }
3944
+ if (char === "(") parenDepth += 1;
3945
+ else if (char === ")") parenDepth = Math.max(0, parenDepth - 1);
3946
+ else if (char === ";" && parenDepth === 0) {
3947
+ output += rewriteDeclarationSegment(block.slice(declarationStart, index), rewriteDeclaration) + ";";
3948
+ declarationStart = index + 1;
3949
+ }
3950
+ index += 1;
3951
+ }
3952
+ return output + rewriteDeclarationSegment(block.slice(declarationStart), rewriteDeclaration);
3953
+ }
3954
+
3955
+ function rewriteDeclarationSegment(segment, rewriteDeclaration) {
3956
+ const colonIndex = findDeclarationColon(segment);
3957
+ if (colonIndex === -1) return segment;
3958
+ const rawProperty = segment.slice(0, colonIndex);
3959
+ const rawPropertyName = stripCssComments(rawProperty).trim();
3960
+ const propertyName = rawPropertyName.startsWith("--") ? rawPropertyName : rawPropertyName.toLowerCase();
3961
+ if (!propertyName) return segment;
3962
+ const rewritten = rewriteDeclaration(propertyName, rawProperty, segment.slice(colonIndex + 1));
3963
+ return rewritten.property + ":" + rewritten.value;
3964
+ }
3965
+
3966
+ function findDeclarationColon(segment) {
3967
+ let index = 0;
3968
+ let quote = "";
3969
+ let parenDepth = 0;
3970
+ while (index < segment.length) {
3971
+ const char = segment[index];
3972
+ if (quote) {
3973
+ if (char === "\\\\") index += 2;
3974
+ else {
3975
+ if (char === quote) quote = "";
3976
+ index += 1;
3977
+ }
3978
+ continue;
3979
+ }
3980
+ if (cssStartsWithComment(segment, index)) {
3981
+ const commentEnd = segment.indexOf("*/", index + 2);
3982
+ index = commentEnd === -1 ? segment.length : commentEnd + 2;
3983
+ continue;
3984
+ }
3985
+ if (char === '"' || char === "'") {
3986
+ quote = char;
3987
+ index += 1;
3988
+ continue;
3989
+ }
3990
+ if (char === "(") parenDepth += 1;
3991
+ else if (char === ")") parenDepth = Math.max(0, parenDepth - 1);
3992
+ else if (char === ":" && parenDepth === 0) return index;
3993
+ index += 1;
3994
+ }
3995
+ return -1;
3996
+ }
3997
+
3998
+ function replaceCssValueOutsideProtectedRanges(value, replaceChunk) {
3999
+ let output = "";
4000
+ let chunkStart = 0;
4001
+ let index = 0;
4002
+ while (index < value.length) {
4003
+ if (cssStartsWithComment(value, index)) {
4004
+ output += replaceChunk(value.slice(chunkStart, index));
4005
+ const commentEnd = value.indexOf("*/", index + 2);
4006
+ const nextIndex = commentEnd === -1 ? value.length : commentEnd + 2;
4007
+ output += value.slice(index, nextIndex);
4008
+ index = nextIndex;
4009
+ chunkStart = index;
4010
+ continue;
4011
+ }
4012
+ const char = value[index];
4013
+ if (char === '"' || char === "'") {
4014
+ output += replaceChunk(value.slice(chunkStart, index));
4015
+ const stringEnd = findCssStringEnd(value, index);
4016
+ output += value.slice(index, stringEnd);
4017
+ index = stringEnd;
4018
+ chunkStart = index;
4019
+ continue;
4020
+ }
4021
+ if (isCssUrlFunctionStart(value, index)) {
4022
+ output += replaceChunk(value.slice(chunkStart, index));
4023
+ const urlEnd = findCssFunctionEnd(value, value.indexOf("(", index));
4024
+ output += value.slice(index, urlEnd);
4025
+ index = urlEnd;
4026
+ chunkStart = index;
4027
+ continue;
4028
+ }
4029
+ index += 1;
4030
+ }
4031
+ return output + replaceChunk(value.slice(chunkStart));
4032
+ }
4033
+
4034
+ function findCssStringEnd(value, quoteIndex) {
4035
+ const quote = value[quoteIndex];
4036
+ let index = quoteIndex + 1;
4037
+ while (index < value.length) {
4038
+ const char = value[index];
4039
+ if (char === "\\\\") index += 2;
4040
+ else {
4041
+ index += 1;
4042
+ if (char === quote) return index;
4043
+ }
4044
+ }
4045
+ return value.length;
4046
+ }
4047
+
4048
+ function findCssFunctionEnd(value, openParenIndex) {
4049
+ let index = openParenIndex + 1;
4050
+ let depth = 1;
4051
+ let quote = "";
4052
+ while (index < value.length) {
4053
+ const char = value[index];
4054
+ if (quote) {
4055
+ if (char === "\\\\") index += 2;
4056
+ else {
4057
+ if (char === quote) quote = "";
4058
+ index += 1;
4059
+ }
4060
+ continue;
4061
+ }
4062
+ if (char === '"' || char === "'") {
4063
+ quote = char;
4064
+ index += 1;
4065
+ continue;
4066
+ }
4067
+ if (cssStartsWithComment(value, index)) {
4068
+ const commentEnd = value.indexOf("*/", index + 2);
4069
+ index = commentEnd === -1 ? value.length : commentEnd + 2;
4070
+ continue;
4071
+ }
4072
+ if (char === "(") depth += 1;
4073
+ else if (char === ")") {
4074
+ depth -= 1;
4075
+ if (depth === 0) return index + 1;
4076
+ }
4077
+ index += 1;
4078
+ }
4079
+ return value.length;
4080
+ }
4081
+
4082
+ function findFontShorthandFamilyStart(value) {
4083
+ const tokens = readCssValueTokens(value);
4084
+ for (let index = 0; index < tokens.length; index += 1) {
4085
+ const token = tokens[index];
4086
+ if (!token || !isFontSizeToken(token.text)) continue;
4087
+ if (findTopLevelSlash(token.text) !== -1) return token.end;
4088
+ const slashIndex = skipCssWhitespaceAndComments(value, token.end);
4089
+ if (value[slashIndex] !== "/") return token.end;
4090
+ const lineHeightStart = skipCssWhitespaceAndComments(value, slashIndex + 1);
4091
+ const lineHeightToken = tokens.find((candidate) => candidate.start >= lineHeightStart);
4092
+ return lineHeightToken ? lineHeightToken.end : token.end;
4093
+ }
4094
+ return -1;
4095
+ }
4096
+
4097
+ function readCssValueTokens(value) {
4098
+ const tokens = [];
4099
+ let index = 0;
4100
+ while (index < value.length) {
4101
+ if (/\\s/.test(value[index] ?? "")) {
4102
+ index += 1;
4103
+ continue;
4104
+ }
4105
+ if (cssStartsWithComment(value, index)) {
4106
+ const commentEnd = value.indexOf("*/", index + 2);
4107
+ index = commentEnd === -1 ? value.length : commentEnd + 2;
4108
+ continue;
4109
+ }
4110
+ const start = index;
4111
+ const char = value[index];
4112
+ if (char === '"' || char === "'") {
4113
+ index = findCssStringEnd(value, index);
4114
+ } else {
4115
+ let parenDepth = 0;
4116
+ while (index < value.length) {
4117
+ if (cssStartsWithComment(value, index)) {
4118
+ if (parenDepth === 0) break;
4119
+ const commentEnd = value.indexOf("*/", index + 2);
4120
+ index = commentEnd === -1 ? value.length : commentEnd + 2;
4121
+ continue;
4122
+ }
4123
+ const tokenChar = value[index];
4124
+ if ((tokenChar === '"' || tokenChar === "'") && parenDepth > 0) {
4125
+ index = findCssStringEnd(value, index);
4126
+ continue;
4127
+ }
4128
+ if (tokenChar === "(") parenDepth += 1;
4129
+ else if (tokenChar === ")") parenDepth = Math.max(0, parenDepth - 1);
4130
+ if (parenDepth === 0 && /\\s/.test(tokenChar ?? "")) break;
4131
+ index += 1;
4132
+ }
4133
+ }
4134
+ tokens.push({ start, end: index, text: value.slice(start, index) });
4135
+ }
4136
+ return tokens;
4137
+ }
4138
+
4139
+ function isFontSizeToken(token) {
4140
+ const slashIndex = findTopLevelSlash(token);
4141
+ const sizeToken = slashIndex === -1 ? token : token.slice(0, slashIndex);
4142
+ return /^(?:xx-small|x-small|small|medium|large|x-large|xx-large|xxx-large|smaller|larger|math|(?:\\d+|\\d*\\.\\d+)(?:px|em|rem|%|vh|vw|vmin|vmax|ch|ex|cap|ic|lh|rlh|cm|mm|q|in|pc|pt))$/i.test(sizeToken) || isFontSizeFunctionToken(sizeToken);
4143
+ }
4144
+
4145
+ function isFontSizeFunctionToken(token) {
4146
+ return /^(?:calc|clamp|min|max|var|env|abs|sign|round|mod|rem|sin|cos|tan|asin|acos|atan|atan2|pow|sqrt|hypot|log|exp)\\(/i.test(token);
4147
+ }
4148
+
4149
+ function findTopLevelSlash(value) {
4150
+ let index = 0;
4151
+ let quote = "";
4152
+ let parenDepth = 0;
4153
+ while (index < value.length) {
4154
+ const char = value[index];
4155
+ if (quote) {
4156
+ if (char === "\\\\") index += 2;
4157
+ else {
4158
+ if (char === quote) quote = "";
4159
+ index += 1;
4160
+ }
4161
+ continue;
4162
+ }
4163
+ if (char === '"' || char === "'") {
4164
+ quote = char;
4165
+ index += 1;
4166
+ continue;
4167
+ }
4168
+ if (char === "(") parenDepth += 1;
4169
+ else if (char === ")") parenDepth = Math.max(0, parenDepth - 1);
4170
+ else if (char === "/" && parenDepth === 0) return index;
4171
+ index += 1;
4172
+ }
4173
+ return -1;
4174
+ }
4175
+
4176
+ function skipCssWhitespaceAndComments(value, startIndex) {
4177
+ let index = startIndex;
4178
+ while (index < value.length) {
4179
+ if (/\\s/.test(value[index] ?? "")) {
4180
+ index += 1;
4181
+ continue;
4182
+ }
4183
+ if (cssStartsWithComment(value, index)) {
4184
+ const commentEnd = value.indexOf("*/", index + 2);
4185
+ index = commentEnd === -1 ? value.length : commentEnd + 2;
4186
+ continue;
4187
+ }
4188
+ return index;
4189
+ }
4190
+ return index;
4191
+ }
4192
+
4193
+ function cssStartsWithComment(value, index) {
4194
+ return value[index] === "/" && value[index + 1] === "*";
4195
+ }
4196
+
4197
+ function isCssUrlFunctionStart(value, index) {
4198
+ return /^url\\s*\\(/i.test(value.slice(index)) && !/[A-Za-z0-9_-]/.test(value[index - 1] ?? "");
4199
+ }
4200
+
4201
+ function stripCssComments(value) {
4202
+ return value.replace(/\\/\\*[\\s\\S]*?\\*\\//g, "");
4203
+ }
4204
+
4205
+ function splitCssCommaList(value) {
4206
+ const parts = [];
4207
+ let current = "";
4208
+ let quote = "";
4209
+ let parenDepth = 0;
4210
+ for (let index = 0; index < value.length; index += 1) {
4211
+ const char = value[index];
4212
+ if (quote) {
4213
+ current += char;
4214
+ if (char === "\\\\") {
4215
+ index += 1;
4216
+ current += value[index] ?? "";
4217
+ } else if (char === quote) quote = "";
4218
+ continue;
4219
+ }
4220
+ if (char === '"' || char === "'") {
4221
+ quote = char;
4222
+ current += char;
4223
+ continue;
4224
+ }
4225
+ if (char === "(") parenDepth += 1;
4226
+ else if (char === ")") parenDepth = Math.max(0, parenDepth - 1);
4227
+ if (char === "," && parenDepth === 0) {
4228
+ parts.push(current);
4229
+ current = "";
4230
+ } else current += char;
4231
+ }
4232
+ parts.push(current);
4233
+ return parts;
4234
+ }
4235
+
4236
+ function escapeRegExp(value) {
4237
+ return value.replace(/[.*+?^\${}()|[\\]\\\\]/g, "\\\\$&");
4238
+ }
4239
+
4240
+ function encodeCssIdentifier(value) {
4241
+ return Array.from(value, (char) => char.codePointAt(0)?.toString(16).padStart(2, "0") ?? "00").join("_");
4242
+ }
4243
+
3030
4244
  return {
3031
4245
  ${configFileSource} publicDir: false,
3032
4246
  resolve: {
3033
- conditions: ["fluid-widget-authoring"],
4247
+ conditions: [
4248
+ "fluid-widget-authoring",
4249
+ "module",
4250
+ "browser",
4251
+ "development|production",
4252
+ ],
3034
4253
  },
3035
- plugins: [fluidWidgetBuildInvariantsPlugin()],
4254
+ plugins: [fluidWidgetBuildInvariantsPlugin(), fluidWidgetCssIsolationPlugin()],
3036
4255
  build: createFluidWidgetBuildInvariants(),
3037
4256
  };
3038
4257
  })()`;