Skip to content

Commit 8cf4d61

Browse files
committed
Support reference library directives in tsc
1 parent 93510e8 commit 8cf4d61

File tree

6 files changed

+71
-23
lines changed

6 files changed

+71
-23
lines changed

src/compiler/parser.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5466,6 +5466,7 @@ namespace ts {
54665466
function processReferenceComments(sourceFile: SourceFile): void {
54675467
const triviaScanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/false, LanguageVariant.Standard, sourceText);
54685468
const referencedFiles: FileReference[] = [];
5469+
const referencedLibraries: FileReference[] = [];
54695470
const amdDependencies: { path: string; name: string }[] = [];
54705471
let amdModuleName: string;
54715472

@@ -5492,7 +5493,12 @@ namespace ts {
54925493
sourceFile.hasNoDefaultLib = referencePathMatchResult.isNoDefaultLib;
54935494
const diagnosticMessage = referencePathMatchResult.diagnosticMessage;
54945495
if (fileReference) {
5495-
referencedFiles.push(fileReference);
5496+
if (referencePathMatchResult.isLibraryReference) {
5497+
referencedLibraries.push(fileReference);
5498+
}
5499+
else {
5500+
referencedFiles.push(fileReference);
5501+
}
54965502
}
54975503
if (diagnosticMessage) {
54985504
parseDiagnostics.push(createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, diagnosticMessage));
@@ -5524,6 +5530,7 @@ namespace ts {
55245530
}
55255531

55265532
sourceFile.referencedFiles = referencedFiles;
5533+
sourceFile.referencedLibraries = referencedLibraries;
55275534
sourceFile.amdDependencies = amdDependencies;
55285535
sourceFile.moduleName = amdModuleName;
55295536
}

src/compiler/program.ts

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ namespace ts {
1212

1313
const emptyArray: any[] = [];
1414

15+
const defaultLibrarySearchPaths = [
16+
'./',
17+
'./typings/',
18+
'./node_modules/',
19+
'./node_modules/@types/',
20+
];
21+
1522
export const version = "1.9.0";
1623

1724
export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean): string {
@@ -371,7 +378,7 @@ namespace ts {
371378
const traceEnabled = isTraceEnabled(compilerOptions, host);
372379

373380
const failedLookupLocations: string[] = [];
374-
const state = {compilerOptions, host, traceEnabled, skipTsx: false};
381+
const state = { compilerOptions, host, traceEnabled, skipTsx: false };
375382
let resolvedFileName = tryLoadModuleUsingOptionalResolutionSettings(moduleName, containingDirectory, nodeLoadModuleByRelativeName,
376383
failedLookupLocations, supportedExtensions, state);
377384

@@ -407,7 +414,7 @@ namespace ts {
407414
}
408415

409416
/* @internal */
410-
export function directoryProbablyExists(directoryName: string, host: { directoryExists?: (directoryName: string) => boolean } ): boolean {
417+
export function directoryProbablyExists(directoryName: string, host: { directoryExists?: (directoryName: string) => boolean }): boolean {
411418
// if host does not support 'directoryExists' assume that directory will exist
412419
return !host.directoryExists || host.directoryExists(directoryName);
413420
}
@@ -554,7 +561,7 @@ namespace ts {
554561

555562

556563
return referencedSourceFile
557-
? { resolvedModule: { resolvedFileName: referencedSourceFile }, failedLookupLocations }
564+
? { resolvedModule: { resolvedFileName: referencedSourceFile }, failedLookupLocations }
558565
: { resolvedModule: undefined, failedLookupLocations };
559566
}
560567

@@ -649,9 +656,9 @@ namespace ts {
649656

650657
export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[] {
651658
let diagnostics = program.getOptionsDiagnostics(cancellationToken).concat(
652-
program.getSyntacticDiagnostics(sourceFile, cancellationToken),
653-
program.getGlobalDiagnostics(cancellationToken),
654-
program.getSemanticDiagnostics(sourceFile, cancellationToken));
659+
program.getSyntacticDiagnostics(sourceFile, cancellationToken),
660+
program.getGlobalDiagnostics(cancellationToken),
661+
program.getSemanticDiagnostics(sourceFile, cancellationToken));
655662

656663
if (program.getCompilerOptions().declaration) {
657664
diagnostics = diagnostics.concat(program.getDeclarationDiagnostics(sourceFile, cancellationToken));
@@ -883,8 +890,8 @@ namespace ts {
883890
const oldResolution = getResolvedModule(oldSourceFile, moduleNames[i]);
884891
const resolutionChanged = oldResolution
885892
? !newResolution ||
886-
oldResolution.resolvedFileName !== newResolution.resolvedFileName ||
887-
!!oldResolution.isExternalLibraryImport !== !!newResolution.isExternalLibraryImport
893+
oldResolution.resolvedFileName !== newResolution.resolvedFileName ||
894+
!!oldResolution.isExternalLibraryImport !== !!newResolution.isExternalLibraryImport
888895
: newResolution;
889896

890897
if (resolutionChanged) {
@@ -1007,9 +1014,9 @@ namespace ts {
10071014
}
10081015

10091016
function getDiagnosticsHelper(
1010-
sourceFile: SourceFile,
1011-
getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => Diagnostic[],
1012-
cancellationToken: CancellationToken): Diagnostic[] {
1017+
sourceFile: SourceFile,
1018+
getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => Diagnostic[],
1019+
cancellationToken: CancellationToken): Diagnostic[] {
10131020
if (sourceFile) {
10141021
return getDiagnostics(sourceFile, cancellationToken);
10151022
}
@@ -1478,6 +1485,10 @@ namespace ts {
14781485
processReferencedFiles(file, basePath);
14791486
}
14801487

1488+
const libraryRoot = computeCommonSourceDirectory(files);
1489+
1490+
processReferencedLibraries(file, libraryRoot);
1491+
14811492
// always process imported modules to record module name resolutions
14821493
processImportedModules(file, basePath);
14831494

@@ -1499,6 +1510,25 @@ namespace ts {
14991510
});
15001511
}
15011512

1513+
function processReferencedLibraries(file: SourceFile, compilationRoot: string) {
1514+
const searchPaths = getEffectiveLibrarySearchPaths();
1515+
for (const ref of file.referencedLibraries) {
1516+
for (const path of searchPaths) {
1517+
const combinedPath = combinePaths(path, ref.fileName);
1518+
if (host.fileExists(combinedPath)) {
1519+
processSourceFile(combinedPath, false, file, ref.pos, ref.end);
1520+
}
1521+
}
1522+
}
1523+
}
1524+
1525+
function getEffectiveLibrarySearchPaths() {
1526+
return options.librarySearchPaths ||
1527+
(options.configFilePath ?
1528+
[options.configFilePath].concat(defaultLibrarySearchPaths) :
1529+
defaultLibrarySearchPaths);
1530+
}
1531+
15021532
function getCanonicalFileName(fileName: string): string {
15031533
return host.getCanonicalFileName(fileName);
15041534
}
@@ -1734,7 +1764,7 @@ namespace ts {
17341764

17351765
// If we failed to find a good common directory, but outDir is specified and at least one of our files is on a windows drive/URL/other resource, add a failure
17361766
if (options.outDir && dir === "" && forEach(files, file => getRootLength(file.fileName) > 1)) {
1737-
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files));
1767+
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files));
17381768
}
17391769
}
17401770

src/compiler/tsc.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ namespace ts {
390390
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"), /* compilerHost */ undefined);
391391
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
392392
}
393+
configParseResult.options.configFilePath = configFileName;
393394
return configParseResult;
394395
}
395396

src/compiler/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,6 +1515,7 @@ namespace ts {
15151515
amdDependencies: AmdDependency[];
15161516
moduleName: string;
15171517
referencedFiles: FileReference[];
1518+
referencedLibraries: FileReference[];
15181519
languageVariant: LanguageVariant;
15191520
isDeclarationFile: boolean;
15201521

@@ -2385,6 +2386,7 @@ namespace ts {
23852386
jsx?: JsxEmit;
23862387
reactNamespace?: string;
23872388
listFiles?: boolean;
2389+
librarySearchPaths?: string[];
23882390
locale?: string;
23892391
mapRoot?: string;
23902392
module?: ModuleKind;
@@ -2434,6 +2436,10 @@ namespace ts {
24342436
// Do not perform validation of output file name in transpile scenarios
24352437
/* @internal */ suppressOutputPathCheck?: boolean;
24362438

2439+
/* @internal */
2440+
// When options come from a config file, its path is recorded here
2441+
configFilePath?: string;
2442+
24372443
[option: string]: string | number | boolean | TsConfigOnlyOptions;
24382444
}
24392445

src/compiler/utilities.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace ts {
66
fileReference?: FileReference;
77
diagnosticMessage?: DiagnosticMessage;
88
isNoDefaultLib?: boolean;
9+
isLibraryReference?: boolean;
910
}
1011

1112
export interface SynthesizedNode extends Node {
@@ -498,6 +499,7 @@ namespace ts {
498499
}
499500

500501
export let fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)('|")(.+?)\2.*?\/>/;
502+
export let fullTripleSlashReferenceLibraryRegEx = /^(\/\/\/\s*<reference\s+library\s*=\s*)('|")(.+?)\2.*?\/>/;
501503
export let fullTripleSlashAMDReferencePathRegEx = /^(\/\/\/\s*<amd-dependency\s+path\s*=\s*)('|")(.+?)\2.*?\/>/;
502504

503505
export function isTypeNode(node: Node): boolean {
@@ -1532,25 +1534,26 @@ namespace ts {
15321534
};
15331535
}
15341536
else {
1535-
const matchResult = fullTripleSlashReferencePathRegEx.exec(comment);
1536-
if (matchResult) {
1537+
const refMatchResult = fullTripleSlashReferencePathRegEx.exec(comment);
1538+
const refLibResult = !refMatchResult && fullTripleSlashReferenceLibraryRegEx.exec(comment);
1539+
if (refMatchResult || refLibResult) {
15371540
const start = commentRange.pos;
15381541
const end = commentRange.end;
15391542
return {
15401543
fileReference: {
15411544
pos: start,
15421545
end: end,
1543-
fileName: matchResult[3]
1546+
fileName: (refMatchResult || refLibResult)[3]
15441547
},
1545-
isNoDefaultLib: false
1546-
};
1547-
}
1548-
else {
1549-
return {
1550-
diagnosticMessage: Diagnostics.Invalid_reference_directive_syntax,
1551-
isNoDefaultLib: false
1548+
isNoDefaultLib: false,
1549+
isLibraryReference: !!refLibResult
15521550
};
15531551
}
1552+
1553+
return {
1554+
diagnosticMessage: Diagnostics.Invalid_reference_directive_syntax,
1555+
isNoDefaultLib: false
1556+
};
15541557
}
15551558
}
15561559

src/services/services.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,7 @@ namespace ts {
792792
public amdDependencies: { name: string; path: string }[];
793793
public moduleName: string;
794794
public referencedFiles: FileReference[];
795+
public referencedLibraries: FileReference[];
795796

796797
public syntacticDiagnostics: Diagnostic[];
797798
public referenceDiagnostics: Diagnostic[];

0 commit comments

Comments
 (0)