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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/lib/content/fields/GroupContent.js +11 -4
  2. package/lib/customtypes/widgets/nestable/NestableWidget.d.ts +0 -157
  3. package/lib/customtypes/widgets/nestable/NestableWidget.js +1 -17
  4. package/lib/import/converters/Document.d.ts +3 -2
  5. package/lib/import/converters/Document.js +9 -7
  6. package/lib/import/converters/fields/UID.d.ts +3 -0
  7. package/lib/import/converters/fields/UID.js +12 -0
  8. package/lib/import/converters/fields/index.d.ts +1 -0
  9. package/lib/import/converters/fields/index.js +1 -0
  10. package/lib/import/converters/fields/nestable/Boolean.d.ts +3 -0
  11. package/lib/import/converters/fields/nestable/Boolean.js +12 -0
  12. package/lib/import/converters/fields/nestable/Color.js +9 -6
  13. package/lib/import/converters/fields/nestable/Date.d.ts +1 -1
  14. package/lib/import/converters/fields/nestable/Date.js +5 -5
  15. package/lib/import/converters/fields/nestable/Embed.d.ts +3 -0
  16. package/lib/import/converters/fields/nestable/Embed.js +13 -0
  17. package/lib/import/converters/fields/nestable/Image.d.ts +18 -0
  18. package/lib/import/converters/fields/nestable/Image.js +45 -0
  19. package/lib/import/converters/fields/nestable/Link.d.ts +3 -0
  20. package/lib/import/converters/fields/nestable/Link.js +19 -0
  21. package/lib/import/converters/fields/nestable/Nestable.d.ts +2 -1
  22. package/lib/import/converters/fields/nestable/Nestable.js +7 -1
  23. package/lib/import/converters/fields/nestable/Number.js +9 -6
  24. package/lib/import/converters/fields/nestable/Select.js +9 -6
  25. package/lib/import/converters/fields/nestable/Text.js +9 -6
  26. package/lib/import/converters/fields/nestable/Timestamp.d.ts +1 -1
  27. package/lib/import/converters/fields/nestable/Timestamp.js +9 -6
  28. package/lib/import/converters/fields/nestable/index.d.ts +3 -0
  29. package/lib/import/converters/fields/nestable/index.js +3 -0
  30. package/lib/import/validators/Document.d.ts +4 -4
  31. package/lib/import/validators/Document.js +48 -37
  32. package/lib/import/validators/fields/ImportContent.d.ts +5 -0
  33. package/lib/import/validators/fields/ImportContent.js +21 -0
  34. package/lib/import/validators/fields/ImportField.d.ts +131 -0
  35. package/lib/import/validators/fields/ImportField.js +24 -0
  36. package/lib/import/validators/fields/UID.d.ts +6 -0
  37. package/lib/import/validators/fields/UID.js +15 -0
  38. package/lib/import/validators/fields/index.d.ts +1 -5
  39. package/lib/import/validators/fields/index.js +1 -0
  40. package/lib/import/validators/fields/nestable/Boolean.d.ts +6 -0
  41. package/lib/import/validators/fields/nestable/Boolean.js +6 -0
  42. package/lib/import/validators/fields/nestable/Color.d.ts +5 -4
  43. package/lib/import/validators/fields/nestable/Color.js +4 -4
  44. package/lib/import/validators/fields/nestable/Date.d.ts +5 -3
  45. package/lib/import/validators/fields/nestable/Date.js +4 -2
  46. package/lib/import/validators/fields/nestable/Embed.d.ts +27 -0
  47. package/lib/import/validators/fields/nestable/Embed.js +54 -0
  48. package/lib/import/validators/fields/nestable/Image.d.ts +24 -0
  49. package/lib/import/validators/fields/nestable/Image.js +45 -0
  50. package/lib/import/validators/fields/nestable/Link.d.ts +20 -0
  51. package/lib/import/validators/fields/nestable/Link.js +30 -0
  52. package/lib/import/validators/fields/nestable/Nestable.d.ts +124 -4
  53. package/lib/import/validators/fields/nestable/Nestable.js +50 -27
  54. package/lib/import/validators/fields/nestable/Number.d.ts +16 -9
  55. package/lib/import/validators/fields/nestable/Number.js +5 -4
  56. package/lib/import/validators/fields/nestable/Select.d.ts +15 -8
  57. package/lib/import/validators/fields/nestable/Select.js +4 -2
  58. package/lib/import/validators/fields/nestable/Text.d.ts +6 -3
  59. package/lib/import/validators/fields/nestable/Text.js +2 -1
  60. package/lib/import/validators/fields/nestable/Timestamp.d.ts +5 -3
  61. package/lib/import/validators/fields/nestable/Timestamp.js +4 -2
  62. package/lib/import/validators/fields/nestable/index.d.ts +3 -0
  63. package/lib/import/validators/fields/nestable/index.js +3 -0
  64. package/lib/utils/Objects.d.ts +1 -0
  65. package/lib/utils/Objects.js +5 -1
  66. package/lib/validators/BasicTypes.d.ts +8 -0
  67. package/lib/validators/BasicTypes.js +19 -1
  68. package/lib/validators/DefaultOrElse.d.ts +5 -0
  69. package/lib/validators/DefaultOrElse.js +21 -0
  70. package/lib/validators/index.d.ts +1 -1
  71. package/lib/validators/index.js +1 -1
  72. package/package.json +3 -2
  73. package/src/content/fields/GroupContent.ts +9 -5
  74. package/src/customtypes/widgets/nestable/NestableWidget.ts +0 -17
  75. package/src/import/converters/Document.ts +18 -11
  76. package/src/import/converters/fields/UID.ts +13 -0
  77. package/src/import/converters/fields/index.ts +1 -0
  78. package/src/import/converters/fields/nestable/Boolean.ts +13 -0
  79. package/src/import/converters/fields/nestable/Color.ts +7 -5
  80. package/src/import/converters/fields/nestable/Date.ts +12 -13
  81. package/src/import/converters/fields/nestable/Embed.ts +15 -0
  82. package/src/import/converters/fields/nestable/Image.ts +68 -0
  83. package/src/import/converters/fields/nestable/Nestable.ts +11 -0
  84. package/src/import/converters/fields/nestable/Number.ts +7 -5
  85. package/src/import/converters/fields/nestable/Select.ts +7 -5
  86. package/src/import/converters/fields/nestable/Text.ts +7 -5
  87. package/src/import/converters/fields/nestable/Timestamp.ts +8 -6
  88. package/src/import/converters/fields/nestable/index.ts +3 -0
  89. package/src/import/validators/Document.ts +95 -63
  90. package/src/import/validators/fields/ImportContent.ts +30 -0
  91. package/src/import/validators/fields/ImportField.ts +25 -0
  92. package/src/import/validators/fields/UID.ts +27 -0
  93. package/src/import/validators/fields/index.ts +1 -7
  94. package/src/import/validators/fields/nestable/Boolean.ts +7 -0
  95. package/src/import/validators/fields/nestable/Color.ts +23 -23
  96. package/src/import/validators/fields/nestable/Date.ts +26 -27
  97. package/src/import/validators/fields/nestable/Embed.ts +86 -0
  98. package/src/import/validators/fields/nestable/Image.ts +90 -0
  99. package/src/import/validators/fields/nestable/Nestable.ts +55 -26
  100. package/src/import/validators/fields/nestable/Number.ts +32 -30
  101. package/src/import/validators/fields/nestable/Select.ts +32 -30
  102. package/src/import/validators/fields/nestable/Text.ts +6 -6
  103. package/src/import/validators/fields/nestable/Timestamp.ts +29 -26
  104. package/src/import/validators/fields/nestable/index.ts +3 -0
  105. package/src/utils/Objects.ts +10 -0
  106. package/src/validators/BasicTypes.ts +48 -0
  107. package/src/validators/DefaultOrElse.ts +24 -0
  108. package/src/validators/index.ts +1 -1
  109. package/lib/import/converters/fields/utils.d.ts +0 -1
  110. package/lib/import/converters/fields/utils.js +0 -10
  111. package/lib/validators/NullOrT.d.ts +0 -2
  112. package/lib/validators/NullOrT.js +0 -13
  113. package/src/import/converters/fields/utils.ts +0 -7
  114. package/src/validators/NullOrT.ts +0 -18
