1 | const path = require('path');
|
2 | const fs = require('fs-extra');
|
3 | const utils = require('../utils.js');
|
4 | const ydoc = require('../ydoc.js');
|
5 | const ydocConfig = ydoc.config;
|
6 | let defaultIndexPageName = 'index';
|
7 | const defaultSummaryPage = 'SUMMARY.md';
|
8 | const defaultNavPage = 'NAV.md';
|
9 | const generate = require('../generate.js').generatePage;
|
10 | const runBatch = require('../generate.js').runBatch;
|
11 | const parseSummary = require('./summary');
|
12 | const parseMarkdown = require('./markdown').parseMarkdown;
|
13 |
|
14 | const parsePage = require('./page.js');
|
15 | const parseHtml = require('./html.js');
|
16 | const parseNav = require('./nav');
|
17 | const emitHook = require('../plugin.js').emitHook;
|
18 | const url = require('url');
|
19 | const color = require('bash-color');
|
20 |
|
21 | function getIndexPath(filepath) {
|
22 | let getIndexPathByType = (type) => path.resolve(filepath, defaultIndexPageName + '.' + type);
|
23 | let types = ['md', 'jsx', 'html'];
|
24 | let contentFilepath;
|
25 | for (let index in types) {
|
26 | contentFilepath = getIndexPathByType(types[index]);
|
27 | if (utils.fileExist(contentFilepath)) {
|
28 | return contentFilepath;
|
29 | }
|
30 | }
|
31 | return null;
|
32 | }
|
33 |
|
34 | function getBookSummary(filepath) {
|
35 | let summaryFilepath = path.resolve(filepath, defaultSummaryPage);
|
36 | if (!utils.fileExist(summaryFilepath)) return null;
|
37 | let summary = parseMarkdown(summaryFilepath);
|
38 | fs.unlinkSync(summaryFilepath);
|
39 | return parseSummary(summary);
|
40 | }
|
41 |
|
42 | function getNav(filepath) {
|
43 | let navFilepath = path.resolve(filepath, defaultNavPage);
|
44 | if (!utils.fileExist(navFilepath)) return null;
|
45 | let content = parseMarkdown(navFilepath);
|
46 | fs.unlinkSync(navFilepath);
|
47 | return parseNav(content);
|
48 | }
|
49 |
|
50 | function getBookContext(book, page) {
|
51 | const context = utils.extend({}, book);
|
52 | context.page = page;
|
53 | context.config = ydocConfig;
|
54 | return context;
|
55 | }
|
56 |
|
57 | function handleMdPathToHtml(filepath) {
|
58 | let fileObj = path.parse(filepath);
|
59 | if (fileObj.ext === '.md' || fileObj.ext === '.jsx') {
|
60 | let name = fileObj.name + '.html';
|
61 | return path.format({
|
62 | dir: fileObj.dir,
|
63 | base: name
|
64 | })
|
65 | } else {
|
66 | return path.format({
|
67 | dir: fileObj.dir,
|
68 | base: fileObj.base
|
69 | })
|
70 | }
|
71 | }
|
72 |
|
73 | exports.parseSite = async function (dist) {
|
74 | try {
|
75 | await emitHook('init');
|
76 |
|
77 | defaultIndexPageName = 'index'
|
78 | let indexPath = getIndexPath(dist);
|
79 | if (!indexPath) {
|
80 | return utils.log.error(`The root directory of site didn't find index page.`)
|
81 | }
|
82 | ydocConfig.nav = getNav(dist);
|
83 |
|
84 | await emitHook('nav', ydocConfig.nav)
|
85 |
|
86 | let books = [
|
87 | {
|
88 | bookpath: dist,
|
89 | indexFile: path.basename(indexPath),
|
90 | title: ydocConfig.title
|
91 | }
|
92 | ]
|
93 | ydocConfig.nav.menus.forEach(menu => {
|
94 | let menuBooks = getBooks(menu.items, dist);
|
95 | books = books.concat(menuBooks)
|
96 | })
|
97 | books = utils.distinct(books, (item) => {
|
98 | return item.bookpath + item.indexFile
|
99 | })
|
100 |
|
101 | for (let j = 0; j < books.length; j++) {
|
102 | await parseBook(books[j]);
|
103 | }
|
104 |
|
105 | let showpath = color.yellow(dist + '/index.html');
|
106 | utils.log.ok(`Generate Site "${ydocConfig.title}" ${showpath}`);
|
107 |
|
108 | await emitHook('finish')
|
109 | } catch (err) {
|
110 | utils.log.error(err);
|
111 | }
|
112 | }
|
113 |
|
114 | function getBooks(menus, dist) {
|
115 | let books = [];
|
116 | for (let i = 0; i < menus.length; i++) {
|
117 | let item = menus[i];
|
118 | if (!item.ref || utils.isUrl(item.ref)) {
|
119 | continue;
|
120 | }
|
121 |
|
122 | if (path.isAbsolute(item.ref)) {
|
123 | item.ref = '.' + item.ref;
|
124 | }
|
125 | let bookHomePath = path.resolve(dist, item.ref);
|
126 | if (!utils.fileExist(bookHomePath)) continue;
|
127 |
|
128 | let indexFile = path.basename(bookHomePath);
|
129 | let bookpath = path.dirname(bookHomePath);
|
130 | let stats;
|
131 | try {
|
132 | stats = fs.statSync(bookpath);
|
133 | } catch (err) {
|
134 | continue;
|
135 | }
|
136 |
|
137 | if (stats.isDirectory() && item[0] !== '_' && item[0] !== 'style') {
|
138 | item.ref = handleMdPathToHtml(item.ref);
|
139 | item.absolutePath = path.resolve(dist, item.ref)
|
140 | books.push({
|
141 | bookpath: bookpath,
|
142 | indexFile: indexFile,
|
143 | title: item.title
|
144 | })
|
145 |
|
146 | }
|
147 | }
|
148 | return books;
|
149 | }
|
150 |
|
151 | function getBookInfo(filepath) {
|
152 | let page;
|
153 | if (path.extname(filepath) === '.md') {
|
154 | page = parsePage(parseMarkdown(filepath));
|
155 | } else if (path.extname(filepath) === '.jsx') {
|
156 | page = {
|
157 | title: ydocConfig.title
|
158 | }
|
159 | } else {
|
160 | page = parsePage(parseHtml(filepath));
|
161 | }
|
162 | return {
|
163 | title: page.title || ydocConfig.title,
|
164 | description: page.description || ''
|
165 | }
|
166 | }
|
167 |
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 | async function parseBook({ bookpath, indexFile, title }) {
|
194 | const book = {};
|
195 | let extname = path.extname(indexFile);
|
196 | let name = path.basename(indexFile, extname);
|
197 | defaultIndexPageName = name;
|
198 |
|
199 | let indexPath = path.resolve(bookpath, indexFile);
|
200 | if (!utils.fileExist(indexPath)) {
|
201 | return;
|
202 | }
|
203 | let baseInfo = getBookInfo(indexPath);
|
204 | let summary = getBookSummary(bookpath);
|
205 |
|
206 | utils.extend(book, baseInfo);
|
207 | book.summary = summary;
|
208 | book.bookpath = path.resolve(bookpath, name + '.html')
|
209 |
|
210 |
|
211 | book.title = title ? title : book.title;
|
212 |
|
213 | await emitHook('book:before', {
|
214 | title: book.title,
|
215 | description: book.description,
|
216 | summary: summary
|
217 | });
|
218 |
|
219 | const generatePage = generate(bookpath);
|
220 |
|
221 |
|
222 | generatePage(getBookContext(book, {
|
223 | title: book.title,
|
224 | srcPath: indexPath,
|
225 | distPath: defaultIndexPageName + '.html'
|
226 | }))
|
227 | if (summary && Array.isArray(summary)) {
|
228 | parseDocuments(bookpath, function (absolutePath, releativeHtmlPath, title = '') {
|
229 | generatePage(getBookContext(book, {
|
230 | title: title,
|
231 | srcPath: absolutePath,
|
232 | distPath: unescape(releativeHtmlPath)
|
233 | }));
|
234 | })(summary);
|
235 | }
|
236 |
|
237 | await runBatch();
|
238 |
|
239 | let showpath = color.yellow(bookpath + '/' + defaultIndexPageName + '.html');
|
240 | utils.log.ok(`Generate book "${book.title}" ${showpath}`);
|
241 |
|
242 | await emitHook('book');
|
243 |
|
244 | }
|
245 |
|
246 |
|
247 | function parseDocuments(bookpath, callback) {
|
248 | return function _parseDocuments(summary) {
|
249 | for (let index = 0; index < summary.length; index++) {
|
250 | let item = summary[index];
|
251 | if (item.ref) {
|
252 | let urlObj = url.parse(item.ref);
|
253 | if (urlObj.host) continue;
|
254 | let releativePath = urlObj.pathname;
|
255 | let absolutePath = path.resolve(bookpath, releativePath);
|
256 | let releativeHtmlPath = handleMdPathToHtml(releativePath);
|
257 | urlObj.hash = urlObj.hash ? urlObj.hash.toLowerCase() : '';
|
258 | item.ref = releativeHtmlPath + urlObj.hash;
|
259 | item.absolutePath = absolutePath;
|
260 | if (utils.fileExist(unescape(absolutePath))) {
|
261 | callback(unescape(absolutePath), releativeHtmlPath, item.title)
|
262 | }
|
263 | }
|
264 |
|
265 | if (item.articles && Array.isArray(item.articles) && item.articles.length > 0) {
|
266 | _parseDocuments(item.articles)
|
267 | }
|
268 | }
|
269 | }
|
270 | } |
\ | No newline at end of file |