Skip to content

Commit 46d28f1

Browse files
committed
added supports for 'types' compiler option
1 parent e2a23fd commit 46d28f1

30 files changed

+345
-95
lines changed

src/compiler/commandLineParser.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,15 @@ namespace ts {
325325
name: "typesRoot",
326326
type: "string"
327327
},
328+
{
329+
name: "types",
330+
type: "list",
331+
element: {
332+
name: "types",
333+
type: "string"
334+
},
335+
description: Diagnostics.Type_declaration_files_to_be_included_in_compilation
336+
},
328337
{
329338
name: "traceResolution",
330339
type: "boolean",

src/compiler/diagnosticMessages.json

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2637,7 +2637,7 @@
26372637
"category": "Error",
26382638
"code": 6114
26392639
},
2640-
"======== Resolving type reference directive '{0}' from '{1}', root dir '{2}'. ========": {
2640+
"======== Resolving type reference directive '{0}', containing file '{1}', root directory '{2}'. ========": {
26412641
"category": "Message",
26422642
"code": 6115
26432643
},
@@ -2665,10 +2665,30 @@
26652665
"category": "Message",
26662666
"code": 6121
26672667
},
2668-
"======== Resolving type reference directive '{0}' from '{1}', root dir not set. ========": {
2668+
"======== Resolving type reference directive '{0}', containing file '{1}', root directory not set. ========": {
26692669
"category": "Message",
26702670
"code": 6122
26712671
},
2672+
"Type declaration files to be included in compilation.": {
2673+
"category": "Message",
2674+
"code": 6123
2675+
},
2676+
"Looking up in 'node_modules' folder, initial location '{0}'": {
2677+
"category": "Message",
2678+
"code": 6124
2679+
},
2680+
"Containing file is not specified and root directory cannot be determined, skipping lookup in 'node_modules' folder.": {
2681+
"category": "Message",
2682+
"code": 6125
2683+
},
2684+
"======== Resolving type reference directive '{0}', containing file not set, root directory '{1}'. ========": {
2685+
"category": "Message",
2686+
"code": 6126
2687+
},
2688+
"======== Resolving type reference directive '{0}', containing file not set, root directory not set. ========": {
2689+
"category": "Message",
2690+
"code": 6127
2691+
},
26722692
"Variable '{0}' implicitly has an '{1}' type.": {
26732693
"category": "Error",
26742694
"code": 7005

src/compiler/program.ts

Lines changed: 118 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@ namespace ts {
191191

192192
const typeReferenceExtensions = [".d.ts"];
193193

194+
/**
195+
* @param {string | undefined} containingFile - file that contains type reference directive, can be undefined if containing file is unknown.
196+
* This is possible in case if resolution is performed for directives specified via 'types' parameter. In this case initial path for secondary lookups
197+
* is assumed to be the same as root directory of the project.
198+
*/
194199
export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string, containingFile: string, options: CompilerOptions, host: ModuleResolutionHost): ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
195200
const traceEnabled = isTraceEnabled(options, host);
196201
const moduleResolutionState: ModuleResolutionState = {
@@ -204,11 +209,21 @@ namespace ts {
204209
const rootDir = options.typesRoot || (options.configFilePath ? getDirectoryPath(options.configFilePath) : undefined);
205210

206211
if (traceEnabled) {
207-
if (rootDir !== undefined) {
208-
trace(host, Diagnostics.Resolving_type_reference_directive_0_from_1_root_dir_2, typeReferenceDirectiveName, containingFile, rootDir);
212+
if (containingFile === undefined) {
213+
if (rootDir === undefined) {
214+
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_not_set, typeReferenceDirectiveName);
215+
}
216+
else {
217+
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_1, typeReferenceDirectiveName, rootDir);
218+
}
209219
}
210220
else {
211-
trace(host, Diagnostics.Resolving_type_reference_directive_0_from_1_root_dir_not_set, typeReferenceDirectiveName, containingFile);
221+
if (rootDir === undefined) {
222+
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_not_set, typeReferenceDirectiveName, containingFile);
223+
}
224+
else {
225+
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_2, typeReferenceDirectiveName, containingFile, rootDir);
226+
}
212227
}
213228
}
214229

@@ -244,17 +259,33 @@ namespace ts {
244259
}
245260
}
246261

247-
if (traceEnabled) {
248-
trace(host, Diagnostics.Resolving_from_node_modules_folder);
262+
let resolvedFile: string;
263+
let initialLocationForSecondaryLookup: string;
264+
if (containingFile) {
265+
initialLocationForSecondaryLookup = getDirectoryPath(containingFile);
249266
}
250-
// check secondary locations
251-
const resolvedFile = loadModuleFromNodeModules(typeReferenceDirectiveName, getDirectoryPath(containingFile), failedLookupLocations, moduleResolutionState);
252-
if (traceEnabled) {
253-
if (resolvedFile) {
254-
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolvedFile, false);
267+
else {
268+
initialLocationForSecondaryLookup = rootDir;
269+
}
270+
271+
if (initialLocationForSecondaryLookup !== undefined) {
272+
// check secondary locations
273+
if (traceEnabled) {
274+
trace(host, Diagnostics.Looking_up_in_node_modules_folder_initial_location_0, initialLocationForSecondaryLookup);
255275
}
256-
else {
257-
trace(host, Diagnostics.Type_reference_directive_0_was_not_resolved, typeReferenceDirectiveName);
276+
resolvedFile = loadModuleFromNodeModules(typeReferenceDirectiveName, initialLocationForSecondaryLookup, failedLookupLocations, moduleResolutionState);
277+
if (traceEnabled) {
278+
if (resolvedFile) {
279+
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolvedFile, false);
280+
}
281+
else {
282+
trace(host, Diagnostics.Type_reference_directive_0_was_not_resolved, typeReferenceDirectiveName);
283+
}
284+
}
285+
}
286+
else {
287+
if (traceEnabled) {
288+
trace(host, Diagnostics.Containing_file_is_not_specified_and_root_directory_cannot_be_determined_skipping_lookup_in_node_modules_folder);
258289
}
259290
}
260291
return {
@@ -927,24 +958,15 @@ namespace ts {
927958
// used to track cases when two file names differ only in casing
928959
const filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? createFileMap<SourceFile>(fileName => fileName.toLowerCase()) : undefined;
929960

930-
if (oldProgram) {
931-
// check properties that can affect structure of the program or module resolution strategy
932-
// if any of these properties has changed - structure cannot be reused
933-
const oldOptions = oldProgram.getCompilerOptions();
934-
if ((oldOptions.module !== options.module) ||
935-
(oldOptions.noResolve !== options.noResolve) ||
936-
(oldOptions.target !== options.target) ||
937-
(oldOptions.noLib !== options.noLib) ||
938-
(oldOptions.jsx !== options.jsx) ||
939-
(oldOptions.allowJs !== options.allowJs) ||
940-
(oldOptions.rootDir !== options.rootDir) ||
941-
(oldOptions.typesSearchPaths !== options.typesSearchPaths) ||
942-
(oldOptions.configFilePath !== options.configFilePath)) {
943-
oldProgram = undefined;
961+
if (!tryReuseStructureFromOldProgram()) {
962+
// load type declarations specified via 'types' argument
963+
if (options.types && options.types.length) {
964+
const resolutions = resolveTypeReferenceDirectiveNamesWorker(options.types, /*containingFile*/ undefined);
965+
for (let i = 0; i < options.types.length; i++) {
966+
processTypeReferenceDirective(options.types[i], resolutions[i]);
967+
}
944968
}
945-
}
946969

947-
if (!tryReuseStructureFromOldProgram()) {
948970
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false));
949971
// Do not process the default library if:
950972
// - The '--noLib' flag is used.
@@ -1036,6 +1058,21 @@ namespace ts {
10361058
return false;
10371059
}
10381060

1061+
// check properties that can affect structure of the program or module resolution strategy
1062+
// if any of these properties has changed - structure cannot be reused
1063+
const oldOptions = oldProgram.getCompilerOptions();
1064+
if ((oldOptions.module !== options.module) ||
1065+
(oldOptions.noResolve !== options.noResolve) ||
1066+
(oldOptions.target !== options.target) ||
1067+
(oldOptions.noLib !== options.noLib) ||
1068+
(oldOptions.jsx !== options.jsx) ||
1069+
(oldOptions.allowJs !== options.allowJs) ||
1070+
(oldOptions.rootDir !== options.rootDir) ||
1071+
(oldOptions.typesSearchPaths !== options.typesSearchPaths) ||
1072+
(oldOptions.configFilePath !== options.configFilePath)) {
1073+
return false;
1074+
}
1075+
10391076
Debug.assert(!oldProgram.structureIsReused);
10401077

10411078
// there is an old program, check if we can reuse its structure
@@ -1044,6 +1081,10 @@ namespace ts {
10441081
return false;
10451082
}
10461083

1084+
if (!arrayIsEqualTo(options.types, oldOptions.types)) {
1085+
return false;
1086+
}
1087+
10471088
// check if program source files has changed in the way that can affect structure of the program
10481089
const newSourceFiles: SourceFile[] = [];
10491090
const filePaths: Path[] = [];
@@ -1733,45 +1774,61 @@ namespace ts {
17331774
const resolvedTypeReferenceDirective = resolutions[i];
17341775
// store resolved type directive on the file
17351776
setResolvedTypeReferenceDirective(file, ref.fileName, resolvedTypeReferenceDirective);
1736-
// If we already found this library as a primary reference - nothing to do
1737-
const previousResolution = resolvedTypeReferenceDirectives[ref.fileName];
1738-
if (previousResolution && previousResolution.primary) {
1739-
continue;
1777+
processTypeReferenceDirective(ref.fileName, resolvedTypeReferenceDirective, file, ref.pos, ref.end);
1778+
}
1779+
}
1780+
1781+
function processTypeReferenceDirective(typeReferenceDirective: string, resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective,
1782+
refFile?: SourceFile, refPos?: number, refEnd?: number): void {
1783+
1784+
// If we already found this library as a primary reference - nothing to do
1785+
const previousResolution = resolvedTypeReferenceDirectives[typeReferenceDirective];
1786+
if (previousResolution && previousResolution.primary) {
1787+
return;
1788+
}
1789+
let saveResolution = true;
1790+
if (resolvedTypeReferenceDirective) {
1791+
if (resolvedTypeReferenceDirective.primary) {
1792+
// resolved from the primary path
1793+
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName, /*isDefaultLib*/ false, /*isReference*/ true, refFile, refPos, refEnd);
17401794
}
1741-
let saveResolution = true;
1742-
if (resolvedTypeReferenceDirective) {
1743-
if (resolvedTypeReferenceDirective.primary) {
1744-
// resolved from the primary path
1745-
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName, /*isDefaultLib*/ false, /*isReference*/ true, file, ref.pos, ref.end);
1795+
else {
1796+
// If we already resolved to this file, it must have been a secondary reference. Check file contents
1797+
// for sameness and possibly issue an error
1798+
if (previousResolution) {
1799+
const otherFileText = host.readFile(resolvedTypeReferenceDirective.resolvedFileName);
1800+
if (otherFileText !== getSourceFile(previousResolution.resolvedFileName).text) {
1801+
fileProcessingDiagnostics.add(createDiagnostic(refFile, refPos, refEnd,
1802+
Diagnostics.Conflicting_library_definitions_for_0_found_at_1_and_2_Copy_the_correct_file_to_the_typings_folder_to_resolve_this_conflict,
1803+
typeReferenceDirective,
1804+
resolvedTypeReferenceDirective.resolvedFileName,
1805+
previousResolution.resolvedFileName
1806+
));
1807+
}
1808+
// don't overwrite previous resolution result
1809+
saveResolution = false;
17461810
}
17471811
else {
1748-
// If we already resolved to this file, it must have been a secondary reference. Check file contents
1749-
// for sameness and possibly issue an error
1750-
if (previousResolution) {
1751-
const otherFileText = host.readFile(resolvedTypeReferenceDirective.resolvedFileName);
1752-
if (otherFileText !== getSourceFile(previousResolution.resolvedFileName).text) {
1753-
fileProcessingDiagnostics.add(createFileDiagnostic(file, ref.pos, ref.end - ref.pos,
1754-
Diagnostics.Conflicting_library_definitions_for_0_found_at_1_and_2_Copy_the_correct_file_to_the_typings_folder_to_resolve_this_conflict,
1755-
ref.fileName,
1756-
resolvedTypeReferenceDirective.resolvedFileName,
1757-
previousResolution.resolvedFileName));
1758-
}
1759-
// don't overwrite previous resolution result
1760-
saveResolution = false;
1761-
}
1762-
else {
1763-
// First resolution of this library
1764-
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName, /*isDefaultLib*/ false, /*isReference*/ true, file, ref.pos, ref.end);
1765-
}
1812+
// First resolution of this library
1813+
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName, /*isDefaultLib*/ false, /*isReference*/ true, refFile, refPos, refEnd);
17661814
}
17671815
}
1768-
else {
1769-
fileProcessingDiagnostics.add(createFileDiagnostic(file, ref.pos, ref.end - ref.pos, Diagnostics.Cannot_find_name_0, ref.fileName));
1770-
}
1816+
}
1817+
else {
1818+
fileProcessingDiagnostics.add(createDiagnostic(refFile, refPos, refEnd, Diagnostics.Cannot_find_name_0, typeReferenceDirective));
1819+
}
17711820

1772-
if (saveResolution) {
1773-
resolvedTypeReferenceDirectives[ref.fileName] = resolvedTypeReferenceDirective;
1774-
}
1821+
if (saveResolution) {
1822+
resolvedTypeReferenceDirectives[typeReferenceDirective] = resolvedTypeReferenceDirective;
1823+
}
1824+
}
1825+
1826+
function createDiagnostic(refFile: SourceFile, refPos: number, refEnd: number, message: DiagnosticMessage, ...args: any[]): Diagnostic {
1827+
if (refFile === undefined || refPos === undefined || refEnd === undefined) {
1828+
return createCompilerDiagnostic(message, ...args);
1829+
}
1830+
else {
1831+
return createFileDiagnostic(refFile, refPos, refEnd - refPos, message, ...args);
17751832
}
17761833
}
17771834

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2476,6 +2476,7 @@ namespace ts {
24762476
/* @internal */
24772477
// Path used to used to compute primary search locations
24782478
typesRoot?: string;
2479+
types?: string[];
24792480

24802481
list?: string[];
24812482
[option: string]: CompilerOptionsValue;

tests/baselines/reference/library-reference-1.trace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[
2-
"======== Resolving type reference directive 'jquery' from '/consumer.ts', root dir '/'. ========",
2+
"======== Resolving type reference directive 'jquery', containing file '/consumer.ts', root directory '/'. ========",
33
"Resolving with primary search path '/types/'",
44
"File '/types/jquery/package.json' does not exist.",
55
"File '/types/jquery/index.d.ts' exist - use it as a name resolution result.",

tests/baselines/reference/library-reference-10.trace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[
2-
"======== Resolving type reference directive 'jquery' from '/consumer.ts', root dir '/'. ========",
2+
"======== Resolving type reference directive 'jquery', containing file '/consumer.ts', root directory '/'. ========",
33
"Resolving with primary search path '/types/'",
44
"Found 'package.json' at '/types/jquery/package.json'.",
55
"'package.json' has 'typings' field 'jquery.d.ts' that references '/types/jquery/jquery.d.ts'.",

tests/baselines/reference/library-reference-11.trace.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[
2-
"======== Resolving type reference directive 'jquery' from '/a/b/consumer.ts', root dir not set. ========",
2+
"======== Resolving type reference directive 'jquery', containing file '/a/b/consumer.ts', root directory not set. ========",
33
"Root directory cannot be determined, skipping primary search paths.",
4-
"Resolving from node_modules folder...",
4+
"Looking up in 'node_modules' folder, initial location '/a/b'",
55
"File '/a/b/node_modules/jquery.ts' does not exist.",
66
"File '/a/b/node_modules/jquery.d.ts' does not exist.",
77
"File '/a/b/node_modules/jquery/package.json' does not exist.",

tests/baselines/reference/library-reference-12.trace.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[
2-
"======== Resolving type reference directive 'jquery' from '/a/b/consumer.ts', root dir not set. ========",
2+
"======== Resolving type reference directive 'jquery', containing file '/a/b/consumer.ts', root directory not set. ========",
33
"Root directory cannot be determined, skipping primary search paths.",
4-
"Resolving from node_modules folder...",
4+
"Looking up in 'node_modules' folder, initial location '/a/b'",
55
"File '/a/b/node_modules/jquery.ts' does not exist.",
66
"File '/a/b/node_modules/jquery.d.ts' does not exist.",
77
"File '/a/b/node_modules/jquery/package.json' does not exist.",
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//// [tests/cases/conformance/references/library-reference-13.ts] ////
2+
3+
//// [index.d.ts]
4+
declare var $: { foo(): void };
5+
6+
7+
//// [consumer.ts]
8+
$.foo();
9+
10+
11+
//// [consumer.js]
12+
$.foo();
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
=== /a/b/consumer.ts ===
2+
$.foo();
3+
>$.foo : Symbol(foo, Decl(index.d.ts, 0, 16))
4+
>$ : Symbol($, Decl(index.d.ts, 0, 11))
5+
>foo : Symbol(foo, Decl(index.d.ts, 0, 16))
6+
7+
=== /a/types/jquery/index.d.ts ===
8+
declare var $: { foo(): void };
9+
>$ : Symbol($, Decl(index.d.ts, 0, 11))
10+
>foo : Symbol(foo, Decl(index.d.ts, 0, 16))
11+
12+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[
2+
"======== Resolving type reference directive 'jquery', containing file not set, root directory '/a'. ========",
3+
"Resolving with primary search path '/a/types/'",
4+
"File '/a/types/jquery/package.json' does not exist.",
5+
"File '/a/types/jquery/index.d.ts' exist - use it as a name resolution result.",
6+
"======== Type reference directive 'jquery' was successfully resolved to '/a/types/jquery/index.d.ts', primary: true. ========"
7+
]
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
=== /a/b/consumer.ts ===
2+
$.foo();
3+
>$.foo() : void
4+
>$.foo : () => void
5+
>$ : { foo(): void; }
6+
>foo : () => void
7+
8+
=== /a/types/jquery/index.d.ts ===
9+
declare var $: { foo(): void };
10+
>$ : { foo(): void; }
11+
>foo : () => void
12+
13+

0 commit comments

Comments
 (0)