@prismicio/types-internal 3.11.2 → 3.12.0-alpha.1

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 (90) hide show
  1. package/CHANGELOG.md +764 -0
  2. package/lib/content/Document.d.ts +32 -7
  3. package/lib/content/Document.js +22 -8
  4. package/lib/content/LegacyContentCtx.d.ts +25 -3
  5. package/lib/content/LegacyContentCtx.js +67 -5
  6. package/lib/content/fields/GroupContent.d.ts +4 -2
  7. package/lib/content/fields/GroupContent.js +40 -17
  8. package/lib/content/fields/UIDContent.js +1 -0
  9. package/lib/content/fields/WidgetContent.d.ts +6 -0
  10. package/lib/content/fields/nestable/BooleanContent.js +1 -0
  11. package/lib/content/fields/nestable/EmbedContent.js +1 -0
  12. package/lib/content/fields/nestable/FieldContent/ColorContent.js +1 -0
  13. package/lib/content/fields/nestable/FieldContent/DateContent.js +1 -0
  14. package/lib/content/fields/nestable/FieldContent/NumberContent.js +1 -0
  15. package/lib/content/fields/nestable/FieldContent/RangeContent.js +1 -0
  16. package/lib/content/fields/nestable/FieldContent/SelectContent.js +1 -0
  17. package/lib/content/fields/nestable/FieldContent/TextContent.js +1 -0
  18. package/lib/content/fields/nestable/FieldContent/TimestampContent.js +1 -0
  19. package/lib/content/fields/nestable/GeoPointContent.js +1 -0
  20. package/lib/content/fields/nestable/ImageContent.js +1 -0
  21. package/lib/content/fields/nestable/IntegrationFieldContent.js +1 -0
  22. package/lib/content/fields/nestable/LinkContent.js +2 -0
  23. package/lib/content/fields/nestable/RepeatableContent.js +1 -0
  24. package/lib/content/fields/nestable/RichTextContent/index.js +1 -0
  25. package/lib/content/fields/nestable/SeparatorContent.js +1 -0
  26. package/lib/content/fields/nestable/TableContent.js +1 -0
  27. package/lib/content/fields/slices/Slice/CompositeSliceContent.d.ts +3 -0
  28. package/lib/content/fields/slices/Slice/CompositeSliceContent.js +19 -5
  29. package/lib/content/fields/slices/Slice/RepeatableContent.d.ts +5 -4
  30. package/lib/content/fields/slices/Slice/RepeatableContent.js +2 -1
  31. package/lib/content/fields/slices/Slice/SharedSliceContent.d.ts +3 -0
  32. package/lib/content/fields/slices/Slice/SharedSliceContent.js +26 -19
  33. package/lib/content/fields/slices/Slice/SimpleSliceContent.js +1 -0
  34. package/lib/content/fields/slices/Slice/index.d.ts +4 -0
  35. package/lib/content/fields/slices/SliceItem.d.ts +12 -0
  36. package/lib/content/fields/slices/SliceItem.js +11 -2
  37. package/lib/content/fields/slices/SlicesContent.d.ts +6 -0
  38. package/lib/content/fields/slices/SlicesContent.js +1 -0
  39. package/lib/customtypes/CustomType.js +6 -9
  40. package/lib/customtypes/Section.js +3 -8
  41. package/lib/customtypes/widgets/Group.js +20 -20
  42. package/lib/customtypes/widgets/nestable/NestableWidgetZ.d.ts +3 -0
  43. package/lib/customtypes/widgets/nestable/NestableWidgetZ.js +29 -0
  44. package/lib/customtypes/widgets/slices/CompositeSlice.js +9 -22
  45. package/lib/customtypes/widgets/slices/SharedSlice.js +18 -37
  46. package/lib/customtypes/widgets/slices/SharedSliceZ.d.ts +16 -0
  47. package/lib/customtypes/widgets/slices/SharedSliceZ.js +39 -0
  48. package/lib/customtypes/widgets/slices/SlicePrimaryWidgetZ.d.ts +3 -0
  49. package/lib/customtypes/widgets/slices/SlicePrimaryWidgetZ.js +6 -0
  50. package/lib/customtypes/widgets/slices/Slices.js +9 -16
  51. package/package.json +1 -1
  52. package/src/content/Document.ts +31 -8
  53. package/src/content/LegacyContentCtx.ts +72 -16
  54. package/src/content/fields/GroupContent.ts +58 -16
  55. package/src/content/fields/UIDContent.ts +1 -0
  56. package/src/content/fields/nestable/BooleanContent.ts +1 -0
  57. package/src/content/fields/nestable/EmbedContent.ts +1 -0
  58. package/src/content/fields/nestable/FieldContent/ColorContent.ts +1 -0
  59. package/src/content/fields/nestable/FieldContent/DateContent.ts +1 -0
  60. package/src/content/fields/nestable/FieldContent/NumberContent.ts +1 -0
  61. package/src/content/fields/nestable/FieldContent/RangeContent.ts +1 -0
  62. package/src/content/fields/nestable/FieldContent/SelectContent.ts +1 -0
  63. package/src/content/fields/nestable/FieldContent/TextContent.ts +1 -0
  64. package/src/content/fields/nestable/FieldContent/TimestampContent.ts +1 -0
  65. package/src/content/fields/nestable/GeoPointContent.ts +1 -0
  66. package/src/content/fields/nestable/ImageContent.ts +1 -0
  67. package/src/content/fields/nestable/IntegrationFieldContent.ts +1 -0
  68. package/src/content/fields/nestable/LinkContent.ts +2 -0
  69. package/src/content/fields/nestable/RepeatableContent.ts +4 -0
  70. package/src/content/fields/nestable/RichTextContent/index.ts +1 -0
  71. package/src/content/fields/nestable/SeparatorContent.ts +1 -0
  72. package/src/content/fields/nestable/TableContent.ts +1 -0
  73. package/src/content/fields/slices/Slice/CompositeSliceContent.ts +19 -5
  74. package/src/content/fields/slices/Slice/RepeatableContent.ts +7 -2
  75. package/src/content/fields/slices/Slice/SharedSliceContent.ts +26 -19
  76. package/src/content/fields/slices/Slice/SimpleSliceContent.ts +1 -0
  77. package/src/content/fields/slices/SliceItem.ts +12 -3
  78. package/src/content/fields/slices/SlicesContent.ts +4 -1
  79. package/src/customtypes/CustomType.ts +6 -9
  80. package/src/customtypes/Section.ts +3 -9
  81. package/src/customtypes/widgets/Group.ts +20 -21
  82. package/src/customtypes/widgets/slices/CompositeSlice.ts +9 -22
  83. package/src/customtypes/widgets/slices/SharedSlice.ts +23 -38
  84. package/src/customtypes/widgets/slices/Slices.ts +9 -15
  85. package/lib/content/fields/RepeatableContent.d.ts +0 -162
  86. package/lib/content/fields/RepeatableContent.js +0 -93
  87. package/lib/content/fields/nestable/RichTextContent/TextBlock.d.ts +0 -727
  88. package/lib/content/fields/nestable/RichTextContent/TextBlock.js +0 -80
  89. package/lib/customtypes/widgets/slices/SliceWidget.d.ts +0 -327
  90. package/lib/customtypes/widgets/slices/SliceWidget.js +0 -8
