@portabletext/editor 3.0.6 → 3.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import {compileSchema, defineSchema} from '@portabletext/schema'
2
2
  import {describe, expect, it} from 'vitest'
3
- import {fromSlateValue, toSlateBlock} from '../values'
3
+ import {toSlateBlock} from '../values'
4
4
 
5
5
  const schemaTypes = compileSchema(defineSchema({}))
6
6
 
@@ -51,7 +51,6 @@ describe(toSlateBlock.name, () => {
51
51
  text: '123',
52
52
  },
53
53
  ],
54
- style: 'normal',
55
54
  })
56
55
  })
57
56
 
@@ -106,125 +105,6 @@ describe(toSlateBlock.name, () => {
106
105
  },
107
106
  },
108
107
  ],
109
- style: 'normal',
110
108
  })
111
109
  })
112
110
  })
113
-
114
- describe('fromSlateValue', () => {
115
- it('runs given empty array', () => {
116
- const result = fromSlateValue([], 'image')
117
- expect(result).toHaveLength(0)
118
- })
119
-
120
- it('converts a slate value to portable text', () => {
121
- const ptValue = fromSlateValue(
122
- [
123
- {
124
- _type: 'block',
125
- _key: 'dr239u3',
126
- children: [
127
- {
128
- _type: 'span',
129
- _key: '252f4swet',
130
- marks: [],
131
- text: 'Hey ',
132
- },
133
- {
134
- _type: 'image',
135
- _key: 'e324t4s',
136
- __inline: true,
137
- children: [{_key: '1', _type: 'span', text: '', marks: []}],
138
- value: {
139
- _type: 'image',
140
- _key: 'e324t4s',
141
- asset: {_ref: '32423r32rewr3rwerwer'},
142
- },
143
- },
144
- ],
145
- markDefs: [],
146
- style: 'normal',
147
- },
148
- {
149
- _type: 'image',
150
- _key: 'wer32434',
151
- children: [{_key: '1', _type: 'span', text: '', marks: []}],
152
- value: {
153
- _type: 'image',
154
- _key: 'wer32434',
155
- asset: {_ref: 'werwer452423423'},
156
- },
157
- },
158
- ],
159
- 'block',
160
- )
161
- expect(ptValue).toEqual([
162
- {
163
- _type: 'block',
164
- _key: 'dr239u3',
165
- children: [
166
- {
167
- _type: 'span',
168
- _key: '252f4swet',
169
- marks: [],
170
- text: 'Hey ',
171
- },
172
- {
173
- _type: 'image',
174
- _key: 'e324t4s',
175
- asset: {_ref: '32423r32rewr3rwerwer'},
176
- },
177
- ],
178
- markDefs: [],
179
- style: 'normal',
180
- },
181
- {
182
- _type: 'image',
183
- _key: 'wer32434',
184
- asset: {_ref: 'werwer452423423'},
185
- },
186
- ])
187
- })
188
-
189
- it('has equality', () => {
190
- const keyMap = {}
191
- const value = [
192
- {
193
- _type: 'image',
194
- _key: 'wer32434',
195
- asset: {_ref: 'werwer452423423'},
196
- },
197
- {
198
- _type: 'block',
199
- _key: 'dr239u3',
200
- children: [
201
- {
202
- _type: 'span',
203
- _key: '252f4swet',
204
- marks: [],
205
- text: 'Hey ',
206
- },
207
- {
208
- _type: 'image',
209
- _key: 'e324t4s',
210
- asset: {_ref: '32423r32rewr3rwerwer'},
211
- },
212
- ],
213
- markDefs: [],
214
- style: 'normal',
215
- },
216
- ]
217
- const toSlate1 = value.map((block) =>
218
- toSlateBlock(block, {schemaTypes}, keyMap),
219
- )
220
- const toSlate2 = value.map((block) =>
221
- toSlateBlock(block, {schemaTypes}, keyMap),
222
- )
223
- expect(toSlate1[0]).toBe(toSlate2[0])
224
- expect(toSlate1[1]).toBe(toSlate2[1])
225
- const fromSlate1 = fromSlateValue(toSlate1, 'block', keyMap)
226
- const fromSlate2 = fromSlateValue(toSlate2, 'block', keyMap)
227
- expect(fromSlate1[0]).toBe(fromSlate2[0])
228
- expect(fromSlate1[1]).toBe(fromSlate2[1])
229
- })
230
- })
@@ -145,7 +145,7 @@ function insertPatch(
145
145
  const normalizedIdx =
146
146
  position === 'after' ? targetBlockIndex + 1 : targetBlockIndex
147
147
 
148
- const editorWasEmptyBefore = isEqualToEmptyEditor(editor.children, schema)
148
+ const editorWasEmptyBefore = isEqualToEmptyEditor(editor.value, schema)
149
149
 
150
150
  Transforms.insertNodes(editor, blocksToInsert, {at: [normalizedIdx]})
151
151
 
@@ -1,5 +1,9 @@
1
1
  import {compileSchemaDefinitionToPortableTextMemberSchemaTypes} from '@portabletext/sanity-bridge'
2
- import {compileSchema, defineSchema} from '@portabletext/schema'
2
+ import {
3
+ compileSchema,
4
+ defineSchema,
5
+ type PortableTextBlock,
6
+ } from '@portabletext/schema'
3
7
  import type {PortableTextTextBlock} from '@sanity/types'
4
8
  import {createEditor, type Descendant} from 'slate'
5
9
  import {beforeEach, describe, expect, it, test} from 'vitest'
@@ -32,13 +36,15 @@ const editorActor = createActor(editorMachine, {
32
36
  })
33
37
  const relayActor = createActor(relayMachine)
34
38
 
35
- const editor = withPlugins(createEditor(), {
39
+ const e = createEditor()
40
+ e.value = []
41
+ const editor = withPlugins(e, {
36
42
  editorActor,
37
43
  relayActor,
38
44
  subscriptions: [],
39
45
  })
40
46
 
41
- const createDefaultValue = () =>
47
+ const createDefaultChildren = () =>
42
48
  [
43
49
  {
44
50
  _type: 'block',
@@ -57,7 +63,25 @@ const createDefaultValue = () =>
57
63
  {_type: 'span', _key: 'fd9b4a4e6c0b', text: '', marks: []},
58
64
  ],
59
65
  },
60
- ] as Descendant[]
66
+ ] satisfies Array<Descendant>
67
+ const createDefaultValue = () =>
68
+ [
69
+ {
70
+ _type: 'block',
71
+ _key: '1f2e64b47787',
72
+ style: 'normal',
73
+ markDefs: [],
74
+ children: [
75
+ {_type: 'span', _key: 'c130395c640c', text: '', marks: []},
76
+ {
77
+ _key: '773866318fa8',
78
+ _type: 'someObject',
79
+ value: {title: 'The Object'},
80
+ },
81
+ {_type: 'span', _key: 'fd9b4a4e6c0b', text: '', marks: []},
82
+ ],
83
+ },
84
+ ] as Array<PortableTextBlock>
61
85
 
62
86
  describe(insertNodePatch.name, () => {
63
87
  test('Scenario: Inserting block object on empty editor', () => {
@@ -121,7 +145,7 @@ describe(insertNodePatch.name, () => {
121
145
 
122
146
  describe('operationToPatches', () => {
123
147
  beforeEach(() => {
124
- editor.children = createDefaultValue()
148
+ editor.children = createDefaultChildren()
125
149
  editor.onChange()
126
150
  })
127
151
 
@@ -418,12 +442,13 @@ describe('operationToPatches', () => {
418
442
  })
419
443
 
420
444
  it('produce correct remove block patch', () => {
445
+ const children = createDefaultChildren()
421
446
  const val = createDefaultValue()
422
447
  expect(
423
448
  removeNodePatch(editorActor.getSnapshot().context.schema, val, {
424
449
  type: 'remove_node',
425
450
  path: [0],
426
- node: val[0],
451
+ node: children[0],
427
452
  }),
428
453
  ).toMatchInlineSnapshot(`
429
454
  [
@@ -7,7 +7,7 @@ import {
7
7
  type InsertPosition,
8
8
  type Patch,
9
9
  } from '@portabletext/patches'
10
- import {isSpan, isTextBlock} from '@portabletext/schema'
10
+ import {isSpan, isTextBlock, type PortableTextBlock} from '@portabletext/schema'
11
11
  import type {Path, PortableTextSpan, PortableTextTextBlock} from '@sanity/types'
12
12
  import {
13
13
  Element,
@@ -29,7 +29,7 @@ export function insertTextPatch(
29
29
  schema: EditorSchema,
30
30
  children: Descendant[],
31
31
  operation: InsertTextOperation,
32
- beforeValue: Descendant[],
32
+ beforeValue: Array<PortableTextBlock>,
33
33
  ): Array<Patch> {
34
34
  const block =
35
35
  isTextBlock({schema}, children[operation.path[0]]) &&
@@ -62,7 +62,7 @@ export function removeTextPatch(
62
62
  schema: EditorSchema,
63
63
  children: Descendant[],
64
64
  operation: RemoveTextOperation,
65
- beforeValue: Descendant[],
65
+ beforeValue: Array<PortableTextBlock>,
66
66
  ): Array<Patch> {
67
67
  const block = children[operation.path[0]]
68
68
  if (!block) {
@@ -271,7 +271,7 @@ export function insertNodePatch(
271
271
  schema: EditorSchema,
272
272
  children: Descendant[],
273
273
  operation: InsertNodeOperation,
274
- beforeValue: Descendant[],
274
+ beforeValue: Array<PortableTextBlock>,
275
275
  ): Array<Patch> {
276
276
  const block = beforeValue[operation.path[0]]
277
277
  if (operation.path.length === 1) {
@@ -346,7 +346,7 @@ export function splitNodePatch(
346
346
  schema: EditorSchema,
347
347
  children: Descendant[],
348
348
  operation: SplitNodeOperation,
349
- beforeValue: Descendant[],
349
+ beforeValue: Array<PortableTextBlock>,
350
350
  ): Array<Patch> {
351
351
  const patches: Patch[] = []
352
352
  const splitBlock = children[operation.path[0]]
@@ -414,7 +414,7 @@ export function splitNodePatch(
414
414
 
415
415
  export function removeNodePatch(
416
416
  schema: EditorSchema,
417
- beforeValue: Descendant[],
417
+ beforeValue: Array<PortableTextBlock>,
418
418
  operation: RemoveNodeOperation,
419
419
  ): Array<Patch> {
420
420
  const block = beforeValue[operation.path[0]]
@@ -454,7 +454,7 @@ export function mergeNodePatch(
454
454
  schema: EditorSchema,
455
455
  children: Descendant[],
456
456
  operation: MergeNodeOperation,
457
- beforeValue: Descendant[],
457
+ beforeValue: Array<PortableTextBlock>,
458
458
  ): Array<Patch> {
459
459
  const patches: Patch[] = []
460
460
 
@@ -532,7 +532,7 @@ export function mergeNodePatch(
532
532
 
533
533
  export function moveNodePatch(
534
534
  schema: EditorSchema,
535
- beforeValue: Descendant[],
535
+ beforeValue: Array<PortableTextBlock>,
536
536
  operation: MoveNodeOperation,
537
537
  ): Array<Patch> {
538
538
  const patches: Patch[] = []
@@ -547,11 +547,7 @@ export function moveNodePatch(
547
547
  const position: InsertPosition =
548
548
  operation.path[0] > operation.newPath[0] ? 'before' : 'after'
549
549
  patches.push(unset([{_key: block._key}]))
550
- patches.push(
551
- insert([fromSlateBlock(block, schema.block.name)], position, [
552
- {_key: targetBlock._key},
553
- ]),
554
- )
550
+ patches.push(insert([block], position, [{_key: targetBlock._key}]))
555
551
  } else if (
556
552
  operation.path.length === 2 &&
557
553
  isTextBlock({schema}, block) &&
@@ -561,9 +557,7 @@ export function moveNodePatch(
561
557
  const targetChild = targetBlock.children[operation.newPath[1]]
562
558
  const position =
563
559
  operation.newPath[1] === targetBlock.children.length ? 'after' : 'before'
564
- const childToInsert = (
565
- fromSlateBlock(block, schema.block.name) as PortableTextTextBlock
566
- ).children[operation.path[1]]
560
+ const childToInsert = block.children[operation.path[1]]
567
561
  patches.push(unset([{_key: block._key}, 'children', {_key: child._key}]))
568
562
  patches.push(
569
563
  insert([childToInsert], position, [
@@ -32,7 +32,6 @@ describe(toSlateBlock.name, () => {
32
32
  text: 'foo',
33
33
  },
34
34
  ],
35
- style: 'normal',
36
35
  })
37
36
  })
38
37
 
@@ -62,7 +61,6 @@ describe(toSlateBlock.name, () => {
62
61
  text: 'foo',
63
62
  },
64
63
  ],
65
- style: 'normal',
66
64
  })
67
65
  })
68
66
 
@@ -101,7 +99,6 @@ describe(toSlateBlock.name, () => {
101
99
  __inline: true,
102
100
  },
103
101
  ],
104
- style: 'normal',
105
102
  })
106
103
  })
107
104
  })
@@ -148,7 +145,6 @@ describe(toSlateBlock.name, () => {
148
145
  },
149
146
  },
150
147
  ],
151
- style: 'normal',
152
148
  })
153
149
  })
154
150
 
@@ -191,7 +187,6 @@ describe(toSlateBlock.name, () => {
191
187
  },
192
188
  },
193
189
  ],
194
- style: 'normal',
195
190
  })
196
191
  })
197
192
  })
@@ -238,7 +233,6 @@ describe(toSlateBlock.name, () => {
238
233
  },
239
234
  },
240
235
  ],
241
- style: 'normal',
242
236
  })
243
237
  })
244
238
 
@@ -281,7 +275,6 @@ describe(toSlateBlock.name, () => {
281
275
  },
282
276
  },
283
277
  ],
284
- style: 'normal',
285
278
  })
286
279
  })
287
280
  })
@@ -35,7 +35,6 @@ export function toSlateBlock(
35
35
  if (isPortableText) {
36
36
  const textBlock = block as PortableTextTextBlock
37
37
  let hasInlines = false
38
- const hasMissingStyle = typeof textBlock.style === 'undefined'
39
38
  const hasMissingMarkDefs = typeof textBlock.markDefs === 'undefined'
40
39
  const hasMissingChildren = typeof textBlock.children === 'undefined'
41
40
 
@@ -86,7 +85,6 @@ export function toSlateBlock(
86
85
 
87
86
  // Return original block
88
87
  if (
89
- !hasMissingStyle &&
90
88
  !hasMissingMarkDefs &&
91
89
  !hasMissingChildren &&
92
90
  !hasInlines &&
@@ -96,11 +94,6 @@ export function toSlateBlock(
96
94
  return block
97
95
  }
98
96
 
99
- // TODO: remove this when we have a better way to handle missing style
100
- if (hasMissingStyle) {
101
- rest.style = schemaTypes.styles[0].name
102
- }
103
-
104
97
  return keepObjectEquality(
105
98
  {_type, _key, ...rest, children},
106
99
  keyMap,
@@ -125,14 +118,6 @@ export function toSlateBlock(
125
118
  ) as Descendant
126
119
  }
127
120
 
128
- export function fromSlateValue(
129
- value: Descendant[],
130
- textBlockType: string,
131
- keyMap: Record<string, PortableTextBlock | PortableTextChild> = {},
132
- ): PortableTextBlock[] {
133
- return value.map((block) => fromSlateBlock(block, textBlockType, keyMap))
134
- }
135
-
136
121
  export function fromSlateBlock(
137
122
  block: Descendant,
138
123
  textBlockType: string,
@@ -184,25 +169,76 @@ export function fromSlateBlock(
184
169
  }
185
170
 
186
171
  export function isEqualToEmptyEditor(
187
- children: Descendant[] | PortableTextBlock[],
172
+ blocks: Array<Descendant> | Array<PortableTextBlock>,
188
173
  schemaTypes: EditorSchema,
189
174
  ): boolean {
190
- return (
191
- children === undefined ||
192
- (children && Array.isArray(children) && children.length === 0) ||
193
- (children &&
194
- Array.isArray(children) &&
195
- children.length === 1 &&
196
- Element.isElement(children[0]) &&
197
- children[0]._type === schemaTypes.block.name &&
198
- 'style' in children[0] &&
199
- children[0].style === schemaTypes.styles[0].name &&
200
- !('listItem' in children[0]) &&
201
- Array.isArray(children[0].children) &&
202
- children[0].children.length === 1 &&
203
- Text.isText(children[0].children[0]) &&
204
- children[0].children[0]._type === 'span' &&
205
- !children[0].children[0].marks?.join('') &&
206
- children[0].children[0].text === '')
207
- )
175
+ // Must have exactly one block
176
+ if (blocks.length !== 1) {
177
+ return false
178
+ }
179
+
180
+ const firstBlock = blocks.at(0)
181
+
182
+ if (!firstBlock) {
183
+ return true
184
+ }
185
+
186
+ if (!Element.isElement(firstBlock)) {
187
+ return false
188
+ }
189
+
190
+ // Must be a text block
191
+ if (firstBlock._type !== schemaTypes.block.name) {
192
+ return false
193
+ }
194
+
195
+ // Must not be a list item
196
+ if ('listItem' in firstBlock) {
197
+ return false
198
+ }
199
+
200
+ // Style must exist and be the default style
201
+ if (
202
+ !('style' in firstBlock) ||
203
+ firstBlock.style !== schemaTypes.styles.at(0)?.name
204
+ ) {
205
+ return false
206
+ }
207
+
208
+ // Must have children array
209
+ if (!Array.isArray(firstBlock.children)) {
210
+ return false
211
+ }
212
+
213
+ // Must have exactly one child
214
+ if (firstBlock.children.length !== 1) {
215
+ return false
216
+ }
217
+
218
+ const firstChild = firstBlock.children.at(0)
219
+
220
+ if (!firstChild) {
221
+ return false
222
+ }
223
+
224
+ if (!Text.isText(firstChild)) {
225
+ return false
226
+ }
227
+
228
+ // Must be a span type
229
+ if (!('_type' in firstChild) || firstChild._type !== schemaTypes.span.name) {
230
+ return false
231
+ }
232
+
233
+ // Must have empty text
234
+ if (firstChild.text !== '') {
235
+ return false
236
+ }
237
+
238
+ // Must have no marks (marks can be undefined or empty array)
239
+ if (firstChild.marks?.join('')) {
240
+ return false
241
+ }
242
+
243
+ return true
208
244
  }
@@ -1,56 +1,32 @@
1
1
  import {isTextBlock} from '@portabletext/schema'
2
2
  import {omit} from 'lodash'
3
- import {Editor, Transforms} from 'slate'
4
- import {KEY_TO_VALUE_ELEMENT} from '../editor/weakMaps'
5
- import {toSlateRange} from '../internal-utils/to-slate-range'
6
- import {fromSlateBlock} from '../internal-utils/values'
3
+ import {Transforms} from 'slate'
7
4
  import {parseBlock} from '../utils/parse-blocks'
8
5
  import type {BehaviorOperationImplementation} from './behavior.operations'
9
6
 
10
7
  export const blockUnsetOperationImplementation: BehaviorOperationImplementation<
11
8
  'block.unset'
12
9
  > = ({context, operation}) => {
13
- const location = toSlateRange({
14
- context: {
15
- schema: context.schema,
16
- value: operation.editor.value,
17
- selection: {
18
- anchor: {path: operation.at, offset: 0},
19
- focus: {path: operation.at, offset: 0},
20
- },
21
- },
22
- blockIndexMap: operation.editor.blockIndexMap,
23
- })
10
+ const blockKey = operation.at[0]._key
11
+ const blockIndex = operation.editor.blockIndexMap.get(blockKey)
24
12
 
25
- if (!location) {
26
- throw new Error(
27
- `Unable to convert ${JSON.stringify(operation.at)} into a Slate Range`,
28
- )
13
+ if (blockIndex === undefined) {
14
+ throw new Error(`Unable to find block index for block key ${blockKey}`)
29
15
  }
30
16
 
31
- const blockEntry = Editor.node(operation.editor, location, {depth: 1})
32
- const block = blockEntry?.[0]
17
+ const block =
18
+ blockIndex !== undefined ? operation.editor.value.at(blockIndex) : undefined
33
19
 
34
20
  if (!block) {
35
21
  throw new Error(`Unable to find block at ${JSON.stringify(operation.at)}`)
36
22
  }
37
23
 
38
- const parsedBlock = fromSlateBlock(
39
- block,
40
- context.schema.block.name,
41
- KEY_TO_VALUE_ELEMENT.get(operation.editor),
42
- )
43
-
44
- if (!parsedBlock) {
45
- throw new Error(`Unable to parse block at ${JSON.stringify(operation.at)}`)
46
- }
47
-
48
- if (isTextBlock(context, parsedBlock)) {
24
+ if (isTextBlock(context, block)) {
49
25
  const propsToRemove = operation.props.filter((prop) => prop !== '_type')
50
26
 
51
27
  const updatedTextBlock = parseBlock({
52
28
  context,
53
- block: omit(parsedBlock, propsToRemove),
29
+ block: omit(block, propsToRemove),
54
30
  options: {
55
31
  normalize: false,
56
32
  removeUnusedMarkDefs: true,
@@ -74,7 +50,7 @@ export const blockUnsetOperationImplementation: BehaviorOperationImplementation<
74
50
  }
75
51
  }
76
52
 
77
- Transforms.setNodes(operation.editor, propsToSet, {at: location})
53
+ Transforms.setNodes(operation.editor, propsToSet, {at: [blockIndex]})
78
54
 
79
55
  return
80
56
  }
@@ -82,7 +58,7 @@ export const blockUnsetOperationImplementation: BehaviorOperationImplementation<
82
58
  const updatedBlockObject = parseBlock({
83
59
  context,
84
60
  block: omit(
85
- parsedBlock,
61
+ block,
86
62
  operation.props.filter((prop) => prop !== '_type'),
87
63
  ),
88
64
  options: {
@@ -105,6 +81,6 @@ export const blockUnsetOperationImplementation: BehaviorOperationImplementation<
105
81
  _key,
106
82
  value: props,
107
83
  },
108
- {at: location},
84
+ {at: [blockIndex]},
109
85
  )
110
86
  }
@@ -1,30 +1,48 @@
1
1
  import {applyAll} from '@portabletext/patches'
2
+ import {isTextBlock} from '@portabletext/schema'
2
3
  import {Editor, Element, Transforms} from 'slate'
3
- import {toSlateRange} from '../internal-utils/to-slate-range'
4
4
  import type {BehaviorOperationImplementation} from './behavior.operations'
5
5
 
6
6
  export const childUnsetOperationImplementation: BehaviorOperationImplementation<
7
7
  'child.unset'
8
8
  > = ({context, operation}) => {
9
- const location = toSlateRange({
10
- context: {
11
- schema: context.schema,
12
- value: operation.editor.value,
13
- selection: {
14
- anchor: {path: operation.at, offset: 0},
15
- focus: {path: operation.at, offset: 0},
16
- },
17
- },
18
- blockIndexMap: operation.editor.blockIndexMap,
19
- })
9
+ const blockKey = operation.at[0]._key
10
+ const blockIndex = operation.editor.blockIndexMap.get(blockKey)
11
+
12
+ if (blockIndex === undefined) {
13
+ throw new Error(`Unable to find block index for block key ${blockKey}`)
14
+ }
15
+
16
+ const block =
17
+ blockIndex !== undefined ? operation.editor.value.at(blockIndex) : undefined
18
+
19
+ if (!block) {
20
+ throw new Error(`Unable to find block at ${JSON.stringify(operation.at)}`)
21
+ }
22
+
23
+ if (!isTextBlock(context, block)) {
24
+ throw new Error(`Block ${JSON.stringify(blockKey)} is not a text block`)
25
+ }
26
+
27
+ const childKey = operation.at[2]._key
20
28
 
21
- if (!location) {
29
+ if (!childKey) {
22
30
  throw new Error(
23
- `Unable to convert ${JSON.stringify(operation.at)} into a Slate Range`,
31
+ `Unable to find child key at ${JSON.stringify(operation.at)}`,
24
32
  )
25
33
  }
26
34
 
27
- const childEntry = Editor.node(operation.editor, location, {depth: 2})
35
+ const childIndex = block.children.findIndex(
36
+ (child) => child._key === childKey,
37
+ )
38
+
39
+ if (childIndex === -1) {
40
+ throw new Error(`Unable to find child at ${JSON.stringify(operation.at)}`)
41
+ }
42
+
43
+ const childEntry = Editor.node(operation.editor, [blockIndex, childIndex], {
44
+ depth: 2,
45
+ })
28
46
  const child = childEntry?.[0]
29
47
  const childPath = childEntry?.[1]
30
48