Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ScriptKind.Deferred treated as LanguageVariant.Standard #60125

Open
blake-newman opened this issue Oct 3, 2024 · 7 comments · May be fixed by #60178
Open

ScriptKind.Deferred treated as LanguageVariant.Standard #60125

blake-newman opened this issue Oct 3, 2024 · 7 comments · May be fixed by #60178
Labels
Experimentation Needed Someone needs to try this out to see what happens Suggestion An idea for TypeScript

Comments

@blake-newman
Copy link

🔎 Search Terms

Deferred ScriptKind TSX
Deferred ScriptKind Standard

Vue, eslint, tsx parser error

🕗 Version & Regression Information

Currently looking at TypeScript 5.5+ likely affects most versions of typescript.

⏯ Playground Link

No response

💻 Code

Not specific to TS code but compiler and parsing.

🙁 Actual behavior

When using typescript-eslint with there new projectSettings option, along side vue with tsx. The file fails to parse

Component.vue
41:8  error  Parsing error: '>' expected

Deferred ScriptKinds are treated as LanguageVariant.Standard rather than LanguageVariant.JSX

https://github.com/microsoft/TypeScript/blob/main/src/compiler/parser.ts#L1746
https://github.com/microsoft/TypeScript/blob/main/src/compiler/utilities.ts#L8832

🙂 Expected behavior

Under the assumption that ScriptKind.Deferred could be treated as LanguageVariant.JSX then this resolves typescript-eslints issue with parsing extraFileExtensions such as vue files.

I'm unsure what the consequences and other use cases of ScriptKind.Deferred are so it could be as simple as adjusting getLanguageVariant.

Additional information about the issue

typescript-eslint/typescript-eslint#9934

@RyanCavanaugh
Copy link
Member

This would just change how the problem could happen. In a non-JSX file you might need have a <type>expr type assertion that would then parse incorrectly.

I don't know why typescript-eslint is using Deferred but that's probably the root cause here

@RyanCavanaugh RyanCavanaugh added the Not a Defect This behavior is one of several equally-correct options label Oct 3, 2024
@typescript-bot
Copy link
Collaborator

This issue has been marked as "Not a Defect" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Oct 6, 2024
@blake-newman
Copy link
Author

blake-newman commented Oct 9, 2024

@RyanCavanaugh sorry for the delay; was looking more into the source of typescript-eslint source code to understand why it was marked as Deferred.

From what I understand extraFileExtensions such as vue are marked as Deferred as they are never part of the root files of a project. So this allows the project service to resolve the extra file extension when it is discovering files in the project. This happens as part of the project service internals and not typescript-eslint.

Marking the file as ScriptKind.TSX/TS for the extra file extensions for the project service will result in the following error:

Parsing error: ....vue was not found by the project service

This is due to the project service being unable to resolve the file as part of a project because it's not a known extension and thus means ts doesn't respect it as part of the program root files.

The reason the extra file is not part of the root files when marking as TSX is because the following code to get supported file extensions ignores any extra file extension that is not marked as Deferred.

https://github.com/microsoft/TypeScript/blob/main/src/compiler/utilities.ts#L9867
Changing to:

...mapDefined(extraFileExtensions, x => !flatBuiltins.includes(x.extension as Extension) ? [x.extension] : undefined)

Resolves the issues downstream when setting the extra file extensions. I can't see from usages why we would need to exclude any extra extensions that are not ScriptKind.Deferred.

There is also a lot of jiggery pokery in other tools such as (vue-tsc/volar](https://github.com/volarjs/volar.js/blob/master/packages/typescript/lib/quickstart/runTsc.ts#L72) to modify the code for setting extra file extensions, likely for similar reasons where by the getSupportExtensions is unable to have extra extensions that are not Deferred.

@RyanCavanaugh
Copy link
Member

Changing to...

We could try a PR for this.

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Experimentation Needed Someone needs to try this out to see what happens and removed Not a Defect This behavior is one of several equally-correct options labels Oct 9, 2024
@RyanCavanaugh RyanCavanaugh reopened this Oct 9, 2024
@sheetalkamat
Copy link
Member

There is host configuration command on tsserver that lets you set script kind for file extensions .. using deferred is just default and let plugins handle through wrapping getScriptKind kind of facility so I don’t think the change you are suggesting is the one you need

@sheetalkamat
Copy link
Member

From what I understand extraFileExtensions such as vue are marked as Deferred as they are never part of the root files of a project. So this allows the project service to resolve the extra file extension when it is discovering files in the project. This happens as part of the project service internals and not typescript-eslint.

Also from plugin perspective they are part of root projects and they are provided through getExternalFiles in normal editing scenario. A

@blake-newman
Copy link
Author

blake-newman commented Oct 9, 2024

There is host configuration command on tsserver that lets you set script kind for file extensions .. using deferred is just default and let plugins handle through wrapping getScriptKind kind of facility so I don’t think the change you are suggesting is the one you need

service.setHostConfiguration({
      extraFileExtensions: extraFileExtensions.map(extension => ({
        extension,
        isMixedContent: false,
        scriptKind: ts.ScriptKind.Deferred,
      })),
    });

Typescript eslint does what you are describing i believe.

However if you say set set scriptKind to ts.ScriptKind.TSX, the internals of getSupportedExtensions will end up stripping that extension out as it's not regarded as a Deferred script kind.

That method is then used in many places (when building up the project state). Which then means the extra file is not added to the rootFilesMap and then not part of the project.

Is there an alternative host configuration that should be set?

blake-newman added a commit to blake-newman/TypeScript that referenced this issue Oct 9, 2024
When configuring the language service host with extra file extensions,
the file extension is only regarded as supported if its `Deferred` or like
JS. If the host can delare a specific ScriptKind such as `TSX` for a file
then it will be stripped out with getSupportedExtensions.

This then later causes the programs rootFiles to not include the extra file
extension, and thus be excluded from the program.

If using `Deferred` then the file when parsed will be treated as TS and fail to
compile when using (J)TSX syntax. In majority of cases the script kind will be
known by the consumer and they can set the explicit script kind for the extra
file extension.

Adjust the logic for `getSupportedExtensions` to include any extra file extension
that are not built in. This way all explicit extra file extensions added
will be included in the project/programs root files and an explicit `scriptKind`
can be set.

resolves: microsoft#60125
blake-newman added a commit to blake-newman/TypeScript that referenced this issue Oct 9, 2024
When configuring the language service host with extra file extensions,
the file extension is only regarded as supported if its `Deferred` or like
JS. If the host can delare a specific ScriptKind such as `TSX` for a file
then it will be stripped out with getSupportedExtensions.

This then later causes the programs rootFiles to not include the extra file
extension, and thus be excluded from the program.

If using `Deferred` then the file when parsed will be treated as TS and fail to
compile when using (J)TSX syntax. In majority of cases the script kind will be
known by the consumer and they can set the explicit script kind for the extra
file extension.

Adjust the logic for `getSupportedExtensions` to include any extra file extension
that are not built in. This way all explicit extra file extensions added
will be included in the project/programs root files and an explicit `scriptKind`
can be set.

resolves: microsoft#60125
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Experimentation Needed Someone needs to try this out to see what happens Suggestion An idea for TypeScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants