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

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 (183) hide show
  1. package/lib/_internal/utils.d.ts +17 -0
  2. package/lib/_internal/utils.js +9 -0
  3. package/lib/common/Asset.d.ts +3 -4
  4. package/lib/common/Embed.d.ts +1 -2
  5. package/lib/common/UUID.d.ts +7 -0
  6. package/lib/common/UUID.js +8 -0
  7. package/lib/common/index.d.ts +1 -0
  8. package/lib/common/index.js +1 -0
  9. package/lib/content/Document.d.ts +22 -3
  10. package/lib/content/Document.js +71 -1
  11. package/lib/content/fields/GroupContent.d.ts +7 -0
  12. package/lib/content/fields/GroupContent.js +34 -1
  13. package/lib/content/fields/WidgetContent.d.ts +6 -6
  14. package/lib/content/fields/nestable/NestableContent.d.ts +2 -0
  15. package/lib/content/fields/nestable/NestableContent.js +29 -1
  16. package/lib/content/fields/slices/Slice/CompositeSliceContent.d.ts +8 -0
  17. package/lib/content/fields/slices/Slice/CompositeSliceContent.js +56 -1
  18. package/lib/content/fields/slices/Slice/RepeatableContent.js +0 -1
  19. package/lib/content/fields/slices/Slice/SharedSliceContent.d.ts +8 -0
  20. package/lib/content/fields/slices/Slice/SharedSliceContent.js +58 -1
  21. package/lib/content/fields/slices/SlicesContent.d.ts +7 -0
  22. package/lib/content/fields/slices/SlicesContent.js +70 -1
  23. package/lib/customtypes/CustomType.d.ts +1 -0
  24. package/lib/customtypes/CustomType.js +8 -1
  25. package/lib/customtypes/widgets/slices/CompositeSlice.d.ts +2 -0
  26. package/lib/customtypes/widgets/slices/CompositeSlice.js +5 -1
  27. package/lib/customtypes/widgets/slices/LegacySlice.d.ts +2 -0
  28. package/lib/customtypes/widgets/slices/LegacySlice.js +5 -1
  29. package/lib/customtypes/widgets/slices/SharedSlice.d.ts +4 -0
  30. package/lib/customtypes/widgets/slices/SharedSlice.js +9 -1
  31. package/lib/import/converters/Document.d.ts +2 -2
  32. package/lib/import/converters/Document.js +6 -6
  33. package/lib/import/converters/fields/Slices/SharedSlice.d.ts +4 -0
  34. package/lib/import/converters/fields/Slices/SharedSlice.js +19 -0
  35. package/lib/import/converters/fields/Slices/SharedSliceContent.d.ts +10 -0
  36. package/lib/import/converters/fields/Slices/SharedSliceContent.js +58 -0
  37. package/lib/import/converters/fields/Slices/Slices.d.ts +4 -0
  38. package/lib/import/converters/fields/Slices/Slices.js +16 -0
  39. package/lib/import/converters/fields/Slices/index.d.ts +1 -0
  40. package/lib/import/converters/fields/Slices/index.js +4 -0
  41. package/lib/import/converters/fields/UID.d.ts +1 -1
  42. package/lib/import/converters/fields/UID.js +0 -2
  43. package/lib/import/converters/fields/index.d.ts +1 -0
  44. package/lib/import/converters/fields/index.js +1 -0
  45. package/lib/import/converters/fields/nestable/Embed.d.ts +2 -1
  46. package/lib/import/converters/fields/nestable/Embed.js +24 -5
  47. package/lib/import/converters/fields/nestable/Image.d.ts +2 -2
  48. package/lib/import/converters/fields/nestable/Image.js +1 -1
  49. package/lib/import/converters/fields/nestable/Link.d.ts +1 -1
  50. package/lib/import/converters/fields/nestable/Link.js +6 -6
  51. package/lib/import/converters/fields/nestable/Nestable.d.ts +4 -3
  52. package/lib/import/converters/fields/nestable/Nestable.js +2 -2
  53. package/lib/import/validators/Document.js +2 -2
  54. package/lib/import/validators/fields/ImportField.d.ts +17 -68
  55. package/lib/import/validators/fields/ImportField.js +8 -4
  56. package/lib/import/validators/fields/ImportSlices/ImportSlices.d.ts +8 -0
  57. package/lib/import/validators/fields/ImportSlices/ImportSlices.js +29 -0
  58. package/lib/import/validators/fields/ImportSlices/SharedSlice/SharedSlice.d.ts +14 -0
  59. package/lib/import/validators/fields/ImportSlices/SharedSlice/SharedSlice.js +61 -0
  60. package/lib/import/validators/fields/ImportSlices/SharedSlice/errors.d.ts +4 -0
  61. package/lib/import/validators/fields/ImportSlices/SharedSlice/errors.js +7 -0
  62. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/OptionalSharedSliceId.d.ts +2 -0
  63. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/OptionalSharedSliceId.js +15 -0
  64. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/SharedSliceContent.d.ts +17 -0
  65. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/SharedSliceContent.js +30 -0
  66. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/SharedSliceContentEntry.d.ts +43 -0
  67. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/SharedSliceContentEntry.js +69 -0
  68. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/errors.d.ts +4 -0
  69. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/errors.js +6 -0
  70. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/index.d.ts +2 -0
  71. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/index.js +5 -0
  72. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/types.d.ts +1 -0
  73. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/types.js +2 -0
  74. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceId.d.ts +9 -0
  75. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceId.js +39 -0
  76. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceType.d.ts +11 -0
  77. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceType.js +24 -0
  78. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceVariation.d.ts +11 -0
  79. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceVariation.js +24 -0
  80. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/index.d.ts +5 -0
  81. package/lib/import/validators/fields/ImportSlices/SharedSlice/fields/index.js +8 -0
  82. package/lib/import/validators/fields/ImportSlices/SharedSlice/index.d.ts +3 -0
  83. package/lib/import/validators/fields/ImportSlices/SharedSlice/index.js +6 -0
  84. package/lib/import/validators/fields/ImportSlices/SharedSlice/utils.d.ts +339 -0
  85. package/lib/import/validators/fields/ImportSlices/SharedSlice/utils.js +11 -0
  86. package/lib/import/validators/fields/ImportSlices/index.d.ts +1 -0
  87. package/lib/import/validators/fields/ImportSlices/index.js +4 -0
  88. package/lib/import/validators/fields/ImportSlices/utils.d.ts +4 -0
  89. package/lib/import/validators/fields/ImportSlices/utils.js +35 -0
  90. package/lib/import/validators/fields/UID.d.ts +2 -2
  91. package/lib/import/validators/fields/UID.js +1 -1
  92. package/lib/import/validators/fields/nestable/Embed.d.ts +6 -23
  93. package/lib/import/validators/fields/nestable/Embed.js +7 -25
  94. package/lib/import/validators/fields/nestable/GeoPoint.js +1 -1
  95. package/lib/import/validators/fields/nestable/Image/Decoder.d.ts +26 -0
  96. package/lib/import/validators/fields/nestable/Image/Decoder.js +40 -0
  97. package/lib/import/validators/fields/nestable/Image/Validator.d.ts +33 -0
  98. package/lib/import/validators/fields/nestable/Image/Validator.js +27 -0
  99. package/lib/import/validators/fields/nestable/Image/index.d.ts +26 -0
  100. package/lib/import/validators/fields/nestable/Image/index.js +41 -0
  101. package/lib/import/validators/fields/nestable/Image/model.d.ts +18 -0
  102. package/lib/import/validators/fields/nestable/Image/model.js +2 -0
  103. package/lib/import/validators/fields/nestable/Link.js +2 -2
  104. package/lib/import/validators/fields/nestable/Nestable.d.ts +9 -60
  105. package/lib/import/validators/fields/nestable/index.d.ts +1 -0
  106. package/lib/import/validators/fields/nestable/index.js +1 -0
  107. package/lib/utils/DocumentId.d.ts +2 -1
  108. package/lib/utils/DocumentId.js +3 -3
  109. package/lib/utils/io-ts.d.ts +2 -0
  110. package/lib/utils/io-ts.js +22 -0
  111. package/lib/validators/BasicTypes.d.ts +0 -1
  112. package/lib/validators/BasicTypes.js +7 -8
  113. package/lib/validators/DefaultOrElse.js +1 -1
  114. package/lib/validators/NonEmptyString.js +1 -1
  115. package/lib/validators/NullOrT.d.ts +2 -0
  116. package/lib/validators/NullOrT.js +12 -0
  117. package/lib/validators/function.d.ts +4 -4
  118. package/lib/validators/function.js +6 -6
  119. package/package.json +4 -2
  120. package/src/_internal/utils.ts +39 -0
  121. package/src/common/Asset.ts +4 -5
  122. package/src/common/Embed.ts +22 -0
  123. package/src/common/UUID.ts +19 -0
  124. package/src/common/index.ts +1 -0
  125. package/src/content/Document.ts +96 -1
  126. package/src/content/fields/GroupContent.ts +47 -0
  127. package/src/content/fields/nestable/NestableContent.ts +32 -0
  128. package/src/content/fields/slices/Slice/CompositeSliceContent.ts +77 -0
  129. package/src/content/fields/slices/Slice/RepeatableContent.ts +0 -1
  130. package/src/content/fields/slices/Slice/SharedSliceContent.ts +82 -0
  131. package/src/content/fields/slices/SlicesContent.ts +96 -0
  132. package/src/customtypes/CustomType.ts +17 -0
  133. package/src/customtypes/widgets/slices/CompositeSlice.ts +7 -0
  134. package/src/customtypes/widgets/slices/LegacySlice.ts +7 -0
  135. package/src/customtypes/widgets/slices/SharedSlice.ts +12 -0
  136. package/src/import/converters/Document.ts +10 -8
  137. package/src/import/converters/fields/Slices/SharedSlice.ts +24 -0
  138. package/src/import/converters/fields/Slices/SharedSliceContent.ts +94 -0
  139. package/src/import/converters/fields/Slices/Slices.ts +20 -0
  140. package/src/import/converters/fields/Slices/index.ts +1 -0
  141. package/src/import/converters/fields/UID.ts +1 -5
  142. package/src/import/converters/fields/index.ts +1 -0
  143. package/src/import/converters/fields/nestable/Embed.ts +29 -7
  144. package/src/import/converters/fields/nestable/Image.ts +4 -4
  145. package/src/import/converters/fields/nestable/Link.ts +5 -5
  146. package/src/import/converters/fields/nestable/Nestable.ts +7 -5
  147. package/src/import/validators/Document.ts +3 -3
  148. package/src/import/validators/fields/ImportField.ts +12 -6
  149. package/src/import/validators/fields/ImportSlices/ImportSlices.ts +54 -0
  150. package/src/import/validators/fields/ImportSlices/SharedSlice/SharedSlice.ts +116 -0
  151. package/src/import/validators/fields/ImportSlices/SharedSlice/errors.ts +6 -0
  152. package/src/import/validators/fields/ImportSlices/SharedSlice/fields/OptionalSharedSliceId.ts +20 -0
  153. package/src/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/SharedSliceContent.ts +64 -0
  154. package/src/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/SharedSliceContentEntry.ts +100 -0
  155. package/src/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/errors.ts +10 -0
  156. package/src/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/index.ts +2 -0
  157. package/src/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceContent/types.ts +1 -0
  158. package/src/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceId.ts +65 -0
  159. package/src/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceType.ts +45 -0
  160. package/src/import/validators/fields/ImportSlices/SharedSlice/fields/SharedSliceVariation.ts +45 -0
  161. package/src/import/validators/fields/ImportSlices/SharedSlice/fields/index.ts +5 -0
  162. package/src/import/validators/fields/ImportSlices/SharedSlice/index.ts +3 -0
  163. package/src/import/validators/fields/ImportSlices/SharedSlice/utils.ts +21 -0
  164. package/src/import/validators/fields/ImportSlices/index.ts +1 -0
  165. package/src/import/validators/fields/ImportSlices/utils.ts +43 -0
  166. package/src/import/validators/fields/UID.ts +2 -2
  167. package/src/import/validators/fields/nestable/Embed.ts +9 -41
  168. package/src/import/validators/fields/nestable/GeoPoint.ts +2 -2
  169. package/src/import/validators/fields/nestable/Image/Decoder.ts +61 -0
  170. package/src/import/validators/fields/nestable/Image/Validator.ts +38 -0
  171. package/src/import/validators/fields/nestable/Image/index.ts +75 -0
  172. package/src/import/validators/fields/nestable/Image/model.ts +18 -0
  173. package/src/import/validators/fields/nestable/Link.ts +2 -2
  174. package/src/import/validators/fields/nestable/index.ts +1 -0
  175. package/src/utils/DocumentId.ts +4 -5
  176. package/src/utils/io-ts.ts +29 -0
  177. package/src/validators/BasicTypes.ts +13 -11
  178. package/src/validators/DefaultOrElse.ts +1 -1
  179. package/src/validators/NonEmptyString.ts +4 -5
  180. package/src/validators/function.ts +4 -4
  181. package/lib/import/validators/fields/nestable/Image.d.ts +0 -62
  182. package/lib/import/validators/fields/nestable/Image.js +0 -76
  183. package/src/import/validators/fields/nestable/Image.ts +0 -147
