text function
Text parser - parses plain text content until a delimiter is encountered.
If config is provided, uses custom delimiters to determine text boundaries.
Optimized to parse multiple characters at once using a pattern-based approach:
- Characters that are not delimiter start chars or whitespace are always safe text
- A delimiter start char is safe only if not followed by the rest of the delimiter
- Whitespace is safe only if not followed by strip delimiters
The whitespace check is critical for Liquid's whitespace control feature:
{{- and {%- strip preceding whitespace, so we must stop parsing text
before whitespace that precedes these delimiters.
This is much more efficient than the naive approach of checking (varStart() | tagStart()).neg() for each character, which requires 11 parser activations per character vs 2-3 for this pattern-based approach.
Implementation
Parser text([LiquidConfig? config]) {
final cfg = config ?? LiquidConfig.standard;
// Build character class for delimiter start characters
final delimiterChars = cfg.delimiterStartChars;
// Any character except delimiter start chars and whitespace is definitely safe
final safeCharPattern = '^$delimiterChars \t\r\n';
final safeChar = pattern(safeCharPattern);
// A delimiter start char is safe if not followed by the rest of the delimiter
final safeBrace = _safeDelimiterChar(cfg);
// Whitespace is safe if not followed by strip delimiters
final safeWhitespace =
pattern(' \t\r\n') &
(string(cfg.varStartStrip) | string(cfg.tagStartStrip)).not();
// A text character is either:
// - A safe char (not delimiter start or whitespace)
// - A safe brace (delimiter start not followed by rest of delimiter)
// - Safe whitespace (whitespace not followed by strip delimiters)
final textChar =
safeChar | safeBrace | safeWhitespace.map((values) => values[0]);
// Parse one or more text characters and combine into a single TextNode
return textChar
.plus()
.flatten()
.map((text) => TextNode(text))
.labeled('text block');
}