Skip to content

Convert TypeScript sources to NodeNext ESM - #9617

Closed
dibarbet wants to merge 3 commits into
dibarbet-esm-tooling-foundationfrom
dibarbet-esm-nodenext-conversion
Closed

Convert TypeScript sources to NodeNext ESM#9617
dibarbet wants to merge 3 commits into
dibarbet-esm-tooling-foundationfrom
dibarbet-esm-nodenext-conversion

Conversation

@dibarbet

@dibarbet dibarbet commented Aug 3, 2026

Copy link
Copy Markdown
Member

Summary

  • mark the package as ESM and convert first-party TypeScript away from CommonJS globals and module patterns
  • upgrade TypeScript from 5.6.2 to 5.7.3 and enable rewriteRelativeImportExtensions while retaining module/moduleResolution: NodeNext
  • write relative first-party imports with their actual .ts source extensions; TypeScript rewrites them to .js throughout out/, including all directly loaded VS Code integration entries
  • preserve six intentional .mjs support imports, Jest’s required transformed-.js source mapper, runtime-correct CJS interop, existing output/copy behavior, and the bundle-level createRequire(import.meta.url) bridge
  • remove the temporary bundle __filename/__dirname shim now that all first-party usages use import.meta.url

Validation

  • npm run compileDev
  • emitted-output audit: zero relative .ts imports and correct .js integration-runner imports
  • raw Node import of all four emitted integration entry points
  • npm run test:unit (11 suites, 514 tests, 350 snapshots)
  • npm run packageDev and node --check dist/extension.mjs
  • npm run test:integration:untrusted (1 test)
  • npm run test:integration:csharp (21 suites, 73 passed, 3 skipped)
  • OmniSharp unit project (37 suites, 401 tests)
  • source audit: 1,449 relative .ts imports, six intentional .mjs imports, zero extensionless/.js/.cjs source imports, and no __filename/__dirname source or banner definitions

@dibarbet
dibarbet requested review from a team as code owners August 3, 2026 23:13
@dibarbet
dibarbet force-pushed the dibarbet-esm-tooling-foundation branch from 97cc912 to fd7f51c Compare August 4, 2026 00:42
dibarbet and others added 2 commits August 3, 2026 17:44
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2af8a1f5-c78a-435b-805d-0328d6cd4106
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2af8a1f5-c78a-435b-805d-0328d6cd4106
Copilot AI review requested due to automatic review settings August 4, 2026 01:10
@dibarbet
dibarbet force-pushed the dibarbet-esm-nodenext-conversion branch from d9a568d to 61309d9 Compare August 4, 2026 01:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Converts the extension’s TypeScript codebase and build/test tooling to an ESM-first setup (NodeNext), replacing CommonJS globals/patterns with import.meta.url-based equivalents while preserving Jest, esbuild bundling, and VS Code integration entry points.

Changes:

  • Switch TypeScript typechecking to module: Preserve / moduleResolution: Bundler with noEmit, and add dedicated tsconfig files for Jest (CJS) and integration entry point emission (NodeNext).
  • Update tests/tooling to work in an ESM package (type: module), including Jest config split for integration vs unit runs and updated runners/import specifiers.
  • Replace CommonJS-only patterns (__dirname, require, module.exports) with ESM-compatible equivalents across tasks, tests, and runtime code.
