Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bd03efd

Browse files
committed
Move & adapt "emoji code" from Intl into its own component
Transfert emoji data from Intl to emoji component Update main composer.json Fix phpunit config Update composer and README descriptions Fix LICENCE date Update src/Symfony/Component/Intl/CHANGELOG.md Co-authored-by: Oskar Stark <[email protected]> Fix Changelog I feel that cool resolve some of the recent issues linked to the Profiler. Rename component Emoji + unlink from Intl (no shared resp/code) Isolated commit to move data Update Github worflows Use Emoji in String component Update src/Symfony/Component/Emoji/CHANGELOG.md Co-authored-by: Nicolas Grekas <[email protected]> Update src/Symfony/Component/Emoji/README.md Co-authored-by: Nicolas Grekas <[email protected]> Present the compress command in both README's Update src/Symfony/Component/Intl/CHANGELOG.md Co-authored-by: Nicolas Grekas <[email protected]> Fix main composer.json Revert symfony/intl requires symfony/emoji Remove EmojiTransliteratorTrait Move emoji data Add "symfony/deprecation-contracts" to Intl Revert data test split Add symfony/emoji to String (dev) Fix String Test namespace Fix .gitattributes hides "bin/compress" script Please Psalm ? Compute quickCheck once Update LICENCE Add Intl conflict with string < 7.1 Fix Int changelog Fix composer.json CS Throw exception in Intl BC layer when symfony/emoji is not installed Test Intl & Emoji in the same job Remove useless check Remove useless check (without breaking things)
1 parent ccbdc1a commit bd03efd

File tree

185 files changed

+445
-146
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

185 files changed

+445
-146
lines changed

.github/workflows/intl-data-tests.yml

+21-7
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1-
name: Intl data
1+
name: Intl/Emoji data
22

33
on:
44
push:
55
paths:
6+
- 'src/Symfony/Component/Emoji/*.php'
7+
- 'src/Symfony/Component/Emoji/Resources/data/**'
8+
- 'src/Symfony/Component/Emoji/Tests/*Test.php'
69
- 'src/Symfony/Component/Intl/*.php'
710
- 'src/Symfony/Component/Intl/Util/GitRepository.php'
811
- 'src/Symfony/Component/Intl/Resources/data/**'
912
- 'src/Symfony/Component/Intl/Tests/*Test.php'
1013
- 'src/Symfony/Component/Intl/Tests/Util/GitRepositoryTest.php'
1114
pull_request:
1215
paths:
16+
- 'src/Symfony/Component/Emoji/*.php'
17+
- 'src/Symfony/Component/Emoji/Resources/data/**'
18+
- 'src/Symfony/Component/Emoji/Tests/*Test.php'
1319
- 'src/Symfony/Component/Intl/*.php'
1420
- 'src/Symfony/Component/Intl/Util/GitRepository.php'
1521
- 'src/Symfony/Component/Intl/Resources/data/**'
@@ -29,7 +35,7 @@ permissions:
2935

3036
jobs:
3137
tests:
32-
name: Intl data
38+
name: Intl/Emoji data
3339
runs-on: Ubuntu-20.04
3440

3541
steps:
@@ -80,15 +86,23 @@ jobs:
8086
- name: Run intl-data tests
8187
run: ./phpunit --group intl-data -v
8288

83-
- name: Test with compressed data
89+
- name: Test intl-data with compressed data
8490
run: |
8591
[ -f src/Symfony/Component/Intl/Resources/data/locales/en.php ]
8692
[ ! -f src/Symfony/Component/Intl/Resources/data/locales/en.php.gz ]
87-
[ -f src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en.php ]
88-
[ ! -f src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en.php.gz ]
8993
src/Symfony/Component/Intl/Resources/bin/compress
9094
[ ! -f src/Symfony/Component/Intl/Resources/data/locales/en.php ]
9195
[ -f src/Symfony/Component/Intl/Resources/data/locales/en.php.gz ]
92-
[ ! -f src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en.php ]
93-
[ -f src/Symfony/Component/Intl/Resources/data/transliterator/emoji/emoji-en.php.gz ]
9496
./phpunit src/Symfony/Component/Intl
97+
98+
- name: Run Emoji tests
99+
run: ./phpunit src/Symfony/Component/Emoji -v
100+
101+
- name: Test Emoji with compressed data
102+
run: |
103+
[ -f src/Symfony/Component/Emoji/Resources/data/emoji-en.php ]
104+
[ ! -f src/Symfony/Component/Emoji/Resources/data/emoji-en.php.gz ]
105+
src/Symfony/Component/Emoji/Resources/bin/compress
106+
[ ! -f src/Symfony/Component/Emoji/Resources/data/emoji-en.php ]
107+
[ -f src/Symfony/Component/Emoji/Resources/data/emoji-en.php.gz ]
108+
./phpunit src/Symfony/Component/Emoji

