linux-command/scripts/build.mjs

252 lines
8.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import FS from 'fs-extra';
import path from 'path';
import stylus from 'stylus';
import * as ejs from 'ejs';
import UglifyJS from 'uglify-js';
import { create } from 'markdown-to-html-cli';
import _ from 'colors-cli/toxic.js';
const deployDir = path.resolve(process.cwd(), '.deploy');
const faviconPath = path.resolve(process.cwd(), 'template', 'img', 'favicon.ico');
const rootIndexJSPath = path.resolve(process.cwd(), 'template', 'js', 'index.js');
const dataJsonPath = path.resolve(process.cwd(), 'dist', 'data.json');
const dataJsonMinPath = path.resolve(process.cwd(), 'dist', 'data.min.json');
const cssPath = path.resolve(deployDir, 'css', 'index.css');
const contributorsPath = path.resolve(process.cwd(), 'CONTRIBUTORS.svg');
;(async () => {
try {
await FS.ensureDir(deployDir);
await FS.emptyDir(deployDir);
await FS.ensureDir(path.resolve(deployDir, 'img'));
await FS.ensureDir(path.resolve(deployDir, 'js'));
await FS.ensureDir(path.resolve(deployDir, 'css'));
await FS.ensureDir(path.resolve(deployDir, 'c'));
await FS.copySync(faviconPath, path.resolve(deployDir, 'img', 'favicon.ico'));
await FS.copyFile(path.resolve(process.cwd(), 'template', 'js', 'copy-to-clipboard.js'), path.resolve(deployDir, 'js', 'copy-to-clipboard.js'));
await FS.copyFile(path.resolve(process.cwd(), 'node_modules/@wcj/dark-mode/main.js'), path.resolve(deployDir, 'js', 'dark-mode.min.js'));
await FS.copyFile(path.resolve(process.cwd(), 'node_modules/@uiw/github-corners/lib/index.js'), path.resolve(deployDir, 'js', 'github-corners.js'));
const jsData = await FS.readFileSync(rootIndexJSPath);
await FS.outputFile(path.resolve(deployDir, 'js', 'index.js'), UglifyJS.minify(jsData.toString()).code)
const files = await readMarkdownPaths(path.resolve(process.cwd(), 'command'));
const jsonData = await createDataJSON(files);
await FS.outputFile(dataJsonPath, JSON.stringify(jsonData.json, null, 2));
await FS.outputFile(dataJsonMinPath, JSON.stringify(jsonData.json));
await FS.outputFile(path.resolve(deployDir, 'js', 'dt.js'), `var linux_commands=${JSON.stringify(jsonData.data)}`);
const cssStr = await createStylToCss(
path.resolve(process.cwd(), 'template', 'styl', 'index.styl'),
path.resolve(deployDir, 'css', 'index.css'),
);
await FS.outputFileSync(cssPath, cssStr)
console.log(` ${'→'.green} ${jsonData.data.length}`)
await createTmpToHTML(
path.resolve(process.cwd(), 'template', 'index.ejs'),
path.resolve(deployDir, 'index.html'),
{
p: '/index.html',
n: 'Linux命令搜索引擎',
d: '最专业的Linux命令大全内容包含Linux命令手册、详解、学习值得收藏的Linux命令速查手册。',
command_length: jsonData.data.length
}
);
await createTmpToHTML(
path.resolve(process.cwd(), 'template', 'list.ejs'),
path.resolve(deployDir, 'list.html'),
{
p: '/list.html',
n: '搜索',
d: '最专业的Linux命令大全命令搜索引擎内容包含Linux命令手册、详解、学习值得收藏的Linux命令速查手册。',
command_length: jsonData.data.length
}
);
await createTmpToHTML(
path.resolve(process.cwd(), 'template', 'hot.ejs'),
path.resolve(deployDir, 'hot.html'),
{
p: '/hot.html',
n: '搜索',
d: '最专业的Linux命令大全命令搜索引擎内容包含Linux命令手册、详解、学习值得收藏的Linux命令速查手册。',
arr: jsonData.data,
command_length: jsonData.data.length
}
);
let svgStr = '';
if (FS.existsSync(contributorsPath)) {
svgStr = (await FS.readFile(contributorsPath)).toString();
}
await createTmpToHTML(
path.resolve(process.cwd(), 'template', 'contributors.ejs'),
path.resolve(deployDir, 'contributors.html'),
{
p: '/contributors.html',
n: '搜索',
d: '最专业的Linux命令大全命令搜索引擎内容包含Linux命令手册、详解、学习值得收藏的Linux命令速查手册。',
arr: jsonData.data,
command_length: jsonData.data.length,
contributors: svgStr,
}
);
await Promise.all(jsonData.data.map(async (item, idx) => {
item.command_length = jsonData.data.length;
await createTmpToHTML(
path.resolve(process.cwd(), 'template', 'details.ejs'),
path.resolve(deployDir, 'c', `${item.n}.html`),
item,
path.resolve(process.cwd(), 'command'),
);
}));
} catch (err) {
if (err && err.message) {
console.log(`\n ERROR :> ${err.message.red_bt}\n`)
}
process.exit(1);
}
})();
/**
* 返回 MD 所有路径的 Array
* @param {String} filepath
*/
function readMarkdownPaths(filepath) {
return new Promise((resolve, reject) => {
try {
let pathAll = [];
const files = FS.readdirSync(filepath);
for (let i = 0; i < files.length; i++) {
if (/\.md$/.test(files[i])) {
pathAll.push(path.join(filepath, files[i]));
}
}
resolve(pathAll);
} catch (err) {
reject(err);
}
});
}
/**
* Ensures that the directory exists.
* @param {String} pathArr
*/
function createDataJSON(pathArr) {
return new Promise((resolve, reject) => {
try {
const commandData = {};
const indexes = [];
pathArr.forEach((mdPath, i) => {
const json = {}
const con = FS.readFileSync(mdPath);
const str = con.toString();
let title = str.match(/[^===]+(?=[===])/g);
title = title[0] ? title[0].replace(/\n/g, '') : title[0];
title = title.replace(/\r/, '')
// 命令名称
json["n"] = title;
// 命令路径
json["p"] = `/${path.basename(mdPath, '.md').replace(/\\/g, '/')}`;
// 命令描述
let des = str.match(/\n==={1,}([\s\S]*?)##/i);
if (!des) {
throw `格式错误: ${mdPath}`;
}
des = des[1] ? des[1].replace(/\n/g, '') : des[1];
des = des.replace(/\r/g, '')
json["d"] = des;
indexes.push(json);
commandData[title] = json;
})
resolve({
json: commandData,
data: indexes
});
} catch (err) {
reject(err);
}
});
}
/**
* @param {String} fromPath ejs path
* @param {String} toPath html path
*/
function createTmpToHTML(fromPath, toPath, desJson, mdPath) {
return new Promise(async (resolve, reject) => {
try {
const current_path = toPath.replace(new RegExp(`${deployDir}`), '');
const tmpStr = await FS.readFile(fromPath);
let mdPathName = '';
let mdhtml = '';
let relative_path = '';
if (mdPath) {
// CSS/JS 引用相对地址
relative_path = '../';
mdPathName = `/command/${desJson.n}.md`;
const READMESTR = await FS.readFile(path.resolve(mdPath, `${desJson.n}.md`));
mdhtml = await markdownToHTML(READMESTR.toString());
}
// 生成 HTML
let html = ejs.render(tmpStr.toString(), {
filename: fromPath,
relative_path, // 当前文件相对于根目录的相对路径
md_path: mdPathName || '', // markdown 路径
mdhtml: mdhtml || '',
current_path, // 当前 html 路径
describe: desJson ? desJson : {}, // 当前 md 的描述
}, {
filename: fromPath
});
await FS.outputFile(toPath, html);
console.log(` ${'♻️ →'.green} ${path.relative(process.cwd(), toPath)}`);
resolve();
} catch (err) {
reject(err);
}
});
}
function markdownToHTML(str) {
return create({
rewrite: (node) => {
if (node.type === 'element' && node.properties?.href && /.md/.test(node.properties.href) && !/^(https?:\/\/)/.test(node.properties.href)) {
let href = node.properties.href;
node.properties.href = href.replace(/([^\.\/\\]+)\.(md|markdown)/gi, '$1.html');
}
},
markdown: str, document: undefined, 'dark-mode': false
});
}
/**
* [createStylToCss 生成CSS]
* @param {[type]} stylPath stylus path
* @param {[type]} cssPath css path
*/
function createStylToCss(stylPath) {
return new Promise((resolve, reject) => {
try {
const stylStr = FS.readFileSync(stylPath, 'utf8');
stylus(stylStr.toString())
.set('filename', stylPath)
.set('compress', true)
.render((err, css) => {
if (err) throw err;
resolve(`${css}`);
});
} catch (err) {
reject(err);
}
});
}