@@ -0,0 +1,13 @@
1
+ import type { UIDContent } from "../../../content"
2
+ import type { ImportUID } from "../../validators/fields/UID"
3
+
4
+ export const uidConverter = (
5
+ field: ImportUID["value"],
6
+ ): UIDContent | undefined => {
7
+ if (field === null) return
8
+
9
+ return {
10
+ value: field,
11
+ __TYPE__: "UIDContent",
12
+ }
13
+ }
@@ -1 +1,2 @@
1
1
  export * from "./nestable"
2
+ export * from "./UID"
@@ -0,0 +1,13 @@
1
+ import type { BooleanContent } from "../../../../content"
2
+ import type { ImportBoolean } from "../../../validators"
3
+
4
+ export const booleanConverter = (
5
+ field: ImportBoolean["value"],
6
+ ): BooleanContent | undefined => {
7
+ if (field === null) return
8
+
9
+ return {
10
+ value: field,
11
+ __TYPE__: "BooleanContent",
12
+ }
13
+ }
@@ -1,12 +1,14 @@
1
1
  import type { ColorContent } from "../../../../content"
2
2
  import type { ImportColor } from "../../../validators"
3
- import { nullableConverter } from "../utils"
4
3
 
5
4
  export const colorConverter = (
6
5
  field: ImportColor["value"],
7
- ): ColorContent | undefined =>
8
- nullableConverter(field, (value: NonNullable<ImportColor["value"]>) => ({
6
+ ): ColorContent | undefined => {
7
+ if (field === null) return
8
+
9
+ return {
9
10
  type: "Color",
10
- value: value,
11
+ value: field,
11
12
  __TYPE__: "FieldContent",
12
- }))
13
+ }
14
+ }
@@ -1,18 +1,17 @@
1
1
  import type { DateContent } from "../../../../content"
