diff --git a/src/compiler/program.ts b/src/compiler/program.ts index aa106a618731e..a9e271fce8bf1 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -536,20 +536,39 @@ namespace ts { return resolutions; } - /* @internal */ - interface SourceFileImportsList { - imports: SourceFile["imports"]; - moduleAugmentations: SourceFile["moduleAugmentations"]; + /** + * Subset of a SourceFile used to calculate index-based resolutions + * This includes some internal fields, so unless you have very good reason, + * (and are willing to use some less stable internals) you should probably just pass a SourceFile. + * + * @internal + */ + export interface SourceFileImportsList { + /* @internal */ imports: SourceFile["imports"]; + /* @internal */ moduleAugmentations: SourceFile["moduleAugmentations"]; impliedNodeFormat?: SourceFile["impliedNodeFormat"]; }; - /* @internal */ + /** + * Calculates the resulting resolution mode for some reference in some file - this is generally the explicitly + * provided resolution mode in the reference, unless one is not present, in which case it is the mode of the containing file. + */ export function getModeForFileReference(ref: FileReference | string, containingFileMode: SourceFile["impliedNodeFormat"]) { return (isString(ref) ? containingFileMode : ref.resolutionMode) || containingFileMode; } - /* @internal */ - export function getModeForResolutionAtIndex(file: SourceFileImportsList, index: number) { + /** + * Calculates the final resolution mode for an import at some index within a file's imports list. This is generally the explicitly + * defined mode of the import if provided, or, if not, the mode of the containing file (with some exceptions: import=require is always commonjs, dynamic import is always esm). + * If you have an actual import node, prefer using getModeForUsageLocation on the reference string node. + * @param file File to fetch the resolution mode within + * @param index Index into the file's complete resolution list to get the resolution of - this is a concatenation of the file's imports and module augmentations + */ + export function getModeForResolutionAtIndex(file: SourceFile, index: number): ModuleKind.CommonJS | ModuleKind.ESNext | undefined; + /** @internal */ + // eslint-disable-next-line @typescript-eslint/unified-signatures + export function getModeForResolutionAtIndex(file: SourceFileImportsList, index: number): ModuleKind.CommonJS | ModuleKind.ESNext | undefined; + export function getModeForResolutionAtIndex(file: SourceFileImportsList, index: number): ModuleKind.CommonJS | ModuleKind.ESNext | undefined { if (file.impliedNodeFormat === undefined) return undefined; // we ensure all elements of file.imports and file.moduleAugmentations have the relevant parent pointers set during program setup, // so it's safe to use them even pre-bind @@ -567,7 +586,15 @@ namespace ts { return false; } - /* @internal */ + /** + * Calculates the final resolution mode for a given module reference node. This is generally the explicitly provided resolution mode, if + * one exists, or the mode of the containing source file. (Excepting import=require, which is always commonjs, and dynamic import, which is always esm). + * Notably, this function always returns `undefined` if the containing file has an `undefined` `impliedNodeFormat` - this field is only set when + * `moduleResolution` is `node16`+. + * @param file The file the import or import-like reference is contained within + * @param usage The module reference string + * @returns The final resolution mode of the import + */ export function getModeForUsageLocation(file: {impliedNodeFormat?: SourceFile["impliedNodeFormat"]}, usage: StringLiteralLike) { if (file.impliedNodeFormat === undefined) return undefined; if ((isImportDeclaration(usage.parent) || isExportDeclaration(usage.parent))) { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index ab7ae0cde4997..62c0b481fb22b 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -5102,6 +5102,31 @@ declare namespace ts { export function formatDiagnostic(diagnostic: Diagnostic, host: FormatDiagnosticsHost): string; export function formatDiagnosticsWithColorAndContext(diagnostics: readonly Diagnostic[], host: FormatDiagnosticsHost): string; export function flattenDiagnosticMessageText(diag: string | DiagnosticMessageChain | undefined, newLine: string, indent?: number): string; + /** + * Calculates the resulting resolution mode for some reference in some file - this is generally the explicitly + * provided resolution mode in the reference, unless one is not present, in which case it is the mode of the containing file. + */ + export function getModeForFileReference(ref: FileReference | string, containingFileMode: SourceFile["impliedNodeFormat"]): ModuleKind.CommonJS | ModuleKind.ESNext | undefined; + /** + * Calculates the final resolution mode for an import at some index within a file's imports list. This is generally the explicitly + * defined mode of the import if provided, or, if not, the mode of the containing file (with some exceptions: import=require is always commonjs, dynamic import is always esm). + * If you have an actual import node, prefer using getModeForUsageLocation on the reference string node. + * @param file File to fetch the resolution mode within + * @param index Index into the file's complete resolution list to get the resolution of - this is a concatenation of the file's imports and module augmentations + */ + export function getModeForResolutionAtIndex(file: SourceFile, index: number): ModuleKind.CommonJS | ModuleKind.ESNext | undefined; + /** + * Calculates the final resolution mode for a given module reference node. This is generally the explicitly provided resolution mode, if + * one exists, or the mode of the containing source file. (Excepting import=require, which is always commonjs, and dynamic import, which is always esm). + * Notably, this function always returns `undefined` if the containing file has an `undefined` `impliedNodeFormat` - this field is only set when + * `moduleResolution` is `node16`+. + * @param file The file the import or import-like reference is contained within + * @param usage The module reference string + * @returns The final resolution mode of the import + */ + export function getModeForUsageLocation(file: { + impliedNodeFormat?: SourceFile["impliedNodeFormat"]; + }, usage: StringLiteralLike): ModuleKind.CommonJS | ModuleKind.ESNext | undefined; export function getConfigFileParsingDiagnostics(configFileParseResult: ParsedCommandLine): readonly Diagnostic[]; /** * A function for determining if a given file is esm or cjs format, assuming modern node module resolution rules, as configured by the diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 658786b63f18c..61df249f1308e 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -5102,6 +5102,31 @@ declare namespace ts { export function formatDiagnostic(diagnostic: Diagnostic, host: FormatDiagnosticsHost): string; export function formatDiagnosticsWithColorAndContext(diagnostics: readonly Diagnostic[], host: FormatDiagnosticsHost): string; export function flattenDiagnosticMessageText(diag: string | DiagnosticMessageChain | undefined, newLine: string, indent?: number): string; + /** + * Calculates the resulting resolution mode for some reference in some file - this is generally the explicitly + * provided resolution mode in the reference, unless one is not present, in which case it is the mode of the containing file. + */ + export function getModeForFileReference(ref: FileReference | string, containingFileMode: SourceFile["impliedNodeFormat"]): ModuleKind.CommonJS | ModuleKind.ESNext | undefined; + /** + * Calculates the final resolution mode for an import at some index within a file's imports list. This is generally the explicitly + * defined mode of the import if provided, or, if not, the mode of the containing file (with some exceptions: import=require is always commonjs, dynamic import is always esm). + * If you have an actual import node, prefer using getModeForUsageLocation on the reference string node. + * @param file File to fetch the resolution mode within + * @param index Index into the file's complete resolution list to get the resolution of - this is a concatenation of the file's imports and module augmentations + */ + export function getModeForResolutionAtIndex(file: SourceFile, index: number): ModuleKind.CommonJS | ModuleKind.ESNext | undefined; + /** + * Calculates the final resolution mode for a given module reference node. This is generally the explicitly provided resolution mode, if + * one exists, or the mode of the containing source file. (Excepting import=require, which is always commonjs, and dynamic import, which is always esm). + * Notably, this function always returns `undefined` if the containing file has an `undefined` `impliedNodeFormat` - this field is only set when + * `moduleResolution` is `node16`+. + * @param file The file the import or import-like reference is contained within + * @param usage The module reference string + * @returns The final resolution mode of the import + */ + export function getModeForUsageLocation(file: { + impliedNodeFormat?: SourceFile["impliedNodeFormat"]; + }, usage: StringLiteralLike): ModuleKind.CommonJS | ModuleKind.ESNext | undefined; export function getConfigFileParsingDiagnostics(configFileParseResult: ParsedCommandLine): readonly Diagnostic[]; /** * A function for determining if a given file is esm or cjs format, assuming modern node module resolution rules, as configured by the