microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

Home Page:https://www.typescriptlang.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

EmitResolver cannot handle JsxOpeningLikeElement and JsxOpeningFragment that didn't originate from the parse tree

itsdouges opened this issue Β· comments

TypeScript Version: 3.7.x-dev.201xxxxx

Search Terms:

Debug Failure. False expression., typescript transformer, jsx element

Code

  • clone https://github.com/madou/untitled-css-in-js-project
  • run git checkout b229dc749e4614bb8d9194c8de340a82f10c8f8a
  • run yarn
  • run yarn test
  • notice one test fails should not blow up when transforming with const
  • notice a similar test but with var instead of const passes

the node transformation is done here - if i return the original jsx element node then the test passes. but then that defeats the purpose of the transformer.. πŸ˜›

the code is essentially transforming

const Component = () => <div css={{ fontSize: '20px' }}>hello world</div>;

to

const Component = () => (
<>
  <style>{'.a { font-size: 20px; } '}</style>
  <div className="a">hello world</div>
</>
);

Expected behavior:

it works no error thrown

Actual behavior:

"Debug Failure. False expression." error thrown. also tried with nightly typescript version - same error.

Related Issues:

#24380

πŸ˜„ would love to get this figured out! hoping it's just something i've done wrong. make from this twitter thread https://twitter.com/orta/status/1206139333448732672

hi is @rbuckton going to be working on this? if not is there any pointers you can give me to fix this? πŸ˜„

TL;DR:

- ts.createJsxOpeningElement(ts.createIdentifier('style'), [], ts.createJsxAttributes([])), node,
+ ts.setOriginalNode(ts.createJsxOpeningElement(ts.createIdentifier('style'), [], ts.createJsxAttributes([])), node),

- ts.createJsxOpeningFragment(),
+ ts.setOriginalNode(ts.createJsxOpeningFragment(), node),

The issue title should rather be: "EmitResolver cannot handle JsxOpeningLikeElement and JsxOpeningFragment that didn't originate from the parse tree"


Explanation:

I looked into this. The es2015 transform tries to generate a unique name for block-scoped bindings if it has the same name as another binding in the same function scope. If there is any block scoped binding in the file, it tries to look up every Identifier to detect potential collisions. Since var is not block-scoped, this code path is not taken in your other test.
Finding out whether there's another binding uses resolveName which relies on Node#parent to walk up the AST. This is a really bad idea in transforms as transformed nodes don't have a parent. resolveNameHelper contains an assertion that expects the function to only exit at a SourceFile as that's typically the only Node without parent.
To prevent everything from blowing up, there's a check in getReferencedDeclarationWithCollidingName to return early if the current Identifier doesn't come from the parse tree (i.e. the original node is not synthesized) and therefore has no parent.

Unfortunately there's the JSX transform transforming your JSX Elements to JSX-factory calls. This code (createReactNamespace in factory.ts) does some trickery to make it look like real nodes from the parse tree. It unsets the Synthesized flag and sets the parent property to the original node of the current JsxOpeningLikeElement | JsxOpeningFragment.
But your JsxOpeningLikeElements and JsxOpeningFragments don't have an original node. Therefore parent is set to undefined which trips up resolveNameHelper as explained above.

hi @ajafff really appreciate you looking into this - thanks!

with this new knowledge for replacing nodes - how would you recommend replacing a node in a typescript transformer the proper way? (let's say I want to change a function declaration to an arrow function) is setOriginalNode needed to do that every time?

i've been writing up this handbook https://github.com/madou/typescript-transformer-handbook - would love to have all pro tips and how to's etc in it. if you have time to give it a proof read would be great πŸ˜„


fix applied, works great thanks mate

atlassian-labs/compiled@8e30b7c