@@ -0,0 +1,45 @@
1
+ import * as E from "fp-ts/Either"
2
+ import { pipe } from "fp-ts/function"
3
+ import * as t from "io-ts"
4
+
5
+ import { SharedSlice as SharedSliceCustomType } from "../../../../../../customtypes"
6
+ import { NonEmptyString } from "../../../../../../validators"
7
+ import { findSlice } from "../utils"
8
+
9
+ export type SharedSliceType = {
10
+ slice_type: string
11
+ data: SharedSliceCustomType
12
+ }
13
+
14
+ /**
15
+ * slice_type - the validated slice_type
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
+ */
18
+ const SharedSliceTypeShape = t.type({
19
+ slice_type: NonEmptyString,
20
+ slice: SharedSliceCustomType,
21
+ })
22
+
23
+ /**
24
+ * Builds the decoder for the 'slice_type' field in the SharedSlice. Alongside the decoded 'slice_type' it also returns the SharedSlice data matching the slice_type.
25
+ * @param slices all the SharedSlices from the custom type
26
+ */
27
+ export const SharedSliceType = (slices: SharedSliceCustomType[]) =>
28
+ new t.Type<SharedSliceType, string, unknown>(
29
+ "slice_type",
30
+ (u): u is SharedSliceType => SharedSliceTypeShape.is(u),
31
+ (u, c) =>
32
+ pipe(
33
+ NonEmptyString.validate(u, c),
34
+ E.chain((slice_type) =>
35
+ pipe(
36
+ findSlice(slices)(slice_type),
37
+ E.fold(
38
+ (err) => t.failure(u, c, err),
39
+ (data) => t.success({ slice_type, data }),
40
+ ),
41
+ ),
42
+ ),
43
+ ),
44
+ ({ slice_type }) => slice_type,
45
+ )
@@ -0,0 +1,45 @@
1
+ import * as E from "fp-ts/Either"
2
+ import { pipe } from "fp-ts/function"
3
+ import * as t from "io-ts"
4
+
5
+ import { SharedSlice, Variation } from "../../../../../../customtypes"
6
+ import { NonEmptyString } from "../../../../../../validators"
7
+ import { findSliceVariation } from "../utils"
8
+
9
+ export type SharedSliceVariation = {
10
+ variation: string
11
+ data: Variation
12
+ }
13
+
14
+ /**
15
+ * variation - the validated variation of the slice
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
+ */
18
+ const SharedSliceVariationShape = t.type({
19
+ variation: NonEmptyString,
20
+ data: Variation,
21
+ })
22
+
23
+ /**
24
+ * Builds the decoder for the 'variation' field in the SharedSlice. Alongside the decoded 'variation' it also returns the Variation data matching the variation custom type.
25
+ * @param slice SharedSlice from the custom type
26
+ */
27
+ export const SharedSliceVariation = (slice: SharedSlice) =>
28
+ new t.Type<SharedSliceVariation, string, unknown>(
29
+ "variation",
30
+ (u): u is SharedSliceVariation => SharedSliceVariationShape.is(u),
31
+ (u, c) =>
32
+ pipe(
33
+ NonEmptyString.validate(u, c),
34
+ E.chain((variation) =>
35
+ pipe(
36
+ findSliceVariation(slice)(variation),
37
+ E.fold(
38
+ (err) => t.failure(u, c, err),
39
+ (data) => t.success({ variation, data }),
40
+ ),
41
+ ),
42
+ ),
43
+ ),
44
+ ({ variation }) => variation,
45
+ )
@@ -0,0 +1,5 @@
1
+ export * from "./OptionalSharedSliceId"
2
+ export * from "./SharedSliceContent"
3
+ export * from "./SharedSliceId"
4
+ export * from "./SharedSliceType"
5
+ export * from "./SharedSliceVariation"
@@ -0,0 +1,3 @@
1
+ export * from "./errors"
2
+ export * from "./fields"
3
+ export * from "./SharedSlice"
@@ -0,0 +1,21 @@
1
+ import * as E from "fp-ts/Either"
2
+ import { pipe } from "fp-ts/function"
3
+
4
+ import type { SharedSlice as SharedSliceCustomType } from "../../../../../customtypes"
5
+ import type { Variation } from "../../../../../customtypes"
6
+ import { SharedSliceErrors } from "./errors"
7
+
8
+ export const findSlice =
9
+ (slices: SharedSliceCustomType[]) => (sliceId: string) =>
10
+ pipe(
11
+ slices.find((slice) => slice.id === sliceId),
12
+ E.fromNullable(SharedSliceErrors.SliceTypeNotFound(sliceId)),
13
+ )
14
+
15
+ export const findSliceVariation =
16
+ (slice: SharedSliceCustomType) =>
17
+ (variation: string): E.Either<string, Variation> =>
18
+ pipe(
19
+ slice.variations.find((v) => v.id === variation),
20
+ E.fromNullable(SharedSliceErrors.VariationNotFound(variation, slice.id)),
21
+ )
@@ -0,0 +1 @@
1
+ export * from "./ImportSlices"
@@ -0,0 +1,43 @@
1
+ import * as A from "fp-ts/Array"
2
+ import { pipe } from "fp-ts/function"
3
+ import * as O from "fp-ts/Option"
4
+
5
+ import {
6
+ SharedSlice as SharedSliceCustomType,
7
+ StaticSlices,
8
+ } from "../../../../customtypes"
9
+ import type { SharedSlice, SharedSliceId } from "./SharedSlice"
10
+
11
+ // Extracts all supported slices from the static slices object
12
+ // For now we only support the SharedSlice, if we want to support other slices in the future, we have to add them here
13
+ export const extractSupportedSlices = (
14
+ staticSlices: StaticSlices,
15
+ ): SharedSliceCustomType[] =>
16
+ pipe(
17
+ Object.values(staticSlices.config?.choices ?? {}).map((slice) =>
18
+ pipe(SharedSliceCustomType.decode(slice), O.fromEither),
19
+ ),
20
+ A.compact,
21
+ )
22
+
23
+ export const findImportSharedSliceDuplicateIds = (
24
+ slices: SharedSlice[],
25
+ ): SharedSliceId[] => {
26
+ const duplicatesMap = slices.reduce((acc, { id }) => {
27
+ if (id) {
28
+ const currentNumOfDuplicates = acc[id] ?? 0
29
+ return {
30
+ ...acc,
31
+ [id]: acc[id] === undefined ? 0 : currentNumOfDuplicates + 1,
32
+ }
33
+ }
34
+ return acc
35
+ }, {} as Record<SharedSliceId, number>)
36
+
37
+ return Object.entries(duplicatesMap).flatMap(([id, numOfDuplicates]) => {
38
+ if (numOfDuplicates > 0) {
39
+ return [id]
40
+ }
41
+ return []
42
+ })
43
+ }
@@ -1,6 +1,6 @@
1
1
  import * as t from "io-ts"
