UNPKG

5 kBPlain TextView Raw
1import * as fs from 'fs-extra';
2import * as _ from 'lodash';
3import * as path from 'path';
4
5import FileEngine from './file.engine';
6
7const decache = require('decache');
8
9export interface markdownReadedDatas {
10 markdown: string;
11 rawData: string;
12}
13
14export class MarkdownEngine {
15 /**
16 * List of markdown files without .md extension
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 * Checks if any of the markdown files is exists with or without endings
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, '&amp;')
143 .replace(/</g, '&lt;')
144 .replace(/>/g, '&gt;')
145 .replace(/"/g, '&quot;')
146 .replace(/'/g, '&#39;')
147 .replace(/@/g, '&#64;');
148 }
149
150 /**
151 * ['README'] => ['README', 'README.md']
152 */
153 private addEndings(files: Array<string>): Array<string> {
154 return _.flatMap(files, x => [x, x + '.md']);
155 }
156}
157
158export default MarkdownEngine.getInstance();