pionxzh / wakaru

🔪📦 Javascript decompiler for modern frontend
https://wakaru.vercel.app/
MIT License
274 stars 13 forks source link

Support detect and replace `swc`'s `runtime-helpers` #50

Open 0xdevalias opened 10 months ago

0xdevalias commented 10 months ago

Spinning this out into a new issue so it doesn't get lost among the old one, but follow through to the original comment for more of the deep dive/evidence that lead to this being figured out:

It seems that the issue here is less about smart-rename's handleReactRename not handling useState properly; and more that wakaru needs to add support for swc's 'runtime helper' functions like _sliced_to_array / etc from @swc/helpers; probably in a similar way to how babel's are currently implemented:

This may in part be relevant to the following 'module detection' issue as well:

  • 41

Originally posted by @0xdevalias in https://github.com/pionxzh/wakaru/issues/49#issuecomment-1818812059


See Also

0xdevalias commented 10 months ago

Looking through the rest of the webpack bundle code (Ref) for the 22830 module, we find it in main.js; which after unpacking, becomes module-22830.js:

⇒ npx @wakaru/unpacker main.js -o ./main-unpacked/
# ..snip..

⇒ npx @wakaru/unminify ./main-unpacked/* -o ./main-unminified
# ..snip..
module-22830.js (full source) Unpacked: ```js "use strict";; ; var n = require(59378); function o(e, t) { return ( (function (e) { if (Array.isArray(e)) return e; })(e) || (function (e, t) { var r, n, o = null == e ? null : ("undefined" != typeof Symbol && e[Symbol.iterator]) || e["@@iterator"]; if (null != o) { var a = [], i = !0, u = !1; try { for ( o = o.call(e); !(i = (r = o.next()).done) && (a.push(r.value), !t || a.length !== t); i = !0 ); } catch (e) { (u = !0), (n = e); } finally { try { i || null == o.return || o.return(); } finally { if (u) throw n; } } return a; } })(e, t) || (0, n.N)(e, t) || (function () { throw TypeError( "Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method." ); })() ); } module.exports = { _: o, _sliced_to_array: o }; ``` Unminified: ``` const { N } = require(59378); function o(e, t) { return ( ((e) => { if (Array.isArray(e)) { return e; } })(e) || ((e, t) => { let r; let n; let o = e == null ? null : (typeof Symbol != "undefined" && e[Symbol.iterator]) || e["@@iterator"]; if (o != null) { const a = []; let i = true; let u = false; try { for ( o = o.call(e); !(i = (r = o.next()).done) && (a.push(r.value), !t || a.length !== t); i = true ) {} } catch (e) { u = true; n = e; } finally { try { if (!i && o.return != null) { o.return(); } } finally { if (u) { throw n; } } } return a; } })(e, t) || N(e, t) || (() => { throw TypeError( "Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method." ); })() ); } export default { _: o, _sliced_to_array: o, }; ```

Originally posted by @0xdevalias in https://github.com/pionxzh/wakaru/issues/49#issuecomment-1818812059


The above code (from the previous issue) imported from var n = require(59378);, which was also found in main.js, in module-59378.js:

module-59378.js (full source) Unpacked: ```js "use strict";; var n = require(14770); function o(e, t) { if (e) { if ("string" == typeof e) return (0, n.F)(e, t); var r = Object.prototype.toString.call(e).slice(8, -1); if ( ("Object" === r && e.constructor && (r = e.constructor.name), "Map" === r || "Set" === r) ) return Array.from(r); if ( "Arguments" === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r) ) return (0, n.F)(e, t); } } module.exports = { N: o }; ``` Unminified: ```js const { F } = require(14770); function o(e, t) { if (e) { if (typeof e == "string") { return F(e, t); } let r = Object.prototype.toString.call(e).slice(8, -1); if (r === "Object" && e.constructor) { r = e.constructor.name; } if (r === "Map" || r === "Set") { return Array.from(r); } if ( r === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r) ) { return F(e, t); } } } export default { N: o, }; ```

Based on the regex (/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(), this appears to be @swc/helper's _unsupported_iterable_to_array:

function _unsupported_iterable_to_array(o, minLen) {
    if (!o) return;
    if (typeof o === "string") return _array_like_to_array(o, minLen);
    var n = Object.prototype.toString.call(o).slice(8, -1);
    if (n === "Object" && o.constructor) n = o.constructor.name;
    if (n === "Map" || n === "Set") return Array.from(n);
    if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
}

Which then implies that the above webpacked code can be 're-symbolised' as follows:


Since in the above code, F appears to be _array_like_to_array, then we can follow the const { F } = require(14770); import and imply that module-14770.js (also extracted from main.js) defines it.

module-14770.js (full source) Unpacked: ```js "use strict";; function n(e, t) { (null == t || t > e.length) && (t = e.length); for (var r = 0, n = Array(t); r < t; r++) n[r] = e[r]; return n; } module.exports = { F: n }; ``` Unminified: ```js function n(e, t) { if (t == null || t > e.length) { t = e.length; } for (var r = 0, n = Array(t); r < t; r++) { n[r] = e[r]; } return n; } export default { F: n, }; ```

@swc/helper's _array_like_to_array looks like this; which appears to align with the webpacked code in module-14770.js:

function _array_like_to_array(arr, len) {
    if (len == null || len > arr.length) len = arr.length;
    for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
    return arr2;
}

Which implies that the webpacked code can be 're-symbolised' as follows:

0xdevalias commented 10 months ago

The seemingly full list of @swc/helpers helpers is availabe at:

And more about the swc compilation setting that controls whether helpers are inlined or made external is available here:

0xdevalias commented 10 months ago

Looking at module-10604.js, we can see that it's a React component:

module-10604.js (full source) Unpacked: ```js var r = require(39324), a = require(22830), i = require(4337), o = require(35250), s = require(19841), l = require(70079), u = require(34303), d = require(38317); function c() { var e = (0, i._)(["absolute right-0 top-1/2 -translate-y-1/2"]); return ( (c = function () { return e; }), e ); } exports.Z = l.forwardRef(function (e, t) { var n = e.name, i = e.placeholder, u = e.type, c = e.displayName, h = e.onChange, g = e.onBlur, m = e.value, p = e.saveOnBlur, v = e.icon, x = e.onInputIconClick, b = e.className, y = e.autoComplete, w = e.autoFocus, j = e.onPressEnter, _ = (0, a._)((0, l.useState)(m), 2), C = _[0], M = _[1], k = (0, l.useCallback)( function (e) { null == g || g(e), p && M(e.target.value); }, [g, p] ), T = (0, l.useCallback)( function (e) { null == h || h(e), p && M(e.target.value); }, [h, p] ), N = (0, l.useCallback)( function (e) { "Enter" === e.key && j && (e.preventDefault(), j()); }, [j] ); (0, l.useEffect)( function () { M(m); }, [m] ); var S = (0, r._)({}, p ? {} : { value: m }, p ? { value: C } : {}); return (0, o.jsxs)("div", { className: (0, s.Z)("rounded-md border border-gray-300 px-3 py-2 shadow-sm focus-within:border-indigo-600 focus-within:ring-1 focus-within:ring-indigo-600 dark:bg-gray-700", b), children: [(0, o.jsx)("label", { htmlFor: n, className: "block text-xs font-medium text-gray-900 dark:text-gray-100", children: c }), (0, o.jsxs)("div", { className: (0, s.Z)(c && "mt-1", "relative"), children: [(0, o.jsx)("input", (0, r._)({ ref: t, type: u, name: n, id: n, className: (0, s.Z)("block w-full border-0 p-0 text-gray-900 placeholder-gray-500 outline-none focus:ring-0 dark:bg-gray-700 dark:text-gray-100 sm:text-sm", v && "pr-6"), placeholder: i, onBlur: k, onChange: T, onKeyDown: N, autoComplete: y, autoFocus: w }, S)), v && (0, o.jsx)(f, { onClick: x, children: (0, o.jsx)(d.ZP, { icon: v }) })] })] }); }); var f = u.Z.button(c()); ``` Unminified: ```js const { _: _$1 } = require(39324); const { _: _$0 } = require(22830); const { _ } = require(4337); const { jsxs, jsx } = require(35250); const { Z: Z$0 } = require(19841); const l = require(70079); const { useState, useCallback, useEffect } = l; const u = require(34303); const d = require(38317); function c() { const e = _(["absolute right-0 top-1/2 -translate-y-1/2"]); c = () => e; return e; } export const Z = l.forwardRef((e, t) => { const { name, placeholder, type, displayName, onChange, onBlur, value, saveOnBlur, icon, onInputIconClick, className, autoComplete, autoFocus, onPressEnter, } = e; const [C, M] = _$0(useState(value), 2); const k = useCallback( (e) => { if (onBlur != null) { onBlur(e); } if (saveOnBlur) { M(e.target.value); } }, [onBlur, saveOnBlur] ); const T = useCallback( (e) => { if (onChange != null) { onChange(e); } if (saveOnBlur) { M(e.target.value); } }, [onChange, saveOnBlur] ); const N = useCallback( (e) => { if (e.key === "Enter" && onPressEnter) { e.preventDefault(); onPressEnter(); } }, [onPressEnter] ); useEffect(() => { M(value); }, [value]); const S = _$1( {}, saveOnBlur ? {} : { value: value }, saveOnBlur ? { value: C } : {} ); return (
{icon && {}}
); }); var F = u.Z.button(c()); ```

Originally posted by @0xdevalias in https://github.com/pionxzh/wakaru/issues/49#issuecomment-1818812059

Looking at the imports of the unminified source, we see:

const { _: _$1 } = require(39324);

const { _: _$0 } = require(22830);

const { _ } = require(4337);

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

const { Z: Z$0 } = require(19841);

const l = require(70079);

const { useState, useCallback, useEffect } = l;

const u = require(34303);
const d = require(38317);

Searching our webpacked code (Ref), we find these modules defined in the following locations:

Which we can unpack into their individual module files as follows:

⇒ cd ./unpacked/_next/static/chunks
⇒ npx @wakaru/unpacker main.js -o ./main-unpacked/
Generated 98 modules from main.js to main-unpacked (2,949.1ms)

⇒ npx @wakaru/unminify ./main-unpacked/* -o ./main-unminified
# ..snip..
⇒ npx @wakaru/unpacker pages/_app.js -o ./pages/_app-unpacked/
Generated 213 modules from pages/_app.js to pages/_app-unpacked (24,049ms)

⇒ npx @wakaru/unminify ./pages/_app-unpacked/* -o ./pages/_app-unminified
# ..snip..
⇒ npx @wakaru/unpacker framework.js -o ./framework-unpacked/
Generated 9 modules from framework.js to framework-unpacked (3,800.3ms)

⇒ npx @wakaru/unminify ./framework-unpacked/* -o ./framework-unminified
# ..snip..

framework.js

framework.js seems to mostly be React related.

module-35250.js is just module.exports = require(82875);, and module-82875.js is:

/**
 * @license React
 * react-jsx-runtime.production.min.js
 *
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */ 

