Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 026632b

Browse filesBrowse files
committed
Merge pull request microsoft#4738 from Microsoft/properExternalModules
Check if imported file is a proper external module for imported node typings
2 parents dcb9e1c + 87e1569 commit 026632b
Copy full SHA for 026632b

28 files changed

+347-145Lines changed: 347 additions & 145 deletions
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/compiler/checker.ts‎

Copy file name to clipboardExpand all lines: src/compiler/checker.ts
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -976,8 +976,8 @@ namespace ts {
976976
}
977977
}
978978

979-
let fileName = getResolvedModuleFileName(getSourceFile(location), moduleReferenceLiteral.text);
980-
let sourceFile = fileName && host.getSourceFile(fileName);
979+
let resolvedModule = getResolvedModule(getSourceFile(location), moduleReferenceLiteral.text);
980+
let sourceFile = resolvedModule && host.getSourceFile(resolvedModule.resolvedFileName);
981981
if (sourceFile) {
982982
if (sourceFile.symbol) {
983983
return sourceFile.symbol;
Collapse file

‎src/compiler/diagnosticInformationMap.generated.ts‎

Copy file name to clipboardExpand all lines: src/compiler/diagnosticInformationMap.generated.ts
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,8 @@ namespace ts {
429429
A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums: { code: 2651, category: DiagnosticCategory.Error, key: "A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums." },
430430
Merged_declaration_0_cannot_include_a_default_export_declaration_Consider_adding_a_separate_export_default_0_declaration_instead: { code: 2652, category: DiagnosticCategory.Error, key: "Merged declaration '{0}' cannot include a default export declaration. Consider adding a separate 'export default {0}' declaration instead." },
431431
Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1: { code: 2653, category: DiagnosticCategory.Error, key: "Non-abstract class expression does not implement inherited abstract member '{0}' from class '{1}'." },
432+
Exported_external_package_typings_file_cannot_contain_tripleslash_references_Please_contact_the_package_author_to_update_the_package_definition: { code: 2654, category: DiagnosticCategory.Error, key: "Exported external package typings file cannot contain tripleslash references. Please contact the package author to update the package definition." },
433+
Exported_external_package_typings_can_only_be_in_d_ts_files_Please_contact_the_package_author_to_update_the_package_definition: { code: 2655, category: DiagnosticCategory.Error, key: "Exported external package typings can only be in '.d.ts' files. Please contact the package author to update the package definition." },
432434
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
433435
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
434436
Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." },
Collapse file

‎src/compiler/diagnosticMessages.json‎

Copy file name to clipboardExpand all lines: src/compiler/diagnosticMessages.json
+8-1Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1705,7 +1705,14 @@
17051705
"category": "Error",
17061706
"code": 2653
17071707
},
1708-
1708+
"Exported external package typings file cannot contain tripleslash references. Please contact the package author to update the package definition.": {
1709+
"category": "Error",
1710+
"code": 2654
1711+
},
1712+
"Exported external package typings can only be in '.d.ts' files. Please contact the package author to update the package definition.": {
1713+
"category": "Error",
1714+
"code": 2655
1715+
},
17091716
"Import declaration '{0}' is using private name '{1}'.": {
17101717
"category": "Error",
17111718
"code": 4000
Collapse file

‎src/compiler/program.ts‎

Copy file name to clipboardExpand all lines: src/compiler/program.ts
+44-47Lines changed: 44 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ namespace ts {
3636
return normalizePath(referencedFileName);
3737
}
3838

39-
export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModule {
39+
export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
4040
let moduleResolution = compilerOptions.moduleResolution !== undefined
4141
? compilerOptions.moduleResolution
4242
: compilerOptions.module === ModuleKind.CommonJS ? ModuleResolutionKind.NodeJs : ModuleResolutionKind.Classic;
@@ -47,7 +47,7 @@ namespace ts {
4747
}
4848
}
4949

50-
export function nodeModuleNameResolver(moduleName: string, containingFile: string, host: ModuleResolutionHost): ResolvedModule {
50+
export function nodeModuleNameResolver(moduleName: string, containingFile: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
5151
let containingDirectory = getDirectoryPath(containingFile);
5252

5353
if (getRootLength(moduleName) !== 0 || nameStartsWithDotSlashOrDotDotSlash(moduleName)) {
@@ -56,11 +56,13 @@ namespace ts {
5656
let resolvedFileName = loadNodeModuleFromFile(candidate, /* loadOnlyDts */ false, failedLookupLocations, host);
5757

5858
if (resolvedFileName) {
59-
return { resolvedFileName, failedLookupLocations };
59+
return { resolvedModule: { resolvedFileName }, failedLookupLocations };
6060
}
6161

6262
resolvedFileName = loadNodeModuleFromDirectory(candidate, /* loadOnlyDts */ false, failedLookupLocations, host);
63-
return { resolvedFileName, failedLookupLocations };
63+
return resolvedFileName
64+
? { resolvedModule: { resolvedFileName }, failedLookupLocations }
65+
: { resolvedModule: undefined, failedLookupLocations };
6466
}
6567
else {
6668
return loadModuleFromNodeModules(moduleName, containingDirectory, host);
@@ -117,7 +119,7 @@ namespace ts {
117119
return loadNodeModuleFromFile(combinePaths(candidate, "index"), loadOnlyDts, failedLookupLocation, host);
118120
}
119121

120-
function loadModuleFromNodeModules(moduleName: string, directory: string, host: ModuleResolutionHost): ResolvedModule {
122+
function loadModuleFromNodeModules(moduleName: string, directory: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
121123
let failedLookupLocations: string[] = [];
122124
directory = normalizeSlashes(directory);
123125
while (true) {
@@ -127,12 +129,12 @@ namespace ts {
127129
let candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
128130
let result = loadNodeModuleFromFile(candidate, /* loadOnlyDts */ true, failedLookupLocations, host);
129131
if (result) {
130-
return { resolvedFileName: result, failedLookupLocations };
132+
return { resolvedModule: { resolvedFileName: result, isExternalLibraryImport: true }, failedLookupLocations };
131133
}
132134

133135
result = loadNodeModuleFromDirectory(candidate, /* loadOnlyDts */ true, failedLookupLocations, host);
134136
if (result) {
135-
return { resolvedFileName: result, failedLookupLocations };
137+
return { resolvedModule: { resolvedFileName: result, isExternalLibraryImport: true }, failedLookupLocations };
136138
}
137139
}
138140

@@ -144,47 +146,19 @@ namespace ts {
144146
directory = parentPath;
145147
}
146148

147-
return { resolvedFileName: undefined, failedLookupLocations };
148-
}
149-
150-
export function baseUrlModuleNameResolver(moduleName: string, containingFile: string, baseUrl: string, host: ModuleResolutionHost): ResolvedModule {
151-
Debug.assert(baseUrl !== undefined);
152-
153-
let normalizedModuleName = normalizeSlashes(moduleName);
154-
let basePart = useBaseUrl(moduleName) ? baseUrl : getDirectoryPath(containingFile);
155-
let candidate = normalizePath(combinePaths(basePart, moduleName));
156-
157-
let failedLookupLocations: string[] = [];
158-
159-
return forEach(supportedExtensions, ext => tryLoadFile(candidate + ext)) || { resolvedFileName: undefined, failedLookupLocations };
160-
161-
function tryLoadFile(location: string): ResolvedModule {
162-
if (host.fileExists(location)) {
163-
return { resolvedFileName: location, failedLookupLocations };
164-
}
165-
else {
166-
failedLookupLocations.push(location);
167-
return undefined;
168-
}
169-
}
149+
return { resolvedModule: undefined, failedLookupLocations };
170150
}
171151

172152
function nameStartsWithDotSlashOrDotDotSlash(name: string) {
173153
let i = name.lastIndexOf("./", 1);
174154
return i === 0 || (i === 1 && name.charCodeAt(0) === CharacterCodes.dot);
175155
}
176-
177-
function useBaseUrl(moduleName: string): boolean {
178-
// path is not rooted
179-
// module name does not start with './' or '../'
180-
return getRootLength(moduleName) === 0 && !nameStartsWithDotSlashOrDotDotSlash(moduleName);
181-
}
182156

183-
export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModule {
157+
export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
184158

185159
// module names that contain '!' are used to reference resources and are not resolved to actual files on disk
186160
if (moduleName.indexOf('!') != -1) {
187-
return { resolvedFileName: undefined, failedLookupLocations: [] };
161+
return { resolvedModule: undefined, failedLookupLocations: [] };
188162
}
189163

190164
let searchPath = getDirectoryPath(containingFile);
@@ -222,7 +196,9 @@ namespace ts {
222196
searchPath = parentPath;
223197
}
224198

225-
return { resolvedFileName: referencedSourceFile, failedLookupLocations };
199+
return referencedSourceFile
200+
? { resolvedModule: { resolvedFileName: referencedSourceFile }, failedLookupLocations }
201+
: { resolvedModule: undefined, failedLookupLocations };
226202
}
227203

228204
/* @internal */
@@ -372,9 +348,9 @@ namespace ts {
372348

373349
host = host || createCompilerHost(options);
374350

375-
const resolveModuleNamesWorker =
376-
host.resolveModuleNames ||
377-
((moduleNames, containingFile) => map(moduleNames, moduleName => resolveModuleName(moduleName, containingFile, options, host).resolvedFileName));
351+
const resolveModuleNamesWorker = host.resolveModuleNames
352+
? ((moduleNames: string[], containingFile: string) => host.resolveModuleNames(moduleNames, containingFile))
353+
: ((moduleNames: string[], containingFile: string) => map(moduleNames, moduleName => resolveModuleName(moduleName, containingFile, options, host).resolvedModule));
378354

379355
let filesByName = createFileMap<SourceFile>(fileName => host.getCanonicalFileName(fileName));
380356

@@ -494,10 +470,17 @@ namespace ts {
494470
let resolutions = resolveModuleNamesWorker(moduleNames, newSourceFile.fileName);
495471
// ensure that module resolution results are still correct
496472
for (let i = 0; i < moduleNames.length; ++i) {
497-
let oldResolution = getResolvedModuleFileName(oldSourceFile, moduleNames[i]);
498-
if (oldResolution !== resolutions[i]) {
473+
let newResolution = resolutions[i];
474+
let oldResolution = getResolvedModule(oldSourceFile, moduleNames[i]);
475+
let resolutionChanged = oldResolution
476+
? !newResolution ||
477+
oldResolution.resolvedFileName !== newResolution.resolvedFileName ||
478+
!!oldResolution.isExternalLibraryImport !== !!newResolution.isExternalLibraryImport
479+
: newResolution;
480+
481+
if (resolutionChanged) {
499482
return false;
500-
}
483+
}
501484
}
502485
}
503486
// pass the cache of module resolutions from the old source file
@@ -874,9 +857,23 @@ namespace ts {
874857
let resolutions = resolveModuleNamesWorker(moduleNames, file.fileName);
875858
for (let i = 0; i < file.imports.length; ++i) {
876859
let resolution = resolutions[i];
877-
setResolvedModuleName(file, moduleNames[i], resolution);
860+
setResolvedModule(file, moduleNames[i], resolution);
878861
if (resolution && !options.noResolve) {
879-
findModuleSourceFile(resolution, file.imports[i]);
862+
const importedFile = findModuleSourceFile(resolution.resolvedFileName, file.imports[i]);
863+
if (importedFile && resolution.isExternalLibraryImport) {
864+
if (!isExternalModule(importedFile)) {
865+
let start = getTokenPosOfNode(file.imports[i], file)
866+
fileProcessingDiagnostics.add(createFileDiagnostic(file, start, file.imports[i].end - start, Diagnostics.File_0_is_not_a_module, importedFile.fileName));
867+
}
868+
else if (!fileExtensionIs(importedFile.fileName, ".d.ts")) {
869+
let start = getTokenPosOfNode(file.imports[i], file)
870+
fileProcessingDiagnostics.add(createFileDiagnostic(file, start, file.imports[i].end - start, Diagnostics.Exported_external_package_typings_can_only_be_in_d_ts_files_Please_contact_the_package_author_to_update_the_package_definition));
871+
}
872+
else if (importedFile.referencedFiles.length) {
873+
let firstRef = importedFile.referencedFiles[0];
874+
fileProcessingDiagnostics.add(createFileDiagnostic(importedFile, firstRef.pos, firstRef.end - firstRef.pos, Diagnostics.Exported_external_package_typings_file_cannot_contain_tripleslash_references_Please_contact_the_package_author_to_update_the_package_definition));
875+
}
876+
}
880877
}
881878
}
882879
}
Collapse file

‎src/compiler/types.ts‎

Copy file name to clipboardExpand all lines: src/compiler/types.ts
+13-4Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,7 +1284,7 @@ namespace ts {
12841284
// Stores a mapping 'external module reference text' -> 'resolved file name' | undefined
12851285
// It is used to resolve module names in the checker.
12861286
// Content of this fiels should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead
1287-
/* @internal */ resolvedModules: Map<string>;
1287+
/* @internal */ resolvedModules: Map<ResolvedModule>;
12881288
/* @internal */ imports: LiteralExpression[];
12891289
}
12901290

@@ -2273,11 +2273,20 @@ namespace ts {
22732273

22742274
export interface ResolvedModule {
22752275
resolvedFileName: string;
2276+
/*
2277+
* Denotes if 'resolvedFileName' is isExternalLibraryImport and thus should be proper external module:
2278+
* - be a .d.ts file
2279+
* - use top level imports\exports
2280+
* - don't use tripleslash references
2281+
*/
2282+
isExternalLibraryImport?: boolean;
2283+
}
2284+
2285+
export interface ResolvedModuleWithFailedLookupLocations {
2286+
resolvedModule: ResolvedModule;
22762287
failedLookupLocations: string[];
22772288
}
22782289

2279-
export type ModuleNameResolver = (moduleName: string, containingFile: string, options: CompilerOptions, host: ModuleResolutionHost) => ResolvedModule;
2280-
22812290
export interface CompilerHost extends ModuleResolutionHost {
22822291
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
22832292
getCancellationToken?(): CancellationToken;
@@ -2295,7 +2304,7 @@ namespace ts {
22952304
* If resolveModuleNames is implemented then implementation for members from ModuleResolutionHost can be just
22962305
* 'throw new Error("NotImplemented")'
22972306
*/
2298-
resolveModuleNames?(moduleNames: string[], containingFile: string): string[];
2307+
resolveModuleNames?(moduleNames: string[], containingFile: string): ResolvedModule[];
22992308
}
23002309

23012310
export interface TextSpan {
Collapse file

‎src/compiler/utilities.ts‎

Copy file name to clipboardExpand all lines: src/compiler/utilities.ts
+5-5Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,20 +99,20 @@ namespace ts {
9999
return true;
100100
}
101101

102-
export function hasResolvedModuleName(sourceFile: SourceFile, moduleNameText: string): boolean {
102+
export function hasResolvedModule(sourceFile: SourceFile, moduleNameText: string): boolean {
103103
return sourceFile.resolvedModules && hasProperty(sourceFile.resolvedModules, moduleNameText);
104104
}
105105

106-
export function getResolvedModuleFileName(sourceFile: SourceFile, moduleNameText: string): string {
107-
return hasResolvedModuleName(sourceFile, moduleNameText) ? sourceFile.resolvedModules[moduleNameText] : undefined;
106+
export function getResolvedModule(sourceFile: SourceFile, moduleNameText: string): ResolvedModule {
107+
return hasResolvedModule(sourceFile, moduleNameText) ? sourceFile.resolvedModules[moduleNameText] : undefined;
108108
}
109109

110-
export function setResolvedModuleName(sourceFile: SourceFile, moduleNameText: string, resolvedFileName: string): void {
110+
export function setResolvedModule(sourceFile: SourceFile, moduleNameText: string, resolvedModule: ResolvedModule): void {
111111
if (!sourceFile.resolvedModules) {
112112
sourceFile.resolvedModules = {};
113113
}
114114

115-
sourceFile.resolvedModules[moduleNameText] = resolvedFileName;
115+
sourceFile.resolvedModules[moduleNameText] = resolvedModule;
116116
}
117117

118118
// Returns true if this node contains a parse error anywhere underneath it.
Collapse file

‎src/harness/harnessLanguageService.ts‎

Copy file name to clipboardExpand all lines: src/harness/harnessLanguageService.ts
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,8 @@ module Harness.LanguageService {
225225
let imports: ts.Map<string> = {};
226226
for (let module of preprocessInfo.importedFiles) {
227227
let resolutionInfo = ts.resolveModuleName(module.fileName, fileName, compilerOptions, moduleResolutionHost);
228-
if (resolutionInfo.resolvedFileName) {
229-
imports[module.fileName] = resolutionInfo.resolvedFileName;
228+
if (resolutionInfo.resolvedModule) {
229+
imports[module.fileName] = resolutionInfo.resolvedModule.resolvedFileName;
230230
}
231231
}
232232
return JSON.stringify(imports);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.