From 2fb95bb97a87f0c7c4dc4dccb8b3393249c2d37c Mon Sep 17 00:00:00 2001 From: Ahmad Faraz <60960217+AhmadFaraz-crypto@users.noreply.github.com> Date: Thu, 9 May 2024 15:10:18 +0500 Subject: [PATCH] feat(un-jsx): inline constant tag inlining (#129) * feat(un-jsx): improve jsx constant tag inlining * test: update test cases * refactor(un-jsx): remove array inlining * refactor(un-jsx): remove ternary inlining * refactor(un-jsx): rewrite the implementation of constant tag variable inlining --------- Co-authored-by: Pionxzh --- .../transformations/__tests__/un-jsx.spec.ts | 29 +++++++++++++++++++ .../unminify/src/transformations/un-jsx.ts | 23 ++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/packages/unminify/src/transformations/__tests__/un-jsx.spec.ts b/packages/unminify/src/transformations/__tests__/un-jsx.spec.ts index 5a3dd52b..194e86aa 100644 --- a/packages/unminify/src/transformations/__tests__/un-jsx.spec.ts +++ b/packages/unminify/src/transformations/__tests__/un-jsx.spec.ts @@ -206,6 +206,35 @@ const Foo = () => { `, ) +inlineTest('jsx with dynamic Component tag - tag name in constant variable', + ` +function fn() { + const Name = "div"; + return React.createElement(Name, null); +} +`, + ` +function fn() { + return
; +} +`, +) + +inlineTest('jsx with dynamic Component tag - tag name in constant variable but the value is not a string', + ` +function fn() { + const Name = 1; + return React.createElement(Name, null); +} +`, + ` +function fn() { + const Name = 1; + 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..ddecf690 100644 --- a/packages/unminify/src/transformations/un-jsx.ts +++ b/packages/unminify/src/transformations/un-jsx.ts @@ -4,6 +4,7 @@ import { removePureAnnotation } from '@wakaru/ast-utils/comments' import { generateName } from '@wakaru/ast-utils/identifier' import { insertBefore } from '@wakaru/ast-utils/insert' import { isNull, isTrue, isUndefined } from '@wakaru/ast-utils/matchers' +import { findDeclaration, removeDeclarationIfUnused } from '@wakaru/ast-utils/scope' import { nonNullable } from '@wakaru/shared/array' import { createJSCodeshiftTransformationRule } from '@wakaru/shared/rule' import { z } from 'zod' @@ -106,7 +107,6 @@ export const transformAST: ASTTransformation = (context, params) if (jsxElement) { const parentWithComments = j.ExpressionStatement.check(path.parent.node) ? path.parent : path removePureAnnotation(j, parentWithComments.node) - path.replace(jsxElement) } }) @@ -131,6 +131,27 @@ function toJSX(j: JSCodeshift, path: ASTPath, pragmas: string[], if (isCapitalizationInvalid(j, type)) return null let tag = toJsxTag(j, type) + + // constant tag name will convert into JSX tag + if (j.JSXIdentifier.check(tag)) { + const scope = path.scope + assertScopeExists(scope) + + const tagName = tag.name + const declaration = findDeclaration(scope, tagName) + if (declaration) { + // if the tag is a variable and it's string literal, inline it + const variableDeclarator = j(declaration).closest(j.VariableDeclarator) + if (variableDeclarator.size() === 1) { + const init = variableDeclarator.get().node.init + if (j.StringLiteral.check(init)) { + tag = j.jsxIdentifier(init.value) + removeDeclarationIfUnused(j, path, tagName) + } + } + } + } + // 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)