@@ -31,33 +31,20 @@ exports.isCompositeSlice = isCompositeSlice;
31
31
  function traverseCompositeSlice(args) {
32
32
  var _a, _b;
33
33
  const { path: prevPath, slice, onField } = args;
34
- let nonRepeat;
34
+ const nonRepeat = {};
35
35
  for (const [key, field] of Object.entries((_a = slice["non-repeat"]) !== null && _a !== void 0 ? _a : {})) {
36
36
  const path = [...prevPath, "non-repeat", key];
37
- const newField = onField({ path, key, field });
38
- if (field !== newField) {
39
- if (!nonRepeat)
40
- nonRepeat = { ...slice["non-repeat"] };
41
- nonRepeat[key] = newField;
42
- }
37
+ nonRepeat[key] = onField({ path, key, field });
43
38
  }
44
- let repeat;
39
+ const repeat = {};
45
40
  for (const [key, field] of Object.entries((_b = slice.repeat) !== null && _b !== void 0 ? _b : {})) {
46
41
  const path = [...prevPath, "repeat", key];
47
- const newField = onField({ path, key, field });
48
- if (field !== newField) {
49
- if (!repeat)
50
- repeat = { ...slice.repeat };
51
- repeat[key] = newField;
52
- }
42
+ repeat[key] = onField({ path, key, field });
53
43
  }
54
- // returns the traversed model instead of a new one if it didn't change
55
- return repeat || nonRepeat
56
- ? {
57
- ...slice,
58
- ...(nonRepeat && { "non-repeat": nonRepeat }),
59
- ...(repeat && { repeat }),
60
- }
61
- : slice;
44
+ return {
45
+ ...slice,
46
+ ...(slice["non-repeat"] && { "non-repeat": nonRepeat }),
47
+ ...(slice.repeat && { repeat }),
48
+ };
62
49
  }
63
50
  exports.traverseCompositeSlice = traverseCompositeSlice;
