oficina / docs Public

fixtures: Yjs wire fixtures generated by real JS yjs

These are the contract for the Rust core. Never edited to make a test
pass; a deliberate rule change regenerates them in the same commit.

The unicode fixture is the one that matters most: Yjs indexes UTF-16
code units and Rust indexes UTF-8 bytes, so an index-conversion bug
shows there and nowhere else.
Paul Campbell pushed by paul@keymail.dev 72cd62abd064ffd3fde4dd2eee2fe5d0754be372 parent 9185299
12 files changed, +137 −0
  • fixtures/.gitignore +1 −0
  • fixtures/data/concurrent.expected.json +3 −0
  • fixtures/data/concurrent.update.bin binary
  • fixtures/data/formatted.expected.json +3 −0
  • fixtures/data/formatted.update.bin binary
  • fixtures/data/hello.expected.json +3 −0
  • fixtures/data/hello.update.bin binary
  • fixtures/data/unicode.expected.json +3 −0
  • fixtures/data/unicode.update.bin binary
  • fixtures/generate.mjs +54 −0
  • fixtures/package-lock.json +61 −0
  • fixtures/package.json +9 −0
diff --git a/fixtures/.gitignore b/fixtures/.gitignore
new file mode 100644
index 0000000..c2658d7
--- /dev/null
+++ b/fixtures/.gitignore
@@ -0,0 +1 @@
+node_modules/
diff --git a/fixtures/data/concurrent.expected.json b/fixtures/data/concurrent.expected.json
new file mode 100644
index 0000000..ac35f31
--- /dev/null
+++ b/fixtures/data/concurrent.expected.json
@@ -0,0 +1,3 @@
+{
+ "text": "AAABBB"
+}
diff --git a/fixtures/data/concurrent.update.bin b/fixtures/data/concurrent.update.bin
new file mode 100644
index 0000000..f77be1c
Binary files /dev/null and b/fixtures/data/concurrent.update.bin differ
diff --git a/fixtures/data/formatted.expected.json b/fixtures/data/formatted.expected.json
new file mode 100644
index 0000000..e763dbd
--- /dev/null
+++ b/fixtures/data/formatted.expected.json
@@ -0,0 +1,3 @@
+{
+ "text": "plain bold plain"
+}
diff --git a/fixtures/data/formatted.update.bin b/fixtures/data/formatted.update.bin
new file mode 100644
index 0000000..7773e5a
Binary files /dev/null and b/fixtures/data/formatted.update.bin differ
diff --git a/fixtures/data/hello.expected.json b/fixtures/data/hello.expected.json
new file mode 100644
index 0000000..da7d1ad
--- /dev/null
+++ b/fixtures/data/hello.expected.json
@@ -0,0 +1,3 @@
+{
+ "text": "hello world"
+}
diff --git a/fixtures/data/hello.update.bin b/fixtures/data/hello.update.bin
new file mode 100644
index 0000000..554e670
Binary files /dev/null and b/fixtures/data/hello.update.bin differ
diff --git a/fixtures/data/unicode.expected.json b/fixtures/data/unicode.expected.json
new file mode 100644
index 0000000..4320fb0
--- /dev/null
+++ b/fixtures/data/unicode.expected.json
@@ -0,0 +1,3 @@
+{
+ "text": "héllo 🌍 café"
+}
diff --git a/fixtures/data/unicode.update.bin b/fixtures/data/unicode.update.bin
new file mode 100644
index 0000000..f261e97
Binary files /dev/null and b/fixtures/data/unicode.update.bin differ
diff --git a/fixtures/generate.mjs b/fixtures/generate.mjs
new file mode 100644
index 0000000..a1cc897
--- /dev/null
+++ b/fixtures/generate.mjs
@@ -0,0 +1,54 @@
+// Generates the Yjs wire fixtures that define compatibility for the Rust
+// core. These are the contract: never edit a fixture to make a test pass.
+// A deliberate rule change regenerates them in the same commit.
+import * as Y from 'yjs'
+import { mkdirSync, writeFileSync } from 'node:fs'
+import { join, dirname } from 'node:path'
+import { fileURLToPath } from 'node:url'
+
+const dataDir = join(dirname(fileURLToPath(import.meta.url)), 'data')
+mkdirSync(dataDir, { recursive: true })
+
+function emit(name, build) {
+ const doc = new Y.Doc()
+ doc.clientID = 1
+ build(doc)
+ const update = Y.encodeStateAsUpdate(doc)
+ writeFileSync(join(dataDir, `${name}.update.bin`), Buffer.from(update))
+ writeFileSync(
+ join(dataDir, `${name}.expected.json`),
+ JSON.stringify({ text: doc.getText('content').toString() }, null, 2) + '\n'
+ )
+ console.log(`${name}: ${update.length} bytes`)
+}
+
+emit('hello', (doc) => {
+ doc.getText('content').insert(0, 'hello world')
+})
+
+emit('unicode', (doc) => {
+ // Surrogate pairs and combining marks: Yjs indexes UTF-16 code units and
+ // Rust indexes UTF-8 bytes, so this is where an index-conversion bug shows.
+ doc.getText('content').insert(0, 'héllo 🌍 café')
+})
+
+emit('formatted', (doc) => {
+ const t = doc.getText('content')
+ t.insert(0, 'plain bold plain')
+ t.format(6, 4, { bold: true })
+})
+
+emit('concurrent', (doc) => {
+ // Two docs diverge and merge. The merged state is order-independent, so
+ // Rust must arrive at the same bytes from the same inputs.
+ const a = new Y.Doc()
+ a.clientID = 1
+ const b = new Y.Doc()
+ b.clientID = 2
+ doc.clientID = 3
+ a.getText('content').insert(0, 'AAA')
+ b.getText('content').insert(0, 'BBB')
+ Y.applyUpdate(a, Y.encodeStateAsUpdate(b))
+ Y.applyUpdate(b, Y.encodeStateAsUpdate(a))
+ Y.applyUpdate(doc, Y.encodeStateAsUpdate(a))
+})
diff --git a/fixtures/package-lock.json b/fixtures/package-lock.json
new file mode 100644
index 0000000..4aaa8ec
--- /dev/null
+++ b/fixtures/package-lock.json
@@ -0,0 +1,61 @@
+{
+ "name": "docs-fixtures",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "docs-fixtures",
+ "dependencies": {
+ "yjs": "13.6.27"
+ }
+ },
+ "node_modules/isomorphic.js": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz",
+ "integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==",
+ "license": "MIT",
+ "funding": {
+ "type": "GitHub Sponsors ❤",
+ "url": "https://github.com/sponsors/dmonad"
+ }
+ },
+ "node_modules/lib0": {
+ "version": "0.2.117",
+ "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.117.tgz",
+ "integrity": "sha512-DeXj9X5xDCjgKLU/7RR+/HQEVzuuEUiwldwOGsHK/sfAfELGWEyTcf0x+uOvCvK3O2zPmZePXWL85vtia6GyZw==",
+ "license": "MIT",
+ "dependencies": {
+ "isomorphic.js": "^0.2.4"
+ },
+ "bin": {
+ "0ecdsa-generate-keypair": "bin/0ecdsa-generate-keypair.js",
+ "0gentesthtml": "bin/gentesthtml.js",
+ "0serve": "bin/0serve.js"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "type": "GitHub Sponsors ❤",
+ "url": "https://github.com/sponsors/dmonad"
+ }
+ },
+ "node_modules/yjs": {
+ "version": "13.6.27",
+ "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.27.tgz",
+ "integrity": "sha512-OIDwaflOaq4wC6YlPBy2L6ceKeKuF7DeTxx+jPzv1FHn9tCZ0ZwSRnUBxD05E3yed46fv/FWJbvR+Ud7x0L7zw==",
+ "license": "MIT",
+ "dependencies": {
+ "lib0": "^0.2.99"
+ },
+ "engines": {
+ "node": ">=16.0.0",
+ "npm": ">=8.0.0"
+ },
+ "funding": {
+ "type": "GitHub Sponsors ❤",
+ "url": "https://github.com/sponsors/dmonad"
+ }
+ }
+ }
+}
diff --git a/fixtures/package.json b/fixtures/package.json
new file mode 100644
index 0000000..8782e50
--- /dev/null
+++ b/fixtures/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "docs-fixtures",
+ "private": true,
+ "type": "module",
+ "description": "Generates Yjs wire fixtures. The JS side is the contract; Rust must reproduce these.",
+ "dependencies": {
+ "yjs": "13.6.27"
+ }
+}