mdToVue.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. const fs = require('fs');
  2. var path = require('path');
  3. let { hashElement } = require('folder-hash');
  4. //marked转换工具
  5. let marked = require('marked');
  6. if (!marked) {
  7. console.log('you need npm i marked -D!');
  8. }
  9. // 基本配置文件信息
  10. let {version} = require("../package.json");
  11. //vue js脚本
  12. //获取所有文件列表
  13. let fileList = [];
  14. // maked文件配置
  15. var rendererMd = new marked.Renderer();
  16. //maked文件规则
  17. rendererMd.code = function (code, infostring, escaped) {
  18. var lang = (infostring || '').match(/\S*/)[0];
  19. if (this.options.highlight) {
  20. var out = this.options.highlight(code, lang);
  21. if (out != null && out !== code) {
  22. escaped = true;
  23. code = out;
  24. }
  25. }
  26. if (!lang) {
  27. return '<pre><code>'
  28. + (escaped ? code : escape(code, true))
  29. + '</code></pre>';
  30. }
  31. if (lang === 'html') {
  32. code = code.replace(/@latest/g, '@' + version)
  33. }
  34. return '<pre class="prettyprint"><span class="lang">' + lang + '</span><code class="'
  35. + this.options.langPrefix
  36. + escape(lang, true)
  37. + '">'
  38. + (escaped ? code : escape(code, true))
  39. + '</code><i class="copy" copy="copy" data-clipboard-action="copy" data-clipboard-target="code" title="复制代码"></i><i toast="toast" title="全屏"></i></pre>\n';
  40. };
  41. marked.setOptions({
  42. renderer: rendererMd,
  43. highlight: function (code) {
  44. return require('highlight.js').highlightAuto(code).value;
  45. },
  46. tables: true
  47. }, res => {
  48. })
  49. /**
  50. * 是否需要单独处理头部信息
  51. * @param {text} sorce 替换 头部信息
  52. */
  53. function insert(sorce) {
  54. var insert = sorce.indexOf('</h1>');
  55. if (insert > -1) {
  56. return sorce.substring(0, insert) + '<i class="qrcode"><a :href="demourl"><span>请使用手机扫码体验</span><img :src="codeurl" alt=""></a></i>' + sorce.substring(insert, sorce.length);
  57. } else {
  58. return sorce
  59. }
  60. }
  61. ///创建一个空文件
  62. /**
  63. * 修复中
  64. * @param {string} output 输出路径
  65. * @param {string} sorce 文件源
  66. * @param {boole} ishasCode 是否需要二维码
  67. */
  68. function createdFile(output, sorce, ishasCode) {
  69. var pathSrc = output;
  70. if (ishasCode) {
  71. var res = insert(sorce);
  72. } else {
  73. var res = sorce;
  74. }
  75. var bufs = `<template><div @click="dsCode">
  76. <div v-if="content" class="layer">
  77. <pre><span class="close-box" @click="closelayer"></span><div v-html="content"></div></pre>
  78. </div>`+ res + `</div></template><script>import root from '../root.js';
  79. export default {
  80. mixins:[root]
  81. }</script>`;
  82. fs.writeFile(pathSrc,bufs,'utf8',(err)=>{
  83. })
  84. }
  85. /**
  86. * 目录读取,找到跟文件
  87. * @fileSrc {string} 打开文件路径
  88. * @callback {fn} 结束后回调函数
  89. */
  90. function readDirRecur(fileSrc, callback) {
  91. fs.readdir(fileSrc, function(err, files) {
  92. var count = 0
  93. var checkEnd = function() {
  94. ++count == files.length && callback()
  95. }
  96. files.forEach(function(file) {
  97. var fullPath = fileSrc + '/' + file;
  98. fs.stat(fullPath, function(err, stats) {
  99. if (stats.isDirectory()) {
  100. return readDirRecur(fullPath, checkEnd);
  101. } else {
  102. /*not use ignore files*/
  103. if(file[0] == '.') {
  104. } else {
  105. fileList.push(fullPath)
  106. }
  107. checkEnd()
  108. }
  109. })
  110. })
  111. //为空时直接回调
  112. files.length === 0 && callback()
  113. })
  114. }
  115. function fileReadStar(filedir,callback){
  116. fs.readFile(filedir, 'utf-8', (err, data) => {
  117. let html = marked(data);
  118. let mdName = "";
  119. let opensName = filedir.replace(/(^.*\/|.md)/g,"");
  120. //如果是doc文件以前缀 为
  121. if (opensName === 'doc') {
  122. mdName = filedir.replace(/(^.*packages\/|\/doc\.md)/g,'');
  123. } else {
  124. //如果不是doc命名的文件
  125. mdName = opensName;
  126. }
  127. callback({
  128. mdName:mdName,
  129. html:html
  130. })
  131. });
  132. }
  133. /**
  134. * 判断是否位md文件 并进行操作
  135. * @src {string} 打开的文件目录
  136. */
  137. function ismd(src,hasobj,callback){
  138. //判断文件类型是否是md文件
  139. let filedir = src;
  140. //return new Promise((resolve,reject)=>{
  141. if (/.md$/.test(filedir)) {
  142. if(hasobj.fileText){
  143. let hasHObjs = hasobj;
  144. hashElement(filedir).then(res=>{
  145. if(hasHObjs.fileText.indexOf(res.hash)==-1){
  146. //执行写入
  147. //同时更新缓存
  148. fs.writeFileSync(hasHObjs.cachePath,
  149. hasHObjs.fileText+'|'+res.hash
  150. ,'utf-8');
  151. fileReadStar(filedir,(obj)=>{
  152. callback(obj)
  153. })
  154. }
  155. })
  156. }else{
  157. //如果没有hash 直接做下一部
  158. fileReadStar(filedir,(obj)=>{
  159. callback(obj)
  160. })
  161. }
  162. //对md文件存储 hash
  163. //文件读取
  164. }
  165. }
  166. /**
  167. * 检查文件是否存折
  168. * @param {*} path
  169. * @param {*} callback
  170. */
  171. function checkIsexists (path,callback){
  172. let pathFileName = path.replace(/[^a-zA-Z]/g,'');
  173. let cacheName = './'+pathFileName+'hashCache.text';
  174. fs.exists(cacheName, res=>{
  175. console.log(res)
  176. if(!res){
  177. fs.writeFile(cacheName,'','utf8',()=>{
  178. callback(cacheName)
  179. })
  180. }else{
  181. callback(cacheName)
  182. }
  183. })
  184. }
  185. let outhash = [];
  186. function pushHash(obj){
  187. //紧紧插入md文件hash
  188. if(/\.md$/.test(obj.name)&&obj['hash']){
  189. outhash.push(obj.hash);
  190. }
  191. if(obj['children']&&obj['children'].length>0){
  192. obj['children'].map(res=>{
  193. pushHash(res)
  194. })
  195. }
  196. }
  197. //hash 对比
  198. /**
  199. * 初始化检查是否有md文件 hash
  200. * 如果没有 hash 创建一个 json文件并把 md文件 hash进去 用来做缓存
  201. * 初始化获取所有md文件的 hash
  202. * @param {*} path
  203. */
  204. function comparehash(path,callback){
  205. checkIsexists(path,(cachePath)=>{
  206. //获取文件内容
  207. let fileText = fs.readFileSync(cachePath,'utf-8');
  208. //获取文件 hash
  209. hashElement(path, {
  210. folders: { exclude: ['.*', 'node_modules', 'test_coverage'] },
  211. files: { include: ['*.md'],exclude:['*.js','*.vue','*.scss','__test__'] }
  212. }).then(hash => {
  213. if(fileText){
  214. //如果有内容
  215. callback({
  216. fileText:fileText,
  217. cachePath:cachePath
  218. })
  219. }else{
  220. pushHash(hash)
  221. console.log(outhash)
  222. fs.writeFileSync(cachePath,outhash.join('|'),'utf-8');
  223. //如果没有内容
  224. callback({
  225. fileText:fileText,
  226. cachePath:cachePath
  227. })
  228. }
  229. })
  230. .catch(error => {
  231. return console.error('hashing failed:', error);
  232. });
  233. })
  234. }
  235. //文件监听
  236. function filelisten(){
  237. let fsWatcher = fs.watchFile(filedir, {
  238. persistent: true,
  239. persistent: 1000
  240. }, (err, data) => {
  241. // console.log(err,data,filedir);
  242. fs.readFile(filedir, 'utf-8', (err, data) => {
  243. let html = marked(data);
  244. let filedirarry = filedir.split('/');
  245. let fileNames = filedirarry[filedirarry.length - 2];
  246. createdFile(outPath + fileNames + '.vue', html, nohead)
  247. });
  248. });
  249. }
  250. /**
  251. * 文件转md
  252. * @param {obj}
  253. * @entry {string} 文件读取路径
  254. * @output {string} 文件输出路径
  255. * @needCode {boolen} 是否需要二维码 默认 true
  256. */
  257. function fileDisplay(param) {
  258. //检查文件是否第一次初始化并获取hash
  259. comparehash(param.entry,(hashMsgObj)=>{
  260. // 获取文件
  261. readDirRecur(param.entry, function(filePath) {
  262. //文件列表
  263. fileList.map(item=>{
  264. ismd(item,hashMsgObj,res=>{
  265. //res md文件处理结果
  266. createdFile(param.output + res.mdName + '.vue', res.html, param.needCode)
  267. })
  268. })
  269. });
  270. });
  271. }
  272. //md转 其他格式类型
  273. /**
  274. *
  275. * @outPath {String} 输出的文件目录
  276. */
  277. function ishasOutFile(outPath,callback){
  278. fs.stat(outPath,(err,res)=>{
  279. if(err){
  280. fs.mkdir(outPath,erro=>{
  281. if(erro){
  282. }else{
  283. callback()
  284. }
  285. })
  286. }else{
  287. callback()
  288. }
  289. })
  290. }
  291. /**
  292. *
  293. * @param {entry} 文件读取路径
  294. * @param {output} 文件输出路径
  295. * @param {needCode} 是否需要二维码 默认 true
  296. */
  297. function MdToHtml(commomOption) {
  298. // 默认参数就这么多了,暂时没想到
  299. let params = {
  300. entry:'',
  301. output:'',
  302. needCode:true
  303. }
  304. params = Object.assign(params,commomOption);
  305. //检查输出路径
  306. ishasOutFile(params.output,()=>{
  307. //获取所有的md 转html的结果
  308. fileDisplay(params);
  309. });
  310. }
  311. //用于后期的扩展暂时没想到
  312. MdToHtml.prototype.apply = function (compiler) {
  313. // console.log(compiler,'lls')
  314. };
  315. module.exports = MdToHtml;