Skip to content

Commit

Permalink
Merge pull request #101 from speee/prevent-emoji-over-escaping
Browse files Browse the repository at this point in the history
Prevent over-escaping in valid emoji shorthand
  • Loading branch information
Yuki Hattori authored Dec 27, 2019
2 parents 73516a2 + 8b5a793 commit 6a2f72e
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 13 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
- Components for [the outdated dialog](https://api.slack.com/dialogs) provided in `@speee-js/jsx-slack/dialog` can no longer use ([#84](https://github.com/speee/jsx-slack/pull/84))
- Drop Node 8 support ([#100](https://github.com/speee/jsx-slack/pull/100))

### Fixed

- Prevent over-escaping in valid emoji shorthand ([#98](https://github.com/speee/jsx-slack/issues/98), [#101](https://github.com/speee/jsx-slack/pull/101))

### Changed

- Upgrade dependent packages to the latest version ([#92](https://github.com/speee/jsx-slack/pull/92))
Expand Down
2 changes: 2 additions & 0 deletions docs/about-escape-and-exact-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ Other special chars will replace to another Unicode character whose similar shap

These replacements also will trigger by using corresponded HTML tag. (e.g. `*` and `` in the contents of `<b>` tag)

> ℹ️ Special characters in valid emoji shorthand won't be escaped. For example, we will leave underscore(s) of the shorthand such as `:white_check_mark:`, `:marca_de_verificación_blanca:` and `:チェックマーク_緑:`.
## Exact mode

Some special characters will work only in breaks of words. Take a look this example:
Expand Down
41 changes: 28 additions & 13 deletions src/html.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import formatDate from './date'
import { JSXSlack, ParseContext } from './jsx'
import { Html, detectSpecialLink } from './utils'

const emojiShorthandRegex = /(:[-a-z0-9ÀÁÂÃÄÇÈÉÊËÍÎÏÑÓÔÕÖŒœÙÚÛÜŸßàáâãäçèéêëíîïñóôõöùúûüÿ__++'\u2e80-\u2fd5\u3005\u3041-\u3096\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcb\uff10-\uff19\uff41-\uff5a\uff61-\uff9f]+:)/

export const escapeEntity = (str: string) =>
str
.replace(/&/g, '&amp;')
Expand All @@ -23,6 +25,28 @@ const buildAttr = (props: { [key: string]: any }) => {
return attr
}

const escapeCharsDefaultReplacer = (partial: string) =>
partial
.replace(/^(&gt;|>)/gm, (_, c) => `\u00ad${c}`)
.replace(/\*/g, '\u2217')
.replace(//g, '\ufe61')
.replace(/_/g, '\u02cd')
.replace(/_/g, '\u2e0f')
.replace(/[``]/g, '\u02cb')
.replace(/~/g, '\u223c')

export const escapeChars = (
mrkdwn: string,
replacer: (partial: string) => string = escapeCharsDefaultReplacer
) =>
mrkdwn
.split(emojiShorthandRegex)
.reduce(
(acc, str, i) => [...acc, i % 2 === 1 ? str : replacer(str)],
[] as string[]
)
.join('')

export const parse = (
name: string,
props: Record<string, any>,
Expand Down Expand Up @@ -54,9 +78,10 @@ export const parse = (
case 'em':
if (isDescendant('i', 'em', 'time')) return text()

return `<i>${text()
.replace(/_/g, '\u02cd')
.replace(/_/g, '\u2e0f')}</i>`
// Underscores have to avoid escaping in emoji shorthand
return `<i>${escapeChars(text(), t =>
t.replace(/_/g, '\u02cd').replace(/_/g, '\u2e0f')
)}</i>`
case 's':
case 'strike':
case 'del':
Expand Down Expand Up @@ -118,16 +143,6 @@ export const parse = (
export const Escape: JSXSlack.FC<{ children: JSXSlack.Children<{}> }> = props =>
JSXSlack.h(JSXSlack.NodeType.escapeInHtml, props)

export const escapeChars = (mrkdwn: string) =>
mrkdwn
.replace(/^(&gt;|>)/gm, (_, c) => `\u00ad${c}`)
.replace(/\*/g, '\u2217')
.replace(//g, '\ufe61')
.replace(/_/g, '\u02cd')
.replace(/_/g, '\u2e0f')
.replace(/[``]/g, '\u02cb')
.replace(/~/g, '\u223c')

export default function html(children: JSXSlack.Children<{}>) {
return JSXSlack(<Html>{children}</Html>)
}
17 changes: 17 additions & 0 deletions test/block-kit/builtin-components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,23 @@ describe('Built-in components', () => {
}),
}),
]))

it('ignores escaping underscore in valid emoji shorthand', () =>
expect(
JSXSlack(
<Blocks>
<Section>
<Escape>_:arrow_down: :custom_emoji: :カスタム_絵文字:_</Escape>
</Section>
</Blocks>
)
).toStrictEqual([
expect.objectContaining({
text: expect.objectContaining({
text: '\u02cd:arrow_down: :custom_emoji: :カスタム_絵文字:\u02cd',
}),
}),
]))
})

describe('<Fragment> component', () => {
Expand Down
5 changes: 5 additions & 0 deletions test/html.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ describe('HTML parser for mrkdwn', () => {
expect(html(<i>Hello, _World_!</i>)).toBe('_Hello, \u2e0fWorld\u2e0f!_')
})

it('does not escape underscore contained in valid emoji shorthand', () => {
expect(html(<i>:arrow_down:</i>)).toBe('_:arrow_down:_')
expect(html(<i>:絵_文字:</i>)).toBe('_:絵_文字:_')
})

it('applies markup per each lines when text has multiline', () => {
expect(
html(
Expand Down

0 comments on commit 6a2f72e

Please sign in to comment.