2
2
 
3
- import { NullOrElse, String } from "../../../validators"
3
+ import { String } from "../../../validators"
4
4
  import { ImportContent } from "./ImportContent"
5
5
 
6
6
  const regex = /^[a-z0-9-_.]+$/
@@ -23,5 +23,5 @@ const uidValue = String.pipe(
23
23
  ),
24
24
  )
25
25
 
26
- export const ImportUID = ImportContent("UID", NullOrElse(uidValue))
26
+ export const ImportUID = ImportContent("UID", uidValue)
27
27
  export type ImportUID = t.TypeOf<typeof ImportUID>
@@ -1,14 +1,8 @@
1
- import * as Either from "fp-ts/lib/Either"
1
+ import * as Either from "fp-ts/Either"
2
2
  import { pipe } from "fp-ts/lib/function"
3
3
  import * as t from "io-ts"
4
- import { withMessage } from "io-ts-types"
5
4
 
6
5
  import { EmptyObjectOrElse } from "../../../../validators"
7
- import {
8
- NumberOrNull,
9
- String,
10
- StringOrNull,
11
- } from "../../../../validators/BasicTypes"
12
6
  import { ImportContent } from "../ImportContent"
13
7
 
14
8
  type URL = string
@@ -38,49 +32,23 @@ const EmbedUrl = new t.Type<URL, URL, unknown>(
38
32
  t.identity,
39
33
  )
40
34
 
41
- const EmbedProto = t.exact(
42
- t.intersection([
43
- t.type({
44
- embed_url: EmbedUrl,
45
- type: String,
46
- }),
47
- t.partial({
48
- version: withMessage(
49
- t.union([t.string, t.number, t.null]),
50
- () => "The value must be either string, number or null",
51
- ),
52
- title: String,
53
- author_name: StringOrNull,
54
- author_url: StringOrNull,
55
- provider_name: StringOrNull,
56
- provider_url: StringOrNull,
57
- cache_age: withMessage(
58
- t.union([t.string, t.number, t.null]),
59
- () => "The value must be either string, number or null",
60
- ),
61
- thumbnail_url: StringOrNull,
62
- thumbnail_width: NumberOrNull,
63
- thumbnail_height: NumberOrNull,
64
- html: StringOrNull,
65
- }),
66
- ]),
67
- )
35
+ const EmbedProto = t.type({
36
+ embed_url: EmbedUrl,
37
+ })
68
38
  type EmbedProto = t.TypeOf<typeof EmbedProto>
69
39
 
70
- type Embed = EmbedProto & {
71
- all: unknown
72
- }
73
- const embedValue = new t.Type<Embed>(
40
+ type Embed = EmbedProto
41
+ const Embed = new t.Type<Embed>(
74
42
  "ImportEmbedValue",
75
- (u: unknown): u is Embed => EmbedProto.is(u) && "all" in u,
43
+ (u: unknown): u is Embed => EmbedProto.is(u),
76
44
  (u: unknown) => {
77
45
  return pipe(
78
46
  EmbedProto.decode(u),
79
- Either.map((parsed) => ({ ...parsed, all: u })),
47
+ Either.map((parsed) => ({ embed_url: parsed.embed_url })),
80
48
  )
81
49
  },
82
50
  t.identity,
83
51
  )
84
52
 
85
- export const ImportEmbed = ImportContent("Embed", EmptyObjectOrElse(embedValue))
53
+ export const ImportEmbed = ImportContent("Embed", EmptyObjectOrElse(Embed))
86
54
  export type ImportEmbed = t.TypeOf<typeof ImportEmbed>
@@ -2,10 +2,10 @@ import type { TypeOf } from "io-ts"
2
2
  import * as t from "io-ts"
3
3
 
4
4
  import { EmptyObjectOrElse, NumberRange } from "../../../../validators"
5
- import { withFallbackMessage } from "../../../../validators/function"
5
+ import { withCustomError } from "../../../../validators/function"
6
6
  import { ImportContent } from "../ImportContent"
7
7
 
8
- const GeooPoint = withFallbackMessage(
8
+ const GeooPoint = withCustomError(
9
9
  t.strict({
10
10
  latitude: NumberRange(-90, 90, "latitude"),
11
11
  longitude: NumberRange(-180, 180, "longitude"),
@@ -0,0 +1,61 @@
1
+ import type { TypeOf } from "io-ts"
2
+
3
+ import type { Image } from "../../../../../customtypes"
4
+ import type ImageConstraint from "../../../../../customtypes/widgets/shared/ImageConstraint"
5
+ import type { ImageField } from "./model"
6
+ import type { ImageFieldValidator, ThumbnailsValidator } from "./Validator"
7
+
8
+ // This function merges user input with custom type constraints.
9
+ // If `image` is missing, `mainImage` is used for the encoding
10
+ // (case when user input lacks thumbnail definition)
11
+ export const decodeImageField = (
12
+ image: TypeOf<typeof ImageFieldValidator> | undefined,
13
+ mainImage: TypeOf<typeof ImageFieldValidator>,
14
+ constraints?: ImageConstraint,
15
+ ): ImageField => {
16
+ const background = image?.edit?.background
17
+ const width =
18
+ constraints?.width ??
19
+ image?.dimensions?.width ??
20
+ mainImage.dimensions?.width
21
+ const height =
22
+ constraints?.height ??
23
+ image?.dimensions?.height ??
24
+ mainImage.dimensions?.height
25
+ const alt = image?.alt
26
+ const copyright = image?.copyright
27
+
28
+ return {
29
+ id: image?.id ?? mainImage?.id,
30
+ edit: {
31
+ x: image?.edit?.x ?? 0,
32
+ y: image?.edit?.y ?? 0,
33
+ zoom: image?.edit?.zoom ?? 1,
34
+ ...(background !== undefined ? { background } : {}),
35
+ },
36
+ dimensions: {
37
+ ...(width !== undefined ? { width } : {}),
38
+ ...(height !== undefined ? { height } : {}),
39
+ },
40
+ ...(alt !== undefined ? { alt } : {}),
41
+ ...(copyright !== undefined ? { copyright } : {}),
42
+ }
43
+ }
44
+ // Merges provided thumbnails with custom type constraints.
45
+ // If any thumbnail is missing, it is created using the origin image (`mainImage`)
46
+ export const decodeThumbnails = (
47
+ mainImage: TypeOf<typeof ImageFieldValidator>,
48
+ thumbnails: TypeOf<typeof ThumbnailsValidator>,
49
+ field?: Image,
50
+ ) =>
51
+ field?.config?.thumbnails?.reduce(
52
+ (acc, thumbnail) => ({
53
+ ...acc,
54
+ [thumbnail.name]: decodeImageField(
55
+ thumbnails[thumbnail.name],
56
+ mainImage,
57
+ thumbnail,
58
+ ),
59
+ }),
60
+ {},
61
+ ) ?? {}
@@ -0,0 +1,38 @@
1
+ import * as t from "io-ts"
2
+
3
+ import {
4
+ Number,
5
+ String,
6
+ StringOrNull,
7
+ } from "../../../../../validators/BasicTypes"
8
+ import { withCustomError } from "../../../../../validators/function"
9
+
10
+ export const ImageFieldValidator = withCustomError(
11
+ t.intersection([
12
+ t.type({
13
+ id: String,
14
+ }),
15
+ t.partial({
16
+ dimensions: withCustomError(
17
+ t.partial({
18
+ width: Number,
19
+ height: Number,
20
+ }),
21
+ () => "The value must be an object",
22
+ ),
23
+ edit: withCustomError(
24
+ t.partial({
25
+ x: Number,
26
+ y: Number,
27
+ zoom: Number,
28
+ background: String,
29
+ }),
30
+ () => "The value must be an object",
31
+ ),
32
+ copyright: StringOrNull,
33
+ alt: StringOrNull,
34
+ }),
35
+ ]),
36
+ () => "The value must be an object",
37
+ )
38
+ export const ThumbnailsValidator = t.record(t.string, ImageFieldValidator)
@@ -0,0 +1,75 @@
1
+ import { chain, map } from "fp-ts/Either"
2
+ import { pipe } from "fp-ts/function"
3
+ import type { Validation } from "io-ts"
4
+ import * as t from "io-ts"
5
+
6
+ import type { Image as ImageDefinition } from "../../../../../customtypes"
7
+ import { DefaultOrElse, EmptyObject } from "../../../../../validators"
8
+ import { withCustomError } from "../../../../../validators/function"
9
+ import { ImportContent } from "../../ImportContent"
10
+ import { decodeImageField, decodeThumbnails } from "./Decoder"
11
+ import type { ImageFieldWithThumbnails } from "./model"
12
+ import { ImageFieldValidator, ThumbnailsValidator } from "./Validator"
13
+
14
+ const defaultImage = (field?: ImageDefinition) => {
15
+ // If there is not thumbnails we expect an empty object
16
+ if (!field?.config?.thumbnails || !field.config.thumbnails.length)
17
+ return EmptyObject
18
+
19
+ // If there are thumbnails, we expect an object with thumbnails as empty objects
20
+ return withCustomError(
21
+ t.strict(
22
+ field.config.thumbnails.reduce(
23
+ (acc, thumbnail) => ({
24
+ ...acc,
25
+ [thumbnail.name]: EmptyObject,
26
+ }),
27
+ {},
28
+ ),
29
+ ),
30
+ () => "The value must be an object",
31
+ )
32
+ }
33
+
34
+ const ImageField = (field?: ImageDefinition) =>
35
+ new t.Type<ImageFieldWithThumbnails>(
36
+ "ImageField",
37
+ (u: unknown): u is ImageFieldWithThumbnails =>
38
+ ImageFieldValidator.is(u) &&
39
+ "thumbnails" in u &&
40
+ ThumbnailsValidator.is(u["thumbnails"]),
41
+ (u: unknown, ctx): Validation<ImageFieldWithThumbnails> => {
42
+ return pipe(
43
+ ImageFieldValidator.validate(u, ctx),
44
+ chain((mainImage) => {
45
+ const { id, dimensions, edit, copyright, alt, ...maybeThumbnails } =
46
+ mainImage
47
+ return pipe(
48
+ ThumbnailsValidator.validate(maybeThumbnails, ctx),
49
+ map((thumbnails) => ({
50
+ ...decodeImageField(
51
+ mainImage,
52
+ mainImage,
53
+ field?.config?.constraint,
54
+ ),
55
+ thumbnails: decodeThumbnails(mainImage, thumbnails, field),
56
+ })),
57
+ )
58
+ }),
59
+ )
60
+ },
61
+ t.identity,
62
+ )
63
+
64
+ const ImageCodec = (field?: ImageDefinition) =>
65
+ withCustomError(
66
+ DefaultOrElse<Record<never, never>, ImageFieldWithThumbnails>(
67
+ defaultImage(field),
68
+ )(ImageField(field)),
69
+ () => "An image field must be an object",
70
+ )
71
+
72
+ export const ImportImage = (field?: ImageDefinition) =>
73
+ ImportContent("Image", ImageCodec(field))
74
+ export type ImportImage = t.TypeOf<ReturnType<typeof ImportImage>>
75
+ export * from "./model"
@@ -0,0 +1,18 @@
1
+ export type ImageField = {
2
+ id: string
3
+ edit: {
4
+ x: number
5
+ y: number
6
+ zoom: number
7
+ background?: string
8
+ }
9
+ dimensions: {
10
+ width?: number
11
+ height?: number
12
+ }
13
+ copyright?: string | null
14
+ alt?: string | null
15
+ }
16
+ export type ImageFieldWithThumbnails = ImageField & {
17
+ thumbnails: Record<string, ImageField>
18
+ }
@@ -1,13 +1,13 @@
1
1
  import type { OutputOf, TypeOf } from "io-ts"
2
2
  import * as t from "io-ts"
3
- import { withMessage } from "io-ts-types"
4
3
 
5
4
  import { DocumentId } from "../../../../utils/DocumentId"
6
5
  import { DefaultOrElse, String } from "../../../../validators"
6
+ import { withCustomError } from "../../../../validators/function"
7
7
  import { ImportContent } from "../ImportContent"
8
8
 
9
9
  const LinkTypeValidator = t.type({
10
- link_type: withMessage(
10
+ link_type: withCustomError(
11
11
  t.union([t.literal("Web"), t.literal("Document"), t.literal("Media")]),
12
12
  () => "The value must be `Web`, `Document` or `Media`",
13
13
  ),
@@ -4,6 +4,7 @@ export * from "./Date"
4
4
  export * from "./Embed"
5
5
  export * from "./GeoPoint"
6
6
  export * from "./Image"
7
+ export * from "./Image/index"
7
8
  export * from "./Link"
8
9
  export * from "./Nestable"
9
10
  export * from "./Number"
@@ -1,9 +1,8 @@
1
- import { withMessage } from "io-ts-types"
1
+ import * as t from "io-ts"
2
2
 
3
- import { String } from "../validators"
4
- import { refineType } from "../validators/function"
3
+ import { refineType, withCustomError } from "../validators/function"
5
4
 
6
- export const DocumentId = withMessage(
7
- refineType(String, "DocumentId", (s) => s.length === 16),
5
+ export const DocumentId = withCustomError(
6
+ refineType(t.string, "DocumentId", (s) => s.length === 16),
8
7
  () => "DocumentId must be a 16 character string",
9
8
  )
@@ -0,0 +1,29 @@
1
+ import * as E from "fp-ts/Either"
2
+ import { pipe } from "fp-ts/function"
3
+ import * as RA from "fp-ts/ReadonlyArray"
4
+ import type { Semigroup } from "fp-ts/Semigroup"
5
+ import type { Errors, Validation } from "io-ts"
6
+
7
+ /*
8
+ * Semigroup simply defines how to concatenate two values of the same type.
9
+ * In this instance, Errors from io-ts are arrays already, so we just need to concatenate them.
10
+ */
11
+ const validationErrorsSemigroup: Semigroup<Errors> = {
12
+ concat: (a: Errors, b: Errors) => [...a, ...b],
13
+ }
14
+
15
+ /*
16
+ * This is a helper function to combine multiple io-ts validations into one.
17
+ * t.array(...) works in the same way - it collects all the errors when decoding an array of values.
18
+ * However, it requires you to pass in a single io-ts validator as a parameter, which is not always convenient.
19
+ * Sometimes we have arrays of validation results received from function calls that don't have a validator instance.
20
+ */
21
+ export const combineValidationResults = <T>(
22
+ validationResults: readonly Validation<T>[],
23
+ ): Validation<readonly T[]> =>
24
+ pipe(
25
+ validationResults,
26
+ RA.traverse(E.getApplicativeValidation(validationErrorsSemigroup))(
27
+ (validation) => validation,
28
+ ),
29
+ )
@@ -1,19 +1,26 @@
1
1
  import { either } from "fp-ts"
2
2
  import { pipe } from "fp-ts/lib/function"
3
3
  import * as t from "io-ts"
4
- import { withMessage } from "io-ts-types"
5
4
 
6
- export const String = withMessage(t.string, () => "The value must be a string")
7
- export const StringOrNull = withMessage(
5
+ import { withCustomError } from "./function"
6
+
7
+ export const String = withCustomError(
8
+ t.string,
9
+ () => "The value must be a string",
10
+ )
11
+ export const StringOrNull = withCustomError(
8
12
  t.union([t.string, t.null]),
9
13
  () => "The value must be a string or null",
10
14
  )
11
- export const Number = withMessage(t.number, () => "The value must be a number")
12
- export const NumberOrNull = withMessage(
15
+ export const Number = withCustomError(
16
+ t.number,
17
+ () => "The value must be a number",
18
+ )
19
+ export const NumberOrNull = withCustomError(
13
20
  t.union([t.number, t.null]),
14
21
  () => "The value must be a number or null",
15
22
  )
16
- export const Boolean = withMessage(
23
+ export const Boolean = withCustomError(
17
24
  t.boolean,
18
25
  () => "The value must be a boolean",
19
26
  )
@@ -46,8 +53,3 @@ export const EmptyArray = new t.Type<never[], never[], unknown>(
46
53
  },
47
54
  () => [],
48
55
  )
49
-
50
- export const AnyObject = withMessage(
51
- t.record(t.string, t.unknown),
52
- () => "The value must be an object",
53
- )
@@ -6,7 +6,7 @@ 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
- "NullOrT",
9
+ "DefaultOrElse",
10
10
  (u: unknown): u is A | null => null === u || codec.is(u),
11
11
  (u: unknown) => {
12
12
  if (isRight(inputValidator.decode(u))) return t.success(null)
@@ -1,9 +1,8 @@
1
1
  import * as t from "io-ts"
2
2
 
3
- import { refineType } from "./function"
3
+ import { refineType, withCustomError } from "./function"
4
4
 
5
- export default refineType(
6
- t.string,
7
- "nonEmptyString",
8
- (s) => s.trim().length > 0,
5
+ export default withCustomError(
6
+ refineType(t.string, "nonEmptyString", (s) => s.trim().length > 0),
7
+ () => "The value must be a non-empty string",
9
8
  )
@@ -78,19 +78,19 @@ export function addType<A, O extends object, I, T extends string>(
78
78
  *
79
79
  * @example
80
80
  * expect(
81
- * withFallbackMessage(
82
- * t.type({age: withMessage(t.number, () => 'Invalid child')}),
81
+ * withCustomError(
82
+ * t.type({age: withCustomError(t.number, () => 'Invalid child')}),
83
83
  * () => "Invalid parent"
84
84
  * )
85
85
  * ).toSubsetEqualLeft([{message: "Invalid child"}])
86
86
  * expect(
87
- * withFallbackMessage(
87
+ * withCustomError(
88
88
  * t.type({age: t.number}),
89
89
  * () => "Invalid parent"
90
90
  * )
91
91
  * ).toSubsetEqualLeft([{message: "Invalid parent"}])
92
92
  */
93
- export function withFallbackMessage<C extends t.Any>(
93
+ export function withCustomError<C extends t.Any>(
94
94
  codec: C,
95
95
  message: (i: t.InputOf<C>, c: t.Context) => string,
96
96
  ): C {