@slicemachine/manager 0.24.16-beta.1 → 0.24.16-beta.11

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.
@@ -3,6 +3,7 @@ import * as prismicCustomTypesClient from "@prismicio/custom-types-client";
3
3
  import {
4
4
  CustomType,
5
5
  Group,
6
+ LinkConfig,
6
7
  NestableWidget,
7
8
  NestedGroup,
8
9
  SharedSlice,
@@ -76,6 +77,30 @@ type SliceMachineManagerUpdateCustomTypeMocksConfigArgs = {
76
77
  mocksConfig: Record<string, unknown>;
77
78
  };
78
79
 
80
+ /** `[field]` or `[group, field]` – path **inside** the Custom Type */
81
+ type PathWithoutCustomType = [string] | [string, string];
82
+
83
+ type SliceMachineManagerUpdateCustomTypeFieldIdChanged = {
84
+ /**
85
+ * Previous path of the changed field, excluding the custom type id. Can be
86
+ * used to identify the field that had an API ID rename (e.g. ["fieldA"] or
87
+ * ["groupA", "fieldA"])
88
+ */
89
+ previousPath: PathWithoutCustomType;
90
+ /**
91
+ * New path of the changed field, excluding the custom type id. Can be used to
92
+ * identify the field that had an API ID rename (e.g. ["fieldB"] or ["groupA",
93
+ * "fieldB"])
94
+ */
95
+ newPath: PathWithoutCustomType;
96
+ };
97
+
98
+ type SliceMachineManagerUpdateCustomTypeArgs = CustomTypeUpdateHookData & {
99
+ updateMeta?: {
100
+ fieldIdChanged?: SliceMachineManagerUpdateCustomTypeFieldIdChanged;
101
+ };
102
+ };
103
+
79
104
  type SliceMachineManagerUpdateCustomTypeMocksConfigArgsReturnType = {
80
105
  errors: HookError[];
81
106
  };
@@ -92,20 +117,15 @@ type CustomTypesMachineManagerUpdateCustomTypeReturnType = {
92
117
  errors: (DecodeError | HookError)[];
93
118
  };
94
119
 
120
+ /** `[ct, field]` or `[ct, group, field]` – path **with** Custom Type ID */
121
+ type PathWithCustomType = [string, string] | [string, string, string];
122
+
95
123
  type CustomTypeFieldIdChangedMeta = {
96
- previousPath: string[];
97
- newPath: string[];
124
+ previousPath: PathWithCustomType;
125
+ newPath: PathWithCustomType;
98
126
  };
99
127
 
100
- type CrCustomType =
101
- | string
102
- | { id: string; fields?: readonly CrCustomTypeNestedCr[] };
103
- type CrCustomTypeNestedCr =
104
- | string
105
- | { id: string; customtypes: readonly CrCustomTypeFieldLeaf[] };
106
- type CrCustomTypeFieldLeaf =
107
- | string
108
- | { id: string; fields?: readonly string[] };
128
+ type LinkCustomType = NonNullable<LinkConfig["customtypes"]>[number];
109
129
 
110
130
  export class CustomTypesManager extends BaseManager {
111
131
  async readCustomTypeLibrary(): Promise<SliceMachineManagerReadCustomTypeLibraryReturnType> {
@@ -198,7 +218,9 @@ export class CustomTypesManager extends BaseManager {
198
218
  * property.
199
219
  */
200
220
  private async updateContentRelationships(
201
- args: { model: CustomType } & CustomTypeFieldIdChangedMeta,
221
+ args: {
222
+ model: CustomType;
223
+ } & SliceMachineManagerUpdateCustomTypeFieldIdChanged,
202
224
  ): Promise<
203
225
  OnlyHookErrors<CallHookReturnType<CustomTypeUpdateHook>> & {
204
226
  rollback?: () => Promise<void>;
@@ -206,12 +228,16 @@ export class CustomTypesManager extends BaseManager {
206
228
  > {
207
229
  assertPluginsInitialized(this.sliceMachinePluginRunner);
208
230
 
209
- const { model } = args;
210
- let { newPath, previousPath } = args;
231
+ const {
232
+ model,
233
+ previousPath: previousFieldPath,
234
+ newPath: newFieldPath,
235
+ } = args;
211
236
 
212
- if (previousPath.join(".") !== newPath.join(".")) {
213
- previousPath = [model.id, ...previousPath];
214
- newPath = [model.id, ...newPath];
237
+ if (previousFieldPath.join(".") !== newFieldPath.join(".")) {
238
+ const { id: ctId } = model;
239
+ const previousPath: PathWithCustomType = [ctId, ...previousFieldPath];
240
+ const newPath: PathWithCustomType = [ctId, ...newFieldPath];
215
241
 
216
242
  const crUpdates: {
217
243
  updatePromise: Promise<{ errors: HookError[] }>;
@@ -294,7 +320,7 @@ export class CustomTypesManager extends BaseManager {
294
320
  }
295
321
 
296
322
  async updateCustomType(
297
- args: CustomTypeUpdateHookData,
323
+ args: SliceMachineManagerUpdateCustomTypeArgs,
298
324
  ): Promise<CustomTypesMachineManagerUpdateCustomTypeReturnType> {
299
325
  assertPluginsInitialized(this.sliceMachinePluginRunner);
300
326
  const { model } = args;
@@ -560,99 +586,227 @@ const InferSliceResponse = z.object({
560
586
  });
561
587
 
562
588
  function updateCRCustomType(
563
- args: { customType: CrCustomType } & CustomTypeFieldIdChangedMeta,
564
- ): CrCustomType {
565
- const [previousCustomTypeId, previousFieldId] = args.previousPath;
566
- const [newCustomTypeId, newFieldId] = args.newPath;
589
+ args: { customType: LinkCustomType } & CustomTypeFieldIdChangedMeta,
590
+ ): LinkCustomType {
591
+ const previousPath = getPathIds(args.previousPath);
592
+ const newPath = getPathIds(args.newPath);
567
593
 
568
- if (!previousCustomTypeId || !newCustomTypeId) {
594
+ if (!previousPath.customTypeId || !newPath.customTypeId) {
569
595
  throw new Error(
570
- "Could not find a customtype id in previousPath and/or newPath, which should not be possible.",
596
+ `Could not find a customtype id in previousPath (${args.previousPath.join(
597
+ ".",
598
+ )}) and/or newPath (${args.newPath.join(
599
+ ".",
600
+ )}), which should not be possible.`,
571
601
  );
572
602
  }
573
603
 
574
- if (!previousFieldId || !newFieldId) {
604
+ if (!previousPath.fieldId || !newPath.fieldId) {
575
605
  throw new Error(
576
- "Could not find a field id in previousPath and/or newPath, which should not be possible.",
606
+ `Could not find a field id in previousPath (${args.previousPath.join(
607
+ ".",
608
+ )}) and/or newPath (${args.newPath.join(
609
+ ".",
610
+ )}), which should not be possible.`,
577
611
  );
578
612
  }
579
613
 
580
614
  const customType = shallowCloneIfObject(args.customType);
581
615
 
582
- if (typeof customType === "string" || !customType.fields) {
616
+ if (typeof customType === "string") {
617
+ // Legacy format support, we don't have anything to update here.
583
618
  return customType;
584
619
  }
585
620
 
586
- const matchedCustomTypeId = customType.id === previousCustomTypeId;
621
+ const matchedCustomTypeId = customType.id === previousPath.customTypeId;
622
+
623
+ return {
624
+ ...customType,
625
+ fields: customType.fields.map((fieldArg) => {
626
+ const customTypeField = shallowCloneIfObject(fieldArg);
627
+
628
+ // Regular field
629
+ if (typeof customTypeField === "string") {
630
+ if (
631
+ matchedCustomTypeId &&
632
+ customTypeField === previousPath.fieldId &&
633
+ customTypeField !== newPath.fieldId
634
+ ) {
635
+ // The id of the field has changed.
636
+ return newPath.fieldId;
637
+ }
587
638
 
588
- const newFields = customType.fields.map((fieldArg) => {
589
- const customTypeField = shallowCloneIfObject(fieldArg);
639
+ return customTypeField;
640
+ }
590
641
 
591
- if (typeof customTypeField === "string") {
592
642
  if (
593
643
  matchedCustomTypeId &&
594
- customTypeField === previousFieldId &&
595
- customTypeField !== newFieldId
644
+ customTypeField.id === previousPath.fieldId &&
645
+ customTypeField.id !== newPath.fieldId
596
646
  ) {
597
- // We have reached a field id that matches the id that was renamed,
598
- // so we update it new one. The field is a string, so return the new
599
- // id.
600
- return newFieldId;
647
+ // The id of the field has changed. We don't exit return because there
648
+ // might be other fields further down in nested custom types or groups
649
+ // that need to be updated.
650
+ customTypeField.id = newPath.fieldId;
601
651
  }
602
652
 
603
- return customTypeField;
604
- }
653
+ // Group field
654
+ if ("fields" in customTypeField) {
655
+ if (
656
+ !previousPath.groupId &&
657
+ !newPath.groupId &&
658
+ customTypeField.id === previousPath.fieldId &&
659
+ customTypeField.id !== newPath.fieldId
660
+ ) {
661
+ // Only the id of the group has changed. Group id is not defined, so
662
+ // we can return early.
663
+ return newPath.fieldId;
664
+ }
665
+
666
+ const matchedGroupId = customTypeField.id === previousPath.groupId;
667
+
668
+ if (
669
+ previousPath.groupId &&
670
+ newPath.groupId &&
671
+ matchedGroupId &&
672
+ customTypeField.id !== newPath.groupId
673
+ ) {
674
+ // The id of the group field has changed, so we update it. We don't
675
+ // return because there are group fields that may need to be updated.
676
+ customTypeField.id = newPath.groupId;
677
+ }
678
+
679
+ return {
680
+ ...customTypeField,
681
+ fields: customTypeField.fields.map((groupFieldArg) => {
682
+ const groupField = shallowCloneIfObject(groupFieldArg);
683
+
684
+ // Regular field inside a group field
685
+ if (typeof groupField === "string") {
686
+ if (
687
+ matchedGroupId &&
688
+ groupField === previousPath.fieldId &&
689
+ groupField !== newPath.fieldId
690
+ ) {
691
+ // The id of the field inside the group has changed.
692
+ return newPath.fieldId;
693
+ }
694
+
695
+ return groupField;
696
+ }
697
+
698
+ // Content relationship field inside a group field
699
+ return {
700
+ ...groupField,
701
+ fields: updateContentRelationshipFields({
702
+ customtypes: groupField.customtypes,
703
+ previousPath,
704
+ newPath,
705
+ }),
706
+ };
707
+ }),
708
+ };
709
+ }
710
+
711
+ // Content relationship field
712
+ return {
713
+ ...customTypeField,
714
+ customtypes: updateContentRelationshipFields({
715
+ customtypes: customTypeField.customtypes,
716
+ previousPath,
717
+ newPath,
718
+ }),
719
+ };
720
+ }),
721
+ };
722
+ }
723
+
724
+ function updateContentRelationshipFields(args: {
725
+ customtypes: readonly (
726
+ | string
727
+ | {
728
+ id: string;
729
+ fields: readonly (string | { id: string; fields: readonly string[] })[];
730
+ }
731
+ )[];
732
+ previousPath: CrUpdatePathIds;
733
+ newPath: CrUpdatePathIds;
734
+ }) {
735
+ const { customtypes, previousPath, newPath } = args;
736
+
737
+ return customtypes.map((nestedCtArg) => {
738
+ const nestedCt = shallowCloneIfObject(nestedCtArg);
605
739
 
606
740
  if (
607
- matchedCustomTypeId &&
608
- customTypeField.id === previousFieldId &&
609
- customTypeField.id !== newFieldId
741
+ typeof nestedCt === "string" ||
742
+ // Since we are entering a new custom type, if the previous id
743
+ // doesn't match, we can return early, because it's not the
744
+ // custom type we are looking for.
745
+ nestedCt.id !== previousPath.customTypeId
610
746
  ) {
611
- // We have reached a field id that matches the id that was renamed,
612
- // so we update it new one.
613
- // Since field is not a string, we don't exit, as we might have
614
- // something to update further down in customtypes.
615
- customTypeField.id = newFieldId;
747
+ return nestedCt;
616
748
  }
617
749
 
618
750
  return {
619
- ...customTypeField,
620
- customtypes: customTypeField.customtypes.map((customTypeArg) => {
621
- const nestedCustomType = shallowCloneIfObject(customTypeArg);
751
+ ...nestedCt,
752
+ fields: nestedCt.fields.map((nestedCtFieldArg) => {
753
+ const nestedCtField = shallowCloneIfObject(nestedCtFieldArg);
754
+
755
+ // Regular field
756
+ if (typeof nestedCtField === "string") {
757
+ if (
758
+ nestedCtField === previousPath.fieldId &&
759
+ nestedCtField !== newPath.fieldId
760
+ ) {
761
+ // The id of the field has changed.
762
+ return newPath.fieldId;
763
+ }
764
+
765
+ return nestedCtField;
766
+ }
767
+
768
+ // Group field
622
769
 
623
770
  if (
624
- typeof nestedCustomType === "string" ||
625
- !nestedCustomType.fields ||
626
- // Since we are on the last level, if we don't start matching right
627
- // at the custom type id, we can return exit early because it's not
628
- // a match.
629
- nestedCustomType.id !== previousCustomTypeId
771
+ nestedCtField.id === previousPath.fieldId &&
772
+ nestedCtField.id !== newPath.fieldId
630
773
  ) {
631
- return nestedCustomType;
774
+ // The id of the field has changed.
775
+ nestedCtField.id = newPath.fieldId;
632
776
  }
633
777
 
634
- return {
635
- ...nestedCustomType,
636
- fields: nestedCustomType.fields.map((fieldArg) => {
637
- const nestedCustomTypeField = shallowCloneIfObject(fieldArg);
778
+ // Further down the path, the field can only be a group field. So if we have
779
+ // no group id defined, no need to continue.
780
+ if (
781
+ !previousPath.groupId ||
782
+ !newPath.groupId ||
783
+ nestedCtField.id !== previousPath.groupId
784
+ ) {
785
+ return nestedCtField;
786
+ }
787
+
788
+ if (nestedCtField.id !== newPath.groupId) {
789
+ // The id of the group has changed.
790
+ nestedCtField.id = newPath.groupId;
791
+ }
638
792
 
793
+ return {
794
+ ...nestedCtField,
795
+ fields: nestedCtField.fields.map((nestedCtGroupFieldId) => {
639
796
  if (
640
- nestedCustomTypeField === previousFieldId &&
641
- nestedCustomTypeField !== newFieldId
797
+ nestedCtGroupFieldId === previousPath.fieldId &&
798
+ nestedCtGroupFieldId !== newPath.fieldId
642
799
  ) {
643
- // Matches the previous id, so we update it and return because
644
- // it's the last level.
645
- return newFieldId;
800
+ // The id of the field inside the group has changed.
801
+ return newPath.fieldId;
646
802
  }
647
803
 
648
- return nestedCustomTypeField;
804
+ return nestedCtGroupFieldId;
649
805
  }),
650
806
  };
651
807
  }),
652
808
  };
653
809
  });
654
-
655
- return { ...customType, fields: newFields };
656
810
  }
657
811
 
658
812
  /**
@@ -673,7 +827,7 @@ function updateFieldContentRelationships<
673
827
  }
674
828
 
675
829
  const newCustomTypes = field.config.customtypes.map((customType) => {
676
- return updateCRCustomType({ customType, ...updateMeta });
830
+ return updateCRCustomType({ ...updateMeta, customType });
677
831
  });
678
832
 
679
833
  return {
@@ -721,7 +875,7 @@ export function updateSharedSliceContentRelationships(
721
875
 
722
876
  for (const { model: slice } of models) {
723
877
  const updateSlice = traverseSharedSlice({
724
- path: ["."],
878
+ path: [],
725
879
  slice,
726
880
  onField: ({ field }) => {
727
881
  return updateFieldContentRelationships({
@@ -738,6 +892,35 @@ export function updateSharedSliceContentRelationships(
738
892
  }
739
893
  }
740
894
 
895
+ interface CrUpdatePathIds {
896
+ customTypeId: string;
897
+ groupId: string | undefined;
898
+ fieldId: string;
899
+ }
900
+
901
+ function getPathIds(path: PathWithCustomType): CrUpdatePathIds {
902
+ if (path.length < 2) {
903
+ throw new Error(
904
+ `Unexpected path length ${
905
+ path.length
906
+ }. Expected at least 2 segments (got: ${path.join(".")}).`,
907
+ );
908
+ }
909
+
910
+ const [customTypeId, groupOrFieldId, fieldId] = path;
911
+
912
+ return {
913
+ customTypeId,
914
+ /**
915
+ * Id of a changed group. If it's defined, it means that a group or a field
916
+ * inside a group had its API ID renamed. It's defined when the path has a
917
+ * third element (e.g. `["customtypeA", "groupA", "fieldA"]`).
918
+ */
919
+ groupId: fieldId ? groupOrFieldId : undefined,
920
+ fieldId: fieldId || groupOrFieldId,
921
+ };
922
+ }
923
+
741
924
  function isEqualModel<T extends CustomType | SharedSlice>(
742
925
  modelA: T,
743
926
  modelB: T,
@@ -9,7 +9,6 @@ export const SegmentEventType = {
9
9
  command_init_start: "command:init:start",
10
10
  command_init_identify: "command:init:identify",
11
11
  command_init_end: "command:init:end",
12
- review: "review",
13
12
  sliceSimulator_open: "slice-simulator:open",
14
13
  sliceSimulator_isNotRunning: "slice-simulator:is-not-running",
15
14
  pageView: "page-view",
@@ -52,7 +51,6 @@ export const HumanSegmentEventType = {
52
51
  [SegmentEventType.command_init_start]: "SliceMachine Init Start",
53
52
  [SegmentEventType.command_init_identify]: "SliceMachine Init Identify",
54
53
  [SegmentEventType.command_init_end]: "SliceMachine Init End",
55
- [SegmentEventType.review]: "SliceMachine Review",
56
54
  [SegmentEventType.sliceSimulator_open]: "SliceMachine Slice Simulator Open",
57
55
  [SegmentEventType.sliceSimulator_isNotRunning]:
58
56
  "SliceMachine Slice Simulator is not running",
@@ -135,15 +133,6 @@ type CommandInitEndSegmentEvent = SegmentEvent<
135
133
  { framework: string; success: boolean; error?: string }
136
134
  >;
137
135
 
138
- type ReviewSegmentEvent = SegmentEvent<
139
- typeof SegmentEventType.review,
140
- {
141
- rating: number;
142
- comment: string;
143
- type: "onboarding";
144
- }
145
- >;
146
-
147
136
  type SliceSimulatorOpenSegmentEvent = SegmentEvent<
148
137
  typeof SegmentEventType.sliceSimulator_open
149
138
  >;
@@ -431,7 +420,6 @@ export type SegmentEvents =
431
420
  | CommandInitStartSegmentEvent
432
421
  | CommandInitIdentifySegmentEvent
433
422
  | CommandInitEndSegmentEvent
434
- | ReviewSegmentEvent
435
423
  | SliceSimulatorOpenSegmentEvent
436
424
  | SliceSimulatorIsNotRunningSegmentEvent
437
425
  | PageViewSegmentEvent