Skip to content

Commit

Permalink
Merge pull request #180 from willosborne/references-same-document
Browse files Browse the repository at this point in the history
Resolve top level references against the pattern itself and only instantiate required properties
  • Loading branch information
willosborne authored May 2, 2024
2 parents 2024438 + 9e25be9 commit 6b11104
Show file tree
Hide file tree
Showing 14 changed files with 267 additions and 45 deletions.
1 change: 1 addition & 0 deletions cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ Options:
-p, --pattern <source> Path to the pattern file to use. May be a file path or a URL.
-o, --output <output> Path location at which to output the generated file.
-s, --schemaDirectory <path> Path to a directory of schemas to be used when instantiating patterns.
-a, --instantiateAll Instantiate ALL properties in the pattern, ignoring the 'required' field. (default: false)
-v, --verbose Enable verbose logging. (default: false)
-h, --help display help for command
```
Expand Down
66 changes: 52 additions & 14 deletions cli/src/commands/generate/components/node.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ beforeEach(() => {
mockSchemaDir = new SchemaDirectory('directory');
});

function getSamplePatternNode(properties: any): any {
function getSamplePatternNode(properties: any, required: any = []): any {
return {
properties: {
nodes: {
type: 'array',
prefixItems: [
{
properties: properties
properties: properties,
required: required
}
]
}
Expand All @@ -39,13 +40,13 @@ function getSamplePatternNode(properties: any): any {


describe('instantiateNodes', () => {
it('return instantiated node with array property', () => {
it('return instantiated required node with array property', () => {
const pattern = getSamplePatternNode({
'property-name': {
type: 'array'
}
});
expect(instantiateNodes(pattern, mockSchemaDir))
expect(instantiateNodes(pattern, mockSchemaDir, false, true))
.toEqual(
[{
'property-name': [
Expand All @@ -62,7 +63,7 @@ describe('instantiateNodes', () => {
}
});

expect(instantiateNodes(pattern, mockSchemaDir))
expect(instantiateNodes(pattern, mockSchemaDir, false, true))
.toEqual([
{
'property-name': '{{ PROPERTY_NAME }}'
Expand All @@ -77,7 +78,25 @@ describe('instantiateNodes', () => {
}
});

expect(instantiateNodes(pattern, mockSchemaDir))
expect(instantiateNodes(pattern, mockSchemaDir, false, true))
.toEqual([
{
'property-name': 'value here'
}
]);
});

it('only instantiate required properties when instantiateAll set to false', () => {
const pattern = getSamplePatternNode({
'property-name': {
const: 'value here'
},
'other-property': {
const: 'should-be-ignored'
}
}, ['property-name']);

expect(instantiateNodes(pattern, mockSchemaDir, false, false))
.toEqual([
{
'property-name': 'value here'
Expand Down Expand Up @@ -109,7 +128,7 @@ describe('instantiateNodes', () => {
}
});

expect(instantiateNodes(pattern, mockSchemaDir))
expect(instantiateNodes(pattern, mockSchemaDir, false, true))
.toEqual([
{
'property-name': 'value here'
Expand Down Expand Up @@ -162,18 +181,19 @@ describe('instantiateNodes', () => {
}
];

expect(instantiateNodes(pattern, mockSchemaDir))
expect(instantiateNodes(pattern, mockSchemaDir, false, false))
.toEqual(expected);

});
});


function getSampleNodeInterfaces(properties: any): any {
function getSampleNodeInterfaces(properties: any, required: string[] = []): any {
return {
prefixItems: [
{
properties: properties
properties: properties,
required: required
}
]
};
Expand All @@ -188,7 +208,7 @@ describe('instantiateNodeInterfaces', () => {
type: 'array'
}
});
expect(instantiateNodeInterfaces(pattern, mockSchemaDir))
expect(instantiateNodeInterfaces(pattern, mockSchemaDir, false, true))
.toEqual(
[{
'property-name': [
Expand All @@ -205,7 +225,7 @@ describe('instantiateNodeInterfaces', () => {
}
});

expect(instantiateNodeInterfaces(pattern, mockSchemaDir))
expect(instantiateNodeInterfaces(pattern, mockSchemaDir, false, true))
.toEqual([
{
'property-name': '{{ PROPERTY_NAME }}'
Expand All @@ -220,7 +240,25 @@ describe('instantiateNodeInterfaces', () => {
}
});

expect(instantiateNodeInterfaces(pattern, mockSchemaDir))
expect(instantiateNodeInterfaces(pattern, mockSchemaDir, false, true))
.toEqual([
{
'property-name': 'value here'
}
]);
});

it('only instantiate required properties when instantiateAll set to false', () => {
const pattern = getSampleNodeInterfaces({
'property-name': {
const: 'value here'
},
'ignored-prop': {
const: 'value here'
}
}, ['property-name']);

expect(instantiateNodeInterfaces(pattern, mockSchemaDir, false, false))
.toEqual([
{
'property-name': 'value here'
Expand Down Expand Up @@ -248,7 +286,7 @@ describe('instantiateNodeInterfaces', () => {
}
});

expect(instantiateNodeInterfaces(pattern, mockSchemaDir))
expect(instantiateNodeInterfaces(pattern, mockSchemaDir, false, true))
.toEqual([
{
'property-name': 'value here'
Expand Down
35 changes: 25 additions & 10 deletions cli/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 { mergeSchemas } from '../util.js';
import { logRequiredMessage, mergeSchemas } from '../util.js';
import { getPropertyValue } from './property.js';

/**
Expand All @@ -12,7 +12,7 @@ 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): any {
export function instantiateNode(nodeDef: any, schemaDirectory: SchemaDirectory, debug: boolean = false, instantiateAll: boolean = false): any {
const logger = initLogger(debug);
let fullDefinition = nodeDef;
if (nodeDef['$ref']) {
Expand All @@ -27,15 +27,22 @@ export function instantiateNode(nodeDef: any, schemaDirectory: SchemaDirectory,
return {};
}

const required = fullDefinition['required'];
logRequiredMessage(logger, required, instantiateAll);

const out = {};
for (const [key, detail] of Object.entries(fullDefinition['properties'])) {
if (key === 'interfaces') {
const interfaces = instantiateNodeInterfaces(detail, schemaDirectory, debug);
const interfaces = instantiateNodeInterfaces(detail, schemaDirectory, debug, instantiateAll);
out['interfaces'] = interfaces;
continue;
}
else {
out[key] = getPropertyValue(key, detail);

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;
}
Expand All @@ -47,7 +54,7 @@ export function instantiateNode(nodeDef: any, schemaDirectory: SchemaDirectory,
* @param debug Whether to log debug detail.
* @returns An array of instantiated nodes.
*/
export function instantiateNodes(pattern: any, schemaDirectory: SchemaDirectory, debug: boolean = false): any {
export function instantiateNodes(pattern: any, schemaDirectory: SchemaDirectory, debug: boolean = false, instantiateAll: boolean = false): any {
const logger = initLogger(debug);
const nodes = pattern?.properties?.nodes?.prefixItems;
if (!nodes) {
Expand All @@ -60,7 +67,7 @@ export function instantiateNodes(pattern: any, schemaDirectory: SchemaDirectory,
const outputNodes = [];

for (const node of nodes) {
outputNodes.push(instantiateNode(node, schemaDirectory));
outputNodes.push(instantiateNode(node, schemaDirectory, debug, instantiateAll));
}
return outputNodes;
}
Expand All @@ -72,7 +79,7 @@ export function instantiateNodes(pattern: any, schemaDirectory: SchemaDirectory,
* @param debug Whether to log debug detail.
* @returns An instantiated interface.
*/
export function instantiateInterface(interfaceDef: object, schemaDirectory: SchemaDirectory, debug: boolean = false): object {
export function instantiateInterface(interfaceDef: object, schemaDirectory: SchemaDirectory, debug: boolean = false, instantiateAll: boolean = false): object {
const logger = initLogger(debug);
let fullDefinition = interfaceDef;
if (interfaceDef['$ref']) {
Expand All @@ -87,16 +94,24 @@ export function instantiateInterface(interfaceDef: object, schemaDirectory: Sche
if (!('properties' in fullDefinition)) {
return {};
}

const required = fullDefinition['required'];
logRequiredMessage(logger, required, instantiateAll);

const out = {};
for (const [key, detail] of Object.entries(fullDefinition['properties'])) {
// TODO flag to force instantiate all
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): any[] {
export function instantiateNodeInterfaces(detail: any, schemaDirectory: SchemaDirectory, debug: boolean = false, instantiateAll: boolean = false): any[] {
const logger = initLogger(debug);
const interfaces = [];
if (!('prefixItems' in detail)) {
Expand All @@ -106,7 +121,7 @@ export function instantiateNodeInterfaces(detail: any, schemaDirectory: SchemaDi

const interfaceDefs = detail.prefixItems;
for (const interfaceDef of interfaceDefs) {
interfaces.push(instantiateInterface(interfaceDef, schemaDirectory, debug));
interfaces.push(instantiateInterface(interfaceDef, schemaDirectory, debug, instantiateAll));
}

return interfaces;
Expand Down
31 changes: 25 additions & 6 deletions cli/src/commands/generate/components/relationship.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ beforeEach(() => {
mockSchemaDir = new SchemaDirectory('directory');
});

function getSamplePatternRelationship(properties: any): any {
function getSamplePatternRelationship(properties: any, required: string[] = []): any {
return {
properties: {
relationships: {
type: 'array',
prefixItems: [
{
properties: properties
properties: properties,
required: required
}
]
}
Expand All @@ -46,7 +47,7 @@ describe('instantiateRelationships', () => {
}
});

expect(instantiateRelationships(pattern, mockSchemaDir))
expect(instantiateRelationships(pattern, mockSchemaDir, false, true))
.toEqual(
[{
'property-name': [
Expand All @@ -63,7 +64,7 @@ describe('instantiateRelationships', () => {
}
});

expect(instantiateRelationships(pattern, mockSchemaDir))
expect(instantiateRelationships(pattern, mockSchemaDir, false, true))
.toEqual([
{
'property-name': '{{ PROPERTY_NAME }}'
Expand All @@ -78,7 +79,25 @@ describe('instantiateRelationships', () => {
}
});

expect(instantiateRelationships(pattern, mockSchemaDir))
expect(instantiateRelationships(pattern, mockSchemaDir, false, true))
.toEqual([
{
'property-name': 'value here'
}
]);
});

it('only instantiate required properties when instantiateAll set to false', () => {
const pattern = getSamplePatternRelationship({
'property-name': {
const: 'value here'
},
'ignored-prop': {
const: 'value'
}
}, ['property-name']);

expect(instantiateRelationships(pattern, mockSchemaDir, false, false))
.toEqual([
{
'property-name': 'value here'
Expand Down Expand Up @@ -110,7 +129,7 @@ describe('instantiateRelationships', () => {
}
});

expect(instantiateRelationships(pattern, mockSchemaDir))
expect(instantiateRelationships(pattern, mockSchemaDir, false, true))
.toEqual([
{
'property-name': 'value here'
Expand Down
15 changes: 11 additions & 4 deletions cli/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 { mergeSchemas } from '../util.js';
import { logRequiredMessage, mergeSchemas } from '../util.js';
import { getPropertyValue } from './property.js';


Expand All @@ -13,7 +13,7 @@ import { getPropertyValue } from './property.js';
* @param debug Whether to log debug detail
* @returns An instantiated relationship.
*/
function instantiateRelationship(relationshipDef: object, schemaDirectory: SchemaDirectory, debug: boolean = false): object {
function instantiateRelationship(relationshipDef: object, schemaDirectory: SchemaDirectory, debug: boolean = false, instantiateAll: boolean = false): object {
const logger = initLogger(debug);
let fullDefinition = relationshipDef;
if (relationshipDef['$ref']) {
Expand All @@ -27,10 +27,17 @@ function instantiateRelationship(relationshipDef: object, schemaDirectory: Schem
return {};
}

const required = fullDefinition['required'];

logger.debug('Generating interface from ' + JSON.stringify(fullDefinition, undefined, 2));
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);
}

Expand All @@ -44,7 +51,7 @@ function instantiateRelationship(relationshipDef: object, schemaDirectory: Schem
* @param debug Whether to log debug detail.
* @returns An array of instantiated relationships.
*/
export function instantiateRelationships(pattern: any, schemaDirectory: SchemaDirectory, debug: boolean = false): any {
export function instantiateRelationships(pattern: any, schemaDirectory: SchemaDirectory, debug: boolean = false, instantiateAll: boolean = false): any {
const logger = initLogger(debug);
const relationships = pattern?.properties?.relationships?.prefixItems;

Expand All @@ -58,7 +65,7 @@ export function instantiateRelationships(pattern: any, schemaDirectory: SchemaDi

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

return outputRelationships;
Expand Down
Loading

0 comments on commit 6b11104

Please sign in to comment.