@platecms/delta-client 0.6.0 → 0.8.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 (103) hide show
  1. package/README.md +309 -96
  2. package/package.json +4 -6
  3. package/src/__generated__/fragment-masking.ts +87 -0
  4. package/src/__generated__/gql.ts +52 -0
  5. package/src/__generated__/graphql.ts +3141 -0
  6. package/src/__generated__/{index.d.ts → index.ts} +1 -1
  7. package/src/api/index.ts +1 -0
  8. package/src/apollo/index.ts +70 -0
  9. package/src/graphql/tags/tag.query.gql +5 -0
  10. package/src/graphql/tags/tags.fragments.gql +17 -0
  11. package/src/index.ts +1 -0
  12. package/src/schema/index.spec.ts +211 -0
  13. package/src/schema/index.ts +18 -0
  14. package/src/schema/lib/schemas/array.spec.ts +111 -0
  15. package/src/schema/lib/schemas/array.ts +38 -0
  16. package/src/schema/lib/schemas/asset.spec.ts +101 -0
  17. package/src/schema/lib/schemas/asset.ts +12 -0
  18. package/src/schema/lib/schemas/baseSchema.ts +42 -0
  19. package/src/schema/lib/schemas/boolean.spec.ts +65 -0
  20. package/src/schema/lib/schemas/boolean.ts +12 -0
  21. package/src/schema/lib/schemas/buildingBlock.spec.ts +56 -0
  22. package/src/schema/lib/schemas/buildingBlock.ts +33 -0
  23. package/src/schema/lib/schemas/contentItem.spec.ts +61 -0
  24. package/src/schema/lib/schemas/contentItem.ts +31 -0
  25. package/src/schema/lib/schemas/contentType.spec.ts +113 -0
  26. package/src/schema/lib/schemas/contentType.ts +12 -0
  27. package/src/schema/lib/schemas/date.spec.ts +82 -0
  28. package/src/schema/lib/schemas/date.ts +17 -0
  29. package/src/schema/lib/schemas/gridPlacement.spec.ts +77 -0
  30. package/src/schema/lib/schemas/gridPlacement.ts +12 -0
  31. package/src/schema/lib/schemas/index.ts +66 -0
  32. package/src/schema/lib/schemas/number.spec.ts +65 -0
  33. package/src/schema/lib/schemas/number.ts +12 -0
  34. package/src/schema/lib/schemas/pathPart.spec.ts +120 -0
  35. package/src/schema/lib/schemas/pathPart.ts +12 -0
  36. package/src/schema/lib/schemas/smartText.spec.ts +105 -0
  37. package/src/schema/lib/schemas/smartText.ts +12 -0
  38. package/src/schema/lib/schemas/string.spec.ts +65 -0
  39. package/src/schema/lib/schemas/string.ts +12 -0
  40. package/src/schema/lib/schemas/tag.spec.ts +89 -0
  41. package/src/schema/lib/schemas/tag.ts +12 -0
  42. package/src/schema/lib/utils/isContentValue.spec.ts +111 -0
  43. package/src/schema/lib/utils/isContentValue.ts +17 -0
  44. package/src/schema/lib/utils/isPrimitiveValue.spec.ts +38 -0
  45. package/src/schema/lib/utils/isPrimitiveValue.ts +7 -0
  46. package/src/slate/index.ts +84 -0
  47. package/src/utils/{index.d.ts → index.ts} +3 -2
  48. package/src/utils/lib/connectors/BaseConnector.ts +26 -0
  49. package/src/utils/lib/connectors/WindowConnector.ts +70 -0
  50. package/src/utils/lib/events/ConnectorEvents.ts +89 -0
  51. package/src/utils/lib/events/EventEmitter.ts +19 -0
  52. package/src/__generated__/fragment-masking.d.ts +0 -19
  53. package/src/__generated__/fragment-masking.js +0 -22
  54. package/src/__generated__/fragment-masking.js.map +0 -1
  55. package/src/__generated__/gql.d.ts +0 -12
  56. package/src/__generated__/gql.js +0 -13
  57. package/src/__generated__/gql.js.map +0 -1
  58. package/src/__generated__/graphql.d.ts +0 -2157
  59. package/src/__generated__/graphql.js +0 -70
  60. package/src/__generated__/graphql.js.map +0 -1
  61. package/src/__generated__/index.js +0 -6
  62. package/src/__generated__/index.js.map +0 -1
  63. package/src/api/index.d.ts +0 -2
  64. package/src/api/index.js +0 -4
  65. package/src/api/index.js.map +0 -1
  66. package/src/apollo/index.d.ts +0 -7
  67. package/src/apollo/index.js +0 -40
  68. package/src/apollo/index.js.map +0 -1
  69. package/src/index.d.ts +0 -1
  70. package/src/index.js +0 -3
  71. package/src/index.js.map +0 -1
  72. package/src/schema/index.d.ts +0 -2
  73. package/src/schema/index.js +0 -8
  74. package/src/schema/index.js.map +0 -1
  75. package/src/schema/lib/nodes.d.ts +0 -46
  76. package/src/schema/lib/nodes.js +0 -14
  77. package/src/schema/lib/nodes.js.map +0 -1
  78. package/src/schema/lib/parser.d.ts +0 -12
  79. package/src/schema/lib/parser.js +0 -49
  80. package/src/schema/lib/parser.js.map +0 -1
  81. package/src/schema/lib/schema.d.ts +0 -17
  82. package/src/schema/lib/schema.js +0 -65
  83. package/src/schema/lib/schema.js.map +0 -1
  84. package/src/schema/lib/utils.d.ts +0 -12
  85. package/src/schema/lib/utils.js +0 -66
  86. package/src/schema/lib/utils.js.map +0 -1
  87. package/src/slate/index.d.ts +0 -65
  88. package/src/slate/index.js +0 -3
  89. package/src/slate/index.js.map +0 -1
  90. package/src/utils/index.js +0 -6
  91. package/src/utils/index.js.map +0 -1
  92. package/src/utils/lib/connectors/BaseConnector.d.ts +0 -16
  93. package/src/utils/lib/connectors/BaseConnector.js +0 -17
  94. package/src/utils/lib/connectors/BaseConnector.js.map +0 -1
  95. package/src/utils/lib/connectors/WindowConnector.d.ts +0 -10
  96. package/src/utils/lib/connectors/WindowConnector.js +0 -53
  97. package/src/utils/lib/connectors/WindowConnector.js.map +0 -1
  98. package/src/utils/lib/events/ConnectorEvents.d.ts +0 -63
  99. package/src/utils/lib/events/ConnectorEvents.js +0 -24
  100. package/src/utils/lib/events/ConnectorEvents.js.map +0 -1
  101. package/src/utils/lib/events/EventEmitter.d.ts +0 -7
  102. package/src/utils/lib/events/EventEmitter.js +0 -21
  103. package/src/utils/lib/events/EventEmitter.js.map +0 -1
@@ -1,2 +1,2 @@
1
1
  export * from "./fragment-masking";
2
- export * from "./gql";
2
+ export * from "./gql";
@@ -0,0 +1 @@
1
+ export default {};
@@ -0,0 +1,70 @@
1
+ import { HeaderKeys, Stage } from "@platecms/delta-types";
2
+ import {
3
+ ApolloClient,
4
+ ApolloLink,
5
+ FetchPolicy,
6
+ InMemoryCache,
7
+ NormalizedCacheObject,
8
+ createHttpLink,
9
+ from,
10
+ } from "@apollo/client";
11
+ import { PRN, ServiceAbbreviation } from "@platecms/delta-plate-resource-notation";
12
+ import { compact } from "lodash";
13
+ import { defu } from "defu";
14
+
15
+ const placeholderOrganizationPrn = new PRN(
16
+ "delta",
17
+ "placeholder",
18
+ ServiceAbbreviation.ORGANIZATIONS_CENTER,
19
+ "organization",
20
+ "0",
21
+ );
22
+
23
+ function createApolloClient(
24
+ uri: string,
25
+ options?: {
26
+ name?: string;
27
+ errorLink?: ApolloLink;
28
+ headers?: Record<string, string>;
29
+ },
30
+ ): ApolloClient<NormalizedCacheObject> {
31
+ function getHeaders(): Record<string, string> {
32
+ return {
33
+ [HeaderKeys.X_DELTA_ORGANIZATION]:
34
+ localStorage.getItem(HeaderKeys.X_DELTA_ORGANIZATION) ?? placeholderOrganizationPrn.toString(),
35
+ [HeaderKeys.X_DELTA_STAGE]: localStorage.getItem(HeaderKeys.X_DELTA_STAGE) ?? Stage.DEVELOPMENT,
36
+ };
37
+ }
38
+
39
+ const authLink = new ApolloLink((operation, forward) => {
40
+ const contextHeaders: Record<string, string> | undefined = operation.getContext()?.headers;
41
+ const setContextHeaders = defu(contextHeaders, getHeaders());
42
+
43
+ operation.setContext({
44
+ headers: setContextHeaders,
45
+ });
46
+ return forward(operation);
47
+ });
48
+
49
+ const httpLink = createHttpLink({
50
+ uri,
51
+ credentials: "include",
52
+ });
53
+
54
+ return new ApolloClient({
55
+ name: options?.name,
56
+ cache: new InMemoryCache(),
57
+ defaultOptions: {
58
+ query: {
59
+ /*
60
+ * Cast to FetchPolicy as cache-and-network is valid but not exposed as a type
61
+ * See @apollo/client/core/watchQueryOptions.d.ts line 13 for more details
62
+ */
63
+ fetchPolicy: "cache-and-network" as FetchPolicy,
64
+ },
65
+ },
66
+ link: from(compact([options?.errorLink, authLink.concat(httpLink)])),
67
+ });
68
+ }
69
+
70
+ export { createApolloClient };
@@ -0,0 +1,5 @@
1
+ query tag($prn: [PRN!]!) {
2
+ tag(prn: $prn) {
3
+ ...tagFragment
4
+ }
5
+ }
@@ -0,0 +1,17 @@
1
+ fragment tagFragment on Tag {
2
+ _id: prn
3
+ prn
4
+ name
5
+ path
6
+ color
7
+ visibility
8
+ forceVisibilityOnDescendants
9
+ stage
10
+ amountOfChildren
11
+ amountOfContentExperiences
12
+ amountOfContentItems
13
+ hasForcedVisibility
14
+ nestingLevel
15
+ createdAt
16
+ updatedAt
17
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,211 @@
1
+ import { describe, it } from "vitest";
2
+ import { BuildingBlockField, ContentItem, ExperienceComponent } from "../__generated__/graphql";
3
+ import { schema } from "./lib/schemas";
4
+ import { c } from "@platecms/delta-castscript";
5
+
6
+ const johnDoe: ContentItem = {
7
+ contentValues: [
8
+ {
9
+ contentField: {
10
+ name: "name",
11
+ },
12
+ primitiveValue: "John Doe",
13
+ },
14
+ {
15
+ contentField: {
16
+ name: "email",
17
+ },
18
+ primitiveValue: "john.doe@example.com",
19
+ },
20
+ ],
21
+ } as unknown as ContentItem;
22
+
23
+ const broccoli: ContentItem = {
24
+ contentValues: [
25
+ {
26
+ contentField: {
27
+ name: "name",
28
+ },
29
+ primitiveValue: "Broccoli",
30
+ },
31
+ {
32
+ contentField: {
33
+ name: "calories",
34
+ },
35
+ primitiveValue: 200,
36
+ },
37
+ {
38
+ contentField: {
39
+ name: "author",
40
+ },
41
+ relatedContentItem: johnDoe,
42
+ },
43
+ ],
44
+ } as unknown as ContentItem;
45
+
46
+ const carrot: ContentItem = {
47
+ contentValues: [
48
+ {
49
+ contentField: {
50
+ name: "name",
51
+ },
52
+ primitiveValue: "Carrot",
53
+ },
54
+ {
55
+ contentField: {
56
+ name: "calories",
57
+ },
58
+ primitiveValue: 100,
59
+ },
60
+ ],
61
+ } as unknown as ContentItem;
62
+
63
+ const experienceComponent: ExperienceComponent = {
64
+ buildingBlockFieldFulfillments: [
65
+ {
66
+ buildingBlockField: {
67
+ prn: "123",
68
+ slug: "title",
69
+ } as unknown as BuildingBlockField,
70
+ contentValue: {
71
+ primitiveValue: "Hello back!",
72
+ },
73
+ },
74
+ {
75
+ buildingBlockField: {
76
+ prn: "123",
77
+ slug: "description",
78
+ } as unknown as BuildingBlockField,
79
+ contentValue: {
80
+ interpolatedSmartText: c("root", [c("paragraph", "Hello back again!")]),
81
+ },
82
+ },
83
+ {
84
+ buildingBlockField: {
85
+ prn: "123",
86
+ slug: "vegatables",
87
+ } as unknown as BuildingBlockField,
88
+ contentValue: {
89
+ relatedContentItem: broccoli,
90
+ },
91
+ },
92
+ {
93
+ buildingBlockField: {
94
+ prn: "123",
95
+ slug: "vegatables",
96
+ } as unknown as BuildingBlockField,
97
+ contentValue: {
98
+ relatedContentItem: carrot,
99
+ },
100
+ },
101
+ {
102
+ buildingBlockField: {
103
+ prn: "123",
104
+ slug: "tags",
105
+ } as unknown as BuildingBlockField,
106
+ contentValue: {
107
+ linkedTag: {
108
+ prn: "123",
109
+ name: "title",
110
+ path: "title",
111
+ },
112
+ },
113
+ },
114
+ {
115
+ buildingBlockField: {
116
+ prn: "123",
117
+ slug: "type",
118
+ } as unknown as BuildingBlockField,
119
+ contentValue: {
120
+ linkedContentType: {
121
+ prn: "123",
122
+ name: "title",
123
+ contentFields: [
124
+ {
125
+ name: "title",
126
+ },
127
+ ],
128
+ },
129
+ },
130
+ },
131
+ ],
132
+ } as unknown as ExperienceComponent;
133
+
134
+ describe("Schema", () => {
135
+ it("should parse an building block with its values", () => {
136
+ const buildingBlock = schema.buildingBlock({
137
+ title: [schema.number(), schema.string()],
138
+ description: schema.smartText(),
139
+ vegatables: schema.array(
140
+ schema.contentItem({
141
+ name: [schema.string(), schema.number()],
142
+ calories: schema.number(),
143
+ author: schema.contentItem({
144
+ name: schema.string(),
145
+ email: schema.string(),
146
+ }),
147
+ }),
148
+ ),
149
+ tags: schema.array(schema.tag()),
150
+ type: schema.contentType(),
151
+ isVisible: schema.boolean().placeholder(true),
152
+ });
153
+
154
+ const result = buildingBlock.parse(experienceComponent.buildingBlockFieldFulfillments, {
155
+ placeholders: true,
156
+ });
157
+
158
+ expect(result).toEqual({
159
+ title: "Hello back!",
160
+ isVisible: true,
161
+ description: {
162
+ type: "root",
163
+ children: [
164
+ {
165
+ type: "paragraph",
166
+ children: [
167
+ {
168
+ type: "text",
169
+ value: "Hello back again!",
170
+ },
171
+ ],
172
+ },
173
+ ],
174
+ },
175
+ vegatables: [
176
+ {
177
+ name: "Broccoli",
178
+ calories: 200,
179
+ author: {
180
+ name: "John Doe",
181
+ email: "john.doe@example.com",
182
+ },
183
+ },
184
+ {
185
+ name: "Carrot",
186
+ calories: 100,
187
+ author: {
188
+ name: null,
189
+ email: null,
190
+ },
191
+ },
192
+ ],
193
+ tags: [
194
+ {
195
+ prn: "123",
196
+ name: "title",
197
+ path: "title",
198
+ },
199
+ ],
200
+ type: {
201
+ prn: "123",
202
+ name: "title",
203
+ contentFields: [
204
+ {
205
+ name: "title",
206
+ },
207
+ ],
208
+ },
209
+ });
210
+ });
211
+ });
@@ -0,0 +1,18 @@
1
+ export * from "./lib/schemas";
2
+
3
+ export * from "./lib/schemas/contentItem";
4
+ export * from "./lib/schemas/buildingBlock";
5
+ export * from "./lib/schemas/array";
6
+
7
+ export * from "./lib/schemas/string";
8
+ export * from "./lib/schemas/number";
9
+ export * from "./lib/schemas/boolean";
10
+ export * from "./lib/schemas/date";
11
+ export * from "./lib/schemas/asset";
12
+ export * from "./lib/schemas/smartText";
13
+ export * from "./lib/schemas/gridPlacement";
14
+ export * from "./lib/schemas/contentType";
15
+ export * from "./lib/schemas/pathPart";
16
+ export * from "./lib/schemas/tag";
17
+
18
+ export * from "./../__generated__/graphql";
@@ -0,0 +1,111 @@
1
+ import { describe, it } from "vitest";
2
+ import { schema as schemaBuilder } from ".";
3
+
4
+ describe("Array schema", () => {
5
+ it("should parse an array of content values", () => {
6
+ const testSchema = schemaBuilder.array(schemaBuilder.string());
7
+
8
+ const result = testSchema.parse([
9
+ {
10
+ primitiveValue: "hello",
11
+ },
12
+ {
13
+ primitiveValue: "world",
14
+ },
15
+ ]);
16
+
17
+ expect(result).toEqual(["hello", "world"]);
18
+ });
19
+
20
+ it("should return an empty array when parsing a non array", () => {
21
+ const testSchema = schemaBuilder.array(schemaBuilder.string());
22
+
23
+ const result = testSchema.parse([]);
24
+
25
+ expect(result).toEqual([]);
26
+ });
27
+
28
+ it("should return an empty array when parsing an empty array", () => {
29
+ const testSchema = schemaBuilder.array(schemaBuilder.string());
30
+
31
+ const result = testSchema.parse([]);
32
+
33
+ expect(result).toEqual([]);
34
+ });
35
+
36
+ it("should display string placholders when parsing an array", () => {
37
+ const testSchema = schemaBuilder
38
+ .array(schemaBuilder.string().placeholder("placeholder"))
39
+ .placeholder({ minLength: 2 });
40
+
41
+ const result = testSchema.parse([], {
42
+ placeholders: true,
43
+ });
44
+
45
+ expect(result).toEqual(["placeholder", "placeholder"]);
46
+ });
47
+
48
+ it("should display placholders for content items when parsing an arraray", () => {
49
+ const testSchema = schemaBuilder
50
+ .array(
51
+ schemaBuilder.contentItem({
52
+ title: schemaBuilder.string().placeholder("title"),
53
+ }),
54
+ )
55
+ .placeholder({ minLength: 2 });
56
+
57
+ const result = testSchema.parse([], {
58
+ placeholders: true,
59
+ });
60
+
61
+ expect(result).toEqual([
62
+ {
63
+ title: "title",
64
+ },
65
+ {
66
+ title: "title",
67
+ },
68
+ ]);
69
+ });
70
+
71
+ it("should display placholders when parsing an array", () => {
72
+ const testSchema = schemaBuilder
73
+ .array(schemaBuilder.string().placeholder("placeholder"))
74
+ .placeholder({ minLength: 1 });
75
+
76
+ const result = testSchema.parse([]);
77
+
78
+ expect(result).toEqual([]);
79
+ });
80
+
81
+ describe("when using multiple schemas", () => {
82
+ it("should parse an array of content values", () => {
83
+ const testSchema = schemaBuilder.array(
84
+ schemaBuilder.contentItem({
85
+ name: schemaBuilder.string(),
86
+ }),
87
+ );
88
+
89
+ const result = testSchema.parse([
90
+ {
91
+ relatedContentItem: {
92
+ contentValues: [
93
+ {
94
+ contentField: {
95
+ name: "name",
96
+ },
97
+ primitiveValue: "hello",
98
+ },
99
+ ],
100
+ },
101
+ },
102
+ ]);
103
+
104
+ expect(result).toEqual([
105
+ {
106
+ name: "hello",
107
+ },
108
+ ]);
109
+ });
110
+ });
111
+ });
@@ -0,0 +1,38 @@
1
+ import { compact, first } from "lodash";
2
+ import { Schema, SchemaConfig } from ".";
3
+
4
+ export class ArraySchema<T extends Schema | Schema[]>
5
+ implements Schema<T extends Schema[] ? T[number]["parse"][] : T extends Schema ? T["parse"][] : never, unknown>
6
+ {
7
+ private _minLength: number = 0;
8
+
9
+ public constructor(private readonly structure: T) {}
10
+
11
+ public placeholder({ minLength }: { minLength: number }): this {
12
+ this._minLength = minLength;
13
+ return this;
14
+ }
15
+
16
+ public parse(
17
+ data: unknown,
18
+ config?: SchemaConfig,
19
+ ): T extends Schema[] ? T[number]["parse"][] : T extends Schema ? T["parse"][] : never {
20
+ const dataAsArray = Array.isArray(data) ? data : [];
21
+
22
+ if (dataAsArray.length < this._minLength) {
23
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
24
+ dataAsArray.push(...Array(this._minLength - dataAsArray.length).fill(null));
25
+ }
26
+
27
+ const results = dataAsArray.map((item) => {
28
+ const structures: Schema[] = Array.isArray(this.structure) ? this.structure : [this.structure];
29
+ const resultForStructures = structures.map((schema) => schema.parse(item, config));
30
+
31
+ return resultForStructures.find((result) => result !== null) ?? first(resultForStructures);
32
+ }) as T extends Schema[] ? T[number]["parse"][] : T extends Schema ? T["parse"][] : never;
33
+
34
+ return config?.placeholders === true
35
+ ? results
36
+ : (compact(results) as T extends Schema[] ? T[number]["parse"][] : T extends Schema ? T["parse"][] : never);
37
+ }
38
+ }
@@ -0,0 +1,101 @@
1
+ import { describe, it } from "vitest";
2
+ import { AssetSchema } from "./asset";
3
+
4
+ describe("Asset schema", () => {
5
+ it("should parse to an asset when parsing an asset content value", () => {
6
+ const schema = new AssetSchema();
7
+
8
+ const result = schema.parse([
9
+ {
10
+ linkedAsset: {
11
+ prn: "123",
12
+ name: "title",
13
+ url: "url",
14
+ mimeType: "image/png",
15
+ fileSize: 100,
16
+ width: 100,
17
+ height: 100,
18
+ },
19
+ },
20
+ ]);
21
+
22
+ expect(result).toEqual({
23
+ prn: "123",
24
+ name: "title",
25
+ url: "url",
26
+ mimeType: "image/png",
27
+ fileSize: 100,
28
+ width: 100,
29
+ height: 100,
30
+ });
31
+ });
32
+
33
+ it("should return null when parsing an a non asset content value", () => {
34
+ const schema = new AssetSchema();
35
+
36
+ const result = schema.parse([
37
+ {
38
+ primitiveValue: "hello",
39
+ },
40
+ ]);
41
+
42
+ expect(result).toEqual(null);
43
+ });
44
+
45
+ describe("when placeholders are enabled", () => {
46
+ it("should return the placeholder when parsing an empty array", () => {
47
+ const schema = new AssetSchema().placeholder({
48
+ prn: "123",
49
+ url: "url",
50
+ mimeType: "image/png",
51
+ fileSize: 100,
52
+ });
53
+
54
+ const result = schema.parse([], {
55
+ placeholders: true,
56
+ });
57
+
58
+ expect(result).toEqual({
59
+ prn: "123",
60
+ url: "url",
61
+ mimeType: "image/png",
62
+ fileSize: 100,
63
+ });
64
+ });
65
+
66
+ it("should return the placeholder when parsing an non asset content value", () => {
67
+ const schema = new AssetSchema().placeholder({
68
+ prn: "123",
69
+ url: "url",
70
+ mimeType: "image/png",
71
+ fileSize: 100,
72
+ });
73
+
74
+ const result = schema.parse(
75
+ [
76
+ {
77
+ primitiveValue: true,
78
+ },
79
+ ],
80
+ {
81
+ placeholders: true,
82
+ },
83
+ );
84
+
85
+ expect(result).toEqual({
86
+ prn: "123",
87
+ url: "url",
88
+ mimeType: "image/png",
89
+ fileSize: 100,
90
+ });
91
+ });
92
+ });
93
+
94
+ describe("when nullable is disabled", () => {
95
+ it("should throw an error when parsing an non asset content value", () => {
96
+ const schema = new AssetSchema().nullable(false);
97
+
98
+ expect(() => schema.parse([{ primitiveValue: 42 }])).toThrow("Data could not be found and is not nullable");
99
+ });
100
+ });
101
+ });
@@ -0,0 +1,12 @@
1
+ import { Asset } from "../../../__generated__/graphql";
2
+ import { BaseSchema } from "./baseSchema";
3
+
4
+ export class AssetSchema extends BaseSchema<Asset | null, unknown> {
5
+ protected override findValue(data: unknown): Asset | null {
6
+ if (typeof data === "object" && data !== null && "linkedAsset" in data) {
7
+ return (data as { linkedAsset: Asset }).linkedAsset;
8
+ }
9
+
10
+ return null;
11
+ }
12
+ }
@@ -0,0 +1,42 @@
1
+ import { isArray } from "lodash";
2
+ import { ResultType, Schema, SchemaConfig } from ".";
3
+
4
+ export abstract class BaseSchema<TResult extends ResultType, TData> implements Schema<TResult, TData> {
5
+ protected _isNullable = true;
6
+ protected _placeholder: TResult | null = null;
7
+
8
+ public nullable(value: boolean = false): this {
9
+ this._isNullable = value;
10
+
11
+ return this;
12
+ }
13
+
14
+ public placeholder(placeholder: Partial<TResult>): this {
15
+ this._placeholder = placeholder as TResult;
16
+
17
+ return this;
18
+ }
19
+
20
+ public parse(data: TData | TData[], config?: SchemaConfig): TResult | null {
21
+ if (isArray(data)) {
22
+ data = data[this.findIndex(data)];
23
+ }
24
+
25
+ if (this.findValue(data) !== null) {
26
+ return this.findValue(data);
27
+ }
28
+
29
+ if (!this._isNullable) {
30
+ throw new Error("Data could not be found and is not nullable");
31
+ }
32
+
33
+ return config?.placeholders === true ? this._placeholder : null;
34
+ }
35
+
36
+ private findIndex(data: TData[]): number {
37
+ const index = data.findIndex((item) => this.findValue(item) !== null);
38
+ return index !== -1 ? index : 0;
39
+ }
40
+
41
+ protected abstract findValue(data: TData): TResult | null;
42
+ }