module-70079.js is just module.exports = require(99504);, and module-99504.js is:

/**
 * @license React
 * react.production.min.js
 *
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

main.js

module-39324.js appears to be @swc/helpers _object_spread

module-39324.js (full source) Unpacked: ```js "use strict";; ; var n = require(96237); function o(e) { for (var t = 1; t < arguments.length; t++) { var r = null != arguments[t] ? arguments[t] : {}, o = Object.keys(r); "function" == typeof Object.getOwnPropertySymbols && (o = o.concat( Object.getOwnPropertySymbols(r).filter(function (e) { return Object.getOwnPropertyDescriptor(r, e).enumerable; }) )), o.forEach(function (t) { (0, n.j)(e, t, r[t]); }); } return e; } module.exports = { _: o, _object_spread: o }; ``` Unminified: ```js const { j } = require(96237); function o(e) { for (let t = 1; t < arguments.length; t++) { const r = arguments[t] != null ? arguments[t] : {}; let o = Object.keys(r); if (typeof Object.getOwnPropertySymbols == "function") { o = o.concat( Object.getOwnPropertySymbols(r).filter( (e) => Object.getOwnPropertyDescriptor(r, e).enumerable ) ); } o.forEach((t) => { j(e, t, r[t]); }); } return e; } export default { _: o, _object_spread: o, }; ```

Which would imply that the const { j } = require(96237); import would be import { _define_property } from "./_define_property.js"; (which, looking at the webpacked code, module-96237.js does appear to be):


module-22830.js we already figured out in another issue is @swc/helpers _sliced_to_array:

pages/_app.js

module-4337.js appears to be @swc/helpers _tagged_template_literal

module-4337.js (full source) Unpacked: ```js "use strict";; function Y(U, B) { return ( B || (B = U.slice(0)), Object.freeze( Object.defineProperties(U, { raw: { value: Object.freeze(B) } }) ) ); } module.exports = { _: Y }; ``` Unminified: ```js function Y(U, B) { if (!B) { B = U.slice(0); } return Object.freeze( Object.defineProperties(U, { raw: { value: Object.freeze(B) } }) ); } export default { _: Y, }; ```

Not sure what module-19841.js is exactly.. but it seems to export a .Z that is used in a lot of JSX className fields.. so it's probably something like classnames / clsx / tw-merge or similar maybe?

Potentially related:

module-19841.js (full source) Unpacked: ```js "use strict";; function Y(U) { var B, G, V = ""; if ("string" == typeof U || "number" == typeof U) V += U; else if ("object" == typeof U) { if (Array.isArray(U)) for (B = 0; B < U.length; B++) U[B] && (G = Y(U[B])) && (V && (V += " "), (V += G)); else for (B in U) U[B] && (V && (V += " "), (V += B)); } return V; } function V() { for (var U, B, G = 0, V = ""; G < arguments.length; ) (U = arguments[G++]) && (B = Y(U)) && (V && (V += " "), (V += B)); return V; } exports.Z = V; ``` Unminified: ```js function Y(U) { let B; let G; let V = ""; if (typeof U == "string" || typeof U == "number") { V += U; } else if (typeof U == "object") { if (Array.isArray(U)) { for (B = 0; B < U.length; B++) { if (U[B] && (G = Y(U[B]))) { V && (V += " "); V += G; } } } else { for (B in U) { if (U[B]) { V && (V += " "); V += B; } } } } return V; } export function Z() { let U; let B; for (var G = 0, V = ""; G < arguments.length; ) { if ((U = arguments[G++]) && (B = Y(U))) { V && (V += " "); V += B; } } return Z; } ```

module-34303 is explored in depth in the following issue, and appears to be related to styled-components / Tailwind-Styled-Component / similar libs:


module-38317.js looks like it might be app specific code containing a bunch of svg's in JSX format, etc.

It imports from some more libraries:

const { _: _$1 } = require(39324);

const { _: _$0 } = require(71209);

const { _ } = require(70216);

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

const { Z: Z$0 } = require(19841);

With the unique ones we haven't yet looked at being:

0xdevalias commented 10 months ago

main.js

module-71209.js appears to be @swc/helpers _object_spread_props

module-71209.js (full source) Unpacked: ```js "use strict";; function n(e, t) { return ( (t = null != t ? t : {}), Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : (function (e, t) { var r = Object.keys(e); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); r.push.apply(r, n); } return r; })(Object(t)).forEach(function (r) { Object.defineProperty( e, r, Object.getOwnPropertyDescriptor(t, r) ); }), e ); } ; module.exports = { _: n, _object_spread_props: n }; ``` Unminified: ```js function n(e, t) { t = t != null ? t : {}; if (Object.getOwnPropertyDescriptors) { Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)); } else { ((e, t) => { const r = Object.keys(e); if (Object.getOwnPropertySymbols) { const n = Object.getOwnPropertySymbols(e); r.push.apply(r, n); } return r; })(Object(t)).forEach((r) => { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } export default { _: n, _object_spread_props: n, }; ```

module-70216.js appears to be @swc/helpers _object_without_properties

module-70216.js (full source) Unpacked: ```js "use strict";; function n(e, t) { if (null == e) return {}; var r, n, o = (function (e, t) { if (null == e) return {}; var r, n, o = {}, a = Object.keys(e); for (n = 0; n < a.length; n++) (r = a[n]), t.indexOf(r) >= 0 || (o[r] = e[r]); return o; })(e, t); if (Object.getOwnPropertySymbols) { var a = Object.getOwnPropertySymbols(e); for (n = 0; n < a.length; n++) (r = a[n]), !(t.indexOf(r) >= 0) && Object.prototype.propertyIsEnumerable.call(e, r) && (o[r] = e[r]); } return o; } ; module.exports = { _: n, _object_without_properties: n }; ``` Unminified: ```js function n(e, t) { if (e == null) { return {}; } let r; let n; const o = ((e, t) => { if (e == null) { return {}; } let r; let n; const o = {}; const a = Object.keys(e); for (n = 0; n < a.length; n++) { r = a[n]; if (!t.includes(r)) { o[r] = e[r]; } } return o; })(e, t); if (Object.getOwnPropertySymbols) { const a = Object.getOwnPropertySymbols(e); for (n = 0; n < a.length; n++) { r = a[n]; if (!t.includes(r) && Object.prototype.propertyIsEnumerable.call(e, r)) { o[r] = e[r]; } } } return o; } export default { _: n, _object_without_properties: n, }; ```
0xdevalias commented 10 months ago

The full list of @swc/helpers is here:

Full list - `_apply_decorated_descriptor` - `_apply_decs_2203_r` - `_array_like_to_array` - `_array_with_holes` - `_array_without_holes` - `_assert_this_initialized` - `_async_generator` - `_async_generator_delegate` - `_async_iterator` - `_async_to_generator` - `_await_async_generator` - `_await_value` - `_check_private_redeclaration` - `_class_apply_descriptor_destructure` - `_class_apply_descriptor_get` - `_class_apply_descriptor_set` - `_class_apply_descriptor_update` - `_class_call_check` - `_class_check_private_static_access` - `_class_check_private_static_field_descriptor` - `_class_extract_field_descriptor` - `_class_name_tdz_error` - `_class_private_field_destructure` - `_class_private_field_get` - `_class_private_field_init` - `_class_private_field_loose_base` - `_class_private_field_loose_key` - `_class_private_field_set` - `_class_private_field_update` - `_class_private_method_get` - `_class_private_method_init` - `_class_private_method_set` - `_class_static_private_field_destructure` - `_class_static_private_field_spec_get` - `_class_static_private_field_spec_set` - `_class_static_private_field_update` - `_class_static_private_method_get` - `_construct` - `_create_class` - `_create_for_of_iterator_helper_loose` - `_create_super` - `_decorate` - `_defaults` - `_define_enumerable_properties` - `_define_property` - `_dispose` - `_export_star` - `_extends` - `_get` - `_get_prototype_of` - `_inherits` - `_inherits_loose` - `_initializer_define_property` - `_initializer_warning_helper` - `_instanceof` - `_interop_require_default` - `_interop_require_wildcard` - `_is_native_function` - `_is_native_reflect_construct` - `_iterable_to_array` - `_iterable_to_array_limit` - `_iterable_to_array_limit_loose` - `_jsx` - `_new_arrow_check` - `_non_iterable_rest` - `_non_iterable_spread` - `_object_destructuring_empty` - `_object_spread` - `_object_spread_props` - `_object_without_properties` - `_object_without_properties_loose` - `_possible_constructor_return` - `_read_only_error` - `_set` - `_set_prototype_of` - `_skip_first_generator_next` - `_sliced_to_array` - `_sliced_to_array_loose` - `_super_prop_base` - `_tagged_template_literal` - `_tagged_template_literal_loose` - `_throw` - `_to_array` - `_to_consumable_array` - `_to_primitive` - `_to_property_key` - `_ts_decorate` - `_ts_generator` - `_ts_metadata` - `_ts_param` - `_ts_values` - `_type_of` - `_unsupported_iterable_to_array` - `_update` - `_using` - `_wrap_async_generator` - `_wrap_native_super` - `_write_only_error`

Searching my webpacked code (Ref) for functions that have a similar format to the helpers:

⇒ find . -type f -exec grep -E '_[[:alnum:]_]+\s*:\s*function' {} +

# ..snip..
# These don't seem to be @swc/helpers related?
./653.js:          __assign: function () {
./653.js:          __asyncDelegator: function () {
./653.js:          __asyncGenerator: function () {
./653.js:          __asyncValues: function () {
./653.js:          __await: function () {
./653.js:          __awaiter: function () {
./653.js:          __classPrivateFieldGet: function () {
./653.js:          __classPrivateFieldIn: function () {
./653.js:          __classPrivateFieldSet: function () {
./653.js:          __createBinding: function () {
./653.js:          __decorate: function () {
./653.js:          __exportStar: function () {
./653.js:          __extends: function () {
./653.js:          __generator: function () {
./653.js:          __importDefault: function () {
./653.js:          __importStar: function () {
./653.js:          __makeTemplateObject: function () {
./653.js:          __metadata: function () {
./653.js:          __param: function () {
./653.js:          __read: function () {
./653.js:          __rest: function () {
./653.js:          __spread: function () {
./653.js:          __spreadArray: function () {
./653.js:          __spreadArrays: function () {
./653.js:          __values: function () {
# ..snip..
# These don't seem to be @swc/helpers related?
./1f110208.js:          __parse: function (e, t) {
./1f110208.js:          __renderToHTMLTree: function (e, t) {
./1f110208.js:          __setFontMetrics: function (e, t) {
./1f110208.js:          __defineMacro: function (e, t) {
# ..snip..
# These do seem to be @swc/helpers related
./main.js:          _async_to_generator: function () {
./main.js:          _class_call_check: function () {
./main.js:          _construct: function () {
./main.js:          _create_class: function () {
./main.js:          _create_super: function () {
./main.js:          _inherits: function () {
./main.js:          _interop_require_default: function () {
./main.js:          _interop_require_wildcard: function () {
./main.js:          _object_spread: function () {
./main.js:          _object_spread_props: function () {
./main.js:          _object_without_properties: function () {
./main.js:          _sliced_to_array: function () {
./main.js:          _to_consumable_array: function () {
./main.js:          _ts_generator: function () {
./main.js:          _type_of: function () {
./main.js:          _wrap_native_super: function () {
# ..snip..
# These don't seem to be @swc/helpers related?
./pages/payments/success.js:          __assign: function () {
./pages/payments/success.js:          __asyncDelegator: function () {
./pages/payments/success.js:          __asyncGenerator: function () {
./pages/payments/success.js:          __asyncValues: function () {
./pages/payments/success.js:          __await: function () {
./pages/payments/success.js:          __awaiter: function () {
./pages/payments/success.js:          __classPrivateFieldGet: function () {
./pages/payments/success.js:          __classPrivateFieldIn: function () {
./pages/payments/success.js:          __classPrivateFieldSet: function () {
./pages/payments/success.js:          __createBinding: function () {
./pages/payments/success.js:          __decorate: function () {
./pages/payments/success.js:          __exportStar: function () {
./pages/payments/success.js:          __extends: function () {
./pages/payments/success.js:          __generator: function () {
./pages/payments/success.js:          __importDefault: function () {
./pages/payments/success.js:          __importStar: function () {
./pages/payments/success.js:          __makeTemplateObject: function () {
./pages/payments/success.js:          __metadata: function () {
./pages/payments/success.js:          __param: function () {
./pages/payments/success.js:          __read: function () {
./pages/payments/success.js:          __rest: function () {
./pages/payments/success.js:          __spread: function () {
./pages/payments/success.js:          __spreadArray: function () {
./pages/payments/success.js:          __spreadArrays: function () {
./pages/payments/success.js:          __values: function () {
# ..snip..

For the __ helpers that aren't @swc/helpers related, I did a GitHub code search:

And it looks like they are probably related to microsoft/tslib:

0xdevalias commented 10 months ago

The following relates to @swc/helpers _tagged_template_literal + self memoisation pattern that it uses for tagged template literals:

Smart-Rename for 'function replaces self' memoisation pattern

We could potentially detect memoisation patterns like the following, and rename the function something more useful:

function p() {
  var e = (0, r._)([
    "\n  absolute w-4 h-4 rounded-full text-[10px] text-white flex  justify-center items-center right-0 top-[20px] -mr-2 border border-white\n  ",
    "\n  ",
    "\n",
  ]);
  return (
    (p = function () {
      return e;
    }),
    e
  );
}

@pionxzh I just had another idea about this, based on some of my deep diving into @swc/helpers tonight.. and I think this is actually another swc related transpilation; related to template literals.

Using the swc playground:

If I pass in some code like this:

const foo = bar`
  staticOne
  staticTwo
  ${dynamicOne}
  ${dynamicTwo}
  staticThree
  ${dynamicThree}
`

It transpiles to this:

function _tagged_template_literal(strings, raw) {
    if (!raw) {
        raw = strings.slice(0);
    }
    return Object.freeze(Object.defineProperties(strings, {
        raw: {
            value: Object.freeze(raw)
        }
    }));
}

function _templateObject() {
    var data = _tagged_template_literal([
        "\n  staticOne\n  staticTwo\n  ",
        "\n  ",
        "\n  staticThree\n  ",
        "\n"
    ]);
    _templateObject = function _templateObject() {
        return data;
    };
    return data;
}

var foo = bar(_templateObject(), dynamicOne, dynamicTwo, dynamicThree);

The _tagged_template_literal function comes from @swc/helpers:

Whereas the _templateObject is generated from our input data; and seems to follow the same 'self memoising function' pattern that I identified earlier in the webpacked code.

Looking at the signature for tagged template functions:

We can see that they take a strings param (represented by the memoised _templateObject), followed by a param for each dynamic expression; which we can see is what happens on the final line:

var foo = bar(_templateObject(), dynamicOne, dynamicTwo, dynamicThree);

Based on that, we could 're-symbolise' that webpacked code as:

function _templateObjectP() {
  var data = _tagged_template_literal([
    "\n  absolute w-4 h-4 rounded-full text-[10px] text-white flex  justify-center items-center right-0 top-[20px] -mr-2 border border-white\n  ",
    "\n  ",
    "\n",
  ]);

  _templateObjectP = function _templateObject() {
    return data;
  };

  return data;
}

y = d.Z.span(
  _templateObjectP(),
  function (e) {
    return "warning" === e.$type && "bg-orange-500 text-white";
  },
  function (e) {
    return "danger" === e.$type && "bg-red-500 text-white";
  }
),

Which we could then 'normalise' back to the original tagged template literal syntax as:

y = d.Z.span`
  absolute w-4 h-4 rounded-full text-[10px] text-white flex  justify-center items-center right-0 top-[20px] -mr-2 border border-white
  function (e) {
    return "warning" === e.$type && "bg-orange-500 text-white";
  }
  function (e) {
    return "danger" === e.$type && "bg-red-500 text-white";
  }
`;

Or even simplify it further to just:

y = d.Z.span`
  absolute w-4 h-4 rounded-full text-[10px] text-white flex  justify-center items-center right-0 top-[20px] -mr-2 border border-white
  (e) => "warning" === e.$type && "bg-orange-500 text-white"
  (e) => "danger" === e.$type && "bg-red-500 text-white"
`;

ChatGPT Explanation > The provided code snippet demonstrates how a tagged template literal is transpiled by SWC, a JavaScript/TypeScript compiler. Let's break down how it works: > > ### Tagged Template Literals in JavaScript > > Before diving into the transpiled code, it's important to understand what tagged template literals are in JavaScript. They allow you to parse template literals with a function. The syntax looks like this: > > ```javascript > const result = tagFunction`string text ${expression} string text`; > ``` > > In this syntax, `tagFunction` is a function that gets called with the parts of the template literal. > > ### Transpiled Code Breakdown > > #### The `_tagged_template_literal` Function > > ```javascript > function _tagged_template_literal(strings, raw) { > if (!raw) { > raw = strings.slice(0); > } > return Object.freeze(Object.defineProperties(strings, { > raw: { > value: Object.freeze(raw) > } > })); > } > ``` > > - **Purpose**: This function is used to process the template strings and their raw representations. > - **Parameters**: > - `strings`: An array of string values from the template literal. > - `raw`: The raw string representations (as if backslashes in the strings were not processed as escape characters). > - **Process**: > - If `raw` is not provided, it creates a copy of `strings`. > - It then freezes the `strings` array and adds a `raw` property to it, containing the frozen `raw` array. > - **Freezing**: `Object.freeze` is used to make sure that the arrays cannot be altered, which is important for template literals to maintain their integrity. > > #### The `_templateObject` Function > > ```javascript > function _templateObject() { > var data = _tagged_template_literal([ > "\n staticOne\n staticTwo\n ", > "\n ", > "\n staticThree\n ", > "\n" > ]); > _templateObject = function _templateObject() { > return data; > }; > return data; > } > ``` > > - **Purpose**: This function initializes the template strings and caches them. > - **Process**: > - It calls `_tagged_template_literal` with the static parts of the template literal. > - The function is then overridden to return the cached `data` on subsequent calls. This ensures that the template strings are only processed once and then reused, which improves performance. > > #### Usage in the Template Tag > > ```javascript > var foo = bar(_templateObject(), dynamicOne, dynamicTwo, dynamicThree); > ``` > > - `bar` is the tag function. > - `_templateObject()` returns the processed and frozen template strings. > - `dynamicOne`, `dynamicTwo`, and `dynamicThree` are the dynamic expressions passed to the tag function. > > ### Summary > > The transpilation process converts a tagged template literal into a form where the template strings are processed and frozen for immutability and performance. The tag function then receives these processed strings and any dynamic values as arguments. This approach maintains the integrity of template literals while optimizing them for repeated use.

Originally posted by @0xdevalias in https://github.com/pionxzh/wakaru/issues/40#issuecomment-1819170475

0xdevalias commented 10 months ago

Helper functions like __extends or _inherits are generated as inline, not imported as modules:

How can we detect them?

While I don't know the specific answer to that off the top of my head, here are the relevant issues/references related to it:

Also:

Originally posted by @0xdevalias in https://github.com/pionxzh/wakaru/issues/58#issuecomment-1823773298

——

Helper functions like __extends or _inherits are generated as inline, not imported as modules:

How can we detect them?

Based on what I know, helpers can be inlined or extracted. Currently, the module scanning is based on regex matching (see babel reference) which also works for inlined helpers.

These examples have been updated to external-helper mode.

Originally posted by @pionxzh in https://github.com/pionxzh/wakaru/issues/58#issuecomment-1823777900