@@ -50,7 +50,7 @@ exports.isDynamicSharedSlice = isDynamicSharedSlice;
50
50
  function traverseVariation(args) {
51
51
  var _a, _b;
52
52
  const { path: prevPath, variation, onField } = args;
53
- let primary;
53
+ const primary = {};
54
54
  for (const [key, prevField] of Object.entries((_a = variation.primary) !== null && _a !== void 0 ? _a : {})) {
55
55
  const path = [...prevPath, "primary", key];
56
56
  let field;
@@ -66,53 +66,34 @@ function traverseVariation(args) {
66
66
  field = prevField;
67
67
  break;
68
68
  }
69
- const newField = onField({ path, key, field });
70
- if (field !== newField) {
71
- if (!primary)
72
- primary = { ...variation.primary };
73
- primary[key] = newField;
74
- }
69
+ primary[key] = onField({ path, key, field });
75
70
  }
76
- let items;
77
- for (const [key, prevField] of Object.entries((_b = variation.items) !== null && _b !== void 0 ? _b : {})) {
71
+ const items = {};
72
+ for (const [key, field] of Object.entries((_b = variation.items) !== null && _b !== void 0 ? _b : {})) {
78
73
  const path = [...prevPath, "items", key];
79
- const newField = onField({
80
- path,
81
- key,
82
- field: prevField,
83
- });
84
- if (prevField !== newField) {
85
- if (!items)
86
- items = { ...variation.items };
87
- items[key] = newField;
88
- }
74
+ items[key] = onField({ path, key, field });
89
75
  }
90
- // returns the traversed model instead of a new one if it didn't change
91
- return primary || items
92
- ? { ...variation, ...(primary && { primary }), ...(items && { items }) }
93
- : variation;
76
+ return {
77
+ ...variation,
78
+ ...(variation.primary && { primary }),
79
+ ...(variation.items && { items }),
80
+ };
94
81
  }
95
82
  exports.traverseVariation = traverseVariation;
96
83
  function traverseSharedSlice(args) {
97
84
  const { path: prevPath, slice, onField } = args;
98
- let variations;
99
- for (let i = 0; i < slice.variations.length; i++) {
100
- const variation = slice.variations[i];
101
- if (!variation)
102
- continue;
85
+ const variations = [];
86
+ for (const variation of slice.variations) {
103
87
  const path = [...prevPath, variation.id];
104
- const newVariation = traverseVariation({
88
+ variations.push(traverseVariation({
105
89
  path,
106
90
  variation,
107
91
  onField,
108
- });
109
- if (newVariation !== variation) {
110
- if (!variations)
111
- variations = [...slice.variations];
112
- variations[i] = newVariation;
113
- }
92
+ }));
114
93
  }
115
- // returns the traversed model instead of a new one if it didn't change
116
- return variations ? { ...slice, variations } : slice;
94
+ return {
95
+ ...slice,
96
+ variations,
97
+ };
117
98
  }
118
99
  exports.traverseSharedSlice = traverseSharedSlice;
@@ -0,0 +1,16 @@
1
+ import { z } from "zod";
2
+ import type { SharedSliceRef } from "./SharedSliceRef";
3
+ import type { DynamicSlice, StaticSlice } from "./Slice";
4
+ export declare const Variation: any;
5
+ export declare type Variation = z.infer<typeof Variation>;
6
+ export declare type VariationFields = {
7
+ type: "SharedSlice";
8
+ sliceName: string;
9
+ variationId: string;
10
+ fields: Pick<Variation, "primary" | "items">;
11
+ };
12
+ export declare const SharedSliceType: "SharedSlice";
13
+ export declare const SharedSlice: any;
14
+ export declare type SharedSlice = z.infer<typeof SharedSlice>;
15
+ export declare function isStaticSharedSlice(slice: StaticSlice): slice is SharedSlice;
16
+ export declare function isDynamicSharedSlice(slice: DynamicSlice): slice is SharedSliceRef;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isDynamicSharedSlice = exports.isStaticSharedSlice = exports.SharedSlice = exports.SharedSliceType = exports.Variation = void 0;
4
+ const zod_1 = require("zod");
5
+ const NestableWidgetZ_1 = require("../nestable/NestableWidgetZ");
6
+ const SlicePrimaryWidgetZ_1 = require("./SlicePrimaryWidgetZ");
7
+ const IMAGE_PLACEHOLDER_URL = "https://images.prismic.io/slice-machine/621a5ec4-0387-4bc5-9860-2dd46cbc07cd_default_ss.png?auto=compress,format";
8
+ // Helper for WidgetKey validation
9
+ const WidgetKeySchema = zod_1.z.string().refine((val) => true, {
10
+ message: "Invalid widget key",
11
+ });
12
+ exports.Variation = zod_1.z.object({
13
+ id: zod_1.z.string(),
14
+ name: zod_1.z.string(),
15
+ description: zod_1.z.string(),
16
+ imageUrl: zod_1.z.string().default(IMAGE_PLACEHOLDER_URL),
17
+ docURL: zod_1.z.string(),
18
+ version: zod_1.z.string(),
19
+ display: zod_1.z.string().optional(),
20
+ primary: zod_1.z.record(WidgetKeySchema, SlicePrimaryWidgetZ_1.SlicePrimaryWidget).optional(),
21
+ items: zod_1.z.record(WidgetKeySchema, NestableWidgetZ_1.NestableWidget).optional(),
22
+ }).strict();
23
+ exports.SharedSliceType = "SharedSlice";
24
+ exports.SharedSlice = zod_1.z.object({
25
+ id: zod_1.z.string(),
26
+ type: zod_1.z.literal(exports.SharedSliceType),
27
+ name: zod_1.z.string(),
28
+ variations: zod_1.z.array(exports.Variation).readonly(),
29
+ description: zod_1.z.string().optional(),
30
+ legacyPaths: zod_1.z.record(zod_1.z.string(), zod_1.z.string()).optional(),
31
+ }).strict();
32
+ function isStaticSharedSlice(slice) {
33
+ return slice.type === "SharedSlice";
34
+ }
35
+ exports.isStaticSharedSlice = isStaticSharedSlice;
36
+ function isDynamicSharedSlice(slice) {
37
+ return slice.type === "SharedSlice";
38
+ }
39
+ exports.isDynamicSharedSlice = isDynamicSharedSlice;
@@ -0,0 +1,3 @@
1
+ import { z } from "zod";
2
+ export declare const SlicePrimaryWidget: any;
3
+ export declare type SlicePrimaryWidget = z.infer<typeof SlicePrimaryWidget>;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SlicePrimaryWidget = void 0;
4
+ require("zod");
5
+ const NestableWidgetZ_1 = require("../nestable/NestableWidgetZ");
6
+ exports.SlicePrimaryWidget = NestableWidgetZ_1.NestableWidget;
@@ -84,7 +84,7 @@ function traverseSlices(args) {
84
84
  const { path: prevPath, slices, onField } = args;
85
85
  if (!((_a = slices.config) === null || _a === void 0 ? void 0 : _a.choices))
86
86
  return slices;
87
- let choices;
87
+ const choices = {};
88
88
  for (const [key, prevModel] of Object.entries(slices.config.choices)) {
89
89
  const path = [...prevPath, key];
90
90
  let model;
@@ -126,21 +126,14 @@ function traverseSlices(args) {
126
126
  });
127
127
  break;
128
128
  }
129
- if (model !== prevModel) {
130
- if (!choices)
131
- choices = { ...slices.config.choices };
132
- choices[key] = model;
133
- }
129
+ choices[key] = model;
134
130
  }
135
- // returns the traversed model instead of a new one if it didn't change
136
- return choices
137
- ? {
138
- ...slices,
139
- config: {
140
- ...slices.config,
141
- choices,
142
- },
143
- }
144
- : slices;
131
+ return {
132
+ ...slices,
133
+ config: {
134
+ ...slices.config,
135
+ choices,
136
+ },
137
+ };
145
138
  }
