Passed
Push — main ( 1d3d49...043de0 )
by Mark
02:14
created

Environment   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 211
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 91
c 0
b 0
f 0
dl 0
loc 211
ccs 101
cts 101
cp 1
rs 10
wmc 29

11 Methods

Rating   Name   Duplication   Size   Complexity  
A normalizeConvert() 0 7 2
A __construct() 0 4 1
A normalizeLocale() 0 29 5
A addRenderer() 0 18 3
A create() 0 9 2
A initializeExtensions() 0 7 3
A addEventListener() 0 25 5
A initializeConfiguration() 0 46 3
A addExtension() 0 12 2
A defaultExtensions() 0 3 1
A normalizePresets() 0 10 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file was originally part of the league/commonmark package.
7
 *
8
 * (c) Colin O'Dell <[email protected]>
9
 *
10
 * Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js)
11
 *  - (c) John MacFarlane
12
 *
13
 * For the full copyright and license information, please view the LICENSE
14
 * file that was distributed with this source code.
15
 */
16
17
namespace League\Emoji\Environment;
18
19
use League\Configuration\Configuration;
20
use League\Configuration\ConfigurationAwareInterface;
21
use League\Emoji\EmojiConverterInterface;
22
use League\Emoji\Emojibase\EmojibaseDatasetInterface;
23
use League\Emoji\Emojibase\EmojibaseShortcodeInterface;
24
use League\Emoji\Event\ListenerData;
25
use League\Emoji\Extension\ConfigurableExtensionInterface;
26
use League\Emoji\Extension\ConfigureConversionTypesInterface;
27
use League\Emoji\Extension\EmojiCoreExtension;
28
use League\Emoji\Extension\ExtensionInterface;
29
use League\Emoji\Renderer\NodeRendererInterface;
30
use League\Emoji\Util\PrioritizedList;
31
use Nette\Schema\Expect;
32
use Nette\Schema\Schema;
33
34
class Environment extends AbstractEnvironment implements EnvironmentInterface, EnvironmentBuilderInterface
35
{
36
    /**
37
     * @param array<string, mixed> $configuration
38
     */
39 708
    public function __construct(array $configuration = [])
40
    {
41 708
        $this->config = new Configuration();
42 708
        $this->config->merge($configuration);
43 708
    }
44
45
    /**
46
     * @param array<string, mixed> $configuration
47
     */
48 660
    public static function create(array $configuration = []): self
49
    {
50 660
        $environment = new self($configuration);
51
52 660
        foreach (self::defaultExtensions() as $extension) {
53 660
            $environment->addExtension($extension);
54
        }
55
56 660
        return $environment;
57
    }
58
59
    /**
60
     * @return ExtensionInterface[]
61
     */
62 660
    protected static function defaultExtensions(): iterable
63
    {
64 660
        return [new EmojiCoreExtension()];
65
    }
66
67
    /**
68
     * @param string|string[] $value
69
     *
70
     * @return string[]
71
     */
72 48
    public static function normalizeConvert($value): array
73
    {
74 48
        if (\is_array($value)) {
75 6
            return $value;
76
        }
77
78 42
        return \array_fill_keys(EmojiConverterInterface::TYPES, $value);
79
    }
80
81 531
    public static function normalizeLocale(string $locale): string
82
    {
83
        /** @var string[] $normalized */
84 531
        static $normalized = [];
85
86
        // Immediately return if locale is an exact match.
87 531
        if (\in_array($locale, EmojibaseDatasetInterface::SUPPORTED_LOCALES, true)) {
88 528
            $normalized[$locale] = $locale;
89
        }
90
91
        // Immediately return if this local has already been normalized.
92 531
        if (isset($normalized[$locale])) {
93 531
            return $normalized[$locale];
94
        }
95
96 3
        $original              = $locale;
97 3
        $normalized[$original] = 'en';
98
99
        // Otherwise, see if it just needs some TLC.
100 3
        $locale = \strtolower($locale);
101 3
        $locale = \preg_replace('/[^a-z]/', '-', $locale) ?? $locale;
102 3
        foreach ([$locale, \current(\explode('-', $locale, 2))] as $locale) {
103 3
            if (\in_array($locale, EmojibaseDatasetInterface::SUPPORTED_LOCALES, true)) {
104 3
                $normalized[$original] = $locale;
105 3
                break;
106
            }
107
        }
108
109 3
        return $normalized[$original];
110
    }
111
112
    /**
113
     * @param string|string[] $presets
114
     *
115
     * @return string[]
116
     */
117 582
    public static function normalizePresets($presets): ?array
118
    {
119
        // Map preset aliases to their correct value.
120
        return \array_unique(\array_filter(\array_map(static function (string $preset): string {
121 582
            if (isset(EmojibaseShortcodeInterface::PRESET_ALIASES[$preset])) {
122 12
                return EmojibaseShortcodeInterface::PRESET_ALIASES[$preset];
123
            }
124
125 570
            return $preset;
126 582
        }, \array_values((array) $presets))));
127
    }
128
129 663
    public function addEventListener(string $eventClass, callable $listener, int $priority = 0): EnvironmentBuilderInterface
130
    {
131 663
        $this->assertUninitialized('Failed to add event listener.');
132
133 660
        if ($this->listenerData === null) {
134
            /** @var PrioritizedList<ListenerData> $listenerData */
135 660
            $listenerData       = new PrioritizedList();
136 660
            $this->listenerData = $listenerData;
137
        }
138
139 660
        $this->listenerData->add(new ListenerData($eventClass, $listener), $priority);
140
141 660
        $object = \is_array($listener)
142 3
            ? $listener[0]
143 660
            : $listener;
144
145 660
        if ($object instanceof EnvironmentAwareInterface) {
146 3
            $object->setEnvironment($this);
147
        }
148
149 660
        if ($object instanceof ConfigurationAwareInterface) {
150 654
            $object->setConfiguration($this->getConfiguration());
151
        }
152
153 660
        return $this;
154
    }
155
156 669
    public function addExtension(ExtensionInterface $extension): EnvironmentBuilderInterface
157
    {
158 669
        $this->assertUninitialized('Failed to add extension.');
159
160 666
        $this->extensions[]              = $extension;
161 666
        $this->uninitializedExtensions[] = $extension;
162
163 666
        if ($extension instanceof ConfigurableExtensionInterface) {
164 18
            $extension->configureSchema($this->config, $this->config->data());
165
        }
166
167 666
        return $this;
168
    }
169
170 666
    public function addRenderer(string $nodeClass, NodeRendererInterface $renderer, int $priority = 0): EnvironmentBuilderInterface
171
    {
172 666
        $this->assertUninitialized('Failed to add renderer.');
173
174 663
        if (! isset($this->renderersByClass[$nodeClass])) {
175
            /** @var PrioritizedList<NodeRendererInterface> $renderers */
176 663
            $renderers = new PrioritizedList();
177
178 663
            $this->renderersByClass[$nodeClass] = $renderers;
179
        }
180
181 663
        $this->renderersByClass[$nodeClass]->add($renderer, $priority);
182
183 663
        if ($renderer instanceof ConfigurationAwareInterface) {
184 651
            $renderer->setConfiguration($this->getConfiguration());
185
        }
186
187 663
        return $this;
188
    }
189
190 699
    protected function initializeConfiguration(): void
191
    {
192 699
        $this->config->addSchema('allow_unsafe_links', Expect::bool(true));
193
194 699
        $default = EmojiConverterInterface::UNICODE;
195
196
        /** @var string[] $conversionTypes */
197 699
        $conversionTypes = EmojiConverterInterface::TYPES;
198
199 699
        foreach ($this->extensions as $extension) {
200 660
            if ($extension instanceof ConfigureConversionTypesInterface) {
201 18
                $extension->configureConversionTypes($default, $conversionTypes, $this->config->data());
202
            }
203
        }
204
205 699
        $conversionTypes = \array_unique($conversionTypes);
206
207 699
        $structuredConversionTypes = Expect::structure(\array_combine(
208 699
            EmojiConverterInterface::TYPES,
209
            \array_map(static function (/** @scrutinizer ignore-unused */ string $conversionType) use ($conversionTypes, $default): Schema {
210 699
                return Expect::anyOf(false, ...$conversionTypes)->default($default)->nullable();
211 699
            }, EmojiConverterInterface::TYPES)
212 699
        ))->castTo('array');
213
214 699
        $this->config->addSchema('convert', Expect::anyOf($structuredConversionTypes, ...$conversionTypes)
215 699
            ->default(\array_fill_keys(EmojiConverterInterface::TYPES, $default))
216 699
            ->before('\League\Emoji\Environment\Environment::normalizeConvert'));
217
218 699
        $this->config->addSchema('exclude', Expect::structure([
219 699
            'shortcodes' => Expect::arrayOf('string')
220 699
                ->default([])
221 699
                ->before('\League\Emoji\Util\Normalize::shortcodes'),
222 699
        ])->castTo('array'));
223
224 699
        $this->config->addSchema('locale', Expect::anyOf(...EmojibaseDatasetInterface::SUPPORTED_LOCALES)
225 699
            ->default('en')
226 699
            ->before('\League\Emoji\Environment\Environment::normalizeLocale'));
227
228 699
        $this->config->addSchema('native', Expect::bool()->nullable());
229
230 699
        $this->config->addSchema('presentation', Expect::anyOf(...EmojibaseDatasetInterface::SUPPORTED_PRESENTATIONS)
231 699
            ->default(EmojibaseDatasetInterface::EMOJI));
232
233 699
        $this->config->addSchema('preset', Expect::anyOf(Expect::listOf(Expect::anyOf(...EmojibaseShortcodeInterface::SUPPORTED_PRESETS)), ...EmojibaseShortcodeInterface::SUPPORTED_PRESETS)
234 699
            ->default(EmojibaseShortcodeInterface::DEFAULT_PRESETS)
235 699
            ->before('\League\Emoji\Environment\Environment::normalizePresets'));
236 699
    }
237
238 687
    protected function initializeExtensions(): void
239
    {
240
        // Ask all extensions to register their components.
241 687
        while (\count($this->uninitializedExtensions) > 0) {
242 654
            foreach ($this->uninitializedExtensions as $i => $extension) {
243 654
                $extension->register($this);
244 654
                unset($this->uninitializedExtensions[$i]);
245
            }
246
        }
247 687
    }
248
}
249