Add tslint

This commit is contained in:
Roman Hotsiy 2016-06-13 20:54:24 +03:00
parent 4498884f62
commit 4f39ab9edc
34 changed files with 272 additions and 205 deletions

View File

@ -9,7 +9,7 @@ var paths = {
output: 'dist/', output: 'dist/',
tmp: '.tmp/', tmp: '.tmp/',
demo: 'demo/**/*', demo: 'demo/**/*',
tests: '{lib,tests}/**/*.spec.js', tests: '{lib,tests}/**/*.spec.ts',
releases: 'demo/releases/' releases: 'demo/releases/'
} }

View File

@ -1,10 +1,15 @@
var gulp = require('gulp'); var gulp = require('gulp');
var eslint = require('gulp-eslint'); var tslint = require('gulp-tslint');
var paths = require('../paths'); var paths = require('../paths');
gulp.task('lint', function () { gulp.task('lint', function () {
return gulp.src([paths.source, paths.tests]) return gulp.src([paths.source, paths.tests])
.pipe(eslint()) .pipe(tslint({
.pipe(eslint.format()) rulesDirectory: 'node_modules/codelyzer'
.pipe(eslint.failAfterError()); }))
.pipe(tslint.report(require('tslint-stylish'), {
emitError: true,
sort: true,
bell: true
}));
}); });

View File

