sheetom 0.1.0-rc.5 → 0.1.0-rc.7

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.
Files changed (40) hide show
  1. package/README.md +141 -45
  2. package/compatibility/baselines/0.1.0-rc.6.json +3211 -0
  3. package/compatibility/baselines/0.1.0-rc.7.json +3386 -0
  4. package/compatibility/baselines/README.md +1 -1
  5. package/compatibility/browser-geometric-contracts.json +93 -0
  6. package/compatibility/native-grammar-inventory.json +1810 -0
  7. package/compatibility/number-result-math-capabilities.json +11380 -0
  8. package/compatibility/numeric-property-contracts.json +23 -0
  9. package/compatibility/schemas/browser-geometric-contracts.schema.json +39 -0
  10. package/compatibility/schemas/browser-longhand-composite-contracts.schema.json +39 -0
  11. package/compatibility/schemas/browser-longhand-keyword-contracts.schema.json +51 -0
  12. package/compatibility/schemas/compatibility-report.schema.json +328 -6
  13. package/compatibility/schemas/function-rule-cases.schema.json +49 -0
  14. package/compatibility/schemas/native-grammar-inventory.schema.json +134 -0
  15. package/compatibility/schemas/number-result-math-corpus.schema.json +71 -0
  16. package/compatibility/schemas/numeric-property-contracts.schema.json +37 -0
  17. package/compatibility/schemas/property-grammar-extensions.schema.json +51 -0
  18. package/compatibility/schemas/property-value-observations.schema.json +43 -0
  19. package/compatibility/schemas/property-value-probes.schema.json +26 -0
  20. package/compatibility/schemas/relative-color-corpus.schema.json +90 -0
  21. package/compatibility/schemas/shorthand-grammar-contracts.schema.json +2 -3
  22. package/compatibility/schemas/shorthand-grammar-observations.schema.json +1 -1
  23. package/compatibility/schemas/webref-branch-ratchet.schema.json +48 -0
  24. package/compatibility/schemas/webref-property-branches.schema.json +158 -0
  25. package/compatibility/schemas/webref-semantic-terminals.schema.json +38 -0
  26. package/compatibility/shorthand-grammar-contracts.json +84 -5
  27. package/compatibility/shorthand-grammar-observations.json +2569 -732
  28. package/compatibility/value-capabilities.json +2643 -13
  29. package/dist/index.cjs +915 -5042
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +90 -2
  32. package/dist/index.d.ts +90 -2
  33. package/dist/index.js +907 -5042
  34. package/dist/index.js.map +1 -1
  35. package/docs/api.md +63 -5
  36. package/docs/releasing.md +12 -8
  37. package/engine-abi.json +5 -0
  38. package/native/index.cjs +44 -0
  39. package/native/resolve-target.cjs +85 -0
  40. package/package.json +93 -9
package/README.md CHANGED
@@ -1,28 +1,41 @@
1
1
  # SheetOM
2
2
 
3
3
  SheetOM is a mutable, browser-shaped CSS authoring object model for Node.js,
4
- Bun, and Deno. It uses Lightning CSS for property parsing and canonicalization
5
- while keeping declaration state and CSSOM serialization under its own control.
4
+ Bun, and Deno. Its repository-owned Rust engine handles parsing,
5
+ canonicalization, declaration state, and safe CSS serialization; JavaScript
6
+ only owns the public WebIDL-shaped facade and live object identity.
6
7
 
7
8
  It is intended for server-side stylesheet editing and serialization. It does
8
9
  not implement the DOM, cascade, selector matching, layout, or computed styles.
9
10
 
10
11
  ## Install
11
12
 
12
- Install the current release candidate from the `next` dist-tag:
13
+ Install the active release:
13
14
 
14
15
  ```sh
15
- npm install sheetom@next
16
+ npm install sheetom
16
17
  ```
17
18
 
