sheetom 0.1.1 → 0.2.1

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.js CHANGED
@@ -4,9 +4,9 @@ import { fileURLToPath } from "node:url";
4
4
  //#endregion
5
5
  //#region src/internal/engine-binding.ts
6
6
  const expectedEngineAbiIdentity = Object.freeze({
7
- abiVersion: 4,
8
- sheetomVersion: "0.1.1",
9
- syntaxEngineSetSha256: "a0f10d0c1f0fe9e5bac9002e8ee548e7b5f6e2c7add1af3d953ae718d25cb37b"
7
+ abiVersion: 5,
8
+ sheetomVersion: "0.2.1",
9
+ syntaxEngineSetSha256: "e53060705956d09b629c87a9779a63ab07c35fae1111cb333866ba9c05dea86b"
10
10
  });
11
11
  var SheetOMEngineBindingError = class extends Error {
12
12
  code;
@@ -356,8 +356,8 @@ function isNativeRuleDescription(value) {
356
356
  }
357
357
  //#endregion
358
358
  //#region src/internal/native-rule-syntax.ts
359
- function normalizeNativeSelector(source, resourceBudget = defaultResourceBudget) {
360
- return callNative(() => engineBinding.normalizeSelector(source, ...nativeBudgetArguments(resourceBudget)));
359
+ function normalizeNativeSelector(source, resourceBudget = defaultResourceBudget, namespaces = "") {
360
+ return callNative(() => engineBinding.normalizeSelector(source, namespaces, ...nativeBudgetArguments(resourceBudget)));
361
361
  }
362
362
  function normalizeNativeMedia(source, resourceBudget = defaultResourceBudget) {
363
363
  return callNative(() => engineBinding.normalizeMedia(source, ...nativeBudgetArguments(resourceBudget)));
@@ -396,6 +396,9 @@ function callNative(operation) {
396
396
  return null;
397
397
  }
398
398
  }
399
+ function supportsNativeCss(source, value) {
400
+ return engineBinding.supportsCss(source, value);
401
+ }
399
402
  //#endregion
400
403
  //#region src/internal/rule-tree.ts
401
404
  /** Owns child-list identity and parent propagation for every live rule node. */
@@ -575,6 +578,39 @@ function assertInternalConstructor(name) {
575
578
  }
576
579
  //#endregion
577
580
  //#region src/index.ts
581
+ /** CSS authoring utilities, without installing or replacing the global CSS namespace. */
582
+ const CSS = {
583
+ /** Serialize a DOMString as a CSS identifier, including lone UTF-16 surrogates. */
584
+ escape(value) {
585
+ requireArguments(arguments.length, 1, "CSS", "escape");
586
+ const input = `${value}`;
587
+ let output = "";
588
+ for (let index = 0; index < input.length; index += 1) {
589
+ const code = input.charCodeAt(index);
590
+ const character = input[index];
591
+ if (code === 0) output += "�";
592
+ else if (code <= 31 || code === 127 || code >= 48 && code <= 57 && (index === 0 || index === 1 && input[0] === "-")) output += `\\${code.toString(16)} `;
593
+ else if (input === "-") output += "\\-";
594
+ else if (code >= 128 || /[a-zA-Z0-9_-]/u.test(character)) output += character;
595
+ else output += `\\${character}`;
596
+ }
597
+ return output;
598
+ },
599
+ /** Test a declaration or supports condition against the pinned authoring capabilities. */
600
+ supports(propertyOrCondition, value) {
601
+ requireArguments(arguments.length, 1, "CSS", "supports");
602
+ try {
603
+ return arguments.length > 1 ? supportsNativeCss(`${propertyOrCondition}`, `${value}`) : supportsNativeCss(`${propertyOrCondition}`);
604
+ } catch (error) {
605
+ rethrowResourceBudgetError(error);
606
+ throw error;
607
+ }
608
+ }
609
+ };
610
+ Object.defineProperty(CSS, Symbol.toStringTag, {
611
+ value: "CSS",
612
+ configurable: true
613
+ });
578
614
  const arrayIndexPattern = /^(0|[1-9]\d*)$/;
579
615
  const regularSheetMetadata = /* @__PURE__ */ new WeakMap();
580
616
  const ruleParentage = /* @__PURE__ */ new WeakMap();
@@ -582,7 +618,19 @@ const ruleResourceBudgets = /* @__PURE__ */ new WeakMap();
582
618
  const sheetResourceBudgets = /* @__PURE__ */ new WeakMap();
583
619
  const sheetRuleArrays = /* @__PURE__ */ new WeakMap();
584
620
  const sheetRuleCounts = /* @__PURE__ */ new WeakMap();
621
+ const sheetNamespaces = /* @__PURE__ */ new WeakMap();
622
+ function namespaceText(sheet) {
623
+ if (!sheet) return "";
624
+ return sheetNamespaces.get(sheet) ?? "";
625
+ }
626
+ function namespaceRulesText(rules) {
627
+ return rules.filter((rule) => rule instanceof CSSNamespaceRule).map((rule) => rule.cssText).join("");
628
+ }
629
+ function permitsNamespaceMutation(rules) {
630
+ return rules.every((rule) => rule instanceof CSSNamespaceRule || rule instanceof CSSImportRule);
631
+ }
585
632
  const functionRuleHeaders = /* @__PURE__ */ new WeakMap();
633
+ const mixinRuleHeaders = /* @__PURE__ */ new WeakMap();
586
634
  const unsignedLongRange = 2 ** 32;
587
635
  const pageMarginRuleNames = /* @__PURE__ */ new Set([
588
636
  "top-left-corner",
@@ -635,8 +683,8 @@ function namedPropertyToCSS(property) {
635
683
  if (/^(webkit|moz|ms|o)-/.test(cssName)) cssName = `-${cssName}`;
636
684
  return cssName;
637
685
  }
638
- function normalizeSelectorText(value, resourceBudget = defaultResourceBudget) {
639
- return normalizeNativeSelector(value, resourceBudget);
686
+ function normalizeSelectorText(value, resourceBudget = defaultResourceBudget, namespaces = "") {
687
+ return normalizeNativeSelector(value, resourceBudget, namespaces);
640
688
  }
641
689
  function toUnsignedLong(value) {
642
690
  const number = Number(value);
@@ -1028,6 +1076,112 @@ var CSSFunctionRule = class extends CSSGroupingRule {
1028
1076
  }
1029
1077
  set cssText(_value) {}
1030
1078
  };
1079
+ /** Experimental revision-pinned native CSS mixin definition. */
1080
+ var CSSMixinRule = class extends CSSGroupingRule {
1081
+ name;
1082
+ contents = true;
1083
+ #parameters;
1084
+ constructor(name, parameters) {
1085
+ super(0);
1086
+ this.name = serializeNativeIdentifier(name);
1087
+ this.#parameters = parameters.map((parameter) => ({ ...parameter }));
1088
+ const header = serializeFunctionHeader(name, parameters, "*").replace(/^@function /u, "@mixin ");
1089
+ mixinRuleHeaders.set(this, parameters.length === 0 ? header.slice(0, -2) : header);
1090
+ lockOwnProperties(this, "name", "contents");
1091
+ }
1092
+ getParameters() {
1093
+ return this.#parameters.map((parameter) => ({ ...parameter }));
1094
+ }
1095
+ get cssText() {
1096
+ return serializeMixinCssText(this);
1097
+ }
1098
+ set cssText(_value) {}
1099
+ };
1100
+ /** Experimental native CSS mixin application with a contents block. */
1101
+ var CSSApplyBlockRule = class extends CSSGroupingRule {
1102
+ name;
1103
+ #arguments;
1104
+ constructor(name, args, header) {
1105
+ super(0);
1106
+ this.name = serializeNativeIdentifier(name);
1107
+ this.#arguments = [...args];
1108
+ mixinRuleHeaders.set(this, header);
1109
+ lockOwnProperties(this, "name");
1110
+ }
1111
+ getArguments() {
1112
+ return [...this.#arguments];
1113
+ }
1114
+ get cssText() {
1115
+ return serializeMixinCssText(this);
1116
+ }
1117
+ set cssText(_value) {}
1118
+ };
1119
+ /** Experimental native CSS mixin application without a contents block. */
1120
+ var CSSApplyStatementRule = class extends CSSRule {
1121
+ name;
1122
+ #arguments;
1123
+ #header;
1124
+ constructor(name, args, header) {
1125
+ super(0);
1126
+ this.name = serializeNativeIdentifier(name);
1127
+ this.#arguments = [...args];
1128
+ this.#header = header;
1129
+ lockOwnProperties(this, "name");
1130
+ }
1131
+ getArguments() {
1132
+ return [...this.#arguments];
1133
+ }
1134
+ get cssText() {
1135
+ return `${this.#header};`;
1136
+ }
1137
+ set cssText(_value) {}
1138
+ };
1139
+ /** Experimental native CSS mixin contents placeholder with a fallback block. */
1140
+ var CSSContentsBlockRule = class extends CSSGroupingRule {
1141
+ constructor() {
1142
+ super(0);
1143
+ mixinRuleHeaders.set(this, "@contents");
1144
+ }
1145
+ get cssText() {
1146
+ return serializeMixinCssText(this);
1147
+ }
1148
+ set cssText(_value) {}
1149
+ };
1150
+ /** Experimental native CSS mixin contents placeholder without a fallback. */
1151
+ var CSSContentsStatementRule = class extends CSSRule {
1152
+ constructor() {
1153
+ super(0);
1154
+ }
1155
+ get cssText() {
1156
+ return "@contents;";
1157
+ }
1158
+ set cssText(_value) {}
1159
+ };
1160
+ function serializeMixinCssText(root) {
1161
+ const chunks = [];
1162
+ const pending = [root];
1163
+ while (pending.length > 0) {
1164
+ const item = pending.pop();
1165
+ if (typeof item === "string") {
1166
+ chunks.push(item);
1167
+ continue;
1168
+ }
1169
+ if (!(item instanceof CSSGroupingRule)) {
1170
+ chunks.push(item.cssText);
1171
+ continue;
1172
+ }
1173
+ const header = groupingRuleHeader(item);
1174
+ chunks.push(header, item instanceof CSSMixinRule ? "{ " : " { ");
1175
+ pending.push(" }");
1176
+ const children = ruleTree.children(item);
1177
+ for (let index = children.length - 1; index >= 0; index -= 1) {
1178
+ pending.push(children[index]);
1179
+ if (index > 0) pending.push(" ");
1180
+ }
1181
+ if (item instanceof CSSStyleRule && item.style.cssText !== "") pending.push(children.length ? `${item.style.cssText} ` : item.style.cssText);
1182
+ }
1183
+ return chunks.join("");
1184
+ }
1031
1185
  function serializeFunctionHeader(name, parameters, returnType) {
1032
1186
  const serializedParameters = parameters.map((parameter) => {
1033
1187
  const type = serializeFunctionType(parameter.type);
@@ -1290,7 +1444,7 @@ var CSSStyleDeclaration = class {
1290
1444
  };
1291
1445
  (ruleDiagnostics.get(this.parentRule) ?? ignoreDiagnostic)(diagnostic);
1292
1446
  };
1293
- this.#block = new NativeDeclarationBlock(reportDeclarationDiagnostic, reportSerializationDiagnostic, parentRule instanceof CSSFontFaceRule ? "font-face" : parentRule instanceof CSSFunctionDeclarations ? "function" : "style", ruleResourceBudgets.get(parentRule) ?? defaultResourceBudget, () => declarationSerializationDepth(parentRule), initialCssText);
1447
+ this.#block = new NativeDeclarationBlock(reportDeclarationDiagnostic, reportSerializationDiagnostic, parentRule instanceof CSSFontFaceRule ? "font-face" : parentRule instanceof CSSPositionTryRule ? "position-try" : parentRule instanceof CSSFunctionDeclarations ? "function" : "style", ruleResourceBudgets.get(parentRule) ?? defaultResourceBudget, () => declarationSerializationDepth(parentRule), initialCssText);
1294
1448
  return new Proxy(this, {
1295
1449
  get(target, property) {
1296
1450
  if (typeof property === "string" && arrayIndexPattern.test(property)) return target.item(Number(property)) || void 0;
@@ -1467,15 +1621,76 @@ var CSSPageRule = class extends CSSGroupingRule {
1467
1621
  }
1468
1622
  set cssText(_value) {}
1469
1623
  };
1470
- /** A live `@position-try` declaration rule. */
1624
+ /** The allowed descriptors of an anchor positioning fallback rule. */
1625
+ var CSSPositionTryDescriptors = class extends CSSStyleDeclaration {};
1626
+ for (const name of [
1627
+ "margin",
1628
+ "margin-top",
1629
+ "margin-right",
1630
+ "margin-bottom",
1631
+ "margin-left",
1632
+ "margin-block",
1633
+ "margin-block-start",
1634
+ "margin-block-end",
1635
+ "margin-inline",
1636
+ "margin-inline-start",
1637
+ "margin-inline-end",
1638
+ "inset",
1639
+ "top",
1640
+ "right",
1641
+ "bottom",
1642
+ "left",
1643
+ "inset-block",
1644
+ "inset-block-start",
1645
+ "inset-block-end",
1646
+ "inset-inline",
1647
+ "inset-inline-start",
1648
+ "inset-inline-end",
1649
+ "width",
1650
+ "min-width",
1651
+ "max-width",
1652
+ "height",
1653
+ "min-height",
1654
+ "max-height",
1655
+ "block-size",
1656
+ "min-block-size",
1657
+ "max-block-size",
1658
+ "inline-size",
1659
+ "min-inline-size",
1660
+ "max-inline-size",
1661
+ "place-self",
1662
+ "align-self",
1663
+ "justify-self",
1664
+ "position-anchor",
1665
+ "position-area"
1666
+ ]) {
1667
+ const camelCase = name.replace(/-([a-z])/gu, (_match, letter) => letter.toUpperCase());
1668
+ for (const accessor of /* @__PURE__ */ new Set([name, camelCase])) Object.defineProperty(CSSPositionTryDescriptors.prototype, accessor, {
1669
+ configurable: true,
1670
+ enumerable: true,
1671
+ get() {
1672
+ return this.getPropertyValue(name);
1673
+ },
1674
+ set(value) {
1675
+ this.setProperty(name, value);
1676
+ }
1677
+ });
1678
+ }
1679
+ /** A named anchor positioning fallback rule. */
1471
1680
  var CSSPositionTryRule = class extends CSSRule {
1472
1681
  name;
1473
- style;
1682
+ #style;
1474
1683
  constructor(name, initialCssText) {
1475
1684
  super(0);
1476
1685
  this.name = name;
1477
- this.style = constructWebIDL(CSSStyleDeclaration, [this, initialCssText]);
1478
- lockOwnProperties(this, "name", "style");
1686
+ this.#style = constructWebIDL(CSSPositionTryDescriptors, [this, initialCssText]);
1687
+ lockOwnProperties(this, "name");
1688
+ }
1689
+ get style() {
1690
+ return this.#style;
1691
+ }
1692
+ set style(cssText) {
1693
+ this.#style.cssText = `${cssText}`;
1479
1694
  }
1480
1695
  get cssText() {
1481
1696
  return `@position-try ${this.name} {${this.style.cssText === "" ? "" : ` ${this.style.cssText}`} }`;
@@ -1822,6 +2037,9 @@ var CSSFontFeatureValuesRule = class extends CSSRule {
1822
2037
  var CSSStyleRule = class extends CSSGroupingRule {
1823
2038
  style;
1824
2039
  #selectorText;
2040
+ #namespaces() {
2041
+ return namespaceText(this.parentStyleSheet);
2042
+ }
1825
2043
  constructor(selectorText, normalized, initialCssText) {
1826
2044
  super(CSSRule.STYLE_RULE);
1827
2045
  this.#selectorText = normalized === normalizedSelectorText ? selectorText : normalizeSelectorText(`${selectorText}`, currentConstructionResourceBudget()) ?? `${selectorText}`;
@@ -1832,7 +2050,7 @@ var CSSStyleRule = class extends CSSGroupingRule {
1832
2050
  return this.#selectorText;
1833
2051
  }
1834
2052
  set selectorText(value) {
1835
- const normalized = normalizeSelectorText(`${value}`, ruleResourceBudgets.get(this) ?? defaultResourceBudget);
2053
+ const normalized = normalizeSelectorText(`${value}`, ruleResourceBudgets.get(this) ?? defaultResourceBudget, this.#namespaces());
1836
2054
  if (normalized === null) return;
1837
2055
  this.#selectorText = normalized;
1838
2056
  }
@@ -1888,17 +2106,24 @@ function describeRuleSafe(rule, strict) {
1888
2106
  declarations: rule.style.serializeSafe(" ", strict),
1889
2107
  children: ruleTree.children(rule)
1890
2108
  };
2109
+ if (rule instanceof CSSApplyStatementRule && rule.getArguments().length === 1 && rule.getArguments()[0] === "") return {
2110
+ kind: "raw",
2111
+ cssText: `@apply ${rule.name}({ });`
2112
+ };
1891
2113
  if (!(rule instanceof CSSGroupingRule)) return {
1892
2114
  kind: "raw",
1893
2115
  cssText: rule.cssText
1894
2116
  };
1895
2117
  return {
1896
2118
  kind: "block",
1897
- header: groupingRuleHeader(rule),
2119
+ header: rule instanceof CSSApplyBlockRule && rule.getArguments().length === 1 && rule.getArguments()[0] === "" ? `@apply ${rule.name}({ })` : groupingRuleHeader(rule),
1898
2120
  children: ruleTree.children(rule)
1899
2121
  };
1900
2122
  }
1901
2123
  function groupingRuleHeader(rule) {
2124
+ const mixinHeader = mixinRuleHeaders.get(rule);
2125
+ if (mixinHeader !== void 0) return mixinHeader;
2126
+ if (rule instanceof CSSStyleRule) return rule.selectorText;
1902
2127
  if (rule instanceof CSSFunctionRule) return functionRuleHeaders.get(rule) ?? "@function";
1903
2128
  if (rule instanceof CSSMediaRule) return `@media ${rule.media.mediaText}`;
1904
2129
  if (rule instanceof CSSSupportsRule) return `@supports ${rule.conditionText}`;
@@ -1950,12 +2175,13 @@ function parseImportPrelude(prelude) {
1950
2175
  supports
1951
2176
  };
1952
2177
  }
1953
- function createRuleFromNative(description, reportDiagnostic, preserveImports, resourceBudget) {
1954
- return constructWithResourceBudget(() => createRuleTreeFromNative(description, reportDiagnostic, preserveImports, resourceBudget), resourceBudget);
2178
+ function createRuleFromNative(description, reportDiagnostic, preserveImports, resourceBudget, parentRule = null) {
2179
+ return constructWithResourceBudget(() => createRuleTreeFromNative(description, reportDiagnostic, preserveImports, resourceBudget, parentRule), resourceBudget);
1955
2180
  }
1956
- function createRuleTreeFromNative(description, reportDiagnostic, preserveImports, resourceBudget) {
2181
+ function createRuleTreeFromNative(description, reportDiagnostic, preserveImports, resourceBudget, parentRule) {
1957
2182
  const root = createRuleShellFromNative(description, reportDiagnostic, preserveImports, resourceBudget);
1958
2183
  if (!root) return null;
2184
+ attachRuleTree(root, parentRule, parentRule?.parentStyleSheet ?? null);
1959
2185
  const pending = [{
1960
2186
  description,
1961
2187
  rule: root
@@ -1967,9 +2193,10 @@ function createRuleTreeFromNative(description, reportDiagnostic, preserveImports
1967
2193
  const childFrames = [];
1968
2194
  for (const childDescription of current.description.children) {
1969
2195
  if (isNativeMetadataRule(childDescription)) continue;
2196
+ if (!isMixinContextAllowed(childDescription.kind, current.rule)) continue;
1970
2197
  const child = createRuleShellFromNative(childDescription, reportDiagnostic, preserveImports, resourceBudget);
1971
2198
  if (!child) continue;
1972
- if (child instanceof CSSFunctionDeclarations && child.style.length === 0) continue;
2199
+ if ((child instanceof CSSFunctionDeclarations || child instanceof CSSNestedDeclarations) && child.style.length === 0) continue;
1973
2200
  if (current.rule instanceof CSSKeyframesRule && !(child instanceof CSSKeyframeRule)) continue;
1974
2201
  children.push(child);
1975
2202
  childFrames.push({
@@ -1987,7 +2214,7 @@ function createRuleTreeFromNative(description, reportDiagnostic, preserveImports
1987
2214
  return root;
1988
2215
  }
1989
2216
  function isNativeMetadataRule(description) {
1990
- return description.kind === "function-parameter" || description.kind === "property-descriptor" || description.kind === "view-transition-type" || description.kind === "layer-name";
2217
+ return description.kind === "function-parameter" || description.kind === "mixin-argument" || description.kind === "property-descriptor" || description.kind === "view-transition-type" || description.kind === "layer-name";
1991
2218
  }
1992
2219
  function createRuleShellFromNative(description, reportDiagnostic, preserveImports, resourceBudget) {
1993
2220
  let rule;
@@ -2075,7 +2302,8 @@ function createRuleShellFromNative(description, reportDiagnostic, preserveImport
2075
2302
  description.children.filter((candidate) => candidate.kind === "view-transition-type").map((candidate) => candidate.prelude),
2076
2303
  description.cssText
2077
2304
  ]);
2078
- case "function": {
2305
+ case "function":
2306
+ case "mixin": {
2079
2307
  const parameters = description.children.filter((candidate) => candidate.kind === "function-parameter").map((candidate) => {
2080
2308
  const defaultValue = candidate.children.find((child) => child.kind === "property-descriptor" && child.prelude === "default-value");
2081
2309
  return defaultValue ? {
@@ -2087,13 +2315,35 @@ function createRuleShellFromNative(description, reportDiagnostic, preserveImport
2087
2315
  type: candidate.declarations
2088
2316
  };
2089
2317
  });
2090
- rule = constructWebIDL(CSSFunctionRule, [
2318
+ rule = description.kind === "mixin" ? constructWebIDL(CSSMixinRule, [description.prelude, parameters]) : constructWebIDL(CSSFunctionRule, [
2091
2319
  description.prelude,
2092
2320
  parameters,
2093
2321
  description.declarations
2094
2322
  ]);
2095
2323
  break;
2096
2324
  }
2325
+ case "apply-block":
2326
+ case "apply-statement": {
2327
+ const arguments_ = description.children.filter((child) => child.kind === "mixin-argument");
2328
+ const args = arguments_.map((argument) => argument.declarations);
2329
+ const header = `@apply ${serializeNativeIdentifier(description.prelude)}${args.length ? `(${arguments_.map((argument) => argument.cssText).join(", ")})` : ""}`;
2330
+ rule = description.kind === "apply-block" ? constructWebIDL(CSSApplyBlockRule, [
2331
+ description.prelude,
2332
+ args,
2333
+ header
2334
+ ]) : constructWebIDL(CSSApplyStatementRule, [
2335
+ description.prelude,
2336
+ args,
2337
+ header
2338
+ ]);
2339
+ break;
2340
+ }
2341
+ case "contents-block":
2342
+ rule = constructWebIDL(CSSContentsBlockRule);
2343
+ break;
2344
+ case "contents-statement":
2345
+ rule = constructWebIDL(CSSContentsStatementRule);
2346
+ break;
2097
2347
  case "namespace": return constructWebIDL(CSSNamespaceRule, [
2098
2348
  nativeRuleDescriptor(description, "namespace-uri"),
2099
2349
  nativeRuleDescriptor(description, "prefix"),
@@ -2131,7 +2381,7 @@ function nativeRuleDescriptor(description, name) {
2131
2381
  function hydrateCounterStyleDescriptors(rule, declarations, resourceBudget) {
2132
2382
  for (const descriptor of parseNativeCounterStyleDescriptors(declarations, resourceBudget)) rule.setParsedDescriptor(descriptor.name, descriptor.value);
2133
2383
  }
2134
- function parseStrictRule(ruleText, reportDiagnostic, preserveImports = false, parentRule = null, resourceBudget = defaultResourceBudget) {
2384
+ function parseStrictRule(ruleText, reportDiagnostic, preserveImports = false, parentRule = null, resourceBudget = defaultResourceBudget, namespaces = namespaceText(parentRule?.parentStyleSheet ?? null)) {
2135
2385
  if (parentRule instanceof CSSPageRule) {
2136
2386
  const page = parseNativeRule(`@page { ${ruleText} }`, resourceBudget);
2137
2387
  if (page?.kind !== "page" || page.children.length !== 1) return null;
@@ -2141,7 +2391,41 @@ function parseStrictRule(ruleText, reportDiagnostic, preserveImports = false, pa
2141
2391
  }
2142
2392
  const description = parseNativeRule(ruleText, resourceBudget) ?? (parentRule && hasFunctionAncestor(parentRule) ? parseNativeRuleWithErrorRecovery(ruleText, resourceBudget) : null);
2143
2393
  if (!description || description.kind === "import" && !preserveImports) return null;
2144
- return createRuleFromNative(description, reportDiagnostic, preserveImports, resourceBudget);
2394
+ if (!isMixinContextAllowed(description.kind, parentRule)) return null;
2395
+ const validSelector = (rule) => {
2396
+ if (rule.kind !== "style" || !rule.prelude.includes("|")) return true;
2397
+ const normalized = normalizeNativeSelector(rule.prelude, resourceBudget, namespaces);
2398
+ if (normalized === null) return false;
2399
+ rule.prelude = normalized;
2400
+ return true;
2401
+ };
2402
+ if (!validSelector(description)) return null;
2403
+ const pending = [description];
2404
+ while (pending.length) {
2405
+ const current = pending.pop();
2406
+ current.children = current.children.filter(validSelector);
2407
+ for (const child of current.children) pending.push(child);
2408
+ }
2409
+ return createRuleFromNative(description, reportDiagnostic, preserveImports, resourceBudget, parentRule);
2410
+ }
2411
+ function isMixinContextAllowed(kind, parent) {
2412
+ if (![
2413
+ "mixin",
2414
+ "apply-block",
2415
+ "apply-statement",
2416
+ "contents-block",
2417
+ "contents-statement",
2418
+ "private"
2419
+ ].includes(kind)) return true;
2420
+ let nested = false;
2421
+ let mixin = false;
2422
+ for (let current = parent; current; current = current.parentRule) {
2423
+ if (current instanceof CSSFunctionRule) return false;
2424
+ if (current instanceof CSSStyleRule || current instanceof CSSMixinRule) nested = true;
2425
+ if (current instanceof CSSMixinRule) mixin = true;
2426
+ }
2427
+ if (kind === "mixin") return !nested;
2428
+ return kind.startsWith("contents-") ? mixin : nested;
2145
2429
  }
2146
2430
  function hasFunctionAncestor(rule) {
2147
2431
  let current = rule;
@@ -2165,11 +2449,17 @@ function genericRuleType(name) {
2165
2449
  }
2166
2450
  }
2167
2451
  function parseStyleSheetRules(cssText, reportDiagnostic, preserveImports, resourceBudget) {
2452
+ let namespaces = "";
2453
+ let namespaceRulesAllowed = true;
2168
2454
  const rules = [];
2169
2455
  let parsedRuleCount = 0;
2170
2456
  for (const rawRule of scanTopLevelRules(cssText, resourceBudget)) {
2171
- const rule = parseStrictRule(rawRule, reportDiagnostic, preserveImports, null, resourceBudget);
2457
+ const rule = parseStrictRule(rawRule, reportDiagnostic, preserveImports, null, resourceBudget, namespaces);
2172
2458
  if (rule) {
2459
+ if (rule instanceof CSSNamespaceRule) {
2460
+ if (!namespaceRulesAllowed) continue;
2461
+ namespaces += rule.cssText;
2462
+ } else if (!(rule instanceof CSSImportRule)) namespaceRulesAllowed = false;
2173
2463
  parsedRuleCount += ruleForestSize([rule]);
2174
2464
  assertRuleCountBudget(parsedRuleCount, resourceBudget);
2175
2465
  rules.push(rule);
@@ -2181,38 +2471,50 @@ function parseStyleSheetRules(cssText, reportDiagnostic, preserveImports, resour
2181
2471
  assertRuleCountBudget(parsedRuleCount, resourceBudget);
2182
2472
  rules.push(opaque);
2183
2473
  }
2184
- return rules;
2474
+ return {
2475
+ rules,
2476
+ namespaces
2477
+ };
2185
2478
  }
2186
- /** A mutable, browser-shaped authoring stylesheet. */
2187
- var CSSStyleSheet = class {
2188
- cssRules;
2479
+ const stylesheetConstructionKey = Symbol("StyleSheet construction");
2480
+ /** Shared stylesheet metadata. Instances are created through CSSStyleSheet. */
2481
+ var StyleSheet = class {
2189
2482
  media;
2190
2483
  ownerNode = null;
2191
2484
  parentStyleSheet = null;
2192
- ownerRule = null;
2193
2485
  title = null;
2194
2486
  type = "text/css";
2195
2487
  disabled;
2488
+ constructor(options = {}, resourceBudget = defaultResourceBudget, key) {
2489
+ if (key !== stylesheetConstructionKey) throw new TypeError("Illegal constructor");
2490
+ const media = options.media === void 0 ? "" : `${options.media}`;
2491
+ this.media = constructWithResourceBudget(() => constructWebIDL(MediaList, [media]), resourceBudget);
2492
+ this.disabled = Boolean(options.disabled);
2493
+ }
2494
+ get href() {
2495
+ return regularSheetMetadata.get(this)?.href ?? null;
2496
+ }
2497
+ };
2498
+ /** A mutable, browser-shaped authoring stylesheet. */
2499
+ var CSSStyleSheet = class extends StyleSheet {
2500
+ cssRules;
2501
+ ownerRule = null;
2196
2502
  #rules = [];
2197
2503
  #diagnostics;
2198
2504
  #constructedBaseURL;
2199
2505
  constructor(options = {}) {
2200
2506
  const normalizedOptions = options ?? {};
2201
2507
  const resourceBudget = normalizeResourceBudget(normalizedOptions.resourceBudget);
2508
+ super(normalizedOptions, resourceBudget, stylesheetConstructionKey);
2202
2509
  sheetResourceBudgets.set(this, resourceBudget);
2203
2510
  sheetRuleArrays.set(this, this.#rules);
2204
2511
  sheetRuleCounts.set(this, 0);
2512
+ sheetNamespaces.set(this, "");
2205
2513
  this.#diagnostics = Boolean(normalizedOptions.diagnostics) ? [] : null;
2206
2514
  this.#constructedBaseURL = normalizedOptions.baseURL === void 0 ? "about:blank" : `${normalizedOptions.baseURL}`;
2207
- const media = normalizedOptions.media === void 0 ? "" : `${normalizedOptions.media}`;
2208
- this.media = constructWithResourceBudget(() => constructWebIDL(MediaList, [media]), resourceBudget);
2209
- this.disabled = Boolean(normalizedOptions.disabled);
2210
2515
  this.cssRules = constructInternally(() => constructWebIDL(CSSRuleList, [this.#rules]));
2211
2516
  lockOwnProperties(this, "cssRules", "media", "ownerNode", "parentStyleSheet", "ownerRule", "title", "type");
2212
2517
  }
2213
- get href() {
2214
- return regularSheetMetadata.get(this)?.href ?? null;
2215
- }
2216
2518
  get baseURL() {
2217
2519
  return regularSheetMetadata.get(this)?.baseURL ?? this.#constructedBaseURL;
2218
2520
  }
@@ -2225,14 +2527,16 @@ var CSSStyleSheet = class {
2225
2527
  if (normalizedIndex > this.#rules.length) throw new DOMException("The index is outside the allowed range.", "IndexSizeError");
2226
2528
  const regular = regularSheetMetadata.has(this);
2227
2529
  const resourceBudget = sheetResourceBudgets.get(this) ?? defaultResourceBudget;
2228
- const rule = parseStrictRule(`${ruleText}`, this.#reportDiagnostic, regular, null, resourceBudget);
2530
+ const rule = parseStrictRule(`${ruleText}`, this.#reportDiagnostic, regular, null, resourceBudget, namespaceText(this));
2229
2531
  if (!rule) throw new DOMException("The rule could not be parsed.", "SyntaxError");
2532
+ if (rule instanceof CSSNamespaceRule && !permitsNamespaceMutation(this.#rules)) throw new DOMException("Namespace rules cannot change after other rules exist.", "InvalidStateError");
2230
2533
  const precedingRules = this.#rules.slice(0, normalizedIndex);
2231
2534
  const followingRules = this.#rules.slice(normalizedIndex);
2232
2535
  if (rule instanceof CSSImportRule ? precedingRules.some((candidate) => !(candidate instanceof CSSImportRule)) : followingRules.some((candidate) => candidate instanceof CSSImportRule)) throw new DOMException("The rule violates stylesheet ordering.", "HierarchyRequestError");
2233
2536
  const insertedCount = assertRuleInsertionBudget(this, rule, resourceBudget);
2234
2537
  attachRuleTree(rule, null, this);
2235
2538
  this.#rules.splice(normalizedIndex, 0, rule);
2539
+ if (rule instanceof CSSNamespaceRule) sheetNamespaces.set(this, namespaceRulesText(this.#rules));
2236
2540
  adjustSheetRuleCount(this, insertedCount);
2237
2541
  return normalizedIndex;
2238
2542
  }
@@ -2240,15 +2544,18 @@ var CSSStyleSheet = class {
2240
2544
  requireArguments(arguments.length, 1, "CSSStyleSheet", "deleteRule");
2241
2545
  const normalizedIndex = toUnsignedLong(index);
2242
2546
  if (normalizedIndex >= this.#rules.length) throw new DOMException("The index is outside the allowed range.", "IndexSizeError");
2547
+ if (this.#rules[normalizedIndex] instanceof CSSNamespaceRule && !permitsNamespaceMutation(this.#rules)) throw new DOMException("Namespace rules cannot change while other rules exist.", "InvalidStateError");
2243
2548
  const [removed] = this.#rules.splice(normalizedIndex, 1);
2244
2549
  if (!removed) return;
2550
+ if (removed instanceof CSSNamespaceRule) sheetNamespaces.set(this, namespaceRulesText(this.#rules));
2245
2551
  adjustSheetRuleCount(this, -ruleForestSize([removed]));
2246
2552
  attachRuleTree(removed, null, null);
2247
2553
  }
2248
2554
  replaceSync(cssText) {
2249
2555
  requireArguments(arguments.length, 1, "CSSStyleSheet", "replaceSync");
2250
- const replacement = parseStyleSheetRules(`${cssText}`, this.#reportDiagnostic, regularSheetMetadata.has(this), sheetResourceBudgets.get(this) ?? defaultResourceBudget);
2556
+ const { rules: replacement, namespaces } = parseStyleSheetRules(`${cssText}`, this.#reportDiagnostic, regularSheetMetadata.has(this), sheetResourceBudgets.get(this) ?? defaultResourceBudget);
2251
2557
  for (const rule of this.#rules) attachRuleTree(rule, null, null);
2558
+ sheetNamespaces.set(this, namespaces);
2252
2559
  for (const rule of replacement) attachRuleTree(rule, null, this);
2253
2560
  this.#rules.splice(0, this.#rules.length, ...replacement);
2254
2561
  sheetRuleCounts.set(this, ruleForestSize(replacement));
@@ -2284,6 +2591,6 @@ function parseStyleSheet(cssText, options = {}) {
2284
2591
  return sheet;
2285
2592
  }
2286
2593
  //#endregion
2287
- export { CSSConditionRule, CSSContainerRule, CSSCounterStyleRule, CSSFontFaceRule, CSSFontFeatureValuesMap, CSSFontFeatureValuesRule, CSSFontPaletteValuesRule, CSSFunctionDeclarations, CSSFunctionDescriptors, CSSFunctionRule, CSSGroupingRule, CSSImportRule, CSSKeyframeRule, CSSKeyframesRule, CSSLayerBlockRule, CSSLayerStatementRule, CSSMarginRule, CSSMediaRule, CSSNamespaceRule, CSSNestedDeclarations, CSSPageRule, CSSPositionTryRule, CSSPropertyRule, CSSRule, CSSRuleList, CSSScopeRule, CSSStartingStyleRule, CSSStyleDeclaration, CSSStyleRule, CSSStyleSheet, CSSSupportsRule, CSSViewTransitionRule, MediaList, SheetOMSerializationError, parseStyleSheet };
2594
+ export { CSS, CSSApplyBlockRule, CSSApplyStatementRule, CSSConditionRule, CSSContainerRule, CSSContentsBlockRule, CSSContentsStatementRule, CSSCounterStyleRule, CSSFontFaceRule, CSSFontFeatureValuesMap, CSSFontFeatureValuesRule, CSSFontPaletteValuesRule, CSSFunctionDeclarations, CSSFunctionDescriptors, CSSFunctionRule, CSSGroupingRule, CSSImportRule, CSSKeyframeRule, CSSKeyframesRule, CSSLayerBlockRule, CSSLayerStatementRule, CSSMarginRule, CSSMediaRule, CSSMixinRule, CSSNamespaceRule, CSSNestedDeclarations, CSSPageRule, CSSPositionTryDescriptors, CSSPositionTryRule, CSSPropertyRule, CSSRule, CSSRuleList, CSSScopeRule, CSSStartingStyleRule, CSSStyleDeclaration, CSSStyleRule, CSSStyleSheet, CSSSupportsRule, CSSViewTransitionRule, MediaList, SheetOMSerializationError, StyleSheet, parseStyleSheet };
2288
2595
 
2289
2596
  //# sourceMappingURL=index.js.map