Output full object types in JSON Schema. Fixes #747
This commit is contained in:
Родитель
6b51705746
Коммит
34f43f117a
|
@ -3,7 +3,7 @@
|
|||
import { Collection } from "immutable";
|
||||
|
||||
import { TargetLanguage } from "../TargetLanguage";
|
||||
import { Type, UnionType, ClassType, matchTypeExhaustive, EnumType } from "../Type";
|
||||
import { Type, UnionType, matchTypeExhaustive, EnumType, ObjectType } from "../Type";
|
||||
import { TypeGraph } from "../TypeGraph";
|
||||
import { ConvenienceRenderer } from "../ConvenienceRenderer";
|
||||
import { Namer, funPrefixNamer, Name } from "../Naming";
|
||||
|
@ -30,6 +30,10 @@ export default class JSONSchemaTargetLanguage extends TargetLanguage {
|
|||
return true;
|
||||
}
|
||||
|
||||
get supportsFullObjectType(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected get rendererClass(): new (
|
||||
targetLanguage: TargetLanguage,
|
||||
graph: TypeGraph,
|
||||
|
@ -108,10 +112,8 @@ export class JSONSchemaRenderer extends ConvenienceRenderer {
|
|||
_stringType => ({ type: "string" }),
|
||||
arrayType => ({ type: "array", items: this.schemaForType(arrayType.items) }),
|
||||
classType => this.makeRef(classType),
|
||||
mapType => ({ type: "object", additionalProperties: this.schemaForType(mapType.values) }),
|
||||
_objectType => {
|
||||
return panic("FIXME: support object types");
|
||||
},
|
||||
mapType => this.definitionForObject(mapType, undefined),
|
||||
objectType => this.makeRef(objectType),
|
||||
enumType => this.makeRef(enumType),
|
||||
unionType => {
|
||||
if (this.unionNeedsName(unionType)) {
|
||||
|
@ -131,20 +133,31 @@ export class JSONSchemaRenderer extends ConvenienceRenderer {
|
|||
return schema;
|
||||
};
|
||||
|
||||
private definitionForClass(c: ClassType, title: string): Schema {
|
||||
const properties: Schema = {};
|
||||
const required: string[] = [];
|
||||
c.properties.forEach((p, name) => {
|
||||
properties[name] = this.schemaForType(p.type);
|
||||
if (!p.isOptional) {
|
||||
required.push(name);
|
||||
}
|
||||
});
|
||||
private definitionForObject(o: ObjectType, title: string | undefined): Schema {
|
||||
let properties: Schema | undefined;
|
||||
let required: string[] | undefined;
|
||||
if (o.properties.isEmpty()) {
|
||||
properties = undefined;
|
||||
required = undefined;
|
||||
} else {
|
||||
const props: Schema = {};
|
||||
const req: string[] = [];
|
||||
o.properties.forEach((p, name) => {
|
||||
props[name] = this.schemaForType(p.type);
|
||||
if (!p.isOptional) {
|
||||
req.push(name);
|
||||
}
|
||||
});
|
||||
properties = props;
|
||||
required = req.sort();
|
||||
}
|
||||
const additionalProperties =
|
||||
o.additionalProperties !== undefined ? this.schemaForType(o.additionalProperties) : false;
|
||||
return {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
additionalProperties,
|
||||
properties,
|
||||
required: required.sort(),
|
||||
required,
|
||||
title
|
||||
};
|
||||
}
|
||||
|
@ -165,9 +178,9 @@ export class JSONSchemaRenderer extends ConvenienceRenderer {
|
|||
// FIXME: Find a better way to do multiple top-levels. Maybe multiple files?
|
||||
const schema = this.makeOneOf(this.topLevels);
|
||||
const definitions: { [name: string]: Schema } = {};
|
||||
this.forEachObject("none", (c: ClassType, name: Name) => {
|
||||
this.forEachObject("none", (o: ObjectType, name: Name) => {
|
||||
const title = defined(this.names.get(name));
|
||||
definitions[title] = this.definitionForClass(c, title);
|
||||
definitions[title] = this.definitionForObject(o, title);
|
||||
});
|
||||
this.forEachUnion("none", (u, name) => {
|
||||
if (!this.unionNeedsName(u)) return;
|
||||
|
|
|
@ -11,7 +11,8 @@ import { emptyTypeAttributes } from "./TypeAttributes";
|
|||
export function replaceObjectType(
|
||||
graph: TypeGraph,
|
||||
stringTypeMapping: StringTypeMapping,
|
||||
_conflateNumbers: boolean
|
||||
_conflateNumbers: boolean,
|
||||
leaveFullObjects: boolean
|
||||
): TypeGraph {
|
||||
function replace(
|
||||
setOfOneType: Set<ObjectType>,
|
||||
|
@ -80,6 +81,9 @@ export function replaceObjectType(
|
|||
}
|
||||
|
||||
const allObjectTypes = graph.allTypesUnordered().filter(t => t.kind === "object") as Set<ObjectType>;
|
||||
const groups = allObjectTypes.toArray().map(t => [t]);
|
||||
const objectTypesToReplace = leaveFullObjects
|
||||
? allObjectTypes.filter(o => o.properties.isEmpty() || o.additionalProperties === undefined)
|
||||
: allObjectTypes;
|
||||
const groups = objectTypesToReplace.toArray().map(t => [t]);
|
||||
return graph.rewrite("replace object type", stringTypeMapping, false, groups, replace);
|
||||
}
|
||||
|
|
10
src/index.ts
10
src/index.ts
|
@ -282,12 +282,10 @@ export class Run {
|
|||
} while (!intersectionsDone || !unionsDone);
|
||||
}
|
||||
|
||||
if (!targetLanguage.supportsFullObjectType) {
|
||||
graph = replaceObjectType(graph, stringTypeMapping, conflateNumbers);
|
||||
do {
|
||||
[graph, unionsDone] = flattenUnions(graph, stringTypeMapping, conflateNumbers, false);
|
||||
} while (!unionsDone);
|
||||
}
|
||||
graph = replaceObjectType(graph, stringTypeMapping, conflateNumbers, targetLanguage.supportsFullObjectType);
|
||||
do {
|
||||
[graph, unionsDone] = flattenUnions(graph, stringTypeMapping, conflateNumbers, false);
|
||||
} while (!unionsDone);
|
||||
|
||||
if (this._options.findSimilarClassesSchemaURI !== undefined) {
|
||||
return graph;
|
||||
|
|
Загрузка…
Ссылка в новой задаче