From b07e9772744f8900b48bbc483d2a935e7ada5851 Mon Sep 17 00:00:00 2001 From: Ahmad Faraz Date: Wed, 1 May 2024 00:23:06 +0500 Subject: [PATCH] fixed inline constant tag name in JSX transformation --- .../transformations/__tests__/un-jsx.spec.ts | 66 +++++++++++++++++-- .../unminify/src/transformations/un-jsx.ts | 47 +++++++++++-- 2 files changed, 103 insertions(+), 10 deletions(-) diff --git a/packages/unminify/src/transformations/__tests__/un-jsx.spec.ts b/packages/unminify/src/transformations/__tests__/un-jsx.spec.ts index 5a3dd52b..d3f94da8 100644 --- a/packages/unminify/src/transformations/__tests__/un-jsx.spec.ts +++ b/packages/unminify/src/transformations/__tests__/un-jsx.spec.ts @@ -163,7 +163,7 @@ function fn() { ` function fn() { const Component = r ? "a" : "div"; - return Hello; + return
Hello
; } `, ) @@ -172,7 +172,7 @@ inlineTest('jsx with dynamic Component tag #2', ` function fn() { return React.createElement( - components[0], + Components, null, "Hello", ); @@ -180,8 +180,7 @@ function fn() { `, ` function fn() { - const Component = components[0]; - return Hello; + return Hello; } `, ) @@ -201,11 +200,68 @@ const Foo = () => { const Foo = () => { const Component = g ? "p" : "div"; const Component_1 = r ? "a" : "div"; - return
barbaz
; + return
bar
baz
; }; `, ) +inlineTest('jsx with dynamic Component tag #4', + ` +function fn() { + const value = "wakaru" + return React.createElement( + value ? "a" : "div", + null, + "Hello", + ); +} +`, + ` +function fn() { + const value = "wakaru" + const Component = value ? "a" : "div"; + return Hello; +} +`, +) + +inlineTest('jsx with dynamic Component tag #5', + ` +function fn() { + const value = "" + return React.createElement( + value ? "a" : "div", + null, + "Hello", + ); +} +`, + ` +function fn() { + const value = "" + const Component = value ? "a" : "div"; + return
Hello
; +} +`, +) + +inlineTest('jsx with dynamic Component tag #6', + ` +function fn() { + const Name = "div"; + const attrs = {id: "x"}; + return React.createElement(Name, attrs); +} +`, + ` +function fn() { + const Name = "div"; + const attrs = {id: "x"}; + return
; +} +`, +) + inlineTest('jsx with child text that should be wrapped', ` function fn() { diff --git a/packages/unminify/src/transformations/un-jsx.ts b/packages/unminify/src/transformations/un-jsx.ts index 9abc5b27..96ec6c30 100644 --- a/packages/unminify/src/transformations/un-jsx.ts +++ b/packages/unminify/src/transformations/un-jsx.ts @@ -102,17 +102,16 @@ export const transformAST: ASTTransformation = (context, params) // bottom-up transformation .reverse() .forEach((path) => { - const jsxElement = toJSX(j, path, pragmas, pragmaFrags) + const jsxElement = toJSX(j, path, pragmas, pragmaFrags, root) if (jsxElement) { const parentWithComments = j.ExpressionStatement.check(path.parent.node) ? path.parent : path removePureAnnotation(j, parentWithComments.node) - path.replace(jsxElement) } }) } -function toJSX(j: JSCodeshift, path: ASTPath, pragmas: string[], pragmaFrags: string[]): JSXElement | JSXFragment | null { +function toJSX(j: JSCodeshift, path: ASTPath, pragmas: string[], pragmaFrags: string[], root: Collection): JSXElement | JSXFragment | null { const scope = path.scope assertScopeExists(scope) @@ -130,13 +129,51 @@ function toJSX(j: JSCodeshift, path: ASTPath, pragmas: string[], if (isCapitalizationInvalid(j, type)) return null - let tag = toJsxTag(j, type) + let tag = toJsxTag(j, type) as JSXIdentifier + + // constant tag name will convert into JSX tag + if (tag?.name) { + root.find(j.VariableDeclarator, { + id: { + type: 'Identifier', + name: tag.name, + }, + }).forEach((path: any) => { + const { id: { loc: { identifierName } } } = path.node + if (tag.name === identifierName) { + tag = { ...tag, name: path.node?.init?.value } + } + }) + } + // If a tag cannot be converted to JSX tag, convert it to a variable if (!tag && !j.SpreadElement.check(type)) { const name = generateName('Component', scope) tag = j.jsxIdentifier(name) const variableDeclaration = j.variableDeclaration('const', [j.variableDeclarator(j.identifier(name), type)]) + const isVariableDeclaration = root.find(j.VariableDeclarator, { + id: { + type: 'Identifier', + name: variableDeclaration.declarations[0].init.test.name, + }, + }) + // if ternary operator variable value exist + if (isVariableDeclaration.length) { + isVariableDeclaration.forEach((path: any) => { + if (path.node.init.value) { + tag = { ...tag, name: variableDeclaration.declarations[0].init.consequent.value } + } + else { + tag = { ...tag, name: variableDeclaration.declarations[0].init.alternate.value } + } + }) + } + else { + if (variableDeclaration.declarations[0].init.alternate.value) { + tag = { ...tag, name: variableDeclaration.declarations[0].init.alternate.value } + } + } insertBefore(j, path, variableDeclaration) scope.markAsStale() } @@ -191,7 +228,7 @@ function toJSX(j: JSCodeshift, path: ASTPath, pragmas: string[], if (attributes.length === 0) { const isFrag1 = j.JSXIdentifier.check(tag) && pragmaFrags.includes(tag.name) - const isFrag2 = j.JSXMemberExpression.check(tag) && pragmaFrags.includes(tag.property.name) + const isFrag2 = j.JSXMemberExpression.check(tag) && pragmaFrags.includes((tag as JSXMemberExpression).property.name) if (isFrag1 || isFrag2) { return j.jsxFragment(j.jsxOpeningFragment(), j.jsxClosingFragment(), children) }