@sprucelabs/spruce-cli
Version:
Command line interface for building Spruce skills.
510 lines (475 loc) • 16.6 kB
text/typescript
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()
}
()
protected static async canCreateNewItemBuilder() {
assert.isTruthy(this.itemBuilder)
}
()
protected static async hasGenerateFunction() {
assert.isFunction(this.itemBuilder.buildTemplateItems)
}
()
protected static turnsSingleContractIntoTemplateItem() {
const { eventContractTemplateItems } =
this.itemBuilder.buildTemplateItems({
contracts: [bookContract],
localNamespace: 'test-namespace',
})
const actual = eventContractTemplateItems[0]
assert.isEqualDeep(actual, didBookTemplateItem)
}
(
'builds emit payload schema into a template item',
[contractWithEmitPayload],
[expectedContractWithEmitPayloadTemplateItem],
[
relatedToRelatedToProximitySchemaTemplateItem,
relatedToProximitySchemaTemplateItem,
proximityEmitPayloadTemplateItem,
]
)
(
'turns 1 contract with 2 event signature into 2 template items',
[contractWith2Signatures],
[didBookTemplateItem, willBookTemplateItem]
)
(
'turns 2 contract with 2 event signature into 4 template items',
[contractWith2Signatures, contractWith2Signatures],
[
didBookTemplateItem,
didBookTemplateItem,
willBookTemplateItem,
willBookTemplateItem,
]
)
(
'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)
}
()
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)
}
()
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')
}
()
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
)
}
}