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.7.3 #15

Open
wants to merge 14 commits into
base: branch_v5.7.3
Choose a base branch
from
1 change: 1 addition & 0 deletions src/compiler/_namespaces/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export * from "../types.js";
export * from "../sys.js";
export * from "../path.js";
export * from "../diagnosticInformationMap.generated.js";
export * as deno from "../deno.js";
export * from "../scanner.js";
export * from "../utilitiesPublic.js";
export * from "../utilities.js";
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/builderState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,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
214 changes: 153 additions & 61 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ const libEntries: [string, string][] = [
["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
252 changes: 252 additions & 0 deletions src/compiler/deno.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
import * as ts from "./_namespaces/ts.js";

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

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

export type EnterSpan = (name: string) => object;
export type ExitSpan = (span: object) => void;

export let enterSpan: EnterSpan = () => ({ });
export let exitSpan: ExitSpan = () => { };

export function setEnterSpan(f: EnterSpan): void {
enterSpan = f;
}
export function setExitSpan(f: ExitSpan): void {
exitSpan = f;
}

export function spanned<T>(name: string, f: () => T): T {
const span = enterSpan(name);
let needsExit = true;
try {
const result = f();
if (result instanceof Promise) {
needsExit = false;
return result.finally(() => exitSpan(span)) as T;
} else {
return result;
}

} finally {
if (needsExit) {
exitSpan(span);
}
}
}

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

export function setNodeOnlyGlobalNames(names: Set<string>): void {
nodeOnlyGlobalNames = names as Set<ts.__String>;
}

export function setTypesNodeIgnorableNames(names: Set<string>): void {
typesNodeIgnorableNames = 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 interface DenoForkContext {
hasNodeSourceFile: (node: ts.Node | undefined) => boolean;
getGlobalsForName: (id: ts.__String) => ts.SymbolTable;
mergeGlobalSymbolTable: (node: ts.Node, source: ts.SymbolTable, unidirectional?: boolean) => void;
combinedGlobals: ts.SymbolTable;
}

export function createDenoForkContext({
mergeSymbol,
globals,
nodeGlobals,
}: {
mergeSymbol(target: ts.Symbol, source: ts.Symbol, unidirectional?: boolean): ts.Symbol;
globals: ts.SymbolTable;
nodeGlobals: ts.SymbolTable;
}): DenoForkContext {
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) {
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);
const isTypesNodeSourceFile = isNodeFile && isTypesNodePkgPath(sourceFile.path);
source.forEach((sourceSymbol, id) => {
const target = isNodeFile ? getGlobalsForName(id) : globals;
const targetSymbol = target.get(id);
if (
isTypesNodeSourceFile
&& targetSymbol !== undefined
&& typesNodeIgnorableNames.has(id)
// if the symbol has a @types/node package then that means the global
// was created within the @types/node package and not the lib.d.ts files,
// so allow merging to it (useful when someone has DOM and deno types disabled)
&& !symbolHasAnyTypesNodePkgDecl(targetSymbol)
) {
return;
}
target.set(id, targetSymbol ? mergeSymbol(targetSymbol, sourceSymbol, unidirectional) : sourceSymbol);
});
}

function symbolHasAnyTypesNodePkgDecl(symbol: ts.Symbol) {
if (symbol.declarations) {
for (const decl of symbol.declarations) {
const sourceFile = ts.getSourceFileOfNode(decl);
const isNodeFile = hasNodeSourceFile(sourceFile);
if (isNodeFile && isTypesNodePkgPath(sourceFile.path)) {
return true;
}
}
}
return false;
}

function isTypesNodePkgPath(path: ts.Path) {
return path.endsWith(".d.ts") && path.includes("/@types/node/");
}

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 | undefined;
subPath: string | undefined;
}

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

export function parseNpmPackageReference(text: string): NpmPackageReference {
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;
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 @@ -216,6 +216,11 @@ function getEncodedRootLength(path: string): number {
return ~path.length; // URL: "file://server", "http://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 @@ -706,6 +711,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
17 changes: 9 additions & 8 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -577,15 +577,16 @@ export function changeCompilerHostLikeToUseCache(
return sourceFile;
} : undefined;

// deno: disable this cache because we always return false here
// fileExists for any kind of extension
host.fileExists = fileName => {
const key = toPath(fileName);
const value = fileExistsCache.get(key);
if (value !== undefined) return value;
const newValue = originalFileExists.call(host, fileName);
fileExistsCache.set(key, !!newValue);
return newValue;
};
// host.fileExists = fileName => {
// const key = toPath(fileName);
// const value = fileExistsCache.get(key);
// if (value !== undefined) return value;
// const newValue = originalFileExists.call(host, fileName);
// fileExistsCache.set(key, !!newValue);
// return newValue;
// };
if (originalWriteFile) {
host.writeFile = (fileName, data, ...rest) => {
const key = toPath(fileName);
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5219,7 +5219,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
16 changes: 13 additions & 3 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ import {
DeclarationWithTypeParameters,
Decorator,
DefaultClause,
deno,
DestructuringAssignment,
Diagnostic,
DiagnosticArguments,
Expand Down Expand Up @@ -11340,7 +11341,9 @@ export interface NameResolverOptions {
compilerOptions: CompilerOptions;
getSymbolOfDeclaration: (node: Declaration) => Symbol;
error: (location: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments) => void;
globals: SymbolTable;
denoGlobals: SymbolTable;
nodeGlobals: SymbolTable;
denoContext: deno.DenoForkContext;
argumentsSymbol: Symbol;
requireSymbol: Symbol;
lookup: (symbols: SymbolTable, name: __String, meaning: SymbolFlags) => Symbol | undefined;
Expand Down Expand Up @@ -11368,7 +11371,9 @@ export function createNameResolver({
argumentsSymbol,
error,
getSymbolOfDeclaration,
globals,
denoGlobals,
nodeGlobals,
denoContext,
lookup,
setRequiresScopeChangeCache = returnUndefined,
getRequiresScopeChangeCache = returnUndefined,
Expand Down Expand Up @@ -11751,7 +11756,12 @@ export function createNameResolver({
}

if (!excludeGlobals) {
result = lookup(globals, name, meaning);
if (denoContext.hasNodeSourceFile(lastLocation)) {
result = lookup(nodeGlobals, name, meaning);
}
if (!result) {
result = lookup(denoGlobals, name, meaning);
}
}
}
if (!result) {
Expand Down
1 change: 1 addition & 0 deletions src/lib/dom.generated.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19105,6 +19105,7 @@ declare var ReadableStream: {
new(underlyingSource: UnderlyingByteSource, strategy?: { highWaterMark?: number }): ReadableStream<Uint8Array>;
new<R = any>(underlyingSource: UnderlyingDefaultSource<R>, strategy?: QueuingStrategy<R>): ReadableStream<R>;
new<R = any>(underlyingSource?: UnderlyingSource<R>, strategy?: QueuingStrategy<R>): ReadableStream<R>;
from<R>(asyncIterable: AsyncIterable<R> | Iterable<R | PromiseLike<R>>): ReadableStream<R>;
};

/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/ReadableStreamBYOBReader) */
Expand Down
2 changes: 1 addition & 1 deletion src/lib/es2020.intl.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ declare namespace Intl {
}

interface DateTimeFormatOptions {
calendar?: string | undefined;
calendar?: string | (typeof globalThis extends { Temporal: { CalendarProtocol: infer T; }; } ? T : undefined) | undefined;
dayPeriod?: "narrow" | "short" | "long" | undefined;
numberingSystem?: string | undefined;

Expand Down
Loading