From 2b5a7f8ad36b71785c7ae80f5582aa2378bf7001 Mon Sep 17 00:00:00 2001 From: Trish Ta Date: Wed, 15 Jan 2025 02:24:01 -0500 Subject: [PATCH] Fix events definition --- package.json | 1 + .../src/surfaces/admin/components.d.ts | 3 + scripts/generator.js | 139 ++++++++++-------- 3 files changed, 85 insertions(+), 58 deletions(-) diff --git a/package.json b/package.json index e9b9703f6..4ba45d240 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build-consumer": "loom build && ./scripts/build-consumer.sh", "build-consumer-spin": "loom build && ./scripts/build-consumer-spin.sh", "generate-definition": "node ./scripts/generator.js", + "generate-definition:admin": "yarn generate-definition packages/ui-extensions/src/surfaces/admin/components.d.ts ../web/areas/clients/admin-web/app/shared/domains/extensibility/ui-extensions/components ../web/areas/clients/admin-web/app/shared/domains/extensibility/ui-extensions/definitionTemplate.txt", "clean": "git clean -xdf ./packages; rm -rf ./build", "predeploy": "yarn build", "deploy": "changeset publish", diff --git a/packages/ui-extensions/src/surfaces/admin/components.d.ts b/packages/ui-extensions/src/surfaces/admin/components.d.ts index 4d16e9e35..dfe97895c 100644 --- a/packages/ui-extensions/src/surfaces/admin/components.d.ts +++ b/packages/ui-extensions/src/surfaces/admin/components.d.ts @@ -2794,6 +2794,9 @@ export type ButtonBaseProps = Required< | 'target' | 'href' | 'download' + | 'onBlur' + | 'onClick' + | 'onFocus' > >; export interface ButtonProps extends ButtonBaseProps { diff --git a/scripts/generator.js b/scripts/generator.js index d766c499a..ab6a0620c 100644 --- a/scripts/generator.js +++ b/scripts/generator.js @@ -18,6 +18,7 @@ const allSymbolNodes = new Map(); const REQUIRED_TYPE = 'Required'; const EXTRACT_TYPE = 'Extract'; const PICK_TYPE = 'Pick'; +const FUNCTION_REGEX = /^on([A-Z][a-zA-Z]+$)/; function generate({ componentName, checker, outputRootFolder, templatePath }) { const definition = constructFullDefinitionFromSymbol({ @@ -30,12 +31,18 @@ function generate({ componentName, checker, outputRootFolder, templatePath }) { : path.join(componentName); if (!definition) { - console.warn(`Failed to generate definition for ${componentName}`); + console.warn( + `Cannot generate definition for ${componentName}. This might not be a real component`, + ); return; } // TEMPORARY - Fix for missing id until we add it to the interface for components definition.properties.id = { type: "'string'" }; + // Strip out empty events + if (!Object.keys(definition.events).length) { + delete definition.events; + } fs.mkdir(outputPath, { recursive: true }, (err) => { if (err) throw err; @@ -76,7 +83,7 @@ function parseComplexType({ type, checker }) { symbolName: type.expression.escapedText, checker, }); - return fullDefininition?.properties; + return fullDefininition; } } else if (type.kind === ts.SyntaxKind.TypeReference) { if (type.typeName.escapedText === REQUIRED_TYPE) { @@ -93,7 +100,7 @@ function parseComplexType({ type, checker }) { symbolName: referenceType.typeName.escapedText, checker, }); - return definition.properties; + return definition; } } else if (type.typeName.escapedText === EXTRACT_TYPE) { const parsedExpression = getParsedExpression({ @@ -119,10 +126,10 @@ function parseDeclarations({ declarations, checker }) { checker, }); - combinedDeclarations = { - ...combinedDeclarations, - ...(heritageDeclations || {}), - }; + combinedDeclarations = deepMergeDefinition( + combinedDeclarations, + heritageDeclations, + ); } const hasComplexExtend = @@ -131,17 +138,14 @@ function parseDeclarations({ declarations, checker }) { if (hasComplexExtend) { const parsedTypes = declaration.types.reduce((acc2, type) => { // Parse expression - const parsedExpression = parseComplexType({ + const parsedDefinition = parseComplexType({ type, checker, }); - return { ...acc2, ...(parsedExpression || {}) }; - }, {}); - return { - ...combinedDeclarations, - ...(parsedTypes || {}), - }; + return deepMergeDefinition(acc2, parsedDefinition); + }, {}); + return deepMergeDefinition(combinedDeclarations, parsedTypes); } // Handle other complex type @@ -153,10 +157,7 @@ function parseDeclarations({ declarations, checker }) { type: declaration.type, checker, }); - return { - ...combinedDeclarations, - ...(parsedExpression || {}), - }; + return deepMergeDefinition(combinedDeclarations, parsedExpression); } return combinedDeclarations; @@ -181,14 +182,15 @@ function constructFullDefinitionFromSymbol({ symbolName, checker }) { } const nodeType = checker.getDeclaredTypeOfSymbol(symbol); - - let all = + let events = {}; + const symbolProperties = getChildDefinition({ symbol, nodeType, checker, }) || {}; + let all = symbolProperties; const declarations = symbol.getDeclarations(); if (declarations) { @@ -197,48 +199,51 @@ function constructFullDefinitionFromSymbol({ symbolName, checker }) { checker, }); - all = { ...all, ...(declarationsDefinitions || {}) }; + all = { + ...all, + ...(declarationsDefinitions.properties || {}), + }; + events = declarationsDefinitions.events || {}; } - const definition = Object.keys(all).reduce((acc, key) => { - if (!all[key]) { - return acc; - } - - if (all[key].generic) { - acc.generic = true; - return acc; - } + const definition = Object.keys(all).reduce( + (acc, key) => { + if (!all[key]) { + return acc; + } - if (all[key].slot) { - if (!Object.prototype.hasOwnProperty.call(acc, 'slots')) { - acc.slots = []; + if (all[key].generic) { + acc.generic = true; + return acc; } - acc.slots.push(`'${key}'`); - return acc; - } + if (all[key].slot) { + if (!Object.prototype.hasOwnProperty.call(acc, 'slots')) { + acc.slots = []; + } - // If this is an event, push to the events array and skip adding it to prop - if (typeof all[key].event === 'string') { - if (!Object.prototype.hasOwnProperty.call(acc, 'events')) { - acc.events = []; + acc.slots.push(`'${key}'`); + return acc; } - acc.events.push(`'${all[key].event}'`); - return acc; - } - if (!Object.prototype.hasOwnProperty.call(acc, 'properties')) { - acc.properties = {}; - } + // If this is an event, push to the events array and skip adding it to prop + if (typeof all[key].event === 'string') { + // This is just set to an empty placeholder because by defaults most events handlers don't need special logic + acc.events[key] = {}; + return acc; + } - acc.properties[key] = all[key]; + acc.properties[key] = all[key]; - return acc; - }, {}); + return acc; + }, + { properties: {}, events }, + ); // Save definition for reuse allSymbolNodes.set(symbolName, { node, definition }); + // console.log('JSON -->', JSON.stringify(definition)); + // console.log('END constructFullDefinitionFromSymbol -->', symbolName); return definition; } @@ -381,7 +386,7 @@ function getDefinition({ checker, }); if (parsedExpression) { - return parsedExpression[name]; + return parsedExpression.properties[name] || parsedExpression.events[name]; } } @@ -409,9 +414,9 @@ function getDefinition({ } if (isFunction) { - const matchHandler = name.match(/^on([A-Z][a-zA-Z]+$)/); + const matchHandler = name.match(FUNCTION_REGEX); if (matchHandler && typeof matchHandler[1] === 'string') { - return { event: matchHandler[1].toLowerCase() }; + return { event: name }; } } @@ -570,7 +575,8 @@ function getParsedExpression({ type, checker }) { switch (type.typeName.escapedText) { case PICK_TYPE: { - const props = {}; + const properties = {}; + const events = {}; const referenceDefinition = constructFullDefinitionFromSymbol({ symbolName: typeReference.typeName.escapedText, checker, @@ -584,10 +590,15 @@ function getParsedExpression({ type, checker }) { } expressionType.types.forEach((t) => { - props[t.literal.text] = referenceDefinition.properties[t.literal.text]; + if (referenceDefinition.properties[t.literal.text]) { + properties[t.literal.text] = + referenceDefinition.properties[t.literal.text]; + } else if (referenceDefinition.events[t.literal.text]) { + events[t.literal.text] = referenceDefinition.events[t.literal.text]; + } }); - return props; + return { properties, events }; } case EXTRACT_TYPE: { if ( @@ -606,14 +617,14 @@ function getParsedExpression({ type, checker }) { return; } - const props = { + const properties = { [propIndex]: { type: referenceDefinition.properties[propIndex].type, default: referenceDefinition.properties[propIndex].default, values: expressionType.types.map((t) => `'${t.literal.text}'`), }, }; - return props; + return { properties, events: {} }; } else if (expressionType.kind === ts.SyntaxKind.TypeLiteral) { // Handles inline declarations like `Extract` // In this case the typeReference we passed in already has the correct interface @@ -621,12 +632,24 @@ function getParsedExpression({ type, checker }) { symbolName: typeReference.typeName.escapedText, checker, }); - return referenceDefinition.properties; + return referenceDefinition; } } } } +function deepMergeDefinition(org = {}, addition = {}) { + if (!addition) { + return org; + } + const { properties = {}, events = {} } = org; + const merged = { + properties: { ...properties, ...(addition.properties || {}) }, + events: { ...events, ...(addition.events || {}) }, + }; + return merged; +} + const filePath = process.argv[2]; const outputRootFolder = process.argv[3]; const templatePath = process.argv[4];