@prismicio/types-internal 2.2.0-traverse.alpha-6 → 2.2.0-traverse.alpha-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.
Files changed (75) hide show
  1. package/lib/_internal/utils.d.ts +3 -6
  2. package/lib/content/Document.d.ts +1248 -32
  3. package/lib/content/Document.js +1 -1
  4. package/lib/content/fields/GroupContent.d.ts +273 -7
  5. package/lib/content/fields/WidgetContent.d.ts +1248 -32
  6. package/lib/content/fields/nestable/NestableContent.d.ts +156 -6
  7. package/lib/content/fields/nestable/NestableContent.js +1 -29
  8. package/lib/content/fields/nestable/RichTextContent/Blocks.d.ts +582 -28
  9. package/lib/content/fields/nestable/RichTextContent/Blocks.js +29 -46
  10. package/lib/content/fields/nestable/RichTextContent/index.d.ts +195 -5
  11. package/lib/content/fields/slices/Slice/CompositeSliceContent.d.ts +314 -10
  12. package/lib/content/fields/slices/Slice/CompositeSliceContent.js +18 -12
  13. package/lib/content/fields/slices/Slice/RepeatableContent.d.ts +117 -3
  14. package/lib/content/fields/slices/Slice/SharedSliceContent.d.ts +312 -8
  15. package/lib/content/fields/slices/Slice/SharedSliceContent.js +5 -1
  16. package/lib/content/fields/slices/Slice/SimpleSliceContent.d.ts +312 -8
  17. package/lib/content/fields/slices/Slice/SimpleSliceContent.js +1 -1
  18. package/lib/content/fields/slices/Slice/index.d.ts +702 -18
  19. package/lib/content/fields/slices/SliceItem.d.ts +702 -18
  20. package/lib/content/fields/slices/SlicesContent.d.ts +936 -24
  21. package/lib/content/fields/slices/SlicesContent.js +2 -4
  22. package/lib/customtypes/CustomType.d.ts +1 -1
  23. package/lib/customtypes/CustomType.js +3 -3
  24. package/lib/customtypes/widgets/slices/CompositeSlice.d.ts +0 -5
  25. package/lib/customtypes/widgets/slices/SharedSlice.d.ts +1 -2
  26. package/lib/import/converters/fields/nestable/GeoPoint.d.ts +3 -0
  27. package/lib/import/converters/fields/nestable/GeoPoint.js +15 -0
  28. package/lib/import/converters/fields/nestable/Image.d.ts +25 -3
  29. package/lib/import/converters/fields/nestable/Image.js +21 -25
  30. package/lib/import/converters/fields/nestable/RichText/embedBlock.d.ts +4 -0
  31. package/lib/import/converters/fields/nestable/RichText/embedBlock.js +14 -0
  32. package/lib/import/converters/fields/nestable/RichText/imageBlock.d.ts +4 -0
  33. package/lib/import/converters/fields/nestable/RichText/imageBlock.js +12 -0
  34. package/lib/import/converters/fields/nestable/RichText/index.d.ts +4 -0
  35. package/lib/import/converters/fields/nestable/RichText/index.js +22 -0
  36. package/lib/import/converters/fields/nestable/RichText/textBlock.d.ts +4 -0
  37. package/lib/import/converters/fields/nestable/RichText/textBlock.js +41 -0
  38. package/lib/import/converters/fields/nestable/index.d.ts +1 -1
  39. package/lib/import/converters/fields/nestable/index.js +1 -1
  40. package/lib/import/validators/fields/ImportContent.js +3 -3
  41. package/lib/import/validators/fields/ImportField.d.ts +1 -1
  42. package/lib/import/validators/fields/ImportSlices/ImportSlices.js +4 -3
  43. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/SharedSliceContentEntry.js +1 -1
  44. package/lib/import/validators/fields/nestable/ImportRichText/ImportRichText.d.ts +1 -1
  45. package/lib/import/validators/fields/nestable/ImportRichText/ImportRichText.js +20 -14
  46. package/lib/import/validators/fields/nestable/ImportRichText/blocks/ImportImageBlock.d.ts +16 -2
  47. package/lib/import/validators/fields/nestable/ImportRichText/blocks/ImportImageBlock.js +7 -5
  48. package/lib/import/validators/fields/nestable/Nestable.d.ts +1 -1
  49. package/lib/validators/DefaultOrElse.js +3 -3
  50. package/package.json +1 -1
  51. package/src/_internal/utils.ts +3 -7
  52. package/src/content/Document.ts +2 -2
  53. package/src/content/fields/nestable/NestableContent.ts +0 -32
  54. package/src/content/fields/nestable/RichTextContent/Blocks.ts +48 -58
  55. package/src/content/fields/slices/Slice/CompositeSliceContent.ts +26 -16
  56. package/src/content/fields/slices/Slice/SharedSliceContent.ts +7 -1
  57. package/src/content/fields/slices/Slice/SimpleSliceContent.ts +1 -1
  58. package/src/content/fields/slices/SlicesContent.ts +4 -6
  59. package/src/customtypes/CustomType.ts +1 -1
  60. package/src/customtypes/widgets/slices/CompositeSlice.ts +0 -6
  61. package/src/customtypes/widgets/slices/SharedSlice.ts +2 -2
  62. package/src/import/converters/fields/nestable/Image.ts +10 -22
  63. package/src/import/converters/fields/nestable/RichText/embedBlock.ts +17 -0
  64. package/src/import/converters/fields/nestable/RichText/imageBlock.ts +17 -0
  65. package/src/import/converters/fields/nestable/RichText/index.ts +23 -0
  66. package/src/import/converters/fields/nestable/RichText/textBlock.ts +48 -0
  67. package/src/import/converters/fields/nestable/index.ts +1 -1
  68. package/src/import/validators/fields/ImportContent.ts +3 -3
  69. package/src/import/validators/fields/ImportSlices/ImportSlices.ts +7 -5
  70. package/src/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/SharedSliceContentEntry.ts +1 -1
  71. package/src/import/validators/fields/nestable/ImportRichText/ImportRichText.ts +38 -25
  72. package/src/import/validators/fields/nestable/ImportRichText/blocks/ImportImageBlock.ts +9 -5
  73. package/src/validators/DefaultOrElse.ts +4 -4
  74. package/src/import/converters/fields/nestable/RichText.ts +0 -62
  75. /package/src/import/converters/fields/nestable/{GeooPoint.ts → GeoPoint.ts} +0 -0
@@ -1,7 +1,6 @@
1
1
  import { isRight } from "fp-ts/lib/Either"
2
2
  import * as t from "io-ts"
3
3
 
4
- import type { NestableWidget } from "../../../customtypes"
5
4
  import type { LegacyContentCtx } from "../../LegacyContentCtx"
6
5
  import { EmptyContent, EmptyLegacy, isEmptyContent } from "../EmptyContent"
7
6
  import {
@@ -201,34 +200,3 @@ export const NestableLegacy = (ctx: LegacyContentCtx) => {
201
200
  },
202
201
  }
203
202
  }
204
-
205
- export function isValidStaticNestableContent(
206
- content: NestableContent,
207
- model?: NestableWidget,
208
- ) {
209
- if (!model) return false
210
-
211
- switch (content.__TYPE__) {
212
- // special case for no content so we can consider it valid no matter its model
213
- case "EmptyContent":
214
- return true
215
- case "BooleanContent":
216
- return model.type === "Boolean"
217
- case "EmbedContent":
218
- return model.type === "Embed"
219
- case "FieldContent":
220
- return content.type === model.type
221
- case "GeoPointContent":
222
- return model.type === "GeoPoint"
223
- case "ImageContent":
224
- return model.type === "Image"
225
- case "IntegrationFieldsContent":
226
- return model.type === "IntegrationFields"
227
- case "LinkContent":
228
- return model.type === "Link"
229
- case "StructuredTextContent":
230
- return model.type === "StructuredText"
231
- case "SeparatorContent":
232
- return model.type === "Separator"
233
- }
234
- }
@@ -1,5 +1,5 @@
1
1
  import { either } from "fp-ts"
2
- import { isLeft, isRight } from "fp-ts/lib/Either"
2
+ import { 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
 
@@ -18,66 +18,54 @@ import {
18
18
  import { ImageContentView } from "../ImageContent"
19
19
  import { Link, LinkLegacy } from "../LinkContent"
20
20
 
21
- export const Meta = t.exact(
22
- t.intersection([
23
- t.partial({
24
- data: t.unknown,
25
- }),
26
- t.type({
27
- start: t.number,
28
- end: t.number,
29
- type: t.union([RichTextNodeTypeCodec, t.literal("label")]),
30
- }),
31
- ]),
32
- )
33
- export type Meta = t.TypeOf<typeof Meta>
34
-
35
- // export alias for code clarity
36
- export const Span = Meta
37
- export type Span = Meta
38
-
39
- export const ValidatedMetas = (linkCodec: LinkCodec) =>
40
- new t.Type<Meta[], Meta[], unknown>(
41
- "ValidatedMetas",
42
- (metas): metas is Meta[] => Array.isArray(metas) && metas.every(Meta.is),
43
- (metas: unknown, c) => {
44
- if (Array.isArray(metas)) {
45
- const res = metas
46
- .reduce<Array<Meta>>((acc, maybeMeta) => {
47
- const maybeDecodedMeta = Meta.decode(maybeMeta)
48
- if (isRight(maybeDecodedMeta)) {
49
- const meta = maybeDecodedMeta.right
50
- // if it's an hyperlink it should have data validated as link otherwise we don't care and keep the meta
51
- if (meta.data && meta.type === "hyperlink") {
52
- const decoded = linkCodec.decode(meta.data)
53
- if (isLeft(decoded)) return acc
54
-
55
- return [...acc, { ...meta, data: decoded.right }]
56
- } else if (meta.type !== "hyperlink") {
57
- return [...acc, meta]
58
- }
59
- }
60
- return acc
21
+ const SpanFn = (linkCodec: typeof Link | typeof LinkLegacy) =>
22
+ t.exact(
23
+ t.intersection([
24
+ t.partial({
25
+ data: linkCodec,
26
+ }),
27
+ t.type({
28
+ start: t.number,
29
+ end: t.number,
30
+ type: t.union([RichTextNodeTypeCodec, t.literal("label")]),
31
+ }),
32
+ ]),
33
+ )
34
+
35
+ export const Span = SpanFn(Link)
36
+ export type Span = t.TypeOf<typeof Span>
37
+
38
+ export const SpanLegacy = SpanFn(LinkLegacy)
39
+ export type SpanLegacy = t.TypeOf<typeof SpanLegacy>
40
+
41
+ export const ValidatedSpans = <C extends typeof Span | typeof SpanLegacy>(
42
+ spanCodec: C,
43
+ ) => {
44
+ type S = t.TypeOf<C>
45
+
46
+ return new t.Type<S[], S[], unknown>(
47
+ "ValidatedSpans",
48
+ (spans): spans is S[] => Array.isArray(spans) && spans.every(spanCodec.is),
49
+ (spans: unknown, c) => {
50
+ if (Array.isArray(spans)) {
51
+ const res = spans
52
+ .reduce<Array<S>>((acc, maybeSpan) => {
53
+ const decodedSpan = spanCodec.decode(maybeSpan)
54
+ return isRight(decodedSpan) ? [...acc, decodedSpan.right] : acc
61
55
  }, [])
62
- .sort((m1: Meta, m2: Meta) => m1.start - m2.start)
56
+ .sort((m1: S, m2: S) => m1.start - m2.start)
63
57
  return t.success(res)
64
- } else return t.failure(metas, c)
58
+ } else return t.failure(spans, c)
65
59
  },
66
60
  (m) => {
67
- return m.reduce<Array<Meta>>((acc, meta) => {
68
- if (meta.type === "hyperlink" && meta.data) {
69
- // since the Span data are typed as unknown we have to redecode for type safety and then encode to either new format or legacy.
70
- const decoded = linkCodec.decode(meta.data)
71
- if (isLeft(decoded)) return acc
72
-
73
- return [...acc, { ...meta, data: linkCodec.encode(decoded.right) }]
74
- }
75
- return [...acc, Meta.encode(meta)]
61
+ return m.reduce<Array<S>>((acc, meta) => {
62
+ return [...acc, spanCodec.encode(meta)]
76
63
  }, [])
77
64
  },
78
65
  )
66
+ }
79
67
 
80
- const ImageBlockCodec = (linkCodec: LinkCodec) =>
68
+ const ImageBlockCodec = (linkCodec: typeof Link | typeof LinkLegacy) =>
81
69
  t.exact(
82
70
  t.intersection([
83
71
  t.type({
@@ -169,8 +157,9 @@ export function checkEmbedBlock(block: Block): block is EmbedBlock {
169
157
  return block.type === RichTextNodeType.embed
170
158
  }
171
159
 
172
- type LinkCodec = typeof Link | typeof LinkLegacy
173
- const TextBlockCodec = (linkCodec: LinkCodec) =>
160
+ const TextBlockCodec = <C extends typeof Span | typeof SpanLegacy>(
161
+ spanCodec: C,
162
+ ) =>
174
163
  t.exact(
175
164
  t.intersection([
176
165
  t.type({
@@ -184,7 +173,7 @@ const TextBlockCodec = (linkCodec: LinkCodec) =>
184
173
  text: t.string,
185
174
  }),
186
175
  t.partial({
187
- spans: ValidatedMetas(linkCodec),
176
+ spans: ValidatedSpans(spanCodec),
188
177
  }),
189
178
  ]),
190
179
  }),
@@ -195,10 +184,11 @@ const TextBlockCodec = (linkCodec: LinkCodec) =>
195
184
  ]),
196
185
  )
197
186
 
198
- export const TextBlock = TextBlockCodec(Link)
187
+ /* These Text block will decode codec A and encode from codec B to A */
188
+ export const TextBlock = TextBlockCodec(Span)
199
189
  export type TextBlock = t.TypeOf<typeof TextBlock>
200
190
 
201
- const TextBlockLegacy = TextBlockCodec(LinkLegacy)
191
+ const TextBlockLegacy = TextBlockCodec(SpanLegacy)
202
192
  type TextBlockLegacy = t.TypeOf<typeof TextBlockLegacy>
203
193
 
204
194
  const legacyBlockCodec = t.union([
@@ -8,10 +8,7 @@ import type {
8
8
  TraverseSliceContentFn,
9
9
  TraverseWidgetContentFn,
10
10
  } from "../../../../_internal/utils"
11
- import type {
12
- CompositeSliceFields,
13
- VariationFields,
14
- } from "../../../../customtypes"
11
+ import type { CompositeSlice, VariationFields } from "../../../../customtypes"
15
12
  import {
16
13
  getFieldCtx,
17
14
  LegacyContentCtx,
@@ -147,7 +144,7 @@ export function traverseCompositeSliceContent({
147
144
  sliceKey: string
148
145
  sliceName: string
149
146
  content: CompositeSliceItemContent
150
- model?: VariationFields | CompositeSliceFields | undefined
147
+ model?: VariationFields | CompositeSlice | undefined
151
148
  }) {
152
149
  return (
153
150
  transformWidget: TraverseWidgetContentFn,
@@ -159,7 +156,7 @@ export function traverseCompositeSliceContent({
159
156
  const fieldDef = (() => {
160
157
  return model?.type === "SharedSlice"
161
158
  ? model?.fields?.primary?.[fieldKey]
162
- : model?.fields?.repeat?.[fieldKey]
159
+ : model?.["non-repeat"]?.[fieldKey]
163
160
  })()
164
161
 
165
162
  const transformedField = transformWidget({
@@ -173,7 +170,13 @@ export function traverseCompositeSliceContent({
173
170
  content: fieldContent,
174
171
  })
175
172
  // Can happen if the transform function returns undefined to filter out a field
176
- if (!transformedField || !isNestableContent(transformedField)) return acc
173
+ if (!transformedField) return acc
174
+ if (!isNestableContent(transformedField)) {
175
+ console.warn(
176
+ `Warn: Non nestable content with key [${fieldKey}] detected in a composite slice [${sliceName}] with key [${sliceKey}]`,
177
+ )
178
+ return acc
179
+ }
177
180
  return {
178
181
  ...acc,
179
182
  [fieldKey]: transformedField,
@@ -183,9 +186,7 @@ export function traverseCompositeSliceContent({
183
186
  const items = traverseGroupItemsContent({
184
187
  path: path.concat([{ key: "repeat", type: "items" }]),
185
188
  model:
186
- model?.type === "SharedSlice"
187
- ? model?.fields.items
188
- : model?.fields.repeat,
189
+ model?.type === "SharedSlice" ? model?.fields.items : model?.repeat,
189
190
  content: content.widget.repeat,
190
191
  })(transformWidget)
191
192
 
@@ -219,9 +220,14 @@ export function migrateCompositeSlice(
219
220
  variation: model.variationId,
220
221
  primary: Object.entries(content.widget.nonRepeat).reduce(
221
222
  (acc, [fieldKey, fieldContent]) => {
222
- return model.fields.primary?.[fieldKey]
223
- ? { ...acc, [fieldKey]: fieldContent }
224
- : acc
223
+ if (!model.fields.primary?.[fieldKey]) {
224
+ console.warn(
225
+ `The widget ${fieldKey} in the non-repeat zone of the composite slice [${model.sliceName}] with key [${content.key}] doesn't exist in the model.`,
226
+ )
227
+ return acc
228
+ }
229
+
230
+ return { ...acc, [fieldKey]: fieldContent }
225
231
  },
226
232
  {},
227
233
  ),
@@ -230,9 +236,13 @@ export function migrateCompositeSlice(
230
236
  __TYPE__: "GroupItemContent",
231
237
  value: groupItem.value.reduce<GroupItemContent["value"]>(
232
238
  (acc, [fieldKey, fieldContent]) => {
233
- return model.fields.items?.[fieldKey]
234
- ? acc.concat([[fieldKey, fieldContent]])
235
- : acc
239
+ if (!model.fields.items?.[fieldKey]) {
240
+ console.warn(
241
+ `The widget ${fieldKey} in the repeat zone of the composite slice [${model.sliceName}] with key [${content.key}] doesn't exist in the model.`,
242
+ )
243
+ return acc
244
+ }
245
+ return acc.concat([[fieldKey, fieldContent]])
236
246
  },
237
247
  [],
238
248
  ),
@@ -174,7 +174,13 @@ export function traverseSharedSliceContent({
174
174
  content: fieldContent,
175
175
  })
176
176
  // Can happen if the transform function returns undefined to filter out a field
177
- if (!transformedField || !isNestableContent(transformedField)) return acc
177
+ if (!transformedField) return acc
178
+ if (!isNestableContent(transformedField)) {
179
+ console.warn(
180
+ `Warn: Non nestable content with key [${fieldKey}] detected in a shared slice [${sliceName}] with key [${sliceKey}]`,
181
+ )
182
+ return acc
183
+ }
178
184
  return {
179
185
  ...acc,
180
186
  [fieldKey]: transformedField,
@@ -168,7 +168,7 @@ export function migrateSimpleSlice(
168
168
  __TYPE__: "SharedSliceContent",
169
169
  variation: model.variationId,
170
170
  primary: model.fields.primary?.[content.name]
171
- ? { [content.key]: content.widget }
171
+ ? { [content.name]: content.widget }
172
172
  : {},
173
173
  items: [],
174
174
  },
@@ -10,7 +10,7 @@ import {
10
10
  } from "../../../_internal/utils"
11
11
  import {
12
12
  type StaticSlices,
13
- CompositeSliceFields,
13
+ CompositeSlice,
14
14
  Group,
15
15
  isCompositeSlice,
16
16
  isLegacySlice,
@@ -146,7 +146,7 @@ function findSliceModel(
146
146
 
147
147
  const legacySliceModel = ():
148
148
  | NestableWidget
149
- | CompositeSliceFields
149
+ | CompositeSlice
150
150
  | Group
151
151
  | undefined => {
152
152
  if (!defaultModel) return
@@ -154,10 +154,8 @@ function findSliceModel(
154
154
  if (isCompositeSlice(defaultModel)) {
155
155
  return {
156
156
  type: "Slice",
157
- fields: {
158
- "non-repeat": defaultModel["non-repeat"] || {},
159
- repeat: defaultModel.repeat || {},
160
- },
157
+ "non-repeat": defaultModel["non-repeat"] || {},
158
+ repeat: defaultModel.repeat || {},
161
159
  }
162
160
  }
163
161
  if (isLegacySlice(defaultModel)) {
@@ -75,7 +75,7 @@ export function flattenWidgets(
75
75
  )
76
76
  }
77
77
 
78
- export function flattenStaticWidgets(
78
+ export function flattenSections(
79
79
  customType: StaticCustomType,
80
80
  ): Array<[string, StaticWidget]> {
81
81
  return Object.entries(customType.json).reduce(
@@ -1,6 +1,5 @@
1
1
  import * as t from "io-ts"
2
2
 
3
- import type { PickOnly } from "../../../_internal/utils"
4
3
  import { WidgetKey } from "../../../common"
5
4
  import { StringOrNull } from "../../../validators"
6
5
  import { NestableWidget } from "../nestable/NestableWidget"
@@ -33,11 +32,6 @@ export const CompositeSlice = t.exact(
33
32
  )
34
33
  export type CompositeSlice = t.TypeOf<typeof CompositeSlice>
35
34
 
36
- export type CompositeSliceFields = {
37
- type: "Slice"
38
- fields: PickOnly<CompositeSlice, "non-repeat" | "repeat">
39
- }
40
-
41
35
  export function isCompositeSlice(
42
36
  slice: DynamicSlice | StaticSlice,
43
37
  ): slice is CompositeSlice {
@@ -1,7 +1,6 @@
1
1
  import * as t from "io-ts"
2
2
  import { withFallback } from "io-ts-types/lib/withFallback"
3
3
 
4
- import type { PickOnly } from "../../../_internal/utils"
5
4
  import { WidgetKey } from "../../../common"
6
5
  import { NestableWidget } from "../nestable/NestableWidget"
7
6
  import type { SharedSliceRef } from "./SharedSliceRef"
@@ -30,11 +29,12 @@ export const Variation = t.exact(
30
29
 
31
30
  export type Variation = t.TypeOf<typeof Variation>
32
31
 
32
+ // VariationFields is used exclusively for the slices migration, LegacySlice -> SharedSlice
33
33
  export type VariationFields = {
34
34
  type: "SharedSlice"
35
35
  sliceName: string
36
36
  variationId: string
37
- fields: PickOnly<Variation, "primary" | "items">
37
+ fields: Pick<Variation, "primary" | "items">
38
38
  }
39
39
 
40
40
  export const SharedSliceType = "SharedSlice"
@@ -5,22 +5,20 @@ import { withOptionals } from "../../../../utils/Objects"
5
5
  import type { ImageField, ImportImage } from "../../../validators"
6
6
  import type { ImportImageBlock } from "../../../validators/fields/nestable/ImportRichText/blocks"
7
7
 
8
- function convertImage<Input extends ImageField | ImportImageBlock>(
8
+ export function convertImageView<Input extends ImageField | ImportImageBlock>(
9
9
  inputImage: Input,
10
10
  image: Asset,
11
11
  ) {
12
12
  // We can do that because anyway all properties being read
13
13
  const imageField: ImageField = {
14
14
  ...inputImage,
15
- edit:
16
- "edit" in inputImage
17
- ? inputImage.edit
18
- : {
19
- x: 0,
20
- y: 0,
21
- zoom: 1,
22
- },
23
- dimensions: "dimensions" in inputImage ? inputImage.dimensions : {},
15
+ edit: {
16
+ x: 0,
17
+ y: 0,
18
+ zoom: 1,
19
+ ...inputImage.edit,
20
+ },
21
+ dimensions: inputImage.dimensions ?? {},
24
22
  }
25
23
  return withOptionals<ImageContentView>(
26
24
  {
@@ -64,7 +62,7 @@ function convertThumbnails(
64
62
  (acc, [thumbnailName, thumbnail]) => {
65
63
  return {
66
64
  ...acc,
67
- [thumbnailName]: convertImage(
65
+ [thumbnailName]: convertImageView(
68
66
  thumbnail,
69
67
  getAssetOrThrow(assets)(thumbnail.id),
70
68
  ),
@@ -74,16 +72,6 @@ function convertThumbnails(
74
72
  )
75
73
  }
76
74
 
77
- export const imageBlockConverter = (
78
- imageBlock: ImportImageBlock,
79
- assets: Record<Asset["id"], Asset | undefined>,
80
- ): ImageContentView => {
81
- return convertImage<ImportImageBlock>(
82
- imageBlock,
83
- getAssetOrThrow(assets)(imageBlock.id),
84
- )
85
- }
86
-
87
75
  // All assets from `imageField` must be present in `assets`
88
76
  // If not then function will throw an error
89
77
  export const imageConverter = (
@@ -93,7 +81,7 @@ export const imageConverter = (
93
81
  if (!imageField) return
94
82
 
95
83
  return {
96
- ...convertImage<ImageField>(
84
+ ...convertImageView<ImageField>(
97
85
  imageField,
98
86
  getAssetOrThrow(assets)(imageField.id),
99
87
  ),
@@ -0,0 +1,17 @@
1
+ import type { Embed } from "../../../../../common"
2
+ import type { EmbedBlock } from "../../../../../content"
3
+ import type { ImportEmbedBlock } from "../../../../validators/fields/nestable/ImportRichText/blocks"
4
+ import { embedConverter } from "../Embed"
5
+
6
+ export function embedBlockConverter(
7
+ block: ImportEmbedBlock,
8
+ embeds: Record<string, Embed | undefined>,
9
+ ): EmbedBlock {
10
+ const embedData = embedConverter(block.oembed, embeds)
11
+
12
+ if (!embedData) throw new Error("Failed to convert embed data")
13
+ return {
14
+ type: block.type,
15
+ data: embedData,
16
+ }
17
+ }
@@ -0,0 +1,17 @@
1
+ import { Asset, getAssetOrThrow } from "../../../../../common"
2
+ import type { ImageBlock } from "../../../../../content"
3
+ import type { ImportImageBlock } from "../../../../validators/fields/nestable/ImportRichText/blocks"
4
+ import { convertImageView } from "../Image"
5
+
6
+ export function imageBlockConverter(
7
+ block: ImportImageBlock,
8
+ assets: Record<Asset["id"], Asset | undefined>,
9
+ ): ImageBlock {
10
+ return {
11
+ type: block.type,
12
+ data: convertImageView<ImportImageBlock>(
13
+ block,
14
+ getAssetOrThrow(assets)(block.id),
15
+ ),
16
+ }
17
+ }
@@ -0,0 +1,23 @@
1
+ import type { Asset, Embed } from "../../../../../common"
2
+ import type { RichTextContent } from "../../../../../content"
3
+ import { RichTextContentType } from "../../../../../content"
4
+ import type { ImportRichText } from "../../../../validators"
5
+ import { embedBlockConverter } from "./embedBlock"
6
+ import { imageBlockConverter } from "./imageBlock"
7
+ import { textBlockConverter } from "./textBlock"
8
+
9
+ export const richTextConverter = (
10
+ richTextField: ImportRichText["value"],
11
+ assets: Record<Asset["id"], Asset | undefined>,
12
+ embeds: Record<string, Embed | undefined>,
13
+ ): RichTextContent | undefined => {
14
+ if (richTextField === null) return
15
+ return {
16
+ __TYPE__: RichTextContentType,
17
+ value: richTextField.map((block) => {
18
+ if (block.type === "image") return imageBlockConverter(block, assets)
19
+ else if (block.type === "embed") return embedBlockConverter(block, embeds)
20
+ return textBlockConverter(block, assets)
21
+ }),
22
+ }
23
+ }
@@ -0,0 +1,48 @@
1
+ import type { Asset } from "../../../../../common"
2
+ import type { TextBlock } from "../../../../../content"
3
+ import type { ImportTextBlock } from "../../../../validators/fields/nestable/ImportRichText/blocks"
4
+ import { linkConverter } from "../Link"
5
+
6
+ export function textBlockConverter(
7
+ block: ImportTextBlock,
8
+ assets: Record<Asset["id"], Asset | undefined>,
9
+ ): TextBlock {
10
+ return {
11
+ type: block.type,
12
+ content: {
13
+ text: block.text,
14
+ ...(() => {
15
+ if (block.spans) {
16
+ const convertedSpans = spansConverter(block.spans, assets)
17
+ if (!convertedSpans) return {}
18
+
19
+ return { spans: convertedSpans }
20
+ }
21
+ return {}
22
+ })(),
23
+ },
24
+ ...(block.direction ? { direction: block.direction } : {}),
25
+ }
26
+ }
27
+
28
+ function spansConverter(
29
+ spans: NonNullable<ImportTextBlock["spans"]>,
30
+ assets: Record<Asset["id"], Asset | undefined>,
31
+ ): TextBlock["content"]["spans"] {
32
+ return spans.map((span) => {
33
+ return {
34
+ type: span.type,
35
+ start: span.start,
36
+ end: span.end,
37
+ ...(() => {
38
+ if (span.type === "hyperlink") {
39
+ const convertedLinkContent = linkConverter(span.data, assets)
40
+ if (!convertedLinkContent) return {}
41
+
42
+ return { data: convertedLinkContent?.value }
43
+ }
44
+ return {}
45
+ })(),
46
+ }
47
+ })
48
+ }
@@ -2,7 +2,7 @@ export * from "./Boolean"
2
2
  export * from "./Color"
3
3
  export * from "./Date"
4
4
  export * from "./Embed"
5
- export * from "./GeooPoint"
5
+ export * from "./GeoPoint"
6
6
  export * from "./Image"
7
7
  export * from "./Link"
8
8
  export * from "./Nestable"
@@ -10,14 +10,14 @@ export const ImportContent = <T extends FieldType, A, O = A>(
10
10
  valueCodec: t.Type<A, O>,
11
11
  ) =>
12
12
  new t.Type<{ type: T; value: A }, O>(
13
- "ImportField",
13
+ `ImportField: ${valueCodec.name}`,
14
14
  (u: unknown): u is { type: T; value: A } => {
15
15
  if (!isObject(u)) return false
16
16
  return type === u["type"] && valueCodec.is(u["value"])
17
17
  },
18
- (u: unknown) => {
18
+ (u: unknown, c) => {
19
19
  return pipe(
20
- valueCodec.decode(u),
20
+ valueCodec.validate(u, c),
21
21
  either.map((decodedValue) => {
22
22
  return {
23
23
  type,
@@ -3,7 +3,7 @@ import { pipe } from "fp-ts/function"
3
3
  import * as t from "io-ts"
4
4
 
5
5
  import type { StaticSlices } from "../../../../customtypes"
6
- import { EmptyObjectOrElse } from "../../../../validators"
6
+ import { EmptyArrayOrElse } from "../../../../validators"
7
7
  import { ImportContent } from "../ImportContent"
8
8
  import { SharedSlice } from "./SharedSlice"
9
9
  import {
@@ -16,13 +16,14 @@ export const ImportSlices = (staticSlices: StaticSlices) => {
16
16
 
17
17
  // For now we only support the SharedSlice, however if we want to support more in the future
18
18
  // we would have to change the codec here to something like this: t.array(t.union([ImportSharedSlice(sharedSlices), NewSliceCodec(newSliceCustomTypes)])).
19
- const SlicesArrayCodec = t.array(SharedSlice(supportedSlices))
19
+ const SharedSliceCodec = SharedSlice(supportedSlices)
20
+ const SlicesArrayCodec = t.array(SharedSliceCodec)
20
21
 
21
22
  return ImportContent(
22
23
  "Slices",
23
- EmptyObjectOrElse(
24
- new t.Type<SharedSlice[]>(
25
- "ImportSlices",
24
+ EmptyArrayOrElse(
25
+ new t.ArrayType<typeof SharedSliceCodec, SharedSlice[]>(
26
+ SlicesArrayCodec.name,
26
27
  (u): u is SharedSlice[] => SlicesArrayCodec.is(u),
27
28
  (u, c) => {
28
29
  return pipe(
@@ -46,6 +47,7 @@ export const ImportSlices = (staticSlices: StaticSlices) => {
46
47
  )
47
48
  },
48
49
  t.identity,
50
+ SharedSliceCodec,
49
51
  ),
50
52
  ),
51
53
  )
@@ -83,8 +83,8 @@ export const SharedSliceContentEntry = (
83
83
  errors.map((error) => {
84
84
  const context = [
85
85
  ...c,
86
- ...error.context.filter(({ key }) => !!key), // We replace the "" key coming from ImportNestable decoder
87
86
  { key, actual: content, type: codec },
87
+ ...error.context.slice(1), // We ignore the first context element with "" key coming from ImportNestable decoder
88
88
  ]
89
89
 
90
90
  const updatedError: t.ValidationError = { ...error, context }