Skip to content

Commit de47fcc

Browse files
committed
Merge pull request #7179 from Microsoft/jsTypingForAcquireDts
Salsa: JS support for discovering and acquiring d.ts files
2 parents f34dcdd + e8772bc commit de47fcc

11 files changed

+391
-51
lines changed

Jakefile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,7 @@ var servicesLintTargets = [
927927
"patternMatcher.ts",
928928
"services.ts",
929929
"shims.ts",
930+
"jsTyping.ts"
930931
].map(function (s) {
931932
return path.join(servicesDirectory, s);
932933
});

src/compiler/commandLineParser.ts

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,7 @@ namespace ts {
543543
return {
544544
options,
545545
fileNames: getFileNames(),
546+
typingOptions: getTypingOptions(),
546547
errors
547548
};
548549

@@ -607,6 +608,35 @@ namespace ts {
607608
}
608609
return fileNames;
609610
}
611+
612+
function getTypingOptions(): TypingOptions {
613+
const options: TypingOptions = getBaseFileName(configFileName) === "jsconfig.json"
614+
? { enableAutoDiscovery: true, include: [], exclude: [] }
615+
: { enableAutoDiscovery: false, include: [], exclude: [] };
616+
const jsonTypingOptions = json["typingOptions"];
617+
if (jsonTypingOptions) {
618+
for (const id in jsonTypingOptions) {
619+
if (id === "enableAutoDiscovery") {
620+
if (typeof jsonTypingOptions[id] === "boolean") {
621+
options.enableAutoDiscovery = jsonTypingOptions[id];
622+
}
623+
else {
624+
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_typing_option_0, id));
625+
}
626+
}
627+
else if (id === "include") {
628+
options.include = convertJsonOptionToStringArray(id, jsonTypingOptions[id], errors);
629+
}
630+
else if (id === "exclude") {
631+
options.exclude = convertJsonOptionToStringArray(id, jsonTypingOptions[id], errors);
632+
}
633+
else {
634+
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_typing_option_0, id));
635+
}
636+
}
637+
}
638+
return options;
639+
}
610640
}
611641

612642
export function convertCompilerOptionsFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: CompilerOptions, errors: Diagnostic[] } {
@@ -647,28 +677,7 @@ namespace ts {
647677
break;
648678
case "object":
649679
// "object" options with 'isFilePath' = true expected to be string arrays
650-
let paths: string[] = [];
651-
let invalidOptionType = false;
652-
if (!isArray(value)) {
653-
invalidOptionType = true;
654-
}
655-
else {
656-
for (const element of <any[]>value) {
657-
if (typeof element === "string") {
658-
paths.push(normalizePath(combinePaths(basePath, element)));
659-
}
660-
else {
661-
invalidOptionType = true;
662-
break;
663-
}
664-
}
665-
}
666-
if (invalidOptionType) {
667-
errors.push(createCompilerDiagnostic(Diagnostics.Option_0_should_have_array_of_strings_as_a_value, opt.name));
668-
}
669-
else {
670-
value = paths;
671-
}
680+
value = convertJsonOptionToStringArray(opt.name, value, errors, (element) => normalizePath(combinePaths(basePath, element)));
672681
break;
673682
}
674683
if (value === "") {
@@ -688,4 +697,28 @@ namespace ts {
688697

689698
return { options, errors };
690699
}
700+
701+
function convertJsonOptionToStringArray(optionName: string, optionJson: any, errors: Diagnostic[], func?: (element: string) => string): string[] {
702+
const items: string[] = [];
703+
let invalidOptionType = false;
704+
if (!isArray(optionJson)) {
705+
invalidOptionType = true;
706+
}
707+
else {
708+
for (const element of <any[]>optionJson) {
709+
if (typeof element === "string") {
710+
const item = func ? func(element) : element;
711+
items.push(item);
712+
}
713+
else {
714+
invalidOptionType = true;
715+
break;
716+
}
717+
}
718+
}
719+
if (invalidOptionType) {
720+
errors.push(createCompilerDiagnostic(Diagnostics.Option_0_should_have_array_of_strings_as_a_value, optionName));
721+
}
722+
return items;
723+
}
691724
}

src/compiler/core.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,14 @@ namespace ts {
278278
return hasOwnProperty.call(map, key);
279279
}
280280

281+
export function getKeys<T>(map: Map<T>): string[] {
282+
const keys: string[] = [];
283+
for (const key in map) {
284+
keys.push(key);
285+
}
286+
return keys;
287+
}
288+
281289
export function getProperty<T>(map: Map<T>, key: string): T {
282290
return hasOwnProperty.call(map, key) ? map[key] : undefined;
283291
}
@@ -778,6 +786,32 @@ namespace ts {
778786
return pathLen > extLen && path.substr(pathLen - extLen, extLen) === extension;
779787
}
780788

789+
export function ensureScriptKind(fileName: string, scriptKind?: ScriptKind): ScriptKind {
790+
// Using scriptKind as a condition handles both:
791+
// - 'scriptKind' is unspecified and thus it is `undefined`
792+
// - 'scriptKind' is set and it is `Unknown` (0)
793+
// If the 'scriptKind' is 'undefined' or 'Unknown' then we attempt
794+
// to get the ScriptKind from the file name. If it cannot be resolved
795+
// from the file name then the default 'TS' script kind is returned.
796+
return (scriptKind || getScriptKindFromFileName(fileName)) || ScriptKind.TS;
797+
}
798+
799+
export function getScriptKindFromFileName(fileName: string): ScriptKind {
800+
const ext = fileName.substr(fileName.lastIndexOf("."));
801+
switch (ext.toLowerCase()) {
802+
case ".js":
803+
return ScriptKind.JS;
804+
case ".jsx":
805+
return ScriptKind.JSX;
806+
case ".ts":
807+
return ScriptKind.TS;
808+
case ".tsx":
809+
return ScriptKind.TSX;
810+
default:
811+
return ScriptKind.Unknown;
812+
}
813+
}
814+
781815
/**
782816
* List of supported extensions in order of file resolution precedence.
783817
*/

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2804,5 +2804,9 @@
28042804
"'super' must be called before accessing 'this' in the constructor of a derived class.": {
28052805
"category": "Error",
28062806
"code": 17009
2807+
},
2808+
"Unknown typing option '{0}'.": {
2809+
"category": "Error",
2810+
"code": 17010
28072811
}
28082812
}

src/compiler/parser.ts

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -407,23 +407,6 @@ namespace ts {
407407
return result;
408408
}
409409

410-
/* @internal */
411-
export function getScriptKindFromFileName(fileName: string): ScriptKind {
412-
const ext = fileName.substr(fileName.lastIndexOf("."));
413-
switch (ext.toLowerCase()) {
414-
case ".js":
415-
return ScriptKind.JS;
416-
case ".jsx":
417-
return ScriptKind.JSX;
418-
case ".ts":
419-
return ScriptKind.TS;
420-
case ".tsx":
421-
return ScriptKind.TSX;
422-
default:
423-
return ScriptKind.TS;
424-
}
425-
}
426-
427410
// Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter
428411
// indicates what changed between the 'text' that this SourceFile has and the 'newText'.
429412
// The SourceFile will be created with the compiler attempting to reuse as many nodes from
@@ -551,12 +534,7 @@ namespace ts {
551534
let parseErrorBeforeNextFinishedNode = false;
552535

553536
export function parseSourceFile(fileName: string, _sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor, setParentNodes?: boolean, scriptKind?: ScriptKind): SourceFile {
554-
// Using scriptKind as a condition handles both:
555-
// - 'scriptKind' is unspecified and thus it is `undefined`
556-
// - 'scriptKind' is set and it is `Unknown` (0)
557-
// If the 'scriptKind' is 'undefined' or 'Unknown' then attempt
558-
// to get the ScriptKind from the file name.
559-
scriptKind = scriptKind ? scriptKind : getScriptKindFromFileName(fileName);
537+
scriptKind = ensureScriptKind(fileName, scriptKind);
560538

561539
initializeState(fileName, _sourceText, languageVersion, _syntaxCursor, scriptKind);
562540

src/compiler/types.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2433,6 +2433,23 @@ namespace ts {
24332433
[option: string]: string | number | boolean | TsConfigOnlyOptions;
24342434
}
24352435

2436+
export interface TypingOptions {
2437+
enableAutoDiscovery?: boolean;
2438+
include?: string[];
2439+
exclude?: string[];
2440+
[option: string]: string[] | boolean;
2441+
}
2442+
2443+
export interface DiscoverTypingsInfo {
2444+
fileNames: string[]; // The file names that belong to the same project.
2445+
cachePath: string; // The path to the typings cache
2446+
projectRootPath: string; // The path to the project root directory
2447+
safeListPath: string; // The path used to retrieve the safe list
2448+
packageNameToTypingLocation: Map<string>; // The map of package names to their cached typing locations
2449+
typingOptions: TypingOptions; // Used to customize the typing inference process
2450+
compilerOptions: CompilerOptions; // Used as a source for typing inference
2451+
}
2452+
24362453
export enum ModuleKind {
24372454
None = 0,
24382455
CommonJS = 1,
@@ -2491,6 +2508,7 @@ namespace ts {
24912508

24922509
export interface ParsedCommandLine {
24932510
options: CompilerOptions;
2511+
typingOptions?: TypingOptions;
24942512
fileNames: string[];
24952513
errors: Diagnostic[];
24962514
}

0 commit comments

Comments
 (0)