@ -34,7 +34,7 @@ describe('Redoc components', () => {
}))); })));
beforeEach((done) => { beforeEach((done) => {
builder.createAsync(TestApp).then(_fixture => { builder.createAsync(TestAppComponent).then(_fixture => {
fixture = _fixture; fixture = _fixture;
component = getChildDebugElement(fixture.debugElement, 'api-info').componentInstance; component = getChildDebugElement(fixture.debugElement, 'api-info').componentInstance;
fixture.detectChanges(); fixture.detectChanges();
@ -67,5 +67,5 @@ describe('Redoc components', () => {
template: template:
`<api-info></api-info>` `<api-info></api-info>`
}) })
class TestApp { class TestAppComponent {
} }

View File

@ -14,7 +14,7 @@ export class ApiInfo extends BaseComponent {
constructor(schemaMgr:SchemaManager, private optionsService:OptionsService) { constructor(schemaMgr:SchemaManager, private optionsService:OptionsService) {
super(schemaMgr); super(schemaMgr);
} }
prepareModel() { prepareModel() {
this.data = this.componentSchema.info; this.data = this.componentSchema.info;
this.specUrl = this.optionsService.options.specUrl; this.specUrl = this.optionsService.options.specUrl;

View File

@ -34,7 +34,7 @@ describe('Redoc components', () => {
return schemaMgr.load(schemaUrl); return schemaMgr.load(schemaUrl);
}))); })));
beforeEach((done) => { beforeEach((done) => {
builder.createAsync(TestApp).then(_fixture => { builder.createAsync(TestAppComponent).then(_fixture => {
fixture = _fixture; fixture = _fixture;
component = getChildDebugElement(fixture.debugElement, 'api-logo').componentInstance; component = getChildDebugElement(fixture.debugElement, 'api-logo').componentInstance;
fixture.detectChanges(); fixture.detectChanges();
@ -49,7 +49,7 @@ describe('Redoc components', () => {
}); });
it('should not display image when no x-logo', () => { it('should not display image when no x-logo', () => {
component.data.should.be.empty; component.data.should.be.empty();
let nativeElement = getChildDebugElement(fixture.debugElement, 'api-logo').nativeElement; let nativeElement = getChildDebugElement(fixture.debugElement, 'api-logo').nativeElement;
let imgElement = nativeElement.querySelector('img'); let imgElement = nativeElement.querySelector('img');
expect(imgElement).toBeNull(); expect(imgElement).toBeNull();
@ -74,5 +74,5 @@ describe('Redoc components', () => {
template: template:
`<api-logo></api-logo>` `<api-logo></api-logo>`
}) })
class TestApp { class TestAppComponent {
} }

View File

@ -9,7 +9,7 @@ import {RedocComponent, BaseComponent, SchemaManager} from '../base';
}) })
export class ApiLogo extends BaseComponent { export class ApiLogo extends BaseComponent {
data:any = {}; data:any = {};
constructor(schemaMgr:SchemaManager) { constructor(schemaMgr:SchemaManager) {
super(schemaMgr); super(schemaMgr);
} }

View File

@ -28,7 +28,7 @@ describe('Redoc components', () => {
instance: { instance: {
pointer: '' pointer: ''
}, },
hostView: {changeDetectorRef: {detectChanges : function() {} }} hostView: { changeDetectorRef: {detectChanges : () => undefined} }
}; };
beforeEachProviders(() => [ beforeEachProviders(() => [
provide(SchemaManager, {useValue: schemaMgr}) provide(SchemaManager, {useValue: schemaMgr})
@ -39,7 +39,7 @@ describe('Redoc components', () => {
spyOn(loader, 'loadNextToLocation').and.returnValue({then: (fn) => fn(appRefMock)}); spyOn(loader, 'loadNextToLocation').and.returnValue({then: (fn) => fn(appRefMock)});
})); }));
beforeEach((done) => { beforeEach((done) => {
builder.createAsync(TestApp).then(_fixture => { builder.createAsync(TestAppComponent).then(_fixture => {
fixture = _fixture; fixture = _fixture;
let debugEl = getChildDebugElement(fixture.debugElement, 'json-schema-lazy'); let debugEl = getChildDebugElement(fixture.debugElement, 'json-schema-lazy');
component = <JsonSchemaLazy>debugEl.componentInstance; component = <JsonSchemaLazy>debugEl.componentInstance;
@ -87,5 +87,5 @@ describe('Redoc components', () => {
template: template:
`<json-schema-lazy></json-schema-lazy>` `<json-schema-lazy></json-schema-lazy>`
}) })
class TestApp { class TestAppComponent {
} }

View File

@ -28,7 +28,7 @@ describe('Redoc components', () => {
builder = tcb; builder = tcb;
})); }));
beforeEach((done) => { beforeEach((done) => {
builder.createAsync(TestApp).then(_fixture => { builder.createAsync(TestAppComponent).then(_fixture => {
fixture = _fixture; fixture = _fixture;
let debugEl = getChildDebugElement(fixture.debugElement, 'json-schema'); let debugEl = getChildDebugElement(fixture.debugElement, 'json-schema');
component = debugEl.componentInstance; component = debugEl.componentInstance;
@ -70,5 +70,5 @@ describe('Redoc components', () => {
template: template:
`<json-schema></json-schema>` `<json-schema></json-schema>`
}) })
class TestApp { class TestAppComponent {
} }

View File

@ -22,7 +22,16 @@ export class JsonSchema extends BaseComponent {
@Input() nestOdd: boolean; @Input() nestOdd: boolean;
@Input() childFor: string; @Input() childFor: string;
@Input() isRequestSchema: boolean; @Input() isRequestSchema: boolean;
static injectPropertyData(propertySchema, propertyName, propPointer, hostPointer?) {
propertySchema = Object.assign({}, propertySchema);
propertySchema._name = propertyName;
runInjectors(propertySchema, propertySchema, propPointer, hostPointer);
return propertySchema;
}
constructor(schemaMgr:SchemaManager, elementRef:ElementRef) { constructor(schemaMgr:SchemaManager, elementRef:ElementRef) {
super(schemaMgr); super(schemaMgr);
this.$element = elementRef.nativeElement; this.$element = elementRef.nativeElement;
@ -137,24 +146,6 @@ export class JsonSchema extends BaseComponent {
return JsonSchema.injectPropertyData(addProps, '<Additional Properties> *', return JsonSchema.injectPropertyData(addProps, '<Additional Properties> *',
JsonPointer.join(addProps._pointer || schema._pointer || this.pointer, ['additionalProperties'])); JsonPointer.join(addProps._pointer || schema._pointer || this.pointer, ['additionalProperties']));
} }
static injectPropertyData(propertySchema, propertyName, propPointer, hostPointer?) {
propertySchema = Object.assign({}, propertySchema);
propertySchema._name = propertyName;
runInjectors(propertySchema, propertySchema, propPointer, hostPointer);
return propertySchema;
}
}
function runInjectors(injectTo, propertySchema, propertyPointer, hostPointer?) {
for (var injName in injectors) {
let injector = injectors[injName];
if (injector.check(propertySchema)) {
injector.inject(injectTo, propertySchema, propertyPointer, hostPointer);
}
}
} }
const injectors = { const injectors = {
@ -283,3 +274,12 @@ const injectors = {
} }
} }
}; };
function runInjectors(injectTo, propertySchema, propertyPointer, hostPointer?) {
for (var injName in injectors) {
let injector = injectors[injName];
if (injector.check(propertySchema)) {
injector.inject(injectTo, propertySchema, propertyPointer, hostPointer);
}
}
}

View File

@ -27,7 +27,7 @@ describe('Redoc components', () => {
return schemaMgr.load('/tests/schemas/extended-petstore.yml'); return schemaMgr.load('/tests/schemas/extended-petstore.yml');
}))); })));
beforeEach((done) => { beforeEach((done) => {
builder.createAsync(TestApp).then(fixture => { builder.createAsync(TestAppComponent).then(fixture => {
component = getChildDebugElement(fixture.debugElement, 'method').componentInstance; component = getChildDebugElement(fixture.debugElement, 'method').componentInstance;
fixture.detectChanges(); fixture.detectChanges();
done(); done();
@ -47,7 +47,7 @@ describe('Redoc components', () => {
it('should main tag', () => { it('should main tag', () => {
component.data.methodInfo.tags.should.be.empty; component.data.methodInfo.tags.should.be.empty();
}); });
}); });
}); });
@ -61,5 +61,5 @@ describe('Redoc components', () => {
template: template:
`<method pointer='#/paths/~1user~1{username}/put'></method>` `<method pointer='#/paths/~1user~1{username}/put'></method>`
}) })
class TestApp { class TestAppComponent {
} }

View File

@ -29,7 +29,7 @@ describe('Redoc components', () => {
return schemaMgr.load('/tests/schemas/methods-list-component.json'); return schemaMgr.load('/tests/schemas/methods-list-component.json');
}))); })));
beforeEach((done) => { beforeEach((done) => {
builder.createAsync(TestApp).then(_fixture => { builder.createAsync(TestAppComponent).then(_fixture => {
fixture = _fixture; fixture = _fixture;
component = getChildDebugElement(fixture.debugElement, 'methods-list').componentInstance; component = getChildDebugElement(fixture.debugElement, 'methods-list').componentInstance;
fixture.detectChanges(); fixture.detectChanges();
@ -46,7 +46,7 @@ describe('Redoc components', () => {
expect(component.data.tags).not.toBeNull(); expect(component.data.tags).not.toBeNull();
component.data.tags.should.have.lengthOf(2); component.data.tags.should.have.lengthOf(2);
component.data.tags[0].name.should.be.equal('traitTag'); component.data.tags[0].name.should.be.equal('traitTag');
component.data.tags[0].methods.should.be.empty; component.data.tags[0].methods.should.be.empty();
component.data.tags[1].name.should.be.equal('tag1'); component.data.tags[1].name.should.be.equal('tag1');
component.data.tags[1].methods.should.have.lengthOf(2); component.data.tags[1].methods.should.have.lengthOf(2);
}); });
@ -59,5 +59,5 @@ describe('Redoc components', () => {
template: template:
`<methods-list></methods-list>` `<methods-list></methods-list>`
}) })
class TestApp { class TestAppComponent {
} }

View File

@ -16,9 +16,9 @@ function safePush(obj, prop, item) {
directives: [JsonSchema, JsonSchemaLazy] directives: [JsonSchema, JsonSchemaLazy]
}) })
export class ParamsList extends BaseComponent { export class ParamsList extends BaseComponent {
data:any; data:any;
constructor(schemaMgr:SchemaManager) { constructor(schemaMgr:SchemaManager) {
super(schemaMgr); super(schemaMgr);
} }

View File

@ -42,7 +42,7 @@ describe('Redoc components', () => {
it('should init component', (done) => { it('should init component', (done) => {
builder.createAsync(TestApp).then(fixture => { builder.createAsync(TestAppComponent).then(fixture => {
let component = getChildDebugElement(fixture.debugElement, 'redoc').componentInstance; let component = getChildDebugElement(fixture.debugElement, 'redoc').componentInstance;
expect(component).not.toBeNull(); expect(component).not.toBeNull();
fixture.destroy(); fixture.destroy();
@ -51,12 +51,12 @@ describe('Redoc components', () => {
}); });
it('should init components tree without errors', (done) => { it('should init components tree without errors', (done) => {
builder.createAsync(TestApp).then(fixture => { builder.createAsync(TestAppComponent).then(fixture => {
(() => fixture.detectChanges()).should.not.throw(); (() => fixture.detectChanges()).should.not.throw();
fixture.destroy(); fixture.destroy();
done(); done();
}, err => { }, err => {
return done.fail(err) return done.fail(err);
}); });
}); });
}); });
@ -116,7 +116,7 @@ describe('Redoc components', () => {
}))); })));
beforeEach((done) => { beforeEach((done) => {
builder.createAsync(TestApp).then(_fixture => { builder.createAsync(TestAppComponent).then(_fixture => {
fixture = _fixture; fixture = _fixture;
element = getChildDebugElement(fixture.debugElement, 'methods-list').nativeElement; element = getChildDebugElement(fixture.debugElement, 'methods-list').nativeElement;
destroySpy = jasmine.createSpy('spy'); destroySpy = jasmine.createSpy('spy');
@ -190,5 +190,5 @@ describe('Redoc components', () => {
template: template:
`<redoc disable-lazy-schemas></redoc>` `<redoc disable-lazy-schemas></redoc>`
}) })
class TestApp { class TestAppComponent {
} }

View File

@ -34,26 +34,11 @@ var _modeLocked = false;
onPushOnly: false onPushOnly: false
}) })
export class Redoc extends BaseComponent { export class Redoc extends BaseComponent {
private element: any;
options: any;
static appRef: ComponentRef<any>; static appRef: ComponentRef<any>;
constructor(schemaMgr: SchemaManager, optionsMgr:OptionsService, elementRef:ElementRef, options: any;
public events:RedocEventsService) {
super(schemaMgr);
this.element = elementRef.nativeElement;
//parse options (top level component doesn't support inputs)
optionsMgr.parseOptions( this.element );
optionsMgr.options.$scrollParent = detectScollParent( this.element );
this.options = optionsMgr.options;
this.events = events;
}
ngAfterViewInit() { private element: any;
setTimeout( () => {
this.events.bootstrapped.next({});
});
}
static showLoadingAnimation() { static showLoadingAnimation() {
let elem = dom.query('redoc'); let elem = dom.query('redoc');
@ -143,7 +128,24 @@ export class Redoc extends BaseComponent {
// Redoc destroy removes host element, so need to restore it // Redoc destroy removes host element, so need to restore it
elClone.innerHTML = 'Loading...'; elClone.innerHTML = 'Loading...';
parent && parent.insertBefore(elClone, nextSibling); if (parent) parent.insertBefore(elClone, nextSibling);
} }
} }
constructor(schemaMgr: SchemaManager, optionsMgr:OptionsService, elementRef:ElementRef,
public events:RedocEventsService) {
super(schemaMgr);
this.element = elementRef.nativeElement;
//parse options (top level component doesn't support inputs)
optionsMgr.parseOptions( this.element );
optionsMgr.options.$scrollParent = detectScollParent( this.element );
this.options = optionsMgr.options;
this.events = events;
}
ngAfterViewInit() {
setTimeout( () => {
this.events.bootstrapped.next({});
});
}
} }

View File

@ -1,5 +1,5 @@
<div class="snippet"> <div class="snippet">
<!-- in case sample is not available for some reason --> <!-- in case sample is not available for some reason -->
<pre *ngIf="data.sample == null"> Sample unavailable </pre> <pre *ngIf="data.sample == undefined"> Sample unavailable </pre>
<pre innerHtml="{{data.sample | jsonFormatter}}"></pre> <pre innerHtml="{{data.sample | jsonFormatter}}"></pre>
</div> </div>

View File

@ -40,7 +40,7 @@ describe('Redoc components', () => {
}))); })));
beforeEach((done) => { beforeEach((done) => {
builder.createAsync(TestApp).then(_fixture => { builder.createAsync(TestAppComponent).then(_fixture => {
fixture = _fixture; fixture = _fixture;
component = getChildDebugElement(fixture.debugElement, 'side-menu').componentInstance; component = getChildDebugElement(fixture.debugElement, 'side-menu').componentInstance;
fixture.detectChanges(); fixture.detectChanges();
@ -69,5 +69,5 @@ describe('Redoc components', () => {
`<side-menu></side-menu> `<side-menu></side-menu>
<methods-list></methods-list>` <methods-list></methods-list>`
}) })
class TestApp { class TestAppComponent {
} }

View File

@ -24,8 +24,8 @@ export class SideMenu extends BaseComponent {
activeItemCaption: string; activeItemCaption: string;
options: any; options: any;
data: any; data: any;
constructor(schemaMgr:SchemaManager, elementRef:ElementRef, private dom:BrowserDomAdapter, constructor(schemaMgr:SchemaManager, elementRef:ElementRef, private dom:BrowserDomAdapter,
private scrollService:ScrollService, private menuService:MenuService, private hash:Hash, private scrollService:ScrollService, private menuService:MenuService, private hash:Hash,
optionsService:OptionsService, private detectorRef:ChangeDetectorRef) { optionsService:OptionsService, private detectorRef:ChangeDetectorRef) {
super(schemaMgr); super(schemaMgr);
this.$element = elementRef.nativeElement; this.$element = elementRef.nativeElement;

View File

@ -284,6 +284,7 @@ describe('Redoc components', () => {
}); });
xdescribe('Merge array allOf', () => { xdescribe('Merge array allOf', () => {
//emtpy
}); });
}); });
}); });

View File

@ -13,7 +13,7 @@ let commonInputs = ['pointer']; // json pointer to the schema chunk
// internal helper function // internal helper function
function safeConcat(a, b) { function safeConcat(a, b) {
let res = a && a.slice() || []; let res = a && a.slice() || [];
b = (b == null) ? [] : b; b = (b == undefined) ? [] : b;
return res.concat(b); return res.concat(b);
} }
@ -33,7 +33,7 @@ function defaults(target, src) {
} }
function snapshot(obj) { function snapshot(obj) {
if(obj == null || typeof(obj) != 'object') { if(obj == undefined || typeof(obj) !== 'object') {
return obj; return obj;
} }
@ -97,6 +97,70 @@ export function RedocComponent(options) {
export class BaseComponent { export class BaseComponent {
componentSchema: any = null; componentSchema: any = null;
pointer: String; pointer: String;
static joinAllOf(schema: any, opts?: any) {
function merge(into, schemas) {
for (let subSchema of schemas) {
if (opts && opts.omitParent && subSchema.discriminator) continue;
// TODO: add support for merge array schemas
if (typeof subSchema !== 'object') {
let errMessage = `Items of allOf should be Object: ${typeof subSchema} found
${subSchema}`;
throw new Error(errMessage);
}
if (into.type && subSchema.type && into.type !== subSchema.type) {
let errMessage = `allOf merging error: schemas with different types can't be merged`;
throw new Error(errMessage);
}
if (into.type === 'array') {
console.warn('allOf: subschemas with type array are not supported yet');
}
// TODO: add check if can be merged correctly (no different properties with the same name)
into.type = into.type || subSchema.type;
if (into.type === 'object' && subSchema.properties) {
if (!into.properties) into.properties = {};
Object.assign(into.properties, subSchema.properties);
Object.keys(subSchema.properties).forEach(propName => {
if (!subSchema.properties[propName]._pointer) {
subSchema.properties[propName]._pointer = subSchema._pointer ?
JsonPointer.join(subSchema._pointer, ['properties', propName]) : null;
}
});
}
if (into.type === 'object' && subSchema.required) {
if (!into.required) into.required = [];
into.required.push(...subSchema.required);
}
// don't merge _pointer
subSchema._pointer = null;
defaults(into, subSchema);
}
into.allOf = null;
}
function traverse(obj) {
if (obj === undefined || typeof(obj) !== 'object') {
return;
}
for(var key in obj) {
if (obj.hasOwnProperty(key)) {
traverse(obj[key]);
}
}
if (obj.allOf) {
merge(obj, obj.allOf);
}
}
traverse(schema);
}
constructor(public schemaMgr: SchemaManager) { constructor(public schemaMgr: SchemaManager) {
} }
@ -168,84 +232,27 @@ export class BaseComponent {
this.componentSchema = snapshot(resolve(schema)); this.componentSchema = snapshot(resolve(schema));
} }
static joinAllOf(schema: any, opts?: any) {
function merge(into, schemas) {
for (let subSchema of schemas) {
if (opts && opts.omitParent && subSchema.discriminator) continue;
// TODO: add support for merge array schemas
if (typeof subSchema !== 'object') {
let errMessage = `Items of allOf should be Object: ${typeof subSchema} found
${subSchema}`;
throw new Error(errMessage);
}
if (into.type && subSchema.type && into.type !== subSchema.type) {
let errMessage = `allOf merging error: schemas with different types can't be merged`;
throw new Error(errMessage);
}
if (into.type === 'array') {
console.warn('allOf: subschemas with type array are not supported yet');
}
// TODO: add check if can be merged correctly (no different properties with the same name)
into.type = into.type || subSchema.type;
if (into.type === 'object' && subSchema.properties) {
into.properties || (into.properties = {});
Object.assign(into.properties, subSchema.properties);
Object.keys(subSchema.properties).forEach(propName => {
if (!subSchema.properties[propName]._pointer) {
subSchema.properties[propName]._pointer = subSchema._pointer ?
JsonPointer.join(subSchema._pointer, ['properties', propName]) : null;
}
});
}
if (into.type === 'object' && subSchema.required) {
into.required || (into.required = []);
into.required.push(...subSchema.required);
}
// don't merge _pointer
subSchema._pointer = null;
defaults(into, subSchema);
}
into.allOf = null;
}
function traverse(obj) {
if (obj === null || typeof(obj) !== 'object') {
return;
}
for(var key in obj) {
if (obj.hasOwnProperty(key)) {
traverse(obj[key]);
}
}
if (obj.allOf) {
merge(obj, obj.allOf);
}
}
traverse(schema);
}
/** /**
* Used to prepare model based on component schema * Used to prepare model based on component schema
* @abstract * @abstract
*/ */
prepareModel() {} prepareModel():any {
// emtpy
}
/** /**
* Used to initialize component. Run after prepareModel * Used to initialize component. Run after prepareModel
* @abstract * @abstract
*/ */
init() {} init() {
// empty
}
/** /**
+ Used to destroy component + Used to destroy component
* @abstract * @abstract
*/ */
destroy() {} destroy() {
// emtpy
}
} }

View File

@ -50,7 +50,7 @@ describe('Menu service', () => {
}); });
beforeEach((done) => { beforeEach((done) => {
builder.createAsync(TestApp).then((fixture) => { builder.createAsync(TestAppComponent).then((fixture) => {
fixture.detectChanges(); fixture.detectChanges();
done(); done();
}).catch((err) => done.fail(err)); }).catch((err) => done.fail(err));
@ -122,5 +122,5 @@ describe('Menu service', () => {
<methods-list></methods-list> <methods-list></methods-list>
</div>` </div>`
}) })
class TestApp { class TestAppComponent {
} }

View File

@ -14,7 +14,7 @@ const CHANGE = {
export class MenuService { export class MenuService {
changed: EventEmitter<any> = new EventEmitter(); changed: EventEmitter<any> = new EventEmitter();
categories: any; categories: any;
activeCatIdx: number = 0; activeCatIdx: number = 0;
activeMethodIdx: number = -1; activeMethodIdx: number = -1;
activeMethodPtr: string; activeMethodPtr: string;

View File

@ -2,7 +2,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { isFunction, isString } from '@angular/core/src/facade/lang'; import { isFunction, isString } from '@angular/core/src/facade/lang';
import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter'; import { BrowserDomAdapter } from '@angular/platform-browser/src/browser/browser_adapter';
import { global } from '@angular/core/src/facade/lang';
const defaults = { const defaults = {
scrollYOffset: 0, scrollYOffset: 0,
@ -15,7 +14,7 @@ const OPTION_NAMES = new Set(['scrollYOffset', 'disableLazySchemas', 'specUrl'])
@Injectable() @Injectable()
export class OptionsService { export class OptionsService {
private _options: any; private _options: any;
constructor(private dom:BrowserDomAdapter) { constructor(private dom:BrowserDomAdapter) {
this._options = defaults; this._options = defaults;
this.dom = dom; this.dom = dom;

View File

@ -26,7 +26,7 @@ export class ScrollService {
} }
scrollY() { scrollY() {
return (this.$scrollParent.pageYOffset != null) ? this.$scrollParent.pageYOffset : this.$scrollParent.scrollTop; return (this.$scrollParent.pageYOffset != undefined) ? this.$scrollParent.pageYOffset : this.$scrollParent.scrollTop;
} }
/* returns 1 if element if above the view, 0 if in view and -1 below the view */ /* returns 1 if element if above the view, 0 if in view and -1 below the view */

View File

@ -13,7 +13,7 @@ export class StickySidebar {
$redocEl: any; $redocEl: any;
@Input() scrollParent:any; @Input() scrollParent:any;
@Input() scrollYOffset:any; @Input() scrollYOffset:any;
constructor(elementRef:ElementRef, private dom:BrowserDomAdapter) { constructor(elementRef:ElementRef, private dom:BrowserDomAdapter) {
this.$element = elementRef.nativeElement; this.$element = elementRef.nativeElement;
@ -30,7 +30,7 @@ export class StickySidebar {
} }
unbind() { unbind() {
this.cancelScrollBinding && this.cancelScrollBinding(); if (this.cancelScrollBinding) this.cancelScrollBinding();
} }
updatePosition() { updatePosition() {
@ -52,7 +52,7 @@ export class StickySidebar {
} }
get scrollY() { get scrollY() {
return (this.scrollParent.pageYOffset != null) ? this.scrollParent.pageYOffset : this.scrollParent.scrollTop; return (this.scrollParent.pageYOffset != undefined) ? this.scrollParent.pageYOffset : this.scrollParent.scrollTop;
} }
ngOnInit() { ngOnInit() {

View File

@ -29,7 +29,7 @@ export class Tabs {
tab.active = false; tab.active = false;
}); });
tab.active = true; tab.active = true;
notify && this.change.next(tab.tabTitle); if (notify) this.change.next(tab.tabTitle);
} }
selectyByTitle(tabTitle, notify = false) { selectyByTitle(tabTitle, notify = false) {
@ -47,7 +47,7 @@ export class Tabs {
} else { } else {
prevActive.active = true; prevActive.active = true;
} }
notify && this.change.next(tabTitle); if (notify) this.change.next(tabTitle);
this.changeDetector.markForCheck(); this.changeDetector.markForCheck();
} }

View File

@ -39,15 +39,15 @@ describe('Common components', () => {
}); });
it('should init component defaults', () => { it('should init component defaults', () => {
component.empty.should.be.false; component.empty.should.be.false();
component.visible.should.be.false; component.visible.should.be.false();
component.type.should.be.equal('general'); component.type.should.be.equal('general');
}); });
it('should init properties from dom params', () => { it('should init properties from dom params', () => {
fixture.detectChanges(); fixture.detectChanges();
component.visible.should.be.true; component.visible.should.be.true();
component.empty.should.be.true; component.empty.should.be.true();
component.title.should.be.equal('Zippy'); component.title.should.be.equal('Zippy');
component.type.should.be.equal('test'); component.type.should.be.equal('test');
}); });
@ -58,7 +58,7 @@ describe('Common components', () => {
expect(contentEl.innerText).toMatch('test'); expect(contentEl.innerText).toMatch('test');
}); });
it('should open and close zippy', () => { it('should open and close zippy', (done) => {
fixture.detectChanges(); fixture.detectChanges();
component.empty = false; component.empty = false;
component.visible = true; component.visible = true;
@ -69,13 +69,17 @@ describe('Common components', () => {
let titleEl = nativeElement.querySelector('.zippy-title'); let titleEl = nativeElement.querySelector('.zippy-title');
mouseclick(titleEl); mouseclick(titleEl);
fixture.detectChanges(); fixture.detectChanges();
component.visible.should.be.false; component.visible.should.be.false();
testComponent.opened.should.be.false; testComponent.opened.should.be.false();
mouseclick(titleEl); mouseclick(titleEl);
fixture.detectChanges(); fixture.detectChanges();
component.visible.should.be.true; setTimeout(() => {
testComponent.opened.should.be.true; component.visible.should.be.true();
testComponent.opened.should.be.true();
testComponent.clickCount.should.be.equal(2);
done();
});
}); });
it('should disable empty zippy', () => { it('should disable empty zippy', () => {
@ -99,7 +103,7 @@ describe('Common components', () => {
selector: 'test-app', selector: 'test-app',
directives: [Zippy], directives: [Zippy],
template: template:
`<zippy title="Zippy" type="test" visible="true" empty="true" (open)="open()" (close)="close()">test</zippy>` `<zippy title="Zippy" type="test" [visible]="true" [empty]="true" (open)="open()" (close)="close()">test</zippy>`
}) })
class TestApp { class TestApp {
opened: boolean; opened: boolean;

View File

@ -1,12 +1,12 @@
'use strict'; 'use strict';
import {Pipe} from '@angular/core'; import { Pipe, PipeTransform } from '@angular/core';
import {isBlank} from '@angular/core/src/facade/lang'; import { isBlank } from '@angular/core/src/facade/lang';
var level = 1; var level = 1;
const COLLAPSE_LEVEL = 2; const COLLAPSE_LEVEL = 2;
@Pipe({ name: 'jsonFormatter' }) @Pipe({ name: 'jsonFormatter' })
export class JsonFormatter { export class JsonFormatter implements PipeTransform {
transform(value) { transform(value) {
if (isBlank(value)) return value; if (isBlank(value)) return value;
return jsonToHTML(value); return jsonToHTML(value);
@ -14,7 +14,8 @@ export class JsonFormatter {
} }
function htmlEncode(t) { function htmlEncode(t) {
return t != null ? t.toString().replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;') : ''; return t != undefined ?
t.toString().replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;') : '';
} }
function decorateWithSpan(value, className) { function decorateWithSpan(value, className) {
@ -23,25 +24,22 @@ function decorateWithSpan(value, className) {
function valueToHTML(value) { function valueToHTML(value) {
var valueType = typeof value, output = ''; var valueType = typeof value, output = '';
if (value == null) { if (value == undefined) {
output += decorateWithSpan('null', 'type-null'); output += decorateWithSpan('null', 'type-null');
} } else if (value && value.constructor === Array) {
else if (value && value.constructor === Array) {
level++; level++;
output += arrayToHTML(value); output += arrayToHTML(value);
level--; level--;
} } else if (valueType === 'object') {
else if (valueType === 'object') {
level++; level++;
output += objectToHTML(value); output += objectToHTML(value);
level--; level--;
} } else if (valueType === 'number') {
else if (valueType === 'number') {
output += decorateWithSpan(value, 'type-number'); output += decorateWithSpan(value, 'type-number');
} } else if (valueType === 'string') {
else if (valueType === 'string') {
if (/^(http|https):\/\/[^\\s]+$/.test(value)) { if (/^(http|https):\/\/[^\\s]+$/.test(value)) {
output += decorateWithSpan('"', 'type-string') + '<a href="' + value + '">' + htmlEncode(value) + '</a>' + decorateWithSpan('"', 'type-string'); output += decorateWithSpan('"', 'type-string') + '<a href="' + value + '">' + htmlEncode(value) + '</a>' +
decorateWithSpan('"', 'type-string');
} else { } else {
output += decorateWithSpan('"' + value + '"', 'type-string'); output += decorateWithSpan('"' + value + '"', 'type-string');
} }

View File

@ -6,9 +6,13 @@ import {methods as swaggerMethods} from './swagger-defs';
export class SchemaManager { export class SchemaManager {
public _schema:any = {}; public _schema:any = {};
public apiUrl: string;
private _instance:any; private _instance:any;
apiUrl: string; static instance() {
return new SchemaManager();
}
constructor() { constructor() {
if (SchemaManager.prototype._instance) { if (SchemaManager.prototype._instance) {
return SchemaManager.prototype._instance; return SchemaManager.prototype._instance;
@ -17,10 +21,6 @@ export class SchemaManager {
SchemaManager.prototype._instance = this; SchemaManager.prototype._instance = this;
} }
static instance() {
return new SchemaManager();
}
load(url) { load(url) {
let promise = new Promise((resolve, reject) => { let promise = new Promise((resolve, reject) => {
this._schema = {}; this._schema = {};

View File

@ -1,8 +1,8 @@
'use strict'; 'use strict';
import {Pipe} from '@angular/core'; import { Pipe, PipeTransform } from '@angular/core';
import {isString, stringify, isBlank} from '@angular/core/src/facade/lang'; import { isString, stringify, isBlank } from '@angular/core/src/facade/lang';
import {BaseException} from '@angular/core/src/facade/exceptions'; import { BaseException } from '@angular/core/src/facade/exceptions';
import JsonPointer from './JsonPointer'; import JsonPointer from './JsonPointer';
declare var Prism: any; declare var Prism: any;
@ -31,7 +31,7 @@ class InvalidPipeArgumentException extends BaseException {
} }
@Pipe({ name: 'keys' }) @Pipe({ name: 'keys' })
export class KeysPipe { export class KeysPipe implements PipeTransform {
transform(value) { transform(value) {
if (isBlank(value)) return value; if (isBlank(value)) return value;
if (typeof value !== 'object') { if (typeof value !== 'object') {
@ -42,7 +42,7 @@ export class KeysPipe {
} }
@Pipe({ name: 'values' }) @Pipe({ name: 'values' })
export class ValuesPipe { export class ValuesPipe implements PipeTransform {
transform(value) { transform(value) {
if (isBlank(value)) return value; if (isBlank(value)) return value;
if (typeof value !== 'object') { if (typeof value !== 'object') {
@ -53,7 +53,7 @@ export class ValuesPipe {
} }
@Pipe({ name: 'jsonPointerEscape' }) @Pipe({ name: 'jsonPointerEscape' })
export class JsonPointerEscapePipe { export class JsonPointerEscapePipe implements PipeTransform {
transform(value) { transform(value) {
if (isBlank(value)) return value; if (isBlank(value)) return value;
if (!isString(value)) { if (!isString(value)) {
@ -64,7 +64,7 @@ export class JsonPointerEscapePipe {
} }
@Pipe({ name: 'marked' }) @Pipe({ name: 'marked' })
export class MarkedPipe { export class MarkedPipe implements PipeTransform {
transform(value) { transform(value) {
if (isBlank(value)) return value; if (isBlank(value)) return value;
if (!isString(value)) { if (!isString(value)) {
@ -83,7 +83,7 @@ const langMap = {
}; };
@Pipe({ name: 'prism' }) @Pipe({ name: 'prism' })
export class PrismPipe { export class PrismPipe implements PipeTransform {
transform(value, args) { transform(value, args) {
if (isBlank(args) || args.length === 0) { if (isBlank(args) || args.length === 0) {
throw new BaseException('Prism pipe requires one argument'); throw new BaseException('Prism pipe requires one argument');
@ -103,7 +103,7 @@ export class PrismPipe {
} }
@Pipe({ name: 'encodeURIComponent' }) @Pipe({ name: 'encodeURIComponent' })
export class EncodeURIComponentPipe { export class EncodeURIComponentPipe implements PipeTransform {
transform(value) { transform(value) {
if (isBlank(value)) return value; if (isBlank(value)) return value;
if (!isString(value)) { if (!isString(value)) {

View File

@ -98,6 +98,7 @@
"babel-polyfill": "^6.3.14", "babel-polyfill": "^6.3.14",
"branch-release": "^0.3.2", "branch-release": "^0.3.2",
"browser-sync": "^2.10.1", "browser-sync": "^2.10.1",
"codelyzer": "0.0.23",
"del": "^2.2.0", "del": "^2.2.0",
"deploy-to-gh-pages": "^1.0.0", "deploy-to-gh-pages": "^1.0.0",
"dropkickjs": "github:robdel12/DropKick", "dropkickjs": "github:robdel12/DropKick",
@ -142,7 +143,9 @@
"should": "^8.0.2", "should": "^8.0.2",
"sinon": "^1.17.2", "sinon": "^1.17.2",
"systemjs-builder": "^0.15.16", "systemjs-builder": "^0.15.16",
"typescript": "^1.8.10", "tslint": "^3.11.0",
"tslint-stylish": "^2.1.0-beta",
"typescript": "^1.9.0-dev.20160612-1.0",
"vinyl-paths": "^2.0.0", "vinyl-paths": "^2.0.0",
"yargs": "^4.7.1", "yargs": "^4.7.1",
"zone.js": "^0.6.12" "zone.js": "^0.6.12"

View File

@ -1,6 +1,7 @@
'use strict'; 'use strict';
import {By} from '@angular/platform-browser'; import {By} from '@angular/platform-browser';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
/** Gets a child DebugElement by tag name. */ /** Gets a child DebugElement by tag name. */
export function getChildDebugElement(parent, tagName) { export function getChildDebugElement(parent, tagName) {
@ -19,10 +20,7 @@ export function getChildDebugElementAll(parent, tagName) {
export function mouseclick( element ) { export function mouseclick( element ) {
// create a mouse click event // create a mouse click event
var event = document.createEvent( 'MouseEvents' ); var dispatchedEvent = getDOM().createMouseEvent('click');
event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false,
false, false, false, 0, element);
// send click to element // send click to element
element.dispatchEvent( event ); getDOM().dispatchEvent(element, dispatchedEvent);
} }

View File

@ -9,10 +9,6 @@ describe('Utils', () => {
schemaMgr = new SchemaManager(); schemaMgr = new SchemaManager();
}); });
it('Should initialize with empty schema', ()=> {
schemaMgr.schema.should.be.empty;
});
it('Should be a singleton', ()=> { it('Should be a singleton', ()=> {
(new SchemaManager()).should.be.equal(schemaMgr); (new SchemaManager()).should.be.equal(schemaMgr);
SchemaManager.instance().should.be.equal(schemaMgr); SchemaManager.instance().should.be.equal(schemaMgr);
@ -50,7 +46,7 @@ describe('Utils', () => {
it('should contain non-empty schema', ()=> { it('should contain non-empty schema', ()=> {
schemaMgr.schema.should.be.an.Object(); schemaMgr.schema.should.be.an.Object();
schemaMgr.schema.should.be.not.empty; schemaMgr.schema.should.be.not.empty();
}); });
it('should correctly init api url', ()=> { it('should correctly init api url', ()=> {
@ -93,7 +89,7 @@ describe('Utils', () => {
it('should return empty array for non-specified tags', () => { it('should return empty array for non-specified tags', () => {
delete schemaMgr._schema.tags; delete schemaMgr._schema.tags;
let tagsMap = schemaMgr.getTagsMap(); let tagsMap = schemaMgr.getTagsMap();
tagsMap.should.be.empty; tagsMap.should.be.empty();
}); });
}); });
@ -155,8 +151,8 @@ describe('Utils', () => {
it('should map x-traitTag to empty methods list', () => { it('should map x-traitTag to empty methods list', () => {
let [, info] = entries[0]; let [, info] = entries[0];
info['x-traitTag'].should.be.true; info['x-traitTag'].should.be.true();
info.methods.should.be.empty; info.methods.should.be.empty();
}); });
it('methods for tag should contain valid pointer and summary', () => { it('methods for tag should contain valid pointer and summary', () => {
@ -238,13 +234,16 @@ describe('Utils', () => {
let deriveDefs = schemaMgr.findDerivedDefinitions('#/definitions/Pet'); let deriveDefs = schemaMgr.findDerivedDefinitions('#/definitions/Pet');
deriveDefs.should.be.instanceof(Array); deriveDefs.should.be.instanceof(Array);
deriveDefs.should.not.be.empty(); deriveDefs.should.not.be.empty();
deriveDefs.should.be.deepEqual([{name: 'Cat', empty: false, $ref: '#/definitions/Cat'}, {name: 'Dog', empty: false, $ref: '#/definitions/Dog'}]); deriveDefs.should.be.deepEqual([
{name: 'Cat', empty: false, $ref: '#/definitions/Cat'},
{name: 'Dog', empty: false, $ref: '#/definitions/Dog'}
]);
}); });
it('should return emtpy array for definitions that dont have discriminator', () => { it('should return emtpy array for definitions that dont have discriminator', () => {
let deriveDefs = schemaMgr.findDerivedDefinitions('#/definitions/Order'); let deriveDefs = schemaMgr.findDerivedDefinitions('#/definitions/Order');
deriveDefs.should.be.instanceof(Array); deriveDefs.should.be.instanceof(Array);
deriveDefs.should.be.empty; deriveDefs.should.be.empty();
}); });
}); });
}); });

51
tslint.json Normal file
View File

@ -0,0 +1,51 @@
{
"rulesDirectory": ["node_modules/codelyzer"],
"rules": {
"class-name": true,
"curly": false,
"eofline": true,
"indent": ["spaces"],
"max-line-length": [true, 140],
"member-ordering": [true,
"public-before-private",
"static-before-instance",
"variables-before-functions"
],
"no-arg": true,
"no-construct": true,
"no-duplicate-key": true,
"no-duplicate-variable": true,
"no-empty": true,
"no-eval": true,
"no-trailing-whitespace": true,
"no-unused-expression": true,
"no-unused-variable": true,
"no-unreachable": true,
"no-use-before-declare": true,
"one-line": [true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"quotemark": [true, "single"],
"semicolon": true,
"trailing-comma": true,
"triple-equals": [true,
"allow-undefined-check"
],
"variable-name": false,
"directive-selector-name": [true, "camelCase"],
"component-selector-name": [true, "kebab-case"],
"directive-selector-type": [true, "attribute"],
"component-selector-type": [true, "element"],
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"no-input-rename": true,
"no-output-rename": true,
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true
}
}