{"id":17274603,"url":"https://github.com/rip21/babel-plugin-hyperscript-to-jsx","last_synced_at":"2025-04-14T08:41:16.995Z","repository":{"id":30272449,"uuid":"124455036","full_name":"RIP21/babel-plugin-hyperscript-to-jsx","owner":"RIP21","description":"This plugin transforms react-hyperscript into JSX. Intended to be used as codemod.","archived":false,"fork":false,"pushed_at":"2023-01-04T21:42:41.000Z","size":1424,"stargazers_count":20,"open_issues_count":15,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-27T22:12:43.951Z","etag":null,"topics":["babel","babel-codemod","babel-plugin","babel-plugin-hyperscript","codemod","hyperscript","jsx","react"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RIP21.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-03-08T22:20:07.000Z","updated_at":"2022-11-02T11:55:52.000Z","dependencies_parsed_at":"2023-01-11T15:37:18.018Z","dependency_job_id":null,"html_url":"https://github.com/RIP21/babel-plugin-hyperscript-to-jsx","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RIP21%2Fbabel-plugin-hyperscript-to-jsx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RIP21%2Fbabel-plugin-hyperscript-to-jsx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RIP21%2Fbabel-plugin-hyperscript-to-jsx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RIP21%2Fbabel-plugin-hyperscript-to-jsx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RIP21","download_url":"https://codeload.github.com/RIP21/babel-plugin-hyperscript-to-jsx/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248848776,"owners_count":21171440,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["babel","babel-codemod","babel-plugin","babel-plugin-hyperscript","codemod","hyperscript","jsx","react"],"created_at":"2024-10-15T08:54:18.328Z","updated_at":"2025-04-14T08:41:16.978Z","avatar_url":"https://github.com/RIP21.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# babel-plugin-hyperscript-to-jsx (codmod usage)\n[![npm version](https://badge.fury.io/js/babel-plugin-hyperscript-to-jsx.svg)](https://badge.fury.io/js/babel-plugin-hyperscript-to-jsx)\n\nIt's a quite complex codemod to migrate from hyperscript to JSX.\n\u003cdetails\u003e\n  \u003csummary\u003eCode Before:\u003c/summary\u003e\n  \n```javascript\nimport h from \"react-hyperscript\";\n\nimport hx from \"shit\"\n\nconst StatelessComponent = props =\u003e h(\"h1\");\n\nconst StatelessWithReturn = props =\u003e {\n  return h(\".class\");\n};\n\nfunction HyperscriptAsRegularFunction(props) {\n  return h(\"h1\");\n}\n\nconst HyperscriptAsVariable = h(\"div.lol\", {\n  someProp: \"lol\"\n});\n\nconst HyperscriptWithExpressionAsChildren = h(\n  AnotherComponent,\n  { foo: \"bar\", bar: () =\u003e ({}), shouldRender: thing.length \u003e 0 },\n  [arr.map(() =\u003e h('h1'))]\n)\n\n// Should be ignored from transforming\nconst FirstArgTemplateLiteralWithComputedExpressions = h(`div.lol${stuff}`, {\n  someProp: \"lol\"\n});\n\n// Not computed so should be fine\nconst FirstArgTemplateLiteral = h(`div.lol`, {\n  someProp: \"lol\"\n});\n\n// Should be ignored\nconst WhenFirstArgumentIsFunctionThatIsCalled = () =\u003e h(getLoadableAnimation('pageCareersDeliver'), [h(fn())])\n\nconst ComputedRootWithObjectPropertyDeclaration = () =\u003e\n  h(\n    ANIMATIONS[country],\n    {\n      className: \"lol\",\n      content: h(\".selectItem\", [\n        h(\"div\", label),\n        h(\".flag\", [\n          h(RoundFlag, {\n            mix: \"flag\",\n            size: \"xs\",\n            code: currencyData.countryCode\n          }),\n          // Computed not root should be wrapped in {}\n          h(ANIMATIONS[country], { className: \"lol\" })\n        ])\n      ])\n    },\n    [h(ANIMATIONS[country], { className: \"lol\" }), h(\"h1\"), kek \u0026\u0026 mem, surreal ? lol : kek, t.tabName, lol, \u003cdiv/\u003e]\n  );\n\nconst ThirdArgOnIgnoredIsNotArray = () =\u003e\n  h(\n    ANIMATIONS[country],\n    {\n      className: \"lol\",\n    },\n    // This first children in array will be ignored FOR THIS UGLY HACK IN INDEX\n    children\n  );\n\nh(isCanada ? doStuff : doAnotherStuff, { someProp: true })\nh('div', isCanada ? someProps : anotherProps)\nh('div', isCanada ? someProps : anotherProps, \"SomeChildren\")\n\nconst SecondArgOnIgnoredIsNotArray = () =\u003e\n  h(ANIMATIONS[country], children);\n\nconst MultiMemberExpressionWithClosingTag = () =\u003e h(Pricing.lol.kek, { className }, [ h('h1') ])\n\n// to handle h(Abc, { [kek]: 0, [\"norm\"]: 1 }) to \u003c Abc {...{ [kek]: 0 }} {...{ [\"norm\" + lol]: 1 }} norm={1} /\u003e\nconst ComplexComputedAttibutesHandling = () =\u003e h(Abc, { [kek]: 0, [\"norm\" + lol]: 1, [\"ok\"]: 2 })\n\n// Should process children but ignore computed parent\nh(`calcualted ${stuff}`, { amazing: \"stuff\" }, [\n  h(\"h1\"),\n  h(\"h2\"),\n  h(\"h3\"),\n  h(\"div\", [ h(\"div\") ])\n])\n\nclass Comp extends React.Component {\n  render() {\n    return h(\"div.example\", [\n      isStuff \u0026\u0026 h(\"h1#heading\", { ...getProps, ...getKnobs(), stuff: \"\" }),\n      isStuff\n        ? h(\"h1#heading\", { ...getProps, ...getKnobs(), stuff: \"\" })\n        : h(\"h1#heading\", \"heading\"),\n      h(\"h1#heading\", { ...getProps, ...getKnobs(), stuff: \"\" }),\n      h(\"h1#heading\", getChildren),\n      h(ANIMATIONS[country], {\n        className: \"lol\"\n      }),\n      h(\"h1#heading\", getChildren(), [h(\"div\")]),\n      h(\"div\", [h(\"div\", \"Some content\")]),\n      h(\"h1#heading\", \"This is hyperscript\"),\n      h(\"h2\", \"creating React.js markup\"),\n      h(\n        AnotherComponent,\n        { foo: \"bar\", bar: () =\u003e ({}), shouldRender: thing.length \u003e 0 },\n        [\n          h(\"li\", [h(\"a\", { href: \"http://whatever.com\" }, \"One list item\")]),\n          h(\"li\", \"Another list item\")\n        ]\n      )\n    ]);\n  }\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eCode After:\u003c/summary\u003e\n\n```jsx harmony\nimport React from 'react'\nimport h from 'react-hyperscript'\n\nimport hx from 'shit'\n\nconst StatelessComponent = props =\u003e \u003ch1 /\u003e\n\nconst StatelessWithReturn = props =\u003e {\n  return \u003cdiv className=\"class\" /\u003e\n}\n\nfunction HyperscriptAsRegularFunction(props) {\n  return \u003ch1 /\u003e\n}\n\nconst HyperscriptAsVariable = \u003cdiv className=\"lol\" someProp=\"lol\" /\u003e\n\nconst HyperscriptWithExpressionAsChildren = (\n  \u003cAnotherComponent foo=\"bar\" bar={() =\u003e ({})} shouldRender={thing.length \u003e 0}\u003e\n    {arr.map(() =\u003e \u003ch1 /\u003e)}\n  \u003c/AnotherComponent\u003e\n)\n\n// Should be ignored from transforming\nconst FirstArgTemplateLiteralWithComputedExpressions = h(`div.lol${stuff}`, {\n  someProp: 'lol'\n})\n\n// Not computed so should be fine\nconst FirstArgTemplateLiteral = \u003cdiv className=\"lol\" someProp=\"lol\" /\u003e\n\n// Should be ignored\nconst WhenFirstArgumentIsFunctionThatIsCalled = () =\u003e\n  h(getLoadableAnimation('pageCareersDeliver'), [h(fn())])\n\nconst ComputedRootWithObjectPropertyDeclaration = () =\u003e\n  h(\n    ANIMATIONS[country],\n    {\n      className: 'lol',\n      content: (\n        \u003cdiv className=\"selectItem\"\u003e\n          \u003cdiv\u003e{label}\u003c/div\u003e\n          \u003cdiv className=\"flag\"\u003e\n            \u003cRoundFlag mix=\"flag\" size=\"xs\" code={currencyData.countryCode} /\u003e\n            {// Computed not root should be wrapped in {}\n            h(ANIMATIONS[country], { className: 'lol' })}\n          \u003c/div\u003e\n        \u003c/div\u003e\n      )\n    },\n    [\n      h(ANIMATIONS[country], { className: 'lol' }),\n      \u003ch1 /\u003e,\n      kek \u0026\u0026 mem,\n      surreal ? lol : kek,\n      t.tabName,\n      lol,\n      \u003cdiv /\u003e\n    ]\n  )\n\nconst ThirdArgOnIgnoredIsNotArray = () =\u003e\n  h(\n    ANIMATIONS[country],\n    {\n      className: 'lol'\n    },\n    // This first children in array will be ignored FOR THIS UGLY HACK IN INDEX\n    children\n  )\n\nh(isCanada ? doStuff : doAnotherStuff, { someProp: true });\n\u003cdiv\u003e{isCanada ? someProps : anotherProps}\u003c/div\u003e;\n\u003cdiv {...(isCanada ? someProps : anotherProps)}\u003eSomeChildren\u003c/div\u003e;\n\nconst SecondArgOnIgnoredIsNotArray = () =\u003e h(ANIMATIONS[country], children)\n\nconst MultiMemberExpressionWithClosingTag = () =\u003e (\n  \u003cPricing.lol.kek className={className}\u003e\n    \u003ch1 /\u003e\n  \u003c/Pricing.lol.kek\u003e\n)\n\n// to handle h(Abc, { [kek]: 0, [\"norm\"]: 1 }) to \u003c Abc {...{ [kek]: 0 }} {...{ [\"norm\" + lol]: 1 }} norm={1} /\u003e\nconst ComplexComputedAttibutesHandling = () =\u003e (\n  \u003cAbc {...{ [kek]: 0 }} {...{ ['norm' + lol]: 1 }} ok={2} /\u003e\n)\n\n// Should process children but ignore computed parent\nh(`calcualted ${stuff}`, { amazing: 'stuff' }, [\n  \u003ch1 /\u003e,\n  \u003ch2 /\u003e,\n  \u003ch3 /\u003e,\n  \u003cdiv\u003e\n    \u003cdiv /\u003e\n  \u003c/div\u003e\n])\n\nclass Comp extends React.Component {\n  render() {\n    return (\n      \u003cdiv className=\"example\"\u003e\n        {isStuff \u0026\u0026 \u003ch1 id=\"heading\" {...getProps} {...getKnobs()} stuff=\"\" /\u003e}\n        {isStuff ? (\n          \u003ch1 id=\"heading\" {...getProps} {...getKnobs()} stuff=\"\" /\u003e\n        ) : (\n          \u003ch1 id=\"heading\"\u003eheading\u003c/h1\u003e\n        )}\n        \u003ch1 id=\"heading\" {...getProps} {...getKnobs()} stuff=\"\" /\u003e\n        \u003ch1 id=\"heading\"\u003e{getChildren}\u003c/h1\u003e\n        {h(ANIMATIONS[country], {\n          className: 'lol'\n        })}\n        \u003ch1 id=\"heading\" {...getChildren()}\u003e\n          \u003cdiv /\u003e\n        \u003c/h1\u003e\n        \u003cdiv\u003e\n          \u003cdiv\u003eSome content\u003c/div\u003e\n        \u003c/div\u003e\n        \u003ch1 id=\"heading\"\u003eThis is hyperscript\u003c/h1\u003e\n        \u003ch2\u003ecreating React.js markup\u003c/h2\u003e\n        \u003cAnotherComponent\n          foo=\"bar\"\n          bar={() =\u003e ({})}\n          shouldRender={thing.length \u003e 0}\n        \u003e\n          \u003cli\u003e\n            \u003ca href=\"http://whatever.com\"\u003eOne list item\u003c/a\u003e\n          \u003c/li\u003e\n          \u003cli\u003eAnother list item\u003c/li\u003e\n        \u003c/AnotherComponent\u003e\n      \u003c/div\u003e\n    )\n  }\n}\n\n```\n\u003c/details\u003e\n\n## Usage\n\nInstall [codemod](https://github.com/codemod-js/codemod) `npm install -g @codemod/cli`\n\nThen install in root of your project `npm install babel-plugin-hyperscript-to-jsx`\n\nRun it like that from node_modules:\n```\ncodemod --plugin ./node_modules/babel-plugin-hyperscript-to-jsx/src/index.js ./src\n```\n\nAlso, you may like to pretty print it immediately using prettier\n```\ncodemod --plugin ./node_modules/babel-plugin-hyperscript-to-jsx/src/index.js ./src --printer prettier\n```\n\nRemove `babel-plugin-hyperscript-to-jsx` from `package.json`\n\nIf there is any issues, let me know in the issues tab here at GitHub.\n\nYou can run it against exact file too e.g. `./src/index.js`\n```\ncodemod --plugin ./node_modules/babel-plugin-hyperscript-to-jsx/src/index.js ./src/index.js --printer prettier\n```\n\n## Limitations\n\n1) When `h` is called this way\n\n```javascript\nh(\"FirstThing\", this.getSomePropsOrChildren());\n```\n\nSecond argument will be a children (to break everything), cause to get whether second argument expression is returning children or props of object is almost impossible.\n\n2) All computed first arguments to `h` like `h(STUFF[computed])` or `h(`.stuff ${anotherClass}`)`\nis impossible to codemod, so they will be ignored, and you will need to fix it yourself, they will be kept\nas is, but their array second and third arguments will be processed with the same approach.\n\n\nFix all that by yourself :)\n\n(it's possible but will require further analysis of AST with hardcore traversal and I don't think it worth it)\n\n## Integration with WebStorm/VS Code to do it nicely file by file\nPreconditions:\n```\nnpm i -g @codemod/cli babel-plugin-hyperscript-to-jsx\n```\n\n### WebStorm:\n1. Go to Preferences -\u003e External Tools -\u003e Click plus to add tool.\n2. Config:\n```\nName: h to JSX\nProgram: codemod\nArguments: -p \u003cyour global node_modules location\u003e/babel-plugin-hyperscript-to-jsx/src/index.js $FilePathRelativeToProjectRoot$\nWorking directory: $ProjectFileDir$\n\nIn advanced settings:\nTick on: Sync file after execution\n```\n\n3. Open file you want to transform\n`Right Click -\u003e External Tools -\u003e h to JSX -\u003e Apply prettier/code formatting -\u003e Enjoy`\n4. For even better experience go to.\n`Preferences -\u003e Keymap -\u003e External Tools -\u003e External Tools -\u003e h to JSX -\u003e Attach some key combination`\n\n### VS Code:\n1. Open command pallete\n2. `\u003eTasks: Configure Task`\n3. Press Up -\u003e Select: `Task from tasks.json template` (or something like that)\n4. Copy and paste this:\n```\n{\n    // See https://go.microsoft.com/fwlink/?LinkId=733558\n    // for the documentation about the tasks.json format\n    \"version\": \"2.0.0\",\n    \"tasks\": [\n        {\n            \"label\": \"H to JSX\",\n            \"type\": \"shell\",\n            \"command\": \"codemod -p \u003cyour global node_modules location\u003e/babel-plugin-hyperscript-to-jsx/src/index.js ${file}\"\n        }\n    ]\n}\n```\n5. Open command pallete and ask it to open `keybindings.json`\n6. Add this:\n```\n    {\n        \"key\": \"cmd+e\",\n        \"command\": \"workbench.action.tasks.runTask\",\n        \"args\": \"H to JSX\"\n    }\n```\n7. Open any file and press cmd+e to apply codemod on file.\n8. Or if you don't want to bloat your `keybindings.json` just open Command pallete and type.\n`Run task -\u003e Enter -\u003e Find in the list \"H to JSX\" -\u003e Enter` (Usually will be on top)\n9. Apply formatting and enjoy\n\n\n#### For Revolut plugin to work.\n##### Webstorm:\n - Add to command line arguments `-o index={\\\"revolut\\\":true}` before the `$FilePathRelativeToProjectRoot$`\n##### VS Code:\n - Add to command line arguments `-o index='{\\\"revolut\\\":true}'` before the `${file}`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frip21%2Fbabel-plugin-hyperscript-to-jsx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frip21%2Fbabel-plugin-hyperscript-to-jsx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frip21%2Fbabel-plugin-hyperscript-to-jsx/lists"}