From 5eb64255698f3143150cfab0816c47d5d7fc70d9 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 2 Jun 2022 14:13:24 -0700 Subject: [PATCH] Expose import mode calculation functions --- src/compiler/program.ts | 35 +++++++++++++++---- .../reference/api/tsserverlibrary.d.ts | 33 +++++++++++++++++ tests/baselines/reference/api/typescript.d.ts | 33 +++++++++++++++++ 3 files changed, 94 insertions(+), 7 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index aa106a61873..19db30ac715 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -536,19 +536,32 @@ 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. + */ + 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 */ + /** + * 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: SourceFileImportsList, index: number) { 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, @@ -567,7 +580,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 ab7ae0cde49..295206967e4 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -5102,6 +5102,39 @@ 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; + /** + * 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. + */ + export interface SourceFileImportsList { + impliedNodeFormat?: SourceFile["impliedNodeFormat"]; + } + /** + * 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: SourceFileImportsList, 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 658786b63f1..786e4bd9175 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -5102,6 +5102,39 @@ 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; + /** + * 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. + */ + export interface SourceFileImportsList { + impliedNodeFormat?: SourceFile["impliedNodeFormat"]; + } + /** + * 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: SourceFileImportsList, 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