feat(compiler): generate proper reexports in .ngfactory.ts
files to not need transitive deps for compiling .ngfactory.ts
files. (#13524)
Note: This checks the constructors of `@Injectable` classes more strictly. E.g this will fail now as the constructor argument has no `@Inject` nor is the type of the argument a DI token. ``` @Injectable() class MyService { constructor(dep: string) {} } ``` Last part of #12787 Closes #12787
This commit is contained in:
@ -7,7 +7,8 @@
|
||||
*/
|
||||
|
||||
|
||||
import {identifierModuleUrl, identifierName} from '../compile_metadata';
|
||||
import {StaticSymbol} from '../aot/static_symbol';
|
||||
import {CompileIdentifierMetadata} from '../compile_metadata';
|
||||
import {isBlank, isPresent} from '../facade/lang';
|
||||
|
||||
import {EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
|
||||
@ -16,17 +17,17 @@ import * as o from './output_ast';
|
||||
import {ImportResolver} from './path_util';
|
||||
|
||||
export class JavaScriptEmitter implements OutputEmitter {
|
||||
constructor(private _importGenerator: ImportResolver) {}
|
||||
emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string {
|
||||
const converter = new JsEmitterVisitor(moduleUrl);
|
||||
constructor(private _importResolver: ImportResolver) {}
|
||||
emitStatements(genFilePath: string, stmts: o.Statement[], exportedVars: string[]): string {
|
||||
const converter = new JsEmitterVisitor(genFilePath, this._importResolver);
|
||||
const ctx = EmitterVisitorContext.createRoot(exportedVars);
|
||||
converter.visitAllStatements(stmts, ctx);
|
||||
const srcParts: string[] = [];
|
||||
converter.importsWithPrefixes.forEach((prefix, importedModuleUrl) => {
|
||||
converter.importsWithPrefixes.forEach((prefix, importedFilePath) => {
|
||||
// Note: can't write the real word for import as it screws up system.js auto detection...
|
||||
srcParts.push(
|
||||
`var ${prefix} = req` +
|
||||
`uire('${this._importGenerator.fileNameToModuleName(importedModuleUrl, moduleUrl)}');`);
|
||||
`uire('${this._importResolver.fileNameToModuleName(importedFilePath, genFilePath)}');`);
|
||||
});
|
||||
srcParts.push(ctx.toSource());
|
||||
return srcParts.join('\n');
|
||||
@ -36,20 +37,23 @@ export class JavaScriptEmitter implements OutputEmitter {
|
||||
class JsEmitterVisitor extends AbstractJsEmitterVisitor {
|
||||
importsWithPrefixes = new Map<string, string>();
|
||||
|
||||
constructor(private _moduleUrl: string) { super(); }
|
||||
constructor(private _genFilePath: string, private _importResolver: ImportResolver) { super(); }
|
||||
|
||||
private _resolveStaticSymbol(value: CompileIdentifierMetadata): StaticSymbol {
|
||||
const reference = value.reference;
|
||||
if (!(reference instanceof StaticSymbol)) {
|
||||
throw new Error(`Internal error: unknown identifier ${JSON.stringify(value)}`);
|
||||
}
|
||||
return this._importResolver.getImportAs(reference) || reference;
|
||||
}
|
||||
|
||||
visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any {
|
||||
const name = identifierName(ast.value);
|
||||
const moduleUrl = identifierModuleUrl(ast.value);
|
||||
if (isBlank(name)) {
|
||||
console.error('>>>', ast.value);
|
||||
throw new Error(`Internal error: unknown identifier ${ast.value}`);
|
||||
}
|
||||
if (isPresent(moduleUrl) && moduleUrl != this._moduleUrl) {
|
||||
let prefix = this.importsWithPrefixes.get(moduleUrl);
|
||||
const {name, filePath} = this._resolveStaticSymbol(ast.value);
|
||||
if (filePath != this._genFilePath) {
|
||||
let prefix = this.importsWithPrefixes.get(filePath);
|
||||
if (isBlank(prefix)) {
|
||||
prefix = `import${this.importsWithPrefixes.size}`;
|
||||
this.importsWithPrefixes.set(moduleUrl, prefix);
|
||||
this.importsWithPrefixes.set(filePath, prefix);
|
||||
}
|
||||
ctx.print(`${prefix}.`);
|
||||
}
|
||||
|
Reference in New Issue
Block a user