diff --git a/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap b/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap index cdc5c8f45..f09e443f3 100644 --- a/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap +++ b/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap @@ -5454,17 +5454,19 @@ export default function CustomButton( exports[`amplify render tests custom components alias parent should render declarations 1`] = ` "import * as React from \\"react\\"; import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\"; -import { CustomButtonProps } from \\"./CustomButton\\"; +import { GridProps } from \\"./Grid\\"; +import { ButtonProps } from \\"@aws-amplify/ui-react\\"; import { ViewTestProps } from \\"./ViewTest\\"; export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes; -export declare type CustomParentAndChildrenOverridesProps = { - CustomParentAndChildren?: ViewTestProps; - MyCustomButton?: CustomButtonProps; +export declare type AliasParentOverridesProps = { + AliasParent?: ViewTestProps; + Grid?: GridProps; + Button?: PrimitiveOverrideProps; } & EscapeHatchProps; -export declare type CustomParentAndChildrenProps = React.PropsWithChildren & { - overrides?: CustomParentAndChildrenOverridesProps | undefined | null; +export declare type AliasParentProps = React.PropsWithChildren & { + overrides?: AliasParentOverridesProps | undefined | null; }>; -export default function CustomParentAndChildren(props: CustomParentAndChildrenProps): React.ReactElement; +export default function AliasParent(props: AliasParentProps): React.ReactElement; " `; @@ -5475,15 +5477,16 @@ import { EscapeHatchProps, getOverrideProps, } from \\"@aws-amplify/ui-react/internal\\"; -import { GridCustom } from \\"./Grid\\"; +import { Grid as GridCustom, GridProps } from \\"./Grid\\"; +import { Button, ButtonProps } from \\"@aws-amplify/ui-react\\"; import ViewTest, { ViewTestProps } from \\"./ViewTest\\"; -import { GridCustomProps } from \\"./GridCustom\\"; export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes; export declare type AliasParentOverridesProps = { AliasParent?: ViewTestProps; - Grid?: GridCustomProps; + Grid?: GridProps; + Button?: PrimitiveOverrideProps; } & EscapeHatchProps; export type AliasParentProps = React.PropsWithChildren< Partial & { @@ -5498,6 +5501,7 @@ export default function AliasParent( /* @ts-ignore: TS2322 */ + ); } diff --git a/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts b/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts index 1dbeeb367..c19d2b2e2 100644 --- a/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts +++ b/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts @@ -548,7 +548,7 @@ describe('amplify render tests', () => { it('should render declarations', () => { expect( - generateWithAmplifyRenderer('custom/customParentAndChildren', { + generateWithAmplifyRenderer('custom/aliasParent', { script: ScriptKind.JS, renderTypeDeclarations: true, }).declaration, diff --git a/packages/codegen-ui-react/lib/amplify-ui-renderers/customComponent.ts b/packages/codegen-ui-react/lib/amplify-ui-renderers/customComponent.ts index 77579febb..3a446d33e 100644 --- a/packages/codegen-ui-react/lib/amplify-ui-renderers/customComponent.ts +++ b/packages/codegen-ui-react/lib/amplify-ui-renderers/customComponent.ts @@ -15,7 +15,7 @@ */ import { StudioComponentChild } from '@aws-amplify/codegen-ui'; import { JsxChild, JsxElement, factory } from 'typescript'; -import { Primitive } from '../primitive'; +import { isAliased } from '../helpers'; import { ReactComponentRenderer } from '../react-component-renderer'; export default class CustomComponentRenderer extends ReactComponentRenderer { @@ -27,8 +27,11 @@ export default class CustomComponentRenderer extends ReactComponentRend factory.createJsxClosingElement(factory.createIdentifier(this.component.componentType)), ); - if (Object.keys(Primitive).includes(this.component.name) && this.component.componentType.match(/(Custom$)/g)) { - this.importCollection.addImport(`./${this.component.name}`, this.component.componentType); + if (isAliased(this.component.componentType)) { + this.importCollection.addImport( + `./${this.component.name}`, + `${this.component.name} as ${this.component.componentType}`, + ); } else { this.importCollection.addImport(`./${this.component.componentType}`, 'default'); } diff --git a/packages/codegen-ui-react/lib/helpers/index.ts b/packages/codegen-ui-react/lib/helpers/index.ts index d0abfb450..0a8bc7b98 100644 --- a/packages/codegen-ui-react/lib/helpers/index.ts +++ b/packages/codegen-ui-react/lib/helpers/index.ts @@ -15,6 +15,7 @@ */ import { GenericDataField, GenericDataSchema } from '@aws-amplify/codegen-ui/lib/types'; import { factory, Statement, Expression, NodeFlags, Identifier } from 'typescript'; +import { isPrimitive } from '../primitive'; export const lowerCaseFirst = (input: string) => input.charAt(0).toLowerCase() + input.slice(1); @@ -104,3 +105,11 @@ export function modelNeedsRelationshipsLoadedForCollection(modelName: string, da ) ); } + +export function isAliased(componentType: string): boolean { + return !!(isPrimitive(removeAlias(componentType)) && componentType.match(/(Custom$)/g)); +} + +export function removeAlias(aliasString: string): string { + return aliasString.replace(/(Custom$)/g, ''); +} diff --git a/packages/codegen-ui-react/lib/react-studio-template-renderer.ts b/packages/codegen-ui-react/lib/react-studio-template-renderer.ts index 5ea154cd9..2bb3281d5 100644 --- a/packages/codegen-ui-react/lib/react-studio-template-renderer.ts +++ b/packages/codegen-ui-react/lib/react-studio-template-renderer.ts @@ -103,6 +103,8 @@ import { buildUseStateExpression, modelNeedsRelationshipsLoadedForCollection, fieldNeedsRelationshipLoadedForCollection, + isAliased, + removeAlias, } from './helpers'; export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer< @@ -355,9 +357,10 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer factory.createTypeLiteralNode( Object.entries(this.componentMetadata.componentNameToTypeMap).map(([name, componentType]) => { const isComponentTypePrimitive = isPrimitive(componentType); - const componentTypePropName = `${componentType}Props`; + const componentName = isAliased(componentType) ? removeAlias(componentType) : componentType; + const componentTypePropName = `${componentName}Props`; this.importCollection.addImport( - isComponentTypePrimitive ? ImportSource.UI_REACT : `./${componentType}`, + isComponentTypePrimitive ? ImportSource.UI_REACT : `./${componentName}`, componentTypePropName, ); return factory.createPropertySignature( diff --git a/packages/codegen-ui/example-schemas/custom/aliasParent.json b/packages/codegen-ui/example-schemas/custom/aliasParent.json index dc75c398f..2c9a13cb8 100644 --- a/packages/codegen-ui/example-schemas/custom/aliasParent.json +++ b/packages/codegen-ui/example-schemas/custom/aliasParent.json @@ -5,6 +5,11 @@ "name": "Grid", "componentType": "GridCustom", "properties": {} + }, + { + "name": "Button", + "componentType": "Button", + "properties": {} } ], "properties": {}, diff --git a/packages/codegen-ui/lib/__tests__/__snapshots__/validation-helper.test.ts.snap b/packages/codegen-ui/lib/__tests__/__snapshots__/validation-helper.test.ts.snap index cc36f4a3b..a07e9fce2 100644 --- a/packages/codegen-ui/lib/__tests__/__snapshots__/validation-helper.test.ts.snap +++ b/packages/codegen-ui/lib/__tests__/__snapshots__/validation-helper.test.ts.snap @@ -14,10 +14,12 @@ exports[`validation-helper validateComponentSchema fails on componentType with l exports[`validation-helper validateComponentSchema fails on componentType with whitespace 1`] = `"Expected an alphanumeric string, starting with a character"`; -exports[`validation-helper validateComponentSchema throws on all components sharing a name 1`] = `"Duplicate names are not allowed within a component, found duplicates of [\\"DeepComp\\",\\"MyComp\\"]"`; +exports[`validation-helper validateComponentSchema throws on child components sharing a name 1`] = `"Duplicate names are not allowed within a component, found duplicates of [\\"ChildComponent\\"]"`; exports[`validation-helper validateComponentSchema throws on invalid schema version 1`] = `"unsupported schemaVersion 1.1.4"`; +exports[`validation-helper validateComponentSchema throws on parent and child components sharing a name 1`] = `"Duplicate names are not allowed within a component, found duplicates of [\\"MyComp\\"]"`; + exports[`validation-helper validateComponentSchema throws on unsupported schema version 1`] = `"unsupported schemaVersion 1.1"`; exports[`validation-helper validateComponentSchema top-level component requires componentType 1`] = `"componentType is a required field"`; diff --git a/packages/codegen-ui/lib/__tests__/validation-helper.test.ts b/packages/codegen-ui/lib/__tests__/validation-helper.test.ts index 2b3975bd6..c48c29e91 100644 --- a/packages/codegen-ui/lib/__tests__/validation-helper.test.ts +++ b/packages/codegen-ui/lib/__tests__/validation-helper.test.ts @@ -289,7 +289,7 @@ describe('validation-helper', () => { }).toThrowErrorMatchingSnapshot(); }); - test('throws on all components sharing a name', () => { + test('throws on parent and child components sharing a name', () => { expect(() => { validateComponentSchema({ name: 'MyComp', @@ -308,7 +308,7 @@ describe('validation-helper', () => { properties: {}, children: [ { - name: 'DeepComp', + name: 'DeepCompChild', componentType: 'Tooltip', properties: {}, }, @@ -324,6 +324,29 @@ describe('validation-helper', () => { }).toThrowErrorMatchingSnapshot(); }); + test('throws on child components sharing a name', () => { + expect(() => { + validateComponentSchema({ + name: 'MyComp', + componentType: 'Flex', + properties: {}, + schemaVersion: '1.0', + children: [ + { + name: 'ChildComponent', + componentType: 'Button', + properties: {}, + }, + { + name: 'ChildComponent', + componentType: 'View', + properties: {}, + }, + ], + }); + }).toThrowErrorMatchingSnapshot(); + }); + test('throws on unsupported schema version', () => { expect(() => { validateComponentSchema({