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

jsx formats that cannot be handled. #36

Open
StringKe opened this issue Nov 10, 2023 · 14 comments
Open

jsx formats that cannot be handled. #36

StringKe opened this issue Nov 10, 2023 · 14 comments
Labels
enhancement New feature or request

Comments

@StringKe
Copy link

using this code:

       (0,
       $ht.s)(edt).render((0,
       Zf.jsx)(i.StrictMode, {
           children: (0,
           Zf.jsx)(Qht, {})
       }))

I get this result:

(0, $ht.s)(edt).render(
 (0, Zf.jsx)(i.StrictMode, {
   children: (0, Zf.jsx)(Qht, {}),
 })
);

Probably the original code:

ReactDOM.render(
    <React.StrictMode>
        <App />
    </React.StrictMode>,
    document.getElementById('root')
)
@pionxzh
Copy link
Owner

pionxzh commented Nov 10, 2023

I noticed... (0, $ht.s) in your example should be transformed if you have an import statement or require for $ht.
Did you copy-paste the short code snippet into wakaru playground? so there is no context for the tool to remove it.

But we can still improve this by relaxing the limitation of requiring an import or require.

Here are some improvements that can be made:

  • un-indirect-call should support loose mode to remove all indirect call (unsafe)
    After removing indirect call, it will become
$ht.s(edt).render(<i.StrictMode children={<Qht />} />);
  • Move that children prop
$ht.s(edt).render(
  <i.StrictMode>
    <Qht />
  </i.StrictMode>
);

@pionxzh pionxzh added the enhancement New feature or request label Nov 10, 2023
@0xdevalias
Copy link

Found another example of JSX not parsing how I would have expected. Would this also be resolved by the above?

Details

Source:

var r = require(4337);
var a = require(35250);
var i = require(70079);
var s = require(34303);
var o = require(64135);
var l = require(88038);
var u = require(13282);
function d() {
  var e = (0, r._)(["bg-black rounded-md"]);
  d = function () {
    return e;
  };
  return e;
}
function c() {
  var e = (0, r._)([
    "flex items-center relative text-gray-200 bg-gray-800 px-4 py-2 text-xs font-sans justify-between rounded-t-md ",
    "",
  ]);
  c = function () {
    return e;
  };
  return e;
}
function f() {
  var e = (0, r._)(["p-4 overflow-y-auto"]);
  f = function () {
    return e;
  };
  return e;
}
function h() {
  var e = (0, r._)(["", ""]);
  h = function () {
    return e;
  };
  return e;
}
var g = s.Z.div(d());
var m = s.Z.div(c(), function (e) {
  return e.$isMessageRedesign && "dark:bg-gray-900";
});
var p = s.Z.div(f());
var v = s.Z.code(h(), function (e) {
  return e.$shouldWrap ? "!whitespace-pre-wrap" : "!whitespace-pre";
});
function x(e) {
  var t = e.children;
  var n = e.className;
  var r = e.language;
  var s = e.content;
  var o = (0, i.useCallback)(
    function () {
      navigator.clipboard.writeText(s);
    },
    [s]
  );
  return (0, a.jsx)(b, {
    title: r,
    headerDecoration: (0, a.jsx)(u.Z, { buttonText: "Copy code", onCopy: o }),
    className: "mb-4",
    codeClassName: n,
    children: t,
  });
}
function b(e) {
  var t = e.children;
  var n = e.title;
  var r = e.headerDecoration;
  var i = e.shouldWrapCode;
  var s = e.className;
  var u = e.codeClassName;
  var d = (0, o.hz)().has(l.FZ);
  return (0, a.jsxs)(g, {
    className: s,
    children: [
      (0, a.jsxs)(m, {
        $isMessageRedesign: d,
        children: [n && (0, a.jsx)("span", { children: n }), r],
      }),
      (0, a.jsx)(p, {
        children: (0, a.jsx)(v, {
          $shouldWrap: void 0 !== i && i,
          className: u,
          children: t,
        }),
      }),
    ],
  });
}

module.exports = {
  $: b,
  Z: x,
};

Transformed:

import u from "module-13282.js";

const { _ } = require(4337);

const { jsx, jsxs } = require(35250);

const { useCallback } = require(70079);

const s = require(34303);

const { hz } = require(64135);

const l = require(88038);
function d() {
  const e = _(["bg-black rounded-md"]);
  d = () => e;
  return e;
}
function c() {
  const e = _([
    "flex items-center relative text-gray-200 bg-gray-800 px-4 py-2 text-xs font-sans justify-between rounded-t-md ",
    "",
  ]);
  c = () => e;
  return e;
}
function f() {
  const e = _(["p-4 overflow-y-auto"]);
  f = () => e;
  return e;
}
function h() {
  const e = _(["", ""]);
  h = () => e;
  return e;
}
const g = s.Z.div(d());
const m = s.Z.div(c(), (e) => e.$isMessageRedesign && "dark:bg-gray-900");
const p = s.Z.div(f());
const v = s.Z.code(h(), (e) =>
  e.$shouldWrap ? "!whitespace-pre-wrap" : "!whitespace-pre"
);
function x(e) {
  const { children, className, language, content } = e;

  const o = useCallback(() => {
    navigator.clipboard.writeText(content);
  }, [content]);
  return jsx(b, {
    title: language,
    headerDecoration: <u.Z buttonText="Copy code" onCopy={o} />,
    className: "mb-4",
    codeClassName: className,
    children: children,
  });
}
function b(e) {
  const {
    children,
    title,
    headerDecoration,
    shouldWrapCode,
    className,
    codeClassName,
  } = e;

  const d = hz().has(l.FZ);
  return jsxs(g, {
    className: className,
    children: [
      jsxs(m, {
        $isMessageRedesign: d,
        children: [title && <span children={title} />, headerDecoration],
      }),
      jsx(p, {
        children: jsx(v, {
          $shouldWrap: shouldWrapCode !== undefined && shouldWrapCode,
          className: codeClassName,
          children: children,
        }),
      }),
    ],
  });
}

export default {
  $: b,
  Z: x,
};

@pionxzh
Copy link
Owner

pionxzh commented Nov 13, 2023

@0xdevalias A few places can be fixed

  1. jsxs should be listed in the pragma
  2. This one is not been transformed because v is not a valid JSX element name (<v will be interpreted as a native element)
jsx(p, , {
  children: jsx(v, {
    $shouldWrap: shouldWrapCode !== undefined && shouldWrapCode,
    className: codeClassName,
    children: children,
  }),
}),

if (isCapitalizationInvalid(j, type)) return null

so a fix should be introduced to auto rename that v to things like V or VComp.

@pionxzh
Copy link
Owner

pionxzh commented Nov 14, 2023

@0xdevalias Your example should be good now.

