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 1 commit
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
35 changes: 28 additions & 7 deletions src/compiler/program.ts
Expand Up @@ -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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idea:

Suggested change
export function getModeForResolutionAtIndex(file: SourceFileImportsList, index: number) {
export function getModeForResolutionAtIndex(file: SourceFile, index: number): ModuleKind.CommonJS | ModuleKind.ESNext | undefined;
/** @internal */
export function getModeForResolutionAtIndex(file: SourceFileImportsList, index: number): ModuleKind.CommonJS | ModuleKind.ESNext | undefined;
export function getModeForResolutionAtIndex(file: SourceFileImportsList, index: number): ModuleKind.CommonJS | ModuleKind.ESNext | undefined {

Then you don't have to expose SourceFileImportsList

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed the changes since I think we should get this into 4.7.3.

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,
Expand All @@ -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))) {
Expand Down
33 changes: 33 additions & 0 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Expand Up @@ -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
Expand Down
33 changes: 33 additions & 0 deletions tests/baselines/reference/api/typescript.d.ts
Expand Up @@ -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
Expand Down