2
- import type { ImportDate } from "../../.."
3
- import { nullableConverter } from "../utils"
2
+ import type { ImportDate } from "../../../validators"
4
3
 
5
4
  export const dateConverter = (
6
5
  field: ImportDate["value"],
7
- ): DateContent | undefined =>
8
- nullableConverter(field, (value: NonNullable<ImportDate["value"]>) => {
9
- // Iso date looks like this '2023-07-10T13:33:12+0000'
10
- const isoDate = value.toISOString()
11
- const [withoutTime] = isoDate.split("T")
6
+ ): DateContent | undefined => {
7
+ if (field === null) return
12
8
 
13
- return {
14
- type: "Date",
15
- value: withoutTime || isoDate,
16
- __TYPE__: "FieldContent",
17
- }
18
- })
9
+ const isoDate = field.toISOString()
10
+ const [withoutTime] = isoDate.split("T")
11
+
12
+ return {
13
+ type: "Date",
14
+ value: withoutTime || isoDate,
15
+ __TYPE__: "FieldContent",
16
+ }
17
+ }
@@ -0,0 +1,15 @@
1
+ import type { EmbedContent } from "../../../../content"
2
+ import type { ImportEmbed } from "../../../validators"
3
+
4
+ export const embedConverter = (
5
+ field: ImportEmbed["value"],
6
+ ): EmbedContent | undefined => {
7
+ if (field === null) return
8
+
9
+ return {
10
+ ...field,
11
+ __TYPE__: "EmbedContent",
12
+ }
13
+
14
+ return
15
+ }
@@ -0,0 +1,68 @@
1
+ import type { ImageContent } from "../../../../content"
2
+ import { mapValues, withOptionals } from "../../../../utils/Objects"
3
+ import type { ImageField, ImportImage } from "../../../validators"
4
+
5
+ export type Asset = {
6
+ id: string
7
+ last_modified: string
8
+ kind: "image" | "all"
9
+ filename?: string
10
+ extension?: string
11
+ size?: string
12
+ origin_url: string
13
+ url: string
14
+ width?: number
15
+ height?: number
16
+ notes?: string
17
+ credits?: string
18
+ alt?: string
19
+ }
20
+
21
+ function convertImage(field: ImageField, image: Asset) {
22
+ return withOptionals<Omit<ImageContent, "__TYPE__" | "thumbnails">>(
23
+ {
24
+ origin: {
25
+ id: field.id,
26
+ url: image.origin_url,
27
+ width: image.width!,
28
+ height: image.height!,
29
+ },
30
+ width: field.edit?.width ?? image.width!,
31
+ height: field.edit?.height ?? image.height!,
32
+ edit: {
33
+ zoom: field.edit?.zoom ?? 1,
34
+ crop: {
35
+ x: field.edit?.x ?? 0,
36
+ y: field.edit?.y ?? 0,
37
+ },
38
+ background: field.edit?.background ?? "transparent",
39
+ },
40
+ url: image.url,
41
+ },
42
+ [
43
+ ["alt", field.alt || image.alt],
44
+ ["credits", field.credit || image.credits],
45
+ ],
46
+ )
47
+ }
48
+
49
+ export const imageConverter = (
50
+ field: ImportImage["value"],
51
+ images: Map<string, Asset>,
52
+ ): ImageContent | undefined => {
53
+ const getImageById = (id: string): Asset => {
54
+ const image = images.get(id)
55
+ if (!image) throw new Error(`Missing asset with id '${id}'`)
56
+ return image
57
+ }
58
+
59
+ if (!field) return
60
+
61
+ return {
62
+ ...convertImage(field, getImageById(field.id)),
63
+ thumbnails: mapValues(field.thumbnails, (thumbnail) =>
64
+ convertImage(thumbnail, getImageById(thumbnail.id)),
65
+ ),
66
+ __TYPE__: "ImageContent",
67
+ }
68
+ }
@@ -1,8 +1,12 @@
1
1
  import type { WidgetContent } from "../../../../content"
2
2
  import type { ImportNestable } from "../../../validators"
3
3
  import {
4
+ Asset,
5
+ booleanConverter,
4
6
  colorConverter,
5
7
  dateConverter,
8
+ embedConverter,
9
+ imageConverter,
6
10
  numberConverter,
7
11
  selectConverter,
8
12
  textConverter,
@@ -11,8 +15,11 @@ import {
11
15
 
12
16
  export function convertNestableWidget(
13
17
  field: ImportNestable,
18
+ images: Map<string, Asset>,
14
19
  ): WidgetContent | undefined {
15
20
  switch (field.type) {
21
+ case "Boolean":
22
+ return booleanConverter(field.value)
16
23
  case "Color":
17
24
  return colorConverter(field.value)
18
25
  case "Select":
@@ -25,6 +32,10 @@ export function convertNestableWidget(
25
32
  return dateConverter(field.value)
26
33
  case "Timestamp":
27
34
  return timestampConverter(field.value)
35
+ case "Embed":
36
+ return embedConverter(field.value)
37
+ case "Image":
38
+ return imageConverter(field.value, images)
28
39
  default:
29
40
  throw new Error(
30
41
  `Unsupported type of nestable converter ${JSON.stringify(field)}`,
@@ -1,12 +1,14 @@
1
1
  import type { NumberContent } from "../../../../content"
2
2
  import type { ImportNumber } from "../../../validators"
3
- import { nullableConverter } from "../utils"
4
3
 
5
4
  export const numberConverter = (
6
5
  field: ImportNumber["value"],
7
- ): NumberContent | undefined =>
8
- nullableConverter(field, (value: NonNullable<ImportNumber["value"]>) => ({
6
+ ): NumberContent | undefined => {
7
+ if (field === null) return
8
+
9
+ return {
9
10
  type: "Number",
10
- value: value.toString(),
11
+ value: field.toString(),
11
12
  __TYPE__: "FieldContent",
12
- }))
13
+ }
14
+ }
@@ -1,12 +1,14 @@
1
1
  import type { SelectContent } from "../../../../content"
2
2
  import type { ImportSelect } from "../../../validators"
3
- import { nullableConverter } from "../utils"
4
3
 
5
4
  export const selectConverter = (
6
5
  field: ImportSelect["value"],
7
- ): SelectContent | undefined =>
8
- nullableConverter(field, (value: NonNullable<ImportSelect["value"]>) => ({
6
+ ): SelectContent | undefined => {
7
+ if (field === null) return
8
+
9
+ return {
9
10
  type: "Select",
10
- value: value,
11
+ value: field,
11
12
  __TYPE__: "FieldContent",
12
- }))
13
+ }
14
+ }
@@ -1,12 +1,14 @@
1
1
  import type { TextContent } from "../../../../content"
2
2
  import type { ImportText } from "../../../validators"
3
- import { nullableConverter } from "../utils"
4
3
 
5
4
  export const textConverter = (
6
5
  field: ImportText["value"],
7
- ): TextContent | undefined =>
8
- nullableConverter(field, (value: NonNullable<ImportText["value"]>) => ({
6
+ ): TextContent | undefined => {
7
+ if (field === null) return
8
+
9
+ return {
9
10
  type: "Text",
10
- value: value,
11
+ value: field,
11
12
  __TYPE__: "FieldContent",
12
- }))
13
+ }
14
+ }
@@ -1,12 +1,14 @@
1
1
  import type { TimestampContent } from "../../../../content"
2
- import type { ImportTimestamp } from "../../.."
3
- import { nullableConverter } from "../utils"
2
+ import type { ImportTimestamp } from "../../../validators"
4
3
 
5
4
  export const timestampConverter = (
6
5
  field: ImportTimestamp["value"],
7
- ): TimestampContent | undefined =>
8
- nullableConverter(field, (value: NonNullable<ImportTimestamp["value"]>) => ({
6
+ ): TimestampContent | undefined => {
7
+ if (field === null) return
8
+
9
+ return {
9
10
  type: "Timestamp",
10
- value: value.toISOString(),
11
+ value: field.toISOString(),
11
12
  __TYPE__: "FieldContent",
12
- }))
13
+ }
14
+ }
@@ -1,5 +1,8 @@
1
+ export * from "./Boolean"
1
2
  export * from "./Color"
2
3
  export * from "./Date"
4
+ export * from "./Embed"
5
+ export * from "./Image"
3
6
  export * from "./Nestable"
4
7
  export * from "./Number"
5
8
  export * from "./Select"
@@ -1,79 +1,111 @@
1
- import * as Either from "fp-ts/Either"
1
+ import { either } from "fp-ts"
2
+ import { Either, isLeft } from "fp-ts/Either"
3
+ import { pipe } from "fp-ts/lib/function"
2
4
  import * as t from "io-ts"
5
+ import { withMessage } from "io-ts-types"
3
6
 
4
7
  import type { WidgetKey } from "../../common"
5
- import {
6
- isNestableWidget,
7
- StaticCustomType,
8
- StaticWidget,
9
- } from "../../customtypes"
8
+ import type { StaticCustomType, StaticWidget } from "../../customtypes"
10
9
  import { isObject } from "../../utils/Objects"
11
- import { getNestableFieldCodec, ImportNestable } from "./fields"
10
+ import { ImportField } from "./fields/ImportField"
12
11
 
13
- export type ImportDocument = Record<WidgetKey, ImportNestable>
14
- export const ImportDocument = (mask: StaticCustomType) =>
15
- new t.Type<ImportDocument, ImportDocument, unknown>(
16
- "ImportDocument",
17
- (u): u is ImportDocument => isObject(u),
18
- (raw: unknown) => {
19
- if (!isObject(raw)) {
20
- const error: t.ValidationError = {
21
- value: raw,
22
- context: [],
23
- message: "document is not an object",
24
- }
25
- return Either.left([error])
26
- }
12
+ const rawImportDocument = withMessage(
13
+ t.record(t.string, t.unknown),
14
+ () => "document is not an object",
15
+ )
27
16
 
28
- // flattening the fields within the tabs
29
- const maskFields = Object.values(mask.json).reduce((acc, tab) => ({
30
- ...acc,
31
- ...tab,
32
- }))
17
+ function flattenCustomTypeFields(
18
+ customType: StaticCustomType,
19
+ ): Partial<Record<string, StaticWidget>> {
20
+ return Object.values(customType.json).reduce((acc, tab) => ({
21
+ ...acc,
22
+ ...tab,
23
+ }))
24
+ }
33
25
 
34
- // Listing all errors for each fields
35
- const { document, errors } = Object.entries(raw).reduce<{
36
- document: ImportDocument
37
- errors: t.Errors
38
- }>(
39
- (acc, [fieldKey, fieldValue]) => {
40
- const maskFieldValue = maskFields[fieldKey]
26
+ function validateField(
27
+ document: Record<string, unknown>,
28
+ customType: StaticCustomType,
29
+ ) {
30
+ return (
31
+ key: string,
32
+ content: unknown,
33
+ model?: StaticWidget,
34
+ ): Either<t.Errors, ImportField> => {
35
+ // the field is not defined in the custom type -> extra field or typo
36
+ if (!model) {
37
+ const error: t.ValidationError = {
38
+ value: content,
39
+ context: [{ key: key, type: t.unknown }],
40
+ message: `The field ${key} is not part of the Custom type`,
41
+ }
42
+ return either.left([error])
43
+ }
41
44
 
42
- // the field is not defined in the custom type -> extra field or typo
43
- if (!maskFieldValue) {
44
- const error: t.ValidationError = {
45
- value: fieldValue,
46
- context: [{ key: fieldKey, type: t.unknown }],
47
- message: `The field ${fieldKey} is not part of the Custom type`,
48
- }
49
- return { ...acc, errors: [...acc.errors, error] }
50
- }
45
+ // retrieving the right codec then testing out fieldValue with it.
46
+ const { result, codec } = ImportField.decode(model)(content)
51
47
 
52
- // retrieving the right codec then testing out fieldValue with it.
53
- const fieldCodec = getFieldCodec(maskFieldValue)
54
- const result = fieldCodec.decode(fieldValue)
48
+ // error.context is pointing at root when it should point to a `fieldKey`.
49
+ // We need to override the context to make it right.
50
+ if (isLeft(result)) {
51
+ const errors: t.Errors = result.left.map((error) => {
52
+ const contextHead = error.context[0]
53
+ const context = [
54
+ { key: "", actual: document, type: ImportDocument(customType) },
55
+ contextHead
56
+ ? { ...contextHead, key: key }
57
+ : { key: key, actual: content, type: codec },
58
+ ...error.context.slice(1),
59
+ ]
55
60
 
56
- // returning validation errors
57
- if (Either.isLeft(result))
58
- return { ...acc, errors: [...acc.errors, ...result.left] }
61
+ return { ...error, context }
62
+ })
63
+ return either.left(errors)
64
+ }
65
+ return either.right(result.right)
66
+ }
67
+ }
59
68
 
60
- // registering the field as validated
61
- return {
62
- ...acc,
63
- document: { ...acc.document, [fieldKey]: result.right },
64
- }
65
- },
66
- { document: {}, errors: [] },
69
+ function validateDocument(
70
+ customType: StaticCustomType,
71
+ rawDoc: Record<string, unknown>,
72
+ ) {
73
+ const fieldModels = flattenCustomTypeFields(customType)
74
+ const { document, errors } = Object.entries(rawDoc).reduce<{
75
+ document: ImportDocument
76
+ errors: t.Errors
77
+ }>(
78
+ (acc, [fieldKey, fieldValue]) => {
79
+ const parsedField = validateField(rawDoc, customType)(
80
+ fieldKey,
81
+ fieldValue,
82
+ fieldModels[fieldKey],
67
83
  )
68
84
 
69
- // Returning either the errors of
70
- if (errors.length > 0) return Either.left(errors)
71
- return Either.right(document)
85
+ if (isLeft(parsedField))
86
+ return { ...acc, errors: [...acc.errors, ...parsedField.left] }
87
+
88
+ return {
89
+ ...acc,
90
+ document: { ...acc.document, [fieldKey]: parsedField.right },
91
+ }
72
92
  },
73
- t.identity,
93
+ { document: {}, errors: [] },
74
94
  )
75
-
76
- function getFieldCodec(maskValue: StaticWidget) {
77
- if (isNestableWidget(maskValue)) return getNestableFieldCodec(maskValue)
78
- throw new Error(`Unsupported type of field ${maskValue.type}`)
95
+ if (errors.length > 0) return either.left(errors)
96
+ return either.right(document)
79
97
  }
98
+
99
+ export type ImportDocument = Record<WidgetKey, ImportField>
100
+ export const ImportDocument = (customType: StaticCustomType) =>
101
+ new t.Type<ImportDocument, ImportDocument, unknown>(
102
+ "ImportDocument",
103
+ (u): u is ImportDocument => isObject(u),
104
+ (raw: unknown) => {
105
+ return pipe(
106
+ rawImportDocument.decode(raw),
107
+ either.chain((doc) => validateDocument(customType, doc)),
108
+ )
109
+ },
110
+ t.identity,
111
+ )
@@ -0,0 +1,30 @@
1
+ import { either } from "fp-ts"
2
+ import { pipe } from "fp-ts/lib/function"
3
+ import * as t from "io-ts"
4
+
5
+ import type { FieldType } from "../../../customtypes"
6
+ import { isObject } from "../../../utils/Objects"
7
+
8
+ export const ImportContent = <T extends FieldType, A, O = A>(
9
+ type: T,
10
+ valueCodec: t.Type<A, O>,
11
+ ) =>
12
+ new t.Type<{ type: T; value: A }, O>(
13
+ "ImportField",
14
+ (u: unknown): u is { type: T; value: A } => {
15
+ if (!isObject(u)) return false
16
+ return type === u["type"] && valueCodec.is(u["value"])
17
+ },
18
+ (u: unknown) => {
19
+ return pipe(
20
+ valueCodec.decode(u),
21
+ either.map((decodedValue) => {
22
+ return {
23
+ type,
24
+ value: decodedValue,
25
+ }
26
+ }),
27
+ )
28
+ },
29
+ (field) => field.value as unknown as O,
30
+ )
@@ -0,0 +1,25 @@
1
+ import type { StaticWidget } from "../../../customtypes"
2
+ import { ImportNestable } from "./nestable"
3
+ import { ImportUID } from "./UID"
4
+
5
+ export type ImportField = ImportUID | ImportNestable
6
+
7
+ export const ImportField = {
8
+ is(u: unknown): u is ImportNestable {
9
+ return ImportUID.is(u) || ImportNestable.is(u)
10
+ },
11
+ decode: (field: StaticWidget) => {
12
+ return (content: unknown) => {
13
+ switch (field.type) {
14
+ case "UID":
15
+ return { codec: ImportUID, result: ImportUID.decode(content) }
16
+ case "Choice":
17
+ case "Slices":
18
+ case "Group":
19
+ throw new Error(`Unsupported type of field ${field.type}`)
20
+ default:
21
+ return ImportNestable.decode(field)(content)
22
+ }
23
+ }
24
+ },
25
+ }
@@ -0,0 +1,27 @@
1
+ import * as t from "io-ts"
2
+
3
+ import { NullOrElse, String } from "../../../validators"
4
+ import { ImportContent } from "./ImportContent"
5
+
6
+ const regex = /^[a-z0-9-_.]+$/
7
+
8
+ const uidValue = String.pipe(
9
+ new t.Type<string, string, string>(
10
+ "ImportUIDField",
11
+ (u: unknown): u is string => String.is(u),
12
+ (n: string, c: t.Context) => {
13
+ if (regex.test(n)) {
14
+ return t.success(n)
15
+ }
16
+ return t.failure(
17
+ n,
18
+ c,
19
+ "UID can only contain alphanumeric characters, dashes, underscores, and dots",
20
+ )
21
+ },
22
+ t.identity,
23
+ ),
24
+ )
25
+
26
+ export const ImportUID = ImportContent("UID", NullOrElse(uidValue))
27
+ export type ImportUID = t.TypeOf<typeof ImportUID>
@@ -1,8 +1,2 @@
1
- import type { FieldType } from "../../../customtypes"
2
-
3
1
  export * from "./nestable"
4
-
5
- export interface ImportFieldOutput<t extends FieldType, v, d = null> {
6
- type: t
7
- value: v | d
8
- }
2
+ export * from "./UID"
@@ -0,0 +1,7 @@
1
+ import type { TypeOf } from "io-ts"
2
+
3
+ import { Boolean, NullOrElse } from "../../../../validators"
4
+ import { ImportContent } from "../ImportContent"
5
+
6
+ export const ImportBoolean = ImportContent("Boolean", NullOrElse(Boolean))
7
+ export type ImportBoolean = TypeOf<typeof ImportBoolean>
@@ -1,28 +1,28 @@
1
1
  import * as t from "io-ts"
2
2
 
3
3
  import { HexaColor, HexaColorCode } from "../../../../common/HexaColorCode"
4
- import { NullOrT, String } from "../../../../validators"
5
- import type { ImportFieldOutput } from ".."
4
+ import { NullOrElse, String } from "../../../../validators"
5
+ import { ImportContent } from "../ImportContent"
6
6
 
7
- export type ImportColor = ImportFieldOutput<"Color", HexaColorCode>
8
- export const ImportColor = NullOrT<HexaColorCode, ImportColor>(
9
- // @ts-expect-error HexaColorCode is not inferred as a string.
10
- String.pipe(
11
- new t.Type<HexaColorCode, HexaColorCode, string>(
12
- "ImportColorField",
13
- (u: unknown): u is HexaColorCode => String.is(u) && HexaColor.is(u),
14
- (s: string, c: t.Context) => {
15
- if (!HexaColor.is(s)) {
16
- return t.failure(
17
- s,
18
- c,
19
- "The color value must be an hexadecimal color code",
20
- )
21
- }
7
+ const colorValue = new t.Type<HexaColorCode, HexaColorCode, string>(
8
+ "ImportColorValue",
9
+ (u: unknown): u is HexaColorCode => String.is(u) && HexaColor.is(u),
10
+ (s: string, c: t.Context) => {
11
+ if (!HexaColor.is(s)) {
12
+ return t.failure(
13
+ s,
14
+ c,
15
+ "The color value must be an hexadecimal color code",
16
+ )
17
+ }
22
18
 
23
- return t.success(s)
24
- },
25
- t.identity,
26
- ),
27
- ),
28
- )((s: HexaColorCode | null) => ({ type: "Color", value: s }))
19
+ return t.success(s)
20
+ },
21
+ t.identity,
22
+ )
23
+
24
+ export const ImportColor = ImportContent(
25
+ "Color",
26
+ NullOrElse(String.pipe(colorValue)),
27
+ )
28
+ export type ImportColor = t.TypeOf<typeof ImportColor>