sheetom 0.1.0-rc.9 → 0.1.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/README.md +32 -0
- package/dist/index.cjs +260 -98
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -13
- package/dist/index.d.ts +60 -13
- package/dist/index.js +260 -99
- package/dist/index.js.map +1 -1
- package/docs/api.md +42 -6
- package/engine-abi.json +3 -3
- package/package.json +19 -19
package/README.md
CHANGED
|
@@ -64,6 +64,31 @@ Constructed sheets strip `@import` during replacement. `parseStyleSheet()` is a
|
|
|
64
64
|
SheetOM extension for existing regular stylesheets and preserves valid imports
|
|
65
65
|
without fetching them.
|
|
66
66
|
|
|
67
|
+
Compilers can apply all known mutations for one rule with one engine crossing
|
|
68
|
+
and still receive one acceptance result per operation:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
function applyCompilerDeclarations(rule: CSSStyleRule, dynamicWidth: string) {
|
|
72
|
+
const results = rule.style.applyMutations([
|
|
73
|
+
{ kind: "set", property: "display", value: "grid" },
|
|
74
|
+
{ kind: "set", property: "width", value: dynamicWidth },
|
|
75
|
+
{ kind: "remove", property: "margin-left" },
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
for (const result of results) {
|
|
79
|
+
if (result.kind === "set" && !result.accepted) {
|
|
80
|
+
console.warn(result.diagnostic);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Operations run in order through the same validation and shorthand/longhand
|
|
87
|
+
state machine as individual calls. Group one batch per declaration block;
|
|
88
|
+
never combine values into declaration text. Batch results already include
|
|
89
|
+
rejection diagnostics, so high-volume callers can leave the sheet diagnostic
|
|
90
|
+
queue disabled unless they also need diagnostics from other APIs.
|
|
91
|
+
|
|
67
92
|
## Browser recovery, safe output
|
|
68
93
|
|
|
69
94
|
Browsers accept some CSS using end-of-input recovery and expose the incomplete
|
|
@@ -94,6 +119,13 @@ sheet.serialize();
|
|
|
94
119
|
| `style.cssText` | Browser-compatible declaration text, including measured recovery quirks. |
|
|
95
120
|
| `rule.cssText` | Browser-compatible text for the current rule. |
|
|
96
121
|
| `sheet.serialize()` | Deterministic, reparsable CSS for a complete stylesheet. |
|
|
122
|
+
| `sheet.serializeStrict()` | Exact-only output that rejects CSSOM states CSS text cannot represent faithfully. |
|
|
123
|
+
|
|
124
|
+
Pending-substitution shorthands survive later longhand edits in reparsable
|
|
125
|
+
output. If an imperative priority combination cannot be represented exactly,
|
|
126
|
+
`serialize()` emits a local best-effort result and an opt-in structured
|
|
127
|
+
diagnostic rather than blocking the whole stylesheet. Use `serializeStrict()`
|
|
128
|
+
when approximation is unacceptable.
|
|
97
129
|
|
|
98
130
|
Invalid property values and priorities are atomic no-ops: the previous state
|
|
99
131
|
survives unchanged. Static shorthands are stored as canonical longhands, so
|
package/dist/index.cjs
CHANGED
|
@@ -28,9 +28,9 @@ let node_url = require("node:url");
|
|
|
28
28
|
//#endregion
|
|
29
29
|
//#region src/internal/engine-binding.ts
|
|
30
30
|
const expectedEngineAbiIdentity = Object.freeze({
|
|
31
|
-
abiVersion:
|
|
32
|
-
sheetomVersion: "0.1.
|
|
33
|
-
syntaxEngineSetSha256: "
|
|
31
|
+
abiVersion: 4,
|
|
32
|
+
sheetomVersion: "0.1.1",
|
|
33
|
+
syntaxEngineSetSha256: "a0f10d0c1f0fe9e5bac9002e8ee548e7b5f6e2c7add1af3d953ae718d25cb37b"
|
|
34
34
|
});
|
|
35
35
|
var SheetOMEngineBindingError = class extends Error {
|
|
36
36
|
code;
|
|
@@ -65,7 +65,7 @@ function loadBinding() {
|
|
|
65
65
|
validateEngineBindingIdentity(addon);
|
|
66
66
|
return {
|
|
67
67
|
...addon,
|
|
68
|
-
createDeclarationState: (context, ...
|
|
68
|
+
createDeclarationState: (context, ...arguments_) => new addon.NativeDeclarationState(context, ...arguments_)
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
71
|
//#endregion
|
|
@@ -114,18 +114,54 @@ function limitValue(value, name, fallback, maximum = maximumUnsignedLong) {
|
|
|
114
114
|
throw new RangeError(`${name} must be an integer between 0 and ${maximum}`);
|
|
115
115
|
}
|
|
116
116
|
//#endregion
|
|
117
|
+
//#region src/serialization-error.ts
|
|
118
|
+
/** A reparsable stylesheet cannot faithfully represent the current CSSOM state. */
|
|
119
|
+
var SheetOMSerializationError = class extends Error {
|
|
120
|
+
code;
|
|
121
|
+
shorthand;
|
|
122
|
+
conflictingLonghands;
|
|
123
|
+
constructor(shorthand, conflictingLonghands, options) {
|
|
124
|
+
super(`SheetOM cannot serialize the pending ${shorthand} shorthand without changing its semantics.`, options);
|
|
125
|
+
this.name = "SheetOMSerializationError";
|
|
126
|
+
this.code = "UNREPRESENTABLE_PENDING_SHORTHAND";
|
|
127
|
+
this.shorthand = shorthand;
|
|
128
|
+
this.conflictingLonghands = Object.freeze([...conflictingLonghands]);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
const unrepresentablePendingShorthandPattern = /^SHEETOM_UNREPRESENTABLE_PENDING_SHORTHAND: shorthand=([^;]+); conflicting=([a-z0-9,-]+)$/u;
|
|
132
|
+
function serializationErrorFrom(error) {
|
|
133
|
+
if (!(error instanceof Error)) return null;
|
|
134
|
+
const match = unrepresentablePendingShorthandPattern.exec(error.message);
|
|
135
|
+
if (!match) return null;
|
|
136
|
+
const shorthand = match[1];
|
|
137
|
+
const conflicts = match[2];
|
|
138
|
+
if (!shorthand || !conflicts) return null;
|
|
139
|
+
return new SheetOMSerializationError(shorthand, conflicts.split(","), { cause: error });
|
|
140
|
+
}
|
|
141
|
+
function rethrowSerializationError(error) {
|
|
142
|
+
const serializationError = serializationErrorFrom(error);
|
|
143
|
+
if (serializationError) throw serializationError;
|
|
144
|
+
}
|
|
145
|
+
//#endregion
|
|
117
146
|
//#region src/internal/native-declaration-block.ts
|
|
118
147
|
/** Thin JS ownership boundary around the Rust declaration state machine. */
|
|
119
148
|
var NativeDeclarationBlock = class {
|
|
120
149
|
#state;
|
|
121
150
|
#reportDiagnostic;
|
|
151
|
+
#reportSerializationDiagnostic;
|
|
122
152
|
#reservedNestingDepth;
|
|
123
153
|
#observableCache;
|
|
124
154
|
#serializationCache = /* @__PURE__ */ new Map();
|
|
125
|
-
constructor(reportDiagnostic, context = "style", resourceBudget = defaultResourceBudget, reservedNestingDepth = () => 0) {
|
|
155
|
+
constructor(reportDiagnostic, reportSerializationDiagnostic, context = "style", resourceBudget = defaultResourceBudget, reservedNestingDepth = () => 0, initialCssText) {
|
|
126
156
|
this.#reportDiagnostic = reportDiagnostic;
|
|
157
|
+
this.#reportSerializationDiagnostic = reportSerializationDiagnostic;
|
|
127
158
|
this.#reservedNestingDepth = reservedNestingDepth;
|
|
128
|
-
|
|
159
|
+
try {
|
|
160
|
+
this.#state = engineBinding.createDeclarationState(context, ...nativeBudgetArguments(resourceBudget), initialCssText);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
rethrowResourceBudgetError(error);
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
129
165
|
}
|
|
130
166
|
get cssText() {
|
|
131
167
|
this.#observableCache ??= this.#state.cssText;
|
|
@@ -155,9 +191,59 @@ var NativeDeclarationBlock = class {
|
|
|
155
191
|
this.#invalidateSerialization();
|
|
156
192
|
return;
|
|
157
193
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
194
|
+
this.#diagnosticForOutcome(outcome, name, value, priority);
|
|
195
|
+
}
|
|
196
|
+
applyMutations(mutations) {
|
|
197
|
+
const kinds = [];
|
|
198
|
+
const properties = [];
|
|
199
|
+
const values = [];
|
|
200
|
+
const priorities = [];
|
|
201
|
+
for (const mutation of mutations) {
|
|
202
|
+
kinds.push(mutation.kind === "set" ? 0 : 1);
|
|
203
|
+
properties.push(mutation.property);
|
|
204
|
+
values.push(mutation.kind === "set" ? mutation.value : "");
|
|
205
|
+
priorities.push(mutation.kind === "set" ? mutation.priority : "");
|
|
206
|
+
}
|
|
207
|
+
let outcomes;
|
|
208
|
+
try {
|
|
209
|
+
outcomes = this.#state.applyMutations(kinds, properties, values, priorities, this.#reservedNestingDepth());
|
|
210
|
+
} catch (error) {
|
|
211
|
+
rethrowResourceBudgetError(error);
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
214
|
+
if (outcomes.length !== mutations.length) throw new Error("SheetOM engine returned an incomplete declaration mutation result.");
|
|
215
|
+
const results = [];
|
|
216
|
+
let mutated = false;
|
|
217
|
+
for (let index = 0; index < outcomes.length; index += 1) {
|
|
218
|
+
const mutation = mutations[index];
|
|
219
|
+
const outcome = outcomes[index];
|
|
220
|
+
if (!mutation || outcome === void 0) throw new Error("SheetOM engine returned a mismatched declaration mutation result.");
|
|
221
|
+
if (mutation.kind === "remove") {
|
|
222
|
+
mutated = true;
|
|
223
|
+
results.push({
|
|
224
|
+
kind: "remove",
|
|
225
|
+
value: outcome
|
|
226
|
+
});
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (outcome === "applied") {
|
|
230
|
+
mutated = true;
|
|
231
|
+
results.push({
|
|
232
|
+
kind: "set",
|
|
233
|
+
accepted: true,
|
|
234
|
+
diagnostic: null
|
|
235
|
+
});
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
if (!isEngineMutationOutcome(outcome)) throw new Error("SheetOM engine returned an invalid declaration mutation outcome.");
|
|
239
|
+
results.push({
|
|
240
|
+
kind: "set",
|
|
241
|
+
accepted: false,
|
|
242
|
+
diagnostic: this.#diagnosticForOutcome(outcome, mutation.property, mutation.value, mutation.priority)
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
if (mutated) this.#invalidateSerialization();
|
|
246
|
+
return results;
|
|
161
247
|
}
|
|
162
248
|
removeProperty(name) {
|
|
163
249
|
const removed = this.#state.removeProperty(name);
|
|
@@ -173,19 +259,63 @@ var NativeDeclarationBlock = class {
|
|
|
173
259
|
}
|
|
174
260
|
this.#invalidateSerialization();
|
|
175
261
|
}
|
|
176
|
-
serialize(safe, indent, separator) {
|
|
177
|
-
const cacheKey = `${safe ? "1" : "0"}\0${indent}\0${separator}`;
|
|
262
|
+
serialize(safe, indent, separator, strict = false) {
|
|
263
|
+
const cacheKey = `${safe ? "1" : "0"}${strict ? "1" : "0"}\0${indent}\0${separator}`;
|
|
178
264
|
const cached = this.#serializationCache.get(cacheKey);
|
|
179
|
-
if (cached !== void 0)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
265
|
+
if (cached !== void 0) {
|
|
266
|
+
if (typeof cached === "string") return cached;
|
|
267
|
+
this.#reportSerializationIssues(cached.issues);
|
|
268
|
+
return cached.serialized;
|
|
269
|
+
}
|
|
270
|
+
let result;
|
|
271
|
+
try {
|
|
272
|
+
if (strict) result = this.#state.serializeFormatted(safe, indent, separator);
|
|
273
|
+
else result = parseResilientSerializationResult(this.#state.serializeFormattedResilient(safe, indent, separator));
|
|
274
|
+
} catch (error) {
|
|
275
|
+
rethrowResourceBudgetError(error);
|
|
276
|
+
rethrowSerializationError(error);
|
|
277
|
+
throw error;
|
|
278
|
+
}
|
|
279
|
+
this.#serializationCache.set(cacheKey, result);
|
|
280
|
+
if (typeof result === "string") return result;
|
|
281
|
+
this.#reportSerializationIssues(result.issues);
|
|
282
|
+
return result.serialized;
|
|
183
283
|
}
|
|
184
284
|
#invalidateSerialization() {
|
|
185
285
|
this.#observableCache = void 0;
|
|
186
286
|
this.#serializationCache.clear();
|
|
187
287
|
}
|
|
288
|
+
#diagnosticForOutcome(outcome, name, value, priority) {
|
|
289
|
+
const normalizedName = name.startsWith("--") ? name : name.toLowerCase();
|
|
290
|
+
const [code, input] = outcome === "invalid-priority" ? ["INVALID_PRIORITY", priority] : outcome === "unsupported-shorthand" ? ["UNSUPPORTED_SHORTHAND_VALUE", value] : ["INVALID_PROPERTY_VALUE", value];
|
|
291
|
+
return this.#reportDiagnostic(code, normalizedName, input);
|
|
292
|
+
}
|
|
293
|
+
#reportSerializationIssues(issues) {
|
|
294
|
+
for (const issue of issues) this.#reportSerializationDiagnostic(issue.shorthand, issue.conflictingLonghands);
|
|
295
|
+
}
|
|
188
296
|
};
|
|
297
|
+
function parseResilientSerializationResult(output) {
|
|
298
|
+
const serialized = output[0];
|
|
299
|
+
if (serialized === void 0 || output.length % 2 === 0) throw new Error("SheetOM engine returned an invalid resilient serialization result.");
|
|
300
|
+
if (output.length === 1) return serialized;
|
|
301
|
+
const issues = [];
|
|
302
|
+
for (let index = 1; index < output.length; index += 2) {
|
|
303
|
+
const shorthand = output[index];
|
|
304
|
+
const conflicts = output[index + 1];
|
|
305
|
+
if (!shorthand || !conflicts) throw new Error("SheetOM engine returned an incomplete resilient serialization issue.");
|
|
306
|
+
issues.push({
|
|
307
|
+
shorthand,
|
|
308
|
+
conflictingLonghands: Object.freeze(conflicts.split(","))
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
return {
|
|
312
|
+
serialized,
|
|
313
|
+
issues
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function isEngineMutationOutcome(value) {
|
|
317
|
+
return value === "invalid-name" || value === "invalid-priority" || value === "invalid-value" || value === "unsupported-shorthand";
|
|
318
|
+
}
|
|
189
319
|
function toUnsignedLong$1(value) {
|
|
190
320
|
const numeric = Number(value);
|
|
191
321
|
if (!Number.isFinite(numeric) || numeric === 0) return 0;
|
|
@@ -377,13 +507,20 @@ var Serializer = class {
|
|
|
377
507
|
this.#describe = describe;
|
|
378
508
|
}
|
|
379
509
|
serialize(node) {
|
|
510
|
+
return this.serializeMany([node]);
|
|
511
|
+
}
|
|
512
|
+
serializeMany(nodes) {
|
|
380
513
|
const chunks = [];
|
|
381
|
-
const pending = [
|
|
382
|
-
|
|
383
|
-
node
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
514
|
+
const pending = [];
|
|
515
|
+
for (let index = nodes.length - 1; index >= 0; index -= 1) {
|
|
516
|
+
const node = nodes[index];
|
|
517
|
+
if (node) pending.push({
|
|
518
|
+
kind: "node",
|
|
519
|
+
node,
|
|
520
|
+
depth: 0,
|
|
521
|
+
child: false
|
|
522
|
+
});
|
|
523
|
+
}
|
|
387
524
|
while (pending.length > 0) {
|
|
388
525
|
const frame = pending.pop();
|
|
389
526
|
if (!frame) continue;
|
|
@@ -490,6 +627,7 @@ const pageMarginRuleNames = /* @__PURE__ */ new Set([
|
|
|
490
627
|
"left-top"
|
|
491
628
|
]);
|
|
492
629
|
const ignoreDiagnostic = () => {};
|
|
630
|
+
const normalizedSelectorText = Symbol("normalizedSelectorText");
|
|
493
631
|
const ruleDiagnostics = /* @__PURE__ */ new WeakMap();
|
|
494
632
|
const ruleTree = new RuleTree((rule, parentRule, parentStyleSheet) => {
|
|
495
633
|
ruleParentage.set(rule, {
|
|
@@ -497,7 +635,8 @@ const ruleTree = new RuleTree((rule, parentRule, parentStyleSheet) => {
|
|
|
497
635
|
parentStyleSheet
|
|
498
636
|
});
|
|
499
637
|
}, (rule) => rule.parentStyleSheet);
|
|
500
|
-
const safeSerializer = new Serializer(describeRuleSafe);
|
|
638
|
+
const safeSerializer = new Serializer((rule) => describeRuleSafe(rule, false));
|
|
639
|
+
const strictSerializer = new Serializer((rule) => describeRuleSafe(rule, true));
|
|
501
640
|
let activeConstructionResourceBudget = defaultResourceBudget;
|
|
502
641
|
function constructWithResourceBudget(factory, resourceBudget) {
|
|
503
642
|
const previous = activeConstructionResourceBudget;
|
|
@@ -1145,24 +1284,37 @@ var CSSViewTransitionRule = class extends CSSRule {
|
|
|
1145
1284
|
var CSSStyleDeclaration = class {
|
|
1146
1285
|
parentRule;
|
|
1147
1286
|
#block;
|
|
1148
|
-
constructor(parentRule) {
|
|
1287
|
+
constructor(parentRule, initialCssText) {
|
|
1149
1288
|
assertInternalConstructor("CSSStyleDeclaration");
|
|
1150
1289
|
this.parentRule = parentRule;
|
|
1151
1290
|
lockOwnProperties(this, "parentRule");
|
|
1152
1291
|
const reportDeclarationDiagnostic = (code, property, input) => {
|
|
1153
|
-
const
|
|
1154
|
-
const unsupportedShorthand = code === "UNSUPPORTED_SHORTHAND_VALUE";
|
|
1155
|
-
(ruleDiagnostics.get(this.parentRule) ?? ignoreDiagnostic)({
|
|
1292
|
+
const diagnostic = {
|
|
1156
1293
|
code,
|
|
1157
1294
|
severity: "warning",
|
|
1158
1295
|
operation: "setProperty",
|
|
1159
|
-
message:
|
|
1296
|
+
message: code === "INVALID_PRIORITY" ? `The mutation was ignored because ${input} is not a valid priority.` : code === "UNSUPPORTED_SHORTHAND_VALUE" ? `The value was ignored because the shorthand codec for ${property} cannot expand it.` : `The value was ignored because it is invalid for ${property}.`,
|
|
1160
1297
|
property,
|
|
1161
1298
|
input,
|
|
1162
1299
|
location: null
|
|
1163
|
-
}
|
|
1300
|
+
};
|
|
1301
|
+
(ruleDiagnostics.get(this.parentRule) ?? ignoreDiagnostic)(diagnostic);
|
|
1302
|
+
return diagnostic;
|
|
1303
|
+
};
|
|
1304
|
+
const reportSerializationDiagnostic = (shorthand, conflictingLonghands) => {
|
|
1305
|
+
const diagnostic = {
|
|
1306
|
+
code: "UNREPRESENTABLE_PENDING_SHORTHAND",
|
|
1307
|
+
severity: "warning",
|
|
1308
|
+
operation: "serialize",
|
|
1309
|
+
message: `The pending ${shorthand} shorthand required a best-effort recovery during serialization.`,
|
|
1310
|
+
property: shorthand,
|
|
1311
|
+
input: "",
|
|
1312
|
+
location: null,
|
|
1313
|
+
conflictingLonghands: Object.freeze([...conflictingLonghands])
|
|
1314
|
+
};
|
|
1315
|
+
(ruleDiagnostics.get(this.parentRule) ?? ignoreDiagnostic)(diagnostic);
|
|
1164
1316
|
};
|
|
1165
|
-
this.#block = new NativeDeclarationBlock(reportDeclarationDiagnostic, parentRule instanceof CSSFontFaceRule ? "font-face" : parentRule instanceof CSSFunctionDeclarations ? "function" : "style", ruleResourceBudgets.get(parentRule) ?? defaultResourceBudget, () => declarationSerializationDepth(parentRule));
|
|
1317
|
+
this.#block = new NativeDeclarationBlock(reportDeclarationDiagnostic, reportSerializationDiagnostic, parentRule instanceof CSSFontFaceRule ? "font-face" : parentRule instanceof CSSFunctionDeclarations ? "function" : "style", ruleResourceBudgets.get(parentRule) ?? defaultResourceBudget, () => declarationSerializationDepth(parentRule), initialCssText);
|
|
1166
1318
|
return new Proxy(this, {
|
|
1167
1319
|
get(target, property) {
|
|
1168
1320
|
if (typeof property === "string" && arrayIndexPattern.test(property)) return target.item(Number(property)) || void 0;
|
|
@@ -1207,21 +1359,49 @@ var CSSStyleDeclaration = class {
|
|
|
1207
1359
|
const stringPriority = priority === null ? "" : `${priority}`;
|
|
1208
1360
|
this.#block.setProperty(stringName, stringValue, stringPriority);
|
|
1209
1361
|
}
|
|
1362
|
+
/** Apply ordered declaration mutations through one engine boundary crossing. */
|
|
1363
|
+
applyMutations(mutations) {
|
|
1364
|
+
requireArguments(arguments.length, 1, "CSSStyleDeclaration", "applyMutations");
|
|
1365
|
+
if (!Array.isArray(mutations)) throw new TypeError("CSSStyleDeclaration.applyMutations requires an array.");
|
|
1366
|
+
const normalized = [];
|
|
1367
|
+
for (let index = 0; index < mutations.length; index += 1) {
|
|
1368
|
+
const mutation = mutations[index];
|
|
1369
|
+
if (typeof mutation !== "object" || mutation === null) throw new TypeError(`Declaration mutation at index ${index} must be an object.`);
|
|
1370
|
+
if (mutation.kind !== "set" && mutation.kind !== "remove") throw new TypeError(`Declaration mutation at index ${index} has an invalid kind.`);
|
|
1371
|
+
if (typeof mutation.property !== "string") throw new TypeError(`Declaration mutation at index ${index} requires a string property.`);
|
|
1372
|
+
if (mutation.kind === "remove") {
|
|
1373
|
+
normalized.push({
|
|
1374
|
+
kind: "remove",
|
|
1375
|
+
property: mutation.property
|
|
1376
|
+
});
|
|
1377
|
+
continue;
|
|
1378
|
+
}
|
|
1379
|
+
if (typeof mutation.value !== "string" && mutation.value !== null) throw new TypeError(`Declaration mutation at index ${index} requires a string or null value.`);
|
|
1380
|
+
if (mutation.priority !== void 0 && mutation.priority !== null && typeof mutation.priority !== "string") throw new TypeError(`Declaration mutation at index ${index} requires a string priority.`);
|
|
1381
|
+
normalized.push({
|
|
1382
|
+
kind: "set",
|
|
1383
|
+
property: mutation.property,
|
|
1384
|
+
value: mutation.value ?? "",
|
|
1385
|
+
priority: mutation.priority ?? ""
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
return this.#block.applyMutations(normalized);
|
|
1389
|
+
}
|
|
1210
1390
|
removeProperty(name) {
|
|
1211
1391
|
requireArguments(arguments.length, 1, "CSSStyleDeclaration", "removeProperty");
|
|
1212
1392
|
return this.#block.removeProperty(`${name}`);
|
|
1213
1393
|
}
|
|
1214
1394
|
/** @internal */
|
|
1215
|
-
serializeSafe(indent) {
|
|
1216
|
-
return this.#block.serialize(true, indent, "\n");
|
|
1395
|
+
serializeSafe(indent, strict = false) {
|
|
1396
|
+
return this.#block.serialize(true, indent, "\n", strict);
|
|
1217
1397
|
}
|
|
1218
1398
|
};
|
|
1219
1399
|
/** A live `@font-face` descriptor rule. */
|
|
1220
1400
|
var CSSFontFaceRule = class extends CSSRule {
|
|
1221
1401
|
style;
|
|
1222
|
-
constructor() {
|
|
1402
|
+
constructor(initialCssText) {
|
|
1223
1403
|
super(CSSRule.FONT_FACE_RULE);
|
|
1224
|
-
this.style = constructWebIDL(CSSStyleDeclaration, [this]);
|
|
1404
|
+
this.style = constructWebIDL(CSSStyleDeclaration, [this, initialCssText]);
|
|
1225
1405
|
lockOwnProperties(this, "style");
|
|
1226
1406
|
}
|
|
1227
1407
|
get cssText() {
|
|
@@ -1232,9 +1412,9 @@ var CSSFontFaceRule = class extends CSSRule {
|
|
|
1232
1412
|
/** Declarations ordered after a nested style rule. */
|
|
1233
1413
|
var CSSNestedDeclarations = class extends CSSRule {
|
|
1234
1414
|
#style;
|
|
1235
|
-
constructor() {
|
|
1415
|
+
constructor(initialCssText) {
|
|
1236
1416
|
super(0);
|
|
1237
|
-
this.#style = constructWebIDL(CSSStyleDeclaration, [this]);
|
|
1417
|
+
this.#style = constructWebIDL(CSSStyleDeclaration, [this, initialCssText]);
|
|
1238
1418
|
}
|
|
1239
1419
|
get style() {
|
|
1240
1420
|
return this.#style;
|
|
@@ -1250,9 +1430,9 @@ var CSSNestedDeclarations = class extends CSSRule {
|
|
|
1250
1430
|
/** A run of live descriptors inside a custom function. */
|
|
1251
1431
|
var CSSFunctionDeclarations = class extends CSSRule {
|
|
1252
1432
|
#style;
|
|
1253
|
-
constructor() {
|
|
1433
|
+
constructor(initialCssText) {
|
|
1254
1434
|
super(0);
|
|
1255
|
-
this.#style = constructWebIDL(CSSFunctionDescriptors, [this]);
|
|
1435
|
+
this.#style = constructWebIDL(CSSFunctionDescriptors, [this, initialCssText]);
|
|
1256
1436
|
}
|
|
1257
1437
|
get style() {
|
|
1258
1438
|
return this.#style;
|
|
@@ -1276,10 +1456,10 @@ var CSSFunctionDescriptors = class extends CSSStyleDeclaration {
|
|
|
1276
1456
|
var CSSMarginRule = class extends CSSRule {
|
|
1277
1457
|
name;
|
|
1278
1458
|
style;
|
|
1279
|
-
constructor(name) {
|
|
1459
|
+
constructor(name, initialCssText) {
|
|
1280
1460
|
super(CSSRule.MARGIN_RULE);
|
|
1281
1461
|
this.name = name;
|
|
1282
|
-
this.style = constructWebIDL(CSSStyleDeclaration, [this]);
|
|
1462
|
+
this.style = constructWebIDL(CSSStyleDeclaration, [this, initialCssText]);
|
|
1283
1463
|
lockOwnProperties(this, "name", "style");
|
|
1284
1464
|
}
|
|
1285
1465
|
get cssText() {
|
|
@@ -1291,10 +1471,10 @@ var CSSMarginRule = class extends CSSRule {
|
|
|
1291
1471
|
var CSSPageRule = class extends CSSGroupingRule {
|
|
1292
1472
|
style;
|
|
1293
1473
|
#selectorText;
|
|
1294
|
-
constructor(selectorText) {
|
|
1474
|
+
constructor(selectorText, initialCssText) {
|
|
1295
1475
|
super(CSSRule.PAGE_RULE);
|
|
1296
1476
|
this.#selectorText = selectorText;
|
|
1297
|
-
this.style = constructWebIDL(CSSStyleDeclaration, [this]);
|
|
1477
|
+
this.style = constructWebIDL(CSSStyleDeclaration, [this, initialCssText]);
|
|
1298
1478
|
lockOwnProperties(this, "style");
|
|
1299
1479
|
}
|
|
1300
1480
|
get selectorText() {
|
|
@@ -1315,10 +1495,10 @@ var CSSPageRule = class extends CSSGroupingRule {
|
|
|
1315
1495
|
var CSSPositionTryRule = class extends CSSRule {
|
|
1316
1496
|
name;
|
|
1317
1497
|
style;
|
|
1318
|
-
constructor(name) {
|
|
1498
|
+
constructor(name, initialCssText) {
|
|
1319
1499
|
super(0);
|
|
1320
1500
|
this.name = name;
|
|
1321
|
-
this.style = constructWebIDL(CSSStyleDeclaration, [this]);
|
|
1501
|
+
this.style = constructWebIDL(CSSStyleDeclaration, [this, initialCssText]);
|
|
1322
1502
|
lockOwnProperties(this, "name", "style");
|
|
1323
1503
|
}
|
|
1324
1504
|
get cssText() {
|
|
@@ -1352,10 +1532,10 @@ function normalizeKeyText(value) {
|
|
|
1352
1532
|
var CSSKeyframeRule = class extends CSSRule {
|
|
1353
1533
|
style;
|
|
1354
1534
|
#keyText;
|
|
1355
|
-
constructor(keyText) {
|
|
1535
|
+
constructor(keyText, initialCssText) {
|
|
1356
1536
|
super(CSSRule.KEYFRAME_RULE);
|
|
1357
1537
|
this.#keyText = normalizeKeyText(keyText) ?? keyText;
|
|
1358
|
-
this.style = constructWebIDL(CSSStyleDeclaration, [this]);
|
|
1538
|
+
this.style = constructWebIDL(CSSStyleDeclaration, [this, initialCssText]);
|
|
1359
1539
|
lockOwnProperties(this, "style");
|
|
1360
1540
|
}
|
|
1361
1541
|
get keyText() {
|
|
@@ -1666,10 +1846,10 @@ var CSSFontFeatureValuesRule = class extends CSSRule {
|
|
|
1666
1846
|
var CSSStyleRule = class extends CSSGroupingRule {
|
|
1667
1847
|
style;
|
|
1668
1848
|
#selectorText;
|
|
1669
|
-
constructor(selectorText) {
|
|
1849
|
+
constructor(selectorText, normalized, initialCssText) {
|
|
1670
1850
|
super(CSSRule.STYLE_RULE);
|
|
1671
|
-
this.#selectorText = normalizeSelectorText(`${selectorText}`, currentConstructionResourceBudget()) ?? `${selectorText}`;
|
|
1672
|
-
this.style = constructWebIDL(CSSStyleDeclaration, [this]);
|
|
1851
|
+
this.#selectorText = normalized === normalizedSelectorText ? selectorText : normalizeSelectorText(`${selectorText}`, currentConstructionResourceBudget()) ?? `${selectorText}`;
|
|
1852
|
+
this.style = constructWebIDL(CSSStyleDeclaration, [this, initialCssText]);
|
|
1673
1853
|
lockOwnProperties(this, "style");
|
|
1674
1854
|
}
|
|
1675
1855
|
get selectorText() {
|
|
@@ -1702,26 +1882,23 @@ function replaceGroupingRules(group, rules) {
|
|
|
1702
1882
|
function attachRuleTree(rule, parentRule, parentStyleSheet) {
|
|
1703
1883
|
ruleTree.attach(rule, parentRule, parentStyleSheet);
|
|
1704
1884
|
}
|
|
1705
|
-
function
|
|
1706
|
-
return safeSerializer.serialize(rule);
|
|
1707
|
-
}
|
|
1708
|
-
function describeRuleSafe(rule) {
|
|
1885
|
+
function describeRuleSafe(rule, strict) {
|
|
1709
1886
|
if (rule instanceof CSSStyleRule) return {
|
|
1710
1887
|
kind: "block",
|
|
1711
1888
|
header: rule.selectorText,
|
|
1712
|
-
declarations: rule.style.serializeSafe(" "),
|
|
1889
|
+
declarations: rule.style.serializeSafe(" ", strict),
|
|
1713
1890
|
children: ruleTree.children(rule)
|
|
1714
1891
|
};
|
|
1715
1892
|
if (rule instanceof CSSNestedDeclarations || rule instanceof CSSFunctionDeclarations) return {
|
|
1716
1893
|
kind: "declarations",
|
|
1717
|
-
declarations: rule.style.serializeSafe("")
|
|
1894
|
+
declarations: rule.style.serializeSafe("", strict)
|
|
1718
1895
|
};
|
|
1719
1896
|
if (rule instanceof CSSFontFaceRule || rule instanceof CSSMarginRule || rule instanceof CSSPositionTryRule || rule instanceof CSSKeyframeRule) {
|
|
1720
1897
|
const blockIndex = rule.cssText.indexOf("{");
|
|
1721
1898
|
return {
|
|
1722
1899
|
kind: "block",
|
|
1723
1900
|
header: rule.cssText.slice(0, blockIndex).trimEnd(),
|
|
1724
|
-
declarations: rule.style.serializeSafe(" ")
|
|
1901
|
+
declarations: rule.style.serializeSafe(" ", strict)
|
|
1725
1902
|
};
|
|
1726
1903
|
}
|
|
1727
1904
|
if (rule instanceof CSSKeyframesRule) return {
|
|
@@ -1732,7 +1909,7 @@ function describeRuleSafe(rule) {
|
|
|
1732
1909
|
if (rule instanceof CSSPageRule) return {
|
|
1733
1910
|
kind: "block",
|
|
1734
1911
|
header: `@page${rule.selectorText === "" ? "" : ` ${rule.selectorText}`}`,
|
|
1735
|
-
declarations: rule.style.serializeSafe(" "),
|
|
1912
|
+
declarations: rule.style.serializeSafe(" ", strict),
|
|
1736
1913
|
children: ruleTree.children(rule)
|
|
1737
1914
|
};
|
|
1738
1915
|
if (!(rule instanceof CSSGroupingRule)) return {
|
|
@@ -1839,24 +2016,19 @@ function isNativeMetadataRule(description) {
|
|
|
1839
2016
|
function createRuleShellFromNative(description, reportDiagnostic, preserveImports, resourceBudget) {
|
|
1840
2017
|
let rule;
|
|
1841
2018
|
switch (description.kind) {
|
|
1842
|
-
case "style":
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
2019
|
+
case "style":
|
|
2020
|
+
rule = constructWebIDL(CSSStyleRule, [
|
|
2021
|
+
description.prelude,
|
|
2022
|
+
normalizedSelectorText,
|
|
2023
|
+
description.declarations
|
|
2024
|
+
]);
|
|
1846
2025
|
break;
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
const nested = constructWebIDL(CSSNestedDeclarations);
|
|
1850
|
-
nested.style.cssText = description.declarations;
|
|
1851
|
-
rule = nested;
|
|
2026
|
+
case "nested-declarations":
|
|
2027
|
+
rule = constructWebIDL(CSSNestedDeclarations, [description.declarations]);
|
|
1852
2028
|
break;
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
const declarations = constructWebIDL(CSSFunctionDeclarations);
|
|
1856
|
-
declarations.style.cssText = description.declarations;
|
|
1857
|
-
rule = declarations;
|
|
2029
|
+
case "function-declarations":
|
|
2030
|
+
rule = constructWebIDL(CSSFunctionDeclarations, [description.declarations]);
|
|
1858
2031
|
break;
|
|
1859
|
-
}
|
|
1860
2032
|
case "import": {
|
|
1861
2033
|
if (!preserveImports) return null;
|
|
1862
2034
|
const parsed = parseImportPrelude(description.cssText.replace(/^@import\s+/iu, "").replace(/;\s*$/u, ""));
|
|
@@ -1869,39 +2041,24 @@ function createRuleShellFromNative(description, reportDiagnostic, preserveImport
|
|
|
1869
2041
|
]);
|
|
1870
2042
|
break;
|
|
1871
2043
|
}
|
|
1872
|
-
case "font-face":
|
|
1873
|
-
|
|
1874
|
-
fontFace.style.cssText = description.declarations;
|
|
1875
|
-
rule = fontFace;
|
|
2044
|
+
case "font-face":
|
|
2045
|
+
rule = constructWebIDL(CSSFontFaceRule, [description.declarations]);
|
|
1876
2046
|
break;
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
const page = constructWebIDL(CSSPageRule, [description.prelude]);
|
|
1880
|
-
page.style.cssText = description.declarations;
|
|
1881
|
-
rule = page;
|
|
2047
|
+
case "page":
|
|
2048
|
+
rule = constructWebIDL(CSSPageRule, [description.prelude, description.declarations]);
|
|
1882
2049
|
break;
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
const margin = constructWebIDL(CSSMarginRule, [description.prelude]);
|
|
1886
|
-
margin.style.cssText = description.declarations;
|
|
1887
|
-
rule = margin;
|
|
2050
|
+
case "margin":
|
|
2051
|
+
rule = constructWebIDL(CSSMarginRule, [description.prelude, description.declarations]);
|
|
1888
2052
|
break;
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
const positionTry = constructWebIDL(CSSPositionTryRule, [description.prelude]);
|
|
1892
|
-
positionTry.style.cssText = description.declarations;
|
|
1893
|
-
rule = positionTry;
|
|
2053
|
+
case "position-try":
|
|
2054
|
+
rule = constructWebIDL(CSSPositionTryRule, [description.prelude, description.declarations]);
|
|
1894
2055
|
break;
|
|
1895
|
-
}
|
|
1896
2056
|
case "keyframes":
|
|
1897
2057
|
rule = constructWebIDL(CSSKeyframesRule, [description.prelude]);
|
|
1898
2058
|
break;
|
|
1899
|
-
case "keyframe":
|
|
1900
|
-
|
|
1901
|
-
keyframe.style.cssText = description.declarations;
|
|
1902
|
-
rule = keyframe;
|
|
2059
|
+
case "keyframe":
|
|
2060
|
+
rule = constructWebIDL(CSSKeyframeRule, [description.prelude, description.declarations]);
|
|
1903
2061
|
break;
|
|
1904
|
-
}
|
|
1905
2062
|
case "counter-style": {
|
|
1906
2063
|
const counterStyle = constructWebIDL(CSSCounterStyleRule, [description.prelude]);
|
|
1907
2064
|
hydrateCounterStyleDescriptors(counterStyle, description.declarations, resourceBudget);
|
|
@@ -2127,9 +2284,13 @@ var CSSStyleSheet = class {
|
|
|
2127
2284
|
}
|
|
2128
2285
|
/** Serialize current state as reparsable CSS without mutating live objects. */
|
|
2129
2286
|
serialize() {
|
|
2130
|
-
return this.#rules
|
|
2287
|
+
return safeSerializer.serializeMany(this.#rules);
|
|
2288
|
+
}
|
|
2289
|
+
/** Serialize current state only when its CSS semantics can be preserved exactly. */
|
|
2290
|
+
serializeStrict() {
|
|
2291
|
+
return strictSerializer.serializeMany(this.#rules);
|
|
2131
2292
|
}
|
|
2132
|
-
/** Drain opt-in mutation diagnostics without affecting CSSOM behavior. */
|
|
2293
|
+
/** Drain opt-in mutation and serialization diagnostics without affecting CSSOM behavior. */
|
|
2133
2294
|
takeDiagnostics() {
|
|
2134
2295
|
if (!this.#diagnostics) return [];
|
|
2135
2296
|
return this.#diagnostics.splice(0);
|
|
@@ -2180,6 +2341,7 @@ exports.CSSStyleSheet = CSSStyleSheet;
|
|
|
2180
2341
|
exports.CSSSupportsRule = CSSSupportsRule;
|
|
2181
2342
|
exports.CSSViewTransitionRule = CSSViewTransitionRule;
|
|
2182
2343
|
exports.MediaList = MediaList;
|
|
2344
|
+
exports.SheetOMSerializationError = SheetOMSerializationError;
|
|
2183
2345
|
exports.parseStyleSheet = parseStyleSheet;
|
|
2184
2346
|
|
|
2185
2347
|
//# sourceMappingURL=index.cjs.map
|