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

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