From 7fa850b41d7b411878fbf542baece3e73031c3d1 Mon Sep 17 00:00:00 2001 From: Roman Hotsiy Date: Mon, 30 Jan 2017 17:21:12 +0200 Subject: [PATCH] Refactor markdown headings parsing --- lib/services/menu.service.ts | 33 +++++++++++++----------------- lib/utils/md-renderer.ts | 39 ++++++++++++++++++++++++++---------- lib/utils/spec-manager.ts | 3 +-- 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/lib/services/menu.service.ts b/lib/services/menu.service.ts index e7b069e5..ccdd3a2d 100644 --- a/lib/services/menu.service.ts +++ b/lib/services/menu.service.ts @@ -8,7 +8,7 @@ import { SpecManager } from '../utils/spec-manager'; import { SchemaHelper } from './schema-helper.service'; import { AppStateService } from './app-state.service'; import { LazyTasksService } from '../shared/components/LazyFor/lazy-for'; -import { JsonPointer } from '../utils/JsonPointer'; +import { JsonPointer, MarkdownHeading, StringMap } from '../utils/'; import * as slugify from 'slugify'; @@ -250,40 +250,35 @@ export class MenuService { addMarkdownItems() { let schema = this.specMgr.schema; - for (let header of (>(schema.info && schema.info['x-redoc-markdown-headers'] || []))) { - let id = 'section/' + slugify(header); + let headings = schema.info['x-redoc-markdown-headers'] as StringMap; + Object.keys(headings).forEach(h => { + let heading = headings[h]; + let id = 'section/' + heading.id; let item = { - name: header, + name: heading.title, id: id, items: null }; - item.items = this.getMarkdownSubheaders(item); + item.items = this.getMarkdownSubheaders(item, heading); this.items.push(item); - } + }); } - getMarkdownSubheaders(parent: MenuItem):MenuItem[] { + getMarkdownSubheaders(parent: MenuItem, parentHeading: MarkdownHeading):MenuItem[] { let res = []; - let schema = this.specMgr.schema; - for (let subheader of (>(schema.info && schema.info['x-redoc-markdown-subheaders'] || []))) { - let parts = subheader.split('/'); - let header = parts[0]; - if (parent.name !== header) { - continue; - } - - let name = parts[1]; - let id = parent.id + '/' + slugify(name); + Object.keys(parentHeading.children || {}).forEach(h => { + let heading = parentHeading.children[h]; + let id = 'section/' + heading.id; let subItem = { - name: name, + name: heading.title, id: id, parent: parent }; res.push(subItem); - } + }); return res; } diff --git a/lib/utils/md-renderer.ts b/lib/utils/md-renderer.ts index b29417cb..ea16309f 100644 --- a/lib/utils/md-renderer.ts +++ b/lib/utils/md-renderer.ts @@ -3,6 +3,7 @@ import { Injectable } from '@angular/core'; import * as slugify from 'slugify'; import * as Remarkable from 'remarkable'; +import { StringMap } from './'; declare var Prism: any; const md = new Remarkable({ @@ -19,11 +20,17 @@ const md = new Remarkable({ } }); +export interface MarkdownHeading { + title?: string; + id: string; + content?: string; + children?: StringMap; +} + @Injectable() export class MdRenderer { - public firstLevelHeadings: string[] = []; - public secondLevelHeadings: string[] = []; - public currentHeading: string = null; + public headings: StringMap = {}; + currentTopHeading: MarkdownHeading; private _origRules:any = {}; private _preProcessors:Function[] = []; @@ -45,21 +52,31 @@ export class MdRenderer { md.renderer.rules.heading_close = this._origRules.close; } + saveHeading(title: string, parent:MarkdownHeading = {id:null, children: this.headings}) :MarkdownHeading { + let id = slugify(title); + if (parent && parent.id) id = `${parent.id}/${id}`; + parent.children = parent.children || {}; + parent.children[id] = { + title, + id + }; + return parent.children[id]; + } + headingOpenRule(tokens, idx) { if (tokens[idx].hLevel > 2 ) { return this._origRules.open(tokens, idx); } else { let content = tokens[idx + 1].content; if (tokens[idx].hLevel === 1 ) { - this.firstLevelHeadings.push(content); - this.currentHeading = content; - let contentSlug = slugify(content); - return `` + - ``; + this.currentTopHeading = this.saveHeading(content);; + let id = this.currentTopHeading.id; + return `` + + ``; } else if (tokens[idx].hLevel === 2 ) { - this.secondLevelHeadings.push(this.currentHeading + `/` + content); - let contentSlug = slugify(this.currentHeading) + `/` + slugify(content); - return `` + + let heading = this.saveHeading(content, this.currentTopHeading); + let contentSlug = `${heading.id}`; + return `` + ``; } } diff --git a/lib/utils/spec-manager.ts b/lib/utils/spec-manager.ts index 22ded568..e32a1d48 100644 --- a/lib/utils/spec-manager.ts +++ b/lib/utils/spec-manager.ts @@ -84,8 +84,7 @@ export class SpecManager { mdRender.addPreprocessor(SecurityDefinitions.insertTagIntoDescription); } this._schema.info['x-redoc-html-description'] = mdRender.renderMd(this._schema.info.description); - this._schema.info['x-redoc-markdown-headers'] = mdRender.firstLevelHeadings; - this._schema.info['x-redoc-markdown-subheaders'] = mdRender.secondLevelHeadings; + this._schema.info['x-redoc-markdown-headers'] = mdRender.headings; } get schema() {