Merge commit '8af268e69b879aff39a04200cda87b5668c3e07a' into releases

This commit is contained in:
RedocBot 2017-03-31 17:02:56 +00:00 committed by travis@localhost
commit e1275cbe8d
38 changed files with 236 additions and 206 deletions

View File

@ -138,7 +138,7 @@ ReDoc makes use of the following [vendor extensions](http://swagger.io/specifica
* **function**: A getter function. Must return a number representing the offset (in pixels); * **function**: A getter function. Must return a number representing the offset (in pixels);
* `suppress-warnings` - if set, warnings are not rendered at the top of documentation (they still are logged to the console). * `suppress-warnings` - if set, warnings are not rendered at the top of documentation (they still are logged to the console).
* `lazy-rendering` - if set, enables lazy rendering mode in ReDoc. This mode is useful for APIs with big number of operations (e.g. > 50). In this mode ReDoc shows initial screen ASAP and then renders the rest operations asynchronously while showing progress bar on the top. Check out the [demo](\\rebilly.github.io/ReDoc) for the example. * `lazy-rendering` - if set, enables lazy rendering mode in ReDoc. This mode is useful for APIs with big number of operations (e.g. > 50). In this mode ReDoc shows initial screen ASAP and then renders the rest operations asynchronously while showing progress bar on the top. Check out the [demo](\\rebilly.github.io/ReDoc) for the example.
* `hide-hostname` - if set, the protocol and hostname is not shown in the method definition. * `hide-hostname` - if set, the protocol and hostname is not shown in the operation definition.
* `expand-responses` - specify which responses to expand by default by response codes. Values should be passed as comma-separated list without spaces e.g. `expand-responses="200,201"`. Special value `"all"` expands all responses by default. Be careful: this option can slow-down documentation rendering time. * `expand-responses` - specify which responses to expand by default by response codes. Values should be passed as comma-separated list without spaces e.g. `expand-responses="200,201"`. Special value `"all"` expands all responses by default. Be careful: this option can slow-down documentation rendering time.
* `required-props-first` - show required properties first ordered in the same order as in `required` array. * `required-props-first` - show required properties first ordered in the same order as in `required` array.

View File

@ -1,7 +1,7 @@
<div class="method-endpoint" (click)="handleClick()"> <div class="operation-endpoint" (click)="handleClick()">
<h5 class="http-verb" [ngClass]="verb">{{verb}}</h5> <h5 class="http-verb" [ngClass]="verb">{{verb}}</h5>
<span><!-- <span><!--
--><span class="method-api-url-path">{{path}}</span><!-- --><span class="operation-api-url-path">{{path}}</span><!--
--></span> --></span>
</div> </div>
<svg class="expand-icon" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0" y="0" viewBox="0 0 24 24" xml:space="preserve"> <svg class="expand-icon" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0" y="0" viewBox="0 0 24 24" xml:space="preserve">
@ -11,7 +11,7 @@
<div *ngFor="let server of servers" class="server-item"> <div *ngFor="let server of servers" class="server-item">
<div class="description" [innerHtml]="server.description | marked"></div> <div class="description" [innerHtml]="server.description | marked"></div>
<div select-on-click class="url"> <div select-on-click class="url">
<span class="method-api-url"> {{server.url}}</span>{{path}} <span class="operation-api-url"> {{server.url}}</span>{{path}}
</div> </div>
</div> </div>
</div> </div>

View File

@ -6,7 +6,7 @@
cursor: pointer; cursor: pointer;
} }
.method-endpoint { .operation-endpoint {
padding: 10px 30px 10px 20px; padding: 10px 30px 10px 20px;
border-radius: $border-radius*2; border-radius: $border-radius*2;
background-color: darken($black, 2%); background-color: darken($black, 2%);
@ -18,7 +18,7 @@
border: 1px solid transparent; border: 1px solid transparent;
} }
.method-endpoint > .method-params-subheader { .operation-endpoint > .operation-params-subheader {
padding-top: 1px; padding-top: 1px;
padding-bottom: 0; padding-bottom: 0;
margin: 0; margin: 0;
@ -29,7 +29,7 @@
border-radius: $border-radius; border-radius: $border-radius;
} }
.method-api-url { .operation-api-url {
color: rgba($black, .8); color: rgba($black, .8);
&-path { &-path {
font-family: $headers-font, $headers-font-family; font-family: $headers-font, $headers-font-family;
@ -96,7 +96,7 @@
transition: all 0.25s ease; transition: all 0.25s ease;
} }
:host.expanded { :host.expanded {
> .method-endpoint { > .operation-endpoint {
border-color: $side-bar-bg-color; border-color: $side-bar-bg-color;
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;

View File

@ -72,11 +72,11 @@ describe('Redoc components', () => {
}); });
/** Test component that contains a Method. */ /** Test component that contains an Operation. */
@Component({ @Component({
selector: 'test-app', selector: 'test-app',
template: template:
`<method pointer='#/paths/~1user~1{username}/put'></method>` `<operation pointer='#/paths/~1user~1{username}/put'></operation>`
}) })
class TestAppComponent { class TestAppComponent {
} }

View File

@ -45,7 +45,7 @@ describe('Redoc components', () => {
}); });
/** Test component that contains a Method. */ /** Test component that contains a lazy schema. */
@Component({ @Component({
selector: 'test-app', selector: 'test-app',
template: template:

View File

@ -57,7 +57,7 @@ describe('Redoc components', () => {
}); });
/** Test component that contains a Method. */ /** Test component that contains a json schema. */
@Component({ @Component({
selector: 'test-app', selector: 'test-app',
template: template:

View File

@ -1,30 +0,0 @@
<div class="method" *ngIf="method">
<div class="method-content">
<h2 class="method-header sharable-header">
<a class="share-link" href="#{{method.anchor}}"></a>{{method.summary}}
</h2>
<div class="method-tags" *ngIf="method.info.tags.length">
<a *ngFor="let tag of method.info.tags" attr.href="#tag/{{tag}}"> {{tag}} </a>
</div>
<p *ngIf="method.info.description" class="method-description"
[innerHtml]="method.info.description | marked">
</p>
<redoc-externalDocs [docs]="method.externalDocs"></redoc-externalDocs>
<params-list pointer="{{pointer}}/parameters"> </params-list>
<responses-list pointer="{{pointer}}/responses"> </responses-list>
</div>
<div class="method-samples">
<h4 class="method-params-subheader">Definition</h4>
<endpoint-link [verb]="method.verb" [path]="method.path"> </endpoint-link>
<div>
<request-samples [pointer]="pointer" [schemaPointer]="method.bodyParam?._pointer">
</request-samples>
</div>
<div>
<br>
<responses-samples pointer="{{pointer}}/responses"> </responses-samples>
</div>
</div>
</div>

View File

@ -0,0 +1,30 @@
<div class="operation" *ngIf="operation">
<div class="operation-content">
<h2 class="operation-header sharable-header">
<a class="share-link" href="#{{operation.anchor}}"></a>{{operation.summary}}
</h2>
<div class="operation-tags" *ngIf="operation.info.tags.length">
<a *ngFor="let tag of operation.info.tags" attr.href="#tag/{{tag}}"> {{tag}} </a>
</div>
<p *ngIf="operation.info.description" class="operation-description"
[innerHtml]="operation.info.description | marked">
</p>
<redoc-externalDocs [docs]="operation.externalDocs"></redoc-externalDocs>
<params-list pointer="{{pointer}}/parameters"> </params-list>
<responses-list pointer="{{pointer}}/responses"> </responses-list>
</div>
<div class="operation-samples">
<h4 class="operation-params-subheader">Definition</h4>
<endpoint-link [verb]="operation.verb" [path]="operation.path"> </endpoint-link>
<div>
<request-samples [pointer]="pointer" [schemaPointer]="operation.bodyParam?._pointer">
</request-samples>
</div>
<div>
<br>
<responses-samples pointer="{{pointer}}/responses"> </responses-samples>
</div>
</div>
</div>

View File

@ -14,11 +14,11 @@
// border-bottom: 0; // border-bottom: 0;
// } // }
.method-header { .operation-header {
margin-bottom: calc(1em - 6px); margin-bottom: calc(1em - 6px);
} }
.method-tags { .operation-tags {
margin-top: 20px; margin-top: 20px;
> a { > a {
@ -39,45 +39,45 @@
} }
} }
.method-content, .method-samples { .operation-content, .operation-samples {
display: block; display: block;
box-sizing: border-box; box-sizing: border-box;
float: left; float: left;
} }
.method-content { .operation-content {
width: 100% - $samples-panel-width; width: 100% - $samples-panel-width;
padding: $section-spacing; padding: $section-spacing;
} }
.method-samples { .operation-samples {
color: $sample-panel-color; color: $sample-panel-color;
width: 40%; width: 40%;
padding: $section-spacing; padding: $section-spacing;
background: $samples-panel-bg-color; background: $samples-panel-bg-color;
} }
.method-samples header, .operation-samples header,
.method-samples > h5 { .operation-samples > h5 {
color: $sample-panel-headers-color; color: $sample-panel-headers-color;
text-transform: uppercase; text-transform: uppercase;
} }
.method-samples > h5 { .operation-samples > h5 {
margin-bottom: 8px; margin-bottom: 8px;
} }
.method-samples schema-sample { .operation-samples schema-sample {
display: block; display: block;
} }
.method:after { .operation:after {
content: ""; content: "";
display: table; display: table;
clear:both; clear:both;
} }
.method-description { .operation-description {
padding: 6px 0 10px 0; padding: 6px 0 10px 0;
margin: 0; margin: 0;
} }
@ -87,15 +87,15 @@
} }
@media (max-width: $right-panel-squash-breakpoint) { @media (max-width: $right-panel-squash-breakpoint) {
.methods:before { .operations:before {
display: none; display: none;
} }
.method-samples, .method-content { .operation-samples, .operation-content {
width: 100%; width: 100%;
} }
.method-samples { .operation-samples {
margin-top: 2em; margin-top: 2em;
} }

View File

@ -9,7 +9,7 @@ import {
import { getChildDebugElement } from '../../../tests/helpers'; import { getChildDebugElement } from '../../../tests/helpers';
import { Method } from './method'; import { Operation } from './operation';
import { SpecManager } from '../../utils/spec-manager';; import { SpecManager } from '../../utils/spec-manager';;
import { LazyTasksService } from '../../shared/components/LazyFor/lazy-for';; import { LazyTasksService } from '../../shared/components/LazyFor/lazy-for';;
@ -17,9 +17,9 @@ describe('Redoc components', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ declarations: [ TestAppComponent ] }); TestBed.configureTestingModule({ declarations: [ TestAppComponent ] });
}); });
describe('Method Component', () => { describe('Operation Component', () => {
let builder; let builder;
let component: Method; let component: Operation;
let specMgr; let specMgr;
beforeEach(async(inject([SpecManager, LazyTasksService], (_specMgr, lazyTasks) => { beforeEach(async(inject([SpecManager, LazyTasksService], (_specMgr, lazyTasks) => {
@ -33,7 +33,7 @@ describe('Redoc components', () => {
beforeEach(() => { beforeEach(() => {
let fixture = TestBed.createComponent(TestAppComponent); let fixture = TestBed.createComponent(TestAppComponent);
component = getChildDebugElement(fixture.debugElement, 'method').componentInstance; component = getChildDebugElement(fixture.debugElement, 'operation').componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
@ -43,23 +43,23 @@ describe('Redoc components', () => {
}); });
it('should init basic component data', () => { it('should init basic component data', () => {
component.method.verb.should.be.equal('put'); component.operation.verb.should.be.equal('put');
component.method.path.should.be.equal('/user/{username}'); component.operation.path.should.be.equal('/user/{username}');
}); });
it('should main tag', () => { it('should main tag', () => {
component.method.info.tags.should.be.empty(); component.operation.info.tags.should.be.empty();
}); });
}); });
}); });
/** Test component that contains a Method. */ /** Test component that contains a Operation. */
@Component({ @Component({
selector: 'test-app', selector: 'test-app',
template: template:
`<method pointer='#/paths/~1user~1{username}/put'></method>` `<operation pointer='#/paths/~1user~1{username}/put'></operation>`
}) })
class TestAppComponent { class TestAppComponent {
} }

View File

@ -6,7 +6,7 @@ import { SchemaHelper } from '../../services/schema-helper.service';
import { OptionsService, MenuService } from '../../services/'; import { OptionsService, MenuService } from '../../services/';
interface MethodInfo { interface OperationInfo {
verb: string; verb: string;
path: string; path: string;
info: { info: {
@ -23,18 +23,18 @@ interface MethodInfo {
} }
@Component({ @Component({
selector: 'method', selector: 'operation',
templateUrl: './method.html', templateUrl: './operation.html',
styleUrls: ['./method.css'], styleUrls: ['./operation.css'],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class Method extends BaseComponent implements OnInit { export class Operation extends BaseComponent implements OnInit {
@Input() pointer :string; @Input() pointer :string;
@Input() parentTagId :string; @Input() parentTagId :string;
@HostBinding('attr.operation-id') operationId; @HostBinding('attr.operation-id') operationId;
method: MethodInfo; operation: OperationInfo;
constructor( constructor(
specMgr:SpecManager, specMgr:SpecManager,
@ -46,7 +46,7 @@ export class Method extends BaseComponent implements OnInit {
init() { init() {
this.operationId = this.componentSchema.operationId; this.operationId = this.componentSchema.operationId;
this.method = { this.operation = {
verb: JsonPointer.baseName(this.pointer), verb: JsonPointer.baseName(this.pointer),
path: JsonPointer.baseName(this.pointer, 2), path: JsonPointer.baseName(this.pointer, 2),
info: { info: {
@ -54,7 +54,7 @@ export class Method extends BaseComponent implements OnInit {
tags: this.filterMainTags(this.componentSchema.tags) tags: this.filterMainTags(this.componentSchema.tags)
}, },
bodyParam: this.findBodyParam(), bodyParam: this.findBodyParam(),
summary: SchemaHelper.methodSummary(this.componentSchema), summary: SchemaHelper.operationSummary(this.componentSchema),
anchor: this.buildAnchor(), anchor: this.buildAnchor(),
externalDocs: this.componentSchema.externalDocs externalDocs: this.componentSchema.externalDocs
}; };
@ -62,7 +62,7 @@ export class Method extends BaseComponent implements OnInit {
buildAnchor():string { buildAnchor():string {
return this.menu.hashFor(this.pointer, return this.menu.hashFor(this.pointer,
{ type: 'method', operationId: this.operationId, pointer: this.pointer }, { type: 'operation', operationId: this.operationId, pointer: this.pointer },
this.parentTagId ); this.parentTagId );
} }
@ -73,8 +73,8 @@ export class Method extends BaseComponent implements OnInit {
} }
findBodyParam() { findBodyParam() {
let pathParams = this.specMgr.getMethodParams(this.pointer); let params = this.specMgr.getOperationParams(this.pointer);
let bodyParam = pathParams.find(param => param.in === 'body'); let bodyParam = params.find(param => param.in === 'body');
return bodyParam; return bodyParam;
} }

View File

@ -1,12 +1,12 @@
<div class="methods"> <div class="operations">
<div class="tag" *ngFor="let tag of tags; trackBy:trackByTagName" [attr.section]="tag.id"> <div class="tag" *ngFor="let tag of tags; trackBy:trackByTagName" [attr.section]="tag.id">
<div class="tag-info" *ngIf="tag.name"> <div class="tag-info" *ngIf="tag.name">
<h1 class="sharable-header"> <a class="share-link" href="#{{tag.id}}"></a>{{tag.name}} </h1> <h1 class="sharable-header"> <a class="share-link" href="#{{tag.id}}"></a>{{tag.name}} </h1>
<p *ngIf="tag.description" [innerHtml]="tag.description | marked"> </p> <p *ngIf="tag.description" [innerHtml]="tag.description | marked"> </p>
<redoc-externalDocs [docs]="tag.metadata.externalDocs"></redoc-externalDocs> <redoc-externalDocs [docs]="tag.metadata.externalDocs"></redoc-externalDocs>
</div> </div>
<method *lazyFor="let methodItem of tag.items; let ready = ready;" <operation *lazyFor="let operation of tag.items; let ready = ready;"
[hidden]="!ready" [pointer]="methodItem.metadata.pointer" [hidden]="!ready" [pointer]="operation.metadata.pointer"
[parentTagId]="tag.id" [attr.section]="methodItem.id"></method> [parentTagId]="tag.id" [attr.section]="operation.id"></operation>
</div> </div>
</div> </div>

View File

@ -32,7 +32,7 @@
margin-top: 0; margin-top: 0;
} }
.methods { .operations {
display: block; display: block;
position: relative;; position: relative;;
} }

View File

@ -10,14 +10,14 @@ import {
import { getChildDebugElement } from '../../../tests/helpers'; import { getChildDebugElement } from '../../../tests/helpers';
import { MethodsList } from './methods-list'; import { OperationsList } from './operations-list';
import { SpecManager } from '../../utils/spec-manager'; import { SpecManager } from '../../utils/spec-manager';
describe('Redoc components', () => { describe('Redoc components', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ declarations: [ TestAppComponent ] }); TestBed.configureTestingModule({ declarations: [ TestAppComponent ] });
}); });
describe('MethodsList Component', () => { describe('OperationsList Component', () => {
let builder; let builder;
let component; let component;
let fixture; let fixture;
@ -28,12 +28,12 @@ describe('Redoc components', () => {
}))); })));
beforeEach(done => { beforeEach(done => {
specMgr.load('/tests/schemas/methods-list-component.json').then(done, done.fail); specMgr.load('/tests/schemas/operations-list-component.json').then(done, done.fail);
}); });
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(TestAppComponent); fixture = TestBed.createComponent(TestAppComponent);
component = getChildDebugElement(fixture.debugElement, 'methods-list').componentInstance; component = getChildDebugElement(fixture.debugElement, 'operations-list').componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
@ -56,7 +56,7 @@ describe('Redoc components', () => {
@Component({ @Component({
selector: 'test-app', selector: 'test-app',
template: template:
`<methods-list></methods-list>` `<operations-list></operations-list>`
}) })
class TestAppComponent { class TestAppComponent {
} }

View File

@ -4,12 +4,12 @@ import { BaseComponent, SpecManager } from '../base';
import { MenuService } from '../../services/index'; import { MenuService } from '../../services/index';
@Component({ @Component({
selector: 'methods-list', selector: 'operations-list',
templateUrl: './methods-list.html', templateUrl: './operations-list.html',
styleUrls: ['./methods-list.css'], styleUrls: ['./operations-list.css'],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class MethodsList extends BaseComponent implements OnInit { export class OperationsList extends BaseComponent implements OnInit {
@Input() pointer:string; @Input() pointer:string;
tags:Array<any> = []; tags:Array<any> = [];
@ -26,13 +26,13 @@ export class MethodsList extends BaseComponent implements OnInit {
items: [] items: []
}; };
flatMenuItems.forEach(menuItem => { flatMenuItems.forEach(menuItem => {
// skip items that are not bound to swagger tags/methods // skip items that are not bound to swagger tags/operations
if (!menuItem.metadata) return; if (!menuItem.metadata) return;
if (menuItem.metadata.type === 'tag') { if (menuItem.metadata.type === 'tag') {
this.tags.push(menuItem); this.tags.push(menuItem);
} }
if (menuItem.metadata.type === 'method' && !menuItem.parent) { if (menuItem.metadata.type === 'operation' && !menuItem.parent) {
emptyTag.items.push(menuItem); emptyTag.items.push(menuItem);
} }
}); });

View File

@ -27,7 +27,7 @@ export class ParamsList extends BaseComponent implements OnInit {
init() { init() {
this.params = []; this.params = [];
let paramsList = this.specMgr.getMethodParams(this.pointer); let paramsList = this.specMgr.getOperationParams(this.pointer);
paramsList = paramsList.map(paramSchema => { paramsList = paramsList.map(paramSchema => {
let propPointer = paramSchema._pointer; let propPointer = paramSchema._pointer;

View File

@ -17,7 +17,7 @@
<div class="api-content"> <div class="api-content">
<warnings></warnings> <warnings></warnings>
<api-info></api-info> <api-info></api-info>
<methods-list> </methods-list> <operations-list> </operations-list>
<footer> <footer>
<div class="powered-by-badge"> <div class="powered-by-badge">
<a href="https://github.com/Rebilly/ReDoc" title="Swagger-generated API Reference Documentation" target="_blank"> <a href="https://github.com/Rebilly/ReDoc" title="Swagger-generated API Reference Documentation" target="_blank">

View File

@ -15,13 +15,29 @@ import { BaseComponent } from '../base';
import * as detectScollParent from 'scrollparent'; import * as detectScollParent from 'scrollparent';
import { SpecManager } from '../../utils/spec-manager'; import { SpecManager } from '../../utils/spec-manager';
import { SearchService, OptionsService, Options, Hash, AppStateService, SchemaHelper } from '../../services/'; import {
SearchService,
OptionsService,
Options,
Hash,
AppStateService,
SchemaHelper,
MenuService,
Marker
} from '../../services/';
import { LazyTasksService } from '../../shared/components/LazyFor/lazy-for'; import { LazyTasksService } from '../../shared/components/LazyFor/lazy-for';
@Component({ @Component({
selector: 'redoc', selector: 'redoc',
templateUrl: './redoc.html', templateUrl: './redoc.html',
styleUrls: ['./redoc.css'], styleUrls: ['./redoc.css'],
providers: [
SpecManager,
MenuService,
SearchService,
LazyTasksService,
Marker
]
//changeDetection: ChangeDetectionStrategy.OnPush //changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class Redoc extends BaseComponent implements OnInit { export class Redoc extends BaseComponent implements OnInit {

View File

@ -16,7 +16,7 @@ import { SpecManager } from '../../utils/spec-manager';
describe('Redoc components', () => { describe('Redoc components', () => {
describe('MethodsList Component', () => { describe('ResponsesList Component', () => {
let builder; let builder;
let component: ResponsesList; let component: ResponsesList;
let fixture: ComponentFixture<ResponsesList> let fixture: ComponentFixture<ResponsesList>

View File

@ -62,7 +62,7 @@
} }
// do not capitalize method summuary in level-1 menu // do not capitalize method summuary in level-1 menu
&.menu-item-for-method > .menu-item-header { &.menu-item-for-operation > .menu-item-header {
text-transform: none; text-transform: none;
} }

View File

@ -11,7 +11,7 @@ import {
import { TestBed, ComponentFixture } from '@angular/core/testing'; import { TestBed, ComponentFixture } from '@angular/core/testing';
import { MethodsList, SideMenu } from '../index'; import { OperationsList, SideMenu } from '../index';
import { SpecManager } from '../../utils/spec-manager'; import { SpecManager } from '../../utils/spec-manager';
@ -19,7 +19,7 @@ let testOptions;
describe('Redoc components', () => { describe('Redoc components', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ declarations: [ TestAppComponent, MethodsList ] }); TestBed.configureTestingModule({ declarations: [ TestAppComponent, OperationsList ] });
}); });
describe('SideMenu Component', () => { describe('SideMenu Component', () => {
let builder; let builder;
@ -90,7 +90,7 @@ describe('Redoc components', () => {
selector: 'test-app', selector: 'test-app',
template: template:
`<side-menu></side-menu> `<side-menu></side-menu>
<methods-list></methods-list>` <operations-list></operations-list>`
}) })
class TestAppComponent { class TestAppComponent {
} }

View File

@ -1,8 +1,15 @@
'use strict'; 'use strict';
import { Component, EventEmitter, Input, Output, ElementRef, ChangeDetectorRef, OnInit, OnDestroy } from '@angular/core'; import { Component,
EventEmitter,
Input,
Output,
ElementRef,
ChangeDetectorRef,
OnInit,
OnDestroy
} from '@angular/core';
//import { global } from '@angular/core/src/facade/lang';
import { trigger, state, animate, transition, style } from '@angular/core'; import { trigger, state, animate, transition, style } from '@angular/core';
import { BaseComponent, SpecManager } from '../base'; import { BaseComponent, SpecManager } from '../base';
import { ScrollService, MenuService, OptionsService, MenuItem, Marker} from '../../services/'; import { ScrollService, MenuService, OptionsService, MenuItem, Marker} from '../../services/';
@ -51,9 +58,15 @@ export class SideMenu extends BaseComponent implements OnInit, OnDestroy {
private $resourcesNav: any; private $resourcesNav: any;
private $scrollParent: any; private $scrollParent: any;
constructor(specMgr:SpecManager, elementRef:ElementRef, constructor(
private scrollService:ScrollService, private menuService:MenuService, specMgr:SpecManager,
optionsService:OptionsService, private detectorRef:ChangeDetectorRef, private marker:Marker) { elementRef:ElementRef,
private scrollService:ScrollService,
private menuService:MenuService,
optionsService:OptionsService,
private detectorRef:ChangeDetectorRef,
private marker:Marker
) {
super(specMgr); super(specMgr);
this.$element = elementRef.nativeElement; this.$element = elementRef.nativeElement;

View File

@ -10,8 +10,8 @@ import { ResponsesList } from './ResponsesList/responses-list';
import { ResponsesSamples } from './ResponsesSamples/responses-samples'; import { ResponsesSamples } from './ResponsesSamples/responses-samples';
import { SchemaSample } from './SchemaSample/schema-sample'; import { SchemaSample } from './SchemaSample/schema-sample';
import { SideMenu, SideMenuItems } from './SideMenu/side-menu'; import { SideMenu, SideMenuItems } from './SideMenu/side-menu';
import { MethodsList } from './MethodsList/methods-list'; import { OperationsList } from './OperationsList/operations-list';
import { Method } from './Method/method'; import { Operation } from './Operation/operation';
import { Warnings } from './Warnings/warnings'; import { Warnings } from './Warnings/warnings';
import { SecurityDefinitions } from './SecurityDefinitions/security-definitions'; import { SecurityDefinitions } from './SecurityDefinitions/security-definitions';
import { LoadingBar } from './LoadingBar/loading-bar'; import { LoadingBar } from './LoadingBar/loading-bar';
@ -23,10 +23,10 @@ import { Redoc } from './Redoc/redoc';
export const REDOC_DIRECTIVES = [ export const REDOC_DIRECTIVES = [
ApiInfo, ApiLogo, JsonSchema, JsonSchemaLazy, ParamsList, RequestSamples, ResponsesList, ApiInfo, ApiLogo, JsonSchema, JsonSchemaLazy, ParamsList, RequestSamples, ResponsesList,
ResponsesSamples, SchemaSample, SideMenu, MethodsList, Method, Warnings, Redoc, SecurityDefinitions, ResponsesSamples, SchemaSample, SideMenu, OperationsList, Operation, Warnings, Redoc, SecurityDefinitions,
LoadingBar, SideMenuItems, RedocSearch, ExternalDocs, EndpointLink LoadingBar, SideMenuItems, RedocSearch, ExternalDocs, EndpointLink
]; ];
export { ApiInfo, ApiLogo, JsonSchema, JsonSchemaLazy, ParamsList, RequestSamples, ResponsesList, export { ApiInfo, ApiLogo, JsonSchema, JsonSchemaLazy, ParamsList, RequestSamples, ResponsesList,
ResponsesSamples, SchemaSample, SideMenu, MethodsList, Method, Warnings, Redoc, SecurityDefinitions, ResponsesSamples, SchemaSample, SideMenu, OperationsList, Operation, Warnings, Redoc, SecurityDefinitions,
LoadingBar, SideMenuItems, RedocSearch, ExternalDocs, EndpointLink } LoadingBar, SideMenuItems, ExternalDocs, EndpointLink }

View File

@ -1,7 +1,7 @@
import { NgModule, ErrorHandler, APP_ID } from '@angular/core'; import { NgModule, ErrorHandler, APP_ID } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Redoc, SecurityDefinitions, Method, REDOC_DIRECTIVES } from './components/index'; import { Redoc, SecurityDefinitions, Operation, REDOC_DIRECTIVES } from './components/index';
import { REDOC_COMMON_DIRECTIVES, DynamicNg2Wrapper } from './shared/components/index'; import { REDOC_COMMON_DIRECTIVES, DynamicNg2Wrapper } from './shared/components/index';
import { REDOC_PIPES } from './utils/pipes'; import { REDOC_PIPES } from './utils/pipes';
import { CustomErrorHandler } from './utils/' import { CustomErrorHandler } from './utils/'
@ -26,20 +26,15 @@ import { SpecManager } from './utils/spec-manager';
imports: [ CommonModule ], imports: [ CommonModule ],
declarations: [ REDOC_DIRECTIVES, REDOC_COMMON_DIRECTIVES, REDOC_PIPES ], declarations: [ REDOC_DIRECTIVES, REDOC_COMMON_DIRECTIVES, REDOC_PIPES ],
bootstrap: [ Redoc ], bootstrap: [ Redoc ],
entryComponents: [ SecurityDefinitions, DynamicNg2Wrapper, Method ], entryComponents: [ SecurityDefinitions, DynamicNg2Wrapper, Operation ],
providers: [ providers: [
SpecManager,
ScrollService, ScrollService,
Hash, Hash,
MenuService,
WarningsService, WarningsService,
OptionsService, OptionsService,
AppStateService, AppStateService,
ComponentParser, ComponentParser,
ContentProjector, ContentProjector,
SearchService,
LazyTasksService,
Marker,
{ provide: APP_ID, useValue: 'redoc' }, { provide: APP_ID, useValue: 'redoc' },
{ provide: ErrorHandler, useClass: CustomErrorHandler }, { provide: ErrorHandler, useClass: CustomErrorHandler },
{ provide: COMPONENT_PARSER_ALLOWED, useValue: { 'security-definitions': SecurityDefinitions} } { provide: COMPONENT_PARSER_ALLOWED, useValue: { 'security-definitions': SecurityDefinitions} }

View File

@ -12,7 +12,7 @@ describe('Hash Service', () => {
hashService = _hash; hashService = _hash;
})); }));
it('should trigger changed event when method start is called', () => { it('should trigger changed event when method `start` is called', () => {
spyOn(hashService.value, 'next').and.stub(); spyOn(hashService.value, 'next').and.stub();
hashService.start(); hashService.start();
expect(hashService.value.next).toHaveBeenCalled(); expect(hashService.value.next).toHaveBeenCalled();

View File

@ -27,8 +27,12 @@ export class Hash {
}); });
} }
update(hash: string|null) { update(hash: string|null, rewriteHistory:boolean = false) {
if (hash == undefined) return; if (hash == undefined) return;
if (rewriteHistory) {
window.history.replaceState(null, '', '#' + hash);
return;
}
this.noEmit = true; this.noEmit = true;
window.location.hash = hash; window.location.hash = hash;
setTimeout(() => { setTimeout(() => {

View File

@ -5,7 +5,7 @@ import {
TestBed TestBed
} from '@angular/core/testing'; } from '@angular/core/testing';
import { MethodsList } from '../components/MethodsList/methods-list'; import { OperationsList } from '../components/OperationsList/operations-list';
import { MenuService, MenuItem } from './menu.service'; import { MenuService, MenuItem } from './menu.service';
import { Hash } from './hash.service'; import { Hash } from './hash.service';
import { LazyTasksService } from '../shared/components/LazyFor/lazy-for'; import { LazyTasksService } from '../shared/components/LazyFor/lazy-for';
@ -15,7 +15,7 @@ import { SpecManager } from '../utils/spec-manager';
describe('Menu service', () => { describe('Menu service', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ declarations: [ TestAppComponent, MethodsList ] }); TestBed.configureTestingModule({ declarations: [ TestAppComponent, OperationsList ] });
}); });
let menu:MenuService, hashService, scroll, tasks; let menu:MenuService, hashService, scroll, tasks;
@ -41,7 +41,7 @@ describe('Menu service', () => {
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should scroll to method when location hash is present [jp]', (done) => { it('should scroll to operation when location hash is present [jp]', (done) => {
let hash = '#tag/pet/paths/~1pet~1findByStatus/get'; let hash = '#tag/pet/paths/~1pet~1findByStatus/get';
spyOn(menu, 'scrollToActive').and.callThrough(); spyOn(menu, 'scrollToActive').and.callThrough();
spyOn(window, 'scrollTo').and.stub(); spyOn(window, 'scrollTo').and.stub();
@ -56,7 +56,7 @@ describe('Menu service', () => {
hashService.value.next(hash); hashService.value.next(hash);
}); });
// //
it('should scroll to method when location hash is present [operation]', (done) => { it('should scroll to operation when location hash is present [operation]', (done) => {
let hash = '#operation/getPetById'; let hash = '#operation/getPetById';
spyOn(menu, 'scrollToActive').and.callThrough(); spyOn(menu, 'scrollToActive').and.callThrough();
spyOn(window, 'scrollTo').and.stub(); spyOn(window, 'scrollTo').and.stub();
@ -133,7 +133,7 @@ describe('Menu service', () => {
}); });
it('should return Array with correct number of items', () => { it('should return Array with correct number of items', () => {
// 3 - defined tags, 1 - tag3 and 1 method item for method without tag // 3 - defined tags, 1 - tag3 and 1 operation item for operation without tag
items.length.should.be.equal(3 + 1 + 1); items.length.should.be.equal(3 + 1 + 1);
}); });
@ -144,19 +144,19 @@ describe('Menu service', () => {
item.items[0].name.should.be.equal('test put'); item.items[0].name.should.be.equal('test put');
}); });
it('should append method items without tags to the end of list', () => { it('should append operation items without tags to the end of list', () => {
let methodItem = items[4]; let operationItem = items[4];
methodItem.name.should.be.equal('test post'); operationItem.name.should.be.equal('test post');
methodItem.metadata.type.should.be.equal('method'); operationItem.metadata.type.should.be.equal('operation');
should.not.exist(methodItem.items); should.not.exist(operationItem.items);
}); });
it('should map x-traitTag to empty method list', () => { it('should map x-traitTag to empty operation list', () => {
let item = items[0]; let item = items[0];
should.not.exist(item.items); should.not.exist(item.items);
}); });
it('methods for tag should contain valid pointer and name', () => { it('operations for tag should contain valid pointer and name', () => {
for (let item of items) { for (let item of items) {
item.should.be.an.Object(); item.should.be.an.Object();
if (item.items) { if (item.items) {
@ -186,7 +186,7 @@ describe('Menu service', () => {
template: template:
`<div id='parent' style='height: 500px; overflow:auto'> `<div id='parent' style='height: 500px; overflow:auto'>
<api-info></api-info> <api-info></api-info>
<methods-list></methods-list> <operations-list></operations-list>
</div>` </div>`
}) })
class TestAppComponent { class TestAppComponent {

View File

@ -54,7 +54,7 @@ export class MenuService {
private _hashSubscription: Subscription; private _hashSubscription: Subscription;
private _scrollSubscription: Subscription; private _scrollSubscription: Subscription;
private _progressSubscription: Subscription; private _progressSubscription: Subscription;
private _tagsWithMethods: any; private _tagsWithOperations: any;
constructor( constructor(
private hash:Hash, private hash:Hash,
@ -162,7 +162,7 @@ export class MenuService {
while(currentItem) { while(currentItem) {
if (currentItem.id) { if (currentItem.id) {
selector = `[section="${currentItem.id}"] ` + selector; selector = `[section="${currentItem.id}"] ` + selector;
// We only need to go up the chain for methods that // We only need to go up the chain for operations that
// might have multiple tags. For headers/subheaders // might have multiple tags. For headers/subheaders
// we need to siply early terminate. // we need to siply early terminate.
if (!currentItem.metadata) { if (!currentItem.metadata) {
@ -202,14 +202,14 @@ export class MenuService {
} }
} }
activate(idx, force = false) { activate(idx, force = false, replaceState = false) {
let item = this.flatItems[idx]; let item = this.flatItems[idx];
if (!force && item && !item.ready) return; if (!force && item && !item.ready) return;
this.deactivate(this.activeIdx); this.deactivate(this.activeIdx);
this.activeIdx = idx; this.activeIdx = idx;
if (idx < 0) { if (idx < 0) {
this.hash.update(''); this.hash.update('', replaceState);
return; return;
} }
@ -220,14 +220,14 @@ export class MenuService {
cItem.parent.active = true; cItem.parent.active = true;
cItem = cItem.parent; cItem = cItem.parent;
} }
this.hash.update(this.hashFor(item.id, item.metadata, item.parent && item.parent.id)); this.hash.update(this.hashFor(item.id, item.metadata, item.parent && item.parent.id), replaceState);
this.changedActiveItem.next(item); this.changedActiveItem.next(item);
} }
changeActive(offset = 1):boolean { changeActive(offset = 1):boolean {
let noChange = (this.activeIdx <= 0 && offset === -1) || let noChange = (this.activeIdx <= 0 && offset === -1) ||
(this.activeIdx === this.flatItems.length - 1 && offset === 1); (this.activeIdx === this.flatItems.length - 1 && offset === 1);
this.activate(this.activeIdx + offset); this.activate(this.activeIdx + offset, false, true);
return noChange; return noChange;
} }
@ -254,7 +254,10 @@ export class MenuService {
} }
idx = this.flatItems.findIndex(item => item.id === searchId); idx = this.flatItems.findIndex(item => item.id === searchId);
if (idx < 0) this.tryScrollToId(searchId); if (idx < 0) {
this.tryScrollToId(searchId);
return false;
}
} else if (namespace === 'operation') { } else if (namespace === 'operation') {
idx = this.flatItems.findIndex(item => { idx = this.flatItems.findIndex(item => {
return item.metadata && item.metadata.operationId === ptr; return item.metadata && item.metadata.operationId === ptr;
@ -304,19 +307,19 @@ export class MenuService {
return res; return res;
} }
getMethodsItems(parent: MenuItem, tag:any):MenuItem[] { getOperationsItems(parent: MenuItem, tag:any):MenuItem[] {
if (!tag.methods || !tag.methods.length) return null; if (!tag.operations || !tag.operations.length) return null;
let res = []; let res = [];
for (let method of tag.methods) { for (let operation of tag.operations) {
let subItem = { let subItem = {
name: SchemaHelper.methodSummary(method), name: SchemaHelper.operationSummary(operation),
id: method._pointer, id: operation._pointer,
description: method.description, description: operation.description,
metadata: { metadata: {
type: 'method', type: 'operation',
pointer: method._pointer, pointer: operation._pointer,
operationId: method.operationId operationId: operation.operationId
}, },
parent: parent parent: parent
}; };
@ -331,7 +334,7 @@ export class MenuService {
parentId: string parentId: string
) { ) {
if (!id) return null; if (!id) return null;
if (itemMeta && itemMeta.type === 'method') { if (itemMeta && itemMeta.type === 'operation') {
if (itemMeta.operationId) { if (itemMeta.operationId) {
return 'operation/' + encodeURIComponent(itemMeta.operationId); return 'operation/' + encodeURIComponent(itemMeta.operationId);
} else { } else {
@ -348,18 +351,18 @@ export class MenuService {
let tags; let tags;
if (!tagGroup) { if (!tagGroup) {
// all tags // all tags
tags = Object.keys(this._tagsWithMethods); tags = Object.keys(this._tagsWithOperations);
} else { } else {
tags = tagGroup.tags; tags = tagGroup.tags;
} }
tags = tags.map(k => { tags = tags.map(k => {
if (!this._tagsWithMethods[k]) { if (!this._tagsWithOperations[k]) {
WarningsService.warn(`Non-existing tag "${k}" is added to the group "${tagGroup.name}"`); WarningsService.warn(`Non-existing tag "${k}" is added to the group "${tagGroup.name}"`);
return null; return null;
} }
this._tagsWithMethods[k].used = true; this._tagsWithOperations[k].used = true;
return this._tagsWithMethods[k]; return this._tagsWithOperations[k];
}); });
let res = []; let res = [];
@ -368,9 +371,9 @@ export class MenuService {
let id = 'tag/' + slugify(tag.name); let id = 'tag/' + slugify(tag.name);
let item: MenuItem; let item: MenuItem;
// don't put empty tag into menu, instead put their methods // don't put empty tag into menu, instead put their operations
if (tag.name === '') { if (tag.name === '') {
let items = this.getMethodsItems(null, tag); let items = this.getOperationsItems(null, tag);
res.push(...items); res.push(...items);
continue; continue;
} }
@ -383,7 +386,7 @@ export class MenuService {
parent: parent, parent: parent,
items: null items: null
}; };
item.items = this.getMethodsItems(item, tag); item.items = this.getOperationsItems(item, tag);
res.push(item); res.push(item);
} }
@ -410,15 +413,15 @@ export class MenuService {
} }
checkAllTagsUsedInGroups() { checkAllTagsUsedInGroups() {
for (let tag of Object.keys(this._tagsWithMethods)) { for (let tag of Object.keys(this._tagsWithOperations)) {
if (!this._tagsWithMethods[tag].used) { if (!this._tagsWithOperations[tag].used) {
WarningsService.warn(`Tag "${tag}" is not added to any group`); WarningsService.warn(`Tag "${tag}" is not added to any group`);
} }
} }
} }
buildMenu() { buildMenu() {
this._tagsWithMethods = SchemaHelper.getTagsWithMethods(this.specMgr.schema); this._tagsWithOperations = SchemaHelper.getTagsWithOperations(this.specMgr.schema);
this.items = this.items || []; this.items = this.items || [];
this.addMarkdownItems(); this.addMarkdownItems();

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import { JsonPointer } from '../utils/JsonPointer'; import { JsonPointer } from '../utils/JsonPointer';
import { methods as swaggerMethods, keywordTypes } from '../utils/swagger-defs'; import { operations as swaggerOperations, keywordTypes } from '../utils/swagger-defs';
import { WarningsService } from './warnings.service'; import { WarningsService } from './warnings.service';
import * as slugify from 'slugify'; import * as slugify from 'slugify';
@ -273,9 +273,9 @@ export class SchemaHelper {
return res; return res;
} }
static methodSummary(method) { static operationSummary(operation) {
return method.summary || method.operationId || return operation.summary || operation.operationId ||
(method.description && method.description.substring(0, 50)) || '<no description>'; (operation.description && operation.description.substring(0, 50)) || '<no description>';
} }
static detectType(schema) { static detectType(schema) {
@ -290,26 +290,26 @@ export class SchemaHelper {
} }
} }
static getTagsWithMethods(schema) { static getTagsWithOperations(schema) {
let tags = {}; let tags = {};
for (let tag of schema.tags || []) { for (let tag of schema.tags || []) {
tags[tag.name] = tag; tags[tag.name] = tag;
tag.methods = []; tag.operations = [];
} }
let paths = schema.paths; let paths = schema.paths;
for (let path of Object.keys(paths)) { for (let path of Object.keys(paths)) {
let methods = Object.keys(paths[path]).filter((k) => swaggerMethods.has(k)); let operations = Object.keys(paths[path]).filter((k) => swaggerOperations.has(k));
for (let method of methods) { for (let operation of operations) {
let methodInfo = paths[path][method]; let operationInfo = paths[path][operation];
let methodTags = methodInfo.tags; let operationTags = operationInfo.tags;
// empty tag // empty tag
if (!(methodTags && methodTags.length)) { if (!(operationTags && operationTags.length)) {
methodTags = ['']; operationTags = [''];
} }
let methodPointer = JsonPointer.compile(['paths', path, method]); let operationPointer = JsonPointer.compile(['paths', path, operation]);
for (let tagName of methodTags) { for (let tagName of operationTags) {
let tag = tags[tagName]; let tag = tags[tagName];
if (!tag) { if (!tag) {
tag = { tag = {
@ -318,9 +318,9 @@ export class SchemaHelper {
tags[tagName] = tag; tags[tagName] = tag;
} }
if (tag['x-traitTag']) continue; if (tag['x-traitTag']) continue;
if (!tag.methods) tag.methods = []; if (!tag.operations) tag.operations = [];
tag.methods.push(methodInfo); tag.operations.push(operationInfo);
methodInfo._pointer = methodPointer; operationInfo._pointer = operationPointer;
} }
} }
} }

View File

@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { AppStateService } from './app-state.service'; import { AppStateService } from './app-state.service';
import { SchemaNormalizer } from './schema-normalizer.service'; import { SchemaNormalizer } from './schema-normalizer.service';
import { JsonPointer, groupBy, SpecManager, StringMap, snapshot, MarkdownHeading } from '../utils/'; import { JsonPointer, groupBy, SpecManager, StringMap, snapshot, MarkdownHeading } from '../utils/';
import { methods as swaggerMethods } from '../utils/swagger-defs'; import { operations as swaggerOperations } from '../utils/swagger-defs';
import * as slugify from 'slugify'; import * as slugify from 'slugify';
import { import {
@ -102,7 +102,7 @@ export class SearchService {
Object.keys(paths).forEach(path => { Object.keys(paths).forEach(path => {
let opearations = paths[path]; let opearations = paths[path];
Object.keys(opearations).forEach(verb => { Object.keys(opearations).forEach(verb => {
if (!swaggerMethods.has(verb)) return; if (!swaggerOperations.has(verb)) return;
const opearation = opearations[verb]; const opearation = opearations[verb];
const ptr = JsonPointer.join(basePtr, [path, verb]); const ptr = JsonPointer.join(basePtr, [path, verb]);
@ -123,7 +123,7 @@ export class SearchService {
} }
indexOperationParameters(operation: SwaggerOperation, operationPointer: string) { indexOperationParameters(operation: SwaggerOperation, operationPointer: string) {
const parameters = this.spec.getMethodParams(operationPointer); const parameters = this.spec.getOperationParams(operationPointer);
if (!parameters) return; if (!parameters) return;
for (let i=0; i<parameters.length; ++i) { for (let i=0; i<parameters.length; ++i) {
const param = parameters[i]; const param = parameters[i];

View File

@ -32,7 +32,6 @@ $headers-font: Montserrat;
$headers-font-family: sans-serif; $headers-font-family: sans-serif;
$headers-font-weight: $regular; $headers-font-weight: $regular;
$headers-color: $primary-color; $headers-color: $primary-color;
$method-headers-color: $primary-color;
$h1: 1.85714285714286em; $h1: 1.85714285714286em;
$h2: 1.5714285714285714em; $h2: 1.5714285714285714em;
$h3: 1.2857142857142858em; $h3: 1.2857142857142858em;

View File

@ -130,7 +130,7 @@ export class SpecManager {
return obj; return obj;
} }
getMethodParams(methodPtr:string):SwaggerParameter[] { getOperationParams(operationPtr:string):SwaggerParameter[] {
/* inject JsonPointer into array elements */ /* inject JsonPointer into array elements */
function injectPointers(array:SwaggerParameter[], root) { function injectPointers(array:SwaggerParameter[], root) {
if (!Array.isArray(array)) { if (!Array.isArray(array)) {
@ -143,23 +143,23 @@ export class SpecManager {
} }
// accept pointer directly to parameters as well // accept pointer directly to parameters as well
if (JsonPointer.baseName(methodPtr) === 'parameters') { if (JsonPointer.baseName(operationPtr) === 'parameters') {
methodPtr = JsonPointer.dirName(methodPtr); operationPtr = JsonPointer.dirName(operationPtr);
} }
//get path params //get path params
let pathParamsPtr = JsonPointer.join(JsonPointer.dirName(methodPtr), ['parameters']); let pathParamsPtr = JsonPointer.join(JsonPointer.dirName(operationPtr), ['parameters']);
let pathParams:SwaggerParameter[] = this.byPointer(pathParamsPtr) || []; let pathParams:SwaggerParameter[] = this.byPointer(pathParamsPtr) || [];
let methodParamsPtr = JsonPointer.join(methodPtr, ['parameters']); let operationParamsPtr = JsonPointer.join(operationPtr, ['parameters']);
let methodParams:SwaggerParameter[] = this.byPointer(methodParamsPtr) || []; let operationParams:SwaggerParameter[] = this.byPointer(operationParamsPtr) || [];
pathParams = injectPointers(pathParams, pathParamsPtr); pathParams = injectPointers(pathParams, pathParamsPtr);
methodParams = injectPointers(methodParams, methodParamsPtr); operationParams = injectPointers(operationParams, operationParamsPtr);
// resolve references // resolve references
methodParams = this.resolveRefs(methodParams); operationParams = this.resolveRefs(operationParams);
pathParams = this.resolveRefs(pathParams); pathParams = this.resolveRefs(pathParams);
return methodParams.concat(pathParams); return operationParams.concat(pathParams);
} }
getTagsMap() { getTagsMap() {

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
export const methods = new Set(['get', 'put', 'post', 'delete', 'options', 'head', 'patch']); export const operations = new Set(['get', 'put', 'post', 'delete', 'options', 'head', 'patch']);
export const keywordTypes = { export const keywordTypes = {
multipleOf: 'number', multipleOf: 'number',

View File

@ -1,7 +1,7 @@
{ {
"name": "redoc", "name": "redoc",
"description": "Swagger-generated API Reference Documentation", "description": "Swagger-generated API Reference Documentation",
"version": "1.12.0", "version": "1.12.1",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git://github.com/Rebilly/ReDoc" "url": "git://github.com/Rebilly/ReDoc"

View File

@ -35,8 +35,8 @@ function basicTests(swaggerUrl, title) {
let $redoc = $('redoc'); let $redoc = $('redoc');
expect($redoc.isPresent()).toBe(true); expect($redoc.isPresent()).toBe(true);
setTimeout(() => { setTimeout(() => {
let $methods = $$('method'); let $operations = $$('operation');
expect($methods.count()).toBeGreaterThan(0); expect($operations.count()).toBeGreaterThan(0);
done(); done();
}); });
}); });

View File

@ -26,7 +26,7 @@
"summary": "test get", "summary": "test get",
"parameters": [ "parameters": [
{ {
"name": "methodParam", "name": "operationParam",
"in": "path", "in": "path",
"type": "string" "type": "string"
} }
@ -41,7 +41,7 @@
"summary": "test get", "summary": "test get",
"parameters": [ "parameters": [
{ {
"name": "methodParam", "name": "operationParam",
"in": "path", "in": "path",
"type": "string" "type": "string"
} }

View File

@ -104,47 +104,47 @@ describe('Utils', () => {
}); });
}); });
describe('getMethodParams method', () => { describe('getOperationParams method', () => {
beforeEach((done:any) => { beforeEach((done:any) => {
specMgr.load('/tests/schemas/schema-mgr-methodparams.json').then(done, done.fail); specMgr.load('/tests/schemas/schema-mgr-operationParams.json').then(done, done.fail);
}); });
it('should propagate path parameters', () => { it('should propagate path parameters', () => {
let params = specMgr.getMethodParams('/paths/test1/get'); let params = specMgr.getOperationParams('/paths/test1/get');
params.length.should.be.equal(2); params.length.should.be.equal(2);
params[0].name.should.be.equal('methodParam'); params[0].name.should.be.equal('operationParam');
params[1].name.should.be.equal('pathParam'); params[1].name.should.be.equal('pathParam');
}); });
it('should inject correct pointers', () => { it('should inject correct pointers', () => {
let params = specMgr.getMethodParams('/paths/test1/get'); let params = specMgr.getOperationParams('/paths/test1/get');
params[0]._pointer.should.be.equal('/paths/test1/get/parameters/0'); params[0]._pointer.should.be.equal('/paths/test1/get/parameters/0');
params[1]._pointer.should.be.equal('/paths/test1/parameters/0'); params[1]._pointer.should.be.equal('/paths/test1/parameters/0');
}); });
it('should accept pointer directly to parameters', () => { it('should accept pointer directly to parameters', () => {
let params = specMgr.getMethodParams('/paths/test1/get/parameters'); let params = specMgr.getOperationParams('/paths/test1/get/parameters');
expect(params).not.toBeNull(); expect(params).not.toBeNull();
params.length.should.be.equal(2); params.length.should.be.equal(2);
}); });
it('should resolve path params from Parameters Definitions Object', () => { it('should resolve path params from Parameters Definitions Object', () => {
let params = specMgr.getMethodParams('/paths/test2/get'); let params = specMgr.getOperationParams('/paths/test2/get');
params.length.should.be.equal(2); params.length.should.be.equal(2);
params[0].name.should.be.equal('methodParam'); params[0].name.should.be.equal('operationParam');
params[1].name.should.be.equal('extParam'); params[1].name.should.be.equal('extParam');
params[1]._pointer.should.be.equal('#/parameters/extparam'); params[1]._pointer.should.be.equal('#/parameters/extparam');
}); });
it('should resolve method params from Parameters Definitions Object', () => { it('should resolve operation params from Parameters Definitions Object', () => {
let params = specMgr.getMethodParams('/paths/test3/get'); let params = specMgr.getOperationParams('/paths/test3/get');
params.length.should.be.equal(1); params.length.should.be.equal(1);
params[0].name.should.be.equal('extParam'); params[0].name.should.be.equal('extParam');
params[0]._pointer.should.be.equal('#/parameters/extparam'); params[0]._pointer.should.be.equal('#/parameters/extparam');
}); });
it('should throw for parameters other than array', () => { it('should throw for parameters other than array', () => {
let func = () => specMgr.getMethodParams('/paths/test4/get'); let func = () => specMgr.getOperationParams('/paths/test4/get');
expect(func).toThrow(); expect(func).toThrow();
}); });
}); });