Skip to content

Commit 07bb258

Browse files
author
Andy Hanson
committed
Don't require resolvedTsFileName and resolvedJsFileName, just resolvedFileName and extension. Also, change search order to do all TS searching before searching for JS.
1 parent dc99355 commit 07bb258

32 files changed

+407
-734
lines changed

src/compiler/moduleNameResolver.ts

+129-154
Large diffs are not rendered by default.

src/compiler/program.ts

+22-15
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,15 @@ namespace ts {
331331

332332
let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string) => ResolvedModule[];
333333
if (host.resolveModuleNames) {
334-
resolveModuleNamesWorker = (moduleNames, containingFile) => host.resolveModuleNames(moduleNames, containingFile).map(convertResolvedModuleFromHost);
334+
resolveModuleNamesWorker = (moduleNames, containingFile) => host.resolveModuleNames(moduleNames, containingFile).map(resolved => {
335+
// An older host may have omitted extension, in which case we should infer it from the file extension of resolvedFileName.
336+
if (!resolved || resolved.extension) {
337+
return resolved;
338+
}
339+
resolved = clone(resolved);
340+
resolved.extension = extensionFromPath(resolved.resolvedFileName);
341+
return resolved;
342+
});
335343
}
336344
else {
337345
const loader = (moduleName: string, containingFile: string) => resolveModuleName(moduleName, containingFile, options, host).resolvedModule;
@@ -1317,7 +1325,7 @@ namespace ts {
13171325
}
13181326

13191327
const isFromNodeModulesSearch = resolution.isExternalLibraryImport;
1320-
const isJsFileFromNodeModules = isFromNodeModulesSearch && !resolution.resolvedTsFileName;
1328+
const isJsFileFromNodeModules = isFromNodeModulesSearch && !extensionIsTypeScript(resolution.extension);
13211329
const resolvedFileName = resolution.resolvedFileName;
13221330

13231331
if (isFromNodeModulesSearch) {
@@ -1581,20 +1589,19 @@ namespace ts {
15811589
* Returns a DiagnosticMessage if we can't use a resolved module due to its extension.
15821590
* The DiagnosticMessage's parameters are the imported module name, and the filename it resolved to.
15831591
*/
1584-
export function getResolutionDiagnostic(options: CompilerOptions, { resolvedTsFileName: ts, resolvedJsFileName: js }: ResolvedModule): DiagnosticMessage | undefined {
1585-
if (ts) {
1586-
return !options.jsx && fileExtensionIs(ts, ".tsx") ? Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set : undefined;
1587-
}
1588-
else {
1589-
if (!options.allowJs) {
1590-
return Diagnostics.Module_0_was_resolved_to_1_but_allowJs_is_not_set;
1591-
}
1592-
else if (!options.jsx && fileExtensionIs(js!, ".jsx")) {
1593-
return Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set;
1594-
}
1595-
else {
1592+
export function getResolutionDiagnostic(options: CompilerOptions, { extension }: ResolvedModule): DiagnosticMessage | undefined {
1593+
switch (extension) {
1594+
case Extension.Ts:
1595+
case Extension.Dts:
1596+
// These are always allowed.
15961597
return undefined;
1597-
}
1598+
1599+
case Extension.Tsx:
1600+
case Extension.Jsx:
1601+
return options.jsx ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set;
1602+
1603+
case Extension.Js:
1604+
return options.allowJs ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_allowJs_is_not_set;
15981605
}
15991606
}
16001607
}

src/compiler/types.ts

+13-9
Original file line numberDiff line numberDiff line change
@@ -3296,22 +3296,26 @@ namespace ts {
32963296
* else resolution should just return `undefined` instead of a ResolvedModule.
32973297
*/
32983298
export interface ResolvedModule {
3299-
/**
3300-
* This should always be set to `resolvedTsFileName || resolvedJsFileName`.
3301-
* Present for backwards compatibility.
3302-
*/
3299+
/** Path of the file the module was resolved to. */
33033300
resolvedFileName: string;
3304-
/** TypeScript (.d.ts, .ts, .tsx) file that the module was resolved to. This will be preferred over a JS file. */
3305-
resolvedTsFileName?: string;
3306-
/** JavaScript (or .jsx) file that the module was resolved to. This should be returned even if '--allowJs' (or '--jsx') is disabled. */
3307-
resolvedJsFileName?: string;
3301+
/** Extension of resolvedFileName. This must match what's at the end of resolvedFileName. */
3302+
extension: Extension;
33083303
/**
33093304
* Denotes if 'resolvedFileName' is isExternalLibraryImport and thus should be a proper external module:
33103305
* - be a .d.ts file
33113306
* - use top level imports\exports
33123307
* - don't use tripleslash references
33133308
*/
3314-
isExternalLibraryImport: boolean;
3309+
isExternalLibraryImport?: boolean;
3310+
}
3311+
3312+
export enum Extension {
3313+
Ts,
3314+
Tsx,
3315+
Dts,
3316+
Js,
3317+
Jsx,
3318+
LastTypeScriptExtension = Dts
33153319
}
33163320

33173321
export interface ResolvedModuleWithFailedLookupLocations {

src/compiler/utilities.ts

+30-24
Original file line numberDiff line numberDiff line change
@@ -118,30 +118,6 @@ namespace ts {
118118
sourceFile.resolvedModules[moduleNameText] = resolvedModule;
119119
}
120120

121-
/** An older host may have omitted resolvedTsFileName and resolvedJsFileName, in which case we should infer them from the file extension of resolvedFileName. */
122-
export function convertResolvedModuleFromHost(resolved: ResolvedModule | undefined): ResolvedModule | undefined {
123-
if (resolved === undefined) {
124-
return undefined;
125-
}
126-
// At least one of `resolevdTsFileName` or `resolvedJsFileName` should be defined.
127-
else if (resolved.resolvedTsFileName || resolved.resolvedJsFileName) {
128-
const { resolvedFileName, resolvedTsFileName, resolvedJsFileName } = resolved as ResolvedModule;
129-
Debug.assert(resolvedFileName === (resolvedTsFileName || resolvedJsFileName));
130-
return resolved;
131-
}
132-
else {
133-
// For backwards compatibility, if both `resolvedTsFileName` and `resolvedJsFileName` are undefined, we infer one of them to define.
134-
const { resolvedFileName, isExternalLibraryImport } = resolved;
135-
if (fileExtensionIsAny(resolvedFileName, supportedTypeScriptExtensions)) {
136-
return { resolvedFileName, resolvedTsFileName: resolvedFileName, resolvedJsFileName: undefined, isExternalLibraryImport };
137-
}
138-
else {
139-
Debug.assert(fileExtensionIsAny(resolvedFileName, supportedJavascriptExtensions));
140-
return { resolvedFileName, resolvedTsFileName: undefined, resolvedJsFileName: resolvedFileName, isExternalLibraryImport };
141-
}
142-
}
143-
}
144-
145121
export function setResolvedTypeReferenceDirective(sourceFile: SourceFile, typeReferenceDirectiveName: string, resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective): void {
146122
if (!sourceFile.resolvedTypeReferenceDirectiveNames) {
147123
sourceFile.resolvedTypeReferenceDirectiveNames = createMap<ResolvedTypeReferenceDirective>();
@@ -157,9 +133,39 @@ namespace ts {
157133
*/
158134
export function moduleResolutionIsEqualTo(oldResolution: ResolvedModule, newResolution: ResolvedModule): boolean {
159135
return oldResolution.isExternalLibraryImport === newResolution.isExternalLibraryImport &&
136+
oldResolution.extension === newResolution.extension &&
160137
oldResolution.resolvedFileName === newResolution.resolvedFileName;
161138
}
162139

140+
/** True if an extension is one of the supported TypeScript extensions. */
141+
export function extensionIsTypeScript(ext: Extension): boolean {
142+
return ext <= Extension.LastTypeScriptExtension;
143+
}
144+
145+
/**
146+
* Gets the extension from a path.
147+
* Path must have a valid extension.
148+
*/
149+
export function extensionFromPath(path: string): Extension {
150+
if (fileExtensionIs(path, ".d.ts")) {
151+
return Extension.Dts;
152+
}
153+
if (fileExtensionIs(path, ".ts")) {
154+
return Extension.Ts;
155+
}
156+
if (fileExtensionIs(path, ".tsx")) {
157+
return Extension.Tsx;
158+
}
159+
if (fileExtensionIs(path, ".js")) {
160+
return Extension.Js;
161+
}
162+
if (fileExtensionIs(path, ".jsx")) {
163+
return Extension.Jsx;
164+
}
165+
Debug.fail(`File ${path} has unknown extension.`);
166+
return Extension.Js;
167+
}
168+
163169
/* @internal */
164170
export function typeDirectiveIsEqualTo(oldResolution: ResolvedTypeReferenceDirective, newResolution: ResolvedTypeReferenceDirective): boolean {
165171
return oldResolution.resolvedFileName === newResolution.resolvedFileName && oldResolution.primary === newResolution.primary;

0 commit comments

Comments
 (0)