Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to TS 5.0.2 #4

Merged
merged 7 commits into from
Mar 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/compiler/_namespaces/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export * from "../moduleNameResolver";
export * from "../binder";
export * from "../symbolWalker";
export * from "../checker";
export * as deno from "../deno";
export * from "../visitorPublic";
export * from "../sourcemap";
export * from "../transformers/utilities";
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/builderState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ export namespace BuilderState {
}

// From ambient modules
for (const ambientModule of program.getTypeChecker().getAmbientModules()) {
for (const ambientModule of program.getTypeChecker().getAmbientModules(sourceFile)) {
if (ambientModule.declarations && ambientModule.declarations.length > 1) {
addReferenceFromAmbientModule(ambientModule);
}
Expand Down
129 changes: 108 additions & 21 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ const libEntries: [string, string][] = [
// Host only
["dom", "lib.dom.d.ts"],
["dom.iterable", "lib.dom.iterable.d.ts"],
["dom.asynciterable", "lib.dom.asynciterable.d.ts"],
["dom.extras", "lib.dom.extras.d.ts"],
["webworker", "lib.webworker.d.ts"],
["webworker.importscripts", "lib.webworker.importscripts.d.ts"],
["webworker.iterable", "lib.webworker.iterable.d.ts"],
Expand Down Expand Up @@ -211,7 +213,7 @@ const libEntries: [string, string][] = [
["es2022.string", "lib.es2022.string.d.ts"],
["es2022.regexp", "lib.es2022.regexp.d.ts"],
["es2023.array", "lib.es2023.array.d.ts"],
["esnext.array", "lib.es2023.array.d.ts"],
["esnext.array", "lib.esnext.array.d.ts"],
["esnext.symbol", "lib.es2019.symbol.d.ts"],
["esnext.asynciterable", "lib.es2018.asynciterable.d.ts"],
["esnext.intl", "lib.esnext.intl.d.ts"],
Expand Down Expand Up @@ -1101,6 +1103,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
name: "allowImportingTsExtensions",
type: "boolean",
affectsSemanticDiagnostics: true,
affectsBuildInfo: true,
category: Diagnostics.Modules,
description: Diagnostics.Allow_imports_to_include_TypeScript_file_extensions_Requires_moduleResolution_bundler_and_either_noEmit_or_emitDeclarationOnly_to_be_set,
defaultValueDescription: false,
Expand Down
190 changes: 190 additions & 0 deletions src/compiler/deno.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import * as ts from "./_namespaces/ts";

export type IsNodeSourceFileCallback = (sourceFile: ts.SourceFile) => boolean;

let isNodeSourceFile: IsNodeSourceFileCallback = () => false;
let nodeBuiltInModuleNames = new Set<string>();
let nodeOnlyGlobalNames = new Set<ts.__String>();

export function setIsNodeSourceFileCallback(callback: IsNodeSourceFileCallback) {
isNodeSourceFile = callback;
}

export function setNodeBuiltInModuleNames(names: readonly string[]) {
nodeBuiltInModuleNames = new Set(names);
}

export function setNodeOnlyGlobalNames(names: readonly string[]) {
nodeBuiltInModuleNames = new Set(names);
nodeOnlyGlobalNames = new Set(names) as Set<ts.__String>;
}

// When upgrading:
// 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

export function createDenoForkContext({
mergeSymbol,
globals,
nodeGlobals,
ambientModuleSymbolRegex,
}: {
mergeSymbol(target: ts.Symbol, source: ts.Symbol, unidirectional?: boolean): ts.Symbol;
globals: ts.SymbolTable;
nodeGlobals: ts.SymbolTable;
ambientModuleSymbolRegex: RegExp,
}) {
return {
hasNodeSourceFile,
getGlobalsForName,
mergeGlobalSymbolTable,
combinedGlobals: createNodeGlobalsSymbolTable(),
};

function hasNodeSourceFile(node: ts.Node | undefined) {
if (!node) return false;
const sourceFile = ts.getSourceFileOfNode(node);
return isNodeSourceFile(sourceFile);
}

function getGlobalsForName(id: ts.__String) {
// Node ambient modules are only accessible in the node code,
// so put them on the node globals
if (ambientModuleSymbolRegex.test(id as string)) {
if ((id as string).startsWith('"node:')) {
// check if it's a node specifier that we support
const name = (id as string).slice(6, -1);
if (nodeBuiltInModuleNames.has(name)) {
return globals;
}
}
return nodeGlobals;
}
return nodeOnlyGlobalNames.has(id) ? nodeGlobals : globals;
}

function mergeGlobalSymbolTable(node: ts.Node, source: ts.SymbolTable, unidirectional = false) {
const sourceFile = ts.getSourceFileOfNode(node);
const isNodeFile = hasNodeSourceFile(sourceFile);
source.forEach((sourceSymbol, id) => {
const target = isNodeFile ? getGlobalsForName(id) : globals;
const targetSymbol = target.get(id);
target.set(id, targetSymbol ? mergeSymbol(targetSymbol, sourceSymbol, unidirectional) : sourceSymbol);
});
}

function createNodeGlobalsSymbolTable() {
return new Proxy(globals, {
get(target, prop: string | symbol, receiver) {
if (prop === "get") {
return (key: ts.__String) => {
return nodeGlobals.get(key) ?? globals.get(key);
};
} else if (prop === "has") {
return (key: ts.__String) => {
return nodeGlobals.has(key) || globals.has(key);
};
} else if (prop === "size") {
let i = 0;
for (const _ignore of getEntries(entry => entry)) {
i++;
}
return i;
} else if (prop === "forEach") {
return (action: (value: ts.Symbol, key: ts.__String) => void) => {
for (const [key, value] of getEntries(entry => entry)) {
action(value, key);
}
};
} else if (prop === "entries") {
return () => {
return getEntries(kv => kv);
};
} else if (prop === "keys") {
return () => {
return getEntries(kv => kv[0]);
};
} else if (prop === "values") {
return () => {
return getEntries(kv => kv[1]);
};
} else if (prop === Symbol.iterator) {
return () => {
// 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 Array.from(getEntries(kv => kv))[Symbol.iterator]();
};
} else {
const value = (target as any)[prop];
if (value instanceof Function) {
return function (this: any, ...args: any[]) {
return value.apply(this === receiver ? target : this, args);
};
}
return value;
}
},
});

function* getEntries<R>(
transform: (value: [ts.__String, ts.Symbol]) => R
) {
const foundKeys = new Set<ts.__String>();
// prefer the node globals over the deno globalThis
for (const entries of [nodeGlobals.entries(), globals.entries()]) {
for (const entry of entries) {
if (!foundKeys.has(entry[0])) {
yield transform(entry);
foundKeys.add(entry[0]);
}
}
}
}
}
}

export interface NpmPackageReference {
name: string;
versionReq: string;
subPath: string | undefined;
}

export function tryParseNpmPackageReference(text: string) {
try {
return parseNpmPackageReference(text);
} catch {
return undefined;
}
}

export function parseNpmPackageReference(text: string) {
if (!text.startsWith("npm:")) {
throw new Error(`Not an npm specifier: ${text}`);
}
text = text.replace(/^npm:\/?/, ""); // todo: remove this regex
const parts = text.split("/");
const namePartLen = text.startsWith("@") ? 2 : 1;
if (parts.length < namePartLen) {
throw new Error(`Not a valid package: ${text}`);
}
const nameParts = parts.slice(0, namePartLen);
const lastNamePart = nameParts.at(-1)!;
const lastAtIndex = lastNamePart.lastIndexOf("@");
let versionReq: string | undefined = undefined;
if (lastAtIndex > 0) {
versionReq = lastNamePart.substring(lastAtIndex + 1);
nameParts[nameParts.length - 1] = lastNamePart.substring(0, lastAtIndex);
}
const name = nameParts.join("/");
if (name.length === 0) {
throw new Error(`Npm specifier did not have a name: ${text}`);
}
return {
name,
versionReq,
subPath: parts.length > nameParts.length ? parts.slice(nameParts.length).join("/") : undefined,
};
}
10 changes: 10 additions & 0 deletions src/compiler/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,11 @@ function getEncodedRootLength(path: string): number {
return ~path.length; // URL: "file:https://server", "http:https://server"
}

// deno: temporary hack until https://github.com/microsoft/TypeScript/issues/53605 is fixed
if (path.startsWith("data:")) {
return ~path.length;
}

// relative
return 0;
}
Expand Down Expand Up @@ -698,6 +703,11 @@ export function ensureTrailingDirectorySeparator(path: string): string;
/** @internal */
export function ensureTrailingDirectorySeparator(path: string) {
if (!hasTrailingDirectorySeparator(path)) {
// deno: added this so that data urls don't get a trailing slash
// https://github.com/microsoft/TypeScript/issues/53605#issuecomment-1492167313
if (path.startsWith("data:")) {
return path;
}
return path + directorySeparator;
}

Expand Down
2 changes: 1 addition & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5078,7 +5078,7 @@ export interface TypeChecker {
/** @internal */ forEachExportAndPropertyOfModule(moduleSymbol: Symbol, cb: (symbol: Symbol, key: __String) => void): void;
getJsxIntrinsicTagNamesAt(location: Node): Symbol[];
isOptionalParameter(node: ParameterDeclaration): boolean;
getAmbientModules(): Symbol[];
getAmbientModules(sourceFile?: SourceFile): Symbol[];

tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined;
/**
Expand Down
3 changes: 2 additions & 1 deletion src/services/completions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4949,7 +4949,8 @@ function isProbablyGlobalType(type: Type, sourceFile: SourceFile, checker: TypeC
if (globalSymbol && checker.getTypeOfSymbolAtLocation(globalSymbol, sourceFile) === type) {
return true;
}
const globalThisSymbol = checker.resolveName("globalThis", /*location*/ undefined, SymbolFlags.Value, /*excludeGlobals*/ false);
// deno: provide sourceFile so that it can figure out if it's a node or deno globalThis
const globalThisSymbol = checker.resolveName("globalThis", /*location*/ sourceFile, SymbolFlags.Value, /*excludeGlobals*/ false);
if (globalThisSymbol && checker.getTypeOfSymbolAtLocation(globalThisSymbol, sourceFile) === type) {
return true;
}
Expand Down