var coffee = require('coffeescript'); var convert = require('convert-source-map'); var path = require('path'); var through = require('through2'); var filePattern = /\.((lit)?coffee|coffee\.md)$/; function isCoffee (file) { return filePattern.test(file); } function isLiterate (file) { return (/\.(litcoffee|coffee\.md)$/).test(file); } function ParseError(error, src, file) { /* Creates a ParseError from a CoffeeScript SyntaxError modeled after substack's syntax-error module */ SyntaxError.call(this); this.message = error.message; this.line = error.location.first_line + 1; // cs linenums are 0-indexed this.column = error.location.first_column + 1; // same with columns var markerLen = 2; if(error.location.first_line === error.location.last_line) { markerLen += error.location.last_column - error.location.first_column; } this.annotated = [ file + ':' + this.line, src.split('\n')[this.line - 1], Array(this.column).join(' ') + Array(markerLen).join('^'), 'ParseError: ' + this.message ].join('\n'); } ParseError.prototype = Object.create(SyntaxError.prototype); ParseError.prototype.toString = function () { return this.annotated; }; ParseError.prototype.inspect = function () { return this.annotated; }; function compile(filename, source, options, callback) { var compiled; try { compiled = coffee.compile(source, Object.assign({ inline: true, literate: isLiterate(filename) }, options)); } catch (e) { var error = e; if (e.location) { error = new ParseError(e, source, filename); } callback(error); return; } if (options.sourceMap) { var map = convert.fromJSON(compiled.v3SourceMap); var basename = path.basename(filename); map.setProperty('file', basename.replace(filePattern, '.js')); map.setProperty('sources', [basename]); map.setProperty('sourcesContent', [source]); callback(null, compiled.js + '\n' + map.toComment() + '\n'); } else { callback(null, compiled + '\n'); } } function coffeeify(filename, options) { if (!isCoffee(filename)) return through(); if (typeof options === 'undefined' || options === null) options = {}; var compileOptions = { sourceMap: (options._flags && options._flags.debug), bare: true, header: false }; for (var i = 0, keys = Object.keys(options); i < keys.length; i++) { var key = keys[i], option = options[key]; if (typeof option !== 'undefined' && option !== null) { if (option === 'false' || option === 'no' || option === '0') { option = false; } compileOptions[key] = option; } } var chunks = []; function transform(chunk, encoding, callback) { chunks.push(chunk); callback(); } function flush(callback) { var stream = this; var source = Buffer.concat(chunks).toString(); compile(filename, source, compileOptions, function(error, result) { if (!error) stream.push(result); callback(error); }); } return through(transform, flush); } coffeeify.compile = compile; coffeeify.isCoffee = isCoffee; coffeeify.isLiterate = isLiterate; module.exports = coffeeify;