1<?php 2 3declare(strict_types=1); 4 5/* 6 * This file is part of the league/commonmark package. 7 * 8 * (c) Colin O'Dell <colinodell@gmail.com> 9 * 10 * Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js) 11 * - (c) John MacFarlane 12 * 13 * Additional emphasis processing code based on commonmark-java (https://github.com/atlassian/commonmark-java) 14 * - (c) Atlassian Pty Ltd 15 * 16 * For the full copyright and license information, please view the LICENSE 17 * file that was distributed with this source code. 18 */ 19 20namespace League\CommonMark\Delimiter\Processor; 21 22use League\CommonMark\Exception\InvalidArgumentException; 23 24final class DelimiterProcessorCollection implements DelimiterProcessorCollectionInterface 25{ 26 /** 27 * @var array<string,DelimiterProcessorInterface>|DelimiterProcessorInterface[] 28 * 29 * @psalm-readonly-allow-private-mutation 30 */ 31 private array $processorsByChar = []; 32 33 public function add(DelimiterProcessorInterface $processor): void 34 { 35 $opening = $processor->getOpeningCharacter(); 36 $closing = $processor->getClosingCharacter(); 37 38 if ($opening === $closing) { 39 $old = $this->processorsByChar[$opening] ?? null; 40 if ($old !== null && $old->getOpeningCharacter() === $old->getClosingCharacter()) { 41 $this->addStaggeredDelimiterProcessorForChar($opening, $old, $processor); 42 } else { 43 $this->addDelimiterProcessorForChar($opening, $processor); 44 } 45 } else { 46 $this->addDelimiterProcessorForChar($opening, $processor); 47 $this->addDelimiterProcessorForChar($closing, $processor); 48 } 49 } 50 51 public function getDelimiterProcessor(string $char): ?DelimiterProcessorInterface 52 { 53 return $this->processorsByChar[$char] ?? null; 54 } 55 56 /** 57 * @return string[] 58 */ 59 public function getDelimiterCharacters(): array 60 { 61 return \array_keys($this->processorsByChar); 62 } 63 64 private function addDelimiterProcessorForChar(string $delimiterChar, DelimiterProcessorInterface $processor): void 65 { 66 if (isset($this->processorsByChar[$delimiterChar])) { 67 throw new InvalidArgumentException(\sprintf('Delim processor for character "%s" already exists', $processor->getOpeningCharacter())); 68 } 69 70 $this->processorsByChar[$delimiterChar] = $processor; 71 } 72 73 private function addStaggeredDelimiterProcessorForChar(string $opening, DelimiterProcessorInterface $old, DelimiterProcessorInterface $new): void 74 { 75 if ($old instanceof StaggeredDelimiterProcessor) { 76 $s = $old; 77 } else { 78 $s = new StaggeredDelimiterProcessor($opening, $old); 79 } 80 81 $s->add($new); 82 $this->processorsByChar[$opening] = $s; 83 } 84 85 public function count(): int 86 { 87 return \count($this->processorsByChar); 88 } 89} 90