.github/workflows/package-tests.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121

2222
- name: Find packages
2323
id: find-packages
24-
run: echo "packages=$(php .github/get-modified-packages.php $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n' | grep -v src/Symfony/Component/Intl/Resources/emoji |jq -R -s -c 'split("\n")[:-1]') $(git diff --name-only origin/${{ github.base_ref }} HEAD | grep src/ | jq -R -s -c 'split("\n")[:-1]'))" >> $GITHUB_OUTPUT
24+
run: echo "packages=$(php .github/get-modified-packages.php $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n' | grep -v src/Symfony/Component/Emoji/Resources/bin |jq -R -s -c 'split("\n")[:-1]') $(git diff --name-only origin/${{ github.base_ref }} HEAD | grep src/ | jq -R -s -c 'split("\n")[:-1]'))" >> $GITHUB_OUTPUT
2525

2626
- name: Verify meta files are correct
2727
run: |

.github/workflows/unit-tests.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ jobs:
9595
echo SYMFONY_DEPRECATIONS_HELPER=weak >> $GITHUB_ENV
9696
cp composer.json composer.json.orig
9797
echo -e '{\n"require":{'"$(grep phpunit-bridge composer.json)"'"php":"*"},"minimum-stability":"dev"}' > composer.json
98-
php .github/build-packages.php HEAD^ $SYMFONY_VERSION $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n' | grep -v src/Symfony/Component/Intl/Resources/emoji)
98+
php .github/build-packages.php HEAD^ $SYMFONY_VERSION $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n' | grep -v src/Symfony/Component/Emoji/Resources/bin)
9999
mv composer.json composer.json.phpunit
100100
mv composer.json.orig composer.json
101101
fi

.php-cs-fixer.dist.php

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
'Symfony/Bundle/FrameworkBundle/Resources/views/Form',
5454
// explicit trigger_error tests
5555
'Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/',
56+
'Symfony/Component/Emoji/Resources/',
5657
'Symfony/Component/Intl/Resources/data/',
5758
])
5859
// explicit tests for ommited @param type, against `no_superfluous_phpdoc_tags`

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"symfony/doctrine-bridge": "self.version",
7272
"symfony/dom-crawler": "self.version",
7373
"symfony/dotenv": "self.version",
74+
"symfony/emoji": "self.version",
7475
"symfony/error-handler": "self.version",
7576
"symfony/event-dispatcher": "self.version",
7677
"symfony/expression-language": "self.version",

