From 24c9eacb4d4ba449ceb2bab176333f0c00d5e047 Mon Sep 17 00:00:00 2001 From: Alexander Harris Date: Wed, 23 Feb 2022 08:36:27 -0800 Subject: [PATCH] fix: support mutation targets with invalid js names --- .../studio-ui-codegen-react.test.ts.snap | 253 ++++++++++++++++++ .../__tests__/studio-ui-codegen-react.test.ts | 13 + .../lib/react-component-render-helper.ts | 9 +- .../codegen-ui-react/lib/workflow/action.ts | 8 +- .../mutationWithUnsanitizedTarget.json | 213 +++++++++++++++ scripts/integ-setup.sh | 2 +- 6 files changed, 489 insertions(+), 9 deletions(-) create mode 100644 packages/codegen-ui/example-schemas/workflow/mutationWithUnsanitizedTarget.json 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 89469d297..1c56d47cc 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 @@ -5731,6 +5731,259 @@ export default function SwitchControlledElement( } `; +exports[`amplify render tests mutations supports invalid statement names for mutation targets 1`] = ` +Object { + "componentText": "/* eslint-disable */ +import React from \\"react\\"; +import { + EscapeHatchProps, + getOverrideProps, + useStateMutationAction, +} from \\"@aws-amplify/ui-react/internal\\"; +import { Listing } from \\"../models\\"; +import { Flex, FlexProps, Image, Text } from \\"@aws-amplify/ui-react\\"; + +export type CardAProps = React.PropsWithChildren< + Partial & { + listing?: Listing; + } & { + overrides?: EscapeHatchProps | undefined | null; + } +>; +export default function CardA(props: CardAProps): React.ReactElement { + const { listing, overrides, ...rest } = props; + const [classicLongSleeveTShirtChildren, setClassicLongSleeveTShirtChildren] = + useStateMutationAction(\\"Classic Long Sleeve T-Shirt\\"); + const Click = () => { + setClassicLongSleeveTShirtChildren(listing?.titl); + }; + return ( + /* @ts-ignore: TS2322 */ + + + + + { + Click(); + }} + {...getOverrideProps(overrides, \\"$99\\")} + > + + + ); +} +", + "declaration": undefined, + "renderComponentToFilesystem": [Function], +} +`; + +exports[`amplify render tests mutations supports invalid statement names for mutation targets with ES5 1`] = ` +"var __assign = + (this && this.__assign) || + function () { + __assign = + Object.assign || + function (t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) + if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); + }; +var __rest = + (this && this.__rest) || + function (s, e) { + var t = {}; + for (var p in s) + if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === \\"function\\") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if ( + e.indexOf(p[i]) < 0 && + Object.prototype.propertyIsEnumerable.call(s, p[i]) + ) + t[p[i]] = s[p[i]]; + } + return t; + }; +/* eslint-disable */ +import React from \\"react\\"; +import { + getOverrideProps, + useStateMutationAction, +} from \\"@aws-amplify/ui-react/internal\\"; +import { Flex, Image, Text } from \\"@aws-amplify/ui-react\\"; +export default function CardA(props) { + var listing = props.listing, + overrides = props.overrides, + rest = __rest(props, [\\"listing\\", \\"overrides\\"]); + var _a = useStateMutationAction(\\"Classic Long Sleeve T-Shirt\\"), + classicLongSleeveTShirtChildren = _a[0], + setClassicLongSleeveTShirtChildren = _a[1]; + var Click = function () { + setClassicLongSleeveTShirtChildren( + listing === null || listing === void 0 ? void 0 : listing.titl + ); + }; + return React.createElement( + Flex, + __assign( + { + gap: \\"16px\\", + direction: \\"column\\", + justifyContent: \\"center\\", + position: \\"relative\\", + padding: \\"0px 0px 0px 0px\\", + backgroundColor: \\"rgba(255,255,255,1)\\", + }, + rest, + getOverrideProps(overrides, \\"CardA\\") + ), + React.createElement( + Image, + __assign( + { + height: \\"400px\\", + shrink: \\"0\\", + alignSelf: \\"stretch\\", + position: \\"relative\\", + padding: \\"0px 0px 0px 0px\\", + }, + getOverrideProps(overrides, \\"image\\") + ) + ), + React.createElement( + Flex, + __assign( + { + gap: \\"8px\\", + direction: \\"column\\", + shrink: \\"0\\", + alignSelf: \\"stretch\\", + position: \\"relative\\", + padding: \\"0px 0px 0px 0px\\", + }, + getOverrideProps(overrides, \\"Text Grouping\\") + ), + React.createElement( + Text, + __assign( + { + fontFamily: \\"Inter\\", + fontSize: \\"16px\\", + fontWeight: \\"400\\", + color: \\"rgba(0,0,0,1)\\", + lineHeight: \\"24px\\", + textAlign: \\"left\\", + display: \\"flex\\", + direction: \\"column\\", + justifyContent: \\"flex-start\\", + letterSpacing: \\"0.01px\\", + shrink: \\"0\\", + alignSelf: \\"stretch\\", + position: \\"relative\\", + padding: \\"0px 0px 0px 0px\\", + whiteSpace: \\"pre-wrap\\", + children: classicLongSleeveTShirtChildren, + }, + getOverrideProps(overrides, \\"Classic Long Sleeve T-Shirt\\") + ) + ), + React.createElement( + Text, + __assign( + { + fontFamily: \\"Inter\\", + fontSize: \\"14px\\", + fontWeight: \\"400\\", + color: \\"rgba(43,51,59,1)\\", + lineHeight: \\"24px\\", + textAlign: \\"left\\", + display: \\"flex\\", + direction: \\"column\\", + justifyContent: \\"flex-start\\", + shrink: \\"0\\", + alignSelf: \\"stretch\\", + position: \\"relative\\", + padding: \\"0px 0px 0px 0px\\", + whiteSpace: \\"pre-wrap\\", + children: \\"$99\\", + onClick: function () { + Click(); + }, + }, + getOverrideProps(overrides, \\"$99\\") + ) + ) + ) + ); +} +" +`; + exports[`amplify render tests mutations supports multiple actions pointing to the same value 1`] = ` Object { "componentText": "/* eslint-disable */ 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 59b96de68..e63d3f422 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 @@ -394,6 +394,19 @@ describe('amplify render tests', () => { it('supports names that cant be directly turned into methodnames', () => { expect(generateWithAmplifyRenderer('workflow/invalidNameForMethod')).toMatchSnapshot(); }); + + it('supports invalid statement names for mutation targets', () => { + expect(generateWithAmplifyRenderer('workflow/mutationWithUnsanitizedTarget')).toMatchSnapshot(); + }); + + it('supports invalid statement names for mutation targets with ES5', () => { + expect( + generateWithAmplifyRenderer('workflow/mutationWithUnsanitizedTarget', { + target: ScriptTarget.ES5, + script: ScriptKind.JS, + }).componentText, + ).toMatchSnapshot(); + }); }); describe('default value', () => { diff --git a/packages/codegen-ui-react/lib/react-component-render-helper.ts b/packages/codegen-ui-react/lib/react-component-render-helper.ts index dc53825ce..294ccd0e8 100644 --- a/packages/codegen-ui-react/lib/react-component-render-helper.ts +++ b/packages/codegen-ui-react/lib/react-component-render-helper.ts @@ -604,12 +604,19 @@ export function addBindingPropertiesImports( } } +// Scrub all non-alphanum characters, and any leading numbers so we can generate a legal +// variable name. +export function sanitizeName(componentName: string): string { + return componentName.replaceAll(/[^a-zA-Z0-9]/g, '').replace(/^[0-9]*/, ''); +} + export function getStateName(stateReference: StateStudioComponentProperty): string { const { componentName, property } = stateReference; - return [ + const rawStateName = [ componentName.charAt(0).toLowerCase() + componentName.slice(1), property.charAt(0).toUpperCase() + property.slice(1), ].join(''); + return sanitizeName(rawStateName); } export function getSetStateName(stateReference: StateStudioComponentProperty): string { diff --git a/packages/codegen-ui-react/lib/workflow/action.ts b/packages/codegen-ui-react/lib/workflow/action.ts index 21ec48521..d423f92d0 100644 --- a/packages/codegen-ui-react/lib/workflow/action.ts +++ b/packages/codegen-ui-react/lib/workflow/action.ts @@ -24,7 +24,7 @@ import { MutationAction, ComponentMetadata, } from '@aws-amplify/codegen-ui'; -import { isActionEvent, propertyToExpression, getSetStateName } from '../react-component-render-helper'; +import { isActionEvent, propertyToExpression, getSetStateName, sanitizeName } from '../react-component-render-helper'; import { ImportCollection, ImportSource, ImportValue } from '../imports'; import { getChildPropMappingForComponentName } from './utils'; @@ -79,12 +79,6 @@ export function getComponentActions(component: StudioComponent | StudioComponent return actions; } -// Scrub all non-alphanum characters, and any leading numbers so we can generate a legal -// variable name. -function sanitizeName(componentName: string): string { - return componentName.replaceAll(/[^a-zA-Z0-9]/g, '').replace(/^[0-9]*/, ''); -} - export function getActionIdentifier(componentName: string, event: string) { const name = sanitizeName(componentName); return [name.charAt(0).toLowerCase() + name.slice(1), event.charAt(0).toUpperCase() + event.slice(1)].join(''); diff --git a/packages/codegen-ui/example-schemas/workflow/mutationWithUnsanitizedTarget.json b/packages/codegen-ui/example-schemas/workflow/mutationWithUnsanitizedTarget.json new file mode 100644 index 000000000..dd397eca2 --- /dev/null +++ b/packages/codegen-ui/example-schemas/workflow/mutationWithUnsanitizedTarget.json @@ -0,0 +1,213 @@ +{ + "id" : "c-K6Xeic3SjLZLz96HrE", + "name" : "CardA", + "sourceId" : "1558:5790", + "componentType" : "Flex", + "properties" : { + "gap" : { + "value" : "16px" + }, + "direction" : { + "value" : "column" + }, + "justifyContent" : { + "value" : "center" + }, + "position" : { + "value" : "relative" + }, + "padding" : { + "value" : "0px 0px 0px 0px" + }, + "backgroundColor" : { + "value" : "rgba(255,255,255,1)" + } + }, + "bindingProperties" : { + "listing" : { + "type" : "Data", + "bindingProperties" : { + "model" : "Listing" + } + } + }, + "overrides" : { }, + "variants" : [ ], + "children" : [ { + "children" : [ ], + "componentType" : "Image", + "name" : "image", + "properties" : { + "height" : { + "value" : "400px" + }, + "shrink" : { + "value" : "0" + }, + "alignSelf" : { + "value" : "stretch" + }, + "position" : { + "value" : "relative" + }, + "padding" : { + "value" : "0px 0px 0px 0px" + } + }, + "events" : { } + }, { + "children" : [ { + "children" : [ ], + "componentType" : "Text", + "name" : "Classic Long Sleeve T-Shirt", + "properties" : { + "fontFamily" : { + "value" : "Inter" + }, + "fontSize" : { + "value" : "16px" + }, + "label" : { + "value" : "Classic Long Sleeve T-Shirt" + }, + "fontWeight" : { + "value" : "400" + }, + "color" : { + "value" : "rgba(0,0,0,1)" + }, + "lineHeight" : { + "value" : "24px" + }, + "textAlign" : { + "value" : "left" + }, + "display" : { + "value" : "flex" + }, + "direction" : { + "value" : "column" + }, + "justifyContent" : { + "value" : "flex-start" + }, + "letterSpacing" : { + "value" : "0.01px" + }, + "shrink" : { + "value" : "0" + }, + "alignSelf" : { + "value" : "stretch" + }, + "position" : { + "value" : "relative" + }, + "padding" : { + "value" : "0px 0px 0px 0px" + }, + "whiteSpace" : { + "value" : "pre-wrap" + } + }, + "events" : { } + }, { + "children" : [ ], + "componentType" : "Text", + "name" : "$99", + "properties" : { + "fontFamily" : { + "value" : "Inter" + }, + "fontSize" : { + "value" : "14px" + }, + "label" : { + "value" : "$99" + }, + "fontWeight" : { + "value" : "400" + }, + "color" : { + "value" : "rgba(43,51,59,1)" + }, + "lineHeight" : { + "value" : "24px" + }, + "textAlign" : { + "value" : "left" + }, + "display" : { + "value" : "flex" + }, + "direction" : { + "value" : "column" + }, + "justifyContent" : { + "value" : "flex-start" + }, + "shrink" : { + "value" : "0" + }, + "alignSelf" : { + "value" : "stretch" + }, + "position" : { + "value" : "relative" + }, + "padding" : { + "value" : "0px 0px 0px 0px" + }, + "whiteSpace" : { + "value" : "pre-wrap" + } + }, + "events" : { + "click" : { + "action" : "Amplify.Mutation", + "parameters" : { + "state" : { + "componentName" : "Classic Long Sleeve T-Shirt", + "property" : "label", + "set" : { + "bindingProperties" : { + "property" : "listing", + "field" : "titl" + } + } + } + } + } + } + } ], + "componentType" : "Flex", + "name" : "Text Grouping", + "properties" : { + "gap" : { + "value" : "8px" + }, + "direction" : { + "value" : "column" + }, + "shrink" : { + "value" : "0" + }, + "alignSelf" : { + "value" : "stretch" + }, + "position" : { + "value" : "relative" + }, + "padding" : { + "value" : "0px 0px 0px 0px" + } + }, + "events" : { } + } ], + "collectionProperties" : { }, + "schemaVersion" : "1.0", + "appId" : "dpkfm6ge03fz3", + "environmentName" : "staging", + "createdAt" : "2021-11-30T21:42:16.945Z", + "modifiedAt" : "2021-11-30T21:42:16.945Z" + } \ No newline at end of file diff --git a/scripts/integ-setup.sh b/scripts/integ-setup.sh index 94536b530..b6e6f792a 100755 --- a/scripts/integ-setup.sh +++ b/scripts/integ-setup.sh @@ -12,7 +12,7 @@ npm run integ:templates # install lerna bootstrap lerna add --scope integration-test aws-amplify -lerna add --scope integration-test @aws-amplify/ui-react +lerna add --scope integration-test @aws-amplify/ui-react@2.5.0 lerna add --scope integration-test @aws-amplify/datastore lerna add --scope integration-test @aws-amplify/codegen-ui lerna add --scope integration-test @aws-amplify/codegen-ui-react