@prismicio/types-internal 2.2.0-traverse.alpha-1 → 2.2.0-traverse.alpha-3

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 (122) 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 +2194 -13
  4. package/lib/content/Document.js +64 -36
  5. package/lib/content/fields/GroupContent.d.ts +6 -4
  6. package/lib/content/fields/GroupContent.js +13 -9
  7. package/lib/content/fields/slices/Slice/CompositeSliceContent.d.ts +9 -6
  8. package/lib/content/fields/slices/Slice/CompositeSliceContent.js +61 -17
  9. package/lib/content/fields/slices/Slice/SharedSliceContent.d.ts +8 -6
  10. package/lib/content/fields/slices/Slice/SharedSliceContent.js +26 -18
  11. package/lib/content/fields/slices/Slice/SimpleSliceContent.d.ts +11 -0
  12. package/lib/content/fields/slices/Slice/SimpleSliceContent.js +100 -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 -60
  17. package/lib/customtypes/CustomType.d.ts +8 -1
  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/converters/fields/nestable/Image.d.ts +3 -1
  27. package/lib/import/converters/fields/nestable/Image.js +18 -2
  28. package/lib/import/converters/fields/nestable/Nestable.js +2 -0
  29. package/lib/import/converters/fields/nestable/RichText.d.ts +4 -0
  30. package/lib/import/converters/fields/nestable/RichText.js +55 -0
  31. package/lib/import/converters/fields/nestable/index.d.ts +1 -0
  32. package/lib/import/converters/fields/nestable/index.js +1 -0
  33. package/lib/import/validators/fields/ImportField.d.ts +6 -0
  34. package/lib/import/validators/fields/ImportSlices/SharedSlice/SharedSlice.js +1 -1
  35. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceType.js +1 -1
  36. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceVariation.js +1 -1
  37. package/lib/import/validators/fields/ImportSlices/SharedSlice/utils.d.ts +3 -0
  38. package/lib/import/validators/fields/nestable/Embed.d.ts +3 -0
  39. package/lib/import/validators/fields/nestable/Embed.js +3 -8
  40. package/lib/import/validators/fields/nestable/GeoPoint.js +2 -2
  41. package/lib/import/validators/fields/nestable/Image/default.d.ts +22 -0
  42. package/lib/import/validators/fields/nestable/Image/default.js +19 -0
  43. package/lib/import/validators/fields/nestable/Image/index.d.ts +19 -0
  44. package/lib/import/validators/fields/nestable/Image/index.js +22 -22
  45. package/lib/import/validators/fields/nestable/Image/merge.d.ts +23 -0
  46. package/lib/import/validators/fields/nestable/Image/{Decoder.js → merge.js} +18 -14
  47. package/lib/import/validators/fields/nestable/Image/{Validator.d.ts → validators.d.ts} +4 -2
  48. package/lib/import/validators/fields/nestable/Image/{Validator.js → validators.js} +7 -3
  49. package/lib/import/validators/fields/nestable/ImportRichText/ImportBlock.d.ts +6 -0
  50. package/lib/import/validators/fields/nestable/ImportRichText/ImportBlock.js +25 -0
  51. package/lib/import/validators/fields/nestable/ImportRichText/ImportRichText.d.ts +24 -0
  52. package/lib/import/validators/fields/nestable/ImportRichText/ImportRichText.js +26 -0
  53. package/lib/import/validators/fields/nestable/ImportRichText/blocks/ImportBlockType.d.ts +6 -0
  54. package/lib/import/validators/fields/nestable/ImportRichText/blocks/ImportBlockType.js +18 -0
  55. package/lib/import/validators/fields/nestable/ImportRichText/blocks/ImportEmbedBlock.d.ts +10 -0
  56. package/lib/import/validators/fields/nestable/ImportRichText/blocks/ImportEmbedBlock.js +11 -0
  57. package/lib/import/validators/fields/nestable/ImportRichText/blocks/ImportImageBlock.d.ts +8 -0
  58. package/lib/import/validators/fields/nestable/ImportRichText/blocks/ImportImageBlock.js +11 -0
  59. package/lib/import/validators/fields/nestable/ImportRichText/blocks/ImportTextBlock.d.ts +70 -0
  60. package/lib/import/validators/fields/nestable/ImportRichText/blocks/ImportTextBlock.js +43 -0
  61. package/lib/import/validators/fields/nestable/ImportRichText/blocks/Span.d.ts +65 -0
  62. package/lib/import/validators/fields/nestable/ImportRichText/blocks/Span.js +20 -0
  63. package/lib/import/validators/fields/nestable/ImportRichText/blocks/index.d.ts +4 -0
  64. package/lib/import/validators/fields/nestable/ImportRichText/blocks/index.js +7 -0
  65. package/lib/import/validators/fields/nestable/ImportRichText/blocks/spans/HyperlinkSpan.d.ts +24 -0
  66. package/lib/import/validators/fields/nestable/ImportRichText/blocks/spans/HyperlinkSpan.js +18 -0
  67. package/lib/import/validators/fields/nestable/ImportRichText/blocks/spans/SpanLocation.d.ts +5 -0
  68. package/lib/import/validators/fields/nestable/ImportRichText/blocks/spans/SpanLocation.js +10 -0
  69. package/lib/import/validators/fields/nestable/ImportRichText/blocks/spans/TextSpan.d.ts +17 -0
  70. package/lib/import/validators/fields/nestable/ImportRichText/blocks/spans/TextSpan.js +22 -0
  71. package/lib/import/validators/fields/nestable/ImportRichText/blocks/spans/index.d.ts +2 -0
  72. package/lib/import/validators/fields/nestable/ImportRichText/blocks/spans/index.js +5 -0
  73. package/lib/import/validators/fields/nestable/ImportRichText/index.d.ts +2 -0
  74. package/lib/import/validators/fields/nestable/ImportRichText/index.js +7 -0
  75. package/lib/import/validators/fields/nestable/Link.d.ts +21 -6
  76. package/lib/import/validators/fields/nestable/Link.js +8 -8
  77. package/lib/import/validators/fields/nestable/Nestable.d.ts +8 -1
  78. package/lib/import/validators/fields/nestable/Nestable.js +5 -1
  79. package/lib/import/validators/fields/nestable/index.d.ts +2 -1
  80. package/lib/import/validators/fields/nestable/index.js +4 -1
  81. package/package.json +1 -1
  82. package/src/_internal/utils.ts +63 -7
  83. package/src/content/Document.ts +106 -47
  84. package/src/content/fields/GroupContent.ts +25 -12
  85. package/src/content/fields/slices/Slice/CompositeSliceContent.ts +91 -22
  86. package/src/content/fields/slices/Slice/SharedSliceContent.ts +42 -26
  87. package/src/content/fields/slices/Slice/SimpleSliceContent.ts +144 -1
  88. package/src/content/fields/slices/SliceItem.ts +39 -3
  89. package/src/content/fields/slices/SlicesContent.ts +172 -67
  90. package/src/customtypes/CustomType.ts +23 -1
  91. package/src/customtypes/widgets/slices/CompositeSlice.ts +6 -0
  92. package/src/customtypes/widgets/slices/SharedSlice.ts +12 -0
  93. package/src/import/converters/fields/nestable/Image.ts +34 -4
  94. package/src/import/converters/fields/nestable/Nestable.ts +3 -0
  95. package/src/import/converters/fields/nestable/RichText.ts +62 -0
  96. package/src/import/converters/fields/nestable/index.ts +1 -0
  97. package/src/import/validators/fields/ImportSlices/SharedSlice/SharedSlice.ts +1 -1
  98. package/src/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceType.ts +1 -1
  99. package/src/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceVariation.ts +1 -1
  100. package/src/import/validators/fields/nestable/Embed.ts +4 -17
  101. package/src/import/validators/fields/nestable/GeoPoint.ts +2 -2
  102. package/src/import/validators/fields/nestable/Image/default.ts +25 -0
  103. package/src/import/validators/fields/nestable/Image/index.ts +34 -36
  104. package/src/import/validators/fields/nestable/Image/{Decoder.ts → merge.ts} +23 -20
  105. package/src/import/validators/fields/nestable/Image/{Validator.ts → validators.ts} +9 -2
  106. package/src/import/validators/fields/nestable/ImportRichText/ImportBlock.ts +39 -0
  107. package/src/import/validators/fields/nestable/ImportRichText/ImportRichText.ts +41 -0
  108. package/src/import/validators/fields/nestable/ImportRichText/blocks/ImportBlockType.ts +44 -0
  109. package/src/import/validators/fields/nestable/ImportRichText/blocks/ImportEmbedBlock.ts +13 -0
  110. package/src/import/validators/fields/nestable/ImportRichText/blocks/ImportImageBlock.ts +13 -0
  111. package/src/import/validators/fields/nestable/ImportRichText/blocks/ImportTextBlock.ts +56 -0
  112. package/src/import/validators/fields/nestable/ImportRichText/blocks/Span.ts +44 -0
  113. package/src/import/validators/fields/nestable/ImportRichText/blocks/index.ts +4 -0
  114. package/src/import/validators/fields/nestable/ImportRichText/blocks/spans/HyperlinkSpan.ts +24 -0
  115. package/src/import/validators/fields/nestable/ImportRichText/blocks/spans/SpanLocation.ts +8 -0
  116. package/src/import/validators/fields/nestable/ImportRichText/blocks/spans/TextSpan.ts +26 -0
  117. package/src/import/validators/fields/nestable/ImportRichText/blocks/spans/index.ts +2 -0
  118. package/src/import/validators/fields/nestable/ImportRichText/index.ts +2 -0
  119. package/src/import/validators/fields/nestable/Link.ts +18 -13
  120. package/src/import/validators/fields/nestable/Nestable.ts +6 -1
  121. package/src/import/validators/fields/nestable/index.ts +2 -1
  122. package/lib/import/validators/fields/nestable/Image/Decoder.d.ts +0 -26
