From 074872b7eec06b7cdb1632b2ed0e5e16931f6329 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 10 Mar 2017 13:29:26 +0100 Subject: [PATCH 1/2] Allow oneOf / anyOf to be used & displayed for root schema definitions --- lib/components/JsonSchema/json-schema.html | 11 ++++- lib/components/JsonSchema/json-schema.scss | 4 ++ lib/components/JsonSchema/json-schema.ts | 51 +++++++++++++++------- lib/services/schema-helper.service.ts | 26 ++++++++--- lib/services/schema-normalizer.service.ts | 12 +++++ 5 files changed, 81 insertions(+), 23 deletions(-) diff --git a/lib/components/JsonSchema/json-schema.html b/lib/components/JsonSchema/json-schema.html index 8ab87420..f1238537 100644 --- a/lib/components/JsonSchema/json-schema.html +++ b/lib/components/JsonSchema/json-schema.html @@ -46,9 +46,17 @@ [nestOdd]="!nestOdd" [isRequestSchema]="isRequestSchema"> +
+ {{schema._choiceTitle}} + + + +
+ - + !prop.readOnly); - } + if (this.schema._wrapped) { + this.schema._wrapped.forEach((schema) => { + SchemaHelper.preprocessProperties(schema, this.normPointer, { + childFor: this.childFor, + discriminator: this.discriminator + }); - if (this.optionsService.options.requiredPropsFirst) { - SchemaHelper.moveRequiredPropsFirst(this.properties, this.schema.required); - } + let properties = schema._properties || []; - this._hasSubSchemas = this.properties && this.properties.some( - propSchema => { - if (propSchema.type === 'array') { - propSchema = propSchema.items; + if (this.isRequestSchema) { + properties = properties.filter(prop => !prop.readOnly); } - return (propSchema && propSchema.type === 'object' && propSchema._pointer); - }); - if (this.properties.length === 1) { - this.properties[0].expanded = true; + if (this.optionsService.options.requiredPropsFirst) { + SchemaHelper.moveRequiredPropsFirst(properties, schema.required); + } + + this._hasSubSchemas = properties && properties.some( + propSchema => { + if (propSchema.type === 'array') { + propSchema = propSchema.items; + } + return (propSchema && propSchema.type === 'object' && propSchema._pointer); + }); + + if (properties.length === 1) { + properties[0].expanded = true; + } + + schema.displayProperties = properties + }) } } diff --git a/lib/services/schema-helper.service.ts b/lib/services/schema-helper.service.ts index 9f07b546..82912337 100644 --- a/lib/services/schema-helper.service.ts +++ b/lib/services/schema-helper.service.ts @@ -85,17 +85,33 @@ const injectors = { }, object: { check: (propertySchema) => { - return propertySchema.type === 'object' && (propertySchema.properties || + let isObject = propertySchema.type === 'object' && (propertySchema.properties || typeof propertySchema.additionalProperties === 'object'); + + let isChoiceObject = propertySchema.oneOf && propertySchema.oneOf.length > 0 || + propertySchema.anyOf && propertySchema.anyOf.length > 0 + + return isObject || isChoiceObject; }, inject: (injectTo, propertySchema = injectTo) => { - let baseName = propertySchema._pointer && JsonPointer.baseName(propertySchema._pointer); - injectTo._displayType = propertySchema.title || baseName || 'object'; injectTo._widgetType = 'object'; + if (propertySchema.type === 'object') { + let baseName = propertySchema._pointer && JsonPointer.baseName(propertySchema._pointer); + injectTo._displayType = propertySchema.title || baseName || 'object'; + injectTo._wrapped = [propertySchema]; + } else if (propertySchema.oneOf) { + injectTo._displayType = 'oneOf'; + injectTo._choiceTitle = 'One of'; + injectTo._wrapped = propertySchema.oneOf + } else if (propertySchema.anyOf) { + injectTo._displayType = 'anyOf'; + injectTo._choiceTitle = 'Any of'; + injectTo._wrapped = propertySchema.anyOf + } } }, noType: { - check: (propertySchema) => !propertySchema.type, + check: (propertySchema) => !propertySchema.type && !propertySchema.oneOf && !propertySchema.anyOf, inject: (injectTo) => { injectTo._displayType = '< anything >'; injectTo._displayTypeHint = 'This field may contain data of any type'; @@ -110,7 +126,7 @@ const injectors = { return (!propertySchema.properties || !Object.keys(propertySchema.properties).length) && (typeof propertySchema.additionalProperties !== 'object'); } - return (propertySchema.type !== 'array') && propertySchema.type; + return (propertySchema.type !== 'array' && !propertySchema.oneOf && !propertySchema.anyOf) && propertySchema.type; }, inject: (injectTo, propertySchema = injectTo) => { injectTo.isTrivial = true; diff --git a/lib/services/schema-normalizer.service.ts b/lib/services/schema-normalizer.service.ts index d3940bb2..3583b168 100644 --- a/lib/services/schema-normalizer.service.ts +++ b/lib/services/schema-normalizer.service.ts @@ -13,6 +13,8 @@ interface Reference { interface Schema { properties: any; allOf: any; + oneOf: any; + anyOf: any; items: any; additionalProperties: any; } @@ -73,6 +75,16 @@ class SchemaWalker { SchemaWalker.walkEach(obj.allOf, ptr, visitor); } + if (obj.oneOf) { + let ptr = JsonPointer.join(pointer, ['oneOf']); + SchemaWalker.walkEach(obj.oneOf, ptr, visitor); + } + + if (obj.anyOf) { + let ptr = JsonPointer.join(pointer, ['anyOf']); + SchemaWalker.walkEach(obj.anyOf, ptr, visitor); + } + if (obj.items) { let ptr = JsonPointer.join(pointer, ['items']); if (Array.isArray(obj.items)) { From 133f1ab77dde2ca574a654605e786411a482d576 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 10 Mar 2017 13:30:23 +0100 Subject: [PATCH 2/2] Add demo to show capability of oneOf attribute --- demo/swagger.yaml | 113 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/demo/swagger.yaml b/demo/swagger.yaml index f21ecef5..41493443 100644 --- a/demo/swagger.yaml +++ b/demo/swagger.yaml @@ -292,6 +292,76 @@ paths: - petstore_auth: - 'write:pets' - 'read:pets' + '/pet/{petId}/behaviors': + put: + tags: + - pet + summary: Change behaviors + description: Update the pet's behaviors + operationId: updateBehavior + produces: + - application/xml + - application/json + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + type: integer + format: int64 + - name: body + in: body + required: true + schema: + oneOf: + - $ref: "#/definitions/CatBehavior" + - $ref: "#/definitions/DogBehavior" + responses: + '200': + description: successful operation + schema: + $ref: '#/definitions/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + security: + - api_key: [] + post: + tags: + - pet + summary: Updates a pet in the store with form data + description: '' + operationId: updatePetWithForm + consumes: + - application/x-www-form-urlencoded + produces: + - application/xml + - application/json + parameters: + - name: petId + in: path + description: ID of pet that needs to be updated + required: true + type: integer + format: int64 + - name: name + in: formData + description: Updated name of the pet + required: false + type: string + - name: status + in: formData + description: Updated status of the pet + required: false + type: string + responses: + '405': + description: Invalid input + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' /pet/findByStatus: get: tags: @@ -653,12 +723,34 @@ definitions: type: string message: type: string + + CatBehavior: + type: object + properties: + mainTrait: + type: string + enum: + - cuddly + - aggressive + - lazy + + dangerous: + type: boolean + + Cat: description: A representation of a cat allOf: - $ref: '#/definitions/Pet' - type: object properties: + behaviors: + type: array + default: [] + description: A list of behaviors for this Cat + items: + $ref: "#/definitions/CatBehavior" + huntingSkill: type: string description: The measured skill for hunting @@ -668,6 +760,7 @@ definitions: - lazy - adventurous - aggressive + required: - huntingSkill Category: @@ -690,12 +783,32 @@ definitions: description: Dumb Property xml: name: Category + + DogBehavior: + type: object + properties: + mainTrait: + type: string + enum: + - noisy + - slimy + - dependent + + dangerous: + type: boolean + Dog: description: A representation of a dog allOf: - $ref: '#/definitions/Pet' - type: object properties: + behaviors: + type: array + default: [] + description: A list of behaviors for this Dog + items: + $ref: "#/definitions/DogBehavior" packSize: type: integer format: int32