UNPKG

@tanstack/highlight

Version:

Tiny class-based syntax highlighting for documentation.

87 lines (86 loc) • 3.95 kB
import { blockCommentEnd } from '../internal/nested-comment.js'; import { defineLanguage } from '../core.js'; import { collectPatternRanges } from '../internal/patterns.js'; const patterns = [ [/@[A-Za-z_$][\w$]*/g, 'attr'], // Named-argument and record labels; the lookbehind keeps ternaries plain. [/(?<![\w$])(?=[a-z_$])(?<=[(,{]\s*)(?!default:)[\w$]+(?=:)/g, 'property'], [/(?<![\w$.])(?:(?:async|sync|yield)\*|abstract|as|assert|async|await|break|case|catch|class|const|continue|default|do|else|enum|export|extends|final|finally|for|if|implements|import|in|is|new|operator|rethrow|return|static|super|switch|this|throw|try|typedef|var|while|with|yield)(?![\w$])/g, 'keyword'], // Built-in and contextual words are keywords only when another word, string or `(` follows. [/(?<![\w$.])(?:base|covariant|deferred|extension|external|factory|get|hide|interface|late|library|mixin|on|part|required|sealed|set|show|when)(?=\s+(?!i[ns]\b)[\w$'"(])/g, 'keyword'], [/(?<![\w$.])(?:true|false|null)(?![\w$])/g, 'literal'], [/\b(?:class|enum|mixin|extension(?:\s+type)?|typedef)\s+([A-Za-z_$][\w$]*)/g, 'type', 1], [/(?<![\w$])(?:int|double|num|bool|void|dynamic|[_$]*[A-Z][A-Z\d_$]*[a-z][\w$]*)(?![\w$])/g, 'type'], [/(?<![\w$])[A-Za-z_$][\w$]*(?=\s*\()/g, 'function'], [/(?<!\.\.)\.\s*([A-Za-z_$][\w$]*)/g, 'property', 1], [/(?:^|[^\w$.])(0[xX][\da-fA-F_]*|(?:\d[\d_]*(?:\.\d[\d_]*)?|\.\d[\d_]*)(?:[eE][+-]?\d[\d_]*)?)(?![\w$]|\.\d)/g, 'number', 1], [/\?\?=?|\?\.\.?|\.\.\.?\??|=>|~\/=?|<<=?|>>>?=?|&&|\|\||\+\+|--|[+\-*/%&|^!<>=]=?|[~?:]/g, 'operator'], ]; export const dart = defineLanguage({ name: 'dart', tokenize(code) { const ranges = []; const lexical = /\/\/.*|\/\*|(?:(?<![\w$])r)?['"]/g; let match; while ((match = lexical.exec(code))) { const comment = match[0][0] === '/'; let end = lexical.lastIndex; if (match[0] === '/*') { end = blockCommentEnd(code, end); } else if (!comment) end = stringEnd(code, end - 1, match[0][0] === 'r'); ranges.push({ start: match.index, end, className: comment ? 'comment' : 'string' }); lexical.lastIndex = end; } return collectPatternRanges(code, patterns, ranges); }, }); // Open quotes and `${` brace depths live on an explicit stack so deep nesting cannot overflow. // Raw strings cannot hold holes, so `raw` only ever describes the innermost open string. function stringEnd(code, index, raw) { const stack = []; let open = true; while (index < code.length) { const char = code[index]; if (open) { const quote = code.startsWith(char.repeat(3), index) ? char.repeat(3) : char; stack.push(quote); index += quote.length; open = false; continue; } const top = stack[stack.length - 1]; if (top === undefined) break; if (typeof top === 'number') { if (char === '"' || char === "'") { open = true; raw = code[index - 1] === 'r'; continue; } if (char === '}' && !top) stack.pop(); else if (char === '{' || char === '}') stack[stack.length - 1] = top + (char === '{' ? 1 : -1); index++; } else if (code.startsWith(top, index) || (char === '\n' && top.length < 3)) { if (char !== '\n') index += top.length; stack.pop(); raw = false; } else if (raw) index++; else if (char === '\\') index += 2; else if (char === '$' && code[index + 1] === '{') { stack.push(0); index += 2; } else index++; } return Math.min(index, code.length); }