\"`\n\nalways unsafe:\n \n %span!= name\n \n \n\nalways safe:\n\n %span&= name\n <script>...</script>\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 > 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 < 100\n %dl\n :each name, value in item\n %dt&= name\n %dd&= 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 \n \n script and css test\n \n \n color me pink\n \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", "installation_instructions": null, "categories": [ "Everything", "System & Data Integrators" ], "owners": [], "owner": null, "code_snippets": {}, "evaluation_results": [], "found_via_ownership_request": false, "security_scans": [ { "repo_url": "https://github.com/creationix/haml-js", "repo_name": "haml-js", "score": 88, "risk_level": "moderate", "score_explanation": "Score starts at 100, deducts points for security issues, and adds points for security best practices", "scan_id": "093f155b-7449-4344-9d58-5f803f31a394", "mcp_app_id": "c2be4edd-a476-43e5-8761-63b955b1404a", "scan_time": "2025-05-08T09:31:06.789193+00:00", "created_at": "2025-05-08T09:31:06.789979+00:00", "updated_at": "2025-05-08T09:31:06.789979+00:00", "findings": [ { "finding_id": "e581053b-af21-4ac2-a17f-019b4604151e", "message": "Use of eval() detected. This can be dangerous if used with untrusted input.", "line": 652, "created_at": "2025-05-08T09:31:06.789979+00:00", "rule_id": "security-validator.scanner.rules.semgrep.dangerous-eval", "scan_id": "093f155b-7449-4344-9d58-5f803f31a394", "type": "semgrep", "severity": "ERROR", "path": "lib/haml.js", "meta_info": { "lines": " eval(\"_$output =\" + js );", "pattern": "", "rule_name": "dangerous_code" } }, { "finding_id": "a62ec863-3667-405e-803e-2881d66e2714", "message": "Use of eval() detected. This can be dangerous if used with untrusted input.", "line": 13, "created_at": "2025-05-08T09:31:06.789979+00:00", "rule_id": "security-validator.scanner.rules.semgrep.dangerous-eval", "scan_id": "093f155b-7449-4344-9d58-5f803f31a394", "type": "semgrep", "severity": "ERROR", "path": "test/test-commonjs.js", "meta_info": { "lines": " var scope = FILE.exists(scopeFile) ? eval(\"(\"+FILE.read(scopeFile)+\")\") : {};", "pattern": "", "rule_name": "dangerous_code" } }, { "finding_id": "e6ab5604-3151-49d7-b62d-c07e03b904ee", "message": "Use of eval() detected. This can be dangerous if used with untrusted input.", "line": 65, "created_at": "2025-05-08T09:31:06.789979+00:00", "rule_id": "security-validator.scanner.rules.semgrep.dangerous-eval", "scan_id": "093f155b-7449-4344-9d58-5f803f31a394", "type": "semgrep", "severity": "ERROR", "path": "test/test.js", "meta_info": { "lines": " load_haml(eval(\"(\" + js + \")\"));", "pattern": "", "rule_name": "dangerous_code" } }, { "finding_id": "3d58fb62-9508-4724-9f80-45d6acdefbe6", "message": "Use of eval() detected. This can be dangerous if used with untrusted input.", "line": 90, "created_at": "2025-05-08T09:31:06.789979+00:00", "rule_id": "security-validator.scanner.rules.semgrep.dangerous-eval", "scan_id": "093f155b-7449-4344-9d58-5f803f31a394", "type": "semgrep", "severity": "ERROR", "path": "test/test.js", "meta_info": { "lines": " var scope = eval(\"(\" + fs.readFileSync(\"escaping.js\") + \")\");", "pattern": "", "rule_name": "dangerous_code" } } ], "vulnerabilities": [] }, { "repo_url": "https://github.com/creationix/haml-js", "repo_name": "haml-js", "score": 100, "risk_level": "low", "score_explanation": "Score starts at 100, deducts points for security issues, and adds points for security best practices", "scan_id": "8f42cc88-f0aa-468e-8304-11662ad26542", "mcp_app_id": "c2be4edd-a476-43e5-8761-63b955b1404a", "scan_time": "2025-06-13T09:54:55.735384+00:00", "created_at": "2025-06-13T09:54:55.736097+00:00", "updated_at": "2025-06-13T09:54:55.736097+00:00", "findings": [ { "finding_id": "05c3a1c4-082a-44c7-a430-98d7cf088f71", "message": "Use of eval() detected. This can be dangerous if used with untrusted input.", "line": 652, "created_at": "2025-06-13T09:54:55.736097+00:00", "rule_id": "security-validator.scanner.rules.semgrep.dangerous-eval", "scan_id": "8f42cc88-f0aa-468e-8304-11662ad26542", "type": "semgrep", "severity": "ERROR", "path": "lib/haml.js", "meta_info": { "lines": " eval(\"_$output =\" + js );", "pattern": "", "rule_name": "dangerous_code" } } ], "vulnerabilities": [] } ] } }