Skip to content

Commit

Permalink
Add new strict option in the emoji extension (#2488)
Browse files Browse the repository at this point in the history
* Add new strict option in the emoji extension

* Add emoji test for strict mode and twemoji not pointing to latest ver.

* Remove unnecessary function
  • Loading branch information
facelessuser authored Oct 6, 2024
1 parent a994065 commit 659b4d9
Show file tree
Hide file tree
Showing 7 changed files with 3,959 additions and 3,853 deletions.
6 changes: 6 additions & 0 deletions docs/src/markdown/about/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 10.12

- **NEW**: Emoji: Add a new `strict` option that will raise an exception if an emoji is used whose name has changed,
removed, or never existed.
- **FIX**: Emoji: Emoji links should be generated such that they point to the new CDN version.

## 10.11.2

- **FIX**: SuperFences: Fix a regression where certain patterns could cause a hang.
Expand Down
13 changes: 9 additions & 4 deletions docs/src/markdown/extensions/emoji.md
Original file line number Diff line number Diff line change
Expand Up @@ -500,17 +500,22 @@ Option | Type | Default | Description
--------------------------- | ---------- | -------------------- | -----------
`emoji_index` | function | `emojione` index | A function that returns the index to use when parsing `:short_name:` syntax. See [Default Emoji Indexes](#default-emoji-indexes) to see the provided indexes.
`emoji_generator` | function | `to_png` generator | A function that takes the emoji info and constructs the desired emoji output. See [Default Emoji Generators](#default-emoji-generators) to see the provided generators.
`title` | string | `#!py3thon 'short'` | Specifies the title format that is fed into the emoji generator function. Can either be `long` which is the long description of the emoji, `short` which is the short name (`:short:`), or `none` which will simply pass `None`.
`alt` | string | `#!py3thon 'unicode'` | Specifies the format for the alt value that is passed to the emoji generator function. If `alt` is set to `short`, the short name will be passed to the generator. If `alt` is set to `unicode` the Unicode characters are passed to the generator. Lastly, if `alt` is set to `html_entity`, the Unicode characters are passed encoded as HTML entities.
`remove_variation_selector` | bool | `#!py3thon False` | Specifies whether variation selectors should be removed from Unicode alt. Currently, only `fe0f` is removed as it is the only one presently found in the current emoji sets.
`options` | dictionary | `#!py3thon {}` | Options that are specific to emoji generator functions. Supported parameters can vary from function to function.
`title` | string | `#!python 'short'` | Specifies the title format that is fed into the emoji generator function. Can either be `long` which is the long description of the emoji, `short` which is the short name (`:short:`), or `none` which will simply pass `None`.
`alt` | string | `#!python 'unicode'` | Specifies the format for the alt value that is passed to the emoji generator function. If `alt` is set to `short`, the short name will be passed to the generator. If `alt` is set to `unicode` the Unicode characters are passed to the generator. Lastly, if `alt` is set to `html_entity`, the Unicode characters are passed encoded as HTML entities.
`remove_variation_selector` | bool | `#!python False` | Specifies whether variation selectors should be removed from Unicode alt. Currently, only `fe0f` is removed as it is the only one presently found in the current emoji sets.
`options` | dictionary | `#!python {}` | Options that are specific to emoji generator functions. Supported parameters can vary from function to function.
`strict` | bool | `#!python False` | Raise an exception if an emoji is used whose name is not found in the database.

/// new | New 7.1
`options` is now shared between index and generator functions opposed to being passed to the generator function
only. The generator and/or index function should decide which of the arguments are relevant for its usage and parse
accordingly.
///

/// new | New 10.12
Added `strict` mode.
///

/// tip | Legacy GitHubEmoji Emulation
The Emoji extension was actually created to replace the now retired GitHubEmoji extension. Emoji was written to be
much more flexible. If you have a desire to configure the output to be like the legacy GitHubEmoji extension, you
Expand Down
2 changes: 1 addition & 1 deletion pymdownx/__meta__.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,5 +185,5 @@ def parse_version(ver, pre=False):
return Version(major, minor, micro, release, pre, post, dev)


__version_info__ = Version(10, 11, 2, "final")
__version_info__ = Version(10, 12, 0, "final")
__version__ = __version_info__._get_canonical()
52 changes: 48 additions & 4 deletions pymdownx/emoji.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"""
from markdown import Extension
from markdown.inlinepatterns import InlineProcessor
from markdown.postprocessors import Postprocessor
from markdown import util as md_util
import xml.etree.ElementTree as etree
import inspect
Expand All @@ -35,8 +36,8 @@
UNICODE_VARIATION_SELECTOR_16 = 'fe0f'
EMOJIONE_SVG_CDN = 'https://cdnjs.cloudflare.com/ajax/libs/emojione/2.2.7/assets/svg/'
EMOJIONE_PNG_CDN = 'https://cdnjs.cloudflare.com/ajax/libs/emojione/2.2.7/assets/png/'
TWEMOJI_SVG_CDN = 'https://cdn.jsdelivr.net/gh/jdecked/twemoji@15.0.3/assets/svg/'
TWEMOJI_PNG_CDN = 'https://cdn.jsdelivr.net/gh/jdecked/twemoji@15.0.3/assets/72x72/'
TWEMOJI_SVG_CDN = 'https://cdn.jsdelivr.net/gh/jdecked/twemoji@15.1.0/assets/svg/'
TWEMOJI_PNG_CDN = 'https://cdn.jsdelivr.net/gh/jdecked/twemoji@15.1.0/assets/72x72/'
GITHUB_UNICODE_CDN = 'https://github.githubassets.com/images/icons/emoji/unicode/'
GITHUB_CDN = 'https://github.githubassets.com/images/icons/emoji/'
NO_TITLE = 'none'
Expand All @@ -52,6 +53,13 @@
Please update your custom index accordingly.
"""

MSG_BAD_EMOJI = """
Emoji Extension (strict mode): The following emoji were detected and either had
their name change, were removed, or have never existed.
{}
"""


def add_attributes(options, attributes):
"""Add additional attributes from options."""
Expand Down Expand Up @@ -226,7 +234,7 @@ def to_alt(index, shortname, alias, uc, alt, title, category, options, md):
class EmojiPattern(InlineProcessor):
"""Return element of type `tag` with a text attribute of group(2) of an `InlineProcessor`."""

def __init__(self, pattern, config, md):
def __init__(self, pattern, config, strict_mode, md):
"""Initialize."""

InlineProcessor.__init__(self, pattern, md)
Expand All @@ -240,6 +248,8 @@ def __init__(self, pattern, config, md):
self.remove_var_sel = config['remove_variation_selector']
self.title = title if title in VALID_TITLE else NO_TITLE
self.generator = config['emoji_generator']
self.strict = config['strict']
self.strict_cache = strict_mode

def _set_index(self, index):
"""Set the index."""
Expand Down Expand Up @@ -336,10 +346,30 @@ def handleMatch(self, m, data):
self.options,
self.md
)
elif self.strict:
self.strict_cache.add(shortname)

return el, m.start(0), m.end(0)


class EmojiAlertPostprocessor(Postprocessor):
"""Post processor to strip out unwanted content."""

def __init__(self, strict_cache, md):
"""Initialize."""

self.strict_cache = strict_cache

def run(self, text):
"""Strip out ids and classes for a simplified HTML output."""

if len(self.strict_cache):
raise RuntimeError(
MSG_BAD_EMOJI.format('\n'.join([f'- {x}' for x in sorted(self.strict_cache)]))
)
return text


class EmojiExtension(Extension):
"""Add emoji extension to Markdown class."""

Expand Down Expand Up @@ -371,21 +401,35 @@ def __init__(self, *args, **kwargs):
False,
"Remove variation selector 16 from unicode. - Default: False"
],
'strict': [
False,
"When enabled, if an emoji with a missing name is detected, an exception will be raised."
],
'options': [
{},
"Emoji options see documentation for options for github and emojione."
]
}
super().__init__(*args, **kwargs)

def reset(self):
"""Reset."""

self.strict_cache.clear()

def extendMarkdown(self, md):
"""Add support for emoji."""

md.registerExtension(self)

config = self.getConfigs()

util.escape_chars(md, [':'])

md.inlinePatterns.register(EmojiPattern(RE_EMOJI, config, md), "emoji", 75)
self.strict_cache = set()
md.inlinePatterns.register(EmojiPattern(RE_EMOJI, config, self.strict_cache, md), "emoji", 75)
if config['strict']:
md.postprocessors.register(EmojiAlertPostprocessor(self.strict_cache, md), "emoji-alert", 50)


###################
Expand Down
Loading

0 comments on commit 659b4d9

Please sign in to comment.