return (
    <G className={className}>
      <M $isMessageRedesign={d}>
        {title && <span>{title}</span>}
        {headerDecoration}
      </M>
      <P>
        {
          <V
            $shouldWrap={shouldWrapCode !== undefined && shouldWrapCode}
            className={codeClassName}
          >
            {children}
          </V>
        }
      </P>
    </G>

@StringKe
Copy link
Author

As a rule of thumb, react projects that use tailwind are likely to use a classname helper class like clsx.

https://www.npmjs.com/package/clsx

@0xdevalias
Copy link

0xdevalias commented Nov 14, 2023

Your example should be good now.

@pionxzh Amazing, thankyou!

Using the same source as before (You can get the full webpack module code i'm unpacking here, and then once unpacked, it's module-2368.js) now gives me this output:

Details

Transformed:

import u from "module-13282.js";

const { _ } = require(4337);

const { jsx, jsxs } = require(35250);

const { useCallback } = require(70079);

const s = require(34303);

const { hz } = require(64135);

const l = require(88038);
function d() {
  const e = _(["bg-black rounded-md"]);
  d = () => e;
  return e;
}
function c() {
  const e = _([
    "flex items-center relative text-gray-200 bg-gray-800 px-4 py-2 text-xs font-sans justify-between rounded-t-md ",
    "",
  ]);
  c = () => e;
  return e;
}
function f() {
  const e = _(["p-4 overflow-y-auto"]);
  f = () => e;
  return e;
}
function h() {
  const e = _(["", ""]);
  h = () => e;
  return e;
}
const G = s.Z.div(d());
const M = s.Z.div(c(), (e) => e.$isMessageRedesign && "dark:bg-gray-900");
const P = s.Z.div(f());
const V = s.Z.code(h(), (e) =>
  e.$shouldWrap ? "!whitespace-pre-wrap" : "!whitespace-pre"
);
function x(e) {
  const { children, className, language, content } = e;

  const o = useCallback(() => {
    navigator.clipboard.writeText(content);
  }, [content]);
  return (
    <B
      title={language}
      headerDecoration={<u.Z buttonText="Copy code" onCopy={o} />}
      className="mb-4"
      codeClassName={className}
    >
      {children}
    </B>
  );
}
function B(e) {
  const {
    children,
    title,
    headerDecoration,
    shouldWrapCode,
    className,
    codeClassName,
  } = e;

  const d = hz().has(l.FZ);
  return (
    <G className={className}>
      <M $isMessageRedesign={d}>
        {title && <span>{title}</span>}
        {headerDecoration}
      </M>
      <P>
        {
          <V
            $shouldWrap={shouldWrapCode !== undefined && shouldWrapCode}
            className={codeClassName}
          >
            {children}
          </V>
        }
      </P>
    </G>
  );
}

export default {
  $: B,
  Z: x,
};

While this is definitely improved from the original, and seems to have fixed the JSX parts, I wonder if there's anything clever that can be done about this sort of pattern (which is probably off topic for this issue):

// ..snip..
function d() {
  const e = _(["bg-black rounded-md"]);
  d = () => e;
  return e;
}
function c() {
  const e = _([
    "flex items-center relative text-gray-200 bg-gray-800 px-4 py-2 text-xs font-sans justify-between rounded-t-md ",
    "",
  ]);
  c = () => e;
  return e;
}
// ..snip..
const G = s.Z.div(d());
const M = s.Z.div(c(), (e) => e.$isMessageRedesign && "dark:bg-gray-900");
// ..snip..

The usage of the _ function seems to imply that it's potentially something like:

And the general pattern of the d/c/f/h functions that redefine themselves seem to be a sort of memoisation pattern (basically something like this, but redefines the function itself):

const d = (() => {
  let memoizedValue;

  return () => {
    if (memoizedValue === undefined) {
      // Compute the value only once
      cachedValue = _(["bg-black rounded-md"]);
    }
    return cachedValue;
  };
})();

Edit: For a far deeper dive into exploring the above code and trying to figure it out, see the following issue:

Edit 2: Further insights about this pattern are explained in the below comment:

@pionxzh
Copy link
Owner

pionxzh commented Nov 14, 2023

These clsx similar library would require module detection, let's move it to another issue.


Thans for the insight on those functions, not sure where they from👀

@pionxzh
Copy link
Owner

pionxzh commented Nov 14, 2023

#41

@0xdevalias
Copy link

Thans for the insight on those functions, not sure where they from

@pionxzh No problem :) I also ended up doing a deeeeep dive into this in the following issue:

Which seemed to identify the library/related libraries; though not fully figure out how all of the code there relates.

These clsx similar library would require module detection, let's move it to another issue.

@pionxzh Sounds like a good idea.

@0xdevalias
Copy link

0xdevalias commented Nov 22, 2023

Thans for the insight on those functions, not sure where they from

Another deep dive the other day turned up some more info on exactly how these functions work/where they come from. See the following comment + issue for notes/references/exploration:

@0xdevalias
Copy link

0xdevalias commented Nov 22, 2023

Summarising what I think is left 'outstanding' in this issue:


Based on the above, I think the only thing potentially remaining before this issue can be closed is:

  • un-indirect-call should support loose mode to remove all indirect call (unsafe) (Ref)

@0xdevalias

This comment was marked as resolved.

@pionxzh

This comment was marked as resolved.

@0xdevalias
Copy link

Can you help me move this case to another issue? 🙏

@pionxzh Sure :) Opened the following and tried to fit the details into the template fields:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants