TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

`{@link https...}` inside a `@remarks` causes error TS2304: Cannot find name 'https'

Open aSemy opened this issue 2 years ago • 16 comments

Bug Report

🔎 Search Terms

  • jsdoc
  • tsdoc
  • TS2304: Cannot find name 'https'.
  • @link
  • @remarks

🕗 Version & Regression Information

  • This is the behaviour in every version I tried, and I reviewed the FAQ for entries ✅

I checked on 4.6.4, 4.6.2.

I tried checking on 4.7.0-rc1 but I got unrelated errors.

⏯ Playground Link

I don't understand how to use the 'Bug Workbench', it doesn't seem to pick up the config I enter.

https://www.typescriptlang.org/dev/bug-workbench/?target=99&allowSyntheticDefaultImports=true&explainFiles=true&forceConsistentCasingInFileNames=true&listEmittedFiles=true&listFiles=true&sourceMap=false&traceResolution=true&noImplicitOverride=true&noFallthroughCasesInSwitch=true&types=%5B%22typescript-to-lua%2Flanguage-extensions%22%2C%20%22lua-types%2F5.2%22%2C%20%22typed-factorio%2Fruntime%22%5D&lib=&ts=4.6.2#code/PTAEAEBcEMCcHMCmkBcpEGcB2iAekAoAkCAMwEsAbRLaAW0TQAdoBjAa2iQDoArDAPZYCAbwKhQAIloNJaSXQCeAWlJtIA2OQHK6AgCaSANOKkA3RLAzascqQAZuAVm73jpyUy1nokRHchYAFdEEwlJDFYtJkgMOzEJcIAjIKpDeVjISndEqX1EMztJTMpQZWUAd19WAAtJUwBfMKkaeHIcOLQExOkDf3kAPwBGABZuIYBOcfqJJo98swARRCYafKxWckx4ufD81ax1ze2u03DKIOhlSEVVzqkAPQAmcaHXHJ6bu6jyGOudC7QIpvMYjD7hL6IfSqdSabTA8bvZoQ26YH4xIpjABs3CeM1AuyklHIrBoGH6UgAqgA5AAyAEkAMIAUWpAGVmYsPp5EJZlgcjlt7iJCZIBDEbNBKPy1jRjsLRSlDtR9DLDnKhXYANoAXQIDSIxDA4Ao1BkjFAsVYQgo8D4giwoFEHgAJJEaog6ED5DVIJAmBgUCBYNAKtw2pAakEUuTYNasH4E9xrXRgAAVVFs9GQNMCWmXYBmSJ9a6oyLRSD-ZSA4BejB+WDAK028jwZTuz3Qe1CbkpphUSwAeQlQmFZykMAQyCKmBw+HBRPISW14-Cs7wkHxEh1yKken0QWoRRTeiw-AXCgMh8QACVMAILpAbEUsH0L5D7lrVxOy9mqzXKGgLB4EuJBlA3MkbDiXdzkuUs7mAFw8Rgn9VmhNRWA0LQBGAYIE3IWRxx3cdPAuNosE-b9ulycJzSKD8-xKZQmDI9ot0SA1cmI3JJClSgBAqNlFATD0n1YZY1EPSB6ToJhNFiAJglCEjMAAWSvah6QTSxxUUkJd0kPAWOgdoADEB3uQJ9JI0hNFJRlR3IesaEgRloGsYCtPM6hqXoE5LSUgziXrZk6HIP0oW8-yrOUnjgsgKLLMCkjXxkliSXCgBBLBFD02KelS2TiU2HMaicvKDMEII40QVToCYOw1EoclKsCElNzQGLWq0TDTKCDYnyEDM7gqkj6x6yBqUPShGQ9DgkusnjAjYW970fZ9OuSnjCvSkq70gaqKNG7aBDS4rwsHCxYC0fJjoKgRTL4yNYAEIJ4BqNzyQwLS2QqcLajyxpmmKetslOOLLjTOAkA6qQkPfUGADVLCSARyTu2iBAACUQaB8lgDGpB287IDZRBKFIQnJEBWklzS+SilgRAAEdUiZ-EDQNIgSBNAdzTQeNAgfbhYiIctfkgbghAAfXacKAAp5YASlAABeAA+UBqNAfj4HlgADfdQCc0A8fyfRLQES0PVADBoAsfWlf1J2gA

But when I set up those 3 files in a directory and run npm install then npm build, I get this error

...
Emitting ...
Emit finished!
node_modules/typed-factorio/generated/classes.d.ts:238:3 - error TS2304: Cannot find name 'https'.

