2016-12-15 09:12:40 -08:00
|
|
|
/**
|
|
|
|
* @license
|
|
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
*/
|
2017-04-26 09:24:42 -07:00
|
|
|
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileNgModuleMetadata, CompileNgModuleSummary, CompilePipeMetadata, CompileProviderMetadata, CompileSummaryKind, CompileTypeMetadata, CompileTypeSummary} from '../compile_metadata';
|
|
|
|
import * as o from '../output/output_ast';
|
2016-12-15 09:12:40 -08:00
|
|
|
import {Summary, SummaryResolver} from '../summary_resolver';
|
2017-05-16 16:30:37 -07:00
|
|
|
import {OutputContext, ValueTransformer, ValueVisitor, visitValue} from '../util';
|
2016-12-15 09:12:40 -08:00
|
|
|
|
|
|
|
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
|
|
|
import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
|
2017-04-26 09:24:42 -07:00
|
|
|
import {summaryForJitFileName, summaryForJitName} from './util';
|
2016-12-15 09:12:40 -08:00
|
|
|
|
|
|
|
export function serializeSummaries(
|
2017-08-15 14:41:48 -07:00
|
|
|
srcFileName: string, forJitCtx: OutputContext, summaryResolver: SummaryResolver<StaticSymbol>,
|
2017-05-16 16:30:37 -07:00
|
|
|
symbolResolver: StaticSymbolResolver, symbols: ResolvedStaticSymbol[], types: {
|
2017-04-26 09:24:42 -07:00
|
|
|
summary: CompileTypeSummary,
|
|
|
|
metadata: CompileNgModuleMetadata | CompileDirectiveMetadata | CompilePipeMetadata |
|
|
|
|
CompileTypeMetadata
|
2017-05-16 16:30:37 -07:00
|
|
|
}[]): {json: string, exportAs: {symbol: StaticSymbol, exportAs: string}[]} {
|
2017-09-28 09:39:16 -07:00
|
|
|
const toJsonSerializer = new ToJsonSerializer(symbolResolver, summaryResolver, srcFileName);
|
2017-05-16 16:30:37 -07:00
|
|
|
const forJitSerializer = new ForJitSerializer(forJitCtx, symbolResolver);
|
2016-12-15 09:12:40 -08:00
|
|
|
|
|
|
|
// for symbols, we use everything except for the class metadata itself
|
|
|
|
// (we keep the statics though), as the class metadata is contained in the
|
|
|
|
// CompileTypeSummary.
|
|
|
|
symbols.forEach(
|
2017-08-22 17:07:55 -07:00
|
|
|
(resolvedSymbol) => toJsonSerializer.addSummary(
|
2016-12-15 09:12:40 -08:00
|
|
|
{symbol: resolvedSymbol.symbol, metadata: resolvedSymbol.metadata}));
|
|
|
|
|
|
|
|
// Add type summaries.
|
2017-04-26 09:24:42 -07:00
|
|
|
types.forEach(({summary, metadata}) => {
|
|
|
|
forJitSerializer.addSourceType(summary, metadata);
|
2017-08-22 17:07:55 -07:00
|
|
|
toJsonSerializer.addSummary(
|
|
|
|
{symbol: summary.type.reference, metadata: undefined, type: summary});
|
|
|
|
});
|
|
|
|
toJsonSerializer.unprocessedSymbolSummariesBySymbol.forEach((summary) => {
|
|
|
|
if (summaryResolver.isLibraryFile(summary.symbol.filePath) && summary.type) {
|
|
|
|
forJitSerializer.addLibType(summary.type);
|
2016-12-15 09:12:40 -08:00
|
|
|
}
|
|
|
|
});
|
2017-08-22 17:07:55 -07:00
|
|
|
|
2017-09-28 09:39:16 -07:00
|
|
|
const {json, exportAs} = toJsonSerializer.serialize();
|
2017-05-16 16:30:37 -07:00
|
|
|
forJitSerializer.serialize(exportAs);
|
|
|
|
return {json, exportAs};
|
2016-12-15 09:12:40 -08:00
|
|
|
}
|
|
|
|
|
2017-08-15 14:41:48 -07:00
|
|
|
export function deserializeSummaries(
|
|
|
|
symbolCache: StaticSymbolCache, summaryResolver: SummaryResolver<StaticSymbol>,
|
2017-09-28 09:39:16 -07:00
|
|
|
libraryFileName: string, json: string): {
|
|
|
|
moduleName: string | null,
|
|
|
|
summaries: Summary<StaticSymbol>[],
|
|
|
|
importAs: {symbol: StaticSymbol, importAs: string}[]
|
|
|
|
} {
|
2017-08-15 14:41:48 -07:00
|
|
|
const deserializer = new FromJsonDeserializer(symbolCache, summaryResolver);
|
|
|
|
return deserializer.deserialize(libraryFileName, json);
|
2016-12-15 09:12:40 -08:00
|
|
|
}
|
|
|
|
|
2017-05-23 13:40:50 -07:00
|
|
|
export function createForJitStub(outputCtx: OutputContext, reference: StaticSymbol) {
|
|
|
|
return createSummaryForJitFunction(outputCtx, reference, o.NULL_EXPR);
|
|
|
|
}
|
|
|
|
|
|
|
|
function createSummaryForJitFunction(
|
|
|
|
outputCtx: OutputContext, reference: StaticSymbol, value: o.Expression) {
|
|
|
|
const fnName = summaryForJitName(reference.name);
|
|
|
|
outputCtx.statements.push(
|
|
|
|
o.fn([], [new o.ReturnStatement(value)], new o.ArrayType(o.DYNAMIC_TYPE)).toDeclStmt(fnName, [
|
|
|
|
o.StmtModifier.Final, o.StmtModifier.Exported
|
|
|
|
]));
|
|
|
|
}
|
|
|
|
|
2017-08-22 17:07:55 -07:00
|
|
|
const enum SerializationFlags {
|
|
|
|
None = 0,
|
|
|
|
ResolveValue = 1,
|
|
|
|
}
|
|
|
|
|
2017-04-26 09:24:42 -07:00
|
|
|
class ToJsonSerializer extends ValueTransformer {
|
2016-12-27 09:36:47 -08:00
|
|
|
// Note: This only contains symbols without members.
|
2017-08-22 17:07:55 -07:00
|
|
|
private symbols: StaticSymbol[] = [];
|
2016-12-15 09:12:40 -08:00
|
|
|
private indexBySymbol = new Map<StaticSymbol, number>();
|
|
|
|
// This now contains a `__symbol: number` in the place of
|
|
|
|
// StaticSymbols, but otherwise has the same shape as the original objects.
|
|
|
|
private processedSummaryBySymbol = new Map<StaticSymbol, any>();
|
|
|
|
private processedSummaries: any[] = [];
|
2017-09-28 09:39:16 -07:00
|
|
|
private moduleName: string|null;
|
2016-12-15 09:12:40 -08:00
|
|
|
|
2017-08-22 17:07:55 -07:00
|
|
|
unprocessedSymbolSummariesBySymbol = new Map<StaticSymbol, Summary<StaticSymbol>>();
|
|
|
|
|
2016-12-27 09:36:47 -08:00
|
|
|
constructor(
|
|
|
|
private symbolResolver: StaticSymbolResolver,
|
2017-09-28 09:39:16 -07:00
|
|
|
private summaryResolver: SummaryResolver<StaticSymbol>, private srcFileName: string) {
|
2016-12-27 09:36:47 -08:00
|
|
|
super();
|
2017-09-28 09:39:16 -07:00
|
|
|
this.moduleName = symbolResolver.getKnownModuleName(srcFileName);
|
2016-12-27 09:36:47 -08:00
|
|
|
}
|
2016-12-15 09:12:40 -08:00
|
|
|
|
2017-08-22 17:07:55 -07:00
|
|
|
addSummary(summary: Summary<StaticSymbol>) {
|
|
|
|
let unprocessedSummary = this.unprocessedSymbolSummariesBySymbol.get(summary.symbol);
|
2016-12-15 09:12:40 -08:00
|
|
|
let processedSummary = this.processedSummaryBySymbol.get(summary.symbol);
|
2017-08-22 17:07:55 -07:00
|
|
|
if (!unprocessedSummary) {
|
|
|
|
unprocessedSummary = {symbol: summary.symbol, metadata: undefined};
|
|
|
|
this.unprocessedSymbolSummariesBySymbol.set(summary.symbol, unprocessedSummary);
|
|
|
|
processedSummary = {symbol: this.processValue(summary.symbol, SerializationFlags.None)};
|
2016-12-15 09:12:40 -08:00
|
|
|
this.processedSummaries.push(processedSummary);
|
|
|
|
this.processedSummaryBySymbol.set(summary.symbol, processedSummary);
|
|
|
|
}
|
2017-08-22 17:07:55 -07:00
|
|
|
if (!unprocessedSummary.metadata && summary.metadata) {
|
|
|
|
let metadata = summary.metadata || {};
|
|
|
|
if (metadata.__symbolic === 'class') {
|
|
|
|
// For classes, we keep everything except their class decorators.
|
|
|
|
// We need to keep e.g. the ctor args, method names, method decorators
|
|
|
|
// so that the class can be extended in another compilation unit.
|
|
|
|
// We don't keep the class decorators as
|
|
|
|
// 1) they refer to data
|
|
|
|
// that should not cause a rebuild of downstream compilation units
|
|
|
|
// (e.g. inline templates of @Component, or @NgModule.declarations)
|
|
|
|
// 2) their data is already captured in TypeSummaries, e.g. DirectiveSummary.
|
|
|
|
const clone: {[key: string]: any} = {};
|
|
|
|
Object.keys(metadata).forEach((propName) => {
|
|
|
|
if (propName !== 'decorators') {
|
|
|
|
clone[propName] = metadata[propName];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
metadata = clone;
|
|
|
|
}
|
|
|
|
unprocessedSummary.metadata = metadata;
|
|
|
|
processedSummary.metadata = this.processValue(metadata, SerializationFlags.ResolveValue);
|
2016-12-15 09:12:40 -08:00
|
|
|
}
|
2017-08-22 17:07:55 -07:00
|
|
|
if (!unprocessedSummary.type && summary.type) {
|
|
|
|
unprocessedSummary.type = summary.type;
|
|
|
|
// Note: We don't add the summaries of all referenced symbols as for the ResolvedSymbols,
|
|
|
|
// as the type summaries already contain the transitive data that they require
|
|
|
|
// (in a minimal way).
|
|
|
|
processedSummary.type = this.processValue(summary.type, SerializationFlags.None);
|
|
|
|
// except for reexported directives / pipes, so we need to store
|
|
|
|
// their summaries explicitly.
|
|
|
|
if (summary.type.summaryKind === CompileSummaryKind.NgModule) {
|
|
|
|
const ngModuleSummary = <CompileNgModuleSummary>summary.type;
|
|
|
|
ngModuleSummary.exportedDirectives.concat(ngModuleSummary.exportedPipes).forEach((id) => {
|
|
|
|
const symbol: StaticSymbol = id.reference;
|
|
|
|
if (this.summaryResolver.isLibraryFile(symbol.filePath) &&
|
|
|
|
!this.unprocessedSymbolSummariesBySymbol.has(symbol)) {
|
|
|
|
const summary = this.summaryResolver.resolveSummary(symbol);
|
|
|
|
if (summary) {
|
|
|
|
this.addSummary(summary);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2016-12-15 09:12:40 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-28 09:39:16 -07:00
|
|
|
serialize(): {json: string, exportAs: {symbol: StaticSymbol, exportAs: string}[]} {
|
2016-12-27 09:36:47 -08:00
|
|
|
const exportAs: {symbol: StaticSymbol, exportAs: string}[] = [];
|
|
|
|
const json = JSON.stringify({
|
2017-09-28 09:39:16 -07:00
|
|
|
moduleName: this.moduleName,
|
2016-12-15 09:12:40 -08:00
|
|
|
summaries: this.processedSummaries,
|
|
|
|
symbols: this.symbols.map((symbol, index) => {
|
2016-12-27 09:36:47 -08:00
|
|
|
symbol.assertNoMembers();
|
2017-03-24 09:59:58 -07:00
|
|
|
let importAs: string = undefined !;
|
2016-12-27 09:36:47 -08:00
|
|
|
if (this.summaryResolver.isLibraryFile(symbol.filePath)) {
|
2017-08-22 17:07:55 -07:00
|
|
|
const summary = this.unprocessedSymbolSummariesBySymbol.get(symbol);
|
|
|
|
if (!summary || !summary.metadata || summary.metadata.__symbolic !== 'interface') {
|
|
|
|
importAs = `${symbol.name}_${index}`;
|
|
|
|
exportAs.push({symbol, exportAs: importAs});
|
|
|
|
}
|
2016-12-27 09:36:47 -08:00
|
|
|
}
|
2016-12-15 09:12:40 -08:00
|
|
|
return {
|
|
|
|
__symbol: index,
|
|
|
|
name: symbol.name,
|
2017-09-28 09:39:16 -07:00
|
|
|
filePath: this.summaryResolver.toSummaryFileName(symbol.filePath, this.srcFileName),
|
2016-12-27 09:36:47 -08:00
|
|
|
importAs: importAs
|
2016-12-15 09:12:40 -08:00
|
|
|
};
|
|
|
|
})
|
|
|
|
});
|
2016-12-27 09:36:47 -08:00
|
|
|
return {json, exportAs};
|
2016-12-15 09:12:40 -08:00
|
|
|
}
|
|
|
|
|
2017-08-22 17:07:55 -07:00
|
|
|
private processValue(value: any, flags: SerializationFlags): any {
|
|
|
|
return visitValue(value, this, flags);
|
|
|
|
}
|
2016-12-15 09:12:40 -08:00
|
|
|
|
|
|
|
visitOther(value: any, context: any): any {
|
|
|
|
if (value instanceof StaticSymbol) {
|
2017-08-22 17:07:55 -07:00
|
|
|
let baseSymbol = this.symbolResolver.getStaticSymbol(value.filePath, value.name);
|
|
|
|
const index = this.visitStaticSymbol(baseSymbol, context);
|
|
|
|
return {__symbol: index, members: value.members};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns null if the options.resolveValue is true, and the summary for the symbol
|
|
|
|
* resolved to a type or could not be resolved.
|
|
|
|
*/
|
|
|
|
private visitStaticSymbol(baseSymbol: StaticSymbol, flags: SerializationFlags): number {
|
|
|
|
let index: number|undefined|null = this.indexBySymbol.get(baseSymbol);
|
|
|
|
let summary: Summary<StaticSymbol>|null = null;
|
|
|
|
if (flags & SerializationFlags.ResolveValue &&
|
|
|
|
this.summaryResolver.isLibraryFile(baseSymbol.filePath)) {
|
|
|
|
if (this.unprocessedSymbolSummariesBySymbol.has(baseSymbol)) {
|
|
|
|
// the summary for this symbol was already added
|
|
|
|
// -> nothing to do.
|
|
|
|
return index !;
|
|
|
|
}
|
|
|
|
summary = this.loadSummary(baseSymbol);
|
|
|
|
if (summary && summary.metadata instanceof StaticSymbol) {
|
|
|
|
// The summary is a reexport
|
|
|
|
index = this.visitStaticSymbol(summary.metadata, flags);
|
|
|
|
// reset the summary as it is just a reexport, so we don't want to store it.
|
|
|
|
summary = null;
|
|
|
|
}
|
|
|
|
} else if (index != null) {
|
2017-01-30 15:32:08 -08:00
|
|
|
// Note: == on purpose to compare with undefined!
|
2017-08-22 17:07:55 -07:00
|
|
|
// No summary and the symbol is already added -> nothing to do.
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
// Note: == on purpose to compare with undefined!
|
|
|
|
if (index == null) {
|
|
|
|
index = this.symbols.length;
|
|
|
|
this.symbols.push(baseSymbol);
|
|
|
|
}
|
|
|
|
this.indexBySymbol.set(baseSymbol, index);
|
|
|
|
if (summary) {
|
|
|
|
this.addSummary(summary);
|
|
|
|
}
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
private loadSummary(symbol: StaticSymbol): Summary<StaticSymbol>|null {
|
|
|
|
let summary = this.summaryResolver.resolveSummary(symbol);
|
|
|
|
if (!summary) {
|
|
|
|
// some symbols might originate from a plain typescript library
|
|
|
|
// that just exported .d.ts and .metadata.json files, i.e. where no summary
|
|
|
|
// files were created.
|
|
|
|
const resolvedSymbol = this.symbolResolver.resolveSymbol(symbol);
|
|
|
|
if (resolvedSymbol) {
|
|
|
|
summary = {symbol: resolvedSymbol.symbol, metadata: resolvedSymbol.metadata};
|
2016-12-15 09:12:40 -08:00
|
|
|
}
|
|
|
|
}
|
2017-08-22 17:07:55 -07:00
|
|
|
return summary;
|
2016-12-15 09:12:40 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-26 09:24:42 -07:00
|
|
|
class ForJitSerializer {
|
|
|
|
private data = new Map<StaticSymbol, {
|
|
|
|
summary: CompileTypeSummary,
|
|
|
|
metadata: CompileNgModuleMetadata|CompileDirectiveMetadata|CompilePipeMetadata|
|
|
|
|
CompileTypeMetadata|null,
|
|
|
|
isLibrary: boolean
|
|
|
|
}>();
|
|
|
|
|
2017-05-16 16:30:37 -07:00
|
|
|
constructor(private outputCtx: OutputContext, private symbolResolver: StaticSymbolResolver) {}
|
2017-04-26 09:24:42 -07:00
|
|
|
|
|
|
|
addSourceType(
|
|
|
|
summary: CompileTypeSummary, metadata: CompileNgModuleMetadata|CompileDirectiveMetadata|
|
|
|
|
CompilePipeMetadata|CompileTypeMetadata) {
|
|
|
|
this.data.set(summary.type.reference, {summary, metadata, isLibrary: false});
|
|
|
|
}
|
|
|
|
|
|
|
|
addLibType(summary: CompileTypeSummary) {
|
|
|
|
this.data.set(summary.type.reference, {summary, metadata: null, isLibrary: true});
|
|
|
|
}
|
|
|
|
|
2017-05-16 16:30:37 -07:00
|
|
|
serialize(exportAs: {symbol: StaticSymbol, exportAs: string}[]): void {
|
2017-04-26 09:24:42 -07:00
|
|
|
const ngModuleSymbols = new Set<StaticSymbol>();
|
|
|
|
|
|
|
|
Array.from(this.data.values()).forEach(({summary, metadata, isLibrary}) => {
|
|
|
|
if (summary.summaryKind === CompileSummaryKind.NgModule) {
|
|
|
|
// collect the symbols that refer to NgModule classes.
|
|
|
|
// Note: we can't just rely on `summary.type.summaryKind` to determine this as
|
|
|
|
// we don't add the summaries of all referenced symbols when we serialize type summaries.
|
|
|
|
// See serializeSummaries for details.
|
|
|
|
ngModuleSymbols.add(summary.type.reference);
|
|
|
|
const modSummary = <CompileNgModuleSummary>summary;
|
|
|
|
modSummary.modules.forEach((mod) => { ngModuleSymbols.add(mod.reference); });
|
|
|
|
}
|
|
|
|
if (!isLibrary) {
|
|
|
|
const fnName = summaryForJitName(summary.type.reference.name);
|
2017-05-23 13:40:50 -07:00
|
|
|
createSummaryForJitFunction(
|
|
|
|
this.outputCtx, summary.type.reference,
|
|
|
|
this.serializeSummaryWithDeps(summary, metadata !));
|
2017-04-26 09:24:42 -07:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
exportAs.forEach((entry) => {
|
|
|
|
const symbol = entry.symbol;
|
|
|
|
if (ngModuleSymbols.has(symbol)) {
|
|
|
|
const jitExportAsName = summaryForJitName(entry.exportAs);
|
2017-05-16 16:30:37 -07:00
|
|
|
this.outputCtx.statements.push(
|
|
|
|
o.variable(jitExportAsName).set(this.serializeSummaryRef(symbol)).toDeclStmt(null, [
|
|
|
|
o.StmtModifier.Exported
|
|
|
|
]));
|
2017-04-26 09:24:42 -07:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private serializeSummaryWithDeps(
|
|
|
|
summary: CompileTypeSummary, metadata: CompileNgModuleMetadata|CompileDirectiveMetadata|
|
|
|
|
CompilePipeMetadata|CompileTypeMetadata): o.Expression {
|
|
|
|
const expressions: o.Expression[] = [this.serializeSummary(summary)];
|
|
|
|
let providers: CompileProviderMetadata[] = [];
|
|
|
|
if (metadata instanceof CompileNgModuleMetadata) {
|
|
|
|
expressions.push(...
|
|
|
|
// For directives / pipes, we only add the declared ones,
|
|
|
|
// and rely on transitively importing NgModules to get the transitive
|
|
|
|
// summaries.
|
|
|
|
metadata.declaredDirectives.concat(metadata.declaredPipes)
|
|
|
|
.map(type => type.reference)
|
|
|
|
// For modules,
|
|
|
|
// we also add the summaries for modules
|
|
|
|
// from libraries.
|
|
|
|
// This is ok as we produce reexports for all transitive modules.
|
|
|
|
.concat(metadata.transitiveModule.modules.map(type => type.reference)
|
|
|
|
.filter(ref => ref !== metadata.type.reference))
|
|
|
|
.map((ref) => this.serializeSummaryRef(ref)));
|
|
|
|
// Note: We don't use `NgModuleSummary.providers`, as that one is transitive,
|
|
|
|
// and we already have transitive modules.
|
|
|
|
providers = metadata.providers;
|
|
|
|
} else if (summary.summaryKind === CompileSummaryKind.Directive) {
|
|
|
|
const dirSummary = <CompileDirectiveSummary>summary;
|
|
|
|
providers = dirSummary.providers.concat(dirSummary.viewProviders);
|
|
|
|
}
|
|
|
|
// Note: We can't just refer to the `ngsummary.ts` files for `useClass` providers (as we do for
|
|
|
|
// declaredDirectives / declaredPipes), as we allow
|
|
|
|
// providers without ctor arguments to skip the `@Injectable` decorator,
|
|
|
|
// i.e. we didn't generate .ngsummary.ts files for these.
|
|
|
|
expressions.push(
|
|
|
|
...providers.filter(provider => !!provider.useClass).map(provider => this.serializeSummary({
|
|
|
|
summaryKind: CompileSummaryKind.Injectable, type: provider.useClass
|
|
|
|
} as CompileTypeSummary)));
|
|
|
|
return o.literalArr(expressions);
|
|
|
|
}
|
|
|
|
|
|
|
|
private serializeSummaryRef(typeSymbol: StaticSymbol): o.Expression {
|
|
|
|
const jitImportedSymbol = this.symbolResolver.getStaticSymbol(
|
|
|
|
summaryForJitFileName(typeSymbol.filePath), summaryForJitName(typeSymbol.name));
|
2017-05-16 16:30:37 -07:00
|
|
|
return this.outputCtx.importExpr(jitImportedSymbol);
|
2017-04-26 09:24:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
private serializeSummary(data: {[key: string]: any}): o.Expression {
|
2017-05-16 16:30:37 -07:00
|
|
|
const outputCtx = this.outputCtx;
|
|
|
|
|
2017-04-26 09:24:42 -07:00
|
|
|
class Transformer implements ValueVisitor {
|
|
|
|
visitArray(arr: any[], context: any): any {
|
|
|
|
return o.literalArr(arr.map(entry => visitValue(entry, this, context)));
|
|
|
|
}
|
|
|
|
visitStringMap(map: {[key: string]: any}, context: any): any {
|
|
|
|
return new o.LiteralMapExpr(Object.keys(map).map(
|
2017-07-05 14:51:39 -07:00
|
|
|
(key) => new o.LiteralMapEntry(key, visitValue(map[key], this, context), false)));
|
2017-04-26 09:24:42 -07:00
|
|
|
}
|
|
|
|
visitPrimitive(value: any, context: any): any { return o.literal(value); }
|
|
|
|
visitOther(value: any, context: any): any {
|
|
|
|
if (value instanceof StaticSymbol) {
|
2017-05-16 16:30:37 -07:00
|
|
|
return outputCtx.importExpr(value);
|
2017-04-26 09:24:42 -07:00
|
|
|
} else {
|
|
|
|
throw new Error(`Illegal State: Encountered value ${value}`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return visitValue(data, new Transformer(), null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class FromJsonDeserializer extends ValueTransformer {
|
2016-12-15 09:12:40 -08:00
|
|
|
private symbols: StaticSymbol[];
|
|
|
|
|
2017-08-15 14:41:48 -07:00
|
|
|
constructor(
|
|
|
|
private symbolCache: StaticSymbolCache,
|
|
|
|
private summaryResolver: SummaryResolver<StaticSymbol>) {
|
|
|
|
super();
|
|
|
|
}
|
2016-12-15 09:12:40 -08:00
|
|
|
|
2017-09-28 09:39:16 -07:00
|
|
|
deserialize(libraryFileName: string, json: string): {
|
|
|
|
moduleName: string | null,
|
|
|
|
summaries: Summary<StaticSymbol>[],
|
|
|
|
importAs: {symbol: StaticSymbol, importAs: string}[]
|
|
|
|
} {
|
|
|
|
const data: {moduleName: string | null, summaries: any[], symbols: any[]} = JSON.parse(json);
|
2016-12-27 09:36:47 -08:00
|
|
|
const importAs: {symbol: StaticSymbol, importAs: string}[] = [];
|
|
|
|
this.symbols = [];
|
|
|
|
data.symbols.forEach((serializedSymbol) => {
|
2017-08-15 14:41:48 -07:00
|
|
|
const symbol = this.symbolCache.get(
|
|
|
|
this.summaryResolver.fromSummaryFileName(serializedSymbol.filePath, libraryFileName),
|
|
|
|
serializedSymbol.name);
|
2016-12-27 09:36:47 -08:00
|
|
|
this.symbols.push(symbol);
|
|
|
|
if (serializedSymbol.importAs) {
|
|
|
|
importAs.push({symbol: symbol, importAs: serializedSymbol.importAs});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
const summaries = visitValue(data.summaries, this, null);
|
2017-09-28 09:39:16 -07:00
|
|
|
return {moduleName: data.moduleName, summaries, importAs};
|
2016-12-15 09:12:40 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
visitStringMap(map: {[key: string]: any}, context: any): any {
|
|
|
|
if ('__symbol' in map) {
|
2016-12-27 09:36:47 -08:00
|
|
|
const baseSymbol = this.symbols[map['__symbol']];
|
|
|
|
const members = map['members'];
|
|
|
|
return members.length ? this.symbolCache.get(baseSymbol.filePath, baseSymbol.name, members) :
|
|
|
|
baseSymbol;
|
2016-12-15 09:12:40 -08:00
|
|
|
} else {
|
|
|
|
return super.visitStringMap(map, context);
|
|
|
|
}
|
|
|
|
}
|
perf: switch angular to use StaticInjector instead of ReflectiveInjector
This change allows ReflectiveInjector to be tree shaken resulting
in not needed Reflect polyfil and smaller bundles.
Code savings for HelloWorld using Closure:
Reflective: bundle.js: 105,864(34,190 gzip)
Static: bundle.js: 154,889(33,555 gzip)
645( 2%)
BREAKING CHANGE:
`platformXXXX()` no longer accepts providers which depend on reflection.
Specifically the method signature when from `Provider[]` to
`StaticProvider[]`.
Example:
Before:
```
[
MyClass,
{provide: ClassA, useClass: SubClassA}
]
```
After:
```
[
{provide: MyClass, deps: [Dep1,...]},
{provide: ClassA, useClass: SubClassA, deps: [Dep1,...]}
]
```
NOTE: This only applies to platform creation and providers for the JIT
compiler. It does not apply to `@Compotent` or `@NgModule` provides
declarations.
Benchpress note: Previously Benchpress also supported reflective
provides, which now require static providers.
DEPRECATION:
- `ReflectiveInjector` is now deprecated as it will be remove. Use
`Injector.create` as a replacement.
closes #18496
2017-08-03 12:33:29 -07:00
|
|
|
}
|