@prismicio/types-internal 2.2.0-traverse.alpha-5 → 2.2.0-traverse.alpha-7
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.
- package/lib/_internal/utils.d.ts +3 -3
- package/lib/content/Document.d.ts +1248 -32
- package/lib/content/Document.js +1 -1
- package/lib/content/fields/GroupContent.d.ts +273 -7
- package/lib/content/fields/WidgetContent.d.ts +1248 -32
- package/lib/content/fields/nestable/NestableContent.d.ts +156 -4
- package/lib/content/fields/nestable/RichTextContent/Blocks.d.ts +582 -28
- package/lib/content/fields/nestable/RichTextContent/Blocks.js +29 -46
- package/lib/content/fields/nestable/RichTextContent/index.d.ts +195 -5
- package/lib/content/fields/slices/Slice/CompositeSliceContent.d.ts +314 -10
- package/lib/content/fields/slices/Slice/CompositeSliceContent.js +3 -5
- package/lib/content/fields/slices/Slice/RepeatableContent.d.ts +117 -3
- package/lib/content/fields/slices/Slice/SharedSliceContent.d.ts +312 -8
- package/lib/content/fields/slices/Slice/SimpleSliceContent.d.ts +312 -8
- package/lib/content/fields/slices/Slice/index.d.ts +702 -18
- package/lib/content/fields/slices/SliceItem.d.ts +702 -18
- package/lib/content/fields/slices/SlicesContent.d.ts +940 -25
- package/lib/content/fields/slices/SlicesContent.js +3 -5
- package/lib/customtypes/widgets/slices/CompositeSlice.d.ts +0 -5
- package/lib/import/converters/fields/nestable/GeoPoint.d.ts +3 -0
- package/lib/import/converters/fields/nestable/GeoPoint.js +15 -0
- package/lib/import/converters/fields/nestable/Image.d.ts +25 -3
- package/lib/import/converters/fields/nestable/Image.js +21 -25
- package/lib/import/converters/fields/nestable/RichText/embedBlock.d.ts +4 -0
- package/lib/import/converters/fields/nestable/RichText/embedBlock.js +14 -0
- package/lib/import/converters/fields/nestable/RichText/imageBlock.d.ts +4 -0
- package/lib/import/converters/fields/nestable/RichText/imageBlock.js +12 -0
- package/lib/import/converters/fields/nestable/RichText/index.d.ts +4 -0
- package/lib/import/converters/fields/nestable/RichText/index.js +22 -0
- package/lib/import/converters/fields/nestable/RichText/textBlock.d.ts +4 -0
- package/lib/import/converters/fields/nestable/RichText/textBlock.js +41 -0
- package/lib/import/converters/fields/nestable/index.d.ts +1 -1
- package/lib/import/converters/fields/nestable/index.js +1 -1
- package/lib/import/validators/fields/ImportContent.js +3 -3
- package/lib/import/validators/fields/ImportField.d.ts +1 -1
- package/lib/import/validators/fields/ImportSlices/ImportSlices.js +4 -3
- package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/SharedSliceContentEntry.js +1 -1
- package/lib/import/validators/fields/nestable/ImportRichText/ImportRichText.d.ts +1 -1
- package/lib/import/validators/fields/nestable/ImportRichText/ImportRichText.js +20 -14
- package/lib/import/validators/fields/nestable/ImportRichText/blocks/ImportImageBlock.d.ts +16 -2
- package/lib/import/validators/fields/nestable/ImportRichText/blocks/ImportImageBlock.js +7 -5
- package/lib/import/validators/fields/nestable/Nestable.d.ts +1 -1
- package/lib/validators/DefaultOrElse.js +3 -3
- package/package.json +1 -1
- package/src/_internal/utils.ts +3 -3
- package/src/content/Document.ts +1 -1
- package/src/content/fields/nestable/RichTextContent/Blocks.ts +48 -58
- package/src/content/fields/slices/Slice/CompositeSliceContent.ts +4 -9
- package/src/content/fields/slices/SlicesContent.ts +11 -10
- package/src/customtypes/widgets/slices/CompositeSlice.ts +0 -6
- package/src/import/converters/fields/nestable/Image.ts +10 -22
- package/src/import/converters/fields/nestable/RichText/embedBlock.ts +17 -0
- package/src/import/converters/fields/nestable/RichText/imageBlock.ts +17 -0
- package/src/import/converters/fields/nestable/RichText/index.ts +23 -0
- package/src/import/converters/fields/nestable/RichText/textBlock.ts +48 -0
- package/src/import/converters/fields/nestable/index.ts +1 -1
- package/src/import/validators/fields/ImportContent.ts +3 -3
- package/src/import/validators/fields/ImportSlices/ImportSlices.ts +7 -5
- package/src/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/SharedSliceContentEntry.ts +1 -1
- package/src/import/validators/fields/nestable/ImportRichText/ImportRichText.ts +38 -25
- package/src/import/validators/fields/nestable/ImportRichText/blocks/ImportImageBlock.ts +9 -5
- package/src/validators/DefaultOrElse.ts +4 -4
- package/src/import/converters/fields/nestable/RichText.ts +0 -62
- /package/src/import/converters/fields/nestable/{GeooPoint.ts → GeoPoint.ts} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { either } from "fp-ts"
|
|
2
|
-
import {
|
|
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
|
-
|
|
22
|
-
t.
|
|
23
|
-
t.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
export
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
export
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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:
|
|
56
|
+
.sort((m1: S, m2: S) => m1.start - m2.start)
|
|
63
57
|
return t.success(res)
|
|
64
|
-
} else return t.failure(
|
|
58
|
+
} else return t.failure(spans, c)
|
|
65
59
|
},
|
|
66
60
|
(m) => {
|
|
67
|
-
return m.reduce<Array<
|
|
68
|
-
|
|
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:
|
|
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
|
-
|
|
173
|
-
|
|
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:
|
|
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
|
-
|
|
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(
|
|
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 |
|
|
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?.
|
|
159
|
+
: model?.["non-repeat"]?.[fieldKey]
|
|
163
160
|
})()
|
|
164
161
|
|
|
165
162
|
const transformedField = transformWidget({
|
|
@@ -183,9 +180,7 @@ export function traverseCompositeSliceContent({
|
|
|
183
180
|
const items = traverseGroupItemsContent({
|
|
184
181
|
path: path.concat([{ key: "repeat", type: "items" }]),
|
|
185
182
|
model:
|
|
186
|
-
model?.type === "SharedSlice"
|
|
187
|
-
? model?.fields.items
|
|
188
|
-
: model?.fields.repeat,
|
|
183
|
+
model?.type === "SharedSlice" ? model?.fields.items : model?.repeat,
|
|
189
184
|
content: content.widget.repeat,
|
|
190
185
|
})(transformWidget)
|
|
191
186
|
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "../../../_internal/utils"
|
|
11
11
|
import {
|
|
12
12
|
type StaticSlices,
|
|
13
|
-
|
|
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
|
-
|
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
repeat: defaultModel.repeat || {},
|
|
160
|
-
},
|
|
157
|
+
"non-repeat": defaultModel["non-repeat"] || {},
|
|
158
|
+
repeat: defaultModel.repeat || {},
|
|
161
159
|
}
|
|
162
160
|
}
|
|
163
161
|
if (isLegacySlice(defaultModel)) {
|
|
@@ -180,10 +178,13 @@ export function traverseSlices({
|
|
|
180
178
|
content: SlicesContent
|
|
181
179
|
model?: StaticSlices | undefined
|
|
182
180
|
}) {
|
|
183
|
-
return (
|
|
184
|
-
transformWidget
|
|
185
|
-
transformSlice
|
|
186
|
-
|
|
181
|
+
return ({
|
|
182
|
+
transformWidget = ({ content }) => content,
|
|
183
|
+
transformSlice = ({ content }) => content,
|
|
184
|
+
}: {
|
|
185
|
+
transformWidget?: TraverseWidgetContentFn
|
|
186
|
+
transformSlice?: TraverseSliceContentFn
|
|
187
|
+
}): SlicesContent | undefined => {
|
|
187
188
|
const value = content.value.reduce<SlicesContent["value"]>(
|
|
188
189
|
(acc, sliceContent) => {
|
|
189
190
|
const sliceModel = model && findSliceModel(path, model, sliceContent)
|
|
@@ -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 {
|
|
@@ -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
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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]:
|
|
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
|
-
...
|
|
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
|
+
}
|
|
@@ -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
|
-
|
|
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.
|
|
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 {
|
|
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
|
|
19
|
+
const SharedSliceCodec = SharedSlice(supportedSlices)
|
|
20
|
+
const SlicesArrayCodec = t.array(SharedSliceCodec)
|
|
20
21
|
|
|
21
22
|
return ImportContent(
|
|
22
23
|
"Slices",
|
|
23
|
-
|
|
24
|
-
new t.
|
|
25
|
-
|
|
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 }
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as E from "fp-ts/Either"
|
|
2
|
+
import { pipe } from "fp-ts/function"
|
|
1
3
|
import * as t from "io-ts"
|
|
2
4
|
|
|
3
5
|
import type { RichText as RichTextCustomType } from "../../../../../customtypes"
|
|
@@ -6,36 +8,47 @@ import { withCustomError } from "../../../../../validators/function"
|
|
|
6
8
|
import { ImportContent } from "../../ImportContent"
|
|
7
9
|
import { ImportBlock } from "./ImportBlock"
|
|
8
10
|
|
|
9
|
-
export const ImportRichText = (customType?: RichTextCustomType) =>
|
|
10
|
-
|
|
11
|
+
export const ImportRichText = (customType?: RichTextCustomType) => {
|
|
12
|
+
const single = customType?.config?.single?.split(",")
|
|
13
|
+
const multi = customType?.config?.multi?.split(",")
|
|
14
|
+
const allowedBlockTypes = multi || single
|
|
15
|
+
|
|
16
|
+
const isSingleBlockAllowed = multi === undefined && single !== undefined
|
|
17
|
+
|
|
18
|
+
const BlockCodec = ImportBlock(allowedBlockTypes ?? [])
|
|
19
|
+
const RichTextArrayCodec = withCustomError(
|
|
20
|
+
t.array(BlockCodec),
|
|
21
|
+
() => "Rich text field must be an array",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
return ImportContent(
|
|
11
25
|
"StructuredText",
|
|
12
26
|
EmptyArrayOrElse(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
27
|
+
new t.ArrayType<typeof BlockCodec, ImportBlock[], ImportBlock[]>(
|
|
28
|
+
RichTextArrayCodec.name,
|
|
29
|
+
(u): u is ImportBlock[] => RichTextArrayCodec.is(u),
|
|
30
|
+
(u, c) => {
|
|
31
|
+
if (allowedBlockTypes === undefined) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
"Invalid custom type for the rich text field: the model is missing a 'single' or 'multi' field defining a list of allowed block types",
|
|
34
|
+
)
|
|
35
|
+
}
|
|
21
36
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
: t.array(ImportBlock(single)).validate(u, c)
|
|
28
|
-
} else {
|
|
29
|
-
throw new Error(
|
|
30
|
-
"Rich text config must have either a 'single' or 'multi' field defined",
|
|
31
|
-
)
|
|
37
|
+
return pipe(
|
|
38
|
+
RichTextArrayCodec.validate(u, c),
|
|
39
|
+
E.chain((blocks) => {
|
|
40
|
+
if (isSingleBlockAllowed && blocks.length > 1) {
|
|
41
|
+
return t.failure(blocks, c, "This field only allows one block")
|
|
32
42
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
return t.success(blocks)
|
|
44
|
+
}),
|
|
45
|
+
)
|
|
46
|
+
},
|
|
47
|
+
t.identity,
|
|
48
|
+
BlockCodec,
|
|
38
49
|
),
|
|
39
50
|
),
|
|
40
51
|
)
|
|
52
|
+
}
|
|
53
|
+
|
|
41
54
|
export type ImportRichText = t.TypeOf<ReturnType<typeof ImportRichText>>
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import * as t from "io-ts"
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { ImportImageView } from "../../Image/validators"
|
|
4
4
|
|
|
5
5
|
export const ImportImageBlockType = t.literal("image")
|
|
6
6
|
export type ImportImageBlockType = t.TypeOf<typeof ImportImageBlockType>
|
|
7
7
|
|
|
8
|
-
export const ImportImageBlock = t.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
export const ImportImageBlock = t.exact(
|
|
9
|
+
t.intersection([
|
|
10
|
+
t.type({
|
|
11
|
+
type: ImportImageBlockType,
|
|
12
|
+
}),
|
|
13
|
+
ImportImageView,
|
|
14
|
+
]),
|
|
15
|
+
)
|
|
12
16
|
|
|
13
17
|
export type ImportImageBlock = t.TypeOf<typeof ImportImageBlock>
|
|
@@ -6,11 +6,11 @@ import { EmptyArray, EmptyObject } from "./BasicTypes"
|
|
|
6
6
|
export const DefaultOrElse = <I, A, O = A>(inputValidator: t.Type<I>) => {
|
|
7
7
|
return (codec: t.Type<A, O>) =>
|
|
8
8
|
new t.Type<A | null, O | undefined>(
|
|
9
|
-
|
|
9
|
+
`DefaultOrElse<${inputValidator.name}, ${codec.name}>`,
|
|
10
10
|
(u: unknown): u is A | null => null === u || codec.is(u),
|
|
11
|
-
(u: unknown) => {
|
|
12
|
-
if (isRight(inputValidator.
|
|
13
|
-
return codec.
|
|
11
|
+
(u: unknown, c) => {
|
|
12
|
+
if (isRight(inputValidator.validate(u, c))) return t.success(null)
|
|
13
|
+
return codec.validate(u, c)
|
|
14
14
|
},
|
|
15
15
|
(chunk) => (chunk ? codec.encode(chunk) : undefined),
|
|
16
16
|
)
|