Skip to content

Commit de7dcbc

Browse files
authored
fix(super-editor): null-safe getTrackChanges to avoid init-race crash (SD-2641) (#3253)
createCommentForTrackChanges is scheduled from processLoadedDocxComments via setTimeout(0). That only defers to the next tick; it does not wait for the editor's PM state to be initialized. When the bootstrap fires before editor.state is attached, getTrackChanges(editor.state) becomes getTrackChanges(undefined) and crashes reading state.doc. The same race affects all four call sites of getTrackChanges in comments-store.js (lines 294, 1143, 1453, 1545), so harden the helper once rather than guarding each caller. A pure helper returning [] when there is no state to inspect is the semantically correct null behaviour. Adds focused unit tests covering undefined / null / missing-doc inputs.
1 parent 53e2c47 commit de7dcbc

2 files changed

Lines changed: 34 additions & 2 deletions

File tree

packages/super-editor/src/editors/v1/extensions/track-changes/trackChangesHelpers/getTrackChanges.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,18 @@ import { findInlineNodes } from './documentHelpers.js';
33

44
/**
55
* Get track changes marks.
6-
* @param {import('prosemirror-state').EditorState} state
7-
* @param {string} id
6+
*
7+
* Tolerates a missing or partially-initialized state and returns an empty array
8+
* instead of throwing. Comment-import bootstrap can call this through a
9+
* setTimeout(0) before the editor's PM state is attached (SD-2641).
10+
*
11+
* @param {import('prosemirror-state').EditorState | null | undefined} state
12+
* @param {string} [id]
813
* @returns {Array} Array with track changes marks.
914
*/
1015
export const getTrackChanges = (state, id = null) => {
1116
const trackedChanges = [];
17+
if (!state?.doc) return trackedChanges;
1218
const allInlineNodes = findInlineNodes(state.doc);
1319

1420
if (!allInlineNodes.length) {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { describe, test, expect } from 'vitest';
2+
import { getTrackChanges } from './getTrackChanges.js';
3+
4+
// SD-2641: The helper must not throw when called before the editor's PM state
5+
// is initialized. During DOCX comment-import bootstrap, the orchestrator schedules
6+
// the call via setTimeout(0) which only defers to the next tick — it does not wait
7+
// for editor.state to be attached. The helper is reused from 4 call sites in
8+
// comments-store.js, so we harden it once at the source rather than guarding each
9+
// caller.
10+
describe('getTrackChanges — null-safe input handling', () => {
11+
test('returns [] when state is undefined', () => {
12+
expect(getTrackChanges(undefined)).toEqual([]);
13+
});
14+
15+
test('returns [] when state is null', () => {
16+
expect(getTrackChanges(null)).toEqual([]);
17+
});
18+
19+
test('returns [] when state has no doc property', () => {
20+
expect(getTrackChanges({})).toEqual([]);
21+
});
22+
23+
test('returns [] when state.doc is undefined', () => {
24+
expect(getTrackChanges({ doc: undefined })).toEqual([]);
25+
});
26+
});

0 commit comments

Comments
 (0)