feat: html and markdown tagged template helpers
This commit is contained in:
parent
03cb8fd5e8
commit
733a1ab84f
6 changed files with 71 additions and 14 deletions
|
@ -13,17 +13,14 @@ API ([documented here](https://core.telegram.org/bots/api#html-style))
|
|||
|
||||
```typescript
|
||||
import { TelegramClient } from '@mtcute/client'
|
||||
import { HtmlMessageEntityParser } from '@mtcute/html-parser'
|
||||
import { HtmlMessageEntityParser, html } from '@mtcute/html-parser'
|
||||
|
||||
const tg = new TelegramClient({ ... })
|
||||
tg.registerParseMode(new HtmlMessageEntityParser())
|
||||
|
||||
tg.sendText(
|
||||
'me',
|
||||
'Hello, <b>me</b>! Updates from the feed:\n' +
|
||||
HtmlMessageEntityParser.escape(
|
||||
await getUpdatesFromFeed()
|
||||
)
|
||||
html`Hello, <b>me</b>! Updates from the feed:\n${await getUpdatesFromFeed()}`
|
||||
)
|
||||
```
|
||||
|
||||
|
@ -94,4 +91,13 @@ bold _and_** _italic_
|
|||
Escaping in this parser works exactly the same as in `htmlparser2`.
|
||||
|
||||
This means that you can keep `<>&` symbols as-is in some cases. However, when dealing with user input, it is always
|
||||
better to use [`HtmlMessageEntityParser.escape`](./classes/htmlmessageentityparser.html#escape)
|
||||
better to use [`HtmlMessageEntityParser.escape`](./classes/htmlmessageentityparser.html#escape) or, even better,
|
||||
`html` helper:
|
||||
|
||||
```typescript
|
||||
import { html } from '@mtcute/html-parser'
|
||||
|
||||
const username = 'Boris <&>'
|
||||
const text = html`Hi, ${username}!`
|
||||
console.log(text) // Hi, Boris &lt;&amp;&gt;!
|
||||
```
|
||||
|
|
|
@ -5,6 +5,22 @@ import bigInt from 'big-integer'
|
|||
|
||||
const MENTION_REGEX = /^tg:\/\/user\?id=(\d+)(?:&hash=(-?[0-9a-fA-F]+)(?:&|$)|&|$)/
|
||||
|
||||
/**
|
||||
* Tagged template based helper for escaping entities in HTML
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const escaped = html`<b>${user.displayName}</b>`
|
||||
* ```
|
||||
*/
|
||||
export function html(strings: TemplateStringsArray, ...sub: string[]): string {
|
||||
let str = ''
|
||||
sub.forEach((it, idx) => {
|
||||
str += strings[idx] + HtmlMessageEntityParser.escape(it)
|
||||
})
|
||||
return str + strings[strings.length - 1]
|
||||
}
|
||||
|
||||
export namespace HtmlMessageEntityParser {
|
||||
/**
|
||||
* Syntax highlighter function used in {@link HtmlMessageEntityParser.unparse}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { describe, it } from 'mocha'
|
||||
import { expect } from 'chai'
|
||||
import { tl } from '@mtcute/tl'
|
||||
import { HtmlMessageEntityParser } from '../src'
|
||||
import { HtmlMessageEntityParser, html } from '../src'
|
||||
import { MessageEntity } from '@mtcute/client'
|
||||
import bigInt from 'big-integer'
|
||||
|
||||
|
@ -450,4 +450,15 @@ describe('HtmlMessageEntityParser', () => {
|
|||
test('<a href="">link</a> <a>link</a>', [], 'link link')
|
||||
})
|
||||
})
|
||||
|
||||
describe('template', () => {
|
||||
it('should work as a tagged template literal', () => {
|
||||
const unsafeString = '<&>'
|
||||
|
||||
expect(html`${unsafeString}`).eq('<&>')
|
||||
expect(html`${unsafeString} <b>text</b>`).eq('<&> <b>text</b>')
|
||||
expect(html`<b>text</b> ${unsafeString}`).eq('<b>text</b> <&>')
|
||||
expect(html`<b>${unsafeString}</b>`).eq('<b><&></b>')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -12,17 +12,14 @@ This package implements formatting syntax similar to Markdown (CommonMark) but s
|
|||
|
||||
```typescript
|
||||
import { TelegramClient } from '@mtcute/client'
|
||||
import { MarkdownMessageEntityParser } from '@mtcute/markdown-parser'
|
||||
import { MarkdownMessageEntityParser, md } from '@mtcute/markdown-parser'
|
||||
|
||||
const tg = new TelegramClient({ ... })
|
||||
tg.registerParseMode(new MarkdownMessageEntityParser())
|
||||
|
||||
tg.sendText(
|
||||
'me',
|
||||
'Hello, **me**! Updates from the feed:\n' +
|
||||
MarkdownMessageEntityParser.escape(
|
||||
await getUpdatesFromFeed()
|
||||
)
|
||||
md`Hello, **me**! Updates from the feed:\n${await getUpdatesFromFeed()}`
|
||||
)
|
||||
```
|
||||
|
||||
|
@ -126,7 +123,7 @@ like `"\\_\\_not italic\\_\\_`.
|
|||
> **Note**: backslash itself must be escaped like this: ` \\ ` (double backslash).
|
||||
>
|
||||
> This will look pretty bad in real code, so use escaping only when really needed, and use
|
||||
> [`MarkdownMessageEntityParser.escape`](./classes/markdownmessageentityparser.html#escape) or
|
||||
> [`MarkdownMessageEntityParser.escape`](./classes/markdownmessageentityparser.html#escape) or `md` or
|
||||
> other parse modes (like HTML one provided by [`@mtcute/html-parser`](../html-parser/index.html))) instead.
|
||||
|
||||
> In theory, you could escape every single non-markup character, but why would you want to do that 😜
|
||||
|
|
|
@ -13,6 +13,22 @@ const TAG_PRE = '```'
|
|||
|
||||
const TO_BE_ESCAPED = /[*_\-~`[\\\]]/g
|
||||
|
||||
/**
|
||||
* Tagged template based helper for escaping entities in Markdown
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const escaped = md`**${user.displayName}**`
|
||||
* ```
|
||||
*/
|
||||
export function md(strings: TemplateStringsArray, ...sub: string[]): string {
|
||||
let str = ''
|
||||
sub.forEach((it, idx) => {
|
||||
str += strings[idx] + MarkdownMessageEntityParser.escape(it)
|
||||
})
|
||||
return str + strings[strings.length - 1]
|
||||
}
|
||||
|
||||
/**
|
||||
* Markdown MessageEntity parser.
|
||||
*
|
||||
|
|
|
@ -2,7 +2,7 @@ import { describe, it } from 'mocha'
|
|||
import { expect } from 'chai'
|
||||
import { tl } from '@mtcute/tl'
|
||||
import { MessageEntity } from '@mtcute/client'
|
||||
import { MarkdownMessageEntityParser } from '../src'
|
||||
import { MarkdownMessageEntityParser, md } from '../src'
|
||||
import bigInt from 'big-integer'
|
||||
|
||||
const createEntity = <T extends tl.TypeMessageEntity['_']>(
|
||||
|
@ -647,4 +647,15 @@ describe('MarkdownMessageEntityParser', () => {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('template', () => {
|
||||
it('should work as a tagged template literal', () => {
|
||||
const unsafeString = '__[]__'
|
||||
|
||||
expect(md`${unsafeString}`).eq('\\_\\_\\[\\]\\_\\_')
|
||||
expect(md`${unsafeString} **text**`).eq('\\_\\_\\[\\]\\_\\_ **text**')
|
||||
expect(md`**text** ${unsafeString}`).eq('**text** \\_\\_\\[\\]\\_\\_')
|
||||
expect(md`**${unsafeString}**`).eq('**\\_\\_\\[\\]\\_\\_**')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue