1 | import * as fs from 'fs-extra';
|
2 | import * as _ from 'lodash';
|
3 | import * as path from 'path';
|
4 |
|
5 | import FileEngine from './file.engine';
|
6 |
|
7 | const decache = require('decache');
|
8 |
|
9 | export interface markdownReadedDatas {
|
10 | markdown: string;
|
11 | rawData: string;
|
12 | }
|
13 |
|
14 | export class MarkdownEngine {
|
15 | |
16 |
|
17 |
|
18 | private readonly markdownFiles = ['README', 'CHANGELOG', 'LICENSE', 'CONTRIBUTING', 'TODO'];
|
19 |
|
20 | private markedInstance;
|
21 |
|
22 | private static instance: MarkdownEngine;
|
23 | private constructor() {
|
24 | decache('marked');
|
25 | const { marked } = require('marked');
|
26 | this.markedInstance = marked;
|
27 |
|
28 | const renderer = new this.markedInstance.Renderer();
|
29 | renderer.code = (code, language) => {
|
30 | let highlighted = code;
|
31 | if (!language) {
|
32 | language = 'none';
|
33 | }
|
34 |
|
35 | highlighted = this.escape(code);
|
36 | return `<div><pre class="line-numbers"><code class="language-${language}">${highlighted}</code></pre></div>`;
|
37 | };
|
38 |
|
39 | renderer.table = (header, body) => {
|
40 | return (
|
41 | '<table class="table table-bordered compodoc-table">\n' +
|
42 | '<thead>\n' +
|
43 | header +
|
44 | '</thead>\n' +
|
45 | '<tbody>\n' +
|
46 | body +
|
47 | '</tbody>\n' +
|
48 | '</table>\n'
|
49 | );
|
50 | };
|
51 |
|
52 | renderer.image = function (href: string, title: string, text: string) {
|
53 | let out = '<img src="' + href + '" alt="' + text + '" class="img-responsive"';
|
54 | if (title) {
|
55 | out += ' title="' + title + '"';
|
56 | }
|
57 | out += '>';
|
58 | return out;
|
59 | };
|
60 |
|
61 | this.markedInstance.setOptions({
|
62 | renderer: renderer,
|
63 | gfm: true,
|
64 | breaks: false
|
65 | });
|
66 | }
|
67 | public static getInstance() {
|
68 | if (!MarkdownEngine.instance) {
|
69 | MarkdownEngine.instance = new MarkdownEngine();
|
70 | }
|
71 | return MarkdownEngine.instance;
|
72 | }
|
73 |
|
74 | public getTraditionalMarkdown(filepath: string): Promise<markdownReadedDatas> {
|
75 | return FileEngine.get(process.cwd() + path.sep + filepath + '.md')
|
76 | .catch(err => FileEngine.get(process.cwd() + path.sep + filepath).then())
|
77 | .then(data => {
|
78 | const returnedData: markdownReadedDatas = {
|
79 | markdown: this.markedInstance(data),
|
80 | rawData: data
|
81 | };
|
82 | return returnedData;
|
83 | });
|
84 | }
|
85 |
|
86 | public getTraditionalMarkdownSync(filepath: string): string {
|
87 | return this.markedInstance(FileEngine.getSync(process.cwd() + path.sep + filepath));
|
88 | }
|
89 |
|
90 | private getReadmeFile(): Promise<string> {
|
91 | return FileEngine.get(process.cwd() + path.sep + 'README.md').then(data =>
|
92 | this.markedInstance(data)
|
93 | );
|
94 | }
|
95 |
|
96 | public readNeighbourReadmeFile(file: string): string {
|
97 | let dirname = path.dirname(file);
|
98 | let readmeFile = dirname + path.sep + path.basename(file, '.ts') + '.md';
|
99 | return fs.readFileSync(readmeFile, 'utf8');
|
100 | }
|
101 |
|
102 | public hasNeighbourReadmeFile(file: string): boolean {
|
103 | let dirname = path.dirname(file);
|
104 | let readmeFile = dirname + path.sep + path.basename(file, '.ts') + '.md';
|
105 | return FileEngine.existsSync(readmeFile);
|
106 | }
|
107 |
|
108 | private componentReadmeFile(file: string): string {
|
109 | let dirname = path.dirname(file);
|
110 | let readmeFile = dirname + path.sep + 'README.md';
|
111 | let readmeAlternativeFile = dirname + path.sep + path.basename(file, '.ts') + '.md';
|
112 | let finalPath = '';
|
113 | if (FileEngine.existsSync(readmeFile)) {
|
114 | finalPath = readmeFile;
|
115 | } else {
|
116 | finalPath = readmeAlternativeFile;
|
117 | }
|
118 | return finalPath;
|
119 | }
|
120 |
|
121 | |
122 |
|
123 |
|
124 | public hasRootMarkdowns(): boolean {
|
125 | return this.addEndings(this.markdownFiles).some(x =>
|
126 | FileEngine.existsSync(process.cwd() + path.sep + x)
|
127 | );
|
128 | }
|
129 |
|
130 | public listRootMarkdowns(): string[] {
|
131 | let foundFiles = this.markdownFiles.filter(
|
132 | x =>
|
133 | FileEngine.existsSync(process.cwd() + path.sep + x + '.md') ||
|
134 | FileEngine.existsSync(process.cwd() + path.sep + x)
|
135 | );
|
136 |
|
137 | return this.addEndings(foundFiles);
|
138 | }
|
139 |
|
140 | private escape(html: string): string {
|
141 | return html
|
142 | .replace(/&/g, '&')
|
143 | .replace(/</g, '<')
|
144 | .replace(/>/g, '>')
|
145 | .replace(/"/g, '"')
|
146 | .replace(/'/g, ''')
|
147 | .replace(/@/g, '@');
|
148 | }
|
149 |
|
150 | |
151 |
|
152 |
|
153 | private addEndings(files: Array<string>): Array<string> {
|
154 | return _.flatMap(files, x => [x, x + '.md']);
|
155 | }
|
156 | }
|
157 |
|
158 | export default MarkdownEngine.getInstance();
|