我试图在Node中编写内容manglement程序。多年来我一直是一个旧的Ruby / Perl / Shell手,我似乎无法在这些语言中使用简单的代码,在Node中看起来类似,呃,简单。
任务:查找所有*.md
个文件,阅读它们(按ls
顺序),转换它们,并用标题注释和页脚注释括起来。这些文件按顺序有一段Markdown,当组装和转换时,它们是一个合理的HTML文档。这是一个shell实现:
echo '<!-- Generate at:' $(date) ' -->' $(ls *.md |xargs cat|markdown)'<!-- Copyright Mumble-demo Inc. -->'
生成所需的HTML:
<!-- Generate at: Tue Jun 6 08:25:59 EDT 2017 --> <h1>This is a Markdown File</h1> <h2>Heading 1</h2> <p>Inside of markdown we can create many interesting items</p> <ul> <li>such</li> <li>as</li> <li>lists</li> </ul><!-- Copyright Mumble-demo Inc. -->
Ruby同样合理......
#!/usr/bin/env ruby
require 'kramdown'
HEADER = "<!-- Generated at #{Time.now} -->\n"
FOOTER = "\n<!-- Copyright Mumble-demo Inc. -->"
OUTPUT = File.open("./output", "w")
results = Dir.glob("*.md").map { |f| File.open(f).readlines.join() }.reduce(:+)
OUTPUT.print(HEADER, Kramdown::Document.new(results).to_html, FOOTER)
但我无法弄清楚如何以一种感觉正确的方式在Node中做到这一点(™)
感觉错误的方式(™)是使用同步接口:
const fs = require("fs")
const marked = require("marked")
const HEADER = `<!-- Generated at ${new Date()} -->\n`
const FOOTER = `\n<!-- Copyright Mumble-demo Inc. -->`
fs.readdir(".", (err, files) => {
if (err) throw err;
let markdownFiles = files.filter((f) => f.endsWith(".md"))
let content = markdownFiles.reduce((memo, fileName) => {
return memo + fs.readFileSync(fileName, 'utf8')
}, "")
let contentString = [HEADER, marked(content), FOOTER].reduce((m, i) => m + i, "")
fs.writeFileSync("derp", contentString);
console.log(contentString);
})
一种感觉良好但我无法工作的方式(™)是:
好消息是 - 这种方法有效,直到将标题注释放在顶部和底部。它们存在于代码中,而不是存在于文件系统中,因此我无法添加&#34;它们作为另一个文件流,无法转换,进入输出流。大多数方法最终产生:页眉,页脚,流数据
显然,pipe()
- 工作是异步工作的,并且在读取+转换工作完成之前页脚打印会触发。我已经尝试了最终无效的可怕(和破碎)Promise
链条。
另一种方法是将页眉和页脚转换为流(看起来很奇怪......)并将它们流入输出流(看起来非常奇怪)。
我已经让几个经验丰富的开发人员难以理解......当然我们在这里找不到一些常见的习语,或者实际上这很难在Node中完成这个简单的任务?
答案 0 :(得分:1)
思想:
util.promisify()
。答案 1 :(得分:0)
你可以运行它&#34;一种感觉正确的方式&#34;通过同步执行器nsynjs。您的代码可能会与此工作示例类似地转换:
MD-cat.js:
var nsynjs = require('nsynjs');
var nsynFs = require('../wrappers/nodeFs'); // part of nsynjs package, needs to be added manually
var synchronousCode = function(nsynFs) {
var HEADER = "<!-- Generated at "+new Date()+" -->\n";
var FOOTER = "\n<!-- Copyright Mumble-demo Inc. -->";
var files = nsynFs.readdir(nsynjsCtx, ".").data;
var content="";
for(var i=0; i<files.length; i++) {
var file = files[i];
if(file.endsWith('.md'))
content+=nsynFs.readFile(nsynjsCtx,file,"utf8").data;
}
nsynFs.writeFile(nsynjsCtx,"derp",HEADER+content+FOOTER);
};
nsynjs.run(synchronousCode, {},nsynFs, function () {
console.log('synchronousCode done')
});
即使它看起来是同步的,它也不会使用任何同步函数,因此它不会阻止节点的事件循环。
答案 2 :(得分:0)
尝试Gulp,这是当今最惯用的方式。
如果不能或不想要,请使用Promise链,它们就像是外壳管道。
#!/usr/bin/env node
'use strict';
const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));
const path = require('path');
const marked = require('marked');
const HEADER = `<!-- Generated at ${(new Date()).toISOString()} -->`;
const FOOTER = '<!-- Copyright Mumble-demo Inc. -->';
fs.readdirAsync(process.cwd())
.map((fileName) => Promise.all([fileName, fs.statAsync(fileName)]))
.filter(([fileName, stat]) => stat.isFile() && path.extname(fileName) === '.md')
.call('sort', ([a], [b]) => a.localeCompare(b, 'en-US'))
.map(([mdFileName]) => fs.readFileAsync(mdFileName, 'utf8'))
.then((mdFiles) => {
let out = [HEADER, marked(mdFiles.join('\n')), FOOTER].join('').replace(/\n/g, '');
console.log(out);
return fs.writeFileAsync('out.html', out);
})
.catch((err) => {
console.error(err);
process.exit(1);
});
思想: