Skip to content

Commit

Permalink
refactor: add data dependencies to component metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
dpilch authored and alharris-at committed Feb 25, 2022
1 parent ce65105 commit 295aff7
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ Array [
exports[`mapSyntheticStateReferences basic 1`] = `
Array [
Object {
"componentName": "UserNameTextField",
"property": "value",
"dataDependencies": Array [],
"reference": Object {
"componentName": "UserNameTextField",
"property": "value",
},
},
]
`;
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('mapSyntheticStateReferences', () => {
const componentMetadata: ComponentMetadata = {
hasAuthBindings: false,
requiredDataModels: [],
stateReferences: [{ componentName: 'UserNameTextField', property: 'value' }],
stateReferences: [{ reference: { componentName: 'UserNameTextField', property: 'value' }, dataDependencies: [] }],
componentNameToTypeMap: { UserNameTextField: 'TextField' },
};
expect(mapSyntheticStateReferences(componentMetadata)).toMatchSnapshot();
Expand Down
47 changes: 25 additions & 22 deletions packages/codegen-ui-react/lib/workflow/mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@ import {
StudioComponentChild,
StateStudioComponentProperty,
ActionStudioComponentEvent,
StateReference,
StudioGenericEvent,
StudioComponentProperty,
ComponentMetadata,
getComponentFromComponentTree,
computeStateReferenceMetadata,
StateReferenceMetadata,
} from '@aws-amplify/codegen-ui';
import {
isStateProperty,
Expand Down Expand Up @@ -75,10 +74,9 @@ export function buildUseEffectStatements(
component: StudioComponent,
componentMetadata: ComponentMetadata,
): Statement[] {
const stateReferenceMetadata = computeStateReferenceMetadata(component, componentMetadata.stateReferences);
return stateReferenceMetadata
return componentMetadata.stateReferences
.filter(({ dataDependencies }) => dataDependencies.length > 0)
.map(({ stateReference, dataDependencies }) => {
.map(({ reference, dataDependencies }) => {
return factory.createExpressionStatement(
factory.createCallExpression(factory.createIdentifier('useEffect'), undefined, [
factory.createArrowFunction(
Expand All @@ -89,8 +87,8 @@ export function buildUseEffectStatements(
factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
factory.createBlock([
factory.createExpressionStatement(
factory.createCallExpression(factory.createIdentifier(getSetStateName(stateReference)), undefined, [
getStateInitialValue(component, componentMetadata, stateReference),
factory.createCallExpression(factory.createIdentifier(getSetStateName(reference)), undefined, [
getStateInitialValue(component, componentMetadata, reference),
]),
),
]),
Expand All @@ -103,10 +101,12 @@ export function buildUseEffectStatements(

export function mapSyntheticStateReferences(componentMetadata: ComponentMetadata) {
return componentMetadata.stateReferences.map((stateReference) => {
const { componentName, property } = stateReference;
const {
reference: { componentName, property },
} = stateReference;
const childrenPropMapping = getChildPropMappingForComponentName(componentMetadata, componentName);
if (childrenPropMapping !== undefined && property === childrenPropMapping) {
return { ...stateReference, property: 'children' };
return { ...stateReference, reference: { ...stateReference.reference, property: 'children' } };
}
return stateReference;
});
Expand Down Expand Up @@ -232,16 +232,19 @@ export function buildOpeningElementControlEvents(
}

/**
* Dedupes state references by componentName + property, returning a consolidate
* Dedupes state references by componentName, property, and dataDependencies, returning a consolidate
* list, stripping the `set` property from them. We do this by serializing to json,
* collecting in a set, then deserializing.
*/
function dedupeStateReferences(stateReferences: StateReference[]): StateReference[] {
function dedupeStateReferences(stateReferences: StateReferenceMetadata[]): StateReferenceMetadata[] {
const dedupedSerializedRefs = [
...new Set(
stateReferences.map((stateReference) => {
const { componentName, property } = stateReference;
return JSON.stringify({ componentName, property });
const {
reference: { componentName, property },
dataDependencies,
} = stateReference;
return JSON.stringify({ reference: { componentName, property }, dataDependencies: dataDependencies.sort() });
}),
),
];
Expand All @@ -267,20 +270,20 @@ export function buildStateStatements(
factory.createBindingElement(
undefined,
undefined,
factory.createIdentifier(getStateName(stateReference)),
factory.createIdentifier(getStateName(stateReference.reference)),
undefined,
),
factory.createBindingElement(
undefined,
undefined,
factory.createIdentifier(getSetStateName(stateReference)),
factory.createIdentifier(getSetStateName(stateReference.reference)),
undefined,
),
]),
undefined,
undefined,
factory.createCallExpression(factory.createIdentifier('useStateMutationAction'), undefined, [
getStateInitialValue(component, componentMetadata, stateReference),
getStateInitialValue(component, componentMetadata, stateReference.reference),
]),
),
],
Expand Down Expand Up @@ -335,23 +338,23 @@ export type MutationReferences = {

export function filterStateReferencesForComponent(
component: StudioComponent | StudioComponentChild,
stateReferences: StateReference[],
stateReferences: StateReferenceMetadata[],
): MutationReferences {
return stateReferences
.filter(({ componentName }) => componentName === component.name)
.filter(({ reference: { componentName } }) => componentName === component.name)
.reduce(mutationReferenceReducerWithComponentType(component.componentType), {});
}

function mutationReferenceReducerWithComponentType(componentType: string) {
return function mutationReferenceReducer(
mutationReferences: MutationReferences,
stateReference: StateReference,
stateReference: StateReferenceMetadata,
): MutationReferences {
const propertyReferences =
stateReference.property in mutationReferences ? mutationReferences[stateReference.property] : [];
const { reference } = stateReference;
const propertyReferences = reference.property in mutationReferences ? mutationReferences[reference.property] : [];
return {
...mutationReferences,
[stateReference.property]: propertyReferences.concat([
[reference.property]: propertyReferences.concat([
{ addControlEvent: PrimitivesWithChangeEvent.has(componentType as Primitive) },
]),
};
Expand Down
137 changes: 124 additions & 13 deletions packages/codegen-ui/lib/__tests__/utils/component-metadata.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,13 +359,25 @@ describe('computeComponentMetadata', () => {
},
},
bindingProperties: {},
children: [
{
componentType: 'TextField',
name: 'UserNameField',
properties: {
value: {
value: 'username',
},
},
},
],
};
const expectedMetadata: ComponentMetadata = {
hasAuthBindings: false,
requiredDataModels: [],
stateReferences: [{ componentName: 'UserNameField', property: 'value' }],
stateReferences: [{ reference: { componentName: 'UserNameField', property: 'value' }, dataDependencies: [] }],
componentNameToTypeMap: {
MyText: 'Text',
UserNameField: 'TextField',
},
};
expect(computeComponentMetadata(component)).toEqual(expectedMetadata);
Expand All @@ -386,13 +398,25 @@ describe('computeComponentMetadata', () => {
},
},
bindingProperties: {},
children: [
{
componentType: 'TextField',
name: 'UserNameField',
properties: {
value: {
value: 'username',
},
},
},
],
};
const expectedMetadata: ComponentMetadata = {
hasAuthBindings: false,
requiredDataModels: [],
stateReferences: [{ componentName: 'UserNameField', property: 'value' }],
stateReferences: [{ reference: { componentName: 'UserNameField', property: 'value' }, dataDependencies: [] }],
componentNameToTypeMap: {
MyText: 'Text',
UserNameField: 'TextField',
},
};
expect(computeComponentMetadata(component)).toEqual(expectedMetadata);
Expand All @@ -418,13 +442,25 @@ describe('computeComponentMetadata', () => {
},
},
},
children: [
{
componentType: 'TextField',
name: 'UserNameField',
properties: {
value: {
value: 'username',
},
},
},
],
};
const expectedMetadata: ComponentMetadata = {
hasAuthBindings: false,
requiredDataModels: ['User'],
stateReferences: [{ componentName: 'UserNameField', property: 'value' }],
stateReferences: [{ reference: { componentName: 'UserNameField', property: 'value' }, dataDependencies: [] }],
componentNameToTypeMap: {
MyText: 'Text',
UserNameField: 'TextField',
},
};
expect(computeComponentMetadata(component)).toEqual(expectedMetadata);
Expand Down Expand Up @@ -457,13 +493,25 @@ describe('computeComponentMetadata', () => {
},
},
},
children: [
{
componentType: 'TextField',
name: 'UserNameField',
properties: {
value: {
value: 'username',
},
},
},
],
};
const expectedMetadata: ComponentMetadata = {
hasAuthBindings: false,
requiredDataModels: ['User'],
stateReferences: [{ componentName: 'UserNameField', property: 'value' }],
stateReferences: [{ reference: { componentName: 'UserNameField', property: 'value' }, dataDependencies: [] }],
componentNameToTypeMap: {
MyText: 'Text',
UserNameField: 'TextField',
},
};
expect(computeComponentMetadata(component)).toEqual(expectedMetadata);
Expand Down Expand Up @@ -501,16 +549,38 @@ describe('computeComponentMetadata', () => {
},
},
},
children: [
{
componentType: 'TextField',
name: 'UserNameField',
properties: {
value: {
value: 'username',
},
},
},
{
componentType: 'TextField',
name: 'NicknameField',
properties: {
value: {
value: 'nickname',
},
},
},
],
};
const expectedMetadata: ComponentMetadata = {
hasAuthBindings: false,
requiredDataModels: ['User'],
stateReferences: [
{ componentName: 'NicknameField', property: 'value' },
{ componentName: 'UserNameField', property: 'value' },
{ reference: { componentName: 'NicknameField', property: 'value' }, dataDependencies: [] },
{ reference: { componentName: 'UserNameField', property: 'value' }, dataDependencies: [] },
],
componentNameToTypeMap: {
MyText: 'Text',
UserNameField: 'TextField',
NicknameField: 'TextField',
},
};
expect(computeComponentMetadata(component)).toEqual(expectedMetadata);
Expand Down Expand Up @@ -548,13 +618,25 @@ describe('computeComponentMetadata', () => {
},
},
},
children: [
{
componentType: 'TextField',
name: 'UserNameField',
properties: {
value: {
value: 'username',
},
},
},
],
};
const expectedMetadata: ComponentMetadata = {
hasAuthBindings: false,
requiredDataModels: ['User'],
stateReferences: [{ componentName: 'UserNameField', property: 'value' }],
stateReferences: [{ reference: { componentName: 'UserNameField', property: 'value' }, dataDependencies: [] }],
componentNameToTypeMap: {
MyText: 'Text',
UserNameField: 'TextField',
},
};
expect(computeComponentMetadata(component)).toEqual(expectedMetadata);
Expand Down Expand Up @@ -592,16 +674,31 @@ describe('computeComponentMetadata', () => {
},
},
},
children: [
{
componentType: 'TextField',
name: 'UserNameField',
properties: {
value: {
value: 'username',
},
},
},
],
};
const expectedMetadata: ComponentMetadata = {
hasAuthBindings: false,
requiredDataModels: ['User'],
stateReferences: [
{ componentName: 'UserNameField', property: 'value' },
{ componentName: 'UserNameField', property: 'value', set: { value: 'Setter' } },
{ reference: { componentName: 'UserNameField', property: 'value' }, dataDependencies: [] },
{
reference: { componentName: 'UserNameField', property: 'value', set: { value: 'Setter' } },
dataDependencies: [],
},
],
componentNameToTypeMap: {
MyText: 'Text',
UserNameField: 'TextField',
},
};
expect(computeComponentMetadata(component)).toEqual(expectedMetadata);
Expand Down Expand Up @@ -789,8 +886,15 @@ describe('computeComponentMetadata', () => {
hasAuthBindings: true,
requiredDataModels: ['User', 'Listing'],
stateReferences: [
{ componentName: 'NicknameField', property: 'value' },
{ componentName: 'NestedComponent', property: 'color', set: { bindingProperties: { property: 'color' } } },
{ reference: { componentName: 'NicknameField', property: 'value' }, dataDependencies: [] },
{
reference: {
componentName: 'NestedComponent',
property: 'color',
set: { bindingProperties: { property: 'color' } },
},
dataDependencies: [],
},
],
componentNameToTypeMap: {
TopLevelComponent: 'Flex',
Expand Down Expand Up @@ -907,8 +1011,15 @@ describe('computeComponentMetadata', () => {
hasAuthBindings: true,
requiredDataModels: ['User', 'Listing'],
stateReferences: [
{ componentName: 'NicknameField', property: 'value' },
{ componentName: 'NestedComponent', property: 'color', set: { bindingProperties: { property: 'color' } } },
{ reference: { componentName: 'NicknameField', property: 'value' }, dataDependencies: [] },
{
reference: {
componentName: 'NestedComponent',
property: 'color',
set: { bindingProperties: { property: 'color' } },
},
dataDependencies: [],
},
],
componentNameToTypeMap: {
TopLevelComponent: 'Flex',
Expand Down
Loading

0 comments on commit 295aff7

Please sign in to comment.