diff --git a/Gulpfile.ts b/Gulpfile.ts index aedde5c33d955..c691afcf333fa 100644 --- a/Gulpfile.ts +++ b/Gulpfile.ts @@ -30,6 +30,7 @@ import through2 = require("through2"); import merge2 = require("merge2"); import * as os from "os"; import fold = require("travis-fold"); +import ts = require("./lib/typescript"); const gulp = helpMaker(originalGulp); Error.stackTraceLimit = 1000; @@ -74,7 +75,22 @@ const cmdLineOptions = minimist(process.argv.slice(2), { } }); +function readJson(jsonPath: string): any { + const jsonText = fs.readFileSync(jsonPath).toString(); + const result = ts.parseConfigFileTextToJson(jsonPath, jsonText); + if (result.error) { + throw new Error(diagnosticsToString([result.error])); + } + + return result.config; + + function diagnosticsToString(s: ts.Diagnostic[]) { + return s.map(e => ts.flattenDiagnosticMessageText(e.messageText, ts.sys.newLine)).join(ts.sys.newLine); + } +} + const noop = () => {}; // tslint:disable-line no-empty + function exec(cmd: string, args: string[], complete: () => void = noop, error: (e: any, status: number) => void = noop) { console.log(`${cmd} ${args.join(" ")}`); // TODO (weswig): Update child_process types to add windowsVerbatimArguments to the type definition @@ -114,71 +130,6 @@ const nodeModulesPathPrefix = path.resolve("./node_modules/.bin/"); const isWin = /^win/.test(process.platform); const mocha = path.join(nodeModulesPathPrefix, "mocha") + (isWin ? ".cmd" : ""); -const es2015LibrarySources = [ - "es2015.core.d.ts", - "es2015.collection.d.ts", - "es2015.generator.d.ts", - "es2015.iterable.d.ts", - "es2015.promise.d.ts", - "es2015.proxy.d.ts", - "es2015.reflect.d.ts", - "es2015.symbol.d.ts", - "es2015.symbol.wellknown.d.ts" -]; - -const es2015LibrarySourceMap = es2015LibrarySources.map(source => - ({ target: "lib." + source, sources: ["header.d.ts", source] })); - -const es2016LibrarySource = ["es2016.array.include.d.ts"]; - -const es2016LibrarySourceMap = es2016LibrarySource.map(source => - ({ target: "lib." + source, sources: ["header.d.ts", source] })); - -const es2017LibrarySource = [ - "es2017.object.d.ts", - "es2017.sharedmemory.d.ts", - "es2017.string.d.ts", - "es2017.intl.d.ts", - "es2017.typedarrays.d.ts", -]; - -const es2017LibrarySourceMap = es2017LibrarySource.map(source => - ({ target: "lib." + source, sources: ["header.d.ts", source] })); - -const esnextLibrarySource = [ - "esnext.asynciterable.d.ts" -]; - -const esnextLibrarySourceMap = esnextLibrarySource.map(source => - ({ target: "lib." + source, sources: ["header.d.ts", source] })); - -const hostsLibrarySources = ["dom.generated.d.ts", "webworker.importscripts.d.ts", "scripthost.d.ts"]; - -const librarySourceMap = [ - // Host library - { target: "lib.dom.d.ts", sources: ["header.d.ts", "dom.generated.d.ts"] }, - { target: "lib.dom.iterable.d.ts", sources: ["header.d.ts", "dom.iterable.d.ts"] }, - { target: "lib.webworker.d.ts", sources: ["header.d.ts", "webworker.generated.d.ts"] }, - { target: "lib.scripthost.d.ts", sources: ["header.d.ts", "scripthost.d.ts"] }, - - // JavaScript library - { target: "lib.es5.d.ts", sources: ["header.d.ts", "es5.d.ts"] }, - { target: "lib.es2015.d.ts", sources: ["header.d.ts", "es2015.d.ts"] }, - { target: "lib.es2016.d.ts", sources: ["header.d.ts", "es2016.d.ts"] }, - { target: "lib.es2017.d.ts", sources: ["header.d.ts", "es2017.d.ts"] }, - { target: "lib.esnext.d.ts", sources: ["header.d.ts", "esnext.d.ts"] }, - - // JavaScript + all host library - { target: "lib.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(hostsLibrarySources) }, - { target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts") }, - { target: "lib.es2016.full.d.ts", sources: ["header.d.ts", "es2016.d.ts"].concat(hostsLibrarySources, "dom.iterable.d.ts") }, - { target: "lib.es2017.full.d.ts", sources: ["header.d.ts", "es2017.d.ts"].concat(hostsLibrarySources, "dom.iterable.d.ts") }, - { target: "lib.esnext.full.d.ts", sources: ["header.d.ts", "esnext.d.ts"].concat(hostsLibrarySources, "dom.iterable.d.ts") }, -].concat(es2015LibrarySourceMap, es2016LibrarySourceMap, es2017LibrarySourceMap, esnextLibrarySourceMap); - -const libraryTargets = librarySourceMap.map(f => - path.join(builtLocalDirectory, f.target)); - /** * .lcg file is what localization team uses to know what messages to localize. * The file is always generated in 'enu\diagnosticMessages.generated.json.lcg' @@ -196,17 +147,6 @@ const localizationTargets = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt .map(f => path.join(builtLocalDirectory, f, "diagnosticMessages.generated.json")) .concat(generatedLCGFile); -for (const i in libraryTargets) { - const entry = librarySourceMap[i]; - const target = libraryTargets[i]; - const sources = [copyright].concat(entry.sources.map(s => path.join(libraryDirectory, s))); - gulp.task(target, /*help*/ false, [], () => - gulp.src(sources) - .pipe(newer(target)) - .pipe(concat(target, { newLine: "\n\n" })) - .pipe(gulp.dest("."))); -} - const configureNightlyJs = path.join(scriptsDirectory, "configureNightly.js"); const configureNightlyTs = path.join(scriptsDirectory, "configureNightly.ts"); const packageJson = "package.json"; @@ -341,6 +281,18 @@ gulp.task("importDefinitelyTypedTests", "Runs scripts/importDefinitelyTypedTests exec(host, [importDefinitelyTypedTestsJs, "./", "../DefinitelyTyped"], done, done); }); +const libraries: { libs: string[], paths: Record } = readJson(path.resolve("./src/lib/libs.json")); +const libraryTargets = libraries.libs.map(lib => { + const sources = [copyright].concat(["header.d.ts", lib + ".d.ts"].map(s => path.join(libraryDirectory, s))); + const target = path.join(builtLocalDirectory, libraries.paths[lib] || ("lib." + lib + ".d.ts")); + gulp.task(target, /*help*/ false, [], () => + gulp.src(sources) + .pipe(newer(target)) + .pipe(concat(target, { newLine: "\n\n" })) + .pipe(gulp.dest("."))); + return target; +}); + gulp.task("lib", "Builds the library targets", libraryTargets); diff --git a/Jakefile.js b/Jakefile.js index 89fcb6500ddc6..02b200a37bbe6 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -37,19 +37,49 @@ else if (process.env.PATH !== undefined) { process.env.PATH = nodeModulesPathPrefix + process.env.PATH; } -function filesFromConfig(configPath) { - var configText = fs.readFileSync(configPath).toString(); - var config = ts.parseConfigFileTextToJson(configPath, configText); - if (config.error) { - throw new Error(diagnosticsToString([config.error])); +function readJson(jsonPath) { + var jsonText = fs.readFileSync(jsonPath).toString(); + var result = ts.parseJsonText(jsonPath, jsonText); + reportDiagnostics(/** @type {*} */(result).parseDiagnostics); + var diagnostics = []; + var json = ts.convertToObject(result, diagnostics); + reportDiagnostics(diagnostics); + return json; + // var result = ts.parseConfigFileTextToJson(jsonPath, jsonText); + // if (result.error) { + // throw new Error(diagnosticsToString([result.error])); + // } + + // return result.config; + + // function diagnosticsToString(s) { + // return s.map(function(e) { return ts.flattenDiagnosticMessageText(e.messageText, ts.sys.newLine); }).join(ts.sys.newLine); + // } +} + +function reportDiagnostics(diagnostics) { + if (diagnostics && diagnostics.length) { + throw new Error("An error ocurred during parse:\n" + diagnosticsToString(diagnostics)); + } + + function diagnosticsToString(s) { + return ts.formatDiagnostics(s, { + getCurrentDirectory() { return process.cwd(); }, + getCanonicalFileName(fileName) { return fileName; }, + getNewLine() { return os.EOL; } + }); } - const configFileContent = ts.parseJsonConfigFileContent(config.config, ts.sys, path.dirname(configPath)); +} + +function filesFromConfig(configPath) { + var jsonText = fs.readFileSync(configPath).toString(); + var config = ts.parseConfigFileTextToJson(configPath, jsonText).config; + var configFileContent = ts.parseJsonConfigFileContent(config, ts.sys, path.dirname(configPath)); if (configFileContent.errors && configFileContent.errors.length) { throw new Error(diagnosticsToString(configFileContent.errors)); } return configFileContent.fileNames; - function diagnosticsToString(s) { return s.map(function(e) { return ts.flattenDiagnosticMessageText(e.messageText, ts.sys.newLine); }).join(ts.sys.newLine); } @@ -171,76 +201,6 @@ var harnessSources = harnessCoreSources.concat([ return path.join(serverDirectory, f); })); -var es2015LibrarySources = [ - "es2015.core.d.ts", - "es2015.collection.d.ts", - "es2015.generator.d.ts", - "es2015.iterable.d.ts", - "es2015.promise.d.ts", - "es2015.proxy.d.ts", - "es2015.reflect.d.ts", - "es2015.symbol.d.ts", - "es2015.symbol.wellknown.d.ts" -]; - -var es2015LibrarySourceMap = es2015LibrarySources.map(function (source) { - return { target: "lib." + source, sources: ["header.d.ts", source] }; -}); - -var es2016LibrarySource = ["es2016.array.include.d.ts"]; - -var es2016LibrarySourceMap = es2016LibrarySource.map(function (source) { - return { target: "lib." + source, sources: ["header.d.ts", source] }; -}); - -var es2017LibrarySource = [ - "es2017.object.d.ts", - "es2017.sharedmemory.d.ts", - "es2017.string.d.ts", - "es2017.intl.d.ts", - "es2017.typedarrays.d.ts", -]; - -var es2017LibrarySourceMap = es2017LibrarySource.map(function (source) { - return { target: "lib." + source, sources: ["header.d.ts", source] }; -}); - -var esnextLibrarySource = [ - "esnext.asynciterable.d.ts" -]; - -var esnextLibrarySourceMap = esnextLibrarySource.map(function (source) { - return { target: "lib." + source, sources: ["header.d.ts", source] }; -}); - -var hostsLibrarySources = ["dom.generated.d.ts", "webworker.importscripts.d.ts", "scripthost.d.ts"]; - -var librarySourceMap = [ - // Host library - { target: "lib.dom.d.ts", sources: ["header.d.ts", "dom.generated.d.ts"] }, - { target: "lib.dom.iterable.d.ts", sources: ["header.d.ts", "dom.iterable.d.ts"] }, - { target: "lib.webworker.d.ts", sources: ["header.d.ts", "webworker.generated.d.ts"] }, - { target: "lib.scripthost.d.ts", sources: ["header.d.ts", "scripthost.d.ts"] }, - - // JavaScript library - { target: "lib.es5.d.ts", sources: ["header.d.ts", "es5.d.ts"] }, - { target: "lib.es2015.d.ts", sources: ["header.d.ts", "es2015.d.ts"] }, - { target: "lib.es2016.d.ts", sources: ["header.d.ts", "es2016.d.ts"] }, - { target: "lib.es2017.d.ts", sources: ["header.d.ts", "es2017.d.ts"] }, - { target: "lib.esnext.d.ts", sources: ["header.d.ts", "esnext.d.ts"] }, - - // JavaScript + all host library - { target: "lib.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(hostsLibrarySources) }, - { target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts") }, - { target: "lib.es2016.full.d.ts", sources: ["header.d.ts", "es2016.d.ts"].concat(hostsLibrarySources, "dom.iterable.d.ts") }, - { target: "lib.es2017.full.d.ts", sources: ["header.d.ts", "es2017.d.ts"].concat(hostsLibrarySources, "dom.iterable.d.ts") }, - { target: "lib.esnext.full.d.ts", sources: ["header.d.ts", "esnext.d.ts"].concat(hostsLibrarySources, "dom.iterable.d.ts") }, -].concat(es2015LibrarySourceMap, es2016LibrarySourceMap, es2017LibrarySourceMap, esnextLibrarySourceMap); - -var libraryTargets = librarySourceMap.map(function (f) { - return path.join(builtLocalDirectory, f.target); -}); - /** * .lcg file is what localization team uses to know what messages to localize. * The file is always generated in 'enu\diagnosticMessages.generated.json.lcg' @@ -415,18 +375,18 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts // Prerequisite task for built directory and library typings directory(builtLocalDirectory); -for (var i in libraryTargets) { - (function (i) { - var entry = librarySourceMap[i]; - var target = libraryTargets[i]; - var sources = [copyright].concat(entry.sources.map(function (s) { - return path.join(libraryDirectory, s); - })); - file(target, [builtLocalDirectory].concat(sources), function () { - concatenateFiles(target, sources); - }); - })(i); -} +/** @type {{ libs:string[], paths: Record }} */ +var libraries = readJson(path.resolve("./src/lib/libs.json")); +var libraryTargets = libraries.libs.map(function (lib) { + var sources = [copyright].concat(["header.d.ts", lib + ".d.ts"].map(function (s) { + return path.join(libraryDirectory, s); + })); + var target = path.join(builtLocalDirectory, libraries.paths[lib] || ("lib." + lib + ".d.ts")); + file(target, [builtLocalDirectory].concat(sources), function () { + concatenateFiles(target, sources); + }); + return target; +}); // Lib target to build the library files desc("Builds the library targets"); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cb373b4375f20..a3c43a3fabba1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15379,52 +15379,7 @@ namespace ts { * Names longer than 30 characters don't get suggestions because Levenshtein distance is an n**2 algorithm. */ function getSpellingSuggestionForName(name: string, symbols: Symbol[], meaning: SymbolFlags): Symbol | undefined { - const worstDistance = name.length * 0.4; - const maximumLengthDifference = Math.min(3, name.length * 0.34); - let bestDistance = Number.MAX_VALUE; - let bestCandidate = undefined; - let justCheckExactMatches = false; - if (name.length > 30) { - return undefined; - } - name = name.toLowerCase(); - for (const candidate of symbols) { - let candidateName = symbolName(candidate); - if (candidate.flags & meaning && - candidateName && - Math.abs(candidateName.length - name.length) < maximumLengthDifference) { - candidateName = candidateName.toLowerCase(); - if (candidateName === name) { - return candidate; - } - if (justCheckExactMatches) { - continue; - } - if (candidateName.length < 3 || - name.length < 3 || - candidateName === "eval" || - candidateName === "intl" || - candidateName === "undefined" || - candidateName === "map" || - candidateName === "nan" || - candidateName === "set") { - continue; - } - const distance = levenshtein(name, candidateName); - if (distance > worstDistance) { - continue; - } - if (distance < 3) { - justCheckExactMatches = true; - bestCandidate = candidate; - } - else if (distance < bestDistance) { - bestDistance = distance; - bestCandidate = candidate; - } - } - } - return bestCandidate; + return getSpellingSuggestion(name, symbols, ["eval", "intl", "undefined", "map", "set"], candidate => candidate.flags & meaning ? symbolName(candidate) : undefined); } function markPropertyAsReferenced(prop: Symbol, nodeForCheckWriteOnly: Node | undefined, isThisAccess: boolean) { diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 43ea77c802044..3e63abfb4925b 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -7,6 +7,49 @@ namespace ts { /* @internal */ export const compileOnSaveCommandLineOption: CommandLineOption = { name: "compileOnSave", type: "boolean" }; + + const commandLineLibMap = 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", + "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", + // 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", + "esnext.asynciterable": "lib.esnext.asynciterable.d.ts", + }); + + /* @internal */ + // Internally we add some additional lib references that we only support when used as part of a + // "lib" reference directive. They are not available on the command line or in tsconfig.json. + export const libMap = cloneMap(commandLineLibMap) + .set("webworker.importscripts", "lib.webworker.importscripts.d.ts"); + + /* @internal */ + export const libs = arrayFrom(commandLineLibMap.keys()); + /* @internal */ export const optionDeclarations: CommandLineOption[] = [ // CommandLine only options @@ -112,38 +155,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", - "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", - "esnext.asynciterable": "lib.esnext.asynciterable.d.ts", - }), + type: commandLineLibMap, }, showInSimplifiedHelpView: true, category: Diagnostics.Basic_Options, @@ -2282,4 +2294,4 @@ namespace ts { }); } } -} +} \ No newline at end of file diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 964264ff6e8e4..af47fdc761ec7 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2228,6 +2228,14 @@ "category": "Error", "code": 2716 }, + "Cannot find lib definition for '{0}'.": { + "category": "Error", + "code": 2717 + }, + "Cannot find lib definition for '{0}'. Did you mean '{1}'?": { + "category": "Error", + "code": 2718 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 6a56b6da04900..d8b084cebb6d7 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -2312,6 +2312,7 @@ namespace ts { if (node.moduleName !== undefined) updated.moduleName = node.moduleName; if (node.referencedFiles !== undefined) updated.referencedFiles = node.referencedFiles; if (node.typeReferenceDirectives !== undefined) updated.typeReferenceDirectives = node.typeReferenceDirectives; + if (node.libReferenceDirectives !== undefined) updated.libReferenceDirectives = node.libReferenceDirectives; if (node.languageVariant !== undefined) updated.languageVariant = node.languageVariant; if (node.isDeclarationFile !== undefined) updated.isDeclarationFile = node.isDeclarationFile; if (node.renamedDependencies !== undefined) updated.renamedDependencies = node.renamedDependencies; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 79b5eb30c49a0..15117ab546e5c 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6077,6 +6077,7 @@ namespace ts { const triviaScanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ false, LanguageVariant.Standard, sourceText); const referencedFiles: FileReference[] = []; const typeReferenceDirectives: FileReference[] = []; + const libReferenceDirectives: FileReference[] = []; const amdDependencies: { path: string; name: string }[] = []; let amdModuleName: string; let checkJsDirective: CheckJsDirective = undefined; @@ -6104,58 +6105,50 @@ namespace ts { const comment = sourceText.substring(range.pos, range.end); const referencePathMatchResult = getFileReferenceFromReferencePath(comment, range); if (referencePathMatchResult) { - const fileReference = referencePathMatchResult.fileReference; - sourceFile.hasNoDefaultLib = referencePathMatchResult.isNoDefaultLib; - const diagnosticMessage = referencePathMatchResult.diagnosticMessage; - if (fileReference) { - if (referencePathMatchResult.isTypeReferenceDirective) { - typeReferenceDirectives.push(fileReference); - } - else { - referencedFiles.push(fileReference); - } - } - if (diagnosticMessage) { - parseDiagnostics.push(createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, diagnosticMessage)); + switch (referencePathMatchResult.kind) { + case "error": + parseDiagnostics.push(createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, referencePathMatchResult.diagnosticMessage)); + break; + case "no-default-lib": + sourceFile.hasNoDefaultLib = true; + break; + case "types": + typeReferenceDirectives.push(referencePathMatchResult.fileReference); + break; + case "lib": + libReferenceDirectives.push(referencePathMatchResult.fileReference); + break; + case "path": + referencedFiles.push(referencePathMatchResult.fileReference); + break; } + continue; } - else { - const amdModuleNameRegEx = /^\/\/\/\s*; @@ -572,7 +573,7 @@ namespace ts { const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options); const structuralIsReused = tryReuseStructureFromOldProgram(); if (structuralIsReused !== StructureIsReused.Completely) { - forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false)); + 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); @@ -595,11 +596,11 @@ namespace ts { // If '--lib' is not specified, include default library file according to '--target' // otherwise, using options specified in '--lib' instead of '--target' default library file if (!options.lib) { - processRootFile(getDefaultLibraryFileName(), /*isDefaultLib*/ true); + processRootFile(getDefaultLibraryFileName(), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false); } else { forEach(options.lib, libFileName => { - processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true); + processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false); }); } } @@ -688,6 +689,13 @@ namespace ts { return commonSourceDirectory; } + function getLibDirectory() { + if (libDirectory === undefined) { + libDirectory = host.getDefaultLibLocation ? host.getDefaultLibLocation() : getDirectoryPath(host.getDefaultLibFileName(options)); + } + return libDirectory; + } + function getClassifiableNames() { if (!classifiableNames) { // Initialize a checker so that all our files are bound. @@ -944,6 +952,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 @@ -1551,8 +1564,8 @@ namespace ts { return sortAndDeduplicateDiagnostics(getDiagnosticsProducingTypeChecker().getGlobalDiagnostics().slice()); } - 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 { @@ -1716,9 +1729,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), + fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, ignoreNoDefaultLib, refFile, refPos, refEnd, packageId), (diagnostic, ...args) => { fileProcessingDiagnostics.add(refFile !== undefined && refEnd !== undefined && refPos !== undefined ? createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...args) @@ -1756,7 +1769,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 @@ -1771,6 +1784,7 @@ namespace ts { sourceFilesFoundSearchingNodeModules.set(file.path, false); if (!options.noResolve) { processReferencedFiles(file, isDefaultLib); + processLibReferenceDirectives(file); processTypeReferenceDirectives(file); } @@ -1836,10 +1850,11 @@ namespace ts { } } - skipDefaultLib = skipDefaultLib || file.hasNoDefaultLib; + skipDefaultLib = skipDefaultLib || (file.hasNoDefaultLib && !ignoreNoDefaultLib); if (!options.noResolve) { processReferencedFiles(file, isDefaultLib); + processLibReferenceDirectives(file); processTypeReferenceDirectives(file); } @@ -1860,7 +1875,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); }); } @@ -1891,7 +1906,7 @@ namespace ts { if (resolvedTypeReferenceDirective) { if (resolvedTypeReferenceDirective.primary) { // resolved from the primary path - processSourceFile(resolvedTypeReferenceDirective.resolvedFileName, /*isDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd); + processSourceFile(resolvedTypeReferenceDirective.resolvedFileName, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd); } else { // If we already resolved to this file, it must have been a secondary reference. Check file contents @@ -1914,7 +1929,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); } } } @@ -1927,6 +1942,29 @@ 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 import. + processRootFile(combinePaths(getLibDirectory(), libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ true); + } + else { + let unqualifiedLibName = libName; + if (startsWith(unqualifiedLibName, "lib.")) { + unqualifiedLibName = unqualifiedLibName.substr(4); + } + if (endsWith(unqualifiedLibName, ".d.ts")) { + unqualifiedLibName = removeExtension(unqualifiedLibName, ".d.ts"); + } + const suggestion = getSpellingSuggestion(unqualifiedLibName, libs, /*exclusions*/ undefined, 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); @@ -1986,7 +2024,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) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1874821727c88..3c2627f190c7e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2393,6 +2393,7 @@ namespace ts { moduleName: string; referencedFiles: ReadonlyArray; typeReferenceDirectives: ReadonlyArray; + libReferenceDirectives: ReadonlyArray; languageVariant: LanguageVariant; isDeclarationFile: boolean; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 41a5512cb2af9..d6fad91df86a0 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -7,13 +7,22 @@ namespace ts { export const externalHelpersModuleNameText = "tslib"; - export interface ReferencePathMatchResult { - fileReference?: FileReference; - diagnosticMessage?: DiagnosticMessage; - isNoDefaultLib?: boolean; - isTypeReferenceDirective?: boolean; + export interface NoDefaultLibDirective { + kind: "no-default-lib"; } + export interface ReferenceDirective { + kind: "path" | "types" | "lib"; + fileReference: FileReference; + } + + export interface ReferenceDirectiveError { + kind: "error"; + diagnosticMessage: DiagnosticMessage; + } + + export type ReferencePathMatchResult = NoDefaultLibDirective | ReferenceDirective | ReferenceDirectiveError; + export function getDeclarationOfKind(symbol: Symbol, kind: T["kind"]): T { const declarations = symbol.declarations; if (declarations) { @@ -252,11 +261,9 @@ namespace ts { commentPos + 2 < commentEnd && text.charCodeAt(commentPos + 2) === CharacterCodes.slash) { const textSubStr = text.substring(commentPos, commentEnd); - return textSubStr.match(fullTripleSlashReferencePathRegEx) || - textSubStr.match(fullTripleSlashAMDReferencePathRegEx) || - textSubStr.match(fullTripleSlashReferenceTypeReferenceDirectiveRegEx) || - textSubStr.match(defaultLibReferenceRegEx) ? - true : false; + return fullTripleSlashReferenceRegEx.test(textSubStr) || + fullTripleSlashAmdDependencyRegEx.test(textSubStr) || + fullTripleSlashAmdModuleNameRegEx.test(textSubStr); } return false; } @@ -722,11 +729,6 @@ namespace ts { text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash); } - export const fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*/; - const fullTripleSlashReferenceTypeReferenceDirectiveRegEx = /^(\/\/\/\s*/; - export const fullTripleSlashAMDReferencePathRegEx = /^(\/\/\/\s*/; - const defaultLibReferenceRegEx = /^(\/\/\/\s*/; - export function isPartOfTypeNode(node: Node): boolean { if (SyntaxKind.FirstTypeNode <= node.kind && node.kind <= SyntaxKind.LastTypeNode) { return true; @@ -1867,38 +1869,69 @@ namespace ts { return undefined; } - export function getFileReferenceFromReferencePath(comment: string, commentRange: CommentRange): ReferencePathMatchResult { - const simpleReferenceRegEx = /^\/\/\/\s*/i; - return { - diagnosticMessage: Diagnostics.Invalid_reference_directive_syntax, - isNoDefaultLib: false - }; - } + export function getFileReferenceFromReferencePath(comment: string, commentRange: CommentRange): ReferencePathMatchResult | undefined { + if (!simpleReferenceRegEx.test(comment)) { + return undefined; + } + const match = fullTripleSlashReferenceRegEx.exec(comment); + if (!match) { + return { + diagnosticMessage: Diagnostics.Invalid_reference_directive_syntax, + kind: "error" + }; + } + const kind = match[2] as "no-default-lib" | "path" | "types" | "lib"; + if (kind === "no-default-lib") { + return { kind }; } + const fileName = match[4]; + const pos = commentRange.pos + match[1].length + 1; + const end = pos + fileName.length; + return { fileReference: { pos, end, fileName }, kind }; + } - return undefined; + const fullTripleSlashAmdModuleNameRegEx = /^\/\/\/\s*/i; + + export function getAmdDependencyFromComment(comment: string): AmdDependency | undefined { + const match = fullTripleSlashAmdDependencyRegEx.exec(comment); + if (match) { + const path = match[2] || match[8]; + const name = match[4] || match[6]; + return { path, name }; + } + } + + const checkJsDirectiveRegEx = /^\/\/\/?\s*(@ts-check|@ts-nocheck)\s*$/i; + + export function getCheckJsDirectiveFromComment(comment: string, commentRange: CommentRange): CheckJsDirective | undefined { + const checkJsDirectiveMatchResult = checkJsDirectiveRegEx.exec(comment); + if (checkJsDirectiveMatchResult) { + return { + enabled: equateStringsCaseInsensitive(checkJsDirectiveMatchResult[1], "@ts-check"), + end: commentRange.end, + pos: commentRange.pos + }; + } } export function isKeyword(token: SyntaxKind): boolean { @@ -3459,6 +3492,64 @@ namespace ts { return 0; } + /** + * Given a name and a list of names 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.3 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) + * Names longer than 30 characters don't get suggestions because Levenshtein distance is an n**2 algorithm. + */ + export function getSpellingSuggestion(name: string, choices: T[], exclusions: string[] | undefined, getName: (candidate: T) => string | undefined): T | undefined { + const worstDistance = name.length * 0.4; + const maximumLengthDifference = Math.min(3, name.length * 0.34); + let bestDistance = Number.MAX_VALUE; + let bestCandidate = undefined; + let justCheckExactMatches = false; + if (name.length > 30) { + return undefined; + } + name = name.toLowerCase(); + for (const candidate of choices) { + let candidateName = getName(candidate); + if (candidateName && + Math.abs(candidateName.length - name.length) < maximumLengthDifference) { + candidateName = candidateName.toLowerCase(); + if (candidateName === name) { + return candidate; + } + if (justCheckExactMatches) { + continue; + } + if (candidateName.length < 3 || + name.length < 3 || + contains(exclusions, candidateName)) { + continue; + } + const distance = levenshtein(name, candidateName); + if (distance > worstDistance) { + continue; + } + if (distance < 3) { + justCheckExactMatches = true; + bestCandidate = candidate; + } + else if (distance < bestDistance) { + bestDistance = distance; + bestCandidate = candidate; + } + } + } + return bestCandidate; + } + export function levenshtein(s1: string, s2: string): number { let previous: number[] = new Array(s2.length + 1); let current: number[] = new Array(s2.length + 1); diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 8a3202b88beb6..5ff2730412cb9 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -2151,5 +2151,10 @@ namespace Harness { return { unitName: libFile, content: io.readFile(libFile) }; } + export function getNamedDefaultLibraryFile(io: Harness.Io, libName: string): Harness.Compiler.TestFile { + const libFile = Harness.userSpecifiedRoot + Harness.libFolder + "lib." + libName + ".d.ts"; + return { unitName: libFile, content: io.readFile(libFile) }; + } + if (Error) (Error).stackTraceLimit = 100; } diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index ffee2be26be67..c4618c38f235b 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -56,6 +56,13 @@ namespace ts.projectSystem { endGroup: noop, getLogFileName: (): string => undefined }; + export const libFiles: FileOrFolder[] = [ + { path: "/a/lib/lib.d.ts", content: Harness.getDefaultLibraryFile("lib.d.ts", Harness.IO).content }, + { path: "/a/lib/lib.es5.d.ts", content: Harness.getNamedDefaultLibraryFile(Harness.IO, "es5").content }, + { path: "/a/lib/lib.dom.d.ts", content: Harness.getNamedDefaultLibraryFile(Harness.IO, "dom").content }, + { path: "/a/lib/lib.webworker.importscripts.d.ts", content: Harness.getNamedDefaultLibraryFile(Harness.IO, "webworker.importscripts").content }, + { path: "/a/lib/lib.scripthost.d.ts", content: Harness.getNamedDefaultLibraryFile(Harness.IO, "scripthost").content } + ]; export class TestTypingsInstaller extends TI.TypingsInstaller implements server.ITypingsInstaller { protected projectService: server.ProjectService; @@ -1281,7 +1288,7 @@ namespace ts.projectSystem { content: "let x: number;" }; - const host = createServerHost([f1, f2, libFile]); + const host = createServerHost([f1, f2, ...libFiles]); const service = createProjectService(host); service.openExternalProject({ projectFileName: "/a/b/project", rootFiles: toExternalFiles([f1.path, f2.path]), options: {} }); @@ -1289,7 +1296,7 @@ namespace ts.projectSystem { service.openClientFile(f2.path, "let x: string"); service.checkNumberOfProjects({ externalProjects: 1 }); - checkProjectActualFiles(service.externalProjects[0], [f1.path, f2.path, libFile.path]); + checkProjectActualFiles(service.externalProjects[0], [f1.path, f2.path, ...libFiles.map(f => f.path)]); const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2, { includeExternalModuleExports: false }); // should contain completions for string @@ -1922,7 +1929,7 @@ namespace ts.projectSystem { content: JSON.stringify({ compilerOptions: { allowJs: true } }) }; - let host = createServerHost([file1, file2, config1, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); + let host = createServerHost([file1, file2, config1, ...libFiles], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); let session = createSession(host); // Specify .html extension as mixed content in a configure host request @@ -1944,7 +1951,7 @@ namespace ts.projectSystem { content: JSON.stringify({ compilerOptions: { allowJs: false } }) }; - host = createServerHost([file1, file2, config2, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); + host = createServerHost([file1, file2, config2, ...libFiles], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); session = createSession(host); session.executeCommand(configureHostRequest); @@ -1963,7 +1970,7 @@ namespace ts.projectSystem { content: JSON.stringify({}) }; - host = createServerHost([file1, file2, config3, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); + host = createServerHost([file1, file2, config3, ...libFiles], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); session = createSession(host); session.executeCommand(configureHostRequest); @@ -1982,7 +1989,7 @@ namespace ts.projectSystem { content: JSON.stringify({ compilerOptions: { allowJs: true }, files: [file1.path, file2.path] }) }; - host = createServerHost([file1, file2, config4, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); + host = createServerHost([file1, file2, config4, ...libFiles], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); session = createSession(host); session.executeCommand(configureHostRequest); @@ -2001,7 +2008,7 @@ namespace ts.projectSystem { content: JSON.stringify({ compilerOptions: { allowJs: true }, exclude: [file2.path] }) }; - host = createServerHost([file1, file2, config5, libFile], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); + host = createServerHost([file1, file2, config5, ...libFiles], { executingFilePath: combinePaths(getDirectoryPath(libFile.path), "tsc.js") }); session = createSession(host); session.executeCommand(configureHostRequest); @@ -4463,7 +4470,7 @@ namespace ts.projectSystem { path: "/a/b/f1.js", content: "function test1() { }" }; - const host = createServerHost([f1, libFile]); + const host = createServerHost([f1, ...libFiles]); const session = createSession(host); openFilesForSession([f1], session); @@ -4499,7 +4506,7 @@ namespace ts.projectSystem { path: "/a/b/f1.js", content: "function test1() { }" }; - const host = createServerHost([f1, libFile]); + const host = createServerHost([f1, ...libFiles]); const session = createSession(host); const projectService = session.getProjectService(); const projectFileName = "/a/b/project.csproj"; diff --git a/src/lib/dom.iterable.d.ts b/src/lib/dom.iterable.d.ts index 6ca728444f22a..2c968671a1a42 100644 --- a/src/lib/dom.iterable.d.ts +++ b/src/lib/dom.iterable.d.ts @@ -1,4 +1,4 @@ -/// +/// interface DOMTokenList { [Symbol.iterator](): IterableIterator; diff --git a/src/lib/es2015.d.ts b/src/lib/es2015.d.ts index 36f22af624117..e81e7fdd3ef7d 100644 --- a/src/lib/es2015.d.ts +++ b/src/lib/es2015.d.ts @@ -1,10 +1,10 @@ -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// \ No newline at end of file +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// \ No newline at end of file diff --git a/src/lib/es2015.full.d.ts b/src/lib/es2015.full.d.ts new file mode 100644 index 0000000000000..4652bbb84c557 --- /dev/null +++ b/src/lib/es2015.full.d.ts @@ -0,0 +1,14 @@ +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// \ No newline at end of file diff --git a/src/lib/es2015.iterable.d.ts b/src/lib/es2015.iterable.d.ts index f3024bc334f02..76caed5c7cc48 100644 --- a/src/lib/es2015.iterable.d.ts +++ b/src/lib/es2015.iterable.d.ts @@ -1,4 +1,4 @@ -/// +/// interface SymbolConstructor { /** diff --git a/src/lib/es2015.symbol.wellknown.d.ts b/src/lib/es2015.symbol.wellknown.d.ts index 268570ff23231..f70cbd5114d18 100644 --- a/src/lib/es2015.symbol.wellknown.d.ts +++ b/src/lib/es2015.symbol.wellknown.d.ts @@ -1,4 +1,4 @@ -/// +/// interface SymbolConstructor { /** diff --git a/src/lib/es2016.d.ts b/src/lib/es2016.d.ts index 34f833d621b41..fc1aab7798cac 100644 --- a/src/lib/es2016.d.ts +++ b/src/lib/es2016.d.ts @@ -1,2 +1,2 @@ -/// -/// \ No newline at end of file +/// +/// \ No newline at end of file diff --git a/src/lib/es2016.full.d.ts b/src/lib/es2016.full.d.ts new file mode 100644 index 0000000000000..5dda8cc35e785 --- /dev/null +++ b/src/lib/es2016.full.d.ts @@ -0,0 +1,5 @@ +/// +/// +/// +/// +/// diff --git a/src/lib/es2017.d.ts b/src/lib/es2017.d.ts index 87aa273140b5e..74e5bea1180e9 100644 --- a/src/lib/es2017.d.ts +++ b/src/lib/es2017.d.ts @@ -1,6 +1,6 @@ -/// -/// -/// -/// -/// -/// +/// +/// +/// +/// +/// +/// diff --git a/src/lib/es2017.full.d.ts b/src/lib/es2017.full.d.ts new file mode 100644 index 0000000000000..ab03ea04d4844 --- /dev/null +++ b/src/lib/es2017.full.d.ts @@ -0,0 +1,5 @@ +/// +/// +/// +/// +/// diff --git a/src/lib/es2017.sharedmemory.d.ts b/src/lib/es2017.sharedmemory.d.ts index b9a9b0f7e10d7..018a2f162a585 100644 --- a/src/lib/es2017.sharedmemory.d.ts +++ b/src/lib/es2017.sharedmemory.d.ts @@ -1,5 +1,5 @@ -/// -/// +/// +/// interface SharedArrayBuffer { /** diff --git a/src/lib/es5.full.d.ts b/src/lib/es5.full.d.ts new file mode 100644 index 0000000000000..d681253ad7ff7 --- /dev/null +++ b/src/lib/es5.full.d.ts @@ -0,0 +1,4 @@ +/// +/// +/// +/// \ No newline at end of file diff --git a/src/lib/esnext.asynciterable.d.ts b/src/lib/esnext.asynciterable.d.ts index 8379ba5ba6cd0..11093af623dee 100644 --- a/src/lib/esnext.asynciterable.d.ts +++ b/src/lib/esnext.asynciterable.d.ts @@ -1,5 +1,5 @@ -/// -/// +/// +/// interface SymbolConstructor { /** diff --git a/src/lib/esnext.d.ts b/src/lib/esnext.d.ts index 71fab82a866bc..1ff3fad8cda3d 100644 --- a/src/lib/esnext.d.ts +++ b/src/lib/esnext.d.ts @@ -1,2 +1,2 @@ -/// -/// +/// +/// diff --git a/src/lib/esnext.full.d.ts b/src/lib/esnext.full.d.ts new file mode 100644 index 0000000000000..70fc982b908bc --- /dev/null +++ b/src/lib/esnext.full.d.ts @@ -0,0 +1,5 @@ +/// +/// +/// +/// +/// diff --git a/src/lib/importes5.d.ts b/src/lib/importes5.d.ts index 872bf0a1bedc2..7c4389bf15aa0 100644 --- a/src/lib/importes5.d.ts +++ b/src/lib/importes5.d.ts @@ -1 +1 @@ -/// +/// diff --git a/src/lib/libs.json b/src/lib/libs.json new file mode 100644 index 0000000000000..f7a1f2052145d --- /dev/null +++ b/src/lib/libs.json @@ -0,0 +1,45 @@ +{ + "libs": [ + // JavaScript only + "es5", + "es2015", + "es2016", + "es2017", + "esnext", + // Host only + "dom.generated", + "dom.iterable", + "webworker.generated", + "webworker.importscripts", + "scripthost", + // By-feature options + "es2015.core", + "es2015.collection", + "es2015.generator", + "es2015.iterable", + "es2015.promise", + "es2015.proxy", + "es2015.reflect", + "es2015.symbol", + "es2015.symbol.wellknown", + "es2016.array.include", + "es2017.object", + "es2017.sharedmemory", + "es2017.string", + "es2017.intl", + "es2017.typedarrays", + "esnext.asynciterable", + // Default libraries + "es5.full", + "es2015.full", + "es2016.full", + "es2017.full", + "esnext.full" + ], + "paths": { + "dom.generated": "lib.dom.d.ts", + "webworker.generated": "lib.webworker.d.ts", + "es5.full": "lib.d.ts", + "es2015.full": "lib.es6.d.ts" + } +} \ No newline at end of file diff --git a/src/services/preProcess.ts b/src/services/preProcess.ts index 8f6a468be6495..a1fe639e55e96 100644 --- a/src/services/preProcess.ts +++ b/src/services/preProcess.ts @@ -27,14 +27,18 @@ namespace ts { const comment = sourceText.substring(commentRange.pos, commentRange.end); const referencePathMatchResult = getFileReferenceFromReferencePath(comment, commentRange); if (referencePathMatchResult) { - isNoDefaultLib = referencePathMatchResult.isNoDefaultLib; - const fileReference = referencePathMatchResult.fileReference; - if (fileReference) { - const collection = referencePathMatchResult.isTypeReferenceDirective - ? typeReferenceDirectives - : referencedFiles; - - collection.push(fileReference); + switch (referencePathMatchResult.kind) { + case "no-default-lib": + isNoDefaultLib = true; + break; + case "types": + typeReferenceDirectives.push(referencePathMatchResult.fileReference); + break; + case "path": + referencedFiles.push(referencePathMatchResult.fileReference); + break; + // TODO(rbuckton): pass lib references to core services + // case "lib": } } }); diff --git a/src/services/services.ts b/src/services/services.ts index 37298c8eba87d..d1455229fe0ba 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -593,6 +593,7 @@ namespace ts { public moduleName: string; public referencedFiles: FileReference[]; public typeReferenceDirectives: FileReference[]; + public libReferenceDirectives: FileReference[]; public syntacticDiagnostics: Diagnostic[]; public referenceDiagnostics: Diagnostic[]; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index a3499de08ab99..6ee45d8fe4348 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -1586,6 +1586,7 @@ declare namespace ts { moduleName: string; referencedFiles: ReadonlyArray; typeReferenceDirectives: ReadonlyArray; + libReferenceDirectives: ReadonlyArray; languageVariant: LanguageVariant; isDeclarationFile: boolean; /** diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 98d7137ddebcc..3278fe0cb3636 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -1586,6 +1586,7 @@ declare namespace ts { moduleName: string; referencedFiles: ReadonlyArray; typeReferenceDirectives: ReadonlyArray; + libReferenceDirectives: ReadonlyArray; languageVariant: LanguageVariant; isDeclarationFile: boolean; /** diff --git a/tests/baselines/reference/libReferenceDirective.2.js b/tests/baselines/reference/libReferenceDirective.2.js new file mode 100644 index 0000000000000..463a3a7c4c2cd --- /dev/null +++ b/tests/baselines/reference/libReferenceDirective.2.js @@ -0,0 +1,8 @@ +//// [libReferenceDirective.2.ts] +/// +Object.create(null); + + +//// [libReferenceDirective.2.js] +/// +Object.create(null); diff --git a/tests/baselines/reference/libReferenceDirective.2.symbols b/tests/baselines/reference/libReferenceDirective.2.symbols new file mode 100644 index 0000000000000..4fd54c552bf49 --- /dev/null +++ b/tests/baselines/reference/libReferenceDirective.2.symbols @@ -0,0 +1,7 @@ +=== tests/cases/compiler/libReferenceDirective.2.ts === +/// +Object.create(null); +>Object.create : Symbol(ObjectConstructor.create, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>create : Symbol(ObjectConstructor.create, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + diff --git a/tests/baselines/reference/libReferenceDirective.2.types b/tests/baselines/reference/libReferenceDirective.2.types new file mode 100644 index 0000000000000..0ace3ff741a88 --- /dev/null +++ b/tests/baselines/reference/libReferenceDirective.2.types @@ -0,0 +1,9 @@ +=== tests/cases/compiler/libReferenceDirective.2.ts === +/// +Object.create(null); +>Object.create(null) : any +>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType): any; } +>Object : ObjectConstructor +>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType): any; } +>null : null + diff --git a/tests/baselines/reference/libReferenceDirective.js b/tests/baselines/reference/libReferenceDirective.js new file mode 100644 index 0000000000000..8be9a68a8a906 --- /dev/null +++ b/tests/baselines/reference/libReferenceDirective.js @@ -0,0 +1,8 @@ +//// [libReferenceDirective.ts] +/// +const m = new Map(); + + +//// [libReferenceDirective.js] +/// +var m = new Map(); diff --git a/tests/baselines/reference/libReferenceDirective.symbols b/tests/baselines/reference/libReferenceDirective.symbols new file mode 100644 index 0000000000000..564506ee0c24b --- /dev/null +++ b/tests/baselines/reference/libReferenceDirective.symbols @@ -0,0 +1,6 @@ +=== tests/cases/compiler/libReferenceDirective.ts === +/// +const m = new Map(); +>m : Symbol(m, Decl(libReferenceDirective.ts, 1, 5)) +>Map : Symbol(Map, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --)) + diff --git a/tests/baselines/reference/libReferenceDirective.types b/tests/baselines/reference/libReferenceDirective.types new file mode 100644 index 0000000000000..5eef516b30946 --- /dev/null +++ b/tests/baselines/reference/libReferenceDirective.types @@ -0,0 +1,7 @@ +=== tests/cases/compiler/libReferenceDirective.ts === +/// +const m = new Map(); +>m : Map +>new Map() : Map +>Map : MapConstructor + diff --git a/tests/baselines/reference/libReferenceDirectiveErrors.errors.txt b/tests/baselines/reference/libReferenceDirectiveErrors.errors.txt new file mode 100644 index 0000000000000..809c64427a7ac --- /dev/null +++ b/tests/baselines/reference/libReferenceDirectiveErrors.errors.txt @@ -0,0 +1,27 @@ +tests/cases/compiler/a.ts(1,1): error TS1084: Invalid 'reference' directive syntax. +tests/cases/compiler/b.ts(1,1): error TS1084: Invalid 'reference' directive syntax. +tests/cases/compiler/c.ts(1,21): error TS2717: Cannot find lib definition for 'es2015.foo'. +tests/cases/compiler/d.ts(1,21): error TS2718: Cannot find lib definition for 'es2015.collections'. Did you mean 'es2015.collection'? +tests/cases/compiler/e.ts(1,21): error TS2718: Cannot find lib definition for 'lib.es2015.d.ts'. Did you mean 'es2015'? + + +==== tests/cases/compiler/a.ts (1 errors) ==== + /// + ~~~~~~~~~~~~~~~~~ +!!! error TS1084: Invalid 'reference' directive syntax. +==== tests/cases/compiler/b.ts (1 errors) ==== + /// + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1084: Invalid 'reference' directive syntax. +==== tests/cases/compiler/c.ts (1 errors) ==== + /// + ~~~~~~~~~~ +!!! error TS2717: Cannot find lib definition for 'es2015.foo'. +==== tests/cases/compiler/d.ts (1 errors) ==== + /// + ~~~~~~~~~~~~~~~~~~ +!!! error TS2718: Cannot find lib definition for 'es2015.collections'. Did you mean 'es2015.collection'? +==== tests/cases/compiler/e.ts (1 errors) ==== + /// + ~~~~~~~~~~~~~~~ +!!! error TS2718: Cannot find lib definition for 'lib.es2015.d.ts'. Did you mean 'es2015'? \ No newline at end of file diff --git a/tests/baselines/reference/libReferenceDirectiveErrors.js b/tests/baselines/reference/libReferenceDirectiveErrors.js new file mode 100644 index 0000000000000..ca141299f507d --- /dev/null +++ b/tests/baselines/reference/libReferenceDirectiveErrors.js @@ -0,0 +1,23 @@ +//// [tests/cases/compiler/libReferenceDirectiveErrors.ts] //// + +//// [a.ts] +/// +//// [b.ts] +/// +//// [c.ts] +/// +//// [d.ts] +/// +//// [e.ts] +/// + +//// [a.js] +/// +//// [b.js] +/// +//// [c.js] +/// +//// [d.js] +/// +//// [e.js] +/// diff --git a/tests/baselines/reference/libReferenceDirectiveErrors.symbols b/tests/baselines/reference/libReferenceDirectiveErrors.symbols new file mode 100644 index 0000000000000..0c5c3937a4517 --- /dev/null +++ b/tests/baselines/reference/libReferenceDirectiveErrors.symbols @@ -0,0 +1,11 @@ +=== tests/cases/compiler/a.ts === +/// +No type information for this code.=== tests/cases/compiler/b.ts === +/// +No type information for this code.=== tests/cases/compiler/c.ts === +/// +No type information for this code.=== tests/cases/compiler/d.ts === +/// +No type information for this code.=== tests/cases/compiler/e.ts === +/// +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/libReferenceDirectiveErrors.types b/tests/baselines/reference/libReferenceDirectiveErrors.types new file mode 100644 index 0000000000000..0c5c3937a4517 --- /dev/null +++ b/tests/baselines/reference/libReferenceDirectiveErrors.types @@ -0,0 +1,11 @@ +=== tests/cases/compiler/a.ts === +/// +No type information for this code.=== tests/cases/compiler/b.ts === +/// +No type information for this code.=== tests/cases/compiler/c.ts === +/// +No type information for this code.=== tests/cases/compiler/d.ts === +/// +No type information for this code.=== tests/cases/compiler/e.ts === +/// +No type information for this code. \ No newline at end of file diff --git a/tests/cases/compiler/libReferenceDirective.2.ts b/tests/cases/compiler/libReferenceDirective.2.ts new file mode 100644 index 0000000000000..09c8140f6a324 --- /dev/null +++ b/tests/cases/compiler/libReferenceDirective.2.ts @@ -0,0 +1,3 @@ +// @target: es5 +/// +Object.create(null); diff --git a/tests/cases/compiler/libReferenceDirective.ts b/tests/cases/compiler/libReferenceDirective.ts new file mode 100644 index 0000000000000..be1250873129d --- /dev/null +++ b/tests/cases/compiler/libReferenceDirective.ts @@ -0,0 +1,3 @@ +// @target: es5 +/// +const m = new Map(); diff --git a/tests/cases/compiler/libReferenceDirectiveErrors.ts b/tests/cases/compiler/libReferenceDirectiveErrors.ts new file mode 100644 index 0000000000000..a40739b5c08c7 --- /dev/null +++ b/tests/cases/compiler/libReferenceDirectiveErrors.ts @@ -0,0 +1,11 @@ +// @target: es5 +// @filename: a.ts +/// +// @filename: b.ts +/// +// @filename: c.ts +/// +// @filename: d.ts +/// +// @filename: e.ts +/// \ No newline at end of file