@prismicio/types-internal 2.2.0-alpha.1 → 2.2.0-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 (145) hide show
  1. package/lib/common/Asset.d.ts +15 -0
  2. package/lib/common/Asset.js +2 -0
  3. package/lib/common/index.d.ts +1 -0
  4. package/lib/common/index.js +1 -0
  5. package/lib/content/Document.d.ts +40 -40
  6. package/lib/content/fields/GroupContent.d.ts +12 -12
  7. package/lib/content/fields/GroupContent.js +11 -4
  8. package/lib/content/fields/WidgetContent.d.ts +56 -56
  9. package/lib/content/fields/nestable/NestableContent.d.ts +7 -7
  10. package/lib/content/fields/nestable/RichTextContent/Blocks.d.ts +12 -12
  11. package/lib/content/fields/nestable/RichTextContent/index.d.ts +9 -9
  12. package/lib/content/fields/slices/Slice/CompositeSliceContent.d.ts +14 -14
  13. package/lib/content/fields/slices/Slice/RepeatableContent.d.ts +5 -5
  14. package/lib/content/fields/slices/Slice/SharedSliceContent.d.ts +14 -14
  15. package/lib/content/fields/slices/Slice/SimpleSliceContent.d.ts +14 -14
  16. package/lib/content/fields/slices/Slice/index.d.ts +30 -30
  17. package/lib/content/fields/slices/SliceItem.d.ts +30 -30
  18. package/lib/content/fields/slices/SlicesContent.d.ts +42 -42
  19. package/lib/customtypes/widgets/nestable/NestableWidget.d.ts +0 -157
  20. package/lib/customtypes/widgets/nestable/NestableWidget.js +1 -17
  21. package/lib/import/converters/Document.d.ts +3 -2
  22. package/lib/import/converters/Document.js +9 -7
  23. package/lib/import/converters/fields/UID.d.ts +3 -0
  24. package/lib/import/converters/fields/UID.js +12 -0
  25. package/lib/import/converters/fields/index.d.ts +1 -0
  26. package/lib/import/converters/fields/index.js +1 -0
  27. package/lib/import/converters/fields/nestable/Boolean.d.ts +3 -0
  28. package/lib/import/converters/fields/nestable/Boolean.js +12 -0
  29. package/lib/import/converters/fields/nestable/Color.js +9 -6
  30. package/lib/import/converters/fields/nestable/Date.d.ts +1 -1
  31. package/lib/import/converters/fields/nestable/Date.js +5 -5
  32. package/lib/import/converters/fields/nestable/Embed.d.ts +3 -0
  33. package/lib/import/converters/fields/nestable/Embed.js +13 -0
  34. package/lib/import/converters/fields/nestable/GeooPoint.d.ts +3 -0
  35. package/lib/import/converters/fields/nestable/GeooPoint.js +15 -0
  36. package/lib/import/converters/fields/nestable/Image.d.ts +4 -0
  37. package/lib/import/converters/fields/nestable/Image.js +45 -0
  38. package/lib/import/converters/fields/nestable/Link.d.ts +3 -0
  39. package/lib/import/converters/fields/nestable/Link.js +19 -0
  40. package/lib/import/converters/fields/nestable/Nestable.d.ts +2 -1
  41. package/lib/import/converters/fields/nestable/Nestable.js +9 -1
  42. package/lib/import/converters/fields/nestable/Number.js +9 -6
  43. package/lib/import/converters/fields/nestable/Select.js +9 -6
  44. package/lib/import/converters/fields/nestable/Text.js +9 -6
  45. package/lib/import/converters/fields/nestable/Timestamp.d.ts +1 -1
  46. package/lib/import/converters/fields/nestable/Timestamp.js +9 -6
  47. package/lib/import/converters/fields/nestable/index.d.ts +4 -0
  48. package/lib/import/converters/fields/nestable/index.js +4 -0
  49. package/lib/import/validators/Document.d.ts +4 -4
  50. package/lib/import/validators/Document.js +41 -44
  51. package/lib/import/validators/fields/ImportContent.d.ts +5 -0
  52. package/lib/import/validators/fields/ImportContent.js +21 -0
  53. package/lib/import/validators/fields/ImportField.d.ts +230 -0
  54. package/lib/import/validators/fields/ImportField.js +24 -0
  55. package/lib/import/validators/fields/UID.d.ts +6 -0
  56. package/lib/import/validators/fields/UID.js +15 -0
  57. package/lib/import/validators/fields/index.d.ts +1 -5
  58. package/lib/import/validators/fields/index.js +1 -0
  59. package/lib/import/validators/fields/nestable/Boolean.d.ts +6 -0
  60. package/lib/import/validators/fields/nestable/Boolean.js +6 -0
  61. package/lib/import/validators/fields/nestable/Color.d.ts +5 -4
  62. package/lib/import/validators/fields/nestable/Color.js +4 -4
  63. package/lib/import/validators/fields/nestable/Date.d.ts +5 -3
  64. package/lib/import/validators/fields/nestable/Date.js +4 -2
  65. package/lib/import/validators/fields/nestable/Embed.d.ts +27 -0
  66. package/lib/import/validators/fields/nestable/Embed.js +54 -0
  67. package/lib/import/validators/fields/nestable/GeoPoint.d.ts +13 -0
  68. package/lib/import/validators/fields/nestable/GeoPoint.js +13 -0
  69. package/lib/import/validators/fields/nestable/Image.d.ts +45 -0
  70. package/lib/import/validators/fields/nestable/Image.js +45 -0
  71. package/lib/import/validators/fields/nestable/Link.d.ts +20 -0
  72. package/lib/import/validators/fields/nestable/Link.js +30 -0
  73. package/lib/import/validators/fields/nestable/Nestable.d.ts +224 -4
  74. package/lib/import/validators/fields/nestable/Nestable.js +55 -28
  75. package/lib/import/validators/fields/nestable/Number.d.ts +16 -9
  76. package/lib/import/validators/fields/nestable/Number.js +5 -4
  77. package/lib/import/validators/fields/nestable/Select.d.ts +15 -8
  78. package/lib/import/validators/fields/nestable/Select.js +4 -2
  79. package/lib/import/validators/fields/nestable/Text.d.ts +6 -3
  80. package/lib/import/validators/fields/nestable/Text.js +2 -1
  81. package/lib/import/validators/fields/nestable/Timestamp.d.ts +5 -3
  82. package/lib/import/validators/fields/nestable/Timestamp.js +4 -2
  83. package/lib/import/validators/fields/nestable/index.d.ts +4 -0
  84. package/lib/import/validators/fields/nestable/index.js +4 -0
  85. package/lib/utils/Objects.d.ts +1 -0
  86. package/lib/utils/Objects.js +5 -1
  87. package/lib/validators/BasicTypes.d.ts +8 -0
  88. package/lib/validators/BasicTypes.js +19 -1
  89. package/lib/validators/DefaultOrElse.d.ts +5 -0
  90. package/lib/validators/DefaultOrElse.js +21 -0
  91. package/lib/validators/NumberRange.d.ts +32 -0
  92. package/lib/validators/NumberRange.js +40 -0
  93. package/lib/validators/function.d.ts +20 -0
  94. package/lib/validators/function.js +41 -1
  95. package/lib/validators/index.d.ts +2 -1
  96. package/lib/validators/index.js +4 -2
  97. package/package.json +3 -2
  98. package/src/common/Asset.ts +15 -0
  99. package/src/common/index.ts +1 -0
  100. package/src/content/fields/GroupContent.ts +9 -5
  101. package/src/customtypes/widgets/nestable/NestableWidget.ts +0 -17
  102. package/src/import/converters/Document.ts +19 -11
  103. package/src/import/converters/fields/UID.ts +13 -0
  104. package/src/import/converters/fields/index.ts +1 -0
  105. package/src/import/converters/fields/nestable/Boolean.ts +13 -0
  106. package/src/import/converters/fields/nestable/Color.ts +7 -5
  107. package/src/import/converters/fields/nestable/Date.ts +12 -13
  108. package/src/import/converters/fields/nestable/Embed.ts +15 -0
  109. package/src/import/converters/fields/nestable/GeooPoint.ts +16 -0
  110. package/src/import/converters/fields/nestable/Image.ts +53 -0
  111. package/src/import/converters/fields/nestable/Nestable.ts +14 -0
  112. package/src/import/converters/fields/nestable/Number.ts +7 -5
  113. package/src/import/converters/fields/nestable/Select.ts +7 -5
  114. package/src/import/converters/fields/nestable/Text.ts +7 -5
  115. package/src/import/converters/fields/nestable/Timestamp.ts +8 -6
  116. package/src/import/converters/fields/nestable/index.ts +4 -0
  117. package/src/import/validators/Document.ts +94 -79
  118. package/src/import/validators/fields/ImportContent.ts +30 -0
  119. package/src/import/validators/fields/ImportField.ts +25 -0
  120. package/src/import/validators/fields/UID.ts +27 -0
  121. package/src/import/validators/fields/index.ts +1 -7
  122. package/src/import/validators/fields/nestable/Boolean.ts +7 -0
  123. package/src/import/validators/fields/nestable/Color.ts +23 -23
  124. package/src/import/validators/fields/nestable/Date.ts +26 -27
  125. package/src/import/validators/fields/nestable/Embed.ts +86 -0
  126. package/src/import/validators/fields/nestable/GeoPoint.ts +21 -0
  127. package/src/import/validators/fields/nestable/Image.ts +77 -0
  128. package/src/import/validators/fields/nestable/Nestable.ts +60 -26
  129. package/src/import/validators/fields/nestable/Number.ts +32 -30
  130. package/src/import/validators/fields/nestable/Select.ts +32 -30
  131. package/src/import/validators/fields/nestable/Text.ts +6 -6
  132. package/src/import/validators/fields/nestable/Timestamp.ts +29 -26
  133. package/src/import/validators/fields/nestable/index.ts +4 -0
  134. package/src/utils/Objects.ts +10 -0
  135. package/src/validators/BasicTypes.ts +48 -0
  136. package/src/validators/DefaultOrElse.ts +24 -0
  137. package/src/validators/NumberRange.ts +51 -0
  138. package/src/validators/function.ts +44 -0
  139. package/src/validators/index.ts +2 -1
  140. package/lib/import/converters/fields/utils.d.ts +0 -1
  141. package/lib/import/converters/fields/utils.js +0 -10
  142. package/lib/validators/NullOrT.d.ts +0 -2
  143. package/lib/validators/NullOrT.js +0 -13
  144. package/src/import/converters/fields/utils.ts +0 -7
  145. package/src/validators/NullOrT.ts +0 -18
