{"id":26655629,"url":"https://github.com/gramiojs/format","last_synced_at":"2026-04-11T00:02:32.641Z","repository":{"id":221898804,"uuid":"755716409","full_name":"gramiojs/format","owner":"gramiojs","description":"Library for formatting text for Telegram Bot API","archived":false,"fork":false,"pushed_at":"2026-04-09T12:05:35.000Z","size":132,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-04-09T14:07:40.177Z","etag":null,"topics":["bot","formatting","gramio","html","markdown","markdownv2","parse-mode","telegram","telegram-bot","telegram-bot-api"],"latest_commit_sha":null,"homepage":"https://gramio.netlify.app/formatting.html","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/gramiojs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-02-10T21:43:10.000Z","updated_at":"2026-04-09T12:04:58.000Z","dependencies_parsed_at":"2024-05-18T12:29:17.881Z","dependency_job_id":"5ffe3740-cc8a-476c-9e6b-fb53a938e78a","html_url":"https://github.com/gramiojs/format","commit_stats":null,"previous_names":["gramiojs/format"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/gramiojs/format","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gramiojs%2Fformat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gramiojs%2Fformat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gramiojs%2Fformat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gramiojs%2Fformat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gramiojs","download_url":"https://codeload.github.com/gramiojs/format/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gramiojs%2Fformat/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31663580,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T17:19:37.612Z","status":"ssl_error","status_checked_at":"2026-04-10T17:19:13.364Z","response_time":98,"last_error":"SSL_read: 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":["bot","formatting","gramio","html","markdown","markdownv2","parse-mode","telegram","telegram-bot","telegram-bot-api"],"created_at":"2025-03-25T06:36:45.671Z","updated_at":"2026-04-11T00:02:32.034Z","avatar_url":"https://github.com/gramiojs.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @gramio/format\n\nLibrary for [formatting](https://core.telegram.org/bots/api#messageentity) text for Telegram Bot API. Used under the hood by [GramIO](https://gramio.dev/) framework but it is framework-agnostic.\n\n[![npm](https://img.shields.io/npm/v/@gramio/format?logo=npm\u0026style=flat\u0026labelColor=000\u0026color=3b82f6)](https://www.npmjs.org/package/@gramio/format)\n[![JSR](https://jsr.io/badges/@gramio/format)](https://jsr.io/@gramio/format)\n[![JSR Score](https://jsr.io/badges/@gramio/format/score)](https://jsr.io/@gramio/format)\n\n## Installation\n\n```sh\nnpm install @gramio/format\n# or\nbun add @gramio/format\n```\n\n## Overview\n\n`@gramio/format` builds [`MessageEntity`](https://core.telegram.org/bots/api#messageentity) objects alongside the text so you never have to track character offsets manually. All formatters compose freely — nest them as deeply as you like.\n\n```ts\nimport { format, bold, italic, link, spoiler } from \"@gramio/format\";\n\nconst msg = format`${bold`Hi!`}\n\nCan ${italic(\"you\")} help ${spoiler`me`}?\n\nCan you give me a ${link(\"star\", \"https://github.com/gramiojs/gramio\")}?`;\n\n// msg.text     → the plain string\n// msg.entities → ready-to-send MessageEntity[]\n```\n\n---\n\n## Template literals\n\n### `format`\n\nStrips leading indentation from every line (safe to indent inside your source).\n\n```ts\nimport { format, bold, italic } from \"@gramio/format\";\n\nformat`Hello ${bold(\"world\")}!`\n// text: \"Hello world!\"\n// entities: [{ type: \"bold\", offset: 6, length: 5 }]\n```\n\n### `formatSaveIndents`\n\nSame as `format` but preserves all whitespace exactly as written.\n\n```ts\nimport { formatSaveIndents, code } from \"@gramio/format\";\n\nformatSaveIndents`Run:\\n    ${code(\"bun install\")}`\n```\n\n---\n\n## Formatters\n\nEvery formatter accepts either a plain string, a `FormattableString`, or a tagged template literal.\n\n```ts\nbold(\"text\")\nbold`text`\nbold(italic(\"text\"))   // nested: bold wraps italic\n```\n\n| Formatter | Telegram entity | Notes |\n|---|---|---|\n| `bold` | `bold` | Cannot be combined with `code` / `pre` |\n| `italic` | `italic` | Cannot be combined with `code` / `pre` |\n| `underline` | `underline` | Cannot be combined with `code` / `pre` |\n| `strikethrough` | `strikethrough` | Cannot be combined with `code` / `pre` |\n| `spoiler` | `spoiler` | Cannot be combined with `code` / `pre` |\n| `blockquote` | `blockquote` | Cannot be nested |\n| `expandableBlockquote` | `expandable_blockquote` | Cannot be nested |\n| `code` | `code` | Inline monospace; cannot be combined with others |\n| `pre(text, lang?)` | `pre` | Code block; optional language for syntax highlight |\n| `link(text, url)` | `text_link` | Cannot be combined with `code` / `pre` |\n| `mention(text, user)` | `text_mention` | |\n| `customEmoji(emoji, id)` | `custom_emoji` | Requires purchased username on Fragment |\n\n### Examples\n\n```ts\nimport {\n    bold, italic, underline, strikethrough, spoiler,\n    blockquote, expandableBlockquote,\n    code, pre, link, mention, customEmoji,\n    format,\n} from \"@gramio/format\";\n\nbold`Important`\nitalic`Subtle`\nunderline`Marked`\nstrikethrough`Removed`\nspoiler`Secret`\n\nblockquote`A quote from someone wise.`\nexpandableBlockquote`A very long quote that can be collapsed.`\n\ncode`npm install`\npre(\"console.log('hi')\", \"js\")\n\nlink(\"GramIO\", \"https://gramio.dev\")\nmention(\"John\", { id: 1, is_bot: false, first_name: \"John\" })\ncustomEmoji(\"⚔️\", \"5222106016283378623\")\n\n// Compose freely\nformat`${bold(\"Price\")}: ${italic(\"$42\")}\\nSee ${link(\"docs\", \"https://gramio.dev\")}`\n```\n\n---\n\n## `join` — formatting arrays\n\nArray `.join()` discards entities. Use `join` instead:\n\n```ts\nimport { join, bold, format } from \"@gramio/format\";\n\nconst items = [\"apple\", \"banana\", \"cherry\"];\n\nformat`Shopping list:\\n${join(items, (item) =\u003e bold(item), \"\\n\")}`;\n// text:     \"Shopping list:\\napple\\nbanana\\ncherry\"\n// entities: bold on each item at the correct offsets\n```\n\nThe third argument is the separator (default `\", \"`). Return `null`, `undefined`, or `false` from the iterator to skip an item.\n\n---\n\n## `markdownToFormattable` — Markdown → FormattableString\n\nConverts a Markdown string to a `FormattableString` with proper entities. Useful when your content comes from a Markdown source (e.g., API docs, user input).\n\n**Requires [`marked`](https://marked.js.org/) as a peer dependency:**\n\n```sh\nnpm install marked\n```\n\n```ts\nimport { markdownToFormattable } from \"@gramio/format/markdown\";\n\nconst result = markdownToFormattable(\n    \"# Title\\n\\n**bold** and *italic*\\n\\n\u003e Blockquote\\n\\n[link](https://gramio.dev)\"\n);\n\n// result.text     → \"Title\\n\\nbold and italic\\n\\nBlockquote\\n\\nlink\"\n// result.entities → bold, italic, blockquote, text_link at correct offsets\n```\n\n### Supported Markdown elements\n\n| Markdown | Result |\n|---|---|\n| `**text**` / `__text__` | bold |\n| `*text*` / `_text_` | italic |\n| `~~text~~` | strikethrough |\n| `` `code` `` | inline code |\n| ```` ```lang\\n...\\n``` ```` | pre block (with optional language) |\n| `\u003e text` | blockquote |\n| `[text](url)` | link |\n| `![alt](url)` | link (image → text link) |\n| `# Heading` … `###### Heading` | bold |\n| `- item` / `1. item` | list with bullet/number prefix |\n\n---\n\n## `htmlToFormattable` — HTML → FormattableString\n\nConverts an HTML string to a `FormattableString`. Designed for HTML produced by rich-text editors such as **TipTap**, **ProseMirror**, or **Quill**.\n\n**Requires [`node-html-parser`](https://github.com/taoqf/node-html-parser) as a peer dependency:**\n\n```sh\nnpm install node-html-parser\n```\n\n```ts\nimport { htmlToFormattable } from \"@gramio/format/html\";\n\nconst result = htmlToFormattable(\n    \"\u003cp\u003e\u003cstrong\u003eHello\u003c/strong\u003e \u003cem\u003eworld\u003c/em\u003e\u003c/p\u003e\"\n);\n\n// result.text     → \"Hello world\"\n// result.entities → [bold offset=0 len=5, italic offset=6 len=5]\n```\n\n### Supported HTML elements\n\n| Element | Result | Notes |\n|---|---|---|\n| `\u003cstrong\u003e`, `\u003cb\u003e` | bold | |\n| `\u003cem\u003e`, `\u003ci\u003e` | italic | |\n| `\u003cu\u003e` | underline | |\n| `\u003cs\u003e`, `\u003cdel\u003e`, `\u003cstrike\u003e` | strikethrough | |\n| `\u003ccode\u003e` | inline code | When not inside `\u003cpre\u003e` |\n| `\u003cpre\u003e\u003ccode class=\"language-js\"\u003e` | pre block | Language extracted from `language-*` class |\n| `\u003cblockquote\u003e` | blockquote | Children processed recursively |\n| `\u003ca href=\"...\"\u003e` | link | |\n| `\u003ch1\u003e` … `\u003ch6\u003e` | bold | |\n| `\u003cp\u003e`, `\u003cdiv\u003e` | transparent wrapper | Children joined with `\"\"` |\n| `\u003cbr\u003e` | `\\n` | |\n| `\u003cul\u003e` | unordered list | Items prefixed with `- ` |\n| `\u003col start=\"N\"\u003e` | ordered list | Items numbered from `start` |\n\nBlock-level elements at the root are separated by `\\n\\n`. List items are separated by `\\n`. Nested lists are supported and indented with `\\n` before the sub-list.\n\n### TipTap example\n\n```ts\nimport { htmlToFormattable } from \"@gramio/format/html\";\n\nconst html = `\n\u003ch1\u003eRelease notes\u003c/h1\u003e\n\u003cp\u003eVersion \u003cstrong\u003e2.0\u003c/strong\u003e is out with \u003cem\u003eexciting\u003c/em\u003e changes:\u003c/p\u003e\n\u003cul\u003e\n  \u003cli\u003e\u003cp\u003eNew \u003ccode\u003ehtmlToFormattable\u003c/code\u003e function\u003c/p\u003e\u003c/li\u003e\n  \u003cli\u003e\u003cp\u003ePerformance improvements\u003c/p\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eRead the \u003ca href=\"https://gramio.dev\"\u003efull docs\u003c/a\u003e.\u003c/p\u003e\n`;\n\nconst result = htmlToFormattable(html);\n// Sends correctly formatted message to Telegram with all entities intact\n```\n\n---\n\n## Using with Telegram Bot API\n\nThe `FormattableString` object has `.text` and `.entities` properties that map directly to Telegram's `sendMessage` parameters:\n\n```ts\nimport { format, bold, link } from \"@gramio/format\";\n\nconst msg = format`Check out ${bold(link(\"GramIO\", \"https://gramio.dev\"))}!`;\n\nawait bot.api.sendMessage({\n    chat_id: chatId,\n    text: msg.text,\n    entities: msg.entities,\n});\n```\n\nWith [GramIO](https://gramio.dev/) you can pass the `FormattableString` directly:\n\n```ts\nbot.on(\"message\", (ctx) =\u003e {\n    ctx.send(format`Hello ${bold(ctx.from.first_name)}!`);\n});\n```\n\n---\n\n## See also\n\n- [Full documentation](https://gramio.dev/formatting.html)\n- [GramIO framework](https://gramio.dev/)\n- [Telegram MessageEntity docs](https://core.telegram.org/bots/api#messageentity)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgramiojs%2Fformat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgramiojs%2Fformat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgramiojs%2Fformat/lists"}