const fs = require('fs');
const path = require('path');
//hash获取工具
let { hashElement } = require('folder-hash');
//marked转换工具
let marked = require('marked');
if (!marked) {
console.log('you need npm i marked -D!');
}
//文件监听
let Chokidar = require('chokidar');
// 基本配置文件信息
let {version} = require("../package.json");
//vue js脚本
//获取所有文件列表
let fileList = [];
// maked文件配置
var rendererMd = new marked.Renderer();
//maked文件规则
rendererMd.code = function (code, infostring, escaped) {
var lang = (infostring || '').match(/\S*/)[0];
if (this.options.highlight) {
var out = this.options.highlight(code, lang);
if (out != null && out !== code) {
escaped = true;
code = out;
}
}
if (!lang) {
return '
'
+ (escaped ? code : escape(code, true))
+ '
';
}
if (lang === 'html') {
code = code.replace(/@latest/g, '@' + version)
}
return '' + lang + ''
+ (escaped ? code : escape(code, true))
+ '
\n';
};
marked.setOptions({
renderer: rendererMd,
highlight: function (code) {
return require('highlight.js').highlightAuto(code).value;
},
tables: true
}, res => {
})
/**
* 是否需要单独处理头部信息
* @param {text} sorce 替换 头部信息
*/
function insert(sorce) {
var insert = sorce.indexOf('');
if (insert > -1) {
return sorce.substring(0, insert) + '请使用手机扫码体验
' + sorce.substring(insert, sorce.length);
} else {
return sorce
}
}
///创建一个空文件
/**
* 修复中
* @param {string} output 输出路径
* @param {string} sorce 文件源
* @param {boole} ishasCode 是否需要二维码
*/
function createdFile(output, sorce, ishasCode) {
var pathSrc = output;
if (ishasCode) {
var res = insert(sorce);
} else {
var res = sorce;
}
var bufs = ``;
fs.writeFile(pathSrc,bufs,'utf8',(err)=>{
})
}
/**
* 目录读取,找到跟文件
* @fileSrc {string} 打开文件路径
* @callback {fn} 结束后回调函数
*/
function readDirRecur(fileSrc, callback) {
fs.readdir(fileSrc, function(err, files) {
var count = 0
var checkEnd = function() {
++count == files.length && callback()
}
files.forEach(function(file) {
var fullPath = fileSrc + '/' + file;
fs.stat(fullPath, function(err, stats) {
if (stats.isDirectory()) {
return readDirRecur(fullPath, checkEnd);
} else {
/*not use ignore files*/
if(file[0] == '.') {
} else {
fileList.push(fullPath)
}
checkEnd()
}
})
})
//为空时直接回调
files.length === 0 && callback()
})
}
function fileReadStar(filedir,callback){
fs.readFile(filedir, 'utf-8', (err, data) => {
let html = marked(data);
let mdName = "";
let opensName = filedir.replace(/(^.*\/|.md)/g,"");
//如果是doc文件以前缀 为
if (opensName === 'doc') {
mdName = filedir.replace(/(^.*packages\/|\/doc\.md)/g,'');
} else {
//如果不是doc命名的文件
mdName = opensName;
}
callback({
mdName:mdName,
html:html
})
});
}
/**
* 判断是否位md文件 并进行操作
* 判断文件是否有改动
* @src {string} 打开的文件目录
* @hasobj {obj} hash对象
* @callback {fn} 回调函数
*/
function ismd(src,hasobj,callback){
//判断文件类型是否是md文件
let filedir = src;
//return new Promise((resolve,reject)=>{
if (/.md$/.test(filedir)) {
if(hasobj.fileText){
let hasHObjs = hasobj;
hashElement(filedir).then(res=>{
if(hasHObjs.fileText.indexOf(res.hash)==-1){
//执行写入
//同时更新缓存
fs.writeFileSync(hasHObjs.cachePath,
hasHObjs.fileText+'|'+res.hash
,'utf-8');
fileReadStar(filedir,(obj)=>{
callback(obj)
})
}
})
}else{
//如果没有hash 直接做下一部
fileReadStar(filedir,(obj)=>{
callback(obj)
})
}
//对md文件存储 hash
//文件读取
}
}
/**
* 检查文件是否存折
* @param {*} path
* @param {*} callback
*/
function checkIsexists (path,callback){
let pathFileName = path.replace(/[^a-zA-Z]/g,'');
let cacheName = './scripts/local'+pathFileName+'.cache';
fs.exists(cacheName, res=>{
if(!res){
fs.writeFile(cacheName,'','utf8',()=>{
callback(cacheName)
})
}else{
callback(cacheName)
}
})
}
/**
* 执行文件缓存
*/
let outhash = [];
function pushHash(obj){
//紧紧插入md文件hash
if(/\.md$/.test(obj.name)&&obj['hash']){
outhash.push(obj.hash);
}
if(obj['children']&&obj['children'].length>0){
obj['children'].map(res=>{
pushHash(res)
})
}
}
//hash 对比
/**
* 初始化检查是否有md文件 hash
* 如果没有 hash 创建一个 json文件并把 md文件 hash进去 用来做缓存
* 初始化获取所有md文件的 hash
* @param {*} path
*/
function comparehash(path,callback){
checkIsexists(path,(cachePath)=>{
//获取文件内容
let fileText = fs.readFileSync(cachePath,'utf-8');
//获取文件 hash
hashElement(path, {
folders: { exclude: ['.*', 'node_modules', 'test_coverage'] },
files: { include: ['*.md'],exclude:['*.js','*.vue','*.scss','__test__'] }
}).then(hash => {
if(fileText){
//如果有内容
callback({
fileText:fileText,
cachePath:cachePath
})
}else{
pushHash(hash)
fs.writeFileSync(cachePath,outhash.join('|'),'utf-8');
//如果没有内容
callback({
fileText:fileText,
cachePath:cachePath
})
}
})
.catch(error => {
return console.error('hashing failed:', error);
});
})
}
//文件监听
function filelisten(param){
let watcher = Chokidar.watch(param.entry,{
persistent: true,
usePolling: true,
})
let log = console.dir.bind(console);
let watchAction = function({event, eventPath}){
// 这里进行文件更改后的操作
fileReadStar(eventPath,(res)=>{
createdFile(param.output + res.mdName + '.vue', res.html, param.needCode)
})
}
watcher.on('change', path => watchAction({event: 'change', eventPath: path}))
.on('unlink', path => watchAction({event: 'remove', eventPath: path}));
}
/**
* 文件转md
* @param {obj}
* @entry {string} 文件读取路径
* @output {string} 文件输出路径
* @needCode {boolen} 是否需要二维码 默认 true
*/
function fileDisplay(param) {
//检查文件是否第一次初始化并获取hash
comparehash(param.entry,(hashMsgObj)=>{
// 获取目录下所有文件
readDirRecur(param.entry, function(filePath) {
//文件列表
fileList.map(item=>{
ismd(item,hashMsgObj,res=>{
//res md文件处理结果
createdFile(param.output + res.mdName + '.vue', res.html, param.needCode)
})
})
});
});
}
/**
* 输出的文件目录 是否存在
* @outPath {String} 输出的文件目录
*/
function ishasOutFile(outPath,callback){
fs.stat(outPath,(err,res)=>{
if(err){
fs.mkdir(outPath,err=>{
if(err){
console.log(err)
}else{
callback()
}
})
}else{
callback()
}
})
}
/**
*
* @param {entry} 文件读取路径
* @param {output} 文件输出路径
* @param {needCode} 是否需要二维码 默认 true
*/
function MdToHtml(commomOption) {
// 默认参数就这么多了,暂时没想到
let params = {
entry:'',
output:'',
needCode:true,
isbuild:true
}
params = Object.assign(params,commomOption);
//检查输出路径
ishasOutFile(params.output,()=>{
//获取所有的md 转html的结果
fileDisplay(params);
//文件监听
if(params.isbuild){
filelisten(params);
}
});
}
//用于后期的扩展暂时没想到
MdToHtml.prototype.apply = function (compiler) {
// console.log(compiler,'lls')
};
module.exports = MdToHtml;