This commit is contained in:
parent
3416264d6b
commit
2623959c10
5 changed files with 72 additions and 7 deletions
|
|
@ -84,8 +84,8 @@ See the [example website source](examples/website/src/index.ts) for a more compl
|
|||
|
||||
React Native's default engine, Hermes, does not expose a runtime `WebAssembly`
|
||||
global, so the WebAssembly build cannot run there. For React Native, the package
|
||||
ships a [`wasm2js`](https://github.com/WebAssembly/binaryen) (pure-JavaScript)
|
||||
build via its `react-native` entry point.
|
||||
ships a pure-JavaScript build produced by [Binaryen's `wasm2js`](https://github.com/WebAssembly/binaryen)
|
||||
via its `react-native` entry point.
|
||||
|
||||
### Python
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
],
|
||||
"scripts": {
|
||||
"build": "node scripts/build-rn.mjs && webpack --mode production",
|
||||
"format": "prettier --write \"./**/*.(ts|scss|json|html)\"",
|
||||
"format": "prettier --write \"./**/*.(ts|mjs|scss|json|html)\"",
|
||||
"test": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export interface WasmBackend {
|
|||
ensureReady(): void;
|
||||
}
|
||||
|
||||
// Define the enum values as const arrays to avoid duplication
|
||||
// Define the enum values as a const array to avoid duplication
|
||||
const BUILTIN_TOKENIZERS = ['Character', 'Line', 'Markdown', 'Word'] as const;
|
||||
|
||||
/**
|
||||
|
|
@ -148,7 +148,8 @@ export interface ReconcileApi {
|
|||
* @param left - The left version of the text (either string or TextWithCursors with cursor positions)
|
||||
* @param right - The right version of the text (either string or TextWithCursors with cursor positions)
|
||||
* @param tokenizer - The tokenisation strategy: "Word" (default, recommended for prose),
|
||||
* "Character" (fine-grained), or "Line" (similar to git merge)
|
||||
* "Character" (fine-grained), "Line" (similar to git merge), or
|
||||
* "Markdown" (splits on Markdown structure)
|
||||
* @returns The reconciled text with automatically repositioned cursor positions
|
||||
*
|
||||
* @example
|
||||
|
|
@ -219,7 +220,8 @@ export interface ReconcileApi {
|
|||
* @param left - The left version of the text (either string or TextWithCursors with cursor positions)
|
||||
* @param right - The right version of the text (either string or TextWithCursors with cursor positions)
|
||||
* @param tokenizer - The tokenisation strategy: "Word" (default, recommended for prose),
|
||||
* "Character" (fine-grained), or "Line" (similar to git merge)
|
||||
* "Character" (fine-grained), "Line" (similar to git merge), or
|
||||
* "Markdown" (splits on Markdown structure)
|
||||
* @returns The reconciled text with cursor positions and detailed change history
|
||||
*
|
||||
* @example
|
||||
|
|
@ -351,7 +353,15 @@ export function makeReconcileApi(backend: WasmBackend): ReconcileApi {
|
|||
backend.ensureReady();
|
||||
assertTokenizer(tokenizer);
|
||||
|
||||
return backend.undiff(original, diffValue, tokenizer);
|
||||
// The real-WebAssembly backend's `diff` emits BigInt spans, whereas the
|
||||
// wasm2js (React Native) backend rejects BigInt outright. Normalise to
|
||||
// plain numbers - exactly as `diff` does on the way out - so a `diff`
|
||||
// result round-trips through `undiff` identically on every platform.
|
||||
return backend.undiff(
|
||||
original,
|
||||
diffValue.map((item) => (typeof item === 'bigint' ? Number(item) : item)),
|
||||
tokenizer
|
||||
);
|
||||
}
|
||||
|
||||
function reconcileWithHistory(
|
||||
|
|
|
|||
|
|
@ -60,6 +60,46 @@ describe('reconcile (wasm2js / React Native build)', () => {
|
|||
expect(result.text).toEqual('Hi world');
|
||||
expect(result.history.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('undiff accepts bigint entries (per the Array<number | bigint | string> type)', () => {
|
||||
const original = 'Hello world';
|
||||
const changed = 'Hello cruel world';
|
||||
|
||||
// `diff` returns plain numbers; emulate a caller that supplies BigInt, which
|
||||
// the public signature permits. The wasm2js (React Native) build rejects raw
|
||||
// BigInt, so the wrapper must normalise it to keep both backends identical.
|
||||
const withBigints = diff(original, changed).map((item) =>
|
||||
typeof item === 'number' ? BigInt(item) : item
|
||||
);
|
||||
|
||||
expect(withBigints.some((item) => typeof item === 'bigint')).toBe(true);
|
||||
expect(undiff(original, withBigints)).toEqual(changed);
|
||||
});
|
||||
|
||||
it('runs every operation with no WebAssembly global (Hermes parity)', () => {
|
||||
// Hermes exposes no `WebAssembly` global - the entire reason the React
|
||||
// Native entry point links a wasm2js (pure-JS) build instead of the real
|
||||
// module. Remove the global to prove the operations never reach for it.
|
||||
const descriptor = Object.getOwnPropertyDescriptor(globalThis, 'WebAssembly');
|
||||
delete (globalThis as { WebAssembly?: unknown }).WebAssembly;
|
||||
try {
|
||||
expect((globalThis as { WebAssembly?: unknown }).WebAssembly).toBeUndefined();
|
||||
|
||||
expect(reconcile('Hello', 'Hello world', 'Hi world').text).toEqual('Hi world');
|
||||
|
||||
const changes = diff('Hello world', 'Hello cruel world');
|
||||
expect(undiff('Hello world', changes)).toEqual('Hello cruel world');
|
||||
|
||||
expect(
|
||||
reconcileWithHistory('Hello', 'Hello world', 'Hi world').history.length
|
||||
).toBeGreaterThan(0);
|
||||
} finally {
|
||||
// Restore the global so the leak check and later suites are unaffected.
|
||||
if (descriptor) {
|
||||
Object.defineProperty(globalThis, 'WebAssembly', descriptor);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('test_diff_and_undiff_are_inverse (wasm2js / React Native build)', () => {
|
||||
|
|
|
|||
|
|
@ -60,6 +60,21 @@ describe('reconcile', () => {
|
|||
expect(result.text).toEqual('Hi world');
|
||||
expect(result.history.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('undiff accepts bigint entries (per the Array<number | bigint | string> type)', () => {
|
||||
const original = 'Hello world';
|
||||
const changed = 'Hello cruel world';
|
||||
|
||||
// `diff` returns plain numbers; emulate a caller that supplies BigInt, which
|
||||
// the public signature permits. The wasm2js (React Native) build rejects raw
|
||||
// BigInt, so the wrapper must normalise it to keep both backends identical.
|
||||
const withBigints = diff(original, changed).map((item) =>
|
||||
typeof item === 'number' ? BigInt(item) : item
|
||||
);
|
||||
|
||||
expect(withBigints.some((item) => typeof item === 'bigint')).toBe(true);
|
||||
expect(undiff(original, withBigints)).toEqual(changed);
|
||||
});
|
||||
});
|
||||
|
||||
describe('test_diff_and_undiff_are_inverse', () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue