Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose import mode calculation functions #49360

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
43 changes: 35 additions & 8 deletions src/compiler/program.ts
Expand Up @@ -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
Expand All @@ -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))) {
Expand Down
25 changes: 25 additions & 0 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Expand Up @@ -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
Expand Down
25 changes: 25 additions & 0 deletions tests/baselines/reference/api/typescript.d.ts
Expand Up @@ -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
Expand Down