Fix search inside circular discriminators

This commit is contained in:
Roman Hotsiy 2017-01-28 13:03:51 +02:00
parent 6e13acbc64
commit c52703f1ed
No known key found for this signature in database
GPG Key ID: 5CB7B3ACABA57CB0
8 changed files with 43 additions and 37 deletions

View File

@ -64,7 +64,8 @@ export class JsonSchemaLazy implements OnDestroy, OnInit, AfterViewInit {
// skip caching view with descendant schemas
// as it needs attached controller
if (!this.disableLazy && (compRef.instance.hasDescendants || compRef.instance._hasSubSchemas)) {
let hasDescendants = compRef.instance.descendants && compRef.instance.descendants.length;
if (!this.disableLazy && (hasDescendants || compRef.instance._hasSubSchemas)) {
this._loadAfterSelf();
return;
}

View File

@ -31,7 +31,7 @@ export class JsonSchema extends BaseSearchableComponent implements OnInit {
schema: any = {};
activeDescendant:any = {};
hasDescendants: boolean = false;
discriminator: string = null;
_hasSubSchemas: boolean = false;
properties: any;
_isArray: boolean;
@ -75,8 +75,7 @@ export class JsonSchema extends BaseSearchableComponent implements OnInit {
initDescendants() {
this.descendants = this.specMgr.findDerivedDefinitions(this.normPointer, this.schema);
if (!this.descendants.length) return;
this.hasDescendants = true;
let discriminator = this.schema.discriminator || this.schema['x-extendedDiscriminator'];
let discriminator = this.discriminator = this.schema.discriminator || this.schema['x-extendedDiscriminator'];
let discrProperty = this.schema.properties &&
this.schema.properties[discriminator];
if (discrProperty && discrProperty.enum) {
@ -91,6 +90,7 @@ export class JsonSchema extends BaseSearchableComponent implements OnInit {
}).sort((a, b) => {
return enumOrder[a.name] > enumOrder[b.name] ? 1 : -1;
});
this.descendants.forEach((d, idx) => d.idx = idx);
}
this.selectDescendantByIdx(0);
}
@ -119,11 +119,12 @@ export class JsonSchema extends BaseSearchableComponent implements OnInit {
if (!this.schema.isTrivial) {
SchemaHelper.preprocessProperties(this.schema, this.normPointer, {
childFor: this.childFor
childFor: this.childFor,
discriminator: this.discriminator
});
}
this.properties = this.schema._properties;
this.properties = this.schema._properties || [];
if (this.isRequestSchema) {
this.properties = this.properties && this.properties.filter(prop => !prop.readOnly);
}

View File

@ -6,22 +6,6 @@ import { Subscription } from 'rxjs/Subscription';
export { SpecManager };
function snapshot(obj) {
if(obj == undefined || typeof(obj) !== 'object') {
return obj;
}
var temp = new obj.constructor();
for(var key in obj) {
if (obj.hasOwnProperty(key)) {
temp[key] = snapshot(obj[key]);
}
}
return temp;
}
/**
* Generic Component
* @class

View File

@ -7,6 +7,7 @@ import * as slugify from 'slugify';
interface PropertyPreprocessOptions {
childFor: string;
skipReadOnly?: boolean;
discriminator?: string;
}
// global var for this module
@ -220,8 +221,7 @@ export class SchemaHelper {
propertySchema._pointer = null;
}
propertySchema._required = !!requiredMap[propName];
propertySchema.isDiscriminator = (schema.discriminator === propName
|| schema['x-extendedDiscriminator'] === propName);
propertySchema.isDiscriminator = opts.discriminator === propName;
return propertySchema;
});

View File

@ -27,6 +27,7 @@ export class SchemaNormalizer {
let hasPtr = !!schema.$ref;
if (opts.resolved && !hasPtr) this._dereferencer.visit(ptr);
if (opts.childFor) this._dereferencer.visit(opts.childFor);
if (schema['x-redoc-normalized']) return schema;
let res = SchemaWalker.walk(schema, ptr, (subSchema, ptr) => {
let resolved = this._dereferencer.dereference(subSchema, ptr);
@ -38,6 +39,7 @@ export class SchemaNormalizer {
return resolved;
});
if (opts.resolved && !hasPtr) this._dereferencer.exit(ptr);
if (opts.childFor) this._dereferencer.exit(opts.childFor);
res['x-redoc-normalized'] = true;
return res;
}
@ -113,6 +115,7 @@ export class AllOfMerger {
defaults(into, subSchema);
subSchema._pointer = tmpPtr;
}
into.discriminator = null;
into.allOf = null;
}

View File

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { AppStateService } from './app-state.service';
import { SchemaNormalizer } from './schema-normalizer.service';
import { JsonPointer, groupBy, SpecManager, StringMap } from '../utils/';
import { JsonPointer, groupBy, SpecManager, StringMap, snapshot } from '../utils/';
import * as lunr from 'lunr';
@ -13,7 +13,7 @@ interface IndexElement {
}
const index = lunr(function () {
this.field('menuId', {boost: 0});
//this.field('menuId', {boost: 0});
this.field('title', {boost: 1.5});
this.field('body');
this.ref('pointer');
@ -33,13 +33,13 @@ export class SearchService {
}
indexAll() {
const swagger = this.spec.schema;
this.indexPaths(swagger);
this.indexPaths(this.spec.schema);
}
search(q):StringMap<IndexElement[]> {
var items = {};
const res:IndexElement[] = index.search(q).map(res => {
items[res.menuId] = res;
return store[res.ref];
});
const grouped = groupBy(res, 'menuId');
@ -79,6 +79,7 @@ export class SearchService {
indexOperationParameters(operation: any, operationPointer: string) {
const parameters = operation.parameters;
if (!parameters) return;
for (let i=0; i<parameters.length; ++i) {
const param = parameters[i];
const paramPointer = JsonPointer.join(operationPointer, ['parameters', i]);
@ -90,6 +91,7 @@ export class SearchService {
});
if (param.in === 'body') {
this.normalizer.reset();
this.indexSchema(param.schema, '', JsonPointer.join(paramPointer, ['schema']), operationPointer);
}
}
@ -109,18 +111,17 @@ export class SearchService {
});
if (resp.schema) {
this.normalizer.reset();
this.indexSchema(resp.schema, '', JsonPointer.join(respPtr, 'schema'), operationPtr);
}
});
}
indexSchema(_schema:any, name: string, absolutePointer: string, menuPointer: string) {
indexSchema(_schema:any, name: string, absolutePointer: string, menuPointer: string, parent?: string) {
if (!_schema) return;
let schema = _schema;
let title = name;
this.normalizer.reset();
schema = this.normalizer.normalize(schema, schema._pointer || absolutePointer);
schema = this.normalizer.normalize(schema, schema._pointer || absolutePointer, { childFor: parent });
let body = schema.description; // TODO: defaults, examples, etc...
@ -129,11 +130,11 @@ export class SearchService {
return;
}
if (schema.discriminator && !schema['x-derived-from']) {
if (schema.discriminator) {
let derived = this.spec.findDerivedDefinitions(schema._pointer, schema);
for (let defInfo of derived ) {
let subSpec = this.spec.getDescendant(defInfo, schema);
this.indexSchema(subSpec, '', absolutePointer, menuPointer);
this.indexSchema(snapshot(subSpec), '', absolutePointer, menuPointer, schema._pointer);
}
}

View File

@ -94,3 +94,19 @@ export function throttle(fn, threshhold, scope) {
export const isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0
|| (function (p) { return p.toString() === '[object SafariRemoteNotification]'; })(!window['safari']
|| safari.pushNotification);
export function snapshot(obj) {
if(obj == undefined || typeof(obj) !== 'object') {
return obj;
}
var temp = new obj.constructor();
for(var key in obj) {
if (obj.hasOwnProperty(key)) {
temp[key] = snapshot(obj[key]);
}
}
return temp;
}

View File

@ -176,7 +176,7 @@ export class SpecManager {
if (!definition.discriminator && !definition['x-extendedDiscriminator']) return [];
let globalDefs = this._schema.definitions || {};
let res = [];
let res:DescendantInfo[] = [];
let extendedDiscriminatorProp = definition['x-extendedDiscriminator'];
for (let defName of Object.keys(globalDefs)) {
let def = globalDefs[defName];
@ -208,7 +208,7 @@ export class SpecManager {
}
}
res.push({name: derivedName, $ref: `#/definitions/${defName}`, idx: res.length});
res.push({name: derivedName, $ref: `#/definitions/${defName}`, idx: null});
}
return res;
}