diff options
Diffstat (limited to 'cli/tsc')
-rw-r--r-- | cli/tsc/00_typescript.js | 384 | ||||
-rw-r--r-- | cli/tsc/99_main_compiler.js | 316 | ||||
-rw-r--r-- | cli/tsc/compiler.d.ts | 7 |
3 files changed, 658 insertions, 49 deletions
diff --git a/cli/tsc/00_typescript.js b/cli/tsc/00_typescript.js index 8b22dd451..c39e70e24 100644 --- a/cli/tsc/00_typescript.js +++ b/cli/tsc/00_typescript.js @@ -48949,12 +48949,23 @@ var ts; var emitResolver = createResolver(); var nodeBuilder = createNodeBuilder(); var globals = ts.createSymbolTable(); + var nodeGlobals = ts.createSymbolTable(); var undefinedSymbol = createSymbol(4 /* SymbolFlags.Property */, "undefined"); undefinedSymbol.declarations = []; var globalThisSymbol = createSymbol(1536 /* SymbolFlags.Module */, "globalThis", 8 /* CheckFlags.Readonly */); globalThisSymbol.exports = globals; globalThisSymbol.declarations = []; globals.set(globalThisSymbol.escapedName, globalThisSymbol); + var denoContext = ts.deno.createDenoForkContext({ + globals: globals, + nodeGlobals: nodeGlobals, + mergeSymbol: mergeSymbol, + ambientModuleSymbolRegex: ambientModuleSymbolRegex, + }); + var nodeGlobalThisSymbol = createSymbol(1536 /* SymbolFlags.Module */, "globalThis", 8 /* CheckFlags.Readonly */); + nodeGlobalThisSymbol.exports = denoContext.combinedGlobals; + nodeGlobalThisSymbol.declarations = []; + nodeGlobals.set(nodeGlobalThisSymbol.escapedName, nodeGlobalThisSymbol); var argumentsSymbol = createSymbol(4 /* SymbolFlags.Property */, "arguments"); var requireSymbol = createSymbol(4 /* SymbolFlags.Property */, "require"); /** This will be set during calls to `getResolvedSignature` where services determines an apparent number of arguments greater than what is actually provided. */ @@ -49464,6 +49475,7 @@ var ts; var reverseMappedCache = new ts.Map(); var inInferTypeForHomomorphicMappedType = false; var ambientModulesCache; + var nodeAmbientModulesCache; /** * List of every ambient module with a "*" wildcard. * Unlike other ambient modules, these can't be stored in `globals` because symbol tables only deal with exact matches. @@ -49851,7 +49863,7 @@ var ts; // Do not report an error when merging `var globalThis` with the built-in `globalThis`, // as we will already report a "Declaration name conflicts..." error, and this error // won't make much sense. - if (target !== globalThisSymbol) { + if (target !== globalThisSymbol && target !== nodeGlobalThisSymbol) { error(source.declarations && ts.getNameOfDeclaration(source.declarations[0]), ts.Diagnostics.Cannot_augment_module_0_with_value_exports_because_it_resolves_to_a_non_module_entity, symbolToString(target)); } } @@ -49950,7 +49962,7 @@ var ts; return; } if (ts.isGlobalScopeAugmentation(moduleAugmentation)) { - mergeSymbolTable(globals, moduleAugmentation.symbol.exports); + denoContext.mergeGlobalSymbolTable(moduleAugmentation, moduleAugmentation.symbol.exports); } else { // find a module that about to be augmented @@ -50631,7 +50643,12 @@ var ts; } } if (!excludeGlobals) { - result = lookup(globals, name, meaning); + if (denoContext.hasNodeSourceFile(lastLocation)) { + result = lookup(nodeGlobals, name, meaning); + } + if (!result) { + result = lookup(globals, name, meaning); + } } } if (!result) { @@ -51888,6 +51905,24 @@ var ts; : undefined; } function resolveExternalModule(location, moduleReference, moduleNotFoundError, errorNode, isForAugmentation) { + var _a; + if (isForAugmentation === void 0) { isForAugmentation = false; } + var result = resolveExternalModuleInner(location, moduleReference, moduleNotFoundError, errorNode, isForAugmentation); + // deno: attempt to resolve an npm package reference to its bare specifier w/ path ambient module + // when not found and the symbol has zero exports + if (moduleReference.startsWith("npm:") && (result == null || ((_a = result === null || result === void 0 ? void 0 : result.exports) === null || _a === void 0 ? void 0 : _a.size) === 0)) { + var npmPackageRef = ts.deno.tryParseNpmPackageReference(moduleReference); + if (npmPackageRef) { + var bareSpecifier = npmPackageRef.name + (npmPackageRef.subPath == null ? "" : "/" + npmPackageRef.subPath); + var ambientModule = tryFindAmbientModule(bareSpecifier, /*withAugmentations*/ true); + if (ambientModule) { + return ambientModule; + } + } + } + return result; + } + function resolveExternalModuleInner(location, moduleReference, moduleNotFoundError, errorNode, isForAugmentation) { var _a, _b, _c, _d, _e, _f, _g, _h; if (isForAugmentation === void 0) { isForAugmentation = false; } if (ts.startsWith(moduleReference, "@types/")) { @@ -52630,6 +52665,12 @@ var ts; if (typeof state_2 === "object") return state_2.value; } + if (denoContext.hasNodeSourceFile(enclosingDeclaration)) { + result = callback(nodeGlobals, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true); + if (result) { + return result; + } + } return callback(globals, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true); } function getQualifiedLeftMeaning(rightMeaning) { @@ -52713,7 +52754,11 @@ var ts; } }); // If there's no result and we're looking at the global symbol table, treat `globalThis` like an alias and try to lookup thru that - return result || (symbols === globals ? getCandidateListForSymbol(globalThisSymbol, globalThisSymbol, ignoreQualification) : undefined); + if (result) { + return result; + } + var globalSymbol = symbols === nodeGlobals ? nodeGlobalThisSymbol : symbols === globals ? globalThisSymbol : undefined; + return globalSymbol != null ? getCandidateListForSymbol(globalSymbol, globalSymbol, ignoreQualification) : undefined; } function getCandidateListForSymbol(symbolFromSymbolTable, resolvedImportedSymbol, ignoreQualification) { if (isAccessible(symbolFromSymbolTable, resolvedImportedSymbol, ignoreQualification)) { @@ -59159,7 +59204,7 @@ var ts; var indexInfos; if (symbol.exports) { members = getExportsOfSymbol(symbol); - if (symbol === globalThisSymbol) { + if (symbol === globalThisSymbol || symbol === nodeGlobalThisSymbol) { var varsOnly_1 = new ts.Map(); members.forEach(function (p) { var _a; @@ -60321,7 +60366,7 @@ var ts; if (ts.isExternalModuleNameRelative(moduleName)) { return undefined; } - var symbol = getSymbol(globals, '"' + moduleName + '"', 512 /* SymbolFlags.ValueModule */); + var symbol = getSymbol(denoContext.combinedGlobals, '"' + moduleName + '"', 512 /* SymbolFlags.ValueModule */); // merged symbol is module declaration symbol combined with all augmentations return symbol && withAugmentations ? getMergedSymbol(symbol) : symbol; } @@ -62988,6 +63033,10 @@ var ts; if (objectType.symbol === globalThisSymbol && propName !== undefined && globalThisSymbol.exports.has(propName) && (globalThisSymbol.exports.get(propName).flags & 418 /* SymbolFlags.BlockScoped */)) { error(accessExpression, ts.Diagnostics.Property_0_does_not_exist_on_type_1, ts.unescapeLeadingUnderscores(propName), typeToString(objectType)); } + // deno: ensure condition and body match the above + else if (objectType.symbol === nodeGlobalThisSymbol && propName !== undefined && nodeGlobalThisSymbol.exports.has(propName) && (nodeGlobalThisSymbol.exports.get(propName).flags & 418 /* SymbolFlags.BlockScoped */)) { + error(accessExpression, ts.Diagnostics.Property_0_does_not_exist_on_type_1, ts.unescapeLeadingUnderscores(propName), typeToString(objectType)); + } else if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && !(accessFlags & 128 /* AccessFlags.SuppressNoImplicitAnyError */)) { if (propName !== undefined && typeHasStaticProperty(propName, objectType)) { var typeName = typeToString(objectType); @@ -71860,7 +71909,7 @@ var ts; if (type.flags & 1048576 /* TypeFlags.Union */ || type.flags & 524288 /* TypeFlags.Object */ && declaredType !== type && !(declaredType === unknownType && isEmptyAnonymousObjectType(type)) || ts.isThisTypeParameter(type) - || type.flags & 2097152 /* TypeFlags.Intersection */ && ts.every(type.types, function (t) { return t.symbol !== globalThisSymbol; })) { + || type.flags & 2097152 /* TypeFlags.Intersection */ && ts.every(type.types, function (t) { return t.symbol !== globalThisSymbol && t.symbol !== nodeGlobalThisSymbol; })) { return filterType(type, function (t) { return isTypePresencePossible(t, name, assumeTrue); }); } return type; @@ -73019,6 +73068,9 @@ var ts; return undefinedType; } else if (includeGlobalThis) { + if (denoContext.hasNodeSourceFile(container)) { + return getTypeOfSymbol(nodeGlobalThisSymbol); + } return getTypeOfSymbol(globalThisSymbol); } } @@ -75690,6 +75742,11 @@ var ts; } return anyType; } + // deno: ensure condition matches above + if (leftType.symbol === nodeGlobalThisSymbol) { + // deno: don't bother with errors like above for simplicity + return anyType; + } if (right.escapedText && !checkAndReportErrorForExtendingInterface(node)) { reportNonexistentProperty(right, ts.isThisTypeParameter(leftType) ? apparentType : leftType, isUncheckedJS); } @@ -75997,7 +76054,7 @@ var ts; if (symbol) return symbol; var candidates; - if (symbols === globals) { + if (symbols === globals || symbols === nodeGlobals) { var primitives = ts.mapDefined(["string", "number", "boolean", "object", "bigint", "symbol"], function (s) { return symbols.has((s.charAt(0).toUpperCase() + s.slice(1))) ? createSymbol(524288 /* SymbolFlags.TypeAlias */, s) : undefined; }); @@ -86656,7 +86713,7 @@ var ts; // find immediate value referenced by exported name (SymbolFlags.Alias is set so we don't chase down aliases) var symbol = resolveName(exportedName, exportedName.escapedText, 111551 /* SymbolFlags.Value */ | 788968 /* SymbolFlags.Type */ | 1920 /* SymbolFlags.Namespace */ | 2097152 /* SymbolFlags.Alias */, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true); - if (symbol && (symbol === undefinedSymbol || symbol === globalThisSymbol || symbol.declarations && isGlobalSourceFile(getDeclarationContainer(symbol.declarations[0])))) { + if (symbol && (symbol === undefinedSymbol || symbol === globalThisSymbol || symbol === nodeGlobalThisSymbol || symbol.declarations && isGlobalSourceFile(getDeclarationContainer(symbol.declarations[0])))) { error(exportedName, ts.Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, ts.idText(exportedName)); } else { @@ -87343,6 +87400,9 @@ var ts; isStaticSymbol = ts.isStatic(location); location = location.parent; } + if (denoContext.hasNodeSourceFile(location)) { + copySymbols(nodeGlobals, meaning); + } copySymbols(globals, meaning); } /** @@ -88717,25 +88777,24 @@ var ts; amalgamatedDuplicates = new ts.Map(); // Initialize global symbol table var augmentations; - for (var _b = 0, _c = host.getSourceFiles(); _b < _c.length; _b++) { - var file = _c[_b]; + var _loop_35 = function (file) { if (file.redirectInfo) { - continue; + return "continue"; } if (!ts.isExternalOrCommonJsModule(file)) { // It is an error for a non-external-module (i.e. script) to declare its own `globalThis`. // We can't use `builtinGlobals` for this due to synthetic expando-namespace generation in JS files. var fileGlobalThisSymbol = file.locals.get("globalThis"); if (fileGlobalThisSymbol === null || fileGlobalThisSymbol === void 0 ? void 0 : fileGlobalThisSymbol.declarations) { - for (var _d = 0, _e = fileGlobalThisSymbol.declarations; _d < _e.length; _d++) { - var declaration = _e[_d]; + for (var _h = 0, _j = fileGlobalThisSymbol.declarations; _h < _j.length; _h++) { + var declaration = _j[_h]; diagnostics.add(ts.createDiagnosticForNode(declaration, ts.Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, "globalThis")); } } - mergeSymbolTable(globals, file.locals); + denoContext.mergeGlobalSymbolTable(file, file.locals); } if (file.jsGlobalAugmentations) { - mergeSymbolTable(globals, file.jsGlobalAugmentations); + denoContext.mergeGlobalSymbolTable(file, file.jsGlobalAugmentations); } if (file.patternAmbientModules && file.patternAmbientModules.length) { patternAmbientModules = ts.concatenate(patternAmbientModules, file.patternAmbientModules); @@ -88746,12 +88805,18 @@ var ts; if (file.symbol && file.symbol.globalExports) { // Merge in UMD exports with first-in-wins semantics (see #9771) var source = file.symbol.globalExports; + var isNodeFile_1 = denoContext.hasNodeSourceFile(file); source.forEach(function (sourceSymbol, id) { - if (!globals.has(id)) { - globals.set(id, sourceSymbol); + var envGlobals = isNodeFile_1 ? denoContext.getGlobalsForName(id) : globals; + if (!envGlobals.has(id)) { + envGlobals.set(id, sourceSymbol); } }); } + }; + for (var _b = 0, _c = host.getSourceFiles(); _b < _c.length; _b++) { + var file = _c[_b]; + _loop_35(file); } // We do global augmentations separately from module augmentations (and before creating global types) because they // 1. Affect global types. We won't have the correct global types until global augmentations are merged. Also, @@ -88762,10 +88827,10 @@ var ts; if (augmentations) { // merge _global_ module augmentations. // this needs to be done after global symbol table is initialized to make sure that all ambient modules are indexed - for (var _f = 0, augmentations_1 = augmentations; _f < augmentations_1.length; _f++) { - var list = augmentations_1[_f]; - for (var _g = 0, list_1 = list; _g < list_1.length; _g++) { - var augmentation = list_1[_g]; + for (var _d = 0, augmentations_1 = augmentations; _d < augmentations_1.length; _d++) { + var list = augmentations_1[_d]; + for (var _e = 0, list_1 = list; _e < list_1.length; _e++) { + var augmentation = list_1[_e]; if (!ts.isGlobalScopeAugmentation(augmentation.parent)) continue; mergeModuleAugmentation(augmentation); @@ -88778,6 +88843,7 @@ var ts; getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments", /*arity*/ 0, /*reportErrors*/ true); getSymbolLinks(unknownSymbol).type = errorType; getSymbolLinks(globalThisSymbol).type = createObjectType(16 /* ObjectFlags.Anonymous */, globalThisSymbol); + getSymbolLinks(nodeGlobalThisSymbol).type = createObjectType(16 /* ObjectFlags.Anonymous */, nodeGlobalThisSymbol); // Initialize special types globalArrayType = getGlobalType("Array", /*arity*/ 1, /*reportErrors*/ true); globalObjectType = getGlobalType("Object", /*arity*/ 0, /*reportErrors*/ true); @@ -88800,10 +88866,10 @@ var ts; if (augmentations) { // merge _nonglobal_ module augmentations. // this needs to be done after global symbol table is initialized to make sure that all ambient modules are indexed - for (var _h = 0, augmentations_2 = augmentations; _h < augmentations_2.length; _h++) { - var list = augmentations_2[_h]; - for (var _j = 0, list_2 = list; _j < list_2.length; _j++) { - var augmentation = list_2[_j]; + for (var _f = 0, augmentations_2 = augmentations; _f < augmentations_2.length; _f++) { + var list = augmentations_2[_f]; + for (var _g = 0, list_2 = list; _g < list_2.length; _g++) { + var augmentation = list_2[_g]; if (ts.isGlobalScopeAugmentation(augmentation.parent)) continue; mergeModuleAugmentation(augmentation); @@ -90373,17 +90439,30 @@ var ts; } return false; } - function getAmbientModules() { - if (!ambientModulesCache) { - ambientModulesCache = []; - globals.forEach(function (global, sym) { + function getAmbientModules(sourceFile) { + var isNode = denoContext.hasNodeSourceFile(sourceFile); + if (isNode) { + if (!nodeAmbientModulesCache) { + nodeAmbientModulesCache = getAmbientModules(denoContext.combinedGlobals); + } + return nodeAmbientModulesCache; + } + else { + if (!ambientModulesCache) { + ambientModulesCache = getAmbientModules(globals); + } + return ambientModulesCache; + } + function getAmbientModules(envGlobals) { + var cache = []; + envGlobals.forEach(function (global, sym) { // No need to `unescapeLeadingUnderscores`, an escaped symbol is never an ambient module. if (ambientModuleSymbolRegex.test(sym)) { - ambientModulesCache.push(global); + cache.push(global); } }); + return cache; } - return ambientModulesCache; } function checkGrammarImportClause(node) { var _a; @@ -90562,6 +90641,234 @@ var ts; } ts.signatureHasLiteralTypes = signatureHasLiteralTypes; })(ts || (ts = {})); +/* @internal */ +var ts; +(function (ts) { + var deno; + (function (deno) { + var isNodeSourceFile = function () { return false; }; + function setIsNodeSourceFileCallback(callback) { + isNodeSourceFile = callback; + } + deno.setIsNodeSourceFileCallback = setIsNodeSourceFileCallback; + // When upgrading: + // 1. Inspect all usages of "globals" and "globalThisSymbol" in checker.ts + // - Beware that `globalThisType` might refer to the global `this` type + // and not the global `globalThis` type + // 2. Inspect the types in @types/node for anything that might need to go below + // as well. + var nodeOnlyGlobalNames = new ts.Set([ + "NodeRequire", + "RequireResolve", + "RequireResolve", + "process", + "console", + "__filename", + "__dirname", + "require", + "module", + "exports", + "gc", + "BufferEncoding", + "BufferConstructor", + "WithImplicitCoercion", + "Buffer", + "Console", + "ImportMeta", + "setTimeout", + "setInterval", + "setImmediate", + "Global", + "AbortController", + "AbortSignal", + "Blob", + "BroadcastChannel", + "MessageChannel", + "MessagePort", + "Event", + "EventTarget", + "performance", + "TextDecoder", + "TextEncoder", + "URL", + "URLSearchParams", + ]); + function createDenoForkContext(_a) { + var mergeSymbol = _a.mergeSymbol, globals = _a.globals, nodeGlobals = _a.nodeGlobals, ambientModuleSymbolRegex = _a.ambientModuleSymbolRegex; + return { + hasNodeSourceFile: hasNodeSourceFile, + getGlobalsForName: getGlobalsForName, + mergeGlobalSymbolTable: mergeGlobalSymbolTable, + combinedGlobals: createNodeGlobalsSymbolTable(), + }; + function hasNodeSourceFile(node) { + if (!node) + return false; + var sourceFile = ts.getSourceFileOfNode(node); + return isNodeSourceFile(sourceFile); + } + function getGlobalsForName(id) { + // Node ambient modules are only accessible in the node code, + // so put them on the node globals + if (ambientModuleSymbolRegex.test(id)) + return nodeGlobals; + return nodeOnlyGlobalNames.has(id) ? nodeGlobals : globals; + } + function mergeGlobalSymbolTable(node, source, unidirectional) { + if (unidirectional === void 0) { unidirectional = false; } + var sourceFile = ts.getSourceFileOfNode(node); + var isNodeFile = hasNodeSourceFile(sourceFile); + source.forEach(function (sourceSymbol, id) { + var target = isNodeFile ? getGlobalsForName(id) : globals; + var targetSymbol = target.get(id); + target.set(id, targetSymbol ? mergeSymbol(targetSymbol, sourceSymbol, unidirectional) : sourceSymbol); + }); + } + function createNodeGlobalsSymbolTable() { + return new Proxy(globals, { + get: function (target, prop, receiver) { + if (prop === "get") { + return function (key) { + var _a; + return (_a = nodeGlobals.get(key)) !== null && _a !== void 0 ? _a : globals.get(key); + }; + } + else if (prop === "has") { + return function (key) { + return nodeGlobals.has(key) || globals.has(key); + }; + } + else if (prop === "size") { + var i_2 = 0; + forEachEntry(function () { + i_2++; + }); + return i_2; + } + else if (prop === "forEach") { + return function (action) { + forEachEntry(function (_a) { + var key = _a[0], value = _a[1]; + action(value, key); + }); + }; + } + else if (prop === "entries") { + return function () { + return getEntries(function (kv) { return kv; }); + }; + } + else if (prop === "keys") { + return function () { + return getEntries(function (kv) { return kv[0]; }); + }; + } + else if (prop === "values") { + return function () { + return getEntries(function (kv) { return kv[1]; }); + }; + } + else if (prop === Symbol.iterator) { + return function () { + // Need to convert this to an array since typescript targets ES5 + // and providing back the iterator won't work here. I don't want + // to change the target to ES6 because I'm not sure if that would + // surface any issues. + return ts.arrayFrom(getEntries(function (kv) { return kv; }))[Symbol.iterator](); + }; + } + else { + var value_3 = target[prop]; + if (value_3 instanceof Function) { + return function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + return value_3.apply(this === receiver ? target : this, args); + }; + } + return value_3; + } + }, + }); + function forEachEntry(action) { + var iterator = getEntries(function (entry) { + action(entry); + }); + // drain the iterator to do the action + while (!iterator.next().done) { } + } + function getEntries(transform) { + var foundKeys, _i, _a, entries, next; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + foundKeys = new ts.Set(); + _i = 0, _a = [nodeGlobals.entries(), globals.entries()]; + _b.label = 1; + case 1: + if (!(_i < _a.length)) return [3 /*break*/, 6]; + entries = _a[_i]; + next = entries.next(); + _b.label = 2; + case 2: + if (!!next.done) return [3 /*break*/, 5]; + if (!!foundKeys.has(next.value[0])) return [3 /*break*/, 4]; + return [4 /*yield*/, transform(next.value)]; + case 3: + _b.sent(); + foundKeys.add(next.value[0]); + _b.label = 4; + case 4: + next = entries.next(); + return [3 /*break*/, 2]; + case 5: + _i++; + return [3 /*break*/, 1]; + case 6: return [2 /*return*/]; + } + }); + } + } + } + deno.createDenoForkContext = createDenoForkContext; + function tryParseNpmPackageReference(text) { + try { + return parseNpmPackageReference(text); + } + catch (_a) { + return undefined; + } + } + deno.tryParseNpmPackageReference = tryParseNpmPackageReference; + function parseNpmPackageReference(text) { + if (!text.startsWith("npm:")) { + throw new Error("Not an npm specifier: ".concat(text)); + } + text = text.replace(/^npm:/, ""); + var parts = text.split("/"); + var namePartLen = text.startsWith("@") ? 2 : 1; + if (parts.length < namePartLen) { + throw new Error("Not a valid package: ".concat(text)); + } + var nameParts = parts.slice(0, namePartLen); + var lastNamePart = nameParts.at(-1); + var lastAtIndex = lastNamePart.lastIndexOf("@"); + var versionReq = undefined; + if (lastAtIndex > 0) { + versionReq = lastNamePart.substring(lastAtIndex + 1); + nameParts[nameParts.length - 1] = lastNamePart.substring(0, lastAtIndex); + } + return { + name: nameParts.join("/"), + versionReq: versionReq, + subPath: parts.length > nameParts.length ? parts.slice(nameParts.length).join("/") : undefined, + }; + } + deno.parseNpmPackageReference = parseNpmPackageReference; + })(deno = ts.deno || (ts.deno = {})); +})(ts || (ts = {})); var ts; (function (ts) { function visitNode(node, visitor, test, lift) { @@ -121271,7 +121578,7 @@ var ts; } } // From ambient modules - for (var _f = 0, _g = program.getTypeChecker().getAmbientModules(); _f < _g.length; _f++) { + for (var _f = 0, _g = program.getTypeChecker().getAmbientModules(sourceFile); _f < _g.length; _f++) { var ambientModule = _g[_f]; if (ambientModule.declarations && ambientModule.declarations.length > 1) { addReferenceFromAmbientModule(ambientModule); @@ -124123,7 +124430,7 @@ var ts; }); // Sort by paths closest to importing file Name directory var sortedPaths = []; - var _loop_35 = function (directory) { + var _loop_36 = function (directory) { var directoryStart = ts.ensureTrailingDirectorySeparator(directory); var pathsInDirectory; allFileNames.forEach(function (_a, fileName) { @@ -124147,7 +124454,7 @@ var ts; }; var out_directory_1; for (var directory = ts.getDirectoryPath(importingFileName); allFileNames.size !== 0;) { - var state_11 = _loop_35(directory); + var state_11 = _loop_36(directory); directory = out_directory_1; if (state_11 === "break") break; @@ -124218,7 +124525,7 @@ var ts; } function tryGetModuleNameFromPaths(relativeToBaseUrl, paths, allowedEndings, host, compilerOptions) { for (var key in paths) { - var _loop_36 = function (patternText_1) { + var _loop_37 = function (patternText_1) { var pattern = ts.normalizePath(patternText_1); var indexOfStar = pattern.indexOf("*"); // In module resolution, if `pattern` itself has an extension, a file with that extension is looked up directly, @@ -124285,7 +124592,7 @@ var ts; }; for (var _i = 0, _a = paths[key]; _i < _a.length; _i++) { var patternText_1 = _a[_i]; - var state_12 = _loop_36(patternText_1); + var state_12 = _loop_37(patternText_1); if (typeof state_12 === "object") return state_12.value; } @@ -137638,7 +137945,8 @@ var ts; if (globalSymbol && checker.getTypeOfSymbolAtLocation(globalSymbol, sourceFile) === type) { return true; } - var globalThisSymbol = checker.resolveName("globalThis", /*location*/ undefined, 111551 /* SymbolFlags.Value */, /*excludeGlobals*/ false); + // deno: provide sourceFile so that it can figure out if it's a node or deno globalThis + var globalThisSymbol = checker.resolveName("globalThis", /*location*/ sourceFile, 111551 /* SymbolFlags.Value */, /*excludeGlobals*/ false); if (globalThisSymbol && checker.getTypeOfSymbolAtLocation(globalThisSymbol, sourceFile) === type) { return true; } diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js index b39f56cf6..7929d3b44 100644 --- a/cli/tsc/99_main_compiler.js +++ b/cli/tsc/99_main_compiler.js @@ -29,6 +29,7 @@ delete Object.prototype.__proto__; // This map stores that relationship, and the original can be restored by the // normalized specifier. // See: https://github.com/denoland/deno/issues/9277#issuecomment-769653834 + /** @type {Map<string, string>} */ const normalizedToOriginalMap = new Map(); /** @@ -40,6 +41,16 @@ delete Object.prototype.__proto__; "languageVersion" in value; } + /** + * @param {ts.ScriptTarget | ts.CreateSourceFileOptions | undefined} versionOrOptions + * @returns {ts.CreateSourceFileOptions} + */ + function getCreateSourceFileOptions(versionOrOptions) { + return isCreateSourceFileOptions(versionOrOptions) + ? versionOrOptions + : { languageVersion: versionOrOptions ?? ts.ScriptTarget.ESNext }; + } + function setLogDebug(debug, source) { logDebug = debug; if (source) { @@ -119,8 +130,23 @@ delete Object.prototype.__proto__; return result; } - // In the case of the LSP, this is initialized with the assets - // when snapshotting and never added to or removed after that. + class SpecifierIsCjsCache { + /** @type {Set<string>} */ + #cache = new Set(); + + /** @param {[string, ts.Extension]} param */ + add([specifier, ext]) { + if (ext === ".cjs" || ext === ".d.cts" || ext === ".cts") { + this.#cache.add(specifier); + } + } + + has(specifier) { + return this.#cache.has(specifier); + } + } + + // In the case of the LSP, this will only ever contain the assets. /** @type {Map<string, ts.SourceFile>} */ const sourceFileCache = new Map(); @@ -130,6 +156,181 @@ delete Object.prototype.__proto__; /** @type {Map<string, string>} */ const scriptVersionCache = new Map(); + /** @type {Map<string, boolean>} */ + const isNodeSourceFileCache = new Map(); + + const isCjsCache = new SpecifierIsCjsCache(); + + /** + * @param {ts.CompilerOptions | ts.MinimalResolutionCacheHost} settingsOrHost + * @returns {ts.CompilerOptions} + */ + function getCompilationSettings(settingsOrHost) { + if (typeof settingsOrHost.getCompilationSettings === "function") { + return settingsOrHost.getCompilationSettings(); + } + return /** @type {ts.CompilerOptions} */ (settingsOrHost); + } + + // We need to use a custom document registry in order to provide source files + // with an impliedNodeFormat to the ts language service + + /** @type {Map<string, ts.SourceFile} */ + const documentRegistrySourceFileCache = new Map(); + const { getKeyForCompilationSettings } = ts.createDocumentRegistry(); // reuse this code + /** @type {ts.DocumentRegistry} */ + const documentRegistry = { + acquireDocument( + fileName, + compilationSettingsOrHost, + scriptSnapshot, + version, + scriptKind, + sourceFileOptions, + ) { + const key = getKeyForCompilationSettings( + getCompilationSettings(compilationSettingsOrHost), + ); + return this.acquireDocumentWithKey( + fileName, + /** @type {ts.Path} */ (fileName), + compilationSettingsOrHost, + key, + scriptSnapshot, + version, + scriptKind, + sourceFileOptions, + ); + }, + + acquireDocumentWithKey( + fileName, + path, + _compilationSettingsOrHost, + key, + scriptSnapshot, + version, + scriptKind, + sourceFileOptions, + ) { + const mapKey = path + key; + let sourceFile = documentRegistrySourceFileCache.get(mapKey); + if (!sourceFile || sourceFile.version !== version) { + sourceFile = ts.createLanguageServiceSourceFile( + fileName, + scriptSnapshot, + { + ...getCreateSourceFileOptions(sourceFileOptions), + impliedNodeFormat: isCjsCache.has(fileName) + ? ts.ModuleKind.CommonJS + : ts.ModuleKind.ESNext, + }, + version, + true, + scriptKind, + ); + documentRegistrySourceFileCache.set(mapKey, sourceFile); + } + return sourceFile; + }, + + updateDocument( + fileName, + compilationSettingsOrHost, + scriptSnapshot, + version, + scriptKind, + sourceFileOptions, + ) { + const key = getKeyForCompilationSettings( + getCompilationSettings(compilationSettingsOrHost), + ); + return this.updateDocumentWithKey( + fileName, + /** @type {ts.Path} */ (fileName), + compilationSettingsOrHost, + key, + scriptSnapshot, + version, + scriptKind, + sourceFileOptions, + ); + }, + + updateDocumentWithKey( + fileName, + path, + compilationSettingsOrHost, + key, + scriptSnapshot, + version, + scriptKind, + sourceFileOptions, + ) { + const mapKey = path + key; + let sourceFile = documentRegistrySourceFileCache.get(mapKey) ?? + this.acquireDocumentWithKey( + fileName, + path, + compilationSettingsOrHost, + key, + scriptSnapshot, + version, + scriptKind, + sourceFileOptions, + ); + + if (sourceFile.version !== version) { + sourceFile = ts.updateLanguageServiceSourceFile( + sourceFile, + scriptSnapshot, + version, + scriptSnapshot.getChangeRange(sourceFile.scriptSnapShot), + ); + } + return sourceFile; + }, + + getKeyForCompilationSettings(settings) { + return getKeyForCompilationSettings(settings); + }, + + releaseDocument( + fileName, + compilationSettings, + scriptKind, + impliedNodeFormat, + ) { + const key = getKeyForCompilationSettings(compilationSettings); + return this.releaseDocumentWithKey( + /** @type {ts.Path} */ (fileName), + key, + scriptKind, + impliedNodeFormat, + ); + }, + + releaseDocumentWithKey(path, key, _scriptKind, _impliedNodeFormat) { + const mapKey = path + key; + documentRegistrySourceFileCache.remove(mapKey); + }, + + reportStats() { + return "[]"; + }, + }; + + ts.deno.setIsNodeSourceFileCallback((sourceFile) => { + const fileName = sourceFile.fileName; + let isNodeSourceFile = isNodeSourceFileCache.get(fileName); + if (isNodeSourceFile == null) { + const result = ops.op_is_node_file(fileName); + isNodeSourceFile = /** @type {boolean} */ (result); + isNodeSourceFileCache.set(fileName, isNodeSourceFile); + } + return isNodeSourceFile; + }); + /** @param {ts.DiagnosticRelatedInformation} diagnostic */ function fromRelatedInformation({ start, @@ -189,6 +390,10 @@ delete Object.prototype.__proto__; /** Diagnostics that are intentionally ignored when compiling TypeScript in * Deno, as they provide misleading or incorrect information. */ const IGNORED_DIAGNOSTICS = [ + // TS1452: 'resolution-mode' assertions are only supported when `moduleResolution` is `node16` or `nodenext`. + // We specify the resolution mode to be CommonJS for some npm files and this + // diagnostic gets generated even though we're using custom module resolution. + 1452, // TS2306: File '.../index.d.ts' is not a module. // We get this for `x-typescript-types` declaration files which don't export // anything. We prefer to treat these as modules with no exports. @@ -228,10 +433,12 @@ delete Object.prototype.__proto__; target: ts.ScriptTarget.ESNext, }; + // todo(dsherret): can we remove this and just use ts.OperationCanceledException? /** Error thrown on cancellation. */ class OperationCanceledError extends Error { } + // todo(dsherret): we should investigate if throttling is really necessary /** * Inspired by ThrottledCancellationToken in ts server. * @@ -291,13 +498,10 @@ delete Object.prototype.__proto__; _onError, _shouldCreateNewSourceFile, ) { + const createOptions = getCreateSourceFileOptions(languageVersion); debug( `host.getSourceFile("${specifier}", ${ - ts.ScriptTarget[ - isCreateSourceFileOptions(languageVersion) - ? languageVersion.languageVersion - : languageVersion - ] + ts.ScriptTarget[createOptions.languageVersion] })`, ); @@ -320,7 +524,12 @@ delete Object.prototype.__proto__; sourceFile = ts.createSourceFile( specifier, data, - languageVersion, + { + ...createOptions, + impliedNodeFormat: isCjsCache.has(specifier) + ? ts.ModuleKind.CommonJS + : ts.ModuleKind.ESNext, + }, false, scriptKind, ); @@ -355,6 +564,50 @@ delete Object.prototype.__proto__; getNewLine() { return "\n"; }, + resolveTypeReferenceDirectives( + typeDirectiveNames, + containingFilePath, + redirectedReference, + options, + containingFileMode, + ) { + return typeDirectiveNames.map((arg) => { + /** @type {ts.FileReference} */ + const fileReference = typeof arg === "string" + ? { + pos: -1, + end: -1, + fileName: arg, + } + : arg; + if (fileReference.fileName.startsWith("npm:")) { + /** @type {[string, ts.Extension] | undefined} */ + const resolved = ops.op_resolve({ + specifiers: [fileReference.fileName], + base: containingFilePath, + })?.[0]; + if (resolved) { + isCjsCache.add(resolved); + return { + primary: true, + resolvedFileName: resolved[0], + }; + } else { + return undefined; + } + } else { + return ts.resolveTypeReferenceDirective( + fileReference.fileName, + containingFilePath, + options, + host, + redirectedReference, + undefined, + containingFileMode ?? fileReference.resolutionMode, + ).resolvedTypeReferenceDirective; + } + }); + }, resolveModuleNames(specifiers, base) { debug(`host.resolveModuleNames()`); debug(` base: ${base}`); @@ -367,7 +620,12 @@ delete Object.prototype.__proto__; if (resolved) { const result = resolved.map((item) => { if (item) { + isCjsCache.add(item); const [resolvedFileName, extension] = item; + if (resolvedFileName.startsWith("node:")) { + // probably means the user doesn't have @types/node, so resolve to undefined + return undefined; + } return { resolvedFileName, extension, @@ -444,6 +702,23 @@ delete Object.prototype.__proto__; }, }; + // override the npm install @types package diagnostics to be deno specific + ts.setLocalizedDiagnosticMessages((() => { + const nodeMessage = "Cannot find name '{0}'."; // don't offer any suggestions + const jqueryMessage = + "Cannot find name '{0}'. Did you mean to import jQuery? Try adding `import $ from \"npm:jquery\";`."; + return { + "Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_node_Try_npm_i_save_dev_types_Slashno_2580": + nodeMessage, + "Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_node_Try_npm_i_save_dev_types_Slashno_2591": + nodeMessage, + "Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_save_dev_types_Slash_2581": + jqueryMessage, + "Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_save_dev_types_Slash_2592": + jqueryMessage, + }; + })()); + /** @type {Array<[string, number]>} */ const stats = []; let statsStart = 0; @@ -557,7 +832,25 @@ delete Object.prototype.__proto__; ...program.getOptionsDiagnostics(), ...program.getGlobalDiagnostics(), ...program.getSemanticDiagnostics(), - ].filter(({ code }) => !IGNORED_DIAGNOSTICS.includes(code)); + ].filter((diagnostic) => { + if (IGNORED_DIAGNOSTICS.includes(diagnostic.code)) { + return false; + } else if ( + diagnostic.code === 1259 && + typeof diagnostic.messageText === "string" && + diagnostic.messageText.startsWith( + "Module '\"deno:///missing_dependency.d.ts\"' can only be default-imported using the 'allowSyntheticDefaultImports' flag", + ) + ) { + // For now, ignore diagnostics like: + // > TS1259 [ERROR]: Module '"deno:///missing_dependency.d.ts"' can only be default-imported using the 'allowSyntheticDefaultImports' flag + // This diagnostic has surfaced due to supporting node cjs imports because this module does `export =`. + // See discussion in https://github.com/microsoft/TypeScript/pull/51136 + return false; + } else { + return true; + } + }); // emit the tsbuildinfo file // @ts-ignore: emitBuildInfo is not exposed (https://github.com/microsoft/TypeScript/issues/49871) @@ -922,13 +1215,14 @@ delete Object.prototype.__proto__; } hasStarted = true; cwd = rootUri; - languageService = ts.createLanguageService(host); + languageService = ts.createLanguageService(host, documentRegistry); setLogDebug(debugFlag, "TSLS"); debug("serverInit()"); } function serverRestart() { - languageService = ts.createLanguageService(host); + languageService = ts.createLanguageService(host, documentRegistry); + isNodeSourceFileCache.clear(); debug("serverRestart()"); } diff --git a/cli/tsc/compiler.d.ts b/cli/tsc/compiler.d.ts index b550c938b..62a1bbdd2 100644 --- a/cli/tsc/compiler.d.ts +++ b/cli/tsc/compiler.d.ts @@ -12,6 +12,7 @@ declare global { var normalizePath: (path: string) => string; interface SourceFile { version?: string; + fileName: string; } interface CompilerHost { @@ -24,6 +25,12 @@ declare global { } var performance: Performance; + + namespace deno { + function setIsNodeSourceFileCallback( + callback: (sourceFile: SourceFile) => boolean, + ); + } } namespace ts { |