Skip to content

Instantly share code, notes, and snippets.

@artisonian
Created August 5, 2014 21:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save artisonian/d3797f50c3f4fdfc88b1 to your computer and use it in GitHub Desktop.
Save artisonian/d3797f50c3f4fdfc88b1 to your computer and use it in GitHub Desktop.
A JavaScript equivalent to Literate CoffeeScript
'use strict';
var fs = require('fs');
var os = require('os');
var vm = require('vm');
var marked = require('marked');
var argv = require('minimist')(process.argv.slice(2));
var usage = function () {
var helpText = [
'Usage: erudite [options] /path/to/filename',
'',
' -h, --help show this help text',
' -o, --outfile write to the given file path'
].join('\n');
process.stdout.write(helpText + '\n\n');
};
var filename = argv._[0];
var outfile = argv.o || argv.outfile;
var help = argv.h || argv.help;
if (help || !fs.existsSync(filename)) {
usage();
process.exit(1);
}
var content = fs.readFileSync(filename, 'utf8');
var tokens = marked.lexer(content);
var SEPARATOR = os.EOL + os.EOL;
var codeBlocks = [];
var buf;
for (var i = 0; i < tokens.length; i++) {
if (tokens[i].type === 'code') {
codeBlocks.push(new Buffer(tokens[i].text));
codeBlocks.push(new Buffer(SEPARATOR));
}
}
codeBlocks.pop(); // remove trailing EOL adding from the while loop
buf = Buffer.concat(codeBlocks);
if (outfile) {
return write(outfile, buf);
}
run(buf.toString());
function write (output, script) {
fs.writeFileSync(output, script, 'utf8');
}
// Basically copied verbatim from CoffeeScript source...
function run (script) {
var ctx = vm.createContext(global);
ctx.__filename = filename;
ctx.__dirname = process.cwd();
ctx.global = ctx.root = ctx.GLOBAL = ctx;
var Module = require('module');
var _module = ctx.module = new Module('eval');
var _require = ctx.require = function (path) {
return Module._load(path, _module, true);
};
_module.filename = ctx.__filename;
Object.getOwnPropertyNames(require).forEach(function (r) {
if (['paths', 'caller', 'callee', 'arguments'].indexOf(r) === -1) {
_require[r] = require[r];
}
});
_require.paths = _module.paths = Module._nodeModulePaths(process.cwd());
_require.resolve = function (request) {
Module._resolveFilename(request, _module);
};
vm.runInContext(script, ctx);
}

Literate JavaScript

I've been inspired by Literate CoffeeScript to create a literate JavaScript parser. I like the idea of writing Markdown, but having executable JavaScript code blocks.

'use strict';
var fs = require('fs');
var stream = require('stream');

Let's read this file, and transform all characters to uppercase.

var readStream = fs.createReadStream(__filename);
var upcaseStream = new stream.Transform();
upcaseStream._transform = function (chunk, encoding, done) {
  this.push(chunk.toString().toUpperCase());
  done();
};
var stdoutStream = new stream.Writable();
stdoutStream._write = function (chunk, encoding, done) {
  console.log(chunk.toString());
  done();
};

Put it in a pipe, and smoke it.

readStream
  .pipe(upcaseStream)
  .pipe(stdoutStream);
{
"name": "erudite",
"version": "0.0.1",
"description": "A JavaScript equivalent to Literate CoffeeScript",
"main": "erudite.js",
"keywords": [
"literate",
"litjs",
"markdown"
],
"author": "Leroy Campbell <leroy@artisonian.com>",
"license": "MIT",
"dependencies": {
"marked": "^0.3.2",
"minimist": "^0.2.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment