UNPKG

7.36 kBJavaScriptView Raw
1const path = require('path');
2const fs = require('fs-extra');
3const utils = require('../utils.js');
4const ydoc = require('../ydoc.js');
5const ydocConfig = ydoc.config;
6let defaultIndexPageName = 'index';
7const defaultSummaryPage = 'SUMMARY.md';
8const defaultNavPage = 'NAV.md';
9const generate = require('../generate.js').generatePage;
10const runBatch = require('../generate.js').runBatch;
11const parseSummary = require('./summary');
12const parseMarkdown = require('./markdown').parseMarkdown;
13
14const parsePage = require('./page.js');
15const parseHtml = require('./html.js');
16const parseNav = require('./nav');
17const emitHook = require('../plugin.js').emitHook;
18const url = require('url');
19const color = require('bash-color');
20
21function 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
34function 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
42function 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
50function getBookContext(book, page) {
51 const context = utils.extend({}, book);
52 context.page = page;
53 context.config = ydocConfig;
54 return context;
55}
56
57function 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
73exports.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
114function 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
151function 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// Schema
169// const bookSchema = {
170// title: 'string',
171// description: 'string',
172// summary: {},
173// nav: {},
174// bookpath: '当前书籍路径',
175// indexPath: '首页相对路径',
176// page: {
177// title: 'string',
178// description: 'string',
179// content: '内容',
180// prev: '上一页连接',
181// next: '下一页链接',
182// releativePath: '相对路径'
183// srcPath: '源文件路径',
184// distPath: '生成文件路径'
185// },
186// assets: { // assets 资源
187// js: [],
188// css: []
189// },
190// config: {} //ydocConfig 配置
191// }
192
193async 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 // 优先使用导航定义的 title
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 // 解析具体的 html
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// 解析文档 (.md)
247function 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