@contentful/experiences-components-react 3.7.0-prerelease-20250917T1034-42f0486.0 → 3.7.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.js CHANGED
@@ -3,7 +3,7 @@ import React, { forwardRef } from 'react';
3
3
  import { documentToReactComponents } from '@contentful/rich-text-react-renderer';
4
4
  import { BLOCKS } from '@contentful/rich-text-types';
5
5
  import { z } from 'zod';
6
- import { cloneDeep } from 'lodash-es';
6
+ import cloneDeep from 'lodash.clonedeep';
7
7
  import 'md5';
8
8
  import { create } from 'zustand';
9
9
 
@@ -1339,7 +1339,7 @@ const BreakpointSchema = z
1339
1339
  id: propertyKeySchema,
1340
1340
  // Can be replace with z.templateLiteral when upgrading to zod v4
1341
1341
  query: z.string().refine((s) => BREAKPOINT_QUERY_REGEX.test(s)),
1342
- previewSize: z.string(),
1342
+ previewSize: z.string().optional(),
1343
1343
  displayName: z.string(),
1344
1344
  displayIcon: z.enum(['desktop', 'tablet', 'mobile']).optional(),
1345
1345
  })
@@ -1376,19 +1376,6 @@ const ComponentVariableSchema = z.object({
1376
1376
  });
1377
1377
  const ComponentTreeNodeSchema = BaseComponentTreeNodeSchema.extend({
1378
1378
  children: z.lazy(() => ComponentTreeNodeSchema.array()),
1379
- }).superRefine(({ id, prebindingId, parameters }, ctx) => {
1380
- if (prebindingId && !parameters) {
1381
- ctx.addIssue({
1382
- code: z.ZodIssueCode.custom,
1383
- message: `Found "prebindingId" but no "parameters" for node with id: "${id}"`,
1384
- });
1385
- }
1386
- if (parameters && !prebindingId) {
1387
- ctx.addIssue({
1388
- code: z.ZodIssueCode.custom,
1389
- message: `Found "parameters" but no "prebindingId" for node with id: "${id}"`,
1390
- });
1391
- }
1392
1379
  });
1393
1380
  const ComponentTreeSchema = z
