TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

Incorrect semantic highlighting

Open Vap0r1ze opened this issue 2 years ago • 8 comments

🔎 Search Terms

token mismatch, syntax highlighting

🕗 Version & Regression Information

I tested with latest 5.0, 5.1, and 5.2 and it happens with all of them.

⏯ Playground Link

No response

💻 Code

import { ElectronAPI } from "@electron-toolkit/preload";

declare global {
    interface Window {
        electron: ElectronAPI;
        api: unknown;
    }
}

🙁 Actual behavior

https://github.com/microsoft/TypeScript/assets/20448879/d6d675c9-0576-4572-b9d8-fbd31d17d124

I have this file in my project that does this and it looks like a sourcemap / token map mismatch / offset or something.

🙂 Expected behavior

The tokens should be mapping to their respective reflections like in this playground

Additional information about the issue

I can't reproduce this in another file it just keeps happening in this specific file in this specific project. I can reproduce it if I copy the project and install the dependencies, so if someone wants to investigate it I can add you to a repository with the code.

Vap0r1ze avatar Oct 30 '23 00:10 Vap0r1ze

I didn't notice this before but this bug actually causes the file to not extend the Window interface. Window["api"] does not exist until I rename index.d.ts to something else (like globals.d.ts). This is my tsconfig.json for clarity:

{
  "extends": "@electron-toolkit/tsconfig/tsconfig.json",
  "include": [
    "src/renderer/src/env.d.ts",
    "src/renderer/src/**/*",
    "src/renderer/src/**/*.svelte",
    "src/preload/*.d.ts"
  ],
  "compilerOptions": {
    "verbatimModuleSyntax": true,
    "useDefineForClassFields": true,
    "strict": false,
    "allowJs": true,
    "checkJs": true,
    "lib": ["ESNext", "DOM", "DOM.Iterable"]
  },
  "references": [{ "path": "./tsconfig.node.json" }]
}

Vap0r1ze avatar Oct 30 '23 01:10 Vap0r1ze

We'll definitely need a way to repro this. Strange.

RyanCavanaugh avatar Oct 30 '23 15:10 RyanCavanaugh

I remembered what template I was using, and it's enough to reproduce it out of the box:

pnpm create @quick-start/electron app-test --template=svelte-ts
cd app-test
pnpm i
code . src/preload/index.d.ts
# wait for ts-server to be done and see weird stuff

Vap0r1ze avatar Oct 30 '23 15:10 Vap0r1ze

Weird, it's wrong but differently-wrong on my machine image

This is specific to semantic highlighting

RyanCavanaugh avatar Oct 30 '23 16:10 RyanCavanaugh

For me it goes a little farther than semantic highlighting. Can you try to do window.api; in preload/index.ts? For me it errors until I rename index.d.ts to something else like real.d.ts

Vap0r1ze avatar Oct 30 '23 19:10 Vap0r1ze

This seems to be because of the index.ts right next to the index.d.ts. If I hover over the ElectrornAPI in the import, it shows the info of contextBridge, which only exists in the index.ts file.

jasonlyu123 avatar Nov 02 '23 05:11 jasonlyu123

I have investigated this issue and the cause seems to be a problem where tsserver is attempting to retrieve the highlights for index.d.ts, but instead returns the semantic highlighting for index.ts. This issue goes away by adding "disableSourceOfProjectReferenceRedirect": true, to the tsconfig, so I will be request @sheetalkamat to take a look at this. Here is the smallest repro I was able to get:

// app-test/src/index.d.ts
declare global {
    interface Window {
      electron: ElectronAPI
      api: unknown
    }
}

// app-test/src/index.ts
const api = {}

// app-test/tsconfig.json
{
    "include": [
      "src/*.d.ts"
    ],
    "compilerOptions": {
    },
    "references": [{ "path": "./tsconfig.node.json" }]
}

// app-test/tsconfig.node.json
{
    "include": ["src/**/*"],
    "compilerOptions": {
      "composite": true,
    }
}

The incorrect highlighting happens in index.d.ts in the space between e g in declare global: image

I also noticed that the same thing happens with completionInfo, definitionAndBoundSpan`, and possibly others. Here are example tsserver logs for all three I found:

Info 122  request:
    {
      "seq": 33,
      "type": "request",
      "command": "documentHighlights",
      "arguments": {
        "file": "c:\\test-semantic-highlighting-no-electron\\app-test\\src\\index.d.ts",
        "line": 1,
        "offset": 9,
        "filesToSearch": [
          "c:\\test-semantic-highlighting-no-electron\\app-test\\src\\index.d.ts"
        ]
      }
    }
Info 124  response:
    {"seq":0,
"type":"response",
"command":"documentHighlights",
"request_seq":33,
"success":true,
"body":[{"file":"c:/test-semantic-highlighting-no-electron/app-test/src/index.ts",
    "highlightSpans":
         [{"start":{"line":1,"offset":7},
            "end":{"line":1,"offset":10},
            "contextStart":{"line":1,"offset":1},
            "contextEnd":{"line":1,"offset":15},
            "kind":"writtenReference"
        }]
    }]
}

Info 125 request:
{
  "seq": 34,
  "type": "request",
  "command": "completionInfo",
  "arguments": {
    "file": "c:\\test-semantic-highlighting-no-electron\\app-test\\src\\index.d.ts",
    "line": 1,
    "offset": 9,
    "triggerCharacter": {
      "id": "type-tree",
      "range": {
        "start": {
          "line": 0,
          "character": 8
        },
        "end": {
          "line": 0,
          "character": 8
        }
      },
      "maxDepth": 6
    }
  }
}

Info 132  response:
{
  "seq":0,
  "type":"response",
  "command":"completionInfo",
  "request_seq":34,"success":true,
  "body":{"isGlobalCompletion":false,
  "isMemberCompletion":false,
  "isNewIdentifierLocation":false,
  "entries":[],
  "__tsExplorerResponse":
  {
    "id":"type-tree",
    "typeInfo":
    {
      "kind":"object",
      "properties":[],
      "indexInfos":[],
      "symbolMeta":
      {
        "name":"api",
        "flags":2,
        "declarations":
        [{
          "location":
          {
            "fileName":"c:/test-semantic-highlighting-no-electron/app-test/src/index.ts",
            "range":{"start":{"line":0,"character":6},"end":{"line":0,"character":9}}
          }
        }]
      },
      "id":"85,14,0"
      }
    }
  }
}

Info 139 request:
    {
      "seq": 37,
      "type": "request",
      "command": "definitionAndBoundSpan",
      "arguments": {
        "file": "c:\\test-semantic-highlighting-no-electron\\app-test\\src\\index.d.ts",
        "line": 1,
        "offset": 8
      }
    }
Info 141  response:
{
  "seq":0,
  "type":"response",
  "command":"definitionAndBoundSpan",
  "request_seq":37,
  "success":true,
  "body":
  {
    "definitions":
    [{
      "file":"c:/test-semantic-highlighting-no-electron/app-test/src/index.ts",
      "start":{"line":1,"offset":7},
      "end":{"line":1,"offset":10},
      "contextStart":{"line":1,"offset":1},
      "contextEnd":{"line":1,"offset":15}
    }],
    "textSpan":{"start":{"line":1,"offset":7},"end":{"line":1,"offset":10}}
  }
}

iisaduan avatar May 02 '24 18:05 iisaduan

I will look into this issue but this is such a bad configuration. There may be many places some of the assumptions going wrong here. app-test/src/index.d.ts is considered output of app-test/src/index.ts since its tsconfig has composite which means declaration to be true as well.

sheetalkamat avatar May 02 '24 19:05 sheetalkamat