mirror of
https://github.com/avwo/whistle.git
synced 2026-10-22 01:06:41 +08:00
223 lines
5.6 KiB
JavaScript
223 lines
5.6 KiB
JavaScript
'use strict';
|
|
|
|
/* eslint-disable no-console */
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const startCase = require('lodash.startcase');
|
|
const correctAnchor = require('./correct-anchor');
|
|
const config = require('./config');
|
|
|
|
const langs = config.langs;
|
|
const docConfig = require('../config.json');
|
|
const docsDir = path.join(__dirname, '../');
|
|
const watchMode = process.argv[2] === '-w';
|
|
|
|
let cache = {};
|
|
start();
|
|
|
|
|
|
function start(){
|
|
build();
|
|
|
|
if (watchMode) {
|
|
watch();
|
|
}
|
|
}
|
|
function build() {
|
|
sammary();
|
|
cache = {};
|
|
combo();
|
|
}
|
|
|
|
function watch(){
|
|
fs.watch(docsDir, { recursive: true }, (eventType, filename) => {
|
|
if (filename.indexOf('/_book') >= 0) {
|
|
return;
|
|
}
|
|
if (filename.indexOf('/script') >= 0) {
|
|
return;
|
|
}
|
|
|
|
const ignores = langs.reduce((result, lang) => {
|
|
result.push(`${lang}/README.md`);
|
|
result.push(`${lang}/SUMMARY.md`);
|
|
return result;
|
|
}, []);
|
|
|
|
const isConfigFile = filename === 'config.json';
|
|
if (isConfigFile) {
|
|
console.warn('Please restart the docs:watch cmd !');
|
|
return;
|
|
}
|
|
const isWatchTarget = langs.some(lang => {
|
|
return filename.startsWith(lang) && ignores.indexOf(filename) < 0;
|
|
});
|
|
if (isWatchTarget) {
|
|
console.log(`file: ${filename} type: ${eventType}`);
|
|
build();
|
|
}
|
|
});
|
|
|
|
langs.forEach((lang) => {
|
|
console.info(`***** start watching ${docsDir}/${lang}/*.md *****`);
|
|
});
|
|
}
|
|
|
|
function getFilename({ lang, parentPaths, slug, isDir }) {
|
|
let filename = '';
|
|
if (isDir) {
|
|
filename = path.join(docsDir, lang, parentPaths.join('/'), isDir ? slug : '', 'README.md');
|
|
if (fs.existsSync(filename)) {
|
|
return filename;
|
|
}
|
|
}
|
|
filename = path.join(docsDir, lang, parentPaths.join('/'), `${slug}.md`);
|
|
if (fs.existsSync(filename)) {
|
|
return filename;
|
|
}
|
|
return '';
|
|
}
|
|
|
|
function getFileId(arr) {
|
|
return arr.join('_');
|
|
}
|
|
|
|
function generateNavTitle({ parentPaths, item, sign, lang }) {
|
|
const isDir = typeof item === 'object' && item.catalog && item.catalog.length;
|
|
const slug = typeof item === 'string' ? item : typeof item === 'object' ? item.name : '';
|
|
const sign_ = sign || '*';
|
|
|
|
if (!slug) {
|
|
return null;
|
|
}
|
|
|
|
const filename = getFilename({
|
|
lang, parentPaths, slug, isDir
|
|
});
|
|
const anchor = filename ? getFileId(parentPaths.concat(slug)) : '';
|
|
const prefix = parentPaths.reduce((pre, next) => {
|
|
return pre += '\t';
|
|
}, '');
|
|
const title = typeof item === 'string' ? prettyCatalog(item) : item.i18n ?
|
|
item.i18n[lang] || item.i18n['en-us'] || prettyCatalog(item.name) : prettyCatalog(item.name);
|
|
|
|
return `${prefix}${sign_} [${title}](README.md#${anchor})`;
|
|
}
|
|
|
|
function appendTitleAnchor(content, anchor) {
|
|
return content.replace(/(\#+.*)/, (match, p1) => {
|
|
return `${p1} {#${anchor}}`;
|
|
});
|
|
}
|
|
|
|
function walk({ catalog, lang, result, parentPaths, fn }) {
|
|
if (!catalog || !catalog.length) {
|
|
return result;
|
|
}
|
|
return catalog.reduce((result, item) => {
|
|
const slug = typeof item === 'string' ? item : typeof item === 'object' ? item.name : '';
|
|
if (slug) {
|
|
const isDir = item.catalog && item.catalog.length;
|
|
fn({ parentPaths, lang, item, isDir, result });
|
|
|
|
if (isDir) {
|
|
parentPaths.push(slug);
|
|
result = walk({ catalog: item.catalog, lang, result, parentPaths, fn });
|
|
parentPaths.pop();
|
|
}
|
|
}
|
|
return result;
|
|
}, result);
|
|
}
|
|
/**
|
|
* generate `SUMMARY.md` by `config.json`
|
|
*/
|
|
function sammary() {
|
|
const nodeFn = function ({ parentPaths, lang, item, isDir, result }) {
|
|
const navTitle = generateNavTitle({ parentPaths, item, sign: isDir ? '-' : '*', lang });
|
|
result.push(navTitle);
|
|
};
|
|
|
|
langs.forEach(dir => {
|
|
const SUMMARY = 'SUMMARY.md';
|
|
const targetFile = path.join(docsDir, `${dir}/${SUMMARY}`);
|
|
|
|
const result = walk({
|
|
catalog: docConfig.catalog,
|
|
lang: dir,
|
|
result: [],
|
|
parentPaths: [],
|
|
fn: nodeFn
|
|
});
|
|
|
|
if (result && result.length) {
|
|
result.unshift('# whistle\n');
|
|
fs.writeFileSync(targetFile, result.join('\n'));
|
|
}
|
|
});
|
|
}
|
|
|
|
function combo() {
|
|
const nodeFn = function ({ parentPaths, lang, item, result }) {
|
|
const isDir = typeof item === 'object' && item.catalog && item.catalog.length;
|
|
const slug = typeof item === 'string' ? item : typeof item === 'object' ? item.name : '';
|
|
const filename = getFilename({
|
|
parentPaths, lang, slug, isDir
|
|
});
|
|
const fileId = getFileId(parentPaths.concat(slug));
|
|
|
|
if (filename) {
|
|
let content = fs.readFileSync(filename).toString();
|
|
content = appendTitleAnchor(content, fileId);
|
|
content = correctAnchor({rootPath: path.join(docsDir, lang) , absFilename: filename, content})
|
|
|
|
cache[fileId] = content;
|
|
result.push(fileId);
|
|
}
|
|
};
|
|
|
|
langs.forEach(dir => {
|
|
const README = 'README.md';
|
|
const targetFile = path.join(docsDir, `${dir}/${README}`);
|
|
|
|
const result = walk({
|
|
catalog: docConfig.catalog,
|
|
lang: dir,
|
|
result: [],
|
|
parentPaths: [],
|
|
fn: nodeFn
|
|
});
|
|
if (result && result.length) {
|
|
const content = result.reduce((pre, next) => {
|
|
if (cache[next]) {
|
|
pre += cache[next] + '\n\n';
|
|
}
|
|
return pre;
|
|
}, '');
|
|
fs.writeFileSync(targetFile, content);
|
|
}
|
|
});
|
|
}
|
|
|
|
function isChinese(string) {
|
|
var req = /[\u4E00-\u9FA5]|[\uFE30-\uFFA0]/gi;
|
|
if (!req.exec(string)) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
function isNonAscii(string) {
|
|
var regExp = /^[ -~\t\n\r]+$/gi;
|
|
return !regExp.test(string);
|
|
}
|
|
|
|
function prettyCatalog(fileName) {
|
|
if (isChinese(fileName) || isNonAscii(fileName)) {
|
|
return fileName;
|
|
}
|
|
return startCase(fileName);
|
|
}
|