var moduleDeps = require("./module-deps"); var fs = require("fs"); var send = require("send"); exports.transform = function(code, options) { if (/^"disable compress"/.test(code)) return code; if (options.amd && moduleDeps.isCJS(code)) { code = "define(function(require, exports, module) {" + code + "\n})"; } if (options.mode == "ts" || options.mode == "es5") { var ts = require("typescript"); return ts.transpileModule(code, { compilerOptions: { downlevelIteration: true, suppressExcessPropertyErrors: true, removeComments: true, newLine: "lf", module: ts.ModuleKind.CommonJS, sourceMap: !!options.srcPath, inlineSourceMap: true }, fileName: options.srcPath }).outputText; } return code; }; var cache = Object.create(null); exports.sendFile = function(req, res, next) { var path = req.params.path; var transform = req.params.transform; var filePath = moduleDeps.resolveModulePath(path, req.pathConfig.pathMap); if (!/\.(js|ts)$/.test(filePath) || /(browserified|\.min|test\d)\.js$/.test(filePath)) { return send(req, filePath.substr(req.pathConfig.root.length)) .root(req.pathConfig.root) .on('error', next) .pipe(res); } function resolvePath(callback) { fs.stat(filePath, function(err, stat) { if (err && err.code == "ENOENT") { var tsPath = filePath.replace(/\.js$/, ".ts"); if (tsPath != filePath) { return fs.stat(tsPath, function(err, stat) { callback(err, stat, tsPath); }); } } callback(err, stat); }); } resolvePath(function(err, stat, srcPath) { if (err) return next(err); var mtime = stat.mtime.valueOf(); var etag = 'W/"' + stat.size.toString(16) + "-" + mtime.toString(16) + '"'; var noneMatch = req.headers && req.headers['if-none-match']; if (noneMatch && noneMatch == etag) { res.statusCode = 304; res.end(); return; } var key = transform + "|" + path; if (cache[key] && cache[key].etag == etag) return sendResponse(cache[key].value); res.setHeader("ETag", etag); cache[key] = null; fs.readFile(srcPath || filePath, "utf8", function(err, value) { if (err) return next(err); var t = Date.now(); try { value = exports.transform(value, { path: filePath, mode: srcPath ? "ts" : transform, amd: true, srcPath: srcPath ? path.replace(/\.js/, ".ts") : "" }); } catch (e) { return next(e); } cache[key] = { value: value, etag: etag }; var delta = Date.now() - t; res.setHeader('Server-Timing', 'transform=' + delta); sendResponse(value); }); function sendResponse(value) { res.setHeader('Content-Type', 'application/javascript'); res.setHeader('Cache-Control', 'public, max-age=0'); res.setHeader('Last-Modified', stat.mtime.toUTCString()); res.end(value); } }); };