-
-
Notifications
You must be signed in to change notification settings - Fork 170
/
Interpreter.ts
132 lines (120 loc) · 5.77 KB
/
Interpreter.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import { CommonModel, Draft6Schema, Draft4Schema, SwaggerV2Schema, AsyncapiV2Schema, Draft7Schema } from '../models';
import { interpretName, isEnum, isModelObject } from './Utils';
import interpretProperties from './InterpretProperties';
import interpretAllOf from './InterpretAllOf';
import interpretConst from './InterpretConst';
import interpretEnum from './InterpretEnum';
import interpretAdditionalProperties from './InterpretAdditionalProperties';
import interpretItems from './InterpretItems';
import interpretPatternProperties from './InterpretPatternProperties';
import interpretNot from './InterpretNot';
import interpretDependencies from './InterpretDependencies';
import interpretAdditionalItems from './InterpretAdditionalItems';
export type InterpreterOptions = {
allowInheritance?: boolean
}
export type InterpreterSchemas = Draft6Schema | Draft4Schema | Draft7Schema | SwaggerV2Schema | AsyncapiV2Schema;
export type InterpreterSchemaType = InterpreterSchemas | boolean;
export class Interpreter {
static defaultInterpreterOptions: InterpreterOptions = {
allowInheritance: false
}
private anonymCounter = 1;
private seenSchemas: Map<InterpreterSchemaType, CommonModel> = new Map();
/**
* Transforms a schema into instances of CommonModel by processing all keywords from schema documents and infers the model definition.
*
* @param schema
* @param interpreterOptions to control the interpret process
*/
interpret(schema: InterpreterSchemaType, options: InterpreterOptions = Interpreter.defaultInterpreterOptions): CommonModel | undefined {
if (this.seenSchemas.has(schema)) {
const cachedModel = this.seenSchemas.get(schema);
if (cachedModel !== undefined) {
return cachedModel;
}
}
//If it is a false validation schema return no CommonModel
if (schema === false) {
return undefined;
}
const model = new CommonModel();
model.originalInput = schema;
this.seenSchemas.set(schema, model);
this.interpretSchema(model, schema, options);
return model;
}
/**
* Function to interpret a schema into a CommonModel.
*
* @param model
* @param schema
* @param interpreterOptions to control the interpret process
*/
private interpretSchema(model: CommonModel, schema: InterpreterSchemaType, interpreterOptions: InterpreterOptions = Interpreter.defaultInterpreterOptions) {
if (schema === true) {
model.setType(['object', 'string', 'number', 'array', 'boolean', 'null', 'integer']);
} else if (typeof schema === 'object') {
this.interpretSchemaObject(model, schema, interpreterOptions);
}
}
private interpretSchemaObject(model: CommonModel, schema: InterpreterSchemas, interpreterOptions: InterpreterOptions = Interpreter.defaultInterpreterOptions) {
if (schema.type !== undefined) {
model.addTypes(schema.type);
}
if (schema.required !== undefined) {
model.required = schema.required;
}
interpretPatternProperties(schema, model, this, interpreterOptions);
interpretAdditionalProperties(schema, model, this, interpreterOptions);
interpretAdditionalItems(schema, model, this, interpreterOptions);
interpretItems(schema, model, this, interpreterOptions);
interpretProperties(schema, model, this, interpreterOptions);
interpretAllOf(schema, model, this, interpreterOptions);
interpretDependencies(schema, model, this, interpreterOptions);
interpretConst(schema, model);
interpretEnum(schema, model);
this.interpretAndCombineMultipleSchemas(schema.oneOf, model, schema, interpreterOptions);
this.interpretAndCombineMultipleSchemas(schema.anyOf, model, schema, interpreterOptions);
if (!(schema instanceof Draft4Schema) && !(schema instanceof Draft6Schema)) {
this.interpretAndCombineSchema(schema.then, model, schema, interpreterOptions);
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 instanceof Draft4Schema) && schema.$id !== undefined) || (schema instanceof Draft4Schema && schema.id !== undefined)) {
model.$id = interpretName(schema);
}
}
/**
* Go through a schema and combine the interpreted models together.
*
* @param schema to go through
* @param currentModel the current output
* @param rootSchema the root schema to use as original schema when merged
* @param interpreterOptions to control the interpret process
*/
interpretAndCombineSchema(schema: InterpreterSchemaType | undefined, currentModel: CommonModel, rootSchema: any, interpreterOptions: InterpreterOptions = Interpreter.defaultInterpreterOptions): void {
if (typeof schema !== 'object') {return;}
const model = this.interpret(schema, interpreterOptions);
if (model !== undefined) {
CommonModel.mergeCommonModels(currentModel, model, rootSchema);
}
}
/**
* Go through multiple schemas and combine the interpreted models together.
*
* @param schema to go through
* @param currentModel the current output
* @param rootSchema the root schema to use as original schema when merged
* @param interpreterOptions to control the interpret process
*/
interpretAndCombineMultipleSchemas(schema: InterpreterSchemaType[] | undefined, currentModel: CommonModel, rootSchema: any, interpreterOptions: InterpreterOptions = Interpreter.defaultInterpreterOptions): void {
if (!Array.isArray(schema)) { return; }
for (const forEachSchema of schema) {
this.interpretAndCombineSchema(forEachSchema, currentModel, rootSchema, interpreterOptions);
}
}
}