1394
1381
  .object({
@@ -1406,6 +1393,25 @@ z.object({
1406
1393
  usedComponents: localeWrapper(UsedComponentsSchema).optional(),
1407
1394
  });
1408
1395
 
1396
+ function treeVisit$1(initialNode, onNode) {
1397
+ const _treeVisit = (currentNode) => {
1398
+ const children = [...currentNode.children];
1399
+ onNode(currentNode);
1400
+ for (const child of children) {
1401
+ _treeVisit(child);
1402
+ }
1403
+ };
1404
+ if (Array.isArray(initialNode)) {
1405
+ for (const node of initialNode) {
1406
+ _treeVisit(node);
1407
+ }
1408
+ }
1409
+ else {
1410
+ _treeVisit(initialNode);
1411
+ }
1412
+ }
1413
+
1414
+ const MAX_ALLOWED_PATHS = 200;
1409
1415
  const THUMBNAIL_IDS = [
1410
1416
  'columns',
1411
1417
  'columnsPlusRight',
@@ -1436,7 +1442,17 @@ const THUMBNAIL_IDS = [
1436
1442
  const VariableMappingSchema = z.object({
1437
1443
  parameterId: propertyKeySchema,
1438
1444
  type: z.literal('ContentTypeMapping'),
1439
- pathsByContentType: z.record(z.string(), z.object({ path: z.string() })),
1445
+ pathsByContentType: z
1446
+ .record(z.string(), z.object({ path: z.string() }))
1447
+ .superRefine((paths, ctx) => {
1448
+ const variableId = ctx.path[ctx.path.length - 2];
1449
+ if (Object.keys(paths).length > MAX_ALLOWED_PATHS) {
1450
+ ctx.addIssue({
1451
+ code: z.ZodIssueCode.custom,
1452
+ message: `Too many paths defined for variable mapping with id "${variableId}", maximum allowed is ${MAX_ALLOWED_PATHS}`,
1453
+ });
1454
+ }
1455
+ }),
1440
1456
  });
1441
1457
  const PassToNodeSchema = z
1442
1458
  .object({
@@ -1460,7 +1476,10 @@ const ParameterDefinitionSchema = z.object({
1460
1476
  })
1461
1477
  .optional(),
1462
1478
  contentTypes: z.array(z.string()).min(1),
1463
- passToNodes: z.array(PassToNodeSchema).optional(),
1479
+ passToNodes: z
1480
+ .array(PassToNodeSchema)
1481
+ .max(1, 'At most one "passToNodes" element is allowed per parameter definition.')
1482
+ .optional(), // we might change this to be empty array for native parameter definitions, that's why we don't use .length(1)
1464
1483
  });
1465
1484
  const ParameterDefinitionsSchema = z.record(propertyKeySchema, ParameterDefinitionSchema);
1466
1485
  const VariableMappingsSchema = z.record(propertyKeySchema, VariableMappingSchema);
@@ -1481,14 +1500,108 @@ const ComponentSettingsSchema = z
1481
1500
  category: z.string().max(50, 'Category must contain at most 50 characters').optional(),
1482
1501
  prebindingDefinitions: z.array(PrebindingDefinitionSchema).length(1).optional(),
1483
1502
  })
1484
- .strict();
1485
- z.object({
1503
+ .strict()
1504
+ .superRefine((componentSettings, ctx) => {
1505
+ const { variableDefinitions, prebindingDefinitions } = componentSettings;
1506
+ if (!prebindingDefinitions || prebindingDefinitions.length === 0) {
1507
+ return;
1508
+ }
1509
+ const { parameterDefinitions, variableMappings, allowedVariableOverrides } = prebindingDefinitions[0];
1510
+ validateAtMostOneNativeParameterDefinition(parameterDefinitions, ctx);
1511
+ validateNoOverlapBetweenMappingAndOverrides(variableMappings, allowedVariableOverrides, ctx);
1512
+ validateMappingsAgainstVariableDefinitions(variableMappings, allowedVariableOverrides, variableDefinitions, ctx);
1513
+ validateMappingsAgainstParameterDefinitions(variableMappings, parameterDefinitions, ctx);
1514
+ });
1515
+ z
1516
+ .object({
1486
1517
  componentTree: localeWrapper(ComponentTreeSchema),
1487
1518
  dataSource: localeWrapper(DataSourceSchema),
1488
1519
  unboundValues: localeWrapper(UnboundValuesSchema),
1489
1520
  usedComponents: localeWrapper(UsedComponentsSchema).optional(),
1490
1521
  componentSettings: localeWrapper(ComponentSettingsSchema),
1522
+ })
1523
+ .superRefine((patternFields, ctx) => {
1524
+ const { componentTree, componentSettings } = patternFields;
1525
+ // values at this point are wrapped under locale code
1526
+ const nonLocalisedComponentTree = Object.values(componentTree)[0];
1527
+ const nonLocalisedComponentSettings = Object.values(componentSettings)[0];
1528
+ if (!nonLocalisedComponentSettings || !nonLocalisedComponentTree) {
1529
+ return;
1530
+ }
1531
+ validatePassToNodes(nonLocalisedComponentTree.children || [], nonLocalisedComponentSettings || {}, ctx);
1491
1532
  });
1533
+ const validateAtMostOneNativeParameterDefinition = (parameterDefinitions, ctx) => {
1534
+ const nativeParamDefinitions = Object.values(parameterDefinitions).filter((paramDefinition) => !(paramDefinition.passToNodes && paramDefinition.passToNodes.length > 0));
1535
+ if (nativeParamDefinitions.length > 1) {
1536
+ ctx.addIssue({
1537
+ code: z.ZodIssueCode.custom,
1538
+ message: `Only one native parameter definition (parameter definition without passToNodes) is allowed per prebinding definition.`,
1539
+ });
1540
+ }
1541
+ };
1542
+ const validateNoOverlapBetweenMappingAndOverrides = (variableMappings, allowedVariableOverrides, ctx) => {
1543
+ const variableMappingKeys = Object.keys(variableMappings || {});
1544
+ const overridesSet = new Set(allowedVariableOverrides || []);
1545
+ const overlap = variableMappingKeys.filter((key) => overridesSet.has(key));
1546
+ if (overlap.length > 0) {
1547
+ ctx.addIssue({
1548
+ code: z.ZodIssueCode.custom,
1549
+ message: `Found both variable mapping and allowed override for the following keys: ${overlap.map((key) => `"${key}"`).join(', ')}.`,
1550
+ });
1551
+ }
1552
+ };
1553
+ const validateMappingsAgainstVariableDefinitions = (variableMappings, allowedVariableOverrides, variableDefinitions, ctx) => {
1554
+ const nonDesignVariableDefinitionKeys = Object.entries(variableDefinitions)
1555
+ .filter(([_, def]) => def.group !== 'style')
1556
+ .map(([key]) => key);
1557
+ const variableMappingKeys = Object.keys(variableMappings || {});
1558
+ const allKeys = [...variableMappingKeys, ...(allowedVariableOverrides || [])];
1559
+ const invalidMappings = allKeys.filter((key) => !nonDesignVariableDefinitionKeys.includes(key));
1560
+ if (invalidMappings.length > 0) {
1561
+ ctx.addIssue({
1562
+ code: z.ZodIssueCode.custom,
1563
+ message: `The following variable mappings or overrides are missing from the variable definitions: ${invalidMappings.map((key) => `"${key}"`).join(', ')}.`,
1564
+ });
1565
+ }
1566
+ };
1567
+ const validateMappingsAgainstParameterDefinitions = (variableMappings, parameterDefinitions, ctx) => {
1568
+ const parameterDefinitionKeys = Object.keys(parameterDefinitions || {});
1569
+ for (const [mappingKey, mappingValue] of Object.entries(variableMappings || {})) {
1570
+ if (!parameterDefinitionKeys.includes(mappingValue.parameterId)) {
1571
+ ctx.addIssue({
1572
+ code: z.ZodIssueCode.custom,
1573
+ message: `The variable mapping with id "${mappingKey}" references a non-existing parameterId "${mappingValue.parameterId}".`,
1574
+ });
1575
+ }
1576
+ }
1577
+ };
1578
+ const validatePassToNodes = (rootChildren, componentSettings, ctx) => {
1579
+ if (!componentSettings.prebindingDefinitions ||
1580
+ componentSettings.prebindingDefinitions.length === 0) {
1581
+ return;
1582
+ }
1583
+ const { parameterDefinitions } = componentSettings.prebindingDefinitions[0];
1584
+ let nodeIds = new Set();
1585
+ for (const paramDef of Object.values(parameterDefinitions || {})) {
1586
+ paramDef.passToNodes?.forEach((n) => nodeIds.add(n.nodeId));
1587
+ }
1588
+ treeVisit$1(rootChildren, (node) => {
1589
+ if (!node.id)
1590
+ return;
1591
+ if (nodeIds.has(node.id)) {
1592
+ nodeIds.delete(node.id);
1593
+ }
1594
+ });
1595
+ if (nodeIds.size > 0) {
1596
+ const stringifiedNodeIds = Array.from(nodeIds)
1597
+ .map((id) => `"${id}"`)
1598
+ .join(', ');
1599
+ ctx.addIssue({
1600
+ code: z.ZodIssueCode.custom,
1601
+ message: `The following node IDs referenced in passToNodes are not present in the component tree: ${stringifiedNodeIds}.`,
1602
+ });
1603
+ }
1604
+ };
1492
1605
 
1493
1606
  z
1494
1607
  .object({