Stand: SMTP-Test, Admin-Mail-Tab, Notifiable-Fix, Lazy-Quill
- Fix: Notifiable-Trait zum User-Model hinzugefuegt (behebt notify()-500er) - Installer: SMTP-Verbindungstest mit EsmtpTransport + Ueberspringen-Link - Admin: Neuer E-Mail-Tab mit SMTP-Konfiguration + Verbindungstest - Admin: Lazy Quill-Initialisierung (nur sichtbare Locale wird geladen) - Uebersetzungen: 17 neue Mail-Keys in allen 6 Sprachen Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
83
vendor/league/commonmark/src/Delimiter/Bracket.php
vendored
Executable file
83
vendor/league/commonmark/src/Delimiter/Bracket.php
vendored
Executable file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Delimiter;
|
||||
|
||||
use League\CommonMark\Node\Node;
|
||||
|
||||
final class Bracket
|
||||
{
|
||||
private Node $node;
|
||||
private ?Bracket $previous;
|
||||
private bool $hasNext = false;
|
||||
private int $position;
|
||||
private bool $image;
|
||||
private bool $active = true;
|
||||
|
||||
public function __construct(Node $node, ?Bracket $previous, int $position, bool $image)
|
||||
{
|
||||
$this->node = $node;
|
||||
$this->previous = $previous;
|
||||
$this->position = $position;
|
||||
$this->image = $image;
|
||||
}
|
||||
|
||||
public function getNode(): Node
|
||||
{
|
||||
return $this->node;
|
||||
}
|
||||
|
||||
public function getPrevious(): ?Bracket
|
||||
{
|
||||
return $this->previous;
|
||||
}
|
||||
|
||||
public function hasNext(): bool
|
||||
{
|
||||
return $this->hasNext;
|
||||
}
|
||||
|
||||
public function getPosition(): int
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function isImage(): bool
|
||||
{
|
||||
return $this->image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only valid in the context of non-images (links)
|
||||
*/
|
||||
public function isActive(): bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function setHasNext(bool $hasNext): void
|
||||
{
|
||||
$this->hasNext = $hasNext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function setActive(bool $active): void
|
||||
{
|
||||
$this->active = $active;
|
||||
}
|
||||
}
|
||||
134
vendor/league/commonmark/src/Delimiter/Delimiter.php
vendored
Executable file
134
vendor/league/commonmark/src/Delimiter/Delimiter.php
vendored
Executable file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js)
|
||||
* - (c) John MacFarlane
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Delimiter;
|
||||
|
||||
use League\CommonMark\Node\Inline\AbstractStringContainer;
|
||||
|
||||
final class Delimiter implements DelimiterInterface
|
||||
{
|
||||
/** @psalm-readonly */
|
||||
private string $char;
|
||||
|
||||
/** @psalm-readonly-allow-private-mutation */
|
||||
private int $length;
|
||||
|
||||
/** @psalm-readonly */
|
||||
private int $originalLength;
|
||||
|
||||
/** @psalm-readonly */
|
||||
private AbstractStringContainer $inlineNode;
|
||||
|
||||
/** @psalm-readonly-allow-private-mutation */
|
||||
private ?DelimiterInterface $previous = null;
|
||||
|
||||
/** @psalm-readonly-allow-private-mutation */
|
||||
private ?DelimiterInterface $next = null;
|
||||
|
||||
/** @psalm-readonly */
|
||||
private bool $canOpen;
|
||||
|
||||
/** @psalm-readonly */
|
||||
private bool $canClose;
|
||||
|
||||
/** @psalm-readonly-allow-private-mutation */
|
||||
private bool $active;
|
||||
|
||||
/** @psalm-readonly */
|
||||
private ?int $index = null;
|
||||
|
||||
public function __construct(string $char, int $numDelims, AbstractStringContainer $node, bool $canOpen, bool $canClose, ?int $index = null)
|
||||
{
|
||||
$this->char = $char;
|
||||
$this->length = $numDelims;
|
||||
$this->originalLength = $numDelims;
|
||||
$this->inlineNode = $node;
|
||||
$this->canOpen = $canOpen;
|
||||
$this->canClose = $canClose;
|
||||
$this->active = true;
|
||||
$this->index = $index;
|
||||
}
|
||||
|
||||
public function canClose(): bool
|
||||
{
|
||||
return $this->canClose;
|
||||
}
|
||||
|
||||
public function canOpen(): bool
|
||||
{
|
||||
return $this->canOpen;
|
||||
}
|
||||
|
||||
public function isActive(): bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(bool $active): void
|
||||
{
|
||||
$this->active = $active;
|
||||
}
|
||||
|
||||
public function getChar(): string
|
||||
{
|
||||
return $this->char;
|
||||
}
|
||||
|
||||
public function getIndex(): ?int
|
||||
{
|
||||
return $this->index;
|
||||
}
|
||||
|
||||
public function getNext(): ?DelimiterInterface
|
||||
{
|
||||
return $this->next;
|
||||
}
|
||||
|
||||
public function setNext(?DelimiterInterface $next): void
|
||||
{
|
||||
$this->next = $next;
|
||||
}
|
||||
|
||||
public function getLength(): int
|
||||
{
|
||||
return $this->length;
|
||||
}
|
||||
|
||||
public function setLength(int $length): void
|
||||
{
|
||||
$this->length = $length;
|
||||
}
|
||||
|
||||
public function getOriginalLength(): int
|
||||
{
|
||||
return $this->originalLength;
|
||||
}
|
||||
|
||||
public function getInlineNode(): AbstractStringContainer
|
||||
{
|
||||
return $this->inlineNode;
|
||||
}
|
||||
|
||||
public function getPrevious(): ?DelimiterInterface
|
||||
{
|
||||
return $this->previous;
|
||||
}
|
||||
|
||||
public function setPrevious(?DelimiterInterface $previous): void
|
||||
{
|
||||
$this->previous = $previous;
|
||||
}
|
||||
}
|
||||
56
vendor/league/commonmark/src/Delimiter/DelimiterInterface.php
vendored
Executable file
56
vendor/league/commonmark/src/Delimiter/DelimiterInterface.php
vendored
Executable file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js)
|
||||
* - (c) John MacFarlane
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Delimiter;
|
||||
|
||||
use League\CommonMark\Node\Inline\AbstractStringContainer;
|
||||
|
||||
interface DelimiterInterface
|
||||
{
|
||||
public function canClose(): bool;
|
||||
|
||||
public function canOpen(): bool;
|
||||
|
||||
/**
|
||||
* @deprecated This method is no longer used internally and will be removed in 3.0
|
||||
*/
|
||||
public function isActive(): bool;
|
||||
|
||||
/**
|
||||
* @deprecated This method is no longer used internally and will be removed in 3.0
|
||||
*/
|
||||
public function setActive(bool $active): void;
|
||||
|
||||
public function getChar(): string;
|
||||
|
||||
public function getIndex(): ?int;
|
||||
|
||||
public function getNext(): ?DelimiterInterface;
|
||||
|
||||
public function setNext(?DelimiterInterface $next): void;
|
||||
|
||||
public function getLength(): int;
|
||||
|
||||
public function setLength(int $length): void;
|
||||
|
||||
public function getOriginalLength(): int;
|
||||
|
||||
public function getInlineNode(): AbstractStringContainer;
|
||||
|
||||
public function getPrevious(): ?DelimiterInterface;
|
||||
|
||||
public function setPrevious(?DelimiterInterface $previous): void;
|
||||
}
|
||||
106
vendor/league/commonmark/src/Delimiter/DelimiterParser.php
vendored
Executable file
106
vendor/league/commonmark/src/Delimiter/DelimiterParser.php
vendored
Executable file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\CommonMark\Delimiter;
|
||||
|
||||
use League\CommonMark\Delimiter\Processor\DelimiterProcessorCollection;
|
||||
use League\CommonMark\Delimiter\Processor\DelimiterProcessorInterface;
|
||||
use League\CommonMark\Node\Inline\Text;
|
||||
use League\CommonMark\Parser\Inline\InlineParserInterface;
|
||||
use League\CommonMark\Parser\Inline\InlineParserMatch;
|
||||
use League\CommonMark\Parser\InlineParserContext;
|
||||
use League\CommonMark\Util\RegexHelper;
|
||||
|
||||
/**
|
||||
* Delimiter parsing is implemented as an Inline Parser with the lowest-possible priority
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class DelimiterParser implements InlineParserInterface
|
||||
{
|
||||
private DelimiterProcessorCollection $collection;
|
||||
|
||||
public function __construct(DelimiterProcessorCollection $collection)
|
||||
{
|
||||
$this->collection = $collection;
|
||||
}
|
||||
|
||||
public function getMatchDefinition(): InlineParserMatch
|
||||
{
|
||||
return InlineParserMatch::oneOf(...$this->collection->getDelimiterCharacters());
|
||||
}
|
||||
|
||||
public function parse(InlineParserContext $inlineContext): bool
|
||||
{
|
||||
$character = $inlineContext->getFullMatch();
|
||||
$numDelims = 0;
|
||||
$cursor = $inlineContext->getCursor();
|
||||
$processor = $this->collection->getDelimiterProcessor($character);
|
||||
|
||||
\assert($processor !== null); // Delimiter processor should never be null here
|
||||
|
||||
$charBefore = $cursor->peek(-1);
|
||||
if ($charBefore === null) {
|
||||
$charBefore = "\n";
|
||||
}
|
||||
|
||||
while ($cursor->peek($numDelims) === $character) {
|
||||
++$numDelims;
|
||||
}
|
||||
|
||||
if ($numDelims < $processor->getMinLength()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cursor->advanceBy($numDelims);
|
||||
|
||||
$charAfter = $cursor->getCurrentCharacter();
|
||||
if ($charAfter === null) {
|
||||
$charAfter = "\n";
|
||||
}
|
||||
|
||||
[$canOpen, $canClose] = self::determineCanOpenOrClose($charBefore, $charAfter, $character, $processor);
|
||||
|
||||
if (! ($canOpen || $canClose)) {
|
||||
$inlineContext->getContainer()->appendChild(new Text(\str_repeat($character, $numDelims)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$node = new Text(\str_repeat($character, $numDelims), [
|
||||
'delim' => true,
|
||||
]);
|
||||
$inlineContext->getContainer()->appendChild($node);
|
||||
|
||||
// Add entry to stack to this opener
|
||||
$delimiter = new Delimiter($character, $numDelims, $node, $canOpen, $canClose, $inlineContext->getCursor()->getPosition());
|
||||
$inlineContext->getDelimiterStack()->push($delimiter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool[]
|
||||
*/
|
||||
private static function determineCanOpenOrClose(string $charBefore, string $charAfter, string $character, DelimiterProcessorInterface $delimiterProcessor): array
|
||||
{
|
||||
$afterIsWhitespace = \preg_match(RegexHelper::REGEX_UNICODE_WHITESPACE_CHAR, $charAfter);
|
||||
$afterIsPunctuation = \preg_match(RegexHelper::REGEX_PUNCTUATION, $charAfter);
|
||||
$beforeIsWhitespace = \preg_match(RegexHelper::REGEX_UNICODE_WHITESPACE_CHAR, $charBefore);
|
||||
$beforeIsPunctuation = \preg_match(RegexHelper::REGEX_PUNCTUATION, $charBefore);
|
||||
|
||||
$leftFlanking = ! $afterIsWhitespace && (! $afterIsPunctuation || $beforeIsWhitespace || $beforeIsPunctuation);
|
||||
$rightFlanking = ! $beforeIsWhitespace && (! $beforeIsPunctuation || $afterIsWhitespace || $afterIsPunctuation);
|
||||
|
||||
if ($character === '_') {
|
||||
$canOpen = $leftFlanking && (! $rightFlanking || $beforeIsPunctuation);
|
||||
$canClose = $rightFlanking && (! $leftFlanking || $afterIsPunctuation);
|
||||
} else {
|
||||
$canOpen = $leftFlanking && $character === $delimiterProcessor->getOpeningCharacter();
|
||||
$canClose = $rightFlanking && $character === $delimiterProcessor->getClosingCharacter();
|
||||
}
|
||||
|
||||
return [$canOpen, $canClose];
|
||||
}
|
||||
}
|
||||
396
vendor/league/commonmark/src/Delimiter/DelimiterStack.php
vendored
Executable file
396
vendor/league/commonmark/src/Delimiter/DelimiterStack.php
vendored
Executable file
@@ -0,0 +1,396 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js)
|
||||
* - (c) John MacFarlane
|
||||
*
|
||||
* Additional emphasis processing code based on commonmark-java (https://github.com/atlassian/commonmark-java)
|
||||
* - (c) Atlassian Pty Ltd
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Delimiter;
|
||||
|
||||
use League\CommonMark\Delimiter\Processor\CacheableDelimiterProcessorInterface;
|
||||
use League\CommonMark\Delimiter\Processor\DelimiterProcessorCollection;
|
||||
use League\CommonMark\Node\Inline\AdjacentTextMerger;
|
||||
use League\CommonMark\Node\Node;
|
||||
|
||||
final class DelimiterStack
|
||||
{
|
||||
/** @psalm-readonly-allow-private-mutation */
|
||||
private ?DelimiterInterface $top = null;
|
||||
|
||||
/** @psalm-readonly-allow-private-mutation */
|
||||
private ?Bracket $brackets = null;
|
||||
|
||||
/**
|
||||
* @deprecated This property will be removed in 3.0 once all delimiters MUST have an index/position
|
||||
*
|
||||
* @var \SplObjectStorage<DelimiterInterface, int>|\WeakMap<DelimiterInterface, int>
|
||||
*/
|
||||
private $missingIndexCache;
|
||||
|
||||
|
||||
private int $remainingDelimiters = 0;
|
||||
|
||||
public function __construct(int $maximumStackSize = PHP_INT_MAX)
|
||||
{
|
||||
$this->remainingDelimiters = $maximumStackSize;
|
||||
|
||||
if (\PHP_VERSION_ID >= 80000) {
|
||||
/** @psalm-suppress PropertyTypeCoercion */
|
||||
$this->missingIndexCache = new \WeakMap(); // @phpstan-ignore-line
|
||||
} else {
|
||||
$this->missingIndexCache = new \SplObjectStorage(); // @phpstan-ignore-line
|
||||
}
|
||||
}
|
||||
|
||||
public function push(DelimiterInterface $newDelimiter): void
|
||||
{
|
||||
if ($this->remainingDelimiters-- <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$newDelimiter->setPrevious($this->top);
|
||||
|
||||
if ($this->top !== null) {
|
||||
$this->top->setNext($newDelimiter);
|
||||
}
|
||||
|
||||
$this->top = $newDelimiter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function addBracket(Node $node, int $index, bool $image): void
|
||||
{
|
||||
if ($this->brackets !== null) {
|
||||
$this->brackets->setHasNext(true);
|
||||
}
|
||||
|
||||
$this->brackets = new Bracket($node, $this->brackets, $index, $image);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-immutable
|
||||
*/
|
||||
public function getLastBracket(): ?Bracket
|
||||
{
|
||||
return $this->brackets;
|
||||
}
|
||||
|
||||
private function findEarliest(int $stackBottom): ?DelimiterInterface
|
||||
{
|
||||
// Move back to first relevant delim.
|
||||
$delimiter = $this->top;
|
||||
$lastChecked = null;
|
||||
|
||||
while ($delimiter !== null && self::getIndex($delimiter) > $stackBottom) {
|
||||
$lastChecked = $delimiter;
|
||||
$delimiter = $delimiter->getPrevious();
|
||||
}
|
||||
|
||||
return $lastChecked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function removeBracket(): void
|
||||
{
|
||||
if ($this->brackets === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->brackets = $this->brackets->getPrevious();
|
||||
|
||||
if ($this->brackets !== null) {
|
||||
$this->brackets->setHasNext(false);
|
||||
}
|
||||
}
|
||||
|
||||
public function removeDelimiter(DelimiterInterface $delimiter): void
|
||||
{
|
||||
if ($delimiter->getPrevious() !== null) {
|
||||
/** @psalm-suppress PossiblyNullReference */
|
||||
$delimiter->getPrevious()->setNext($delimiter->getNext());
|
||||
}
|
||||
|
||||
if ($delimiter->getNext() === null) {
|
||||
// top of stack
|
||||
$this->top = $delimiter->getPrevious();
|
||||
} else {
|
||||
/** @psalm-suppress PossiblyNullReference */
|
||||
$delimiter->getNext()->setPrevious($delimiter->getPrevious());
|
||||
}
|
||||
|
||||
// Nullify all references from the removed delimiter to other delimiters.
|
||||
// All references to this particular delimiter in the linked list should be gone,
|
||||
// but it's possible we're still hanging on to other references to things that
|
||||
// have been (or soon will be) removed, which may interfere with efficient
|
||||
// garbage collection by the PHP runtime.
|
||||
// Explicitly releasing these references should help to avoid possible
|
||||
// segfaults like in https://bugs.php.net/bug.php?id=68606.
|
||||
$delimiter->setPrevious(null);
|
||||
$delimiter->setNext(null);
|
||||
|
||||
// TODO: Remove the line below once PHP 7.4 support is dropped, as WeakMap won't hold onto the reference, making this unnecessary
|
||||
unset($this->missingIndexCache[$delimiter]);
|
||||
}
|
||||
|
||||
private function removeDelimiterAndNode(DelimiterInterface $delimiter): void
|
||||
{
|
||||
$delimiter->getInlineNode()->detach();
|
||||
$this->removeDelimiter($delimiter);
|
||||
}
|
||||
|
||||
private function removeDelimitersBetween(DelimiterInterface $opener, DelimiterInterface $closer): void
|
||||
{
|
||||
$delimiter = $closer->getPrevious();
|
||||
$openerPosition = self::getIndex($opener);
|
||||
while ($delimiter !== null && self::getIndex($delimiter) > $openerPosition) {
|
||||
$previous = $delimiter->getPrevious();
|
||||
$this->removeDelimiter($delimiter);
|
||||
$delimiter = $previous;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DelimiterInterface|int|null $stackBottom
|
||||
*/
|
||||
public function removeAll($stackBottom = null): void
|
||||
{
|
||||
$stackBottomPosition = \is_int($stackBottom) ? $stackBottom : self::getIndex($stackBottom);
|
||||
|
||||
while ($this->top && $this->getIndex($this->top) > $stackBottomPosition) {
|
||||
$this->removeDelimiter($this->top);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method is no longer used internally and will be removed in 3.0
|
||||
*/
|
||||
public function removeEarlierMatches(string $character): void
|
||||
{
|
||||
$opener = $this->top;
|
||||
while ($opener !== null) {
|
||||
if ($opener->getChar() === $character) {
|
||||
$opener->setActive(false);
|
||||
}
|
||||
|
||||
$opener = $opener->getPrevious();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function deactivateLinkOpeners(): void
|
||||
{
|
||||
$opener = $this->brackets;
|
||||
while ($opener !== null && $opener->isActive()) {
|
||||
$opener->setActive(false);
|
||||
$opener = $opener->getPrevious();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method is no longer used internally and will be removed in 3.0
|
||||
*
|
||||
* @param string|string[] $characters
|
||||
*/
|
||||
public function searchByCharacter($characters): ?DelimiterInterface
|
||||
{
|
||||
if (! \is_array($characters)) {
|
||||
$characters = [$characters];
|
||||
}
|
||||
|
||||
$opener = $this->top;
|
||||
while ($opener !== null) {
|
||||
if (\in_array($opener->getChar(), $characters, true)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$opener = $opener->getPrevious();
|
||||
}
|
||||
|
||||
return $opener;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DelimiterInterface|int|null $stackBottom
|
||||
*
|
||||
* @todo change $stackBottom to an int in 3.0
|
||||
*/
|
||||
public function processDelimiters($stackBottom, DelimiterProcessorCollection $processors): void
|
||||
{
|
||||
/** @var array<string, int> $openersBottom */
|
||||
$openersBottom = [];
|
||||
|
||||
$stackBottomPosition = \is_int($stackBottom) ? $stackBottom : self::getIndex($stackBottom);
|
||||
|
||||
// Find first closer above stackBottom
|
||||
$closer = $this->findEarliest($stackBottomPosition);
|
||||
|
||||
// Move forward, looking for closers, and handling each
|
||||
while ($closer !== null) {
|
||||
$closingDelimiterChar = $closer->getChar();
|
||||
|
||||
$delimiterProcessor = $processors->getDelimiterProcessor($closingDelimiterChar);
|
||||
if (! $closer->canClose() || $delimiterProcessor === null) {
|
||||
$closer = $closer->getNext();
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($delimiterProcessor instanceof CacheableDelimiterProcessorInterface) {
|
||||
$openersBottomCacheKey = $delimiterProcessor->getCacheKey($closer);
|
||||
} else {
|
||||
$openersBottomCacheKey = $closingDelimiterChar;
|
||||
}
|
||||
|
||||
$openingDelimiterChar = $delimiterProcessor->getOpeningCharacter();
|
||||
|
||||
$useDelims = 0;
|
||||
$openerFound = false;
|
||||
$potentialOpenerFound = false;
|
||||
$opener = $closer->getPrevious();
|
||||
while ($opener !== null && ($openerPosition = self::getIndex($opener)) > $stackBottomPosition && $openerPosition >= ($openersBottom[$openersBottomCacheKey] ?? 0)) {
|
||||
if ($opener->canOpen() && $opener->getChar() === $openingDelimiterChar) {
|
||||
$potentialOpenerFound = true;
|
||||
$useDelims = $delimiterProcessor->getDelimiterUse($opener, $closer);
|
||||
if ($useDelims > 0) {
|
||||
$openerFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$opener = $opener->getPrevious();
|
||||
}
|
||||
|
||||
if (! $openerFound) {
|
||||
// Set lower bound for future searches
|
||||
// TODO: Remove this conditional check in 3.0. It only exists to prevent behavioral BC breaks in 2.x.
|
||||
if ($potentialOpenerFound === false || $delimiterProcessor instanceof CacheableDelimiterProcessorInterface) {
|
||||
$openersBottom[$openersBottomCacheKey] = self::getIndex($closer);
|
||||
}
|
||||
|
||||
if (! $potentialOpenerFound && ! $closer->canOpen()) {
|
||||
// We can remove a closer that can't be an opener,
|
||||
// once we've seen there's no matching opener.
|
||||
$next = $closer->getNext();
|
||||
$this->removeDelimiter($closer);
|
||||
$closer = $next;
|
||||
} else {
|
||||
$closer = $closer->getNext();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
\assert($opener !== null);
|
||||
|
||||
$openerNode = $opener->getInlineNode();
|
||||
$closerNode = $closer->getInlineNode();
|
||||
|
||||
// Remove number of used delimiters from stack and inline nodes.
|
||||
$opener->setLength($opener->getLength() - $useDelims);
|
||||
$closer->setLength($closer->getLength() - $useDelims);
|
||||
|
||||
$openerNode->setLiteral(\substr($openerNode->getLiteral(), 0, -$useDelims));
|
||||
$closerNode->setLiteral(\substr($closerNode->getLiteral(), 0, -$useDelims));
|
||||
|
||||
$this->removeDelimitersBetween($opener, $closer);
|
||||
// The delimiter processor can re-parent the nodes between opener and closer,
|
||||
// so make sure they're contiguous already. Exclusive because we want to keep opener/closer themselves.
|
||||
AdjacentTextMerger::mergeTextNodesBetweenExclusive($openerNode, $closerNode);
|
||||
$delimiterProcessor->process($openerNode, $closerNode, $useDelims);
|
||||
|
||||
// No delimiter characters left to process, so we can remove delimiter and the now empty node.
|
||||
if ($opener->getLength() === 0) {
|
||||
$this->removeDelimiterAndNode($opener);
|
||||
}
|
||||
|
||||
// phpcs:disable SlevomatCodingStandard.ControlStructures.EarlyExit.EarlyExitNotUsed
|
||||
if ($closer->getLength() === 0) {
|
||||
$next = $closer->getNext();
|
||||
$this->removeDelimiterAndNode($closer);
|
||||
$closer = $next;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all delimiters
|
||||
$this->removeAll($stackBottomPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
while ($this->top) {
|
||||
$this->removeDelimiter($this->top);
|
||||
}
|
||||
|
||||
while ($this->brackets) {
|
||||
$this->removeBracket();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method will be dropped in 3.0 once all delimiters MUST have an index/position
|
||||
*/
|
||||
private function getIndex(?DelimiterInterface $delimiter): int
|
||||
{
|
||||
if ($delimiter === null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (($index = $delimiter->getIndex()) !== null) {
|
||||
return $index;
|
||||
}
|
||||
|
||||
if (isset($this->missingIndexCache[$delimiter])) {
|
||||
return $this->missingIndexCache[$delimiter];
|
||||
}
|
||||
|
||||
$prev = $delimiter->getPrevious();
|
||||
$next = $delimiter->getNext();
|
||||
|
||||
$i = 0;
|
||||
do {
|
||||
$i++;
|
||||
if ($prev === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($prev->getIndex() !== null) {
|
||||
return $this->missingIndexCache[$delimiter] = $prev->getIndex() + $i;
|
||||
}
|
||||
} while ($prev = $prev->getPrevious());
|
||||
|
||||
$j = 0;
|
||||
do {
|
||||
$j++;
|
||||
if ($next === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($next->getIndex() !== null) {
|
||||
return $this->missingIndexCache[$delimiter] = $next->getIndex() - $j;
|
||||
}
|
||||
} while ($next = $next->getNext());
|
||||
|
||||
// No index was defined on this delimiter, and none could be guesstimated based on the stack.
|
||||
return $this->missingIndexCache[$delimiter] = $this->getIndex($delimiter->getPrevious()) + 1;
|
||||
}
|
||||
}
|
||||
46
vendor/league/commonmark/src/Delimiter/Processor/CacheableDelimiterProcessorInterface.php
vendored
Executable file
46
vendor/league/commonmark/src/Delimiter/Processor/CacheableDelimiterProcessorInterface.php
vendored
Executable file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Delimiter\Processor;
|
||||
|
||||
use League\CommonMark\Delimiter\DelimiterInterface;
|
||||
|
||||
/**
|
||||
* Special marker interface for delimiter processors that return dynamic values from getDelimiterUse()
|
||||
*
|
||||
* In order to guarantee linear performance of delimiter processing, the delimiter stack must be able to
|
||||
* cache the lower bound when searching for a matching opener. This gets complicated for delimiter processors
|
||||
* that use a dynamic number of characters (like with emphasis and its "multiple of 3" rule).
|
||||
*/
|
||||
interface CacheableDelimiterProcessorInterface extends DelimiterProcessorInterface
|
||||
{
|
||||
/**
|
||||
* Returns a cache key of the factors that determine the number of characters to use.
|
||||
*
|
||||
* In order to guarantee linear performance of delimiter processing, the delimiter stack must be able to
|
||||
* cache the lower bound when searching for a matching opener. This lower bound is usually quite simple;
|
||||
* for example, with quotes, it's just the last opener with that characted. However, this gets complicated
|
||||
* for delimiter processors that use a dynamic number of characters (like with emphasis and its "multiple
|
||||
* of 3" rule), because the delimiter length being considered may change during processing because of that
|
||||
* dynamic logic in getDelimiterUse(). Therefore, we cannot safely cache the lower bound for these dynamic
|
||||
* processors without knowing the factors that determine the number of characters to use.
|
||||
*
|
||||
* At a minimum, this should include the delimiter character, plus any other factors used to determine
|
||||
* the result of getDelimiterUse(). The format of the string is not important so long as it is unique
|
||||
* (compared to other processors) and consistent for a given set of factors.
|
||||
*
|
||||
* If getDelimiterUse() always returns the same hard-coded value, this method should return just
|
||||
* the delimiter character.
|
||||
*/
|
||||
public function getCacheKey(DelimiterInterface $closer): string;
|
||||
}
|
||||
89
vendor/league/commonmark/src/Delimiter/Processor/DelimiterProcessorCollection.php
vendored
Executable file
89
vendor/league/commonmark/src/Delimiter/Processor/DelimiterProcessorCollection.php
vendored
Executable file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js)
|
||||
* - (c) John MacFarlane
|
||||
*
|
||||
* Additional emphasis processing code based on commonmark-java (https://github.com/atlassian/commonmark-java)
|
||||
* - (c) Atlassian Pty Ltd
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Delimiter\Processor;
|
||||
|
||||
use League\CommonMark\Exception\InvalidArgumentException;
|
||||
|
||||
final class DelimiterProcessorCollection implements DelimiterProcessorCollectionInterface
|
||||
{
|
||||
/**
|
||||
* @var array<string,DelimiterProcessorInterface>|DelimiterProcessorInterface[]
|
||||
*
|
||||
* @psalm-readonly-allow-private-mutation
|
||||
*/
|
||||
private array $processorsByChar = [];
|
||||
|
||||
public function add(DelimiterProcessorInterface $processor): void
|
||||
{
|
||||
$opening = $processor->getOpeningCharacter();
|
||||
$closing = $processor->getClosingCharacter();
|
||||
|
||||
if ($opening === $closing) {
|
||||
$old = $this->processorsByChar[$opening] ?? null;
|
||||
if ($old !== null && $old->getOpeningCharacter() === $old->getClosingCharacter()) {
|
||||
$this->addStaggeredDelimiterProcessorForChar($opening, $old, $processor);
|
||||
} else {
|
||||
$this->addDelimiterProcessorForChar($opening, $processor);
|
||||
}
|
||||
} else {
|
||||
$this->addDelimiterProcessorForChar($opening, $processor);
|
||||
$this->addDelimiterProcessorForChar($closing, $processor);
|
||||
}
|
||||
}
|
||||
|
||||
public function getDelimiterProcessor(string $char): ?DelimiterProcessorInterface
|
||||
{
|
||||
return $this->processorsByChar[$char] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getDelimiterCharacters(): array
|
||||
{
|
||||
return \array_keys($this->processorsByChar);
|
||||
}
|
||||
|
||||
private function addDelimiterProcessorForChar(string $delimiterChar, DelimiterProcessorInterface $processor): void
|
||||
{
|
||||
if (isset($this->processorsByChar[$delimiterChar])) {
|
||||
throw new InvalidArgumentException(\sprintf('Delim processor for character "%s" already exists', $processor->getOpeningCharacter()));
|
||||
}
|
||||
|
||||
$this->processorsByChar[$delimiterChar] = $processor;
|
||||
}
|
||||
|
||||
private function addStaggeredDelimiterProcessorForChar(string $opening, DelimiterProcessorInterface $old, DelimiterProcessorInterface $new): void
|
||||
{
|
||||
if ($old instanceof StaggeredDelimiterProcessor) {
|
||||
$s = $old;
|
||||
} else {
|
||||
$s = new StaggeredDelimiterProcessor($opening, $old);
|
||||
}
|
||||
|
||||
$s->add($new);
|
||||
$this->processorsByChar[$opening] = $s;
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return \count($this->processorsByChar);
|
||||
}
|
||||
}
|
||||
46
vendor/league/commonmark/src/Delimiter/Processor/DelimiterProcessorCollectionInterface.php
vendored
Executable file
46
vendor/league/commonmark/src/Delimiter/Processor/DelimiterProcessorCollectionInterface.php
vendored
Executable file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js)
|
||||
* - (c) John MacFarlane
|
||||
*
|
||||
* Additional emphasis processing code based on commonmark-java (https://github.com/atlassian/commonmark-java)
|
||||
* - (c) Atlassian Pty Ltd
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Delimiter\Processor;
|
||||
|
||||
use League\CommonMark\Exception\InvalidArgumentException;
|
||||
|
||||
interface DelimiterProcessorCollectionInterface extends \Countable
|
||||
{
|
||||
/**
|
||||
* Add the given delim processor to the collection
|
||||
*
|
||||
* @param DelimiterProcessorInterface $processor The delim processor to add
|
||||
*
|
||||
* @throws InvalidArgumentException Exception will be thrown if attempting to add multiple processors for the same character
|
||||
*/
|
||||
public function add(DelimiterProcessorInterface $processor): void;
|
||||
|
||||
/**
|
||||
* Returns the delim processor which handles the given character if one exists
|
||||
*/
|
||||
public function getDelimiterProcessor(string $char): ?DelimiterProcessorInterface;
|
||||
|
||||
/**
|
||||
* Returns an array of delimiter characters who have associated processors
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getDelimiterCharacters(): array;
|
||||
}
|
||||
81
vendor/league/commonmark/src/Delimiter/Processor/DelimiterProcessorInterface.php
vendored
Executable file
81
vendor/league/commonmark/src/Delimiter/Processor/DelimiterProcessorInterface.php
vendored
Executable file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js)
|
||||
* - (c) John MacFarlane
|
||||
*
|
||||
* Additional emphasis processing code based on commonmark-java (https://github.com/atlassian/commonmark-java)
|
||||
* - (c) Atlassian Pty Ltd
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Delimiter\Processor;
|
||||
|
||||
use League\CommonMark\Delimiter\DelimiterInterface;
|
||||
use League\CommonMark\Node\Inline\AbstractStringContainer;
|
||||
|
||||
/**
|
||||
* Interface for a delimiter processor
|
||||
*/
|
||||
interface DelimiterProcessorInterface
|
||||
{
|
||||
/**
|
||||
* Returns the character that marks the beginning of a delimited node.
|
||||
*
|
||||
* This must not clash with any other processors being added to the environment.
|
||||
*/
|
||||
public function getOpeningCharacter(): string;
|
||||
|
||||
/**
|
||||
* Returns the character that marks the ending of a delimited node.
|
||||
*
|
||||
* This must not clash with any other processors being added to the environment.
|
||||
*
|
||||
* Note that for a symmetric delimiter such as "*", this is the same as the opening.
|
||||
*/
|
||||
public function getClosingCharacter(): string;
|
||||
|
||||
/**
|
||||
* Minimum number of delimiter characters that are needed to active this.
|
||||
*
|
||||
* Must be at least 1.
|
||||
*/
|
||||
public function getMinLength(): int;
|
||||
|
||||
/**
|
||||
* Determine how many (if any) of the delimiter characters should be used.
|
||||
*
|
||||
* This allows implementations to decide how many characters to be used
|
||||
* based on the properties of the delimiter runs. An implementation can also
|
||||
* return 0 when it doesn't want to allow this particular combination of
|
||||
* delimiter runs.
|
||||
*
|
||||
* IMPORTANT: Unless this method returns the same hard-coded value in all cases,
|
||||
* you MUST implement the CacheableDelimiterProcessorInterface interface instead.
|
||||
*
|
||||
* @param DelimiterInterface $opener The opening delimiter run
|
||||
* @param DelimiterInterface $closer The closing delimiter run
|
||||
*/
|
||||
public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int;
|
||||
|
||||
/**
|
||||
* Process the matched delimiters, e.g. by wrapping the nodes between opener
|
||||
* and closer in a new node, or appending a new node after the opener.
|
||||
*
|
||||
* Note that removal of the delimiter from the delimiter nodes and detaching
|
||||
* them is done by the caller.
|
||||
*
|
||||
* @param AbstractStringContainer $opener The node that contained the opening delimiter
|
||||
* @param AbstractStringContainer $closer The node that contained the closing delimiter
|
||||
* @param int $delimiterUse The number of delimiters that were used
|
||||
*/
|
||||
public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse): void;
|
||||
}
|
||||
111
vendor/league/commonmark/src/Delimiter/Processor/StaggeredDelimiterProcessor.php
vendored
Executable file
111
vendor/league/commonmark/src/Delimiter/Processor/StaggeredDelimiterProcessor.php
vendored
Executable file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* Additional emphasis processing code based on commonmark-java (https://github.com/atlassian/commonmark-java)
|
||||
* - (c) Atlassian Pty Ltd
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Delimiter\Processor;
|
||||
|
||||
use League\CommonMark\Delimiter\DelimiterInterface;
|
||||
use League\CommonMark\Exception\InvalidArgumentException;
|
||||
use League\CommonMark\Node\Inline\AbstractStringContainer;
|
||||
|
||||
/**
|
||||
* An implementation of DelimiterProcessorInterface that dispatches all calls to two or more other DelimiterProcessors
|
||||
* depending on the length of the delimiter run. All child DelimiterProcessors must have different minimum
|
||||
* lengths. A given delimiter run is dispatched to the child with the largest acceptable minimum length. If no
|
||||
* child is applicable, the one with the largest minimum length is chosen.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class StaggeredDelimiterProcessor implements DelimiterProcessorInterface
|
||||
{
|
||||
/** @psalm-readonly */
|
||||
private string $delimiterChar;
|
||||
|
||||
/** @psalm-readonly-allow-private-mutation */
|
||||
private int $minLength = 0;
|
||||
|
||||
/**
|
||||
* @var array<int, DelimiterProcessorInterface>|DelimiterProcessorInterface[]
|
||||
*
|
||||
* @psalm-readonly-allow-private-mutation
|
||||
*/
|
||||
private array $processors = []; // keyed by minLength in reverse order
|
||||
|
||||
public function __construct(string $char, DelimiterProcessorInterface $processor)
|
||||
{
|
||||
$this->delimiterChar = $char;
|
||||
$this->add($processor);
|
||||
}
|
||||
|
||||
public function getOpeningCharacter(): string
|
||||
{
|
||||
return $this->delimiterChar;
|
||||
}
|
||||
|
||||
public function getClosingCharacter(): string
|
||||
{
|
||||
return $this->delimiterChar;
|
||||
}
|
||||
|
||||
public function getMinLength(): int
|
||||
{
|
||||
return $this->minLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given processor to this staggered delimiter processor
|
||||
*
|
||||
* @throws InvalidArgumentException if attempting to add another processors for the same character and minimum length
|
||||
*/
|
||||
public function add(DelimiterProcessorInterface $processor): void
|
||||
{
|
||||
$len = $processor->getMinLength();
|
||||
|
||||
if (isset($this->processors[$len])) {
|
||||
throw new InvalidArgumentException(\sprintf('Cannot add two delimiter processors for char "%s" and minimum length %d', $this->delimiterChar, $len));
|
||||
}
|
||||
|
||||
$this->processors[$len] = $processor;
|
||||
\krsort($this->processors);
|
||||
|
||||
$this->minLength = \min($this->minLength, $len);
|
||||
}
|
||||
|
||||
public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int
|
||||
{
|
||||
return $this->findProcessor($opener->getLength())->getDelimiterUse($opener, $closer);
|
||||
}
|
||||
|
||||
public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse): void
|
||||
{
|
||||
$this->findProcessor($delimiterUse)->process($opener, $closer, $delimiterUse);
|
||||
}
|
||||
|
||||
private function findProcessor(int $len): DelimiterProcessorInterface
|
||||
{
|
||||
// Find the "longest" processor which can handle this length
|
||||
foreach ($this->processors as $processor) {
|
||||
if ($processor->getMinLength() <= $len) {
|
||||
return $processor;
|
||||
}
|
||||
}
|
||||
|
||||
// Just use the first one in our list
|
||||
$first = \reset($this->processors);
|
||||
\assert($first instanceof DelimiterProcessorInterface);
|
||||
|
||||
return $first;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user