238   on_init(f: (() => void) | undefined): void
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Process finished with exit code 2

Here's a reproduction inside the TSTL playground. You might have to edit the file to trigger it

https://typescripttolua.github.io/play/#code/PQKhCgAIUhRA7ALgJwJ6QA4HsCWTIBmWykyApgOY4DOiZyeFkZAbmfgBYCG8AJgDb1qAOkgBJRJBqQuAY1llq1HACNBkRB2RYArhQ4aOZSBX5YVXfpHMArMrMnwuAWzK9IAA2qyGGRB+EoCGhIAG8AAX48AGtIDkREDGoALmBgfh0uAFouDBxhAjlEYhwsYVksZ3SuOlpgABlMgCEsLERaZFzheOcrADUcMgB3SF4sWR1XJBrS+ABfIMhw+CwAZTJ+AiDgcDw6ZEKFSEauFraO3LCoSFBgyBDw8mcuZGjqa+gPmHqY6khZHiYXD4YoySAAVQASvVkmFIjE4gkkqlgFRNDoVOVKsBnDgfFhqFgCIhgO0xrIFvdoDt7lh4AB9PA4RAACgIsJZLIAlJAALwAPkgLFwvB5XNhwpwvHAC3AFXgtEg3l8klhJzO7RQl15Vyp1gZTMQHIAHjyBZBjdyZeBwMqcH5hHTGfBmZyzYLQhgGEgWQAiIhYX1cuZc8BAA

image

💻 Code

An MRE is below, but the error originates in the TSDoc of the Typed Factorio project, in classes.d.ts.

  /**
   * Register a function to be run on mod initialization...
   *
   * {@link https://lua-api.factorio.com/latest/LuaBootstrap.html#LuaBootstrap.on_init View documentation}
   * @param f The handler for this event. Passing `nil` will unregister it.
   * @remarks For more context, refer to the {@link https://lua-api.factorio.com/latest/Data-Lifecycle.html Data Lifecycle} page.
   * @example Initialize a `players` table in `global` for later use.
   *
   * ```
   * script.on_init(function()
   *   global.players = {}
   * end)
   * ```
   */
  on_init(f: (() => void) | undefined): void

If I remove the {@link ...} from the @remarks, then it works!

  /**
   * Register a function to be run on mod initialization...
   *
   * {@link https://lua-api.factorio.com/latest/LuaBootstrap.html#LuaBootstrap.on_init View documentation}
   * @param f The handler for this event. Passing `nil` will unregister it.
   * @remarks For more context, refer to the xxxxxxxxxxxxxxxxxx page.
   * @example Initialize a `players` table in `global` for later use.
   *
   * ```
   * script.on_init(function()
   *   global.players = {}
   * end)
   * ```
   */
  on_init(f: (() => void) | undefined): void

The @remarks and the {@link ...} was added last week:

https://github.com/GlassBricks/typed-factorio/commit/f18205f70d75f88b02c14fff7a70abcc562e721b#diff-9e3b31eca93c33b0d77c73d8688a93f48e81e18d86efdc4c57ac1d5d76ce8845R229

If I revert Typed Factorio to v1.0.0, then again, there's no error.

Minimal, reproducible example

click to expand
./control.ts
script.on_init(() => {
  log(`mod is added to the save`)
})
./package.json
{
  "name": "my-factorio-mod",
  "version": "0.5.0",
  "private": true,
  "scripts": {
    "build": "tstl",
    "dev": "tstl --watch"
  },
  "engines": {
    "node": "~14.19.1"
  },
  "devDependencies": {},
  "dependencies": {
    "lua-types": "^2.11.0",
    "typescript-to-lua": "1.4.4",
    "typed-factorio": "1.1.0",
    "typescript": "4.6.2"
  },
  "license": "UNLICENSED",
  "peerDependencies": {},
  "optionalDependencies": {},
  "bundledDependencies": []
}
./tsconfig.json
{
  "$schema": "https://raw.githubusercontent.com/TypeScriptToLua/vscode-typescript-to-lua/master/tsconfig-schema.json",
  "compilerOptions": {
    "target": "esnext",
    "lib": [
      "esnext"
    ],
    "module": "commonjs",
    "moduleResolution": "node",
    "types": [
      "typescript-to-lua/language-extensions",
      "lua-types/5.2",
      "typed-factorio/runtime"
    ],
    "plugins": [
      {
        "name": "typescript-tstl-plugin"
      }
    ],
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "explainFiles": true,
    "forceConsistentCasingInFileNames": true,
    "listEmittedFiles": true,
    "listFiles": true,
    "noImplicitAny": true,
    "noImplicitThis": true,
    "sourceMap": false,
    "strict": true,
    "strictFunctionTypes": true,
    "strictNullChecks": true,
    "traceResolution": true,
    "noImplicitReturns": true,
    "noImplicitOverride": true,
    "noFallthroughCasesInSwitch": true
  },
  "tstl": {
    "luaTarget": "5.2",
    "tstlVerbose": true,
    "noHeader": true,
    "noImplicitSelf": true,
    "luaLibImport": "require"
  }
}