@@ -2,13 +2,22 @@ import { either } from "fp-ts"
2
2
  import { pipe } from "fp-ts/lib/function"
3
3
  import * as t from "io-ts"
4
4
 
5
- import type { ContentPath, TraverseContentFn } from "../../../_internal/utils"
6
5
  import {
7
- type StaticSlice,
6
+ ContentPath,
7
+ SliceModel,
8
+ TraverseSliceContentFn,
9
+ TraverseWidgetContentFn,
10
+ } from "../../../_internal/utils"
11
+ import {
8
12
  type StaticSlices,
13
+ CompositeSliceFields,
14
+ Group,
9
15
  isCompositeSlice,
10
16
  isLegacySlice,
11
17
  isStaticSharedSlice,
18
+ NestableWidget,
19
+ SharedSlice,
20
+ VariationFields,
12
21
  } from "../../../customtypes"
13
22
  import type {
14
23
  FieldOrSliceType,
@@ -16,10 +25,16 @@ import type {
16
25
  WithTypes,
17
26
  } from "../../LegacyContentCtx"
18
27
  import { hasContentType } from "../../utils"
19
- import { traverseGroupContent } from "../GroupContent"
20
28
  import { traverseCompositeSliceContent } from "./Slice/CompositeSliceContent"
21
29
  import { traverseSharedSliceContent } from "./Slice/SharedSliceContent"
22
- import { SliceItemContent, SlicesItemLegacy } from "./SliceItem"
30
+ import { traverseSimpleSliceContent } from "./Slice/SimpleSliceContent"
31
+ import {
32
+ isCompositeSliceItemContent,
33
+ isSharedSliceItemContent,
34
+ isSimpleSliceItemContent,
35
+ SliceItemContent,
36
+ SlicesItemLegacy,
37
+ } from "./SliceItem"
23
38
 
24
39
  export const SlicesContentType = "SliceContentType"
25
40
 
@@ -66,85 +81,175 @@ export const SlicesContent = t.type({
66
81
 
67
82
  export type SlicesContent = t.TypeOf<typeof SlicesContent>
68
83
 
84
+ function findSliceModel(
85
+ slicesPath: ContentPath,
86
+ model: StaticSlices,
87
+ content: SliceItemContent,
88
+ ): SliceModel | undefined {
89
+ const defaultModel = model?.config?.choices?.[content.name]
90
+
91
+ // regular case for shared slices
92
+ const sharedSliceModel = (): VariationFields | undefined => {
93
+ if (isSharedSliceItemContent(content)) {
94
+ if (defaultModel && isStaticSharedSlice(defaultModel)) {
95
+ const variationDef = defaultModel.variations.find(
96
+ (v) => v.id === content.widget.variation,
97
+ )
98
+ return variationDef
99
+ ? {
100
+ type: "SharedSlice",
101
+ sliceName: defaultModel.id,
102
+ variationId: variationDef.id,
103
+ fields: {
104
+ primary: variationDef.primary || {},
105
+ items: variationDef.items || {},
106
+ },
107
+ }
108
+ : undefined
109
+ }
110
+ }
111
+ return
112
+ }
113
+
114
+ const migratedSliceModel = (): VariationFields | undefined => {
115
+ const legacyContentPath = ContentPath.append(
116
+ ContentPath.serialize(slicesPath),
117
+ content.name,
118
+ )
119
+
120
+ const migratedSliceModel = Object.values(model?.config?.choices || {}).find(
121
+ (sliceModel): sliceModel is SharedSlice => {
122
+ if (isStaticSharedSlice(sliceModel)) {
123
+ return !!sliceModel.legacyPaths?.[legacyContentPath]
124
+ }
125
+
126
+ return false
127
+ },
128
+ )
129
+ if (!migratedSliceModel) return
130
+
131
+ const migratedVariation = migratedSliceModel?.variations.find(
132
+ (v) => v.id === migratedSliceModel.legacyPaths?.[legacyContentPath],
133
+ )
134
+ if (!migratedVariation) return
135
+
136
+ return {
137
+ type: "SharedSlice",
138
+ sliceName: migratedSliceModel.id,
139
+ variationId: migratedVariation.id,
140
+ fields: {
141
+ primary: migratedVariation.primary || {},
142
+ items: migratedVariation.items || {},
143
+ },
144
+ }
145
+ }
146
+
147
+ const legacySliceModel = ():
148
+ | NestableWidget
149
+ | CompositeSliceFields
150
+ | Group
151
+ | undefined => {
152
+ if (!defaultModel) return
153
+
154
+ if (isCompositeSlice(defaultModel)) {
155
+ return {
156
+ type: "Slice",
157
+ fields: {
158
+ "non-repeat": defaultModel["non-repeat"] || {},
159
+ repeat: defaultModel.repeat || {},
160
+ },
161
+ }
162
+ }
163
+ if (isLegacySlice(defaultModel)) {
164
+ return defaultModel
165
+ }
166
+
167
+ return
168
+ }
169
+ return sharedSliceModel() || migratedSliceModel() || legacySliceModel()
170
+ }
171
+
69
172
  export function traverseSlices({
70
173
  path,
174
+ key,
71
175
  model,
72
176
  content,
73
177
  }: {
74
178
  path: ContentPath
179
+ key: string
75
180
  content: SlicesContent
76
181
  model?: StaticSlices | undefined
77
182
  }) {
78
- return (transform: TraverseContentFn): SlicesContent => {
183
+ return (
184
+ transformWidget: TraverseWidgetContentFn,
185
+ transformSlice: TraverseSliceContentFn,
186
+ ): SlicesContent | undefined => {
79
187
  const value = content.value.reduce<SlicesContent["value"]>(
80
188
  (acc, sliceContent) => {
81
- const sliceModel: StaticSlice | undefined =
82
- model?.config?.choices?.[sliceContent.name]
83
-
84
- const slicePath = path.concat({
85
- key: sliceContent.key,
86
- type: sliceContent.widget.__TYPE__,
87
- })
88
-
89
- const convertedSliceWidget = (() => {
90
- switch (sliceContent.widget.__TYPE__) {
91
- case "SharedSliceContent":
92
- return traverseSharedSliceContent({
93
- path: slicePath,
94
- sliceName: sliceContent.name,
95
- model:
96
- sliceModel && isStaticSharedSlice(sliceModel)
97
- ? sliceModel
98
- : undefined,
99
- content: sliceContent.widget,
100
- })(transform)
101
- case "CompositeSliceContent":
102
- return traverseCompositeSliceContent({
103
- path: slicePath,
104
- sliceName: sliceContent.name,
105
- model:
106
- sliceModel && isCompositeSlice(sliceModel)
107
- ? sliceModel
108
- : undefined,
109
- content: sliceContent.widget,
110
- })(transform)
111
- case "GroupContentType":
112
- return traverseGroupContent({
113
- path: slicePath,
114
- model:
115
- sliceModel &&
116
- isLegacySlice(sliceModel) &&
117
- sliceModel.type === "Group"
118
- ? sliceModel
119
- : undefined,
120
- content: sliceContent.widget,
121
- })(transform)
122
- default:
123
- return sliceContent.widget
124
- }
189
+ const sliceModel = model && findSliceModel(path, model, sliceContent)
190
+
191
+ const convertedSlice: SliceItemContent | undefined = (() => {
192
+ if (isSharedSliceItemContent(sliceContent))
193
+ return traverseSharedSliceContent({
194
+ path: path.concat({
195
+ key: sliceContent.key,
196
+ type: "SharedSlice",
197
+ }),
198
+ sliceKey: sliceContent.key,
199
+ sliceName: sliceContent.name,
200
+ model:
201
+ sliceModel?.type === "SharedSlice" ? sliceModel : undefined,
202
+ content: sliceContent,
203
+ })(transformWidget, transformSlice)
204
+
205
+ if (isCompositeSliceItemContent(sliceContent))
206
+ return traverseCompositeSliceContent({
207
+ path: path.concat({
208
+ key: sliceContent.key,
209
+ type: "Slice",
210
+ }),
211
+ sliceKey: sliceContent.key,
212
+ sliceName: sliceContent.name,
213
+ model:
214
+ sliceModel?.type === "Slice" ||
215
+ sliceModel?.type === "SharedSlice"
216
+ ? sliceModel
217
+ : undefined,
218
+ content: sliceContent,
219
+ })(transformWidget, transformSlice)
220
+
221
+ if (isSimpleSliceItemContent(sliceContent))
222
+ return traverseSimpleSliceContent({
223
+ path: path.concat({
224
+ key: sliceContent.key,
225
+ type: "LegacySlice",
226
+ }),
227
+ sliceKey: sliceContent.key,
228
+ sliceName: sliceContent.name,
229
+ model:
230
+ sliceModel && sliceModel?.type !== "Slice"
231
+ ? sliceModel
232
+ : undefined,
233
+ content: sliceContent,
234
+ })(transformWidget, transformSlice)
235
+
236
+ return
125
237
  })()
126
238
 
127
- const convertedSlice = transform({
128
- key: sliceContent.key,
129
- apiId: sliceContent.name,
130
- path: slicePath,
131
- model: sliceModel,
132
- content: convertedSliceWidget,
133
- })
134
-
135
- const convertedSliceParent = convertedSlice && {
136
- ...sliceContent,
137
- widget: convertedSlice,
138
- }
139
-
140
- return convertedSliceParent ? acc.concat(convertedSliceParent) : acc
239
+ return convertedSlice ? acc.concat(convertedSlice) : acc
141
240
  },
142
241
  [],
143
242
  )
144
243
 
145
- return {
146
- __TYPE__: content.__TYPE__,
147
- value,
148
- }
244
+ return transformWidget({
245
+ path,
246
+ key,
247
+ apiId: key,
248
+ model,
249
+ content: {
250
+ __TYPE__: content.__TYPE__,
251
+ value,
252
+ },
253
+ })
149
254
  }
150
255
  }
@@ -215,7 +215,7 @@ export function filterMissingSharedSlices(
215
215
 
216
216
  export function flattenCustomTypeFields(
217
217
  customType: StaticCustomType,
218
- ): Partial<Record<string, StaticWidget>> {
218
+ ): Record<string, StaticWidget> {
219
219
  return Object.values(customType.json).reduce(
220
220
  (acc, tab) => ({
221
221
  ...acc,
@@ -224,3 +224,25 @@ export function flattenCustomTypeFields(
224
224
  {},
225
225
  )
226
226
  }
227
+
228
+ export function collectSharedSlices(customType: {
229
+ customTypeId: string
230
+ fields: Record<string, StaticWidget>
231
+ }): Record<string, SharedSlice> {
232
+ return Object.entries(customType.fields).reduce((acc, [, w]) => {
233
+ if (w.type === "Slices" || w.type === "Choice") {
234
+ return {
235
+ ...acc,
236
+ ...Object.entries(w.config?.choices || {}).reduce(
237
+ (sliceZoneAcc, [sliceKey, sliceModel]) => {
238
+ return sliceModel.type === "SharedSlice"
239
+ ? { ...sliceZoneAcc, [sliceKey]: sliceModel }
240
+ : sliceZoneAcc
241
+ },
242
+ {},
243
+ ),
244
+ }
245
+ }
246
+ return acc
247
+ }, {})
248
+ }
@@ -1,5 +1,6 @@
1
1
  import * as t from "io-ts"
2
2
 
3
+ import type { PickOnly } from "../../../_internal/utils"
3
4
  import { WidgetKey } from "../../../common"
4
5
  import { StringOrNull } from "../../../validators"
5
6
  import { NestableWidget } from "../nestable/NestableWidget"
@@ -32,6 +33,11 @@ export const CompositeSlice = t.exact(
32
33
  )
33
34
  export type CompositeSlice = t.TypeOf<typeof CompositeSlice>
34
35
 
36
+ export type CompositeSliceFields = {
37
+ type: "Slice"
38
+ fields: PickOnly<CompositeSlice, "non-repeat" | "repeat">
39
+ }
40
+
35
41
  export function isCompositeSlice(
36
42
  slice: DynamicSlice | StaticSlice,
37
43
  ): slice is CompositeSlice {
@@ -1,6 +1,7 @@
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"
4
5
  import { WidgetKey } from "../../../common"
5
6
  import { NestableWidget } from "../nestable/NestableWidget"
6
7
  import type { SharedSliceRef } from "./SharedSliceRef"
@@ -29,8 +30,18 @@ export const Variation = t.exact(
29
30
 
30
31
  export type Variation = t.TypeOf<typeof Variation>
31
32
 
33
+ export type VariationFields = {
34
+ type: "SharedSlice"
35
+ sliceName: string
36
+ variationId: string
37
+ fields: PickOnly<Variation, "primary" | "items">
38
+ }
39
+
32
40
  export const SharedSliceType = "SharedSlice"
33
41
 
42
+ const LegacyPath = t.string
43
+ const VariationId = t.string
44
+
34
45
  export const SharedSlice = t.exact(
35
46
  t.intersection([
36
47
  t.type({
@@ -41,6 +52,7 @@ export const SharedSlice = t.exact(
41
52
  }),
42
53
  t.partial({
43
54
  description: t.string,
55
+ legacyPaths: t.record(LegacyPath, VariationId),
44
56
  }),
45
57
  ]),
46
58
  )
@@ -1,11 +1,28 @@
1
1
  import type { Asset } from "../../../../common"
2
2
  import { getAssetOrThrow } from "../../../../common"
3
- import type { ImageContent } from "../../../../content"
3
+ import type { ImageContent, ImageContentView } from "../../../../content"
4
4
  import { withOptionals } from "../../../../utils/Objects"
5
5
  import type { ImageField, ImportImage } from "../../../validators"
6
+ import type { ImportImageBlock } from "../../../validators/fields/nestable/ImportRichText/blocks"
6
7
 
7
- function convertImage(imageField: ImageField, image: Asset) {
8
- return withOptionals<Omit<ImageContent, "__TYPE__" | "thumbnails">>(
8
+ function convertImage<Input extends ImageField | ImportImageBlock>(
9
+ inputImage: Input,
10
+ image: Asset,
11
+ ) {
12
+ // We can do that because anyway all properties being read
13
+ const imageField: ImageField = {
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 : {},
24
+ }
25
+ return withOptionals<ImageContentView>(
9
26
  {
10
27
  origin: {
11
28
  id: image.id,
@@ -57,6 +74,16 @@ function convertThumbnails(
57
74
  )
58
75
  }
59
76
 
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
+
60
87
  // All assets from `imageField` must be present in `assets`
61
88
  // If not then function will throw an error
62
89
  export const imageConverter = (
@@ -66,7 +93,10 @@ export const imageConverter = (
66
93
  if (!imageField) return
67
94
 
68
95
  return {
69
- ...convertImage(imageField, getAssetOrThrow(assets)(imageField.id)),
96
+ ...convertImage<ImageField>(
97
+ imageField,
98
+ getAssetOrThrow(assets)(imageField.id),
99
+ ),
70
100
  thumbnails: convertThumbnails(imageField, assets),
71
101
  __TYPE__: "ImageContent" as const,
72
102
  }
@@ -11,6 +11,7 @@ import {
11
11
  imageConverter,
12
12
  linkConverter,
13
13
  numberConverter,
14
+ richTextConverter,
14
15
  selectConverter,
15
16
  textConverter,
16
17
  timestampConverter,
@@ -44,6 +45,8 @@ export function convertNestableWidget(
44
45
  return linkConverter(field.value, assets)
45
46
  case "Image":
46
47
  return imageConverter(field.value, assets)
48
+ case "StructuredText":
49
+ return richTextConverter(field.value, assets, embeds)
47
50
  default:
48
51
  throw new Error(
49
52
  `Unsupported type of nestable converter ${JSON.stringify(field)}`,
@@ -0,0 +1,62 @@
1
+ import type { Asset, Embed } from "../../../../common"
2
+ import type { Block, RichTextContent } from "../../../../content"
3
+ import { RichTextContentType } from "../../../../content"
4
+ import type { ImportBlock, ImportRichText } from "../../../validators"
5
+ import { embedConverter } from "./Embed"
6
+ import { imageBlockConverter } from "./Image"
7
+ import { linkConverter } from "./Link"
8
+
9
+ const richTextBlockConverter = (
10
+ importBlock: ImportBlock,
11
+ assets: Record<Asset["id"], Asset | undefined>,
12
+ embeds: Record<string, Embed | undefined>,
13
+ ): Block => {
14
+ if (importBlock.type === "image") {
15
+ return {
16
+ type: importBlock.type,
17
+ data: imageBlockConverter(importBlock, assets),
18
+ }
19
+ } else if (importBlock.type === "embed") {
20
+ const embedData = embedConverter(importBlock.oembed, embeds)
21
+ if (!embedData) throw new Error("Failed to convert embed data")
22
+ return {
23
+ type: importBlock.type,
24
+ data: embedData,
25
+ }
26
+ } else {
27
+ // Text block
28
+ return {
29
+ type: importBlock.type,
30
+ direction: importBlock.direction ?? "ltr",
31
+ content: {
32
+ text: importBlock.text,
33
+ spans:
34
+ importBlock.spans?.map((span) => {
35
+ const linkData =
36
+ span.type === "hyperlink"
37
+ ? linkConverter(span.data, assets)
38
+ : undefined
39
+ return {
40
+ type: span.type,
41
+ start: span.start,
42
+ end: span.end,
43
+ data: linkData,
44
+ }
45
+ }) ?? [],
46
+ },
47
+ }
48
+ }
49
+ }
50
+ export const richTextConverter = (
51
+ richTextField: ImportRichText["value"],
52
+ assets: Record<Asset["id"], Asset | undefined>,
53
+ embeds: Record<string, Embed | undefined>,
54
+ ): RichTextContent | undefined => {
55
+ if (richTextField === null) return
56
+ return {
57
+ __TYPE__: RichTextContentType,
58
+ value: richTextField.map((block) =>
59
+ richTextBlockConverter(block, assets, embeds),
60
+ ),
61
+ }
62
+ }
@@ -7,6 +7,7 @@ export * from "./Image"
7
7
  export * from "./Link"
8
8
  export * from "./Nestable"
9
9
  export * from "./Number"
10
+ export * from "./RichText"
10
11
  export * from "./Select"
11
12
  export * from "./Text"
12
13
  export * from "./Timestamp"
@@ -24,7 +24,7 @@ export type SharedSlice = {
24
24
  version: string | null | undefined
25
25
  }
26
26
 
27
- const SharedSliceShape = t.type({
27
+ const SharedSliceShape = t.strict({
28
28
  id: OptionalSharedSliceId,
29
29
  slice_type: NonEmptyString,
30
30
  name: String,
@@ -15,7 +15,7 @@ export type SharedSliceType = {
15
15
  * slice_type - the validated slice_type
16
16
  * slice - SharedSlice custom type data matching the slice_type. We return it alongside the validated slice_type, because it is needed to decode the 'variation' field in the SharedSlice (see SharedSliceVariation.ts)
17
17
  */
18
- const SharedSliceTypeShape = t.type({
18
+ const SharedSliceTypeShape = t.strict({
19
19
  slice_type: NonEmptyString,
20
20
  slice: SharedSliceCustomType,
21
21
  })
@@ -15,7 +15,7 @@ export type SharedSliceVariation = {
15
15
  * variation - the validated variation of the slice
16
16
  * data - Variation data matching the variation. We return it alongside the validated variation, because it is needed to decode the 'primary' and 'items' fields in the SharedSlice.
17
17
  */
18
- const SharedSliceVariationShape = t.type({
18
+ const SharedSliceVariationShape = t.strict({
19
19
  variation: NonEmptyString,
20
20
  data: Variation,
21
21
  })
@@ -1,5 +1,3 @@
1
- import * as Either from "fp-ts/Either"
2
- import { pipe } from "fp-ts/lib/function"
3
1
  import * as t from "io-ts"
4
2
 
5
3
  import { EmptyObjectOrElse } from "../../../../validators"
@@ -32,23 +30,12 @@ const EmbedUrl = new t.Type<URL, URL, unknown>(
32
30
  t.identity,
33
31
  )
34
32
 
35
- const EmbedProto = t.type({
33
+ export const ImportEmbedValue = t.strict({
36
34
  embed_url: EmbedUrl,
37
35
  })
38
- type EmbedProto = t.TypeOf<typeof EmbedProto>
39
36
 
40
- type Embed = EmbedProto
41
- const Embed = new t.Type<Embed>(
42
- "ImportEmbedValue",
43
- (u: unknown): u is Embed => EmbedProto.is(u),
44
- (u: unknown) => {
45
- return pipe(
46
- EmbedProto.decode(u),
47
- Either.map((parsed) => ({ embed_url: parsed.embed_url })),
48
- )
49
- },
50
- t.identity,
37
+ export const ImportEmbed = ImportContent(
38
+ "Embed",
39
+ EmptyObjectOrElse(ImportEmbedValue),
51
40
  )
52
-
53
- export const ImportEmbed = ImportContent("Embed", EmptyObjectOrElse(Embed))
54
41
  export type ImportEmbed = t.TypeOf<typeof ImportEmbed>
@@ -5,7 +5,7 @@ import { EmptyObjectOrElse, NumberRange } from "../../../../validators"
5
5
  import { withCustomError } from "../../../../validators/function"
6
6
  import { ImportContent } from "../ImportContent"
7
7
 
8
- const GeooPoint = withCustomError(
8
+ const GeoPoint = withCustomError(
9
9
  t.strict({
10
10
  latitude: NumberRange(-90, 90, "latitude"),
11
11
  longitude: NumberRange(-180, 180, "longitude"),
@@ -16,6 +16,6 @@ const GeooPoint = withCustomError(
16
16
 
17
17
  export const ImportGeoPoint = ImportContent(
18
18
  "GeoPoint",
19
- EmptyObjectOrElse(GeooPoint),
19
+ EmptyObjectOrElse(GeoPoint),
20
20
  )
21
21
  export type ImportGeoPoint = TypeOf<typeof ImportGeoPoint>
@@ -0,0 +1,25 @@
1
+ import * as t from "io-ts"
2
+
3
+ import type { Image as ImageDefinition } from "../../../../../customtypes"
4
+ import { EmptyObject } from "../../../../../validators"
5
+ import { withCustomError } from "../../../../../validators/function"
6
+
7
+ export const defaultImportImage = (field?: ImageDefinition) => {
8
+ // If there is not thumbnails we expect an empty object
9
+ if (!field?.config?.thumbnails || !field.config.thumbnails.length)
10
+ return EmptyObject
11
+
12
+ // If there are thumbnails, we expect an object with thumbnails as empty objects
13
+ return withCustomError(
14
+ t.strict(
15
+ field.config.thumbnails.reduce(
16
+ (acc, thumbnail) => ({
17
+ ...acc,
18
+ [thumbnail.name]: EmptyObject,
19
+ }),
20
+ {},
21
+ ),
22
+ ),
23
+ () => "The value must be an object",
24
+ )
25
+ }