@prismicio/types-internal 2.2.0-traverse.alpha-0 → 2.2.0-traverse.alpha-2

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.
Files changed (40) hide show
  1. package/lib/_internal/utils.d.ts +21 -4
  2. package/lib/_internal/utils.js +11 -0
  3. package/lib/content/Document.d.ts +2185 -13
  4. package/lib/content/Document.js +130 -35
  5. package/lib/content/fields/GroupContent.d.ts +11 -4
  6. package/lib/content/fields/GroupContent.js +31 -15
  7. package/lib/content/fields/slices/Slice/CompositeSliceContent.d.ts +8 -6
  8. package/lib/content/fields/slices/Slice/CompositeSliceContent.js +33 -36
  9. package/lib/content/fields/slices/Slice/SharedSliceContent.d.ts +8 -6
  10. package/lib/content/fields/slices/Slice/SharedSliceContent.js +28 -38
  11. package/lib/content/fields/slices/Slice/SimpleSliceContent.d.ts +10 -0
  12. package/lib/content/fields/slices/Slice/SimpleSliceContent.js +60 -1
  13. package/lib/content/fields/slices/SliceItem.d.ts +15 -0
  14. package/lib/content/fields/slices/SliceItem.js +15 -1
  15. package/lib/content/fields/slices/SlicesContent.d.ts +4 -3
  16. package/lib/content/fields/slices/SlicesContent.js +125 -62
  17. package/lib/customtypes/CustomType.d.ts +4 -0
  18. package/lib/customtypes/CustomType.js +18 -1
  19. package/lib/customtypes/Section.d.ts +3 -0
  20. package/lib/customtypes/diff/SharedSlice.d.ts +6 -0
  21. package/lib/customtypes/widgets/Widget.d.ts +3 -0
  22. package/lib/customtypes/widgets/slices/CompositeSlice.d.ts +5 -0
  23. package/lib/customtypes/widgets/slices/SharedSlice.d.ts +8 -0
  24. package/lib/customtypes/widgets/slices/SharedSlice.js +3 -0
  25. package/lib/customtypes/widgets/slices/Slices.d.ts +6 -0
  26. package/lib/import/validators/fields/ImportSlices/SharedSlice/utils.d.ts +3 -0
  27. package/package.json +1 -1
  28. package/src/_internal/utils.ts +63 -7
  29. package/src/content/Document.ts +177 -42
  30. package/src/content/fields/GroupContent.ts +50 -16
  31. package/src/content/fields/slices/Slice/CompositeSliceContent.ts +55 -44
  32. package/src/content/fields/slices/Slice/SharedSliceContent.ts +43 -49
  33. package/src/content/fields/slices/Slice/SimpleSliceContent.ts +99 -1
  34. package/src/content/fields/slices/SliceItem.ts +39 -3
  35. package/src/content/fields/slices/SlicesContent.ts +172 -69
  36. package/src/customtypes/CustomType.ts +21 -0
  37. package/src/customtypes/widgets/slices/CompositeSlice.ts +6 -0
  38. package/src/customtypes/widgets/slices/SharedSlice.ts +12 -0
  39. package/lib/validators/NullOrT.d.ts +0 -2
  40. package/lib/validators/NullOrT.js +0 -12
@@ -3,15 +3,26 @@ import { isLeft, isRight } from "fp-ts/lib/Either"
3
3
  import { pipe } from "fp-ts/lib/function"
4
4
  import * as t from "io-ts"
5
5
 
6
- import { type TraverseContentFn, ContentPath } from "../_internal/utils"
6
+ import {
7
+ ContentPath,
8
+ TraverseSliceContentFn,
9
+ TraverseWidgetContentFn,
10
+ } from "../_internal/utils"
7
11
  import { WidgetKey } from "../common"
8
12
  import {
9
- type StaticCustomType,
10
13
  type StaticWidget,
14
+ collectSharedSlices,
11
15
  flattenStaticWidgets,
16
+ StaticCustomType,
17
+ VariationFields,
12
18
  } from "../customtypes"
