atom/language-typescript

Type parameters on JSX open tag identifiers cause the JSX block to be highlighted incorrectly

Closed this issue · 11 comments

Edit by @rsese to add code from #34 (comment) and link to Apollo example code

export const TaskListItem = ({ id, children }: taskListItemProps) => (
  <Query<taskListItem, taskListItemVariables>
    query={TASK_LIST_ITEM}
    variables={{ id }}
  >
    {(queryProps) => {
      const { loading, data } = queryProps

      if (!loading && data && data.task) {
        return (
          <Mutations task={data.task}>
            {(mutations) => {
              return children({ ...queryProps, mutations })
            }}
          </Mutations>
        )
      } else {
        return children({ ...queryProps, mutations: undefined })
      }
    }}
  </Query>
)

Apollo code example: https://github.com/apollographql/react-apollo/blob/master/examples/typescript/src/Character.tsx


Prerequisites

Description

when adding aliases (?) to a component the rest of the JSX does not render correctly

for example, in the following code

  <Query<taskListItem, taskListItemVariables>
    query={TASK_LIST_ITEM}
    variables={{ id }}
  >
    {(queryProps) => (
      <Mutations id={id}>
        {(mutations) => {
          const finalProps = { ...queryProps, mutations }
          return children(finalProps)
        }}
      </Mutations>
    )}
  </Query>

the <taskListItem, taskListItemVariables> causes the entire jsx block to be rendered incorrectly.

inspecting it looks like the scope goes from:

source.tsx
meta.var.expr.tsx
meta.tag.tsx
entity.name.tag.tsx
support.class.component.tsx

to

source.tsx
meta.var.expr.tsx
variable.other.readwrite.tsx

Versions

Atom: 1.34.0
language-typescript: 0.4.11

rsese commented

Thanks for the report @chrisdrackett 👍 Could you clarify a few things? I haven't played with JSX before so I don't have any context for what you're describing and want to make sure I'm reproducing the right thing:

when adding aliases (?) to a component

What are the aliases in the code snippet?

the rest of the JSX does not render correctly

Can you share a screenshot of what you see and describe what's incorrect?

inspecting it looks like the scope goes from:

Where in the code are you when you're logging the scopes?

Lastly, do things look ok with Tree-sitter disabled?

Here is a screenshot without the typescript alias(? hopefully I'm using the right term, I'm new to ts):

before

and then after I add the alias:

after

notice that most the coloring (other than red) is lost after the <Query<taskListItem, taskListItemVariables> line.

I currently have tree-sitter disabled because the coloring on files with JSX is completely strange when I turn it on. (here is a screenshot of tree-sitter, I believe:)

tree-sitter

@chrisdrackett It's easier for someone else to reproduce and debug if you provide text that can be copied. Images are good to see exactly what you're talking about though.

sure, I was asked for screenshots so that is what I provided. Here is the related text:

export const TaskListItem = ({ id, children }: taskListItemProps) => (
  <Query<taskListItem, taskListItemVariables>
    query={TASK_LIST_ITEM}
    variables={{ id }}
  >
    {(queryProps) => {
      const { loading, data } = queryProps

      if (!loading && data && data.task) {
        return (
          <Mutations task={data.task}>
            {(mutations) => {
              return children({ ...queryProps, mutations })
            }}
          </Mutations>
        )
      } else {
        return children({ ...queryProps, mutations: undefined })
      }
    }}
  </Query>
)

@Aerijo also, this text was available in my original issue request :D am I missing something? I can provide more if needed!

@chrisdrackett Right, sorry. I only saw the provided images and had a knee jerk reaction.

Adding that extra text makes tree-sitter-typescript interprete the tag as a type assertion, and then it gets an error when it sees the { of {(queryProps). It continues normally, but sees the closing tag as a binary comparison with a regex.

As far as I can tell, that syntax is illegal anyway
Specifically,


The as operator

Recall how to write a type assertion:

var foo = <foo>bar;

This asserts the variable bar to have the type foo. Since TypeScript also uses angle brackets for type assertions, combining it with JSX’s syntax would introduce certain parsing difficulties. As a result, TypeScript disallows angle bracket type assertions in .tsx files.


Does this example compile and run properly?

it does. I got this format from the Apollo Client examples here:

https://github.com/apollographql/react-apollo/blob/master/examples/typescript/src/Character.tsx

not saying those are correct as well, but not only does it compile but I get the correct auto-complete in my editor. I'll keep digging as I'm super new to typescript :)

I stumbled into the same problem today. The syntax is not illegal though, Generic JSX components were introduced in Typescript 2.9. I tried setting the grammar to source.ts, but then I lose emmet, not sure how to proceed.

rsese commented

Confirmed this issue with another maintainer - Tree-sitter doesn't parse this as JSX and is a https://github.com/tree-sitter/tree-sitter-typescript issue.

Updated the issue body with that link to the Apollo example code and the code from #34 (comment).

Hey @as-cii, I'm out of office next week and you have some context on this, so I assigned you. My PRs in tree-sitter/tree-sitter-typescript#68 and #37 should be good to go. I'm just waiting on a second review for the change to tree-sitter-typescript, and I don't anticipate much change will be needed.