UNPKG

markdown-posts-to-json

Version:

将 Markdown 格式的文章(.md)后缀,提取元数据,并使用 Markdown-it 将文章内容转化为 Html,最后输出为 json 文件。

138 lines (134 loc) 4.79 kB
const path = require('path') const glob = require("glob") const rf = require("fs") const yaml = require('js-yaml') // 合并选项对象 function mp2j(options) { mp2j.options = Object.assign({ postPath: './', outPath: 'posts/', includeSubPath: false, indexName: 'index', mergeIndex2dir: true, defaultNode: 'default', subNode: 'posts' }, options); } // 目录树分析函数 function rTree (pathArray, now, treeObject, metas){ let key = pathArray[now]; let subNode = mp2j.options.subNode; if( treeObject[subNode] == null ){ treeObject[subNode] = {} } if((now+1) === pathArray.length){ if(mp2j.options.mergeIndex2dir && key === 'index'){ Object.assign(treeObject, metas); }else{ treeObject[subNode][key] = metas } }else{ if(treeObject[subNode][key] == null){ treeObject[subNode][key] = {} } treeObject[subNode][key] = rTree (pathArray, now+1, treeObject[subNode][key], metas) } return treeObject; } // 功能函数 mp2j.prototype.apply = function(compiler) { compiler.plugin('emit', function(compilation, callback) { // 初始化搜索字符串,主要是判断是否包含子目录 let pattern = (mp2j.options.includeSubPath ? '**/' : '') + '*.md'; // 遍历查找所有符合的文件 let posts = glob.sync(pattern, { cwd: mp2j.options.postPath, nodir: true }); // 初始化输出路径 let outPath = mp2j.options.outPath.substr(mp2j.options.outPath.length-1) !== '/' ? mp2j.options.outPath+'/' : mp2j.options.outPath; // 遍历处理所有文件 let postCount = Object.keys(posts).length; let processed = 0; let tree = {}; for(let post of posts){ // 获取文件绝对地址 let postPath = path.resolve(mp2j.options.postPath, post); // 读取文件并处理 rf.readFile(postPath, "utf-8", function(err, postData){ if(err){ console.log('Read File '+post+' Error: '+err); }else{ let postOutPath = outPath+post.replace(/\.md$/, '.json'); // 打散文章数据 let postArray = postData.split(/(?:-|=){3,}[ \t]*(?:\n|\r)/); let metas = ''; let metaIndex = -1; if(postArray.length > 1){ metaIndex = (postArray[0].replace(/\s*/g,'') === '') ? 1 // 第一组没有内容 : 0; try { metas = yaml.safeLoad(postArray[metaIndex]); } catch (e) { metaIndex = -1; console.log('YAML to JS maybe has an Error at '+post); } } let postContent = ''; if(typeof(metas) !== 'object' || metaIndex === -1){ // 没有文章元数据 metas = { path: postOutPath }; postContent = postData; }else{ Object.assign(metas, { path: postOutPath } ); if(metaIndex === 0){ postContent = postData.replace(/^[\s\S]*?(-|=){3,}[ \t]*(?:\n|\r)/, '') } else { postContent = postData.replace(/^([\s\S]*?(-|=){3,}[ \t]*(?:\n|\r)){2}/, '') } } let postJson = JSON.stringify( Object.assign({}, metas, { content: mp2j.options.md.render(postContent) }) ); compilation.assets[ postOutPath ] = { source: function() { return postJson; }, size: function() { return postJson.length; } }; // 将当前文件加入文件树 if(metas.parent === "" || metas.parent === undefined){ post = (post.substr(0, 1) === "/" ? mp2j.options.defaultNode.replace(/\/$/, "") : mp2j.options.defaultNode.replace(/\/$/, "") + "/") + post }else{ post = metas.parent.replace(/\/$/, "")+"/"+post.replace(/^.*\//, "") } let pathArray = post.replace(/\.md$/,'').split(/\/|\\/g); tree = rTree ( pathArray, 0, tree, metas) } // 统计已处理文章数量 processed++; // 回调结束插件工作 if(processed >= postCount){ tree = tree[mp2j.options.subNode]; postsIndex = JSON.stringify(tree); compilation.assets[ outPath+mp2j.options.indexName+'.json' ] = { source: function() { return postsIndex; }, size: function() { return postsIndex.length; } }; callback(); } }) } }); }; module.exports = mp2j;