Output full object types in JSON Schema. Fixes #747

This commit is contained in:
Mark Probst 2018-04-06 09:49:40 -07:00
Родитель 6b51705746
Коммит 34f43f117a
3 изменённых файлов: 41 добавлений и 26 удалений

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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;