1
|
"use strict";
|
2
|
/**
|
3
|
* @license
|
4
|
* Copyright Google Inc. All Rights Reserved.
|
5
|
*
|
6
|
* Use of this source code is governed by an MIT-style license that can be
|
7
|
* found in the LICENSE file at https://angular.io/license
|
8
|
*/
|
9
|
var __extends = (this && this.__extends) || (function () {
|
10
|
var extendStatics = Object.setPrototypeOf ||
|
11
|
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
12
|
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
13
|
return function (d, b) {
|
14
|
extendStatics(d, b);
|
15
|
function __() { this.constructor = d; }
|
16
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
17
|
};
|
18
|
})();
|
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
20
|
var tsc_wrapped_1 = require("@angular/tsc-wrapped");
|
21
|
var fs = require("fs");
|
22
|
var path = require("path");
|
23
|
var ts = require("typescript");
|
24
|
var EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
25
|
var DTS = /\.d\.ts$/;
|
26
|
var NODE_MODULES = '/node_modules/';
|
27
|
var IS_GENERATED = /\.(ngfactory|ngstyle|ngsummary)$/;
|
28
|
var GENERATED_FILES = /\.ngfactory\.ts$|\.ngstyle\.ts$|\.ngsummary\.ts$/;
|
29
|
var GENERATED_OR_DTS_FILES = /\.d\.ts$|\.ngfactory\.ts$|\.ngstyle\.ts$|\.ngsummary\.ts$/;
|
30
|
var SHALLOW_IMPORT = /^((\w|-)+|(@(\w|-)+(\/(\w|-)+)+))$/;
|
31
|
var CompilerHost = (function () {
|
32
|
function CompilerHost(program, options, context, collectorOptions) {
|
33
|
var _this = this;
|
34
|
this.program = program;
|
35
|
this.options = options;
|
36
|
this.context = context;
|
37
|
this.metadataCollector = new tsc_wrapped_1.MetadataCollector();
|
38
|
this.resolverCache = new Map();
|
39
|
this.flatModuleIndexCache = new Map();
|
40
|
this.flatModuleIndexNames = new Set();
|
41
|
this.flatModuleIndexRedirectNames = new Set();
|
42
|
this.moduleFileNames = new Map();
|
43
|
// normalize the path so that it never ends with '/'.
|
44
|
this.basePath = path.normalize(path.join(this.options.basePath, '.')).replace(/\\/g, '/');
|
45
|
this.genDir = path.normalize(path.join(this.options.genDir, '.')).replace(/\\/g, '/');
|
46
|
var genPath = path.relative(this.basePath, this.genDir);
|
47
|
this.isGenDirChildOfRootDir = genPath === '' || !genPath.startsWith('..');
|
48
|
this.resolveModuleNameHost = Object.create(this.context);
|
49
|
// When calling ts.resolveModuleName,
|
50
|
// additional allow checks for .d.ts files to be done based on
|
51
|
// checks for .ngsummary.json files,
|
52
|
// so that our codegen depends on fewer inputs and requires to be called
|
53
|
// less often.
|
54
|
// This is needed as we use ts.resolveModuleName in reflector_host
|
55
|
// and it should be able to resolve summary file names.
|
56
|
this.resolveModuleNameHost.fileExists = function (fileName) {
|
57
|
if (_this.context.fileExists(fileName)) {
|
58
|
return true;
|
59
|
}
|
60
|
if (DTS.test(fileName)) {
|
61
|
var base = fileName.substring(0, fileName.length - 5);
|
62
|
return _this.context.fileExists(base + '.ngsummary.json');
|
63
|
}
|
64
|
return false;
|
65
|
};
|
66
|
}
|
67
|
// We use absolute paths on disk as canonical.
|
68
|
CompilerHost.prototype.getCanonicalFileName = function (fileName) { return fileName; };
|
69
|
CompilerHost.prototype.moduleNameToFileName = function (m, containingFile) {
|
70
|
var key = m + ':' + (containingFile || '');
|
71
|
var result = this.moduleFileNames.get(key) || null;
|
72
|
if (!result) {
|
73
|
if (!containingFile || !containingFile.length) {
|
74
|
if (m.indexOf('.') === 0) {
|
75
|
throw new Error('Resolution of relative paths requires a containing file.');
|
76
|
}
|
77
|
// Any containing file gives the same result for absolute imports
|
78
|
containingFile = this.getCanonicalFileName(path.join(this.basePath, 'index.ts'));
|
79
|
}
|
80
|
m = m.replace(EXT, '');
|
81
|
var resolved = ts.resolveModuleName(m, containingFile.replace(/\\/g, '/'), this.options, this.resolveModuleNameHost)
|
82
|
.resolvedModule;
|
83
|
result = resolved ? this.getCanonicalFileName(resolved.resolvedFileName) : null;
|
84
|
this.moduleFileNames.set(key, result);
|
85
|
}
|
86
|
return result;
|
87
|
};
|
88
|
/**
|
89
|
* We want a moduleId that will appear in import statements in the generated code.
|
90
|
* These need to be in a form that system.js can load, so absolute file paths don't work.
|
91
|
*
|
92
|
* The `containingFile` is always in the `genDir`, where as the `importedFile` can be in
|
93
|
* `genDir`, `node_module` or `basePath`. The `importedFile` is either a generated file or
|
94
|
* existing file.
|
95
|
*
|
96
|
* | genDir | node_module | rootDir
|
97
|
* --------------+----------+-------------+----------
|
98
|
* generated | relative | relative | n/a
|
99
|
* existing file | n/a | absolute | relative(*)
|
100
|
*
|
101
|
* NOTE: (*) the relative path is computed depending on `isGenDirChildOfRootDir`.
|
102
|
*/
|
103
|
CompilerHost.prototype.fileNameToModuleName = function (importedFile, containingFile) {
|
104
|
// If a file does not yet exist (because we compile it later), we still need to
|
105
|
// assume it exists it so that the `resolve` method works!
|
106
|
if (importedFile !== containingFile && !this.context.fileExists(importedFile)) {
|
107
|
this.context.assumeFileExists(importedFile);
|
108
|
}
|
109
|
containingFile = this.rewriteGenDirPath(containingFile);
|
110
|
var containingDir = path.dirname(containingFile);
|
111
|
// drop extension
|
112
|
importedFile = importedFile.replace(EXT, '');
|
113
|
var nodeModulesIndex = importedFile.indexOf(NODE_MODULES);
|
114
|
var importModule = nodeModulesIndex === -1 ?
|
115
|
null :
|
116
|
importedFile.substring(nodeModulesIndex + NODE_MODULES.length);
|
117
|
var isGeneratedFile = IS_GENERATED.test(importedFile);
|
118
|
if (isGeneratedFile) {
|
119
|
// rewrite to genDir path
|
120
|
if (importModule) {
|
121
|
// it is generated, therefore we do a relative path to the factory
|
122
|
return this.dotRelative(containingDir, this.genDir + NODE_MODULES + importModule);
|
123
|
}
|
124
|
else {
|
125
|
// assume that import is also in `genDir`
|
126
|
importedFile = this.rewriteGenDirPath(importedFile);
|
127
|
return this.dotRelative(containingDir, importedFile);
|
128
|
}
|
129
|
}
|
130
|
else {
|
131
|
// user code import
|
132
|
if (importModule) {
|
133
|
return importModule;
|
134
|
}
|
135
|
else {
|
136
|
if (!this.isGenDirChildOfRootDir) {
|
137
|
// assume that they are on top of each other.
|
138
|
importedFile = importedFile.replace(this.basePath, this.genDir);
|
139
|
}
|
140
|
if (SHALLOW_IMPORT.test(importedFile)) {
|
141
|
return importedFile;
|
142
|
}
|
143
|
return this.dotRelative(containingDir, importedFile);
|
144
|
}
|
145
|
}
|
146
|
};
|
147
|
CompilerHost.prototype.dotRelative = function (from, to) {
|
148
|
var rPath = path.relative(from, to).replace(/\\/g, '/');
|
149
|
return rPath.startsWith('.') ? rPath : './' + rPath;
|
150
|
};
|
151
|
/**
|
152
|
* Moves the path into `genDir` folder while preserving the `node_modules` directory.
|
153
|
*/
|
154
|
CompilerHost.prototype.rewriteGenDirPath = function (filepath) {
|
155
|
var nodeModulesIndex = filepath.indexOf(NODE_MODULES);
|
156
|
if (nodeModulesIndex !== -1) {
|
157
|
// If we are in node_modulse, transplant them into `genDir`.
|
158
|
return path.join(this.genDir, filepath.substring(nodeModulesIndex));
|
159
|
}
|
160
|
else {
|
161
|
// pretend that containing file is on top of the `genDir` to normalize the paths.
|
162
|
// we apply the `genDir` => `rootDir` delta through `rootDirPrefix` later.
|
163
|
return filepath.replace(this.basePath, this.genDir);
|
164
|
}
|
165
|
};
|
166
|
CompilerHost.prototype.getSourceFile = function (filePath) {
|
167
|
var sf = this.program.getSourceFile(filePath);
|
168
|
if (!sf) {
|
169
|
if (this.context.fileExists(filePath)) {
|
170
|
var sourceText = this.context.readFile(filePath);
|
171
|
return ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true);
|
172
|
}
|
173
|
throw new Error("Source file " + filePath + " not present in program.");
|
174
|
}
|
175
|
return sf;
|
176
|
};
|
177
|
CompilerHost.prototype.getMetadataFor = function (filePath) {
|
178
|
if (!this.context.fileExists(filePath)) {
|
179
|
// If the file doesn't exists then we cannot return metadata for the file.
|
180
|
// This will occur if the user referenced a declared module for which no file
|
181
|
// exists for the module (i.e. jQuery or angularjs).
|
182
|
return;
|
183
|
}
|
184
|
if (DTS.test(filePath)) {
|
185
|
var metadataPath = filePath.replace(DTS, '.metadata.json');
|
186
|
if (this.context.fileExists(metadataPath)) {
|
187
|
return this.readMetadata(metadataPath, filePath);
|
188
|
}
|
189
|
else {
|
190
|
// If there is a .d.ts file but no metadata file we need to produce a
|
191
|
// v3 metadata from the .d.ts file as v3 includes the exports we need
|
192
|
// to resolve symbols.
|
193
|
return [this.upgradeVersion1Metadata({ '__symbolic': 'module', 'version': 1, 'metadata': {} }, filePath)];
|
194
|
}
|
195
|
}
|
196
|
var sf = this.getSourceFile(filePath);
|
197
|
var metadata = this.metadataCollector.getMetadata(sf);
|
198
|
return metadata ? [metadata] : [];
|
199
|
};
|
200
|
CompilerHost.prototype.readMetadata = function (filePath, dtsFilePath) {
|
201
|
var metadatas = this.resolverCache.get(filePath);
|
202
|
if (metadatas) {
|
203
|
return metadatas;
|
204
|
}
|
205
|
try {
|
206
|
var metadataOrMetadatas = JSON.parse(this.context.readFile(filePath));
|
207
|
var metadatas_1 = metadataOrMetadatas ?
|
208
|
(Array.isArray(metadataOrMetadatas) ? metadataOrMetadatas : [metadataOrMetadatas]) :
|
209
|
[];
|
210
|
var v1Metadata = metadatas_1.find(function (m) { return m.version === 1; });
|
211
|
var v3Metadata = metadatas_1.find(function (m) { return m.version === 3; });
|
212
|
if (!v3Metadata && v1Metadata) {
|
213
|
metadatas_1.push(this.upgradeVersion1Metadata(v1Metadata, dtsFilePath));
|
214
|
}
|
215
|
this.resolverCache.set(filePath, metadatas_1);
|
216
|
return metadatas_1;
|
217
|
}
|
218
|
catch (e) {
|
219
|
console.error("Failed to read JSON file " + filePath);
|
220
|
throw e;
|
221
|
}
|
222
|
};
|
223
|
CompilerHost.prototype.upgradeVersion1Metadata = function (v1Metadata, dtsFilePath) {
|
224
|
// patch up v1 to v3 by merging the metadata with metadata collected from the d.ts file
|
225
|
// as the only difference between the versions is whether all exports are contained in
|
226
|
// the metadata and the `extends` clause.
|
227
|
var v3Metadata = { '__symbolic': 'module', 'version': 3, 'metadata': {} };
|
228
|
if (v1Metadata.exports) {
|
229
|
v3Metadata.exports = v1Metadata.exports;
|
230
|
}
|
231
|
for (var prop in v1Metadata.metadata) {
|
232
|
v3Metadata.metadata[prop] = v1Metadata.metadata[prop];
|
233
|
}
|
234
|
var exports = this.metadataCollector.getMetadata(this.getSourceFile(dtsFilePath));
|
235
|
if (exports) {
|
236
|
for (var prop in exports.metadata) {
|
237
|
if (!v3Metadata.metadata[prop]) {
|
238
|
v3Metadata.metadata[prop] = exports.metadata[prop];
|
239
|
}
|
240
|
}
|
241
|
if (exports.exports) {
|
242
|
v3Metadata.exports = exports.exports;
|
243
|
}
|
244
|
}
|
245
|
return v3Metadata;
|
246
|
};
|
247
|
CompilerHost.prototype.loadResource = function (filePath) {
|
248
|
if (this.context.readResource)
|
249
|
return this.context.readResource(filePath);
|
250
|
return this.context.readFile(filePath);
|
251
|
};
|
252
|
CompilerHost.prototype.loadSummary = function (filePath) {
|
253
|
if (this.context.fileExists(filePath)) {
|
254
|
return this.context.readFile(filePath);
|
255
|
}
|
256
|
return null;
|
257
|
};
|
258
|
CompilerHost.prototype.getOutputFileName = function (sourceFilePath) {
|
259
|
return sourceFilePath.replace(EXT, '') + '.d.ts';
|
260
|
};
|
261
|
CompilerHost.prototype.isSourceFile = function (filePath) {
|
262
|
var excludeRegex = this.options.generateCodeForLibraries === false ? GENERATED_OR_DTS_FILES : GENERATED_FILES;
|
263
|
if (excludeRegex.test(filePath)) {
|
264
|
return false;
|
265
|
}
|
266
|
if (DTS.test(filePath)) {
|
267
|
// Check for a bundle index.
|
268
|
if (this.hasBundleIndex(filePath)) {
|
269
|
var normalFilePath = path.normalize(filePath);
|
270
|
return this.flatModuleIndexNames.has(normalFilePath) ||
|
271
|
this.flatModuleIndexRedirectNames.has(normalFilePath);
|
272
|
}
|
273
|
}
|
274
|
return true;
|
275
|
};
|
276
|
CompilerHost.prototype.calculateEmitPath = function (filePath) {
|
277
|
// Write codegen in a directory structure matching the sources.
|
278
|
var root = this.options.basePath;
|
279
|
for (var _i = 0, _a = this.options.rootDirs || []; _i < _a.length; _i++) {
|
280
|
var eachRootDir = _a[_i];
|
281
|
if (this.options.trace) {
|
282
|
console.error("Check if " + filePath + " is under rootDirs element " + eachRootDir);
|
283
|
}
|
284
|
if (path.relative(eachRootDir, filePath).indexOf('.') !== 0) {
|
285
|
root = eachRootDir;
|
286
|
}
|
287
|
}
|
288
|
// transplant the codegen path to be inside the `genDir`
|
289
|
var relativePath = path.relative(root, filePath);
|
290
|
while (relativePath.startsWith('..' + path.sep)) {
|
291
|
// Strip out any `..` path such as: `../node_modules/@foo` as we want to put everything
|
292
|
// into `genDir`.
|
293
|
relativePath = relativePath.substr(3);
|
294
|
}
|
295
|
return path.join(this.options.genDir, relativePath);
|
296
|
};
|
297
|
CompilerHost.prototype.hasBundleIndex = function (filePath) {
|
298
|
var _this = this;
|
299
|
var checkBundleIndex = function (directory) {
|
300
|
var result = _this.flatModuleIndexCache.get(directory);
|
301
|
if (result == null) {
|
302
|
if (path.basename(directory) == 'node_module') {
|
303
|
// Don't look outside the node_modules this package is installed in.
|
304
|
result = false;
|
305
|
}
|
306
|
else {
|
307
|
// A bundle index exists if the typings .d.ts file has a metadata.json that has an
|
308
|
// importAs.
|
309
|
try {
|
310
|
var packageFile = path.join(directory, 'package.json');
|
311
|
if (_this.context.fileExists(packageFile)) {
|
312
|
// Once we see a package.json file, assume false until it we find the bundle index.
|
313
|
result = false;
|
314
|
var packageContent = JSON.parse(_this.context.readFile(packageFile));
|
315
|
if (packageContent.typings) {
|
316
|
var typings = path.normalize(path.join(directory, packageContent.typings));
|
317
|
if (DTS.test(typings)) {
|
318
|
var metadataFile = typings.replace(DTS, '.metadata.json');
|
319
|
if (_this.context.fileExists(metadataFile)) {
|
320
|
var metadata = JSON.parse(_this.context.readFile(metadataFile));
|
321
|
if (metadata.flatModuleIndexRedirect) {
|
322
|
_this.flatModuleIndexRedirectNames.add(typings);
|
323
|
// Note: don't set result = true,
|
324
|
// as this would mark this folder
|
325
|
// as having a bundleIndex too early without
|
326
|
// filling the bundleIndexNames.
|
327
|
}
|
328
|
else if (metadata.importAs) {
|
329
|
_this.flatModuleIndexNames.add(typings);
|
330
|
result = true;
|
331
|
}
|
332
|
}
|
333
|
}
|
334
|
}
|
335
|
}
|
336
|
else {
|
337
|
var parent_1 = path.dirname(directory);
|
338
|
if (parent_1 != directory) {
|
339
|
// Try the parent directory.
|
340
|
result = checkBundleIndex(parent_1);
|
341
|
}
|
342
|
else {
|
343
|
result = false;
|
344
|
}
|
345
|
}
|
346
|
}
|
347
|
catch (e) {
|
348
|
// If we encounter any errors assume we this isn't a bundle index.
|
349
|
result = false;
|
350
|
}
|
351
|
}
|
352
|
_this.flatModuleIndexCache.set(directory, result);
|
353
|
}
|
354
|
return result;
|
355
|
};
|
356
|
return checkBundleIndex(path.dirname(filePath));
|
357
|
};
|
358
|
return CompilerHost;
|
359
|
}());
|
360
|
exports.CompilerHost = CompilerHost;
|
361
|
var CompilerHostContextAdapter = (function () {
|
362
|
function CompilerHostContextAdapter() {
|
363
|
this.assumedExists = {};
|
364
|
}
|
365
|
CompilerHostContextAdapter.prototype.assumeFileExists = function (fileName) { this.assumedExists[fileName] = true; };
|
366
|
return CompilerHostContextAdapter;
|
367
|
}());
|
368
|
exports.CompilerHostContextAdapter = CompilerHostContextAdapter;
|
369
|
var ModuleResolutionHostAdapter = (function (_super) {
|
370
|
__extends(ModuleResolutionHostAdapter, _super);
|
371
|
function ModuleResolutionHostAdapter(host) {
|
372
|
var _this = _super.call(this) || this;
|
373
|
_this.host = host;
|
374
|
if (host.directoryExists) {
|
375
|
_this.directoryExists = function (directoryName) { return host.directoryExists(directoryName); };
|
376
|
}
|
377
|
return _this;
|
378
|
}
|
379
|
ModuleResolutionHostAdapter.prototype.fileExists = function (fileName) {
|
380
|
return this.assumedExists[fileName] || this.host.fileExists(fileName);
|
381
|
};
|
382
|
ModuleResolutionHostAdapter.prototype.readFile = function (fileName) { return this.host.readFile(fileName); };
|
383
|
ModuleResolutionHostAdapter.prototype.readResource = function (s) {
|
384
|
if (!this.host.fileExists(s)) {
|
385
|
// TODO: We should really have a test for error cases like this!
|
386
|
throw new Error("Compilation failed. Resource file not found: " + s);
|
387
|
}
|
388
|
return Promise.resolve(this.host.readFile(s));
|
389
|
};
|
390
|
return ModuleResolutionHostAdapter;
|
391
|
}(CompilerHostContextAdapter));
|
392
|
exports.ModuleResolutionHostAdapter = ModuleResolutionHostAdapter;
|
393
|
var NodeCompilerHostContext = (function (_super) {
|
394
|
__extends(NodeCompilerHostContext, _super);
|
395
|
function NodeCompilerHostContext() {
|
396
|
return _super !== null && _super.apply(this, arguments) || this;
|
397
|
}
|
398
|
NodeCompilerHostContext.prototype.fileExists = function (fileName) {
|
399
|
return this.assumedExists[fileName] || fs.existsSync(fileName);
|
400
|
};
|
401
|
NodeCompilerHostContext.prototype.directoryExists = function (directoryName) {
|
402
|
try {
|
403
|
return fs.statSync(directoryName).isDirectory();
|
404
|
}
|
405
|
catch (e) {
|
406
|
return false;
|
407
|
}
|
408
|
};
|
409
|
NodeCompilerHostContext.prototype.readFile = function (fileName) { return fs.readFileSync(fileName, 'utf8'); };
|
410
|
NodeCompilerHostContext.prototype.readResource = function (s) {
|
411
|
if (!this.fileExists(s)) {
|
412
|
// TODO: We should really have a test for error cases like this!
|
413
|
throw new Error("Compilation failed. Resource file not found: " + s);
|
414
|
}
|
415
|
return Promise.resolve(this.readFile(s));
|
416
|
};
|
417
|
return NodeCompilerHostContext;
|
418
|
}(CompilerHostContextAdapter));
|
419
|
exports.NodeCompilerHostContext = NodeCompilerHostContext;
|
420
|
//# sourceMappingURL=compiler_host.js.map
|