{"id":30180938,"url":"https://github.com/streamich/jml-h","last_synced_at":"2025-08-12T08:06:24.559Z","repository":{"id":57281181,"uuid":"62643451","full_name":"streamich/jml-h","owner":"streamich","description":"JsonML + Virtual Hypertext generator (h)","archived":false,"fork":false,"pushed_at":"2018-01-05T09:31:38.000Z","size":11,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-09T08:57:43.489Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/streamich.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-07-05T14:28:01.000Z","updated_at":"2019-10-01T13:41:19.000Z","dependencies_parsed_at":"2022-09-19T21:03:41.905Z","dependency_job_id":null,"html_url":"https://github.com/streamich/jml-h","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/streamich/jml-h","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamich%2Fjml-h","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamich%2Fjml-h/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamich%2Fjml-h/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamich%2Fjml-h/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/streamich","download_url":"https://codeload.github.com/streamich/jml-h/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamich%2Fjml-h/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269734006,"owners_count":24466541,"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","status":"online","status_checked_at":"2025-08-10T02:00:08.965Z","response_time":71,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2025-08-12T08:06:10.854Z","updated_at":"2025-08-12T08:06:24.543Z","avatar_url":"https://github.com/streamich.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# jml-h\r\n\r\n\u003e **J**son**ML** + Virtual **H**ypertext generator\r\n\r\nSuper light-weight 60-line package to work with `JsonML` and *Virtual Hypertext* functions \r\nto generate XML/HTML or virtual DOM from `JsonML`.\r\n\r\n```js\r\nvar lib = require('jml-h');\r\nvar h = lib.h;\r\n\r\nvar html =\r\n    h('div', {'class': 'wrapper'},\r\n        h('div', {'class': 'avatar'},\r\n            h('img', {src: '...'}),\r\n            h('span', {},\r\n                'Hello there'\r\n            ),\r\n            h('br')\r\n        )\r\n    );\r\nconsole.log(html);\r\n// \u003cdiv class=\"wrapper\"\u003e\u003cdiv class=\"avatar\"\u003e\u003cimg src=\"...\"/\u003e\u003cspan\u003eHello there\u003c/span\u003e\u003cbr/\u003e\u003c/div\u003e\u003c/div\u003e\r\n```\r\n\r\nOr using `JsonML`:\r\n\r\n```js\r\nconsole.log(lib.dom(\r\n    ['div', {'class': 'wrapper'},\r\n        ['div', {'class': 'avatar'},\r\n            ['img', {src: '...'}],\r\n            ['span',\r\n                'Hello there'\r\n            ],\r\n            ['br']\r\n        ]\r\n    ]\r\n));\r\n// \u003cdiv class=\"wrapper\"\u003e\u003cdiv class=\"avatar\"\u003e\u003cimg src=\"...\"/\u003e\u003cspan\u003eHello there\u003c/span\u003e\u003cbr/\u003e\u003c/div\u003e\u003c/div\u003e\r\n```\r\n\r\n## Reference\r\n\r\n```ts\r\ntype JsonMLNode         = [tag: string, attributes?: {}, ...children: JsonMLNode[]];\r\ntype JsonMLNodeReplaced = any|[tag: string, attributes?: {}, ...children: (any|JsonMLNode)[]];\r\ntype VHypertext         = (tag: string, attributes: {}, ...children: JsonMLNodeReplaced[]) =\u003e JsonMLNodeReplaced;\r\n```\r\n\r\n#### `attr(obj: {}): string`\r\n\r\nFormats a collection of tag attributes into an HTML string.\r\n\r\n```js\r\nvar attributes = {id: 'header', 'class': 'floating'};\r\nconsole.log(lib.attr(attributes));\r\n// id=\"header\" class=\"floating\"\r\n```\r\n\r\n#### `h(tag: string, attributes: {}, ...children: string[]): string`\r\n\r\nThe most basic *Virtual Hypertext* function that directly generates an HTML string.\r\n\r\n```js\r\nvar h = lib.h;\r\nvar html = h('div', {'class': 'main'},\r\n    h('a', {href: '...'},\r\n        'Click me'\r\n    )\r\n);\r\nconsole.log(html);\r\n// \u003cdiv class=\"main\"\u003e\u003ca href=\"...\"\u003eClick me\u003c/a\u003e\u003c/div\u003e\r\n```\r\n\r\n#### `traverse(jml: JsonMLNode, callback: (node: JsonMLNodeReplaced) =\u003e any): any`\r\n\r\nTraverses `JsonML` object starting from leaf nodes calling `callback` for every node. `callback`\r\nreceives a `JsonML` node as a single argument.\r\n\r\nThe value returned by `callback` is used to replace that node when the `callback`\r\nis called for its parent node.\r\n\r\n```js\r\nlib.traverse(\r\n    ['div', {'class': 'wrapper'},\r\n        ['div', {'class': 'avatar'},\r\n            ['img', {src: '...'}],\r\n            ['span',\r\n                'Hello there'\r\n            ],\r\n            ['br']\r\n        ]\r\n    ], function(node) {\r\n        console.log(node);\r\n        return node;\r\n    }\r\n);\r\n```\r\n\r\n#### `dom(jml: JsonMLNode, h: VHypertext): any`\r\n\r\n`dom` accepts two arguments: a `JsonML` tree and a *Virtual Hypertext* function `h`, it\r\nfeeds `JsomML` nodes one-by-one to the, Virtual Hypertext effectively creating a `Virtual DOM`.\r\n\r\nBy default it uses the bundled `h` function:\r\n\r\n```js\r\nvar vdom = lib.dom(\r\n    ['div', {'class': 'wrapper'},\r\n        ['a', {'href': '#link'}, 'Click me!']\r\n    ]\r\n);\r\nconsole.log(vdom); // \u003cdiv class=\"wrapper\"\u003e\u003ca href=\"#link\"\u003eClick me!\u003c/a\u003e\u003c/div\u003e\r\n```\r\n\r\nAlternatively you can provide the Virtual Hypertext function of your framework, for example:\r\n\r\n```js\r\nvar jml = ['div', {'class': 'wrapper'},\r\n    ['a', {'href': '#link'}, 'Click me!]\r\n];\r\n\r\n// React.js\r\nlib.dom(jml, React.createElement.bind(React));\r\n\r\n// Mithril.js\r\nlib.dom(jml, m);\r\n\r\n// virtual-dom\r\nvar h = require('virtual-dom/h');\r\nlib.dom(jml, h);\r\n```\r\n\r\n#### `map(transform: (node: JsonMLNode) =\u003e JsonMLNode, h: VHypertext): VHypertext`\r\n\r\nBased on existing hypertext function `h` creates a new hypertext function that applies `transform` function\r\nto every JsonML node before giving it to the original `h`.\r\n\r\nFor example, replace `div` tags with `span` tags:\r\n\r\n```js\r\nvar jml = ['div', null, 'Hello'];\r\nfunction divToSpan(node) {\r\n    if(node[0] === 'div') node[0] = 'span';\r\n    return node;\r\n}\r\nvar new_h = lib.map(divToSpan, lib.h);\r\nconsole.log(lib.dom(jml, new_h));\r\n```\r\n\r\n## What is `JsonML`\r\n\r\n`JsonML` is a compact representation of `XML/HTML` as JSON or JavaScript objects. Consider the following\r\n HTML snippet:\r\n \r\n```html\r\n\u003cul class=\"my-list\"\u003e\r\n    \u003cli\u003e\u003ca href=\"#link1\"\u003eClick 1\u003c/a\u003e\u003c/li\u003e\r\n    \u003cli\u003e\u003ca href=\"#link2\"\u003eClick 2\u003c/a\u003e\u003c/li\u003e\r\n\u003c/ul\u003e\r\n```\r\n\r\nIn `JsonML` it can be represented as follows:\r\n\r\n```js\r\n['ul', {'class': 'my-list'},\r\n    ['li',\r\n        ['a', {href: '#link1'}, 'Click 1'],\r\n    ]\r\n    ['li',\r\n        ['a', {href: '#link2'}, 'Click 2'],\r\n    ]\r\n]\r\n```\r\n\r\nBasically, every node is represented by an array, where first element is a tag name,\r\nthe second element is a collection of attributes and all the rest elements represent child nodes.\r\n\r\n```ts\r\ntype JsonMLNode = [tag: string, attributes?: {}, ...children: JsonMLNode[]];\r\n```\r\n\r\n## Virtual Hypertext Generator `h`\r\n\r\n*Virtual Hypertext* generator function, frequently represented by `h` and has a similar syntax to `JsonML`.\r\n\r\nIt is frequently used in virtual DOM templating libraries, such as `React.js`, `Mithril.js`, `virtual-dom`, etc.\r\n\r\nEven if your virtual DOM templating library does not have a Virtual Hypertext function, you can create it yourself.\r\n\r\nTo generate the above HTML with `h`, you would write this:\r\n\r\n```js\r\nh('ul', {'class': 'my-list'},\r\n    h('li', null,\r\n        h('a', {href: '#link1'}, 'Click 1'),\r\n    ),\r\n    h('li', null,\r\n        h('a', {href: '#link2'}, 'Click 2'),\r\n    )\r\n);\r\n```\r\n\r\nVirtual Hypertext function is defined as follows:\r\n\r\n```ts\r\nh(tag: string, attributes: {}, ...children: any[]): any;\r\n```\r\n\r\n## Virtual Tag Functions\r\n\r\nCreate convenience function `div()`, `span()`, etc..\r\n\r\n```js\r\nvar h = lib.h;\r\nlib.tags(h, h, ['div', 'span']);\r\nvar {div, span} = h;\r\nconsole.log(div({'class': 'test'}, span(null, 'Hello')));\r\n// \u003cdiv class=\"test\"\u003e\u003cspan\u003eHello\u003c/span\u003e\u003c/div\u003e\r\n```\r\n\r\n## Usage with React.js\r\n\r\nThe second argument to the `dom()` function is a Virtual Hypertext generator function, you can provide\r\n`React.createElement.bind(React)` to it to generate React's virtual DOM.\r\n\r\nGenerate React Virtual DOM representations from `JsonML` lists instead of using `React.createElement` or `.jsx`\r\nfiles and compiling them to `.js`: \r\n\r\n```js\r\nvar react_dom = lib.dom(\r\n    ['div', {className: 'test'},\r\n        ['span', null,\r\n            'Hello world!'\r\n        ]\r\n    ], React.createElement.bind(React)\r\n);\r\n```\r\n\r\nThis is equivalent to:\r\n\r\n```js\r\nvar react_dom = React.createElement('div', {className: 'test'},\r\n    React.createElement('span', null, 'Hello world!'));\r\n```\r\n\r\nYou might consider creating the *React's Virtual Hypertext* function for convenience:\r\n\r\n```js\r\nReact.h = React.createElement.bind(React);\r\n```\r\n\r\nAnd then create `JsonML` to virtual DOM generator:\r\n\r\n```js\r\nReact.dom = function(jml) {\r\n    return lib.dom(jml, React.h);\r\n};\r\n```\r\n\r\nSo now, instead of installing `.jsx` to `.js` compiler and writing `XML` in your JavaScript projects,\r\nlike so:\r\n\r\n```jsx\r\nvar CommentBox = React.createClass({\r\n    render: function() {\r\n        return (\r\n            \u003cdiv className=\"commentBox\"\u003e\r\n                Hello, world! I am a CommentBox.\r\n            \u003c/div\u003e\r\n        );\r\n    }\r\n});\r\n```\r\n\r\nYou can do everything in **100%** JavaScript:\r\n\r\n```jsx\r\nvar CommentBox = React.createClass({\r\n    render: function() {\r\n        return React.dom(\r\n            // BONUS:\r\n            // You can now add plain comments to your React templates,\r\n            // without the required {/* */} syntax (in some places).           \r\n            ['div', {className: 'commentBox'},\r\n                'Hello, world! I am a CommentBox.'\r\n            ]\r\n        );\r\n    }\r\n});\r\n```\r\n\r\nTypeScript definitions for your extension:\r\n\r\n```ts\r\ndeclare namespace __React {\r\n    export var h: (...jml: any[]) =\u003e React.ReactElement\u003cany\u003e;\r\n    export var dom: (jml: any[]) =\u003e React.ReactElement\u003cany\u003e;\r\n}\r\n```\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstreamich%2Fjml-h","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstreamich%2Fjml-h","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstreamich%2Fjml-h/lists"}