Skip to content

Commit

Permalink
feat: split enums and use them as values (#231)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonaslagoni authored Jun 16, 2021
1 parent 3ffe75f commit 9296f51
Show file tree
Hide file tree
Showing 24 changed files with 116 additions and 75 deletions.
2 changes: 1 addition & 1 deletion src/generators/java/presets/JacksonPreset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { JavaPreset } from '../JavaPreset';
export const JAVA_JACKSON_PRESET: JavaPreset = {
class: {
self({renderer, content}) {
renderer.addDependency('import com.fasterxml.jackson.annotations.*;');
renderer.addDependency('import com.fasterxml.jackson.annotation.*;');
return content;
},
getter({ renderer, propertyName, content }) {
Expand Down
2 changes: 1 addition & 1 deletion src/generators/java/renderers/EnumRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ ${this.indent(this.renderBlock(content, 2))}

export const JAVA_DEFAULT_ENUM_PRESET: EnumPreset<EnumRenderer> = {
self({ renderer }) {
renderer.addDependency('import com.fasterxml.jackson.annotations.*;');
renderer.addDependency('import com.fasterxml.jackson.annotation.*;');
return renderer.defaultSelf();
},
item({ renderer, item }) {
Expand Down
2 changes: 1 addition & 1 deletion src/interpreter/InterpretAdditionalProperties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { isModelObject } from './Utils';
* @param interpreterOptions to control the interpret process
*/
export default function interpretAdditionalProperties(schema: Schema, model: CommonModel, interpreter : Interpreter, interpreterOptions: InterpreterOptions = Interpreter.defaultInterpreterOptions): void {
if (!isModelObject(model)) {return;}
if (isModelObject(model) === false) {return;}
const additionalPropertiesModel = interpreter.interpret(schema.additionalProperties || true, interpreterOptions);
if (additionalPropertiesModel !== undefined) {
model.addAdditionalProperty(additionalPropertiesModel, schema);
Expand Down
2 changes: 1 addition & 1 deletion src/interpreter/InterpretAllOf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default function interpretAllOf(schema: Schema, model: CommonModel, inter
for (const allOfSchema of schema.allOf) {
const allOfModel = interpreter.interpret(allOfSchema, interpreterOptions);
if (allOfModel === undefined) {continue;}
if (isModelObject(allOfModel) && interpreterOptions.allowInheritance === true) {
if (isModelObject(allOfModel) === true && interpreterOptions.allowInheritance === true) {
Logger.info(`Processing allOf, inheritance is enabled, ${model.$id} inherits from ${allOfModel.$id}`, model, allOfModel);
model.addExtendedModel(allOfModel);
} else {
Expand Down
19 changes: 9 additions & 10 deletions src/interpreter/Interpreter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CommonModel, Schema } from '../models';
import { interpretName } from './Utils';
import { interpretName, isEnum, isModelObject } from './Utils';
import interpretProperties from './InterpretProperties';
import interpretAllOf from './InterpretAllOf';
import interpretConst from './InterpretConst';
Expand Down Expand Up @@ -59,16 +59,8 @@ export class Interpreter {
if (schema.type !== undefined) {
model.addTypes(schema.type);
}

//All schemas of type object MUST have ids
if (model.type !== undefined && model.type.includes('object')) {
model.$id = interpretName(schema) || `anonymSchema${this.anonymCounter++}`;
} else if (schema.$id !== undefined) {
model.$id = interpretName(schema);
}

model.required = schema.required || model.required;

interpretPatternProperties(schema, model, this, interpreterOptions);
interpretAdditionalProperties(schema, model, this, interpreterOptions);
interpretItems(schema, model, this, interpreterOptions);
Expand All @@ -84,6 +76,13 @@ export class Interpreter {
this.interpretAndCombineSchema(schema.else, model, schema, interpreterOptions);

interpretNot(schema, model, this, interpreterOptions);

//All schemas of type model object or enum MUST have ids
if (isModelObject(model) === true || isEnum(model) === true) {
model.$id = interpretName(schema) || `anonymSchema${this.anonymCounter++}`;
} else if (schema.$id !== undefined) {
model.$id = interpretName(schema);
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/interpreter/PostInterpreter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CommonModel } from '../models';
import { Logger } from '../utils';
import { isModelObject } from './Utils';
import { isEnum, isModelObject } from './Utils';
/**
* Post process the interpreted model. By applying the following:
* - Ensure models are split as required
Expand All @@ -21,7 +21,7 @@ export function postInterpretModel(model: CommonModel): CommonModel[] {
*/
function trySplitModels(model: CommonModel, splitModels: CommonModel[], iteratedModels: CommonModel[]): CommonModel {
let modelToReturn: CommonModel = model;
if (isModelObject(model)) {
if (isModelObject(model) === true || isEnum(model) === true) {
Logger.info(`Splitting model ${model.$id || 'any'} since it should be on its own`);
const switchRootModel = new CommonModel();
switchRootModel.$ref = model.$id;
Expand Down
15 changes: 14 additions & 1 deletion src/interpreter/Utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import { CommonModel } from '../models/CommonModel';

/**
* check if CommonModel is a separate model or a simple model.
* Check if CommonModel is an enum
*
* @param model
*/
export function isEnum(model: CommonModel) : boolean {
if (model.enum !== undefined) {
return true;
}
return false;
}

/**
* Check if CommonModel is a separate model or a simple model.
* @param model
*/
export function isModelObject(model: CommonModel) : boolean {
if (model.type !== undefined) {
Expand Down
15 changes: 8 additions & 7 deletions test/blackbox/Dummy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ describe('Dummy JSON Schema file', () => {
const generator = new JavaGenerator();
const generatedModels = await generateModels(fileToGenerate, generator);
expect(generatedModels).not.toHaveLength(0);
const renderOutputPath = path.resolve(__dirname, './output/java');
const renderOutputPath = path.resolve(__dirname, './output/java/class');
const dependencyPath = path.resolve(__dirname, './dependencies/java/*');
await renderJavaModelsToSeparateFiles(generatedModels, renderOutputPath);
const compileCommand = `javac ${path.resolve(renderOutputPath, '*.java')}`;
const compileCommand = `javac -cp ${dependencyPath} ${path.resolve(renderOutputPath, '*.java')}`;
await execCommand(compileCommand);
});
});
Expand All @@ -22,9 +23,9 @@ describe('Dummy JSON Schema file', () => {
const generator = new TypeScriptGenerator();
const generatedModels = await generateModels(fileToGenerate, generator);
expect(generatedModels).not.toHaveLength(0);
const renderOutputPath = path.resolve(__dirname, './output/ts/output.ts');
const renderOutputPath = path.resolve(__dirname, './output/ts/class/output.ts');
await renderModels(generatedModels, renderOutputPath);
const transpiledOutputPath = path.resolve(__dirname, './output/ts/output.js');
const transpiledOutputPath = path.resolve(__dirname, './output/ts/class/output.js');
const transpileAndRunCommand = `tsc -t es5 ${renderOutputPath} && node ${transpiledOutputPath}`;
await execCommand(transpileAndRunCommand);
});
Expand All @@ -33,9 +34,9 @@ describe('Dummy JSON Schema file', () => {
const generator = new TypeScriptGenerator({modelType: 'interface'});
const generatedModels = await generateModels(fileToGenerate, generator);
expect(generatedModels).not.toHaveLength(0);
const renderOutputPath = path.resolve(__dirname, './output/ts/output.ts');
const renderOutputPath = path.resolve(__dirname, './output/ts/interface/output.ts');
await renderModels(generatedModels, renderOutputPath);
const transpiledOutputPath = path.resolve(__dirname, './output/ts/output.js');
const transpiledOutputPath = path.resolve(__dirname, './output/ts/interface/output.js');
const transpileAndRunCommand = `tsc -t es5 ${renderOutputPath} && node ${transpiledOutputPath}`;
await execCommand(transpileAndRunCommand);
});
Expand All @@ -46,7 +47,7 @@ describe('Dummy JSON Schema file', () => {
const generator = new JavaScriptGenerator();
const generatedModels = await generateModels(fileToGenerate, generator);
expect(generatedModels).not.toHaveLength(0);
const renderOutputPath = path.resolve(__dirname, './output/js/output.js');
const renderOutputPath = path.resolve(__dirname, './output/js/class/output.js');
await renderModels(generatedModels, renderOutputPath);
const transpileAndRunCommand = `node ${renderOutputPath}`;
await execCommand(transpileAndRunCommand);
Expand Down
Binary file not shown.
8 changes: 4 additions & 4 deletions test/generators/java/JavaGenerator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ describe('JavaGenerator', () => {
const model = inputModel.models['States'];

let enumModel = await generator.renderEnum(model, inputModel);
const expectedDependencies = ['import com.fasterxml.jackson.annotations.*;'];
const expectedDependencies = ['import com.fasterxml.jackson.annotation.*;'];
expect(enumModel.result).toEqual(expected);
expect(enumModel.dependencies).toEqual(expectedDependencies);

Expand Down Expand Up @@ -202,7 +202,7 @@ describe('JavaGenerator', () => {
const model = inputModel.models['Numbers'];

let enumModel = await generator.renderEnum(model, inputModel);
const expectedDependencies = ['import com.fasterxml.jackson.annotations.*;'];
const expectedDependencies = ['import com.fasterxml.jackson.annotation.*;'];
expect(enumModel.result).toEqual(expected);
expect(enumModel.dependencies).toEqual(expectedDependencies);

Expand Down Expand Up @@ -251,7 +251,7 @@ describe('JavaGenerator', () => {
const model = inputModel.models['Union'];

let enumModel = await generator.renderEnum(model, inputModel);
const expectedDependencies = ['import com.fasterxml.jackson.annotations.*;'];
const expectedDependencies = ['import com.fasterxml.jackson.annotation.*;'];
expect(enumModel.result).toEqual(expected);
expect(enumModel.dependencies).toEqual(expectedDependencies);

Expand Down Expand Up @@ -312,7 +312,7 @@ public enum CustomEnum {
const model = inputModel.models['CustomEnum'];

let enumModel = await generator.render(model, inputModel);
const expectedDependencies = ['import com.fasterxml.jackson.annotations.*;'];
const expectedDependencies = ['import com.fasterxml.jackson.annotation.*;'];
expect(enumModel.result).toEqual(expected);
expect(enumModel.dependencies).toEqual(expectedDependencies);

Expand Down
2 changes: 1 addition & 1 deletion test/generators/java/presets/DescriptionPreset.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,6 @@ public enum Enum {

const enumModel = await generator.renderEnum(model, inputModel);
expect(enumModel.result).toEqual(expected);
expect(enumModel.dependencies).toEqual(['import com.fasterxml.jackson.annotations.*;']);
expect(enumModel.dependencies).toEqual(['import com.fasterxml.jackson.annotation.*;']);
});
});
2 changes: 1 addition & 1 deletion test/generators/java/presets/JacksonPreset.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ describe('JAVA_DESCRIPTION_PRESET', () => {

const classModel = await generator.renderClass(model, inputModel);
expect(classModel.result).toEqual(expected);
expect(classModel.dependencies).toEqual(['import com.fasterxml.jackson.annotations.*;']);
expect(classModel.dependencies).toEqual(['import com.fasterxml.jackson.annotation.*;']);
});
});
32 changes: 0 additions & 32 deletions test/generators/typescript/TypeScriptGenerator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,6 @@ describe('TypeScriptGenerator', () => {
beforeEach(() => {
generator = new TypeScriptGenerator();
});
test('should render union property type', async () => {
const doc = {
$id: '_address',
type: 'object',
properties: {
state: { type: 'string', enum: ['Texas', 'Alabama', 'California', 'other'] }
}
};
const expected = `export class Address {
private _state?: "Texas" | "Alabama" | "California" | "other";
constructor(input: {
state?: "Texas" | "Alabama" | "California" | "other",
}) {
this._state = input.state;
}
get state(): "Texas" | "Alabama" | "California" | "other" | undefined { return this._state; }
set state(state: "Texas" | "Alabama" | "California" | "other" | undefined) { this._state = state; }
}`;

const inputModel = await generator.process(doc);
const model = inputModel.models['_address'];

let classModel = await generator.renderClass(model, inputModel);
expect(classModel.result).toEqual(expected);
expect(classModel.dependencies).toEqual([]);

classModel = await generator.render(model, inputModel);
expect(classModel.result).toEqual(expected);
expect(classModel.dependencies).toEqual([]);
});
test('should render `class` type', async () => {
const doc = {
$id: '_address',
Expand Down
41 changes: 39 additions & 2 deletions test/interpreter/PostInterpreter.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { CommonModel } from '../../src';
import { postInterpretModel } from '../../src/interpreter/PostInterpreter';
import { isModelObject } from '../../src/interpreter/Utils';
import { isEnum, isModelObject } from '../../src/interpreter/Utils';
jest.mock('../../src/interpreter/Utils');
describe('PostInterpreter', () => {
beforeEach(() => {
jest.clearAllMocks();
jest.resetAllMocks();
});
afterAll(() => {
jest.restoreAllMocks();
Expand All @@ -30,6 +30,43 @@ describe('PostInterpreter', () => {
expect(postProcessedModels).toHaveLength(1);
expect(postProcessedModels[0]).toMatchObject(expectedSchema1Model);
});
test('should split models on enums', () => {
const rawModel = {
$id: 'schema1',
properties: {
testProp: {
$id: 'schema2',
enum: [
'test'
]
}
}
};
const model = CommonModel.toCommonModel(rawModel);
(isEnum as jest.Mock).mockReturnValue(true);

const postProcessedModels = postInterpretModel(model);

const expectedSchema1Model = CommonModel.toCommonModel({
$id: 'schema1',
properties: {
testProp: {
$ref: 'schema2'
}
}
});
const expectedSchema2Model = CommonModel.toCommonModel({
$id: 'schema2',
enum: [
'test'
]
});

expect(postProcessedModels).toHaveLength(2);
expect(isEnum).toHaveBeenNthCalledWith(1, expectedSchema2Model);
expect(postProcessedModels[0]).toMatchObject(expectedSchema1Model);
expect(postProcessedModels[1]).toMatchObject(expectedSchema2Model);
});
test('should split models when nested models occur', () => {
const rawModel = {
$id: 'schema1',
Expand Down
14 changes: 12 additions & 2 deletions test/interpreter/unit/Intepreter.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Interpreter} from '../../../src/interpreter/Interpreter';
import {interpretName} from '../../../src/interpreter/Utils';
import {interpretName, isEnum, isModelObject} from '../../../src/interpreter/Utils';
import interpretProperties from '../../../src/interpreter/InterpretProperties';
import interpretConst from '../../../src/interpreter/InterpretConst';
import interpretEnum from '../../../src/interpreter/InterpretEnum';
Expand All @@ -26,7 +26,7 @@ CommonModel.mergeCommonModels = jest.fn();
*/
describe('Interpreter', () => {
beforeEach(() => {
jest.clearAllMocks();
jest.resetAllMocks();
});
afterAll(() => {
jest.restoreAllMocks();
Expand Down Expand Up @@ -62,9 +62,19 @@ describe('Interpreter', () => {
expect(model).not.toBeUndefined();
expect(model?.type).toEqual(['object', 'string', 'number', 'array', 'boolean', 'null', 'integer']);
});
test('should set id of model if enum', () => {
const schema = { enum: ['value'] };
const interpreter = new Interpreter();
(isEnum as jest.Mock).mockReturnValue(true);
const model = interpreter.interpret(schema);
expect(model).not.toBeUndefined();
expect(interpretName).toHaveBeenNthCalledWith(1, schema);
expect(model?.$id).toEqual('anonymSchema1');
});
test('should set id of model if object', () => {
const schema = { type: 'object' };
const interpreter = new Interpreter();
(isModelObject as jest.Mock).mockReturnValue(true);
const model = interpreter.interpret(schema);
expect(model).not.toBeUndefined();
expect(interpretName).toHaveBeenNthCalledWith(1, schema);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jest.mock('../../../src/interpreter/Interpreter');
jest.mock('../../../src/models/CommonModel');
describe('Interpretation of additionalProperties', () => {
beforeEach(() => {
jest.clearAllMocks();
jest.resetAllMocks();
});
afterAll(() => {
jest.restoreAllMocks();
Expand Down
2 changes: 1 addition & 1 deletion test/interpreter/unit/InterpretAllOf.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ CommonModel.mergeCommonModels = jest.fn();
*/
describe('Interpretation of allOf', () => {
beforeEach(() => {
jest.clearAllMocks();
jest.resetAllMocks();
});
afterAll(() => {
jest.restoreAllMocks();
Expand Down
2 changes: 1 addition & 1 deletion test/interpreter/unit/InterpretConst.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jest.mock('../../../src/interpreter/Utils');
jest.mock('../../../src/models/CommonModel');
describe('Interpretation of const', () => {
beforeEach(() => {
jest.clearAllMocks();
jest.resetAllMocks();
});
afterAll(() => {
jest.restoreAllMocks();
Expand Down
2 changes: 1 addition & 1 deletion test/interpreter/unit/InterpretEnum.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jest.mock('../../../src/models/CommonModel');

describe('Interpretation of enum', () => {
beforeEach(() => {
jest.clearAllMocks();
jest.resetAllMocks();
});
afterAll(() => {
jest.restoreAllMocks();
Expand Down
2 changes: 1 addition & 1 deletion test/interpreter/unit/InterpretItems.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jest.mock('../../../src/interpreter/Interpreter');
jest.mock('../../../src/models/CommonModel');
describe('Interpretation of', () => {
beforeEach(() => {
jest.clearAllMocks();
jest.resetAllMocks();
});
afterAll(() => {
jest.restoreAllMocks();
Expand Down
2 changes: 1 addition & 1 deletion test/interpreter/unit/InterpretNot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jest.mock('../../../src/utils');
jest.mock('../../../src/interpreter/Interpreter');
describe('Interpretation of not', () => {
beforeEach(() => {
jest.clearAllMocks();
jest.resetAllMocks();
(inferTypeFromValue as jest.Mock).mockImplementation(() => {return;});
interpreterOptions = Interpreter.defaultInterpreterOptions;
});
Expand Down
Loading

0 comments on commit 9296f51

Please sign in to comment.