UNPKG

@sprucelabs/spruce-cli

Version:

Command line interface for building Spruce skills.

280 lines (241 loc) • 9.6 kB
import { EventContract } from '@sprucelabs/mercury-types' import { Schema, SchemaError, SchemaTemplateItem } from '@sprucelabs/schema' import { eventContractUtil, NamedEventSignature, } from '@sprucelabs/spruce-event-utils' import { MERCURY_API_NAMESPACE, namesUtil, } from '@sprucelabs/spruce-skill-utils' import { EventContractTemplateItem, EventSignatureTemplateItem, } from '@sprucelabs/spruce-templates' import schemaDiskUtil from '../features/schema/utilities/schemaDisk.utility' import SchemaTemplateItemBuilder from './SchemaTemplateItemBuilder' export default class EventTemplateItemBuilder { public buildTemplateItems(options: { contracts: EventContract[] localNamespace?: string eventBuilderFile?: string }): { eventContractTemplateItems: EventContractTemplateItem[] schemaTemplateItems: SchemaTemplateItem[] } { const { contracts, localNamespace, eventBuilderFile } = options const eventContractTemplateItems: EventContractTemplateItem[] = [] const schemaTemplateItems: SchemaTemplateItem[] = [] for (const contract of contracts) { const { schemaTemplateItems: schemaItems, eventContractTemplateItems: contractItems, } = this.buildTemplateItemsForContract( contract, localNamespace, eventBuilderFile ) eventContractTemplateItems.push(...contractItems) schemaTemplateItems.push(...schemaItems) } eventContractTemplateItems.sort((a, b) => { if (a.nameCamel > b.nameCamel) { return 1 } else if (a.nameCamel < b.nameCamel) { return -1 } return 0 }) return { eventContractTemplateItems, schemaTemplateItems } } public buildEventTemplateItemForName( contracts: EventContract[], fullyQualifiedEventName: string ): { responsePayloadSchemaTemplateItem: SchemaTemplateItem | undefined emitPayloadSchemaTemplateItem: SchemaTemplateItem | undefined } { for (const contract of contracts) { const namedSignatures = eventContractUtil.getNamedEventSignatures(contract) for (const namedSig of namedSignatures) { if ( namedSig.fullyQualifiedEventName === fullyQualifiedEventName ) { const schemaTemplateItems: SchemaTemplateItem[] = this.mapEventSigsToSchemaTemplateItems(namedSignatures) const signatureTemplateItem: EventSignatureTemplateItem = this.buildEventSigTemplateItem( namedSig, schemaTemplateItems ) return { emitPayloadSchemaTemplateItem: signatureTemplateItem.emitPayloadSchema, responsePayloadSchemaTemplateItem: signatureTemplateItem.responsePayloadSchema, } } } } throw new SchemaError({ code: 'INVALID_PARAMETERS', parameters: ['fullyQualifiedEventName'], friendlyMessages: [ `I could not find any events that match ${fullyQualifiedEventName}.`, ], }) } private buildTemplateItemsForContract( contract: EventContract, localNamespace?: string, eventBuilderFile?: string ): { eventContractTemplateItems: EventContractTemplateItem[] schemaTemplateItems: SchemaTemplateItem[] } { const namedSignatures = eventContractUtil.getNamedEventSignatures(contract) const schemaTemplateItems: SchemaTemplateItem[] = this.mapEventSigsToSchemaTemplateItems(namedSignatures) const eventContractTemplateItems: EventContractTemplateItem[] = [] for (const namedSig of namedSignatures) { const item: EventContractTemplateItem = this.buildTemplateItemForEventSignature( namedSig, schemaTemplateItems, namedSig.eventNamespace === localNamespace, eventBuilderFile ) eventContractTemplateItems.push(item) } return { eventContractTemplateItems, schemaTemplateItems, } } private buildTemplateItemForEventSignature( namedSig: NamedEventSignature, schemaTemplateItems: SchemaTemplateItem[], isLocal: boolean, eventBuilderFile?: string ) { const namespacePascal = this.sigToNamespacePascal(namedSig) const signatureTemplateItem: EventSignatureTemplateItem = this.buildEventSigTemplateItem(namedSig, schemaTemplateItems) const item: EventContractTemplateItem = { nameCamel: namesUtil.toCamel(namedSig.eventName), namePascal: namesUtil.toPascal(namedSig.eventName), version: namedSig.version ?? '***MISSING***', isLocal, namespace: namesUtil.toKebab( namedSig.eventNamespace ?? MERCURY_API_NAMESPACE ), namespaceCamel: namesUtil.toCamel( namedSig.eventNamespace ?? MERCURY_API_NAMESPACE ), imports: [ signatureTemplateItem.emitPayloadSchema as SchemaTemplateItem, signatureTemplateItem.responsePayloadSchema as SchemaTemplateItem, ] .filter((i) => !!i) .map((item: SchemaTemplateItem) => ({ package: schemaDiskUtil.resolvePath({ destination: '#spruce/schemas', schema: item.schema, shouldIncludeFileExtension: false, }), importAs: `${item.nameCamel}Schema`, })), namespacePascal, eventSignatures: { [namedSig.fullyQualifiedEventName]: signatureTemplateItem, }, } item.imports.push({ importAs: '{ buildEventContract }', package: eventBuilderFile ?? '@sprucelabs/mercury-types', }) if ( namedSig.signature.listenPermissionContract || namedSig.signature.emitPermissionContract ) { item.imports.push({ importAs: '{ buildPermissionContract }', package: eventBuilderFile ?? '@sprucelabs/mercury-types', }) } return item } private buildEventSigTemplateItem( namedSig: NamedEventSignature, schemaItems: SchemaTemplateItem[] ) { const { emitPayloadSchema, responsePayloadSchema, ...signature } = namedSig.signature const signatureTemplateItem: EventSignatureTemplateItem = { ...signature, } if (emitPayloadSchema) { signatureTemplateItem.emitPayloadSchema = schemaItems.find( (i) => i.id === emitPayloadSchema.id && (!emitPayloadSchema.namespace || i.namespace === emitPayloadSchema.namespace) ) } if (responsePayloadSchema) { signatureTemplateItem.responsePayloadSchema = schemaItems.find( (i) => i.id === responsePayloadSchema.id && (!responsePayloadSchema.namespace || i.namespace === responsePayloadSchema.namespace) ) } return signatureTemplateItem } private mapEventSigsToSchemaTemplateItems( namedSignatures: NamedEventSignature[] ) { const schemasByNamespace: Record<string, Schema[]> = this.mapEventSigsToSchemasByNamepace(namedSignatures) const schemaTemplateItemBuilder = new SchemaTemplateItemBuilder('Cli') const schemaItems: SchemaTemplateItem[] = schemaTemplateItemBuilder.buildTemplateItems( schemasByNamespace, '#spruce/events' ) return schemaItems } private mapEventSigsToSchemasByNamepace( namedSignatures: NamedEventSignature[] ) { const schemasByNamespace: Record<string, Schema[]> = {} for (const namedSig of namedSignatures) { const namespacePascal = this.sigToNamespacePascal(namedSig) const { emitPayloadSchema, responsePayloadSchema } = namedSig.signature if (!schemasByNamespace[namespacePascal]) { schemasByNamespace[namespacePascal] = [] } if (emitPayloadSchema) { schemasByNamespace[namespacePascal].push({ version: namedSig.version, ...emitPayloadSchema, }) } if (responsePayloadSchema) { schemasByNamespace[namespacePascal].push({ version: namedSig.version, ...responsePayloadSchema, }) } } return schemasByNamespace } private sigToNamespacePascal(namedSig: NamedEventSignature) { return namesUtil.toPascal( namedSig.eventNamespace ?? MERCURY_API_NAMESPACE ) } }