input = $input; } public function parse(): array { $input = fopen('php://temp', 'r+'); fputs($input, $this->input); rewind($input); $output = []; while ($line = fgets($input)) { $output[] = $this->parseLine($line); } fclose($input); return $this->output = $output; } private function parseLine(string $input) { $line = [ 'raw' => $input, ]; $input = ltrim($input); if (str_starts_with($input, '```')) { $this->preformattedMode = $this->preformattedMode === 'on' ? 'off' : 'on'; $line['type'] = $this->preformattedMode === 'on' ? 'preformatted_on' : 'preformatted_off'; $line['text'] = $line['alt'] = trim(substr($input, 3)); } else if ($this->preformattedMode === 'on') { $line['type'] = 'preformatted'; $line['text'] = $line['raw']; } else if (str_starts_with($input, '#')) { $firstWhitespacePosition = $this->findWhitespace($input); $line['type'] = 'heading'; $line['size'] = substr_count( haystack: $input, needle: '#', length: min($firstWhitespacePosition, 3) ); $line['text'] = trim(substr( string: $input, offset: min($firstWhitespacePosition, 3) )); } else if (str_starts_with($input, '*')) { $line['type'] = 'listitem'; $line['text'] = trim(substr($input, 1)); } else if (str_starts_with($input, '>')) { $line['type'] = 'quote'; $line['text'] = trim(substr($input, 1)); } else if (str_starts_with($input, '=>')) { $whitespacePosition = $this->findWhitespace($input, 3); $link = substr(string: $input, offset: 2, length: $whitespacePosition - 2); $text = substr(string: $input, offset: $whitespacePosition); $line['type'] = 'link'; $line['link'] = trim($link); $line['text'] = trim($text); } else { $line['type'] = 'text'; $line['text'] = rtrim($input); } return $line; } private function findWhitespace(string $input, int $offset = 0): int { $space = strpos($input, ' ', $offset); $tab = strpos($input, "\t", $offset); return $space === false ? ($tab === false ? PHP_INT_MAX : $tab) : $space; } }