UNPKG

@angular/compiler

Version:

Angular - the compiler library

762 lines • 148 kB
/** * @license * Copyright Google LLC 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 */ import { componentFactoryName, flatten, identifierName, templateSourceUrl } from '../compile_metadata'; import { ConstantPool } from '../constant_pool'; import { ViewEncapsulation } from '../core'; import { MessageBundle } from '../i18n/message_bundle'; import { createTokenForExternalReference, Identifiers } from '../identifiers'; import { HtmlParser } from '../ml_parser/html_parser'; import { removeWhitespaces } from '../ml_parser/html_whitespaces'; import { DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig } from '../ml_parser/interpolation_config'; import * as o from '../output/output_ast'; import { compileNgModuleFromRender2 as compileR3Module } from '../render3/r3_module_compiler'; import { compilePipeFromRender2 as compileR3Pipe } from '../render3/r3_pipe_compiler'; import { htmlAstToRender3Ast } from '../render3/r3_template_transform'; import { compileComponentFromRender2 as compileR3Component, compileDirectiveFromRender2 as compileR3Directive } from '../render3/view/compiler'; import { DomElementSchemaRegistry } from '../schema/dom_element_schema_registry'; import { BindingParser } from '../template_parser/binding_parser'; import { error, newArray, syntaxError, visitValue } from '../util'; import { GeneratedFile } from './generated_file'; import { listLazyRoutes, parseLazyRoute } from './lazy_routes'; import { StaticSymbol } from './static_symbol'; import { createForJitStub, serializeSummaries } from './summary_serializer'; import { ngfactoryFilePath, normalizeGenFileSuffix, splitTypescriptSuffix, summaryFileName, summaryForJitFileName } from './util'; export class AotCompiler { constructor(_config, _options, _host, reflector, _metadataResolver, _templateParser, _styleCompiler, _viewCompiler, _typeCheckCompiler, _ngModuleCompiler, _injectableCompiler, _outputEmitter, _summaryResolver, _symbolResolver) { this._config = _config; this._options = _options; this._host = _host; this.reflector = reflector; this._metadataResolver = _metadataResolver; this._templateParser = _templateParser; this._styleCompiler = _styleCompiler; this._viewCompiler = _viewCompiler; this._typeCheckCompiler = _typeCheckCompiler; this._ngModuleCompiler = _ngModuleCompiler; this._injectableCompiler = _injectableCompiler; this._outputEmitter = _outputEmitter; this._summaryResolver = _summaryResolver; this._symbolResolver = _symbolResolver; this._templateAstCache = new Map(); this._analyzedFiles = new Map(); this._analyzedFilesForInjectables = new Map(); } clearCache() { this._metadataResolver.clearCache(); } analyzeModulesSync(rootFiles) { const analyzeResult = analyzeAndValidateNgModules(rootFiles, this._host, this._symbolResolver, this._metadataResolver); analyzeResult.ngModules.forEach(ngModule => this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(ngModule.type.reference, true)); return analyzeResult; } analyzeModulesAsync(rootFiles) { const analyzeResult = analyzeAndValidateNgModules(rootFiles, this._host, this._symbolResolver, this._metadataResolver); return Promise .all(analyzeResult.ngModules.map(ngModule => this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(ngModule.type.reference, false))) .then(() => analyzeResult); } _analyzeFile(fileName) { let analyzedFile = this._analyzedFiles.get(fileName); if (!analyzedFile) { analyzedFile = analyzeFile(this._host, this._symbolResolver, this._metadataResolver, fileName); this._analyzedFiles.set(fileName, analyzedFile); } return analyzedFile; } _analyzeFileForInjectables(fileName) { let analyzedFile = this._analyzedFilesForInjectables.get(fileName); if (!analyzedFile) { analyzedFile = analyzeFileForInjectables(this._host, this._symbolResolver, this._metadataResolver, fileName); this._analyzedFilesForInjectables.set(fileName, analyzedFile); } return analyzedFile; } findGeneratedFileNames(fileName) { const genFileNames = []; const file = this._analyzeFile(fileName); // Make sure we create a .ngfactory if we have a injectable/directive/pipe/NgModule // or a reference to a non source file. // Note: This is overestimating the required .ngfactory files as the real calculation is harder. // Only do this for StubEmitFlags.Basic, as adding a type check block // does not change this file (as we generate type check blocks based on NgModules). if (this._options.allowEmptyCodegenFiles || file.directives.length || file.pipes.length || file.injectables.length || file.ngModules.length || file.exportsNonSourceFiles) { genFileNames.push(ngfactoryFilePath(file.fileName, true)); if (this._options.enableSummariesForJit) { genFileNames.push(summaryForJitFileName(file.fileName, true)); } } const fileSuffix = normalizeGenFileSuffix(splitTypescriptSuffix(file.fileName, true)[1]); file.directives.forEach((dirSymbol) => { const compMeta = this._metadataResolver.getNonNormalizedDirectiveMetadata(dirSymbol).metadata; if (!compMeta.isComponent) { return; } // Note: compMeta is a component and therefore template is non null. compMeta.template.styleUrls.forEach((styleUrl) => { const normalizedUrl = this._host.resourceNameToFileName(styleUrl, file.fileName); if (!normalizedUrl) { throw syntaxError(`Couldn't resolve resource ${styleUrl} relative to ${file.fileName}`); } const needsShim = (compMeta.template.encapsulation || this._config.defaultEncapsulation) === ViewEncapsulation.Emulated; genFileNames.push(_stylesModuleUrl(normalizedUrl, needsShim, fileSuffix)); if (this._options.allowEmptyCodegenFiles) { genFileNames.push(_stylesModuleUrl(normalizedUrl, !needsShim, fileSuffix)); } }); }); return genFileNames; } emitBasicStub(genFileName, originalFileName) { const outputCtx = this._createOutputContext(genFileName); if (genFileName.endsWith('.ngfactory.ts')) { if (!originalFileName) { throw new Error(`Assertion error: require the original file for .ngfactory.ts stubs. File: ${genFileName}`); } const originalFile = this._analyzeFile(originalFileName); this._createNgFactoryStub(outputCtx, originalFile, 1 /* Basic */); } else if (genFileName.endsWith('.ngsummary.ts')) { if (this._options.enableSummariesForJit) { if (!originalFileName) { throw new Error(`Assertion error: require the original file for .ngsummary.ts stubs. File: ${genFileName}`); } const originalFile = this._analyzeFile(originalFileName); _createEmptyStub(outputCtx); originalFile.ngModules.forEach(ngModule => { // create exports that user code can reference createForJitStub(outputCtx, ngModule.type.reference); }); } } else if (genFileName.endsWith('.ngstyle.ts')) { _createEmptyStub(outputCtx); } // Note: for the stubs, we don't need a property srcFileUrl, // as later on in emitAllImpls we will create the proper GeneratedFiles with the // correct srcFileUrl. // This is good as e.g. for .ngstyle.ts files we can't derive // the url of components based on the genFileUrl. return this._codegenSourceModule('unknown', outputCtx); } emitTypeCheckStub(genFileName, originalFileName) { const originalFile = this._analyzeFile(originalFileName); const outputCtx = this._createOutputContext(genFileName); if (genFileName.endsWith('.ngfactory.ts')) { this._createNgFactoryStub(outputCtx, originalFile, 2 /* TypeCheck */); } return outputCtx.statements.length > 0 ? this._codegenSourceModule(originalFile.fileName, outputCtx) : null; } loadFilesAsync(fileNames, tsFiles) { const files = fileNames.map(fileName => this._analyzeFile(fileName)); const loadingPromises = []; files.forEach(file => file.ngModules.forEach(ngModule => loadingPromises.push(this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(ngModule.type.reference, false)))); const analyzedInjectables = tsFiles.map(tsFile => this._analyzeFileForInjectables(tsFile)); return Promise.all(loadingPromises).then(_ => ({ analyzedModules: mergeAndValidateNgFiles(files), analyzedInjectables: analyzedInjectables, })); } loadFilesSync(fileNames, tsFiles) { const files = fileNames.map(fileName => this._analyzeFile(fileName)); files.forEach(file => file.ngModules.forEach(ngModule => this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(ngModule.type.reference, true))); const analyzedInjectables = tsFiles.map(tsFile => this._analyzeFileForInjectables(tsFile)); return { analyzedModules: mergeAndValidateNgFiles(files), analyzedInjectables: analyzedInjectables, }; } _createNgFactoryStub(outputCtx, file, emitFlags) { let componentId = 0; file.ngModules.forEach((ngModuleMeta, ngModuleIndex) => { // Note: the code below needs to executed for StubEmitFlags.Basic and StubEmitFlags.TypeCheck, // so we don't change the .ngfactory file too much when adding the type-check block. // create exports that user code can reference this._ngModuleCompiler.createStub(outputCtx, ngModuleMeta.type.reference); // add references to the symbols from the metadata. // These can be used by the type check block for components, // and they also cause TypeScript to include these files into the program too, // which will make them part of the analyzedFiles. const externalReferences = [ // Add references that are available from all the modules and imports. ...ngModuleMeta.transitiveModule.directives.map(d => d.reference), ...ngModuleMeta.transitiveModule.pipes.map(d => d.reference), ...ngModuleMeta.importedModules.map(m => m.type.reference), ...ngModuleMeta.exportedModules.map(m => m.type.reference), // Add references that might be inserted by the template compiler. ...this._externalIdentifierReferences([Identifiers.TemplateRef, Identifiers.ElementRef]), ]; const externalReferenceVars = new Map(); externalReferences.forEach((ref, typeIndex) => { externalReferenceVars.set(ref, `_decl${ngModuleIndex}_${typeIndex}`); }); externalReferenceVars.forEach((varName, reference) => { outputCtx.statements.push(o.variable(varName) .set(o.NULL_EXPR.cast(o.DYNAMIC_TYPE)) .toDeclStmt(o.expressionType(outputCtx.importExpr(reference, /* typeParams */ null, /* useSummaries */ false)))); }); if (emitFlags & 2 /* TypeCheck */) { // add the type-check block for all components of the NgModule ngModuleMeta.declaredDirectives.forEach((dirId) => { const compMeta = this._metadataResolver.getDirectiveMetadata(dirId.reference); if (!compMeta.isComponent) { return; } componentId++; this._createTypeCheckBlock(outputCtx, `${compMeta.type.reference.name}_Host_${componentId}`, ngModuleMeta, this._metadataResolver.getHostComponentMetadata(compMeta), [compMeta.type], externalReferenceVars); this._createTypeCheckBlock(outputCtx, `${compMeta.type.reference.name}_${componentId}`, ngModuleMeta, compMeta, ngModuleMeta.transitiveModule.directives, externalReferenceVars); }); } }); if (outputCtx.statements.length === 0) { _createEmptyStub(outputCtx); } } _externalIdentifierReferences(references) { const result = []; for (let reference of references) { const token = createTokenForExternalReference(this.reflector, reference); if (token.identifier) { result.push(token.identifier.reference); } } return result; } _createTypeCheckBlock(ctx, componentId, moduleMeta, compMeta, directives, externalReferenceVars) { const { template: parsedTemplate, pipes: usedPipes } = this._parseTemplate(compMeta, moduleMeta, directives); ctx.statements.push(...this._typeCheckCompiler.compileComponent(componentId, compMeta, parsedTemplate, usedPipes, externalReferenceVars, ctx)); } emitMessageBundle(analyzeResult, locale) { const errors = []; const htmlParser = new HtmlParser(); // TODO(vicb): implicit tags & attributes const messageBundle = new MessageBundle(htmlParser, [], {}, locale); analyzeResult.files.forEach(file => { const compMetas = []; file.directives.forEach(directiveType => { const dirMeta = this._metadataResolver.getDirectiveMetadata(directiveType); if (dirMeta && dirMeta.isComponent) { compMetas.push(dirMeta); } }); compMetas.forEach(compMeta => { const html = compMeta.template.template; // Template URL points to either an HTML or TS file depending on whether // the file is used with `templateUrl:` or `template:`, respectively. const templateUrl = compMeta.template.templateUrl; const interpolationConfig = InterpolationConfig.fromArray(compMeta.template.interpolation); errors.push(...messageBundle.updateFromTemplate(html, templateUrl, interpolationConfig)); }); }); if (errors.length) { throw new Error(errors.map(e => e.toString()).join('\n')); } return messageBundle; } emitAllPartialModules({ ngModuleByPipeOrDirective, files }, r3Files) { const contextMap = new Map(); const getContext = (fileName) => { if (!contextMap.has(fileName)) { contextMap.set(fileName, this._createOutputContext(fileName)); } return contextMap.get(fileName); }; files.forEach(file => this._compilePartialModule(file.fileName, ngModuleByPipeOrDirective, file.directives, file.pipes, file.ngModules, file.injectables, getContext(file.fileName))); r3Files.forEach(file => this._compileShallowModules(file.fileName, file.shallowModules, getContext(file.fileName))); return Array.from(contextMap.values()) .map(context => ({ fileName: context.genFilePath, statements: [...context.constantPool.statements, ...context.statements], })); } _compileShallowModules(fileName, shallowModules, context) { shallowModules.forEach(module => compileR3Module(context, module, this._injectableCompiler)); } _compilePartialModule(fileName, ngModuleByPipeOrDirective, directives, pipes, ngModules, injectables, context) { const errors = []; const schemaRegistry = new DomElementSchemaRegistry(); const hostBindingParser = new BindingParser(this._templateParser.expressionParser, DEFAULT_INTERPOLATION_CONFIG, schemaRegistry, [], errors); // Process all components and directives directives.forEach(directiveType => { const directiveMetadata = this._metadataResolver.getDirectiveMetadata(directiveType); if (directiveMetadata.isComponent) { const module = ngModuleByPipeOrDirective.get(directiveType); module || error(`Cannot determine the module for component '${identifierName(directiveMetadata.type)}'`); let htmlAst = directiveMetadata.template.htmlAst; const preserveWhitespaces = directiveMetadata.template.preserveWhitespaces; if (!preserveWhitespaces) { htmlAst = removeWhitespaces(htmlAst); } const render3Ast = htmlAstToRender3Ast(htmlAst.rootNodes, hostBindingParser); // Map of StaticType by directive selectors const directiveTypeBySel = new Map(); const directives = module.transitiveModule.directives.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference)); directives.forEach(directive => { if (directive.selector) { directiveTypeBySel.set(directive.selector, directive.type.reference); } }); // Map of StaticType by pipe names const pipeTypeByName = new Map(); const pipes = module.transitiveModule.pipes.map(pipe => this._metadataResolver.getPipeSummary(pipe.reference)); pipes.forEach(pipe => { pipeTypeByName.set(pipe.name, pipe.type.reference); }); compileR3Component(context, directiveMetadata, render3Ast, this.reflector, hostBindingParser, directiveTypeBySel, pipeTypeByName); } else { compileR3Directive(context, directiveMetadata, this.reflector, hostBindingParser); } }); pipes.forEach(pipeType => { const pipeMetadata = this._metadataResolver.getPipeMetadata(pipeType); if (pipeMetadata) { compileR3Pipe(context, pipeMetadata, this.reflector); } }); injectables.forEach(injectable => this._injectableCompiler.compile(injectable, context)); } emitAllPartialModules2(files) { // Using reduce like this is a select many pattern (where map is a select pattern) return files.reduce((r, file) => { r.push(...this._emitPartialModule2(file.fileName, file.injectables)); return r; }, []); } _emitPartialModule2(fileName, injectables) { const context = this._createOutputContext(fileName); injectables.forEach(injectable => this._injectableCompiler.compile(injectable, context)); if (context.statements && context.statements.length > 0) { return [{ fileName, statements: [...context.constantPool.statements, ...context.statements] }]; } return []; } emitAllImpls(analyzeResult) { const { ngModuleByPipeOrDirective, files } = analyzeResult; const sourceModules = files.map(file => this._compileImplFile(file.fileName, ngModuleByPipeOrDirective, file.directives, file.pipes, file.ngModules, file.injectables)); return flatten(sourceModules); } _compileImplFile(srcFileUrl, ngModuleByPipeOrDirective, directives, pipes, ngModules, injectables) { const fileSuffix = normalizeGenFileSuffix(splitTypescriptSuffix(srcFileUrl, true)[1]); const generatedFiles = []; const outputCtx = this._createOutputContext(ngfactoryFilePath(srcFileUrl, true)); generatedFiles.push(...this._createSummary(srcFileUrl, directives, pipes, ngModules, injectables, outputCtx)); // compile all ng modules ngModules.forEach((ngModuleMeta) => this._compileModule(outputCtx, ngModuleMeta)); // compile components directives.forEach((dirType) => { const compMeta = this._metadataResolver.getDirectiveMetadata(dirType); if (!compMeta.isComponent) { return; } const ngModule = ngModuleByPipeOrDirective.get(dirType); if (!ngModule) { throw new Error(`Internal Error: cannot determine the module for component ${identifierName(compMeta.type)}!`); } // compile styles const componentStylesheet = this._styleCompiler.compileComponent(outputCtx, compMeta); // Note: compMeta is a component and therefore template is non null. compMeta.template.externalStylesheets.forEach((stylesheetMeta) => { // Note: fill non shim and shim style files as they might // be shared by component with and without ViewEncapsulation. const shim = this._styleCompiler.needsStyleShim(compMeta); generatedFiles.push(this._codegenStyles(srcFileUrl, compMeta, stylesheetMeta, shim, fileSuffix)); if (this._options.allowEmptyCodegenFiles) { generatedFiles.push(this._codegenStyles(srcFileUrl, compMeta, stylesheetMeta, !shim, fileSuffix)); } }); // compile components const compViewVars = this._compileComponent(outputCtx, compMeta, ngModule, ngModule.transitiveModule.directives, componentStylesheet, fileSuffix); this._compileComponentFactory(outputCtx, compMeta, ngModule, fileSuffix); }); if (outputCtx.statements.length > 0 || this._options.allowEmptyCodegenFiles) { const srcModule = this._codegenSourceModule(srcFileUrl, outputCtx); generatedFiles.unshift(srcModule); } return generatedFiles; } _createSummary(srcFileName, directives, pipes, ngModules, injectables, ngFactoryCtx) { const symbolSummaries = this._symbolResolver.getSymbolsOf(srcFileName) .map(symbol => this._symbolResolver.resolveSymbol(symbol)); const typeData = [ ...ngModules.map(meta => ({ summary: this._metadataResolver.getNgModuleSummary(meta.type.reference), metadata: this._metadataResolver.getNgModuleMetadata(meta.type.reference) })), ...directives.map(ref => ({ summary: this._metadataResolver.getDirectiveSummary(ref), metadata: this._metadataResolver.getDirectiveMetadata(ref) })), ...pipes.map(ref => ({ summary: this._metadataResolver.getPipeSummary(ref), metadata: this._metadataResolver.getPipeMetadata(ref) })), ...injectables.map(ref => ({ summary: this._metadataResolver.getInjectableSummary(ref.symbol), metadata: this._metadataResolver.getInjectableSummary(ref.symbol).type })) ]; const forJitOutputCtx = this._options.enableSummariesForJit ? this._createOutputContext(summaryForJitFileName(srcFileName, true)) : null; const { json, exportAs } = serializeSummaries(srcFileName, forJitOutputCtx, this._summaryResolver, this._symbolResolver, symbolSummaries, typeData, this._options.createExternalSymbolFactoryReexports); exportAs.forEach((entry) => { ngFactoryCtx.statements.push(o.variable(entry.exportAs).set(ngFactoryCtx.importExpr(entry.symbol)).toDeclStmt(null, [ o.StmtModifier.Exported ])); }); const summaryJson = new GeneratedFile(srcFileName, summaryFileName(srcFileName), json); const result = [summaryJson]; if (forJitOutputCtx) { result.push(this._codegenSourceModule(srcFileName, forJitOutputCtx)); } return result; } _compileModule(outputCtx, ngModule) { const providers = []; if (this._options.locale) { const normalizedLocale = this._options.locale.replace(/_/g, '-'); providers.push({ token: createTokenForExternalReference(this.reflector, Identifiers.LOCALE_ID), useValue: normalizedLocale, }); } if (this._options.i18nFormat) { providers.push({ token: createTokenForExternalReference(this.reflector, Identifiers.TRANSLATIONS_FORMAT), useValue: this._options.i18nFormat }); } this._ngModuleCompiler.compile(outputCtx, ngModule, providers); } _compileComponentFactory(outputCtx, compMeta, ngModule, fileSuffix) { const hostMeta = this._metadataResolver.getHostComponentMetadata(compMeta); const hostViewFactoryVar = this._compileComponent(outputCtx, hostMeta, ngModule, [compMeta.type], null, fileSuffix) .viewClassVar; const compFactoryVar = componentFactoryName(compMeta.type.reference); const inputsExprs = []; for (let propName in compMeta.inputs) { const templateName = compMeta.inputs[propName]; // Don't quote so that the key gets minified... inputsExprs.push(new o.LiteralMapEntry(propName, o.literal(templateName), false)); } const outputsExprs = []; for (let propName in compMeta.outputs) { const templateName = compMeta.outputs[propName]; // Don't quote so that the key gets minified... outputsExprs.push(new o.LiteralMapEntry(propName, o.literal(templateName), false)); } outputCtx.statements.push(o.variable(compFactoryVar) .set(o.importExpr(Identifiers.createComponentFactory).callFn([ o.literal(compMeta.selector), outputCtx.importExpr(compMeta.type.reference), o.variable(hostViewFactoryVar), new o.LiteralMapExpr(inputsExprs), new o.LiteralMapExpr(outputsExprs), o.literalArr(compMeta.template.ngContentSelectors.map(selector => o.literal(selector))) ])) .toDeclStmt(o.importType(Identifiers.ComponentFactory, [o.expressionType(outputCtx.importExpr(compMeta.type.reference))], [o.TypeModifier.Const]), [o.StmtModifier.Final, o.StmtModifier.Exported])); } _compileComponent(outputCtx, compMeta, ngModule, directiveIdentifiers, componentStyles, fileSuffix) { const { template: parsedTemplate, pipes: usedPipes } = this._parseTemplate(compMeta, ngModule, directiveIdentifiers); const stylesExpr = componentStyles ? o.variable(componentStyles.stylesVar) : o.literalArr([]); const viewResult = this._viewCompiler.compileComponent(outputCtx, compMeta, parsedTemplate, stylesExpr, usedPipes); if (componentStyles) { _resolveStyleStatements(this._symbolResolver, componentStyles, this._styleCompiler.needsStyleShim(compMeta), fileSuffix); } return viewResult; } _parseTemplate(compMeta, ngModule, directiveIdentifiers) { if (this._templateAstCache.has(compMeta.type.reference)) { return this._templateAstCache.get(compMeta.type.reference); } const preserveWhitespaces = compMeta.template.preserveWhitespaces; const directives = directiveIdentifiers.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference)); const pipes = ngModule.transitiveModule.pipes.map(pipe => this._metadataResolver.getPipeSummary(pipe.reference)); const result = this._templateParser.parse(compMeta, compMeta.template.htmlAst, directives, pipes, ngModule.schemas, templateSourceUrl(ngModule.type, compMeta, compMeta.template), preserveWhitespaces); this._templateAstCache.set(compMeta.type.reference, result); return result; } _createOutputContext(genFilePath) { const importExpr = (symbol, typeParams = null, useSummaries = true) => { if (!(symbol instanceof StaticSymbol)) { throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`); } const arity = this._symbolResolver.getTypeArity(symbol) || 0; const { filePath, name, members } = this._symbolResolver.getImportAs(symbol, useSummaries) || symbol; const importModule = this._fileNameToModuleName(filePath, genFilePath); // It should be good enough to compare filePath to genFilePath and if they are equal // there is a self reference. However, ngfactory files generate to .ts but their // symbols have .d.ts so a simple compare is insufficient. They should be canonical // and is tracked by #17705. const selfReference = this._fileNameToModuleName(genFilePath, genFilePath); const moduleName = importModule === selfReference ? null : importModule; // If we are in a type expression that refers to a generic type then supply // the required type parameters. If there were not enough type parameters // supplied, supply any as the type. Outside a type expression the reference // should not supply type parameters and be treated as a simple value reference // to the constructor function itself. const suppliedTypeParams = typeParams || []; const missingTypeParamsCount = arity - suppliedTypeParams.length; const allTypeParams = suppliedTypeParams.concat(newArray(missingTypeParamsCount, o.DYNAMIC_TYPE)); return members.reduce((expr, memberName) => expr.prop(memberName), o.importExpr(new o.ExternalReference(moduleName, name, null), allTypeParams)); }; return { statements: [], genFilePath, importExpr, constantPool: new ConstantPool() }; } _fileNameToModuleName(importedFilePath, containingFilePath) { return this._summaryResolver.getKnownModuleName(importedFilePath) || this._symbolResolver.getKnownModuleName(importedFilePath) || this._host.fileNameToModuleName(importedFilePath, containingFilePath); } _codegenStyles(srcFileUrl, compMeta, stylesheetMetadata, isShimmed, fileSuffix) { const outputCtx = this._createOutputContext(_stylesModuleUrl(stylesheetMetadata.moduleUrl, isShimmed, fileSuffix)); const compiledStylesheet = this._styleCompiler.compileStyles(outputCtx, compMeta, stylesheetMetadata, isShimmed); _resolveStyleStatements(this._symbolResolver, compiledStylesheet, isShimmed, fileSuffix); return this._codegenSourceModule(srcFileUrl, outputCtx); } _codegenSourceModule(srcFileUrl, ctx) { return new GeneratedFile(srcFileUrl, ctx.genFilePath, ctx.statements); } listLazyRoutes(entryRoute, analyzedModules) { const self = this; if (entryRoute) { const symbol = parseLazyRoute(entryRoute, this.reflector).referencedModule; return visitLazyRoute(symbol); } else if (analyzedModules) { const allLazyRoutes = []; for (const ngModule of analyzedModules.ngModules) { const lazyRoutes = listLazyRoutes(ngModule, this.reflector); for (const lazyRoute of lazyRoutes) { allLazyRoutes.push(lazyRoute); } } return allLazyRoutes; } else { throw new Error(`Either route or analyzedModules has to be specified!`); } function visitLazyRoute(symbol, seenRoutes = new Set(), allLazyRoutes = []) { // Support pointing to default exports, but stop recursing there, // as the StaticReflector does not yet support default exports. if (seenRoutes.has(symbol) || !symbol.name) { return allLazyRoutes; } seenRoutes.add(symbol); const lazyRoutes = listLazyRoutes(self._metadataResolver.getNgModuleMetadata(symbol, true), self.reflector); for (const lazyRoute of lazyRoutes) { allLazyRoutes.push(lazyRoute); visitLazyRoute(lazyRoute.referencedModule, seenRoutes, allLazyRoutes); } return allLazyRoutes; } } } function _createEmptyStub(outputCtx) { // Note: We need to produce at least one import statement so that // TypeScript knows that the file is an es6 module. Otherwise our generated // exports / imports won't be emitted properly by TypeScript. outputCtx.statements.push(o.importExpr(Identifiers.ComponentFactory).toStmt()); } function _resolveStyleStatements(symbolResolver, compileResult, needsShim, fileSuffix) { compileResult.dependencies.forEach((dep) => { dep.setValue(symbolResolver.getStaticSymbol(_stylesModuleUrl(dep.moduleUrl, needsShim, fileSuffix), dep.name)); }); } function _stylesModuleUrl(stylesheetUrl, shim, suffix) { return `${stylesheetUrl}${shim ? '.shim' : ''}.ngstyle${suffix}`; } export function analyzeNgModules(fileNames, host, staticSymbolResolver, metadataResolver) { const files = _analyzeFilesIncludingNonProgramFiles(fileNames, host, staticSymbolResolver, metadataResolver); return mergeAnalyzedFiles(files); } export function analyzeAndValidateNgModules(fileNames, host, staticSymbolResolver, metadataResolver) { return validateAnalyzedModules(analyzeNgModules(fileNames, host, staticSymbolResolver, metadataResolver)); } function validateAnalyzedModules(analyzedModules) { if (analyzedModules.symbolsMissingModule && analyzedModules.symbolsMissingModule.length) { const messages = analyzedModules.symbolsMissingModule.map(s => `Cannot determine the module for class ${s.name} in ${s.filePath}! Add ${s.name} to the NgModule to fix it.`); throw syntaxError(messages.join('\n')); } return analyzedModules; } // Analyzes all of the program files, // including files that are not part of the program // but are referenced by an NgModule. function _analyzeFilesIncludingNonProgramFiles(fileNames, host, staticSymbolResolver, metadataResolver) { const seenFiles = new Set(); const files = []; const visitFile = (fileName) => { if (seenFiles.has(fileName) || !host.isSourceFile(fileName)) { return false; } seenFiles.add(fileName); const analyzedFile = analyzeFile(host, staticSymbolResolver, metadataResolver, fileName); files.push(analyzedFile); analyzedFile.ngModules.forEach(ngModule => { ngModule.transitiveModule.modules.forEach(modMeta => visitFile(modMeta.reference.filePath)); }); }; fileNames.forEach((fileName) => visitFile(fileName)); return files; } export function analyzeFile(host, staticSymbolResolver, metadataResolver, fileName) { const abstractDirectives = []; const directives = []; const pipes = []; const injectables = []; const ngModules = []; const hasDecorators = staticSymbolResolver.hasDecorators(fileName); let exportsNonSourceFiles = false; const isDeclarationFile = fileName.endsWith('.d.ts'); // Don't analyze .d.ts files that have no decorators as a shortcut // to speed up the analysis. This prevents us from // resolving the references in these files. // Note: exportsNonSourceFiles is only needed when compiling with summaries, // which is not the case when .d.ts files are treated as input files. if (!isDeclarationFile || hasDecorators) { staticSymbolResolver.getSymbolsOf(fileName).forEach((symbol) => { const resolvedSymbol = staticSymbolResolver.resolveSymbol(symbol); const symbolMeta = resolvedSymbol.metadata; if (!symbolMeta || symbolMeta.__symbolic === 'error') { return; } let isNgSymbol = false; if (symbolMeta.__symbolic === 'class') { if (metadataResolver.isDirective(symbol)) { isNgSymbol = true; // This directive either has a selector or doesn't. Selector-less directives get tracked // in abstractDirectives, not directives. The compiler doesn't deal with selector-less // directives at all, really, other than to persist their metadata. This is done so that // apps will have an easier time migrating to Ivy, which requires the selector-less // annotations to be applied. if (!metadataResolver.isAbstractDirective(symbol)) { // The directive is an ordinary directive. directives.push(symbol); } else { // The directive has no selector and is an "abstract" directive, so track it // accordingly. abstractDirectives.push(symbol); } } else if (metadataResolver.isPipe(symbol)) { isNgSymbol = true; pipes.push(symbol); } else if (metadataResolver.isNgModule(symbol)) { const ngModule = metadataResolver.getNgModuleMetadata(symbol, false); if (ngModule) { isNgSymbol = true; ngModules.push(ngModule); } } else if (metadataResolver.isInjectable(symbol)) { isNgSymbol = true; const injectable = metadataResolver.getInjectableMetadata(symbol, null, false); if (injectable) { injectables.push(injectable); } } } if (!isNgSymbol) { exportsNonSourceFiles = exportsNonSourceFiles || isValueExportingNonSourceFile(host, symbolMeta); } }); } return { fileName, directives, abstractDirectives, pipes, ngModules, injectables, exportsNonSourceFiles, }; } export function analyzeFileForInjectables(host, staticSymbolResolver, metadataResolver, fileName) { const injectables = []; const shallowModules = []; if (staticSymbolResolver.hasDecorators(fileName)) { staticSymbolResolver.getSymbolsOf(fileName).forEach((symbol) => { const resolvedSymbol = staticSymbolResolver.resolveSymbol(symbol); const symbolMeta = resolvedSymbol.metadata; if (!symbolMeta || symbolMeta.__symbolic === 'error') { return; } if (symbolMeta.__symbolic === 'class') { if (metadataResolver.isInjectable(symbol)) { const injectable = metadataResolver.getInjectableMetadata(symbol, null, false); if (injectable) { injectables.push(injectable); } } else if (metadataResolver.isNgModule(symbol)) { const module = metadataResolver.getShallowModuleMetadata(symbol); if (module) { shallowModules.push(module); } } } }); } return { fileName, injectables, shallowModules }; } function isValueExportingNonSourceFile(host, metadata) { let exportsNonSourceFiles = false; class Visitor { visitArray(arr, context) { arr.forEach(v => visitValue(v, this, context)); } visitStringMap(map, context) { Object.keys(map).forEach((key) => visitValue(map[key], this, context)); } visitPrimitive(value, context) { } visitOther(value, context) { if (value instanceof StaticSymbol && !host.isSourceFile(value.filePath)) { exportsNonSourceFiles = true; } } } visitValue(metadata, new Visitor(), null); return exportsNonSourceFiles; } export function mergeAnalyzedFiles(analyzedFiles) { const allNgModules = []; const ngModuleByPipeOrDirective = new Map(); const allPipesAndDirectives = new Set(); analyzedFiles.forEach(af => { af.ngModules.forEach(ngModule => { allNgModules.push(ngModule); ngModule.declaredDirectives.forEach(d => ngModuleByPipeOrDirective.set(d.reference, ngModule)); ngModule.declaredPipes.forEach(p => ngModuleByPipeOrDirective.set(p.reference, ngModule)); }); af.directives.forEach(d => allPipesAndDirectives.add(d)); af.pipes.forEach(p => allPipesAndDirectives.add(p)); }); const symbolsMissingModule = []; allPipesAndDirectives.forEach(ref => { if (!ngModuleByPipeOrDirective.has(ref)) { symbolsMissingModule.push(ref); } }); return { ngModules: allNgModules, ngModuleByPipeOrDirective, symbolsMissingModule, files: analyzedFiles }; } function mergeAndValidateNgFiles(files) { return validateAnalyzedModules(mergeAnalyzedFiles(files)); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcGlsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9jb21waWxlci9zcmMvYW90L2NvbXBpbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUVILE9BQU8sRUFBOFEsb0JBQW9CLEVBQUUsT0FBTyxFQUFFLGNBQWMsRUFBRSxpQkFBaUIsRUFBQyxNQUFNLHFCQUFxQixDQUFDO0FBRWxYLE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSxrQkFBa0IsQ0FBQztBQUM5QyxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSxTQUFTLENBQUM7QUFDMUMsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLHdCQUF3QixDQUFDO0FBQ3JELE9BQU8sRUFBQywrQkFBK0IsRUFBRSxXQUFXLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUc1RSxPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sMEJBQTBCLENBQUM7QUFDcEQsT0FBTyxFQUFDLGlCQUFpQixFQUFDLE1BQU0sK0JBQStCLENBQUM7QUFDaEUsT0FBTyxFQUFDLDRCQUE0QixFQUFFLG1CQUFtQixFQUFDLE1BQU0sbUNBQW1DLENBQUM7QUFHcEcsT0FBTyxLQUFLLENBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQUUxQyxPQUFPLEVBQUMsMEJBQTBCLElBQUksZUFBZSxFQUFDLE1BQU0sK0JBQStCLENBQUM7QUFDNUYsT0FBTyxFQUFDLHNCQUFzQixJQUFJLGFBQWEsRUFBQyxNQUFNLDZCQUE2QixDQUFDO0FBQ3BGLE9BQU8sRUFBQyxtQkFBbUIsRUFBQyxNQUFNLGtDQUFrQyxDQUFDO0FBQ3JFLE9BQU8sRUFBQywyQkFBMkIsSUFBSSxrQkFBa0IsRUFBRSwyQkFBMkIsSUFBSSxrQkFBa0IsRUFBQyxNQUFNLDBCQUEwQixDQUFDO0FBQzlJLE9BQU8sRUFBQyx3QkFBd0IsRUFBQyxNQUFNLHVDQUF1QyxDQUFDO0FBRy9FLE9BQU8sRUFB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