13
19
  import {
14
- SliceContent,
20
+ CompositeSliceItemContent,
21
+ GroupItemContent,
22
+ isCompositeSliceItemContent,
23
+ isSimpleSliceItemContent,
24
+ SharedSliceItemContent,
25
+ SimpleSliceItemContent,
15
26
  traverseGroupContent,
16
27
  traverseSlices,
17
28
  WidgetContent,
@@ -119,7 +130,10 @@ function extractMetadata(data: { [p: string]: unknown }): {
119
130
  }
120
131
  }
121
132
 
122
- function parseLegacyDocument(legacyDoc: unknown): Document | undefined {
133
+ function parseLegacyDocument(
134
+ legacyDoc: unknown,
135
+ customType: StaticCustomType,
136
+ ): Document | undefined {
123
137
  const result = pipe(
124
138
  // ensure it's the right document format first
125
139
  t.record(WidgetKey, t.unknown).decode(legacyDoc),
@@ -131,7 +145,7 @@ function parseLegacyDocument(legacyDoc: unknown): Document | undefined {
131
145
  }),
132
146
  )
133
147
 
134
- return isLeft(result) ? undefined : result.right
148
+ return isLeft(result) ? undefined : migrateDocument(result.right, customType)
135
149
  }
136
150
 
137
151
  function encodeToLegacyDocument(document: Document): DocumentLegacy {
@@ -153,9 +167,21 @@ export const DocumentLegacy = {
153
167
  * @param transform: A user function that provides a way to transform any kind of content wherever it is in a structured Prismic object content.
154
168
  * @returns a transformed document with the user's transformation applied with the transform function
155
169
  */
156
- export function traverseDocument(document: Document, model?: StaticCustomType) {
157
- return (transform: TraverseContentFn): Document => {
158
- const fieldDefs =
170
+ export function traverseDocument({
171
+ document,
172
+ model,
173
+ }: {
174
+ document: Document
175
+ model?: StaticCustomType
176
+ }) {
177
+ return ({
178
+ transformWidget = ({ content }) => content,
179
+ transformSlice = ({ content }) => content,
180
+ }: {
181
+ transformWidget?: TraverseWidgetContentFn
182
+ transformSlice?: TraverseSliceContentFn
183
+ }): Document => {
184
+ const fieldModels =
159
185
  model &&
160
186
  flattenStaticWidgets(model).reduce<Record<string, StaticWidget>>(
161
187
  (acc, [key, def]) => ({ ...acc, [key]: def }),
@@ -163,40 +189,49 @@ export function traverseDocument(document: Document, model?: StaticCustomType) {
163
189
  )
164
190
 
165
191
  return Object.entries(document).reduce((acc, [key, content]) => {
166
- const fieldDef = fieldDefs && fieldDefs[key]
192
+ const fieldModel = fieldModels && fieldModels[key]
193
+
194
+ const path = ContentPath.make([
195
+ { key: model?.id, type: "CustomType" },
196
+ { key, type: "Widget" },
197
+ ])
167
198
 
168
- const path = [{ key, type: content.__TYPE__ }]
169
- const transformedWidgetContent = (() => {
199
+ const transformedWidget = (() => {
170
200
  switch (content.__TYPE__) {
171
201
  case "SliceContentType":
172
202
  return traverseSlices({
173
203
  path,
204
+ key,
174
205
  model:
175
- fieldDef?.type === "Slices" || fieldDef?.type === "Choice"
176
- ? fieldDef
206
+ fieldModel?.type === "Slices" || fieldModel?.type === "Choice"
207
+ ? fieldModel
177
208
  : undefined,
178
209
  content,
179
- })(transform)
210
+ })(transformWidget, transformSlice)
180
211
  case "GroupContentType":
181
212
  return traverseGroupContent({
182
213
  path,
183
- model: fieldDef?.type === "Group" ? fieldDef : undefined,
214
+ key,
215
+ apiId: key,
216
+ model: fieldModel?.type === "Group" ? fieldModel : undefined,
184
217
  content,
185
- })(transform)
218
+ })(transformWidget)
186
219
  default:
187
- return content
220
+ return transformWidget({
221
+ path,
222
+ key,
223
+ apiId: key,
224
+ model:
225
+ fieldModel?.type !== "Group" &&
226
+ fieldModel?.type !== "Slices" &&
227
+ fieldModel?.type !== "Choice"
228
+ ? fieldModel
229
+ : undefined,
230
+ content,
231
+ })
188
232
  }
189
233
  })()
190
234
 
191
- const transformedWidget =
192
- transformedWidgetContent &&
193
- transform({
194
- path,
195
- key,
196
- apiId: key,
197
- model: fieldDef,
198
- content: transformedWidgetContent,
199
- })
200
235
  return {
201
236
  ...acc,
202
237
  ...(transformedWidget ? { [key]: transformedWidget } : {}),
@@ -205,26 +240,126 @@ export function traverseDocument(document: Document, model?: StaticCustomType) {
205
240
  }
206
241
  }
207
242
 
208
- /**
209
- * The goal is to be able to collect all widgets or slices of a given type at any level of nesting inside a prismic content
210
- *
211
- * @param document parsed prismic content
212
- * @param is typeguard to match specifically the type of widget we want to collect
213
- * @returns a record containing the path of the widget as key and the typed collected content as value
214
- */
215
- export function collectWidgets<W extends WidgetContent | SliceContent>(
243
+ // /**
244
+ // * The goal is to be able to collect all widgets or slices of a given type at any level of nesting inside a prismic content
245
+ // *
246
+ // * @param document parsed prismic content
247
+ // * @param is typeguard to match specifically the type of widget we want to collect
248
+ // * @returns a record containing the path of the widget as key and the typed collected content as value
249
+ // */
250
+ export function collectWidgets<W extends WidgetContent>(
216
251
  document: Document,
217
- is: (
218
- content: WidgetContent | SliceContent,
219
- path: ContentPath,
220
- ) => content is W,
252
+ is: (content: WidgetContent, path: ContentPath) => content is W,
221
253
  ): Record<string, W> {
222
254
  const collected: Record<string, W> = {}
223
255
 
224
- traverseDocument(document)(({ content, path }) => {
225
- const key = ContentPath.serialize(path)
226
- if (is(content, path)) collected[key] = content
227
- return content
256
+ traverseDocument({ document })({
257
+ transformWidget: ({ content, path }) => {
258
+ const key = ContentPath.serialize(path)
259
+ if (is(content, path)) collected[key] = content
260
+ return content
261
+ },
228
262
  })
229
263
  return collected
230
264
  }
265
+
266
+ function migrateCompositeSlice(
267
+ model: VariationFields,
268
+ content: CompositeSliceItemContent,
269
+ ): SharedSliceItemContent {
270
+ return {
271
+ key: content.key,
272
+ name: model.sliceName,
273
+ maybeLabel: content.maybeLabel,
274
+ widget: {
275
+ __TYPE__: "SharedSliceContent",
276
+ variation: model.variationId,
277
+ primary: Object.entries(content.widget.nonRepeat).reduce(
278
+ (acc, [fieldKey, fieldContent]) => {
279
+ return model.fields.primary?.[fieldKey]
280
+ ? { ...acc, [fieldKey]: fieldContent }
281
+ : acc
282
+ },
283
+ {},
284
+ ),
285
+ items: content.widget.repeat.map((groupItem) => {
286
+ return {
287
+ __TYPE__: "GroupItemContent",
288
+ value: groupItem.value.reduce<GroupItemContent["value"]>(
289
+ (acc, [fieldKey, fieldContent]) => {
290
+ return model.fields.items?.[fieldKey]
291
+ ? acc.concat([[fieldKey, fieldContent]])
292
+ : acc
293
+ },
294
+ [],
295
+ ),
296
+ }
297
+ }, []),
298
+ },
299
+ }
300
+ }
301
+
302
+ function migrateSimpleSlice(
303
+ model: VariationFields,
304
+ content: SimpleSliceItemContent,
305
+ ): SharedSliceItemContent {
306
+ if (content.widget.__TYPE__ === "GroupContentType") {
307
+ return {
308
+ key: content.key,
309
+ name: model.sliceName,
310
+ maybeLabel: content.maybeLabel,
311
+ widget: {
312
+ __TYPE__: "SharedSliceContent",
313
+ variation: model.variationId,
314
+ primary: {},
315
+ items: content.widget.value.map((groupItem) => {
316
+ return {
317
+ __TYPE__: "GroupItemContent",
318
+ value: groupItem.value.reduce<GroupItemContent["value"]>(
319
+ (acc, [fieldKey, fieldContent]) => {
320
+ return model.fields.items?.[fieldKey]
321
+ ? acc.concat([[fieldKey, fieldContent]])
322
+ : acc
323
+ },
324
+ [],
325
+ ),
326
+ }
327
+ }, []),
328
+ },
329
+ }
330
+ }
331
+ return {
332
+ key: content.key,
333
+ name: model.sliceName,
334
+ maybeLabel: content.maybeLabel,
335
+ widget: {
336
+ __TYPE__: "SharedSliceContent",
337
+ variation: model.variationId,
338
+ primary: model.fields.primary?.[content.name]
339
+ ? { [content.key]: content.widget }
340
+ : {},
341
+ items: [],
342
+ },
343
+ }
344
+ }
345
+
346
+ export function migrateDocument(document: Document, model: StaticCustomType) {
347
+ const needsMigration = Object.values(collectSharedSlices(model)).some(
348
+ (slice) => Boolean(slice.legacyPaths),
349
+ )
350
+
351
+ if (!needsMigration) return document
352
+
353
+ return traverseDocument({
354
+ document,
355
+ model,
356
+ })({
357
+ transformSlice: ({ content, model }) => {
358
+ if (isCompositeSliceItemContent(content) && model?.type === "SharedSlice")
359
+ return migrateCompositeSlice(model, content)
360
+ if (isSimpleSliceItemContent(content) && model?.type === "SharedSlice")
361
+ return migrateSimpleSlice(model, content)
362
+ return content
363
+ },
364
+ })
365
+ }
@@ -3,8 +3,11 @@ import { isLeft } from "fp-ts/lib/Either"
3
3
  import { pipe } from "fp-ts/lib/function"
4
4
  import * as t from "io-ts"
5
5
 
6
- import type { ContentPath, TraverseContentFn } from "../../_internal/utils"
7
- import type { Group } from "../../customtypes"
6
+ import type {
7
+ ContentPath,
8
+ TraverseWidgetContentFn,
9
+ } from "../../_internal/utils"
10
+ import type { Group, NestableWidget } from "../../customtypes"
8
11
  import {
9
12
  FieldOrSliceType,
10
13
  getFieldCtx,
@@ -12,7 +15,7 @@ import {
12
15
  WithTypes,
13
16
  } from "../LegacyContentCtx"
14
17
  import { hasContentType } from "../utils"
15
- import { NestableContent, NestableLegacy } from "./nestable"
18
+ import { isNestableContent, NestableContent, NestableLegacy } from "./nestable"
16
19
 
17
20
  export const GroupItemContentType = "GroupItemContent" as const
18
21
 
@@ -122,31 +125,67 @@ export type GroupContent = t.TypeOf<typeof GroupContent>
122
125
 
123
126
  export function traverseGroupContent({
124
127
  path,
128
+ key,
129
+ apiId,
125
130
  model,
126
131
  content,
127
132
  }: {
128
133
  path: ContentPath
134
+ key: string
135
+ apiId: string
129
136
  content: GroupContent
130
137
  model?: Group | undefined
131
138
  }) {
132
- return (transform: TraverseContentFn): GroupContent | undefined => {
133
- const groupItems = content.value.map((groupItem, index) => {
139
+ return (transform: TraverseWidgetContentFn): GroupContent | undefined => {
140
+ const groupItems = traverseGroupItemsContent({
141
+ path,
142
+ model: model?.config?.fields,
143
+ content: content.value,
144
+ })(transform)
145
+
146
+ return transform({
147
+ path,
148
+ key,
149
+ apiId,
150
+ model,
151
+ content: {
152
+ __TYPE__: content.__TYPE__,
153
+ value: groupItems,
154
+ },
155
+ })
156
+ }
157
+ }
158
+
159
+ export function traverseGroupItemsContent({
160
+ path,
161
+ model,
162
+ content,
163
+ }: {
164
+ path: ContentPath
165
+ content: Array<GroupItemContent>
166
+ model?: Record<string, NestableWidget> | undefined
167
+ }) {
168
+ return (transform: TraverseWidgetContentFn): Array<GroupItemContent> => {
169
+ return content.map((groupItem, index) => {
170
+ const groupItemPath = path.concat([
171
+ { key: index.toString(), type: "GroupItem" },
172
+ ])
173
+
134
174
  const groupItemFields = groupItem.value.reduce<GroupItemContent["value"]>(
135
175
  (acc, [fieldKey, fieldContent]) => {
136
- const fieldDef = model?.config?.fields?.[fieldKey]
176
+ const fieldDef = model?.[fieldKey]
137
177
 
138
178
  const transformedField = transform({
139
- path: path.concat([
140
- { key: index.toString(), type: "GroupItem" },
141
- { key: fieldKey, type: fieldContent.__TYPE__ },
142
- ]),
179
+ path: groupItemPath.concat([{ key: fieldKey, type: "Widget" }]),
143
180
  key: fieldKey,
144
181
  apiId: fieldKey,
145
182
  model: fieldDef,
146
183
  content: fieldContent,
147
184
  })
148
185
  // Can happen if the transform function returns undefined to filter out a field
149
- if (!transformedField) return acc
186
+ if (!transformedField || !isNestableContent(transformedField))
187
+ return acc
188
+
150
189
  return acc.concat([[fieldKey, transformedField]])
151
190
  },
152
191
  [],
@@ -157,10 +196,5 @@ export function traverseGroupContent({
157
196
  value: groupItemFields,
158
197
  }
159
198
  })
160
-
161
- return {
162
- __TYPE__: content.__TYPE__,
163
- value: groupItems,
164
- }
165
199
  }
166
200
  }
@@ -5,17 +5,29 @@ import * as t from "io-ts"
5
5
 
6
6
  import type {
7
7
  ContentPath,
8
- TraverseContentFn,
8
+ TraverseSliceContentFn,
9
+ TraverseWidgetContentFn,
9
10
  } from "../../../../_internal/utils"
10
- import type { CompositeSlice } from "../../../../customtypes"
11
+ import type {
12
+ CompositeSliceFields,
13
+ VariationFields,
14
+ } from "../../../../customtypes"
11
15
  import {
12
16
  getFieldCtx,
13
17
  LegacyContentCtx,
14
18
  WithTypes,
15
19
  } from "../../../LegacyContentCtx"
16
20
  import { hasContentType } from "../../../utils"
17
- import type { GroupItemContent } from "../../GroupContent"
18
- import { NestableContent, NestableLegacy } from "../../nestable"
21
+ import { traverseGroupItemsContent } from "../../GroupContent"
22
+ import {
23
+ isNestableContent,
24
+ NestableContent,
25
+ NestableLegacy,
26
+ } from "../../nestable"
27
+ import type {
28
+ CompositeSliceItemContent,
29
+ SharedSliceItemContent,
30
+ } from "../SliceItem"
19
31
  import { RepeatableWidgets, RepeatableWidgetsLegacy } from "./RepeatableContent"
20
32
 
21
33
  export const CompositeSliceContentType = "CompositeSliceContent"
@@ -126,25 +138,34 @@ export type CompositeSliceContent = t.TypeOf<typeof CompositeSliceContent>
126
138
 
127
139
  export function traverseCompositeSliceContent({
128
140
  path,
141
+ sliceKey,
129
142
  sliceName,
130
143
  model,
131
144
  content,
132
145
  }: {
133
146
  path: ContentPath
147
+ sliceKey: string
134
148
  sliceName: string
135
- content: CompositeSliceContent
136
- model?: CompositeSlice | undefined
149
+ content: CompositeSliceItemContent
150
+ model?: VariationFields | CompositeSliceFields | undefined
137
151
  }) {
138
- return (transform: TraverseContentFn): CompositeSliceContent | undefined => {
139
- const primary = Object.entries(content.nonRepeat).reduce<
140
- Record<string, NestableContent>
152
+ return (
153
+ transformWidget: TraverseWidgetContentFn,
154
+ transformSlice: TraverseSliceContentFn,
155
+ ): SharedSliceItemContent | CompositeSliceItemContent | undefined => {
156
+ const primary = Object.entries(content.widget.nonRepeat).reduce<
157
+ CompositeSliceContent["nonRepeat"]
141
158
  >((acc, [fieldKey, fieldContent]) => {
142
- const fieldDef = model?.["non-repeat"]?.[fieldKey]
159
+ const fieldDef = (() => {
160
+ return model?.type === "SharedSlice"
161
+ ? model?.fields?.primary?.[fieldKey]
162
+ : model?.fields?.repeat?.[fieldKey]
163
+ })()
143
164
 
144
- const transformedField = transform({
165
+ const transformedField = transformWidget({
145
166
  path: path.concat([
146
167
  { key: "non-repeat", type: "primary" },
147
- { key: fieldKey, type: fieldContent.__TYPE__ },
168
+ { key: fieldKey, type: "Widget" },
148
169
  ]),
149
170
  key: fieldKey,
150
171
  apiId: sliceName,
@@ -152,45 +173,35 @@ export function traverseCompositeSliceContent({
152
173
  content: fieldContent,
153
174
  })
154
175
  // Can happen if the transform function returns undefined to filter out a field
155
- if (!transformedField) return acc
176
+ if (!transformedField || !isNestableContent(transformedField)) return acc
156
177
  return {
157
178
  ...acc,
158
179
  [fieldKey]: transformedField,
159
180
  }
160
181
  }, {})
161
182
 
162
- const items = content.repeat.map((itemBlock) => {
163
- const itemBlockFields = itemBlock.value.reduce<GroupItemContent["value"]>(
164
- (acc, [fieldKey, fieldContent]) => {
165
- const fieldDef = model?.repeat?.[fieldKey]
166
-
167
- const transformedField = transform({
168
- path: path.concat([
169
- { key: "repeat", type: "items" },
170
- { key: fieldKey, type: fieldContent.__TYPE__ },
171
- ]),
172
- key: fieldKey,
173
- apiId: sliceName,
174
- model: fieldDef,
175
- content: fieldContent,
176
- })
177
- // Can happen if the transform function returns undefined to filter out a field
178
- if (!transformedField) return acc
179
- return acc.concat([[fieldKey, transformedField]])
183
+ const items = traverseGroupItemsContent({
184
+ path: path.concat([{ key: "repeat", type: "items" }]),
185
+ model:
186
+ model?.type === "SharedSlice"
187
+ ? model?.fields.items
188
+ : model?.fields.repeat,
189
+ content: content.widget.repeat,
190
+ })(transformWidget)
191
+
192
+ return transformSlice({
193
+ key: sliceKey,
194
+ apiId: sliceName,
195
+ path,
196
+ model,
197
+ content: {
198
+ ...content,
199
+ widget: {
200
+ __TYPE__: "CompositeSliceContent",
201
+ repeat: items,
202
+ nonRepeat: primary,
180
203
  },
181
- [],
182
- )
183
-
184
- return {
185
- __TYPE__: itemBlock.__TYPE__,
186
- value: itemBlockFields,
187
- }
204
+ },
188
205
  })
189
-
190
- return {
191
- __TYPE__: content.__TYPE__,
192
- repeat: items,
193
- nonRepeat: primary,
194
- }
195
206
  }
196
207
  }
@@ -6,17 +6,23 @@ import { withFallback } from "io-ts-types"
6
6
 
7
7
  import type {
8
8
  ContentPath,
9
- TraverseContentFn,
9
+ TraverseSliceContentFn,
10
+ TraverseWidgetContentFn,
10
11
  } from "../../../../_internal/utils"
11
- import type { SharedSlice } from "../../../../customtypes"
12
+ import type { VariationFields } from "../../../../customtypes"
12
13
  import {
13
14
  getFieldCtx,
14
15
  LegacyContentCtx,
15
16
  WithTypes,
16
17
  } from "../../../LegacyContentCtx"
17
18
  import { hasContentType } from "../../../utils"
18
- import type { GroupItemContent } from "../../GroupContent"
19
- import { NestableContent, NestableLegacy } from "../../nestable"
19
+ import { traverseGroupItemsContent } from "../../GroupContent"
20
+ import {
21
+ isNestableContent,
22
+ NestableContent,
23
+ NestableLegacy,
24
+ } from "../../nestable"
25
+ import type { SharedSliceItemContent } from "../SliceItem"
20
26
  import { RepeatableWidgets, RepeatableWidgetsLegacy } from "./RepeatableContent"
21
27
 
22
28
  export const SharedSliceContentType = "SharedSliceContent"
@@ -137,29 +143,30 @@ export type SharedSliceContent = t.TypeOf<typeof SharedSliceContent>
137
143
 
138
144
  export function traverseSharedSliceContent({
139
145
  path,
146
+ sliceKey,
140
147
  sliceName,
141
148
  model,
142
149
  content,
143
150
  }: {
144
151
  path: ContentPath
152
+ sliceKey: string
145
153
  sliceName: string
146
- content: SharedSliceContent
147
- model?: SharedSlice | undefined
154
+ content: SharedSliceItemContent
155
+ model?: VariationFields | undefined
148
156
  }) {
149
- return (transform: TraverseContentFn): SharedSliceContent | undefined => {
150
- const variationDef = model?.variations.find(
151
- (v) => v.id === content.variation,
152
- )
153
-
154
- const primary = Object.entries(content.primary).reduce<
155
- Record<string, NestableContent>
157
+ return (
158
+ transformWidget: TraverseWidgetContentFn,
159
+ transformSlice: TraverseSliceContentFn,
160
+ ): SharedSliceItemContent | undefined => {
161
+ const primary = Object.entries(content.widget.primary).reduce<
162
+ SharedSliceContent["primary"]
156
163
  >((acc, [fieldKey, fieldContent]) => {
157
- const fieldDef = variationDef && variationDef.primary?.[fieldKey]
164
+ const fieldDef = model?.fields?.primary?.[fieldKey]
158
165
 
159
- const transformedField = transform({
166
+ const transformedField = transformWidget({
160
167
  path: path.concat([
161
168
  { key: "primary", type: "primary" },
162
- { key: fieldKey, type: fieldContent.__TYPE__ },
169
+ { key: fieldKey, type: "Widget" },
163
170
  ]),
164
171
  key: fieldKey,
165
172
  apiId: sliceName,
@@ -167,46 +174,33 @@ export function traverseSharedSliceContent({
167
174
  content: fieldContent,
168
175
  })
169
176
  // Can happen if the transform function returns undefined to filter out a field
170
- if (!transformedField) return acc
177
+ if (!transformedField || !isNestableContent(transformedField)) return acc
171
178
  return {
172
179
  ...acc,
173
180
  [fieldKey]: transformedField,
174
181
  }
175
182
  }, {})
176
183
 
177
- const items = content.items.map((itemBlock) => {
178
- const itemBlockFields = itemBlock.value.reduce<GroupItemContent["value"]>(
179
- (acc, [fieldKey, fieldContent]) => {
180
- const fieldDef = variationDef && variationDef.items?.[fieldKey]
181
-
182
- const transformedField = transform({
183
- path: path.concat([
184
- { key: "items", type: "items" },
185
- { key: fieldKey, type: fieldContent.__TYPE__ },
186
- ]),
187
- key: fieldKey,
188
- apiId: sliceName,
189
- model: fieldDef,
190
- content: fieldContent,
191
- })
192
- // Can happen if the transform function returns undefined to filter out a field
193
- if (!transformedField) return acc
194
- return acc.concat([[fieldKey, transformedField]])
184
+ const items = traverseGroupItemsContent({
185
+ path: path.concat([{ key: "items", type: "items" }]),
186
+ model: model?.fields.items,
187
+ content: content.widget.items,
188
+ })(transformWidget)
189
+
190
+ return transformSlice({
191
+ key: sliceKey,
192
+ apiId: sliceName,
193
+ path,
194
+ model: model,
195
+ content: {
196
+ ...content,
197
+ widget: {
198
+ __TYPE__: "SharedSliceContent",
199
+ variation: content.widget.variation,
200
+ primary,
201
+ items,
195
202
  },
196
- [],
197
- )
198
-
199
- return {
200
- __TYPE__: itemBlock.__TYPE__,
201
- value: itemBlockFields,
202
- }
203
+ },
203
204
  })
204
-
205
- return {
206
- __TYPE__: content.__TYPE__,
207
- variation: content.variation,
208
- primary,
209
- items,
210
- }
211
205
  }
212
206
  }