/** * @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.dev/license */ import { Expression } from '@angular/compiler'; import ts from 'typescript'; import { UnifiedModulesHost } from '../../core/api'; import { LogicalFileSystem } from '../../file_system'; import { DeclarationNode, ReflectionHost } from '../../reflection'; import { Reference } from './references'; import { ModuleResolver } from './resolver'; /** * Flags which alter the imports generated by the `ReferenceEmitter`. */ export declare enum ImportFlags { None = 0, /** * Force the generation of a new import when generating a reference, even if an identifier already * exists in the target file which could be used instead. * * This is sometimes required if there's a risk TypeScript might remove imports during emit. */ ForceNewImport = 1, /** * Don't make use of any aliasing information when emitting a reference. * * This is sometimes required if emitting into a context where generated references will be fed * into TypeScript and type-checked (such as in template type-checking). */ NoAliasing = 2, /** * Indicates that an import to a type-only declaration is allowed. * * For references that occur in type-positions, the referred declaration may be a type-only * declaration that is not retained during emit. Including this flag allows to emit references to * type-only declarations as used in e.g. template type-checking. */ AllowTypeImports = 4, /** * Indicates that importing from a declaration file using a relative import path is allowed. * * The generated imports should normally use module specifiers that are valid for use in * production code, where arbitrary relative imports into e.g. node_modules are not allowed. For * template type-checking code it is however acceptable to use relative imports, as such files are * never emitted to JS code. * * Non-declaration files have to be contained within a configured `rootDir` so using relative * paths may not be possible for those, hence this flag only applies when importing from a * declaration file. */ AllowRelativeDtsImports = 8, /** * Indicates that references coming from ambient imports are allowed. */ AllowAmbientReferences = 16 } /** * An emitter strategy has the ability to indicate which `ts.SourceFile` is being imported by the * expression that it has generated. This information is useful for consumers of the emitted * reference that would otherwise have to perform a relatively expensive module resolution step, * e.g. for cyclic import analysis. In cases the emitter is unable to definitively determine the * imported source file or a computation would be required to actually determine the imported * source file, then `'unknown'` should be returned. If the generated expression does not represent * an import then `null` should be used. */ export type ImportedFile = ts.SourceFile | 'unknown' | null; export declare enum ReferenceEmitKind { Success = 0, Failed = 1 } /** * Represents the emitted expression of a `Reference` that is valid in the source file it was * emitted from. */ export interface EmittedReference { kind: ReferenceEmitKind.Success; /** * The expression that refers to `Reference`. */ expression: Expression; /** * The `ts.SourceFile` that is imported by `expression`. This is not necessarily the source file * of the `Reference`'s declaration node, as the reference may have been rewritten through an * alias export. It could also be `null` if `expression` is a local identifier, or `'unknown'` if * the exact source file that is being imported is not known to the emitter. */ importedFile: ImportedFile; } /** * Represents a failure to emit a `Reference` into a different source file. */ export interface FailedEmitResult { kind: ReferenceEmitKind.Failed; /** * The reference that could not be emitted. */ ref: Reference; /** * The source file into which the reference was requested to be emitted. */ context: ts.SourceFile; /** * Describes why the reference could not be emitted. This may be shown in a diagnostic. */ reason: string; } export type ReferenceEmitResult = EmittedReference | FailedEmitResult; /** * Verifies that a reference was emitted successfully, or raises a `FatalDiagnosticError` otherwise. * @param result The emit result that should have been successful. * @param origin The node that is used to report the failure diagnostic. * @param typeKind The kind of the symbol that the reference represents, e.g. 'component' or * 'class'. */ export declare function assertSuccessfulReferenceEmit(result: ReferenceEmitResult, origin: ts.Node, typeKind: string): asserts result is EmittedReference; /** * A particular strategy for generating an expression which refers to a `Reference`. * * There are many potential ways a given `Reference` could be referred to in the context of a given * file. A local declaration could be available, the `Reference` could be importable via a relative * import within the project, or an absolute import into `node_modules` might be necessary. * * Different `ReferenceEmitStrategy` implementations implement specific logic for generating such * references. A single strategy (such as using a local declaration) may not always be able to * generate an expression for every `Reference` (for example, if no local identifier is available), * and may return `null` in such a case. */ export interface ReferenceEmitStrategy { /** * Emit an `Expression` which refers to the given `Reference` in the context of a particular * source file, if possible. * * @param ref the `Reference` for which to generate an expression * @param context the source file in which the `Expression` must be valid * @param importFlags a flag which controls whether imports should be generated or not * @returns an `EmittedReference` which refers to the `Reference`, or `null` if none can be * generated */ emit(ref: Reference, context: ts.SourceFile, importFlags: ImportFlags): ReferenceEmitResult | null; } /** * Generates `Expression`s which refer to `Reference`s in a given context. * * A `ReferenceEmitter` uses one or more `ReferenceEmitStrategy` implementations to produce an * `Expression` which refers to a `Reference` in the context of a particular file. */ export declare class ReferenceEmitter { private strategies; constructor(strategies: ReferenceEmitStrategy[]); emit(ref: Reference, context: ts.SourceFile, importFlags?: ImportFlags): ReferenceEmitResult; } /** * A `ReferenceEmitStrategy` which will refer to declarations by any local `ts.Identifier`s, if * such identifiers are available. */ export declare class LocalIdentifierStrategy implements ReferenceEmitStrategy { emit(ref: Reference, context: ts.SourceFile, importFlags: ImportFlags): EmittedReference | null; } /** * Represents the exported declarations from a module source file. */ interface ModuleExports { /** * The source file of the module. */ module: ts.SourceFile | null; /** * The map of declarations to their exported name. */ exportMap: Map | null; } /** * A `ReferenceEmitStrategy` which will refer to declarations that come from `node_modules` using * an absolute import. * * Part of this strategy involves looking at the target entry point and identifying the exported * name of the targeted declaration, as it might be different from the declared name (e.g. a * directive might be declared as FooDirImpl, but exported as FooDir). If no export can be found * which maps back to the original directive, an error is thrown. */ export declare class AbsoluteModuleStrategy implements ReferenceEmitStrategy { protected program: ts.Program; protected checker: ts.TypeChecker; protected moduleResolver: ModuleResolver; private reflectionHost; /** * A cache of the exports of specific modules, because resolving a module to its exports is a * costly operation. */ private moduleExportsCache; constructor(program: ts.Program, checker: ts.TypeChecker, moduleResolver: ModuleResolver, reflectionHost: ReflectionHost); emit(ref: Reference, context: ts.SourceFile, importFlags: ImportFlags): ReferenceEmitResult | null; private getExportsOfModule; protected enumerateExportsOfModule(specifier: string, fromFile: string): ModuleExports; } /** * A `ReferenceEmitStrategy` which will refer to declarations via relative paths, provided they're * both in the logical project "space" of paths. * * This is trickier than it sounds, as the two files may be in different root directories in the * project. Simply calculating a file system relative path between the two is not sufficient. * Instead, `LogicalProjectPath`s are used. */ export declare class LogicalProjectStrategy implements ReferenceEmitStrategy { private reflector; private logicalFs; private relativePathStrategy; constructor(reflector: ReflectionHost, logicalFs: LogicalFileSystem); emit(ref: Reference, context: ts.SourceFile, importFlags: ImportFlags): ReferenceEmitResult | null; } /** * A `ReferenceEmitStrategy` which constructs relatives paths between `ts.SourceFile`s. * * This strategy can be used if there is no `rootDir`/`rootDirs` structure for the project which * necessitates the stronger logic of `LogicalProjectStrategy`. */ export declare class RelativePathStrategy implements ReferenceEmitStrategy { private reflector; constructor(reflector: ReflectionHost); emit(ref: Reference, context: ts.SourceFile): ReferenceEmitResult | null; } /** * A `ReferenceEmitStrategy` which uses a `UnifiedModulesHost` to generate absolute import * references. */ export declare class UnifiedModulesStrategy implements ReferenceEmitStrategy { private reflector; private unifiedModulesHost; constructor(reflector: ReflectionHost, unifiedModulesHost: UnifiedModulesHost); emit(ref: Reference, context: ts.SourceFile): EmittedReference | null; } export {};