{"id":16756779,"url":"https://github.com/charmander/razorleaf","last_synced_at":"2025-10-08T05:36:25.487Z","repository":{"id":7339294,"uuid":"8662166","full_name":"charmander/razorleaf","owner":"charmander","description":"A template engine for HTML in Node.js JavaScript","archived":false,"fork":false,"pushed_at":"2023-02-04T23:16:32.000Z","size":870,"stargazers_count":12,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-09-23T18:52:36.897Z","etag":null,"topics":["nodejs","template-engine"],"latest_commit_sha":null,"homepage":"https://charmander.me/razorleaf/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/charmander.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2013-03-08T23:41:38.000Z","updated_at":"2023-02-04T23:16:36.000Z","dependencies_parsed_at":"2023-02-18T20:15:57.948Z","dependency_job_id":null,"html_url":"https://github.com/charmander/razorleaf","commit_stats":null,"previous_names":["campersander/razorleaf"],"tags_count":42,"template":false,"template_full_name":null,"purl":"pkg:github/charmander/razorleaf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charmander%2Frazorleaf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charmander%2Frazorleaf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charmander%2Frazorleaf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charmander%2Frazorleaf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/charmander","download_url":"https://codeload.github.com/charmander/razorleaf/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charmander%2Frazorleaf/sbom","scorecard":{"id":274572,"data":{"date":"2025-08-11","repo":{"name":"github.com/charmander/razorleaf","commit":"2aef11401863eeed42d6f90e9c4bc99ff5ad6b51"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: ISC License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-17T14:08:18.911Z","repository_id":7339294,"created_at":"2025-08-17T14:08:18.912Z","updated_at":"2025-08-17T14:08:18.912Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278893453,"owners_count":26064194,"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-10-08T02:00:06.501Z","response_time":56,"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":["nodejs","template-engine"],"created_at":"2024-10-13T03:42:03.186Z","updated_at":"2025-10-08T05:36:25.438Z","avatar_url":"https://github.com/charmander.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build status][ci image]][ci]\n\nRazor Leaf is an HTML template engine for Node.js.\n\n\n## Features\n\n- automatic escaping\n\n- template inheritance\n\n- recursive macros\n\n- conditional attributes and classes\n\n- explicit whitespace only to make it clear when it affects the content\n\n- no dependencies\\*\n\n- unrestricted JavaScript expressions and inline code; no sandboxes to work around\n\n\u003csmall\u003e\\* This might change.\u003c/small\u003e\n\n\n## Example\n\n`example.rl`:\n\n```\ndoctype html\n    head\n        meta charset: \"utf-8\"\n        meta name: \"viewport\" content: \"initial-scale=1\"\n\n        title \"Example\"\n    body\n        h1 \"Hello, world!\"\n\n        do const { left, right } = data;\n        p \"#{left} × #{right} = #{left * right}\"\n```\n\n`example.js`:\n\n```javascript\nconst DirectoryLoader = require('razorleaf/directory-loader');\n\nconst templateLoader = new DirectoryLoader(__dirname);\nconst template = templateLoader.load('example');\n\nconsole.log(\n    template({\n        left: 9,\n        right: 12,\n    })\n);\n```\n\nOutput:\n\n\u003e # Hello, world!\n\u003e\n\u003e 9 × 12 = 108\n\n\n## Syntax\n\n### Elements\n\nElements are defined by their names only; no other special character is\nnecessary.\n\n```\np\n```\n\n```html\n\u003cp\u003e\u003c/p\u003e\n```\n\nVoid elements are recognized automatically.\n\n```\nmeta\n```\n\n```html\n\u003cmeta\u003e\n```\n\n### Strings\n\nStrings are double-quoted and escaped for use in HTML as needed. Backslash\nescape codes can be used as in JavaScript. No whitespace is added\naround strings.\n\n```\n\"--\u003e A string \u003c--\\n\" \"A string containing \\\"double-quotes\\\"\"\n```\n\n```html\n--\u0026gt; A string \u0026lt;--\nA string containing \"double-quotes\"\n```\n\nStrings can also contain interpolated sections, delimited by `#{` and `}`.\n`#{` can be escaped with a leading backslash; `}` doesn’t require escaping.\n\n```\n\"#{6 * 7}\"\n```\n\n```html\n42\n```\n\nIf an exclamation mark precedes the string, it and any of its interpolated\nsections will not be escaped.\n\n```\n!\"\u003c!-- A significant comment --\u003e\"\n```\n\n```html\n\u003c!-- A significant comment --\u003e\n```\n\n### Attributes\n\nAttributes are marked up using the syntax \u003ccode\u003e\u003ci\u003ename\u003c/i\u003e: \"\u003ci\u003evalue\u003c/i\u003e\"\u003c/code\u003e, where \u003ccode\u003e\"\u003ci\u003evalue\u003c/i\u003e\"\u003c/code\u003e is a string as described above. Use an empty string for boolean attributes.\n\n```\nmeta charset: \"utf-8\"\n```\n\n```html\n\u003cmeta charset=\"utf-8\"\u003e\n```\n\nIf a boolean attribute is conditional, it can be written in shorthand:\n\n```\ninput\n    name: \"#{field.name}\"\n    disabled: if field.disabled\n```\n\nequivalent to:\n\n```\ninput\n    name: \"#{field.name}\"\n\n    if field.disabled\n        disabled: \"\"\n```\n\n### Classes\n\nClasses are marked up with a leading period, as in \u003ccode\u003e.\u003ci\u003eclass\u003c/i\u003e\u003c/code\u003e.\n\n```\nfieldset .upload-meta\n    input.required\n```\n\n```html\n\u003cfieldset class=\"upload-meta\"\u003e\u003cinput class=\"required\"\u003e\u003c/fieldset\u003e\n```\n\n### Hierarchy\n\nHierarchy in Razor Leaf is defined using indentation. For example:\n\n```\ndoctype\n\nhtml\n    head\n        meta charset: \"utf-8\"\n\n        title \"Example\"\n\n        link\n            rel: \"stylesheet\"\n            type: \"text/css\"\n            href: \"stylesheets/example.css\"\n\n    body\n        p id: \"introduction\"\n            \"This template is a brief example of hierarchy.\"\n```\n\n```html\n\u003c!DOCTYPE html\u003e\u003chtml\u003e\u003chead\u003e\u003cmeta charset=utf-8\u003e\u003ctitle\u003eExample\u003c/title\u003e\u003clink rel=stylesheet type=text/css href=stylesheets/example.css\u003e\u003c/head\u003e\u003cbody\u003e\u003cp id=introduction\u003eThis template is a brief example of hierarchy.\u003c/p\u003e\u003c/body\u003e\u003c/html\u003e\n```\n\nContent found after an element on the same line will also be considered that\nelement’s content.\n\n### Comments\n\nComments begin with `#` and continue to the end of the line. They do not affect\nthe rendered HTML.\n\n### Code\n\n**Code blocks** begin with `do` and treats all of their content as JavaScript.\n\n```\ndo\n    const compareKeys = (a, b) =\u003e\n        a.key \u003c b.key ? -1 :\n        a.key \u003e b.key ? 1 :\n        0;\n\n    const sorted = (array, by) =\u003e\n        array\n            .map(value =\u003e ({key: by(value), value}))\n            .sort(compareKeys)\n            .map(({value}) =\u003e value);\n\n    let characterCount = 0;\n\nfor post of sorted(posts, post =\u003e post.title)\n    post-detail(post)\n    do characterCount += post.content.length;\n```\n\n### Special blocks\n\nSome names define special blocks. These are:\n\n- **`doctype`**: Inserts `\u003c!DOCTYPE html\u003e`.\n- **`if (condition)`**: Includes its content only if *`condition`* is met.\n- **`elif (condition)`**: Can immediately follow an `if` or an `elif`.\n- **`else`**: Can immediately follow an `if` or an `elif`.\n- **`for (identifier) of (collection)`**: Includes its content for each element of the array or array-like object *`collection`*.\n- **`for (identifier), (index) of (collection)`**: Allows the index variable in a `for` loop to be named.\n- **`include (name)`**: Loads and includes another template.\n- **`extends (name)`**: Loads another template and replaces its blocks. A template that extends another template cannot have any content outside of block actions.\n- **`block (name)`**: Defines a replaceable block.\n- **`replace (name)`**: Replaces a block.\n- **`append (name)`**: Appends to a block.\n- **`do`**: See [**Code**](#code).\n\n## API\n\n### `new razorleaf.DirectoryLoader(root, [options])`\n\nCreates a loader that maps template names to files with the `.rl` extension\nin the directory located at *`root`*.\n\n#### `razorleaf.DirectoryLoader.prototype.load(name, [options])`\n\nReturns a template object loaded from the root directory.\n\n### `razorleaf.compile(template, [options])`\n\nCompiles a template string into a function. The compiled function takes\none argument, `data`, which can be used (under that name) in the template.\n\n### Options\n\n- **`load(name)`**: A function that returns a parsed template represented by `name`. This is filled automatically by most loaders.\n- **`globals`**: An object representing the global variables that should be made available to the template.\n\n\n  [ci]: https://travis-ci.org/charmander/razorleaf\n  [ci image]: https://api.travis-ci.org/charmander/razorleaf.svg?branch=master\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcharmander%2Frazorleaf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcharmander%2Frazorleaf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcharmander%2Frazorleaf/lists"}