@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 +1211 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -2527,18 +2527,10 @@ function validateCssUrl(value, cssUrlPath, errors) {
|
|
|
2527
2527
|
});
|
|
2528
2528
|
return;
|
|
2529
2529
|
}
|
|
2530
|
-
if (!
|
|
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
|
|
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
|
-
|
|
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}]
|
|
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
|
-
|
|
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
|
|
2639
|
-
|
|
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(
|
|
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
|
})()`;
|