{"id":13727007,"url":"https://github.com/tmorin/idomizer","last_synced_at":"2025-05-07T22:30:47.241Z","repository":{"id":1626680,"uuid":"43452026","full_name":"tmorin/idomizer","owner":"tmorin","description":"An HTML template parser compiling an incremental-dom render factory.","archived":true,"fork":false,"pushed_at":"2022-12-30T13:50:39.000Z","size":1725,"stargazers_count":15,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-11T15:19:15.411Z","etag":null,"topics":["babel-plugin","browserify","incremental-dom","loader","template","webpack"],"latest_commit_sha":null,"homepage":"http://tmorin.github.io/idomizer","language":"TypeScript","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/tmorin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":"thibault.morin","issuehunt":null,"otechie":null,"custom":null}},"created_at":"2015-09-30T18:46:08.000Z","updated_at":"2022-12-30T13:50:40.000Z","dependencies_parsed_at":"2023-01-13T11:16:40.371Z","dependency_job_id":null,"html_url":"https://github.com/tmorin/idomizer","commit_stats":null,"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tmorin%2Fidomizer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tmorin%2Fidomizer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tmorin%2Fidomizer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tmorin%2Fidomizer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tmorin","download_url":"https://codeload.github.com/tmorin/idomizer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252965181,"owners_count":21832835,"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-plugin","browserify","incremental-dom","loader","template","webpack"],"created_at":"2024-08-03T01:03:35.356Z","updated_at":"2025-05-07T22:30:46.270Z","avatar_url":"https://github.com/tmorin.png","language":"TypeScript","readme":"# idomizer\n\n[![Continous Integration](https://github.com/tmorin/idomizer/actions/workflows/continous-integration.yaml/badge.svg)](https://github.com/tmorin/idomizer/actions/workflows/continous-integration.yaml)\n\n`idomizer` is an HTML template compiler providing an [incremental-dom] render factory.\n`idomizer` can be used at compile time (front end projects) or runtime time(back end projects).\n\nVersions and compatibilities:\n\n- idomizer \u003c= 0.5 -\u003e _incremental-dom_ 0.4 and below.\n- idomizer \u003e= 0.6 -\u003e _incremental-dom_ 0.5 and above.\n- idomizer \u003e= 1.0.0 -\u003e _incremental-dom_ 0.6 and above.\n\n## Installation\n\n```bash\n$ npm install idomizer\n```\n\n```html\n\u003cscript src=\"https://ajax.googleapis.com/ajax/libs/incrementaldom/0.6.0/incremental-dom-min.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"https://unpkg.com/idomizer/dist/idomizer.min.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n    var factory = idomizer.compile('\u003ch1\u003eHello!\u003c/h1\u003e');\n    var render = factory(IncrementalDOM);\n    IncrementalDOM.patch(document.body, render);\n\u003c/script\u003e\n```\n\n### Babel\n\nA babel's plugin is available to compile an idomizer template into an [incremental-dom] render factory.\n\nSee the [babel's plugins](https://babeljs.io/docs/en/plugins#syntax-plugins) page to get more information about plugins in babel.\n\n```javascript\n{\n    plugins: ['idomizer/lib/plugins/babel-idomizer.js']\n}\n```\n\nPresently the plugin only support [ES6 Template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) tagged with _idomizer_.\n\nFor instance,\n```javascript\nconst template = idomizer`\u003ch1 class=\"{{data.h1Class}}\"\u003eHello\u003c/h1\u003e`;\n```\nwill be compiled into:\n```javascript\nvar template = function (_i, _h) {\n  var _elementOpen = _i.elementOpen,\n      _elementClose = _i.elementClose,\n      _elementVoid = _i.elementVoid,\n      _text = _i.text,\n      _skip = _i.skip;\n  return function (_data_) {\n    var helpers = _h || {},\n        data = _data_ || {};\n    _elementOpen('h1', null, null, 'class', data.h1Class);\n    _text('Hello');\n    _elementClose('h1');\n  };\n};\n```\n\nBe aware the template can not contain expressions like ``${anExpression}``.\n\n### Webpack\n\nA webpack's loader is available to compile an idomizer file into an [incremental-dom] render factory.\n\nSee [module.rules](https://webpack.js.org/configuration/module/#module-rules) to get more information about loaders in webpack.\n\n```\nmodule.loaders: [\n    {test: /\\.idomizer$/, loader: 'idomizer/lib/plugins/idomizer-loader'}\n];\n```\n\n### Browserify\n\nA browserify's transform module is available to compile an idomizer file into an [incremental-dom] render factory.\n\nSee [transforms](https://github.com/substack/browserify-handbook#transforms) to get more information about the transform system in browserify.\n\n```shell\nbrowserify -t idomizer/lib/plugins/idomizerify main.js \u003e bundle.js\n```\n\n```javascript\nconst browserify = require('browserify');\nconst idomizerify = require('idomizer/lib/plugins/idomizerify');\nconst bundle = browserify();\nbundle.transform({ extension: 'html' }, idomizerify);\n```\n\n## API\n\n``idomizer.compile`` transforms an HTML template into a factory method.\n\n```javascript\n// idomizer.compile('\u003ch1 class=\"main\"\u003eHello\u003c/h1\u003e') will return:\nfunction template(_i, _h) {\n  var _elementOpen = _i.elementOpen,\n      _elementClose = _i.elementClose,\n      _elementVoid = _i.elementVoid,\n      _text = _i.text,\n      _skip = _i.skip;\n  return function (_data_) {\n    var helpers = _h || {},\n        data = _data_ || {};\n    _elementOpen('h1', null, ['class', 'main'], null);\n    _text('Hello');\n    _elementClose('h1');\n  };\n}\n```\n\nThe factory method requires the _incremental-dom_ library and an optional map of helpers.\nThe factory returns the _incremental-dom_'s render method.\n\n## Syntax\n\n### Static attributes\n\nFrom\n```javascript\nidomizer.compile(`\u003ch1 class=\"main\"\u003eHello\u003c/h1\u003e`)(IncrementalDOM);\n```\nTo\n```javascript\nfunction template(_i, _h) {\n  var _elementOpen = _i.elementOpen,\n      _elementClose = _i.elementClose,\n      _elementVoid = _i.elementVoid,\n      _text = _i.text,\n      _skip = _i.skip;\n  return function (_data_) {\n    var helpers = _h || {},\n        data = _data_ || {};\n    _elementOpen('h1', null, ['class', 'main'], null);\n    _text('Hello');\n    _elementClose('h1');\n  };\n}\n```\n\n### Dynamic attributes\n\nFrom\n```javascript\nidomizer.compile(`\u003ch1 class=\"{{data.h1Class}}\"\u003eHello\u003c/h1\u003e`)(IncrementalDOM)\n```\nTo\n```javascript\nfunction template(_i, _h) {\n  var _elementOpen = _i.elementOpen,\n      _elementClose = _i.elementClose,\n      _elementVoid = _i.elementVoid,\n      _text = _i.text,\n      _skip = _i.skip;\n  return function (_data_) {\n    var helpers = _h || {},\n        data = _data_ || {};\n    _elementOpen('h1', null, null, 'class', (data.h1Class));\n    _text('Hello');\n    _elementClose('h1');\n  };\n}\n```\n\n### Self closing elements\n\nFrom\n```javascript\nidomizer.compile(`\u003cinput type=\"text\" value=\"{{data.value}}\"\u003e`)(IncrementalDOM)\n```\nTo\n```javascript\nfunction template(_i, _h) {\n  var _elementOpen = _i.elementOpen,\n      _elementClose = _i.elementClose,\n      _elementVoid = _i.elementVoid,\n      _text = _i.text,\n      _skip = _i.skip;\n  return function (_data_) {\n    var helpers = _h || {},\n        data = _data_ || {};\n    _elementVoid('input', null, ['type', 'text'], 'value', (data.value));\n  };\n}\n```\n\n### Dynamic text nodes\n\nFrom\n```javascript\nidomizer.compile(`\u003cstrong\u003e\u003ctpl-text value=\"data.value\"/\u003e\u003c/strong\u003e`)(IncrementalDOM)\n// or\nidomizer.compile(`\u003cstrong\u003e{{ data.value }}\u003c/strong\u003e`)(IncrementalDOM)\n```\nTo\n```javascript\nfunction template(_i, _h) {\n  var _elementOpen = _i.elementOpen,\n      _elementClose = _i.elementClose,\n      _elementVoid = _i.elementVoid,\n      _text = _i.text,\n      _skip = _i.skip;\n  return function (_data_) {\n    var helpers = _h || {},\n        data = _data_ || {};\n    _elementOpen('strong', null, null, null);\n    _text(data.value);\n    _elementClose('strong');\n  };\n}\n```\n\n### Condition with the tags _if_, _else-if_ and _else_\n\nFrom\n```javascript\nidomizer.compile(`\n    \u003ctpl-if expression=\"data.yes\"\u003e\n        YES!\n    \u003ctpl-else-if expression=\"data.yes !== false\" /\u003e\n        MAY BE!\n    \u003ctpl-else/\u003e\n        NO!\n    \u003c/tpl-if\u003e\n`)(IncrementalDOM);\n```\nTo\n```javascript\nfunction template(_i, _h) {\n  var _elementOpen = _i.elementOpen,\n      _elementClose = _i.elementClose,\n      _elementVoid = _i.elementVoid,\n      _text = _i.text,\n      _skip = _i.skip;\n  return function (_data_) {\n    var helpers = _h || {},\n        data = _data_ || {};\n    if (data.yes) {\n        _text('YES!');\n    } else if (data.yes !== false) {\n        _text('MAY BE!');\n    } else {\n        _text('NO!');\n    }\n  };\n}\n```\n\n### Iteration with the tag _each_\n\nFrom\n```javascript\nidomizer.compile(`\n    \u003ctpl-each items=\"data.items\"\u003e\n        \u003cstrong tpl-key=\"{{index}}\"\u003e\n            \u003ctpl-text value=\"index\"/\u003e-\u003ctpl-text value=\"item\"/\u003e\n        \u003c/strong\u003e\n    \u003c/tpl-each\u003e\n`)(IncrementalDOM);\n```\nTo\n```javascript\nfunction template(_i, _h) {\n  var _elementOpen = _i.elementOpen,\n      _elementClose = _i.elementClose,\n      _elementVoid = _i.elementVoid,\n      _text = _i.text,\n      _skip = _i.skip;\n  return function (_data_) {\n    var helpers = _h || {},\n        data = _data_ || {};\n    (data.items || []).forEach(function (item, index) {\n        _elementOpen('strong', (index), null, null);\n            _text(index);\n            _text('-');\n            _text(item);\n        _elementClose('strong');\n    });\n  };\n}\n```\n\n### Iteration with inline javascript\n\nFrom\n```javascript\nidomizer.compile(`\n    [[ data.items.forEach(function (item, i) { ]]\n        \u003cstrong tpl-key=\"{{i}}\"\u003e\n            \u003ctpl-text value=\"i\"/\u003e-\u003ctpl-text value=\"item\"/\u003e\n        \u003c/strong\u003e\n    [[ }); ]]\n`)(IncrementalDOM);\n```\nTo\n```javascript\nfunction template(_i, _h) {\n  var _elementOpen = _i.elementOpen,\n      _elementClose = _i.elementClose,\n      _elementVoid = _i.elementVoid,\n      _text = _i.text,\n      _skip = _i.skip;\n  return function (_data_) {\n    var helpers = _h || {},\n        data = _data_ || {};\n    data.items.forEach(function (item, i) {\n        _elementOpen('strong', (i), null, null);\n            _text(i);\n            _text('-');\n            _text(item);\n        _elementClose('strong');\n    });\n  };\n}\n```\n\n### Custom tags\n\nFrom\n```javascript\nidomizer.compile(`\u003cstrong\u003estrong text\u003c/strong\u003e\u003cx-test\u003e\u003c/x-test\u003e\u003cstrong\u003estrong text\u003c/strong\u003e`, {\n     tags: {\n        'x-test': {\n            onopentag(name, attrs, key, statics, varArgs, options) {\n                return `t('${name} element');`;\n            }\n        }\n    }\n})(IncrementalDOM);\n```\nTo\n```javascript\nfunction template(_i, _h) {\n  var _elementOpen = _i.elementOpen,\n      _elementClose = _i.elementClose,\n      _elementVoid = _i.elementVoid,\n      _text = _i.text,\n      _skip = _i.skip;\n  return function (_data_) {\n    var helpers = _h || {},\n        data = _data_ || {};\n    _elementOpen('strong', null, null, null);\n      _text('strong text');\n    _elementClose('strong');\n    _text('x-test element');\n    _elementOpen('strong', null, null, null);\n      _text('strong text');\n    _elementClose('strong');\n  };\n}\n```\n\n### Custom helpers\n\nFrom\n```javascript\nconst subRender = compile(`helper content`)(IncrementalDOM);\nidomizer.compile(`\n    \u003cstrong\u003estrong text\u003c/strong\u003e\n    \u003ctpl-call name=\"subRender\" /\u003e\n    \u003cstrong\u003estrong text\u003c/strong\u003e\n`)(IncrementalDOM, {subRender});\n```\nTo\n```javascript\nfunction template(_i, _h) {\n  var _elementOpen = _i.elementOpen,\n      _elementClose = _i.elementClose,\n      _elementVoid = _i.elementVoid,\n      _text = _i.text,\n      _skip = _i.skip;\n  return function (_data_) {\n    var helpers = _h || {},\n        data = _data_ || {};\n    _elementOpen('strong', null, null, null);\n        _text('strong text');\n    _elementClose('strong');\n    helpers.subRender(data);\n    _elementOpen('strong', null, null, null);\n        _text('strong text');\n    _elementClose('strong');\n  };\n}\n```\n\n### Custom elements\n\nFor [incremental-dom], custom elements are regular HTML elements.\nSo, if a custom element generates a sub-tree (i.e. a light DOM) outside of a ShadowDOM node,\nit will be overridden during the execution of the function `patch()`.\nTo control this default behavior, [incremental-dom] provides the function `skip()` saying:\n_don't touch the inner light DOM of the just opened node!_\n\nBy default, idomizier detects the custom elements and force the call of the function `skip()` to protect their light DOM nodes.\nCustom elements are detected according to the following rules:\n\n- from the name, because of the `-` character\n- from the attribute `ìs`\n\nObviously, this behavior can be deactivated:\n\n- globally (for a whole HTML template)\n    ```javascript\n    const render = compile(`\u003cx-element\u003e\u003cp\u003ewill part of the light DOM\u003c/p\u003e\u003c/x-element\u003e`, {skipCustomElements : false})\n    ```\n- locally (an HTML element), ``\n    ```javascript\n    const render = compile(`\u003cx-element tpl-skip=\"deactivated\"\u003e\u003cp\u003ewill part of the light DOM\u003c/p\u003e\u003c/x-element\u003e`)\n    ```\n\n[incremental-dom]: https://google.github.io/incremental-dom\n","funding_links":["https://liberapay.com/thibault.morin"],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftmorin%2Fidomizer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftmorin%2Fidomizer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftmorin%2Fidomizer/lists"}