🙁 Actual behavior

TSDoc with a {@link https:...} inside of a @remark block causes an error

   * @remarks For more context, refer to the {@link https://lua-api.factorio.com/latest/Data-Lifecycle.html Data Lifecycle} page.
node_modules/typed-factorio/generated/classes.d.ts:238:3 - error TS2304: Cannot find name 'https'.

238   on_init(f: (() => void) | undefined): void
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Process finished with exit code 2

🙂 Expected behavior

TSDoc with a {@link https:...} inside of a @remark block does not cause an error

Workaround

A workaround is to add "skipLibCheck": true to tsconfig.json > compilerOptions.

See also

  • https://github.com/GlassBricks/typed-factorio/issues/13
  • https://github.com/microsoft/tsdoc/issues/9
  • https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1058

aSemy avatar May 14 '22 12:05 aSemy

This is a tstl issue.

andrewbranch avatar May 24 '22 23:05 andrewbranch

Thanks for investigating @andrewbranch, I appreciate it.

I thought the error was related to TypeScript because TSTL is producing correct LUA code, it's only the TypeScript compiler that complains. Can you provide more information on how you came to think that? What needs to change in TSTL to fix it?

aSemy avatar May 25 '22 08:05 aSemy

I’m not 100% sure how it’s happening, but I was unable to reproduce the problem with TypeScript alone (whether with tsc or viewing errors in the editor). Also, I know we don’t issue name resolution errors on @link tags because doing so was a feature request we recently discussed that I argued we should decline. And the fact that the error appeared not on the JSDoc tag itself but on the usage of one of the things it decorated is very bizarre, which reads a lot like someone made a mistake leveraging the TS compiler. My investigation was pretty quick so there’s always a chance I’m wrong, but there was enough evidence that I feel comfortable saying you’d need to give a repro that doesn’t use external tools in order for me to believe the issue is not in the external tools.

andrewbranch avatar May 25 '22 16:05 andrewbranch

This issue has been marked as 'External' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

typescript-bot avatar May 28 '22 10:05 typescript-bot

@andrewbranch I have done some further investigation, this looks to me like we are using the TS API as intended, if not please correct me where we are going wrong:

This diagnostic seems to happen when calling getJsDocTags() on the signature of the CallExpression script.on_init(() =>{ }).

Effectively what we are doing is (where callExpression is the code above):

typeChecker.getResolvedSignature(callExpression).getJsDocTags()

Full stacktrace of my little reproduction scenario is: image

Digging a little further with my debugger it seems that getDisplayPartsFromComment is called with the following node: image

Node at index 0 seems fine, but the second node seems a bit suspicious. node.kind is 324, which is SyntaxKind.JSDocLink as expected, what is weird that node.name is an identifier 'https'. It then tries to resolve this symbol as if it was referring to a variable in code in using checker.getSymbolAtLocation(link.name) in buildLinkParts which ends up adding the diagnostic via resolveEntityName on this https identifier.

I'm not sure what expected behavior is here, or what we could do to prevent this.

Perryvw avatar Jul 03 '22 17:07 Perryvw

When I change @remarks to remarks then it doesn't trigger the error tstl-playground example

interface LuaBootstrap {
  /**
   * remarks
   *
   * Link {@link https://github.com/microsoft/tsdoc}
   */
  on_init(f: (() => void) ): void
}

const script : LuaBootstrap = {
    on_init: (x) => x()
}

script.on_init(() => { })

When I change remarks back to @remarks it does tstl-playground example (make an incidental edit to trigger the error)

Both examples have the same JSDocLink structure, with a https as an Identifier

image

The difference between the two is that the @remarks version has a FirstJSDocTagNode, while the other does not.

image

The error is specifically triggered by an {@link ...} being inside a @remarks block - if the link is in a preceding block, it works tstl-playground example

What does tsc do inside of a @remarks block that's different to a regular JSDoc block?

~Additionally, I think I found a workaround: change {@link ... } to {@linkplain ... } when it's referring to a http link.~ never mind, it causes the same issue tstl playground

aSemy avatar Jul 03 '22 18:07 aSemy

@Perryvw the thing that makes me most suspicious is that in the TSTL playground, the error appears on the method signature node itself rather than on the bit of the JSDoc that it tried to resolve and couldn’t. I can’t quite see what could cause that.

I suspect you at least have an order of operations issue. The diagnostic is generated by a language service API call, which I think in an ideal world would not happen, but you can avoid that pitfall by only asking for diagnostics from a clean program; i.e. make sure you ask for diagnostics before running any other language service methods which could modify the checker state.

andrewbranch avatar Jul 05 '22 16:07 andrewbranch

@andrewbranch Interesting, I was not expecting this order of operations to matter but it seems that at least in our tstl tests we are calling getPreEmitDiagnostics(program) after we are done transforming, which looks like it triggers the issue.

I made the following change which seems to resolve the problem:

     public getLuaResult(): tstl.TranspileVirtualProjectResult {
         const program = this.getProgram();
         const collector = createEmitOutputCollector();
+
+        const preEmitDiagnostics = ts.getPreEmitDiagnostics(program);
+
         const { diagnostics: transpileDiagnostics } = new tstl.Transpiler({ emitHost: this.getEmitHost() }).emit({
             program,
             customTransformers: this.customTransformers,
            writeFile: collector.writeFile,
        });
 
         const diagnostics = ts.sortAndDeduplicateDiagnostics([
-            ...ts.getPreEmitDiagnostics(program),
+            ...preEmitDiagnostics,
             ...transpileDiagnostics,
         ]);

Seems like we are actually doing the same thing everywhere, so it might be an easy workaround for us to just swap some lines around. This does not strike me as intended/expected behavior from TypeScript side either, but at least we can work around it pretty easily for now.

Perryvw avatar Jul 05 '22 20:07 Perryvw

Yeah, double checked with the team and it’s definitely not supposed to happen, though I don’t find it too surprising.

The call to getSymbolAtLocation from buildLinkParts in src/services/utilities.ts is the first thing in the stack that’s possibly suspicious. That call should never be able to trigger an error that getSemanticDiagnostics doesn’t also trigger. I think the checker should probably know based on the location that it shouldn’t trigger name resolution errors there. JSDoc @link tags can probably just be explicitly exempt from errors in resolveEntityName in checker.ts (@sandersn please correct me if that’s not right).

Why this only happens when the @link tag comes after another tag (not just @remarks, happens for any tag) is a total mystery to me.

andrewbranch avatar Jul 05 '22 20:07 andrewbranch

I looked briefly at the code and

  1. @link tags are checked the same regardless of whether they're inside a tag or just the top-level comment text.
  2. They are explicitly exempt from errors in resolveEntityName in that code path, which is the one the compiler uses. The one where they're not obviously exempted is only used by the language service -- but editors don't seem to report those? At least I couldn't get them to in a simple test.

Edit: re-reading @andrewbranch 's comment, the problem might be the language service code in getSymbolOfNameOrPropertyAccessExpression, which might make getSemanticDiagnostics give no error, but getSymbolAtLocation give an error.

sandersn avatar Jul 15 '22 23:07 sandersn

Seems like this is not just an API concern, this comes up in the language service in #50341

DanielRosenwasser avatar Aug 17 '22 20:08 DanielRosenwasser

not working

shahrukhnasir avatar Sep 02 '22 06:09 shahrukhnasir

Not sure if the same issue, but I get the same error message with just @see and @link (no @remarks): https://typescripttolua.github.io/play/#code/PQKhCgAIUhlB7AtgU0gYySgdgFyhaSAAQGdlUBvIgGwEssBrSACxxwAcSAuYYAc1o5mAVwBGAOgyJgiWmgBO8EvABmOYABUAnu2SwFtdutokSw5CWAAWAJwBGAAw2AvvmDhkAD3bx5OSCrCWGg4tPBYkACyWgBiQSFhWAAUAJSQFK5AA

for some reason, it only shows once you start typing in the editor.

SantoJambit avatar Sep 28 '22 12:09 SantoJambit

Did anyone find a workaround?

Pentadome avatar Feb 17 '23 13:02 Pentadome

@Andarist recently fixed a few related bugs; I’m not sure if this got fixed as a side-effect.

andrewbranch avatar Feb 17 '23 17:02 andrewbranch

If this is the same as #50341, which is very likely, then it's still broken as of 5.1 beta.

sandersn avatar May 05 '23 17:05 sandersn