Show a summary per file
File Description
wallaby.js Convert Wallaby config to ESM export default.
tsconfig.json Switch to ESM-preserving typecheck config (Preserve/Bundler, noEmit).
tsconfig.jest.json Add CJS tsconfig override for Jest preset needing CommonJS.
tsconfig.integration.json Add NodeNext-emitting config for VS Code integration test entry points.
test/vsCodeUnitFramework.ts Ensure vscode virtual mock is set up for both Jest mock systems.
test/vsCodeFramework.ts Add ESM-compatible unstable_mockModule for vscode virtual mock.
test/vsCodeEnvironment.ts Export Jest environment class via ESM default export.
test/untrustedWorkspace/integrationTests/jest.config.mjs Use the integration-oriented base Jest config.
test/untrustedWorkspace/integrationTests/index.ts Use explicit .js specifier for compiled runner import edge.
test/runIntegrationTests.ts Switch to default-imported Jest API for ESM runtime.
test/razor/razorTests/Microsoft.AspNetCore.Razor.VSCode.Grammar.Test/tests/infrastructure/tokenizedContentProvider.ts Replace __dirname with import.meta.url-based pathing and adjust CJS interop imports.
test/razor/razorIntegrationTests/jest.config.mjs Use the integration-oriented base Jest config.
test/razor/razorIntegrationTests/index.ts Use explicit .js specifier for compiled runner import edge.
test/omnisharp/runFeatureTests.ts Replace __dirname usage with import.meta.url-based directory resolution.
test/omnisharp/omnisharpUnitTests/testAssets/mockHttpsServer.ts Use createRequire(import.meta.url) bridge for CJS-only dependency.
test/omnisharp/omnisharpUnitTests/packages/zipInstaller.test.ts Update fs-extra import for ESM/CJS interop.
test/omnisharp/omnisharpUnitTests/packages/packageFilterer.test.ts Convert fs mocking to unstable_mockModule + top-level await import(...).
test/omnisharp/omnisharpUnitTests/jest.config.mjs Add unit test setup file for vscode mocking.
test/omnisharp/omnisharpUnitTests/blazorWebAssemblyDetection.test.ts Update fs-extra import for ESM/CJS interop.
test/omnisharp/omnisharpIntegrationTests/launchConfiguration.integration.test.ts Update fs-extra import for ESM/CJS interop.
test/omnisharp/omnisharpIntegrationTests/jest.config.mjs Use the integration-oriented base Jest config.
test/omnisharp/omnisharpIntegrationTests/index.ts Use explicit .js specifier for compiled runner import edge.
test/lsptoolshost/unitTests/roslynLanguageClient.test.ts Convert mocks/imports to ESM-safe unstable_mockModule + dynamic imports.
test/lsptoolshost/unitTests/migrateOptions.test.ts Convert fs mocking to unstable_mockModule + top-level await import(...).
test/lsptoolshost/unitTests/jest.config.mjs Add unit test setup file for vscode mocking.
test/lsptoolshost/integrationTests/testAssets/testAssets.ts Update fs-extra import for ESM/CJS interop.
test/lsptoolshost/integrationTests/jest.config.mjs Use the integration-oriented base Jest config.
test/lsptoolshost/integrationTests/index.ts Use explicit .js specifier for compiled runner import edge.
test/lsptoolshost/artifactTests/vsix.test.ts Update fs-extra and glob imports for ESM/CJS interop.
test/createTmpAsset.ts Avoid named import from fs-extra in ESM; use namespace/default import.
tasks/tests/testHelpers.ts Switch to default-imported Jest API for ESM runtime.
tasks/projectPaths.ts Replace __dirname usage with import.meta.url-based root resolution.
tasks/packaging/offlinePackagingTasks.ts Update fs-extra import for ESM/CJS interop.
tasks/compilation/copyEsmSupportFiles.ts Add build step to copy .mjs Jest support file into out/test.
src/shared/workspaceConfigurationProvider.ts Update fs-extra import for ESM/CJS interop.
src/shared/utils.ts Update fs-extra import for ESM/CJS interop.
src/shared/telemetryReporter.ts Add telemetry reporter interface that includes telemetryLevel.
src/shared/projectConfiguration.ts Adjust node-machine-id import shape for ESM/CJS interop.
src/shared/processPicker.ts Update fs-extra import for ESM/CJS interop.
src/shared/platform.ts Replace __dirname usage with import.meta.url-based directory resolution.
src/shared/dotnetConfigurationProvider.ts Update fs-extra import for ESM/CJS interop.
src/shared/assets.ts Update fs-extra import for ESM/CJS interop.
src/razor/src/blazorDebug/blazorDebugConfigurationProvider.ts Replace require('path') pattern and adjust servicehub imports for ESM.
src/packageManager/zipInstaller.ts Avoid named import from fs-extra in ESM; use namespace/default import.
src/packageManager/downloadAndInstallPackages.ts Avoid named import from fs-extra in ESM; use namespace/default import.
src/omnisharp/features/workspaceSymbolProvider.ts Formatting-only rewrite consistent with ESM conversion.
src/omnisharp/features/definitionMetadataDocumentProvider.ts Formatting-only rewrite consistent with ESM conversion.
src/omnisharp/engines/lspEngine.ts Refactor feature disabling to use request/notification method IDs (ESM-friendly imports).
src/main.ts Adjust extension-telemetry import for CJS interop under ESM.
src/lsptoolshost/server/roslynLanguageServer.ts Accept telemetry reporter interface and expose protocol converter for workspace edits.
src/lsptoolshost/extensions/builtInComponents.ts Replace __dirname usage with import.meta.url-based directory resolution.
src/lsptoolshost/diagnostics/nestedCodeAction.ts Use shared protocol converter for workspace edits (and contains a typo to fix).
src/lsptoolshost/diagnostics/fixAllCodeAction.ts Use shared protocol converter for workspace edits.
src/lsptoolshost/commands.ts Decouple from concrete telemetry reporter type via local interface.
src/lsptoolshost/activate.ts Replace __dirname usage and switch to telemetry reporter interface type.
src/activateRoslyn.ts Switch telemetry reporter parameter to interface with telemetry level.
src/activateOmniSharp.ts Switch telemetry reporter parameter to interface type.
package.json Mark package as ESM and update compile/test scripts for ESM + Jest VM modules.
eslint.config.mjs Expand ignore list to include .vscode-test/**.
esbuild.mjs Remove temporary bundled __filename/__dirname shims from banner.
baseJestConfig.mjs Split base Jest config for unit (ESM) vs integration (CJS) environments.
.vscode/launch.json Point integration test launch configs at explicit compiled index.js entry points.
mocks/vscode.ts Convert vscode manual mock to ESM exports shape.

Copilot's findings

Suppressed comments (1)

src/lsptoolshost/diagnostics/nestedCodeAction.ts:77

  • Error message has a typo (“am edit”), and it’s inconsistent with the earlier log line that says “an edit”. This can make logs/telemetry harder to search and understand.
                            const componentName = '[roslyn.client.nestedCodeAction]';
                            const errorMessage = 'Failed to make am edit for completion.';
                            outputChannel.show();
  • Files reviewed: 60/63 changed files
  • Comments generated: 0

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2af8a1f5-c78a-435b-805d-0328d6cd4106
Copilot AI review requested due to automatic review settings August 4, 2026 01:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

@dibarbet

dibarbet commented Aug 4, 2026

Copy link
Copy Markdown
Member Author

Superseded by #9632 on dev/esm-nodenext-conversion so the updated branch trigger runs CI. The replacement PR is part of stack #9634.

@dibarbet dibarbet closed this Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants