Skip to content

Commit

Permalink
Merge pull request #2984 from udecode/fix/string-char-mapping-key-order
Browse files Browse the repository at this point in the history
Fix `StringCharMapping` key order dependency
  • Loading branch information
12joan authored Feb 19, 2024
2 parents c8c7ae6 + d523a07 commit bec7349
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 26 deletions.
5 changes: 5 additions & 0 deletions .changeset/great-buses-switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@udecode/plate-diff": patch
---

Fix: Node equivalency checking is incorrectly dependent on the key order of the node object
10 changes: 10 additions & 0 deletions packages/diff/src/internal/utils/string-char-mapping.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { StringCharMapping } from './string-char-mapping';

describe('StringCharMapping', () => {
it('treats nodes as equivalent regardless of key order', () => {
const map = new StringCharMapping();
const c1 = map.nodeToChar({ type: 'a', children: [] });
const c2 = map.nodeToChar({ children: [], type: 'a' });
expect(c1).toBe(c2);
});
});
43 changes: 17 additions & 26 deletions packages/diff/src/internal/utils/string-char-mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,28 @@
*/

import { TDescendant } from '@udecode/plate-common';
import isEqual from 'lodash/isEqual.js';

import { unusedCharGenerator } from './unused-char-generator';

export class StringCharMapping {
private _nextChar: string = 'A';
private _charToNode: Map<string, TDescendant> = new Map();
private _keyToChar: Map<string, string> = new Map();
private _charGenerator = unusedCharGenerator();
private _mappedNodes: [TDescendant, string][] = [];

public nodesToString(nodes: TDescendant[]): string {
return nodes.map(this.nodeToChar.bind(this)).join('');
}

public nodeToChar(node: TDescendant): string {
const key = this.getKeyForNode(node);

const existingChar = this._keyToChar.get(key);
if (existingChar) return existingChar;

const c = this.getNextChar();

this._keyToChar.set(key, c);
this._charToNode.set(c, node);

// Check for a previously assigned character
for (const [n, c] of this._mappedNodes) {
if (isEqual(n, node)) {
return c;
}
}

const c = this._charGenerator.next().value;
this._mappedNodes.push([node, c]);
return c;
}

Expand All @@ -33,18 +34,8 @@ export class StringCharMapping {
}

public charToNode(c: string): TDescendant {
const node = this._charToNode.get(c);
if (!node) throw new Error(`No node found for char ${c}`);
return node;
}

private getKeyForNode(node: TDescendant): string {
return JSON.stringify(node);
}

private getNextChar(): string {
const c = this._nextChar;
this._nextChar = String.fromCodePoint(this._nextChar.codePointAt(0)! + 1);
return c;
const entry = this._mappedNodes.find(([_node, c2]) => c2 === c);
if (!entry) throw new Error(`No node found for char ${c}`);
return entry[0];
}
}

0 comments on commit bec7349

Please sign in to comment.