Merge commit 'a2beb2432dc62f48b23a6f1c7487d0b3a31b3b19' into releases

This commit is contained in:
RedocBot 2016-07-01 15:44:33 +00:00 committed by travis@localhost
commit e26aa7834c
38 changed files with 356 additions and 503 deletions

View File

@ -39,7 +39,6 @@ module.exports = function (config) {
//load angular dependencies and browser polyfills
files: [
'node_modules/zone.js/dist/zone.js',
'node_modules/zone.js/dist/fake-async-test.js',
'node_modules/zone.js/dist/async-test.js',
'node_modules/zone.js/dist/jasmine-patch.js',
'node_modules/zone.js/dist/long-stack-trace-zone.js',

View File

@ -1,47 +1,32 @@
'use strict';
import { getChildDebugElement } from '../../../tests/helpers';
import { Component, provide } from '@angular/core';
import { Component } from '@angular/core';
import {
inject,
async,
expect,
beforeEach,
beforeEachProviders,
it
TestComponentBuilder
} from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { ApiInfo } from './api-info';
import { SpecManager } from '../../utils/SpecManager';
import { OptionsService } from '../../services/index';
describe('Redoc components', () => {
describe('ApiInfo Component', () => {
let builder;
let component;
let fixture;
beforeEachProviders(() => [
provide(SpecManager, {useValue: new SpecManager()}),
provide(OptionsService, {useClass: OptionsService})
]);
beforeEach(async(inject([TestComponentBuilder, SpecManager], (tcb, specMgr) => {
builder = tcb;
return specMgr.load('/tests/schemas/api-info-test.json');
})));
beforeEach((done) => {
builder.createAsync(TestAppComponent).then(_fixture => {
fixture = _fixture;
component = getChildDebugElement(fixture.debugElement, 'api-info').componentInstance;
fixture.detectChanges();
done();
}, err => {
done.fail(err);
});
beforeEach(() => {
fixture = builder.createSync(TestAppComponent);
component = getChildDebugElement(fixture.debugElement, 'api-info').componentInstance;
fixture.detectChanges();
});
@ -54,7 +39,7 @@ describe('Redoc components', () => {
it('should render api name and version', () => {
let nativeElement = getChildDebugElement(fixture.debugElement, 'api-info').nativeElement;
let headerElement = nativeElement.querySelector('h1');
expect(headerElement).toHaveText('Swagger Petstore (1.0.0)');
expect(headerElement.innerText).toContain('Swagger Petstore (v1.0.0)');
});
});
});

View File

@ -18,5 +18,8 @@ export class ApiInfo extends BaseComponent {
prepareModel() {
this.data = this.componentSchema.info;
this.specUrl = this.optionsService.options.specUrl;
if (parseInt(this.data.version.substring(0, 1)) !== NaN) {
this.data.version = 'v' + this.data.version;
}
}
}

View File

@ -1,18 +1,14 @@
'use strict';
import { getChildDebugElement } from '../../../tests/helpers';
import {Component, provide} from '@angular/core';
import { Component } from '@angular/core';
import {
inject,
async,
beforeEach,
beforeEachProviders,
it
TestComponentBuilder
} from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { ApiLogo } from './api-logo';
import { SpecManager } from '../../utils/SpecManager';
@ -25,21 +21,15 @@ describe('Redoc components', () => {
let specMgr;
let schemaUrl = '/tests/schemas/api-info-test.json';
beforeEachProviders(() => [
provide(SpecManager, {useValue: new SpecManager()})
]);
beforeEach(async(inject([TestComponentBuilder, SpecManager], (tcb, _specMgr) => {
builder = tcb;
specMgr = _specMgr;
return specMgr.load(schemaUrl);
})));
beforeEach((done) => {
builder.createAsync(TestAppComponent).then(_fixture => {
fixture = _fixture;
component = getChildDebugElement(fixture.debugElement, 'api-logo').componentInstance;
fixture.detectChanges();
done();
}, err => done.fail(err));
beforeEach(() => {
fixture = builder.createSync(TestAppComponent);
component = getChildDebugElement(fixture.debugElement, 'api-logo').componentInstance;
fixture.detectChanges();
});

View File

@ -87,6 +87,11 @@ $sub-schema-offset: ($bullet-size/2) + $bullet-margin;
display: inline-block;
}
.param-type-file {
font-weight: bold;
text-transform: capitalize;
}
/* tree */
// Bullet

View File

@ -1,41 +1,33 @@
'use strict';
import { getChildDebugElement } from '../../../tests/helpers';
import { Component, provide } from '@angular/core';
import { Component } from '@angular/core';
import {
inject,
beforeEach,
beforeEachProviders,
it
TestComponentBuilder
} from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { JsonSchemaLazy } from './json-schema-lazy';
import { SpecManager } from '../../utils/SpecManager';
describe('Redoc components', () => {
describe('JsonSchemaLazy Component', () => {
let builder;
let component;
let specMgr = new SpecManager();
let fixture;
beforeEachProviders(() => [
provide(SpecManager, {useValue: specMgr})
]);
beforeEach(inject([TestComponentBuilder], (tcb, dcl) => {
beforeEach(inject([TestComponentBuilder], (tcb) => {
builder = tcb;
}));
beforeEach((done) => {
builder.createAsync(TestAppComponent).then(_fixture => {
fixture = _fixture;
let debugEl = getChildDebugElement(fixture.debugElement, 'json-schema-lazy');
component = <JsonSchemaLazy>debugEl.componentInstance;
spyOn(component, '_loadAfterSelf').and.callThrough();
done();
}, err => done.fail(err));
beforeEach(() => {
fixture = builder.createSync(TestAppComponent);
let debugEl = getChildDebugElement(fixture.debugElement, 'json-schema-lazy');
component = <JsonSchemaLazy>debugEl.componentInstance;
spyOn(component, '_loadAfterSelf').and.stub();
});
afterEach(() => {
component._loadAfterSelf.and.callThrough();
});
it('should init component', () => {

View File

@ -1,10 +1,14 @@
<span *ngIf="schema.isFile" class="param-wrap">
<span class="param-file">file</span>
<span class="param-type-file">file</span>
<div *ngIf="schema._produces && !isRequestSchema" class="file produces">
Produces: {{ schema._produces | json }}
<ul>
<li *ngFor="let type of schema._produces">{{type}}</li>
</ul>
</div>
<div *ngIf="schema._consumes && isRequestSchema" class="file consume">
Consumes: {{ schema._consumes | json }}
<ul>
<li *ngFor="let type of schema._consumes">{{type}}</li>
</ul>
</div>
</span>
<span *ngIf="schema.isTrivial && !schema.isFile" class="param-wrap">

View File

@ -180,31 +180,16 @@ $array-marker-line-height: 1.5;
}
}
ul {
text-align: left;
ul, li {
margin: 0;
padding: 0;
display: block;
}
li {
margin: 0.5em 0.3em 0.2em 0;
font-family: $headers-font, $headers-font-family;
font-size: .929em;
line-height: .929em;
border: 0;
color: white;
padding: 2px 8px 4px 8px;
border-radius: $border-radius;
background-color: rgba($black, 0.3);
display: inline-block;
cursor: pointer;
&:last-of-type {
margin-right: 0;
}
&.active {
background-color: $primary-color;
}
ul {
list-style: none;
padding-left: 1em;
}
li:before {
content: "- ";
font-weight: bold;
}

View File

@ -1,13 +1,10 @@
'use strict';
import { Component, provide } from '@angular/core';
import { Component } from '@angular/core';
import {
inject,
beforeEach,
beforeEachProviders,
it
TestComponentBuilder
} from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { getChildDebugElement } from '../../../tests/helpers';
@ -19,21 +16,17 @@ describe('Redoc components', () => {
describe('JsonSchema Component', () => {
let builder;
let component;
let specMgr = new SpecManager();
let fixture;
beforeEachProviders(() => [
provide(SpecManager, {useValue: specMgr})
]);
beforeEach(inject([TestComponentBuilder], (tcb) => {
let specMgr;
beforeEach(inject([TestComponentBuilder, SpecManager], (tcb, _spec) => {
builder = tcb;
specMgr = _spec;
}));
beforeEach((done) => {
builder.createAsync(TestAppComponent).then(_fixture => {
fixture = _fixture;
let debugEl = getChildDebugElement(fixture.debugElement, 'json-schema');
component = debugEl.componentInstance;
done();
}, err => done.fail(err));
beforeEach(() => {
fixture = builder.createSync(TestAppComponent);
let debugEl = getChildDebugElement(fixture.debugElement, 'json-schema');
component = debugEl.componentInstance;
});
it('should init component', () => {

View File

@ -1,7 +1,7 @@
<div class="method">
<div class="method-content">
<h2 class="method-header sharable-header">
<a class="share-link" href="#{{data.methodAnchor}}"></a>{{data.methodInfo.summary}}
<a class="share-link" href="#{{data.methodAnchor}}"></a>{{data.summary}}
</h2>
<div class="method-tags" *ngIf="data.methodInfo.tags.length">
<a *ngFor="let tag of data.methodInfo.tags" attr.href="#{{tag}}"> {{tag}} </a>

View File

@ -38,7 +38,7 @@ responses-list, params-list {
}
.api-url {
color: rgba(#ffffff, .8);
color: rgba(#ffffff, .6);
margin-left: 10px;
margin-top: 2px;
position: relative;

View File

@ -1,14 +1,11 @@
'use strict';
import { Component, provide } from '@angular/core';
import { Component } from '@angular/core';
import {
inject,
async,
beforeEach,
beforeEachProviders,
it
TestComponentBuilder
} from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { getChildDebugElement } from '../../../tests/helpers';
@ -19,19 +16,16 @@ describe('Redoc components', () => {
describe('Method Component', () => {
let builder;
let component;
beforeEachProviders(() => [
provide(SpecManager, {useValue: new SpecManager()})
]);
beforeEach(async(inject([TestComponentBuilder, SpecManager], (tcb, specMgr) => {
builder = tcb;
return specMgr.load('/tests/schemas/extended-petstore.yml');
})));
beforeEach((done) => {
builder.createAsync(TestAppComponent).then(fixture => {
component = getChildDebugElement(fixture.debugElement, 'method').componentInstance;
fixture.detectChanges();
done();
}, err => done.fail(err));
beforeEach(() => {
let fixture = builder.createSync(TestAppComponent);
component = getChildDebugElement(fixture.debugElement, 'method').componentInstance;
fixture.detectChanges();
});

View File

@ -8,6 +8,7 @@ import { ResponsesList } from '../ResponsesList/responses-list';
import { ResponsesSamples } from '../ResponsesSamples/responses-samples';
import { SchemaSample } from '../SchemaSample/schema-sample';
import { RequestSamples } from '../RequestSamples/request-samples';
import { SchemaHelper } from '../../services/schema-helper.service';
@RedocComponent({
selector: 'method',
@ -31,6 +32,7 @@ export class Method extends BaseComponent {
this.data.methodInfo = this.componentSchema;
this.data.methodInfo.tags = this.filterMainTags(this.data.methodInfo.tags);
this.data.bodyParam = this.findBodyParam();
this.data.summary = SchemaHelper.methodSummary(this.componentSchema);
if (this.componentSchema.operationId) {
this.data.methodAnchor = 'operation/' + encodeURIComponent(this.componentSchema.operationId);
} else {

View File

@ -1,6 +1,6 @@
<div class="methods">
<div class="tag" *ngFor="let tag of data.tags">
<div class="tag-info" [attr.tag]="tag.name">
<div class="tag" *ngFor="let tag of data.tags;trackBy:trackByTagName">
<div class="tag-info" [attr.tag]="tag.name" *ngIf="!tag.empty">
<h1 class="sharable-header"> <a class="share-link" href="#tag/{{tag.name | encodeURIComponent}}"></a>{{tag.name}} </h1>
<p *ngIf="tag.description" [innerHtml]="tag.description | marked"> </p>
</div>

View File

@ -1,14 +1,11 @@
'use strict';
import { Component, provide } from '@angular/core';
import { Component } from '@angular/core';
import {
inject,
async,
beforeEach,
beforeEachProviders,
it
TestComponentBuilder
} from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { getChildDebugElement } from '../../../tests/helpers';
@ -21,20 +18,15 @@ describe('Redoc components', () => {
let builder;
let component;
let fixture;
beforeEachProviders(() => [
provide(SpecManager, {useValue: new SpecManager()})
]);
beforeEach(async(inject([TestComponentBuilder, SpecManager], (tcb, specMgr) => {
builder = tcb;
return specMgr.load('/tests/schemas/methods-list-component.json');
})));
beforeEach((done) => {
builder.createAsync(TestAppComponent).then(_fixture => {
fixture = _fixture;
component = getChildDebugElement(fixture.debugElement, 'methods-list').componentInstance;
fixture.detectChanges();
done();
}, err => done.fail(err) );
beforeEach(() => {
fixture = builder.createSync(TestAppComponent);
component = getChildDebugElement(fixture.debugElement, 'methods-list').componentInstance;
fixture.detectChanges();
});

View File

@ -4,6 +4,7 @@ import { forwardRef } from '@angular/core';
import { RedocComponent, BaseComponent, SpecManager } from '../base';
import { Method } from '../Method/method';
import { EncodeURIComponentPipe } from '../../utils/pipes';
import { SchemaHelper } from '../../services/index';
@RedocComponent({
selector: 'methods-list',
@ -24,21 +25,14 @@ export class MethodsList extends BaseComponent {
// follow SwaggerUI behavior for cases when one method has more than one tag:
// duplicate methods
let menuStructure = this.specMgr.buildMenuTree();
let tags = Array.from<any>(menuStructure.entries())
.map((entry) => {
let [tag, {description, methods}] = entry;
// inject tag name into method info
methods = methods || [];
methods.forEach(method => {
method.tag = tag;
});
return {
name: tag,
description: description,
methods: methods
};
let tags = SchemaHelper.buildMenuTree(this.specMgr.schema);
tags.forEach(tagInfo => {
// inject tag name into method info
tagInfo.methods = tagInfo.methods || [];
tagInfo.methods.forEach(method => {
method.tag = tagInfo.name;
});
});
this.data.tags = tags;
// TODO: check $ref field
}
@ -46,4 +40,8 @@ export class MethodsList extends BaseComponent {
trackByPointer(idx, el) {
return el.pointer;
}
trackByTagName(idx, el) {
return el.name;
}
}

View File

@ -1,15 +1,12 @@
'use strict';
import { getChildDebugElement } from '../../../tests/helpers';
import { Component, provide, ComponentRef } from '@angular/core';
import { Component, ComponentRef } from '@angular/core';
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
import {
inject,
async,
beforeEach,
beforeEachProviders,
it
async
} from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
@ -24,40 +21,27 @@ describe('Redoc components', () => {
describe('Redoc Component', () => {
let builder;
let specMgr;
beforeEachProviders(() => [
provide(SpecManager, {useValue: new SpecManager()}),
]);
beforeEach(async(inject([TestComponentBuilder, SpecManager, OptionsService],
(tcb, _specMgr, _optsMgr) => {
optsMgr = _optsMgr;
builder = tcb;
specMgr = _specMgr;
return specMgr.load('/tests/schemas/extended-petstore.yml');
})));
beforeEach((done) => {
return specMgr.load('/tests/schemas/extended-petstore.yml')
.then(() => done())
.catch(err => done.fail(err));
it('should init component', () => {
let fixture = builder.createSync(TestAppComponent);
let component = getChildDebugElement(fixture.debugElement, 'redoc').componentInstance;
expect(component).not.toBeNull();
fixture.destroy();
});
it('should init component', (done) => {
builder.createAsync(TestAppComponent).then(fixture => {
let component = getChildDebugElement(fixture.debugElement, 'redoc').componentInstance;
expect(component).not.toBeNull();
fixture.destroy();
done();
}, err => done.fail(err));
});
it('should init components tree without errors', (done) => {
builder.createAsync(TestAppComponent).then(fixture => {
(() => fixture.detectChanges()).should.not.throw();
fixture.destroy();
done();
}, err => {
return done.fail(err);
});
it('should init components tree without errors', () => {
let fixture = builder.createSync(TestAppComponent);
(() => fixture.detectChanges()).should.not.throw();
fixture.destroy();
});
});
@ -74,7 +58,7 @@ describe('Redoc components', () => {
});
it('should return promise', () => {
let res = Redoc.init();
let res = Redoc.init().catch(() => {/**/});
res.should.be.instanceof(Promise);
});
@ -82,7 +66,7 @@ describe('Redoc components', () => {
spyOn(Redoc, 'hideLoadingAnimation').and.callThrough();
spyOn(Redoc, 'displayError').and.callThrough();
let res = Redoc.init();
return res.then(() => {
return res.catch(() => {
expect(Redoc.hideLoadingAnimation).toHaveBeenCalled();
expect(Redoc.displayError).toHaveBeenCalled();
});
@ -103,29 +87,25 @@ describe('Redoc components', () => {
let builder;
let fixture;
let element;
let dom;
let destroySpy;
let dom = new BrowserDomAdapter();
beforeEachProviders(() => [
provide(SpecManager, {useValue: new SpecManager()}),
provide(BrowserDomAdapter, {useValue: new BrowserDomAdapter()}),
provide(OptionsService, {useValue: optsMgr})
]);
beforeEach(async(inject([TestComponentBuilder, SpecManager], (tcb, specMgr) => {
beforeEach(async(inject([TestComponentBuilder, SpecManager, OptionsService, BrowserDomAdapter],
(tcb, specMgr, opts, _dom) => {
builder = tcb;
return specMgr.load('/tests/schemas/methods-list-component.json');
optsMgr = opts;
dom = _dom;
return specMgr.load('/tests/schemas/extended-petstore.yml');
})));
beforeEach((done) => {
builder.createAsync(TestAppComponent).then(_fixture => {
fixture = _fixture;
element = getChildDebugElement(fixture.debugElement, 'methods-list').nativeElement;
destroySpy = jasmine.createSpy('spy');
Redoc.appRef = <ComponentRef<any>>{
destroy: destroySpy
};
fixture.detectChanges();
done();
}, err => { throw err; });
beforeEach(() => {
fixture = builder.createSync(TestAppComponent);
element = getChildDebugElement(fixture.debugElement, 'methods-list').nativeElement;
destroySpy = jasmine.createSpy('spy');
Redoc.appRef = <ComponentRef<any>>{
destroy: destroySpy
};
fixture.detectChanges();
});
afterEach(()=> {

View File

@ -79,10 +79,10 @@ export class Redoc extends BaseComponent implements AfterViewInit {
Redoc.hideLoadingAnimation();
Redoc.appRef = appRef;
console.log('ReDoc bootstrapped!');
}, err => {
console.log(err);
}).catch(err => {
Redoc.hideLoadingAnimation();
Redoc.displayError(err);
throw err;
});
}
@ -97,7 +97,6 @@ export class Redoc extends BaseComponent implements AfterViewInit {
}
static displayError(err) {
console.log(err);
let redocEl = dom.query('redoc');
if (!redocEl) return;
let heading = 'Oops... ReDoc failed to render this spec';

View File

@ -9,7 +9,8 @@
<h5 class="menu-header"> API reference </h5>
<div *ngFor="let cat of data.menu; let idx = index" class="menu-cat">
<label class="menu-cat-header" (click)="activateAndScroll(idx, -1)" [ngClass]="{active: cat.active}"> {{cat.name}}</label>
<label class="menu-cat-header" (click)="activateAndScroll(idx, -1)" [hidden]="cat.empty"
[ngClass]="{active: cat.active}"> {{cat.name}}</label>
<ul class="menu-subitems" @itemAnimation="cat.active ? 'expanded' : 'collapsed'">
<li *ngFor="let method of cat.methods; let methIdx = index"
[ngClass]="{active: method.active}"

View File

@ -29,6 +29,10 @@ $mobile-menu-compact-breakpoint: 550px;
color: $primary-color;
background-color: $side-menu-active-bg-color;
}
&[hidden] {
display: none;
}
}
.menu-subitems {

View File

@ -1,15 +1,12 @@
'use strict';
import { getChildDebugElement } from '../../../tests/helpers';
import { Component, provide } from '@angular/core';
import { Component } from '@angular/core';
import { OptionsService } from '../../services/index';
import {
inject,
async,
beforeEach,
beforeEachProviders,
it
async
} from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
@ -25,9 +22,7 @@ describe('Redoc components', () => {
let builder;
let component;
let fixture;
beforeEachProviders(() => [
provide(SpecManager, {useValue: new SpecManager()})
]);
beforeEach(async(inject([TestComponentBuilder, SpecManager, OptionsService],
(tcb, specMgr, opts) => {
builder = tcb;
@ -39,15 +34,10 @@ describe('Redoc components', () => {
return specMgr.load('/tests/schemas/extended-petstore.yml');
})));
beforeEach((done) => {
builder.createAsync(TestAppComponent).then(_fixture => {
fixture = _fixture;
component = getChildDebugElement(fixture.debugElement, 'side-menu').componentInstance;
fixture.detectChanges();
done();
}, err => {
throw err;
});
beforeEach(() => {
fixture = builder.createSync(TestAppComponent);
component = getChildDebugElement(fixture.debugElement, 'side-menu').componentInstance;
fixture.detectChanges();
});
afterEach(() => {

View File

@ -60,9 +60,7 @@ export function RedocComponent(options) {
inputs: inputs,
outputs: options.outputs,
providers: options.providers,
changeDetection: options.detect ?
(options.onPushOnly ? ChangeDetectionStrategy.OnPush : ChangeDetectionStrategy.Default) :
ChangeDetectionStrategy.Detached,
changeDetection: options.onPushOnly ? ChangeDetectionStrategy.OnPush : ChangeDetectionStrategy.Default,
animations: options.animations,
templateUrl: options.templateUrl,
template: options.template,

View File

@ -1,17 +1,11 @@
'use strict';
import { provide, Component } from '@angular/core';
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
import { Component } from '@angular/core';
import {
inject,
beforeEach,
describe,
beforeEachProviders,
it,
async
async,
TestComponentBuilder
} from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { MenuService } from './menu.service';
import { Hash } from './hash.service';
import { ScrollService } from './scroll.service';
@ -21,37 +15,21 @@ import { SpecManager } from '../utils/SpecManager';;
describe('Menu service', () => {
let menu, hashService, scroll;
let builder;
let specMgr = new SpecManager();
let specMgr;
beforeEachProviders(() => [
provide(BrowserDomAdapter, {useClass: BrowserDomAdapter}),
provide(Hash, {useClass: Hash}),
provide(ScrollService, {useClass: ScrollService}),
provide(SpecManager, {useValue: new SpecManager()})
]);
beforeEach(async(inject([Hash, ScrollService, TestComponentBuilder, SpecManager],
(_hash, _scroll, tcb, _specMgr) => {
beforeEach(async(inject([TestComponentBuilder, SpecManager, Hash, ScrollService],
(tcb, _specMgr, _hash, _scroll, _menu) => {
hashService = _hash;
scroll = _scroll;
builder = tcb;
specMgr = _specMgr;
return specMgr.load('/tests/schemas/extended-petstore.yml');
})));
beforeEach(done => {
specMgr.load('/tests/schemas/extended-petstore.yml').then(r => {
done();
}).catch(e => {
done.fail(e);
});
});
beforeEach(done => {
beforeEach(() => {
menu = new MenuService(hashService, scroll, specMgr);
builder.createAsync(TestAppComponent).then(fixture => {
fixture.detectChanges();
done();
}).catch(err => done.fail(err) );
let fixture = builder.createSync(TestAppComponent);
fixture.detectChanges();
});
it('should run hashScroll when hash changed', (done) => {

View File

@ -3,6 +3,7 @@ import { Injectable, EventEmitter } from '@angular/core';
import { ScrollService, INVIEW_POSITION } from './scroll.service';
import { Hash } from './hash.service';
import { SpecManager } from '../utils/SpecManager';
import { SchemaHelper } from './schema-helper.service';
const CHANGE = {
NEXT : 1,
@ -21,9 +22,7 @@ export class MenuService {
constructor(private hash:Hash, private scrollService:ScrollService, specMgr:SpecManager) {
this.hash = hash;
this.categories = Array.from(specMgr.buildMenuTree().entries()).map(
el => ({name: el[0], description: el[1].description, methods: el[1].methods})
);
this.categories = SchemaHelper.buildMenuTree(specMgr.schema);
scrollService.scroll.subscribe((evt) => {
this.scrollUpdate(evt.isScrolledDown);

View File

@ -1,10 +1,6 @@
'use strict';
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
import {
it
} from '@angular/core/testing';
import { OptionsService } from './options.service';
describe('Options Service', () => {

View File

@ -0,0 +1,84 @@
'use strict';
import { SchemaHelper } from './schema-helper.service';
import { SpecManager } from '../utils/SpecManager';
describe('Spec Helper', () => {
describe('buildMenuTree method', () => {
let suitSchema = {
tags: [
{name: 'tag1', description: 'info1', 'x-traitTag': true},
{name: 'tag2', description: 'info2'}
],
paths: {
test: {
put: {
tags: ['tag1', 'tag3'],
summary: 'test put'
},
get: {
tags: ['tag1', 'tag2'],
summary: 'test get'
},
// no tags
post: {
summary: 'test post'
}
}
}
};
let menuTree;
let specMgr;
beforeAll(() => {
specMgr = new SpecManager();
specMgr._schema = suitSchema;
menuTree = SchemaHelper.buildMenuTree(suitSchema);
});
it('should return instance of Array', () => {
menuTree.should.be.instanceof(Array);
});
it('should return Array with correct number of items', () => {
//2 - defined tags, 1 - tag3 and 1 [other] tag for no-tags method
menuTree.length.should.be.equal(2 + 1 + 1);
});
it('should append not defined tags to the end of list', () => {
let info = menuTree[2];
info.name.should.be.equal('tag3');
info.methods.length.should.be.equal(1);
info.methods[0].summary.should.be.equal('test put');
});
it('should append methods without tags to [other] tag', () => {
let info = menuTree[3];
info.name.should.be.equal('');
info.methods.length.should.be.equal(1);
info.methods[0].summary.should.be.equal('test post');
});
it('should map x-traitTag to empty methods list', () => {
let info = menuTree[0];
info['x-traitTag'].should.be.true();
info.methods.should.be.empty();
});
it('methods for tag should contain valid pointer and summary', () => {
for (let entr of menuTree) {
let info = entr;
info.should.be.an.Object();
info.methods.should.be.an.Array();
for (let methodInfo of info.methods) {
methodInfo.should.have.properties(['pointer', 'summary']);
let methSchema = specMgr.byPointer(methodInfo.pointer);
expect(methSchema).not.toBeNull();
if (methSchema.summary) {
methSchema.summary.should.be.equal(methodInfo.summary);
}
}
}
});
});
});

View File

@ -1,6 +1,7 @@
'use strict';
import { JsonPointer } from '../utils/JsonPointer';
import { SpecManager } from '../utils/SpecManager';
import {methods as swaggerMethods} from '../utils/swagger-defs';
interface PropertyPreprocessOptions {
childFor: string;
@ -218,4 +219,57 @@ export class SchemaHelper {
}
return res;
}
static methodSummary(method) {
return method.summary || method.operationId || method.description.substring(0, 50);
}
static buildMenuTree(schema) {
let tag2MethodMapping = {};
let definedTags = schema.tags || [];
// add tags into map to preserve order
for (let tag of definedTags) {
tag2MethodMapping[tag.name] = {
'description': tag.description,
'name': tag.name,
'x-traitTag': tag['x-traitTag'],
'methods': []
};
}
let paths = schema.paths;
for (let path of Object.keys(paths)) {
let methods = Object.keys(paths[path]).filter((k) => swaggerMethods.has(k));
for (let method of methods) {
let methodInfo = paths[path][method];
let tags = methodInfo.tags;
if (!tags || !tags.length) {
tags = [''];
}
let methodPointer = JsonPointer.compile(['paths', path, method]);
let methodSummary = SchemaHelper.methodSummary(methodInfo);
for (let tag of tags) {
let tagDetails = tag2MethodMapping[tag];
if (!tag2MethodMapping[tag]) {
tagDetails = {
name: tag,
empty: tag === ''
};
tag2MethodMapping[tag] = tagDetails;
}
if (tagDetails['x-traitTag']) continue;
if (!tagDetails.methods) tagDetails.methods = [];
tagDetails.methods.push({
pointer: methodPointer,
summary: methodSummary,
operationId: methodInfo.operationId,
tag: tag
});
}
}
}
return Object.keys(tag2MethodMapping).map(tag => tag2MethodMapping[tag]);
}
}

View File

@ -1,10 +1,5 @@
'use strict';
import { SchemaNormalizer } from './schema-normalizer.service';
import {
describe,
it
} from '@angular/core/testing';
import { SpecManager } from '../utils/SpecManager';;
describe('Spec Helper', () => {
@ -116,9 +111,18 @@ describe('Spec Helper', () => {
let resolved;
beforeAll(() => {
let pointer = '/paths/test5/get/parameters/0';
spyOn(console, 'warn').and.stub();
resolved = normalizer.normalize(specMgr.byPointer(pointer), pointer);
});
afterAll(() => {
(<jasmine.Spy>console.warn).and.callThrough();
});
it('should print warning to console', () => {
expect(console.warn).toHaveBeenCalled();
});
it('should skip other fields', () => {
expect(resolved.$ref).toBeUndefined();
expect(resolved.title).toBeDefined();

View File

@ -1,18 +1,12 @@
'use strict';
import { getChildDebugElementByType } from '../../../../tests/helpers';
import { Component, provide } from '@angular/core';
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
import { Component } from '@angular/core';
import {
inject,
beforeEach,
beforeEachProviders,
it
TestComponentBuilder
} from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { StickySidebar } from '../index';
describe('Common components', () => {
@ -21,20 +15,12 @@ describe('Common components', () => {
let component;
let fixture;
beforeEachProviders(() => [
provide(BrowserDomAdapter, {useValue: new BrowserDomAdapter()})
]);
beforeEach(inject([TestComponentBuilder], (tcb) => {
builder = tcb;
fixture = builder.createSync(TestApp);
let debugEl = getChildDebugElementByType(fixture.debugElement, StickySidebar);
component = debugEl.injector.get(StickySidebar);
}));
beforeEach((done) => {
builder.createAsync(TestApp).then(_fixture => {
fixture = _fixture;
let debugEl = getChildDebugElementByType(fixture.debugElement, StickySidebar);
component = debugEl.injector.get(StickySidebar);
done();
}, err => done.fail(err));
});
it('should init component', () => {

View File

@ -1,7 +1,7 @@
'use strict';
import { Directive, ElementRef, Input, OnInit, OnDestroy } from '@angular/core';
import {BrowserDomAdapter} from '@angular/platform-browser/src/browser/browser_adapter';
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
@Directive({
selector: '[sticky-sidebar]'

View File

@ -5,12 +5,9 @@ import { Component } from '@angular/core';
import {
inject,
beforeEach,
it
TestComponentBuilder
} from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
import {Tabs, Tab} from '../index';
describe('Common components', () => {
@ -24,18 +21,12 @@ describe('Common components', () => {
beforeEach(inject([TestComponentBuilder], (tcb) => {
builder = tcb;
fixture = builder.createSync(TestApp);
hostComponent = fixture.debugElement.componentInstance;
debugEl = getChildDebugElement(fixture.debugElement, 'tabs');
childDebugEls = getChildDebugElementAll(debugEl, 'tab');
component = debugEl.componentInstance;
}));
beforeEach((done) => {
builder.createAsync(TestApp).then(_fixture => {
fixture = _fixture;
hostComponent = fixture.debugElement.componentInstance;
debugEl = getChildDebugElement(fixture.debugElement, 'tabs');
childDebugEls = getChildDebugElementAll(debugEl, 'tab');
component = debugEl.componentInstance;
done();
}, err => done.fail(err));
});
it('should init component', () => {
expect(component).not.toBeNull();

View File

@ -5,12 +5,10 @@ import { getChildDebugElement, mouseclick } from '../../../../tests/helpers';
import { Component } from '@angular/core';
import {
inject,
beforeEach,
it,
expect
expect,
TestComponentBuilder
} from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { Zippy } from '../index';
describe('Common components', () => {
@ -22,17 +20,11 @@ describe('Common components', () => {
beforeEach(inject([TestComponentBuilder], (tcb) => {
builder = tcb;
fixture = builder.createSync(TestApp);
let debugEl = getChildDebugElement(fixture.debugElement, 'zippy');
component = debugEl.componentInstance;
nativeElement = debugEl.nativeElement;
}));
beforeEach((done) => {
builder.createAsync(TestApp).then(_fixture => {
fixture = _fixture;
let debugEl = getChildDebugElement(fixture.debugElement, 'zippy');
component = debugEl.componentInstance;
nativeElement = debugEl.nativeElement;
done();
}, err => done.fail(err));
});
it('should init component', () => {
expect(component).not.toBeNull();

View File

@ -2,7 +2,6 @@
import JsonSchemaRefParser from 'json-schema-ref-parser';
import JsonPointer from './JsonPointer';
import {methods as swaggerMethods} from './swagger-defs';
export class SpecManager {
public _schema:any = {};
@ -114,52 +113,6 @@ export class SpecManager {
return tagsMap;
}
/* returns ES6 Map */
buildMenuTree():Map<string, any> {
let tag2MethodMapping = new Map();
let definedTags = this._schema.tags || [];
// add tags into map to preserve order
for (let tag of definedTags) {
tag2MethodMapping.set(tag.name, {
'description': tag.description,
'x-traitTag': tag['x-traitTag'],
'methods': []
});
}
let paths = this._schema.paths;
for (let path of Object.keys(paths)) {
let methods = Object.keys(paths[path]).filter((k) => swaggerMethods.has(k));
for (let method of methods) {
let methodInfo = paths[path][method];
let tags = methodInfo.tags;
//TODO: mb need to do something cleverer
if (!tags || !tags.length) {
tags = ['[Other]'];
}
let methodPointer = JsonPointer.compile(['paths', path, method]);
let methodSummary = methodInfo.summary || methodInfo.operationId;
for (let tag of tags) {
let tagDetails = tag2MethodMapping.get(tag);
if (!tagDetails) {
tagDetails = {};
tag2MethodMapping.set(tag, tagDetails);
}
if (tagDetails['x-traitTag']) continue;
if (!tagDetails.methods) tagDetails.methods = [];
tagDetails.methods.push({
pointer: methodPointer,
summary: methodSummary,
operationId: methodInfo.operationId
});
}
}
}
return tag2MethodMapping;
}
findDerivedDefinitions(defPointer) {
let definition = this.byPointer(defPointer);
if (!definition) throw new Error(`Can't load schema at ${defPointer}`);

View File

@ -1,7 +1,7 @@
{
"name": "redoc",
"description": "Swagger-generated API Reference Documentation",
"version": "0.15.1",
"version": "0.15.2",
"repository": {
"type": "git",
"url": "git://github.com/Rebilly/ReDoc"
@ -32,17 +32,11 @@
"jspm": {
"configFile": "system.config.js",
"dependencies": {
"@angular/common": "npm:@angular/common@^2.0.0-rc.2",
"@angular/common@2.0.0-rc.3": "npm:@angular/common@2.0.0-rc.3",
"@angular/compiler": "npm:@angular/compiler@^2.0.0-rc.2",
"@angular/compiler@2.0.0-rc.3": "npm:@angular/compiler@2.0.0-rc.3",
"@angular/core": "npm:@angular/core@^2.0.0-rc.2",
"@angular/core@2.0.0-rc.3": "npm:@angular/core@2.0.0-rc.3",
"@angular/platform-browser": "npm:@angular/platform-browser@^2.0.0-rc.2",
"@angular/platform-browser-dynamic": "npm:@angular/platform-browser-dynamic@^2.0.0-rc.2",
"@angular/platform-browser-dynamic@2.0.0-rc.3": "npm:@angular/platform-browser-dynamic@2.0.0-rc.3",
"@angular/platform-browser@2.0.0-rc.3": "npm:@angular/platform-browser@2.0.0-rc.3",
"@angular/platform-server@2.0.0-rc.3": "npm:@angular/platform-server@2.0.0-rc.3",
"@angular/common@2.0.0-rc.4": "npm:@angular/common@2.0.0-rc.4",
"@angular/compiler@2.0.0-rc.4": "npm:@angular/compiler@2.0.0-rc.4",
"@angular/core@2.0.0-rc.4": "npm:@angular/core@2.0.0-rc.4",
"@angular/platform-browser-dynamic@2.0.0-rc.4": "npm:@angular/platform-browser-dynamic@2.0.0-rc.4",
"@angular/platform-browser@2.0.0-rc.4": "npm:@angular/platform-browser@2.0.0-rc.4",
"dropkickjs": "npm:dropkickjs@^2.1.8",
"es6-shim": "github:es-shims/es6-shim@^0.33.6",
"hint.css": "npm:hint.css@^2.2.1",
@ -82,12 +76,12 @@
}
},
"devDependencies": {
"@angular/common": "^2.0.0-rc.3",
"@angular/compiler": "^2.0.0-rc.3",
"@angular/core": "^2.0.0-rc.2",
"@angular/platform-browser": "^2.0.0-rc.3",
"@angular/platform-browser-dynamic": "^2.0.0-rc.3",
"@angular/platform-server": "^2.0.0-rc.3",
"@angular/common": "^2.0.0-rc.4",
"@angular/compiler": "^2.0.0-rc.4",
"@angular/core": "^2.0.0-rc.4",
"@angular/platform-browser": "^2.0.0-rc.4",
"@angular/platform-browser-dynamic": "^2.0.0-rc.4",
"@angular/platform-server": "^2.0.0-rc.4",
"babel-polyfill": "^6.3.14",
"branch-release": "^1.0.3",
"browser-sync": "^2.10.1",
@ -139,7 +133,7 @@
"should": "^9.0.2",
"sinon": "^1.17.2",
"systemjs-builder": "^0.15.16",
"tslint": "^3.11.0",
"tslint": "^3.13.0",
"tslint-stylish": "^2.1.0-beta",
"typescript": "^1.8.10",
"vinyl-paths": "^2.0.0",

View File

@ -16,17 +16,11 @@ System.config({
},
map: {
"@angular/common": "npm:@angular/common@2.0.0-rc.3",
"@angular/common@2.0.0-rc.3": "npm:@angular/common@2.0.0-rc.3",
"@angular/compiler": "npm:@angular/compiler@2.0.0-rc.3",
"@angular/compiler@2.0.0-rc.3": "npm:@angular/compiler@2.0.0-rc.3",
"@angular/core": "npm:@angular/core@2.0.0-rc.3",
"@angular/core@2.0.0-rc.3": "npm:@angular/core@2.0.0-rc.3",
"@angular/platform-browser": "npm:@angular/platform-browser@2.0.0-rc.3",
"@angular/platform-browser-dynamic": "npm:@angular/platform-browser-dynamic@2.0.0-rc.3",
"@angular/platform-browser-dynamic@2.0.0-rc.3": "npm:@angular/platform-browser-dynamic@2.0.0-rc.3",
"@angular/platform-browser@2.0.0-rc.3": "npm:@angular/platform-browser@2.0.0-rc.3",
"@angular/platform-server@2.0.0-rc.3": "npm:@angular/platform-server@2.0.0-rc.3",
"@angular/common": "npm:@angular/common@2.0.0-rc.4",
"@angular/compiler": "npm:@angular/compiler@2.0.0-rc.4",
"@angular/core": "npm:@angular/core@2.0.0-rc.4",
"@angular/platform-browser-dynamic": "npm:@angular/platform-browser-dynamic@2.0.0-rc.4",
"@angular/platform-browser": "npm:@angular/platform-browser@2.0.0-rc.4",
"babel": "npm:babel-core@5.8.34",
"babel-runtime": "npm:babel-runtime@5.8.34",
"clean-css": "npm:clean-css@3.4.17",
@ -122,39 +116,32 @@ System.config({
"github:jspm/nodelibs-zlib@0.1.0": {
"browserify-zlib": "npm:browserify-zlib@0.1.4"
},
"npm:@angular/common@2.0.0-rc.3": {
"@angular/core": "npm:@angular/core@2.0.0-rc.3",
"npm:@angular/common@2.0.0-rc.4": {
"@angular/core": "npm:@angular/core@2.0.0-rc.4",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:@angular/compiler@2.0.0-rc.3": {
"@angular/core": "npm:@angular/core@2.0.0-rc.3",
"npm:@angular/compiler@2.0.0-rc.4": {
"@angular/core": "npm:@angular/core@2.0.0-rc.4",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:@angular/core@2.0.0-rc.3": {
"npm:@angular/core@2.0.0-rc.4": {
"process": "github:jspm/nodelibs-process@0.1.2",
"rxjs": "npm:rxjs@5.0.0-beta.6",
"zone.js": "npm:zone.js@0.6.12"
},
"npm:@angular/platform-browser-dynamic@2.0.0-rc.3": {
"@angular/common": "npm:@angular/common@2.0.0-rc.3",
"@angular/compiler": "npm:@angular/compiler@2.0.0-rc.3",
"@angular/core": "npm:@angular/core@2.0.0-rc.3",
"@angular/platform-browser": "npm:@angular/platform-browser@2.0.0-rc.3",
"npm:@angular/platform-browser-dynamic@2.0.0-rc.4": {
"@angular/common": "npm:@angular/common@2.0.0-rc.4",
"@angular/compiler": "npm:@angular/compiler@2.0.0-rc.4",
"@angular/core": "npm:@angular/core@2.0.0-rc.4",
"@angular/platform-browser": "npm:@angular/platform-browser@2.0.0-rc.4",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:@angular/platform-browser@2.0.0-rc.3": {
"@angular/common": "npm:@angular/common@2.0.0-rc.3",
"@angular/compiler": "npm:@angular/compiler@2.0.0-rc.3",
"@angular/core": "npm:@angular/core@2.0.0-rc.3",
"npm:@angular/platform-browser@2.0.0-rc.4": {
"@angular/common": "npm:@angular/common@2.0.0-rc.4",
"@angular/compiler": "npm:@angular/compiler@2.0.0-rc.4",
"@angular/core": "npm:@angular/core@2.0.0-rc.4",
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:@angular/platform-server@2.0.0-rc.3": {
"@angular/common": "npm:@angular/common@2.0.0-rc.3",
"@angular/compiler": "npm:@angular/compiler@2.0.0-rc.3",
"@angular/core": "npm:@angular/core@2.0.0-rc.3",
"@angular/platform-browser": "npm:@angular/platform-browser@2.0.0-rc.3",
"parse5": "npm:parse5@1.3.2"
},
"npm:amdefine@1.0.0": {
"fs": "github:jspm/nodelibs-fs@0.1.2",
"module": "github:jspm/nodelibs-module@0.1.0",
@ -686,9 +673,6 @@ System.config({
"pbkdf2": "npm:pbkdf2@3.0.4",
"systemjs-json": "github:systemjs/plugin-json@0.1.2"
},
"npm:parse5@1.3.2": {
"process": "github:jspm/nodelibs-process@0.1.2"
},
"npm:path-browserify@0.0.0": {
"process": "github:jspm/nodelibs-process@0.1.2"
},

View File

@ -110,8 +110,6 @@
"parameters": [
{
"$ref": "#/definitions/CircularTransitive",
"title": "test",
"description": "test"
}
]
}

View File

@ -2,7 +2,8 @@
import {setBaseTestProviders} from '@angular/core/testing';
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
import { OptionsService, RedocEventsService} from '../lib/services/index';
import { OptionsService, RedocEventsService, Hash, ScrollService, MenuService } from '../lib/services/index';
import { SpecManager } from '../lib/utils/SpecManager';
import { provide } from '@angular/core';
import {
@ -15,6 +16,10 @@ setBaseTestProviders(
TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
provide(BrowserDomAdapter, {useClass: BrowserDomAdapter}),
provide(OptionsService, {useClass: OptionsService}),
provide(RedocEventsService, {useClass: RedocEventsService})
provide(RedocEventsService, {useClass: RedocEventsService}),
provide(SpecManager, {useClass: SpecManager}),
provide(Hash, {useClass: Hash}),
provide(ScrollService, {useClass: ScrollService}),
provide(MenuService, {useClass: MenuService})
],
[TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS]);

View File

@ -93,85 +93,6 @@ describe('Utils', () => {
});
});
describe('buildMenuTree method', () => {
let suitSchema = {
tags: [
{name: 'tag1', description: 'info1', 'x-traitTag': true},
{name: 'tag2', description: 'info2'}
],
paths: {
test: {
put: {
tags: ['tag1', 'tag3'],
summary: 'test put'
},
get: {
tags: ['tag1', 'tag2'],
summary: 'test get'
},
// no tags
post: {
summary: 'test post'
}
}
}
};
let menuTree;
let entries;
beforeAll(() => {
specMgr._schema = suitSchema;
menuTree = specMgr.buildMenuTree();
entries = Array.from(menuTree.entries());
});
it('should return instance of Map', () => {
menuTree.should.be.instanceof(Map);
});
it('should return Map with correct number of entries', () => {
//2 - defined tags, 1 - tag3 and 1 [other] tag for no-tags method
entries.length.should.be.equal(2 + 1 + 1);
});
it('should append not defined tags to the end of list', () => {
let [tag, info] = entries[2];
tag.should.be.equal('tag3');
info.methods.length.should.be.equal(1);
info.methods[0].summary.should.be.equal('test put');
});
it('should append methods without tags to [other] tag', () => {
let [tag, info] = entries[3];
tag.should.be.equal('[Other]');
info.methods.length.should.be.equal(1);
info.methods[0].summary.should.be.equal('test post');
});
it('should map x-traitTag to empty methods list', () => {
let [, info] = entries[0];
info['x-traitTag'].should.be.true();
info.methods.should.be.empty();
});
it('methods for tag should contain valid pointer and summary', () => {
for (let entr of entries) {
let [, info] = entr;
info.should.be.an.Object();
info.methods.should.be.an.Array();
for (let methodInfo of info.methods) {
methodInfo.should.have.properties(['pointer', 'summary']);
let methSchema = specMgr.byPointer(methodInfo.pointer);
expect(methSchema).not.toBeNull();
if (methSchema.summary) {
methSchema.summary.should.be.equal(methodInfo.summary);
}
}
}
});
});
describe('getMethodParams method', () => {
beforeAll((done) => {
specMgr.load('/tests/schemas/schema-mgr-methodparams.json').then(() => {