UNPKG

5.84 kBJavaScriptView Raw
1/// <reference path="typings/typescript/typescript.d.ts"/>
2/// <reference path="typings/chalk/chalk.d.ts"/>
3/// <reference path="typings/node/node.d.ts"/>
4/// <reference path="typings/sanitize-filename/sanitize-filename.d.ts"/>
5var chalk = require("chalk");
6var fs = require("fs");
7var os = require("os");
8var path = require("path");
9var sanitize = require("sanitize-filename");
10var typescript = require("typescript");
11/**
12 * Module Configuration Options
13 */
14var Config;
15(function (Config) {
16 Config[Config["EMIT_ERROR"] = 0] = "EMIT_ERROR";
17 Config[Config["USE_CACHE"] = 1] = "USE_CACHE";
18 Config[Config["COMPILER_OPTIONS"] = 2] = "COMPILER_OPTIONS";
19})(Config || (Config = {}));
20/**
21 * Requires a TypeScript file
22 * @param {Module} module The node module
23 * @param {string} filename The module filename
24 */
25function req(module, filename) {
26 var options = compilerOptions();
27 var out = dest(filename, options);
28 if (!useCache() || isModified(filename, out)) {
29 compile(filename, options);
30 }
31 module._compile(fs.readFileSync(out, "utf8"), filename);
32}
33require.extensions[".ts"] = req;
34/**
35 * Checks the environment for whether or not we should emit an error. Defaults
36 * to true.
37 * @return {boolean} Whether or not to emit TypeScript errors
38 */
39function emitError() {
40 return env(0 /* EMIT_ERROR */, true, toBoolean);
41}
42/**
43 * Checks the environment for whether or not we should use a build cache.
44 * Defaults to true.
45 * @return {boolean} Whether or not to use cached JavaScript files
46 */
47function useCache() {
48 return env(1 /* USE_CACHE */, true, toBoolean);
49}
50/**
51 * TypeScript Default Configuration
52 * @type {typescript.CompilerOptions}
53 */
54var defaultCompilerOptions = {
55 module: 1 /* CommonJS */,
56 outDir: getCachePath(process.cwd()),
57 target: 1 /* ES5 */
58};
59/**
60 * Returns path to cache for source directory.
61 * @param {string} directory Directory with source code
62 * @return {string} Path with all special characters replaced with _ and
63 * prepended path to temporary directory
64 */
65function getCachePath(directory) {
66 var sanitizeOptions = {
67 replacement: "_"
68 };
69 var parts = directory.split(path.sep).map(function (p) { return sanitize(p, sanitizeOptions); });
70 var cachePath = path.join.apply(null, parts);
71 return path.join(os.tmpdir(), "typescript-register", cachePath);
72}
73/**
74 * Checks the environment for JSON stringified compiler options. By default it
75 * will compile TypeScript files into a scoped temp directory using ES5 and
76 * CommonJS targets.
77 * @return {typescript.CompilerOptions} The TypeScript compiler settings
78 */
79function compilerOptions() {
80 return env(2 /* COMPILER_OPTIONS */, defaultCompilerOptions, toOptions);
81}
82/**
83 * Gets a value from env
84 * @param {Config} config The configuration target
85 * @param {T} fallback The default value
86 * @param {Function} map The map function if the value exists
87 * @return {T} The environment variable
88 */
89function env(config, fallback, map) {
90 var key = "TYPESCRIPT_REGISTER_" + Config[config];
91 if (process.env.hasOwnProperty(key)) {
92 return map(process.env[key]);
93 }
94 return fallback;
95}
96/**
97 * Returns the JavaScript destination for the path
98 * @param {string} filename The TypeScript filename
99 * @param {typescript.CompilerOptiones} options The Compiler Options
100 * @return {string} The JavaScript filepath
101 */
102function dest(filename, options) {
103 var basename = path.basename(filename, ".ts");
104 var outDir = options.outDir || path.dirname(filename);
105 return path.join(outDir, basename + ".js");
106}
107/**
108 * Check whether or not the path is modified
109 * @param {string} tsPath The path to the TypeScript file
110 * @param {string} jsPath The path to the JavaScript file
111 * @return {boolean} Whether or not the file is modified
112 */
113function isModified(tsPath, jsPath) {
114 try {
115 var js = fs.statSync(jsPath).mtime;
116 var ts = fs.statSync(tsPath).mtime;
117 return ts > js;
118 }
119 catch (err) {
120 return true;
121 }
122}
123/**
124 * Compiles the TypeScript file
125 * @param {string} filename The root file to compile
126 * @param {typescript.CompilerOptions} options The Compiler Options
127 */
128function compile(filename, options) {
129 var host = typescript.createCompilerHost(options);
130 var program = typescript.createProgram([filename], options, host);
131 var checker = program.getTypeChecker(true);
132 var result = checker.emitFiles();
133 if (emitError()) {
134 checkErrors(program.getDiagnostics().concat(checker.getDiagnostics().concat(result.diagnostics)));
135 }
136}
137/**
138 * Converts a list of errors into something readable
139 * @param {typescript.Diagnostic[]} errors The TypeScript Diagnostics
140 * @return {Error} The Compiler Error
141 */
142function checkErrors(errors) {
143 if (errors.length === 0) {
144 return;
145 }
146 errors.forEach(function (diagnostic) {
147 var position = diagnostic.file.getLineAndCharacterFromPosition(diagnostic.start);
148 console.error(chalk.bgRed("" + diagnostic.code), chalk.grey("" + diagnostic.file.filename + ", (" + position.line + "," + position.character + ")"), diagnostic.messageText);
149 });
150 throw new Error("TypeScript Compilation Errors");
151}
152/**
153 * Converts a string to boolean
154 * @param {string} value The string value
155 * @return {boolean} Whether or not the string is "true"
156 */
157function toBoolean(value) {
158 return value === "true";
159}
160/**
161 * Converts a string to TypeScript compiler options
162 * @param {string} value The string value
163 * @return {typescript.CompilerOptions} The TypeScript Compiler Options
164 */
165function toOptions(value) {
166 return JSON.parse(value);
167}