API / Minn\Blocks / BlockStream

BlockStream final class

Minn\Blocks\BlockStream · public/minn/src/Minn/Blocks/BlockStream.php · 285 lines

Block markup read one token at a time, as the reference's streaming block processor reads it (probe block-processor). A delimiter is an HTML comment: whitespace after "<!--", an optional "/" (the closing flag), "wp:", a name (lowercase, an optional namespace), whitespace, optional JSON object attributes followed by whitespace, then "-->" or "/-->" (void). Any other comment is HTML. The HTML between delimiters comes out as its own token, reported as void (freeform at the top, inner HTML in a block) before the delimiter that ends it, which is already read, so the closing flag shows that delimiter's. Quirks kept on purpose: - trailing HTML after the last delimiter is dropped when it holds a comment; - an unterminated comment is incomplete input only when it could still become a delimiter, otherwise reading just stops; - attributes are parsed only when asked, and only that sets the JSON error.

Uses 1

Constants and properties

constCLOSER = 'closer'
constOPENER = 'opener'
constVOID = 'void'
constREADY = 'processor-ready'
constMATCHED = 'processor-matched'
constHTML_SPAN = 'processor-html-span'
constINCOMPLETE_INPUT = 'incomplete-input'
constCOMPLETE = 'processor-complete'
privateWHITESPACE = ' '
privateDELIMITER = '#^[ \\t\\n\\r\\f]+(/)?wp:([a-z][a-z0-9_-]*(?:/[a-z][a-z0-9_-]*)?)[ \\t\\n\\r\\f]+(?:(\\{.*\\})[ \\t\\n\\r\\f]+)?(/)?$#s'
privatestring $state
private?string $error
privateint $jsonError
privateint $cursor
privatearray $delimiter
privatearray $html
privatebool $delimiterWaiting
privatebool $popNext
privatearray $open
privatereadonly string $text

Promoted from the constructor.

Public

new__construct(string $text)#

A stream over block markup, before its first token.

staticnormalize(string $name): string#

The name with core/ in front when it has no namespace.

methodnext(): bool#

Moves to the next token, HTML or delimiter; false at the end or on incomplete input.

methodstate(): string#

The current token's state: one of the class constants.

methoderror(): ?string#

incomplete-input when the text ran out inside what could be a delimiter, else null.

methodjsonError(): int#

The JSON error from the last time attributes were asked for.

methoddelimiterType(): ?string#

opener, closer or void for a delimiter, void for HTML, null otherwise.

methodclosing(): bool#

The last delimiter read had the closing flag.

methodblockType(): ?string#

The delimiter's block type, null for anything else.

methodprintableType(): ?string#

The block type, or core/freeform for top-level HTML and #innerHTML for HTML inside a block.

methodisHtml(): bool#

Whether the token is HTML between delimiters.

methodhtmlContent(): ?string#

The HTML span's text, null for anything else.

methodnonWhitespaceHtml(): bool#

Whether the token is HTML with something other than whitespace in it.

methodbreadcrumbs(): array#

The open block types, outermost first, with #html for an HTML span. @return list<string>

@return list<string>
methodopens(?string $type): bool#

Whether this token opens a block (of the type, when given): never after a closer, and HTML only at the top.

methodisType(string $type): bool#

Whether the token is of the type; * matches anything.

methodspan(): ?array#

The token's start and length in the text, null when there is no token. @return array{0: int, 1: int}|null

@return array{0: int, 1: int}|null
methodattributes(): ?array#

The delimiter's attributes, parsed now (setting the JSON error), or null. @return array<mixed>|null

@return array<mixed>|null

Internals 7

Private and protected methods: how the class does its work. Not a contract; they change whenever the code is tidied.

privatescan(): bool#

From where the last token ended: the HTML before the next delimiter, the delimiter, or the end.

privateemitHtml(int $at, int $length): bool#
privatematchDelimiter(): bool#
privatefinish(?string $error): bool#
privatenextDelimiter(int $from): array|false|null#

The next delimiter from a position; null when there is none and no comment came first (the rest is HTML), false when reading stops there (a comment came first, or one is cut off; cut off where a delimiter could still begin is incomplete input).

@return array{at: int, length: int, type: string, closing: bool, name: string, json: ?string}|false|null
privatecommentEnd(int $at): ?int#

Where a comment starting here ends (just past it), or null when it never does.

privatecouldBeDelimiter(int $at): bool#

Whether a comment cut off by the end of the text could still have become a delimiter.