psalm.xml

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
<directory name="src/Symfony/*/*/Tests" />
1818
<directory name="src/Symfony/*/*/*/Tests" />
1919
<directory name="src/Symfony/*/*/*/*/Tests" />
20-
<directory name="src/Symfony/Component/Intl/Resources/emoji/" />
20+
<directory name="src/Symfony/Component/Intl/Resources/data/" />
21+
<directory name="src/Symfony/Component/Emoji/Resources/data/" />
2122
<directory name="vendor" />
2223
</ignoreFiles>
2324
</projectFiles>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/Resources/bin/build.php export-ignore
2+
/Resources/bin/composer.json export-ignore
3+
/Resources/bin/Makefile export-ignore
4+
/Resources/bin/README.md export-ignore
5+
/Tests export-ignore
6+
/phpunit.xml.dist export-ignore
7+
/.gitattributes export-ignore
8+
/.gitignore export-ignore
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
vendor/
2+
composer.lock
3+
phpunit.xml
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Emoji;
13+
14+
use Symfony\Component\Emoji\Util\GzipStreamWrapper;
15+
16+
if (!class_exists(\Transliterator::class)) {
17+
throw new \LogicException(sprintf('You cannot use the "%s\EmojiTransliterator" class as the "intl" extension is not installed. See https://php.net/intl.', __NAMESPACE__));
18+
}
19+
20+
final class EmojiTransliterator extends \Transliterator
21+
{
22+
private const QUICK_CHECK = "\xA9\xAE\xE2\xE3\xF0";
23+
private const REVERSEABLE_IDS = [
24+
'emoji-github' => 'github-emoji',
25+
'emoji-slack' => 'slack-emoji',
26+
'github-emoji' => 'emoji-github',
27+
'slack-emoji' => 'emoji-slack',
28+
];
29+
30+
public readonly string $id;
31+
32+
private array $map;
33+
34+
private string $quickCheck;
35+
36+
private \Transliterator $transliterator;
37+
38+
public static function create(string $id, int $direction = self::FORWARD): self
39+
{
40+
$id = strtolower($id);
41+
42+
if (!isset(self::REVERSEABLE_IDS[$id]) && !str_starts_with($id, 'emoji-')) {
43+
$id = 'emoji-'.$id;
44+
}
45+
46+
if (self::REVERSE === $direction) {
47+
if (!isset(self::REVERSEABLE_IDS[$id])) {
48+
// Create a failing reverse-transliterator to populate intl_get_error_*()
49+
\Transliterator::createFromRules('A > B')->createInverse();
50+
51+
throw new \IntlException(intl_get_error_message(), intl_get_error_code());
52+
}
53+
$id = self::REVERSEABLE_IDS[$id];
54+
}
55+
56+
$file = __DIR__."/Resources/data/{$id}.php";
57+
if (!preg_match('/^[a-z0-9@_\\.\\-]*$/', $id) || !is_file($file) && !is_file($file .= '.gz')) {
58+
\Transliterator::create($id); // Populate intl_get_error_*()
59+
60+
throw new \IntlException(intl_get_error_message(), intl_get_error_code());
61+
}
62+
63+
/**
64+
* @var array<string, array> $maps
65+
*/
66+
static $maps;
67+
68+
// Create an instance of \Transliterator with a custom id; that's the only way
69+
static $newInstance;
70+
$instance = ($newInstance ??= (new \ReflectionClass(self::class))->newInstanceWithoutConstructor(...))();
71+
$instance->id = $id;
72+
$instance->map = $maps[$id] ??= str_ends_with($file, '.gz') ? GzipStreamWrapper::require($file) : require $file;
73+
74+
return $instance;
75+
}
76+
77+
public function createInverse(): self
78+
{
79+
return self::create($this->id, \Transliterator::REVERSE);
80+
}
81+
82+
public function getErrorCode(): int|false
83+
{
84+
return $this->transliterator?->getErrorCode() ?? 0;
85+
}
86+
87+
public function getErrorMessage(): string|false
88+
{
89+
return $this->transliterator?->getErrorMessage() ?? false;
90+
}
91+
92+
public static function listIDs(): array
93+
{
94+
static $ids = [];
95+
96+
if ($ids) {
97+
return $ids;
98+
}
99+
100+
foreach (scandir(__DIR__.'/Resources/data/') as $file) {
101+
if (str_ends_with($file, '.php.gz')) {
102+
$ids[] = substr($file, 0, -7);
103+
} elseif (str_ends_with($file, '.php')) {
104+
$ids[] = substr($file, 0, -4);
105+
}
106+
}
107+
108+
return $ids;
109+
}
110+
111+
public function transliterate(string $string, int $start = 0, int $end = -1): string|false
112+
{
113+
$this->quickCheck ??= str_starts_with(array_key_first($this->map), ':') ? ':' : self::QUICK_CHECK;
114+
115+
if (0 === $start && -1 === $end && preg_match('//u', $string)) {
116+
return \strlen($string) === strcspn($string, $this->quickCheck) ? $string : strtr($string, $this->map);
117+
}
118+
119+
// Here we rely on intl to validate the $string, $start and $end arguments
120+
// and to slice the string. Slicing is done by replacing the part if $string
121+
// between $start and $end by a unique cookie that can be reliably used to
122+
// identify which part of $string should be transliterated.
123+
124+
static $cookie;
125+
static $transliterator;
126+
127+
$cookie ??= hash('xxh128', random_bytes(8));
128+
$this->transliterator ??= clone $transliterator ??= \Transliterator::createFromRules('[:any:]* > '.$cookie);
129+
130+
if (false === $result = $this->transliterator->transliterate($string, $start, $end)) {
131+
return false;
132+
}
133+
134+
$parts = explode($cookie, $result);
135+
$start = \strlen($parts[0]);
136+
$length = -\strlen($parts[1]) ?: null;
137+
$string = substr($string, $start, $length);
138+
139+
return $parts[0].(\strlen($string) === strcspn($string, $this->quickCheck) ? $string : strtr($string, $this->map)).$parts[1];
140+
}
141+
}

