diff --git a/lib/utils/helpers.ts b/lib/utils/helpers.ts index 991526bf..46f1ed66 100644 --- a/lib/utils/helpers.ts +++ b/lib/utils/helpers.ts @@ -1,25 +1,4 @@ 'use strict'; -import * as Remarkable from 'remarkable'; -declare var Prism: any; - -const md = new Remarkable({ - html: true, - linkify: true, - breaks: false, - typographer: false, - highlight: (str, lang) => { - if (lang === 'json') lang = 'js'; - let grammar = Prism.languages[lang]; - //fallback to clike - if (!grammar) return str; - return Prism.highlight(str, grammar); - } -}); - -interface HeadersHandler { - open: Function; - close: Function; -} export function stringify(obj:any) { return JSON.stringify(obj); @@ -34,41 +13,7 @@ export function isFunction(func: any) { } export function isBlank(obj: any): boolean { - return obj == null; -} - -export function renderMd(rawText:string, headersHandler?:HeadersHandler) { - let _origRule; - if (headersHandler) { - _origRule = { - open: md.renderer.rules.heading_open, - close: md.renderer.rules.heading_close - }; - md.renderer.rules.heading_open = (tokens, idx) => { - if (tokens[idx].hLevel !== 1 ) { - return _origRule.open(tokens, idx); - } else { - return headersHandler.open(tokens, idx); - } - }; - - md.renderer.rules.heading_close = (tokens, idx) => { - if (tokens[idx].hLevel !== 1 ) { - return _origRule.close(tokens, idx); - } else { - return headersHandler.close(tokens, idx); - } - }; - } - - let res = md.render(rawText); - - if (headersHandler) { - md.renderer.rules.heading_open = _origRule.open; - md.renderer.rules.heading_close = _origRule.close; - } - - return res; + return obj == undefined; } export function statusCodeType(statusCode) { diff --git a/lib/utils/index.ts b/lib/utils/index.ts index e1b0cf0c..cd933708 100644 --- a/lib/utils/index.ts +++ b/lib/utils/index.ts @@ -1 +1,3 @@ export * from './custom-error-handler'; +export * from './helpers'; +export * from './md-renderer'; diff --git a/lib/utils/md-renderer.ts b/lib/utils/md-renderer.ts new file mode 100644 index 00000000..3c89bd67 --- /dev/null +++ b/lib/utils/md-renderer.ts @@ -0,0 +1,95 @@ +'use strict'; + +import { Injectable } from '@angular/core'; +import * as slugify from 'slugify'; +import * as Remarkable from 'remarkable'; + +import { SecurityDefinitions } from '../components/'; + +declare var Prism: any; +const md = new Remarkable({ + html: true, + linkify: true, + breaks: false, + typographer: false, + highlight: (str, lang) => { + if (lang === 'json') lang = 'js'; + let grammar = Prism.languages[lang]; + //fallback to clike + if (!grammar) return str; + return Prism.highlight(str, grammar); + } +}); + +interface HeadersHandler { + open: Function; + close: Function; +} + +@Injectable() +export class MdRenderer { + private _origRules:any = {}; + private _preProcessors:Function[] = []; + + public firstLevelHeadings: string[] = []; + constructor(private raw: boolean = false) { + // TODO + if (!raw) { + this.addPreprocessor(SecurityDefinitions.insertTagIntoDescription); + } + } + + addPreprocessor(p: Function) { + this._preProcessors.push(p); + } + + saveOrigRules() { + this._origRules.open = md.renderer.rules.heading_open; + this._origRules.close = md.renderer.rules.heading_close; + } + + restoreOrigRules() { + md.renderer.rules.heading_open = this._origRules.open; + md.renderer.rules.heading_close = this._origRules.close; + } + + headingOpenRule(tokens, idx) { + if (tokens[idx].hLevel !== 1 ) { + return this._origRules.open(tokens, idx); + } else { + let content = tokens[idx + 1].content; + this.firstLevelHeadings.push(content); + let contentSlug = slugify(content); + return `` + + ``; + } + } + + headingCloseRule(tokens, idx) { + if (tokens[idx].hLevel !== 1 ) { + return this._origRules.close(tokens, idx); + } else { + return `\n`; + } + } + + renderMd(rawText:string) { + if (!this.raw) { + this.saveOrigRules(); + md.renderer.rules.heading_open = this.headingOpenRule.bind(this); + md.renderer.rules.heading_close = this.headingCloseRule.bind(this); + } + let text = rawText; + + for (let i=0; i${renderMd(value)}` + `${this.renderer.renderMd(value)}` ); } } @@ -125,5 +128,5 @@ export class EncodeURIComponentPipe implements PipeTransform { } export const REDOC_PIPES = [ - JsonPointerEscapePipe, MarkedPipe, SafePipe, PrismPipe, EncodeURIComponentPipe, JsonFormatter + JsonPointerEscapePipe, MarkedPipe, SafePipe, PrismPipe, EncodeURIComponentPipe, JsonFormatter, KeysPipe ]; diff --git a/lib/utils/spec-manager.ts b/lib/utils/spec-manager.ts index f9e9d4c4..283d82e3 100644 --- a/lib/utils/spec-manager.ts +++ b/lib/utils/spec-manager.ts @@ -2,11 +2,11 @@ import * as JsonSchemaRefParser from 'json-schema-ref-parser'; import { JsonPointer } from './JsonPointer'; -import { renderMd, safePush } from './helpers'; -import * as slugify from 'slugify'; import { parse as urlParse, resolve as urlResolve } from 'url'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; +import { MdRenderer } from './'; + export class SpecManager { public _schema: any = {}; public apiUrl: string; @@ -75,18 +75,10 @@ export class SpecManager { } preprocess() { - this._schema.info['x-redoc-html-description'] = renderMd( this._schema.info.description, { - open: (tokens, idx) => { - let content = tokens[idx + 1].content; - safePush(this._schema.info, 'x-redoc-markdown-headers', content); - content = slugify(content); - return `` + - ``; - }, - close: (tokens, idx) => { - return ``; - } - }); + let mdRender = new MdRenderer(); + if (!this._schema.info.description) this._schema.info.description = ''; + this._schema.info['x-redoc-html-description'] = mdRender.renderMd(this._schema.info.description); + this._schema.info['x-redoc-markdown-headers'] = mdRender.firstLevelHeadings; } get schema() {