@@ -1,96 +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
- }
27
-
28
- // flattening the fields within the tabs
29
- const maskFields = Object.values(mask.json).reduce((acc, tab) => ({
30
- ...acc,
31
- ...tab,
32
- }))
33
-
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]
12
+ const rawImportDocument = withMessage(
13
+ t.record(t.string, t.unknown),
14
+ () => "document is not an object",
15
+ )
41
16
 
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
- }
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
+ }
51
25
 
52
- // retrieving the right codec then testing out fieldValue with it.
53
- const fieldCodec = getFieldCodec(maskFieldValue)
54
- const result = fieldCodec.decode(fieldValue)
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
+ }
55
44
 
56
- // returning validation errors
57
- if (Either.isLeft(result)) {
58
- // error.context is pointing at root when it should point to a `fieldKey`.
59
- // We need to override the context to make it right.
60
- const errors: t.Errors = result.left.map(error => {
61
- const contextHead = error.context[0];
62
- const context = [
63
- { key: '', actual: raw, type: ImportDocument(mask) },
64
- contextHead
65
- ? { ...contextHead, key: fieldKey }
66
- : {key: fieldKey, actual: fieldValue, type: fieldCodec},
67
- ...error.context.slice(1)
68
- ];
45
+ // retrieving the right codec then testing out fieldValue with it.
46
+ const { result, codec } = ImportField.decode(model)(content)
69
47
 
70
- return { ...error, context };
71
- });
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
+ ]
72
60
 
