{"id":13631101,"url":"https://github.com/creationix/haml-js","last_synced_at":"2025-04-12T18:45:00.423Z","repository":{"id":687256,"uuid":"331286","full_name":"creationix/haml-js","owner":"creationix","description":"Haml ported to server-side Javascript.  This is a traditional server-side templating language. Tested with node-js","archived":false,"fork":false,"pushed_at":"2021-06-24T10:25:19.000Z","size":268,"stargazers_count":901,"open_issues_count":30,"forks_count":110,"subscribers_count":22,"default_branch":"master","last_synced_at":"2024-05-02T06:10:43.743Z","etag":null,"topics":[],"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/creationix.png","metadata":{"files":{"readme":"README.markdown","changelog":"CHANGELOG.markdown","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":"2009-10-08T18:53:59.000Z","updated_at":"2024-02-26T10:46:13.000Z","dependencies_parsed_at":"2022-08-16T10:40:50.469Z","dependency_job_id":null,"html_url":"https://github.com/creationix/haml-js","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fhaml-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fhaml-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fhaml-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fhaml-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/creationix","download_url":"https://codeload.github.com/creationix/haml-js/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248617264,"owners_count":21134190,"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":[],"created_at":"2024-08-01T22:02:10.501Z","updated_at":"2025-04-12T18:45:00.399Z","avatar_url":"https://github.com/creationix.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# haml-js - Server side templating language for JavaScript\n\nEver wanted to use the excellent HAML syntax on a javascript project?  Me too, so I made one!.  This has most of the same functionality as the traditional [haml][].\n\n## About the language\n\nHere is the first example(with a little extra added) from the [haml][] site converted to haml-js:\n\n**haml-js**\n\n    !!! XML\n    !!! strict\n    %html{ xmlns: \"http://www.w3.org/1999/xhtml\" }\n      %head\n        %title Sample haml template\n      %body\n        .profile\n          .left.column\n            #date= print_date()\n            #address= current_user.address\n          .right.column\n            #email= current_user.email\n            #bio= current_user.bio\n\n**html**\n\n    \u003c?xml version='1.0' encoding='utf-8' ?\u003e\n    \u003c!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"\u003e\n    \u003chtml xmlns=\"http://www.w3.org/1999/xhtml\"\u003e\u003chead\u003e\u003ctitle\u003eSample haml template\n    \u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003cdiv class=\"profile\"\u003e\u003cdiv class=\"left column\"\u003e\u003cdiv id=\"date\"\u003eJanuary 1, 2009\n    \u003c/div\u003e\u003cdiv id=\"address\"\u003eRichardson, TX\n    \u003c/div\u003e\u003c/div\u003e\u003cdiv class=\"right column\"\u003e\u003cdiv id=\"email\"\u003etim@creationix.com\n    \u003c/div\u003e\u003cdiv id=\"bio\"\u003eExperienced software professional...\n    \u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/body\u003e\u003c/html\u003e\n\nNote that this works almost the same as ruby's [haml][], but doesn't pretty print the html.  This would greatly slow down and complicate the code.  If you really want pretty printed html, then I suggest writing one using the xml parser library and process the resulting html..\n\n## API\n\n### Haml(haml) -\u003e template(locals) -\u003e html\n\nThis is the new (as of 0.2.0) way to generate haml templates.  A haml template is a live function that takes in \"this\" context and a \"locals\" variable.  This compile step takes a few milliseconds to complete so it should be done at startup and the resulting function should be cached.  Then to use the template function you simply call it with the desired local variables and it will output html at blazing speeds (we're talking millions per second on my 13\" MBP)\n\nCompile and store a template:\n\n    var main = Haml(main_haml);\n\nThen use it whenever you need a new version:\n\n    main({name: \"Tim\", age: 28});\n\nThat's it. Haml templating made easy!\n\nIf you want to store the generated javascript to a file to skip the compile step later on you can either decompile the template function or use the `compile` and `optimize` advanced functions directly.\n\n\n### Haml.compile(text) -\u003e JavaScript compiled template\n\nGiven a haml template as raw text, this compiles it to a javascript expression\nthat can later be eval'ed to get the final HTML.\n\nThe following input:\n\n    #home\n      = title\n      %ul.menu\n        %li Go Home\n        %li Go Back\n\nProduces the following JavaScript expression:\n\n    \"\u003cdiv id=\\\"home\\\"\u003e\" + \n    title +\n    \"\\n\" + \n    \"\u003cul class=\\\"menu\\\"\u003e\" + \n    \"\u003cli\u003e\" + \n    \"Go Home\\n\" + \n    \"\u003c/li\u003e\" + \n    \"\u003cli\u003e\" + \n    \"Go Back\\n\" + \n    \"\u003c/li\u003e\" + \n    \"\u003c/ul\u003e\" + \n    \"\u003c/div\u003e\"\n\n### Haml.optimize(js) -\u003e optimized JavaScript expression\n\nTakes the output of compile and optimizes it to run faster with the tradeoff of longer compile time.  This is useful for framework developers wanting to use haml in their framework and want to cache the compiled templates for performance.\n\nWith the previous input it outputs:\n\n    \"\u003cdiv id=\\\"home\\\"\u003e\" + \n    title +\n    \"\\n\u003cul class=\\\"menu\\\"\u003e\u003cli\u003eGo Home\\n\u003c/li\u003e\u003cli\u003eGo Back\\n\u003c/li\u003e\u003c/ul\u003e\u003c/div\u003e\"\n\nNotice how congruent static strings are merged into a single string literal when possible.\n\n### Haml.execute(js, context, locals) -\u003e Executes a compiled template\n\nContext is the value of `this` in the template, and locals is a hash of local variables.\n\n### Haml.render(text, options) -\u003e html text\n\nThis is a convenience function that compiles and executes to html in one shot.  Most casual users will want to use this function exclusively.\n\nThe `text` parameter is the haml source already read from a file.\n\nThe three recognized `options` are:\n\n - **context**: This is the `this` context within the haml template.\n - **locals**: This is an object that's used in the `with` scope.  Basically it creates local variables and function accessible to the haml template.\n - **optimize**: This is a flag to tell the compiler to use the extra optimizations.\n \nSee [test.js][] for an example usage of Haml.render\n\n## Executable JavaScript (not output)\n\nNew in version 0.2.6 is the ability to embed javascript in your template function.  This lets you do variable assignments, if/else, switch statements, and even define functions. In Haml.js, execution blocks begin with a `-` and define a raw js block. This behaves slightly differently from Ruby's Haml.  The advantage is that you can easily have multi-line executable blocks and comments, but the downside is that that you have to \"outdent\" the haml if you want to output from within a javascript block.\n\nSimple example:\n\n    - var area = 0.5 * length * height\n    .area= area\n\nMulti-line example:\n\n    - var obj = {\n        area: 0.5 * b * h,\n        r: opposite / adjacent\n      }\n    .triangle-details Area is: #{area} and the ratio is: #{r}\n\n\"Outdent\" the haml in a javascript block (the \"goodbye\" div is not rendered!)\n\n    .conditional\n      - var a = \"strings are truthy\"\n      - if(a){\n      .hello\n      -  } else{\n      .goodbye\n      - }\n\nYou can even define functions:\n\n    - function b(item){\n    .item\n      %b= item\n      %span.length= item.length\n    - }\n    - b(\"Hi\")\n    - b(\"World\")\n\nThis outputs:\n\n    \u003cdiv class=\"item\"\u003e\u003cb\u003eHi\u003c/b\u003e\u003cspan class=\"length\"\u003e2\u003c/span\u003e\u003c/div\u003e\u003cdiv class=\"item\"\u003e\u003cb\u003eWorld\u003c/b\u003e\u003cspan class=\"length\"\u003e5\u003c/span\u003e\u003c/div\u003e\n\nPlease see test/raw_complex.haml for more details and examples.\n\n## Comments\n\nComments that will **not** appear in the compiled JS function nor the output begin with `-#`\n\n    -# This is a comment\n    - # This is a syntax error because of the extraneous space between the - and #.\n\nIf you want to have comments that will be in the compiled JS function but *NOT* the final HTML output:\n\n    - /*\n      here we can have a comment that will not be output. Since executable-JS is block-level,\n      we can have as much comment as we want, and it will not be output to html */\n\nIf you want an HTML comment that **WILL** be in the final HTML, begin with `/`\n\n## Whitespace\n\nBy default, Haml.js **has no whitespace between tags**.  In this way, Haml.js is the opposite of Haml in Ruby.  You can insert whitespace around or inside tags with `\u003e` and `\u003c`, respectively. \n\nMost commonly, you want to have an `a` or `span` with whitespace around it:\n\n    Download the file\n    %a(href=\"/home\")\u003e here\n    now.\n\nWill produce:\n\n    Download the file \u003ca href=\"/home\"\u003ehere\u003c/a\u003e now.\n\nYou can also combine them if you want to have whitespace around and inside your tag.\n\n    %span\u003c\u003e This will have space in and around it.\n    %span\u003e\u003c This will, too.\n    %span\u003e\u003c= \"also works with code\".toUpperCase()\n\nPlease see `test/whitespace.haml` for more examples.\n\n## Code interpolation\n\nAs of version 0.2.0 there is string interpolation throughout.  This means that the body of regular text areas can have embedded code.  This is true for attributes and the contents of plugins like javascript and markdown also.  If you notice an area that doesn't support interpolation and it should then send me a note and I'll add it.\n\nFor interpolation, you may use `#{}` for escaped interpolation or `!{}` for unsafe interpolation.\n\n## Html Escaping / Sanitizer\n\nYou probably don't want to put unescaped user input right into your html.  http://xkcd.com/327/  HTML/XSS sanitization is the new \"Bobby Tables.\"\n\nLet's assume we have a malicious username: `name = \"\u003cscript\u003e...\u003c/script\u003e\"`\n\nAlways unsafe:\n      \n      %span!= name\n      \n      \u003cspan\u003e\u003cscript\u003e...\u003c/script\u003e\u003c/span\u003e\n\nAlways safe:\n\n      %span\u0026= name\n      \u003cspan\u003e\u0026lt;script\u0026gt;...\u0026lt;/script\u0026gt;\u003c/span\u003e\n\nSometimes safe:\n\n      %span= name\n\nThe behavior of `=` depends on the setting of the `escapeHtmlByDefault` configuration variable.  To make `=` safe, call Haml like this:\n\n      Haml(src, {escapeHtmlByDefault: true})\n\n## Plugins\n\nThere are plugins in the parser for things like inline script tags, css blocks, and support for if statements and for loops.\n\n### `:if/:else` statements\n\n`if` statements evaluate a condition for truthiness (as opposed to a strict comparison to `true`) and includes the content inside the block if it's truthy. An optional `else` is also supported.\n\n    :if todolist.length \u003e 20\n      %p Oh my, you are a busy fellow!\n\n    :if val == selectedVal\n      %option{value: val, selected: true}= val\n    :else\n      %option{value: val}= val\n\n### `:each` loops\n\n`:each` loops allow you to loop over a collection including a block of content once for each item. You need to what variable to pull the data from and where to put the index and value.  The index variable is optional and defaults to `__key__`.\n\nHere is an example over a simple array.\n\n    %ul.todolist\n      :each item in todolist\n        %li= item.description\n\nYou can loop over the keys and values of objects too (Note the inner `:each` loop)\n\n    :each item in data\n      :if item.age \u003c 100\n        %dl\n          :each name, value in item\n            %dt\u0026= name\n            %dd\u0026= value\n\n### `:css` and `:script` helpers.\n\nIt's easy to embed script and css tags in an haml document. Note that both `:script` and `:javascript` will work.\n\n    %head\n      :javascript\n        function greet(message) {\n          alert(\"Message from MCP: \" + message);\n        }\n      %title Script and Css test\n      :css\n        body {\n          color: pink;\n        }\n    %body{ onload: \"greet(\\\"I'm Pink\\\")\" } COLOR ME PINK\n\nThis compiles to the following HTML:\n\n    \u003chead\u003e\n    \u003cscript type=\"text/javascript\"\u003e\n    //\u003c![CDATA[\n      function greet(message) {\n        alert(\"Message from MCP: \" + message);\n      }\n    //]]\u003e\n    \u003c/script\u003e\n    \u003ctitle\u003eScript and Css test\n    \u003c/title\u003e\n    \u003cstyle type=\"text/css\"\u003e\n      body {\n        color: pink;\n      }\n    \u003c/style\u003e\n    \u003c/head\u003e\u003cbody onload=\"greet(\u0026quot;I'm Pink\u0026quot;)\"\u003e COLOR ME PINK\n    \u003c/body\u003e\n\n\n## Custom Escaper\n\nBy default, Haml(src) returns a completely self-sufficient function, including a nested `html_escape` function.  However, repeating the html_escape function definition in each of your templates is going to use more size than necessary.  So, you may pass the name of a custom escaper in an optional config variable.\n\n      Haml(src, {customEscape: \"MyApp.esc\"})\n\nThen, the output template function definition will call `MyApp.esc(string)` and will omit the `html_escape` function definition. Haml.html_escape exposes the default escape function.  If you are going to render your templates in the same context where you compile them (for instance, if you are only rendering them on the server side,) it might make sense to use  `Haml(src, {customEscape: \"Haml.html_escape\"})`\n\n## Get Involved\n\nIf you want to use this project and something is missing then send me a message.  I'm very busy and have several open source projects I manage.  I'll contribute to this project as I have time, but if there is more interest for some particular aspect, I'll work on it a lot faster.  Also you're welcome to fork this project and send me patches/pull-requests.\n\n## About Performance\n\nThe haml compiler isn't built for speed, it's built for maintainability.  The actual generated templates, however are blazing fast.  I benchmarked them with over 65 million renders per second on a small (20 line) template with some dynamic data on my laptop.  Compare this to the 629 compiles per second I got out of the compiler.  The idea is that you pre-compile your templates and reuse them on every request.  While 629 per second is nothing compared to 65 million, that still means that your server with over 600 different views can boot up in about a second.  I think that's fine for something that only happens every few weeks.\n\n## License\n\nHaml-js is [licensed][] under the [MIT license][].\n\n[MIT license]: http://creativecommons.org/licenses/MIT/\n[licensed]: http://github.com/creationix/haml-js/blob/master/LICENSE\n[jquery-haml]: http://github.com/creationix/jquery-haml\n[haml]: http://haml.info/\n[test.js]: http://github.com/creationix/haml-js/blob/master/test/test.js\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcreationix%2Fhaml-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcreationix%2Fhaml-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcreationix%2Fhaml-js/lists"}