146
139
  exports.traverseSlices = traverseSlices;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prismicio/types-internal",
3
- "version": "3.11.2",
3
+ "version": "3.12.0-alpha.1",
4
4
  "description": "Prismic types for Custom Types and Prismic Data",
5
5
  "keywords": [
6
6
  "typescript",
@@ -47,7 +47,10 @@ type DocumentLegacy = t.TypeOf<typeof legacyDocReader>
47
47
  * `DocumentLegacyCodec` handles decoding and encoding documents to the legacy
48
48
  * format used by Prismic DB, therefore, this function itself is not "legacy".
49
49
  */
50
- const DocumentLegacyCodec = (allTypes?: LegacyContentCtx["allTypes"]) => {
50
+ const DocumentLegacyCodec = (
51
+ allTypes?: LegacyContentCtx["allTypes"],
52
+ allKeys?: LegacyContentCtx["allKeys"],
53
+ ) => {
51
54
  return new t.Type<Document, WithTypes<DocumentLegacy>, unknown>(
52
55
  "Document",
53
56
  (u): u is Document => !!u && typeof u === "object",
@@ -57,7 +60,7 @@ const DocumentLegacyCodec = (allTypes?: LegacyContentCtx["allTypes"]) => {
57
60
  either.map((parsedDoc) => {
58
61
  return Object.entries(parsedDoc).reduce(
59
62
  (acc, [widgetKey, widgetValue]) => {
60
- const widgetCtx = defaultCtx(widgetKey, allTypes)
63
+ const widgetCtx = defaultCtx(widgetKey, allTypes, allKeys)
61
64
  const parsedW = WidgetLegacy(widgetCtx).decode(widgetValue)
62
65
  if (!parsedW || isLeft(parsedW)) return acc
63
66
 
@@ -78,9 +81,10 @@ const DocumentLegacyCodec = (allTypes?: LegacyContentCtx["allTypes"]) => {
78
81
  return {
79
82
  content: { ...acc.content, [key]: result.content },
80
83
  types: { ...acc.types, ...result.types },
84
+ keys: { ...acc.keys, ...result.keys },
81
85
  }
82
86
  },
83
- { content: {}, types: {} },
87
+ { content: {}, types: {}, keys: {} },
84
88
  )
85
89
  },
86
90
  )
@@ -89,12 +93,13 @@ const DocumentLegacyCodec = (allTypes?: LegacyContentCtx["allTypes"]) => {
89
93
  function extractMetadata(data: { [p: string]: unknown }): {
90
94
  types: Map<string, FieldOrSliceType>
91
95
  widgets: Partial<Record<WidgetKey, unknown>>
96
+ keys: Map<string, string>
92
97
  slugs: ReadonlyArray<string>
93
98
  uid: string | undefined
94
99
  } {
95
100
  const fields: [string, unknown][] = Object.entries(data)
96
101
 
97
- const { types, widgets } = fields.reduce(
102
+ const { types, widgets, keys } = fields.reduce(
98
103
  (acc, [k, v]) => {
99
104
  if (k.endsWith("_TYPE")) {
100
105
  const decodedValue = FieldOrSliceType.decode(v)
@@ -108,7 +113,23 @@ function extractMetadata(data: { [p: string]: unknown }): {
108
113
  }
109
114
  }
110
115
  }
111
- if (!k.endsWith("_POSITION") && !k.endsWith("_TYPE")) {
116
+ if (k.endsWith("_KEY")) {
117
+ const decodedValue = t.string.decode(v)
118
+ if (isRight(decodedValue)) {
119
+ return {
120
+ ...acc,
121
+ keys: acc.keys.set(
122
+ k.substring(0, k.length - 4),
123
+ decodedValue.right,
124
+ ),
125
+ }
126
+ }
127
+ }
128
+ if (
129
+ !k.endsWith("_POSITION") &&
130
+ !k.endsWith("_TYPE") &&
131
+ !k.endsWith("_KEY")
132
+ ) {
112
133
  return {
113
134
  ...acc,
114
135
  widgets: {
@@ -122,6 +143,7 @@ function extractMetadata(data: { [p: string]: unknown }): {
122
143
  {
123
144
  types: new Map<string, FieldOrSliceType>(),
124
145
  widgets: {},
146
+ keys: new Map<string, string>(),
125
147
  },
126
148
  )
127
149
 
@@ -131,6 +153,7 @@ function extractMetadata(data: { [p: string]: unknown }): {
131
153
  return {
132
154
  widgets,
133
155
  types,
156
+ keys,
134
157
  uid,
135
158
  slugs,
136
159
  }
@@ -150,9 +173,9 @@ function parseLegacyDocument(
150
173
  t.record(WidgetKey, t.unknown).decode(legacyDoc),
151
174
  either.chain((doc) => {
152
175
  // extract all metadata, meaning all _TYPES keys from legacy format + the widgets as unknown
153
- const { types, widgets } = extractMetadata(doc)
176
+ const { types, widgets, keys } = extractMetadata(doc)
154
177
  // parse the actual widgets
155
- return DocumentLegacyCodec(types).decode(widgets)
178
+ return DocumentLegacyCodec(types, keys).decode(widgets)
156
179
  }),
157
180
  )
158
181
 
@@ -161,7 +184,7 @@ function parseLegacyDocument(
161
184
 
162
185
  function encodeToLegacyDocument(document: Document): DocumentLegacy {
163
186
  const encoded = DocumentLegacyCodec().encode(document)
164
- return { ...encoded.content, ...encoded.types }
187
+ return { ...encoded.content, ...encoded.types, ...encoded.keys }
165
188
  }
166
189
 
167
190
  export const DocumentLegacy = {
@@ -1,4 +1,5 @@
1
1
  import * as t from "io-ts"
2
+ import { v4 as uuid } from "uuid"
2
3
 
3
4
  import { FieldType, SlicesTypes } from "../customtypes/widgets"
4
5
 
@@ -7,54 +8,109 @@ export const FieldOrSliceType = t.union([
7
8
  t.literal("Repeatable.Link"),
8
9
  ])
9
10
  export type FieldOrSliceType = t.TypeOf<typeof FieldOrSliceType>
11
+
12
+ interface LegacyContentCtxParams {
13
+ fieldKey: string
14
+ contentKey?: string
15
+ fieldPath?: Array<string>
16
+ contentPath?: Array<string>
17
+ allTypes?: Map<string, FieldOrSliceType>
18
+ allKeys?: Map<string, string>
19
+ }
20
+
10
21
  export class LegacyContentCtx {
11
22
  fieldKey: string
12
23
  prefixedKey: string
13
24
  keyOfType: string
25
+ keyOfKey: string
14
26
  fieldPath: Array<string>
15
27
  fieldType?: FieldOrSliceType | undefined
16
28
  allTypes: Map<string, FieldOrSliceType>
29
+ allKeys: Map<string, string>
30
+ contentKey: string
31
+ contentPath: Array<string>
32
+ fieldContentKey: string
17
33
 
18
- constructor(
19
- fieldKey: string,
20
- fieldPath?: Array<string>,
21
- allTypes?: Map<string, FieldOrSliceType>,
22
- ) {
34
+ constructor({
35
+ fieldKey,
36
+ contentKey,
37
+ contentPath,
38
+ fieldPath,
39
+ allTypes,
40
+ allKeys,
41
+ }: LegacyContentCtxParams) {
23
42
  this.fieldKey = fieldKey
43
+ this.contentKey = contentKey || fieldKey
24
44
  this.fieldPath = fieldPath || []
45
+ this.contentPath = contentPath || []
25
46
  this.allTypes = allTypes || new Map<string, FieldOrSliceType>()
47
+ this.allKeys = allKeys || new Map<string, string>()
26
48
 
27
49
  const prefixedKey = Array.of(this.fieldPath, [this.fieldKey])
28
50
  .flat()
29
51
  .join(".")
30
52
 
53
+ const prefixedContentKey = Array.of(this.contentPath, [this.contentKey])
54
+ .flat()
55
+ .join(".")
56
+
31
57
  this.prefixedKey = prefixedKey
32
58
  this.keyOfType = `${prefixedKey}_TYPE`
33
-
59
+ this.keyOfKey = `${prefixedContentKey}_KEY`
34
60
  this.fieldType = this.allTypes.get(this.prefixedKey)
61
+ this.fieldContentKey = this.allKeys.get(prefixedContentKey) ?? uuid()
62
+ }
63
+
64
+ withContentKey(contentKey: string): LegacyContentCtx {
65
+ return new LegacyContentCtx({
66
+ ...this,
67
+ contentPath: [...this.contentPath, this.contentKey],
68
+ contentKey,
69
+ })
35
70
  }
36
71
  }
37
72
 
38
- export function getFieldCtx(
39
- fieldKey: string,
40
- ctx: LegacyContentCtx,
41
- prefixes?: Array<string>,
42
- ): LegacyContentCtx {
43
- return new LegacyContentCtx(
73
+ interface GetFieldCtxParams {
74
+ fieldKey: string
75
+ contentKey?: string
76
+ ctx: LegacyContentCtx
77
+ prefixes?: Array<string>
78
+ }
79
+
80
+ export function getFieldCtx({
81
+ fieldKey,
82
+ contentKey: contentKeyParam,
83
+ ctx,
84
+ prefixes,
85
+ }: GetFieldCtxParams): LegacyContentCtx {
86
+ const contentKey = contentKeyParam || fieldKey
87
+ return new LegacyContentCtx({
44
88
  fieldKey,
45
- [...ctx.fieldPath, ctx.fieldKey, ...(prefixes || [])],
46
- ctx.allTypes,
47
- )
89
+ contentKey,
90
+ contentPath: [...ctx.contentPath, ctx.contentKey, ...(prefixes || [])],
91
+ fieldPath: [...ctx.fieldPath, ctx.fieldKey, ...(prefixes || [])],
92
+ allTypes: ctx.allTypes,
93
+ allKeys: ctx.allKeys,
94
+ })
48
95
  }
49
96
 
50
97
  export function defaultCtx(
51
98
  key: string,
52
99
  allTypes: Map<string, FieldOrSliceType> = new Map(),
100
+ allKeys: Map<string, string> = new Map(),
53
101
  ): LegacyContentCtx {
54
- return new LegacyContentCtx(key, [], allTypes)
102
+ return new LegacyContentCtx({
103
+ fieldKey: key,
104
+ contentKey: key,
105
+ contentPath: [],
106
+ fieldPath: [],
107
+ allTypes,
108
+ allKeys,
109
+ })
55
110
  }
56
111
 
57
112
  export type WithTypes<T> = {
113
+ keys: Record<string, string>
58
114
  types: Record<string, FieldOrSliceType>
59
115
  content: T
60
116
  }
@@ -1,4 +1,4 @@
1
- import { either } from "fp-ts"
1
+ import { array, either } from "fp-ts"
2
2
  import { isLeft } from "fp-ts/lib/Either"
3
3
  import { pipe } from "fp-ts/lib/function"
4
4
  import * as t from "io-ts"
@@ -38,6 +38,7 @@ export const GroupItemContent: t.Type<GroupItemContent> = t.recursion(
38
38
  () =>
39
39
  t.strict({
40
40
  __TYPE__: t.literal(GroupItemContentType),
41
+ key: t.string,
41
42
  value: t.array(
42
43
  t.tuple([t.string, t.union([NestableContent, GroupContent])]),
43
44
  ),
@@ -45,6 +46,7 @@ export const GroupItemContent: t.Type<GroupItemContent> = t.recursion(
45
46
  )
46
47
  export type GroupItemContent = {
47
48
  __TYPE__: typeof GroupItemContentType
49
+ key: string
48
50
  value: [string, NestableContent | GroupContent][]
49
51
  }
50
52
 
@@ -70,9 +72,9 @@ export const GroupContentDefaultValue: GroupContent = {
70
72
  }
71
73
 
72
74
  const itemLegacyReader = t.record(t.string, t.unknown)
73
- type GroupItemLegacy = t.TypeOf<typeof itemLegacyReader>
75
+ export type GroupItemLegacy = t.TypeOf<typeof itemLegacyReader>
74
76
 
75
- export const GroupItemLegacy = (ctx: LegacyContentCtx) => {
77
+ export const GroupItemLegacy = (ctx: LegacyContentCtx, index: number) => {
76
78
  return new t.Type<GroupItemContent, WithTypes<GroupItemLegacy>>(
77
79
  "GroupItemLegacy",
78
80
  (u): u is GroupItemContent =>
@@ -81,10 +83,15 @@ export const GroupItemLegacy = (ctx: LegacyContentCtx) => {
81
83
  const parsed = pipe(
82
84
  itemLegacyReader.decode(u),
83
85
  either.map((items) => {
86
+ const groupItemCtx = ctx.withContentKey(`${index}`)
84
87
  const parsedItems = Object.entries(items).reduce<
85
88
  Array<[string, NestableContent | GroupContent]>
86
89
  >((acc, [itemKey, itemValue]) => {
87
- const itemCtx = getFieldCtx(itemKey, ctx)
90
+ const itemCtx = getFieldCtx({
91
+ fieldKey: itemKey,
92
+ contentKey: itemKey,
93
+ ctx: groupItemCtx,
94
+ })
88
95
  const result =
89
96
  itemCtx.fieldType === GroupFieldType
90
97
  ? GroupLegacy(itemCtx).decode(itemValue)
@@ -99,15 +106,17 @@ export const GroupItemLegacy = (ctx: LegacyContentCtx) => {
99
106
  return {
100
107
  value: parsedItems,
101
108
  __TYPE__: GroupItemContentType,
109
+ key: groupItemCtx.fieldContentKey,
102
110
  }
103
111
  }),
104
112
  )
105
113
  return parsed
106
114
  },
107
115
  (item) => {
116
+ const groupItemCtx = ctx.withContentKey(`${index}`)
108
117
  return item.value.reduce<WithTypes<GroupItemLegacy>>(
109
118
  (acc, [key, value]) => {
110
- const itemCtx = getFieldCtx(key, ctx)
119
+ const itemCtx = getFieldCtx({ fieldKey: key, ctx })
111
120
  const encoded = isGroupContent(value)
112
121
  ? GroupLegacy(itemCtx).encode(value)
113
122
  : NestableLegacy(itemCtx).encode(value)
@@ -117,20 +126,46 @@ export const GroupItemLegacy = (ctx: LegacyContentCtx) => {
117
126
  return {
118
127
  content: { ...acc.content, [key]: encoded.content },
119
128
  types: { ...acc.types, ...encoded.types },
129
+ keys: { ...acc.keys, ...encoded.keys },
120
130
  }
121
131
  },
122
- { content: {}, types: {} },
132
+ { content: {}, types: {}, keys: { [groupItemCtx.keyOfKey]: item.key } },
123
133
  )
124
134
  },
125
135
  )
126
136
  }
127
137
 
138
+ export function arrayWithIndexCodec<T, O>(
139
+ f: (index: number) => t.Type<T, O, unknown>,
140
+ ): t.Type<Array<T>, O[], unknown> {
141
+ return new t.Type<Array<T>, O[], unknown>(
142
+ "ArrayWithIndexCodec",
143
+ (u): u is Array<T> => Array.isArray(u),
144
+ (items) =>
145
+ pipe(
146
+ t.array(t.unknown).decode(items),
147
+ either.chain((validItems) => {
148
+ const decodedItems = validItems.map((item, index) => {
149
+ return f(index).decode(item)
150
+ })
151
+ return array.sequence(either.Applicative)(decodedItems)
152
+ }),
153
+ ),
154
+ (items) => items.map((item, index) => f(index).encode(item)),
155
+ )
156
+ }
157
+
128
158
  type GroupLegacy = Array<GroupItemLegacy>
129
159
  export const GroupLegacy = (
130
160
  ctx: LegacyContentCtx,
131
161
  ): t.Type<GroupContent, WithTypes<GroupLegacy>, unknown> => {
132
- const codecDecode = t.array(t.union([t.null, GroupItemLegacy(ctx)]))
133
- const codecEncode = t.array(GroupItemLegacy(ctx))
162
+ const codecDecode = arrayWithIndexCodec<
163
+ GroupItemContent | null,
164
+ WithTypes<GroupItemLegacy> | null
165
+ >((index) => t.union([GroupItemLegacy(ctx, index), t.null]))
166
+
167
+ const codecEncode = (items: GroupItemContent[]) =>
168
+ items.map((item, index) => GroupItemLegacy(ctx, index).encode(item))
134
169
 
135
170
  return new t.Type<GroupContent, WithTypes<GroupLegacy>, unknown>(
136
171
  "GroupLegacy",
@@ -139,19 +174,22 @@ export const GroupLegacy = (
139
174
  return pipe(
140
175
  codecDecode.decode(items),
141
176
  either.map((parsedItems) => {
177
+ const value = parsedItems.map((i, index) => {
178
+ if (i === null) {
179
+ const key = ctx.withContentKey(`${index}`).fieldContentKey
180
+ return { __TYPE__: GroupItemContentType, key, value: [] }
181
+ }
182
+ return i
183
+ })
142
184
  return {
143
- value: parsedItems.map((i) => {
144
- if (i === null) {
145
- return { __TYPE__: GroupItemContentType, value: [] }
146
- } else return i
147
- }),
185
+ value,
148
186
  __TYPE__: GroupContentType,
149
187
  }
150
188
  }),
151
189
  )
152
190
  },
153
191
  (g: GroupContent) => {
154
- const res = codecEncode.encode(g.value)
192
+ const res = codecEncode(g.value)
155
193
  return {
156
194
  content: res.map((block) => block.content),
157
195
  types: res.reduce<Record<string, FieldOrSliceType>>(
@@ -160,6 +198,9 @@ export const GroupLegacy = (
160
198
  },
161
199
  { [ctx.keyOfType]: GroupFieldType },
162
200
  ),
201
+ keys: res.reduce<Record<string, string>>((acc, block) => {
202
+ return { ...acc, ...block.keys }
203
+ }, {}),
163
204
  }
164
205
  },
165
206
  )
@@ -223,9 +264,9 @@ export function traverseGroupItemsContent({
223
264
  model?: Record<string, Group | NestableWidget> | undefined
224
265
  }) {
225
266
  return (transform: TraverseWidgetContentFn): Array<GroupItemContent> => {
226
- return content.map((groupItem, index) => {
267
+ return content.map((groupItem) => {
227
268
  const groupItemPath = path.concat([
228
- { key: index.toString(), type: "GroupItem" },
269
+ { key: groupItem.key, type: "GroupItem" },
229
270
  ])
230
271
 
231
272
  const groupItemFields = groupItem.value.reduce<GroupItemContent["value"]>(
@@ -284,6 +325,7 @@ export function traverseGroupItemsContent({
284
325
 
285
326
  return {
286
327
  __TYPE__: groupItem.__TYPE__,
328
+ key: groupItem.key,
287
329
  value: groupItemFields,
288
330
  }
289
331
  })
@@ -29,6 +29,7 @@ export const UIDLegacy = (ctx: LegacyContentCtx) =>
29
29
  return {
30
30
  content: uid.value,
31
31
  types: { [ctx.keyOfType]: "UID" },
32
+ keys: {},
32
33
  }
33
34
  },
34
35
  )
@@ -29,6 +29,7 @@ export const BooleanLegacy = (ctx: LegacyContentCtx) =>
29
29
  return {
30
30
  content: b.value,
31
31
  types: { [ctx.keyOfType]: "Boolean" },
32
+ keys: {},
32
33
  }
33
34
  },
34
35
  )
@@ -58,6 +58,7 @@ export const EmbedLegacy = (ctx: LegacyContentCtx) =>
58
58
  **/
59
59
  content: embed.all,
60
60
  types: { [ctx.keyOfType]: "Embed" },
61
+ keys: {},
61
62
  }
62
63
  },
63
64
  )