73
- return { ...acc, errors: [...acc.errors, ...errors] };
74
- }
61
+ return { ...error, context }
62
+ })
63
+ return either.left(errors)
64
+ }
65
+ return either.right(result.right)
66
+ }
67
+ }
75
68
 
76
- // registering the field as validated
77
- return {
78
- ...acc,
79
- document: { ...acc.document, [fieldKey]: result.right },
80
- }
81
- },
82
- { 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],
83
83
  )
84
84
 
85
- // Returning either the errors of
86
- if (errors.length > 0) return Either.left(errors)
87
- 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
+ }
88
92
  },
89
- t.identity,
93
+ { document: {}, errors: [] },
90
94
  )
91
-
92
- function getFieldCodec(maskValue: StaticWidget) {
93
- if (isNestableWidget(maskValue)) return getNestableFieldCodec(maskValue)
94
- throw new Error(`Unsupported type of field ${maskValue.type}`)
95
+ if (errors.length > 0) return either.left(errors)
96
+ return either.right(document)
95
97
  }
96
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>
@@ -2,34 +2,33 @@ import { chain } from "fp-ts/Either"
2
2
  import { pipe } from "fp-ts/function"
3
3
  import * as t from "io-ts"
4
4
 
5
- import { NullOrT, String } from "../../../../validators"
6
- import type { ImportFieldOutput } from ".."
7
-
5
+ import { NullOrElse, String } from "../../../../validators"
6
+ import { ImportContent } from "../ImportContent"
8
7
  const DATE_INPUT_REGEX = /^(\d{1,4})-(\d{1,2})-(\d{1,2})$/
