UNPKG

ts-node

Version:

TypeScript execution environment and REPL for node

345 lines 15 kB
"use strict"; var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var path_1 = require('path'); var fs_1 = require('fs'); var os_1 = require('os'); var sourceMapSupport = require('source-map-support'); var extend = require('xtend'); var mkdirp = require('mkdirp'); var crypto = require('crypto'); var yn = require('yn'); var make_error_1 = require('make-error'); var tsconfig_1 = require('tsconfig'); var pkg = require('../package.json'); exports.VERSION = pkg.version; var DEFAULTS = { getFile: getFile, fileExists: fileExists, cache: yn(process.env['TS_NODE_CACHE']), cacheDirectory: process.env['TS_NODE_CACHE_DIRECTORY'], disableWarnings: yn(process.env['TS_NODE_DISABLE_WARNINGS']), compiler: process.env['TS_NODE_COMPILER'], compilerOptions: parse(process.env['TS_NODE_COMPILER_OPTIONS']), project: process.env['TS_NODE_PROJECT'], ignore: split(process.env['TS_NODE_IGNORE']), ignoreWarnings: split(process.env['TS_NODE_IGNORE_WARNINGS']), fast: yn(process.env['TS_NODE_FAST']) }; function split(value) { return value ? value.split(/ *, */g) : []; } exports.split = split; function parse(value) { return value ? JSON.parse(value) : undefined; } exports.parse = parse; function slash(value) { return value.replace(/\\/g, '/'); } exports.slash = slash; function register(options) { if (options === void 0) { options = {}; } var compiler = options.compiler || 'typescript'; var ignoreWarnings = (options.ignoreWarnings || DEFAULTS.ignoreWarnings).map(Number); var disableWarnings = !!(options.disableWarnings == null ? DEFAULTS.disableWarnings : options.disableWarnings); var getFile = options.getFile || DEFAULTS.getFile; var fileExists = options.fileExists || DEFAULTS.fileExists; var shouldCache = !!(options.cache == null ? DEFAULTS.cache : options.cache); var fast = !!(options.fast == null ? DEFAULTS.fast : options.fast); var project = options.project || DEFAULTS.project; var cacheDirectory = options.cacheDirectory || DEFAULTS.cacheDirectory || path_1.join(os_1.tmpdir(), 'ts-node'); var compilerOptions = extend(DEFAULTS.compilerOptions, options.compilerOptions); var result; var ignore = ((typeof options.ignore === 'boolean' ? (options.ignore === false ? [] : undefined) : (options.ignore || DEFAULTS.ignore)) || ['/node_modules/']).map(function (str) { return new RegExp(str); }); function load() { var cache = { contents: {}, versions: {}, sourceMaps: {} }; sourceMapSupport.install({ environment: 'node', retrieveSourceMap: function (fileName) { if (cache.sourceMaps[fileName]) { return { url: cache.sourceMaps[fileName], map: getFile(cache.sourceMaps[fileName]) }; } } }); var cwd = process.cwd(); var ts = require(compiler); var config = readConfig(compilerOptions, project, cwd, ts); var configDiagnostics = formatDiagnostics(config.errors, ignoreWarnings, disableWarnings, cwd, ts); var cachedir = path_1.join(path_1.resolve(cwd, cacheDirectory), getCompilerDigest({ version: ts.version, fast: fast, ignoreWarnings: ignoreWarnings, disableWarnings: disableWarnings, config: config, compiler: compiler })); mkdirp.sync(cachedir); if (configDiagnostics.length) { throw new TSError(configDiagnostics); } if (config.options.allowJs) { registerExtension('.js', ignore, service); } for (var _i = 0, _a = config.fileNames; _i < _a.length; _i++) { var fileName = _a[_i]; if (/\.d\.ts$/.test(fileName)) { cache.versions[fileName] = 1; } } function getExtension(fileName) { if (config.options.jsx === ts.JsxEmit.Preserve && path_1.extname(fileName) === '.tsx') { return '.jsx'; } return '.js'; } var getOutput = function (code, fileName) { var result = ts.transpileModule(code, { fileName: fileName, compilerOptions: config.options, reportDiagnostics: true }); var diagnosticList = result.diagnostics ? formatDiagnostics(result.diagnostics, ignoreWarnings, disableWarnings, cwd, ts) : []; if (diagnosticList.length) { throw new TSError(diagnosticList); } return [result.outputText, result.sourceMapText]; }; var compile = readThrough(cachedir, shouldCache, getFile, fileExists, cache, getOutput, getExtension); var getTypeInfo = function (fileName, position) { throw new TypeError("No type information available under \"--fast\" mode"); }; if (!fast) { var addVersion_1 = function (fileName) { if (!cache.versions.hasOwnProperty(fileName)) { cache.versions[fileName] = 1; } }; var addCache_1 = function (code, fileName) { cache.contents[fileName] = code; cache.versions[fileName] += 1; }; var serviceHost = { getScriptFileNames: function () { return Object.keys(cache.versions); }, getScriptVersion: function (fileName) { return String(cache.versions[fileName]); }, getScriptSnapshot: function (fileName) { if (!cache.contents.hasOwnProperty(fileName)) { if (!fileExists(fileName)) { return undefined; } cache.contents[fileName] = getFile(fileName); } return ts.ScriptSnapshot.fromString(cache.contents[fileName]); }, getDirectories: getDirectories, directoryExists: directoryExists, getNewLine: function () { return os_1.EOL; }, getCurrentDirectory: function () { return cwd; }, getCompilationSettings: function () { return config.options; }, getDefaultLibFileName: function (options) { return ts.getDefaultLibFilePath(config.options); } }; var service_1 = ts.createLanguageService(serviceHost); getOutput = function (code, fileName) { var output = service_1.getEmitOutput(fileName); var diagnostics = service_1.getCompilerOptionsDiagnostics() .concat(service_1.getSyntacticDiagnostics(fileName)) .concat(service_1.getSemanticDiagnostics(fileName)); var diagnosticList = formatDiagnostics(diagnostics, ignoreWarnings, disableWarnings, cwd, ts); if (output.emitSkipped) { diagnosticList.push(path_1.relative(cwd, fileName) + ": Emit skipped"); } if (diagnosticList.length) { throw new TSError(diagnosticList); } if (output.outputFiles.length === 0) { throw new TypeError('Unable to require `.d.ts` file.\n' + 'This is usually the result of a faulty configuration or import. ' + 'Make sure there is a `.js`, `.json` or another executable extension and ' + ("loader (attached before `ts-node`) available alongside `" + fileName + "`.")); } return [output.outputFiles[1].text, output.outputFiles[0].text]; }; compile = readThrough(cachedir, shouldCache, getFile, fileExists, cache, function (code, fileName) { addVersion_1(fileName); addCache_1(code, fileName); return getOutput(code, fileName); }, getExtension); getTypeInfo = function (fileName, position) { addVersion_1(fileName); var info = service_1.getQuickInfoAtPosition(fileName, position); var name = ts.displayPartsToString(info ? info.displayParts : []); var comment = ts.displayPartsToString(info ? info.documentation : []); return { name: name, comment: comment }; }; } return { cwd: cwd, compile: compile, getOutput: getOutput, getTypeInfo: getTypeInfo }; } function service() { return result || (result = load()); } registerExtension('.ts', ignore, service); registerExtension('.tsx', ignore, service); if (!options.lazy) { service(); } return service; } exports.register = register; function shouldIgnore(filename, service, ignore) { var relname = slash(filename); return ignore.some(function (x) { return x.test(relname); }); } function registerExtension(ext, ignore, service) { var old = require.extensions[ext] || require.extensions['.js']; require.extensions[ext] = function (m, filename) { if (shouldIgnore(filename, service, ignore)) { return old(m, filename); } var _compile = m._compile; m._compile = function (code, fileName) { return _compile.call(this, service().compile(code, fileName), fileName); }; return old(m, filename); }; } function readConfig(compilerOptions, project, cwd, ts) { var result = tsconfig_1.loadSync(cwd, typeof project === 'string' ? project : undefined); result.config.compilerOptions = extend({ target: 'es5', module: 'commonjs' }, result.config.compilerOptions, compilerOptions, { sourceMap: true, inlineSourceMap: false, inlineSources: true, declaration: false, noEmit: false, outDir: '$$ts-node$$' }); delete result.config.compilerOptions.out; delete result.config.compilerOptions.outFile; delete result.config.compilerOptions.declarationDir; var basePath = result.path ? path_1.dirname(result.path) : cwd; if (typeof ts.parseConfigFile === 'function') { return ts.parseConfigFile(result.config, ts.sys, basePath); } if (typeof ts.parseJsonConfigFileContent === 'function') { return ts.parseJsonConfigFileContent(result.config, ts.sys, basePath, null, result.path); } throw new TypeError('Could not find a compatible `parseConfigFile` function'); } function readThrough(cachedir, shouldCache, getFile, fileExists, cache, compile, getExtension) { if (shouldCache === false) { return function (code, fileName) { var cachePath = path_1.join(cachedir, getCacheName(code, fileName)); var extension = getExtension(fileName); var sourceMapPath = "" + cachePath + extension + ".map"; var out = compile(code, fileName); cache.sourceMaps[fileName] = sourceMapPath; var output = updateOutput(out[0], fileName, extension, sourceMapPath); var sourceMap = updateSourceMap(out[1], fileName); fs_1.writeFileSync(sourceMapPath, sourceMap); return output; }; } return function (code, fileName) { var cachePath = path_1.join(cachedir, getCacheName(code, fileName)); var extension = getExtension(fileName); var outputPath = "" + cachePath + extension; var sourceMapPath = outputPath + ".map"; cache.sourceMaps[fileName] = sourceMapPath; if (fileExists(outputPath)) { return getFile(outputPath); } var out = compile(code, fileName); var output = updateOutput(out[0], fileName, extension, sourceMapPath); var sourceMap = updateSourceMap(out[1], fileName); fs_1.writeFileSync(outputPath, output); fs_1.writeFileSync(sourceMapPath, sourceMap); return output; }; } function updateOutput(outputText, fileName, extension, sourceMapPath) { var ext = path_1.extname(fileName); var originalPath = path_1.basename(fileName).slice(0, -ext.length) + (extension + ".map"); return outputText.slice(0, -originalPath.length) + sourceMapPath.replace(/\\/g, '/'); } function updateSourceMap(sourceMapText, fileName) { var sourceMap = JSON.parse(sourceMapText); sourceMap.file = fileName; sourceMap.sources = [fileName]; delete sourceMap.sourceRoot; return JSON.stringify(sourceMap); } function getCacheName(sourceCode, fileName) { return crypto.createHash('sha1') .update(path_1.extname(fileName), 'utf8') .update('\0', 'utf8') .update(sourceCode, 'utf8') .digest('hex'); } function getCompilerDigest(opts) { return crypto.createHash('sha1').update(JSON.stringify(opts), 'utf8').digest('hex'); } function fileExists(fileName) { try { var stats = fs_1.statSync(fileName); return stats.isFile() || stats.isFIFO(); } catch (err) { return false; } } exports.fileExists = fileExists; function getDirectories(path) { return fs_1.readdirSync(path).filter(function (name) { return directoryExists(path_1.join(path, name)); }); } exports.getDirectories = getDirectories; function directoryExists(path) { try { return fs_1.statSync(path).isDirectory(); } catch (err) { return false; } } exports.directoryExists = directoryExists; function getFile(fileName) { return fs_1.readFileSync(fileName, 'utf8'); } exports.getFile = getFile; function formatDiagnostics(diagnostics, ignore, disable, cwd, ts) { if (disable) { return []; } return diagnostics .filter(function (diagnostic) { return ignore.indexOf(diagnostic.code) === -1; }) .map(function (diagnostic) { return formatDiagnostic(diagnostic, cwd, ts); }); } function formatDiagnostic(diagnostic, cwd, ts) { var message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); if (diagnostic.file) { var path = path_1.relative(cwd, diagnostic.file.fileName); var _a = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start), line = _a.line, character = _a.character; return path + " (" + (line + 1) + "," + (character + 1) + "): " + message + " (" + diagnostic.code + ")"; } return message + " (" + diagnostic.code + ")"; } var TSError = (function (_super) { __extends(TSError, _super); function TSError(diagnostics) { _super.call(this, "\u2A2F Unable to compile TypeScript\n" + diagnostics.join('\n')); this.name = 'TSError'; this.diagnostics = diagnostics; } return TSError; }(make_error_1.BaseError)); exports.TSError = TSError; //# sourceMappingURL=index.js.map