Skip to content

Commit cfdcf10

Browse files
committed
fixup! feat: Portable Text-native node traversal
1 parent 3b0b1b3 commit cfdcf10

File tree

15 files changed

+274
-146
lines changed

15 files changed

+274
-146
lines changed
Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import {describe, expect, test} from 'vitest'
22
import {getChildren} from './get-children'
3-
import {createTestbed} from './testbed'
3+
import {allEditableTypes, createTestbed} from './testbed'
44

55
describe(getChildren.name, () => {
66
const testbed = createTestbed()
77

88
test('root children', () => {
9-
expect(getChildren(testbed.root, [], testbed.schema)).toEqual([
9+
expect(
10+
getChildren(testbed.root, [], testbed.schema, allEditableTypes),
11+
).toEqual([
1012
testbed.textBlock1,
1113
testbed.image,
1214
testbed.textBlock2,
@@ -16,63 +18,74 @@ describe(getChildren.name, () => {
1618
})
1719

1820
test('text block children', () => {
19-
expect(getChildren(testbed.root, [0], testbed.schema)).toEqual([
20-
testbed.span1,
21-
testbed.stockTicker1,
22-
testbed.span2,
23-
])
21+
expect(
22+
getChildren(testbed.root, [0], testbed.schema, allEditableTypes),
23+
).toEqual([testbed.span1, testbed.stockTicker1, testbed.span2])
2424
})
2525

2626
test('code block children (code lines)', () => {
27-
expect(getChildren(testbed.root, [3], testbed.schema)).toEqual([
28-
testbed.codeLine1,
29-
testbed.codeLine2,
30-
])
27+
expect(
28+
getChildren(testbed.root, [3], testbed.schema, allEditableTypes),
29+
).toEqual([testbed.codeLine1, testbed.codeLine2])
3130
})
3231

3332
test('code line children', () => {
34-
expect(getChildren(testbed.root, [3, 0], testbed.schema)).toEqual([
35-
testbed.codeSpan1,
36-
])
33+
expect(
34+
getChildren(testbed.root, [3, 0], testbed.schema, allEditableTypes),
35+
).toEqual([testbed.codeSpan1])
3736
})
3837

3938
test('table children (rows)', () => {
40-
expect(getChildren(testbed.root, [4], testbed.schema)).toEqual([
41-
testbed.row1,
42-
testbed.row2,
43-
])
39+
expect(
40+
getChildren(testbed.root, [4], testbed.schema, allEditableTypes),
41+
).toEqual([testbed.row1, testbed.row2])
4442
})
4543

4644
test('row children (cells)', () => {
47-
expect(getChildren(testbed.root, [4, 0], testbed.schema)).toEqual([
48-
testbed.cell1,
49-
testbed.cell2,
50-
])
45+
expect(
46+
getChildren(testbed.root, [4, 0], testbed.schema, allEditableTypes),
47+
).toEqual([testbed.cell1, testbed.cell2])
5148
})
5249

5350
test('cell with multiple blocks', () => {
54-
expect(getChildren(testbed.root, [4, 0, 0], testbed.schema)).toEqual([
55-
testbed.cellBlock1,
56-
testbed.cellBlock2,
57-
])
51+
expect(
52+
getChildren(testbed.root, [4, 0, 0], testbed.schema, allEditableTypes),
53+
).toEqual([testbed.cellBlock1, testbed.cellBlock2])
5854
})
5955

6056
test('block inside cell children', () => {
61-
expect(getChildren(testbed.root, [4, 0, 0, 0], testbed.schema)).toEqual([
62-
testbed.cellSpan1,
63-
testbed.stockTicker2,
64-
])
57+
expect(
58+
getChildren(testbed.root, [4, 0, 0, 0], testbed.schema, allEditableTypes),
59+
).toEqual([testbed.cellSpan1, testbed.stockTicker2])
6560
})
6661

6762
test('leaf node returns empty array', () => {
68-
expect(getChildren(testbed.root, [0, 0], testbed.schema)).toEqual([])
63+
expect(
64+
getChildren(testbed.root, [0, 0], testbed.schema, allEditableTypes),
65+
).toEqual([])
6966
})
7067

7168
test('block object without children returns empty array', () => {
72-
expect(getChildren(testbed.root, [1], testbed.schema)).toEqual([])
69+
expect(
70+
getChildren(testbed.root, [1], testbed.schema, allEditableTypes),
71+
).toEqual([])
7372
})
7473

7574
test('invalid path returns empty array', () => {
76-
expect(getChildren(testbed.root, [99], testbed.schema)).toEqual([])
75+
expect(
76+
getChildren(testbed.root, [99], testbed.schema, allEditableTypes),
77+
).toEqual([])
78+
})
79+
80+
test('non-editable code block returns empty array', () => {
81+
const tableOnly = new Set(['table', 'table.row', 'table.row.cell'])
82+
expect(getChildren(testbed.root, [3], testbed.schema, tableOnly)).toEqual(
83+
[],
84+
)
85+
})
86+
87+
test('non-editable table returns empty array', () => {
88+
const codeOnly = new Set(['code-block'])
89+
expect(getChildren(testbed.root, [4], testbed.schema, codeOnly)).toEqual([])
7790
})
7891
})

packages/editor/src/node-traversal/get-children.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ export function getChildren(
99
root: {children: Array<Node>},
1010
path: Array<number>,
1111
schema: EditorSchema,
12+
editableTypes: Set<string>,
1213
): Array<Node> {
1314
let currentChildren: Array<Node> = root.children
1415
let currentScope: ReadonlyArray<OfDefinition> | undefined
16+
let scopePath = ''
1517

1618
for (const index of path) {
1719
const node = currentChildren[index]
@@ -24,6 +26,12 @@ export function getChildren(
2426
currentChildren = node.children
2527
currentScope = undefined
2628
} else if (isObjectNode({schema}, node)) {
29+
const scopedKey = scopePath ? `${scopePath}.${node._type}` : node._type
30+
31+
if (!editableTypes.has(scopedKey)) {
32+
return []
33+
}
34+
2735
const arrayField = resolveChildArrayField(
2836
{schema, scope: currentScope},
2937
node,
@@ -37,6 +45,7 @@ export function getChildren(
3745
arrayField.name
3846
] as Array<Node>
3947
currentScope = arrayField.of
48+
scopePath = scopedKey
4049
} else {
4150
return []
4251
}
Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,56 @@
11
import {describe, expect, test} from 'vitest'
22
import {getFirst} from './get-first'
3-
import {createTestbed} from './testbed'
3+
import {allEditableTypes, createTestbed} from './testbed'
44

55
describe(getFirst.name, () => {
66
const testbed = createTestbed()
77

88
test('first descendant from root', () => {
9-
expect(getFirst(testbed.root, [], testbed.schema)).toEqual([
10-
testbed.textBlock1,
11-
[0],
12-
])
9+
expect(
10+
getFirst(testbed.root, [], testbed.schema, allEditableTypes),
11+
).toEqual([testbed.textBlock1, [0]])
1312
})
1413

1514
test('first descendant of text block', () => {
16-
expect(getFirst(testbed.root, [0], testbed.schema)).toEqual([
17-
testbed.span1,
18-
[0, 0],
19-
])
15+
expect(
16+
getFirst(testbed.root, [0], testbed.schema, allEditableTypes),
17+
).toEqual([testbed.span1, [0, 0]])
2018
})
2119

2220
test('first descendant of code block', () => {
23-
expect(getFirst(testbed.root, [3], testbed.schema)).toEqual([
24-
testbed.codeLine1,
25-
[3, 0],
26-
])
21+
expect(
22+
getFirst(testbed.root, [3], testbed.schema, allEditableTypes),
23+
).toEqual([testbed.codeLine1, [3, 0]])
2724
})
2825

2926
test('first descendant of table', () => {
30-
expect(getFirst(testbed.root, [4], testbed.schema)).toEqual([
31-
testbed.row1,
32-
[4, 0],
33-
])
27+
expect(
28+
getFirst(testbed.root, [4], testbed.schema, allEditableTypes),
29+
).toEqual([testbed.row1, [4, 0]])
3430
})
3531

3632
test('leaf node returns undefined', () => {
37-
expect(getFirst(testbed.root, [0, 0], testbed.schema)).toBeUndefined()
33+
expect(
34+
getFirst(testbed.root, [0, 0], testbed.schema, allEditableTypes),
35+
).toBeUndefined()
3836
})
3937

4038
test('void block object returns undefined', () => {
41-
expect(getFirst(testbed.root, [1], testbed.schema)).toBeUndefined()
39+
expect(
40+
getFirst(testbed.root, [1], testbed.schema, allEditableTypes),
41+
).toBeUndefined()
4242
})
4343

4444
test('invalid path returns undefined', () => {
45-
expect(getFirst(testbed.root, [99], testbed.schema)).toBeUndefined()
45+
expect(
46+
getFirst(testbed.root, [99], testbed.schema, allEditableTypes),
47+
).toBeUndefined()
48+
})
49+
50+
test('first of non-editable container returns undefined', () => {
51+
const tableOnly = new Set(['table', 'table.row', 'table.row.cell'])
52+
expect(
53+
getFirst(testbed.root, [3], testbed.schema, tableOnly),
54+
).toBeUndefined()
4655
})
4756
})

packages/editor/src/node-traversal/get-first.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ export function getFirst(
66
root: {children: Array<Node>},
77
path: Array<number>,
88
schema: EditorSchema,
9+
editableTypes: Set<string>,
910
): [Node, Array<number>] | undefined {
10-
const children = getChildren(root, path, schema)
11+
const children = getChildren(root, path, schema, editableTypes)
1112
const first = children[0]
1213

1314
if (!first) {
Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,56 @@
11
import {describe, expect, test} from 'vitest'
22
import {getLast} from './get-last'
3-
import {createTestbed} from './testbed'
3+
import {allEditableTypes, createTestbed} from './testbed'
44

55
describe(getLast.name, () => {
66
const testbed = createTestbed()
77

88
test('last descendant from root', () => {
9-
expect(getLast(testbed.root, [], testbed.schema)).toEqual([
10-
testbed.table,
11-
[4],
12-
])
9+
expect(getLast(testbed.root, [], testbed.schema, allEditableTypes)).toEqual(
10+
[testbed.table, [4]],
11+
)
1312
})
1413

1514
test('last descendant of text block', () => {
16-
expect(getLast(testbed.root, [0], testbed.schema)).toEqual([
17-
testbed.span2,
18-
[0, 2],
19-
])
15+
expect(
16+
getLast(testbed.root, [0], testbed.schema, allEditableTypes),
17+
).toEqual([testbed.span2, [0, 2]])
2018
})
2119

2220
test('last descendant of code block', () => {
23-
expect(getLast(testbed.root, [3], testbed.schema)).toEqual([
24-
testbed.codeLine2,
25-
[3, 1],
26-
])
21+
expect(
22+
getLast(testbed.root, [3], testbed.schema, allEditableTypes),
23+
).toEqual([testbed.codeLine2, [3, 1]])
2724
})
2825

2926
test('last descendant of table', () => {
30-
expect(getLast(testbed.root, [4], testbed.schema)).toEqual([
31-
testbed.row2,
32-
[4, 1],
33-
])
27+
expect(
28+
getLast(testbed.root, [4], testbed.schema, allEditableTypes),
29+
).toEqual([testbed.row2, [4, 1]])
3430
})
3531

3632
test('leaf node returns undefined', () => {
37-
expect(getLast(testbed.root, [0, 0], testbed.schema)).toBeUndefined()
33+
expect(
34+
getLast(testbed.root, [0, 0], testbed.schema, allEditableTypes),
35+
).toBeUndefined()
3836
})
3937

4038
test('void block object returns undefined', () => {
41-
expect(getLast(testbed.root, [1], testbed.schema)).toBeUndefined()
39+
expect(
40+
getLast(testbed.root, [1], testbed.schema, allEditableTypes),
41+
).toBeUndefined()
4242
})
4343

4444
test('invalid path returns undefined', () => {
45-
expect(getLast(testbed.root, [99], testbed.schema)).toBeUndefined()
45+
expect(
46+
getLast(testbed.root, [99], testbed.schema, allEditableTypes),
47+
).toBeUndefined()
48+
})
49+
50+
test('last of non-editable container returns undefined', () => {
51+
const tableOnly = new Set(['table', 'table.row', 'table.row.cell'])
52+
expect(
53+
getLast(testbed.root, [3], testbed.schema, tableOnly),
54+
).toBeUndefined()
4655
})
4756
})

packages/editor/src/node-traversal/get-last.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ export function getLast(
66
root: {children: Array<Node>},
77
path: Array<number>,
88
schema: EditorSchema,
9+
editableTypes: Set<string>,
910
): [Node, Array<number>] | undefined {
10-
const children = getChildren(root, path, schema)
11+
const children = getChildren(root, path, schema, editableTypes)
1112
const lastIndex = children.length - 1
1213
const last = children[lastIndex]
1314

0 commit comments

Comments
 (0)