createCodeBlockRegExp
Creates a regular expression that matches a single fenced code block anywhere in a Markdown note.
A fresh instance is returned on each call so callers may safely use stateful methods (e.g. RegExp.exec) without sharing lastIndex between scans.
Named capture groups: - LinePrefix — the leading indentation / callout blockquote prefix (> repeated once per nesting level) shared by every line of the block. - CodeBlockStartDelimiter / CodeBlockStartDelimiterChar — the opening fence (3+ backticks or tildes) and the fence character. - CodeBlockLanguage — the info-string language token immediately after the opening fence. - CodeBlockArgs — any extra arguments after the language token. - CodeBlockContent — the block body. Each content line carries the same LinePrefix. - CodeBlockEndDelimiter — the closing fence.
The CodeBlockContent group is written as \k<LinePrefix>.*(?:\n\k<LinePrefix>.*)*? — a first line followed by zero or more lines each introduced by a mandatory newline. This deliberately avoids the ambiguous (?:\n?\k<LinePrefix>.*)+? form (optional newline + repeatable line remainder), which lets a single line be partitioned in exponentially many ways and causes catastrophic backtracking — a synchronous freeze — when the scan meets a fence-open with no valid closing fence before the end of the note. The mandatory-newline form matches the same text linearly.
A block starts at the start of the text or right after a line break, which the m flag’s ^ expresses without a lookbehind: a lookbehind is a syntax error on iOS before 16.4, below the iOS 15 that Obsidian mobile still supports, and a regex literal that cannot parse fails the whole bundle. The m flag’s ^ also accepts as that line break a lone \r, which CommonMark treats as one too, and the Unicode line and paragraph separators, which no editor writes between note lines. The block end is (?![\s\S]) rather than $, so the m flag does not let a closing fence end before a \r.
Import:
import { createCodeBlockRegExp } from '@mnaoumov/obsidian-lib/code-block-reg-exp';Signature:
function createCodeBlockRegExp(): RegExpReturns: RegExp — A fresh global RegExp matching one fenced code block.