/** * Tiny, dependency-free highlighter for the static shell and YAML snippets on marketing and docs * pages. It only needs to look right for hand-written examples, so each language is a short list of * regex rules tried in order at every position. */ export type SnippetLanguage = "bash" | "yaml"; export type TokenKind = "comment" | "string" | "keyword" | "property" | "entity" | "sign" | "plain"; export type Token = { kind: TokenKind; text: string }; type Rule = { kind: TokenKind; pattern: RegExp }; const EXPRESSION = { kind: "entity", pattern: /\$\{\{.*?\}\}/y } as const; const BASH_RULES: ReadonlyArray = [ { kind: "comment", pattern: /#.*/y }, { kind: "string", pattern: /"(?:\\.|[^"\\])*"|'[^']*'/y }, { kind: "entity", pattern: /\$\{?[A-Za-z_][\w]*\}?/y }, { kind: "property", pattern: /--?[A-Za-z][\w-]*/y }, { kind: "sign", pattern: /&&|\|\||[|;>]/y }, ]; const YAML_RULES: ReadonlyArray = [ { kind: "comment", pattern: /#.*/y }, EXPRESSION, { kind: "string", pattern: /"(?:\\.|[^"\\])*"|'[^']*'/y }, { kind: "sign", pattern: /- |[[\]{},]/y }, { kind: "keyword", pattern: /\b(?:true|false|null|\d+(?:\.\d+)?)\b/y }, ]; const YAML_KEY = /^(\s*(?:- )?)([\w.-]+)(:)(?=\s|$)/; const BASH_COMMAND_START = /(^|&&|\|\||[|;])(\s*)$/; function scan(line: string, rules: ReadonlyArray, start: number, tokens: Token[]): void { let plain = ""; let index = start; const flushPlain = () => { if (plain) tokens.push({ kind: "plain", text: plain }); plain = ""; }; while (index < line.length) { let matched = false; for (const rule of rules) { rule.pattern.lastIndex = index; const match = rule.pattern.exec(line); if (match && match[0].length > 0) { flushPlain(); tokens.push({ kind: rule.kind, text: match[0] }); index += match[0].length; matched = true; break; } } if (!matched) { plain += line[index]; index += 1; } } flushPlain(); } /** Marks the first word of each command (`git`, `bun`, …) as a keyword. */ function markCommands(tokens: Token[]): Token[] { const out: Token[] = []; let before = ""; for (const token of tokens) { if (token.kind !== "plain") { out.push(token); before += token.text; continue; } let rest = token.text; while (rest) { const atStart = BASH_COMMAND_START.test(before); const word = /^(\s*)([^\s]+)/.exec(rest); if (!atStart || !word) { out.push({ kind: "plain", text: rest }); before += rest; break; } if (word[1]) out.push({ kind: "plain", text: word[1] }); out.push({ kind: "keyword", text: word[2] }); before += word[0]; rest = rest.slice(word[0].length); } } return out; } export function highlightLine(line: string, language: SnippetLanguage): Token[] { const tokens: Token[] = []; if (language === "bash") { scan(line, BASH_RULES, 0, tokens); return markCommands(tokens); } const key = YAML_KEY.exec(line); if (key && !line.trimStart().startsWith("#")) { const [, lead, name, colon] = key; if (lead.includes("-")) { tokens.push({ kind: "plain", text: lead.slice(0, lead.indexOf("-")) }); tokens.push({ kind: "sign", text: lead.slice(lead.indexOf("-")) }); } else if (lead) tokens.push({ kind: "plain", text: lead }); tokens.push({ kind: "property", text: name }, { kind: "sign", text: colon }); scan(line, YAML_RULES, key[0].length, tokens); return tokens; } scan(line, YAML_RULES, 0, tokens); return tokens; }