text_dedent()
def text_dedent(content) -> stringRemove common leading whitespace from all non-empty lines.
Similar to Python’s textwrap.dedent. Finds the longest common leading whitespace and removes it from all lines.
Args
content: string: String to dedent
Returns
str: Dedented string
text_dedup_diagnostics()
def text_dedup_diagnostics(diagnostics) -> listRemove duplicate diagnostics.
Deduplicates based on the JSON representation of each diagnostic, preserving the first occurrence of each unique diagnostic.
Args
diagnostics: list: List of diagnostic dicts
Returns
list: Deduplicated diagnostics
text_diagnostic()
def text_diagnostic(file, severity, message, line, column, end_line, end_column, code, source, related)Create a diagnostic dictionary.
Creates a structured diagnostic record suitable for rendering in various formats (GitHub Actions, SARIF, etc.).
Args
file: string: Source file pathseverity: string: “error”, “warning”, “info”, “hint”, or “note”message: string: Diagnostic messageline: Line number (1-based, optional)column: Column number (1-based, optional)end_line: End line number (1-based, optional)end_column: End column number (1-based, optional)code: Error/warning code (optional)source: Source tool name (optional)related: List of related diagnostics (optional)
Returns
dict: Diagnostic record
text_grep()
def text_grep(path, pattern, ignore_case, invert, max)Search for lines matching a regex pattern.
Args
path: string: Path to the filepattern: string: Regular expression patternignore_case: bool: Case-insensitive matchinginvert: bool: Return non-matching lines insteadmax: Maximum number of matches (None for unlimited)
Returns
list[dict]: Matches with keys: line, text, match, named
text_head()
def text_head(path, n) -> listGet the first n lines of a file.
Args
path: string: Path to the filen: int: Number of lines to read (must be non-negative)
Returns
list[str]: First n lines
text_line_count()
def text_line_count(path) -> intCount the number of lines in a file.
Efficiently counts lines by scanning for newline characters without UTF-8 validation, making it very fast even for large files.
Args
path: string: Path to the file
Returns
int: Number of lines in the file
text_match_to_diagnostic()
def text_match_to_diagnostic(match, severity, default_message, default_file, source, related)Convert a regex match result to a diagnostic.
Takes a regex match result (from text_regex_scan_tagged or similar) and converts it to a diagnostic by extracting named capture groups. This is more efficient than manually extracting fields in Starlark code.
Named Capture Groups: The function looks for these named groups in the match: - file: File path - line: Line number (1-based) - column: Column number (1-based) - end_line: End line number (1-based) - end_column: End column number (1-based) - code: Error/warning code - message: Diagnostic message
Args
match: Regex match result from text_regex_scan_tagged or similarseverity: string: Severity level (“error”, “warning”, “info”, “hint”, or “note”)default_message: string: Message to use if no “message” capture group existsdefault_file: string: File to use if no “file” capture group existssource: Source identifier for the diagnostic (e.g., “eslint”, “rustc”)related: List of related diagnostics (optional)
Returns
dict: Diagnostic record that can be rendered with text_render_diagnostics
text_read_line_range()
def text_read_line_range(path, start, end) -> listRead a range of lines from a file (1-based, inclusive).
Args
path: string: Path to the filestart: int: First line number (1-based)end: int: Last line number (1-based, inclusive)
Returns
list[str]: Lines in the specified range
text_regex_scan()
def text_regex_scan(content, patterns) -> listScan content for multiple regex patterns simultaneously.
Uses an efficient regex set to quickly determine if any pattern matches, then runs captures only on matching patterns.
Args
content: string: String content to scanpatterns: list: List of regex pattern strings
Returns
list[dict]: Matches with keys: pattern_index, line, column, match, named
text_regex_scan_file()
def text_regex_scan_file(path, patterns) -> listScan a file for multiple regex patterns, streaming from disk.
Args
path: string: Path to the filepatterns: list: List of regex pattern strings
Returns
list[dict]: Matches with keys: pattern_index, line, column, match, named
text_regex_scan_tagged()
def text_regex_scan_tagged(content, patterns, first_match_only) -> listScan content for tagged regex patterns.
Each pattern is a dict with “tag” and “pattern” keys. Results include the tag instead of pattern_index.
Args
content: string: String content to scanpatterns: list: List of dicts with “tag” (str) and “pattern” (str) keysfirst_match_only: bool: If True, stop after finding the first match (default: False)
Returns
list[dict]: Matches with keys: tag, line, column, match, named
text_regex_scan_tagged_file()
def text_regex_scan_tagged_file(path, patterns, first_match_only) -> listScan a file for tagged regex patterns, streaming from disk.
Args
path: string: Path to the filepatterns: list: List of dicts with “tag” (str) and “pattern” (str) keysfirst_match_only: bool: If True, stop after finding the first match (default: False)
Returns
list[dict]: Matches with keys: tag, line, column, match, named
text_render_diagnostics()
def text_render_diagnostics(diagnostics, format) -> stringRender diagnostics in a specified format.
Formats: - “human”: One line per diagnostic: “file:line:col: severity: message” - “github”: GitHub Actions workflow commands (::error, ::warning, etc.) - “json”: Pretty-printed JSON array - “sarif”: SARIF 2.1.0 format for static analysis tools
Args
diagnostics: list: List of diagnostic dictsformat: string: Output format - “human”, “github”, “json”, or “sarif”
Returns
str: Formatted diagnostics
text_scan_file()
def text_scan_file(path, callback, encoding, strip_newline)Stream a file line-by-line and invoke a callback for each line.
Reads the file efficiently without loading it entirely into memory, making it suitable for large files. The callback is invoked for each line with the line content and line number.
Args
path: string: Path to the file to scancallback: Function with signature (line: str, line_num: int) -> value Return None to skip, any other value to collectencoding: string: “utf-8” (strict) or “lossy” (replacement chars for invalid UTF-8)strip_newline: bool: Whether to remove trailing newline characters
Returns
list: All non-None values returned by the callback
text_scan_lines()
def text_scan_lines(content, callback)Scan a string line-by-line with a callback.
Similar to scan_file but operates on an already-loaded string. Splits on newlines and invokes the callback for each line.
Args
content: string: String content to scancallback: Function with signature (line: str, line_num: int) -> value
Returns
list: All non-None values returned by the callback
text_scan_windows()
def text_scan_windows(content, n, callback)Scan content with a sliding window of n consecutive lines.
Invokes callback(window, start_line_num) for each window position, where window is a list of up to n lines.
Args
content: string: String content to scann: int: Window size (must be >= 1)callback: Function with signature (window: list[str], start_line: int) -> value
Returns
list: All non-None values returned by the callback
text_scan_windows_file()
def text_scan_windows_file(path, n, callback)Scan a file with a sliding window, streaming from disk.
Like scan_windows but reads from a file efficiently without loading the entire file into memory.
Args
path: string: Path to the filen: int: Window size (must be >= 1)callback: Function with signature (window: list[str], start_line: int) -> value
Returns
list: All non-None values returned by the callback
text_tail()
def text_tail(path, n) -> listGet the last n lines of a file.
Efficiently reads the file in a single pass using a circular buffer, making it suitable for large files.
Args
path: string: Path to the filen: int: Number of lines to read (must be non-negative)
Returns
list[str]: Last n lines