From c67aa390ddf0a50d2fa4d3631c78588df74b972c Mon Sep 17 00:00:00 2001 From: Will Osborne Date: Fri, 25 Oct 2024 15:38:06 +0100 Subject: [PATCH] #486 clean up functions and split property instantiation --- .../generate/components/instantiate.ts | 8 ++- .../commands/generate/components/metadata.ts | 1 - .../commands/generate/components/node.spec.ts | 2 +- cli/src/commands/generate/components/node.ts | 54 ------------------- .../generate/components/property.spec.ts | 39 +++++++------- .../commands/generate/components/property.ts | 10 +++- .../generate/components/relationship.ts | 1 - 7 files changed, 37 insertions(+), 78 deletions(-) diff --git a/cli/src/commands/generate/components/instantiate.ts b/cli/src/commands/generate/components/instantiate.ts index 3b57f3cce..3441fc508 100644 --- a/cli/src/commands/generate/components/instantiate.ts +++ b/cli/src/commands/generate/components/instantiate.ts @@ -2,7 +2,7 @@ import { Logger } from "winston"; import { initLogger } from "../../helper.js"; import { SchemaDirectory } from "../schema-directory.js"; import { appendPath, logRequiredMessage, mergeSchemas, renderPath } from "../util.js"; -import { getPropertyValue } from "./property.js"; +import { getConstValue, getPropertyValue } from "./property.js"; export function instantiateGenericObject(definition: object, schemaDirectory: SchemaDirectory, objectType: string, path: string[], debug: boolean = false, instantiateAll: boolean = false): object { const logger = initLogger(debug); @@ -13,6 +13,7 @@ export function instantiateGenericObject(definition: object, schemaDirectory: Sc fullDefinition = mergeSchemas(schemaDef, definition); } + // TODO rework to properly separate 'verbose' from 'debug' level logging // logger.debug('Generating ' + objectType + ' object from ' + JSON.stringify(fullDefinition)); if (!('properties' in fullDefinition)) { @@ -28,11 +29,14 @@ export function instantiateGenericObject(definition: object, schemaDirectory: Sc const renderedPath = renderPath(currentPath); if (!instantiateAll && required && !required.includes(key)) { // TODO should we always do interfaces even if not required? + if (key === 'interfaces') { + logger.warn(`${renderedPath}: 'interfaces' property was not marked as required. You might be missing some values if this object has interfaces defined.`) + } logger.debug(`${renderedPath}: Skipping property ${key} as it is not marked as required.`); continue; } if (!!detail?.const) { - out[key] = getPropertyValue(key, detail); + out[key] = getConstValue(detail); } else if (detail?.type === 'object') { // recursive instantiation diff --git a/cli/src/commands/generate/components/metadata.ts b/cli/src/commands/generate/components/metadata.ts index aa369f746..4c8827935 100644 --- a/cli/src/commands/generate/components/metadata.ts +++ b/cli/src/commands/generate/components/metadata.ts @@ -2,7 +2,6 @@ import { initLogger } from '../../helper.js'; import { SchemaDirectory } from '../schema-directory.js'; import { appendPath, logRequiredMessage, mergeSchemas } from '../util.js'; import { instantiateGenericObject } from './instantiate.js'; -import { getPropertyValue } from './property.js'; export function instantiateMetadataObject(definition: object, schemaDirectory: SchemaDirectory, path: string[], debug: boolean = false, instantiateAll: boolean = false): object { return instantiateGenericObject(definition, schemaDirectory, 'metadata', path, debug, instantiateAll); diff --git a/cli/src/commands/generate/components/node.spec.ts b/cli/src/commands/generate/components/node.spec.ts index 032c961d1..d1377dfca 100644 --- a/cli/src/commands/generate/components/node.spec.ts +++ b/cli/src/commands/generate/components/node.spec.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { SchemaDirectory } from '../schema-directory'; -import { instantiateNodeInterfaces, instantiateNodes } from './node'; +import { instantiateNodes } from './node'; jest.mock('../../helper', () => { return { diff --git a/cli/src/commands/generate/components/node.ts b/cli/src/commands/generate/components/node.ts index afe5b83ff..d1cf3a85e 100644 --- a/cli/src/commands/generate/components/node.ts +++ b/cli/src/commands/generate/components/node.ts @@ -4,7 +4,6 @@ import { initLogger } from '../../helper.js'; import { SchemaDirectory } from '../schema-directory.js'; import { appendPath, logRequiredMessage, mergeSchemas } from '../util.js'; import { instantiateGenericObject } from './instantiate.js'; -import { getPropertyValue } from './property.js'; /** * Instantiate an individual node from its definition, resolving $refs if appropriate. @@ -41,57 +40,4 @@ export function instantiateNodes(pattern: any, schemaDirectory: SchemaDirectory, outputNodes.push(instantiateNode(node, schemaDirectory, path, debug, instantiateAll)); } return outputNodes; -} - -// TODO remove all this -/** - * Instantiate an individual interface on a node. - * @param interfaceDef The definition of the interface. - * @param schemaDirectory The schema directory to resolve refs against. - * @param debug Whether to log debug detail. - * @returns An instantiated interface. - */ -export function instantiateInterface(interfaceDef: object, schemaDirectory: SchemaDirectory, debug: boolean = false, instantiateAll: boolean = false): object { - const logger = initLogger(debug); - let fullDefinition = interfaceDef; - if (interfaceDef['$ref']) { - const ref = interfaceDef['$ref']; - const schemaDef = schemaDirectory.getDefinition(ref); - - fullDefinition = mergeSchemas(schemaDef, interfaceDef); - } - - logger.debug('Generating interface from ' + JSON.stringify(fullDefinition, undefined, 2)); - - if (!('properties' in fullDefinition)) { - return {}; - } - - const required = fullDefinition['required']; - logRequiredMessage(logger, required, instantiateAll); - - const out = {}; - for (const [key, detail] of Object.entries(fullDefinition['properties'])) { - if (!instantiateAll && required && !required.includes(key)) { - logger.debug('Skipping property ' + key + ' as it is not marked as required.'); - continue; - } - out[key] = getPropertyValue(key, detail); - } - - return out; -} - -export function instantiateNodeInterfaces(detail: any, schemaDirectory: SchemaDirectory, debug: boolean = false, instantiateAll: boolean = false): any[] { - const interfaces = []; - if (!('prefixItems' in detail)) { - return []; - } - - const interfaceDefs = detail.prefixItems; - for (const interfaceDef of interfaceDefs) { - interfaces.push(instantiateInterface(interfaceDef, schemaDirectory, debug, instantiateAll)); - } - - return interfaces; } \ No newline at end of file diff --git a/cli/src/commands/generate/components/property.spec.ts b/cli/src/commands/generate/components/property.spec.ts index 0a5b6286d..6594e3904 100644 --- a/cli/src/commands/generate/components/property.spec.ts +++ b/cli/src/commands/generate/components/property.spec.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { getPropertyValue } from './property'; +import { getConstValue, getPropertyValue } from './property'; jest.mock('../../helper', () => { return { @@ -13,30 +13,16 @@ jest.mock('../../helper', () => { }; }); -describe('getPropertyValue', () => { - it('generates string placeholder name from variable', () => { - expect(getPropertyValue('key-name', { - 'type': 'string' - })) - .toBe('{{ KEY_NAME }}'); - }); - - it('generates integer placeholder from variable', () => { - expect(getPropertyValue('key-name', { - 'type': 'integer' - })) - .toBe(-1); - }); - +describe('getConstValue', () => { it('generates const value if const is provided', () => { - expect(getPropertyValue('key-name', { + expect(getConstValue({ 'const': 'Example value' })) .toBe('Example value'); }); it('generates const value with entire subtree if const is provided', () => { - expect(getPropertyValue('key-name', { + expect(getConstValue({ 'const': { 'connects': { 'source': 'source', @@ -51,6 +37,23 @@ describe('getPropertyValue', () => { } }); }); +}) + +describe('getPropertyValue', () => { + it('generates string placeholder name from variable', () => { + expect(getPropertyValue('key-name', { + 'type': 'string' + })) + .toBe('{{ KEY_NAME }}'); + }); + + it('generates integer placeholder from variable', () => { + expect(getPropertyValue('key-name', { + 'type': 'integer' + })) + .toBe(-1); + }); + it('generates array with single string placeholder', () => { expect(getPropertyValue('key-name', { diff --git a/cli/src/commands/generate/components/property.ts b/cli/src/commands/generate/components/property.ts index 787739722..0cec50fb6 100644 --- a/cli/src/commands/generate/components/property.ts +++ b/cli/src/commands/generate/components/property.ts @@ -16,8 +16,16 @@ interface Detail { $ref?: string } +/** + * Simply return the value of the const object when instantiating a const. + * @param detail The detail from the object to instantiate + * @returns Either the value or the object described by the 'const' property. + */ +export function getConstValue(detail: Detail) : string | object { + return detail.const; +} + export function getPropertyValue(keyName: string, detail: Detail): string | string[] | number | object { - // should be able to instantiate not just a simple enum type but also a whole sub-object // if both const and type are defined, prefer const if (detail.const) { return detail.const; diff --git a/cli/src/commands/generate/components/relationship.ts b/cli/src/commands/generate/components/relationship.ts index 321f47203..4054e8a30 100644 --- a/cli/src/commands/generate/components/relationship.ts +++ b/cli/src/commands/generate/components/relationship.ts @@ -4,7 +4,6 @@ import { initLogger } from '../../helper.js'; import { SchemaDirectory } from '../schema-directory.js'; import { appendPath, logRequiredMessage, mergeSchemas } from '../util.js'; import { instantiateGenericObject } from './instantiate.js'; -import { getPropertyValue } from './property.js'; /**