Skip to content

Support TypeScript 7 content-mapper projects - #4

Merged
NullVoxPopuli merged 1 commit into
NullVoxPopuli:mainfrom
NullVoxPopuli-ai-agent:ts7-content-mapper
Aug 23, 2026
Merged

Support TypeScript 7 content-mapper projects#4
NullVoxPopuli merged 1 commit into
NullVoxPopuli:mainfrom
NullVoxPopuli-ai-agent:ts7-content-mapper

Conversation

@NullVoxPopuli-ai-agent

Copy link
Copy Markdown
Contributor

When the nearest tsconfig.json declares contentMappers (e.g. ember-content-mapper), the classic pipeline is wrong in both directions: ts_ls + @glint/tsserver-plugin only works against a TS 5/6 tsserver, and in a TS 7 project the plugin is absent, so tsserver parses <template> as plain TS and paints syntax errors over the whole file.

This PR detects "contentMappers" in the nearest tsconfig and, for those projects:

  • attaches nvim-lspconfig's tsc (TypeScript 7's native LSP) with init_options = { runExternalCode = true }, the explicit opt-in TypeScript requires before spawning mapper processes (VS Code sends the same for trusted workspaces)
  • maps typescript.glimmer / javascript.glimmer filetypes to plain typescript / javascript language ids via get_language_id
  • keeps ts_ls and glint detached

Non-content-mapper projects are untouched. nvim-lspconfig's tsc config resolves the workspace node_modules/.bin/tsc from the root we pass it, so the project's own TypeScript 7 nightly is used.

Verified against ember-content-mapper's example apps: only tsc attaches, a clean application.gts has zero diagnostics, and a planted {{oops.nah}} reports 2339 Property 'nah' does not exist on type '1' at the exact template position.

🤖 Generated with Claude Code

When the nearest tsconfig.json declares contentMappers (e.g.
ember-content-mapper), attach nvim-lspconfig's tsc (TypeScript 7's
native LSP) with runExternalCode enabled and glimmer filetypes mapped
to plain typescript/javascript language ids, and keep ts_ls and glint
detached: the content mapper transforms gts/gjs for TypeScript itself,
so the classic tsserver plugin pipeline would only report bogus syntax
errors on <template> tags.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@NullVoxPopuli-ai-agent

Copy link
Copy Markdown
Contributor Author

Why tsc and not ts_ls for these projects: ts_ls cannot drive TypeScript 7.

  • ts_ls (typescript-language-server) wraps tsserver, the Node server that ships inside typescript 5/6 as lib/tsserver.js. The TypeScript 7 npm package is the Go compiler: no tsserver.js, no JS API. Pointed at a TS 7 workspace, ts_ls silently falls back to its bundled TS 5/6, which has no idea what contentMappers means, and without @glint/tsserver-plugin it parses <template> as plain TS. That fallback is exactly the wall of syntax errors this PR fixes.
  • There is no "ts_ls + plugin" middle path either: tsserver plugins are a tsserver-protocol feature, and TS 7 dropped that plugin system. Its extension point for foreign file types is the content mapper.
  • TS 7 replaced tsserver with a native LSP server, spawned as tsc --lsp --stdio from the workspace binary. nvim-lspconfig's config name for that server is tsc (tsgo is a deprecated alias for it). It resolves <root>/node_modules/.bin/tsc, so the project's own TS 7 nightly is used, and it accepts the runExternalCode init option that enables content mappers (init_options, not a CLI flag; without it the server answers "no project found" for .gts files).

So the routing is: "contentMappers" in the nearest tsconfig means TS 7 native LSP via tsc; everything else keeps the existing ts_ls/glint behavior unchanged.

-- declare `contentMappers` in tsconfig.json (e.g. ember-content-mapper).
-- The mapper transforms gts/gjs for TypeScript itself, so ts_ls and glint
-- both stay detached in these projects (see lsp/utils.lua).
vim.lsp.config('tsc', {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is nvim-lspconfig's config for TypeScript 7's native LSP (tsc --lsp --stdio, resolved from the workspace node_modules/.bin/tsc; tsgo is its deprecated alias). ts_ls can't serve these projects: it wraps tsserver, which doesn't exist in the TS 7 package, so it falls back to a bundled TS 5/6 that neither understands contentMappers nor loads @glint/tsserver-plugin (TS 7 dropped the tsserver plugin system; content mappers are its replacement extension point).

@NullVoxPopuli
NullVoxPopuli merged commit aeeaa8b into NullVoxPopuli:main Aug 23, 2026
1 check passed
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