This commit is contained in:
emmymayo
2025-02-05 23:15:46 +01:00
commit 7269c99357
16995 changed files with 3389680 additions and 0 deletions
@@ -0,0 +1,467 @@
<?php
namespace MailPoetVendor\Symfony\Component\String;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Symfony\Component\String\Exception\ExceptionInterface;
use MailPoetVendor\Symfony\Component\String\Exception\InvalidArgumentException;
use MailPoetVendor\Symfony\Component\String\Exception\RuntimeException;
abstract class AbstractString implements \Stringable, \JsonSerializable
{
public const PREG_PATTERN_ORDER = \PREG_PATTERN_ORDER;
public const PREG_SET_ORDER = \PREG_SET_ORDER;
public const PREG_OFFSET_CAPTURE = \PREG_OFFSET_CAPTURE;
public const PREG_UNMATCHED_AS_NULL = \PREG_UNMATCHED_AS_NULL;
public const PREG_SPLIT = 0;
public const PREG_SPLIT_NO_EMPTY = \PREG_SPLIT_NO_EMPTY;
public const PREG_SPLIT_DELIM_CAPTURE = \PREG_SPLIT_DELIM_CAPTURE;
public const PREG_SPLIT_OFFSET_CAPTURE = \PREG_SPLIT_OFFSET_CAPTURE;
protected $string = '';
protected $ignoreCase = \false;
public abstract function __construct(string $string = '');
public static function unwrap(array $values) : array
{
foreach ($values as $k => $v) {
if ($v instanceof self) {
$values[$k] = $v->__toString();
} elseif (\is_array($v) && $values[$k] !== ($v = static::unwrap($v))) {
$values[$k] = $v;
}
}
return $values;
}
public static function wrap(array $values) : array
{
$i = 0;
$keys = null;
foreach ($values as $k => $v) {
if (\is_string($k) && '' !== $k && $k !== ($j = (string) new static($k))) {
$keys = $keys ?? \array_keys($values);
$keys[$i] = $j;
}
if (\is_string($v)) {
$values[$k] = new static($v);
} elseif (\is_array($v) && $values[$k] !== ($v = static::wrap($v))) {
$values[$k] = $v;
}
++$i;
}
return null !== $keys ? \array_combine($keys, $values) : $values;
}
public function after($needle, bool $includeNeedle = \false, int $offset = 0) : self
{
$str = clone $this;
$i = \PHP_INT_MAX;
foreach ((array) $needle as $n) {
$n = (string) $n;
$j = $this->indexOf($n, $offset);
if (null !== $j && $j < $i) {
$i = $j;
$str->string = $n;
}
}
if (\PHP_INT_MAX === $i) {
return $str;
}
if (!$includeNeedle) {
$i += $str->length();
}
return $this->slice($i);
}
public function afterLast($needle, bool $includeNeedle = \false, int $offset = 0) : self
{
$str = clone $this;
$i = null;
foreach ((array) $needle as $n) {
$n = (string) $n;
$j = $this->indexOfLast($n, $offset);
if (null !== $j && $j >= $i) {
$i = $offset = $j;
$str->string = $n;
}
}
if (null === $i) {
return $str;
}
if (!$includeNeedle) {
$i += $str->length();
}
return $this->slice($i);
}
public abstract function append(string ...$suffix) : self;
public function before($needle, bool $includeNeedle = \false, int $offset = 0) : self
{
$str = clone $this;
$i = \PHP_INT_MAX;
foreach ((array) $needle as $n) {
$n = (string) $n;
$j = $this->indexOf($n, $offset);
if (null !== $j && $j < $i) {
$i = $j;
$str->string = $n;
}
}
if (\PHP_INT_MAX === $i) {
return $str;
}
if ($includeNeedle) {
$i += $str->length();
}
return $this->slice(0, $i);
}
public function beforeLast($needle, bool $includeNeedle = \false, int $offset = 0) : self
{
$str = clone $this;
$i = null;
foreach ((array) $needle as $n) {
$n = (string) $n;
$j = $this->indexOfLast($n, $offset);
if (null !== $j && $j >= $i) {
$i = $offset = $j;
$str->string = $n;
}
}
if (null === $i) {
return $str;
}
if ($includeNeedle) {
$i += $str->length();
}
return $this->slice(0, $i);
}
public function bytesAt(int $offset) : array
{
$str = $this->slice($offset, 1);
return '' === $str->string ? [] : \array_values(\unpack('C*', $str->string));
}
public abstract function camel() : self;
public abstract function chunk(int $length = 1) : array;
public function collapseWhitespace() : self
{
$str = clone $this;
$str->string = \trim(\preg_replace("/(?:[ \n\r\t\f]{2,}+|[\n\r\t\f])/", ' ', $str->string), " \n\r\t\f");
return $str;
}
public function containsAny($needle) : bool
{
return null !== $this->indexOf($needle);
}
public function endsWith($suffix) : bool
{
if (!\is_array($suffix) && !$suffix instanceof \Traversable) {
throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class));
}
foreach ($suffix as $s) {
if ($this->endsWith((string) $s)) {
return \true;
}
}
return \false;
}
public function ensureEnd(string $suffix) : self
{
if (!$this->endsWith($suffix)) {
return $this->append($suffix);
}
$suffix = \preg_quote($suffix);
$regex = '{(' . $suffix . ')(?:' . $suffix . ')++$}D';
return $this->replaceMatches($regex . ($this->ignoreCase ? 'i' : ''), '$1');
}
public function ensureStart(string $prefix) : self
{
$prefix = new static($prefix);
if (!$this->startsWith($prefix)) {
return $this->prepend($prefix);
}
$str = clone $this;
$i = $prefixLen = $prefix->length();
while ($this->indexOf($prefix, $i) === $i) {
$str = $str->slice($prefixLen);
$i += $prefixLen;
}
return $str;
}
public function equalsTo($string) : bool
{
if (!\is_array($string) && !$string instanceof \Traversable) {
throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class));
}
foreach ($string as $s) {
if ($this->equalsTo((string) $s)) {
return \true;
}
}
return \false;
}
public abstract function folded() : self;
public function ignoreCase() : self
{
$str = clone $this;
$str->ignoreCase = \true;
return $str;
}
public function indexOf($needle, int $offset = 0) : ?int
{
if (!\is_array($needle) && !$needle instanceof \Traversable) {
throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class));
}
$i = \PHP_INT_MAX;
foreach ($needle as $n) {
$j = $this->indexOf((string) $n, $offset);
if (null !== $j && $j < $i) {
$i = $j;
}
}
return \PHP_INT_MAX === $i ? null : $i;
}
public function indexOfLast($needle, int $offset = 0) : ?int
{
if (!\is_array($needle) && !$needle instanceof \Traversable) {
throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class));
}
$i = null;
foreach ($needle as $n) {
$j = $this->indexOfLast((string) $n, $offset);
if (null !== $j && $j >= $i) {
$i = $offset = $j;
}
}
return $i;
}
public function isEmpty() : bool
{
return '' === $this->string;
}
public abstract function join(array $strings, ?string $lastGlue = null) : self;
public function jsonSerialize() : string
{
return $this->string;
}
public abstract function length() : int;
public abstract function lower() : self;
public abstract function match(string $regexp, int $flags = 0, int $offset = 0) : array;
public abstract function padBoth(int $length, string $padStr = ' ') : self;
public abstract function padEnd(int $length, string $padStr = ' ') : self;
public abstract function padStart(int $length, string $padStr = ' ') : self;
public abstract function prepend(string ...$prefix) : self;
public function repeat(int $multiplier) : self
{
if (0 > $multiplier) {
throw new InvalidArgumentException(\sprintf('Multiplier must be positive, %d given.', $multiplier));
}
$str = clone $this;
$str->string = \str_repeat($str->string, $multiplier);
return $str;
}
public abstract function replace(string $from, string $to) : self;
public abstract function replaceMatches(string $fromRegexp, $to) : self;
public abstract function reverse() : self;
public abstract function slice(int $start = 0, ?int $length = null) : self;
public abstract function snake() : self;
public abstract function splice(string $replacement, int $start = 0, ?int $length = null) : self;
public function split(string $delimiter, ?int $limit = null, ?int $flags = null) : array
{
if (null === $flags) {
throw new \TypeError('Split behavior when $flags is null must be implemented by child classes.');
}
if ($this->ignoreCase) {
$delimiter .= 'i';
}
\set_error_handler(static function ($t, $m) {
throw new InvalidArgumentException($m);
});
try {
if (\false === ($chunks = \preg_split($delimiter, $this->string, $limit, $flags))) {
$lastError = \preg_last_error();
foreach (\get_defined_constants(\true)['pcre'] as $k => $v) {
if ($lastError === $v && '_ERROR' === \substr($k, -6)) {
throw new RuntimeException('Splitting failed with ' . $k . '.');
}
}
throw new RuntimeException('Splitting failed with unknown error code.');
}
} finally {
\restore_error_handler();
}
$str = clone $this;
if (self::PREG_SPLIT_OFFSET_CAPTURE & $flags) {
foreach ($chunks as &$chunk) {
$str->string = $chunk[0];
$chunk[0] = clone $str;
}
} else {
foreach ($chunks as &$chunk) {
$str->string = $chunk;
$chunk = clone $str;
}
}
return $chunks;
}
public function startsWith($prefix) : bool
{
if (!\is_array($prefix) && !$prefix instanceof \Traversable) {
throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class));
}
foreach ($prefix as $prefix) {
if ($this->startsWith((string) $prefix)) {
return \true;
}
}
return \false;
}
public abstract function title(bool $allWords = \false) : self;
public function toByteString(?string $toEncoding = null) : ByteString
{
$b = new ByteString();
$toEncoding = \in_array($toEncoding, ['utf8', 'utf-8', 'UTF8'], \true) ? 'UTF-8' : $toEncoding;
if (null === $toEncoding || $toEncoding === ($fromEncoding = $this instanceof AbstractUnicodeString || \preg_match('//u', $b->string) ? 'UTF-8' : 'Windows-1252')) {
$b->string = $this->string;
return $b;
}
\set_error_handler(static function ($t, $m) {
throw new InvalidArgumentException($m);
});
try {
try {
$b->string = \mb_convert_encoding($this->string, $toEncoding, 'UTF-8');
} catch (InvalidArgumentException|\ValueError $e) {
if (!\function_exists('iconv')) {
if ($e instanceof \ValueError) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
throw $e;
}
$b->string = \iconv('UTF-8', $toEncoding, $this->string);
}
} finally {
\restore_error_handler();
}
return $b;
}
public function toCodePointString() : CodePointString
{
return new CodePointString($this->string);
}
public function toString() : string
{
return $this->string;
}
public function toUnicodeString() : UnicodeString
{
return new UnicodeString($this->string);
}
public abstract function trim(string $chars = " \t\n\r\x00\v\f ") : self;
public abstract function trimEnd(string $chars = " \t\n\r\x00\v\f ") : self;
public function trimPrefix($prefix) : self
{
if (\is_array($prefix) || $prefix instanceof \Traversable) {
foreach ($prefix as $s) {
$t = $this->trimPrefix($s);
if ($t->string !== $this->string) {
return $t;
}
}
return clone $this;
}
$str = clone $this;
if ($prefix instanceof self) {
$prefix = $prefix->string;
} else {
$prefix = (string) $prefix;
}
if ('' !== $prefix && \strlen($this->string) >= \strlen($prefix) && 0 === \substr_compare($this->string, $prefix, 0, \strlen($prefix), $this->ignoreCase)) {
$str->string = \substr($this->string, \strlen($prefix));
}
return $str;
}
public abstract function trimStart(string $chars = " \t\n\r\x00\v\f ") : self;
public function trimSuffix($suffix) : self
{
if (\is_array($suffix) || $suffix instanceof \Traversable) {
foreach ($suffix as $s) {
$t = $this->trimSuffix($s);
if ($t->string !== $this->string) {
return $t;
}
}
return clone $this;
}
$str = clone $this;
if ($suffix instanceof self) {
$suffix = $suffix->string;
} else {
$suffix = (string) $suffix;
}
if ('' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === \substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase)) {
$str->string = \substr($this->string, 0, -\strlen($suffix));
}
return $str;
}
public function truncate(int $length, string $ellipsis = '', bool $cut = \true) : self
{
$stringLength = $this->length();
if ($stringLength <= $length) {
return clone $this;
}
$ellipsisLength = '' !== $ellipsis ? (new static($ellipsis))->length() : 0;
if ($length < $ellipsisLength) {
$ellipsisLength = 0;
}
if (!$cut) {
if (null === ($length = $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1))) {
return clone $this;
}
$length += $ellipsisLength;
}
$str = $this->slice(0, $length - $ellipsisLength);
return $ellipsisLength ? $str->trimEnd()->append($ellipsis) : $str;
}
public abstract function upper() : self;
public abstract function width(bool $ignoreAnsiDecoration = \true) : int;
public function wordwrap(int $width = 75, string $break = "\n", bool $cut = \false) : self
{
$lines = '' !== $break ? $this->split($break) : [clone $this];
$chars = [];
$mask = '';
if (1 === \count($lines) && '' === $lines[0]->string) {
return $lines[0];
}
foreach ($lines as $i => $line) {
if ($i) {
$chars[] = $break;
$mask .= '#';
}
foreach ($line->chunk() as $char) {
$chars[] = $char->string;
$mask .= ' ' === $char->string ? ' ' : '?';
}
}
$string = '';
$j = 0;
$b = $i = -1;
$mask = \wordwrap($mask, $width, '#', $cut);
while (\false !== ($b = \strpos($mask, '#', $b + 1))) {
for (++$i; $i < $b; ++$i) {
$string .= $chars[$j];
unset($chars[$j++]);
}
if ($break === $chars[$j] || ' ' === $chars[$j]) {
unset($chars[$j++]);
}
$string .= $break;
}
$str = clone $this;
$str->string = $string . \implode('', $chars);
return $str;
}
public function __sleep() : array
{
return ['string'];
}
public function __clone()
{
$this->ignoreCase = \false;
}
public function __toString() : string
{
return $this->string;
}
}
@@ -0,0 +1,447 @@
<?php
namespace MailPoetVendor\Symfony\Component\String;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Symfony\Component\String\Exception\ExceptionInterface;
use MailPoetVendor\Symfony\Component\String\Exception\InvalidArgumentException;
use MailPoetVendor\Symfony\Component\String\Exception\RuntimeException;
abstract class AbstractUnicodeString extends AbstractString
{
public const NFC = \Normalizer::NFC;
public const NFD = \Normalizer::NFD;
public const NFKC = \Normalizer::NFKC;
public const NFKD = \Normalizer::NFKD;
// all ASCII letters sorted by typical frequency of occurrence
private const ASCII = " eiasntrolud][cmp'\ng|hv.fb,:=-q10C2*yx)(L9AS/P\"EjMIk3>5T<D4}B{8FwR67UGN;JzV#HOW_&!K?XQ%Y\\\tZ+~^\$@`\x00\x01\x02\x03\x04\x05\x06\x07\x08\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f";
// the subset of folded case mappings that is not in lower case mappings
private const FOLD_FROM = ['İ', 'µ', 'ſ', "ͅ", 'ς', 'ϐ', 'ϑ', 'ϕ', 'ϖ', 'ϰ', 'ϱ', 'ϵ', 'ẛ', "", 'ß', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'և', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'ẚ', 'ẞ', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'ᾐ', 'ᾑ', 'ᾒ', 'ᾓ', 'ᾔ', 'ᾕ', 'ᾖ', 'ᾗ', 'ᾘ', 'ᾙ', 'ᾚ', 'ᾛ', 'ᾜ', 'ᾝ', 'ᾞ', 'ᾟ', 'ᾠ', 'ᾡ', 'ᾢ', 'ᾣ', 'ᾤ', 'ᾥ', 'ᾦ', 'ᾧ', 'ᾨ', 'ᾩ', 'ᾪ', 'ᾫ', 'ᾬ', 'ᾭ', 'ᾮ', 'ᾯ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'ᾼ', 'ῂ', 'ῃ', 'ῄ', 'ῆ', 'ῇ', 'ῌ', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ῲ', 'ῳ', 'ῴ', 'ῶ', 'ῷ', 'ῼ', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'ſt', 'st', 'ﬓ', 'ﬔ', 'ﬕ', 'ﬖ', 'ﬗ'];
private const FOLD_TO = ['i̇', 'μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', 'ṡ', 'ι', 'ss', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'եւ', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'aʾ', 'ss', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὰι', 'αι', 'άι', 'ᾶ', 'ᾶι', 'αι', 'ὴι', 'ηι', 'ήι', 'ῆ', 'ῆι', 'ηι', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ὼι', 'ωι', 'ώι', 'ῶ', 'ῶι', 'ωι', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'st', 'st', 'մն', 'մե', 'մի', 'վն', 'մխ'];
// the subset of upper case mappings that map one code point to many code points
private const UPPER_FROM = ['ß', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'ſt', 'st', 'և', 'ﬓ', 'ﬔ', 'ﬕ', 'ﬖ', 'ﬗ', 'ʼn', 'ΐ', 'ΰ', 'ǰ', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'ẚ', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ᾶ', 'ῆ', 'ῒ', 'ΐ', 'ῖ', 'ῗ', 'ῢ', 'ΰ', 'ῤ', 'ῦ', 'ῧ', 'ῶ'];
private const UPPER_TO = ['SS', 'FF', 'FI', 'FL', 'FFI', 'FFL', 'ST', 'ST', 'ԵՒ', 'ՄՆ', 'ՄԵ', 'ՄԻ', 'ՎՆ', 'ՄԽ', 'ʼN', 'Ϊ́', 'Ϋ́', 'J̌', 'H̱', 'T̈', 'W̊', 'Y̊', 'Aʾ', 'Υ̓', 'Υ̓̀', 'Υ̓́', 'Υ̓͂', 'Α͂', 'Η͂', 'Ϊ̀', 'Ϊ́', 'Ι͂', 'Ϊ͂', 'Ϋ̀', 'Ϋ́', 'Ρ̓', 'Υ͂', 'Ϋ͂', 'Ω͂'];
// the subset of https://github.com/unicode-org/cldr/blob/master/common/transforms/Latin-ASCII.xml that is not in NFKD
private const TRANSLIT_FROM = ['Æ', 'Ð', 'Ø', 'Þ', 'ß', 'æ', 'ð', 'ø', 'þ', 'Đ', 'đ', 'Ħ', 'ħ', 'ı', 'ĸ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'ʼn', 'Ŋ', 'ŋ', 'Œ', 'œ', 'Ŧ', 'ŧ', 'ƀ', 'Ɓ', 'Ƃ', 'ƃ', 'Ƈ', 'ƈ', 'Ɖ', 'Ɗ', 'Ƌ', 'ƌ', 'Ɛ', 'Ƒ', 'ƒ', 'Ɠ', 'ƕ', 'Ɩ', 'Ɨ', 'Ƙ', 'ƙ', 'ƚ', 'Ɲ', 'ƞ', 'Ƣ', 'ƣ', 'Ƥ', 'ƥ', 'ƫ', 'Ƭ', 'ƭ', 'Ʈ', 'Ʋ', 'Ƴ', 'ƴ', 'Ƶ', 'ƶ', 'DŽ', 'Dž', 'dž', 'Ǥ', 'ǥ', 'ȡ', 'Ȥ', 'ȥ', 'ȴ', 'ȵ', 'ȶ', 'ȷ', 'ȸ', 'ȹ', 'Ⱥ', 'Ȼ', 'ȼ', 'Ƚ', 'Ⱦ', 'ȿ', 'ɀ', 'Ƀ', 'Ʉ', 'Ɇ', 'ɇ', 'Ɉ', 'ɉ', 'Ɍ', 'ɍ', 'Ɏ', 'ɏ', 'ɓ', 'ɕ', 'ɖ', 'ɗ', 'ɛ', 'ɟ', 'ɠ', 'ɡ', 'ɢ', 'ɦ', 'ɧ', 'ɨ', 'ɪ', 'ɫ', 'ɬ', 'ɭ', 'ɱ', 'ɲ', 'ɳ', 'ɴ', 'ɶ', 'ɼ', 'ɽ', 'ɾ', 'ʀ', 'ʂ', 'ʈ', 'ʉ', 'ʋ', 'ʏ', 'ʐ', 'ʑ', 'ʙ', 'ʛ', 'ʜ', 'ʝ', 'ʟ', 'ʠ', 'ʣ', 'ʥ', 'ʦ', 'ʪ', 'ʫ', 'ᴀ', 'ᴁ', 'ᴃ', '', 'ᴅ', 'ᴆ', 'ᴇ', 'ᴊ', 'ᴋ', 'ᴌ', 'ᴍ', '', 'ᴘ', 'ᴛ', '', '', '', '', 'ᵫ', 'ᵬ', 'ᵭ', 'ᵮ', 'ᵯ', 'ᵰ', 'ᵱ', 'ᵲ', 'ᵳ', 'ᵴ', 'ᵵ', 'ᵶ', 'ᵺ', 'ᵻ', 'ᵽ', 'ᵾ', 'ᶀ', 'ᶁ', 'ᶂ', '', 'ᶄ', 'ᶅ', 'ᶆ', 'ᶇ', 'ᶈ', 'ᶉ', 'ᶊ', '', 'ᶍ', 'ᶎ', 'ᶏ', 'ᶑ', 'ᶒ', 'ᶓ', 'ᶖ', 'ᶙ', 'ẚ', 'ẜ', '', 'ẞ', 'Ỻ', 'ỻ', 'Ỽ', 'ỽ', 'Ỿ', 'ỿ', '©', '®', '₠', '₢', '₣', '₤', '₧', '₺', '₹', '', '℞', '㎧', '㎮', '㏆', '㏗', '㏞', '㏟', '¼', '½', '¾', '⅓', '⅔', '⅕', '⅖', '⅗', '⅘', '⅙', '⅚', '⅛', '⅜', '⅝', '⅞', '⅟', '', '', '', '', '', '“', '”', '„', '‟', '', '″', '〝', '〞', '«', '»', '', '', '', '', '', '', '—', '―', '︱', '︲', '', '‖', '', '⁅', '⁆', '', '、', '。', '〈', '〉', '《', '》', '', '', '〘', '〙', '〚', '〛', '︑', '︒', '︹', '︺', '︽', '︾', '︿', '﹀', '﹑', '﹝', '﹞', '⦅', '⦆', '。', '、', '×', '÷', '', '', '', '', '∥', '≪', '≫', '⦅', '⦆'];
private const TRANSLIT_TO = ['AE', 'D', 'O', 'TH', 'ss', 'ae', 'd', 'o', 'th', 'D', 'd', 'H', 'h', 'i', 'q', 'L', 'l', 'L', 'l', '\'n', 'N', 'n', 'OE', 'oe', 'T', 't', 'b', 'B', 'B', 'b', 'C', 'c', 'D', 'D', 'D', 'd', 'E', 'F', 'f', 'G', 'hv', 'I', 'I', 'K', 'k', 'l', 'N', 'n', 'OI', 'oi', 'P', 'p', 't', 'T', 't', 'T', 'V', 'Y', 'y', 'Z', 'z', 'DZ', 'Dz', 'dz', 'G', 'g', 'd', 'Z', 'z', 'l', 'n', 't', 'j', 'db', 'qp', 'A', 'C', 'c', 'L', 'T', 's', 'z', 'B', 'U', 'E', 'e', 'J', 'j', 'R', 'r', 'Y', 'y', 'b', 'c', 'd', 'd', 'e', 'j', 'g', 'g', 'G', 'h', 'h', 'i', 'I', 'l', 'l', 'l', 'm', 'n', 'n', 'N', 'OE', 'r', 'r', 'r', 'R', 's', 't', 'u', 'v', 'Y', 'z', 'z', 'B', 'G', 'H', 'j', 'L', 'q', 'dz', 'dz', 'ts', 'ls', 'lz', 'A', 'AE', 'B', 'C', 'D', 'D', 'E', 'J', 'K', 'L', 'M', 'O', 'P', 'T', 'U', 'V', 'W', 'Z', 'ue', 'b', 'd', 'f', 'm', 'n', 'p', 'r', 'r', 's', 't', 'z', 'th', 'I', 'p', 'U', 'b', 'd', 'f', 'g', 'k', 'l', 'm', 'n', 'p', 'r', 's', 'v', 'x', 'z', 'a', 'd', 'e', 'e', 'i', 'u', 'a', 's', 's', 'SS', 'LL', 'll', 'V', 'v', 'Y', 'y', '(C)', '(R)', 'CE', 'Cr', 'Fr.', 'L.', 'Pts', 'TL', 'Rs', 'x', 'Rx', 'm/s', 'rad/s', 'C/kg', 'pH', 'V/m', 'A/m', ' 1/4', ' 1/2', ' 3/4', ' 1/3', ' 2/3', ' 1/5', ' 2/5', ' 3/5', ' 4/5', ' 1/6', ' 5/6', ' 1/8', ' 3/8', ' 5/8', ' 7/8', ' 1/', '0', '\'', '\'', ',', '\'', '"', '"', ',,', '"', '\'', '"', '"', '"', '<<', '>>', '<', '>', '-', '-', '-', '-', '-', '-', '-', '-', '-', '||', '/', '[', ']', '*', ',', '.', '<', '>', '<<', '>>', '[', ']', '[', ']', '[', ']', ',', '.', '[', ']', '<<', '>>', '<', '>', ',', '[', ']', '((', '))', '.', ',', '*', '/', '-', '/', '\\', '|', '||', '<<', '>>', '((', '))'];
private static $transliterators = [];
private static $tableZero;
private static $tableWide;
public static function fromCodePoints(int ...$codes) : self
{
$string = '';
foreach ($codes as $code) {
if (0x80 > ($code %= 0x200000)) {
$string .= \chr($code);
} elseif (0x800 > $code) {
$string .= \chr(0xc0 | $code >> 6) . \chr(0x80 | $code & 0x3f);
} elseif (0x10000 > $code) {
$string .= \chr(0xe0 | $code >> 12) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f);
} else {
$string .= \chr(0xf0 | $code >> 18) . \chr(0x80 | $code >> 12 & 0x3f) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f);
}
}
return new static($string);
}
public function ascii(array $rules = []) : self
{
$str = clone $this;
$s = $str->string;
$str->string = '';
\array_unshift($rules, 'nfd');
$rules[] = 'latin-ascii';
if (\function_exists('transliterator_transliterate')) {
$rules[] = 'any-latin/bgn';
}
$rules[] = 'nfkd';
$rules[] = '[:nonspacing mark:] remove';
while (\strlen($s) - 1 > ($i = \strspn($s, self::ASCII))) {
if (0 < --$i) {
$str->string .= \substr($s, 0, $i);
$s = \substr($s, $i);
}
if (!($rule = \array_shift($rules))) {
$rules = [];
// An empty rule interrupts the next ones
}
if ($rule instanceof \Transliterator) {
$s = $rule->transliterate($s);
} elseif ($rule instanceof \Closure) {
$s = $rule($s);
} elseif ($rule) {
if ('nfd' === ($rule = \strtolower($rule))) {
\normalizer_is_normalized($s, self::NFD) ?: ($s = \normalizer_normalize($s, self::NFD));
} elseif ('nfkd' === $rule) {
\normalizer_is_normalized($s, self::NFKD) ?: ($s = \normalizer_normalize($s, self::NFKD));
} elseif ('[:nonspacing mark:] remove' === $rule) {
$s = \preg_replace('/\\p{Mn}++/u', '', $s);
} elseif ('latin-ascii' === $rule) {
$s = \str_replace(self::TRANSLIT_FROM, self::TRANSLIT_TO, $s);
} elseif ('de-ascii' === $rule) {
$s = \preg_replace("/([AUO])̈(?=\\p{Ll})/u", '$1e', $s);
$s = \str_replace(["", "", "", "", "", ""], ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'], $s);
} elseif (\function_exists('transliterator_transliterate')) {
if (null === ($transliterator = self::$transliterators[$rule] ?? (self::$transliterators[$rule] = \Transliterator::create($rule)))) {
if ('any-latin/bgn' === $rule) {
$rule = 'any-latin';
$transliterator = self::$transliterators[$rule] ?? (self::$transliterators[$rule] = \Transliterator::create($rule));
}
if (null === $transliterator) {
throw new InvalidArgumentException(\sprintf('Unknown transliteration rule "%s".', $rule));
}
self::$transliterators['any-latin/bgn'] = $transliterator;
}
$s = $transliterator->transliterate($s);
}
} elseif (!\function_exists('iconv')) {
$s = \preg_replace('/[^\\x00-\\x7F]/u', '?', $s);
} else {
$s = @\preg_replace_callback('/[^\\x00-\\x7F]/u', static function ($c) {
$c = (string) \iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]);
if ('' === $c && '' === \iconv('UTF-8', 'ASCII//TRANSLIT', '²')) {
throw new \LogicException(\sprintf('"%s" requires a translit-able iconv implementation, try installing "gnu-libiconv" if you\'re using Alpine Linux.', static::class));
}
return 1 < \strlen($c) ? \ltrim($c, '\'`"^~') : ('' !== $c ? $c : '?');
}, $s);
}
}
$str->string .= $s;
return $str;
}
public function camel() : parent
{
$str = clone $this;
$str->string = \str_replace(' ', '', \preg_replace_callback('/\\b.(?![A-Z]{2,})/u', static function ($m) use(&$i) {
return 1 === ++$i ? 'İ' === $m[0] ? 'i̇' : \mb_strtolower($m[0], 'UTF-8') : \mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8');
}, \preg_replace('/[^\\pL0-9]++/u', ' ', $this->string)));
return $str;
}
public function codePointsAt(int $offset) : array
{
$str = $this->slice($offset, 1);
if ('' === $str->string) {
return [];
}
$codePoints = [];
foreach (\preg_split('//u', $str->string, -1, \PREG_SPLIT_NO_EMPTY) as $c) {
$codePoints[] = \mb_ord($c, 'UTF-8');
}
return $codePoints;
}
public function folded(bool $compat = \true) : parent
{
$str = clone $this;
if (!$compat || \PHP_VERSION_ID < 70300 || !\defined('Normalizer::NFKC_CF')) {
$str->string = \normalizer_normalize($str->string, $compat ? \Normalizer::NFKC : \Normalizer::NFC);
$str->string = \mb_strtolower(\str_replace(self::FOLD_FROM, self::FOLD_TO, $str->string), 'UTF-8');
} else {
$str->string = \normalizer_normalize($str->string, \Normalizer::NFKC_CF);
}
return $str;
}
public function join(array $strings, ?string $lastGlue = null) : parent
{
$str = clone $this;
$tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue . \array_pop($strings) : '';
$str->string = \implode($this->string, $strings) . $tail;
if (!\preg_match('//u', $str->string)) {
throw new InvalidArgumentException('Invalid UTF-8 string.');
}
return $str;
}
public function lower() : parent
{
$str = clone $this;
$str->string = \mb_strtolower(\str_replace('İ', 'i̇', $str->string), 'UTF-8');
return $str;
}
public function match(string $regexp, int $flags = 0, int $offset = 0) : array
{
$match = (\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags ? 'preg_match_all' : 'preg_match';
if ($this->ignoreCase) {
$regexp .= 'i';
}
\set_error_handler(static function ($t, $m) {
throw new InvalidArgumentException($m);
});
try {
if (\false === $match($regexp . 'u', $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) {
$lastError = \preg_last_error();
foreach (\get_defined_constants(\true)['pcre'] as $k => $v) {
if ($lastError === $v && '_ERROR' === \substr($k, -6)) {
throw new RuntimeException('Matching failed with ' . $k . '.');
}
}
throw new RuntimeException('Matching failed with unknown error code.');
}
} finally {
\restore_error_handler();
}
return $matches;
}
public function normalize(int $form = self::NFC) : self
{
if (!\in_array($form, [self::NFC, self::NFD, self::NFKC, self::NFKD])) {
throw new InvalidArgumentException('Unsupported normalization form.');
}
$str = clone $this;
\normalizer_is_normalized($str->string, $form) ?: ($str->string = \normalizer_normalize($str->string, $form));
return $str;
}
public function padBoth(int $length, string $padStr = ' ') : parent
{
if ('' === $padStr || !\preg_match('//u', $padStr)) {
throw new InvalidArgumentException('Invalid UTF-8 string.');
}
$pad = clone $this;
$pad->string = $padStr;
return $this->pad($length, $pad, \STR_PAD_BOTH);
}
public function padEnd(int $length, string $padStr = ' ') : parent
{
if ('' === $padStr || !\preg_match('//u', $padStr)) {
throw new InvalidArgumentException('Invalid UTF-8 string.');
}
$pad = clone $this;
$pad->string = $padStr;
return $this->pad($length, $pad, \STR_PAD_RIGHT);
}
public function padStart(int $length, string $padStr = ' ') : parent
{
if ('' === $padStr || !\preg_match('//u', $padStr)) {
throw new InvalidArgumentException('Invalid UTF-8 string.');
}
$pad = clone $this;
$pad->string = $padStr;
return $this->pad($length, $pad, \STR_PAD_LEFT);
}
public function replaceMatches(string $fromRegexp, $to) : parent
{
if ($this->ignoreCase) {
$fromRegexp .= 'i';
}
if (\is_array($to) || $to instanceof \Closure) {
if (!\is_callable($to)) {
throw new \TypeError(\sprintf('Argument 2 passed to "%s::replaceMatches()" must be callable, array given.', static::class));
}
$replace = 'preg_replace_callback';
$to = static function (array $m) use($to) : string {
$to = $to($m);
if ('' !== $to && (!\is_string($to) || !\preg_match('//u', $to))) {
throw new InvalidArgumentException('Replace callback must return a valid UTF-8 string.');
}
return $to;
};
} elseif ('' !== $to && !\preg_match('//u', $to)) {
throw new InvalidArgumentException('Invalid UTF-8 string.');
} else {
$replace = 'preg_replace';
}
\set_error_handler(static function ($t, $m) {
throw new InvalidArgumentException($m);
});
try {
if (null === ($string = $replace($fromRegexp . 'u', $to, $this->string))) {
$lastError = \preg_last_error();
foreach (\get_defined_constants(\true)['pcre'] as $k => $v) {
if ($lastError === $v && '_ERROR' === \substr($k, -6)) {
throw new RuntimeException('Matching failed with ' . $k . '.');
}
}
throw new RuntimeException('Matching failed with unknown error code.');
}
} finally {
\restore_error_handler();
}
$str = clone $this;
$str->string = $string;
return $str;
}
public function reverse() : parent
{
$str = clone $this;
$str->string = \implode('', \array_reverse(\preg_split('/(\\X)/u', $str->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY)));
return $str;
}
public function snake() : parent
{
$str = $this->camel();
$str->string = \mb_strtolower(\preg_replace(['/(\\p{Lu}+)(\\p{Lu}\\p{Ll})/u', '/([\\p{Ll}0-9])(\\p{Lu})/u'], 'MailPoetVendor\\1_\\2', $str->string), 'UTF-8');
return $str;
}
public function title(bool $allWords = \false) : parent
{
$str = clone $this;
$limit = $allWords ? -1 : 1;
$str->string = \preg_replace_callback('/\\b./u', static function (array $m) : string {
return \mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8');
}, $str->string, $limit);
return $str;
}
public function trim(string $chars = " \t\n\r\x00\v\f ") : parent
{
if (" \t\n\r\x00\v\f " !== $chars && !\preg_match('//u', $chars)) {
throw new InvalidArgumentException('Invalid UTF-8 chars.');
}
$chars = \preg_quote($chars);
$str = clone $this;
$str->string = \preg_replace("{^[{$chars}]++|[{$chars}]++\$}uD", '', $str->string);
return $str;
}
public function trimEnd(string $chars = " \t\n\r\x00\v\f ") : parent
{
if (" \t\n\r\x00\v\f " !== $chars && !\preg_match('//u', $chars)) {
throw new InvalidArgumentException('Invalid UTF-8 chars.');
}
$chars = \preg_quote($chars);
$str = clone $this;
$str->string = \preg_replace("{[{$chars}]++\$}uD", '', $str->string);
return $str;
}
public function trimPrefix($prefix) : parent
{
if (!$this->ignoreCase) {
return parent::trimPrefix($prefix);
}
$str = clone $this;
if ($prefix instanceof \Traversable) {
$prefix = \iterator_to_array($prefix, \false);
} elseif ($prefix instanceof parent) {
$prefix = $prefix->string;
}
$prefix = \implode('|', \array_map('preg_quote', (array) $prefix));
$str->string = \preg_replace("{^(?:{$prefix})}iuD", '', $this->string);
return $str;
}
public function trimStart(string $chars = " \t\n\r\x00\v\f ") : parent
{
if (" \t\n\r\x00\v\f " !== $chars && !\preg_match('//u', $chars)) {
throw new InvalidArgumentException('Invalid UTF-8 chars.');
}
$chars = \preg_quote($chars);
$str = clone $this;
$str->string = \preg_replace("{^[{$chars}]++}uD", '', $str->string);
return $str;
}
public function trimSuffix($suffix) : parent
{
if (!$this->ignoreCase) {
return parent::trimSuffix($suffix);
}
$str = clone $this;
if ($suffix instanceof \Traversable) {
$suffix = \iterator_to_array($suffix, \false);
} elseif ($suffix instanceof parent) {
$suffix = $suffix->string;
}
$suffix = \implode('|', \array_map('preg_quote', (array) $suffix));
$str->string = \preg_replace("{(?:{$suffix})\$}iuD", '', $this->string);
return $str;
}
public function upper() : parent
{
$str = clone $this;
$str->string = \mb_strtoupper($str->string, 'UTF-8');
if (\PHP_VERSION_ID < 70300) {
$str->string = \str_replace(self::UPPER_FROM, self::UPPER_TO, $str->string);
}
return $str;
}
public function width(bool $ignoreAnsiDecoration = \true) : int
{
$width = 0;
$s = \str_replace(["\x00", "\x05", "\x07"], '', $this->string);
if (\false !== \strpos($s, "\r")) {
$s = \str_replace(["\r\n", "\r"], "\n", $s);
}
if (!$ignoreAnsiDecoration) {
$s = \preg_replace('/[\\p{Cc}\\x7F]++/u', '', $s);
}
foreach (\explode("\n", $s) as $s) {
if ($ignoreAnsiDecoration) {
$s = \preg_replace('/(?:\\x1B(?:
\\[ [\\x30-\\x3F]*+ [\\x20-\\x2F]*+ [\\x40-\\x7E]
| [P\\]X^_] .*? \\x1B\\\\
| [\\x41-\\x7E]
)|[\\p{Cc}\\x7F]++)/xu', '', $s);
}
$lineWidth = $this->wcswidth($s);
if ($lineWidth > $width) {
$width = $lineWidth;
}
}
return $width;
}
private function pad(int $len, self $pad, int $type) : parent
{
$sLen = $this->length();
if ($len <= $sLen) {
return clone $this;
}
$padLen = $pad->length();
$freeLen = $len - $sLen;
$len = $freeLen % $padLen;
switch ($type) {
case \STR_PAD_RIGHT:
return $this->append(\str_repeat($pad->string, \intdiv($freeLen, $padLen)) . ($len ? $pad->slice(0, $len) : ''));
case \STR_PAD_LEFT:
return $this->prepend(\str_repeat($pad->string, \intdiv($freeLen, $padLen)) . ($len ? $pad->slice(0, $len) : ''));
case \STR_PAD_BOTH:
$freeLen /= 2;
$rightLen = \ceil($freeLen);
$len = $rightLen % $padLen;
$str = $this->append(\str_repeat($pad->string, \intdiv($rightLen, $padLen)) . ($len ? $pad->slice(0, $len) : ''));
$leftLen = \floor($freeLen);
$len = $leftLen % $padLen;
return $str->prepend(\str_repeat($pad->string, \intdiv($leftLen, $padLen)) . ($len ? $pad->slice(0, $len) : ''));
default:
throw new InvalidArgumentException('Invalid padding type.');
}
}
private function wcswidth(string $string) : int
{
$width = 0;
foreach (\preg_split('//u', $string, -1, \PREG_SPLIT_NO_EMPTY) as $c) {
$codePoint = \mb_ord($c, 'UTF-8');
if (0 === $codePoint || 0x34f === $codePoint || 0x200b <= $codePoint && 0x200f >= $codePoint || 0x2028 === $codePoint || 0x2029 === $codePoint || 0x202a <= $codePoint && 0x202e >= $codePoint || 0x2060 <= $codePoint && 0x2063 >= $codePoint) {
continue;
}
// Non printable characters
if (32 > $codePoint || 0x7f <= $codePoint && 0xa0 > $codePoint) {
return -1;
}
if (null === self::$tableZero) {
self::$tableZero = (require __DIR__ . '/Resources/data/wcswidth_table_zero.php');
}
if ($codePoint >= self::$tableZero[0][0] && $codePoint <= self::$tableZero[$ubound = \count(self::$tableZero) - 1][1]) {
$lbound = 0;
while ($ubound >= $lbound) {
$mid = \floor(($lbound + $ubound) / 2);
if ($codePoint > self::$tableZero[$mid][1]) {
$lbound = $mid + 1;
} elseif ($codePoint < self::$tableZero[$mid][0]) {
$ubound = $mid - 1;
} else {
continue 2;
}
}
}
if (null === self::$tableWide) {
self::$tableWide = (require __DIR__ . '/Resources/data/wcswidth_table_wide.php');
}
if ($codePoint >= self::$tableWide[0][0] && $codePoint <= self::$tableWide[$ubound = \count(self::$tableWide) - 1][1]) {
$lbound = 0;
while ($ubound >= $lbound) {
$mid = \floor(($lbound + $ubound) / 2);
if ($codePoint > self::$tableWide[$mid][1]) {
$lbound = $mid + 1;
} elseif ($codePoint < self::$tableWide[$mid][0]) {
$ubound = $mid - 1;
} else {
$width += 2;
continue 2;
}
}
}
++$width;
}
return $width;
}
}
@@ -0,0 +1,378 @@
<?php
namespace MailPoetVendor\Symfony\Component\String;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Symfony\Component\String\Exception\ExceptionInterface;
use MailPoetVendor\Symfony\Component\String\Exception\InvalidArgumentException;
use MailPoetVendor\Symfony\Component\String\Exception\RuntimeException;
class ByteString extends AbstractString
{
private const ALPHABET_ALPHANUMERIC = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
public function __construct(string $string = '')
{
$this->string = $string;
}
public static function fromRandom(int $length = 16, ?string $alphabet = null) : self
{
if ($length <= 0) {
throw new InvalidArgumentException(\sprintf('A strictly positive length is expected, "%d" given.', $length));
}
$alphabet = $alphabet ?? self::ALPHABET_ALPHANUMERIC;
$alphabetSize = \strlen($alphabet);
$bits = (int) \ceil(\log($alphabetSize, 2.0));
if ($bits <= 0 || $bits > 56) {
throw new InvalidArgumentException('The length of the alphabet must in the [2^1, 2^56] range.');
}
$ret = '';
while ($length > 0) {
$urandomLength = (int) \ceil(2 * $length * $bits / 8.0);
$data = \random_bytes($urandomLength);
$unpackedData = 0;
$unpackedBits = 0;
for ($i = 0; $i < $urandomLength && $length > 0; ++$i) {
// Unpack 8 bits
$unpackedData = $unpackedData << 8 | \ord($data[$i]);
$unpackedBits += 8;
// While we have enough bits to select a character from the alphabet, keep
// consuming the random data
for (; $unpackedBits >= $bits && $length > 0; $unpackedBits -= $bits) {
$index = $unpackedData & (1 << $bits) - 1;
$unpackedData >>= $bits;
// Unfortunately, the alphabet size is not necessarily a power of two.
// Worst case, it is 2^k + 1, which means we need (k+1) bits and we
// have around a 50% chance of missing as k gets larger
if ($index < $alphabetSize) {
$ret .= $alphabet[$index];
--$length;
}
}
}
}
return new static($ret);
}
public function bytesAt(int $offset) : array
{
$str = $this->string[$offset] ?? '';
return '' === $str ? [] : [\ord($str)];
}
public function append(string ...$suffix) : parent
{
$str = clone $this;
$str->string .= 1 >= \count($suffix) ? $suffix[0] ?? '' : \implode('', $suffix);
return $str;
}
public function camel() : parent
{
$str = clone $this;
$parts = \explode(' ', \trim(\ucwords(\preg_replace('/[^a-zA-Z0-9\\x7f-\\xff]++/', ' ', $this->string))));
$parts[0] = 1 !== \strlen($parts[0]) && \ctype_upper($parts[0]) ? $parts[0] : \lcfirst($parts[0]);
$str->string = \implode('', $parts);
return $str;
}
public function chunk(int $length = 1) : array
{
if (1 > $length) {
throw new InvalidArgumentException('The chunk length must be greater than zero.');
}
if ('' === $this->string) {
return [];
}
$str = clone $this;
$chunks = [];
foreach (\str_split($this->string, $length) as $chunk) {
$str->string = $chunk;
$chunks[] = clone $str;
}
return $chunks;
}
public function endsWith($suffix) : bool
{
if ($suffix instanceof parent) {
$suffix = $suffix->string;
} elseif (\is_array($suffix) || $suffix instanceof \Traversable) {
return parent::endsWith($suffix);
} else {
$suffix = (string) $suffix;
}
return '' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === \substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase);
}
public function equalsTo($string) : bool
{
if ($string instanceof parent) {
$string = $string->string;
} elseif (\is_array($string) || $string instanceof \Traversable) {
return parent::equalsTo($string);
} else {
$string = (string) $string;
}
if ('' !== $string && $this->ignoreCase) {
return 0 === \strcasecmp($string, $this->string);
}
return $string === $this->string;
}
public function folded() : parent
{
$str = clone $this;
$str->string = \strtolower($str->string);
return $str;
}
public function indexOf($needle, int $offset = 0) : ?int
{
if ($needle instanceof parent) {
$needle = $needle->string;
} elseif (\is_array($needle) || $needle instanceof \Traversable) {
return parent::indexOf($needle, $offset);
} else {
$needle = (string) $needle;
}
if ('' === $needle) {
return null;
}
$i = $this->ignoreCase ? \stripos($this->string, $needle, $offset) : \strpos($this->string, $needle, $offset);
return \false === $i ? null : $i;
}
public function indexOfLast($needle, int $offset = 0) : ?int
{
if ($needle instanceof parent) {
$needle = $needle->string;
} elseif (\is_array($needle) || $needle instanceof \Traversable) {
return parent::indexOfLast($needle, $offset);
} else {
$needle = (string) $needle;
}
if ('' === $needle) {
return null;
}
$i = $this->ignoreCase ? \strripos($this->string, $needle, $offset) : \strrpos($this->string, $needle, $offset);
return \false === $i ? null : $i;
}
public function isUtf8() : bool
{
return '' === $this->string || \preg_match('//u', $this->string);
}
public function join(array $strings, ?string $lastGlue = null) : parent
{
$str = clone $this;
$tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue . \array_pop($strings) : '';
$str->string = \implode($this->string, $strings) . $tail;
return $str;
}
public function length() : int
{
return \strlen($this->string);
}
public function lower() : parent
{
$str = clone $this;
$str->string = \strtolower($str->string);
return $str;
}
public function match(string $regexp, int $flags = 0, int $offset = 0) : array
{
$match = (\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags ? 'preg_match_all' : 'preg_match';
if ($this->ignoreCase) {
$regexp .= 'i';
}
\set_error_handler(static function ($t, $m) {
throw new InvalidArgumentException($m);
});
try {
if (\false === $match($regexp, $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) {
$lastError = \preg_last_error();
foreach (\get_defined_constants(\true)['pcre'] as $k => $v) {
if ($lastError === $v && '_ERROR' === \substr($k, -6)) {
throw new RuntimeException('Matching failed with ' . $k . '.');
}
}
throw new RuntimeException('Matching failed with unknown error code.');
}
} finally {
\restore_error_handler();
}
return $matches;
}
public function padBoth(int $length, string $padStr = ' ') : parent
{
$str = clone $this;
$str->string = \str_pad($this->string, $length, $padStr, \STR_PAD_BOTH);
return $str;
}
public function padEnd(int $length, string $padStr = ' ') : parent
{
$str = clone $this;
$str->string = \str_pad($this->string, $length, $padStr, \STR_PAD_RIGHT);
return $str;
}
public function padStart(int $length, string $padStr = ' ') : parent
{
$str = clone $this;
$str->string = \str_pad($this->string, $length, $padStr, \STR_PAD_LEFT);
return $str;
}
public function prepend(string ...$prefix) : parent
{
$str = clone $this;
$str->string = (1 >= \count($prefix) ? $prefix[0] ?? '' : \implode('', $prefix)) . $str->string;
return $str;
}
public function replace(string $from, string $to) : parent
{
$str = clone $this;
if ('' !== $from) {
$str->string = $this->ignoreCase ? \str_ireplace($from, $to, $this->string) : \str_replace($from, $to, $this->string);
}
return $str;
}
public function replaceMatches(string $fromRegexp, $to) : parent
{
if ($this->ignoreCase) {
$fromRegexp .= 'i';
}
if (\is_array($to)) {
if (!\is_callable($to)) {
throw new \TypeError(\sprintf('Argument 2 passed to "%s::replaceMatches()" must be callable, array given.', static::class));
}
$replace = 'preg_replace_callback';
} else {
$replace = $to instanceof \Closure ? 'preg_replace_callback' : 'preg_replace';
}
\set_error_handler(static function ($t, $m) {
throw new InvalidArgumentException($m);
});
try {
if (null === ($string = $replace($fromRegexp, $to, $this->string))) {
$lastError = \preg_last_error();
foreach (\get_defined_constants(\true)['pcre'] as $k => $v) {
if ($lastError === $v && '_ERROR' === \substr($k, -6)) {
throw new RuntimeException('Matching failed with ' . $k . '.');
}
}
throw new RuntimeException('Matching failed with unknown error code.');
}
} finally {
\restore_error_handler();
}
$str = clone $this;
$str->string = $string;
return $str;
}
public function reverse() : parent
{
$str = clone $this;
$str->string = \strrev($str->string);
return $str;
}
public function slice(int $start = 0, ?int $length = null) : parent
{
$str = clone $this;
$str->string = (string) \substr($this->string, $start, $length ?? \PHP_INT_MAX);
return $str;
}
public function snake() : parent
{
$str = $this->camel();
$str->string = \strtolower(\preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\\d])([A-Z])/'], 'MailPoetVendor\\1_\\2', $str->string));
return $str;
}
public function splice(string $replacement, int $start = 0, ?int $length = null) : parent
{
$str = clone $this;
$str->string = \substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX);
return $str;
}
public function split(string $delimiter, ?int $limit = null, ?int $flags = null) : array
{
if (1 > ($limit = $limit ?? \PHP_INT_MAX)) {
throw new InvalidArgumentException('Split limit must be a positive integer.');
}
if ('' === $delimiter) {
throw new InvalidArgumentException('Split delimiter is empty.');
}
if (null !== $flags) {
return parent::split($delimiter, $limit, $flags);
}
$str = clone $this;
$chunks = $this->ignoreCase ? \preg_split('{' . \preg_quote($delimiter) . '}iD', $this->string, $limit) : \explode($delimiter, $this->string, $limit);
foreach ($chunks as &$chunk) {
$str->string = $chunk;
$chunk = clone $str;
}
return $chunks;
}
public function startsWith($prefix) : bool
{
if ($prefix instanceof parent) {
$prefix = $prefix->string;
} elseif (!\is_string($prefix)) {
return parent::startsWith($prefix);
}
return '' !== $prefix && 0 === ($this->ignoreCase ? \strncasecmp($this->string, $prefix, \strlen($prefix)) : \strncmp($this->string, $prefix, \strlen($prefix)));
}
public function title(bool $allWords = \false) : parent
{
$str = clone $this;
$str->string = $allWords ? \ucwords($str->string) : \ucfirst($str->string);
return $str;
}
public function toUnicodeString(?string $fromEncoding = null) : UnicodeString
{
return new UnicodeString($this->toCodePointString($fromEncoding)->string);
}
public function toCodePointString(?string $fromEncoding = null) : CodePointString
{
$u = new CodePointString();
if (\in_array($fromEncoding, [null, 'utf8', 'utf-8', 'UTF8', 'UTF-8'], \true) && \preg_match('//u', $this->string)) {
$u->string = $this->string;
return $u;
}
\set_error_handler(static function ($t, $m) {
throw new InvalidArgumentException($m);
});
try {
try {
$validEncoding = \false !== \mb_detect_encoding($this->string, $fromEncoding ?? 'Windows-1252', \true);
} catch (InvalidArgumentException $e) {
if (!\function_exists('iconv')) {
throw $e;
}
$u->string = \iconv($fromEncoding ?? 'Windows-1252', 'UTF-8', $this->string);
return $u;
}
} finally {
\restore_error_handler();
}
if (!$validEncoding) {
throw new InvalidArgumentException(\sprintf('Invalid "%s" string.', $fromEncoding ?? 'Windows-1252'));
}
$u->string = \mb_convert_encoding($this->string, 'UTF-8', $fromEncoding ?? 'Windows-1252');
return $u;
}
public function trim(string $chars = " \t\n\r\x00\v\f") : parent
{
$str = clone $this;
$str->string = \trim($str->string, $chars);
return $str;
}
public function trimEnd(string $chars = " \t\n\r\x00\v\f") : parent
{
$str = clone $this;
$str->string = \rtrim($str->string, $chars);
return $str;
}
public function trimStart(string $chars = " \t\n\r\x00\v\f") : parent
{
$str = clone $this;
$str->string = \ltrim($str->string, $chars);
return $str;
}
public function upper() : parent
{
$str = clone $this;
$str->string = \strtoupper($str->string);
return $str;
}
public function width(bool $ignoreAnsiDecoration = \true) : int
{
$string = \preg_match('//u', $this->string) ? $this->string : \preg_replace('/[\\x80-\\xFF]/', '?', $this->string);
return (new CodePointString($string))->width($ignoreAnsiDecoration);
}
}
@@ -0,0 +1,197 @@
<?php
namespace MailPoetVendor\Symfony\Component\String;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Symfony\Component\String\Exception\ExceptionInterface;
use MailPoetVendor\Symfony\Component\String\Exception\InvalidArgumentException;
class CodePointString extends AbstractUnicodeString
{
public function __construct(string $string = '')
{
if ('' !== $string && !\preg_match('//u', $string)) {
throw new InvalidArgumentException('Invalid UTF-8 string.');
}
$this->string = $string;
}
public function append(string ...$suffix) : AbstractString
{
$str = clone $this;
$str->string .= 1 >= \count($suffix) ? $suffix[0] ?? '' : \implode('', $suffix);
if (!\preg_match('//u', $str->string)) {
throw new InvalidArgumentException('Invalid UTF-8 string.');
}
return $str;
}
public function chunk(int $length = 1) : array
{
if (1 > $length) {
throw new InvalidArgumentException('The chunk length must be greater than zero.');
}
if ('' === $this->string) {
return [];
}
$rx = '/(';
while (65535 < $length) {
$rx .= '.{65535}';
$length -= 65535;
}
$rx .= '.{' . $length . '})/us';
$str = clone $this;
$chunks = [];
foreach (\preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) {
$str->string = $chunk;
$chunks[] = clone $str;
}
return $chunks;
}
public function codePointsAt(int $offset) : array
{
$str = $offset ? $this->slice($offset, 1) : $this;
return '' === $str->string ? [] : [\mb_ord($str->string, 'UTF-8')];
}
public function endsWith($suffix) : bool
{
if ($suffix instanceof AbstractString) {
$suffix = $suffix->string;
} elseif (\is_array($suffix) || $suffix instanceof \Traversable) {
return parent::endsWith($suffix);
} else {
$suffix = (string) $suffix;
}
if ('' === $suffix || !\preg_match('//u', $suffix)) {
return \false;
}
if ($this->ignoreCase) {
return \preg_match('{' . \preg_quote($suffix) . '$}iuD', $this->string);
}
return \strlen($this->string) >= \strlen($suffix) && 0 === \substr_compare($this->string, $suffix, -\strlen($suffix));
}
public function equalsTo($string) : bool
{
if ($string instanceof AbstractString) {
$string = $string->string;
} elseif (\is_array($string) || $string instanceof \Traversable) {
return parent::equalsTo($string);
} else {
$string = (string) $string;
}
if ('' !== $string && $this->ignoreCase) {
return \strlen($string) === \strlen($this->string) && 0 === \mb_stripos($this->string, $string, 0, 'UTF-8');
}
return $string === $this->string;
}
public function indexOf($needle, int $offset = 0) : ?int
{
if ($needle instanceof AbstractString) {
$needle = $needle->string;
} elseif (\is_array($needle) || $needle instanceof \Traversable) {
return parent::indexOf($needle, $offset);
} else {
$needle = (string) $needle;
}
if ('' === $needle) {
return null;
}
$i = $this->ignoreCase ? \mb_stripos($this->string, $needle, $offset, 'UTF-8') : \mb_strpos($this->string, $needle, $offset, 'UTF-8');
return \false === $i ? null : $i;
}
public function indexOfLast($needle, int $offset = 0) : ?int
{
if ($needle instanceof AbstractString) {
$needle = $needle->string;
} elseif (\is_array($needle) || $needle instanceof \Traversable) {
return parent::indexOfLast($needle, $offset);
} else {
$needle = (string) $needle;
}
if ('' === $needle) {
return null;
}
$i = $this->ignoreCase ? \mb_strripos($this->string, $needle, $offset, 'UTF-8') : \mb_strrpos($this->string, $needle, $offset, 'UTF-8');
return \false === $i ? null : $i;
}
public function length() : int
{
return \mb_strlen($this->string, 'UTF-8');
}
public function prepend(string ...$prefix) : AbstractString
{
$str = clone $this;
$str->string = (1 >= \count($prefix) ? $prefix[0] ?? '' : \implode('', $prefix)) . $this->string;
if (!\preg_match('//u', $str->string)) {
throw new InvalidArgumentException('Invalid UTF-8 string.');
}
return $str;
}
public function replace(string $from, string $to) : AbstractString
{
$str = clone $this;
if ('' === $from || !\preg_match('//u', $from)) {
return $str;
}
if ('' !== $to && !\preg_match('//u', $to)) {
throw new InvalidArgumentException('Invalid UTF-8 string.');
}
if ($this->ignoreCase) {
$str->string = \implode($to, \preg_split('{' . \preg_quote($from) . '}iuD', $this->string));
} else {
$str->string = \str_replace($from, $to, $this->string);
}
return $str;
}
public function slice(int $start = 0, ?int $length = null) : AbstractString
{
$str = clone $this;
$str->string = \mb_substr($this->string, $start, $length, 'UTF-8');
return $str;
}
public function splice(string $replacement, int $start = 0, ?int $length = null) : AbstractString
{
if (!\preg_match('//u', $replacement)) {
throw new InvalidArgumentException('Invalid UTF-8 string.');
}
$str = clone $this;
$start = $start ? \strlen(\mb_substr($this->string, 0, $start, 'UTF-8')) : 0;
$length = $length ? \strlen(\mb_substr($this->string, $start, $length, 'UTF-8')) : $length;
$str->string = \substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX);
return $str;
}
public function split(string $delimiter, ?int $limit = null, ?int $flags = null) : array
{
if (1 > ($limit = $limit ?? \PHP_INT_MAX)) {
throw new InvalidArgumentException('Split limit must be a positive integer.');
}
if ('' === $delimiter) {
throw new InvalidArgumentException('Split delimiter is empty.');
}
if (null !== $flags) {
return parent::split($delimiter . 'u', $limit, $flags);
}
if (!\preg_match('//u', $delimiter)) {
throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.');
}
$str = clone $this;
$chunks = $this->ignoreCase ? \preg_split('{' . \preg_quote($delimiter) . '}iuD', $this->string, $limit) : \explode($delimiter, $this->string, $limit);
foreach ($chunks as &$chunk) {
$str->string = $chunk;
$chunk = clone $str;
}
return $chunks;
}
public function startsWith($prefix) : bool
{
if ($prefix instanceof AbstractString) {
$prefix = $prefix->string;
} elseif (\is_array($prefix) || $prefix instanceof \Traversable) {
return parent::startsWith($prefix);
} else {
$prefix = (string) $prefix;
}
if ('' === $prefix || !\preg_match('//u', $prefix)) {
return \false;
}
if ($this->ignoreCase) {
return 0 === \mb_stripos($this->string, $prefix, 0, 'UTF-8');
}
return 0 === \strncmp($this->string, $prefix, \strlen($prefix));
}
}
@@ -0,0 +1,6 @@
<?php
namespace MailPoetVendor\Symfony\Component\String\Exception;
if (!defined('ABSPATH')) exit;
interface ExceptionInterface extends \Throwable
{
}
@@ -0,0 +1,6 @@
<?php
namespace MailPoetVendor\Symfony\Component\String\Exception;
if (!defined('ABSPATH')) exit;
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
@@ -0,0 +1,6 @@
<?php
namespace MailPoetVendor\Symfony\Component\String\Exception;
if (!defined('ABSPATH')) exit;
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
@@ -0,0 +1,384 @@
<?php
namespace MailPoetVendor\Symfony\Component\String\Inflector;
if (!defined('ABSPATH')) exit;
final class EnglishInflector implements InflectorInterface
{
private const PLURAL_MAP = [
// First entry: plural suffix, reversed
// Second entry: length of plural suffix
// Third entry: Whether the suffix may succeed a vowel
// Fourth entry: Whether the suffix may succeed a consonant
// Fifth entry: singular suffix, normal
// bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
['a', 1, \true, \true, ['on', 'um']],
// nebulae (nebula)
['ea', 2, \true, \true, 'a'],
// services (service)
['secivres', 8, \true, \true, 'service'],
// mice (mouse), lice (louse)
['eci', 3, \false, \true, 'ouse'],
// geese (goose)
['esee', 4, \false, \true, 'oose'],
// fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius)
['i', 1, \true, \true, 'us'],
// men (man), women (woman)
['nem', 3, \true, \true, 'man'],
// children (child)
['nerdlihc', 8, \true, \true, 'child'],
// oxen (ox)
['nexo', 4, \false, \false, 'ox'],
// indices (index), appendices (appendix), prices (price)
['seci', 4, \false, \true, ['ex', 'ix', 'ice']],
// codes (code)
['sedoc', 5, \false, \true, 'code'],
// selfies (selfie)
['seifles', 7, \true, \true, 'selfie'],
// zombies (zombie)
['seibmoz', 7, \true, \true, 'zombie'],
// movies (movie)
['seivom', 6, \true, \true, 'movie'],
// names (name)
['seman', 5, \true, \false, 'name'],
// conspectuses (conspectus), prospectuses (prospectus)
['sesutcep', 8, \true, \true, 'pectus'],
// feet (foot)
['teef', 4, \true, \true, 'foot'],
// geese (goose)
['eseeg', 5, \true, \true, 'goose'],
// teeth (tooth)
['hteet', 5, \true, \true, 'tooth'],
// news (news)
['swen', 4, \true, \true, 'news'],
// series (series)
['seires', 6, \true, \true, 'series'],
// babies (baby)
['sei', 3, \false, \true, 'y'],
// accesses (access), addresses (address), kisses (kiss)
['sess', 4, \true, \false, 'ss'],
// statuses (status)
['sesutats', 8, \true, \true, 'status'],
// analyses (analysis), ellipses (ellipsis), fungi (fungus),
// neuroses (neurosis), theses (thesis), emphases (emphasis),
// oases (oasis), crises (crisis), houses (house), bases (base),
// atlases (atlas)
['ses', 3, \true, \true, ['s', 'se', 'sis']],
// objectives (objective), alternative (alternatives)
['sevit', 5, \true, \true, 'tive'],
// drives (drive)
['sevird', 6, \false, \true, 'drive'],
// lives (life), wives (wife)
['sevi', 4, \false, \true, 'ife'],
// moves (move)
['sevom', 5, \true, \true, 'move'],
// hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf), caves (cave), staves (staff)
['sev', 3, \true, \true, ['f', 've', 'ff']],
// axes (axis), axes (ax), axes (axe)
['sexa', 4, \false, \false, ['ax', 'axe', 'axis']],
// indexes (index), matrixes (matrix)
['sex', 3, \true, \false, 'x'],
// quizzes (quiz)
['sezz', 4, \true, \false, 'z'],
// bureaus (bureau)
['suae', 4, \false, \true, 'eau'],
// fees (fee), trees (tree), employees (employee)
['see', 3, \true, \true, 'ee'],
// edges (edge)
['segd', 4, \true, \true, 'dge'],
// roses (rose), garages (garage), cassettes (cassette),
// waltzes (waltz), heroes (hero), bushes (bush), arches (arch),
// shoes (shoe)
['se', 2, \true, \true, ['', 'e']],
// status (status)
['sutats', 6, \true, \true, 'status'],
// tags (tag)
['s', 1, \true, \true, ''],
// chateaux (chateau)
['xuae', 4, \false, \true, 'eau'],
// people (person)
['elpoep', 6, \true, \true, 'person'],
];
private const SINGULAR_MAP = [
// First entry: singular suffix, reversed
// Second entry: length of singular suffix
// Third entry: Whether the suffix may succeed a vowel
// Fourth entry: Whether the suffix may succeed a consonant
// Fifth entry: plural suffix, normal
// axes (axis)
['sixa', 4, \false, \false, 'axes'],
// criterion (criteria)
['airetirc', 8, \false, \false, 'criterion'],
// nebulae (nebula)
['aluben', 6, \false, \false, 'nebulae'],
// children (child)
['dlihc', 5, \true, \true, 'children'],
// prices (price)
['eci', 3, \false, \true, 'ices'],
// services (service)
['ecivres', 7, \true, \true, 'services'],
// lives (life), wives (wife)
['efi', 3, \false, \true, 'ives'],
// selfies (selfie)
['eifles', 6, \true, \true, 'selfies'],
// movies (movie)
['eivom', 5, \true, \true, 'movies'],
// lice (louse)
['esuol', 5, \false, \true, 'lice'],
// mice (mouse)
['esuom', 5, \false, \true, 'mice'],
// geese (goose)
['esoo', 4, \false, \true, 'eese'],
// houses (house), bases (base)
['es', 2, \true, \true, 'ses'],
// geese (goose)
['esoog', 5, \true, \true, 'geese'],
// caves (cave)
['ev', 2, \true, \true, 'ves'],
// drives (drive)
['evird', 5, \false, \true, 'drives'],
// objectives (objective), alternative (alternatives)
['evit', 4, \true, \true, 'tives'],
// moves (move)
['evom', 4, \true, \true, 'moves'],
// staves (staff)
['ffats', 5, \true, \true, 'staves'],
// hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf)
['ff', 2, \true, \true, 'ffs'],
// hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf)
['f', 1, \true, \true, ['fs', 'ves']],
// arches (arch)
['hc', 2, \true, \true, 'ches'],
// bushes (bush)
['hs', 2, \true, \true, 'shes'],
// teeth (tooth)
['htoot', 5, \true, \true, 'teeth'],
// albums (album)
['mubla', 5, \true, \true, 'albums'],
// bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
['mu', 2, \true, \true, 'a'],
// men (man), women (woman)
['nam', 3, \true, \true, 'men'],
// people (person)
['nosrep', 6, \true, \true, ['persons', 'people']],
// bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
['noi', 3, \true, \true, 'ions'],
// coupon (coupons)
['nop', 3, \true, \true, 'pons'],
// seasons (season), treasons (treason), poisons (poison), lessons (lesson)
['nos', 3, \true, \true, 'sons'],
// icons (icon)
['noc', 3, \true, \true, 'cons'],
// bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
['no', 2, \true, \true, 'a'],
// echoes (echo)
['ohce', 4, \true, \true, 'echoes'],
// heroes (hero)
['oreh', 4, \true, \true, 'heroes'],
// atlases (atlas)
['salta', 5, \true, \true, 'atlases'],
// irises (iris)
['siri', 4, \true, \true, 'irises'],
// analyses (analysis), ellipses (ellipsis), neuroses (neurosis)
// theses (thesis), emphases (emphasis), oases (oasis),
// crises (crisis)
['sis', 3, \true, \true, 'ses'],
// accesses (access), addresses (address), kisses (kiss)
['ss', 2, \true, \false, 'sses'],
// syllabi (syllabus)
['suballys', 8, \true, \true, 'syllabi'],
// buses (bus)
['sub', 3, \true, \true, 'buses'],
// circuses (circus)
['suc', 3, \true, \true, 'cuses'],
// hippocampi (hippocampus)
['supmacoppih', 11, \false, \false, 'hippocampi'],
// campuses (campus)
['sup', 3, \true, \true, 'puses'],
// status (status)
['sutats', 6, \true, \true, ['status', 'statuses']],
// conspectuses (conspectus), prospectuses (prospectus)
['sutcep', 6, \true, \true, 'pectuses'],
// fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius)
['su', 2, \true, \true, 'i'],
// news (news)
['swen', 4, \true, \true, 'news'],
// feet (foot)
['toof', 4, \true, \true, 'feet'],
// chateaux (chateau), bureaus (bureau)
['uae', 3, \false, \true, ['eaus', 'eaux']],
// oxen (ox)
['xo', 2, \false, \false, 'oxen'],
// hoaxes (hoax)
['xaoh', 4, \true, \false, 'hoaxes'],
// indices (index)
['xedni', 5, \false, \true, ['indicies', 'indexes']],
// boxes (box)
['xo', 2, \false, \true, 'oxes'],
// indexes (index), matrixes (matrix)
['x', 1, \true, \false, ['cies', 'xes']],
// appendices (appendix)
['xi', 2, \false, \true, 'ices'],
// babies (baby)
['y', 1, \false, \true, 'ies'],
// quizzes (quiz)
['ziuq', 4, \true, \false, 'quizzes'],
// waltzes (waltz)
['z', 1, \true, \true, 'zes'],
];
private const UNINFLECTED = [
'',
// data
'atad',
// deer
'reed',
// equipment
'tnempiuqe',
// feedback
'kcabdeef',
// fish
'hsif',
// health
'htlaeh',
// history
'yrotsih',
// info
'ofni',
// information
'noitamrofni',
// money
'yenom',
// moose
'esoom',
// series
'seires',
// sheep
'peehs',
// species
'seiceps',
// traffic
'ciffart',
// aircraft
'tfarcria',
];
public function singularize(string $plural) : array
{
$pluralRev = \strrev($plural);
$lowerPluralRev = \strtolower($pluralRev);
$pluralLength = \strlen($lowerPluralRev);
// Check if the word is one which is not inflected, return early if so
if (\in_array($lowerPluralRev, self::UNINFLECTED, \true)) {
return [$plural];
}
// The outer loop iterates over the entries of the plural table
// The inner loop $j iterates over the characters of the plural suffix
// in the plural table to compare them with the characters of the actual
// given plural suffix
foreach (self::PLURAL_MAP as $map) {
$suffix = $map[0];
$suffixLength = $map[1];
$j = 0;
// Compare characters in the plural table and of the suffix of the
// given plural one by one
while ($suffix[$j] === $lowerPluralRev[$j]) {
// Let $j point to the next character
++$j;
// Successfully compared the last character
// Add an entry with the singular suffix to the singular array
if ($j === $suffixLength) {
// Is there any character preceding the suffix in the plural string?
if ($j < $pluralLength) {
$nextIsVowel = \false !== \strpos('aeiou', $lowerPluralRev[$j]);
if (!$map[2] && $nextIsVowel) {
// suffix may not succeed a vowel but next char is one
break;
}
if (!$map[3] && !$nextIsVowel) {
// suffix may not succeed a consonant but next char is one
break;
}
}
$newBase = \substr($plural, 0, $pluralLength - $suffixLength);
$newSuffix = $map[4];
// Check whether the first character in the plural suffix
// is uppercased. If yes, uppercase the first character in
// the singular suffix too
$firstUpper = \ctype_upper($pluralRev[$j - 1]);
if (\is_array($newSuffix)) {
$singulars = [];
foreach ($newSuffix as $newSuffixEntry) {
$singulars[] = $newBase . ($firstUpper ? \ucfirst($newSuffixEntry) : $newSuffixEntry);
}
return $singulars;
}
return [$newBase . ($firstUpper ? \ucfirst($newSuffix) : $newSuffix)];
}
// Suffix is longer than word
if ($j === $pluralLength) {
break;
}
}
}
// Assume that plural and singular is identical
return [$plural];
}
public function pluralize(string $singular) : array
{
$singularRev = \strrev($singular);
$lowerSingularRev = \strtolower($singularRev);
$singularLength = \strlen($lowerSingularRev);
// Check if the word is one which is not inflected, return early if so
if (\in_array($lowerSingularRev, self::UNINFLECTED, \true)) {
return [$singular];
}
// The outer loop iterates over the entries of the singular table
// The inner loop $j iterates over the characters of the singular suffix
// in the singular table to compare them with the characters of the actual
// given singular suffix
foreach (self::SINGULAR_MAP as $map) {
$suffix = $map[0];
$suffixLength = $map[1];
$j = 0;
// Compare characters in the singular table and of the suffix of the
// given plural one by one
while ($suffix[$j] === $lowerSingularRev[$j]) {
// Let $j point to the next character
++$j;
// Successfully compared the last character
// Add an entry with the plural suffix to the plural array
if ($j === $suffixLength) {
// Is there any character preceding the suffix in the plural string?
if ($j < $singularLength) {
$nextIsVowel = \false !== \strpos('aeiou', $lowerSingularRev[$j]);
if (!$map[2] && $nextIsVowel) {
// suffix may not succeed a vowel but next char is one
break;
}
if (!$map[3] && !$nextIsVowel) {
// suffix may not succeed a consonant but next char is one
break;
}
}
$newBase = \substr($singular, 0, $singularLength - $suffixLength);
$newSuffix = $map[4];
// Check whether the first character in the singular suffix
// is uppercased. If yes, uppercase the first character in
// the singular suffix too
$firstUpper = \ctype_upper($singularRev[$j - 1]);
if (\is_array($newSuffix)) {
$plurals = [];
foreach ($newSuffix as $newSuffixEntry) {
$plurals[] = $newBase . ($firstUpper ? \ucfirst($newSuffixEntry) : $newSuffixEntry);
}
return $plurals;
}
return [$newBase . ($firstUpper ? \ucfirst($newSuffix) : $newSuffix)];
}
// Suffix is longer than word
if ($j === $singularLength) {
break;
}
}
}
// Assume that plural is singular with a trailing `s`
return [$singular . 's'];
}
}
@@ -0,0 +1,96 @@
<?php
namespace MailPoetVendor\Symfony\Component\String\Inflector;
if (!defined('ABSPATH')) exit;
final class FrenchInflector implements InflectorInterface
{
private const PLURALIZE_REGEXP = [
// First entry: regexp
// Second entry: replacement
// Words finishing with "s", "x" or "z" are invariables
// Les mots finissant par "s", "x" ou "z" sont invariables
['/(s|x|z)$/i', '\\1'],
// Words finishing with "eau" are pluralized with a "x"
// Les mots finissant par "eau" prennent tous un "x" au pluriel
['/(eau)$/i', '\\1x'],
// Words finishing with "au" are pluralized with a "x" excepted "landau"
// Les mots finissant par "au" prennent un "x" au pluriel sauf "landau"
['/^(landau)$/i', '\\1s'],
['/(au)$/i', '\\1x'],
// Words finishing with "eu" are pluralized with a "x" excepted "pneu", "bleu", "émeu"
// Les mots finissant en "eu" prennent un "x" au pluriel sauf "pneu", "bleu", "émeu"
['/^(pneu|bleu|émeu)$/i', '\\1s'],
['/(eu)$/i', '\\1x'],
// Words finishing with "al" are pluralized with a "aux" excepted
// Les mots finissant en "al" se terminent en "aux" sauf
['/^(bal|carnaval|caracal|chacal|choral|corral|étal|festival|récital|val)$/i', '\\1s'],
['/al$/i', '\\1aux'],
// Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux
['/^(aspir|b|cor|ém|ferm|soupir|trav|vant|vitr)ail$/i', '\\1aux'],
// Bijou, caillou, chou, genou, hibou, joujou et pou qui prennent un x au pluriel
['/^(bij|caill|ch|gen|hib|jouj|p)ou$/i', '\\1oux'],
// Invariable words
['/^(cinquante|soixante|mille)$/i', '\\1'],
// French titles
['/^(mon|ma)(sieur|dame|demoiselle|seigneur)$/', 'MailPoetVendor\\mes\\2s'],
['/^(Mon|Ma)(sieur|dame|demoiselle|seigneur)$/', 'MailPoetVendor\\Mes\\2s'],
];
private const SINGULARIZE_REGEXP = [
// First entry: regexp
// Second entry: replacement
// Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux
['/((aspir|b|cor|ém|ferm|soupir|trav|vant|vitr))aux$/i', '\\1ail'],
// Words finishing with "eau" are pluralized with a "x"
// Les mots finissant par "eau" prennent tous un "x" au pluriel
['/(eau)x$/i', '\\1'],
// Words finishing with "al" are pluralized with a "aux" expected
// Les mots finissant en "al" se terminent en "aux" sauf
['/(amir|anim|arsen|boc|can|capit|capor|chev|crist|génér|hopit|hôpit|idé|journ|littor|loc|m|mét|minér|princip|radic|termin)aux$/i', '\\1al'],
// Words finishing with "au" are pluralized with a "x" excepted "landau"
// Les mots finissant par "au" prennent un "x" au pluriel sauf "landau"
['/(au)x$/i', '\\1'],
// Words finishing with "eu" are pluralized with a "x" excepted "pneu", "bleu", "émeu"
// Les mots finissant en "eu" prennent un "x" au pluriel sauf "pneu", "bleu", "émeu"
['/(eu)x$/i', '\\1'],
// Words finishing with "ou" are pluralized with a "s" excepted bijou, caillou, chou, genou, hibou, joujou, pou
// Les mots finissant par "ou" prennent un "s" sauf bijou, caillou, chou, genou, hibou, joujou, pou
['/(bij|caill|ch|gen|hib|jouj|p)oux$/i', '\\1ou'],
// French titles
['/^mes(dame|demoiselle)s$/', 'MailPoetVendor\\ma\\1'],
['/^Mes(dame|demoiselle)s$/', 'MailPoetVendor\\Ma\\1'],
['/^mes(sieur|seigneur)s$/', 'MailPoetVendor\\mon\\1'],
['/^Mes(sieur|seigneur)s$/', 'MailPoetVendor\\Mon\\1'],
// Default rule
['/s$/i', ''],
];
private const UNINFLECTED = '/^(abcès|accès|abus|albatros|anchois|anglais|autobus|bois|brebis|carquois|cas|chas|colis|concours|corps|cours|cyprès|décès|devis|discours|dos|embarras|engrais|entrelacs|excès|fils|fois|gâchis|gars|glas|héros|intrus|jars|jus|kermès|lacis|legs|lilas|marais|mars|matelas|mépris|mets|mois|mors|obus|os|palais|paradis|parcours|pardessus|pays|plusieurs|poids|pois|pouls|printemps|processus|progrès|puits|pus|rabais|radis|recors|recours|refus|relais|remords|remous|rictus|rhinocéros|repas|rubis|sans|sas|secours|sens|souris|succès|talus|tapis|tas|taudis|temps|tiers|univers|velours|verglas|vernis|virus)$/i';
public function singularize(string $plural) : array
{
if ($this->isInflectedWord($plural)) {
return [$plural];
}
foreach (self::SINGULARIZE_REGEXP as $rule) {
[$regexp, $replace] = $rule;
if (1 === \preg_match($regexp, $plural)) {
return [\preg_replace($regexp, $replace, $plural)];
}
}
return [$plural];
}
public function pluralize(string $singular) : array
{
if ($this->isInflectedWord($singular)) {
return [$singular];
}
foreach (self::PLURALIZE_REGEXP as $rule) {
[$regexp, $replace] = $rule;
if (1 === \preg_match($regexp, $singular)) {
return [\preg_replace($regexp, $replace, $singular)];
}
}
return [$singular . 's'];
}
private function isInflectedWord(string $word) : bool
{
return 1 === \preg_match(self::UNINFLECTED, $word);
}
}
@@ -0,0 +1,8 @@
<?php
namespace MailPoetVendor\Symfony\Component\String\Inflector;
if (!defined('ABSPATH')) exit;
interface InflectorInterface
{
public function singularize(string $plural) : array;
public function pluralize(string $singular) : array;
}
@@ -0,0 +1,102 @@
<?php
namespace MailPoetVendor\Symfony\Component\String;
if (!defined('ABSPATH')) exit;
class LazyString implements \Stringable, \JsonSerializable
{
private $value;
public static function fromCallable($callback, ...$arguments) : self
{
if (!\is_callable($callback) && !(\is_array($callback) && isset($callback[0]) && $callback[0] instanceof \Closure && 2 >= \count($callback))) {
throw new \TypeError(\sprintf('Argument 1 passed to "%s()" must be a callable or a [Closure, method] lazy-callable, "%s" given.', __METHOD__, \get_debug_type($callback)));
}
$lazyString = new static();
$lazyString->value = static function () use(&$callback, &$arguments, &$value) : string {
if (null !== $arguments) {
if (!\is_callable($callback)) {
$callback[0] = $callback[0]();
$callback[1] = $callback[1] ?? '__invoke';
}
$value = $callback(...$arguments);
$callback = self::getPrettyName($callback);
$arguments = null;
}
return $value ?? '';
};
return $lazyString;
}
public static function fromStringable($value) : self
{
if (!self::isStringable($value)) {
throw new \TypeError(\sprintf('Argument 1 passed to "%s()" must be a scalar or a stringable object, "%s" given.', __METHOD__, \get_debug_type($value)));
}
if (\is_object($value)) {
return static::fromCallable([$value, '__toString']);
}
$lazyString = new static();
$lazyString->value = (string) $value;
return $lazyString;
}
public static final function isStringable($value) : bool
{
return \is_string($value) || $value instanceof self || (\is_object($value) ? \method_exists($value, '__toString') : \is_scalar($value));
}
public static final function resolve($value) : string
{
return $value;
}
public function __toString()
{
if (\is_string($this->value)) {
return $this->value;
}
try {
return $this->value = ($this->value)();
} catch (\Throwable $e) {
if (\TypeError::class === \get_class($e) && __FILE__ === $e->getFile()) {
$type = \explode(', ', $e->getMessage());
$type = \substr(\array_pop($type), 0, -\strlen(' returned'));
$r = new \ReflectionFunction($this->value);
$callback = $r->getStaticVariables()['callback'];
$e = new \TypeError(\sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type));
}
if (\PHP_VERSION_ID < 70400) {
// leverage the ErrorHandler component with graceful fallback when it's not available
return \trigger_error($e, \E_USER_ERROR);
}
throw $e;
}
}
public function __sleep() : array
{
$this->__toString();
return ['value'];
}
public function jsonSerialize() : string
{
return $this->__toString();
}
private function __construct()
{
}
private static function getPrettyName(callable $callback) : string
{
if (\is_string($callback)) {
return $callback;
}
if (\is_array($callback)) {
$class = \is_object($callback[0]) ? \get_debug_type($callback[0]) : $callback[0];
$method = $callback[1];
} elseif ($callback instanceof \Closure) {
$r = new \ReflectionFunction($callback);
if (\str_contains($r->name, '{closure') || !($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass())) {
return $r->name;
}
$class = $class->name;
$method = $r->name;
} else {
$class = \get_debug_type($callback);
$method = '__invoke';
}
return $class . '::' . $method;
}
}
@@ -0,0 +1,4 @@
<?php
namespace MailPoetVendor;
if (!defined('ABSPATH')) exit;
return [[4352, 4447], [8986, 8987], [9001, 9001], [9002, 9002], [9193, 9196], [9200, 9200], [9203, 9203], [9725, 9726], [9748, 9749], [9800, 9811], [9855, 9855], [9875, 9875], [9889, 9889], [9898, 9899], [9917, 9918], [9924, 9925], [9934, 9934], [9940, 9940], [9962, 9962], [9970, 9971], [9973, 9973], [9978, 9978], [9981, 9981], [9989, 9989], [9994, 9995], [10024, 10024], [10060, 10060], [10062, 10062], [10067, 10069], [10071, 10071], [10133, 10135], [10160, 10160], [10175, 10175], [11035, 11036], [11088, 11088], [11093, 11093], [11904, 11929], [11931, 12019], [12032, 12245], [12272, 12287], [12288, 12288], [12289, 12291], [12292, 12292], [12293, 12293], [12294, 12294], [12295, 12295], [12296, 12296], [12297, 12297], [12298, 12298], [12299, 12299], [12300, 12300], [12301, 12301], [12302, 12302], [12303, 12303], [12304, 12304], [12305, 12305], [12306, 12307], [12308, 12308], [12309, 12309], [12310, 12310], [12311, 12311], [12312, 12312], [12313, 12313], [12314, 12314], [12315, 12315], [12316, 12316], [12317, 12317], [12318, 12319], [12320, 12320], [12321, 12329], [12330, 12333], [12334, 12335], [12336, 12336], [12337, 12341], [12342, 12343], [12344, 12346], [12347, 12347], [12348, 12348], [12349, 12349], [12350, 12350], [12353, 12438], [12441, 12442], [12443, 12444], [12445, 12446], [12447, 12447], [12448, 12448], [12449, 12538], [12539, 12539], [12540, 12542], [12543, 12543], [12549, 12591], [12593, 12686], [12688, 12689], [12690, 12693], [12694, 12703], [12704, 12735], [12736, 12771], [12783, 12783], [12784, 12799], [12800, 12830], [12832, 12841], [12842, 12871], [12880, 12880], [12881, 12895], [12896, 12927], [12928, 12937], [12938, 12976], [12977, 12991], [12992, 13055], [13056, 13311], [13312, 19903], [19968, 40959], [40960, 40980], [40981, 40981], [40982, 42124], [42128, 42182], [43360, 43388], [44032, 55203], [63744, 64109], [64110, 64111], [64112, 64217], [64218, 64255], [65040, 65046], [65047, 65047], [65048, 65048], [65049, 65049], [65072, 65072], [65073, 65074], [65075, 65076], [65077, 65077], [65078, 65078], [65079, 65079], [65080, 65080], [65081, 65081], [65082, 65082], [65083, 65083], [65084, 65084], [65085, 65085], [65086, 65086], [65087, 65087], [65088, 65088], [65089, 65089], [65090, 65090], [65091, 65091], [65092, 65092], [65093, 65094], [65095, 65095], [65096, 65096], [65097, 65100], [65101, 65103], [65104, 65106], [65108, 65111], [65112, 65112], [65113, 65113], [65114, 65114], [65115, 65115], [65116, 65116], [65117, 65117], [65118, 65118], [65119, 65121], [65122, 65122], [65123, 65123], [65124, 65126], [65128, 65128], [65129, 65129], [65130, 65131], [65281, 65283], [65284, 65284], [65285, 65287], [65288, 65288], [65289, 65289], [65290, 65290], [65291, 65291], [65292, 65292], [65293, 65293], [65294, 65295], [65296, 65305], [65306, 65307], [65308, 65310], [65311, 65312], [65313, 65338], [65339, 65339], [65340, 65340], [65341, 65341], [65342, 65342], [65343, 65343], [65344, 65344], [65345, 65370], [65371, 65371], [65372, 65372], [65373, 65373], [65374, 65374], [65375, 65375], [65376, 65376], [65504, 65505], [65506, 65506], [65507, 65507], [65508, 65508], [65509, 65510], [94176, 94177], [94178, 94178], [94179, 94179], [94180, 94180], [94192, 94193], [94208, 100343], [100352, 101119], [101120, 101589], [101632, 101640], [110576, 110579], [110581, 110587], [110589, 110590], [110592, 110847], [110848, 110882], [110898, 110898], [110928, 110930], [110933, 110933], [110948, 110951], [110960, 111355], [126980, 126980], [127183, 127183], [127374, 127374], [127377, 127386], [127488, 127490], [127504, 127547], [127552, 127560], [127568, 127569], [127584, 127589], [127744, 127776], [127789, 127797], [127799, 127868], [127870, 127891], [127904, 127946], [127951, 127955], [127968, 127984], [127988, 127988], [127992, 127994], [127995, 127999], [128000, 128062], [128064, 128064], [128066, 128252], [128255, 128317], [128331, 128334], [128336, 128359], [128378, 128378], [128405, 128406], [128420, 128420], [128507, 128511], [128512, 128591], [128640, 128709], [128716, 128716], [128720, 128722], [128725, 128727], [128732, 128735], [128747, 128748], [128756, 128764], [128992, 129003], [129008, 129008], [129292, 129338], [129340, 129349], [129351, 129535], [129648, 129660], [129664, 129672], [129680, 129725], [129727, 129733], [129742, 129755], [129760, 129768], [129776, 129784], [131072, 173791], [173792, 173823], [173824, 177977], [177978, 177983], [177984, 178205], [178206, 178207], [178208, 183969], [183970, 183983], [183984, 191456], [191457, 191471], [191472, 192093], [192094, 194559], [194560, 195101], [195102, 195103], [195104, 196605], [196608, 201546], [201547, 201551], [201552, 205743], [205744, 262141]];
File diff suppressed because one or more lines are too long
@@ -0,0 +1,22 @@
<?php
namespace MailPoetVendor\Symfony\Component\String;
if (!defined('ABSPATH')) exit;
if (!\function_exists(u::class)) {
function u(?string $string = '') : UnicodeString
{
return new UnicodeString($string ?? '');
}
}
if (!\function_exists(b::class)) {
function b(?string $string = '') : ByteString
{
return new ByteString($string ?? '');
}
}
if (!\function_exists(s::class)) {
function s(?string $string = '') : AbstractString
{
$string = $string ?? '';
return \preg_match('//u', $string) ? new UnicodeString($string) : new ByteString($string);
}
}
@@ -0,0 +1,99 @@
<?php
namespace MailPoetVendor\Symfony\Component\String\Slugger;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Symfony\Component\String\AbstractUnicodeString;
use MailPoetVendor\Symfony\Component\String\UnicodeString;
use MailPoetVendor\Symfony\Contracts\Translation\LocaleAwareInterface;
if (!\interface_exists(LocaleAwareInterface::class)) {
throw new \LogicException('You cannot use the "Symfony\\Component\\String\\Slugger\\AsciiSlugger" as the "symfony/translation-contracts" package is not installed. Try running "composer require symfony/translation-contracts".');
}
class AsciiSlugger implements SluggerInterface, LocaleAwareInterface
{
private const LOCALE_TO_TRANSLITERATOR_ID = ['am' => 'Amharic-Latin', 'ar' => 'Arabic-Latin', 'az' => 'Azerbaijani-Latin', 'be' => 'Belarusian-Latin', 'bg' => 'Bulgarian-Latin', 'bn' => 'Bengali-Latin', 'de' => 'de-ASCII', 'el' => 'Greek-Latin', 'fa' => 'Persian-Latin', 'he' => 'Hebrew-Latin', 'hy' => 'Armenian-Latin', 'ka' => 'Georgian-Latin', 'kk' => 'Kazakh-Latin', 'ky' => 'Kirghiz-Latin', 'ko' => 'Korean-Latin', 'mk' => 'Macedonian-Latin', 'mn' => 'Mongolian-Latin', 'or' => 'Oriya-Latin', 'ps' => 'Pashto-Latin', 'ru' => 'Russian-Latin', 'sr' => 'Serbian-Latin', 'sr_Cyrl' => 'Serbian-Latin', 'th' => 'Thai-Latin', 'tk' => 'Turkmen-Latin', 'uk' => 'Ukrainian-Latin', 'uz' => 'Uzbek-Latin', 'zh' => 'Han-Latin'];
private $defaultLocale;
private $symbolsMap = ['en' => ['@' => 'at', '&' => 'and']];
private $transliterators = [];
public function __construct(?string $defaultLocale = null, $symbolsMap = null)
{
if (null !== $symbolsMap && !\is_array($symbolsMap) && !$symbolsMap instanceof \Closure) {
throw new \TypeError(\sprintf('Argument 2 passed to "%s()" must be array, Closure or null, "%s" given.', __METHOD__, \gettype($symbolsMap)));
}
$this->defaultLocale = $defaultLocale;
$this->symbolsMap = $symbolsMap ?? $this->symbolsMap;
}
public function setLocale($locale)
{
$this->defaultLocale = $locale;
}
public function getLocale()
{
return $this->defaultLocale;
}
public function slug(string $string, string $separator = '-', ?string $locale = null) : AbstractUnicodeString
{
$locale = $locale ?? $this->defaultLocale;
$transliterator = [];
if ($locale && ('de' === $locale || 0 === \strpos($locale, 'de_'))) {
// Use the shortcut for German in UnicodeString::ascii() if possible (faster and no requirement on intl)
$transliterator = ['de-ASCII'];
} elseif (\function_exists('transliterator_transliterate') && $locale) {
$transliterator = (array) $this->createTransliterator($locale);
}
if ($this->symbolsMap instanceof \Closure) {
// If the symbols map is passed as a closure, there is no need to fallback to the parent locale
// as the closure can just provide substitutions for all locales of interest.
$symbolsMap = $this->symbolsMap;
\array_unshift($transliterator, static function ($s) use($symbolsMap, $locale) {
return $symbolsMap($s, $locale);
});
}
$unicodeString = (new UnicodeString($string))->ascii($transliterator);
if (\is_array($this->symbolsMap)) {
$map = null;
if (isset($this->symbolsMap[$locale])) {
$map = $this->symbolsMap[$locale];
} else {
$parent = self::getParentLocale($locale);
if ($parent && isset($this->symbolsMap[$parent])) {
$map = $this->symbolsMap[$parent];
}
}
if ($map) {
foreach ($map as $char => $replace) {
$unicodeString = $unicodeString->replace($char, ' ' . $replace . ' ');
}
}
}
return $unicodeString->replaceMatches('/[^A-Za-z0-9]++/', $separator)->trim($separator);
}
private function createTransliterator(string $locale) : ?\Transliterator
{
if (\array_key_exists($locale, $this->transliterators)) {
return $this->transliterators[$locale];
}
// Exact locale supported, cache and return
if ($id = self::LOCALE_TO_TRANSLITERATOR_ID[$locale] ?? null) {
return $this->transliterators[$locale] = \Transliterator::create($id . '/BGN') ?? \Transliterator::create($id);
}
// Locale not supported and no parent, fallback to any-latin
if (!($parent = self::getParentLocale($locale))) {
return $this->transliterators[$locale] = null;
}
// Try to use the parent locale (ie. try "de" for "de_AT") and cache both locales
if ($id = self::LOCALE_TO_TRANSLITERATOR_ID[$parent] ?? null) {
$transliterator = \Transliterator::create($id . '/BGN') ?? \Transliterator::create($id);
}
return $this->transliterators[$locale] = $this->transliterators[$parent] = $transliterator ?? null;
}
private static function getParentLocale(?string $locale) : ?string
{
if (!$locale) {
return null;
}
if (\false === ($str = \strrchr($locale, '_'))) {
// no parent locale
return null;
}
return \substr($locale, 0, -\strlen($str));
}
}
@@ -0,0 +1,8 @@
<?php
namespace MailPoetVendor\Symfony\Component\String\Slugger;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Symfony\Component\String\AbstractUnicodeString;
interface SluggerInterface
{
public function slug(string $string, string $separator = '-', ?string $locale = null) : AbstractUnicodeString;
}
@@ -0,0 +1,274 @@
<?php
namespace MailPoetVendor\Symfony\Component\String;
if (!defined('ABSPATH')) exit;
use MailPoetVendor\Symfony\Component\String\Exception\ExceptionInterface;
use MailPoetVendor\Symfony\Component\String\Exception\InvalidArgumentException;
class UnicodeString extends AbstractUnicodeString
{
public function __construct(string $string = '')
{
$this->string = \normalizer_is_normalized($string) ? $string : \normalizer_normalize($string);
if (\false === $this->string) {
throw new InvalidArgumentException('Invalid UTF-8 string.');
}
}
public function append(string ...$suffix) : AbstractString
{
$str = clone $this;
$str->string = $this->string . (1 >= \count($suffix) ? $suffix[0] ?? '' : \implode('', $suffix));
\normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string));
if (\false === $str->string) {
throw new InvalidArgumentException('Invalid UTF-8 string.');
}
return $str;
}
public function chunk(int $length = 1) : array
{
if (1 > $length) {
throw new InvalidArgumentException('The chunk length must be greater than zero.');
}
if ('' === $this->string) {
return [];
}
$rx = '/(';
while (65535 < $length) {
$rx .= '\\X{65535}';
$length -= 65535;
}
$rx .= '\\X{' . $length . '})/u';
$str = clone $this;
$chunks = [];
foreach (\preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) {
$str->string = $chunk;
$chunks[] = clone $str;
}
return $chunks;
}
public function endsWith($suffix) : bool
{
if ($suffix instanceof AbstractString) {
$suffix = $suffix->string;
} elseif (\is_array($suffix) || $suffix instanceof \Traversable) {
return parent::endsWith($suffix);
} else {
$suffix = (string) $suffix;
}
$form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
\normalizer_is_normalized($suffix, $form) ?: ($suffix = \normalizer_normalize($suffix, $form));
if ('' === $suffix || \false === $suffix) {
return \false;
}
if ($this->ignoreCase) {
return 0 === \mb_stripos(\grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix)), $suffix, 0, 'UTF-8');
}
return $suffix === \grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix));
}
public function equalsTo($string) : bool
{
if ($string instanceof AbstractString) {
$string = $string->string;
} elseif (\is_array($string) || $string instanceof \Traversable) {
return parent::equalsTo($string);
} else {
$string = (string) $string;
}
$form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
\normalizer_is_normalized($string, $form) ?: ($string = \normalizer_normalize($string, $form));
if ('' !== $string && \false !== $string && $this->ignoreCase) {
return \strlen($string) === \strlen($this->string) && 0 === \mb_stripos($this->string, $string, 0, 'UTF-8');
}
return $string === $this->string;
}
public function indexOf($needle, int $offset = 0) : ?int
{
if ($needle instanceof AbstractString) {
$needle = $needle->string;
} elseif (\is_array($needle) || $needle instanceof \Traversable) {
return parent::indexOf($needle, $offset);
} else {
$needle = (string) $needle;
}
$form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
\normalizer_is_normalized($needle, $form) ?: ($needle = \normalizer_normalize($needle, $form));
if ('' === $needle || \false === $needle) {
return null;
}
try {
$i = $this->ignoreCase ? \grapheme_stripos($this->string, $needle, $offset) : \grapheme_strpos($this->string, $needle, $offset);
} catch (\ValueError $e) {
return null;
}
return \false === $i ? null : $i;
}
public function indexOfLast($needle, int $offset = 0) : ?int
{
if ($needle instanceof AbstractString) {
$needle = $needle->string;
} elseif (\is_array($needle) || $needle instanceof \Traversable) {
return parent::indexOfLast($needle, $offset);
} else {
$needle = (string) $needle;
}
$form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
\normalizer_is_normalized($needle, $form) ?: ($needle = \normalizer_normalize($needle, $form));
if ('' === $needle || \false === $needle) {
return null;
}
$string = $this->string;
if (0 > $offset) {
// workaround https://bugs.php.net/74264
if (0 > ($offset += \grapheme_strlen($needle))) {
$string = \grapheme_substr($string, 0, $offset);
}
$offset = 0;
}
$i = $this->ignoreCase ? \grapheme_strripos($string, $needle, $offset) : \grapheme_strrpos($string, $needle, $offset);
return \false === $i ? null : $i;
}
public function join(array $strings, ?string $lastGlue = null) : AbstractString
{
$str = parent::join($strings, $lastGlue);
\normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string));
return $str;
}
public function length() : int
{
return \grapheme_strlen($this->string);
}
public function normalize(int $form = self::NFC) : parent
{
$str = clone $this;
if (\in_array($form, [self::NFC, self::NFKC], \true)) {
\normalizer_is_normalized($str->string, $form) ?: ($str->string = \normalizer_normalize($str->string, $form));
} elseif (!\in_array($form, [self::NFD, self::NFKD], \true)) {
throw new InvalidArgumentException('Unsupported normalization form.');
} elseif (!\normalizer_is_normalized($str->string, $form)) {
$str->string = \normalizer_normalize($str->string, $form);
$str->ignoreCase = null;
}
return $str;
}
public function prepend(string ...$prefix) : AbstractString
{
$str = clone $this;
$str->string = (1 >= \count($prefix) ? $prefix[0] ?? '' : \implode('', $prefix)) . $this->string;
\normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string));
if (\false === $str->string) {
throw new InvalidArgumentException('Invalid UTF-8 string.');
}
return $str;
}
public function replace(string $from, string $to) : AbstractString
{
$str = clone $this;
\normalizer_is_normalized($from) ?: ($from = \normalizer_normalize($from));
if ('' !== $from && \false !== $from) {
$tail = $str->string;
$result = '';
$indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos';
while ('' !== $tail && \false !== ($i = $indexOf($tail, $from))) {
$slice = \grapheme_substr($tail, 0, $i);
$result .= $slice . $to;
$tail = \substr($tail, \strlen($slice) + \strlen($from));
}
$str->string = $result . $tail;
\normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string));
if (\false === $str->string) {
throw new InvalidArgumentException('Invalid UTF-8 string.');
}
}
return $str;
}
public function replaceMatches(string $fromRegexp, $to) : AbstractString
{
$str = parent::replaceMatches($fromRegexp, $to);
\normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string));
return $str;
}
public function slice(int $start = 0, ?int $length = null) : AbstractString
{
$str = clone $this;
if (\PHP_VERSION_ID < 80000 && 0 > $start && \grapheme_strlen($this->string) < -$start) {
$start = 0;
}
$str->string = (string) \grapheme_substr($this->string, $start, $length ?? 2147483647);
return $str;
}
public function splice(string $replacement, int $start = 0, ?int $length = null) : AbstractString
{
$str = clone $this;
if (\PHP_VERSION_ID < 80000 && 0 > $start && \grapheme_strlen($this->string) < -$start) {
$start = 0;
}
$start = $start ? \strlen(\grapheme_substr($this->string, 0, $start)) : 0;
$length = $length ? \strlen(\grapheme_substr($this->string, $start, $length ?? 2147483647)) : $length;
$str->string = \substr_replace($this->string, $replacement, $start, $length ?? 2147483647);
\normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string));
if (\false === $str->string) {
throw new InvalidArgumentException('Invalid UTF-8 string.');
}
return $str;
}
public function split(string $delimiter, ?int $limit = null, ?int $flags = null) : array
{
if (1 > ($limit = $limit ?? 2147483647)) {
throw new InvalidArgumentException('Split limit must be a positive integer.');
}
if ('' === $delimiter) {
throw new InvalidArgumentException('Split delimiter is empty.');
}
if (null !== $flags) {
return parent::split($delimiter . 'u', $limit, $flags);
}
\normalizer_is_normalized($delimiter) ?: ($delimiter = \normalizer_normalize($delimiter));
if (\false === $delimiter) {
throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.');
}
$str = clone $this;
$tail = $this->string;
$chunks = [];
$indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos';
while (1 < $limit && \false !== ($i = $indexOf($tail, $delimiter))) {
$str->string = \grapheme_substr($tail, 0, $i);
$chunks[] = clone $str;
$tail = \substr($tail, \strlen($str->string) + \strlen($delimiter));
--$limit;
}
$str->string = $tail;
$chunks[] = clone $str;
return $chunks;
}
public function startsWith($prefix) : bool
{
if ($prefix instanceof AbstractString) {
$prefix = $prefix->string;
} elseif (\is_array($prefix) || $prefix instanceof \Traversable) {
return parent::startsWith($prefix);
} else {
$prefix = (string) $prefix;
}
$form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
\normalizer_is_normalized($prefix, $form) ?: ($prefix = \normalizer_normalize($prefix, $form));
if ('' === $prefix || \false === $prefix) {
return \false;
}
if ($this->ignoreCase) {
return 0 === \mb_stripos(\grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES), $prefix, 0, 'UTF-8');
}
return $prefix === \grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES);
}
public function __wakeup()
{
if (!\is_string($this->string)) {
throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__);
}
\normalizer_is_normalized($this->string) ?: ($this->string = \normalizer_normalize($this->string));
}
public function __clone()
{
if (null === $this->ignoreCase) {
\normalizer_is_normalized($this->string) ?: ($this->string = \normalizer_normalize($this->string));
}
$this->ignoreCase = \false;
}
}
@@ -0,0 +1 @@
<?php