Skip to content

Make extension property of ResolvedModule optional #11899

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

Merged
1 commit merged into from
Oct 27, 2016
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/compiler/moduleNameResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ namespace ts {
}

/** Adds `isExernalLibraryImport` to a Resolved to get a ResolvedModule. */
function resolvedModuleFromResolved({ path, extension }: Resolved, isExternalLibraryImport: boolean): ResolvedModule {
function resolvedModuleFromResolved({ path, extension }: Resolved, isExternalLibraryImport: boolean): ResolvedModuleFull {
return { resolvedFileName: path, extension, isExternalLibraryImport };
}

Expand Down
16 changes: 8 additions & 8 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,16 +329,16 @@ namespace ts {
// Map storing if there is emit blocking diagnostics for given input
const hasEmitBlockingDiagnostics = createFileMap<boolean>(getCanonicalFileName);

let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string) => ResolvedModule[];
let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string) => ResolvedModuleFull[];
if (host.resolveModuleNames) {
resolveModuleNamesWorker = (moduleNames, containingFile) => host.resolveModuleNames(moduleNames, containingFile).map(resolved => {
// An older host may have omitted extension, in which case we should infer it from the file extension of resolvedFileName.
if (!resolved || resolved.extension !== undefined) {
return resolved;
if (!resolved || (resolved as ResolvedModuleFull).extension !== undefined) {
return resolved as ResolvedModuleFull;
}
resolved = clone(resolved);
resolved.extension = extensionFromPath(resolved.resolvedFileName);
return resolved;
const withExtension = clone(resolved) as ResolvedModuleFull;
withExtension.extension = extensionFromPath(resolved.resolvedFileName);
return withExtension;
});
}
else {
Expand Down Expand Up @@ -1294,7 +1294,7 @@ namespace ts {
function processImportedModules(file: SourceFile) {
collectExternalModuleReferences(file);
if (file.imports.length || file.moduleAugmentations.length) {
file.resolvedModules = createMap<ResolvedModule>();
file.resolvedModules = createMap<ResolvedModuleFull>();
const moduleNames = map(concatenate(file.imports, file.moduleAugmentations), getTextOfLiteral);
const resolutions = resolveModuleNamesWorker(moduleNames, getNormalizedAbsolutePath(file.fileName, currentDirectory));
Debug.assert(resolutions.length === moduleNames.length);
Expand Down Expand Up @@ -1571,7 +1571,7 @@ namespace ts {
* Returns a DiagnosticMessage if we can't use a resolved module due to its extension.
* The DiagnosticMessage's parameters are the imported module name, and the filename it resolved to.
*/
export function getResolutionDiagnostic(options: CompilerOptions, { extension }: ResolvedModule): DiagnosticMessage | undefined {
export function getResolutionDiagnostic(options: CompilerOptions, { extension }: ResolvedModuleFull): DiagnosticMessage | undefined {
switch (extension) {
case Extension.Ts:
case Extension.Dts:
Expand Down
23 changes: 16 additions & 7 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ namespace ts {
ThisNodeHasError = 1 << 19, // If the parser encountered an error when parsing the code that created this node
JavaScriptFile = 1 << 20, // If node was parsed in a JavaScript
ThisNodeOrAnySubNodesHasError = 1 << 21, // If this node or any of its children had an error
HasAggregatedChildData = 1 << 22, // If we've computed data from children and cached it in this node
HasAggregatedChildData = 1 << 22, // If we've computed data from children and cached it in this node

BlockScoped = Let | Const,

Expand Down Expand Up @@ -2083,7 +2083,7 @@ namespace ts {
// Stores a mapping 'external module reference text' -> 'resolved file name' | undefined
// It is used to resolve module names in the checker.
// Content of this field should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead
/* @internal */ resolvedModules: Map<ResolvedModule>;
/* @internal */ resolvedModules: Map<ResolvedModuleFull>;
/* @internal */ resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
/* @internal */ imports: LiteralExpression[];
/* @internal */ moduleAugmentations: LiteralExpression[];
Expand Down Expand Up @@ -3352,14 +3352,11 @@ namespace ts {
* Module resolution will pick up tsx/jsx/js files even if '--jsx' and '--allowJs' are turned off.
* The Program will then filter results based on these flags.
*
* At least one of `resolvedTsFileName` or `resolvedJsFileName` must be defined,
* else resolution should just return `undefined` instead of a ResolvedModule.
* Prefer to return a `ResolvedModuleFull` so that the file type does not have to be inferred.
*/
export interface ResolvedModule {
/** Path of the file the module was resolved to. */
resolvedFileName: string;
/** Extension of resolvedFileName. This must match what's at the end of resolvedFileName. */
extension: Extension;
/**
* Denotes if 'resolvedFileName' is isExternalLibraryImport and thus should be a proper external module:
* - be a .d.ts file
Expand All @@ -3369,6 +3366,18 @@ namespace ts {
isExternalLibraryImport?: boolean;
}

/**
* ResolvedModule with an explicitly provided `extension` property.
* Prefer this over `ResolvedModule`.
*/
export interface ResolvedModuleFull extends ResolvedModule {
/**
* Extension of resolvedFileName. This must match what's at the end of resolvedFileName.
* This is optional for backwards-compatibility, but will be added if not provided.
*/
extension: Extension;
}

export enum Extension {
Ts,
Tsx,
Expand All @@ -3379,7 +3388,7 @@ namespace ts {
}

export interface ResolvedModuleWithFailedLookupLocations {
resolvedModule: ResolvedModule | undefined;
resolvedModule: ResolvedModuleFull | undefined;
failedLookupLocations: string[];
}

Expand Down
12 changes: 4 additions & 8 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,13 @@ namespace ts {
return !!(sourceFile && sourceFile.resolvedModules && sourceFile.resolvedModules[moduleNameText]);
}

export function getResolvedModule(sourceFile: SourceFile, moduleNameText: string): ResolvedModule {
export function getResolvedModule(sourceFile: SourceFile, moduleNameText: string): ResolvedModuleFull {
return hasResolvedModule(sourceFile, moduleNameText) ? sourceFile.resolvedModules[moduleNameText] : undefined;
}

export function setResolvedModule(sourceFile: SourceFile, moduleNameText: string, resolvedModule: ResolvedModule): void {
export function setResolvedModule(sourceFile: SourceFile, moduleNameText: string, resolvedModule: ResolvedModuleFull): void {
if (!sourceFile.resolvedModules) {
sourceFile.resolvedModules = createMap<ResolvedModule>();
sourceFile.resolvedModules = createMap<ResolvedModuleFull>();
}

sourceFile.resolvedModules[moduleNameText] = resolvedModule;
Expand All @@ -108,11 +108,7 @@ namespace ts {
}

/* @internal */
/**
* Considers two ResolvedModules equal if they have the same `resolvedFileName`.
* Thus `{ ts: foo, js: bar }` is equal to `{ ts: foo, js: baz }` because `ts` is preferred.
*/
export function moduleResolutionIsEqualTo(oldResolution: ResolvedModule, newResolution: ResolvedModule): boolean {
export function moduleResolutionIsEqualTo(oldResolution: ResolvedModuleFull, newResolution: ResolvedModuleFull): boolean {
return oldResolution.isExternalLibraryImport === newResolution.isExternalLibraryImport &&
oldResolution.extension === newResolution.extension &&
oldResolution.resolvedFileName === newResolution.resolvedFileName;
Expand Down
6 changes: 3 additions & 3 deletions src/harness/unittests/moduleResolution.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// <reference path="..\harness.ts" />

namespace ts {
export function checkResolvedModule(expected: ResolvedModule, actual: ResolvedModule): boolean {
export function checkResolvedModule(expected: ResolvedModuleFull, actual: ResolvedModuleFull): boolean {
if (!expected === !actual) {
if (expected) {
assert.isTrue(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
Expand All @@ -13,13 +13,13 @@ namespace ts {
return false;
}

export function checkResolvedModuleWithFailedLookupLocations(actual: ResolvedModuleWithFailedLookupLocations, expectedResolvedModule: ResolvedModule, expectedFailedLookupLocations: string[]): void {
export function checkResolvedModuleWithFailedLookupLocations(actual: ResolvedModuleWithFailedLookupLocations, expectedResolvedModule: ResolvedModuleFull, expectedFailedLookupLocations: string[]): void {
assert.isTrue(actual.resolvedModule !== undefined, "module should be resolved");
checkResolvedModule(actual.resolvedModule, expectedResolvedModule);
assert.deepEqual(actual.failedLookupLocations, expectedFailedLookupLocations);
}

export function createResolvedModule(resolvedFileName: string, isExternalLibraryImport = false): ResolvedModule {
export function createResolvedModule(resolvedFileName: string, isExternalLibraryImport = false): ResolvedModuleFull {
return { resolvedFileName, extension: extensionFromPath(resolvedFileName), isExternalLibraryImport };
}

Expand Down
2 changes: 1 addition & 1 deletion src/server/lsHost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ namespace ts.server {
m => m.resolvedTypeReferenceDirective, r => r.resolvedFileName, /*logChanges*/ false);
}

resolveModuleNames(moduleNames: string[], containingFile: string): ResolvedModule[] {
resolveModuleNames(moduleNames: string[], containingFile: string): ResolvedModuleFull[] {
return this.resolveNamesWithLocalCache(moduleNames, containingFile, this.resolvedModuleNames, this.resolveModuleName,
m => m.resolvedModule, r => r.resolvedFileName, /*logChanges*/ true);
}
Expand Down
2 changes: 1 addition & 1 deletion src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ namespace ts {
public languageVariant: LanguageVariant;
public identifiers: Map<string>;
public nameTable: Map<number>;
public resolvedModules: Map<ResolvedModule>;
public resolvedModules: Map<ResolvedModuleFull>;
public resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
public imports: LiteralExpression[];
public moduleAugmentations: LiteralExpression[];
Expand Down
2 changes: 1 addition & 1 deletion src/services/shims.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ namespace ts {
private loggingEnabled = false;
private tracingEnabled = false;

public resolveModuleNames: (moduleName: string[], containingFile: string) => ResolvedModule[];
public resolveModuleNames: (moduleName: string[], containingFile: string) => ResolvedModuleFull[];
public resolveTypeReferenceDirectives: (typeDirectiveNames: string[], containingFile: string) => ResolvedTypeReferenceDirective[];
public directoryExists: (directoryName: string) => boolean;

Expand Down