Minn\Html
The HTML tag processor. 7 classes, 74 public methods and 19 internals. This page is the public surface; each class name opens the whole class.
Decoder final class
public/minn/src/Minn/Html/Decoder.php · 129 lines · Open the class →
Character reference decoding for text and attribute values: numeric and named references, the legacy names that work without a semicolon (not in an attribute when an "=" or alphanumeric follows), unknown ones left as is.
| static | text(string $raw): string | Text with its character references decoded. |
| static | attribute(string $raw): string | An attribute value with its character references decoded. |
| static | reference(string $context, string $text, int $at): ?array | The character reference at $at in a context ("data" or "attribute"): its text and how many bytes it spans, or null when none decodes there. @return array{0: string, 1: int}|null |
| static | char(int $code): string | The UTF-8 text for a code point, U+FFFD for one that cannot be a character, Windows-1252's for the C1 range. |
| inside | decode(), codePoint(), legacy() |
Edits final class
public/minn/src/Minn/Html/Edits.php · 336 lines · Open the class →
The edits pending on the current token: attribute sets and removals, class additions and removals, and a text replacement, in call order. They answer reads before they are written, and become the source replacements the reader splices in when it moves on.
| static | validName(string $name): bool | Whether an attribute name may be set at all, by the reference's rules. |
| method | setAttribute(string $name, string|true $value): void | Records a set; setting class outright forgets the class edits before it. |
| method | setEscapedAttribute(string $name, string $escaped): void | Records an attribute value that comes already escaped (a URL through esc_url), written as it is. |
| method | removeAttribute(string $name): void | Records a removal of an attribute the source has. |
| method | cancelAttribute(string $name): void | Forgets a pending set that never reached the source: cancelling an addition is not a removal. |
| method | attribute(string $lower): ?array | The pending set or removal for a lowercase name, or null when there is none. @return array{name: string, value: string|true|null}|null @return array{name: string, value: string|true|null}|null |
| method | addClass(string $class): void | Records a class to add; a later removal of the same class wins. |
| method | removeClass(string $class): void | Records a class to remove; a later addition of the same class wins. |
| method | hasClassEdits(): bool | Whether any class edit is pending. |
| method | hasTagEdits(): bool | Whether any attribute or class edit is pending. |
| method | classesAfter(array $base): array | The class list after the pending edits: additions appended once, removals gone. @param list<string> $base@return list<string> |
| static | closesComment(string $text): bool | Whether text holds a comment closer, "-->" or "--!>". |
| method | setTextFor(?string $type, ?string $tagName, ?string $commentType, string $text): bool | Records a text replacement for a token of a kind that takes one: text (escaped), an ordinary HTML comment, or a raw-text element's body (script and style bodies get their closers escaped). False when the kind takes none, or the text would end the element early. |
| method | takeText(): ?string | The pending text replacement, taken: it is cleared on read. |
| method | takeReplacements(array $attributes, int $nameEnd, ?string $baseClassValue): array | The source replacements the attribute and class edits amount to, and forgets them: a changed attribute is rewritten in place (its duplicates removed), a removed one is cut, a new one is inserted after the tag name (several in the order of their text). @param list<array{name: string, lower: string, start: int, end: int, value: ?string}> $attributes the tag's own@return list<array{int, int, string}> start, end, text |
| method | clear(): void | Forgets everything pending. |
| static | splice(string $html, array $replacements, array $bookmarks, int $tokenStart, int $tokenEnd): array | Splices replacements into the source, ascending, and moves the bookmarks and the cursor by what the token at [$tokenStart, $tokenEnd] gained or lost. @param list<array{int, int, string}> $replacements@param array<string, array{0: int, 1: int}> $bookmarks@return array{0: string, 1: array<string, array{0: int, 1: int}>, 2: int} the source, the bookmarks, the cursor |
| static | classValue(?array $pending, array $attributes): ?string | The class attribute's decoded value before class edits: a pending set, else the source's; null when there is none. @param array{value: string|true}|null $pending@param list<array{lower: string, value: ?string}> $attributes |
| static | classList(?array $pending, array $attributes): array | The class names before class edits. @param array{value: string|true}|null $pending@param list<array{lower: string, value: ?string}> $attributes@return list<string> |
| inside | rebuiltClassValue(), existingName(), escape() |
Escaped final readonly class
public/minn/src/Minn/Html/Escaped.php · 6 lines · Open the class →
An attribute value that comes already escaped (a URL through esc_url), written as it is.
| new | __construct(string $value) | |
| prop | readonly string $value |
Scanner final class
public/minn/src/Minn/Html/Scanner.php · 291 lines · Open the class →
Reads one token's shape out of raw HTML at an offset: a tag with its name and attributes, a comment of one of the reference's kinds, a doctype, or a processing instruction. Pure and stateless; null means the input ends before the token does, which is where a streaming reader pauses.
| static | tag(string $html, int $at, int $nameStart): ?array | A tag starting at $at, its name from $nameStart (one byte in for an opener, two for a closer): the name, where it ends, the end offset, the attributes with their source offsets, and the self-closing flag. @return array{name: string, nameEnd: int, end: int, attributes: list<array{name: string, lower: string, start: int, end: int, value: ?string, quoted: bool}>, selfClosing: bool}|null |
| static | rawText(string $html, string $name, int $from): ?array | A raw-text element's body (script, style, textarea, ...): from $from to its closing tag, or null when the closer never comes. @return array{textStart: int, textLength: int, end: int}|null |
| static | markupDeclaration(string $html, int $at): ?array | What "<!" opens at $at: an HTML comment (abruptly closed or not), a doctype, a CDATA lookalike, or a bogus comment. @return array{kind: string, start: int, end: int, textStart: int, textLength: int, commentType?: string, fullStart?: int, fullLength?: int}|null |
| static | question(string $html, int $at): ?array | What "<?" opens at $at: a processing instruction when an ASCII alphanumeric target (not "xml") is followed by space, "?" or ">" (its text after the space, up to "?>" or ">"); a PI lookalike comment for another XML name closed by "?>"; otherwise an invalid comment. @return array{kind: string, start: int, end: int, textStart: int, textLength: int, target?: string, commentType?: string, fullStart?: int, fullLength?: int}|null |
| static | attributeValue(array $attributes, string $lower): string|true|null | A source attribute's decoded value (true when it has none), or null when the tag lacks it. @param list<array{lower: string, value: ?string}> $attributes |
| static | opensMarkup(string $html, int $at): bool | Whether the "<" at $at opens markup: a tag, a closer, "<!" or "<?". |
| static | textEnd(string $html, int $at): int | Where text starting at $at ends: at the next "<" that opens markup, before a "<" ending the input, or at the end. |
| static | cdata(string $html, int $at): ?array | A CDATA section in foreign content, "<![CDATA[" to "]]>"; null when it does not close. @return array{kind: string, start: int, end: int, textStart: int, textLength: int}|null |
| static | doctype(string $body): array | A doctype's body split into its name and public and system identifiers. @return array{name: ?string, public: ?string, system: ?string} |
| static | isSpace(string $c): bool | Whether a byte is HTML whitespace. |
| inside | attribute(), comment() |
TagQuery final readonly class
public/minn/src/Minn/Html/TagQuery.php · 37 lines · Open the class →
A tag processor's next_tag() query: a tag name (any case), a class, the nth match to stop at, and whether closers count.
| prop | readonly ?string $tagName | |
| prop | readonly ?string $className | |
| prop | readonly int $offset | |
| prop | readonly string $closers | |
| static | from(array $query): self | The query read from the array a caller passes. @param array{tag_name?: ?string, class_name?: ?string, match_offset?: int, tag_closers?: string} $query |
| method | matches(string $name, int $closer, callable $hasClass): bool | Whether a tag (by name, closer or not, and a class test) matches, before the offset is counted. |
Tags final class
public/minn/src/Minn/Html/Tags.php · 589 lines · Open the class →
A streaming HTML tokenizer with in-place edits: every token in document order, attributes decoded, edits applied to the source without reserialising the rest, bookmarks to seek back to (probe html-tag-processor).
| const | TAG = '#tag' | |
| const | TEXT = '#text' | |
| const | COMMENT = '#comment' | |
| const | DOCTYPE = '#doctype' | |
| const | PI = '#processing-instruction' | |
| const | FUNKY = '#funky-comment' | |
| const | CDATA = '#cdata-section' | |
| const | PRESUMPTUOUS = '#presumptuous-tag' | |
| const | COMMENT_HTML = 'COMMENT_AS_HTML_COMMENT' | |
| const | COMMENT_ABRUPT = 'COMMENT_AS_ABRUPTLY_CLOSED_COMMENT' | |
| const | COMMENT_INVALID = 'COMMENT_AS_INVALID_HTML' | |
| const | COMMENT_CDATA = 'COMMENT_AS_CDATA_LOOKALIKE' | |
| const | COMMENT_PI = 'COMMENT_AS_PI_NODE_LOOKALIKE' | |
| const | RAW_TEXT = array ( 0 => 'script', 1 => 'style', 2 => 'textarea', 3 => 'title', 4 => 'xmp', 5 => 'iframe', 6 => 'noembed', 7 => 'noframes', ) | Elements whose body is raw text up to the closer. |
| new | __construct(string $html) | |
| method | nextToken(): bool | Advances to the next token; false at the end or at an incomplete one. |
| method | nextTag(array $query): bool | Advances to the next tag matching the query; false when none. @param array{tag_name?: ?string, class_name?: ?string, match_offset?: int, tag_closers?: string} $query @param array{tag_name?: ?string, class_name?: ?string, match_offset?: int, tag_closers?: string} $query |
| method | pausedAtIncompleteToken(): bool | Whether the scan stopped inside an unfinished token. |
| method | tokenType(): ?string | The current token's kind. |
| method | tokenName(): ?string | The current token's name. |
| method | tag(): ?string | The current tag name, upper-cased; a processing instruction's target, or a PI lookalike's, as written. |
| method | isCloser(): bool | Whether the current tag is a closer. |
| method | selfClosing(): bool | Whether the current tag has the self-closing flag. |
| method | commentType(): ?string | The current comment's kind. |
| method | fullCommentText(): ?string | The current comment's whole text (a funky comment's is its text). |
| method | modifiableText(): string | The current token's text as a reader sees it. |
| method | doctype(): ?array | Doctype pieces, or null when the token is not a doctype. @return array{name: ?string, public: ?string, system: ?string}|null @return array{name: ?string, public: ?string, system: ?string}|null |
| method | attribute(string $name): string|true|null | The decoded value, true for a bare attribute, null when absent; a pending edit answers first. |
| method | attributeNames(string $prefix): ?array | The current tag's attribute names with a prefix, lower-cased, in source order; null off a tag. @return list<string>|null @return list<string>|null |
| method | classes(): array | The current tag's classes. @return list<string> distinct class names after pending edits @return list<string> distinct class names after pending edits |
| method | hasClass(string $class): bool | Whether the current tag has a class. |
| method | setAttribute(string $name, Minn\Html\Escaped|string|int|float|bool|null $value): bool | Sets an attribute on the current tag. |
| method | removeAttribute(string $name): bool | Removes an attribute from the current tag. |
| method | addClass(string $class): bool | Adds a class to the current tag. |
| method | removeClass(string $class): bool | Removes a class from the current tag. |
| method | setModifiableText(string $text): bool | Replaces the current token's text, when its kind allows it. |
| method | setBookmark(string $name): bool | Names the current token's position. |
| method | releaseBookmark(string $name): bool | Forgets a bookmark. |
| method | hasBookmark(string $name): bool | Whether a bookmark exists. |
| method | seek(string $name): bool | Moves to a bookmark. |
| method | parseAs(string $namespace, string $tagBodies = 'html'): void | What follows as a namespace's content: outside HTML "<![CDATA[" opens a section; tag bodies read as HTML ("html", raw text elements whole) unless foreign ("foreign"). |
| method | allowBookmarks(int $max): void | Raises how many bookmarks may be held at once. |
| method | rewind(): void | Back to the start of the document, with every update written in and the bookmarks kept. |
| method | splitText(int $length): void | The current text token cut to its first bytes; the rest is read next. |
| method | tokenSpan(): array | Where the current token sits in the document: [start, end]. |
| method | textSpan(): array | Where the current text token's text sits: [start, length]. |
| method | source(int $start, int $length): string | The source between two offsets, updates written in. |
| method | bookmarkSpan(string $name): ?array | Where a bookmark sits: [start, end], or null when there is none of that name. |
| method | replaceAfter(int $start, int $end, string $text): void | Replaces a span at or after the current token's end, updates written in first: the new text is read next, and bookmarks past the span move with it. |
| method | html(): string | The document with every update written in. |
| inside | setToken(), resetToken(), takeTag(), take(), baseClassList(), baseClassValue(), flush(), applyReplacements(), rescanCurrent(), rescan() |
TokenMap final class
public/minn/src/Minn/Html/TokenMap.php · 87 lines · Open the class →
A map from words to replacements that reads the longest word at a place in a text (as character reference names are read): words shorter than the key length stand alone, the others are grouped by their first bytes, longest first.
| new | __construct(array $mappings, int $keyLength) | @param array<string, string> $mappings |
| method | keyLength(): int | How many leading bytes group the words. |
| method | contains(string $word, string $caseSensitivity): bool | Whether the word is in the map ("case-sensitive" or "ascii-case-insensitive"). |
| method | read(string $text, int $offset, string $caseSensitivity): ?array | The replacement for the longest word at $offset, and the word's length; null when none starts there. @return array{0: string, 1: int}|null |
| method | toArray(): array | Every word and its replacement: the short words first, then each group longest first. @return array<string, string> |
| inside | same() |
Nothing matches.