Skip to content

Commit

Permalink
finos#486 add path context to generate command logging
Browse files Browse the repository at this point in the history
  • Loading branch information
willosborne authored and Will Osborne committed Nov 14, 2024
1 parent 0bb10f8 commit f88a2df
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 79 deletions.
80 changes: 19 additions & 61 deletions shared/src/commands/generate/components/instantiate.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Logger } from "winston";
import { initLogger } from "../../helper.js";
import { SchemaDirectory } from "../schema-directory.js";
import { logRequiredMessage, mergeSchemas } from "../util.js";
import { appendPath, logRequiredMessage, mergeSchemas, renderPath } from "../util.js";
import { getPropertyValue } from "./property.js";

export function instantiateGenericObject(definition: object, schemaDirectory: SchemaDirectory, objectType: string, debug: boolean = false, instantiateAll: boolean = false): object {
export function instantiateGenericObject(definition: object, schemaDirectory: SchemaDirectory, objectType: string, path: string[], debug: boolean = false, instantiateAll: boolean = false): object {
const logger = initLogger(debug);
let fullDefinition = definition;
if (definition['$ref']) {
Expand All @@ -24,24 +24,27 @@ export function instantiateGenericObject(definition: object, schemaDirectory: Sc

const out = {};
for (const [key, detail] of Object.entries(fullDefinition['properties'])) {
const currentPath = appendPath(path, key);
const renderedPath = renderPath(currentPath);

if (!instantiateAll && required && !required.includes(key)) { // TODO should we always do interfaces even if not required?
logger.debug('Skipping property ' + key + ' as it is not marked as required.');
logger.debug(`${renderedPath}: Skipping property ${key} as it is not marked as required.`);
continue;
}
if (!!detail?.const) {
out[key] = getPropertyValue(key, detail);
}
if (detail?.type === 'object') {
// recursive instantiation
logger.info('Recursively instantiating an ' + objectType + ' object');
out[key] = instantiateGenericObject(detail, schemaDirectory, objectType, instantiateAll, debug);
logger.info(`${renderedPath}: Recursively instantiating an ${objectType} object`);
out[key] = instantiateGenericObject(detail, schemaDirectory, objectType, currentPath, instantiateAll, debug);
}
else if (detail?.type === 'array' && isArrayObjectComplex(detail, logger)) {
logger.info('Recursively instantiating an array object.');
else if (detail?.type === 'array' && isArrayObjectComplex(detail, logger, renderedPath)) {
logger.info(`${renderedPath}: Recursively instantiating an array object.`);

// isArrayObjectComplex ensures this is present
const prefixItems = detail.prefixItems;
out[key] = instantiateArray(prefixItems, schemaDirectory, objectType, instantiateAll, debug);
out[key] = instantiateArray(prefixItems, schemaDirectory, objectType, currentPath, instantiateAll, debug);
}
else {
out[key] = getPropertyValue(key, detail);
Expand All @@ -50,22 +53,19 @@ export function instantiateGenericObject(definition: object, schemaDirectory: Sc
return out;
}

function isArrayObjectComplex(detail: any, logger: Logger) {
console.log(detail)
function isArrayObjectComplex(detail: any, logger: Logger, pathContext: string) {
if (!detail) {
return false;
}

console.log(detail)

const arrayContentsType = detail.items?.type
if (!!arrayContentsType && ['integer', 'number', 'boolean', 'string', 'const'].includes(arrayContentsType)) {
logger.info('Skipping recursive instantiation of array as it has a simple type and no prefixItems')
logger.info(`${pathContext}: Skipping recursive instantiation of array as it has a simple type and no prefixItems`)
return false
}

if (!!detail.prefixItems && !!detail.items) {
logger.warn("Both 'items' and 'prefixItems' are defined on this array schema; only prefixItems will be instantiated.")
logger.warn(`${pathContext}: Both 'items' and 'prefixItems' are defined on this array schema; only prefixItems will be instantiated.`)
}

if (!!detail.prefixItems) {
Expand All @@ -77,57 +77,15 @@ function isArrayObjectComplex(detail: any, logger: Logger) {
return false;
}

export function instantiateArray(prefixItems: object[], schemaDirectory: SchemaDirectory, objectType: string, instantiateAll: boolean, debug: boolean) {
export function instantiateArray(prefixItems: object[], schemaDirectory: SchemaDirectory, objectType: string, path: string[], instantiateAll: boolean, debug: boolean) {
const logger = initLogger(debug);
const output = [];

logger.debug("Instantiating elements of array as defined in prefixItems")
for (const item of prefixItems) {
output.push(instantiateGenericObject(item, schemaDirectory, objectType, debug, instantiateAll));
logger.debug(`${path}: Instantiating elements of array as defined in prefixItems`)
for (const [index, element] of prefixItems.entries()) {
const currentPath = appendPath(path, index)
output.push(instantiateGenericObject(element, schemaDirectory, objectType, currentPath, debug, instantiateAll));
}

return output;
}

export function instantiateArrayObject(definition: object, schemaDirectory: SchemaDirectory, objectType: string, debug: boolean = false, instantiateAll: boolean = false): object {
const logger = initLogger(debug);
let fullDefinition = definition;
if (definition['$ref']) {
const ref = definition['$ref'];
const schemaDef = schemaDirectory.getDefinition(ref);

fullDefinition = mergeSchemas(schemaDef, definition);
}
logger.debug('Generating ' + objectType + ' object from ' + JSON.stringify(fullDefinition));

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;
}
if (detail?.type === 'object') {
// recursive instantiation
logger.debug('Recursively instantiating an ' + objectType + ' object');
out[key] = instantiateGenericObject(detail, schemaDirectory, objectType, instantiateAll, debug);
}
else if (detail?.type === 'array') {
if (key === 'interfaces')
logger.debug('Instantiating interfaces for a node object.');
else
logger.debug('Recursively instantiating an array object.');

}
else {
out[key] = getPropertyValue(key, detail);
}
}
return out;
}
6 changes: 3 additions & 3 deletions shared/src/commands/generate/components/metadata.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('instantiateMetadataObject', () => {
}
}
};
expect(instantiateMetadataObject(metadataDef, mockSchemaDir, false, true))
expect(instantiateMetadataObject(metadataDef, mockSchemaDir, [], false, true))
.toEqual(
{
'string-prop': '{{ STRING_PROP }}',
Expand All @@ -65,7 +65,7 @@ describe('instantiateMetadataObject', () => {
}
}
};
expect(instantiateMetadataObject(metadataDef, mockSchemaDir, false, true))
expect(instantiateMetadataObject(metadataDef, mockSchemaDir, [], false, true))
.toEqual(
{
'property-name': {
Expand Down Expand Up @@ -99,7 +99,7 @@ describe('instantiateMetadataObject', () => {
spy.mockReturnValue(returnedDef);


expect(instantiateMetadataObject(metadataDef, mockSchemaDir, false, true))
expect(instantiateMetadataObject(metadataDef, mockSchemaDir, [], false, true))
.toEqual(
{
'property-name': {
Expand Down
11 changes: 6 additions & 5 deletions shared/src/commands/generate/components/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { initLogger } from '../../helper.js';
import { SchemaDirectory } from '../schema-directory.js';
import { logRequiredMessage, mergeSchemas } from '../util.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, debug: boolean = false, instantiateAll: boolean = false): object {
return instantiateGenericObject(definition, schemaDirectory, 'metadata', debug, instantiateAll);
export function instantiateMetadataObject(definition: object, schemaDirectory: SchemaDirectory, path: string[], debug: boolean = false, instantiateAll: boolean = false): object {
return instantiateGenericObject(definition, schemaDirectory, 'metadata', path, debug, instantiateAll);
}

export function instantiateAllMetadata(pattern: object, schemaDirectory: SchemaDirectory, debug: boolean = false, instantiateAll: boolean = false): object[] {
Expand All @@ -20,8 +20,9 @@ export function instantiateAllMetadata(pattern: object, schemaDirectory: SchemaD
}
const outputMetadata = [];

for (const node of metadataObjects) {
outputMetadata.push(instantiateMetadataObject(node, schemaDirectory, debug, instantiateAll));
for (const [index, metadataObj] of metadataObjects.entries()) {
const path = appendPath(['metadata'], index);
outputMetadata.push(instantiateMetadataObject(metadataObj, schemaDirectory, path, debug, instantiateAll));
}
return outputMetadata;
}
11 changes: 6 additions & 5 deletions shared/src/commands/generate/components/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { initLogger } from '../../helper.js';
import { SchemaDirectory } from '../schema-directory.js';
import { logRequiredMessage, mergeSchemas } from '../util.js';
import { appendPath, logRequiredMessage, mergeSchemas } from '../util.js';
import { instantiateGenericObject } from './instantiate.js';
import { getPropertyValue } from './property.js';

Expand All @@ -13,8 +13,8 @@ import { getPropertyValue } from './property.js';
* @param debug Whether to log debug detail.
* @returns An instantiated node.
*/
export function instantiateNode(nodeDef: any, schemaDirectory: SchemaDirectory, debug: boolean = false, instantiateAll: boolean = false): any {
return instantiateGenericObject(nodeDef, schemaDirectory, 'node', debug, instantiateAll);
export function instantiateNode(nodeDef: any, schemaDirectory: SchemaDirectory, path: string[], debug: boolean = false, instantiateAll: boolean = false): any {
return instantiateGenericObject(nodeDef, schemaDirectory, 'node', path, debug, instantiateAll);
}

/**
Expand All @@ -36,8 +36,9 @@ export function instantiateNodes(pattern: any, schemaDirectory: SchemaDirectory,
}
const outputNodes = [];

for (const node of nodes) {
outputNodes.push(instantiateNode(node, schemaDirectory, debug, instantiateAll));
for (const [index, node] of nodes.entries()) {
const path = appendPath(['nodes'], index)
outputNodes.push(instantiateNode(node, schemaDirectory, path, debug, instantiateAll));
}
return outputNodes;
}
Expand Down
12 changes: 7 additions & 5 deletions shared/src/commands/generate/components/relationship.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { initLogger } from '../../helper.js';
import { SchemaDirectory } from '../schema-directory.js';
import { logRequiredMessage, mergeSchemas } from '../util.js';
import { appendPath, logRequiredMessage, mergeSchemas } from '../util.js';
import { instantiateGenericObject } from './instantiate.js';
import { getPropertyValue } from './property.js';

Expand All @@ -11,11 +11,12 @@ import { getPropertyValue } from './property.js';
* Instantiates an individual relationship.
* @param relationshipDef The relationship definition to instantiate
* @param schemaDirectory The schema directory to resolve refs against.
* @param path The current path in the document, for logging purposes.
* @param debug Whether to log debug detail
* @returns An instantiated relationship.
*/
function instantiateRelationship(relationshipDef: object, schemaDirectory: SchemaDirectory, debug: boolean = false, instantiateAll: boolean = false): object {
return instantiateGenericObject(relationshipDef, schemaDirectory, 'relationship', debug, instantiateAll);
function instantiateRelationship(relationshipDef: object, schemaDirectory: SchemaDirectory, path: string[], debug: boolean = false, instantiateAll: boolean = false): object {
return instantiateGenericObject(relationshipDef, schemaDirectory, 'relationship', path, debug, instantiateAll);
}

/**
Expand All @@ -38,8 +39,9 @@ export function instantiateRelationships(pattern: any, schemaDirectory: SchemaDi
}

const outputRelationships = [];
for (const relationship of relationships) {
outputRelationships.push(instantiateRelationship(relationship, schemaDirectory, debug, instantiateAll));
for (const [index, relationship] of relationships.entries()) {
const path = appendPath(['relationships'], index);
outputRelationships.push(instantiateRelationship(relationship, schemaDirectory, path, debug, instantiateAll));
}

return outputRelationships;
Expand Down
9 changes: 9 additions & 0 deletions shared/src/commands/generate/util.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import _ from 'lodash';
import { Logger } from 'winston';
import pointer from 'json-pointer';

/**
* Recursively merge two schemas into a new object, without modifying either.
Expand All @@ -24,4 +25,12 @@ export function logRequiredMessage(logger: Logger, required: string[], instantia
} else {
logger.debug('Required properties: ' + required);
}
}

export function appendPath(path: string[], element) : string[] {
return [...path, element];
}

export function renderPath(path: string[]): string {
return pointer.compile(path);
}

0 comments on commit f88a2df

Please sign in to comment.