Skip to content

Commit 48bef09

Browse files
committed
languageserver: add .js extensions to imports (ESM prep)
1 parent 656a821 commit 48bef09

27 files changed

+120
-113
lines changed

docs/esm-migration-plan.md

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,27 @@
44

55
This document outlines the plan to migrate from TypeScript's deprecated `"moduleResolution": "node"` (node10) to `"moduleResolution": "node16"` or `"nodenext"`. This change is necessary because the published ESM packages have extensionless imports that don't work correctly in modern ESM environments.
66

7+
## TL;DR - Remaining Work
8+
9+
- [x] expressions - Migrated ✅
10+
- [x] workflow-parser - Migrated ✅
11+
- [x] languageservice - Migrated ✅
12+
- [x] languageserver - Add `.js` extensions to imports ✅
13+
- [ ] languageserver - Update `tsconfig.build.json` to `moduleResolution: "node16"` (blocked by vscode-languageserver)
14+
- [ ] languageserver - Upgrade `vscode-languageserver` to stable v10+ when released
15+
16+
**Blocker:** `vscode-languageserver@8.0.2` lacks ESM exports. Stable v10 with `exports` field needed.
17+
18+
### ⚠️ Important: `skipLibCheck: true` Required
19+
20+
All migrated packages use `skipLibCheck: true` in their `tsconfig.build.json`. This works around a TS2386 "Overload signatures must all be optional or required" error in `@types/node/module.d.ts`.
21+
22+
**Why can't we just fix the error?** The error is in `@types/node`, a third-party package maintained by DefinitelyTyped. We can't modify `node_modules`, and upstream fixes take time.
23+
24+
**Is `skipLibCheck` safe?** Yes. It only skips type checking of `.d.ts` files (declaration files from dependencies). Our own `.ts` source files are still fully type-checked. This is a common and recommended workaround for issues in third-party type definitions.
25+
26+
---
27+
728
## Issues Fixed
829

930
This migration will resolve the following issues:
@@ -199,14 +220,13 @@ src/connection.ts(1,43): error TS2307: Cannot find module 'vscode-languageserver
199220

200221
With `moduleResolution: "node16"`, TypeScript follows Node.js ESM resolution rules which require explicit `exports` for subpath imports like `vscode-languageserver/browser` and `vscode-languageserver/node`.
201222

202-
**Status:** Verified December 2025. Version 9.0.1 is available but ESM export support is not confirmed.
223+
**Status:** Partial - `.js` extensions added, waiting for stable `vscode-languageserver` release with ESM exports to complete migration.
203224

204-
**Current Decision:** The languageserver package is **deferred** from this migration until the upstream `vscode-languageserver` package adds proper ESM exports. It will continue using the old `moduleResolution: "node"` configuration.
225+
**Completed:** All relative imports in languageserver source files have been updated to use `.js` extensions. This is compatible with the current `moduleResolution: "node"` and will enable a seamless migration once a stable vscode-languageserver version with ESM exports is available.
205226

206227
**Options to resolve:**
207-
- Wait for vscode-languageserver to add ESM exports
208-
- Try upgrading to vscode-languageserver v9.x to see if exports were added
209-
- Use a bundler to work around the module resolution
228+
- Wait for stable vscode-languageserver v10+ with ESM exports
229+
- Use pre-release `vscode-languageserver@10.0.0-next.16` (has proper exports but is unstable)
210230
- Fork or patch the dependency
211231

212232
---
@@ -218,7 +238,7 @@ With `moduleResolution: "node16"`, TypeScript follows Node.js ESM resolution rul
218238
| expressions | 1068 | ✅ Migrated |
219239
| workflow-parser | 292 | ✅ Migrated |
220240
| languageservice | 452 | ✅ Migrated |
221-
| languageserver | 6 files | ⏸️ Deferred (vscode-languageserver lacks ESM exports) |
241+
| languageserver | 31 | 🔶 Partial (`.js` extensions added, awaiting stable vscode-languageserver) |
222242

223243
---
224244

languageserver/src/connection.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@ import {
1818
TextDocumentSyncKind
1919
} from "vscode-languageserver";
2020
import {TextDocument} from "vscode-languageserver-textdocument";
21-
import {getClient} from "./client";
22-
import {Commands} from "./commands";
23-
import {contextProviders} from "./context-providers";
24-
import {descriptionProvider} from "./description-provider";
25-
import {getFileProvider} from "./file-provider";
26-
import {InitializationOptions, RepositoryContext} from "./initializationOptions";
27-
import {onCompletion} from "./on-completion";
28-
import {ReadFileRequest, Requests} from "./request";
29-
import {getActionsMetadataProvider} from "./utils/action-metadata";
30-
import {TTLCache} from "./utils/cache";
31-
import {timeOperation} from "./utils/timer";
32-
import {valueProviders} from "./value-providers";
21+
import {getClient} from "./client.js";
22+
import {Commands} from "./commands.js";
23+
import {contextProviders} from "./context-providers.js";
24+
import {descriptionProvider} from "./description-provider.js";
25+
import {getFileProvider} from "./file-provider.js";
26+
import {InitializationOptions, RepositoryContext} from "./initializationOptions.js";
27+
import {onCompletion} from "./on-completion.js";
28+
import {ReadFileRequest, Requests} from "./request.js";
29+
import {getActionsMetadataProvider} from "./utils/action-metadata.js";
30+
import {TTLCache} from "./utils/cache.js";
31+
import {timeOperation} from "./utils/timer.js";
32+
import {valueProviders} from "./value-providers.js";
3333

3434
export function initConnection(connection: Connection) {
3535
const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);

languageserver/src/context-providers.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {data, DescriptionDictionary} from "@actions/expressions";
22
import {WorkflowContext} from "@actions/languageservice/context/workflow-context";
33
import {Mode} from "@actions/languageservice/context-providers/default";
4-
import {contextProviders} from "./context-providers";
5-
import {RepositoryContext} from "./initializationOptions";
6-
import {TTLCache} from "./utils/cache";
4+
import {contextProviders} from "./context-providers.js";
5+
import {RepositoryContext} from "./initializationOptions.js";
6+
import {TTLCache} from "./utils/cache.js";
77

88
describe("contextProviders", () => {
99
const mockCache = new TTLCache();

languageserver/src/context-providers.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import {ContextProviderConfig} from "@actions/languageservice";
33
import {Mode} from "@actions/languageservice/context-providers/default";
44
import {WorkflowContext} from "@actions/languageservice/context/workflow-context";
55
import {Octokit} from "@octokit/rest";
6-
import {getSecrets} from "./context-providers/secrets";
7-
import {getStepsContext} from "./context-providers/steps";
8-
import {getVariables} from "./context-providers/variables";
9-
import {RepositoryContext} from "./initializationOptions";
10-
import {TTLCache} from "./utils/cache";
6+
import {getSecrets} from "./context-providers/secrets.js";
7+
import {getStepsContext} from "./context-providers/steps.js";
8+
import {getVariables} from "./context-providers/variables.js";
9+
import {RepositoryContext} from "./initializationOptions.js";
10+
import {TTLCache} from "./utils/cache.js";
1111

1212
export function contextProviders(
1313
client: Octokit | undefined,

languageserver/src/context-providers/action-outputs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {ActionOutputs, ActionReference} from "@actions/languageservice/action";
22
import {Octokit} from "@octokit/rest";
3-
import {fetchActionMetadata} from "../utils/action-metadata";
4-
import {TTLCache} from "../utils/cache";
3+
import {fetchActionMetadata} from "../utils/action-metadata.js";
4+
import {TTLCache} from "../utils/cache.js";
55

66
export async function getActionOutputs(
77
octokit: Octokit,

languageserver/src/context-providers/secrets.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import {warn} from "@actions/languageservice/log";
66
import {isMapping, isString} from "@actions/workflow-parser";
77
import {Octokit} from "@octokit/rest";
88

9-
import {RepositoryContext} from "../initializationOptions";
10-
import {TTLCache} from "../utils/cache";
11-
import {errorStatus} from "../utils/error";
12-
import {getRepoPermission} from "../utils/repo-permission";
9+
import {RepositoryContext} from "../initializationOptions.js";
10+
import {TTLCache} from "../utils/cache.js";
11+
import {errorStatus} from "../utils/error.js";
12+
import {getRepoPermission} from "../utils/repo-permission.js";
1313

1414
export async function getSecrets(
1515
workflowContext: WorkflowContext,

languageserver/src/context-providers/steps.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import {getStepsContext as getDefaultStepsContext} from "@actions/languageservic
33
import {Octokit} from "@octokit/rest";
44
import fetchMock from "fetch-mock";
55

6-
import {createWorkflowContext} from "../test-utils/workflow-context";
7-
import {TTLCache} from "../utils/cache";
8-
import {getStepsContext} from "./steps";
6+
import {createWorkflowContext} from "../test-utils/workflow-context.js";
7+
import {TTLCache} from "../utils/cache.js";
8+
import {getStepsContext} from "./steps.js";
99

1010
const workflow = `
1111
name: Caching Primes

languageserver/src/context-providers/steps.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import {parseActionReference} from "@actions/languageservice/action";
33
import {WorkflowContext} from "@actions/languageservice/context/workflow-context";
44
import {isActionStep} from "@actions/workflow-parser/model/type-guards";
55
import {Octokit} from "@octokit/rest";
6-
import {TTLCache} from "../utils/cache";
7-
import {getActionOutputs} from "./action-outputs";
6+
import {TTLCache} from "../utils/cache.js";
7+
import {getActionOutputs} from "./action-outputs.js";
88

99
export async function getStepsContext(
1010
octokit: Octokit,

languageserver/src/context-providers/variables.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import {isMapping, isString} from "@actions/workflow-parser";
77
import {Octokit} from "@octokit/rest";
88
import {RequestError} from "@octokit/request-error";
99

10-
import {RepositoryContext} from "../initializationOptions";
11-
import {TTLCache} from "../utils/cache";
12-
import {errorStatus} from "../utils/error";
13-
import {getRepoPermission} from "../utils/repo-permission";
10+
import {RepositoryContext} from "../initializationOptions.js";
11+
import {TTLCache} from "../utils/cache.js";
12+
import {errorStatus} from "../utils/error.js";
13+
import {getRepoPermission} from "../utils/repo-permission.js";
1414

1515
export async function getVariables(
1616
workflowContext: WorkflowContext,

languageserver/src/description-provider.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import {DescriptionProvider} from "@actions/languageservice/hover";
22
import {Octokit} from "@octokit/rest";
3-
import {getActionDescription} from "./description-providers/action-description";
4-
import {getActionInputDescription} from "./description-providers/action-input";
5-
import {TTLCache} from "./utils/cache";
3+
import {getActionDescription} from "./description-providers/action-description.js";
4+
import {getActionInputDescription} from "./description-providers/action-input.js";
5+
import {TTLCache} from "./utils/cache.js";
66

77
export function descriptionProvider(client: Octokit | undefined, cache: TTLCache): DescriptionProvider {
88
const getDescription: DescriptionProvider["getDescription"] = async (context, token, path) => {

0 commit comments

Comments
 (0)