1 | "use strict";
|
2 | var fs = require("fs");
|
3 | var path = require("path");
|
4 | var _ = require("lodash");
|
5 | var helpers_1 = require("./helpers");
|
6 | var checker_1 = require("./checker");
|
7 | var watch_mode_1 = require("./watch-mode");
|
8 | var colors = require('colors/safe');
|
9 | var pkg = require('../package.json');
|
10 | var mkdirp = require('mkdirp');
|
11 | function getRootCompiler(compiler) {
|
12 | if (compiler.parentCompilation) {
|
13 | return getRootCompiler(compiler.parentCompilation.compiler);
|
14 | }
|
15 | else {
|
16 | return compiler;
|
17 | }
|
18 | }
|
19 | exports.getRootCompiler = getRootCompiler;
|
20 | function resolveInstance(compiler, instanceName) {
|
21 | if (!compiler._tsInstances) {
|
22 | compiler._tsInstances = {};
|
23 | }
|
24 | return compiler._tsInstances[instanceName];
|
25 | }
|
26 | var COMPILER_ERROR = colors.red("\n\nTypescript compiler cannot be found, please add it to your package.json file:\n npm install --save-dev typescript\n");
|
27 | var BABEL_ERROR = colors.red("\n\nBabel compiler cannot be found, please add it to your package.json file:\n npm install --save-dev babel-core\n");
|
28 | var id = 0;
|
29 | function ensureInstance(webpack, query, options, instanceName, rootCompiler) {
|
30 | var exInstance = resolveInstance(rootCompiler, instanceName);
|
31 | if (exInstance) {
|
32 | return exInstance;
|
33 | }
|
34 | var watching = isWatching(rootCompiler);
|
35 | var context = process.cwd();
|
36 | var compilerInfo = setupTs(query.compiler);
|
37 | var tsImpl = compilerInfo.tsImpl;
|
38 | var _a = readConfigFile(context, query, options, tsImpl), configFilePath = _a.configFilePath, compilerConfig = _a.compilerConfig, loaderConfig = _a.loaderConfig;
|
39 | applyDefaults(configFilePath, compilerConfig, loaderConfig, context);
|
40 | if (!loaderConfig.silent) {
|
41 | var sync = watching === WatchMode.Enabled ? ' (in a forked process)' : '';
|
42 | console.log("\n[" + instanceName + "] Using typescript@" + compilerInfo.compilerVersion + " from " + compilerInfo.compilerPath + " and "
|
43 | + ("\"tsconfig.json\" from " + configFilePath + sync + ".\n"));
|
44 | }
|
45 | var babelImpl = setupBabel(loaderConfig, context);
|
46 | var cacheIdentifier = setupCache(loaderConfig, tsImpl, webpack, babelImpl, context);
|
47 | var compiler = webpack._compiler;
|
48 | setupWatchRun(compiler, instanceName);
|
49 | setupAfterCompile(compiler, instanceName);
|
50 | var webpackOptions = _.pick(webpack._compiler.options, 'resolve');
|
51 | var checker = new checker_1.Checker(compilerInfo, loaderConfig, compilerConfig, webpackOptions, context, watching === WatchMode.Enabled);
|
52 | return rootCompiler._tsInstances[instanceName] = {
|
53 | id: ++id,
|
54 | babelImpl: babelImpl,
|
55 | compiledFiles: {},
|
56 | loaderConfig: loaderConfig,
|
57 | configFilePath: configFilePath,
|
58 | compilerConfig: compilerConfig,
|
59 | checker: checker,
|
60 | cacheIdentifier: cacheIdentifier,
|
61 | context: context
|
62 | };
|
63 | }
|
64 | exports.ensureInstance = ensureInstance;
|
65 | function findTsImplPackage(inputPath) {
|
66 | var pkgDir = path.dirname(inputPath);
|
67 | if (fs.readdirSync(pkgDir).find(function (value) { return value === 'package.json'; })) {
|
68 | return path.join(pkgDir, 'package.json');
|
69 | }
|
70 | else {
|
71 | return findTsImplPackage(pkgDir);
|
72 | }
|
73 | }
|
74 | function setupTs(compiler) {
|
75 | var compilerPath = compiler || 'typescript';
|
76 | var tsImpl;
|
77 | var tsImplPath;
|
78 | try {
|
79 | tsImplPath = require.resolve(compilerPath);
|
80 | tsImpl = require(tsImplPath);
|
81 | }
|
82 | catch (e) {
|
83 | console.error(e);
|
84 | console.error(COMPILER_ERROR);
|
85 | process.exit(1);
|
86 | }
|
87 | var pkgPath = findTsImplPackage(tsImplPath);
|
88 | var compilerVersion = require(pkgPath).version;
|
89 | var compilerInfo = {
|
90 | compilerPath: compilerPath,
|
91 | compilerVersion: compilerVersion,
|
92 | tsImpl: tsImpl,
|
93 | };
|
94 | return compilerInfo;
|
95 | }
|
96 | exports.setupTs = setupTs;
|
97 | function setupCache(loaderConfig, tsImpl, webpack, babelImpl, context) {
|
98 | var cacheIdentifier = null;
|
99 | if (loaderConfig.useCache) {
|
100 | if (!loaderConfig.cacheDirectory) {
|
101 | loaderConfig.cacheDirectory = path.join(context, '.awcache');
|
102 | }
|
103 | if (!fs.existsSync(loaderConfig.cacheDirectory)) {
|
104 | mkdirp.sync(loaderConfig.cacheDirectory);
|
105 | }
|
106 | cacheIdentifier = {
|
107 | 'typescript': tsImpl.version,
|
108 | 'awesome-typescript-loader': pkg.version,
|
109 | 'awesome-typescript-loader-query': webpack.query,
|
110 | 'babel-core': babelImpl
|
111 | ? babelImpl.version
|
112 | : null
|
113 | };
|
114 | }
|
115 | }
|
116 | function setupBabel(loaderConfig, context) {
|
117 | var babelImpl;
|
118 | if (loaderConfig.useBabel) {
|
119 | try {
|
120 | var babelPath = loaderConfig.babelCore || path.join(context, 'node_modules', 'babel-core');
|
121 | babelImpl = require(babelPath);
|
122 | }
|
123 | catch (e) {
|
124 | console.error(BABEL_ERROR);
|
125 | process.exit(1);
|
126 | }
|
127 | }
|
128 | return babelImpl;
|
129 | }
|
130 | function applyDefaults(configFilePath, compilerConfig, loaderConfig, context) {
|
131 | _.defaults(compilerConfig.options, {
|
132 | sourceMap: true,
|
133 | verbose: false,
|
134 | skipDefaultLibCheck: true,
|
135 | suppressOutputPathCheck: true
|
136 | });
|
137 | if (loaderConfig.transpileOnly) {
|
138 | compilerConfig.options.isolatedModules = true;
|
139 | }
|
140 | _.defaults(compilerConfig.options, {
|
141 | sourceRoot: compilerConfig.options.sourceMap ? context : undefined
|
142 | });
|
143 | _.defaults(loaderConfig, {
|
144 | sourceMap: true,
|
145 | verbose: false,
|
146 | });
|
147 | delete compilerConfig.options.outDir;
|
148 | delete compilerConfig.options.outFile;
|
149 | delete compilerConfig.options.out;
|
150 | delete compilerConfig.options.noEmit;
|
151 | }
|
152 | function absolutize(fileName, context) {
|
153 | if (path.isAbsolute(fileName)) {
|
154 | return fileName;
|
155 | }
|
156 | else {
|
157 | return path.join(context, fileName);
|
158 | }
|
159 | }
|
160 | function readConfigFile(context, query, options, tsImpl) {
|
161 | var configFilePath;
|
162 | if (query.configFileName && query.configFileName.match(/\.json$/)) {
|
163 | configFilePath = absolutize(query.configFileName, context);
|
164 | }
|
165 | else {
|
166 | configFilePath = tsImpl.findConfigFile(context, tsImpl.sys.fileExists);
|
167 | }
|
168 | var existingOptions = tsImpl.convertCompilerOptionsFromJson(query, context, 'atl.query');
|
169 | if (!configFilePath || query.configFileContent) {
|
170 | return {
|
171 | configFilePath: configFilePath || path.join(context, 'tsconfig.json'),
|
172 | compilerConfig: tsImpl.parseJsonConfigFileContent(query.configFileContent || {}, tsImpl.sys, context, _.extend({}, tsImpl.getDefaultCompilerOptions(), existingOptions.options), context),
|
173 | loaderConfig: query
|
174 | };
|
175 | }
|
176 | var jsonConfigFile = tsImpl.readConfigFile(configFilePath, tsImpl.sys.readFile);
|
177 | var compilerConfig = tsImpl.parseJsonConfigFileContent(jsonConfigFile.config, tsImpl.sys, path.dirname(configFilePath), existingOptions.options, configFilePath);
|
178 | return {
|
179 | configFilePath: configFilePath,
|
180 | compilerConfig: compilerConfig,
|
181 | loaderConfig: _.defaults(query, jsonConfigFile.config.awesomeTypescriptLoaderOptions, options)
|
182 | };
|
183 | }
|
184 | exports.readConfigFile = readConfigFile;
|
185 | var EXTENSIONS = /\.tsx?$|\.jsx?$/;
|
186 | function setupWatchRun(compiler, instanceName) {
|
187 | compiler.plugin('watch-run', function (watching, callback) {
|
188 | var instance = resolveInstance(watching.compiler, instanceName);
|
189 | var checker = instance.checker;
|
190 | var watcher = watching.compiler.watchFileSystem.watcher
|
191 | || watching.compiler.watchFileSystem.wfs.watcher;
|
192 | var mtimes = watcher.mtimes || {};
|
193 | var changedFiles = Object.keys(mtimes).map(helpers_1.toUnix);
|
194 | var updates = changedFiles
|
195 | .filter(function (file) { return EXTENSIONS.test(file); })
|
196 | .map(function (changedFile) {
|
197 | if (fs.existsSync(changedFile)) {
|
198 | checker.updateFile(changedFile, fs.readFileSync(changedFile).toString());
|
199 | }
|
200 | else {
|
201 | checker.removeFile(changedFile);
|
202 | }
|
203 | });
|
204 | Promise.all(updates)
|
205 | .then(function () { return callback(); })
|
206 | .catch(callback);
|
207 | });
|
208 | }
|
209 | var WatchMode;
|
210 | (function (WatchMode) {
|
211 | WatchMode[WatchMode["Enabled"] = 0] = "Enabled";
|
212 | WatchMode[WatchMode["Disabled"] = 1] = "Disabled";
|
213 | WatchMode[WatchMode["Unknown"] = 2] = "Unknown";
|
214 | })(WatchMode || (WatchMode = {}));
|
215 | function isWatching(compiler) {
|
216 | var value = compiler && compiler[watch_mode_1.WatchModeSymbol];
|
217 | if (value === true) {
|
218 | return WatchMode.Enabled;
|
219 | }
|
220 | else if (value === false) {
|
221 | return WatchMode.Disabled;
|
222 | }
|
223 | else {
|
224 | return WatchMode.Unknown;
|
225 | }
|
226 | }
|
227 | function setupAfterCompile(compiler, instanceName, forkChecker) {
|
228 | if (forkChecker === void 0) { forkChecker = false; }
|
229 | compiler.plugin('after-compile', function (compilation, callback) {
|
230 | if (compilation.compiler.isChild()) {
|
231 | callback();
|
232 | return;
|
233 | }
|
234 | var watchMode = isWatching(compilation.compiler);
|
235 | var instance = resolveInstance(compilation.compiler, instanceName);
|
236 | var silent = instance.loaderConfig.silent;
|
237 | var asyncErrors = watchMode === WatchMode.Enabled && !silent;
|
238 | var emitError = function (msg) {
|
239 | if (compilation.bail) {
|
240 | console.error('Error in bail mode:', msg);
|
241 | process.exit(1);
|
242 | }
|
243 | if (asyncErrors) {
|
244 | console.log(msg, '\n');
|
245 | }
|
246 | else {
|
247 | compilation.errors.push(new Error(msg));
|
248 | }
|
249 | };
|
250 | instance.compiledFiles = {};
|
251 | var files = instance.checker.getFiles()
|
252 | .then(function (_a) {
|
253 | var files = _a.files;
|
254 | Array.prototype.push.apply(compilation.fileDependencies, files.map(path.normalize));
|
255 | });
|
256 | var diag = instance.loaderConfig.transpileOnly
|
257 | ? Promise.resolve()
|
258 | : instance.checker.getDiagnostics()
|
259 | .then(function (diags) {
|
260 | diags.forEach(function (diag) { return emitError(diag.pretty); });
|
261 | });
|
262 | files
|
263 | .then(function () {
|
264 | if (asyncErrors) {
|
265 | return;
|
266 | }
|
267 | else {
|
268 | return diag;
|
269 | }
|
270 | })
|
271 | .then(function () { return callback(); })
|
272 | .catch(callback);
|
273 | });
|
274 | }
|
275 |
|
\ | No newline at end of file |