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 a089297

Browse filesBrowse files
committed
Add 'lib' reference support
1 parent c05923b commit a089297
Copy full SHA for a089297

32 files changed

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

‎src/compiler/core.ts‎

Copy file name to clipboardExpand all lines: src/compiler/core.ts
-104Lines changed: 0 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -2029,110 +2029,6 @@ namespace ts {
20292029
return res > max ? undefined : res;
20302030
}
20312031

2032-
export function normalizeSlashes(path: string): string {
2033-
return path.replace(/\\/g, "/");
2034-
}
2035-
2036-
/**
2037-
* Returns length of path root (i.e. length of "/", "x:/", "//server/share/, file:///user/files")
2038-
*/
2039-
export function getRootLength(path: string): number {
2040-
if (path.charCodeAt(0) === CharacterCodes.slash) {
2041-
if (path.charCodeAt(1) !== CharacterCodes.slash) return 1;
2042-
const p1 = path.indexOf("/", 2);
2043-
if (p1 < 0) return 2;
2044-
const p2 = path.indexOf("/", p1 + 1);
2045-
if (p2 < 0) return p1 + 1;
2046-
return p2 + 1;
2047-
}
2048-
if (path.charCodeAt(1) === CharacterCodes.colon) {
2049-
if (path.charCodeAt(2) === CharacterCodes.slash || path.charCodeAt(2) === CharacterCodes.backslash) return 3;
2050-
}
2051-
// Per RFC 1738 'file' URI schema has the shape file://<host>/<path>
2052-
// if <host> is omitted then it is assumed that host value is 'localhost',
2053-
// however slash after the omitted <host> is not removed.
2054-
// file:///folder1/file1 - this is a correct URI
2055-
// file://folder2/file2 - this is an incorrect URI
2056-
if (path.lastIndexOf("file:///", 0) === 0) {
2057-
return "file:///".length;
2058-
}
2059-
const idx = path.indexOf("://");
2060-
if (idx !== -1) {
2061-
return idx + "://".length;
2062-
}
2063-
return 0;
2064-
}
2065-
2066-
/**
2067-
* Internally, we represent paths as strings with '/' as the directory separator.
2068-
* When we make system calls (eg: LanguageServiceHost.getDirectory()),
2069-
* we expect the host to correctly handle paths in our specified format.
2070-
*/
2071-
export const directorySeparator = "/";
2072-
const directorySeparatorCharCode = CharacterCodes.slash;
2073-
function getNormalizedParts(normalizedSlashedPath: string, rootLength: number): string[] {
2074-
const parts = normalizedSlashedPath.substr(rootLength).split(directorySeparator);
2075-
const normalized: string[] = [];
2076-
for (const part of parts) {
2077-
if (part !== ".") {
2078-
if (part === ".." && normalized.length > 0 && lastOrUndefined(normalized) !== "..") {
2079-
normalized.pop();
2080-
}
2081-
else {
2082-
// A part may be an empty string (which is 'falsy') if the path had consecutive slashes,
2083-
// e.g. "path//file.ts". Drop these before re-joining the parts.
2084-
if (part) {
2085-
normalized.push(part);
2086-
}
2087-
}
2088-
}
2089-
}
2090-
2091-
return normalized;
2092-
}
2093-
2094-
export function normalizePath(path: string): string {
2095-
return normalizePathAndParts(path).path;
2096-
}
2097-
2098-
export function normalizePathAndParts(path: string): { path: string, parts: string[] } {
2099-
path = normalizeSlashes(path);
2100-
const rootLength = getRootLength(path);
2101-
const root = path.substr(0, rootLength);
2102-
const parts = getNormalizedParts(path, rootLength);
2103-
if (parts.length) {
2104-
const joinedParts = root + parts.join(directorySeparator);
2105-
return { path: pathEndsWithDirectorySeparator(path) ? joinedParts + directorySeparator : joinedParts, parts };
2106-
}
2107-
else {
2108-
return { path: root, parts };
2109-
}
2110-
}
2111-
2112-
/** A path ending with '/' refers to a directory only, never a file. */
2113-
export function pathEndsWithDirectorySeparator(path: string): boolean {
2114-
return path.charCodeAt(path.length - 1) === directorySeparatorCharCode;
2115-
}
2116-
2117-
/**
2118-
* Returns the path except for its basename. Eg:
2119-
*
2120-
* /path/to/file.ext -> /path/to
2121-
*/
2122-
export function getDirectoryPath(path: Path): Path;
2123-
export function getDirectoryPath(path: string): string;
2124-
export function getDirectoryPath(path: string): string {
2125-
return path.substr(0, Math.max(getRootLength(path), path.lastIndexOf(directorySeparator)));
2126-
}
2127-
2128-
export function isUrl(path: string) {
2129-
return path && !isRootedDiskPath(path) && stringContains(path, "://");
2130-
}
2131-
2132-
export function pathIsRelative(path: string): boolean {
2133-
return /^\.\.?($|[\\/])/.test(path);
2134-
}
2135-
21362032
export function getEmitScriptTarget(compilerOptions: CompilerOptions) {
21372033
return compilerOptions.target || ScriptTarget.ES3;
21382034
}
Collapse file

‎src/compiler/diagnosticMessages.json‎

Copy file name to clipboardExpand all lines: src/compiler/diagnosticMessages.json
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2356,6 +2356,14 @@
23562356
"category": "Error",
23572357
"code": 2724
23582358
},
2359+
"Cannot find lib definition for '{0}'.": {
2360+
"category": "Error",
2361+
"code": 2725
2362+
},
2363+
"Cannot find lib definition for '{0}'. Did you mean '{1}'?": {
2364+
"category": "Error",
2365+
"code": 2726
2366+
},
23592367
"Import declaration '{0}' is using private name '{1}'.": {
23602368
"category": "Error",
23612369
"code": 4000
Collapse file

‎src/compiler/factory.ts‎

Copy file name to clipboardExpand all lines: src/compiler/factory.ts
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2417,12 +2417,13 @@ namespace ts {
24172417

24182418
// Top-level nodes
24192419

2420-
export function updateSourceFileNode(node: SourceFile, statements: ReadonlyArray<Statement>, isDeclarationFile?: boolean, referencedFiles?: SourceFile["referencedFiles"], typeReferences?: SourceFile["typeReferenceDirectives"], hasNoDefaultLib?: boolean) {
2420+
export function updateSourceFileNode(node: SourceFile, statements: ReadonlyArray<Statement>, isDeclarationFile?: boolean, referencedFiles?: SourceFile["referencedFiles"], typeReferences?: SourceFile["typeReferenceDirectives"], hasNoDefaultLib?: boolean, libReferences?: SourceFile["libReferenceDirectives"]) {
24212421
if (
24222422
node.statements !== statements ||
24232423
(isDeclarationFile !== undefined && node.isDeclarationFile !== isDeclarationFile) ||
24242424
(referencedFiles !== undefined && node.referencedFiles !== referencedFiles) ||
24252425
(typeReferences !== undefined && node.typeReferenceDirectives !== typeReferences) ||
2426+
(libReferences !== undefined && node.libReferenceDirectives !== libReferences) ||
24262427
(hasNoDefaultLib !== undefined && node.hasNoDefaultLib !== hasNoDefaultLib)
24272428
) {
24282429
const updated = <SourceFile>createSynthesizedNode(SyntaxKind.SourceFile);
@@ -2436,6 +2437,7 @@ namespace ts {
24362437
updated.referencedFiles = referencedFiles === undefined ? node.referencedFiles : referencedFiles;
24372438
updated.typeReferenceDirectives = typeReferences === undefined ? node.typeReferenceDirectives : typeReferences;
24382439
updated.hasNoDefaultLib = hasNoDefaultLib === undefined ? node.hasNoDefaultLib : hasNoDefaultLib;
2440+
updated.libReferenceDirectives = libReferences === undefined ? node.libReferenceDirectives : libReferences;
24392441
if (node.amdDependencies !== undefined) updated.amdDependencies = node.amdDependencies;
24402442
if (node.moduleName !== undefined) updated.moduleName = node.moduleName;
24412443
if (node.languageVariant !== undefined) updated.languageVariant = node.languageVariant;
Collapse file

‎src/compiler/parser.ts‎

Copy file name to clipboardExpand all lines: src/compiler/parser.ts
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7592,6 +7592,7 @@ namespace ts {
75927592
checkJsDirective?: CheckJsDirective;
75937593
referencedFiles: FileReference[];
75947594
typeReferenceDirectives: FileReference[];
7595+
libReferenceDirectives: FileReference[];
75957596
amdDependencies: AmdDependency[];
75967597
hasNoDefaultLib?: boolean;
75977598
moduleName?: string;
@@ -7645,6 +7646,7 @@ namespace ts {
76457646
context.checkJsDirective = undefined;
76467647
context.referencedFiles = [];
76477648
context.typeReferenceDirectives = [];
7649+
context.libReferenceDirectives = [];
76487650
context.amdDependencies = [];
76497651
context.hasNoDefaultLib = false;
76507652
context.pragmas.forEach((entryOrList, key) => {
@@ -7654,13 +7656,17 @@ namespace ts {
76547656
case "reference": {
76557657
const referencedFiles = context.referencedFiles;
76567658
const typeReferenceDirectives = context.typeReferenceDirectives;
7659+
const libReferenceDirectives = context.libReferenceDirectives;
76577660
forEach(toArray(entryOrList), (arg: PragmaPsuedoMap["reference"]) => {
76587661
if (arg.arguments["no-default-lib"]) {
76597662
context.hasNoDefaultLib = true;
76607663
}
76617664
else if (arg.arguments.types) {
76627665
typeReferenceDirectives.push({ pos: arg.arguments.types.pos, end: arg.arguments.types.end, fileName: arg.arguments.types.value });
76637666
}
7667+
else if (arg.arguments.lib) {
7668+
libReferenceDirectives.push({ pos: arg.arguments.lib.pos, end: arg.arguments.lib.end, fileName: arg.arguments.lib.value });
7669+
}
76647670
else if (arg.arguments.path) {
76657671
referencedFiles.push({ pos: arg.arguments.path.pos, end: arg.arguments.path.end, fileName: arg.arguments.path.value });
76667672
}
Collapse file

‎src/compiler/program.ts‎

Copy file name to clipboardExpand all lines: src/compiler/program.ts
+37-13Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ namespace ts {
584584
const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
585585
const structuralIsReused = tryReuseStructureFromOldProgram();
586586
if (structuralIsReused !== StructureIsReused.Completely) {
587-
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false));
587+
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false));
588588

589589
// load type declarations specified via 'types' argument or implicitly from types/ and node_modules/@types folders
590590
const typeReferences: string[] = getAutomaticTypeDirectiveNames(options, host);
@@ -608,11 +608,11 @@ namespace ts {
608608
// otherwise, using options specified in '--lib' instead of '--target' default library file
609609
const defaultLibraryFileName = getDefaultLibraryFileName();
610610
if (!options.lib && defaultLibraryFileName) {
611-
processRootFile(defaultLibraryFileName, /*isDefaultLib*/ true);
611+
processRootFile(defaultLibraryFileName, /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false);
612612
}
613613
else {
614614
forEach(options.lib, libFileName => {
615-
processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true);
615+
processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false);
616616
});
617617
}
618618
}
@@ -964,6 +964,11 @@ namespace ts {
964964
if (fileChanged) {
965965
// The `newSourceFile` object was created for the new program.
966966

967+
if (!arrayIsEqualTo(oldSourceFile.libReferenceDirectives, newSourceFile.libReferenceDirectives, fileReferenceIsEqualTo)) {
968+
// 'lib' references has changed. Matches behavior in chagnesAffectModuleResolution
969+
return oldProgram.structureIsReused = StructureIsReused.Not;
970+
}
971+
967972
if (oldSourceFile.hasNoDefaultLib !== newSourceFile.hasNoDefaultLib) {
968973
// value of no-default-lib has changed
969974
// this will affect if default library is injected into the list of files
@@ -1579,8 +1584,8 @@ namespace ts {
15791584
return configFileParsingDiagnostics || emptyArray;
15801585
}
15811586

1582-
function processRootFile(fileName: string, isDefaultLib: boolean) {
1583-
processSourceFile(normalizePath(fileName), isDefaultLib, /*packageId*/ undefined);
1587+
function processRootFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean) {
1588+
processSourceFile(normalizePath(fileName), isDefaultLib, ignoreNoDefaultLib, /*packageId*/ undefined);
15841589
}
15851590

15861591
function fileReferenceIsEqualTo(a: FileReference, b: FileReference): boolean {
@@ -1747,9 +1752,9 @@ namespace ts {
17471752
}
17481753

17491754
/** This has side effects through `findSourceFile`. */
1750-
function processSourceFile(fileName: string, isDefaultLib: boolean, packageId: PackageId | undefined, refFile?: SourceFile, refPos?: number, refEnd?: number): void {
1755+
function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, refFile?: SourceFile, refPos?: number, refEnd?: number): void {
17511756
getSourceFileFromReferenceWorker(fileName,
1752-
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, refFile, refPos, refEnd, packageId),
1757+
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, ignoreNoDefaultLib, refFile, refPos, refEnd, packageId),
17531758
(diagnostic, ...args) => {
17541759
fileProcessingDiagnostics.add(refFile !== undefined && refEnd !== undefined && refPos !== undefined
17551760
? createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...args)
@@ -1787,7 +1792,7 @@ namespace ts {
17871792
}
17881793

17891794
// Get source file from normalized fileName
1790-
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined {
1795+
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined {
17911796
if (filesByName.has(path)) {
17921797
const file = filesByName.get(path);
17931798
// try to check if we've already seen this file but with a different casing in path
@@ -1802,6 +1807,7 @@ namespace ts {
18021807
sourceFilesFoundSearchingNodeModules.set(file.path, false);
18031808
if (!options.noResolve) {
18041809
processReferencedFiles(file, isDefaultLib);
1810+
processLibReferenceDirectives(file);
18051811
processTypeReferenceDirectives(file);
18061812
}
18071813

@@ -1867,10 +1873,11 @@ namespace ts {
18671873
}
18681874
}
18691875

1870-
skipDefaultLib = skipDefaultLib || file.hasNoDefaultLib;
1876+
skipDefaultLib = skipDefaultLib || (file.hasNoDefaultLib && !ignoreNoDefaultLib);
18711877

18721878
if (!options.noResolve) {
18731879
processReferencedFiles(file, isDefaultLib);
1880+
processLibReferenceDirectives(file);
18741881
processTypeReferenceDirectives(file);
18751882
}
18761883

@@ -1891,7 +1898,7 @@ namespace ts {
18911898
function processReferencedFiles(file: SourceFile, isDefaultLib: boolean) {
18921899
forEach(file.referencedFiles, ref => {
18931900
const referencedFileName = resolveTripleslashReference(ref.fileName, file.fileName);
1894-
processSourceFile(referencedFileName, isDefaultLib, /*packageId*/ undefined, file, ref.pos, ref.end);
1901+
processSourceFile(referencedFileName, isDefaultLib, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined, file, ref.pos, ref.end);
18951902
});
18961903
}
18971904

@@ -1922,7 +1929,7 @@ namespace ts {
19221929
if (resolvedTypeReferenceDirective) {
19231930
if (resolvedTypeReferenceDirective.primary) {
19241931
// resolved from the primary path
1925-
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName, /*isDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd);
1932+
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd);
19261933
}
19271934
else {
19281935
// If we already resolved to this file, it must have been a secondary reference. Check file contents
@@ -1945,7 +1952,7 @@ namespace ts {
19451952
}
19461953
else {
19471954
// First resolution of this library
1948-
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName, /*isDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd);
1955+
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd);
19491956
}
19501957
}
19511958
}
@@ -1958,6 +1965,23 @@ namespace ts {
19581965
}
19591966
}
19601967

1968+
function processLibReferenceDirectives(file: SourceFile) {
1969+
forEach(file.libReferenceDirectives, libReference => {
1970+
const libName = libReference.fileName.toLocaleLowerCase();
1971+
const libFileName = libMap.get(libName);
1972+
if (libFileName) {
1973+
// we ignore any 'no-default-lib' reference set on this file.
1974+
processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ true);
1975+
}
1976+
else {
1977+
const unqualifiedLibName = removeSuffix(removePrefix(libName, "lib."), ".d.ts");
1978+
const suggestion = getSpellingSuggestion(unqualifiedLibName, libs, identity);
1979+
const message = suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 : Diagnostics.Cannot_find_lib_definition_for_0;
1980+
fileProcessingDiagnostics.add(createDiagnostic(file, libReference.pos, libReference.end, message, libName, suggestion));
1981+
}
1982+
});
1983+
}
1984+
19611985
function createDiagnostic(refFile: SourceFile, refPos: number, refEnd: number, message: DiagnosticMessage, ...args: any[]): Diagnostic {
19621986
if (refFile === undefined || refPos === undefined || refEnd === undefined) {
19631987
return createCompilerDiagnostic(message, ...args);
@@ -2018,7 +2042,7 @@ namespace ts {
20182042
else if (shouldAddFile) {
20192043
const path = toPath(resolvedFileName);
20202044
const pos = skipTrivia(file.text, file.imports[i].pos);
2021-
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, file, pos, file.imports[i].end, resolution.packageId);
2045+
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, file, pos, file.imports[i].end, resolution.packageId);
20222046
}
20232047

20242048
if (isFromNodeModulesSearch) {
Collapse file

‎src/compiler/transformers/declarations.ts‎

Copy file name to clipboardExpand all lines: src/compiler/transformers/declarations.ts
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,12 @@ namespace ts {
156156
[createModifier(SyntaxKind.DeclareKeyword)],
157157
createLiteral(getResolvedExternalModuleName(context.getEmitHost(), sourceFile)),
158158
createModuleBlock(setTextRange(createNodeArray(filterCandidateImports(statements)), sourceFile.statements))
159-
)], /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false);
159+
)], /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []);
160160
return newFile;
161161
}
162162
needsDeclare = true;
163163
const updated = visitNodes(sourceFile.statements, visitDeclarationStatements);
164-
return updateSourceFileNode(sourceFile, filterCandidateImports(updated), /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false);
164+
return updateSourceFileNode(sourceFile, filterCandidateImports(updated), /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []);
165165
}
166166
));
167167
bundle.syntheticFileReferences = [];

0 commit comments

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