readme-ssi
Version:
Update your markdown readme's ToC and snippets without seperate template or docs files, according to directives that remind of Server Side Includes. [npm search keywords: code examples, documentation, table of contents]
131 lines (108 loc) • 4.09 kB
JavaScript
/*jslint indent: 2, maxlen: 80, continue: false, unparam: false, node: true */
/* -*- tab-width: 2 -*- */
;
var EX = module.exports, coreCmds = require('./core_cmds.js'),
codeQuot = coreCmds.markDown.codeBlockQuotes,
cmdVerbatim = require('./cmd_verbatim.js'),
Promise = require('bluebird'),
kisi = require('./kitchen_sink.js');
function ifFun(x, d) { return ((typeof x) === 'function' ? x : d); }
function opporSplit(x, s) { return (x && ifFun(x.split) ? x.split(s) : x); }
function trimRight(s) { return s.replace(/\s+$/, ''); }
EX.cmd = {};
EX.transforms = {
mjsUsageDemo1802: require('./transforms/mjsUsageDemo1802'),
trimR: function (lines) { return lines.map(trimRight); },
};
EX.cmd.include = function (text, tag, buf) {
if (text) { throw tag.err('unexpected input text'); }
var renderer = this, endMark, opts;
opts = tag.popAttr(['code', 'file', 'start', 'stop', 'maxln',
'indent', 'outdent', 'cut-head', 'cut-tail', 'transform']);
if (cmdVerbatim.checkEat(renderer, buf)) { endMark = true; }
if (!endMark) {
endMark = (opts.code === undefined ? undefined : codeQuot);
tag.try(coreCmds.replaceUntilMark, [buf, endMark]);
if (opts.code !== undefined) {
opts.code = (opts.code || 'text');
if (buf.peekLine() === codeQuot + '\n') { buf.eat(); }
}
}
if (opts.file) {
return function ssiIncludeFileFetcher(deliver) {
renderer.readFileRel(opts.file,
EX.includeGeneric.bind(renderer, opts, tag, deliver));
};
}
throw tag.err('No source file specified');
};
EX.includeGeneric = function (opts, tag, deliver, readErr, text) {
if (readErr) { return deliver(readErr); }
var maxLnCnt = +opts.maxln;
text = String(text);
if (text[0] === '\uFEFF') { text = text.slice(1); }
text = text.replace(/\s+$/, '').split(/[ \t\r]*\n/);
if (opts.start !== undefined) {
text.start = text.indexOf(opts.start);
if (text.start < 0) {
return deliver(tag.err('Cannot find start mark: ' + opts.start));
}
text = text.slice(text.start + 1);
}
if (opts.stop !== undefined) {
text.stop = text.indexOf(opts.stop);
if (text.stop < 0) {
return deliver(tag.err('Cannot find stop mark: ' + opts.stop));
}
text = text.slice(0, text.stop);
}
if (maxLnCnt && (maxLnCnt < text.length)) { text = text.slice(0, maxLnCnt); }
if (opts.outdent || opts.indent || opts['cut-head'] || opts['cut-tail']) {
text = text.map(EX.redentOneLine.bind(null,
opts.outdent,
opts['cut-head'],
opts['cut-tail'],
(opts.indent || '')));
}
if (text.err) { return deliver(text.err); }
Promise.try(function applyTransforms() {
return EX.applyTransforms(opts.transform, text, {
opts: opts,
tag: tag,
});
}).then(function transformed(lines) {
var verbatim = lines.length, before = [verbatim], after = [];
if (opts.code !== undefined) {
before.push(codeQuot + (opts.code || 'text'));
after.push(codeQuot);
verbatim += 2;
}
before[0] = '<!--#verbatim lncnt="' + verbatim + '" -->';
deliver(null, before.concat(lines, after, '').join('\n'));
}).then(null, deliver);
};
EX.applyTransforms = function (trNames, origLines, meta) {
if (!trNames) { return origLines; }
function applyOne(lines, trName) {
if (!trName) { return lines; }
return Promise.try(function () {
var how = EX.transforms[trName];
if (!ifFun(how)) { throw new Error('unsupported transform: ' + trName); }
return how(lines, meta);
}).then(function (trLn) {
trLn = opporSplit(trLn, /\n/);
if (!trLn) {
throw new Error('bad data after transform: ' + trName + ': ' + trLn);
}
return trLn;
});
}
return Promise.reduce(opporSplit(trNames, /\s+/), applyOne, origLines);
};
EX.redentOneLine = function (outdent, cutHead, cutTail, indent, ln) {
if (outdent && ln.startsWith(outdent)) { ln = ln.slice(outdent.length); }
ln = kisi.multiMarkSplit(ln, cutHead, -1);
ln = kisi.multiMarkSplit(ln, cutTail, 0);
return (indent + ln);
};
/*scroll*/