Repository navigation
Description
🔎 Search Terms
"content mapper", "contentMappers", "workspace/diagnostic/refresh", "didChangeWatchedFiles", "isRelevantExtension", "stale diagnostics", "restart TS server", ".d.ts"
🕗 Version & Regression Information
- This changed in Strongly type file paths #64159, which switched
Session.DidChangeWatchedFilesfrom taking everything after the last dot topath.Extension(). Seen on typescript@7.1.0-beta.
⏯ Playground Link
No response
💻 Code
Repro: https://github.com/mrlubos/ts-content-mapper-refresh (npm install && npm run repro)
// tsconfig.json
{ "compilerOptions": { "module": "nodenext", "strict": true, "noEmit": true },
"contentMappers": [{ "package": "toy-mapper", "extensions": [".data"] }] }// index.ts. toy-mapper turns each `name: type` line of shape.data into a member of `Data`.
import type { Dep } from './dep.js';
import type { Data } from './shape.data';
declare const dep: Dep;
declare const data: Data;
export const fromTs = dep.age; // error until `age` is added to dep.ts
export const fromData = data.age; // error until `age: number` is added to shape.data🙁 Actual behavior
After shape.data changes on disk (written by another process, with the editor sending workspace/didChangeWatchedFiles), the server never sends workspace/diagnostic/refresh. In VS Code the error on data.age stays until "TypeScript: Restart TS Server". The server already has the right answer: a textDocument/diagnostic request made by hand returns no errors. npm run repro drives tsc --lsp as VS Code does and prints:
- dep.ts changed on disk, refresh requests: 1
- shape.data changed on disk, refresh requests: 0
errors when pulled by hand: [] - shape.data edited while open, refresh requests: 1
🙂 Expected behavior
A change on disk to a file a registered content mapper handles should refresh diagnostics the way a change to a .ts file does, since it changes the program. This matters most when a tool regenerates the mapped file, for example a dev server writing an API description on each reload, because the editor never has that file open.
Additional information about the issue
path.Extension() returns only the extensions TypeScript reads itself. For shape.data it returns "", so the path is treated as a possible directory: DirectoryExists is false and the change is dropped. The check against the extensions a project's contentMappers register is in the else branch, which a mapped extension never reaches.
The same change breaks .d.ts files: path.Extension() returns .d.ts, which isRelevantExtension does not list, so a declaration file changed on disk does not refresh diagnostics either.
A workaround for mapped files is to keep the file open in an editor tab, so VS Code reloads it and sends didChange.
Activity
[-]Content-mapped file changed on disk never triggers workspace/diagnostic/refresh[/-][+]File changed on disk with a content-mapped or .d.ts extension never triggers workspace/diagnostic/refresh[/+][-]File changed on disk with a content-mapped or .d.ts extension never triggers workspace/diagnostic/refresh[/-][+]File changed on disk with a content-mapped or `.d.ts` extension never triggers workspace/diagnostic/refresh[/+]Refresh diagnostics when a content-mapped or declaration file changes…