Skip to content

Commit

Permalink
refactor: const interpretation (#200)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonaslagoni committed May 20, 2021
1 parent 0db6ea0 commit 92185d7
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 1 deletion.
2 changes: 2 additions & 0 deletions docs/interpretation_of_JSON_Schema_draft_7.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The order of transformation:
- `required` are determined as is.
- `properties` are determined as is, where duplicate properties for the model are merged.
- [allOf](#allOf-sub-schemas)
- `const` overwrite already interpreted `enums`.
- [oneOf/anyOf/then/else](#Processing-sub-schemas)

## allOf sub schemas
Expand All @@ -26,6 +27,7 @@ To determine the types for the model we use the following interpretation (and in
- `true` schema infers all model types (`object`, `string`, `number`, `array`, `boolean`, `null`, `integer`).
- Usage of `type` infers the initial model type.
- Usage of `properties` infers `object` model type.
- Usage of `const` infers the constant value as type, if schema does not have `type` specified.

## Processing sub schemas
The following JSON Schema keywords are merged with the already interpreted model:
Expand Down
25 changes: 25 additions & 0 deletions src/interpreter/InterpretConst.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

import { CommonModel } from '../models/CommonModel';
import { Schema } from '../models/Schema';
import { inferTypeFromValue } from './Utils';

/**
* Interpreter function for JSON Schema draft 7 const keyword.
*
* @param schema
* @param model
*/
export default function interpretConst(schema: Schema | boolean, model: CommonModel) {
if (typeof schema === 'boolean' || schema.const === undefined) return;

const schemaConst = schema.const;
model.enum = [schemaConst];

//If schema does not contain type interpret the schema
if (schema.type === undefined) {
const inferredType = inferTypeFromValue(schemaConst);
if (inferredType !== undefined) {
model.setType(inferredType);
}
}
}
2 changes: 2 additions & 0 deletions src/interpreter/Interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { SimplificationOptions } from '../models/SimplificationOptions';
import { interpretName, isModelObject } from './Utils';
import interpretProperties from './InterpretProperties';
import interpretAllOf from './InterpretAllOf';
import interpretConst from './InterpretConst';
import { Logger } from '../utils';

export class Interpreter {
Expand Down Expand Up @@ -80,6 +81,7 @@ export class Interpreter {

interpretProperties(schema, model, this);
interpretAllOf(schema, model, this);
interpretConst(schema, model);

this.combineSchemas(schema.oneOf, model, schema);
this.combineSchemas(schema.anyOf, model, schema);
Expand Down
10 changes: 9 additions & 1 deletion test/interpreter/Intepreter.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {Interpreter} from '../../src/interpreter/Interpreter';
import {isModelObject, interpretName} from '../../src/interpreter/Utils';
import interpretProperties from '../../src/interpreter/InterpretProperties';
import { CommonModel, Schema } from '../../src/models';
import interpretConst from '../../src/interpreter/InterpretConst';
import interpretAllOf from '../../src/interpreter/InterpretAllOf';
import { CommonModel, Schema } from '../../src/models';

let mockedIsModelObjectReturn = false;
jest.mock('../../src/interpreter/Utils', () => {
Expand All @@ -14,6 +15,7 @@ jest.mock('../../src/interpreter/Utils', () => {
}
});
jest.mock('../../src/interpreter/InterpretProperties');
jest.mock('../../src/interpreter/InterpretConst');
jest.mock('../../src/interpreter/InterpretAllOf');
CommonModel.mergeCommonModels = jest.fn();
/**
Expand Down Expand Up @@ -162,6 +164,12 @@ describe('Interpreter', function() {
expect(interpretProperties).toHaveBeenNthCalledWith(1, schema, expect.anything(), expect.anything());
});

test('should always try to interpret const', function() {
const schema = {};
const interpreter = new Interpreter();
interpreter.interpret(schema);
expect(interpretConst).toHaveBeenNthCalledWith(1, schema, expect.anything());
});
test('should always try to interpret allOf', function() {
const schema = {};
const interpreter = new Interpreter();
Expand Down
52 changes: 52 additions & 0 deletions test/interpreter/InterpretConst.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

import { CommonModel } from '../../src/models/CommonModel';
import interpretConst from '../../src/interpreter/InterpretConst';
import {inferTypeFromValue} from '../../src/interpreter/Utils';
jest.mock('../../src/interpreter/Utils');
describe('Interpretation of const', function() {
beforeEach(() => {
jest.clearAllMocks();
});
afterAll(() => {
jest.restoreAllMocks();
});
test('should not do anything for boolean schemas', function() {
const model = new CommonModel();
const schema: any = true;
interpretConst(schema, model);
expect(model.type).toBeUndefined();
expect(model.enum).toBeUndefined();
});
test('should not do anything if schema does not contain const', function() {
const model = new CommonModel();
const schema: any = { type: 'string'};
interpretConst(schema, model);
expect(model.type).toBeUndefined();
expect(model.enum).toBeUndefined();
});
test('should not infer type from const if schema have type', function() {
const model = new CommonModel();
const schema: any = { type: 'string', const: 'test'};
interpretConst(schema, model);
expect(model.type).toBeUndefined();
expect(model.enum).toEqual([schema.const]);
});
test('should infer type and enum', function() {
(inferTypeFromValue as jest.Mock).mockReturnValue("string");
const schema: any = { const: 'test'};
const model = new CommonModel();
interpretConst(schema, model);
expect(model.enum).toEqual([schema.const]);
expect(inferTypeFromValue).toHaveBeenNthCalledWith(1, 'test');
expect(model.type).toEqual("string");
});
test('should not infer unknown type', function() {
(inferTypeFromValue as jest.Mock).mockReturnValue(undefined);
const schema: any = { const: 'test'};
const model = new CommonModel();
interpretConst(schema, model);
expect(model.enum).toEqual([schema.const]);
expect(model.type).toBeUndefined();
expect(inferTypeFromValue).toHaveBeenNthCalledWith(1, 'test');
});
});

0 comments on commit 92185d7

Please sign in to comment.