fix: made .mention() work with tagged templates

This commit is contained in:
teidesu 2021-07-02 21:28:30 +03:00
parent 733a1ab84f
commit 9ed51fd996
13 changed files with 63 additions and 22 deletions

View file

@ -157,7 +157,6 @@ import { setProfilePhoto } from './methods/users/set-profile-photo'
import { unblockUser } from './methods/users/unblock-user'
import { updateProfile } from './methods/users/update-profile'
import { updateUsername } from './methods/users/update-username'
import { IMessageEntityParser } from './parser'
import { Readable } from 'stream'
import {
ArrayWithTotal,
@ -171,6 +170,7 @@ import {
Dialog,
FileDownloadParameters,
GameHighScore,
IMessageEntityParser,
InputFileLike,
InputInlineResult,
InputMediaLike,

View file

@ -6,7 +6,6 @@ export {
} from '@mtcute/core'
export * from '@mtcute/tl/errors'
export * from './parser'
export * from './types'
export * from './client'
export * from './utils/peer-utils'

View file

@ -1,8 +1,5 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
// @copy
import { IMessageEntityParser } from '../parser'
// @copy
import { Readable } from 'stream'
@ -41,7 +38,8 @@ import {
ArrayWithTotal,
BotCommands,
MessageMedia,
RawDocument
RawDocument,
IMessageEntityParser
} from '../types'
// @copy

View file

@ -1,4 +1,4 @@
import { IMessageEntityParser } from '../../parser'
import { IMessageEntityParser } from '../../types'
import { TelegramClient } from '../../client'
// @extension

View file

@ -1,6 +1,5 @@
import { TelegramClient } from '../../client'
import { IMessageEntityParser } from '../../parser'
import { MtCuteError } from '../../types'
import { MtCuteError, IMessageEntityParser } from '../../types'
/**
* Register a given {@link IMessageEntityParser} as a parse mode

View file

@ -7,5 +7,6 @@ export * from './peers'
export * from './misc'
export * from './errors'
export * from './parser'
export { MaybeDynamic, ArrayWithTotal } from './utils'
export { MaybeAsync, PartialExcept, PartialOnly } from '@mtcute/core'

View file

@ -38,3 +38,19 @@ export interface IMessageEntityParser {
*/
unparse(text: string, entities: ReadonlyArray<MessageEntity>): string
}
/**
* Raw string that will not be escaped when passing
* to tagged template helpers (like `html` and `md`)
*/
export class RawString {
raw!: true
constructor (readonly value: string) {}
toString(): string {
return this.value
}
}
RawString.prototype.raw = true

View file

@ -8,6 +8,7 @@ import { makeInspectable } from '../utils'
import { ChatsIndex, InputPeerLike, User, UsersIndex } from './index'
import { ChatLocation } from './chat-location'
import { InputMediaLike } from '../media'
import { RawString } from '../parser'
export namespace Chat {
/**
@ -548,7 +549,7 @@ export class Chat {
* msg.replyText(`Hello, ${msg.chat.mention()`)
* ```
*/
mention(text?: string | null, parseMode?: string | null): string {
mention(text?: string | null, parseMode?: string | null): string | RawString {
if (this.user) return this.user.mention(text, parseMode)
if (!text && this.username) {
@ -560,7 +561,7 @@ export class Chat {
if (!parseMode) parseMode = this.client['_defaultParseMode']
return this.client.getParseMode(parseMode).unparse(text, [
return new RawString(this.client.getParseMode(parseMode).unparse(text, [
{
raw: undefined as any,
type: 'text_link',
@ -568,7 +569,7 @@ export class Chat {
length: text.length,
url: `https://t.me/${this.username}`
},
])
]))
}
/**

View file

@ -5,6 +5,7 @@ import { MtCuteArgumentError } from '../errors'
import { makeInspectable } from '../utils'
import { assertTypeIs } from '../../utils/type-assertion'
import { InputMediaLike } from '../media'
import { RawString } from '../parser'
export namespace User {
/**
@ -290,7 +291,7 @@ export class User {
* msg.replyText(`Hello, ${msg.sender.mention()`)
* ```
*/
mention(text?: string | null, parseMode?: string | null): string {
mention(text?: string | null, parseMode?: string | null): string | RawString {
if (!text && this.username) {
return `@${this.username}`
}
@ -298,7 +299,7 @@ export class User {
if (!text) text = this.displayName
if (!parseMode) parseMode = this.client['_defaultParseMode']
return this.client.getParseMode(parseMode).unparse(text, [
return new RawString(this.client.getParseMode(parseMode).unparse(text, [
{
raw: undefined as any,
type: 'text_mention',
@ -306,7 +307,7 @@ export class User {
length: text.length,
userId: this.id,
},
])
]))
}
/**

View file

@ -1,4 +1,4 @@
import type { IMessageEntityParser, MessageEntity } from '@mtcute/client'
import type { IMessageEntityParser, MessageEntity, RawString } from '@mtcute/client'
import { tl } from '@mtcute/tl'
import { Parser } from 'htmlparser2'
import bigInt from 'big-integer'
@ -13,10 +13,11 @@ const MENTION_REGEX = /^tg:\/\/user\?id=(\d+)(?:&hash=(-?[0-9a-fA-F]+)(?:&|$)|&|
* const escaped = html`<b>${user.displayName}</b>`
* ```
*/
export function html(strings: TemplateStringsArray, ...sub: string[]): string {
export function html(strings: TemplateStringsArray, ...sub: (string | RawString)[]): string {
let str = ''
sub.forEach((it, idx) => {
str += strings[idx] + HtmlMessageEntityParser.escape(it)
if (typeof it === 'string') it = HtmlMessageEntityParser.escape(it)
str += strings[idx] + it
})
return str + strings[strings.length - 1]
}

View file

@ -2,7 +2,7 @@ import { describe, it } from 'mocha'
import { expect } from 'chai'
import { tl } from '@mtcute/tl'
import { HtmlMessageEntityParser, html } from '../src'
import { MessageEntity } from '@mtcute/client'
import { MessageEntity, RawString } from '@mtcute/client'
import bigInt from 'big-integer'
const createEntity = <T extends tl.TypeMessageEntity['_']>(
@ -460,5 +460,17 @@ describe('HtmlMessageEntityParser', () => {
expect(html`<b>text</b> ${unsafeString}`).eq('<b>text</b> &lt;&amp;&gt;')
expect(html`<b>${unsafeString}</b>`).eq('<b>&lt;&amp;&gt;</b>')
})
it('should skip with RawString', () => {
const unsafeString2 = '<&>'
const unsafeString = new RawString('<&>')
expect(html`${unsafeString}`).eq('<&>')
expect(html`${unsafeString} ${unsafeString2}`).eq('<&> &lt;&amp;&gt;')
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>')
expect(html`<b>${unsafeString} ${unsafeString2}</b>`).eq('<b><&> &lt;&amp;&gt;</b>')
})
})
})

View file

@ -1,6 +1,7 @@
import type { IMessageEntityParser, MessageEntity } from '@mtcute/client'
import { tl } from '@mtcute/tl'
import bigInt from 'big-integer'
import { RawString } from '@mtcute/client'
const MENTION_REGEX = /^tg:\/\/user\?id=(\d+)(?:&hash=(-?[0-9a-fA-F]+)(?:&|$)|&|$)/
@ -21,10 +22,11 @@ const TO_BE_ESCAPED = /[*_\-~`[\\\]]/g
* const escaped = md`**${user.displayName}**`
* ```
*/
export function md(strings: TemplateStringsArray, ...sub: string[]): string {
export function md(strings: TemplateStringsArray, ...sub: (string | RawString)[]): string {
let str = ''
sub.forEach((it, idx) => {
str += strings[idx] + MarkdownMessageEntityParser.escape(it)
if (typeof it === 'string') it = MarkdownMessageEntityParser.escape(it as string)
str += strings[idx] + it
})
return str + strings[strings.length - 1]
}

View file

@ -1,7 +1,7 @@
import { describe, it } from 'mocha'
import { expect } from 'chai'
import { tl } from '@mtcute/tl'
import { MessageEntity } from '@mtcute/client'
import { MessageEntity, RawString } from '@mtcute/client'
import { MarkdownMessageEntityParser, md } from '../src'
import bigInt from 'big-integer'
@ -657,5 +657,16 @@ describe('MarkdownMessageEntityParser', () => {
expect(md`**text** ${unsafeString}`).eq('**text** \\_\\_\\[\\]\\_\\_')
expect(md`**${unsafeString}**`).eq('**\\_\\_\\[\\]\\_\\_**')
})
it('should skip with RawString', () => {
const unsafeString2 = '__[]__'
const unsafeString = new RawString('__[]__')
expect(md`${unsafeString}`).eq('__[]__')
expect(md`${unsafeString} ${unsafeString2}`).eq('__[]__ \\_\\_\\[\\]\\_\\_')
expect(md`${unsafeString} **text**`).eq('__[]__ **text**')
expect(md`**text** ${unsafeString}`).eq('**text** __[]__')
expect(md`**${unsafeString} ${unsafeString2}**`).eq('**__[]__ \\_\\_\\[\\]\\_\\_**')
})
})
})