9
8
 
10
- export type ImportDate = ImportFieldOutput<"Date", Date>
11
- export const ImportDate = NullOrT<Date, ImportDate>(
12
- new t.Type<Date, Date, unknown>(
13
- "ImportDate",
14
- (u: unknown): u is Date => u instanceof Date,
15
- (u: unknown, c: t.Context) =>
16
- pipe(
17
- String.validate(u, c),
18
- chain((s: string) => {
19
- const date = new Date(s)
20
- const isInvalidDate = isNaN(date.getTime())
9
+ const dateValue = new t.Type<Date, Date, unknown>(
10
+ "ImportNumberValue",
11
+ (u: unknown): u is Date => u instanceof Date,
12
+ (u: unknown, c: t.Context) =>
13
+ pipe(
14
+ String.validate(u, c),
15
+ chain((s: string) => {
16
+ const date = new Date(s)
17
+ const isInvalidDate = isNaN(date.getTime())
18
+
19
+ if (isInvalidDate || !DATE_INPUT_REGEX.test(s)) {
20
+ return t.failure(
21
+ u,
22
+ c,
23
+ "The value must be a Date in the format YYYY-MM-DD",
24
+ )
25
+ }
21
26
 
22
- if (isInvalidDate || !DATE_INPUT_REGEX.test(s)) {
23
- return t.failure(
24
- u,
25
- c,
26
- "The value must be a Date in the format YYYY-MM-DD",
27
- )
28
- }
27
+ return t.success(date)
28
+ }),
29
+ ),
30
+ t.identity,
31
+ )
29
32
 
30
- return t.success(date)
31
- }),
32
- ),
33
- t.identity,
34
- ),
35
- )((s: Date | null) => ({ type: "Date", value: s }))
33
+ export const ImportDate = ImportContent("Date", NullOrElse(dateValue))
34
+ export type ImportDate = t.TypeOf<typeof ImportDate>
@@ -0,0 +1,86 @@
1
+ import * as Either from "fp-ts/lib/Either"
2
+ import { pipe } from "fp-ts/lib/function"
3
+ import * as t from "io-ts"
4
+ import { withMessage } from "io-ts-types"
5
+
6
+ import { EmptyObjectOrElse } from "../../../../validators"
7
+ import {
8
+ NumberOrNull,
9
+ String,
10
+ StringOrNull,
11
+ } from "../../../../validators/BasicTypes"
12
+ import { ImportContent } from "../ImportContent"
13
+
14
+ type URL = string
15
+
16
+ function isValidHttpUrl(param: unknown): param is URL {
17
+ try {
18
+ if (typeof param !== "string") {
19
+ return false
20
+ }
21
+ const url = new URL(param)
22
+ return ["http:", "https:"].includes(url.protocol)
23
+ } catch (err) {
24
+ return false
25
+ }
26
+ }
27
+
28
+ const EmbedUrl = new t.Type<URL, URL, unknown>(
29
+ "EmbedUrl",
30
+ (u: unknown): u is URL => isValidHttpUrl(u),
31
+ (u: unknown, c: t.Context) => {
32
+ if (isValidHttpUrl(u)) {
33
+ return t.success(u)
34
+ } else {
35
+ return t.failure(u, c, "The value must be a valid http/https url")
36
+ }
37
+ },
38
+ t.identity,
39
+ )
40
+
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
+ )
68
+ type EmbedProto = t.TypeOf<typeof EmbedProto>
69
+
70
+ type Embed = EmbedProto & {
71
+ all: unknown
72
+ }
73
+ const embedValue = new t.Type<Embed>(
74
+ "ImportEmbedValue",
75
+ (u: unknown): u is Embed => EmbedProto.is(u) && "all" in u,
76
+ (u: unknown) => {
77
+ return pipe(
78
+ EmbedProto.decode(u),
79
+ Either.map((parsed) => ({ ...parsed, all: u })),
80
+ )
81
+ },
82
+ t.identity,
83
+ )
84
+
85
+ export const ImportEmbed = ImportContent("Embed", EmptyObjectOrElse(embedValue))
86
+ export type ImportEmbed = t.TypeOf<typeof ImportEmbed>
@@ -0,0 +1,21 @@
1
+ import type { TypeOf } from "io-ts"
2
+ import * as t from "io-ts"
3
+
4
+ import { EmptyObjectOrElse, NumberRange } from "../../../../validators"
5
+ import { withFallbackMessage } from "../../../../validators/function"
6
+ import { ImportContent } from "../ImportContent"
7
+
8
+ const GeooPoint = withFallbackMessage(
9
+ t.strict({
10
+ latitude: NumberRange(-90, 90, "latitude"),
11
+ longitude: NumberRange(-180, 180, "longitude"),
12
+ }),
13
+ () =>
14
+ "GeoPoint must be an object with the properties `latitude` and `longitude` between the given ranges",
15
+ )
16
+
17
+ export const ImportGeoPoint = ImportContent(
18
+ "GeoPoint",
19
+ EmptyObjectOrElse(GeooPoint),
20
+ )
21
+ export type ImportGeoPoint = TypeOf<typeof ImportGeoPoint>
@@ -0,0 +1,77 @@
1
+ import { chain, map } from "fp-ts/Either"
2
+ import { pipe } from "fp-ts/lib/function"
3
+ import type { Validation } from "io-ts"
4
+ import * as t from "io-ts"
5
+
6
+ import { withOptionals } from "../../../../utils/Objects"
7
+ import { AnyObject, NullOrElse, Number } from "../../../../validators"
8
+ import { String, StringOrNull } from "../../../../validators/BasicTypes"
9
+ import { ImportContent } from "../ImportContent"
10
+
11
+ const ImageFieldCodec = AnyObject.pipe(
12
+ t.intersection([
13
+ t.type({
14
+ id: String,
15
+ }),
16
+ t.partial({
17
+ edit: AnyObject.pipe(
18
+ t.strict({
19
+ x: Number,
20
+ y: Number,
21
+ width: Number,
22
+ height: Number,
23
+ zoom: Number,
24
+ background: String,
25
+ }),
26
+ ),
27
+ credit: StringOrNull,
28
+ alt: StringOrNull,
29
+ }),
30
+ ]),
31
+ )
32
+
33
+ const ThumbnailsCodec = t.record(t.string, ImageFieldCodec)
34
+ type Thumbnails = t.TypeOf<typeof ThumbnailsCodec>
35
+
36
+ export type ImageField = t.TypeOf<typeof ImageFieldCodec>
37
+
38
+ type ImageFieldWithThumbnails = ImageField & { thumbnails: Thumbnails }
39
+
40
+ const ImageFieldWithThumbnails = new t.Type(
41
+ "ImageFieldWithThumbnails",
42
+ (u: unknown): u is ImageFieldWithThumbnails =>
43
+ ImageFieldCodec.is(u) &&
44
+ "thumbnails" in u &&
45
+ ThumbnailsCodec.is(u["thumbnails"]),
46
+ (u: unknown, ctx): Validation<ImageFieldWithThumbnails> => {
47
+ return pipe(
48
+ ImageFieldCodec.validate(u, ctx),
49
+ chain((proto) => {
50
+ const { id, edit, credit, alt, ...maybeThumbnails } = proto
51
+ return pipe(
52
+ ThumbnailsCodec.validate(maybeThumbnails, ctx),
53
+ map((thumbnails) =>
54
+ withOptionals<ImageFieldWithThumbnails>(
55
+ {
56
+ id,
57
+ thumbnails,
58
+ },
59
+ [
60
+ ["edit", edit],
61
+ ["credit", credit],
62
+ ["alt", alt],
63
+ ],
64
+ ),
65
+ ),
66
+ )
67
+ }),
68
+ )
69
+ },
70
+ t.identity,
71
+ )
72
+
73
+ export const ImportImage = ImportContent(
74
+ "Image",
75
+ NullOrElse(ImageFieldWithThumbnails),
76
+ )
77
+ export type ImportImage = t.TypeOf<typeof ImportImage>