Created
January 5, 2026 17:26
-
-
Save bensheldon/7f474bdd671b906662b39a1b3c09c073 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # frozen_string_literal: true | |
| module I18nTaskYamlExt | |
| UNMASKED_EMOJI = / | |
| (?: | |
| (?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F) # base emoji | |
| (?:\u200D(?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F))* # + ZWJ parts | |
| ) | |
| /ux | |
| def dump(tree, options) | |
| builder = Psych::Visitors::YAMLTree.create | |
| builder << tree | |
| ast = builder.tree | |
| _process_node(ast) | |
| strip_trailing_spaces(restore_emojis(ast.to_yaml(nil, options || {}))) | |
| end | |
| private | |
| def _process_node(node) | |
| case node | |
| when Psych::Nodes::Scalar | |
| node.plain = false | |
| node.quoted = true | |
| node.style = node.value.include?("\n") ? Psych::Nodes::Scalar::LITERAL : Psych::Nodes::Scalar::DOUBLE_QUOTED # <== THE ENTIRE PURPOSE OF THIS MONKEYPATCH ๐ซ | |
| node.value = _mask_emoji(node.value) if node.style == Psych::Nodes::Scalar::LITERAL # pre-mask emoji because otherwise libyaml will double-quote when we want literal style | |
| when Psych::Nodes::Mapping | |
| # only process the values, not the keys | |
| node.children.each_slice(2) { |_key, value| _process_node(value) } | |
| when Psych::Nodes::Stream, Psych::Nodes::Document, Psych::Nodes::Sequence | |
| node.children.each { |node| _process_node(node) } | |
| else | |
| raise "not handling #{node.inspect}" | |
| end | |
| end | |
| # libyaml will do this, but we want to do it first so that libyaml doesn't _also_ | |
| # mark the node as unprintable and thus prevent it from being in a literal | |
| # https://github.com/yaml/libyaml/issues/279 | |
| # "Hello ๐ world ๐!" => "Hello \\u0001F44B world \\u0001F30D!" | |
| def _mask_emoji(string) | |
| string.gsub(UNMASKED_EMOJI) do |emoji| | |
| emoji.codepoints | |
| .map { |cp| format('\\u%08X', cp) } | |
| .join('_') | |
| end | |
| end | |
| end | |
| I18n::Tasks::Data::Adapter::YamlAdapter.singleton_class.prepend I18nTaskYamlExt |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment