From 01ad841b9c9c26cca3eda87d8b85d4d6461a74a2 Mon Sep 17 00:00:00 2001 From: Lukas Valenta Date: Sun, 25 Apr 2021 09:25:30 +0200 Subject: [PATCH 1/2] feat: Export TypedProfile type --- .../types/starwars/character-information.ts | 12 ++-- src/logic/generate.ts | 59 ++++++++++++++----- src/logic/generate.utils.ts | 39 ++++++++++-- 3 files changed, 87 insertions(+), 23 deletions(-) diff --git a/fixtures/install/playground/superface/types/starwars/character-information.ts b/fixtures/install/playground/superface/types/starwars/character-information.ts index 313a5cbb..5e3183b7 100644 --- a/fixtures/install/playground/superface/types/starwars/character-information.ts +++ b/fixtures/install/playground/superface/types/starwars/character-information.ts @@ -1,4 +1,4 @@ -import { typeHelper } from '@superfaceai/one-sdk'; +import { typeHelper, TypedProfile } from '@superfaceai/one-sdk'; /** Starwars **/ export interface RetrieveCharacterInformationInput { characterName?: unknown; @@ -9,8 +9,10 @@ export interface RetrieveCharacterInformationResult { weight?: unknown; yearOfBirth?: unknown; } -export const starwarsCharacterInformation = { - "starwars/character-information": { - "RetrieveCharacterInformation": typeHelper() - } +export const profile = { + "RetrieveCharacterInformation": typeHelper() +}; +export type StarwarsCharacterInformationProfile = TypedProfile; +export const starwars/character-information = { + "starwars/character-information": profile }; diff --git a/src/logic/generate.ts b/src/logic/generate.ts index 4bd718bb..6c153251 100644 --- a/src/logic/generate.ts +++ b/src/logic/generate.ts @@ -8,6 +8,7 @@ import { } from '@superfaceai/parser'; import { InterfaceDeclaration, + isExportDeclaration, isIdentifier, isImportDeclaration, isObjectLiteralExpression, @@ -25,8 +26,10 @@ import { camelize, capitalize, createSource, + getExportText, getImportText, getVariableName, + id, interfaceType, literalUnion, namedImport, @@ -35,9 +38,12 @@ import { pascalize, propertyAssignment, propertySignature, + reexport, typeAlias, typedClientStatement, typeDefinitions, + typeQuery, + typeReference, variableStatement, variableType, } from './generate.utils'; @@ -119,10 +125,10 @@ export function createUsecaseTypes( return [...inputs, ...results]; } -export function createUsecasesType( +export function createProfileType( profileName: string, usecaseNames: string[] -): Statement { +): Statement[] { const usecases = usecaseNames.map(usecaseName => { const pascalizedUsecaseName = pascalize(usecaseName); const helperCall = callExpression( @@ -133,20 +139,28 @@ export function createUsecasesType( return propertyAssignment(usecaseName, helperCall); }); - const profile = objectLiteral([ - propertyAssignment(profileName, objectLiteral(usecases)), - ]); - return variableStatement(camelize(profileName), profile); + const profile = variableStatement('profile', objectLiteral(usecases)); + const profileType = typeAlias( + pascalize(profileName) + 'Profile', + typeReference('TypedProfile', [typeQuery('profile')]) + ); + const profileWrapper = variableStatement( + profileName, + objectLiteral([propertyAssignment(profileName, id('profile'))]) + ); + + return [profile, profileType, profileWrapper]; } export function generateTypesFile( profiles: string[], typesFile?: string ): string { - const imports = profiles.map(profile => - namedImport([camelize(profile)], './types/' + profile) - ); + const imports = profiles.flatMap(profile => [ + namedImport([camelize(profile)], './types/' + profile), + reexport([pascalize(profile) + 'Profile'], './types/' + profile), + ]); const statements = [ namedImport(['createTypedClient'], '@superfaceai/one-sdk'), ...imports, @@ -180,7 +194,9 @@ export function updateTypesFile( const originalStatements = parseSource(typesFile); const newImports = statements.filter(isImportDeclaration); + const newExports = statements.filter(isExportDeclaration); const originalImports = originalStatements.filter(isImportDeclaration); + const originalExports = originalStatements.filter(isExportDeclaration); const newTypeDefinition = statements .filter(isVariableStatement) .find(node => getVariableName(node) === 'typeDefinitions'); @@ -188,7 +204,10 @@ export function updateTypesFile( .filter(isVariableStatement) .find(node => getVariableName(node) === 'typeDefinitions'); - const mergedStatements: Statement[] = [...originalImports]; + const mergedStatements: Statement[] = [ + ...originalImports, + ...originalExports, + ]; for (const newImport of newImports) { const importText = getImportText(newImport); @@ -202,6 +221,18 @@ export function updateTypesFile( } } + for (const newExport of newExports) { + const exportText = getExportText(newExport); + if ( + exportText !== undefined && + originalExports.find( + originalExport => getExportText(originalExport) === exportText + ) === undefined + ) { + mergedStatements.push(newExport); + } + } + if (newTypeDefinition === undefined && originalTypeDefinition !== undefined) { mergedStatements.push(originalTypeDefinition); } else if ( @@ -240,14 +271,14 @@ export function generateTypingsForProfile( profileAST: ProfileDocumentNode ): string { const output = getProfileOutput(profileAST); - const inputTypes = output.usecases.map(usecase => + const inputTypes = output.usecases.flatMap(usecase => createUsecaseTypes(usecase, 'unknown') ); const statements = [ - namedImport(['typeHelper'], '@superfaceai/one-sdk'), - ...inputTypes.reduce((acc, input) => [...acc, ...input], []), - createUsecasesType( + namedImport(['typeHelper', 'TypedProfile'], '@superfaceai/one-sdk'), + ...inputTypes, + ...createProfileType( profileName, output.usecases.map(usecase => usecase.useCaseName) ), diff --git a/src/logic/generate.utils.ts b/src/logic/generate.utils.ts index 3588693f..22158fe4 100644 --- a/src/logic/generate.utils.ts +++ b/src/logic/generate.utils.ts @@ -7,14 +7,17 @@ import { createPrinter, createSourceFile, EmitHint, + ExportDeclaration, Expression, factory, FalseLiteral, Identifier, ImportDeclaration, InterfaceDeclaration, + isExportSpecifier, isIdentifier, isImportSpecifier, + isNamedExports, isNamedImports, KeywordTypeNode, LiteralTypeNode, @@ -37,6 +40,7 @@ import { TypeElement, TypeLiteralNode, TypeNode, + TypeQueryNode, TypeReferenceNode, UnionTypeNode, VariableStatement, @@ -307,8 +311,11 @@ export function asExpression(name: string, asType: string): AsExpression { ); } -export function typeReference(name: string): TypeReferenceNode { - return factory.createTypeReferenceNode(name); +export function typeReference( + name: string, + typeArguments?: TypeNode[] +): TypeReferenceNode { + return factory.createTypeReferenceNode(name, typeArguments); } export function callExpression( @@ -318,7 +325,7 @@ export function callExpression( ): CallExpression { return factory.createCallExpression( id(functionName), - typeArguments?.map(typeReference) ?? [], + typeArguments?.map(argument => typeReference(argument)) ?? [], functionArguments ); } @@ -383,7 +390,7 @@ export function createSource(statements: Statement[]): string { export function getImportText(node: ImportDeclaration): string | undefined { if ( - node.importClause?.namedBindings && + node.importClause?.namedBindings !== undefined && isNamedImports(node.importClause.namedBindings) ) { return node.importClause.namedBindings.elements.find(isImportSpecifier) @@ -393,6 +400,14 @@ export function getImportText(node: ImportDeclaration): string | undefined { return undefined; } +export function getExportText(node: ExportDeclaration): string | undefined { + if (node.exportClause !== undefined && isNamedExports(node.exportClause)) { + return node.exportClause.elements.find(isExportSpecifier)?.name.text; + } + + return undefined; +} + export function getVariableName(node: VariableStatement): string | undefined { if ( node.declarationList.declarations.length > 0 && @@ -403,3 +418,19 @@ export function getVariableName(node: VariableStatement): string | undefined { return undefined; } + +export function typeQuery(name: string): TypeQueryNode { + return factory.createTypeQueryNode(id(name)); +} + +export function reexport(names: string[], from: string): ExportDeclaration { + return factory.createExportDeclaration( + undefined, + undefined, + false, + factory.createNamedExports( + names.map(name => factory.createExportSpecifier(undefined, name)) + ), + stringLiteral(from) + ); +} From 3030d3fa13238566b39096a6520c72d82ac71c93 Mon Sep 17 00:00:00 2001 From: Lukas Valenta Date: Mon, 26 Apr 2021 08:28:27 +0200 Subject: [PATCH 2/2] chore: Fix missing camel --- fixtures/install/playground/superface/sdk.ts | 1 + .../superface/types/starwars/character-information.ts | 2 +- src/logic/generate.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fixtures/install/playground/superface/sdk.ts b/fixtures/install/playground/superface/sdk.ts index fd6da60c..22e5a1c5 100644 --- a/fixtures/install/playground/superface/sdk.ts +++ b/fixtures/install/playground/superface/sdk.ts @@ -1,5 +1,6 @@ import { createTypedClient } from "@superfaceai/one-sdk"; import { starwarsCharacterInformation } from "./types/starwars/character-information"; +export { StarwarsCharacterInformationProfile } from "./types/starwars/character-information"; export const typeDefinitions = { ...starwarsCharacterInformation }; diff --git a/fixtures/install/playground/superface/types/starwars/character-information.ts b/fixtures/install/playground/superface/types/starwars/character-information.ts index 5e3183b7..04780d01 100644 --- a/fixtures/install/playground/superface/types/starwars/character-information.ts +++ b/fixtures/install/playground/superface/types/starwars/character-information.ts @@ -13,6 +13,6 @@ export const profile = { "RetrieveCharacterInformation": typeHelper() }; export type StarwarsCharacterInformationProfile = TypedProfile; -export const starwars/character-information = { +export const starwarsCharacterInformation = { "starwars/character-information": profile }; diff --git a/src/logic/generate.ts b/src/logic/generate.ts index 6c153251..4a2c3191 100644 --- a/src/logic/generate.ts +++ b/src/logic/generate.ts @@ -146,7 +146,7 @@ export function createProfileType( typeReference('TypedProfile', [typeQuery('profile')]) ); const profileWrapper = variableStatement( - profileName, + camelize(profileName), objectLiteral([propertyAssignment(profileName, id('profile'))]) );