From 61dc5aa71a58455bee7c1dbdf40436fe6e8a1abc Mon Sep 17 00:00:00 2001 From: kpranoto-aws <93277742+kpranoto-aws@users.noreply.github.com> Date: Tue, 28 Dec 2021 14:17:13 -0800 Subject: [PATCH] fix: proper use of type from ui builder backend (#317) --- ...react-component-render-helper.test.ts.snap | 2 + .../studio-ui-codegen-react.test.ts.snap | 1 + .../react-component-render-helper.test.ts | 11 ++++ .../studio-ui-json/buttonGolden.json | 4 ++ .../lib/react-component-render-helper.ts | 59 +++++++++++-------- 5 files changed, 51 insertions(+), 26 deletions(-) diff --git a/packages/codegen-ui-react/lib/__tests__/__snapshots__/react-component-render-helper.test.ts.snap b/packages/codegen-ui-react/lib/__tests__/__snapshots__/react-component-render-helper.test.ts.snap index 28071d30a..eaad0e4a1 100644 --- a/packages/codegen-ui-react/lib/__tests__/__snapshots__/react-component-render-helper.test.ts.snap +++ b/packages/codegen-ui-react/lib/__tests__/__snapshots__/react-component-render-helper.test.ts.snap @@ -12,6 +12,8 @@ exports[`react-component-render-helper buildFixedJsxExpression parsed null 1`] = exports[`react-component-render-helper buildFixedJsxExpression parsed number 1`] = `"{400}"`; +exports[`react-component-render-helper buildFixedJsxExpression parsed number 2`] = `"{400}"`; + exports[`react-component-render-helper buildFixedJsxExpression parsed object 1`] = `"{{ \\"transponder\\": \\"rocinante\\" }}"`; exports[`react-component-render-helper buildFixedJsxExpression string 1`] = `"\\"some text\\""`; 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 d1c8c9fc8..722d3a919 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 @@ -76,6 +76,7 @@ export default function CustomButton( diff --git a/packages/codegen-ui-react/lib/__tests__/react-component-render-helper.test.ts b/packages/codegen-ui-react/lib/__tests__/react-component-render-helper.test.ts index 40c15bce8..60271ce57 100644 --- a/packages/codegen-ui-react/lib/__tests__/react-component-render-helper.test.ts +++ b/packages/codegen-ui-react/lib/__tests__/react-component-render-helper.test.ts @@ -108,6 +108,7 @@ describe('react-component-render-helper', () => { test('parsed number', () => { assertASTMatchesSnapshot(buildFixedJsxExpression({ value: '400', type: 'Number' })); + assertASTMatchesSnapshot(buildFixedJsxExpression({ value: '400', type: 'number' })); }); test('boolean', () => { @@ -145,5 +146,15 @@ describe('react-component-render-helper', () => { test('parsed null', () => { assertASTMatchesSnapshot(buildFixedJsxExpression({ value: 'null', type: 'Object' })); }); + + test('type mismatch error', () => { + expect(() => buildFixedJsxExpression({ value: 'true', type: 'number' })).toThrow( + 'Parsed value type "boolean" and specified type "number" mismatch', + ); + }); + + test('json parse error', () => { + expect(() => buildFixedJsxExpression({ value: '⭐', type: 'number' })).toThrow('Failed to parse value "⭐"'); + }); }); }); diff --git a/packages/codegen-ui-react/lib/__tests__/studio-ui-json/buttonGolden.json b/packages/codegen-ui-react/lib/__tests__/studio-ui-json/buttonGolden.json index 1fa61b146..5bea4787c 100644 --- a/packages/codegen-ui-react/lib/__tests__/studio-ui-json/buttonGolden.json +++ b/packages/codegen-ui-react/lib/__tests__/studio-ui-json/buttonGolden.json @@ -9,6 +9,10 @@ "width": { "type": "Number", "value": "20" + }, + "isDisabled": { + "type": "boolean", + "value": "true" } } } 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 60afa72f9..730fa2ac5 100644 --- a/packages/codegen-ui-react/lib/react-component-render-helper.ts +++ b/packages/codegen-ui-react/lib/react-component-render-helper.ts @@ -145,37 +145,44 @@ export function buildFixedJsxExpression(prop: FixedStudioComponentProperty): Str case 'boolean': return factory.createJsxExpression(undefined, value ? factory.createTrue() : factory.createFalse()); case 'string': - switch (type) { - case undefined: - return factory.createStringLiteral(value as string); - case 'String': - return factory.createStringLiteral(value as string); - case 'Object': - case 'Number': - case 'Boolean': - try { - const parsedValue = JSON.parse(value as string); - - if (typeof parsedValue === 'number') { - return factory.createJsxExpression(undefined, factory.createNumericLiteral(parsedValue, undefined)); - } - if (typeof parsedValue === 'boolean') { - return factory.createJsxExpression(undefined, parsedValue ? factory.createTrue() : factory.createFalse()); - } - // object, array, and null - if (typeof parsedValue === 'object') { - return factory.createJsxExpression(undefined, jsonToLiteral(parsedValue)); - } - } catch {} // eslint-disable-line no-empty - throw new Error(`Failed to parse value "${value}" as type ${type}`); - default: - throw new Error(`Invalid type ${type} for "${value}"`); - } + return stringToJsxExpression(value as string, type); default: throw new Error(`Invalid type ${typeof value} for "${value}"`); } } +function stringToJsxExpression(strValue: string, type: string | undefined) { + switch (type) { + case undefined: + case 'String': + case 'string': + return factory.createStringLiteral(strValue); + default: + try { + const parsedValue = JSON.parse(strValue); + if (type && typeof parsedValue !== type.toLowerCase()) { + throw new Error(`Parsed value type "${typeof parsedValue}" and specified type "${type}" mismatch`); + } + + switch (typeof parsedValue) { + case 'number': + return factory.createJsxExpression(undefined, factory.createNumericLiteral(parsedValue, undefined)); + case 'boolean': + return factory.createJsxExpression(undefined, parsedValue ? factory.createTrue() : factory.createFalse()); + // object, array, and null + default: + return factory.createJsxExpression(undefined, jsonToLiteral(parsedValue)); + } + } catch (e) { + if (e instanceof SyntaxError) { + throw new Error(`Failed to parse value "${strValue}"`); + } else { + throw e; + } + } + } +} + export function buildFixedAttr(prop: FixedStudioComponentProperty, propName: string): JsxAttribute { const expr = buildFixedJsxExpression(prop); return factory.createJsxAttribute(factory.createIdentifier(propName), expr);