src/Symfony/Component/Emoji/LICENSE

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2024-present Fabien Potencier
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is furnished
8+
to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.

src/Symfony/Component/Emoji/README.md

+18

src/Symfony/Component/Intl/Resources/emoji/build.php renamed to src/Symfony/Component/Emoji/Resources/bin/build.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
final class Builder
2727
{
28-
private const TARGET_DIR = __DIR__.'/../data/transliterator/emoji/';
28+
private const TARGET_DIR = __DIR__.'/../data/';
2929

3030
public static function getEmojisCodePoints(): array
3131
{
@@ -233,7 +233,7 @@ public static function saveRules(iterable $rulesByLocale): void
233233
sort($firstChars);
234234

235235
$quickCheck = '"'.str_replace('%', '\\x', rawurlencode(implode('', $firstChars))).'"';
236-
$file = dirname(__DIR__, 2).'/Transliterator/EmojiTransliterator.php';
236+
$file = dirname(__DIR__, 2).'/EmojiTransliterator.php';
237237
file_put_contents($file, preg_replace('/QUICK_CHECK = .*;/m', "QUICK_CHECK = {$quickCheck};", file_get_contents($file)));
238238
}
239239

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
/*
5+
* This file is part of the Symfony package.
6+
*
7+
* (c) Fabien Potencier <[email protected]>
8+
*
9+
* For the full copyright and license information, please view the LICENSE
10+
* file that was distributed with this source code.
11+
*/
12+
13+
if ('cli' !== PHP_SAPI) {
14+
throw new Exception('This script must be run from the command line.');
15+
}
16+
if (!extension_loaded('zlib')) {
17+
throw new Exception('This script requires the zlib extension.');
18+
}
19+
20+
$iterator = new RecursiveIteratorIterator(
21+
new RecursiveDirectoryIterator(
22+
dirname(__DIR__).'/data',
23+
FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS
24+
)
25+
);
26+
27+
foreach ($iterator as $file) {
28+
if ('php' !== $file->getExtension()) {
29+
continue;
30+
}
31+
32+
$data = file_get_contents($file);
33+
file_put_contents('compress.zlib://'.$file.'.gz', $data);
34+
35+
unlink($file.(filesize($file.'.gz') >= strlen($data) ? '.gz' : ''));
36+
}

src/Symfony/Component/Intl/Tests/Transliterator/EmojiTransliteratorTest.php renamed to src/Symfony/Component/Emoji/Tests/EmojiTransliteratorTest.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
namespace Symfony\Component\Intl\Tests\Transliterator;
12+
namespace Symfony\Component\Emoji\Tests;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Emoji\EmojiTransliterator;
1516
use Symfony\Component\Finder\Finder;
16-
use Symfony\Component\Intl\Transliterator\EmojiTransliterator;
1717

1818
/**
1919
* @requires extension intl
@@ -95,7 +95,7 @@ public function testAllTransliterator(string $locale)
9595
public static function provideLocaleTest(): iterable
9696
{
9797
$file = (new Finder())
98-
->in(__DIR__.'/../../Resources/data/transliterator/emoji')
98+
->in(__DIR__.'/../Resources/data')
9999
->name('*.php')
100100
->notName('emoji-strip.php')
101101
->files()

0 commit comments

Comments
 (0)