export interface LocalizationState { id: string name: string selector: { v: string; x: string } sizes: number[] fixture: string group: string } export interface LocalizationGroup { label: string states: LocalizationState[] } export interface LocalizationScreen { board: string groups: LocalizationGroup[] } const BOARD_LINE = /^Board:\s*([^.]+?)\./m const GROUP_HEADING = /^## (L\d+[a-z]*) (.+)$/ const STATE_ROW = /^\| (loc\.[A-Za-z0-9.]+) \| / const SELECTOR = /LocaleFrame\{s:\{v:"([^"]+)",x:"([^"]*)"\}\}/ export function parseSizes(cell: string) { return cell .split(',') .map((part) => Number.parseInt(part.trim(), 10)) .filter((width) => Number.isFinite(width)) } export function parseSelector(cell: string) { const match = SELECTOR.exec(cell) if (!match) { throw new Error(`Not a LocaleFrame selector: ${cell}`) } return { v: match[1]!, x: match[2]! } } export function parseLocalizationScreen(markdown: string): LocalizationScreen { const board = BOARD_LINE.exec(markdown) if (!board) { throw new Error('The localization screen file has no "Board:" reference line') } const groups: LocalizationGroup[] = [] for (const line of markdown.split('\n')) { const heading = GROUP_HEADING.exec(line) if (heading) { groups.push({ label: `${heading[1]} ${heading[2]}`, states: [] }) continue } const group = groups[groups.length - 1] if (!group || !STATE_ROW.test(line)) { continue } const cells = line .split('|') .slice(1, -1) .map((cell) => cell.trim()) const [id, name, , selector, sizes, fixture] = cells group.states.push({ id: id!, name: name!, selector: parseSelector(selector!), sizes: parseSizes(sizes!), fixture: fixture!, group: group.label, }) } return { board: `${board[1]}.dc.html`, groups: groups.filter((group) => group.states.length) } } export function localizationSizeLabel(width: number) { return width === 1440 ? 'desktop' : width === 1024 ? 'tablet' : 'mobile' }