diff --git a/packages/core/src/design-jsx/component-properties.ts b/packages/core/src/design-jsx/component-properties.ts index 905395a8f..779f7a3db 100644 --- a/packages/core/src/design-jsx/component-properties.ts +++ b/packages/core/src/design-jsx/component-properties.ts @@ -34,6 +34,11 @@ export function componentMetadata( const definitions = v.parse(v.array(definitionSchema), props.properties) if (new Set(definitions.map((definition) => definition.id)).size !== definitions.length) throw new Error('Duplicate component property IDs') + const variantNames = definitions + .filter((item) => item.type === 'VARIANT') + .map((item) => item.name) + if (new Set(variantNames).size !== variantNames.length) + throw new Error('Duplicate variant property names') result.componentPropertyDefinitions = definitions } if (props.propertyRefs !== undefined) { diff --git a/tests/engine/render/jsx/component/properties.test.ts b/tests/engine/render/jsx/component/properties.test.ts index 172e2f2a4..ef5bf1d01 100644 --- a/tests/engine/render/jsx/component/properties.test.ts +++ b/tests/engine/render/jsx/component/properties.test.ts @@ -174,4 +174,28 @@ test('validates metadata rather than accepting silent malformed property definit await expect(renderTree(graph, Component({ properties: [MESSAGE, MESSAGE] }))).rejects.toThrow( 'Duplicate' ) + for (const element of [Component, ComponentSet]) { + await expect( + renderTree( + graph, + element({ + properties: [ + { id: 'kind-a', name: 'Kind', type: 'VARIANT', defaultValue: 'A' }, + { id: 'kind-b', name: 'Kind', type: 'VARIANT', defaultValue: 'B' } + ] + }) + ) + ).rejects.toThrow('Duplicate variant property names') + } +}) + +test('preserves duplicate display names for non-variant properties with distinct IDs', async () => { + const graph = makeSceneGraph() + const result = await renderTree( + graph, + Component({ properties: [MESSAGE, { ...MESSAGE, id: 'other-message' }] }) + ) + expect( + getNodeOrThrow(graph, result.id).componentPropertyDefinitions.map((item) => item.id) + ).toEqual(['message', 'other-message']) })