UNPKG

23.8 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3/**
4 * @license
5 * Copyright Google Inc. All Rights Reserved.
6 *
7 * Use of this source code is governed by an MIT-style license that can be
8 * found in the LICENSE file at https://angular.io/license
9 */
10var path = require("path");
11var ts = require("typescript");
12var collector_1 = require("./collector");
13var schema_1 = require("./schema");
14// The character set used to produce private names.
15var PRIVATE_NAME_CHARS = 'abcdefghijklmnopqrstuvwxyz';
16var MetadataBundler = (function () {
17 function MetadataBundler(root, importAs, host) {
18 this.root = root;
19 this.importAs = importAs;
20 this.host = host;
21 this.symbolMap = new Map();
22 this.metadataCache = new Map();
23 this.exports = new Map();
24 this.rootModule = "./" + path.basename(root);
25 }
26 MetadataBundler.prototype.getMetadataBundle = function () {
27 // Export the root module. This also collects the transitive closure of all values referenced by
28 // the exports.
29 var exportedSymbols = this.exportAll(this.rootModule);
30 this.canonicalizeSymbols(exportedSymbols);
31 // TODO: exports? e.g. a module re-exports a symbol from another bundle
32 var metadata = this.getEntries(exportedSymbols);
33 var privates = Array.from(this.symbolMap.values())
34 .filter(function (s) { return s.referenced && s.isPrivate; })
35 .map(function (s) { return ({
36 privateName: s.privateName,
37 name: s.declaration.name,
38 module: s.declaration.module
39 }); });
40 var origins = Array.from(this.symbolMap.values())
41 .filter(function (s) { return s.referenced && !s.reexport; })
42 .reduce(function (p, s) {
43 p[s.isPrivate ? s.privateName : s.name] = s.declaration.module;
44 return p;
45 }, {});
46 var exports = this.getReExports(exportedSymbols);
47 return {
48 metadata: {
49 __symbolic: 'module',
50 version: schema_1.VERSION,
51 exports: exports.length ? exports : undefined, metadata: metadata, origins: origins,
52 importAs: this.importAs
53 },
54 privates: privates
55 };
56 };
57 MetadataBundler.resolveModule = function (importName, from) {
58 return resolveModule(importName, from);
59 };
60 MetadataBundler.prototype.getMetadata = function (moduleName) {
61 var result = this.metadataCache.get(moduleName);
62 if (!result) {
63 if (moduleName.startsWith('.')) {
64 var fullModuleName = resolveModule(moduleName, this.root);
65 result = this.host.getMetadataFor(fullModuleName);
66 }
67 this.metadataCache.set(moduleName, result);
68 }
69 return result;
70 };
71 MetadataBundler.prototype.exportAll = function (moduleName) {
72 var _this = this;
73 var module = this.getMetadata(moduleName);
74 var result = this.exports.get(moduleName);
75 if (result) {
76 return result;
77 }
78 result = [];
79 var exportSymbol = function (exportedSymbol, exportAs) {
80 var symbol = _this.symbolOf(moduleName, exportAs);
81 result.push(symbol);
82 exportedSymbol.reexportedAs = symbol;
83 symbol.exports = exportedSymbol;
84 };
85 // Export all the symbols defined in this module.
86 if (module && module.metadata) {
87 for (var key in module.metadata) {
88 var data = module.metadata[key];
89 if (schema_1.isMetadataImportedSymbolReferenceExpression(data)) {
90 // This is a re-export of an imported symbol. Record this as a re-export.
91 var exportFrom = resolveModule(data.module, moduleName);
92 this.exportAll(exportFrom);
93 var symbol = this.symbolOf(exportFrom, data.name);
94 exportSymbol(symbol, key);
95 }
96 else {
97 // Record that this symbol is exported by this module.
98 result.push(this.symbolOf(moduleName, key));
99 }
100 }
101 }
102 // Export all the re-exports from this module
103 if (module && module.exports) {
104 for (var _i = 0, _a = module.exports; _i < _a.length; _i++) {
105 var exportDeclaration = _a[_i];
106 var exportFrom = resolveModule(exportDeclaration.from, moduleName);
107 // Record all the exports from the module even if we don't use it directly.
108 var exportedSymbols = this.exportAll(exportFrom);
109 if (exportDeclaration.export) {
110 // Re-export all the named exports from a module.
111 for (var _b = 0, _c = exportDeclaration.export; _b < _c.length; _b++) {
112 var exportItem = _c[_b];
113 var name_1 = typeof exportItem == 'string' ? exportItem : exportItem.name;
114 var exportAs = typeof exportItem == 'string' ? exportItem : exportItem.as;
115 var symbol = this.symbolOf(exportFrom, name_1);
116 if (exportedSymbols && exportedSymbols.length == 1 && exportedSymbols[0].reexport &&
117 exportedSymbols[0].name == '*') {
118 // This is a named export from a module we have no metadata about. Record the named
119 // export as a re-export.
120 symbol.reexport = true;
121 }
122 exportSymbol(this.symbolOf(exportFrom, name_1), exportAs);
123 }
124 }
125 else {
126 // Re-export all the symbols from the module
127 var exportedSymbols_1 = this.exportAll(exportFrom);
128 for (var _d = 0, exportedSymbols_2 = exportedSymbols_1; _d < exportedSymbols_2.length; _d++) {
129 var exportedSymbol = exportedSymbols_2[_d];
130 var name_2 = exportedSymbol.name;
131 exportSymbol(exportedSymbol, name_2);
132 }
133 }
134 }
135 }
136 if (!module) {
137 // If no metadata is found for this import then it is considered external to the
138 // library and should be recorded as a re-export in the final metadata if it is
139 // eventually re-exported.
140 var symbol = this.symbolOf(moduleName, '*');
141 symbol.reexport = true;
142 result.push(symbol);
143 }
144 this.exports.set(moduleName, result);
145 return result;
146 };
147 /**
148 * Fill in the canonicalSymbol which is the symbol that should be imported by factories.
149 * The canonical symbol is the one exported by the index file for the bundle or definition
150 * symbol for private symbols that are not exported by bundle index.
151 */
152 MetadataBundler.prototype.canonicalizeSymbols = function (exportedSymbols) {
153 var symbols = Array.from(this.symbolMap.values());
154 this.exported = new Set(exportedSymbols);
155 symbols.forEach(this.canonicalizeSymbol, this);
156 };
157 MetadataBundler.prototype.canonicalizeSymbol = function (symbol) {
158 var rootExport = getRootExport(symbol);
159 var declaration = getSymbolDeclaration(symbol);
160 var isPrivate = !this.exported.has(rootExport);
161 var canonicalSymbol = isPrivate ? declaration : rootExport;
162 symbol.isPrivate = isPrivate;
163 symbol.declaration = declaration;
164 symbol.canonicalSymbol = canonicalSymbol;
165 symbol.reexport = declaration.reexport;
166 };
167 MetadataBundler.prototype.getEntries = function (exportedSymbols) {
168 var _this = this;
169 var result = {};
170 var exportedNames = new Set(exportedSymbols.map(function (s) { return s.name; }));
171 var privateName = 0;
172 function newPrivateName() {
173 while (true) {
174 var digits = [];
175 var index = privateName++;
176 var base = PRIVATE_NAME_CHARS;
177 while (!digits.length || index > 0) {
178 digits.unshift(base[index % base.length]);
179 index = Math.floor(index / base.length);
180 }
181 digits.unshift('\u0275');
182 var result_1 = digits.join('');
183 if (!exportedNames.has(result_1))
184 return result_1;
185 }
186 }
187 exportedSymbols.forEach(function (symbol) { return _this.convertSymbol(symbol); });
188 var symbolsMap = new Map();
189 Array.from(this.symbolMap.values()).forEach(function (symbol) {
190 if (symbol.referenced && !symbol.reexport) {
191 var name_3 = symbol.name;
192 var identifier = symbol.declaration.module + ":" + symbol.declaration.name;
193 if (symbol.isPrivate && !symbol.privateName) {
194 name_3 = newPrivateName();
195 symbol.privateName = name_3;
196 }
197 if (symbolsMap.has(identifier)) {
198 var names = symbolsMap.get(identifier);
199 names.push(name_3);
200 }
201 else {
202 symbolsMap.set(identifier, [name_3]);
203 }
204 result[name_3] = symbol.value;
205 }
206 });
207 // check for duplicated entries
208 symbolsMap.forEach(function (names, identifier) {
209 if (names.length > 1) {
210 var _a = identifier.split(':'), module_1 = _a[0], declaredName = _a[1];
211 // prefer the export that uses the declared name (if any)
212 var reference_1 = names.indexOf(declaredName);
213 if (reference_1 === -1) {
214 reference_1 = 0;
215 }
216 // keep one entry and replace the others by references
217 names.forEach(function (name, i) {
218 if (i !== reference_1) {
219 result[name] = { __symbolic: 'reference', name: names[reference_1] };
220 }
221 });
222 }
223 });
224 return result;
225 };
226 MetadataBundler.prototype.getReExports = function (exportedSymbols) {
227 var modules = new Map();
228 var exportAlls = new Set();
229 for (var _i = 0, exportedSymbols_3 = exportedSymbols; _i < exportedSymbols_3.length; _i++) {
230 var symbol = exportedSymbols_3[_i];
231 if (symbol.reexport) {
232 var declaration = symbol.declaration;
233 var module_2 = declaration.module;
234 if (declaration.name == '*') {
235 // Reexport all the symbols.
236 exportAlls.add(declaration.module);
237 }
238 else {
239 // Re-export the symbol as the exported name.
240 var entry = modules.get(module_2);
241 if (!entry) {
242 entry = [];
243 modules.set(module_2, entry);
244 }
245 var as = symbol.name;
246 var name_4 = declaration.name;
247 entry.push({ name: name_4, as: as });
248 }
249 }
250 }
251 return Array.from(exportAlls.values()).map(function (from) { return ({ from: from }); }).concat(Array.from(modules.entries()).map(function (_a) {
252 var from = _a[0], exports = _a[1];
253 return ({ export: exports, from: from });
254 }));
255 };
256 MetadataBundler.prototype.convertSymbol = function (symbol) {
257 var canonicalSymbol = symbol.canonicalSymbol;
258 if (!canonicalSymbol.referenced) {
259 canonicalSymbol.referenced = true;
260 var declaration = canonicalSymbol.declaration;
261 var module_3 = this.getMetadata(declaration.module);
262 if (module_3) {
263 var value = module_3.metadata[declaration.name];
264 if (value && !declaration.name.startsWith('___')) {
265 canonicalSymbol.value = this.convertEntry(declaration.module, value);
266 }
267 }
268 }
269 };
270 MetadataBundler.prototype.convertEntry = function (moduleName, value) {
271 if (schema_1.isClassMetadata(value)) {
272 return this.convertClass(moduleName, value);
273 }
274 if (schema_1.isFunctionMetadata(value)) {
275 return this.convertFunction(moduleName, value);
276 }
277 if (schema_1.isInterfaceMetadata(value)) {
278 return value;
279 }
280 return this.convertValue(moduleName, value);
281 };
282 MetadataBundler.prototype.convertClass = function (moduleName, value) {
283 var _this = this;
284 return {
285 __symbolic: 'class',
286 arity: value.arity,
287 extends: this.convertExpression(moduleName, value.extends),
288 decorators: value.decorators && value.decorators.map(function (d) { return _this.convertExpression(moduleName, d); }),
289 members: this.convertMembers(moduleName, value.members),
290 statics: value.statics && this.convertStatics(moduleName, value.statics)
291 };
292 };
293 MetadataBundler.prototype.convertMembers = function (moduleName, members) {
294 var _this = this;
295 var result = {};
296 for (var name_5 in members) {
297 var value = members[name_5];
298 result[name_5] = value.map(function (v) { return _this.convertMember(moduleName, v); });
299 }
300 return result;
301 };
302 MetadataBundler.prototype.convertMember = function (moduleName, member) {
303 var _this = this;
304 var result = { __symbolic: member.__symbolic };
305 result.decorators =
306 member.decorators && member.decorators.map(function (d) { return _this.convertExpression(moduleName, d); });
307 if (schema_1.isMethodMetadata(member)) {
308 result.parameterDecorators = member.parameterDecorators &&
309 member.parameterDecorators.map(function (d) { return d && d.map(function (p) { return _this.convertExpression(moduleName, p); }); });
310 if (schema_1.isConstructorMetadata(member)) {
311 if (member.parameters) {
312 result.parameters =
313 member.parameters.map(function (p) { return _this.convertExpression(moduleName, p); });
314 }
315 }
316 }
317 return result;
318 };
319 MetadataBundler.prototype.convertStatics = function (moduleName, statics) {
320 var result = {};
321 for (var key in statics) {
322 var value = statics[key];
323 result[key] = schema_1.isFunctionMetadata(value) ? this.convertFunction(moduleName, value) : value;
324 }
325 return result;
326 };
327 MetadataBundler.prototype.convertFunction = function (moduleName, value) {
328 var _this = this;
329 return {
330 __symbolic: 'function',
331 parameters: value.parameters,
332 defaults: value.defaults && value.defaults.map(function (v) { return _this.convertValue(moduleName, v); }),
333 value: this.convertValue(moduleName, value.value)
334 };
335 };
336 MetadataBundler.prototype.convertValue = function (moduleName, value) {
337 var _this = this;
338 if (isPrimitive(value)) {
339 return value;
340 }
341 if (schema_1.isMetadataError(value)) {
342 return this.convertError(moduleName, value);
343 }
344 if (schema_1.isMetadataSymbolicExpression(value)) {
345 return this.convertExpression(moduleName, value);
346 }
347 if (Array.isArray(value)) {
348 return value.map(function (v) { return _this.convertValue(moduleName, v); });
349 }
350 // Otherwise it is a metadata object.
351 var object = value;
352 var result = {};
353 for (var key in object) {
354 result[key] = this.convertValue(moduleName, object[key]);
355 }
356 return result;
357 };
358 MetadataBundler.prototype.convertExpression = function (moduleName, value) {
359 if (value) {
360 switch (value.__symbolic) {
361 case 'error':
362 return this.convertError(moduleName, value);
363 case 'reference':
364 return this.convertReference(moduleName, value);
365 default:
366 return this.convertExpressionNode(moduleName, value);
367 }
368 }
369 return value;
370 };
371 MetadataBundler.prototype.convertError = function (module, value) {
372 return {
373 __symbolic: 'error',
374 message: value.message,
375 line: value.line,
376 character: value.character,
377 context: value.context, module: module
378 };
379 };
380 MetadataBundler.prototype.convertReference = function (moduleName, value) {
381 var _this = this;
382 var createReference = function (symbol) {
383 var declaration = symbol.declaration;
384 if (declaration.module.startsWith('.')) {
385 // Reference to a symbol defined in the module. Ensure it is converted then return a
386 // references to the final symbol.
387 _this.convertSymbol(symbol);
388 return {
389 __symbolic: 'reference',
390 get name() {
391 // Resolved lazily because private names are assigned late.
392 var canonicalSymbol = symbol.canonicalSymbol;
393 if (canonicalSymbol.isPrivate == null) {
394 throw Error('Invalid state: isPrivate was not initialized');
395 }
396 return canonicalSymbol.isPrivate ? canonicalSymbol.privateName : canonicalSymbol.name;
397 }
398 };
399 }
400 else {
401 // The symbol was a re-exported symbol from another module. Return a reference to the
402 // original imported symbol.
403 return { __symbolic: 'reference', name: declaration.name, module: declaration.module };
404 }
405 };
406 if (schema_1.isMetadataGlobalReferenceExpression(value)) {
407 var metadata = this.getMetadata(moduleName);
408 if (metadata && metadata.metadata && metadata.metadata[value.name]) {
409 // Reference to a symbol defined in the module
410 return createReference(this.canonicalSymbolOf(moduleName, value.name));
411 }
412 // If a reference has arguments, the arguments need to be converted.
413 if (value.arguments) {
414 return {
415 __symbolic: 'reference',
416 name: value.name,
417 arguments: value.arguments.map(function (a) { return _this.convertValue(moduleName, a); })
418 };
419 }
420 // Global references without arguments (such as to Math or JSON) are unmodified.
421 return value;
422 }
423 if (schema_1.isMetadataImportedSymbolReferenceExpression(value)) {
424 // References to imported symbols are separated into two, references to bundled modules and
425 // references to modules external to the bundle. If the module reference is relative it is
426 // assumed to be in the bundle. If it is Global it is assumed to be outside the bundle.
427 // References to symbols outside the bundle are left unmodified. References to symbol inside
428 // the bundle need to be converted to a bundle import reference reachable from the bundle
429 // index.
430 if (value.module.startsWith('.')) {
431 // Reference is to a symbol defined inside the module. Convert the reference to a reference
432 // to the canonical symbol.
433 var referencedModule = resolveModule(value.module, moduleName);
434 var referencedName = value.name;
435 return createReference(this.canonicalSymbolOf(referencedModule, referencedName));
436 }
437 // Value is a reference to a symbol defined outside the module.
438 if (value.arguments) {
439 // If a reference has arguments the arguments need to be converted.
440 return {
441 __symbolic: 'reference',
442 name: value.name,
443 module: value.module,
444 arguments: value.arguments.map(function (a) { return _this.convertValue(moduleName, a); })
445 };
446 }
447 return value;
448 }
449 if (schema_1.isMetadataModuleReferenceExpression(value)) {
450 // Cannot support references to bundled modules as the internal modules of a bundle are erased
451 // by the bundler.
452 if (value.module.startsWith('.')) {
453 return {
454 __symbolic: 'error',
455 message: 'Unsupported bundled module reference',
456 context: { module: value.module }
457 };
458 }
459 // References to unbundled modules are unmodified.
460 return value;
461 }
462 };
463 MetadataBundler.prototype.convertExpressionNode = function (moduleName, value) {
464 var result = { __symbolic: value.__symbolic };
465 for (var key in value) {
466 result[key] = this.convertValue(moduleName, value[key]);
467 }
468 return result;
469 };
470 MetadataBundler.prototype.symbolOf = function (module, name) {
471 var symbolKey = module + ":" + name;
472 var symbol = this.symbolMap.get(symbolKey);
473 if (!symbol) {
474 symbol = { module: module, name: name };
475 this.symbolMap.set(symbolKey, symbol);
476 }
477 return symbol;
478 };
479 MetadataBundler.prototype.canonicalSymbolOf = function (module, name) {
480 // Ensure the module has been seen.
481 this.exportAll(module);
482 var symbol = this.symbolOf(module, name);
483 if (!symbol.canonicalSymbol) {
484 this.canonicalizeSymbol(symbol);
485 }
486 return symbol;
487 };
488 return MetadataBundler;
489}());
490exports.MetadataBundler = MetadataBundler;
491var CompilerHostAdapter = (function () {
492 function CompilerHostAdapter(host) {
493 this.host = host;
494 this.collector = new collector_1.MetadataCollector();
495 }
496 CompilerHostAdapter.prototype.getMetadataFor = function (fileName) {
497 var sourceFile = this.host.getSourceFile(fileName + '.ts', ts.ScriptTarget.Latest);
498 return this.collector.getMetadata(sourceFile);
499 };
500 return CompilerHostAdapter;
501}());
502exports.CompilerHostAdapter = CompilerHostAdapter;
503function resolveModule(importName, from) {
504 if (importName.startsWith('.') && from) {
505 var normalPath = path.normalize(path.join(path.dirname(from), importName));
506 if (!normalPath.startsWith('.') && from.startsWith('.')) {
507 // path.normalize() preserves leading '../' but not './'. This adds it back.
508 normalPath = "." + path.sep + normalPath;
509 }
510 // Replace windows path delimiters with forward-slashes. Otherwise the paths are not
511 // TypeScript compatible when building the bundle.
512 return normalPath.replace(/\\/g, '/');
513 }
514 return importName;
515}
516function isPrimitive(o) {
517 return o === null || (typeof o !== 'function' && typeof o !== 'object');
518}
519function getRootExport(symbol) {
520 return symbol.reexportedAs ? getRootExport(symbol.reexportedAs) : symbol;
521}
522function getSymbolDeclaration(symbol) {
523 return symbol.exports ? getSymbolDeclaration(symbol.exports) : symbol;
524}
525//# sourceMappingURL=bundler.js.map
\No newline at end of file