mirror of
				https://github.com/Redocly/redoc.git
				synced 2025-11-04 01:37:32 +03:00 
			
		
		
		
	Fix search inside circular discriminators
This commit is contained in:
		
							parent
							
								
									6e13acbc64
								
							
						
					
					
						commit
						c52703f1ed
					
				| 
						 | 
				
			
			@ -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;
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user