diff --git a/build/tasks/build.js b/build/tasks/build.js index b51a3e35..c5cd692f 100644 --- a/build/tasks/build.js +++ b/build/tasks/build.js @@ -23,8 +23,7 @@ gulp.task('build', function (callback) { } return runSequence( 'clean', - 'tsc', - 'inlineTemplates', + 'transpile', 'bundle', 'concatDeps', 'copyDebug', @@ -32,6 +31,14 @@ gulp.task('build', function (callback) { ); }); +gulp.task('transpile', function(cb) { + return runSequence( + 'tsc', + 'inlineTemplates', + cb + ); +}); + gulp.task('copyDebug', () => { if (!argv.prod) { // copy for be accessible from demo for debug @@ -39,16 +46,6 @@ gulp.task('copyDebug', () => { } }); -gulp.task('rebuild', function(done) { - return runSequence( - 'inlineTemplates', - 'bundle', - 'concatDeps', - 'copyDebug', - done - ); -}); - gulp.task('tsc', function() { exec('tsc -p ./tsconfig.json'); }); @@ -81,7 +78,7 @@ gulp.task('tsc', function() { // .pipe(gulp.dest(config.tmp)); // } -gulp.task('inlineTemplates', ['tsc', 'sass'], function() { +gulp.task('inlineTemplates', ['sass'], function() { return gulp.src('.tmp/**/*.js', { base: './tmp' }) .pipe(replace(/'(.*?)\.css'/g, '\'$1.scss\'')) .pipe(inlineNg2Template({ @@ -98,14 +95,14 @@ gulp.task('inlineTemplates', ['tsc', 'sass'], function() { .pipe(gulp.dest(paths.tmp)); }); -function compileSass(ext, file) { - file = file.replace('../../shared/styles/variables', 'lib/shared/styles/variables'); - file = file.replace('json-schema-common', 'lib/components/JsonSchema/json-schema-common'); - file = file.replace('../../shared/styles/share-link', 'lib/shared/styles/share-link'); - file = file.replace('../JsonSchema/lib/components/JsonSchema/json-schema-common', 'lib/components/JsonSchema/json-schema-common'); - file = file.replace('../../styles/variables', 'lib/shared/styles/variables'); +function compileSass(ext, file, cb) { + file = file.replace('../../shared/styles/variables', 'lib/shared/styles/variables'); + file = file.replace('json-schema-common', 'lib/components/JsonSchema/json-schema-common'); + file = file.replace('../../shared/styles/share-link', 'lib/shared/styles/share-link'); + file = file.replace('../JsonSchema/lib/components/JsonSchema/json-schema-common', 'lib/components/JsonSchema/json-schema-common'); + file = file.replace('../../styles/variables', 'lib/shared/styles/variables'); - return sassCopm.renderSync({data: file}).css; + cb(null, sassCopm.renderSync({data: file}).css); } var JS_DEPS = argv.prod ? [ @@ -116,7 +113,7 @@ var JS_DEPS = argv.prod ? [ ]: [ 'lib/utils/browser-update.js', 'node_modules/zone.js/dist/zone.js', - //'node_modules/zone.js/dist/long-stack-trace-zone.js', + 'node_modules/zone.js/dist/long-stack-trace-zone.js', 'node_modules/reflect-metadata/Reflect.js', 'node_modules/babel-polyfill/dist/polyfill.js' ]; @@ -138,7 +135,7 @@ gulp.task('concatDeps', ['concatPrism'], function() { .pipe(gulp.dest('.')) }); -gulp.task('bundle', function bundle(done) { +gulp.task('bundle', ['injectVersionFile'], function bundle(done) { mkdir('-p', 'dist'); cp('lib/index.js', path.join(paths.tmp, paths.sourceEntryPoint)); var builder = new Builder('./', 'system.config.js'); @@ -188,7 +185,8 @@ gulp.task('concatPrism', function() { }); // needs inlineTemplates run before to create .tmp/lib folder -gulp.task('injectVersionFile', ['inlineTemplates'], function() { +gulp.task('injectVersionFile', function() { var version = require('../../package.json').version; - fs.writeFileSync(path.join(paths.tmp, 'lib/version.json'), JSON.stringify(version)); + var exportStatement = `export var redocVersion = "${version}"`; + fs.writeFileSync(path.join(paths.tmp, 'lib/version.js'), exportStatement); }) diff --git a/build/tasks/test.js b/build/tasks/test.js index 58270bb3..c572bac5 100644 --- a/build/tasks/test.js +++ b/build/tasks/test.js @@ -1,12 +1,21 @@ var gulp = require('gulp'); - +var runSequence = require('run-sequence'); var Server = require('karma').Server; var remapIstanbul = require('remap-istanbul/lib/gulpRemapIstanbul'); +gulp.task('prepare-test', function(cb) { + return runSequence( + 'clean', + 'transpile', + 'concatPrism', + 'injectVersionFile', + cb + ); +}) /** * Run test once and exit */ -gulp.task('test', ['concatPrism', 'inlineTemplates', 'injectVersionFile'], function (done) { +gulp.task('test', ['prepare-test'], function (done) { new Server({ configFile: __dirname + '/../../karma.conf.js', singleRun: true diff --git a/build/tasks/watch.js b/build/tasks/watch.js index bf2fc0bf..a0cdcdda 100644 --- a/build/tasks/watch.js +++ b/build/tasks/watch.js @@ -7,8 +7,8 @@ function changed(event) { } gulp.task('watch', ['build'], function () { - gulp.watch([ paths.source ], [ 'rebuild', browserSync.reload ]).on('change', changed); - gulp.watch([ paths.html ], [ 'rebuild', browserSync.reload]).on('change', changed); - gulp.watch([ paths.scss ], [ 'rebuild', browserSync.reload]).on('change', changed); + gulp.watch([ paths.source ], [ 'build', browserSync.reload ]).on('change', changed); + gulp.watch([ paths.html ], [ 'build', browserSync.reload]).on('change', changed); + gulp.watch([ paths.scss ], [ 'build', browserSync.reload]).on('change', changed); gulp.watch([ paths.demo ], [ '', browserSync.reload ]).on('change', changed); }); diff --git a/demo/index.html b/demo/index.html index 0b3bf995..8f466a01 100644 --- a/demo/index.html +++ b/demo/index.html @@ -24,6 +24,6 @@ - + diff --git a/demo/swagger.yaml b/demo/swagger.yaml index 34e3414f..5034a924 100644 --- a/demo/swagger.yaml +++ b/demo/swagger.yaml @@ -25,18 +25,12 @@ tags: Sometimes you just can't get enough. For this reason, we've provided a convenient way to access more data in any request for sequential data. Simply call the url in the next_url parameter and we'll respond with the next set of data. ```json { - ... - "pagination": { - "next_url": "https://api.instagram.com/v1/tags/puppy/media/recent?access_token=fb2e77d.47a0479900504cb3ab4a1f626d174d2d&max_id=13872296", - "next_max_id": "13872296" - } - } ``` diff --git a/karma.conf.js b/karma.conf.js index fa926f1b..9966e216 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -53,7 +53,7 @@ module.exports = function (config) { loadFiles: ['.tmp/tests/setup.js', '.tmp/tests/helpers.js', '.tmp/lib/**/*.js', '.tmp/tests/unit/*.js'], serveFiles: ['tests/schemas/**/*.json','tests/schemas/**/*.yml', 'lib/**/*.html', - '.tmp/lib/**/*.json', '.tmp/*js', '.tmp/lib/**/*.css'] + '.tmp/*js', '.tmp/lib/**/*.css'] }, proxies: { diff --git a/lib/components/ApiInfo/api-info.html b/lib/components/ApiInfo/api-info.html index 8083a884..1c8151f5 100644 --- a/lib/components/ApiInfo/api-info.html +++ b/lib/components/ApiInfo/api-info.html @@ -1,6 +1,6 @@

{{data.title}} ({{data.version}})

-

+

Contact: diff --git a/lib/components/ApiInfo/api-info.spec.ts b/lib/components/ApiInfo/api-info.spec.ts index 15e2611b..5d0f26b4 100644 --- a/lib/components/ApiInfo/api-info.spec.ts +++ b/lib/components/ApiInfo/api-info.spec.ts @@ -15,7 +15,7 @@ import { import { TestComponentBuilder } from '@angular/compiler/testing'; import { ApiInfo } from './api-info'; -import { SchemaManager } from '../../utils/SchemaManager'; +import { SpecManager } from '../../utils/SpecManager'; import { OptionsService } from '../../services/index'; describe('Redoc components', () => { @@ -24,13 +24,13 @@ describe('Redoc components', () => { let component; let fixture; beforeEachProviders(() => [ - provide(SchemaManager, {useValue: new SchemaManager()}), + provide(SpecManager, {useValue: new SpecManager()}), provide(OptionsService, {useClass: OptionsService}) ]); - beforeEach(async(inject([TestComponentBuilder, SchemaManager], (tcb, schemaMgr) => { + beforeEach(async(inject([TestComponentBuilder, SpecManager], (tcb, specMgr) => { builder = tcb; - return schemaMgr.load('/tests/schemas/api-info-test.json'); + return specMgr.load('/tests/schemas/api-info-test.json'); }))); beforeEach((done) => { diff --git a/lib/components/ApiInfo/api-info.ts b/lib/components/ApiInfo/api-info.ts index 8d8c4a3e..2a8c20bf 100644 --- a/lib/components/ApiInfo/api-info.ts +++ b/lib/components/ApiInfo/api-info.ts @@ -1,6 +1,6 @@ 'use strict'; -import { SchemaManager, RedocComponent, BaseComponent } from '../base'; +import { SpecManager, RedocComponent, BaseComponent } from '../base'; import { OptionsService } from '../../services/index'; @RedocComponent({ @@ -11,8 +11,8 @@ import { OptionsService } from '../../services/index'; export class ApiInfo extends BaseComponent { data: any; specUrl: String; - constructor(schemaMgr:SchemaManager, private optionsService:OptionsService) { - super(schemaMgr); + constructor(specMgr:SpecManager, private optionsService:OptionsService) { + super(specMgr); } prepareModel() { diff --git a/lib/components/ApiLogo/api-logo.spec.ts b/lib/components/ApiLogo/api-logo.spec.ts index e53a24a7..e9a6fbf3 100644 --- a/lib/components/ApiLogo/api-logo.spec.ts +++ b/lib/components/ApiLogo/api-logo.spec.ts @@ -14,7 +14,7 @@ import { import { TestComponentBuilder } from '@angular/compiler/testing'; import { ApiLogo } from './api-logo'; -import { SchemaManager } from '../../utils/SchemaManager'; +import { SpecManager } from '../../utils/SpecManager'; describe('Redoc components', () => { @@ -22,16 +22,16 @@ describe('Redoc components', () => { let builder; let component; let fixture; - let schemaMgr; + let specMgr; let schemaUrl = '/tests/schemas/api-info-test.json'; beforeEachProviders(() => [ - provide(SchemaManager, {useValue: new SchemaManager()}) + provide(SpecManager, {useValue: new SpecManager()}) ]); - beforeEach(async(inject([TestComponentBuilder, SchemaManager], (tcb, _schemaMgr) => { + beforeEach(async(inject([TestComponentBuilder, SpecManager], (tcb, _specMgr) => { builder = tcb; - schemaMgr = _schemaMgr; - return schemaMgr.load(schemaUrl); + specMgr = _specMgr; + return specMgr.load(schemaUrl); }))); beforeEach((done) => { builder.createAsync(TestAppComponent).then(_fixture => { @@ -70,7 +70,7 @@ describe('Redoc components', () => { @Component({ selector: 'test-app', directives: [ApiLogo], - providers: [SchemaManager], + providers: [SpecManager], template: `` }) diff --git a/lib/components/ApiLogo/api-logo.ts b/lib/components/ApiLogo/api-logo.ts index 929e8626..fb1edad3 100644 --- a/lib/components/ApiLogo/api-logo.ts +++ b/lib/components/ApiLogo/api-logo.ts @@ -1,6 +1,6 @@ 'use strict'; -import {RedocComponent, BaseComponent, SchemaManager} from '../base'; +import {RedocComponent, BaseComponent, SpecManager} from '../base'; @RedocComponent({ selector: 'api-logo', @@ -10,8 +10,8 @@ import {RedocComponent, BaseComponent, SchemaManager} from '../base'; export class ApiLogo extends BaseComponent { data:any = {}; - constructor(schemaMgr:SchemaManager) { - super(schemaMgr); + constructor(specMgr:SpecManager) { + super(specMgr); } prepareModel() { diff --git a/lib/components/JsonSchema/json-schema-common.scss b/lib/components/JsonSchema/json-schema-common.scss index ddcb9656..e2458f58 100644 --- a/lib/components/JsonSchema/json-schema-common.scss +++ b/lib/components/JsonSchema/json-schema-common.scss @@ -11,16 +11,6 @@ $param-name-height: 20px; $sub-schema-offset: ($bullet-size/2) + $bullet-margin; -/* -.param-schema { - padding-left: $sub-schema-offset - $lines-width; - border-left: $line-border; -} - -.param-wrap { - position: relative; -}*/ - .param-name { font-size: 0.929em; @@ -34,7 +24,7 @@ $sub-schema-offset: ($bullet-size/2) + $bullet-margin; vertical-align: top; } -.param-name-content { +.param-name-wrap { padding-right: $cell-spacing; display: inline-block; font-family: $headers-font, $headers-font-family; @@ -45,6 +35,7 @@ $sub-schema-offset: ($bullet-size/2) + $bullet-margin; box-sizing: border-box; border-bottom: 1px solid #ccc; width: 75%; + line-height: 1em; } .param-range { diff --git a/lib/components/JsonSchema/json-schema-lazy.spec.ts b/lib/components/JsonSchema/json-schema-lazy.spec.ts index 5b45428c..d1026189 100644 --- a/lib/components/JsonSchema/json-schema-lazy.spec.ts +++ b/lib/components/JsonSchema/json-schema-lazy.spec.ts @@ -2,7 +2,6 @@ import { getChildDebugElement } from '../../../tests/helpers'; import { Component, provide } from '@angular/core'; -import { DynamicComponentLoader } from '@angular/core'; import { inject, @@ -15,42 +14,30 @@ import { TestComponentBuilder } from '@angular/compiler/testing'; import { JsonSchemaLazy } from './json-schema-lazy'; -import { SchemaManager } from '../../utils/SchemaManager'; +import { SpecManager } from '../../utils/SpecManager'; describe('Redoc components', () => { describe('JsonSchemaLazy Component', () => { let builder; let component; - let schemaMgr = new SchemaManager(); + let specMgr = new SpecManager(); let fixture; - let loader; - let appRefMock = { - instance: { - pointer: '' - }, - hostView: { changeDetectorRef: {detectChanges : () => undefined} } - }; beforeEachProviders(() => [ - provide(SchemaManager, {useValue: schemaMgr}) + provide(SpecManager, {useValue: specMgr}) ]); - beforeEach(inject([TestComponentBuilder, DynamicComponentLoader], (tcb, dcl) => { + beforeEach(inject([TestComponentBuilder], (tcb, dcl) => { builder = tcb; - loader = dcl; - spyOn(loader, 'loadNextToLocation').and.returnValue({then: (fn) => fn(appRefMock)}); })); beforeEach((done) => { builder.createAsync(TestAppComponent).then(_fixture => { fixture = _fixture; let debugEl = getChildDebugElement(fixture.debugElement, 'json-schema-lazy'); component = debugEl.componentInstance; + spyOn(component, '_loadAfterSelf').and.callThrough(); done(); }, err => done.fail(err)); }); - afterEach(() => { - loader.loadNextToLocation.and.callThrough(); - }); - it('should init component', () => { expect(component).not.toBeNull(); }); @@ -59,7 +46,7 @@ describe('Redoc components', () => { component.pointer = '#/def'; fixture.detectChanges(); component.load(); - expect(loader.loadNextToLocation).toHaveBeenCalled(); + expect(component._loadAfterSelf).toHaveBeenCalled(); }); it('should not run loadNextToLocation if already loaded', () => { @@ -67,14 +54,7 @@ describe('Redoc components', () => { fixture.detectChanges(); component.load(); component.load(); - expect(loader.loadNextToLocation.calls.count()).toEqual(1); - }); - - it('should init json-schema with correct pointer', () => { - component.pointer = '#/def'; - fixture.detectChanges(); - component.load(); - expect(appRefMock.instance.pointer).toEqual(component.pointer); + expect(component._loadAfterSelf.calls.count()).toEqual(1); }); }); }); diff --git a/lib/components/JsonSchema/json-schema-lazy.ts b/lib/components/JsonSchema/json-schema-lazy.ts index af01a9dd..c83be690 100644 --- a/lib/components/JsonSchema/json-schema-lazy.ts +++ b/lib/components/JsonSchema/json-schema-lazy.ts @@ -1,17 +1,15 @@ 'use strict'; -import { Component, ElementRef, ViewContainerRef, OnDestroy, AfterViewInit } from '@angular/core'; +import { Component, ElementRef, ViewContainerRef, OnDestroy, Input, + AfterViewInit, ComponentResolver, Renderer } from '@angular/core'; import { CORE_DIRECTIVES } from '@angular/common'; -import { DynamicComponentLoader, Input } from '@angular/core'; import { JsonSchema } from './json-schema'; import { OptionsService } from '../../services/options.service'; -import { SchemaManager } from '../../utils/SchemaManager'; - +import { SpecManager } from '../../utils/SpecManager'; var cache = {}; - @Component({ selector: 'json-schema-lazy', template: '', @@ -21,23 +19,33 @@ export class JsonSchemaLazy implements OnDestroy, AfterViewInit { @Input() pointer: string; @Input() auto: boolean; @Input() isRequestSchema: boolean; + @Input() final: boolean = false; + @Input() nestOdd: boolean; + @Input() childFor: string; + @Input() isArray: boolean; loaded: boolean = false; - constructor(private schemaMgr:SchemaManager, private viewRef:ViewContainerRef, private elementRef:ElementRef, - private dcl:DynamicComponentLoader, private optionsService:OptionsService) { + constructor(private specMgr:SpecManager, private location:ViewContainerRef, private elementRef:ElementRef, + private resolver:ComponentResolver, private optionsService:OptionsService, private _renderer: Renderer) { } normalizePointer() { - let schema = this.schemaMgr.byPointer(this.pointer); + let schema = this.specMgr.byPointer(this.pointer); return schema && schema.$ref || this.pointer; } _loadAfterSelf() { - return this.dcl.loadNextToLocation(JsonSchema, this.viewRef).then((compRef) => { - this.initComponent(compRef); - if (compRef.changeDetectorRef) { - compRef.changeDetectorRef.detectChanges(); - } + // FIXME: get rid of DynamicComponentLoader as it is deprecated + return this.resolver.resolveComponent(JsonSchema).then(componentFactory => { + let contextInjector = this.location.parentInjector; + let compRef = this.location.createComponent( + componentFactory, null, contextInjector, null); + this.initComponent(compRef.instance); + this._renderer.setElementAttribute(compRef.location.nativeElement, 'class', this.location.element.nativeElement.className); + compRef.changeDetectorRef.detectChanges(); return compRef; + }).catch(err => { + console.log(err); + throw err; }); } @@ -58,9 +66,10 @@ export class JsonSchemaLazy implements OnDestroy, AfterViewInit { setTimeout( ()=> { let $element = compRef.location.nativeElement; - // skip caching view with tabs inside (discriminator) as it needs attached controller - // FIXME: get rid of dependency on selector - if ($element.querySelector('.discriminator-wrap')) { + // skip caching view with tabs inside (discriminator) + // as it needs attached controller + if (compRef.instance.hasDescendants || compRef.instance._hasSubSchemas) { + this._loadAfterSelf(); return; } insertAfter($element.cloneNode(true), this.elementRef.nativeElement); @@ -71,12 +80,15 @@ export class JsonSchemaLazy implements OnDestroy, AfterViewInit { } } - initComponent(compRef) { - compRef.instance.pointer = this.pointer; - compRef.instance.isRequestSchema = this.isRequestSchema; + initComponent(instance:JsonSchema) { + Object.assign(instance, this); } ngAfterViewInit() { + if (this.optionsService.options.disableLazySchemas) { + this._loadAfterSelf(); + return; + } if (!this.auto) return; this.loadCached(); } diff --git a/lib/components/JsonSchema/json-schema.html b/lib/components/JsonSchema/json-schema.html index 4605645c..f3512c8e 100644 --- a/lib/components/JsonSchema/json-schema.html +++ b/lib/components/JsonSchema/json-schema.html @@ -19,14 +19,20 @@ -