mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #23893 from Microsoft/libReference
Adds 'lib' reference directives
This commit is contained in:
+3
-80
@@ -17382,88 +17382,11 @@ namespace ts {
|
||||
* and 1 insertion/deletion at 3 characters)
|
||||
*/
|
||||
function getSpellingSuggestionForName(name: string, symbols: Symbol[], meaning: SymbolFlags): Symbol | undefined {
|
||||
const maximumLengthDifference = Math.min(2, Math.floor(name.length * 0.34));
|
||||
let bestDistance = Math.floor(name.length * 0.4) + 1; // If the best result isn't better than this, don't bother.
|
||||
let bestCandidate: Symbol | undefined;
|
||||
let justCheckExactMatches = false;
|
||||
const nameLowerCase = name.toLowerCase();
|
||||
for (const candidate of symbols) {
|
||||
return getSpellingSuggestion(name, symbols, getCandidateName);
|
||||
function getCandidateName(candidate: Symbol) {
|
||||
const candidateName = symbolName(candidate);
|
||||
if (candidateName.charCodeAt(0) === CharacterCodes.doubleQuote
|
||||
|| !(candidate.flags & meaning && Math.abs(candidateName.length - nameLowerCase.length) <= maximumLengthDifference)) {
|
||||
continue;
|
||||
}
|
||||
const candidateNameLowerCase = candidateName.toLowerCase();
|
||||
if (candidateNameLowerCase === nameLowerCase) {
|
||||
return candidate;
|
||||
}
|
||||
if (justCheckExactMatches) {
|
||||
continue;
|
||||
}
|
||||
if (candidateName.length < 3) {
|
||||
// Don't bother, user would have noticed a 2-character name having an extra character
|
||||
continue;
|
||||
}
|
||||
// Only care about a result better than the best so far.
|
||||
const distance = levenshteinWithMax(nameLowerCase, candidateNameLowerCase, bestDistance - 1);
|
||||
if (distance === undefined) {
|
||||
continue;
|
||||
}
|
||||
if (distance < 3) {
|
||||
justCheckExactMatches = true;
|
||||
bestCandidate = candidate;
|
||||
}
|
||||
else {
|
||||
Debug.assert(distance < bestDistance); // Else `levenshteinWithMax` should return undefined
|
||||
bestDistance = distance;
|
||||
bestCandidate = candidate;
|
||||
}
|
||||
return !startsWith(candidateName, "\"") && candidate.flags & meaning ? candidateName : undefined;
|
||||
}
|
||||
return bestCandidate;
|
||||
}
|
||||
|
||||
function levenshteinWithMax(s1: string, s2: string, max: number): number | undefined {
|
||||
let previous = new Array(s2.length + 1);
|
||||
let current = new Array(s2.length + 1);
|
||||
/** Represents any value > max. We don't care about the particular value. */
|
||||
const big = max + 1;
|
||||
|
||||
for (let i = 0; i <= s2.length; i++) {
|
||||
previous[i] = i;
|
||||
}
|
||||
|
||||
for (let i = 1; i <= s1.length; i++) {
|
||||
const c1 = s1.charCodeAt(i - 1);
|
||||
const minJ = i > max ? i - max : 1;
|
||||
const maxJ = s2.length > max + i ? max + i : s2.length;
|
||||
current[0] = i;
|
||||
/** Smallest value of the matrix in the ith column. */
|
||||
let colMin = i;
|
||||
for (let j = 1; j < minJ; j++) {
|
||||
current[j] = big;
|
||||
}
|
||||
for (let j = minJ; j <= maxJ; j++) {
|
||||
const dist = c1 === s2.charCodeAt(j - 1)
|
||||
? previous[j - 1]
|
||||
: Math.min(/*delete*/ previous[j] + 1, /*insert*/ current[j - 1] + 1, /*substitute*/ previous[j - 1] + 2);
|
||||
current[j] = dist;
|
||||
colMin = Math.min(colMin, dist);
|
||||
}
|
||||
for (let j = maxJ + 1; j <= s2.length; j++) {
|
||||
current[j] = big;
|
||||
}
|
||||
if (colMin > max) {
|
||||
// Give up -- everything in this column is > max and it can't get better in future columns.
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const temp = previous;
|
||||
previous = current;
|
||||
current = temp;
|
||||
}
|
||||
|
||||
const res = previous[s2.length];
|
||||
return res > max ? undefined : res;
|
||||
}
|
||||
|
||||
function markPropertyAsReferenced(prop: Symbol, nodeForCheckWriteOnly: Node | undefined, isThisAccess: boolean) {
|
||||
|
||||
@@ -1,6 +1,66 @@
|
||||
namespace ts {
|
||||
/* @internal */
|
||||
export const compileOnSaveCommandLineOption: CommandLineOption = { name: "compileOnSave", type: "boolean" };
|
||||
|
||||
// NOTE: The order here is important to default lib ordering as entries will have the same
|
||||
// order in the generated program (see `getDefaultLibPriority` in program.ts). This
|
||||
// order also affects overload resolution when a type declared in one lib is
|
||||
// augmented in another lib.
|
||||
const libEntries: [string, string][] = [
|
||||
// JavaScript only
|
||||
["es5", "lib.es5.d.ts"],
|
||||
["es6", "lib.es2015.d.ts"],
|
||||
["es2015", "lib.es2015.d.ts"],
|
||||
["es7", "lib.es2016.d.ts"],
|
||||
["es2016", "lib.es2016.d.ts"],
|
||||
["es2017", "lib.es2017.d.ts"],
|
||||
["es2018", "lib.es2018.d.ts"],
|
||||
["esnext", "lib.esnext.d.ts"],
|
||||
// Host only
|
||||
["dom", "lib.dom.d.ts"],
|
||||
["dom.iterable", "lib.dom.iterable.d.ts"],
|
||||
["webworker", "lib.webworker.d.ts"],
|
||||
["webworker.importscripts", "lib.webworker.importscripts.d.ts"],
|
||||
["scripthost", "lib.scripthost.d.ts"],
|
||||
// ES2015 Or ESNext By-feature options
|
||||
["es2015.core", "lib.es2015.core.d.ts"],
|
||||
["es2015.collection", "lib.es2015.collection.d.ts"],
|
||||
["es2015.generator", "lib.es2015.generator.d.ts"],
|
||||
["es2015.iterable", "lib.es2015.iterable.d.ts"],
|
||||
["es2015.promise", "lib.es2015.promise.d.ts"],
|
||||
["es2015.proxy", "lib.es2015.proxy.d.ts"],
|
||||
["es2015.reflect", "lib.es2015.reflect.d.ts"],
|
||||
["es2015.symbol", "lib.es2015.symbol.d.ts"],
|
||||
["es2015.symbol.wellknown", "lib.es2015.symbol.wellknown.d.ts"],
|
||||
["es2016.array.include", "lib.es2016.array.include.d.ts"],
|
||||
["es2017.object", "lib.es2017.object.d.ts"],
|
||||
["es2017.sharedmemory", "lib.es2017.sharedmemory.d.ts"],
|
||||
["es2017.string", "lib.es2017.string.d.ts"],
|
||||
["es2017.intl", "lib.es2017.intl.d.ts"],
|
||||
["es2017.typedarrays", "lib.es2017.typedarrays.d.ts"],
|
||||
["es2018.intl", "lib.es2018.intl.d.ts"],
|
||||
["es2018.promise", "lib.es2018.promise.d.ts"],
|
||||
["es2018.regexp", "lib.es2018.regexp.d.ts"],
|
||||
["esnext.array", "lib.esnext.array.d.ts"],
|
||||
["esnext.symbol", "lib.esnext.symbol.d.ts"],
|
||||
["esnext.asynciterable", "lib.esnext.asynciterable.d.ts"],
|
||||
];
|
||||
|
||||
/**
|
||||
* An array of supported "lib" reference file names used to determine the order for inclusion
|
||||
* when referenced, as well as for spelling suggestions. This ensures the correct ordering for
|
||||
* overload resolution when a type declared in one lib is extended by another.
|
||||
*/
|
||||
/* @internal */
|
||||
export const libs = libEntries.map(entry => entry[0]);
|
||||
|
||||
/**
|
||||
* A map of lib names to lib files. This map is used both for parsing the "lib" command line
|
||||
* option as well as for resolving lib reference directives.
|
||||
*/
|
||||
/* @internal */
|
||||
export const libMap = createMapFromEntries(libEntries);
|
||||
|
||||
/* @internal */
|
||||
export const optionDeclarations: CommandLineOption[] = [
|
||||
// CommandLine only options
|
||||
@@ -114,44 +174,7 @@ namespace ts {
|
||||
type: "list",
|
||||
element: {
|
||||
name: "lib",
|
||||
type: createMapFromTemplate({
|
||||
// JavaScript only
|
||||
"es5": "lib.es5.d.ts",
|
||||
"es6": "lib.es2015.d.ts",
|
||||
"es2015": "lib.es2015.d.ts",
|
||||
"es7": "lib.es2016.d.ts",
|
||||
"es2016": "lib.es2016.d.ts",
|
||||
"es2017": "lib.es2017.d.ts",
|
||||
"es2018": "lib.es2018.d.ts",
|
||||
"esnext": "lib.esnext.d.ts",
|
||||
// Host only
|
||||
"dom": "lib.dom.d.ts",
|
||||
"dom.iterable": "lib.dom.iterable.d.ts",
|
||||
"webworker": "lib.webworker.d.ts",
|
||||
"scripthost": "lib.scripthost.d.ts",
|
||||
// ES2015 Or ESNext By-feature options
|
||||
"es2015.core": "lib.es2015.core.d.ts",
|
||||
"es2015.collection": "lib.es2015.collection.d.ts",
|
||||
"es2015.generator": "lib.es2015.generator.d.ts",
|
||||
"es2015.iterable": "lib.es2015.iterable.d.ts",
|
||||
"es2015.promise": "lib.es2015.promise.d.ts",
|
||||
"es2015.proxy": "lib.es2015.proxy.d.ts",
|
||||
"es2015.reflect": "lib.es2015.reflect.d.ts",
|
||||
"es2015.symbol": "lib.es2015.symbol.d.ts",
|
||||
"es2015.symbol.wellknown": "lib.es2015.symbol.wellknown.d.ts",
|
||||
"es2016.array.include": "lib.es2016.array.include.d.ts",
|
||||
"es2017.object": "lib.es2017.object.d.ts",
|
||||
"es2017.sharedmemory": "lib.es2017.sharedmemory.d.ts",
|
||||
"es2017.string": "lib.es2017.string.d.ts",
|
||||
"es2017.intl": "lib.es2017.intl.d.ts",
|
||||
"es2017.typedarrays": "lib.es2017.typedarrays.d.ts",
|
||||
"es2018.intl": "lib.es2018.intl.d.ts",
|
||||
"es2018.promise": "lib.es2018.promise.d.ts",
|
||||
"es2018.regexp": "lib.es2018.regexp.d.ts",
|
||||
"esnext.array": "lib.esnext.array.d.ts",
|
||||
"esnext.symbol": "lib.esnext.symbol.d.ts",
|
||||
"esnext.asynciterable": "lib.esnext.asynciterable.d.ts",
|
||||
}),
|
||||
type: libMap
|
||||
},
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Basic_Options,
|
||||
|
||||
+107
-2
@@ -59,6 +59,14 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function createMapFromEntries<T>(entries: [string, T][]): Map<T> {
|
||||
const map = createMap<T>();
|
||||
for (const [key, value] of entries) {
|
||||
map.set(key, value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
export function createMapFromTemplate<T>(template: MapLike<T>): Map<T> {
|
||||
const map: Map<T> = new MapCtr<T>();
|
||||
|
||||
@@ -1796,7 +1804,7 @@ namespace ts {
|
||||
* Case-insensitive comparisons compare both strings one code-point at a time using the integer
|
||||
* value of each code-point after applying `toUpperCase` to each string. We always map both
|
||||
* strings to their upper-case form as some unicode characters do not properly round-trip to
|
||||
* lowercase (such as `ẞ` (German sharp capital s)).
|
||||
* lowercase (such as `ẞ` (German sharp capital s)).
|
||||
*/
|
||||
export function compareStringsCaseInsensitive(a: string, b: string) {
|
||||
if (a === b) return Comparison.EqualTo;
|
||||
@@ -1868,7 +1876,7 @@ namespace ts {
|
||||
//
|
||||
// For case insensitive comparisons we always map both strings to their
|
||||
// upper-case form as some unicode characters do not properly round-trip to
|
||||
// lowercase (such as `ẞ` (German sharp capital s)).
|
||||
// lowercase (such as `ẞ` (German sharp capital s)).
|
||||
return (a, b) => compareWithCallback(a, b, compareDictionaryOrder);
|
||||
|
||||
function compareDictionaryOrder(a: string, b: string) {
|
||||
@@ -1993,6 +2001,103 @@ namespace ts {
|
||||
return text1 ? Comparison.GreaterThan : Comparison.LessThan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a name and a list of names that are *not* equal to the name, return a spelling suggestion if there is one that is close enough.
|
||||
* Names less than length 3 only check for case-insensitive equality, not Levenshtein distance.
|
||||
*
|
||||
* If there is a candidate that's the same except for case, return that.
|
||||
* If there is a candidate that's within one edit of the name, return that.
|
||||
* Otherwise, return the candidate with the smallest Levenshtein distance,
|
||||
* except for candidates:
|
||||
* * With no name
|
||||
* * Whose length differs from the target name by more than 0.34 of the length of the name.
|
||||
* * Whose levenshtein distance is more than 0.4 of the length of the name
|
||||
* (0.4 allows 1 substitution/transposition for every 5 characters,
|
||||
* and 1 insertion/deletion at 3 characters)
|
||||
*/
|
||||
export function getSpellingSuggestion<T>(name: string, candidates: T[], getName: (candidate: T) => string | undefined): T | undefined {
|
||||
const maximumLengthDifference = Math.min(2, Math.floor(name.length * 0.34));
|
||||
let bestDistance = Math.floor(name.length * 0.4) + 1; // If the best result isn't better than this, don't bother.
|
||||
let bestCandidate: T | undefined;
|
||||
let justCheckExactMatches = false;
|
||||
const nameLowerCase = name.toLowerCase();
|
||||
for (const candidate of candidates) {
|
||||
const candidateName = getName(candidate);
|
||||
if (candidateName !== undefined && Math.abs(candidateName.length - nameLowerCase.length) <= maximumLengthDifference) {
|
||||
const candidateNameLowerCase = candidateName.toLowerCase();
|
||||
if (candidateNameLowerCase === nameLowerCase) {
|
||||
return candidate;
|
||||
}
|
||||
if (justCheckExactMatches) {
|
||||
continue;
|
||||
}
|
||||
if (candidateName.length < 3) {
|
||||
// Don't bother, user would have noticed a 2-character name having an extra character
|
||||
continue;
|
||||
}
|
||||
// Only care about a result better than the best so far.
|
||||
const distance = levenshteinWithMax(nameLowerCase, candidateNameLowerCase, bestDistance - 1);
|
||||
if (distance === undefined) {
|
||||
continue;
|
||||
}
|
||||
if (distance < 3) {
|
||||
justCheckExactMatches = true;
|
||||
bestCandidate = candidate;
|
||||
}
|
||||
else {
|
||||
Debug.assert(distance < bestDistance); // Else `levenshteinWithMax` should return undefined
|
||||
bestDistance = distance;
|
||||
bestCandidate = candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestCandidate;
|
||||
}
|
||||
|
||||
function levenshteinWithMax(s1: string, s2: string, max: number): number | undefined {
|
||||
let previous = new Array(s2.length + 1);
|
||||
let current = new Array(s2.length + 1);
|
||||
/** Represents any value > max. We don't care about the particular value. */
|
||||
const big = max + 1;
|
||||
|
||||
for (let i = 0; i <= s2.length; i++) {
|
||||
previous[i] = i;
|
||||
}
|
||||
|
||||
for (let i = 1; i <= s1.length; i++) {
|
||||
const c1 = s1.charCodeAt(i - 1);
|
||||
const minJ = i > max ? i - max : 1;
|
||||
const maxJ = s2.length > max + i ? max + i : s2.length;
|
||||
current[0] = i;
|
||||
/** Smallest value of the matrix in the ith column. */
|
||||
let colMin = i;
|
||||
for (let j = 1; j < minJ; j++) {
|
||||
current[j] = big;
|
||||
}
|
||||
for (let j = minJ; j <= maxJ; j++) {
|
||||
const dist = c1 === s2.charCodeAt(j - 1)
|
||||
? previous[j - 1]
|
||||
: Math.min(/*delete*/ previous[j] + 1, /*insert*/ current[j - 1] + 1, /*substitute*/ previous[j - 1] + 2);
|
||||
current[j] = dist;
|
||||
colMin = Math.min(colMin, dist);
|
||||
}
|
||||
for (let j = maxJ + 1; j <= s2.length; j++) {
|
||||
current[j] = big;
|
||||
}
|
||||
if (colMin > max) {
|
||||
// Give up -- everything in this column is > max and it can't get better in future columns.
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const temp = previous;
|
||||
previous = current;
|
||||
current = temp;
|
||||
}
|
||||
|
||||
const res = previous[s2.length];
|
||||
return res > max ? undefined : res;
|
||||
}
|
||||
|
||||
export function getEmitScriptTarget(compilerOptions: CompilerOptions) {
|
||||
return compilerOptions.target || ScriptTarget.ES3;
|
||||
}
|
||||
|
||||
@@ -2369,6 +2369,14 @@
|
||||
"category": "Error",
|
||||
"code": 2725
|
||||
},
|
||||
"Cannot find lib definition for '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 2726
|
||||
},
|
||||
"Cannot find lib definition for '{0}'. Did you mean '{1}'?": {
|
||||
"category": "Error",
|
||||
"code": 2727
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -2432,12 +2432,13 @@ namespace ts {
|
||||
|
||||
// Top-level nodes
|
||||
|
||||
export function updateSourceFileNode(node: SourceFile, statements: ReadonlyArray<Statement>, isDeclarationFile?: boolean, referencedFiles?: SourceFile["referencedFiles"], typeReferences?: SourceFile["typeReferenceDirectives"], hasNoDefaultLib?: boolean) {
|
||||
export function updateSourceFileNode(node: SourceFile, statements: ReadonlyArray<Statement>, isDeclarationFile?: boolean, referencedFiles?: SourceFile["referencedFiles"], typeReferences?: SourceFile["typeReferenceDirectives"], hasNoDefaultLib?: boolean, libReferences?: SourceFile["libReferenceDirectives"]) {
|
||||
if (
|
||||
node.statements !== statements ||
|
||||
(isDeclarationFile !== undefined && node.isDeclarationFile !== isDeclarationFile) ||
|
||||
(referencedFiles !== undefined && node.referencedFiles !== referencedFiles) ||
|
||||
(typeReferences !== undefined && node.typeReferenceDirectives !== typeReferences) ||
|
||||
(libReferences !== undefined && node.libReferenceDirectives !== libReferences) ||
|
||||
(hasNoDefaultLib !== undefined && node.hasNoDefaultLib !== hasNoDefaultLib)
|
||||
) {
|
||||
const updated = <SourceFile>createSynthesizedNode(SyntaxKind.SourceFile);
|
||||
@@ -2451,6 +2452,7 @@ namespace ts {
|
||||
updated.referencedFiles = referencedFiles === undefined ? node.referencedFiles : referencedFiles;
|
||||
updated.typeReferenceDirectives = typeReferences === undefined ? node.typeReferenceDirectives : typeReferences;
|
||||
updated.hasNoDefaultLib = hasNoDefaultLib === undefined ? node.hasNoDefaultLib : hasNoDefaultLib;
|
||||
updated.libReferenceDirectives = libReferences === undefined ? node.libReferenceDirectives : libReferences;
|
||||
if (node.amdDependencies !== undefined) updated.amdDependencies = node.amdDependencies;
|
||||
if (node.moduleName !== undefined) updated.moduleName = node.moduleName;
|
||||
if (node.languageVariant !== undefined) updated.languageVariant = node.languageVariant;
|
||||
|
||||
@@ -7659,6 +7659,7 @@ namespace ts {
|
||||
checkJsDirective?: CheckJsDirective;
|
||||
referencedFiles: FileReference[];
|
||||
typeReferenceDirectives: FileReference[];
|
||||
libReferenceDirectives: FileReference[];
|
||||
amdDependencies: AmdDependency[];
|
||||
hasNoDefaultLib?: boolean;
|
||||
moduleName?: string;
|
||||
@@ -7712,6 +7713,7 @@ namespace ts {
|
||||
context.checkJsDirective = undefined;
|
||||
context.referencedFiles = [];
|
||||
context.typeReferenceDirectives = [];
|
||||
context.libReferenceDirectives = [];
|
||||
context.amdDependencies = [];
|
||||
context.hasNoDefaultLib = false;
|
||||
context.pragmas!.forEach((entryOrList, key) => { // TODO: GH#18217
|
||||
@@ -7721,6 +7723,7 @@ namespace ts {
|
||||
case "reference": {
|
||||
const referencedFiles = context.referencedFiles;
|
||||
const typeReferenceDirectives = context.typeReferenceDirectives;
|
||||
const libReferenceDirectives = context.libReferenceDirectives;
|
||||
forEach(toArray(entryOrList), (arg: PragmaPsuedoMap["reference"]) => {
|
||||
// TODO: GH#18217
|
||||
if (arg!.arguments["no-default-lib"]) {
|
||||
@@ -7729,6 +7732,9 @@ namespace ts {
|
||||
else if (arg!.arguments.types) {
|
||||
typeReferenceDirectives.push({ pos: arg!.arguments.types!.pos, end: arg!.arguments.types!.end, fileName: arg!.arguments.types!.value });
|
||||
}
|
||||
else if (arg!.arguments.lib) {
|
||||
libReferenceDirectives.push({ pos: arg!.arguments.lib!.pos, end: arg!.arguments.lib!.end, fileName: arg!.arguments.lib!.value });
|
||||
}
|
||||
else if (arg!.arguments.path) {
|
||||
referencedFiles.push({ pos: arg!.arguments.path!.pos, end: arg!.arguments.path!.end, fileName: arg!.arguments.path!.value });
|
||||
}
|
||||
|
||||
Executable → Regular
+75
-18
@@ -520,7 +520,9 @@ namespace ts {
|
||||
let { oldProgram } = createProgramOptions;
|
||||
|
||||
let program: Program;
|
||||
let files: SourceFile[] = [];
|
||||
let processingDefaultLibFiles: SourceFile[] | undefined;
|
||||
let processingOtherFiles: SourceFile[] | undefined;
|
||||
let files: SourceFile[];
|
||||
let commonSourceDirectory: string;
|
||||
let diagnosticsProducingTypeChecker: TypeChecker;
|
||||
let noDiagnosticsTypeChecker: TypeChecker;
|
||||
@@ -620,7 +622,7 @@ namespace ts {
|
||||
if (parsedRef) {
|
||||
if (parsedRef.commandLine.options.outFile) {
|
||||
const dtsOutfile = changeExtension(parsedRef.commandLine.options.outFile, ".d.ts");
|
||||
processSourceFile(dtsOutfile, /*isDefaultLib*/ false, /*packageId*/ undefined);
|
||||
processSourceFile(dtsOutfile, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
|
||||
}
|
||||
addProjectReferenceRedirects(parsedRef.commandLine, projectReferenceRedirects);
|
||||
}
|
||||
@@ -630,7 +632,9 @@ namespace ts {
|
||||
const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
|
||||
const structuralIsReused = tryReuseStructureFromOldProgram();
|
||||
if (structuralIsReused !== StructureIsReused.Completely) {
|
||||
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false));
|
||||
processingDefaultLibFiles = [];
|
||||
processingOtherFiles = [];
|
||||
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false));
|
||||
|
||||
// load type declarations specified via 'types' argument or implicitly from types/ and node_modules/@types folders
|
||||
const typeReferences: string[] = getAutomaticTypeDirectiveNames(options, host);
|
||||
@@ -654,16 +658,19 @@ namespace ts {
|
||||
// otherwise, using options specified in '--lib' instead of '--target' default library file
|
||||
const defaultLibraryFileName = getDefaultLibraryFileName();
|
||||
if (!options.lib && defaultLibraryFileName) {
|
||||
processRootFile(defaultLibraryFileName, /*isDefaultLib*/ true);
|
||||
processRootFile(defaultLibraryFileName, /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false);
|
||||
}
|
||||
else {
|
||||
forEach(options.lib, libFileName => {
|
||||
processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true);
|
||||
processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
missingFilePaths = arrayFrom(filesByName.keys(), p => <Path>p).filter(p => !filesByName.get(p));
|
||||
files = stableSort(processingDefaultLibFiles, compareDefaultLibFiles).concat(processingOtherFiles);
|
||||
processingDefaultLibFiles = undefined;
|
||||
processingOtherFiles = undefined;
|
||||
}
|
||||
|
||||
Debug.assert(!!missingFilePaths);
|
||||
@@ -711,6 +718,7 @@ namespace ts {
|
||||
isSourceFileDefaultLibrary,
|
||||
dropDiagnosticsProducingTypeChecker,
|
||||
getSourceFileFromReference,
|
||||
getLibFileFromReference,
|
||||
sourceFileToPackageName,
|
||||
redirectTargetsSet,
|
||||
isEmittedFile,
|
||||
@@ -725,6 +733,21 @@ namespace ts {
|
||||
|
||||
return program;
|
||||
|
||||
function compareDefaultLibFiles(a: SourceFile, b: SourceFile) {
|
||||
return compareValues(getDefaultLibFilePriority(a), getDefaultLibFilePriority(b));
|
||||
}
|
||||
|
||||
function getDefaultLibFilePriority(a: SourceFile) {
|
||||
if (containsPath(defaultLibraryPath, a.fileName, /*ignoreCase*/ false)) {
|
||||
const basename = getBaseFileName(a.fileName);
|
||||
if (basename === "lib.d.ts" || basename === "lib.es6.d.ts") return 0;
|
||||
const name = removeSuffix(removePrefix(basename, "lib."), ".d.ts");
|
||||
const index = libs.indexOf(name);
|
||||
if (index !== -1) return index + 1;
|
||||
}
|
||||
return libs.length + 2;
|
||||
}
|
||||
|
||||
function getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations | undefined {
|
||||
return moduleResolutionCache && resolveModuleNameFromCache(moduleName, containingFile, moduleResolutionCache);
|
||||
}
|
||||
@@ -1047,6 +1070,11 @@ namespace ts {
|
||||
if (fileChanged) {
|
||||
// The `newSourceFile` object was created for the new program.
|
||||
|
||||
if (!arrayIsEqualTo(oldSourceFile.libReferenceDirectives, newSourceFile.libReferenceDirectives, fileReferenceIsEqualTo)) {
|
||||
// 'lib' references has changed. Matches behavior in changesAffectModuleResolution
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
|
||||
if (oldSourceFile.hasNoDefaultLib !== newSourceFile.hasNoDefaultLib) {
|
||||
// value of no-default-lib has changed
|
||||
// this will affect if default library is injected into the list of files
|
||||
@@ -1708,8 +1736,8 @@ namespace ts {
|
||||
return configFileParsingDiagnostics || emptyArray;
|
||||
}
|
||||
|
||||
function processRootFile(fileName: string, isDefaultLib: boolean) {
|
||||
processSourceFile(normalizePath(fileName), isDefaultLib, /*packageId*/ undefined);
|
||||
function processRootFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean) {
|
||||
processSourceFile(normalizePath(fileName), isDefaultLib, ignoreNoDefaultLib, /*packageId*/ undefined);
|
||||
}
|
||||
|
||||
function fileReferenceIsEqualTo(a: FileReference, b: FileReference): boolean {
|
||||
@@ -1830,6 +1858,14 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getLibFileFromReference(ref: FileReference) {
|
||||
const libName = ref.fileName.toLocaleLowerCase();
|
||||
const libFileName = libMap.get(libName);
|
||||
if (libFileName) {
|
||||
return getSourceFile(combinePaths(defaultLibraryPath, libFileName));
|
||||
}
|
||||
}
|
||||
|
||||
/** This should have similar behavior to 'processSourceFile' without diagnostics or mutation. */
|
||||
function getSourceFileFromReference(referencingFile: SourceFile, ref: FileReference): SourceFile | undefined {
|
||||
return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), fileName => filesByName.get(toPath(fileName)));
|
||||
@@ -1880,9 +1916,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** This has side effects through `findSourceFile`. */
|
||||
function processSourceFile(fileName: string, isDefaultLib: boolean, packageId: PackageId | undefined, refFile?: SourceFile, refPos?: number, refEnd?: number): void {
|
||||
function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, refFile?: SourceFile, refPos?: number, refEnd?: number): void {
|
||||
getSourceFileFromReferenceWorker(fileName,
|
||||
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, refFile!, refPos!, refEnd!, packageId), // TODO: GH#18217
|
||||
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, ignoreNoDefaultLib, refFile!, refPos!, refEnd!, packageId), // TODO: GH#18217
|
||||
(diagnostic, ...args) => {
|
||||
fileProcessingDiagnostics.add(refFile !== undefined && refEnd !== undefined && refPos !== undefined
|
||||
? createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...args)
|
||||
@@ -1920,7 +1956,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Get source file from normalized fileName
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
if (filesByName.has(path)) {
|
||||
const file = filesByName.get(path);
|
||||
// try to check if we've already seen this file but with a different casing in path
|
||||
@@ -1938,6 +1974,8 @@ namespace ts {
|
||||
processTypeReferenceDirectives(file);
|
||||
}
|
||||
|
||||
processLibReferenceDirectives(file);
|
||||
|
||||
modulesWithElidedImports.set(file.path, false);
|
||||
processImportedModules(file);
|
||||
}
|
||||
@@ -1988,7 +2026,7 @@ namespace ts {
|
||||
redirectTargetsSet.set(fileFromPackageId.path, true);
|
||||
filesByName.set(path, dupFile);
|
||||
sourceFileToPackageName.set(path, packageId.name);
|
||||
files.push(dupFile);
|
||||
processingOtherFiles!.push(dupFile);
|
||||
return dupFile;
|
||||
}
|
||||
else if (file) {
|
||||
@@ -2019,21 +2057,23 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
skipDefaultLib = skipDefaultLib || file.hasNoDefaultLib;
|
||||
skipDefaultLib = skipDefaultLib || (file.hasNoDefaultLib && !ignoreNoDefaultLib);
|
||||
|
||||
if (!options.noResolve) {
|
||||
processReferencedFiles(file, isDefaultLib);
|
||||
processTypeReferenceDirectives(file);
|
||||
}
|
||||
|
||||
processLibReferenceDirectives(file);
|
||||
|
||||
// always process imported modules to record module name resolutions
|
||||
processImportedModules(file);
|
||||
|
||||
if (isDefaultLib) {
|
||||
files.unshift(file);
|
||||
processingDefaultLibFiles!.push(file);
|
||||
}
|
||||
else {
|
||||
files.push(file);
|
||||
processingOtherFiles!.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2060,7 +2100,7 @@ namespace ts {
|
||||
function processReferencedFiles(file: SourceFile, isDefaultLib: boolean) {
|
||||
forEach(file.referencedFiles, ref => {
|
||||
const referencedFileName = resolveTripleslashReference(ref.fileName, file.fileName);
|
||||
processSourceFile(referencedFileName, isDefaultLib, /*packageId*/ undefined, file, ref.pos, ref.end);
|
||||
processSourceFile(referencedFileName, isDefaultLib, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined, file, ref.pos, ref.end);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2095,7 +2135,7 @@ namespace ts {
|
||||
if (resolvedTypeReferenceDirective) {
|
||||
if (resolvedTypeReferenceDirective.primary) {
|
||||
// resolved from the primary path
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd); // TODO: GH#18217
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd); // TODO: GH#18217
|
||||
}
|
||||
else {
|
||||
// If we already resolved to this file, it must have been a secondary reference. Check file contents
|
||||
@@ -2118,7 +2158,7 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
// First resolution of this library
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd);
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2131,6 +2171,23 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function processLibReferenceDirectives(file: SourceFile) {
|
||||
forEach(file.libReferenceDirectives, libReference => {
|
||||
const libName = libReference.fileName.toLocaleLowerCase();
|
||||
const libFileName = libMap.get(libName);
|
||||
if (libFileName) {
|
||||
// we ignore any 'no-default-lib' reference set on this file.
|
||||
processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ true);
|
||||
}
|
||||
else {
|
||||
const unqualifiedLibName = removeSuffix(removePrefix(libName, "lib."), ".d.ts");
|
||||
const suggestion = getSpellingSuggestion(unqualifiedLibName, libs, identity);
|
||||
const message = suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 : Diagnostics.Cannot_find_lib_definition_for_0;
|
||||
fileProcessingDiagnostics.add(createDiagnostic(file, libReference.pos, libReference.end, message, libName, suggestion));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createDiagnostic(refFile: SourceFile, refPos: number, refEnd: number, message: DiagnosticMessage, ...args: any[]): Diagnostic {
|
||||
if (refFile === undefined || refPos === undefined || refEnd === undefined) {
|
||||
return createCompilerDiagnostic(message, ...args);
|
||||
@@ -2191,7 +2248,7 @@ namespace ts {
|
||||
else if (shouldAddFile) {
|
||||
const path = toPath(resolvedFileName);
|
||||
const pos = skipTrivia(file.text, file.imports[i].pos);
|
||||
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, file, pos, file.imports[i].end, resolution.packageId);
|
||||
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, file, pos, file.imports[i].end, resolution.packageId);
|
||||
}
|
||||
|
||||
if (isFromNodeModulesSearch) {
|
||||
|
||||
@@ -171,12 +171,12 @@ namespace ts {
|
||||
[createModifier(SyntaxKind.DeclareKeyword)],
|
||||
createLiteral(getResolvedExternalModuleName(context.getEmitHost(), sourceFile)),
|
||||
createModuleBlock(setTextRange(createNodeArray(transformAndReplaceLatePaintedStatements(statements)), sourceFile.statements))
|
||||
)], /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false);
|
||||
)], /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []);
|
||||
return newFile;
|
||||
}
|
||||
needsDeclare = true;
|
||||
const updated = visitNodes(sourceFile.statements, visitDeclarationStatements);
|
||||
return updateSourceFileNode(sourceFile, transformAndReplaceLatePaintedStatements(updated), /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false);
|
||||
return updateSourceFileNode(sourceFile, transformAndReplaceLatePaintedStatements(updated), /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []);
|
||||
}
|
||||
), mapDefined(node.prepends, prepend => {
|
||||
if (prepend.kind === SyntaxKind.InputFiles) {
|
||||
|
||||
+19
-10
@@ -2565,6 +2565,7 @@ namespace ts {
|
||||
moduleName?: string;
|
||||
referencedFiles: ReadonlyArray<FileReference>;
|
||||
typeReferenceDirectives: ReadonlyArray<FileReference>;
|
||||
libReferenceDirectives: ReadonlyArray<FileReference>;
|
||||
languageVariant: LanguageVariant;
|
||||
isDeclarationFile: boolean;
|
||||
|
||||
@@ -2785,6 +2786,7 @@ namespace ts {
|
||||
/* @internal */ structureIsReused?: StructureIsReused;
|
||||
|
||||
/* @internal */ getSourceFileFromReference(referencingFile: SourceFile, ref: FileReference): SourceFile | undefined;
|
||||
/* @internal */ getLibFileFromReference(ref: FileReference): SourceFile | undefined;
|
||||
|
||||
/** Given a source file, get the name of the package it was imported from. */
|
||||
/* @internal */ sourceFileToPackageName: Map<string>;
|
||||
@@ -5454,8 +5456,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface PragmaDefinition<T1 extends string = string, T2 extends string = string, T3 extends string = string> {
|
||||
args?: [PragmaArgumentSpecification<T1>] | [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>] | [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>, PragmaArgumentSpecification<T3>];
|
||||
export interface PragmaDefinition<T1 extends string = string, T2 extends string = string, T3 extends string = string, T4 extends string = string> {
|
||||
args?:
|
||||
| [PragmaArgumentSpecification<T1>]
|
||||
| [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>]
|
||||
| [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>, PragmaArgumentSpecification<T3>]
|
||||
| [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>, PragmaArgumentSpecification<T3>, PragmaArgumentSpecification<T4>];
|
||||
// If not present, defaults to PragmaKindFlags.Default
|
||||
kind?: PragmaKindFlags;
|
||||
}
|
||||
@@ -5464,7 +5470,7 @@ namespace ts {
|
||||
* This function only exists to cause exact types to be inferred for all the literals within `commentPragmas`
|
||||
*/
|
||||
/* @internal */
|
||||
function _contextuallyTypePragmas<T extends {[name: string]: PragmaDefinition<K1, K2, K3>}, K1 extends string, K2 extends string, K3 extends string>(args: T): T {
|
||||
function _contextuallyTypePragmas<T extends {[name: string]: PragmaDefinition<K1, K2, K3, K4>}, K1 extends string, K2 extends string, K3 extends string, K4 extends string>(args: T): T {
|
||||
return args;
|
||||
}
|
||||
|
||||
@@ -5475,6 +5481,7 @@ namespace ts {
|
||||
"reference": {
|
||||
args: [
|
||||
{ name: "types", optional: true, captureSpan: true },
|
||||
{ name: "lib", optional: true, captureSpan: true },
|
||||
{ name: "path", optional: true, captureSpan: true },
|
||||
{ name: "no-default-lib", optional: true }
|
||||
],
|
||||
@@ -5515,13 +5522,15 @@ namespace ts {
|
||||
*/
|
||||
/* @internal */
|
||||
type PragmaArgumentType<T extends PragmaDefinition> =
|
||||
T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>, PragmaArgumentSpecification<infer TName3>] }
|
||||
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2> & PragmaArgTypeOptional<T["args"][2], TName3>
|
||||
: T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>] }
|
||||
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2>
|
||||
: T extends { args: [PragmaArgumentSpecification<infer TName>] }
|
||||
? PragmaArgTypeOptional<T["args"][0], TName>
|
||||
: object;
|
||||
T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>, PragmaArgumentSpecification<infer TName3>, PragmaArgumentSpecification<infer TName4>] }
|
||||
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2> & PragmaArgTypeOptional<T["args"][2], TName3> & PragmaArgTypeOptional<T["args"][2], TName4>
|
||||
: T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>, PragmaArgumentSpecification<infer TName3>] }
|
||||
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2> & PragmaArgTypeOptional<T["args"][2], TName3>
|
||||
: T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>] }
|
||||
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2>
|
||||
: T extends { args: [PragmaArgumentSpecification<infer TName>] }
|
||||
? PragmaArgTypeOptional<T["args"][0], TName>
|
||||
: object;
|
||||
// The above fallback to `object` when there's no args to allow `{}` (as intended), but not the number 2, for example
|
||||
// TODO: Swap to `undefined` for a cleaner API once strictNullChecks is enabled
|
||||
|
||||
|
||||
Reference in New Issue
Block a user