UNPKG

@sprucelabs/spruce-cli

Version:

Command line interface for building Spruce skills.

510 lines (475 loc) • 16.6 kB
import { coreEventContracts } from '@sprucelabs/mercury-core-events' import { EventContract } from '@sprucelabs/mercury-types' import { buildSchema, SchemaTemplateItem } from '@sprucelabs/schema' import { MERCURY_API_NAMESPACE, namesUtil, versionUtil, } from '@sprucelabs/spruce-skill-utils' import { EventContractTemplateItem } from '@sprucelabs/spruce-templates' import { test, assert } from '@sprucelabs/test-utils' import EventTemplateItemBuilder from '../../templateItemBuilders/EventTemplateItemBuilder' import AbstractCliTest from '../../tests/AbstractCliTest' const expectedVersion = versionUtil.generateVersion().dirValue const bookContract: EventContract = { eventSignatures: { [`did-book::${expectedVersion}`]: {}, }, } const contractWith2Signatures: EventContract = { eventSignatures: { [`did-book::${expectedVersion}`]: {}, [`will-book::${expectedVersion}`]: {}, }, } const contractWith2NamespacedSignatures: EventContract = { eventSignatures: { [`appointments.did-book::${expectedVersion}`]: {}, [`appointments.will-book::${expectedVersion}`]: {}, }, } const didBookTemplateItem: EventContractTemplateItem = { version: expectedVersion, namePascal: 'DidBook', nameCamel: 'didBook', isLocal: false, namespace: namesUtil.toKebab(MERCURY_API_NAMESPACE), namespaceCamel: namesUtil.toCamel(MERCURY_API_NAMESPACE), namespacePascal: namesUtil.toPascal(MERCURY_API_NAMESPACE), imports: [ { importAs: '{ buildEventContract }', package: '@sprucelabs/mercury-types', }, ], eventSignatures: { [`did-book::${expectedVersion}`]: {}, }, } const willBookTemplateItem: EventContractTemplateItem = { version: expectedVersion, namePascal: 'WillBook', nameCamel: 'willBook', isLocal: false, namespace: namesUtil.toKebab(MERCURY_API_NAMESPACE), imports: [ { importAs: '{ buildEventContract }', package: '@sprucelabs/mercury-types', }, ], namespaceCamel: namesUtil.toCamel(MERCURY_API_NAMESPACE), namespacePascal: namesUtil.toPascal(MERCURY_API_NAMESPACE), eventSignatures: { [`will-book::${expectedVersion}`]: {}, }, } const didBookWithNamespaceTemplateItem: EventContractTemplateItem = { version: expectedVersion, namePascal: 'DidBook', nameCamel: 'didBook', isLocal: true, namespace: 'appointments', namespaceCamel: 'appointments', namespacePascal: 'Appointments', imports: [ { importAs: '{ buildEventContract }', package: '@sprucelabs/mercury-types', }, ], eventSignatures: { [`appointments.did-book::${expectedVersion}`]: {}, }, } const willBookWithNamespaceTemplateItem: EventContractTemplateItem = { version: expectedVersion, namePascal: 'WillBook', nameCamel: 'willBook', isLocal: true, namespace: 'appointments', namespaceCamel: 'appointments', namespacePascal: 'Appointments', imports: [ { importAs: '{ buildEventContract }', package: '@sprucelabs/mercury-types', }, ], eventSignatures: { [`appointments.will-book::${expectedVersion}`]: {}, }, } const relatedToRelatedToProximitySchema = buildSchema({ id: 'relatedToRelatedToProximitySchema', version: expectedVersion, fields: { onlyField: { type: 'text', }, }, }) const relatedToRelatedToProximitySchemaTemplateItem: SchemaTemplateItem = { namespace: 'proximity', id: relatedToRelatedToProximitySchema.id, nameCamel: 'relatedToRelatedToProximitySchema', namePascal: 'RelatedToRelatedToProximitySchema', nameReadable: 'relatedToRelatedToProximitySchema', schema: { ...relatedToRelatedToProximitySchema, namespace: 'proximity', }, isNested: true, destinationDir: '#spruce/events', } const relatedToProximitySchema = buildSchema({ version: expectedVersion, id: 'relatedToProximitySchema', fields: { boolField: { type: 'boolean', }, relatedToRelatedSchema: { type: 'schema', options: { schema: relatedToRelatedToProximitySchema, }, }, }, }) const relatedToProximitySchemaTemplateItem: SchemaTemplateItem = { namespace: 'proximity', id: relatedToProximitySchema.id, nameCamel: 'relatedToProximitySchema', namePascal: 'RelatedToProximitySchema', nameReadable: 'relatedToProximitySchema', schema: { id: 'relatedToProximitySchema', namespace: 'proximity', version: expectedVersion, fields: { boolField: { type: 'boolean', }, relatedToRelatedSchema: { type: 'schema', options: { schemaIds: [ { id: 'relatedToRelatedToProximitySchema', namespace: 'proximity', version: expectedVersion, }, ], }, }, }, }, isNested: true, destinationDir: '#spruce/events', } const proximityEmitPayloadSchema = buildSchema({ version: expectedVersion, id: 'proximityEmitPayload', namespace: 'proximity', fields: { textField: { type: 'text', }, relatedSchema: { type: 'schema', options: { schema: relatedToProximitySchema, }, }, }, }) const proximityEmitPayloadTemplateItem: SchemaTemplateItem = { namespace: 'proximity', id: proximityEmitPayloadSchema.id, nameCamel: 'proximityEmitPayload', namePascal: 'ProximityEmitPayload', nameReadable: 'proximityEmitPayload', schema: { id: 'proximityEmitPayload', namespace: 'proximity', version: expectedVersion, fields: { textField: { type: 'text', }, relatedSchema: { type: 'schema', options: { schemaIds: [ { id: 'relatedToProximitySchema', namespace: 'proximity', version: expectedVersion, }, ], }, }, }, }, isNested: false, destinationDir: '#spruce/events', } const contractWithEmitPayload: EventContract = { eventSignatures: { [`proximity.did-enter::${expectedVersion}`]: { emitPayloadSchema: proximityEmitPayloadSchema, }, }, } const expectedContractWithEmitPayloadTemplateItem: EventContractTemplateItem = { namePascal: 'DidEnter', nameCamel: 'didEnter', namespace: 'proximity', isLocal: false, version: expectedVersion, namespaceCamel: 'proximity', namespacePascal: 'Proximity', imports: [ { package: `#spruce/schemas/proximity/${expectedVersion}/proximityEmitPayload.schema`, importAs: 'proximityEmitPayloadSchema', }, { importAs: '{ buildEventContract }', package: '@sprucelabs/mercury-types', }, ], eventSignatures: { [`proximity.did-enter::${expectedVersion}`]: { emitPayloadSchema: { ...proximityEmitPayloadTemplateItem, }, }, }, } export default class EventTemplateItemBuilderTest extends AbstractCliTest { private static itemBuilder: EventTemplateItemBuilder protected static async beforeEach() { await super.beforeEach() this.itemBuilder = new EventTemplateItemBuilder() } @test() protected static async canCreateNewItemBuilder() { assert.isTruthy(this.itemBuilder) } @test() protected static async hasGenerateFunction() { assert.isFunction(this.itemBuilder.buildTemplateItems) } @test() protected static turnsSingleContractIntoTemplateItem() { const { eventContractTemplateItems } = this.itemBuilder.buildTemplateItems({ contracts: [bookContract], localNamespace: 'test-namespace', }) const actual = eventContractTemplateItems[0] assert.isEqualDeep(actual, didBookTemplateItem) } @test( 'builds emit payload schema into a template item', [contractWithEmitPayload], [expectedContractWithEmitPayloadTemplateItem], [ relatedToRelatedToProximitySchemaTemplateItem, relatedToProximitySchemaTemplateItem, proximityEmitPayloadTemplateItem, ] ) @test( 'turns 1 contract with 2 event signature into 2 template items', [contractWith2Signatures], [didBookTemplateItem, willBookTemplateItem] ) @test( 'turns 2 contract with 2 event signature into 4 template items', [contractWith2Signatures, contractWith2Signatures], [ didBookTemplateItem, didBookTemplateItem, willBookTemplateItem, willBookTemplateItem, ] ) @test( 'turns 1 contract with 2 namespaced event signatures to 2 template items', [contractWith2NamespacedSignatures], [didBookWithNamespaceTemplateItem, willBookWithNamespaceTemplateItem] ) protected static generateItems( contracts: EventContract[], expectedEventContractTemplateItems: EventContractTemplateItem[], expectedSchemaTemplateItems: SchemaTemplateItem[] = [] ) { const { eventContractTemplateItems, schemaTemplateItems } = this.itemBuilder.buildTemplateItems({ contracts, localNamespace: 'appointments', }) assert.isEqualDeep( eventContractTemplateItems, expectedEventContractTemplateItems ) assert.isEqualDeep(schemaTemplateItems, expectedSchemaTemplateItems) } @test() protected static canPullEventContractSchemaFromCoreEventContract() { const { schemaTemplateItems } = this.itemBuilder.buildTemplateItems({ contracts: [ { eventSignatures: { 'register-events': coreEventContracts[0].eventSignatures[ 'can-listen::v2020_12_25' ], }, }, ], localNamespace: 'testing', }) const match = schemaTemplateItems.find( (item) => item.id === 'eventSource' ) assert.isTruthy(match) } @test() protected static sortsEventsAlphabetically() { const { eventContractTemplateItems } = this.itemBuilder.buildTemplateItems({ contracts: [ { eventSignatures: { 'zebra-cheeta': {}, 'register-events': coreEventContracts[0].eventSignatures[ 'can-listen::v2020_12_25' ], }, }, ], localNamespace: 'testing', }) assert.isEqual( eventContractTemplateItems[0].nameCamel, 'registerEvents' ) assert.isEqual(eventContractTemplateItems[1].nameCamel, 'zebraCheeta') } @test() protected static eventContractTemplateItemsHaveProperNamespacesImports() { const groupsExpectedImports = [ { package: '#spruce/schemas/groups/v2021_12_01/listEmitTargetAndPayload.schema', importAs: 'listEmitTargetAndPayloadSchema', }, { package: '#spruce/schemas/groups/v2021_12_01/listResponsePayload.schema', importAs: 'listResponsePayloadSchema', }, { importAs: '{ buildEventContract }', package: '@sprucelabs/mercury-types', }, { importAs: '{ buildPermissionContract }', package: '@sprucelabs/mercury-types', }, ] const appointmentsExpectedImports = [ { package: '#spruce/schemas/appointments/v2021_06_23/listEmitTargetAndPayload.schema', importAs: 'listEmitTargetAndPayloadSchema', }, { package: '#spruce/schemas/appointments/v2021_06_23/listResponsePayload.schema', importAs: 'listResponsePayloadSchema', }, { importAs: '{ buildEventContract }', package: '@sprucelabs/mercury-types', }, { importAs: '{ buildPermissionContract }', package: '@sprucelabs/mercury-types', }, ] const { eventContractTemplateItems } = this.itemBuilder.buildTemplateItems({ contracts: [ { eventSignatures: { 'groups.list::v2021_12_01': { emitPayloadSchema: { id: 'listEmitTargetAndPayload', version: 'v2021_12_01', namespace: 'Groups', name: '', fields: {}, }, responsePayloadSchema: { id: 'listResponsePayload', version: 'v2021_12_01', namespace: 'Groups', name: '', fields: {}, }, emitPermissionContract: { id: 'listEmitPermissions', name: 'list', requireAllPermissions: false, permissions: [], }, }, 'appointments.list::v2021_06_23': { emitPayloadSchema: { id: 'listEmitTargetAndPayload', version: 'v2021_06_23', namespace: 'Appointments', name: '', fields: {}, }, responsePayloadSchema: { id: 'listResponsePayload', version: 'v2021_06_23', namespace: 'Appointments', name: '', fields: {}, }, emitPermissionContract: { id: 'listEmitPermissions', name: 'list appointments', requireAllPermissions: false, permissions: [], }, listenPermissionContract: { id: 'listListenPermissions', name: 'list appointments', requireAllPermissions: false, permissions: [], }, }, }, }, ], localNamespace: 'testing', }) assert.isEqualDeep( eventContractTemplateItems[0].imports, groupsExpectedImports ) assert.isEqualDeep( eventContractTemplateItems[1].imports, appointmentsExpectedImports ) } }