{"id":18419320,"url":"https://github.com/akd-io/aldent","last_synced_at":"2026-02-11T20:36:31.778Z","repository":{"id":258545275,"uuid":"870111084","full_name":"akd-io/aldent","owner":"akd-io","description":"An al dente indentation tag function","archived":false,"fork":false,"pushed_at":"2024-10-21T11:23:33.000Z","size":1472,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-09T00:38:18.135Z","etag":null,"topics":["dedent","multi-line-string","tag","template-literal"],"latest_commit_sha":null,"homepage":"","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/akd-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-09T13:12:50.000Z","updated_at":"2024-10-21T11:23:37.000Z","dependencies_parsed_at":"2024-10-19T13:55:14.851Z","dependency_job_id":"43e55b92-2b13-4bbb-8d28-c23f2f09284e","html_url":"https://github.com/akd-io/aldent","commit_stats":null,"previous_names":["akd-io/aldent"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/akd-io/aldent","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akd-io%2Faldent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akd-io%2Faldent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akd-io%2Faldent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akd-io%2Faldent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/akd-io","download_url":"https://codeload.github.com/akd-io/aldent/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akd-io%2Faldent/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29344184,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-11T20:11:40.865Z","status":"ssl_error","status_checked_at":"2026-02-11T20:10:41.637Z","response_time":97,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["dedent","multi-line-string","tag","template-literal"],"created_at":"2024-11-06T04:16:38.941Z","updated_at":"2026-02-11T20:36:31.751Z","avatar_url":"https://github.com/akd-io.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🍝 aldent\n\n[![npm](https://img.shields.io/npm/v/aldent)](https://www.npmjs.com/package/aldent)\n\n\u003cimg src=\"https://raw.githubusercontent.com/akd-io/aldent/refs/heads/main/img/aldent.png\" alt=\"Aldent banner with usage example\" width=\"100%\" /\u003e\n\nAn al dente indentation tag function inspired by `dedent` and `endent`.\n\n## Usage\n\n### Installation\n\n```sh\nnpm install aldent\n```\n\n### Removing superfluous indentation\n\nUse the `aldent` tag function to remove superfluous indentation from a string:\n\n```ts\nimport aldent from \"aldent\";\n\naldent`\n    \u003cdiv\u003e\n      Hello world\n      \u003cspan\u003e\n        This is some indented text\n      \u003c/span\u003e\n    \u003c/div\u003e\n`;\n```\n\nResolves to:\n\n```\n\u003cdiv\u003e\n  Hello world\n  \u003cspan\u003e\n    This is some indented text\n  \u003c/span\u003e\n\u003c/div\u003e\n```\n\n### Indentation during string interpolation\n\n`aldent` also maintains correct indentation during string interpolation:\n\n```ts\nconst innerElements = `\u003cspan\u003ea\u003c/span\u003e\n\u003cspan\u003eb\u003c/span\u003e\n\u003cspan\u003ec\u003c/span\u003e`;\n\naldent`\n  \u003cdiv\u003e\n    ${innerElements}\n  \u003c/div\u003e\n`;\n```\n\nResolves to:\n\n```\n\u003cdiv\u003e\n  \u003cspan\u003ea\u003c/span\u003e\n  \u003cspan\u003eb\u003c/span\u003e\n  \u003cspan\u003ec\u003c/span\u003e\n\u003c/div\u003e\n```\n\nNotice here, that the `innerElements` variable does not contain any indentation, but is correctly indented in the final output. The resulting indentation is based on the position of the `${innerElements}` syntax.\n\nIf we were to indent the `${innerElements}` code further, you would get this:\n\n```ts\nconst innerElements = `\u003cspan\u003ea\u003c/span\u003e\n\u003cspan\u003eb\u003c/span\u003e\n\u003cspan\u003ec\u003c/span\u003e`;\n\naldent`\n  \u003cdiv\u003e\n        ${innerElements}\n  \u003c/div\u003e\n`;\n```\n\nResolving to:\n\n```\n\u003cdiv\u003e\n      \u003cspan\u003ea\u003c/span\u003e\n      \u003cspan\u003eb\u003c/span\u003e\n      \u003cspan\u003ec\u003c/span\u003e\n\u003c/div\u003e\n```\n\nThis example also shows that `aldent` knows nothing about HTML, or any other language for that matter. It does not prettify code. We are only manipulating strings here. As such it isn't bound to any language, making it a very versatile tool when it comes to code templating/generation.\n\n### Nested template strings\n\nIn the above examples, `innerElements` has not had any indentation. Had it been indented, you would need to use `aldent` on the inner template string as well.\n\nBelow we also showcase the `aldent(foo)` syntax, which is equivalent to calling `` aldent`${foo}` ``:\n\n```ts\nconst innerElements = `\n      \u003cspan\u003ea\u003c/span\u003e\n      \u003cspan\u003eb\u003c/span\u003e\n      \u003cspan\u003ec\u003c/span\u003e\n`;\n\naldent`\n  \u003cdiv\u003e\n    ${aldent(innerElements)}\n  \u003c/div\u003e\n`;\n```\n\nResolves to:\n\n```\n\u003cdiv\u003e\n  \u003cspan\u003ea\u003c/span\u003e\n  \u003cspan\u003eb\u003c/span\u003e\n  \u003cspan\u003ec\u003c/span\u003e\n\u003c/div\u003e\n```\n\nAgain, the position of the `${aldent(innerElements)}` syntax determines the indentation level of the nested `aldent` call.\n\n## Comparison to `dedent` and `endent`\n\nTo understand where `aldent` is coming from, let's first compare existing solutions `dedent` and `endent`.\n\n### `dedent` vs `endent`\n\n`endent` was built on top of `dedent` to support correct indentation during string interpolation, as shown an example of earlier in the [usage section](#usage).\n\nAn example of `dedent`'s behavior:\n\n```ts\nconst innerElements = `\u003cspan\u003ea\u003c/span\u003e\n\u003cspan\u003eb\u003c/span\u003e\n\u003cspan\u003ec\u003c/span\u003e`;\n\ndedent`\n  \u003cdiv\u003e\n    ${innerElements}\n  \u003c/div\u003e\n`;\n```\n\nResolves to:\n\n```\n\u003cdiv\u003e\n\u003cspan\u003ea\u003c/span\u003e\n\u003cspan\u003eb\u003c/span\u003e\n\u003cspan\u003ec\u003c/span\u003e\n\u003c/div\u003e\n```\n\nThat is, the inner elements are not indented correctly.\n\nRunning the same code with `endent`, would give you correctly indented code:\n\n```\n\u003cdiv\u003e\n  \u003cspan\u003ea\u003c/span\u003e\n  \u003cspan\u003eb\u003c/span\u003e\n  \u003cspan\u003ec\u003c/span\u003e\n\u003c/div\u003e\n```\n\n### `endent` vs `aldent`\n\nWhile `aldent` is dependency-free, `endent` depends on three other packages, `dedent`, `fast-json-parse`, and `objectorarray`.\n\n`endent` uses these dependencies to parse JSON-values in the template string. `aldent` does not concern itself with json-formatting, sees this as a separate concern, and leaves it up to the user to create a wrapper function for this purpose if needed.\n\nApart from being dependency-free and leaving formatting up to the user, `aldent` differs from `endent` mainly by not stripping the leading spaces of the first not-purely-whitespace line of text.\n\nFor example:\n\n```ts\nendent`\n      \u003c/a\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n`;\n```\n\nresolves to\n\n```\n\u003c/a\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\nwhereas\n\n```ts\naldent`\n      \u003c/a\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n`;\n```\n\nresolves to\n\n```\n    \u003c/a\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakd-io%2Faldent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fakd-io%2Faldent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakd-io%2Faldent/lists"}