diff --git a/Herebyfile.mjs b/Herebyfile.mjs
index 8447834a6338a..bd67e520c2351 100644
--- a/Herebyfile.mjs
+++ b/Herebyfile.mjs
@@ -1,6 +1,5 @@
// @ts-check
import { CancelToken } from "@esfx/canceltoken";
-import assert from "assert";
import chalk from "chalk";
import chokidar from "chokidar";
import esbuild from "esbuild";
@@ -172,7 +171,6 @@ async function runDtsBundler(entrypoint, output) {
* @param {BundlerTaskOptions} [taskOptions]
*
* @typedef BundlerTaskOptions
- * @property {boolean} [exportIsTsObject]
* @property {boolean} [treeShaking]
* @property {boolean} [usePublicAPI]
* @property {() => void} [onWatchRebuild]
@@ -180,17 +178,15 @@ async function runDtsBundler(entrypoint, output) {
function createBundler(entrypoint, outfile, taskOptions = {}) {
const getOptions = memoize(async () => {
const copyright = await getCopyrightHeader();
- const banner = taskOptions.exportIsTsObject ? "var ts = {}; ((module) => {" : "";
-
/** @type {esbuild.BuildOptions} */
const options = {
entryPoints: [entrypoint],
- banner: { js: copyright + banner },
+ banner: { js: copyright },
bundle: true,
outfile,
platform: "node",
target: ["es2020", "node14.17"],
- format: "cjs",
+ format: "esm",
sourcemap: "linked",
sourcesContent: false,
treeShaking: taskOptions.treeShaking,
@@ -200,66 +196,17 @@ function createBundler(entrypoint, outfile, taskOptions = {}) {
};
if (taskOptions.usePublicAPI) {
- options.external = ["./typescript.js"];
options.plugins = options.plugins || [];
options.plugins.push({
- name: "remap-typescript-to-require",
+ name: "remap-typescript-to-public-api",
setup(build) {
- build.onLoad({ filter: /src[\\/]typescript[\\/]typescript\.ts$/ }, () => {
- return { contents: `export * from "./typescript.js"` };
+ build.onResolve({ filter: /^(?:\.\.[\\/])*typescript[\\/]typescript\.js$/ }, () => {
+ return { path: "./typescript.js", external: true };
});
},
});
}
- if (taskOptions.exportIsTsObject) {
- // Monaco bundles us as ESM by wrapping our code with something that defines module.exports
- // but then does not use it, instead using the `ts` variable. Ensure that if we think we're CJS
- // that we still set `ts` to the module.exports object.
- options.footer = { js: `})(typeof module !== "undefined" && module.exports ? module : { exports: ts });\nif (typeof module !== "undefined" && module.exports) { ts = module.exports; }` };
-
- // esbuild converts calls to "require" to "__require"; this function
- // calls the real require if it exists, or throws if it does not (rather than
- // throwing an error like "require not defined"). But, since we want typescript
- // to be consumable by other bundlers, we need to convert these calls back to
- // require so our imports are visible again.
- //
- // To fix this, we redefine "require" to a name we're unlikely to use with the
- // same length as "require", then replace it back to "require" after bundling,
- // ensuring that source maps still work.
- //
- // See: https://github.com/evanw/esbuild/issues/1905
- const require = "require";
- const fakeName = "Q".repeat(require.length);
- const fakeNameRegExp = new RegExp(fakeName, "g");
- options.define = { [require]: fakeName };
-
- // For historical reasons, TypeScript does not set __esModule. Hack esbuild's __toCommonJS to be a noop.
- // We reference `__copyProps` to ensure the final bundle doesn't have any unreferenced code.
- const toCommonJsRegExp = /var __toCommonJS .*/;
- const toCommonJsRegExpReplacement = "var __toCommonJS = (mod) => (__copyProps, mod); // Modified helper to skip setting __esModule.";
-
- options.plugins = options.plugins || [];
- options.plugins.push(
- {
- name: "post-process",
- setup: build => {
- build.onEnd(async () => {
- let contents = await fs.promises.readFile(outfile, "utf-8");
- contents = contents.replace(fakeNameRegExp, require);
- let matches = 0;
- contents = contents.replace(toCommonJsRegExp, () => {
- matches++;
- return toCommonJsRegExpReplacement;
- });
- assert(matches === 1, "Expected exactly one match for __toCommonJS");
- await fs.promises.writeFile(outfile, contents);
- });
- },
- },
- );
- }
-
return options;
});
@@ -304,6 +251,7 @@ let printedWatchWarning = false;
* @param {string} options.builtEntrypoint
* @param {string} options.output
* @param {Task[]} [options.mainDeps]
+ * @param {boolean} [options.reexportDefault]
* @param {BundlerTaskOptions} [options.bundlerOptions]
*/
function entrypointBuildTask(options) {
@@ -324,13 +272,13 @@ function entrypointBuildTask(options) {
});
/**
- * Writes a CJS module that reexports another CJS file. E.g. given
+ * Writes a module that reexports another file. E.g. given
* `options.builtEntrypoint = "./built/local/tsc/tsc.js"` and
* `options.output = "./built/local/tsc.js"`, this will create a file
* named "./built/local/tsc.js" containing:
*
* ```
- * module.exports = require("./tsc/tsc.js")
+ * export * from "./tsc/tsc.js";
* ```
*/
const shim = task({
@@ -338,8 +286,19 @@ function entrypointBuildTask(options) {
run: async () => {
const outDir = path.dirname(options.output);
await fs.promises.mkdir(outDir, { recursive: true });
- const moduleSpecifier = path.relative(outDir, options.builtEntrypoint);
- await fs.promises.writeFile(options.output, `module.exports = require("./${moduleSpecifier.replace(/[\\/]/g, "/")}")`);
+ const moduleSpecifier = path.relative(outDir, options.builtEntrypoint).replace(/[\\/]/g, "/");
+ const lines = [
+ `export * from "./${moduleSpecifier}";`,
+ ];
+
+ if (options.reexportDefault) {
+ lines.push(
+ `import _default from "./${moduleSpecifier}";`,
+ `export default _default;`,
+ );
+ }
+
+ await fs.promises.writeFile(options.output, lines.join("\n") + "\n");
},
});
@@ -404,7 +363,7 @@ const { main: services, build: buildServices, watch: watchServices } = entrypoin
builtEntrypoint: "./built/local/typescript/typescript.js",
output: "./built/local/typescript.js",
mainDeps: [generateLibs],
- bundlerOptions: { exportIsTsObject: true },
+ reexportDefault: true,
});
export { services, watchServices };
@@ -445,25 +404,22 @@ export const watchMin = task({
dependencies: [watchTsc, watchTsserver],
});
-// This is technically not enough to make tsserverlibrary loadable in the
-// browser, but it's unlikely that anyone has actually been doing that.
const lsslJs = `
-if (typeof module !== "undefined" && module.exports) {
- module.exports = require("./typescript.js");
-}
-else {
- throw new Error("tsserverlibrary requires CommonJS; use typescript.js instead");
-}
+import ts from "./typescript.js";
+export * from "./typescript.js";
+export default ts;
`;
const lsslDts = `
-import ts = require("./typescript.js");
-export = ts;
+import ts from "./typescript.js";
+export * from "./typescript.js";
+export default ts;
`;
const lsslDtsInternal = `
-import ts = require("./typescript.internal.js");
-export = ts;
+import ts from "./typescript.internal.js";
+export * from "./typescript.internal.js";
+export default ts;
`;
/**
@@ -504,7 +460,7 @@ const { main: tests, watch: watchTests } = entrypointBuildTask({
description: "Builds the test infrastructure",
buildDeps: [generateDiagnostics],
project: "src/testRunner",
- srcEntrypoint: "./src/testRunner/_namespaces/Harness.ts",
+ srcEntrypoint: "./src/testRunner/runner.ts",
builtEntrypoint: "./built/local/testRunner/runner.js",
output: testRunner,
mainDeps: [generateLibs],
diff --git a/bin/tsc b/bin/tsc
index 19c62bf7a0004..bef1027ea20a1 100755
--- a/bin/tsc
+++ b/bin/tsc
@@ -1,2 +1,2 @@
#!/usr/bin/env node
-require('../lib/tsc.js')
+import '../lib/tsc.js';
diff --git a/bin/tsserver b/bin/tsserver
index 7143b6a73ab8a..d90c1a2ece3ff 100755
--- a/bin/tsserver
+++ b/bin/tsserver
@@ -1,2 +1,2 @@
#!/usr/bin/env node
-require('../lib/tsserver.js')
+import '../lib/tsserver.js';
diff --git a/package-lock.json b/package-lock.json
index 2c467651009a9..130c0800768d4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,7 @@
"@esfx/canceltoken": "^1.0.0",
"@octokit/rest": "^20.1.1",
"@types/chai": "^4.3.16",
+ "@types/diff": "^5.2.1",
"@types/microsoft__typescript-etw": "^0.1.3",
"@types/minimist": "^1.2.5",
"@types/mocha": "^10.0.6",
@@ -976,6 +977,12 @@
"integrity": "sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ==",
"dev": true
},
+ "node_modules/@types/diff": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.2.1.tgz",
+ "integrity": "sha512-uxpcuwWJGhe2AR1g8hD9F5OYGCqjqWnBUQFD8gMZsDbv8oPHzxJF6iMO6n8Tk0AdzlxoaaoQhOYlIg/PukVU8g==",
+ "dev": true
+ },
"node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
@@ -5011,6 +5018,12 @@
"integrity": "sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ==",
"dev": true
},
+ "@types/diff": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.2.1.tgz",
+ "integrity": "sha512-uxpcuwWJGhe2AR1g8hD9F5OYGCqjqWnBUQFD8gMZsDbv8oPHzxJF6iMO6n8Tk0AdzlxoaaoQhOYlIg/PukVU8g==",
+ "dev": true
+ },
"@types/istanbul-lib-coverage": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
diff --git a/package.json b/package.json
index 4b300c1a0d6c5..a7389f387e60a 100644
--- a/package.json
+++ b/package.json
@@ -43,6 +43,7 @@
"@esfx/canceltoken": "^1.0.0",
"@octokit/rest": "^20.1.1",
"@types/chai": "^4.3.16",
+ "@types/diff": "^5.2.1",
"@types/microsoft__typescript-etw": "^0.1.3",
"@types/minimist": "^1.2.5",
"@types/mocha": "^10.0.6",
diff --git a/patchProcessGetBuiltin.cjs b/patchProcessGetBuiltin.cjs
new file mode 100644
index 0000000000000..f147fca8b3cb6
--- /dev/null
+++ b/patchProcessGetBuiltin.cjs
@@ -0,0 +1,9 @@
+const _module = require("module");
+
+/** @type {(name: string) => any} */
+function getBuiltinModule(name) {
+ if (!_module.isBuiltin(name)) return undefined;
+ return require(name);
+}
+
+process.getBuiltinModule = getBuiltinModule;
diff --git a/scripts/browserIntegrationTest.mjs b/scripts/browserIntegrationTest.mjs
index f1fab43f2213c..f67f84105bcc1 100644
--- a/scripts/browserIntegrationTest.mjs
+++ b/scripts/browserIntegrationTest.mjs
@@ -28,7 +28,7 @@ for (const browserType of browsers) {
await page.setContent(`
-
+
`);
diff --git a/scripts/checkModuleFormat.mjs b/scripts/checkModuleFormat.mjs
index ed33b5fb00382..d6ab73eaf624a 100644
--- a/scripts/checkModuleFormat.mjs
+++ b/scripts/checkModuleFormat.mjs
@@ -19,7 +19,7 @@ console.log(`Testing ${typescript}...`);
/** @type {[fn: (() => Promise), shouldSucceed: boolean][]} */
const fns = [
[() => require(typescript).version, true],
- [() => require(typescript).default.version, false],
+ [() => require(typescript).default.version, true],
[() => __importDefault(require(typescript)).version, false],
[() => __importDefault(require(typescript)).default.version, true],
[() => __importStar(require(typescript)).version, true],
diff --git a/scripts/dtsBundler.mjs b/scripts/dtsBundler.mjs
index e7ace12303e1d..b14e39992cd0d 100644
--- a/scripts/dtsBundler.mjs
+++ b/scripts/dtsBundler.mjs
@@ -357,6 +357,8 @@ function isSelfReference(reference, symbol) {
* @param {ts.Symbol} moduleSymbol
*/
function emitAsNamespace(name, parent, moduleSymbol, needExportModifier) {
+ if (name === "default") return;
+
assert(moduleSymbol.flags & ts.SymbolFlags.ValueModule, "moduleSymbol is not a module");
const fullName = parent ? `${parent}.${name}` : name;
@@ -465,6 +467,7 @@ function emitAsNamespace(name, parent, moduleSymbol, needExportModifier) {
emitAsNamespace("ts", "", moduleSymbol, /*needExportModifier*/ false);
+// TODO(jakebailey): require(ESM) - fix this
write("export = ts;", WriteTarget.Both);
const copyrightNotice = fs.readFileSync(path.join(__dirname, "CopyrightNotice.txt"), "utf-8");
diff --git a/src/.eslintrc.json b/src/.eslintrc.json
index 697574c6a8ec5..3684d3c6fc87a 100644
--- a/src/.eslintrc.json
+++ b/src/.eslintrc.json
@@ -14,7 +14,10 @@
{ "name": "clearInterval" },
{ "name": "setImmediate" },
{ "name": "clearImmediate" },
- { "name": "performance" }
+ { "name": "performance" },
+ { "name": "require" },
+ { "name": "__dirname" },
+ { "name": "__filename" }
]
},
"overrides": [
diff --git a/src/cancellationToken/cancellationToken.ts b/src/cancellationToken/cancellationToken.ts
index 4676e9b14e0a3..97c5c7f0612fd 100644
--- a/src/cancellationToken/cancellationToken.ts
+++ b/src/cancellationToken/cancellationToken.ts
@@ -17,7 +17,7 @@ function pipeExists(name: string): boolean {
return fs.existsSync(name);
}
-function createCancellationToken(args: string[]): ServerCancellationToken {
+export function createCancellationToken(args: string[]): ServerCancellationToken {
let cancellationPipeName: string | undefined;
for (let i = 0; i < args.length - 1; i++) {
if (args[i] === "--cancellationPipeName") {
@@ -66,4 +66,3 @@ function createCancellationToken(args: string[]): ServerCancellationToken {
};
}
}
-export = createCancellationToken;
diff --git a/src/compiler/core.ts b/src/compiler/core.ts
index d7f6fe0580d5f..a9005487dd901 100644
--- a/src/compiler/core.ts
+++ b/src/compiler/core.ts
@@ -2730,5 +2730,5 @@ export function isNodeLikeSystem(): boolean {
return typeof process !== "undefined"
&& !!process.nextTick
&& !(process as any).browser
- && typeof require !== "undefined";
+ && typeof (process as any).getBuiltinModule === "function";
}
diff --git a/src/compiler/nodeGetBuiltinModule.ts b/src/compiler/nodeGetBuiltinModule.ts
new file mode 100644
index 0000000000000..e8c26c8df53e8
--- /dev/null
+++ b/src/compiler/nodeGetBuiltinModule.ts
@@ -0,0 +1,12 @@
+export function nodeCreateRequire(path: string): NodeJS.Require {
+ const mod = nodeGetBuiltinModule("module") as typeof import("module") | undefined;
+ if (!mod) throw new Error("missing node:module");
+ return mod.createRequire(path);
+}
+
+function nodeGetBuiltinModule(moduleName: string): unknown {
+ if (typeof process === "undefined" || typeof (process as any).getBuiltinModule !== "function") {
+ throw new Error("process.getBuiltinModule is not supported in this environment.");
+ }
+ return (process as any).getBuiltinModule(moduleName);
+}
diff --git a/src/compiler/perfLogger.ts b/src/compiler/perfLogger.ts
index f2476db967541..f02e8eb2c366c 100644
--- a/src/compiler/perfLogger.ts
+++ b/src/compiler/perfLogger.ts
@@ -1,3 +1,5 @@
+import { nodeCreateRequire } from "./nodeGetBuiltinModule.js";
+
/** @internal */
export interface PerfLogger {
logEvent(msg: string): void;
@@ -27,6 +29,7 @@ export interface PerfLogger {
let etwModule: typeof import("@microsoft/typescript-etw") | undefined;
try {
const etwModulePath = process.env.TS_ETW_MODULE_PATH ?? "./node_modules/@microsoft/typescript-etw";
+ const require = nodeCreateRequire(import.meta.url);
// require() will throw an exception if the module is not found
// It may also return undefined if not installed properly
diff --git a/src/compiler/performanceCore.ts b/src/compiler/performanceCore.ts
index abff50eb8aae6..4086e39116ef1 100644
--- a/src/compiler/performanceCore.ts
+++ b/src/compiler/performanceCore.ts
@@ -1,4 +1,5 @@
import { isNodeLikeSystem } from "./_namespaces/ts.js";
+import { nodeCreateRequire } from "./nodeGetBuiltinModule.js";
// The following definitions provide the minimum compatible support for the Web Performance User Timings API
// between browsers and NodeJS:
@@ -31,7 +32,8 @@ function tryGetPerformance() {
if (isNodeLikeSystem()) {
try {
// By default, only write native events when generating a cpu profile or using the v8 profiler.
- const { performance } = require("perf_hooks") as typeof import("perf_hooks");
+ const require = nodeCreateRequire(import.meta.url);
+ const { performance } = require("perf_hooks");
return {
shouldWriteNativeEvents: false,
performance,
diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts
index a8fdd4d156822..66aa231b71e92 100644
--- a/src/compiler/sys.ts
+++ b/src/compiler/sys.ts
@@ -47,6 +47,7 @@ import {
WatchOptions,
writeFileEnsuringDirectories,
} from "./_namespaces/ts.js";
+import { nodeCreateRequire } from "./nodeGetBuiltinModule.js";
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
declare function clearTimeout(handle: any): void;
@@ -1466,9 +1467,15 @@ export let sys: System = (() => {
const byteOrderMarkIndicator = "\uFEFF";
function getNodeSystem(): System {
+ // TODO(jakebailey): Only use createRequire for sys.require.
+ const require = nodeCreateRequire(import.meta.url);
+ const _path: typeof import("path") = require("path");
+ const _url: typeof import("url") = require("url");
+ const __filename = _url.fileURLToPath(new URL(import.meta.url));
+ const __dirname = _path.dirname(__filename);
+
const nativePattern = /^native |^\([^)]+\)$|^(internal[\\/]|[a-zA-Z0-9_\s]+(\.js)?$)/;
const _fs: typeof import("fs") = require("fs");
- const _path: typeof import("path") = require("path");
const _os = require("os");
// crypto can be absent on reduced node installations
let _crypto: typeof import("crypto") | undefined;
diff --git a/src/compiler/tracing.ts b/src/compiler/tracing.ts
index 94e9bd57c83b6..985ac39753775 100644
--- a/src/compiler/tracing.ts
+++ b/src/compiler/tracing.ts
@@ -22,6 +22,7 @@ import {
UnionType,
} from "./_namespaces/ts.js";
import * as performance from "./_namespaces/ts.performance.js";
+import { nodeCreateRequire } from "./nodeGetBuiltinModule.js";
/* Tracing events for the compiler. */
@@ -60,6 +61,7 @@ export namespace tracingEnabled {
if (fs === undefined) {
try {
+ const require = nodeCreateRequire(import.meta.url);
fs = require("fs");
}
catch (e) {
diff --git a/src/harness/findUpDir.ts b/src/harness/findUpDir.ts
index 20b1afe414ece..29008b44726be 100644
--- a/src/harness/findUpDir.ts
+++ b/src/harness/findUpDir.ts
@@ -4,10 +4,14 @@ import {
join,
resolve,
} from "path";
+import { fileURLToPath } from "url";
// search directories upward to avoid hard-wired paths based on the
// build tree (same as scripts/build/findUpDir.js)
+const __filename = fileURLToPath(new URL(import.meta.url));
+const __dirname = dirname(__filename);
+
export function findUpFile(name: string): string {
let dir = __dirname;
while (true) {
diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts
index 6c7a14535d2c5..2f9a3125dd52f 100644
--- a/src/harness/fourslashImpl.ts
+++ b/src/harness/fourslashImpl.ts
@@ -1,3 +1,4 @@
+import sourceMapSupport from "source-map-support";
import * as fakes from "./_namespaces/fakes.js";
import * as FourSlashInterface from "./_namespaces/FourSlashInterface.js";
import * as Harness from "./_namespaces/Harness.js";
@@ -4582,22 +4583,9 @@ function runCode(code: string, state: TestState, fileName: string): void {
const generatedFile = ts.changeExtension(fileName, ".js");
const wrappedCode = `(function(ts, test, goTo, config, verify, edit, debug, format, cancellation, classification, completion, verifyOperationIsCancelled, ignoreInterpolations) {${code}\n//# sourceURL=${ts.getBaseFileName(generatedFile)}\n})`;
- type SourceMapSupportModule = typeof import("source-map-support") & {
- // TODO(rbuckton): This is missing from the DT definitions and needs to be added.
- resetRetrieveHandlers(): void;
- };
-
// Provide the content of the current test to 'source-map-support' so that it can give us the correct source positions
// for test failures.
- let sourceMapSupportModule: SourceMapSupportModule | undefined;
- try {
- sourceMapSupportModule = require("source-map-support");
- }
- catch {
- // do nothing
- }
-
- sourceMapSupportModule?.install({
+ sourceMapSupport?.install({
retrieveFile: path => {
return path === generatedFile ? wrappedCode :
undefined!;
@@ -4623,7 +4611,7 @@ function runCode(code: string, state: TestState, fileName: string): void {
throw err;
}
finally {
- sourceMapSupportModule?.resetRetrieveHandlers();
+ sourceMapSupport?.resetRetrieveHandlers();
}
}
diff --git a/src/harness/harnessIO.ts b/src/harness/harnessIO.ts
index fb0a80b71d457..4c00f974c79d7 100644
--- a/src/harness/harnessIO.ts
+++ b/src/harness/harnessIO.ts
@@ -1,3 +1,6 @@
+import * as Diff from "diff";
+import fs from "fs";
+import pathModule from "path";
import * as compiler from "./_namespaces/compiler.js";
import * as documents from "./_namespaces/documents.js";
import * as fakes from "./_namespaces/fakes.js";
@@ -54,14 +57,6 @@ export const virtualFileSystemRoot = "/";
function createNodeIO(): IO {
const workspaceRoot = Utils.findUpRoot();
- let fs: any, pathModule: any;
- if (require) {
- fs = require("fs");
- pathModule = require("path");
- }
- else {
- fs = pathModule = {};
- }
function deleteFile(path: string) {
try {
@@ -1018,7 +1013,6 @@ export namespace Compiler {
}
else if (original.text !== doc.text) {
jsCode += `\r\n\r\n!!!! File ${Utils.removeTestPathPrefixes(doc.file)} differs from original emit in noCheck emit\r\n`;
- const Diff = require("diff");
const expected = original.text;
const actual = doc.text;
const patch = Diff.createTwoFilesPatch("Expected", "Actual", expected, actual, "The full check baseline", "with noCheck set");
@@ -1514,8 +1508,7 @@ export namespace Baseline {
IO.writeFile(actualFileName, encodedActual);
}
const errorMessage = getBaselineFileChangedErrorMessage(relativeFileName);
- if (!!require && opts && opts.PrintDiff) {
- const Diff = require("diff");
+ if (opts && opts.PrintDiff) {
const patch = Diff.createTwoFilesPatch("Expected", "Actual", expected, actual, "The current baseline", "The new version");
throw new Error(`${errorMessage}${ts.ForegroundColorEscapeSequences.Grey}\n\n${patch}`);
}
diff --git a/src/harness/harnessUtils.ts b/src/harness/harnessUtils.ts
index d7989da8d6980..b049c51d5f416 100644
--- a/src/harness/harnessUtils.ts
+++ b/src/harness/harnessUtils.ts
@@ -1,3 +1,4 @@
+import vm from "vm";
import * as Harness from "./_namespaces/Harness.js";
import * as ts from "./_namespaces/ts.js";
@@ -6,7 +7,6 @@ export function encodeString(s: string): string {
}
export function evalFile(fileContents: string, fileName: string, nodeContext?: any) {
- const vm = require("vm");
if (nodeContext) {
vm.runInNewContext(fileContents, nodeContext, fileName);
}
diff --git a/src/testRunner/parallel/host.ts b/src/testRunner/parallel/host.ts
index cbfc9b391c491..f6b1159b969c9 100644
--- a/src/testRunner/parallel/host.ts
+++ b/src/testRunner/parallel/host.ts
@@ -1,3 +1,11 @@
+import { fork } from "child_process";
+import { statSync } from "fs";
+import Mocha from "mocha";
+import ms from "ms";
+import os from "os";
+import path from "path";
+import readline from "readline";
+import tty from "tty";
import {
configOption,
globalTimeout,
@@ -25,21 +33,16 @@ import {
import * as ts from "../_namespaces/ts.js";
import * as Utils from "../_namespaces/Utils.js";
+import { createRequire } from "module";
+const require = createRequire(import.meta.url);
+
export function start(importTests: () => Promise) {
- const Mocha = require("mocha") as typeof import("mocha");
const Base = Mocha.reporters.Base;
const color = Base.color;
const cursor = Base.cursor;
- const ms = require("ms") as typeof import("ms");
- const readline = require("readline") as typeof import("readline");
- const os = require("os") as typeof import("os");
- const tty = require("tty") as typeof import("tty");
const isatty = tty.isatty(1) && tty.isatty(2);
- const path = require("path") as typeof import("path");
- const { fork } = require("child_process") as typeof import("child_process");
- const { statSync } = require("fs") as typeof import("fs");
- // NOTE: paths for module and types for FailedTestReporter _do not_ line up due to our use of --outFile for run.js
+ // NOTE: paths for module and types for FailedTestReporter _do not_ line up when bundled
const FailedTestReporter = require(Utils.findUpFile("scripts/failed-tests.cjs")) as typeof import("../../../scripts/failed-tests.cjs");
const perfdataFileNameFragment = ".parallelperf";
diff --git a/src/testRunner/parallel/worker.ts b/src/testRunner/parallel/worker.ts
index 4b61633e45a53..23c089ef35411 100644
--- a/src/testRunner/parallel/worker.ts
+++ b/src/testRunner/parallel/worker.ts
@@ -1,3 +1,4 @@
+import Mocha from "mocha";
import {
createRunner,
globalTimeout,
@@ -39,9 +40,6 @@ export function start(importTests: () => Promise) {
let exceptionsHooked = false;
hookUncaughtExceptions();
- // Capitalization is aligned with the global `Mocha` namespace for typespace/namespace references.
- const Mocha = require("mocha") as typeof import("mocha");
-
/**
* Mixin helper.
* @param base The base class constructor.
diff --git a/src/testRunner/unittests/skipJSDocParsing.ts b/src/testRunner/unittests/skipJSDocParsing.ts
index 4fd6e87819628..45c4e67881e8c 100644
--- a/src/testRunner/unittests/skipJSDocParsing.ts
+++ b/src/testRunner/unittests/skipJSDocParsing.ts
@@ -1,10 +1,9 @@
+import * as Diff from "diff";
import * as Harness from "../_namespaces/Harness.js";
import * as ts from "../_namespaces/ts.js";
import * as Utils from "../_namespaces/Utils.js";
describe("unittests:: skipJSDocParsing", () => {
- const Diff = require("diff");
-
const kinds = [
ts.JSDocParsingMode.ParseAll,
ts.JSDocParsingMode.ParseForTypeErrors,
diff --git a/src/tsserver/nodeServer.ts b/src/tsserver/nodeServer.ts
index 280b0d3b630df..a3429a3ebe7a4 100644
--- a/src/tsserver/nodeServer.ts
+++ b/src/tsserver/nodeServer.ts
@@ -1,3 +1,9 @@
+import childProcess from "child_process";
+import fs from "fs";
+import net from "net";
+import os from "os";
+import readline from "readline";
+import { nodeCreateRequire } from "../compiler/nodeGetBuiltinModule.js";
import {
CharacterCodes,
combinePaths,
@@ -9,7 +15,6 @@ import {
getDirectoryPath,
getRootLength,
LanguageServiceMode,
- MapLike,
noop,
noopFileWatcher,
normalizePath,
@@ -38,24 +43,6 @@ interface LogOptions {
logToFile?: boolean;
}
-interface NodeChildProcess {
- send(message: any, sendHandle?: any): void;
- on(message: "message" | "exit", f: (m: any) => void): void;
- kill(): void;
- pid: number;
-}
-
-interface ReadLineOptions {
- input: NodeJS.ReadableStream;
- output?: NodeJS.WritableStream;
- terminal?: boolean;
- historySize?: number;
-}
-
-interface NodeSocket {
- write(data: string, encoding: string): boolean;
-}
-
function parseLoggingEnvironmentString(logEnvStr: string | undefined): LogOptions {
if (!logEnvStr) {
return {};
@@ -124,41 +111,6 @@ function parseServerMode(): LanguageServiceMode | string | undefined {
/** @internal */
export function initializeNodeSystem(): StartInput {
const sys = Debug.checkDefined(ts.sys) as ts.server.ServerHost;
- const childProcess: {
- execFileSync(file: string, args: string[], options: { stdio: "ignore"; env: MapLike; }): string | Buffer;
- } = require("child_process");
-
- interface Stats {
- isFile(): boolean;
- isDirectory(): boolean;
- isBlockDevice(): boolean;
- isCharacterDevice(): boolean;
- isSymbolicLink(): boolean;
- isFIFO(): boolean;
- isSocket(): boolean;
- dev: number;
- ino: number;
- mode: number;
- nlink: number;
- uid: number;
- gid: number;
- rdev: number;
- size: number;
- blksize: number;
- blocks: number;
- atime: Date;
- mtime: Date;
- ctime: Date;
- birthtime: Date;
- }
-
- const fs: {
- openSync(path: string, options: string): number;
- close(fd: number, callback: (err: NodeJS.ErrnoException) => void): void;
- writeSync(fd: number, buffer: Buffer, offset: number, length: number, position?: number): number;
- statSync(path: string): Stats;
- stat(path: string, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void;
- } = require("fs");
class Logger implements Logger {
private seq = 0;
@@ -244,7 +196,7 @@ export function initializeNodeSystem(): StartInput {
if (this.fd >= 0) {
const buf = Buffer.from(s);
// eslint-disable-next-line no-restricted-syntax
- fs.writeSync(this.fd, buf, 0, buf.length, /*position*/ null!); // TODO: GH#18217
+ fs.writeSync(this.fd, buf, 0, buf.length, /*position*/ null); // TODO: GH#18217
}
if (this.traceToConsole) {
console.warn(s);
@@ -339,8 +291,9 @@ export function initializeNodeSystem(): StartInput {
let cancellationToken: ts.server.ServerCancellationToken;
try {
- const factory = require("./cancellationToken");
- cancellationToken = factory(sys.args);
+ const require = nodeCreateRequire(import.meta.url);
+ const { createCancellationToken } = require("./cancellationToken.js");
+ cancellationToken = createCancellationToken(sys.args);
}
catch (e) {
cancellationToken = ts.server.nullCancellationToken;
@@ -452,23 +405,6 @@ function parseEventPort(eventPortStr: string | undefined) {
return eventPort !== undefined && !isNaN(eventPort) ? eventPort : undefined;
}
function startNodeSession(options: StartSessionOptions, logger: ts.server.Logger, cancellationToken: ts.server.ServerCancellationToken) {
- const childProcess: {
- fork(modulePath: string, args: string[], options?: { execArgv: string[]; env?: MapLike; }): NodeChildProcess;
- } = require("child_process");
-
- const os: {
- homedir?(): string;
- tmpdir(): string;
- } = require("os");
-
- const net: {
- connect(options: { port: number; }, onConnect?: () => void): NodeSocket;
- } = require("net");
-
- const readline: {
- createInterface(options: ReadLineOptions): NodeJS.EventEmitter;
- } = require("readline");
-
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
@@ -476,7 +412,7 @@ function startNodeSession(options: StartSessionOptions, logger: ts.server.Logger
});
class NodeTypingsInstallerAdapter extends ts.server.TypingsInstallerAdapter {
- protected override installer!: NodeChildProcess;
+ protected override installer!: childProcess.ChildProcess;
// This number is essentially arbitrary. Processing more than one typings request
// at a time makes sense, but having too many in the pipe results in a hang
// (see https://github.com/nodejs/node/issues/7657).
@@ -546,7 +482,7 @@ function startNodeSession(options: StartSessionOptions, logger: ts.server.Logger
const typingsInstaller = combinePaths(getDirectoryPath(sys.getExecutingFilePath()), "typingsInstaller.js");
this.installer = childProcess.fork(typingsInstaller, args, { execArgv });
- this.installer.on("message", m => this.handleMessage(m));
+ this.installer.on("message", m => this.handleMessage(m as any));
// We have to schedule this event to the next tick
// cause this fn will be called during
@@ -563,7 +499,7 @@ function startNodeSession(options: StartSessionOptions, logger: ts.server.Logger
class IOSession extends ts.server.Session {
private eventPort: number | undefined;
- private eventSocket: NodeSocket | undefined;
+ private eventSocket: net.Socket | undefined;
private socketEventQueue: { body: any; eventName: string; }[] | undefined;
/** No longer needed if syntax target is es6 or above. Any access to "this" before initialized will be a runtime error. */
private constructed: boolean | undefined;
diff --git a/src/tsserver/server.ts b/src/tsserver/server.ts
index dac80d8496f2f..d74ca4f04d645 100644
--- a/src/tsserver/server.ts
+++ b/src/tsserver/server.ts
@@ -1,3 +1,4 @@
+import os from "os";
import * as ts from "../typescript/typescript.js";
import { StartInput } from "./common.js";
import { initializeNodeSystem } from "./nodeServer.js";
@@ -53,4 +54,4 @@ function start({ args, logger, cancellationToken, serverMode, unknownServerMode,
}
ts.setStackTraceLimit();
-start(initializeNodeSystem(), require("os").platform());
+start(initializeNodeSystem(), os.platform());
diff --git a/src/typescript/typescript.ts b/src/typescript/typescript.ts
index 9e54bbe9c15b0..fa83f781938b1 100644
--- a/src/typescript/typescript.ts
+++ b/src/typescript/typescript.ts
@@ -23,3 +23,5 @@ if (typeof console !== "undefined") {
}
export * from "./_namespaces/ts.js";
+import * as ts from "./_namespaces/ts.js";
+export default ts;
diff --git a/src/typingsInstaller/nodeTypingsInstaller.ts b/src/typingsInstaller/nodeTypingsInstaller.ts
index 836b64473cb05..984d7b80c5b7e 100644
--- a/src/typingsInstaller/nodeTypingsInstaller.ts
+++ b/src/typingsInstaller/nodeTypingsInstaller.ts
@@ -1,3 +1,4 @@
+import { execFileSync } from "child_process";
import * as fs from "fs";
import * as path from "path";
@@ -79,10 +80,8 @@ interface ExecSyncOptions {
cwd: string;
encoding: "utf-8";
}
-type ExecSync = (command: string, options: ExecSyncOptions) => string;
export class NodeTypingsInstaller extends ts.server.typingsInstaller.TypingsInstaller {
- private readonly nodeExecSync: ExecSync;
private readonly npmPath: string;
readonly typesRegistry: Map>;
@@ -109,7 +108,6 @@ export class NodeTypingsInstaller extends ts.server.typingsInstaller.TypingsInst
this.log.writeLine(`NPM location: ${this.npmPath} (explicit '${ts.server.Arguments.NpmLocation}' ${npmLocation === undefined ? "not " : ""} provided)`);
this.log.writeLine(`validateDefaultNpmLocation: ${validateDefaultNpmLocation}`);
}
- ({ execSync: this.nodeExecSync } = require("child_process"));
this.ensurePackageDirectoryExists(globalTypingsCacheLocation);
@@ -174,7 +172,7 @@ export class NodeTypingsInstaller extends ts.server.typingsInstaller.TypingsInst
this.log.writeLine(`Exec: ${command}`);
}
try {
- const stdout = this.nodeExecSync(command, { ...options, encoding: "utf-8" });
+ const stdout = execFileSync(command, { ...options, encoding: "utf-8" });
if (this.log.isEnabled()) {
this.log.writeLine(` Succeeded. stdout:${indent(sys.newLine, stdout)}`);
}
diff --git a/testImportESM.mjs b/testImportESM.mjs
new file mode 100644
index 0000000000000..d4f29ec3a001a
--- /dev/null
+++ b/testImportESM.mjs
@@ -0,0 +1,5 @@
+import * as ts from "./built/local/typescript.js";
+import ts2 from "./built/local/typescript.js";
+
+console.log(ts.version);
+console.log(ts2.version);
diff --git a/testRequireESM.cjs b/testRequireESM.cjs
new file mode 100644
index 0000000000000..d6c1afae10252
--- /dev/null
+++ b/testRequireESM.cjs
@@ -0,0 +1,2 @@
+const ts = require("./built/local/typescript.js");
+console.log(ts.version);
diff --git a/tests/baselines/reference/APILibCheck.errors.txt b/tests/baselines/reference/APILibCheck.errors.txt
new file mode 100644
index 0000000000000..1dd48855ecd32
--- /dev/null
+++ b/tests/baselines/reference/APILibCheck.errors.txt
@@ -0,0 +1,48 @@
+tsserverlibrary.d.ts(17,15): error TS2498: Module '"typescript"' uses 'export =' and cannot be used with 'export *'.
+tsserverlibrary.internal.d.ts(17,15): error TS2498: Module '"typescript.internal"' uses 'export =' and cannot be used with 'export *'.
+
+
+==== node_modules/typescript/package.json (0 errors) ====
+ {
+ "name": "typescript",
+ "type": "module",
+ "exports": "./lib/typescript.d.ts"
+ }
+
+==== node_modules/typescript-internal/package.json (0 errors) ====
+ {
+ "name": "typescript-internal",
+ "type": "module",
+ "exports": "./lib/typescript.internal.d.ts"
+ }
+
+==== node_modules/tsserverlibrary/package.json (0 errors) ====
+ {
+ "name": "tsserverlibrary",
+ "type": "module",
+ "exports": "./lib/tsserverlibrary.d.ts"
+ }
+
+==== node_modules/tsserverlibrary-internal/package.json (0 errors) ====
+ {
+ "name": "tsserverlibrary-internal",
+ "type": "module",
+ "exports": "./lib/tsserverlibrary.internal.d.ts"
+ }
+
+==== package.json (0 errors) ====
+ {
+ "name": "project",
+ "type": "module"
+ }
+
+==== index.ts (0 errors) ====
+ import * as ts from "typescript";
+ import tsDefault from "typescript";
+ import * as tsInternal from "typescript-internal";
+ import tsInternalDefault from "typescript-internal";
+ import * as tsserverlibrary from "tsserverlibrary";
+ import tsserverlibraryDefault from "tsserverlibrary";
+ import * as tsserverlibraryInternal from "tsserverlibrary-internal";
+ import tsserverlibraryInternalDefault from "tsserverlibrary-internal";
+
\ No newline at end of file
diff --git a/tests/baselines/reference/APILibCheck.js b/tests/baselines/reference/APILibCheck.js
index 76bacfbf7a675..4e5c1eeff1759 100644
--- a/tests/baselines/reference/APILibCheck.js
+++ b/tests/baselines/reference/APILibCheck.js
@@ -3,34 +3,47 @@
//// [package.json]
{
"name": "typescript",
- "types": "/.ts/typescript.d.ts"
+ "type": "module",
+ "exports": "./lib/typescript.d.ts"
}
//// [package.json]
{
"name": "typescript-internal",
- "types": "/.ts/typescript.internal.d.ts"
+ "type": "module",
+ "exports": "./lib/typescript.internal.d.ts"
}
//// [package.json]
{
"name": "tsserverlibrary",
- "types": "/.ts/tsserverlibrary.d.ts"
+ "type": "module",
+ "exports": "./lib/tsserverlibrary.d.ts"
}
//// [package.json]
{
"name": "tsserverlibrary-internal",
- "types": "/.ts/tsserverlibrary.internal.d.ts"
+ "type": "module",
+ "exports": "./lib/tsserverlibrary.internal.d.ts"
+}
+
+//// [package.json]
+{
+ "name": "project",
+ "type": "module"
}
//// [index.ts]
-import ts = require("typescript");
-import tsInternal = require("typescript-internal");
-import tsserverlibrary = require("tsserverlibrary");
-import tsserverlibraryInternal = require("tsserverlibrary-internal");
+import * as ts from "typescript";
+import tsDefault from "typescript";
+import * as tsInternal from "typescript-internal";
+import tsInternalDefault from "typescript-internal";
+import * as tsserverlibrary from "tsserverlibrary";
+import tsserverlibraryDefault from "tsserverlibrary";
+import * as tsserverlibraryInternal from "tsserverlibrary-internal";
+import tsserverlibraryInternalDefault from "tsserverlibrary-internal";
//// [index.js]
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
+export {};
diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts
index 3db5faa718232..5f60c7df8eeb4 100644
--- a/tests/baselines/reference/api/tsserverlibrary.d.ts
+++ b/tests/baselines/reference/api/tsserverlibrary.d.ts
@@ -13,5 +13,6 @@ See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
-import ts = require("./typescript.js");
-export = ts;
+import ts from "./typescript.js";
+export * from "./typescript.js";
+export default ts;
diff --git a/tests/cases/compiler/APILibCheck.ts b/tests/cases/compiler/APILibCheck.ts
index 7abf10e9821e9..c2805372e7106 100644
--- a/tests/cases/compiler/APILibCheck.ts
+++ b/tests/cases/compiler/APILibCheck.ts
@@ -1,36 +1,54 @@
-// @module: commonjs
+// @module: nodenext
// @noImplicitAny: true
// @strictNullChecks: true
// @lib: es2018
// @exactOptionalPropertyTypes: true
// @noTypesAndSymbols: true
+// @link: /.ts/typescript.d.ts -> node_modules/typescript/lib/typescript.d.ts
// @filename: node_modules/typescript/package.json
{
"name": "typescript",
- "types": "/.ts/typescript.d.ts"
+ "type": "module",
+ "exports": "./lib/typescript.d.ts"
}
+// @link: /.ts/typescript.internal.d.ts -> node_modules/typescript-internal/lib/typescript.internal.d.ts
// @filename: node_modules/typescript-internal/package.json
{
"name": "typescript-internal",
- "types": "/.ts/typescript.internal.d.ts"
+ "type": "module",
+ "exports": "./lib/typescript.internal.d.ts"
}
+// @link: /.ts/tsserverlibrary.d.ts -> node_modules/tsserverlibrary/lib/tsserverlibrary.d.ts
// @filename: node_modules/tsserverlibrary/package.json
{
"name": "tsserverlibrary",
- "types": "/.ts/tsserverlibrary.d.ts"
+ "type": "module",
+ "exports": "./lib/tsserverlibrary.d.ts"
}
+// @link: /.ts/tsserverlibrary.internal.d.ts -> node_modules/tsserverlibrary-internal/lib/tsserverlibrary.internal.d.ts
// @filename: node_modules/tsserverlibrary-internal/package.json
{
"name": "tsserverlibrary-internal",
- "types": "/.ts/tsserverlibrary.internal.d.ts"
+ "type": "module",
+ "exports": "./lib/tsserverlibrary.internal.d.ts"
+}
+
+// @filename: package.json
+{
+ "name": "project",
+ "type": "module"
}
// @filename: index.ts
-import ts = require("typescript");
-import tsInternal = require("typescript-internal");
-import tsserverlibrary = require("tsserverlibrary");
-import tsserverlibraryInternal = require("tsserverlibrary-internal");
+import * as ts from "typescript";
+import tsDefault from "typescript";
+import * as tsInternal from "typescript-internal";
+import tsInternalDefault from "typescript-internal";
+import * as tsserverlibrary from "tsserverlibrary";
+import tsserverlibraryDefault from "tsserverlibrary";
+import * as tsserverlibraryInternal from "tsserverlibrary-internal";
+import tsserverlibraryInternalDefault from "tsserverlibrary-internal";