@contentful/experiences-validators 3.7.0-dev-20250917T1203-0e23897.0 → 3.7.0-dev-20250917T1515-4c340b9.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.
package/dist/index.d.ts CHANGED
@@ -424,12 +424,16 @@ type Parameter = z.infer<typeof ParameterSchema>;
424
424
  declare const VariableMappingSchema: z.ZodObject<{
425
425
  parameterId: z.ZodString;
426
426
  type: z.ZodLiteral<"ContentTypeMapping">;
427
- pathsByContentType: z.ZodRecord<z.ZodString, z.ZodObject<{
427
+ pathsByContentType: z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodObject<{
428
428
  path: z.ZodString;
429
429
  }, "strip", z.ZodTypeAny, {
430
430
  path: string;
431
431
  }, {
432
432
  path: string;
433
+ }>>, Record<string, {
434
+ path: string;
435
+ }>, Record<string, {
436
+ path: string;
433
437
  }>>;
434
438
  }, "strip", z.ZodTypeAny, {
435
439
  type: "ContentTypeMapping";
@@ -547,7 +551,7 @@ declare const ParameterDefinitionSchema: z.ZodObject<{
547
551
  nodeId: string;
548
552
  }[] | undefined;
549
553
  }>;
550
- declare const ComponentSettingsSchema: z.ZodObject<{
554
+ declare const ComponentSettingsSchema: z.ZodEffects<z.ZodObject<{
551
555
  variableDefinitions: z.ZodRecord<z.ZodString, z.ZodObject<{
552
556
  displayName: z.ZodOptional<z.ZodString>;
553
557
  type: z.ZodEnum<["Text", "RichText", "Number", "Date", "Boolean", "Location", "Media", "Object", "Hyperlink", "Array", "Link"]>;
@@ -816,12 +820,16 @@ declare const ComponentSettingsSchema: z.ZodObject<{
816
820
  variableMappings: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
817
821
  parameterId: z.ZodString;
818
822
  type: z.ZodLiteral<"ContentTypeMapping">;
819
- pathsByContentType: z.ZodRecord<z.ZodString, z.ZodObject<{
823
+ pathsByContentType: z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodObject<{
820
824
  path: z.ZodString;
821
825
  }, "strip", z.ZodTypeAny, {
822
826
  path: string;
823
827
  }, {
824
828
  path: string;
829
+ }>>, Record<string, {
830
+ path: string;
831
+ }>, Record<string, {
832
+ path: string;
825
833
  }>>;
826
834
  }, "strip", z.ZodTypeAny, {
827
835
  type: "ContentTypeMapping";
@@ -1030,8 +1038,142 @@ declare const ComponentSettingsSchema: z.ZodObject<{
1030
1038
  }> | undefined;
1031
1039
  allowedVariableOverrides?: string[] | undefined;
1032
1040
  }[] | undefined;
1041
+ }>, {
1042
+ variableDefinitions: Record<string, {
1043
+ type: "Text" | "RichText" | "Number" | "Date" | "Boolean" | "Location" | "Media" | "Object" | "Hyperlink" | "Array" | "Link";
1044
+ displayName?: string | undefined;
1045
+ description?: string | undefined;
1046
+ group?: string | undefined;
1047
+ defaultValue?: string | number | boolean | Record<any, any> | {
1048
+ type: "DesignValue";
1049
+ valuesByBreakpoint: Record<string, string | number | boolean | Record<any, any> | undefined>;
1050
+ } | {
1051
+ path: string;
1052
+ type: "BoundValue";
1053
+ } | {
1054
+ type: "HyperlinkValue";
1055
+ linkTargetKey: string;
1056
+ overrides?: {} | undefined;
1057
+ } | {
1058
+ type: "UnboundValue";
1059
+ key: string;
1060
+ } | {
1061
+ type: "ComponentValue";
1062
+ key: string;
1063
+ } | {
1064
+ type: "NoValue";
1065
+ } | undefined;
1066
+ validations?: {
1067
+ required?: boolean | undefined;
1068
+ bindingSourceType?: ["entry" | "asset" | "manual" | "experience", ...("entry" | "asset" | "manual" | "experience")[]] | undefined;
1069
+ format?: "URL" | undefined;
1070
+ in?: {
1071
+ value: string | number;
1072
+ displayName?: string | undefined;
1073
+ }[] | undefined;
1074
+ } | undefined;
1075
+ }>;
1076
+ thumbnailId?: "columns" | "columnsPlusRight" | "imagesSquare" | "subtitles" | "rowsPlusBottom" | "userRectangle" | "textbox" | "monitorPlay" | "article" | "table" | "star" | "heartStraight" | "frameCorners" | "rows" | "dotsThreeOutline" | "listDashes" | "checkerBoard" | "gridFour" | "slideshow" | "diamondsFour" | "cards" | "textColumns" | "duplex" | undefined;
1077
+ category?: string | undefined;
1078
+ prebindingDefinitions?: {
1079
+ id: string;
1080
+ parameterDefinitions: Record<string, {
1081
+ contentTypes: string[];
1082
+ defaultSource?: {
1083
+ type: "Entry";
1084
+ contentTypeId: string;
1085
+ link: {
1086
+ sys: {
1087
+ type: "Link";
1088
+ id: string;
1089
+ linkType: "Entry";
1090
+ };
1091
+ };
1092
+ } | undefined;
1093
+ passToNodes?: {
1094
+ prebindingId: string;
1095
+ parameterId: string;
1096
+ nodeId: string;
1097
+ }[] | undefined;
1098
+ }>;
1099
+ variableMappings?: Record<string, {
1100
+ type: "ContentTypeMapping";
1101
+ parameterId: string;
1102
+ pathsByContentType: Record<string, {
1103
+ path: string;
1104
+ }>;
1105
+ }> | undefined;
1106
+ allowedVariableOverrides?: string[] | undefined;
1107
+ }[] | undefined;
1108
+ }, {
1109
+ variableDefinitions: Record<string, {
1110
+ type: "Text" | "RichText" | "Number" | "Date" | "Boolean" | "Location" | "Media" | "Object" | "Hyperlink" | "Array" | "Link";
1111
+ displayName?: string | undefined;
1112
+ description?: string | undefined;
1113
+ group?: string | undefined;
1114
+ defaultValue?: string | number | boolean | Record<any, any> | {
1115
+ type: "DesignValue";
1116
+ valuesByBreakpoint: Record<string, string | number | boolean | Record<any, any> | undefined>;
1117
+ } | {
1118
+ path: string;
1119
+ type: "BoundValue";
1120
+ } | {
1121
+ type: "HyperlinkValue";
1122
+ linkTargetKey: string;
1123
+ overrides?: {} | undefined;
1124
+ } | {
1125
+ type: "UnboundValue";
1126
+ key: string;
1127
+ } | {
1128
+ type: "ComponentValue";
1129
+ key: string;
1130
+ } | {
1131
+ type: "NoValue";
1132
+ } | undefined;
1133
+ validations?: {
1134
+ required?: boolean | undefined;
1135
+ bindingSourceType?: ["entry" | "asset" | "manual" | "experience", ...("entry" | "asset" | "manual" | "experience")[]] | undefined;
1136
+ format?: "URL" | undefined;
1137
+ in?: {
1138
+ value: string | number;
1139
+ displayName?: string | undefined;
1140
+ }[] | undefined;
1141
+ } | undefined;
1142
+ }>;
1143
+ thumbnailId?: "columns" | "columnsPlusRight" | "imagesSquare" | "subtitles" | "rowsPlusBottom" | "userRectangle" | "textbox" | "monitorPlay" | "article" | "table" | "star" | "heartStraight" | "frameCorners" | "rows" | "dotsThreeOutline" | "listDashes" | "checkerBoard" | "gridFour" | "slideshow" | "diamondsFour" | "cards" | "textColumns" | "duplex" | undefined;
1144
+ category?: string | undefined;
1145
+ prebindingDefinitions?: {
1146
+ id: string;
1147
+ parameterDefinitions: Record<string, {
1148
+ contentTypes: string[];
1149
+ defaultSource?: {
1150
+ type: "Entry";
1151
+ contentTypeId: string;
1152
+ link: {
1153
+ sys: {
1154
+ type: "Link";
1155
+ id: string;
1156
+ linkType: "Entry";
1157
+ };
1158
+ };
1159
+ } | undefined;
1160
+ passToNodes?: {
1161
+ prebindingId: string;
1162
+ parameterId: string;
1163
+ nodeId: string;
1164
+ }[] | undefined;
1165
+ }>;
1166
+ variableMappings?: Record<string, {
1167
+ type: "ContentTypeMapping";
1168
+ parameterId: string;
1169
+ pathsByContentType: Record<string, {
1170
+ path: string;
1171
+ }>;
1172
+ }> | undefined;
1173
+ allowedVariableOverrides?: string[] | undefined;
1174
+ }[] | undefined;
1033
1175
  }>;
1034
- declare const PatternFieldsCMAShapeSchema: z.ZodObject<{
1176
+ declare const PatternFieldsCMAShapeSchema: z.ZodEffects<z.ZodObject<{
1035
1177
  componentTree: z.ZodRecord<z.ZodString, z.ZodTypeAny>;
1036
1178
  dataSource: z.ZodRecord<z.ZodString, z.ZodTypeAny>;
1037
1179
  unboundValues: z.ZodRecord<z.ZodString, z.ZodTypeAny>;
@@ -1049,6 +1191,18 @@ declare const PatternFieldsCMAShapeSchema: z.ZodObject<{
1049
1191
  unboundValues: Record<string, any>;
1050
1192
  componentSettings: Record<string, any>;
1051
1193
  usedComponents?: Record<string, any> | undefined;
1194
+ }>, {
1195
+ componentTree: Record<string, any>;
1196
+ dataSource: Record<string, any>;
1197
+ unboundValues: Record<string, any>;
1198
+ componentSettings: Record<string, any>;
1199
+ usedComponents?: Record<string, any> | undefined;
1200
+ }, {
1201
+ componentTree: Record<string, any>;
1202
+ dataSource: Record<string, any>;
1203
+ unboundValues: Record<string, any>;
1204
+ componentSettings: Record<string, any>;
1205
+ usedComponents?: Record<string, any> | undefined;
1052
1206
  }>;
1053
1207
  type PatternFields = z.infer<typeof PatternFieldsCMAShapeSchema>;
1054
1208
  type ParameterDefinition = z.infer<typeof ParameterDefinitionSchema>;
package/dist/index.js CHANGED
@@ -247,6 +247,25 @@ const ExperienceFieldsCMAShapeSchema = z.object({
247
247
  usedComponents: localeWrapper(UsedComponentsSchema).optional(),
248
248
  });
249
249
 
250
+ function treeVisit(initialNode, onNode) {
251
+ const _treeVisit = (currentNode) => {
252
+ const children = [...currentNode.children];
253
+ onNode(currentNode);
254
+ for (const child of children) {
255
+ _treeVisit(child);
256
+ }
257
+ };
258
+ if (Array.isArray(initialNode)) {
259
+ for (const node of initialNode) {
260
+ _treeVisit(node);
261
+ }
262
+ }
263
+ else {
264
+ _treeVisit(initialNode);
265
+ }
266
+ }
267
+
268
+ const MAX_ALLOWED_PATHS = 200;
250
269
  const THUMBNAIL_IDS = [
251
270
  'columns',
252
271
  'columnsPlusRight',
@@ -277,7 +296,17 @@ const THUMBNAIL_IDS = [
277
296
  const VariableMappingSchema = z.object({
278
297
  parameterId: propertyKeySchema,
279
298
  type: z.literal('ContentTypeMapping'),
280
- pathsByContentType: z.record(z.string(), z.object({ path: z.string() })),
299
+ pathsByContentType: z
300
+ .record(z.string(), z.object({ path: z.string() }))
301
+ .superRefine((paths, ctx) => {
302
+ const variableId = ctx.path[ctx.path.length - 2];
303
+ if (Object.keys(paths).length > MAX_ALLOWED_PATHS) {
304
+ ctx.addIssue({
305
+ code: z.ZodIssueCode.custom,
306
+ message: `Too many paths defined for variable mapping with id "${variableId}", maximum allowed is ${MAX_ALLOWED_PATHS}`,
307
+ });
308
+ }
309
+ }),
281
310
  });
282
311
  const PassToNodeSchema = z
283
312
  .object({
@@ -301,7 +330,10 @@ const ParameterDefinitionSchema = z.object({
301
330
  })
302
331
  .optional(),
303
332
  contentTypes: z.array(z.string()).min(1),
304
- passToNodes: z.array(PassToNodeSchema).optional(),
333
+ passToNodes: z
334
+ .array(PassToNodeSchema)
335
+ .max(1, 'At most one "passToNodes" element is allowed per parameter definition.')
336
+ .optional(), // we might change this to be empty array for native parameter definitions, that's why we don't use .length(1)
305
337
  });
306
338
  const ParameterDefinitionsSchema = z.record(propertyKeySchema, ParameterDefinitionSchema);
307
339
  const VariableMappingsSchema = z.record(propertyKeySchema, VariableMappingSchema);
@@ -322,14 +354,108 @@ const ComponentSettingsSchema = z
322
354
  category: z.string().max(50, 'Category must contain at most 50 characters').optional(),
323
355
  prebindingDefinitions: z.array(PrebindingDefinitionSchema).length(1).optional(),
324
356
  })
325
- .strict();
326
- const PatternFieldsCMAShapeSchema = z.object({
357
+ .strict()
358
+ .superRefine((componentSettings, ctx) => {
359
+ const { variableDefinitions, prebindingDefinitions } = componentSettings;
360
+ if (!prebindingDefinitions || prebindingDefinitions.length === 0) {
361
+ return;
362
+ }
363
+ const { parameterDefinitions, variableMappings, allowedVariableOverrides } = prebindingDefinitions[0];
364
+ validateAtMostOneNativeParameterDefinition(parameterDefinitions, ctx);
365
+ validateNoOverlapBetweenMappingAndOverrides(variableMappings, allowedVariableOverrides, ctx);
366
+ validateMappingsAgainstVariableDefinitions(variableMappings, allowedVariableOverrides, variableDefinitions, ctx);
367
+ validateMappingsAgainstParameterDefinitions(variableMappings, parameterDefinitions, ctx);
368
+ });
369
+ const PatternFieldsCMAShapeSchema = z
370
+ .object({
327
371
  componentTree: localeWrapper(ComponentTreeSchema),
328
372
  dataSource: localeWrapper(DataSourceSchema),
329
373
  unboundValues: localeWrapper(UnboundValuesSchema),
330
374
  usedComponents: localeWrapper(UsedComponentsSchema).optional(),
331
375
  componentSettings: localeWrapper(ComponentSettingsSchema),
376
+ })
377
+ .superRefine((patternFields, ctx) => {
378
+ const { componentTree, componentSettings } = patternFields;
379
+ // values at this point are wrapped under locale code
380
+ const nonLocalisedComponentTree = Object.values(componentTree)[0];
381
+ const nonLocalisedComponentSettings = Object.values(componentSettings)[0];
382
+ if (!nonLocalisedComponentSettings || !nonLocalisedComponentTree) {
383
+ return;
384
+ }
385
+ validatePassToNodes(nonLocalisedComponentTree.children || [], nonLocalisedComponentSettings || {}, ctx);
332
386
  });
387
+ const validateAtMostOneNativeParameterDefinition = (parameterDefinitions, ctx) => {
388
+ const nativeParamDefinitions = Object.values(parameterDefinitions).filter((paramDefinition) => !(paramDefinition.passToNodes && paramDefinition.passToNodes.length > 0));
389
+ if (nativeParamDefinitions.length > 1) {
390
+ ctx.addIssue({
391
+ code: z.ZodIssueCode.custom,
392
+ message: `Only one native parameter definition (parameter definition without passToNodes) is allowed per prebinding definition.`,
393
+ });
394
+ }
395
+ };
396
+ const validateNoOverlapBetweenMappingAndOverrides = (variableMappings, allowedVariableOverrides, ctx) => {
397
+ const variableMappingKeys = Object.keys(variableMappings || {});
398
+ const overridesSet = new Set(allowedVariableOverrides || []);
399
+ const overlap = variableMappingKeys.filter((key) => overridesSet.has(key));
400
+ if (overlap.length > 0) {
401
+ ctx.addIssue({
402
+ code: z.ZodIssueCode.custom,
403
+ message: `Found both variable mapping and allowed override for the following keys: ${overlap.map((key) => `"${key}"`).join(', ')}.`,
404
+ });
405
+ }
406
+ };
407
+ const validateMappingsAgainstVariableDefinitions = (variableMappings, allowedVariableOverrides, variableDefinitions, ctx) => {
408
+ const nonDesignVariableDefinitionKeys = Object.entries(variableDefinitions)
409
+ .filter(([_, def]) => def.group !== 'style')
410
+ .map(([key]) => key);
411
+ const variableMappingKeys = Object.keys(variableMappings || {});
412
+ const allKeys = [...variableMappingKeys, ...(allowedVariableOverrides || [])];
413
+ const invalidMappings = allKeys.filter((key) => !nonDesignVariableDefinitionKeys.includes(key));
414
+ if (invalidMappings.length > 0) {
415
+ ctx.addIssue({
416
+ code: z.ZodIssueCode.custom,
417
+ message: `The following variable mappings or overrides are missing from the variable definitions: ${invalidMappings.map((key) => `"${key}"`).join(', ')}.`,
418
+ });
419
+ }
420
+ };
421
+ const validateMappingsAgainstParameterDefinitions = (variableMappings, parameterDefinitions, ctx) => {
422
+ const parameterDefinitionKeys = Object.keys(parameterDefinitions || {});
423
+ for (const [mappingKey, mappingValue] of Object.entries(variableMappings || {})) {
424
+ if (!parameterDefinitionKeys.includes(mappingValue.parameterId)) {
425
+ ctx.addIssue({
426
+ code: z.ZodIssueCode.custom,
427
+ message: `The variable mapping with id "${mappingKey}" references a non-existing parameterId "${mappingValue.parameterId}".`,
428
+ });
429
+ }
430
+ }
431
+ };
432
+ const validatePassToNodes = (rootChildren, componentSettings, ctx) => {
433
+ if (!componentSettings.prebindingDefinitions ||
434
+ componentSettings.prebindingDefinitions.length === 0) {
435
+ return;
436
+ }
437
+ const { parameterDefinitions } = componentSettings.prebindingDefinitions[0];
438
+ let nodeIds = new Set();
439
+ for (const paramDef of Object.values(parameterDefinitions || {})) {
440
+ paramDef.passToNodes?.forEach((n) => nodeIds.add(n.nodeId));
441
+ }
442
+ treeVisit(rootChildren, (node) => {
443
+ if (!node.id)
444
+ return;
445
+ if (nodeIds.has(node.id)) {
446
+ nodeIds.delete(node.id);
447
+ }
448
+ });
449
+ if (nodeIds.size > 0) {
450
+ const stringifiedNodeIds = Array.from(nodeIds)
451
+ .map((id) => `"${id}"`)
452
+ .join(', ');
453
+ ctx.addIssue({
454
+ code: z.ZodIssueCode.custom,
455
+ message: `The following node IDs referenced in passToNodes are not present in the component tree: ${stringifiedNodeIds}.`,
456
+ });
457
+ }
458
+ };
333
459
 
334
460
  const ComponentDefinitionSchema = z
335
461
  .object({