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]
90 lines (68 loc) • 2.26 kB
JavaScript
/*jslint indent: 2, maxlen: 80, continue: false, unparam: false, node: true */
/* -*- tab-width: 2 -*- */
;
var EX, Promise = require('bluebird'),
unresolve = require('unresolve');
function ifFun(x, d) { return ((typeof x) === 'function' ? x : d); }
EX = function (lines, meta) {
if (!meta.opts.code) { meta.opts.code = 'javascript'; }
var state = { output: [], copy: false, meta: meta,
srcFn: String(meta.opts.file || ''),
};
return Promise.mapSeries(lines, function (ln, idx) {
state.input = ln;
state.lnidx = idx;
return EX.eatLine(state);
}).then(function () { return state.output; });
};
EX.eatPrefix = function (st, rx) {
var m = rx.exec(st.input);
if (!m) { return false; }
st.input = st.input.slice(m[0].length);
return m;
};
EX.eatLine = function (st) {
var ctrl = EX.eatPrefix(st, /^\s*\/{2} ¦mjsUsageDemo¦\s*/);
if (!ctrl) {
if (st.copy) { st.output.push(st.input); }
return;
}
function nextCtrl() {
if (!st.input) { return; }
ctrl = EX.eatPrefix(st, /^(\w+|\W)\s*/);
if (!ctrl) { throw new Error('w00t? neither word nor non-word char?'); }
ctrl = (ctrl[1] || ctrl[2]);
var how = EX.ctrl[ctrl];
if (!ifFun(how)) { throw new Error('Unsupported directive: ' + ctrl); }
return Promise.try(function () { return how(st); }).then(nextCtrl);
}
return nextCtrl();
};
EX.ctrl = {
'+': function (st) { st.copy = true; },
'-': function (st) { st.copy = false; },
};
EX.ctrl.importPkgName = function (st) {
var output = st.output, lastLnIdx = output.length - 1,
origLn = output[lastLnIdx],
from = origLn.split(/( from )('|")((?:\.+(?:\/|(?='|")))*)/),
before, file, after, upPath;
if (from.length !== 5) {
throw new Error('Expected exactly one "from" in ' + origLn);
}
upPath = from[from.length - 2];
if (!upPath) {
throw new Error('Expected a relative path but found: ' + after);
}
before = from.slice(0, -2).join('');
after = from[from.length - 1].split(/(?='|")/);
file = upPath + after[0];
after = after.slice(1).join('');
return unresolve(file, {
srcFile: st.srcFn,
unmain: true,
}).then(function (id) {
output[lastLnIdx] = before + id + after;
});
};
module.exports = EX;