18
- `lightningcss`, `css-tree`, `cssstyle`, and the CSS Tools tokenizer are regular
19
- dependencies; consumers do not need to install peer dependencies or globals.
20
- SheetOM validates values before using `cssstyle` only as a static shorthand
21
- expander, and uses the tokenizer for lossless recovered-rule spans.
22
-
23
- Node.js 22 and 24 are tested on Linux x64, Windows x64, and macOS arm64. Bun
24
- 1.3.1 and Deno 2.9.5 are tested on Linux x64. Deno must use a local
25
- `node_modules` directory and grant the native Lightning CSS binding FFI and
19
+ After the first stable release, use `npm install sheetom@next` to opt into an
20
+ active prerelease. Until then, the `latest` and `next` dist-tags both identify
21
+ the active release candidate.
22
+
23
+ The root package has no JavaScript runtime or peer dependencies and contains no
24
+ native addon. It pins one matching `@sheetom/native-*` implementation as an
25
+ optional dependency, so npm installs only the binary for the current operating
26
+ system, CPU, and Linux libc. Installing with `--omit=optional` is unsupported
27
+ and produces an explicit missing-binding error rather than a behavioral
28
+ fallback. The native engine includes a pinned, locally maintained Lightning CSS
29
+ source snapshot; consumers do not install a second parser, provide globals, or
30
+ select a fallback engine.
31
+ SheetOM owns observable-value serialization and shorthand expansion rather
32
+ than delegating CSSOM state to a browser-DOM emulation package.
33
+
34
+ Node.js 22 executes the exact published package on macOS arm64/x64, Windows
35
+ arm64/x64/x86, Linux glibc arm64/ARMv7/x64/ppc64le/s390x, and Linux musl
36
+ arm64/ARMv7/x64. Node.js 24 is additionally tested on Linux x64, Windows x64,
37
+ and macOS arm64. Bun 1.3.1 and Deno 2.9.5 are tested on Linux x64. Deno must use a local
38
+ `node_modules` directory and grant SheetOM's native binding FFI and
26
39
  system-information permissions:
27
40
 
28
41
  ```sh
@@ -31,6 +44,29 @@ deno run --node-modules-dir=manual --allow-ffi --allow-sys app.ts
31
44
 
32
45
  SheetOM exports browser-named classes but never modifies `globalThis`.
33
46
 
47
+ Browser applications can install the separate, ESM-only WebAssembly backend:
48
+
49
+ ```sh
50
+ npm install @sheetom/wasm
51
+ ```
52
+
53
+ ```ts
54
+ import { createSheetOM } from "@sheetom/wasm";
55
+
56
+ const { CSSStyleSheet } = await createSheetOM();
57
+ const sheet = new CSSStyleSheet();
58
+ sheet.replaceSync(".card { color: red; }");
59
+ ```
60
+
61
+ `createSheetOM()` resolves the `.wasm` file relative to its own module and
62
+ shares concurrent default initialization within one JavaScript realm. Passing
63
+ an explicit `URL`, `Response`, `ArrayBuffer`, or `WebAssembly.Module` creates
64
+ an independent facade with distinct class identity. The WASM backend uses the
65
+ same Rust parser, Engine ABI Identity, Resource Budget, and CSSOM facade as the
66
+ native package; it is never an automatic fallback for a missing native addon.
67
+ See [`@sheetom/wasm` usage](./packages/wasm/README.md) for server and worker
68
+ requirements.
69
+
34
70
  ## Use
35
71
 
36
72
  ```ts
@@ -42,7 +78,7 @@ sheet.replaceSync(".card { width: 12px; }");
42
78
  const rule = sheet.cssRules[0];
43
79
  if (rule instanceof CSSStyleRule) {
44
80
  rule.style.setProperty("padding", "8px 16px");
45
- Reflect.set(rule.style, "backgroundColor", "rebeccapurple");
81
+ rule.style.setProperty("background-color", "rebeccapurple");
46
82
  }
47
83
 
48
84
  console.log(sheet.serialize());
@@ -53,6 +89,11 @@ const existing = parseStyleSheet('@import "theme.css"; .card { color: red; }', {
53
89
  console.log(existing.cssRules.length); // 2
54
90
  ```
55
91
 
92
+ `setProperty()` is the standard, fully typed way to set a declaration,
93
+ especially when its name is dynamic. Browser-style camelCase assignments such
94
+ as `rule.style.backgroundColor = "rebeccapurple"` work at runtime, but the
95
+ current TypeScript declarations do not enumerate every named CSS property.
96
+
56
97
  Constructed sheets follow browser replacement behavior and strip `@import`.
57
98
  `parseStyleSheet` creates a regular authoring sheet and preserves valid imports
58
99
  without loading them.
@@ -60,15 +101,18 @@ without loading them.
60
101
  ## Recovered values and reparsable serialization
61
102
 
62
103
  SheetOM distinguishes browser-facing CSSOM text from reparsable stylesheet
63
- output. Chromium
64
- accepts some values using CSS Syntax end-of-input recovery while preserving the
65
- unclosed input in `getPropertyValue()` and `cssText`:
104
+ output. Chromium accepts some values using CSS Syntax end-of-input recovery
105
+ while preserving the unclosed input in `getPropertyValue()` and `cssText`:
66
106
 
67
107
  ```ts
68
108
  const sheet = new CSSStyleSheet();
69
109
  sheet.insertRule(".card {}");
70
110
 
71
- const rule = sheet.cssRules[0] as CSSStyleRule;
111
+ const rule = sheet.cssRules[0];
112
+ if (!(rule instanceof CSSStyleRule)) {
113
+ throw new TypeError("Expected a style rule");
114
+ }
115
+
72
116
  rule.style.setProperty("padding", "72px var(--space, var(--space,");
73
117
 
74
118
  rule.style.getPropertyValue("padding");
@@ -107,17 +151,24 @@ getters and `cssText` are synthesized only while the complete current longhand
107
151
  set has compatible values and priorities; genuinely deferred substitutions
108
152
  retain separate provenance until a longhand mutation breaks their group.
109
153
 
110
- The Chromium 151 compatibility baseline has exhaustive property breadth for all
111
- 129 manifested multi-longhand shorthands. Grammar depth is a finite reviewed
112
- contract rather than a claim to implement every future CSS production: 23 codec
113
- profiles currently carry 92 positive and neighboring-negative branch cases,
114
- including cardinality, slash and comma lists, compound optional keywords,
115
- mutation atomicity, and safe round-trips. CI reprobes those cases against the
154
+ The Chromium 151 compatibility baseline covers all 129 manifested
155
+ multi-longhand shorthands. Grammar depth is a finite reviewed contract rather
156
+ than a claim to implement every future CSS production: 24 codec profiles
157
+ currently carry 96 positive and neighboring-negative branch cases, including
158
+ cardinality, slash and comma lists, compound optional keywords, mutation
159
+ atomicity, and reparsable round-trips. CI reprobes those cases against the
116
160
  pinned Chromium engine, and a release is blocked unless all 129 breadth seeds
117
- and all 92 reviewed branches pass exactly. The contracts and browser
161
+ and all 96 reviewed branches pass exactly. The contracts and browser
118
162
  observations ship as audit evidence but are never imported as runtime value
119
163
  authority.
120
164
 
165
+ Relative colors use the same typed engine rather than a text fallback. The
166
+ pinned Chromium 151 and WPT corpus contains 1,146 accepted and 160 rejected
167
+ branches across `rgb()`, `hsl()`, `hwb()`, Lab, LCH, predefined color spaces,
168
+ channel calculations, missing components, and nested color functions. CI
169
+ compares all 1,306 browser-facing getters in one batched browser session and
170
+ also requires every accepted value to survive reparsable serialization.
171
+
121
172
  ## API scope
122
173
 
123
174
  - `CSSStyleSheet`, live `CSSRuleList`, `CSSRule`, and `MediaList`
@@ -126,6 +177,8 @@ authority.
126
177
  - import, font-face, page/margin, nested-declaration, and position-try rules
127
178
  - keyframes and mutable keyframe rules
128
179
  - counter-style descriptors and font-feature-value maps
180
+ - custom `@function` parameters, return types, conditional groups, and live
181
+ function descriptors
129
182
  - live indexed and named `CSSStyleDeclaration`
130
183
  - `insertRule`, `deleteRule`, `replace`, and `replaceSync`
131
184
  - `parseStyleSheet` for forgiving regular-sheet parsing
@@ -136,12 +189,37 @@ SheetOM targets standards and shared browser behavior first, with Chromium
136
189
  behavior used only as the final measured divergence fallback. Versioned JSON
137
190
  Operation Fixtures execute through SheetOM and native browser adapters;
138
191
  applicable WPT subtests retain their pinned source path, title, and blob SHA.
139
- Every release ships its machine-readable Compatibility Report.
192
+ Every release ships its machine-readable Compatibility Report. RC7-or-later
193
+ reports distinguish native and WebAssembly backend evidence; the WASM dimension
194
+ records direct HTTP, worker, bundler, memory-soak, and Publisher-shaped browser
195
+ results instead of inferring them from the shared Rust engine.
140
196
 
141
197
  Modern or implementation-dependent value grammar is bounded by the checked-in
142
198
  [`Value Capability Corpus`](./compatibility/value-capabilities.json). Each
143
199
  measured family includes accepted and rejected neighboring cases; browser
144
200
  probing occurs only during conformance work and never at runtime.
201
+ The corpus includes 94 CSS Math branches across number, integer, length,
202
+ percentage, angle, and time contexts. It locks dimensional rejection,
203
+ mixed-unit ordering, non-finite constants, function arity, CSSOM observable
204
+ serialization, and atomic failure to Chromium 151.
205
+
206
+ Computed-context number results are covered separately by the checked-in
207
+ [`Number Result Math Corpus`](./compatibility/number-result-math-capabilities.json).
208
+ It records 860 batched Chromium observations across all 70 accepting
209
+ properties, including relative lengths, percentages, dynamic products and
210
+ quotients, dimension-result neighbors, invalid dimensional multiplication,
211
+ CSSOM expansion, declaration serialization, multi-item animations, slash
212
+ sections, and contextual values in every position of `flex`, `grid`, columns,
213
+ aspect ratios, and border-image families. Both direct and composite properties
214
+ must pass mutation, `cssText`, safe round-trip, and atomic-rejection gates.
215
+
216
+ Direct numeric and cross-dimension syntax is gated independently by the
217
+ [`Numeric Property Contracts`](./compatibility/numeric-property-contracts.json).
218
+ It crosses 57 number-, percentage-, length-, and legacy-number properties with
219
+ 11 accepted and rejected neighboring branches. The public binding must match
220
+ Chromium for acceptance, observable values, `cssText`, indexed names, and
221
+ invalid-mutation atomicity; the browser observations remain test evidence and
222
+ are never loaded by the runtime.
145
223
 
146
224
  The corresponding shorthand depth evidence is split between the reviewed
147
225
  [`Grammar Branch Contracts`](./compatibility/shorthand-grammar-contracts.json)
@@ -160,36 +238,54 @@ advancing the Compatibility Baseline.
160
238
 
161
239
  SheetOM does not fetch `@import` targets or URLs and does not execute CSS. It is
162
240
  also not a sanitizer: valid authored URLs, imports, and browser features remain
163
- in serialized output. Callers must sanitize untrusted output before attaching
164
- it to a document or another rendering environment.
241
+ in serialized output. Callers must apply their own content and resource policy
242
+ before attaching untrusted output to a document or another rendering
243
+ environment.
244
+
245
+ Every sheet has a high default Resource Budget that is checked before native
246
+ parsing or CSSOM mutation: 64 MiB of stylesheet source, 1 MiB per declaration
247
+ value, syntax depth 4,096, one million rules, and 100,000 declarations per
248
+ block. Exceeding a budget throws `RangeError` without changing the previous
249
+ sheet or declaration state. Limits are UTF-8 byte counts where applicable and
250
+ can be changed per sheet without affecting other sheets:
251
+
252
+ ```js
253
+ const bounded = new CSSStyleSheet({
254
+ resourceBudget: {
255
+ maxStylesheetBytes: 8 * 1024 * 1024,
256
+ maxRuleCount: 100_000,
257
+ },
258
+ });
259
+ ```
165
260
 
166
- The browser-shaped interface has no implicit input-size, nesting-depth, or
167
- mutation-count limits. Isolate or bound untrusted workloads according to your
168
- application's resource policy. See [SECURITY.md](./SECURITY.md) for private
169
- vulnerability reporting and supported-release policy.
261
+ Resource Budgets protect the host process; they are not content policy,
262
+ sanitization, or a rendering sandbox. See [the API contract](./docs/api.md) and
263
+ [SECURITY.md](./SECURITY.md) for details.
170
264
 
171
265
  ## Development
172
266
 
173
267
  ```sh
174
- npm test
175
- npm run typecheck
176
- npm run build
177
- npm run conformance:validate
268
+ npm run check
269
+ npm run test:browser:matrix
270
+ npm run test:differential
178
271
  npm run conformance:drift
179
272
  npm run fuzz
180
273
  npm run benchmark
181
- npm run pack:test
182
274
  ```
183
275
 
184
- `npm test` runs unit, deterministic fuzz, and local Chromium projects. Use
185
- `npm run test:browser:matrix` on a machine with all Playwright dependencies to
186
- run Chromium, Firefox, and WebKit. The browser matrix also runs a deterministic,
187
- grammar-oriented declaration differential; any minimized mismatch must become
188
- an immutable Operation Fixture with an explicit Compatibility Resolution.
189
- `npm run docs:build` generates the TypeDoc reference under `site/api`. The benchmark gates both a 10,000-rule stress case
190
- and a publisher-shaped reference workload with one shared stylesheet, 20 page
191
- stylesheets, nested layers/media, distributed mutations, and two idempotent
192
- serialization passes.
276
+ `npm run check` covers types, public unit behavior, conformance documents, API
277
+ documentation, build output, runtime artifacts, and the packed-package smoke
278
+ test. Use `npm run test:browser:matrix` on a machine with all Playwright
279
+ dependencies to run Chromium, Firefox, and WebKit. CI separately runs
280
+ `npm run test:differential`, a deterministic, grammar-oriented declaration
281
+ differential with native-browser reparsing witnesses. Any minimized mismatch
282
+ must become an immutable Operation Fixture with an explicit Compatibility
283
+ Resolution.
284
+
285
+ `npm run docs:build` generates the TypeDoc reference under `site/api`. The
286
+ benchmark gates both a 10,000-rule stress case and a publisher-shaped reference
287
+ workload with one shared stylesheet, 20 page stylesheets, nested layers/media,
288
+ distributed mutations, and two idempotent serialization passes.
193
289
 
194
290
  Only the latest published `0.x` minor and its active prereleases receive fixes
195
291
  before 1.0. During `0.x`, observable compatibility corrections and interface