fix(markdown-parser): handle interpolation inside links
This commit is contained in:
parent
e081fddbc2
commit
41a3575805
2 changed files with 94 additions and 45 deletions
|
@ -146,6 +146,9 @@ function parse(
|
|||
let insidePre = false
|
||||
let insideLink = false
|
||||
|
||||
let insideLinkUrl = false
|
||||
let pendingLinkUrl = ''
|
||||
|
||||
function feed(text: string) {
|
||||
const len = text.length
|
||||
let pos = 0
|
||||
|
@ -154,7 +157,11 @@ function parse(
|
|||
const c = text[pos]
|
||||
|
||||
if (c === '\\') {
|
||||
result += text[pos + 1]
|
||||
if (insideLinkUrl) {
|
||||
pendingLinkUrl += text[pos + 1]
|
||||
} else {
|
||||
result += text[pos + 1]
|
||||
}
|
||||
pos += 2
|
||||
continue
|
||||
}
|
||||
|
@ -220,51 +227,58 @@ function parse(
|
|||
}
|
||||
|
||||
pos += 2
|
||||
let url = ''
|
||||
|
||||
while (pos < text.length && text[pos] !== ')') {
|
||||
url += text[pos++]
|
||||
}
|
||||
|
||||
pos += 1 // )
|
||||
|
||||
if (pos > text.length) {
|
||||
throw new Error('Malformed LINK entity, expected )')
|
||||
}
|
||||
|
||||
if (url.length) {
|
||||
ent.length = result.length - ent.offset
|
||||
|
||||
let m = url.match(MENTION_REGEX)
|
||||
|
||||
if (m) {
|
||||
const userId = parseInt(m[1])
|
||||
const accessHash = m[2]
|
||||
|
||||
if (accessHash) {
|
||||
(ent as tl.Mutable<tl.RawInputMessageEntityMentionName>)._ =
|
||||
'inputMessageEntityMentionName'
|
||||
;(ent as tl.Mutable<tl.RawInputMessageEntityMentionName>).userId = {
|
||||
_: 'inputUser',
|
||||
userId,
|
||||
accessHash: Long.fromString(accessHash, false, 16),
|
||||
}
|
||||
} else {
|
||||
(ent as tl.Mutable<tl.RawMessageEntityMentionName>)._ = 'messageEntityMentionName'
|
||||
;(ent as tl.Mutable<tl.RawMessageEntityMentionName>).userId = userId
|
||||
}
|
||||
} else if ((m = EMOJI_REGEX.exec(url))) {
|
||||
(ent as tl.Mutable<tl.RawMessageEntityCustomEmoji>)._ = 'messageEntityCustomEmoji'
|
||||
;(ent as tl.Mutable<tl.RawMessageEntityCustomEmoji>).documentId = Long.fromString(m[1])
|
||||
} else {
|
||||
if (url.match(/^\/\//)) url = 'http:' + url
|
||||
;(ent as tl.Mutable<tl.RawMessageEntityTextUrl>)._ = 'messageEntityTextUrl'
|
||||
;(ent as tl.Mutable<tl.RawMessageEntityTextUrl>).url = url
|
||||
}
|
||||
entities.push(ent)
|
||||
}
|
||||
|
||||
insideLink = false
|
||||
insideLinkUrl = true
|
||||
stacks.link.push(ent)
|
||||
continue
|
||||
}
|
||||
|
||||
if (insideLinkUrl) {
|
||||
pos += 1
|
||||
|
||||
if (c !== ')') {
|
||||
// not ended yet
|
||||
pendingLinkUrl += c
|
||||
continue
|
||||
}
|
||||
|
||||
const ent = stacks.link.pop()!
|
||||
|
||||
let url = pendingLinkUrl
|
||||
pendingLinkUrl = ''
|
||||
insideLinkUrl = false
|
||||
|
||||
if (!url.length) continue
|
||||
|
||||
ent.length = result.length - ent.offset
|
||||
|
||||
let m = url.match(MENTION_REGEX)
|
||||
|
||||
if (m) {
|
||||
const userId = parseInt(m[1])
|
||||
const accessHash = m[2]
|
||||
|
||||
if (accessHash) {
|
||||
(ent as tl.Mutable<tl.RawInputMessageEntityMentionName>)._ = 'inputMessageEntityMentionName'
|
||||
;(ent as tl.Mutable<tl.RawInputMessageEntityMentionName>).userId = {
|
||||
_: 'inputUser',
|
||||
userId,
|
||||
accessHash: Long.fromString(accessHash, false, 16),
|
||||
}
|
||||
} else {
|
||||
(ent as tl.Mutable<tl.RawMessageEntityMentionName>)._ = 'messageEntityMentionName'
|
||||
;(ent as tl.Mutable<tl.RawMessageEntityMentionName>).userId = userId
|
||||
}
|
||||
} else if ((m = EMOJI_REGEX.exec(url))) {
|
||||
(ent as tl.Mutable<tl.RawMessageEntityCustomEmoji>)._ = 'messageEntityCustomEmoji'
|
||||
;(ent as tl.Mutable<tl.RawMessageEntityCustomEmoji>).documentId = Long.fromString(m[1])
|
||||
} else {
|
||||
if (url.match(/^\/\//)) url = 'http:' + url
|
||||
;(ent as tl.Mutable<tl.RawMessageEntityTextUrl>)._ = 'messageEntityTextUrl'
|
||||
;(ent as tl.Mutable<tl.RawMessageEntityTextUrl>).url = url
|
||||
}
|
||||
entities.push(ent)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -395,6 +409,19 @@ function parse(
|
|||
|
||||
if (typeof it === 'boolean' || !it) return
|
||||
|
||||
if (insideLinkUrl) {
|
||||
if (typeof it === 'string' || typeof it === 'number') {
|
||||
pendingLinkUrl += it
|
||||
} else if (Long.isLong(it)) {
|
||||
pendingLinkUrl += it.toString(10)
|
||||
} else {
|
||||
// ignore the entity, only use text
|
||||
pendingLinkUrl += it.text
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof it === 'string' || typeof it === 'number') {
|
||||
result += it
|
||||
} else if (Long.isLong(it)) {
|
||||
|
|
|
@ -514,6 +514,11 @@ describe('MarkdownMessageEntityParser', () => {
|
|||
test(md_`${'**plain**'}`, [], '**plain**')
|
||||
})
|
||||
|
||||
it('should handle numbers/Longs', () => {
|
||||
test(md_`${1234567890}`, [], '1234567890')
|
||||
test(md_`${Long.fromString('1234567890')}`, [], '1234567890')
|
||||
})
|
||||
|
||||
it('should skip falsy values', () => {
|
||||
test(md_`some text ${null} more text ${false}`, [], 'some text more text ')
|
||||
})
|
||||
|
@ -579,6 +584,23 @@ describe('MarkdownMessageEntityParser', () => {
|
|||
)
|
||||
})
|
||||
|
||||
it('should interpolate inside links', () => {
|
||||
test(
|
||||
md_`[${'link'}](${'https'}://example.com/\\)${'foo'}/bar/${'baz'}?foo=bar&baz=${'egg'})`,
|
||||
[
|
||||
createEntity('messageEntityTextUrl', 0, 4, {
|
||||
url: 'https://example.com/)foo/bar/baz?foo=bar&baz=egg',
|
||||
}),
|
||||
],
|
||||
'link',
|
||||
)
|
||||
test(
|
||||
md_`[emoji](tg://emoji?id=${Long.fromNumber(123123)})`,
|
||||
[createEntity('messageEntityCustomEmoji', 0, 5, { documentId: Long.fromNumber(123123) })],
|
||||
'emoji',
|
||||
)
|
||||
})
|
||||
|
||||
it('should process MessageEntity', () => {
|
||||
test(
|
||||
md_`**bold ${new MessageEntity(createEntity('messageEntityItalic', 0, 11), 'bold italic')} more bold**`,
|
||||
|
|
Loading…
Reference in a new issue