@drghaliasri/butex 5.6.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/document2-cli/main.ts","../src/document2-cli/httpServer.ts","../src/document2/ids.ts","../src/document2/articleMeta.ts","../src/document2/citations.ts","../src/ast/commands/index.ts","../src/ast/arabic_ast.ts","../src/document/mathObject.ts","../src/document2/labels.ts","../src/document2/inlineScanner.ts","../src/document2/importJson.ts","../src/editor/atomicCommandsOperators.ts","../src/editor/characterFonts.ts","../src/editor/display/delimiter.ts","../src/editor/display/frac.ts","../src/editor/display/sqrt.ts","../src/editor/display/overset.ts","../src/editor/display/underset.ts","../src/editor/display/accent.ts","../src/editor/display/env.ts","../src/diwani-font.ts","../src/editor/display/atomicCommand.ts","../src/editor/display/atomicCommandsOperators.ts","../src/editor/styles.ts","../src/document/normalizeCharImport.ts","../src/document/mathEditorAdapter.ts","../src/document2/commands.ts","../src/document2/exportJson.ts","../src/document2/jsonCommands.ts","../src/document2/outline.ts","../src/document2-cli/protocol.ts","../src/document2-cli/execute.ts","../src/document2-cli/stdinTransport.ts"],"sourcesContent":["import { once } from 'node:events';\nimport type { Server } from 'node:http';\nimport { createDocument2HttpServer } from './httpServer.js';\nimport { runDocument2Stdin } from './stdinTransport.js';\n\ntype CliOptions = {\n serve: boolean;\n host: string;\n help: boolean;\n};\n\nfunction parseArgs(args: string[]): CliOptions {\n const options: CliOptions = { serve: false, host: '127.0.0.1', help: false };\n for (let index = 0; index < args.length; index += 1) {\n const arg = args[index];\n if (arg === '--serve') {\n options.serve = true;\n } else if (arg === '--host') {\n const host = args[index + 1];\n if (!host) {\n throw new Error('--host requires a value');\n }\n options.host = host;\n index += 1;\n } else if (arg === '--help' || arg === '-h') {\n options.help = true;\n } else {\n throw new Error(`Unknown argument: ${String(arg)}`);\n }\n }\n return options;\n}\n\nfunction usage(): string {\n return [\n 'Usage:',\n ' butex-document2 Read one JSON request from stdin',\n ' butex-document2 --serve [--host] Run the stateless HTTP worker',\n '',\n 'HTTP mode requires BUTEX_WORKER_TOKEN and honors Railway PORT.',\n '',\n ].join('\\n');\n}\n\nfunction portFromEnvironment(): number {\n const value = process.env.PORT ?? '3000';\n const port = Number(value);\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw new Error('PORT must be an integer between 1 and 65535');\n }\n return port;\n}\n\nasync function listen(server: Server, port: number, host: string): Promise<void> {\n server.listen(port, host);\n await once(server, 'listening');\n}\n\nfunction installShutdownHandlers(server: Server): void {\n let closing = false;\n const close = () => {\n if (closing) {\n return;\n }\n closing = true;\n server.close((error) => {\n if (error) {\n console.error(error);\n process.exitCode = 1;\n }\n });\n };\n process.once('SIGTERM', close);\n process.once('SIGINT', close);\n}\n\nasync function main(): Promise<number> {\n const options = parseArgs(process.argv.slice(2));\n if (options.help) {\n process.stdout.write(usage());\n return 0;\n }\n if (!options.serve) {\n return runDocument2Stdin(process.stdin, process.stdout, process.stderr);\n }\n\n const token = process.env.BUTEX_WORKER_TOKEN ?? '';\n const port = portFromEnvironment();\n const server = createDocument2HttpServer({ token });\n installShutdownHandlers(server);\n await listen(server, port, options.host);\n console.error(JSON.stringify({ service: 'butex-document2', status: 'listening', host: options.host, port }));\n return 0;\n}\n\nmain()\n .then((exitCode) => {\n process.exitCode = exitCode;\n })\n .catch((error: unknown) => {\n const detail = error instanceof Error ? error.stack ?? error.message : String(error);\n process.stderr.write(`${detail}\\n`);\n process.exitCode = 1;\n });\n","import { timingSafeEqual } from 'node:crypto';\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http';\nimport { executeDocument2WorkerRequest } from './execute.js';\nimport {\n Document2WorkerProtocolError,\n workerFailure,\n} from './protocol.js';\nimport type { Document2WorkerResponse } from './protocol.js';\nimport { DOCUMENT2_WORKER_MAX_BODY_BYTES } from './stdinTransport.js';\n\nexport const DOCUMENT2_WORKER_REQUEST_TIMEOUT_MS = 15_000;\n\nexport type Document2WorkerLogEntry = {\n requestId: string;\n operation: string;\n status: number;\n durationMs: number;\n unexpected?: unknown;\n};\n\nexport type Document2HttpServerOptions = {\n token: string;\n maxBodyBytes?: number;\n logger?: (entry: Document2WorkerLogEntry) => void;\n};\n\nfunction sendJson(response: ServerResponse, status: number, body: Document2WorkerResponse | Record<string, unknown>): void {\n const json = JSON.stringify(body);\n response.writeHead(status, {\n 'content-type': 'application/json; charset=utf-8',\n 'content-length': Buffer.byteLength(json),\n 'cache-control': 'no-store',\n });\n response.end(json);\n}\n\nfunction bearerToken(request: IncomingMessage): string {\n const header = request.headers.authorization;\n if (typeof header !== 'string' || !header.startsWith('Bearer ')) {\n return '';\n }\n return header.slice('Bearer '.length);\n}\n\nfunction tokenMatches(expected: string, received: string): boolean {\n const expectedBuffer = Buffer.from(expected);\n const receivedBuffer = Buffer.from(received);\n return expectedBuffer.length === receivedBuffer.length && timingSafeEqual(expectedBuffer, receivedBuffer);\n}\n\nasync function readJsonBody(request: IncomingMessage, maxBodyBytes: number): Promise<unknown> {\n const chunks: Buffer[] = [];\n let size = 0;\n for await (const chunk of request) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));\n size += buffer.length;\n if (size > maxBodyBytes) {\n throw new Document2WorkerProtocolError('payload_too_large', 'Worker request exceeds the 5 MiB limit');\n }\n chunks.push(buffer);\n }\n try {\n return JSON.parse(Buffer.concat(chunks).toString('utf8')) as unknown;\n } catch {\n throw new Document2WorkerProtocolError('invalid_json', 'Request body must be valid JSON');\n }\n}\n\nfunction requestId(request: IncomingMessage): string {\n const value = request.headers['x-request-id'];\n return typeof value === 'string' ? value.slice(0, 200) : '-';\n}\n\nfunction actionForPath(pathname: string): 'normalize' | 'outline' | 'apply_command' | null {\n if (pathname === '/v1/document2/normalize') {\n return 'normalize';\n }\n if (pathname === '/v1/document2/outline') {\n return 'outline';\n }\n if (pathname === '/v1/document2/commands') {\n return 'apply_command';\n }\n return null;\n}\n\nfunction defaultLogger(entry: Document2WorkerLogEntry): void {\n const unexpected = entry.unexpected instanceof Error\n ? { name: entry.unexpected.name, message: entry.unexpected.message, stack: entry.unexpected.stack }\n : entry.unexpected;\n console.error(JSON.stringify({\n request_id: entry.requestId,\n operation: entry.operation,\n status: entry.status,\n duration_ms: entry.durationMs,\n ...(unexpected !== undefined ? { unexpected } : {}),\n }));\n}\n\nexport function createDocument2HttpServer(options: Document2HttpServerOptions): Server {\n if (options.token.length === 0) {\n throw new Error('Document worker HTTP mode requires BUTEX_WORKER_TOKEN');\n }\n const maxBodyBytes = options.maxBodyBytes ?? DOCUMENT2_WORKER_MAX_BODY_BYTES;\n const logger = options.logger ?? defaultLogger;\n\n const server = createServer(async (request, response) => {\n const startedAt = Date.now();\n const pathname = new URL(request.url ?? '/', 'http://worker.local').pathname;\n const operation = `${request.method ?? 'UNKNOWN'} ${pathname}`;\n let status: number | undefined;\n let unexpected: unknown;\n\n try {\n if (request.method === 'GET' && pathname === '/health') {\n status = 200;\n sendJson(response, status, { ok: true, service: 'butex-document2' });\n return;\n }\n\n const action = request.method === 'POST' ? actionForPath(pathname) : null;\n if (!action) {\n throw new Document2WorkerProtocolError('not_found', 'Worker endpoint was not found');\n }\n if (!tokenMatches(options.token, bearerToken(request))) {\n throw new Document2WorkerProtocolError('unauthorized', 'Worker service token is invalid');\n }\n\n const body = await readJsonBody(request, maxBodyBytes);\n if (typeof body !== 'object' || body === null || Array.isArray(body)) {\n throw new Document2WorkerProtocolError('invalid_request', 'Request body must be an object');\n }\n const responseBody = executeDocument2WorkerRequest({ ...body, action });\n status = 200;\n sendJson(response, status, responseBody);\n } catch (error) {\n const failure = workerFailure(error);\n status = failure.status;\n unexpected = failure.unexpected;\n if (!response.headersSent) {\n sendJson(response, status, failure.response);\n } else {\n response.destroy();\n }\n } finally {\n logger({\n requestId: requestId(request),\n operation,\n status: status ?? 500,\n durationMs: Date.now() - startedAt,\n ...(unexpected !== undefined ? { unexpected } : {}),\n });\n }\n });\n\n server.requestTimeout = DOCUMENT2_WORKER_REQUEST_TIMEOUT_MS;\n server.headersTimeout = DOCUMENT2_WORKER_REQUEST_TIMEOUT_MS;\n server.keepAliveTimeout = 5_000;\n return server;\n}\n","let nextId = 1;\nconst instanceId = `${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n\nexport function document2Id(prefix: string): string {\n const id = `${prefix}_${instanceId}_${String(nextId)}`;\n nextId += 1;\n return id;\n}\n","import { formatDigits } from '../editor/digits.js';\nimport type { DigitFormId } from '../editor/types.js';\nimport type { ButexUiLocale } from '../uiLocale.js';\nimport type { Document2HijriDate, Document2Meta, HijriMonthId } from './types.js';\n\nexport const BUTEX_BASMALA_LINE1 = 'بِسْمِ ٱللَّٰهِ ٱلرَّحْمَٰنِ ٱلرَّحِيمِ';\n\nexport const BUTEX_BASMALA_LINE2 = 'وَٱلصَّلَاةُ وَٱلسَّلَامُ عَلَىٰ رَسُولِ ٱللَّٰهِ';\n\nexport const BUTEX_BASMALA_SALAWAT = 'صَلَّى ٱللَّهُ عَلَيْهِ وَسَلَّمَ';\n\n/** Three-line basmala joined for UI / plain-text matchers. */\nexport const BUTEX_BASMALA = `${BUTEX_BASMALA_LINE1}\\n${BUTEX_BASMALA_LINE2}\\n${BUTEX_BASMALA_SALAWAT}`;\n\nexport const BUTEX_CLOSING_HAMDALA = 'الْحَمْدُ لِلَّهِ نَفَعَنَا بِعِلْمِهِ';\n\nfunction escapeButexTextArg(text: string): string {\n return text.replace(/\\\\/g, '\\\\textbackslash{}').replace(/[{}]/g, '\\\\$&');\n}\n\nfunction butexFontDisplayTex(macro: '\\\\butexdiwani' | '\\\\butexmaghribi', text: string): string {\n return `${macro}{${escapeButexTextArg(text)}}`;\n}\n\n/** Display-math body using BuTeX Diwani (for MathJax preview islands). */\nexport function butexDiwaniDisplayTex(text: string): string {\n return butexFontDisplayTex('\\\\butexdiwani', text);\n}\n\n/** Full display equation for XeLaTeX export. */\nexport function butexDiwaniDisplayLatex(text: string): string {\n return `\\\\[\\n${butexDiwaniDisplayTex(text)}\\n\\\\]`;\n}\n\n/** Display-math body using BuTeX Maghribi (for document chrome). */\nexport function butexMaghribiDisplayTex(text: string): string {\n return butexFontDisplayTex('\\\\butexmaghribi', text);\n}\n\n/** Full display equation using BuTeX Maghribi for XeLaTeX export. */\nexport function butexMaghribiDisplayLatex(text: string): string {\n return `\\\\[\\n${butexMaghribiDisplayTex(text)}\\n\\\\]`;\n}\n\nconst BASMALA_LINES = [BUTEX_BASMALA_LINE1, BUTEX_BASMALA_LINE2, BUTEX_BASMALA_SALAWAT] as const;\n\n/** Three-line Maghribi body for MathJax basmala islands. */\nexport function butexBasmalaDisplayTex(): string {\n return BASMALA_LINES.map((line) => butexMaghribiDisplayTex(line)).join(' \\\\\\\\ ');\n}\n\n/** Standalone display equation when there is no \\\\maketitle (title-less docs). */\nexport function butexBasmalaDisplayLatex(): string {\n return `\\\\[\\n\\\\begin{gathered}\\n${BASMALA_LINES.map((line) => butexMaghribiDisplayTex(line)).join(' \\\\\\\\\\n')}\\n\\\\end{gathered}\\n\\\\]`;\n}\n\n/**\n * Keep \\\\maketitle inside the current column when twocolumn is on.\n * Standard article otherwise does \\\\twocolumn[\\\\@maketitle] and spans both columns.\n * Call after titling so \\\\@maketitle still includes \\\\pretitle hooks.\n */\nexport function butexInColumnMaketitleHook(): string {\n return String.raw`\\makeatletter\n\\renewcommand{\\maketitle}{%\n \\par\n \\begingroup\n \\renewcommand\\thefootnote{\\@fnsymbol\\c@footnote}%\n \\def\\@makefnmark{\\rlap{\\@textsuperscript{\\normalfont\\@thefnmark}}}%\n \\long\\def\\@makefntext##1{\\parindent 1em\\noindent\n \\hb@xt@1.8em{\\hss\\@textsuperscript{\\normalfont\\@thefnmark}}##1}%\n \\@maketitle\n \\thispagestyle{plain}\\@thanks\n \\endgroup\n \\setcounter{footnote}{0}%\n \\global\\let\\thanks\\relax\n \\global\\let\\maketitle\\relax\n \\global\\let\\@maketitle\\relax\n \\global\\let\\@thanks\\@empty\n \\global\\let\\@author\\@empty\n \\global\\let\\@date\\@empty\n \\global\\let\\@title\\@empty\n \\global\\let\\title\\relax\n \\global\\let\\author\\relax\n \\global\\let\\date\\relax\n \\global\\let\\and\\relax\n}\n\\makeatother`;\n}\n\n/** Titling hooks so the basmala stays attached to the visible title. */\nexport function butexBasmalaTitlingPreamble(options: { twocolumn?: boolean } = {}): string {\n const lines = [\n '\\\\usepackage{titling}',\n '\\\\pretitle{%',\n ' \\\\begin{center}',\n ...BASMALA_LINES.map((line, index) => {\n const suffix = index < BASMALA_LINES.length - 1 ? '\\\\\\\\' : '';\n return ` ${butexMaghribiDisplayTex(line)}${suffix}`;\n }),\n ' \\\\par\\\\vspace{1.5em}',\n ' \\\\LARGE',\n '}',\n '\\\\posttitle{\\\\par\\\\end{center}}',\n ];\n if (options.twocolumn) {\n lines.push(butexInColumnMaketitleHook());\n }\n return lines.join('\\n');\n}\nexport const HIJRI_YEAR_MIN = 1400;\nexport const HIJRI_YEAR_MAX = 1500;\n\nexport const HIJRI_MONTH_IDS: HijriMonthId[] = [\n 'محرم',\n 'صفر',\n 'ربيع الأول',\n 'ربيع الآخر',\n 'جمادى الأولى',\n 'جمادى الآخرة',\n 'رجب',\n 'شعبان',\n 'رمضان',\n 'شوال',\n 'ذو القعدة',\n 'ذو الحجة',\n];\n\nconst HIJRI_MONTH_LABELS_EN: Record<HijriMonthId, string> = {\n محرم: 'Muharram',\n صفر: 'Safar',\n 'ربيع الأول': 'Rabiʻ I',\n 'ربيع الآخر': 'Rabiʻ II',\n 'جمادى الأولى': 'Jumada I',\n 'جمادى الآخرة': 'Jumada II',\n رجب: 'Rajab',\n شعبان: 'Shaʻban',\n رمضان: 'Ramadan',\n شوال: 'Shawwal',\n 'ذو القعدة': 'Dhul Qaʻdah',\n 'ذو الحجة': 'Dhul Hijjah',\n};\n\n/** Legacy Latin month ids from earlier drafts — accepted on import only. */\nconst LEGACY_LATIN_MONTH: Record<string, HijriMonthId> = {\n muharram: 'محرم',\n safar: 'صفر',\n rabiAwwal: 'ربيع الأول',\n rabiThani: 'ربيع الآخر',\n jumadaAwwal: 'جمادى الأولى',\n jumadaThani: 'جمادى الآخرة',\n rajab: 'رجب',\n shaban: 'شعبان',\n ramadan: 'رمضان',\n shawwal: 'شوال',\n dhulQadah: 'ذو القعدة',\n dhulHijjah: 'ذو الحجة',\n};\n\nexport const DEFAULT_HIJRI_DATE: Document2HijriDate = {\n day: 1,\n month: 'محرم',\n year: 1448,\n};\n\nexport function hijriMonthLabel(month: HijriMonthId, locale: ButexUiLocale = 'ar'): string {\n return locale === 'en' ? HIJRI_MONTH_LABELS_EN[month] : month;\n}\n\nexport function emptyDocument2Meta(): Document2Meta {\n return {\n title: '',\n authors: '',\n date: { ...DEFAULT_HIJRI_DATE },\n abstract: '',\n };\n}\n\nfunction clampInt(value: number, min: number, max: number): number {\n if (!Number.isFinite(value)) {\n return min;\n }\n return Math.min(max, Math.max(min, Math.trunc(value)));\n}\n\nfunction isHijriMonthId(value: unknown): value is HijriMonthId {\n return typeof value === 'string' && (HIJRI_MONTH_IDS as string[]).includes(value);\n}\n\nfunction resolveHijriMonthId(value: unknown): HijriMonthId {\n if (isHijriMonthId(value)) {\n return value;\n }\n if (typeof value === 'string' && value in LEGACY_LATIN_MONTH) {\n return LEGACY_LATIN_MONTH[value]!;\n }\n return DEFAULT_HIJRI_DATE.month;\n}\n\nexport function normalizeDocument2HijriDate(value: unknown): Document2HijriDate {\n if (typeof value !== 'object' || value === null) {\n return { ...DEFAULT_HIJRI_DATE };\n }\n const raw = value as Record<string, unknown>;\n const day = clampInt(typeof raw.day === 'number' ? raw.day : Number(raw.day), 1, 30);\n const year = clampInt(typeof raw.year === 'number' ? raw.year : Number(raw.year), HIJRI_YEAR_MIN, HIJRI_YEAR_MAX);\n const month = resolveHijriMonthId(raw.month);\n return { day, month, year };\n}\n\nexport function normalizeDocument2Meta(value: unknown): Document2Meta {\n if (typeof value !== 'object' || value === null) {\n return emptyDocument2Meta();\n }\n const raw = value as Record<string, unknown>;\n return {\n title: typeof raw.title === 'string' ? raw.title : '',\n authors: typeof raw.authors === 'string' ? raw.authors : '',\n date: normalizeDocument2HijriDate(raw.date),\n abstract: typeof raw.abstract === 'string' ? raw.abstract : '',\n };\n}\n\nexport type Document2MetaProp = Partial<Omit<Document2Meta, 'date'>> & {\n date?: Partial<Document2HijriDate>;\n};\n\n/** Prop fills gaps; JSON wins only when the key is present on the JSON object. */\nexport function mergeDocument2Meta(fromJson: unknown, fromProp?: Document2MetaProp): Document2Meta {\n const fromPropMeta: Document2Meta = {\n title: typeof fromProp?.title === 'string' ? fromProp.title : '',\n authors: typeof fromProp?.authors === 'string' ? fromProp.authors : '',\n abstract: typeof fromProp?.abstract === 'string' ? fromProp.abstract : '',\n date: fromProp?.date\n ? normalizeDocument2HijriDate({ ...DEFAULT_HIJRI_DATE, ...fromProp.date })\n : { ...DEFAULT_HIJRI_DATE },\n };\n if (typeof fromJson !== 'object' || fromJson === null) {\n return fromPropMeta;\n }\n const json = fromJson as Record<string, unknown>;\n return {\n title: 'title' in json && typeof json.title === 'string' ? json.title : fromPropMeta.title,\n authors: 'authors' in json && typeof json.authors === 'string' ? json.authors : fromPropMeta.authors,\n abstract: 'abstract' in json && typeof json.abstract === 'string' ? json.abstract : fromPropMeta.abstract,\n date: 'date' in json ? normalizeDocument2HijriDate(json.date) : fromPropMeta.date,\n };\n}\n\n/** For live Document2Node meta: prop fills empty title/authors/abstract; date patch merges. */\nexport function fillDocument2MetaGaps(current: Document2Meta, fromProp?: Document2MetaProp): Document2Meta {\n if (!fromProp) {\n return cloneDocument2Meta(current);\n }\n return {\n title: current.title.trim().length > 0 ? current.title : typeof fromProp.title === 'string' ? fromProp.title : current.title,\n authors:\n current.authors.trim().length > 0\n ? current.authors\n : typeof fromProp.authors === 'string'\n ? fromProp.authors\n : current.authors,\n abstract:\n current.abstract.trim().length > 0\n ? current.abstract\n : typeof fromProp.abstract === 'string'\n ? fromProp.abstract\n : current.abstract,\n date: fromProp.date\n ? normalizeDocument2HijriDate({ ...current.date, ...fromProp.date })\n : { ...current.date },\n };\n}\n\nexport function document2HasMaketitle(meta: Document2Meta): boolean {\n return meta.title.trim().length > 0 || meta.authors.trim().length > 0;\n}\n\nexport function document2HasAbstract(meta: Document2Meta): boolean {\n return meta.abstract.trim().length > 0;\n}\n\nexport function document2HasTitleStack(meta: Document2Meta): boolean {\n return document2HasMaketitle(meta) || document2HasAbstract(meta);\n}\n\nexport type FormatHijriDateOptions = {\n locale?: ButexUiLocale;\n digitForm?: DigitFormId;\n};\n\nexport function formatHijriDate(date: Document2HijriDate, options: FormatHijriDateOptions | ButexUiLocale = 'ar'): string {\n const opts: FormatHijriDateOptions = typeof options === 'string' ? { locale: options } : options;\n const locale = opts.locale ?? 'ar';\n const digitForm: DigitFormId =\n opts.digitForm ?? (locale === 'en' ? 'western' : 'arabicIndic');\n const month = hijriMonthLabel(date.month, locale);\n const day = formatDigits(String(date.day), digitForm);\n const year = formatDigits(String(date.year), digitForm);\n if (locale === 'en') {\n return `${day} ${month} ${year} AH`;\n }\n return `${day} ${month} ${year}هـ`;\n}\n\nexport function cloneDocument2Meta(meta: Document2Meta): Document2Meta {\n return {\n title: meta.title,\n authors: meta.authors,\n date: { ...meta.date },\n abstract: meta.abstract,\n };\n}\n","import { formatDigits } from '../editor/digits.js';\nimport type { DigitFormId } from '../editor/types.js';\nimport type { FormatCiteLabelOptions, Reference2, Reference2Json, ReferenceFieldSeparator } from './types.js';\nimport { document2Id } from './ids.js';\n\nexport const DEFAULT_REFERENCE_FIELD_SEPARATOR: ReferenceFieldSeparator = '،';\n\nexport function normalizeReferenceFieldSeparator(value: unknown): ReferenceFieldSeparator {\n return value === ',' ? ',' : DEFAULT_REFERENCE_FIELD_SEPARATOR;\n}\n\nexport function referenceNumberMap(references: Array<Pick<Reference2, 'key'>>): Map<string, number> {\n const map = new Map<string, number>();\n references.forEach((reference, index) => {\n if (!map.has(reference.key)) {\n map.set(reference.key, index + 1);\n }\n });\n return map;\n}\n\nexport function resolveCiteNumbers(keys: string[], references: Array<Pick<Reference2, 'key'>>): Array<number | null> {\n const map = referenceNumberMap(references);\n return keys.map((key) => map.get(key) ?? null);\n}\n\nexport function formatCiteLabel(\n keys: string[],\n references: Array<Pick<Reference2, 'key'>>,\n options: FormatCiteLabelOptions = {},\n): string {\n const documentDirection = options.documentDirection ?? 'rtl';\n const digitForm: DigitFormId = options.digitForm ?? (documentDirection === 'rtl' ? 'arabicIndic' : 'western');\n const numbers = resolveCiteNumbers(keys, references).map((value) => (value === null ? '?' : String(value)));\n const display = documentDirection === 'rtl' ? [...numbers].reverse() : numbers;\n const separator = documentDirection === 'rtl' ? '،' : ', ';\n const body = display.map((part) => formatDigits(part, digitForm)).join(separator);\n return `[${body}]`;\n}\n\nexport function formatBibliographyNumber(index: number, options: FormatCiteLabelOptions = {}): string {\n const documentDirection = options.documentDirection ?? 'rtl';\n const digitForm: DigitFormId = options.digitForm ?? (documentDirection === 'rtl' ? 'arabicIndic' : 'western');\n return formatDigits(String(index), digitForm);\n}\n\nexport function parseCiteKeys(source: string): string[] {\n const match = /^\\\\cite\\{([^}]*)\\}$/.exec(source.trim());\n if (!match) {\n return [];\n }\n return (match[1] ?? '')\n .split(',')\n .map((key) => key.trim())\n .filter((key) => key.length > 0);\n}\n\nexport function citeTokenLatex(keys: string[]): string {\n return `\\\\cite{${keys.join(',')}}`;\n}\n\nexport function referenceFromJson(json: Reference2Json): Reference2 {\n return {\n id: document2Id('ref'),\n key: json.key,\n authors: typeof json.authors === 'string' ? json.authors : '',\n title: typeof json.title === 'string' ? json.title : '',\n year: typeof json.year === 'string' ? json.year : '',\n url: typeof json.url === 'string' ? json.url : '',\n venue: typeof json.venue === 'string' ? json.venue : '',\n fieldSeparator: normalizeReferenceFieldSeparator(json.field_separator),\n };\n}\n\nexport function createEmptyReference2(partial: Partial<Reference2Json> = {}): Reference2 {\n return referenceFromJson({\n key: partial.key ?? `ref${String(Date.now()).slice(-4)}`,\n authors: partial.authors,\n title: partial.title,\n year: partial.year,\n url: partial.url,\n venue: partial.venue,\n field_separator: partial.field_separator,\n });\n}\n\n/** Joined authors/title/venue/year for preview and export (no \\\\bibitem wrapper). */\nexport function bibliographyEntryBody(\n reference: Pick<Reference2, 'authors' | 'title' | 'venue' | 'year' | 'fieldSeparator'>,\n separator: ReferenceFieldSeparator = reference.fieldSeparator,\n options: { digitForm?: DigitFormId } = {},\n): string {\n const year =\n options.digitForm !== undefined ? formatDigits(reference.year, options.digitForm) : reference.year;\n const parts = [reference.authors, reference.title, reference.venue, year].filter((part) => part.trim().length > 0);\n return parts.join(`${separator} `);\n}\n\nexport function bibliographyEntryLatex(reference: Reference2): string {\n const body = bibliographyEntryBody(reference);\n const url = reference.url.trim().length > 0 ? ` \\\\url{${reference.url}}` : '';\n return `\\\\bibitem{${reference.key}} ${body}${url}`.trim();\n}\n\n/**\n * Build an href for a bibliography URL. Values without a scheme become https://…\n * so the browser does not resolve them against the editor origin (e.g. localhost).\n * Leaves http(s)/mailto/ftp and other schemed URLs unchanged. Empty → ''.\n */\nexport function absoluteHttpHref(url: string): string {\n const trimmed = url.trim();\n if (trimmed.length === 0) {\n return '';\n }\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) {\n return trimmed;\n }\n if (trimmed.startsWith('//')) {\n return `https:${trimmed}`;\n }\n return `https://${trimmed}`;\n}\n","import type { ChainNode } from '../arabic_ast.js';\n\ntype CommandRenderContext = {\n name: string;\n optionalArgs: ChainNode[];\n mandatoryArgs: ChainNode[];\n renderChain: (chain: ChainNode) => string;\n};\n\nexport function renderCommandCore(context: CommandRenderContext): string {\n const optional = context.optionalArgs.map((arg) => `[${context.renderChain(arg)}]`).join('');\n const mandatory = context.mandatoryArgs.map((arg) => `{${context.renderChain(arg)}}`).join('');\n return context.name + optional + mandatory;\n}\n","import { renderCommandCore } from './commands/index.js';\n\nexport type ArabicNodeJson = {\n node_type: string;\n expr?: string;\n name?: string;\n superscript?: ChainJson | null;\n subscript?: ChainJson | null;\n left_delim_expr?: string;\n right_delim_expr?: string;\n inner_expr?: ChainJson;\n optional_args?: ChainJson[];\n mandatory_args?: ChainJson[];\n opening?: string;\n closing?: string;\n lines?: ChainJson[];\n};\n\nexport type ChainJson = {\n node_type: 'ChainClass';\n chain: ArabicNodeJson[];\n};\n\nexport class State {\n // Empty for now, like the Python State placeholder used by BaseNode.\n}\n\nexport class BaseAstNode {\n state: State;\n superscript: ChainNode | null;\n subscript: ChainNode | null;\n nodeType: string;\n\n constructor(state: State | null = null) {\n if (state === null) {\n state = new State();\n }\n\n this.state = state;\n this.superscript = null;\n this.subscript = null;\n this.nodeType = this.constructor.name;\n }\n\n latex(): string {\n throw new Error('NotImplementedError');\n }\n\n arabicLatex(): string {\n throw new Error('NotImplementedError');\n }\n\n toArabicLatex(): string {\n return this.arabicLatex();\n }\n\n /** Latin-style scripts: `^{...}` and `_{...}` for english_json rendering. */\n latexScripts(): string {\n let s = '';\n\n if (this.superscript !== null) {\n s += '^{' + this.superscript.latex() + '}';\n }\n\n if (this.subscript !== null) {\n s += '_{' + this.subscript.latex() + '}';\n }\n\n return s;\n }\n\n /**\n * Arabic scripts use \\\\prescript{sup}{sub}{content} (matches reference Python output).\n * Call with rendered strings for sup/sub chains (may be empty strings).\n */\n arabicLatexScripts(sup: string, sub: string, content: string): string {\n if (sup !== '' || sub !== '') {\n return '\\\\prescript{' + sup + '}{' + sub + '}{' + content + '}';\n }\n return content;\n }\n}\n\nexport class ChainNode {\n chain: BaseAstNode[];\n\n constructor(chain: BaseAstNode[] = []) {\n this.chain = chain;\n }\n\n latex(): string {\n return this.chain.map((node) => node.latex()).join(' ');\n }\n toEnglishLatex(): string {\n return this.chain.map((node) => node.latex()).join(' ');\n }\n /** RTL: reverse order relative to Latin chain (see test/ref_tests.txt). */\n arabicLatex(): string {\n const reversed = this.chain.slice().reverse();\n return reversed.map((node) => node.arabicLatex()).join(' ');\n }\n\n toArabicLatex(): string {\n return this.arabicLatex();\n }\n}\n\nexport class NumberNode extends BaseAstNode {\n expr: string;\n\n constructor(expr: string, state: State | null = null) {\n super(state);\n this.nodeType = 'NumberObject';\n this.expr = expr;\n }\n\n latex(): string {\n return this.expr + this.latexScripts();\n }\n\n arabicLatex(): string {\n const sup = this.superscript !== null ? this.superscript.arabicLatex() : '';\n const sub = this.subscript !== null ? this.subscript.arabicLatex() : '';\n return this.arabicLatexScripts(sup, sub, this.expr);\n }\n}\n\nexport class CharNode extends BaseAstNode {\n expr: string;\n\n constructor(expr: string, state: State | null = null) {\n super(state);\n this.nodeType = 'CharObject';\n this.expr = expr;\n }\n\n latex(): string {\n return this.expr + this.latexScripts();\n }\n\n arabicLatex(): string {\n const sup = this.superscript !== null ? this.superscript.arabicLatex() : '';\n const sub = this.subscript !== null ? this.subscript.arabicLatex() : '';\n return this.arabicLatexScripts(sup, sub, this.expr);\n }\n}\n\n/**\n * Operator leaf: value comes from JSON as-is (English or Arabic side already chosen by the service).\n * Scripts are not appended (Python parity).\n */\nexport class OperatorNode extends BaseAstNode {\n expr: string;\n\n constructor(expr: string, state: State | null = null) {\n super(state);\n this.nodeType = 'OperatorObject';\n this.expr = expr;\n }\n\n latex(): string {\n return this.expr;\n }\n\n arabicLatex(): string {\n return this.expr;\n }\n}\n\nexport class DelimiterNode extends BaseAstNode {\n leftDelimExpr: string;\n innerExpr: ChainNode;\n rightDelimExpr: string;\n\n constructor(leftDelimExpr: string, innerExpr: ChainNode, rightDelimExpr: string, state: State | null = null) {\n super(state);\n this.nodeType = 'DelimiterObject';\n this.leftDelimExpr = leftDelimExpr;\n this.innerExpr = innerExpr;\n this.rightDelimExpr = rightDelimExpr;\n }\n\n latex(): string {\n return this.leftDelimExpr + this.innerExpr.latex() + this.rightDelimExpr + this.latexScripts();\n }\n\n arabicLatex(): string {\n const sup = this.superscript !== null ? this.superscript.arabicLatex() : '';\n const sub = this.subscript !== null ? this.subscript.arabicLatex() : '';\n const content = this.leftDelimExpr + this.innerExpr.arabicLatex() + this.rightDelimExpr;\n return this.arabicLatexScripts(sup, sub, content);\n }\n}\n\nexport class CommandNode extends BaseAstNode {\n name: string;\n optionalArgs: ChainNode[];\n mandatoryArgs: ChainNode[];\n\n constructor(\n name: string,\n optionalArgs: ChainNode[] = [],\n mandatoryArgs: ChainNode[] = [],\n state: State | null = null\n ) {\n super(state);\n this.nodeType = 'CommandObject';\n this.name = name;\n this.optionalArgs = optionalArgs;\n this.mandatoryArgs = mandatoryArgs;\n }\n\n latex(): string {\n const content = renderCommandCore({\n name: this.name,\n optionalArgs: this.optionalArgs,\n mandatoryArgs: this.mandatoryArgs,\n renderChain: (chain) => chain.latex(),\n });\n return content + this.latexScripts();\n }\n\n arabicLatex(): string {\n const sup = this.superscript !== null ? this.superscript.arabicLatex() : '';\n const sub = this.subscript !== null ? this.subscript.arabicLatex() : '';\n const arabicName =\n this.name === '\\\\sqrt' || this.name === '\\\\arabsqrt' ? '\\\\arsqrt' : this.name;\n const content = renderCommandCore({\n name: arabicName,\n optionalArgs: this.optionalArgs,\n mandatoryArgs: this.mandatoryArgs,\n renderChain: (chain) => chain.arabicLatex(),\n });\n return this.arabicLatexScripts(sup, sub, content);\n }\n}\n\nexport class EnvNode extends BaseAstNode {\n opening: string;\n lines: ChainNode[];\n closing: string;\n\n constructor(opening: string, lines: ChainNode[] = [], closing: string, state: State | null = null) {\n super(state);\n this.nodeType = 'EnvObject';\n this.opening = opening;\n this.lines = lines;\n this.closing = closing;\n }\n\n latex(): string {\n if (this.lines.length === 0) {\n return this.opening + this.closing + this.latexScripts();\n }\n\n const formattedLines = this.lines.map((line) => ` ${line.latex()}`);\n const content = formattedLines.join(' \\\\\\\\' + '\\n');\n return `${this.opening}\\n${content}\\n${this.closing}` + this.latexScripts();\n }\n\n arabicLatex(): string {\n const sup = this.superscript !== null ? this.superscript.arabicLatex() : '';\n const sub = this.subscript !== null ? this.subscript.arabicLatex() : '';\n\n if (this.lines.length === 0) {\n return this.arabicLatexScripts(sup, sub, this.opening + this.closing);\n }\n\n const formattedLines = this.lines.map((line) => ` ${line.arabicLatex()}`);\n const content = formattedLines.join(' \\\\\\\\' + '\\n');\n const fullContent = `${this.opening}\\n${content}\\n${this.closing}`;\n return this.arabicLatexScripts(sup, sub, fullContent);\n }\n}\n\ntype ParseMode = 'english' | 'arabic';\n\nfunction parseScripts(node: BaseAstNode, json: ArabicNodeJson, mode: ParseMode): void {\n if (json.superscript) {\n node.superscript = parseChain(json.superscript, mode);\n }\n\n if (json.subscript) {\n node.subscript = parseChain(json.subscript, mode);\n }\n}\n\nfunction parseNode(json: ArabicNodeJson, mode: ParseMode): BaseAstNode {\n if (json.node_type === 'DelimiterObject') {\n const node = parseDelimiter(json, mode);\n parseScripts(node, json, mode);\n return node;\n }\n\n if (json.node_type === 'OperatorObject') {\n if (typeof json.expr !== 'string') {\n throw new Error('OperatorObject requires string expr');\n }\n const node = new OperatorNode(json.expr);\n parseScripts(node, json, mode);\n return node;\n }\n\n if (json.node_type === 'CommandObject') {\n const node = parseCommand(json, mode);\n parseScripts(node, json, mode);\n return node;\n }\n\n if (json.node_type === 'EnvObject') {\n const node = parseEnv(json, mode);\n parseScripts(node, json, mode);\n return node;\n }\n\n if (typeof json.expr !== 'string') {\n throw new Error(`${json.node_type} requires string expr`);\n }\n\n let node: BaseAstNode;\n\n if (json.node_type === 'NumberObject') {\n node = new NumberNode(json.expr);\n } else if (json.node_type === 'CharObject') {\n node = new CharNode(json.expr);\n } else {\n throw new Error(`Unsupported node_type: ${json.node_type}`);\n }\n\n parseScripts(node, json, mode);\n return node;\n}\n\nfunction parseDelimiter(json: ArabicNodeJson, mode: ParseMode): DelimiterNode {\n if (typeof json.left_delim_expr !== 'string') {\n throw new Error('DelimiterObject requires string left_delim_expr');\n }\n\n if (!json.inner_expr || json.inner_expr.node_type !== 'ChainClass') {\n throw new Error('DelimiterObject requires ChainClass inner_expr');\n }\n\n if (typeof json.right_delim_expr !== 'string') {\n throw new Error('DelimiterObject requires string right_delim_expr');\n }\n\n const innerExpr = parseChain(json.inner_expr, mode);\n return new DelimiterNode(json.left_delim_expr, innerExpr, json.right_delim_expr);\n}\n\nfunction parseCommand(json: ArabicNodeJson, mode: ParseMode): CommandNode {\n if (typeof json.name !== 'string') {\n throw new Error('CommandObject requires string name');\n }\n\n const optionalJson = Array.isArray(json.optional_args) ? json.optional_args : [];\n const mandatoryJson = Array.isArray(json.mandatory_args) ? json.mandatory_args : [];\n const optionalArgs = optionalJson.map((arg) => parseChain(arg, mode));\n const mandatoryArgs = mandatoryJson.map((arg) => parseChain(arg, mode));\n\n return new CommandNode(json.name, optionalArgs, mandatoryArgs);\n}\n\nfunction parseEnv(json: ArabicNodeJson, mode: ParseMode): EnvNode {\n if (typeof json.opening !== 'string') {\n throw new Error('EnvObject requires string opening');\n }\n\n if (typeof json.closing !== 'string') {\n throw new Error('EnvObject requires string closing');\n }\n\n if (!Array.isArray(json.lines)) {\n throw new Error('EnvObject requires lines array');\n }\n\n const lines = json.lines.map((line) => parseChain(line, mode));\n return new EnvNode(json.opening, lines, json.closing);\n}\n\nfunction parseChain(json: ChainJson, mode: ParseMode): ChainNode {\n if (json.node_type !== 'ChainClass') {\n throw new Error(`Expected ChainClass, got: ${json.node_type}`);\n }\n\n const nodes = json.chain.map((childJson) => parseNode(childJson, mode));\n return new ChainNode(nodes);\n}\n\n/** Import AST from Python english_dict JSON (Latin expr fields). */\nexport function fromEnglishJson(json: ChainJson | ArabicNodeJson): ChainNode | BaseAstNode {\n if (json.node_type === 'ChainClass') {\n return parseChain(json as ChainJson, 'english');\n }\n return parseNode(json, 'english');\n}\n\n/** Import AST from Python arabic_dict JSON (Arabic expr fields). Same shape as English; values differ. */\nexport function fromArabicJson(json: ChainJson | ArabicNodeJson): ChainNode | BaseAstNode {\n if (json.node_type === 'ChainClass') {\n return parseChain(json as ChainJson, 'arabic');\n }\n return parseNode(json, 'arabic');\n}\n","import {\n BaseAstNode,\n ChainNode,\n CharNode,\n CommandNode,\n DelimiterNode,\n EnvNode,\n NumberNode,\n OperatorNode,\n fromArabicJson,\n fromEnglishJson,\n type ArabicNodeJson,\n type ChainJson,\n} from '../ast/arabic_ast.js';\nimport type { DocumentParseMode, MathNode, MathObjectJson } from './types.js';\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isMathObjectJson(value: unknown): value is MathObjectJson {\n return isObject(value) && value.node_type === 'MathObject';\n}\n\nfunction assertChainNode(value: unknown): ChainNode {\n if (!(value instanceof ChainNode)) {\n throw new Error('MathObject lines must parse to ChainNode');\n }\n return value;\n}\n\nexport function fromMathObjectJson(json: unknown, mode: DocumentParseMode = 'english'): MathNode {\n if (!isMathObjectJson(json)) {\n throw new Error('MathObject requires node_type \"MathObject\"');\n }\n\n if (typeof json.math_mode !== 'string') {\n throw new Error('MathObject requires string math_mode');\n }\n\n if (typeof json.closing !== 'string') {\n throw new Error('MathObject requires string closing');\n }\n\n if (!Array.isArray(json.lines) || json.lines.length === 0) {\n throw new Error('MathObject requires non-empty lines array');\n }\n\n const parseChain = mode === 'arabic' ? fromArabicJson : fromEnglishJson;\n const lines = json.lines.map((line) => assertChainNode(parseChain(line)));\n\n return {\n nodeType: 'MathObject',\n mathMode: json.math_mode,\n lines,\n closing: json.closing,\n };\n}\n\nfunction scriptsToJson(node: BaseAstNode, path: string): Pick<ArabicNodeJson, 'superscript' | 'subscript'> {\n return {\n ...(node.superscript ? { superscript: chainToJson(node.superscript, `${path}.superscript`) } : {}),\n ...(node.subscript ? { subscript: chainToJson(node.subscript, `${path}.subscript`) } : {}),\n };\n}\n\nfunction nodeToJson(node: BaseAstNode, path: string): ArabicNodeJson {\n const scripts = scriptsToJson(node, path);\n if (node instanceof CharNode || node instanceof NumberNode || node instanceof OperatorNode) {\n return { node_type: node.nodeType, expr: node.expr, ...scripts };\n }\n if (node instanceof DelimiterNode) {\n return {\n node_type: 'DelimiterObject',\n left_delim_expr: node.leftDelimExpr,\n inner_expr: chainToJson(node.innerExpr, `${path}.inner_expr`),\n right_delim_expr: node.rightDelimExpr,\n ...scripts,\n };\n }\n if (node instanceof CommandNode) {\n return {\n node_type: 'CommandObject',\n name: node.name,\n optional_args: node.optionalArgs.map((arg, index) => chainToJson(arg, `${path}.optional_args[${String(index)}]`)),\n mandatory_args: node.mandatoryArgs.map((arg, index) => chainToJson(arg, `${path}.mandatory_args[${String(index)}]`)),\n ...scripts,\n };\n }\n if (node instanceof EnvNode) {\n return {\n node_type: 'EnvObject',\n opening: node.opening,\n lines: node.lines.map((line, index) => chainToJson(line, `${path}.lines[${String(index)}]`)),\n closing: node.closing,\n ...scripts,\n };\n }\n throw new Error(`Unsupported runtime math node at ${path}: ${node.nodeType}`);\n}\n\nfunction chainToJson(chain: ChainNode, path: string): ChainJson {\n if (!(chain instanceof ChainNode)) {\n throw new Error(`Expected live ChainNode at ${path}`);\n }\n return {\n node_type: 'ChainClass',\n chain: chain.chain.map((node, index) => nodeToJson(node, `${path}.chain[${String(index)}]`)),\n };\n}\n\nexport function toMathObjectJson(math: MathNode): MathObjectJson {\n if (math.nodeType !== 'MathObject' || !Array.isArray(math.lines) || math.lines.length === 0) {\n throw new Error('Cannot serialize invalid runtime MathObject');\n }\n return {\n node_type: 'MathObject',\n math_mode: math.mathMode,\n lines: math.lines.map((line, index) => chainToJson(line, `$.lines[${String(index)}]`)),\n closing: math.closing,\n };\n}\n\nexport function renderMathNodeLatex(math: MathNode): string {\n const lines = math.lines.map((line) => line.arabicLatex());\n\n if (math.mathMode === '$' || math.mathMode === '\\\\(') {\n return math.mathMode + lines.join(' ') + math.closing;\n }\n\n if (math.mathMode === '$$' || math.mathMode === '\\\\[') {\n if (lines.length === 1) {\n return math.mathMode + '\\n' + lines[0] + '\\n' + math.closing;\n }\n return math.mathMode + '\\n' + lines.map((line) => ` ${line}`).join(' \\\\\\\\\\n') + '\\n' + math.closing;\n }\n\n if (lines.length === 1) {\n return `${math.mathMode}\\n ${lines[0]}\\n${math.closing}`;\n }\n\n return `${math.mathMode}\\n${lines.map((line) => ` ${line}`).join(' \\\\\\\\\\n')}\\n${math.closing}`;\n}\n\nexport function isDisplayMathNode(math: MathNode): boolean {\n return math.mathMode === '$$' || math.mathMode === '\\\\[' || math.mathMode.startsWith('\\\\begin{');\n}\n","import { formatDigits } from '../editor/digits.js';\nimport type { DigitFormId } from '../editor/types.js';\nimport type { ButexUiLocale } from '../uiLocale.js';\nimport { formatBibliographyNumber } from './citations.js';\nimport type {\n Document2Block,\n Document2Direction,\n Document2Node,\n FormatCiteLabelOptions,\n ImageBlock2,\n InlineField2,\n MathToken2,\n TableBlock2,\n} from './types.js';\n\nexport type Document2LabelKind = 'fig' | 'tab' | 'eq';\n\nexport type Document2LabelEntry = {\n key: string;\n kind: Document2LabelKind;\n caption: string;\n /** Block id for fig/tab, or math token id for eq. */\n ownerId: string;\n number: number;\n};\n\nexport type FloatMetaPatch = {\n centered?: boolean;\n captionEnabled?: boolean;\n caption?: string;\n labelEnabled?: boolean;\n label?: string;\n};\n\nexport function defaultFloatMeta(): {\n centered: true;\n captionEnabled: false;\n caption: '';\n labelEnabled: false;\n label: '';\n} {\n return {\n centered: true,\n captionEnabled: false,\n caption: '',\n labelEnabled: false,\n label: '',\n };\n}\n\nexport function parseFloatMetaFromJson(json: {\n caption?: string;\n label?: string;\n caption_enabled?: boolean;\n label_enabled?: boolean;\n centered?: boolean;\n}): {\n centered: boolean;\n captionEnabled: boolean;\n caption: string;\n labelEnabled: boolean;\n label: string;\n} {\n const caption = typeof json.caption === 'string' ? json.caption : '';\n const label = typeof json.label === 'string' ? json.label : '';\n return {\n centered: json.centered !== false,\n captionEnabled: json.caption_enabled === true || (typeof json.caption_enabled !== 'boolean' && caption.length > 0),\n caption,\n labelEnabled: json.label_enabled === true || (typeof json.label_enabled !== 'boolean' && label.trim().length > 0),\n label,\n };\n}\n\nexport function parseRefKeys(source: string): { keys: string[]; refCommand: 'ref' | 'eqref' } {\n const eqref = /^\\\\eqref\\{([^}]*)\\}$/.exec(source.trim());\n if (eqref) {\n return {\n refCommand: 'eqref',\n keys: (eqref[1] ?? '')\n .split(',')\n .map((key) => key.trim())\n .filter((key) => key.length > 0),\n };\n }\n const ref = /^\\\\ref\\{([^}]*)\\}$/.exec(source.trim());\n if (ref) {\n return {\n refCommand: 'ref',\n keys: (ref[1] ?? '')\n .split(',')\n .map((key) => key.trim())\n .filter((key) => key.length > 0),\n };\n }\n return { keys: [], refCommand: 'ref' };\n}\n\nexport function refTokenLatex(keys: string[], refCommand: 'ref' | 'eqref'): string {\n const command = refCommand === 'eqref' ? '\\\\eqref' : '\\\\ref';\n return `${command}{${keys.join(',')}}`;\n}\n\n/** Collect enabled labels in document order, numbering per kind. */\nexport function collectDocument2Labels(document: Document2Node): Document2LabelEntry[] {\n const entries: Document2LabelEntry[] = [];\n const counters: Record<Document2LabelKind, number> = { fig: 0, tab: 0, eq: 0 };\n\n function pushEqFromField(tokens: MathToken2[] | InlineField2['tokens']): void {\n for (const token of tokens) {\n if (token.kind !== 'math') {\n continue;\n }\n if (token.display && token.labelEnabled && token.label && token.label.trim().length > 0) {\n counters.eq += 1;\n entries.push({\n key: token.label.trim(),\n kind: 'eq',\n caption: '',\n ownerId: token.id,\n number: counters.eq,\n });\n }\n }\n }\n\n function walk(blocks: Document2Block[]): void {\n for (const block of blocks) {\n if (block.kind === 'image' && block.labelEnabled && block.label.trim().length > 0) {\n counters.fig += 1;\n entries.push({\n key: block.label.trim(),\n kind: 'fig',\n caption: block.captionEnabled ? block.caption : '',\n ownerId: block.id,\n number: counters.fig,\n });\n }\n if (block.kind === 'table') {\n if (block.labelEnabled && block.label.trim().length > 0) {\n counters.tab += 1;\n entries.push({\n key: block.label.trim(),\n kind: 'tab',\n caption: block.captionEnabled ? block.caption : '',\n ownerId: block.id,\n number: counters.tab,\n });\n }\n for (const row of block.rows) {\n for (const cell of row) {\n pushEqFromField(cell.tokens);\n }\n }\n }\n if (block.kind === 'textBlock') {\n pushEqFromField(block.field.tokens);\n }\n if (block.kind === 'list') {\n for (const item of block.items) {\n pushEqFromField(item.field.tokens);\n walk(item.blocks);\n }\n }\n }\n }\n\n walk(document.blocks);\n return entries;\n}\n\nexport function labelNumberMap(document: Document2Node): Map<string, { kind: Document2LabelKind; number: number }> {\n const map = new Map<string, { kind: Document2LabelKind; number: number }>();\n for (const entry of collectDocument2Labels(document)) {\n if (!map.has(entry.key)) {\n map.set(entry.key, { kind: entry.kind, number: entry.number });\n }\n }\n return map;\n}\n\nexport type FormatFloatCaptionTitleOptions = {\n uiLocale?: ButexUiLocale;\n documentDirection?: Document2Direction;\n digitForm?: DigitFormId;\n};\n\n/** Localized numbered float/equation title: الشكل ١ / Figure 1 / المعادلة ١. */\nexport function formatFloatCaptionTitle(\n kind: Document2LabelKind,\n number: number,\n options: FormatFloatCaptionTitleOptions = {},\n): string {\n const locale = options.uiLocale ?? 'ar';\n const kindWord =\n kind === 'fig'\n ? locale === 'ar'\n ? 'الشكل'\n : 'Figure'\n : kind === 'tab'\n ? locale === 'ar'\n ? 'الجدول'\n : 'Table'\n : locale === 'ar'\n ? 'المعادلة'\n : 'Equation';\n const digits = formatBibliographyNumber(number, {\n documentDirection: options.documentDirection ?? (locale === 'ar' ? 'rtl' : 'ltr'),\n digitForm: options.digitForm ?? (locale === 'ar' ? 'arabicIndic' : 'western'),\n });\n return `${kindWord} ${digits}`;\n}\n\n/** Caption line as shown in document preview: الشكل ١: نص / Figure 1. text. */\nexport function formatFloatCaptionPreview(\n title: string,\n caption: string | undefined,\n uiLocale: ButexUiLocale = 'ar',\n): string {\n const trimmed = caption?.trim() ?? '';\n if (trimmed.length === 0) {\n return title;\n }\n const separator = uiLocale === 'ar' ? ': ' : '. ';\n return `${title}${separator}${trimmed}`;\n}\n\nexport function formatRefLabel(\n keys: string[],\n document: Document2Node,\n refCommand: 'ref' | 'eqref',\n options: FormatCiteLabelOptions = {},\n): string {\n const documentDirection: Document2Direction = options.documentDirection ?? 'rtl';\n const digitForm: DigitFormId = options.digitForm ?? (documentDirection === 'rtl' ? 'arabicIndic' : 'western');\n const map = labelNumberMap(document);\n const parts = keys.map((key) => {\n const hit = map.get(key);\n if (!hit) {\n return '?';\n }\n return formatDigits(String(hit.number), digitForm);\n });\n const body = parts.join(documentDirection === 'rtl' ? '،' : ', ');\n if (refCommand === 'eqref') {\n return `(${body})`;\n }\n return body;\n}\n\nexport function stripDisplayMathDelimiters(source: string): string {\n const trimmed = source.trim();\n if (trimmed.startsWith('\\\\[') && trimmed.endsWith('\\\\]')) {\n return trimmed.slice(2, -2).trim();\n }\n if (trimmed.startsWith('$$') && trimmed.endsWith('$$')) {\n return trimmed.slice(2, -2).trim();\n }\n if (trimmed.startsWith('\\\\begin{equation}') && trimmed.endsWith('\\\\end{equation}')) {\n return trimmed.slice('\\\\begin{equation}'.length, -'\\\\end{equation}'.length).trim();\n }\n return trimmed;\n}\n\nexport function applyFloatMetaPatch<T extends ImageBlock2 | TableBlock2>(block: T, patch: FloatMetaPatch): void {\n if (typeof patch.centered === 'boolean') {\n block.centered = patch.centered;\n }\n if (typeof patch.captionEnabled === 'boolean') {\n block.captionEnabled = patch.captionEnabled;\n }\n if (typeof patch.caption === 'string') {\n block.caption = patch.caption;\n }\n if (typeof patch.labelEnabled === 'boolean') {\n block.labelEnabled = patch.labelEnabled;\n }\n if (typeof patch.label === 'string') {\n block.label = patch.label;\n }\n}\n","import type { DetectedInlineSpan2, DetectedMathSpan2 } from './types.js';\nimport { parseCiteKeys } from './citations.js';\nimport { parseRefKeys } from './labels.js';\n\nconst MATH_ENVIRONMENTS = new Set([\n 'equation',\n 'equation*',\n 'align',\n 'align*',\n 'aligned',\n 'gather',\n 'gather*',\n 'multline',\n 'multline*',\n]);\n\nfunction isEscaped(value: string, index: number): boolean {\n let slashCount = 0;\n let i = index - 1;\n while (i >= 0 && value[i] === '\\\\') {\n slashCount += 1;\n i -= 1;\n }\n return slashCount % 2 === 1;\n}\n\nfunction findClosingDollar(value: string, start: number): number {\n let i = start;\n while (i < value.length) {\n if (value[i] === '$' && !isEscaped(value, i)) {\n return i;\n }\n i += 1;\n }\n return -1;\n}\n\nfunction environmentSpan(value: string, start: number): DetectedMathSpan2 | null {\n const match = /^\\\\begin\\{([A-Za-z*]+)\\}/.exec(value.slice(start));\n if (!match) {\n return null;\n }\n\n const envName = match[1] ?? '';\n if (!MATH_ENVIRONMENTS.has(envName)) {\n return null;\n }\n\n const opening = match[0] ?? '';\n const closing = `\\\\end{${envName}}`;\n const closingStart = value.indexOf(closing, start + opening.length);\n if (closingStart < 0) {\n return null;\n }\n\n const end = closingStart + closing.length;\n return { start, end, source: value.slice(start, end), opening, closing, display: true };\n}\n\nfunction citeSpan(value: string, start: number): DetectedInlineSpan2 | null {\n if (!value.startsWith('\\\\cite{', start) || isEscaped(value, start)) {\n return null;\n }\n const openBrace = start + '\\\\cite'.length;\n if (value[openBrace] !== '{') {\n return null;\n }\n let depth = 0;\n for (let i = openBrace; i < value.length; i += 1) {\n const char = value[i];\n if (char === '{' && !isEscaped(value, i)) {\n depth += 1;\n continue;\n }\n if (char === '}' && !isEscaped(value, i)) {\n depth -= 1;\n if (depth === 0) {\n const end = i + 1;\n const source = value.slice(start, end);\n return { kind: 'cite', start, end, source, keys: parseCiteKeys(source) };\n }\n }\n }\n return null;\n}\n\nfunction refSpan(value: string, start: number): DetectedInlineSpan2 | null {\n const eqrefPrefix = '\\\\eqref{';\n const refPrefix = '\\\\ref{';\n let refCommand: 'ref' | 'eqref' = 'ref';\n let prefix = refPrefix;\n if (value.startsWith(eqrefPrefix, start) && !isEscaped(value, start)) {\n refCommand = 'eqref';\n prefix = eqrefPrefix;\n } else if (value.startsWith(refPrefix, start) && !isEscaped(value, start)) {\n refCommand = 'ref';\n prefix = refPrefix;\n } else {\n return null;\n }\n\n const openBrace = start + prefix.length - 1;\n if (value[openBrace] !== '{') {\n return null;\n }\n let depth = 0;\n for (let i = openBrace; i < value.length; i += 1) {\n const char = value[i];\n if (char === '{' && !isEscaped(value, i)) {\n depth += 1;\n continue;\n }\n if (char === '}' && !isEscaped(value, i)) {\n depth -= 1;\n if (depth === 0) {\n const end = i + 1;\n const source = value.slice(start, end);\n const parsed = parseRefKeys(source);\n return { kind: 'ref', start, end, source, keys: parsed.keys, refCommand };\n }\n }\n }\n return null;\n}\n\nfunction mathSpanAt(value: string, i: number): DetectedMathSpan2 | null {\n if (value.startsWith('\\\\begin{', i)) {\n return environmentSpan(value, i);\n }\n\n if (value.startsWith('\\\\(', i)) {\n const close = value.indexOf('\\\\)', i + 2);\n if (close >= 0) {\n const end = close + 2;\n return { start: i, end, source: value.slice(i, end), opening: '\\\\(', closing: '\\\\)', display: false };\n }\n }\n\n if (value.startsWith('\\\\[', i)) {\n const close = value.indexOf('\\\\]', i + 2);\n if (close >= 0) {\n const end = close + 2;\n return { start: i, end, source: value.slice(i, end), opening: '\\\\[', closing: '\\\\]', display: true };\n }\n }\n\n if (value.startsWith('$$', i) && !isEscaped(value, i)) {\n const close = value.indexOf('$$', i + 2);\n if (close >= 0) {\n const end = close + 2;\n return { start: i, end, source: value.slice(i, end), opening: '$$', closing: '$$', display: true };\n }\n }\n\n if (value[i] === '$' && !isEscaped(value, i)) {\n const close = findClosingDollar(value, i + 1);\n if (close >= 0) {\n const end = close + 1;\n return { start: i, end, source: value.slice(i, end), opening: '$', closing: '$', display: false };\n }\n }\n\n return null;\n}\n\n/** Math-only spans (used for math_objects alignment counts). */\nexport function detectMathSpans2(value: string): DetectedMathSpan2[] {\n return detectInlineSpans2(value)\n .filter((span): span is DetectedInlineSpan2 & { kind: 'math' } => span.kind === 'math')\n .map(({ kind: _kind, ...span }) => span);\n}\n\n/** Left-to-right math + \\\\cite + \\\\ref/\\\\eqref spans without overlap. */\nexport function detectInlineSpans2(value: string): DetectedInlineSpan2[] {\n const spans: DetectedInlineSpan2[] = [];\n let i = 0;\n\n while (i < value.length) {\n const cite = citeSpan(value, i);\n if (cite) {\n spans.push(cite);\n i = cite.end;\n continue;\n }\n\n const ref = refSpan(value, i);\n if (ref) {\n spans.push(ref);\n i = ref.end;\n continue;\n }\n\n const math = mathSpanAt(value, i);\n if (math) {\n spans.push({ kind: 'math', ...math });\n i = math.end;\n continue;\n }\n\n i += 1;\n }\n\n return spans;\n}\n","import { fromMathObjectJson } from '../document/mathObject.js';\nimport { normalizeDocument2Meta, emptyDocument2Meta } from './articleMeta.js';\nimport { referenceFromJson } from './citations.js';\nimport { document2Id } from './ids.js';\nimport { detectInlineSpans2, detectMathSpans2 } from './inlineScanner.js';\nimport { parseFloatMetaFromJson } from './labels.js';\nimport type {\n BibliographyBlock2,\n Document2Block,\n Document2BlockJson,\n Document2Diagnostic,\n Document2MathObjectJson,\n Document2ListItemJson,\n Document2Node,\n Document2ParseMode,\n ImageBlock2,\n ImportDocument2Options,\n InlineField2,\n InlineToken2,\n ListBlock2,\n ListItem2,\n RawBlock2,\n Reference2,\n Reference2Json,\n TableBlock2,\n TextFormatSpan2Json,\n TextStyle2,\n TextBlock2,\n} from './types.js';\n\nconst TEXT_COMMANDS = new Set(['\\\\section', '\\\\subsection', '\\\\subsubsection', '\\\\paragraph']);\nconst LIST_COMMANDS = new Set(['\\\\begin{itemize}', '\\\\begin{enumerate}']);\n\ntype BlockIdState = {\n used: Set<string>;\n};\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction requireString(value: unknown, message: string): string {\n if (typeof value !== 'string') {\n throw new Error(message);\n }\n return value;\n}\n\nfunction isRecordOfStrings(value: unknown): value is Record<string, string> {\n return isObject(value) && Object.values(value).every((entry) => typeof entry === 'string');\n}\n\nfunction asBlockJson(value: unknown): Document2BlockJson {\n if (!isObject(value)) {\n throw new Error('Document block must be an object');\n }\n if (typeof value.command !== 'string') {\n throw new Error('Document block requires string command');\n }\n return value as Document2BlockJson;\n}\n\nfunction blockIdFromJson(json: Document2BlockJson, state: BlockIdState): string {\n const imported = typeof json.id === 'string' ? json.id.trim() : '';\n if (imported.length > 0 && !state.used.has(imported)) {\n state.used.add(imported);\n return imported;\n }\n\n let generated = document2Id('block');\n while (state.used.has(generated)) {\n generated = document2Id('block');\n }\n state.used.add(generated);\n return generated;\n}\n\nfunction pushDiagnostic(diagnostics: Document2Diagnostic[], options: ImportDocument2Options, path: string, message: string): void {\n if (options.strict) {\n throw new Error(message);\n }\n diagnostics.push({ code: 'math_alignment', message, path });\n}\n\nfunction parseReferences(json: unknown): Reference2[] {\n if (!Array.isArray(json)) {\n return [];\n }\n const references: Reference2[] = [];\n for (const entry of json) {\n if (!isObject(entry) || typeof entry.key !== 'string' || entry.key.trim().length === 0) {\n continue;\n }\n references.push(\n referenceFromJson({\n key: entry.key.trim(),\n authors: typeof entry.authors === 'string' ? entry.authors : undefined,\n title: typeof entry.title === 'string' ? entry.title : undefined,\n year: typeof entry.year === 'string' ? entry.year : undefined,\n url: typeof entry.url === 'string' ? entry.url : undefined,\n venue: typeof entry.venue === 'string' ? entry.venue : undefined,\n field_separator:\n entry.field_separator === ',' || entry.field_separator === '،'\n ? entry.field_separator\n : undefined,\n } satisfies Reference2Json),\n );\n }\n return references;\n}\n\nexport function createInlineField2(\n value = '',\n mathObjects: Array<Document2MathObjectJson | null> = [],\n options: ImportDocument2Options = {},\n path = '$',\n diagnostics: Document2Diagnostic[] = [],\n formats: TextFormatSpan2Json[] = [],\n): InlineField2 {\n const mode: Document2ParseMode = options.mode ?? 'english';\n const spans = detectInlineSpans2(value);\n const mathSpans = spans.filter((span) => span.kind === 'math');\n const tokens: InlineToken2[] = [];\n let index = 0;\n let mathObjectIndex = 0;\n\n if (mathObjects.length > 0 && mathObjects.length !== mathSpans.length) {\n pushDiagnostic(diagnostics, options, path, `math_objects count mismatch: detected ${String(mathSpans.length)}, got ${String(mathObjects.length)}`);\n }\n\n for (const span of spans) {\n if (span.start > index) {\n pushFormattedTextTokens(tokens, value.slice(index, span.start), index, formats);\n }\n\n if (span.kind === 'cite') {\n tokens.push({\n id: document2Id('cite'),\n kind: 'cite',\n keys: span.keys.length > 0 ? span.keys : [],\n });\n index = span.end;\n continue;\n }\n\n if (span.kind === 'ref') {\n tokens.push({\n id: document2Id('ref'),\n kind: 'ref',\n keys: span.keys.length > 0 ? span.keys : [],\n refCommand: span.refCommand,\n });\n index = span.end;\n continue;\n }\n\n const mathJson = mathObjects[mathObjectIndex];\n mathObjectIndex += 1;\n const structuredMathJson = mathJson?.node_type === 'MathObject' ? mathJson : null;\n if (structuredMathJson && (structuredMathJson.math_mode !== span.opening || structuredMathJson.closing !== span.closing)) {\n pushDiagnostic(diagnostics, options, path, 'math_objects order mismatch');\n }\n\n if (structuredMathJson && structuredMathJson.math_mode === span.opening && structuredMathJson.closing === span.closing) {\n tokens.push({\n id: document2Id('math'),\n kind: 'math',\n display: span.display,\n opening: span.opening,\n closing: span.closing,\n source: span.source,\n sourceSide:\n structuredMathJson.source_side === 'arabic' || structuredMathJson.source_side === 'english'\n ? structuredMathJson.source_side\n : mode,\n math: fromMathObjectJson(structuredMathJson, mode),\n editable: true,\n sourceOwner: structuredMathJson.source_owner === 'editor' ? 'editor' : 'imported-structured',\n ...(typeof structuredMathJson.label_enabled === 'boolean' ? { labelEnabled: structuredMathJson.label_enabled } : {}),\n ...(typeof structuredMathJson.label === 'string' ? { label: structuredMathJson.label } : {}),\n });\n } else {\n tokens.push({\n id: document2Id('math'),\n kind: 'math',\n display: span.display,\n opening: span.opening,\n closing: span.closing,\n source: span.source,\n math: null,\n editable: false,\n reason: 'هذه المعادلة محفوظة كنص خام فقط حاليا',\n sourceOwner: 'raw',\n ...(mathJson?.node_type === 'RawMathObject' && typeof mathJson.label_enabled === 'boolean'\n ? { labelEnabled: mathJson.label_enabled }\n : {}),\n ...(mathJson?.node_type === 'RawMathObject' && typeof mathJson.label === 'string'\n ? { label: mathJson.label }\n : {}),\n });\n }\n\n index = span.end;\n }\n\n if (index < value.length || tokens.length === 0) {\n pushFormattedTextTokens(tokens, value.slice(index), index, formats);\n }\n\n return { id: document2Id('field'), tokens: compactTextTokens(tokens) };\n}\n\nfunction styleFromFormat(format: TextFormatSpan2Json): TextStyle2 | null {\n const style: TextStyle2 = {};\n if (format.bold === true) {\n style.bold = true;\n }\n if (format.italic === true) {\n style.italic = true;\n }\n if (format.underline === true) {\n style.underline = true;\n }\n return style.bold || style.italic || style.underline ? style : null;\n}\n\nfunction mergeTextStyle(base: TextStyle2 | undefined, added: TextStyle2): TextStyle2 {\n return {\n ...(base?.bold ? { bold: true as const } : {}),\n ...(base?.italic ? { italic: true as const } : {}),\n ...(base?.underline ? { underline: true as const } : {}),\n ...(added.bold ? { bold: true as const } : {}),\n ...(added.italic ? { italic: true as const } : {}),\n ...(added.underline ? { underline: true as const } : {}),\n };\n}\n\nfunction textStylesEqual(a: TextStyle2 | undefined, b: TextStyle2 | undefined): boolean {\n return Boolean(a?.bold) === Boolean(b?.bold) && Boolean(a?.italic) === Boolean(b?.italic) && Boolean(a?.underline) === Boolean(b?.underline);\n}\n\nfunction compactTextTokens(tokens: InlineToken2[]): InlineToken2[] {\n const compacted: InlineToken2[] = [];\n for (const token of tokens) {\n const previous = compacted[compacted.length - 1];\n if (previous?.kind === 'text' && token.kind === 'text' && textStylesEqual(previous.style, token.style)) {\n previous.text += token.text;\n } else {\n compacted.push(token);\n }\n }\n return compacted;\n}\n\nfunction styleKey(style: TextStyle2 | undefined): string {\n return `${style?.bold ? 'b' : ''}${style?.italic ? 'i' : ''}${style?.underline ? 'u' : ''}`;\n}\n\nfunction pushFormattedTextTokens(tokens: InlineToken2[], text: string, sourceStart: number, formats: TextFormatSpan2Json[]): void {\n if (text.length === 0) {\n tokens.push({ id: document2Id('text'), kind: 'text', text });\n return;\n }\n const styles: Array<TextStyle2 | undefined> = Array.from({ length: text.length });\n for (const format of formats) {\n const style = styleFromFormat(format);\n if (!style || !Number.isFinite(format.start) || !Number.isFinite(format.end)) {\n continue;\n }\n const start = Math.max(0, Math.min(text.length, Math.trunc(format.start) - sourceStart));\n const end = Math.max(0, Math.min(text.length, Math.trunc(format.end) - sourceStart));\n if (end <= start) {\n continue;\n }\n for (let index = start; index < end; index += 1) {\n styles[index] = mergeTextStyle(styles[index], style);\n }\n }\n\n let chunkStart = 0;\n for (let index = 1; index <= text.length; index += 1) {\n if (index < text.length && styleKey(styles[index]) === styleKey(styles[chunkStart])) {\n continue;\n }\n const chunk = text.slice(chunkStart, index);\n const style = styles[chunkStart];\n tokens.push({ id: document2Id('text'), kind: 'text', text: chunk, ...(style ? { style } : {}) });\n chunkStart = index;\n }\n}\n\nfunction closingForList(command: '\\\\begin{itemize}' | '\\\\begin{enumerate}'): '\\\\end{itemize}' | '\\\\end{enumerate}' {\n return command === '\\\\begin{itemize}' ? '\\\\end{itemize}' : '\\\\end{enumerate}';\n}\n\nfunction parseTextBlock(\n json: Document2BlockJson,\n options: ImportDocument2Options,\n path: string,\n diagnostics: Document2Diagnostic[],\n blockIds: BlockIdState,\n): TextBlock2 {\n const value = requireString(json.value, `${json.command} requires string value`);\n return {\n id: blockIdFromJson(json, blockIds),\n kind: 'textBlock',\n command: json.command as TextBlock2['command'],\n field: createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics, json.command === '\\\\paragraph' ? json.formats ?? [] : []),\n ...(json.centered === true ? { centered: true } : {}),\n };\n}\n\nfunction parseListItem(\n json: Document2ListItemJson,\n options: ImportDocument2Options,\n path: string,\n diagnostics: Document2Diagnostic[],\n blockIds: BlockIdState,\n): ListItem2 {\n const value = requireString(json.value, 'Document list item requires string value');\n const blocksJson = Array.isArray(json.blocks) ? json.blocks : [];\n return {\n id: document2Id('item'),\n field: createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics, json.formats ?? []),\n blocks: blocksJson.map((block, index) =>\n parseBlock(asBlockJson(block), options, `${path}.blocks[${String(index)}]`, diagnostics, blockIds),\n ),\n };\n}\n\nfunction parseListBlock(\n json: Document2BlockJson,\n options: ImportDocument2Options,\n path: string,\n diagnostics: Document2Diagnostic[],\n blockIds: BlockIdState,\n): ListBlock2 {\n if (!Array.isArray(json.items)) {\n throw new Error(`${json.command} requires items array`);\n }\n const command = json.command as ListBlock2['command'];\n const closing = closingForList(command);\n return {\n id: blockIdFromJson(json, blockIds),\n kind: 'list',\n command,\n closing,\n items: json.items.map((item, index) =>\n parseListItem(item, options, `${path}.items[${String(index)}]`, diagnostics, blockIds),\n ),\n };\n}\n\nfunction parseTableBlock(\n json: Document2BlockJson,\n options: ImportDocument2Options,\n path: string,\n diagnostics: Document2Diagnostic[],\n blockIds: BlockIdState,\n): TableBlock2 {\n if (!Array.isArray(json.rows)) {\n throw new Error('\\\\begin{tabular} requires rows array');\n }\n\n const mathObjects = json.math_objects ?? [];\n let mathObjectIndex = 0;\n const rows = json.rows.map((row, rowIndex) => {\n if (!Array.isArray(row)) {\n throw new Error('\\\\begin{tabular} rows must be arrays');\n }\n return row.map((cell, columnIndex) => {\n const value = requireString(cell, '\\\\begin{tabular} cells must be strings');\n const spanCount = detectMathSpans2(value).length;\n const cellMathObjects = mathObjects.slice(mathObjectIndex, mathObjectIndex + spanCount);\n mathObjectIndex += spanCount;\n const cellFormats = json.cell_formats?.[rowIndex]?.[columnIndex] ?? [];\n return createInlineField2(value, cellMathObjects, options, `${path}.rows[${String(rowIndex)}][${String(columnIndex)}]`, diagnostics, cellFormats);\n });\n });\n\n if (mathObjects.length > 0 && mathObjects.length !== mathObjectIndex) {\n pushDiagnostic(diagnostics, options, path, `math_objects count mismatch: detected ${String(mathObjectIndex)}, got ${String(mathObjects.length)}`);\n }\n\n return {\n id: blockIdFromJson(json, blockIds),\n kind: 'table',\n command: '\\\\begin{tabular}',\n closing: '\\\\end{tabular}',\n columns: typeof json.columns === 'string' ? json.columns : '',\n rows,\n ...parseFloatMetaFromJson(json),\n };\n}\n\nfunction parseImageBlock(json: Document2BlockJson, blockIds: BlockIdState): ImageBlock2 {\n const assetId = typeof json.asset_id === 'string' && json.asset_id.length > 0 ? json.asset_id : undefined;\n const value =\n assetId !== undefined\n ? typeof json.value === 'string'\n ? json.value\n : ''\n : requireString(json.value, '\\\\includegraphics requires string value');\n return {\n id: blockIdFromJson(json, blockIds),\n kind: 'image',\n command: '\\\\includegraphics',\n value,\n ...(assetId !== undefined ? { assetId } : {}),\n options: isRecordOfStrings(json.options) ? json.options : {},\n ...parseFloatMetaFromJson(json),\n };\n}\n\nfunction parseRawBlock(json: Document2BlockJson, blockIds: BlockIdState): RawBlock2 {\n return {\n id: blockIdFromJson(json, blockIds),\n kind: 'raw',\n command: '\\\\raw',\n value: typeof json.value === 'string' ? json.value : '',\n };\n}\n\nfunction parseBibliographyBlock(json: Document2BlockJson, blockIds: BlockIdState): BibliographyBlock2 {\n return {\n id: blockIdFromJson(json, blockIds),\n kind: 'bibliography',\n command: '\\\\begin{thebibliography}',\n closing: '\\\\end{thebibliography}',\n };\n}\n\nfunction parseBlock(\n json: Document2BlockJson,\n options: ImportDocument2Options,\n path: string,\n diagnostics: Document2Diagnostic[],\n blockIds: BlockIdState,\n): Document2Block {\n if (TEXT_COMMANDS.has(json.command)) {\n return parseTextBlock(json, options, path, diagnostics, blockIds);\n }\n if (LIST_COMMANDS.has(json.command)) {\n return parseListBlock(json, options, path, diagnostics, blockIds);\n }\n if (json.command === '\\\\begin{tabular}') {\n return parseTableBlock(json, options, path, diagnostics, blockIds);\n }\n if (json.command === '\\\\includegraphics') {\n return parseImageBlock(json, blockIds);\n }\n if (json.command === '\\\\begin{thebibliography}' || json.command === '\\\\bibliography') {\n return parseBibliographyBlock(json, blockIds);\n }\n if (json.command === '\\\\raw') {\n return parseRawBlock(json, blockIds);\n }\n return {\n id: blockIdFromJson(json, blockIds),\n kind: 'raw',\n command: '\\\\raw',\n value: typeof json.value === 'string' ? json.value : json.command,\n };\n}\n\nexport function fromDocumentJson2(json: unknown, options: ImportDocument2Options = {}): Document2Node {\n if (!isObject(json) || json.node_type !== 'DocumentObject') {\n throw new Error('DocumentObject requires node_type \"DocumentObject\"');\n }\n if (!Array.isArray(json.blocks)) {\n throw new Error('DocumentObject requires blocks array');\n }\n\n const diagnostics: Document2Diagnostic[] = [];\n const blockIds: BlockIdState = { used: new Set<string>() };\n return {\n nodeType: 'DocumentObject',\n meta: normalizeDocument2Meta(json.meta),\n references: parseReferences(json.references),\n blocks: json.blocks.map((block, index) =>\n parseBlock(asBlockJson(block), options, `$.blocks[${String(index)}]`, diagnostics, blockIds),\n ),\n diagnostics,\n };\n}\n\nexport function createEmptyDocument2(): Document2Node {\n return {\n nodeType: 'DocumentObject',\n meta: emptyDocument2Meta(),\n references: [],\n blocks: [],\n diagnostics: [],\n };\n}\n","export const ATOMIC_OPERATOR_COMMANDS = {\n inf: {\n id: 'inf',\n category: 'operators1',\n Tex: '\\\\infty',\n mirror: true,\n Label: '∞',\n title: 'اللانهاية',\n svg_path: null,\n },\n times: {\n id: 'times',\n category: 'operators1',\n Tex: '\\\\times',\n mirror: false,\n Label: '×',\n title: 'ضرب',\n svg_path: null,\n },\n div: {\n id: 'div',\n category: 'operators1',\n Tex: '\\\\div',\n mirror: false,\n Label: '÷',\n title: 'قسمة',\n svg_path: null,\n },\n pm: {\n id: 'pm',\n category: 'operators1',\n Tex: '\\\\pm',\n mirror: false,\n Label: '±',\n title: 'زائد أو ناقص',\n svg_path: null,\n },\n mp: {\n id: 'mp',\n category: 'operators1',\n Tex: '\\\\mp',\n mirror: false,\n Label: '∓',\n title: 'ناقص أو زائد',\n svg_path: null,\n },\n neq: {\n id: 'neq',\n category: 'operators1',\n Tex: '\\\\neq',\n mirror: true,\n compileMirror: true,\n Label: '≠',\n title: 'لا يساوي',\n svg_path: null,\n },\n approx: {\n id: 'approx',\n category: 'operators1',\n Tex: '\\\\approx',\n mirror: false,\n displayMirror: true,\n Label: '≈',\n title: 'تقريبا يساوي',\n svg_path: null,\n },\n sim: {\n id: 'sim',\n category: 'operators1',\n Tex: '\\\\sim',\n mirror: false,\n displayMirror: true,\n Label: '∼',\n title: 'مشابه',\n svg_path: null,\n },\n mid: {\n id: 'mid',\n category: 'operators1',\n Tex: '\\\\mid',\n mirror: false,\n Label: '∣',\n title: 'يقسم',\n svg_path: null,\n },\n leq: {\n id: 'leq',\n category: 'operators1',\n Tex: '\\\\leq',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '≤',\n title: 'أصغر من أو يساوي',\n svg_path: null,\n },\n geq: {\n id: 'geq',\n category: 'operators1',\n Tex: '\\\\geq',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '≥',\n title: 'أكبر من أو يساوي',\n svg_path: null,\n },\n coloneqq: {\n id: 'coloneqq',\n category: 'operators1',\n Tex: '\\\\coloneqq',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '≔',\n title: 'يعرف بأنه يساوي',\n svg_path: null,\n },\n eqqcolon: {\n id: 'eqqcolon',\n category: 'operators1',\n Tex: '\\\\eqqcolon',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '≕',\n title: 'يساوي بالتعريف',\n svg_path: null,\n },\n\n ///// Operators 2\n propto: {\n id: 'propto',\n category: 'operators2',\n Tex: '\\\\propto',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '∝',\n title: 'يتناسب مع',\n svg_path: null,\n },\n in: {\n id: 'in',\n category: 'operators2',\n Tex: '\\\\in',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '∈',\n title: 'ينتمي إلى',\n svg_path: null,\n },\n notin: {\n id: 'notin',\n category: 'operators2',\n Tex: '\\\\notin',\n mirror: false,\n displayMirror: true,\n Label: '∉',\n title: 'لا ينتمي إلى',\n svg_path: null,\n },\n subset: {\n id: 'subset',\n category: 'operators2',\n Tex: '\\\\subset',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '⊂',\n title: 'مجموعة جزئية من',\n svg_path: null,\n },\n supset: {\n id: 'supset',\n category: 'operators2',\n Tex: '\\\\supset',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '⊃',\n title: 'مجموعة شاملة لـ',\n svg_path: null,\n },\n subseteq: {\n id: 'subseteq',\n category: 'operators2',\n Tex: '\\\\subseteq',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '⊆',\n title: 'مجموعة جزئية أو تساوي',\n svg_path: null,\n },\n supseteq: {\n id: 'supseteq',\n category: 'operators2',\n Tex: '\\\\supseteq',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '⊇',\n title: 'مجموعة شاملة أو تساوي',\n svg_path: null,\n },\n cap: {\n id: 'cap',\n category: 'operators2',\n Tex: '\\\\cap',\n mirror: false,\n displayMirror: true,\n Label: '∩',\n title: 'تقاطع',\n svg_path: null,\n },\n cup: {\n id: 'cup',\n category: 'operators2',\n Tex: '\\\\cup',\n mirror: false,\n displayMirror: true,\n Label: '∪',\n title: 'اتحاد',\n svg_path: null,\n },\n emptyset: {\n id: 'emptyset',\n category: 'operators2',\n Tex: '\\\\emptyset',\n mirror: false,\n displayMirror: true,\n Label: '∅',\n title: 'المجموعة الخالية',\n svg_path: null,\n },\n nsubseteq: {\n id: 'nsubseteq',\n category: 'operators2',\n Tex: '\\\\nsubseteq',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '⊈',\n title: 'ليست مجموعة جزئية أو تساوي',\n svg_path: null,\n },\n nsupseteq: {\n id: 'nsupseteq',\n category: 'operators2',\n Tex: '\\\\nsupseteq',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '⊉',\n title: 'ليست مجموعة شاملة أو تساوي',\n svg_path: null,\n },\n\n ///// Dots\n ldots: {\n id: 'ldots',\n category: 'dots',\n Tex: '\\\\ldots',\n mirror: false,\n Label: '…',\n title: 'نقاط أفقية',\n svg_path: null,\n },\n cdot: {\n id: 'cdot',\n category: 'dots',\n Tex: '\\\\cdot',\n mirror: false,\n Label: '·',\n title: 'نقطة ضرب',\n svg_path: null,\n },\n cdots: {\n id: 'cdots',\n category: 'dots',\n Tex: '\\\\cdots',\n mirror: false,\n Label: '⋯',\n title: 'نقاط وسطية أفقية',\n svg_path: null,\n },\n vdots: {\n id: 'vdots',\n category: 'dots',\n Tex: '\\\\vdots',\n mirror: false,\n Label: '⋮',\n title: 'نقاط عمودية',\n svg_path: null,\n },\n ddots: {\n id: 'ddots',\n category: 'dots',\n Tex: '\\\\ddots',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '⋱',\n title: 'نقاط قطرية',\n svg_path: null,\n },\n\n /// Operators 3\n leftrightarrowDouble: {\n id: 'leftrightarrowDouble',\n category: 'operators3',\n Tex: '\\\\Leftrightarrow',\n mirror: false,\n Label: '⇔',\n title: 'يكافئ',\n svg_path: null,\n },\n implies: {\n id: 'implies',\n category: 'operators3',\n Tex: '\\\\implies',\n mirror: true,\n compileMirror: true,\n Label: '⇒',\n title: 'يستلزم',\n svg_path: null,\n },\n impliedby: {\n id: 'impliedby',\n category: 'operators3',\n Tex: '\\\\impliedby',\n mirror: true,\n compileMirror: true,\n Label: '⇐',\n title: 'مستلزم من',\n svg_path: null,\n },\n iff: {\n id: 'iff',\n category: 'operators3',\n Tex: '\\\\iff',\n mirror: false,\n Label: '⇔',\n title: 'إذا وفقط إذا',\n svg_path: null,\n },\n Longrightarrow: {\n id: 'Longrightarrow',\n category: 'operators3',\n Tex: '\\\\Longrightarrow',\n mirror: true,\n compileMirror: true,\n Label: '⟹',\n title: 'سهم مزدوج طويل إلى اليمين',\n svg_path: null,\n },\n Longleftarrow: {\n id: 'Longleftarrow',\n category: 'operators3',\n Tex: '\\\\Longleftarrow',\n mirror: true,\n compileMirror: true,\n Label: '⟸',\n title: 'سهم مزدوج طويل إلى اليسار',\n svg_path: null,\n },\n to: {\n id: 'to',\n category: 'operators3',\n Tex: '\\\\to',\n mirror: true,\n compileMirror: true,\n Label: '→',\n title: 'يؤول إلى',\n svg_path: null,\n },\n rightleftharpoons: {\n id: 'rightleftharpoons',\n category: 'operators3',\n Tex: '\\\\rightleftharpoons',\n mirror: true,\n compileMirror: true,\n Label: '⇌',\n title: 'اتزان',\n svg_path: null,\n },\n leftarrow: {\n id: 'leftarrow',\n category: 'operators3',\n Tex: '\\\\leftarrow',\n mirror: true,\n compileMirror: true,\n Label: '←',\n title: 'سهم إلى اليسار',\n svg_path: null,\n },\n rightarrow: {\n id: 'rightarrow',\n category: 'operators3',\n Tex: '\\\\rightarrow',\n mirror: true,\n compileMirror: true,\n Label: '→',\n title: 'سهم إلى اليمين',\n svg_path: null,\n },\n leftarrowDouble: {\n id: 'leftarrowDouble',\n category: 'operators3',\n Tex: '\\\\Leftarrow',\n mirror: true,\n compileMirror: true,\n Label: '⇐',\n title: 'سهم مزدوج إلى اليسار',\n svg_path: null,\n },\n rightarrowDouble: {\n id: 'rightarrowDouble',\n category: 'operators3',\n Tex: '\\\\Rightarrow',\n mirror: true,\n compileMirror: true,\n Label: '⇒',\n title: 'سهم مزدوج إلى اليمين',\n svg_path: null,\n },\n leftharpoonup: {\n id: 'leftharpoonup',\n category: 'operators3',\n Tex: '\\\\leftharpoonup',\n mirror: true,\n compileMirror: true,\n Label: '↼',\n title: 'سهم خطافي علوي إلى اليسار',\n svg_path: null,\n },\n rightharpoonup: {\n id: 'rightharpoonup',\n category: 'operators3',\n Tex: '\\\\rightharpoonup',\n mirror: true,\n compileMirror: true,\n Label: '⇀',\n title: 'سهم خطافي علوي إلى اليمين',\n svg_path: null,\n },\n leftharpoondown: {\n id: 'leftharpoondown',\n category: 'operators3',\n Tex: '\\\\leftharpoondown',\n mirror: true,\n compileMirror: true,\n Label: '↽',\n title: 'سهم خطافي سفلي إلى اليسار',\n svg_path: null,\n },\n rightharpoondown: {\n id: 'rightharpoondown',\n category: 'operators3',\n Tex: '\\\\rightharpoondown',\n mirror: true,\n compileMirror: true,\n Label: '⇁',\n title: 'سهم خطافي سفلي إلى اليمين',\n svg_path: null,\n },\n\n // Integrals\n int: {\n id: 'int',\n category: 'integrals',\n Tex: '\\\\int',\n mirror: true,\n compileMirror: true,\n Label: '∫',\n title: 'تكامل',\n svg_path: null,\n },\n iint: {\n id: 'iint',\n category: 'integrals',\n Tex: '\\\\iint',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '∬',\n title: 'تكامل مزدوج',\n svg_path: null,\n },\n iiint: {\n id: 'iiint',\n category: 'integrals',\n Tex: '\\\\iiint',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '∭',\n title: 'تكامل ثلاثي',\n svg_path: null,\n },\n iiiint: {\n id: 'iiiint',\n category: 'integrals',\n Tex: '\\\\iiiint',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '⨌',\n title: 'تكامل رباعي',\n svg_path: null,\n },\n oint: {\n id: 'oint',\n category: 'integrals',\n Tex: '\\\\oint',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '∮',\n title: 'تكامل مغلق',\n svg_path: null,\n },\n oiint: {\n id: 'oiint',\n category: 'integrals',\n Tex: '\\\\oiint',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '∯',\n title: 'تكامل سطحي مغلق',\n svg_path: null,\n },\n oiiint: {\n id: 'oiiint',\n category: 'integrals',\n Tex: '\\\\oiiint',\n mirror: true,\n displayMirror: false,\n compileMirror: true,\n Label: '∰',\n title: 'تكامل حجمي مغلق',\n svg_path: null,\n },\n} as const;\n\nexport type AtomicOperatorCommandId = keyof typeof ATOMIC_OPERATOR_COMMANDS;\n\nexport type AtomicOperatorCommandCategory =\n | 'operators1'\n | 'operators2'\n | 'operators3'\n | 'dots'\n | 'integrals';\n\nexport type AtomicOperatorCommandSpec =\n (typeof ATOMIC_OPERATOR_COMMANDS)[AtomicOperatorCommandId] & {\n displayMirror?: boolean;\n compileMirror?: boolean;\n };\n\nexport function shouldMirrorOperatorDisplay(\n command: AtomicOperatorCommandSpec | null | undefined,\n): boolean {\n return command?.displayMirror ?? command?.mirror ?? false;\n}\n\nconst MIRRORED_OPERATOR_TEX = Object.values(ATOMIC_OPERATOR_COMMANDS)\n .filter((command) => command.mirror)\n .map((command) => command.Tex)\n .sort((a, b) => b.length - a.length) as string[];\n\nconst COMPILE_MIRRORED_OPERATOR_TEX = Object.values(ATOMIC_OPERATOR_COMMANDS)\n .filter((command) => 'compileMirror' in command && command.compileMirror)\n .map((command) => command.Tex)\n .sort((a, b) => b.length - a.length) as string[];\n\nfunction matchingMirroredOperatorFrom(tex: string, index: number, operatorTexList: string[]): string | null {\n for (const operatorTex of operatorTexList) {\n if (!tex.startsWith(operatorTex, index)) {\n continue;\n }\n const next = tex[index + operatorTex.length];\n if (next != null && /[A-Za-z]/.test(next)) {\n continue;\n }\n return operatorTex;\n }\n return null;\n}\n\nfunction findMatchingBrace(tex: string, openIndex: number): number {\n let depth = 0;\n for (let index = openIndex; index < tex.length; index += 1) {\n const char = tex[index];\n if (char === '\\\\') {\n index += 1;\n continue;\n }\n if (char === '{') {\n depth += 1;\n } else if (char === '}') {\n depth -= 1;\n if (depth === 0) {\n return index;\n }\n }\n }\n return -1;\n}\n\nexport function mirrorBuTeXOperatorsInTex(tex: string, options: { target?: 'preview' | 'compile' } = {}): string {\n const mirroredOperatorTex = options.target === 'compile'\n ? COMPILE_MIRRORED_OPERATOR_TEX\n : MIRRORED_OPERATOR_TEX;\n let result = '';\n let index = 0;\n\n while (index < tex.length) {\n if (tex.startsWith('\\\\butexmirror{', index)) {\n const end = findMatchingBrace(tex, index + '\\\\butexmirror'.length);\n if (end !== -1) {\n const bodyStart = index + '\\\\butexmirror{'.length;\n const body = tex.slice(bodyStart, end);\n if (\n options.target === 'compile' &&\n MIRRORED_OPERATOR_TEX.includes(body) &&\n !mirroredOperatorTex.includes(body)\n ) {\n result += body;\n } else {\n result += tex.slice(index, end + 1);\n }\n index = end + 1;\n continue;\n }\n }\n\n const operatorTex = matchingMirroredOperatorFrom(tex, index, mirroredOperatorTex);\n if (operatorTex) {\n result += `\\\\butexmirror{${operatorTex}}`;\n index += operatorTex.length;\n continue;\n }\n\n result += tex[index];\n index += 1;\n }\n\n return result;\n}\n\nexport function atomicOperatorCommandsByCategory(\n category: AtomicOperatorCommandCategory,\n): AtomicOperatorCommandSpec[] {\n return Object.values(ATOMIC_OPERATOR_COMMANDS).filter(\n (command) => command.category === category,\n );\n}\n\nexport function atomicOperatorCommandSpec(\n id: string,\n): AtomicOperatorCommandSpec | null {\n return Object.prototype.hasOwnProperty.call(ATOMIC_OPERATOR_COMMANDS, id)\n ? ATOMIC_OPERATOR_COMMANDS[id as AtomicOperatorCommandId]\n : null;\n}\n","import type { CharacterFontId } from './types.js';\n\nexport type CharacterFontSpec = {\n id: CharacterFontId;\n label: string;\n titleKey:\n | 'defaultFont'\n | 'takweenFont'\n | 'diwaniFont'\n | 'diwaniOutlineFont'\n | 'maghribiFont';\n cssClass?: string;\n mathJaxClass?: string;\n macro?: string;\n latexFontCommand?: string;\n latexFontFamily?: string;\n browserFontStack?: string;\n importAliases?: string[];\n svgLayoutKey?: string;\n};\n\nexport const CHARACTER_FONT_SPECS: CharacterFontSpec[] = [\n {\n id: 'default',\n label: 'س',\n titleKey: 'defaultFont',\n },\n {\n id: 'takween',\n label: 'تك',\n titleKey: 'takweenFont',\n cssClass: 'node-value--takween',\n mathJaxClass: 'butex-takween-text',\n macro: '\\\\butextakween',\n latexFontCommand: '\\\\takween',\n latexFontFamily: 'Takween',\n browserFontStack: '\"BuTeX Takween\", Amiri, \"Segoe UI\", Tahoma, sans-serif',\n importAliases: ['\\\\takween'],\n svgLayoutKey: 'takween',\n },\n {\n id: 'diwani',\n label: 'ديو',\n titleKey: 'diwaniFont',\n cssClass: 'node-value--diwani',\n mathJaxClass: 'butex-diwani-text',\n macro: '\\\\butexdiwani',\n latexFontCommand: '\\\\diwani',\n latexFontFamily: 'Diwani Letter',\n browserFontStack: '\"Diwani Letter\", Amiri, \"Segoe UI\", Tahoma, sans-serif',\n importAliases: ['\\\\diwani'],\n svgLayoutKey: 'diwani',\n },\n {\n id: 'diwaniOutline',\n label: 'ظل',\n titleKey: 'diwaniOutlineFont',\n cssClass: 'node-value--diwani-outline',\n mathJaxClass: 'butex-diwani-outline-text',\n macro: '\\\\butexdiwanioutline',\n latexFontCommand: '\\\\diwanioutlineshaded',\n latexFontFamily: 'Diwani Outline Shaded',\n browserFontStack: '\"BuTeX Diwani Outline\", \"Diwani Letter\", Amiri, \"Segoe UI\", Tahoma, sans-serif',\n importAliases: ['\\\\diwanioutlineshaded'],\n svgLayoutKey: 'diwani-outline',\n },\n {\n id: 'maghribi',\n label: 'مغ',\n titleKey: 'maghribiFont',\n cssClass: 'node-value--maghribi',\n mathJaxClass: 'butex-maghribi-text',\n macro: '\\\\butexmaghribi',\n latexFontCommand: '\\\\maghribi',\n latexFontFamily: 'Almaghribi Warsh Quran',\n browserFontStack: '\"Almaghribi Warsh Quran\", Amiri, \"Segoe UI\", Tahoma, sans-serif',\n svgLayoutKey: 'maghribi',\n },\n];\n\nexport const CHARACTER_FONT_OPTIONS = CHARACTER_FONT_SPECS.map(({ id, label }) => ({ id, label }));\n\nexport const NON_DEFAULT_CHARACTER_FONT_SPECS = CHARACTER_FONT_SPECS.filter(\n (font): font is CharacterFontSpec & { macro: string } => font.id !== 'default' && typeof font.macro === 'string',\n);\n\nexport function characterFontSpec(fontId: CharacterFontId): CharacterFontSpec {\n return CHARACTER_FONT_SPECS.find((font) => font.id === fontId) ?? CHARACTER_FONT_SPECS[0];\n}\n\nexport function characterFontSpecByMacro(macro: string): CharacterFontSpec | null {\n return NON_DEFAULT_CHARACTER_FONT_SPECS.find(\n (font) => font.macro === macro || font.importAliases?.includes(macro),\n ) ?? null;\n}\n","import type { EditorChain, EditorNode } from '../types.js';\n\ntype BuildChain = (chain: EditorChain) => HTMLElement;\n\nexport const DELIMITER_CSS = `\n.delim-pair {\n display: inline-flex;\n align-items: stretch;\n min-height: 1.85em;\n}\n\n.delim-inner {\n display: inline-flex;\n align-items: center;\n}\n\n.delim {\n display: inline-flex;\n align-self: stretch;\n align-items: center;\n justify-content: center;\n color: var(--butex-delim-color, #475569);\n padding: 0 1px;\n min-height: 100%;\n}\n\n.delim-glyph {\n display: inline-flex;\n align-items: center;\n line-height: 1;\n font-size: clamp(20px, 1.08em + 0.8vh, 36px);\n transform: translateY(-20%) scaleY(var(--butex-delim-scale, 1));\n transform-origin: center;\n}\n`.trim();\n\nconst DELIMITER_BASE_HEIGHT_PX = 18;\nconst DELIMITER_MAX_SCALE = 4.8;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nfunction applyDelimiterScale(pair: HTMLElement, inner: HTMLElement): void {\n const innerHeight = Math.max(inner.getBoundingClientRect().height, DELIMITER_BASE_HEIGHT_PX);\n const scale = clamp((innerHeight / DELIMITER_BASE_HEIGHT_PX) * 1.18, 1.18, DELIMITER_MAX_SCALE);\n pair.style.setProperty('--butex-delim-scale', scale.toFixed(3));\n}\n\nfunction visibleDelimiter(expr: string): string {\n return expr\n .replace('\\\\left', '')\n .replace('\\\\right', '')\n .replace('\\\\{', '{')\n .replace('\\\\}', '}');\n}\n\nexport function buildDelimiterNodeBody(node: EditorNode, buildChain: BuildChain): HTMLElement {\n const pair = document.createElement('span');\n pair.className = 'delim-pair';\n\n const left = document.createElement('span');\n left.className = 'delim delim--left';\n const leftGlyph = document.createElement('span');\n leftGlyph.className = 'delim-glyph';\n leftGlyph.textContent = visibleDelimiter(node.leftDelimExpr);\n left.appendChild(leftGlyph);\n pair.appendChild(left);\n\n const inner = document.createElement('span');\n inner.className = 'delim-inner';\n if (node.innerExpr) {\n inner.appendChild(buildChain(node.innerExpr));\n }\n pair.appendChild(inner);\n\n const right = document.createElement('span');\n right.className = 'delim delim--right';\n const rightGlyph = document.createElement('span');\n rightGlyph.className = 'delim-glyph';\n rightGlyph.textContent = visibleDelimiter(node.rightDelimExpr);\n right.appendChild(rightGlyph);\n pair.appendChild(right);\n\n applyDelimiterScale(pair, inner);\n requestAnimationFrame(() => applyDelimiterScale(pair, inner));\n\n return pair;\n}\n","import type { EditorChain, EditorNode } from '../types.js';\n\ntype BuildChain = (chain: EditorChain) => HTMLElement;\n\nexport const FRAC_CSS = `\n.frac {\n display: inline-flex;\n flex-direction: column;\n align-items: stretch;\n justify-content: center;\n vertical-align: middle;\n margin: 0 3px;\n min-width: 1.5em;\n}\n\n.frac-num,\n.frac-den {\n display: inline-flex;\n justify-content: center;\n align-items: center;\n min-height: 1.1em;\n padding: 0 4px;\n}\n\n.frac-bar {\n align-self: stretch;\n height: 1px;\n background: var(--butex-frac-bar, currentColor);\n opacity: 0.88;\n}\n`.trim();\n\nexport function buildFracNodeBody(node: EditorNode, buildChain: BuildChain): HTMLElement {\n const wrap = document.createElement('span');\n wrap.className = 'frac';\n\n const num = document.createElement('span');\n num.className = 'frac-num';\n if (node.numerator) {\n num.appendChild(buildChain(node.numerator));\n }\n\n const bar = document.createElement('span');\n bar.className = 'frac-bar';\n bar.setAttribute('aria-hidden', 'true');\n\n const den = document.createElement('span');\n den.className = 'frac-den';\n if (node.denominator) {\n den.appendChild(buildChain(node.denominator));\n }\n\n wrap.appendChild(num);\n wrap.appendChild(bar);\n wrap.appendChild(den);\n\n return wrap;\n}\n","import type { EditorChain, EditorNode, EditorSide } from '../types.js';\n\ntype BuildChain = (chain: EditorChain) => HTMLElement;\n\nexport const SQRT_CSS = `\n.sqrt {\n display: inline-flex;\n align-items: stretch;\n position: relative;\n vertical-align: middle;\n margin: 0 2px;\n min-height: 2.1em;\n direction: ltr;\n --butex-sqrt-scale: 1;\n}\n\n.sqrt.sqrt--english .sqrt-root {\n order: 1;\n}\n\n.sqrt.sqrt--english .sqrt-sign {\n order: 2;\n}\n\n.sqrt.sqrt--english .sqrt-radicand {\n order: 3;\n}\n\n.sqrt.sqrt--arabic .sqrt-radicand {\n order: 1;\n}\n\n.sqrt.sqrt--arabic .sqrt-sign {\n order: 2;\n}\n\n.sqrt.sqrt--arabic .sqrt-root {\n order: 3;\n}\n\n.sqrt.sqrt--arabic .sqrt-root,\n.sqrt.sqrt--arabic .sqrt-radicand {\n direction: rtl;\n}\n\n.sqrt-root {\n align-self: flex-start;\n min-width: 0.9em;\n min-height: 1em;\n margin-inline-end: -0.18em;\n transform: translate(0.16em, 0.02em);\n font-size: 0.64em;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n position: relative;\n z-index: 1;\n}\n\n.sqrt.sqrt--arabic .sqrt-root {\n margin-inline-start: -0.22em;\n margin-inline-end: 0;\n transform: translate(-0.16em, 0.02em);\n}\n\n.sqrt-root .chain {\n min-height: auto;\n}\n\n.sqrt-sign {\n display: inline-flex;\n align-items: flex-end;\n justify-content: center;\n align-self: stretch;\n line-height: 0.78;\n font-size: 2em;\n color: var(--butex-sqrt-color, currentColor);\n transform: scaleY(var(--butex-sqrt-scale));\n transform-origin: center bottom;\n margin-inline-end: -0.24em;\n min-height: 100%;\n position: relative;\n z-index: 1;\n}\n\n.sqrt.sqrt--arabic .sqrt-sign {\n transform: scaleX(-1) scaleY(var(--butex-sqrt-scale));\n margin-inline-start: -0.24em;\n margin-inline-end: 0;\n}\n\n.sqrt-radicand {\n display: inline-flex;\n align-items: center;\n min-width: 1.35em;\n min-height: 1.35em;\n padding: 0.06em 0.24em 0;\n border-top: 2px solid var(--butex-sqrt-bar, currentColor);\n transform: translateY(-0.08em);\n position: relative;\n}\n\n.sqrt-radicand .chain {\n min-height: auto;\n}\n`.trim();\n\nconst SQRT_BASE_HEIGHT_PX = 32;\nconst SQRT_MAX_SCALE = 3.8;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nfunction applySqrtScale(wrap: HTMLElement, radicand: HTMLElement): void {\n const radicandHeight = Math.max(radicand.getBoundingClientRect().height, SQRT_BASE_HEIGHT_PX);\n const scale = clamp(radicandHeight / SQRT_BASE_HEIGHT_PX, 1, SQRT_MAX_SCALE);\n wrap.style.setProperty('--butex-sqrt-scale', scale.toFixed(3));\n}\n\nexport function buildSqrtNodeBody(node: EditorNode, buildChain: BuildChain, side: EditorSide): HTMLElement {\n const wrap = document.createElement('span');\n wrap.className = `sqrt sqrt--${side}`;\n\n const root = document.createElement('span');\n root.className = 'sqrt-root';\n if (node.rootIndex) {\n root.appendChild(buildChain(node.rootIndex));\n }\n\n const sign = document.createElement('span');\n sign.className = 'sqrt-sign';\n sign.setAttribute('aria-hidden', 'true');\n sign.textContent = '\\u221a';\n\n const radicand = document.createElement('span');\n radicand.className = 'sqrt-radicand';\n if (node.radicand) {\n radicand.appendChild(buildChain(node.radicand));\n }\n\n wrap.appendChild(root);\n wrap.appendChild(sign);\n wrap.appendChild(radicand);\n\n applySqrtScale(wrap, radicand);\n requestAnimationFrame(() => applySqrtScale(wrap, radicand));\n\n return wrap;\n}\n","import type { EditorChain, EditorNode } from '../types.js';\n\ntype BuildChain = (chain: EditorChain) => HTMLElement;\n\nexport const OVERSET_CSS = `\n.overset {\n display: inline-flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n vertical-align: middle;\n margin: 0 2px;\n min-width: 1.2em;\n}\n\n.overset-over {\n display: inline-flex;\n justify-content: center;\n align-items: center;\n min-height: 0.85em;\n padding: 0 2px;\n font-size: 0.72em;\n line-height: 1.1;\n}\n\n.overset-base {\n display: inline-flex;\n justify-content: center;\n align-items: center;\n min-height: 1.05em;\n padding: 0 2px;\n}\n`.trim();\n\nexport function buildOversetNodeBody(node: EditorNode, buildChain: BuildChain): HTMLElement {\n const wrap = document.createElement('span');\n wrap.className = 'overset';\n\n const over = document.createElement('span');\n over.className = 'overset-over';\n if (node.overExpr) {\n over.appendChild(buildChain(node.overExpr));\n }\n\n const base = document.createElement('span');\n base.className = 'overset-base';\n if (node.baseExpr) {\n base.appendChild(buildChain(node.baseExpr));\n }\n\n wrap.appendChild(over);\n wrap.appendChild(base);\n return wrap;\n}\n","import type { EditorChain, EditorNode } from '../types.js';\n\ntype BuildChain = (chain: EditorChain) => HTMLElement;\n\nexport const UNDERSET_CSS = `\n.underset {\n display: inline-flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n vertical-align: middle;\n margin: 0 2px;\n min-width: 1.2em;\n}\n\n.underset-base {\n display: inline-flex;\n justify-content: center;\n align-items: center;\n min-height: 1.05em;\n padding: 0 2px;\n}\n\n.underset-under {\n display: inline-flex;\n justify-content: center;\n align-items: center;\n min-height: 0.85em;\n padding: 0 2px;\n font-size: 0.72em;\n line-height: 1.1;\n}\n`.trim();\n\nexport function buildUndersetNodeBody(node: EditorNode, buildChain: BuildChain): HTMLElement {\n const wrap = document.createElement('span');\n wrap.className = 'underset';\n\n const base = document.createElement('span');\n base.className = 'underset-base';\n if (node.baseExpr) {\n base.appendChild(buildChain(node.baseExpr));\n }\n\n const under = document.createElement('span');\n under.className = 'underset-under';\n if (node.underExpr) {\n under.appendChild(buildChain(node.underExpr));\n }\n\n wrap.appendChild(base);\n wrap.appendChild(under);\n return wrap;\n}\n","import { accentCommandSpec } from '../accentCommands.js';\nimport type { EditorChain, EditorNode } from '../types.js';\n\ntype BuildChain = (chain: EditorChain) => HTMLElement;\n\nexport const ACCENT_CSS = `\n.math-accent {\n display: inline-flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n vertical-align: middle;\n margin: 0 2px;\n min-width: 1.1em;\n}\n\n.math-accent-chrome {\n display: inline-flex;\n justify-content: center;\n align-items: center;\n min-height: 0.7em;\n padding: 0 2px;\n font-size: 0.85em;\n line-height: 1;\n color: var(--butex-script-color, #475569);\n user-select: none;\n}\n\n.math-accent-base {\n display: inline-flex;\n justify-content: center;\n align-items: center;\n min-height: 1.05em;\n padding: 0 2px;\n}\n\n.math-accent--under .math-accent-chrome {\n min-height: 0.45em;\n border-top: 1.5px solid currentColor;\n width: 100%;\n font-size: 0;\n color: var(--butex-surface-fg, #0f172a);\n}\n`.trim();\n\nexport function buildAccentNodeBody(node: EditorNode, buildChain: BuildChain): HTMLElement {\n const wrap = document.createElement('span');\n const spec = accentCommandSpec(node.expr);\n const placement = spec?.placement ?? 'over';\n wrap.className = placement === 'under' ? 'math-accent math-accent--under' : 'math-accent math-accent--over';\n\n const chrome = document.createElement('span');\n chrome.className = 'math-accent-chrome';\n chrome.setAttribute('aria-hidden', 'true');\n if (placement === 'over') {\n chrome.textContent = spec?.label ?? 'ˆ';\n }\n\n const base = document.createElement('span');\n base.className = 'math-accent-base';\n if (node.baseExpr) {\n base.appendChild(buildChain(node.baseExpr));\n }\n\n if (placement === 'under') {\n wrap.appendChild(base);\n wrap.appendChild(chrome);\n } else {\n wrap.appendChild(chrome);\n wrap.appendChild(base);\n }\n return wrap;\n}\n","import type { EditorChain, EditorNode, EditorSide, MatrixEnvStyle } from '../types.js';\n\ntype BuildChain = (chain: EditorChain) => HTMLElement;\n\nconst WRAPPERS: Record<MatrixEnvStyle, { left: string; right: string }> = {\n matrix: { left: '', right: '' },\n pmatrix: { left: '(', right: ')' },\n bmatrix: { left: '[', right: ']' },\n Bmatrix: { left: '{', right: '}' },\n vmatrix: { left: '|', right: '|' },\n Vmatrix: { left: '||', right: '||' },\n};\n\nexport const MATRIX_ENV_CSS = `\n.matrix-env {\n display: inline-flex;\n align-items: stretch;\n vertical-align: middle;\n margin: 0 3px;\n --butex-matrix-delim-scale: 1.25;\n}\n\n.matrix-env__wrapper {\n display: inline-flex;\n align-self: stretch;\n align-items: center;\n justify-content: center;\n min-width: 0.42em;\n padding: 0 2px;\n color: var(--butex-delim-color, currentColor);\n font-family: ui-serif, \"Cambria Math\", \"Times New Roman\", serif;\n font-size: clamp(22px, 1.35em + 0.8vh, 42px);\n line-height: 1;\n transform: scaleY(var(--butex-matrix-delim-scale));\n transform-origin: center;\n}\n\n.matrix-env__grid {\n display: inline-grid;\n direction: ltr;\n gap: 2px 5px;\n align-items: center;\n justify-items: center;\n padding: 2px 3px;\n}\n\n.matrix-env__cell {\n min-width: 1.35em;\n min-height: 1.45em;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 5px;\n border: 1px dashed rgba(148, 163, 184, 0.48);\n padding: 1px 3px;\n}\n\n.matrix-env__cell .chain {\n min-height: auto;\n}\n\n.matrix-env--arabic .matrix-env__cell {\n direction: rtl;\n}\n\n.matrix-env--english .matrix-env__cell {\n direction: ltr;\n}\n`.trim();\n\nconst MATRIX_DELIMITER_BASE_HEIGHT_PX = 20;\nconst MATRIX_DELIMITER_MAX_SCALE = 5.2;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nfunction applyMatrixDelimiterScale(wrap: HTMLElement, grid: HTMLElement): void {\n const gridHeight = Math.max(grid.getBoundingClientRect().height, MATRIX_DELIMITER_BASE_HEIGHT_PX);\n const scale = clamp((gridHeight / MATRIX_DELIMITER_BASE_HEIGHT_PX) * 1.22, 1.25, MATRIX_DELIMITER_MAX_SCALE);\n wrap.style.setProperty('--butex-matrix-delim-scale', scale.toFixed(3));\n}\n\nexport function buildMatrixEnvNodeBody(node: EditorNode, buildChain: BuildChain, side: EditorSide): HTMLElement {\n const wrap = document.createElement('span');\n wrap.className = `matrix-env matrix-env--${side}`;\n\n const style = node.envName ?? node.matrixStyle ?? 'matrix';\n const glyphs = style === 'array' || style === 'aligned' ? undefined : WRAPPERS[style];\n\n const left = document.createElement('span');\n left.className = 'matrix-env__wrapper matrix-env__wrapper--left';\n left.textContent = glyphs?.left ?? '';\n\n const grid = document.createElement('span');\n grid.className = 'matrix-env__grid';\n\n const rows = node.matrixRows ?? [];\n const columnCount = Math.max(1, ...rows.map((row) => row.length));\n grid.style.gridTemplateColumns = `repeat(${String(columnCount)}, minmax(1.35em, auto))`;\n\n const displayRows = side === 'arabic' ? rows.map((row) => row.slice().reverse()) : rows;\n for (const row of displayRows) {\n for (const cellChain of row) {\n const cell = document.createElement('span');\n cell.className = 'matrix-env__cell';\n cell.dir = side === 'arabic' ? 'rtl' : 'ltr';\n cell.appendChild(buildChain(cellChain));\n grid.appendChild(cell);\n }\n }\n\n const right = document.createElement('span');\n right.className = 'matrix-env__wrapper matrix-env__wrapper--right';\n right.textContent = glyphs?.right ?? '';\n\n wrap.appendChild(left);\n wrap.appendChild(grid);\n wrap.appendChild(right);\n\n applyMatrixDelimiterScale(wrap, grid);\n requestAnimationFrame(() => applyMatrixDelimiterScale(wrap, grid));\n\n return wrap;\n}\n","import diwaniLetterUrl from './fonts/Diwani Letter Regular.ttf';\nimport diwaniOutlineUrl from './fonts/DWNOUTSH.TTF';\nimport maghribiUrl from './fonts/Almaghribi-Warsh-Quran.otf';\nimport takweenUrl from './fonts/Takween.otf';\n\n\nexport const BUTEX_DIWANI_FONT_FAMILY = 'Diwani Letter';\nexport const BUTEX_DIWANI_OUTLINE_FONT_FAMILY = 'BuTeX Diwani Outline';\nexport const BUTEX_MAGHRIBI_FONT_FAMILY = 'Almaghribi Warsh Quran';\nexport const BUTEX_TAKWEEN_FONT_FAMILY = 'BuTeX Takween';\n\nexport const BUTEX_DIWANI_FONT_STACK = `\"${BUTEX_DIWANI_FONT_FAMILY}\", Amiri, \"Segoe UI\", Tahoma, sans-serif`;\nexport const BUTEX_DIWANI_OUTLINE_FONT_STACK = `\"${BUTEX_DIWANI_OUTLINE_FONT_FAMILY}\", \"${BUTEX_DIWANI_FONT_FAMILY}\", Amiri, \"Segoe UI\", Tahoma, sans-serif`;\nexport const BUTEX_MAGHRIBI_FONT_STACK = `\"${BUTEX_MAGHRIBI_FONT_FAMILY}\", Amiri, \"Segoe UI\", Tahoma, sans-serif`;\nexport const BUTEX_TAKWEEN_FONT_STACK = `\"${BUTEX_TAKWEEN_FONT_FAMILY}\", Amiri, \"Segoe UI\", Tahoma, sans-serif`;\n\nexport const BUTEX_DIWANI_FONT_FACE_CSS = `\n@font-face {\n font-family: \"${BUTEX_DIWANI_FONT_FAMILY}\";\n src: url(\"${diwaniLetterUrl}\") format(\"truetype\");\n font-weight: 400;\n font-style: normal;\n font-display: swap;\n}\n`.trim();\n\nexport const BUTEX_TAKWEEN_FONT_FACE_CSS = `\n@font-face {\n font-family: \"${BUTEX_TAKWEEN_FONT_FAMILY}\";\n src: url(\"${takweenUrl}\") format(\"opentype\");\n font-weight: 400;\n font-style: normal;\n font-display: swap;\n}\n`.trim();\n\nexport const BUTEX_DIWANI_OUTLINE_FONT_FACE_CSS = `\n@font-face {\n font-family: \"${BUTEX_DIWANI_OUTLINE_FONT_FAMILY}\";\n src: url(\"${diwaniOutlineUrl}\") format(\"truetype\");\n font-weight: 400;\n font-style: normal;\n font-display: swap;\n}\n`.trim();\n\nexport const BUTEX_MAGHRIBI_FONT_FACE_CSS = `\n@font-face {\n font-family: \"${BUTEX_MAGHRIBI_FONT_FAMILY}\";\n src: url(\"${maghribiUrl}\") format(\"opentype\");\n font-weight: 400;\n font-style: normal;\n font-display: swap;\n}\n`.trim();\n\nexport const BUTEX_FONT_FACE_CSS = `\n${BUTEX_DIWANI_FONT_FACE_CSS}\n\n${BUTEX_DIWANI_OUTLINE_FONT_FACE_CSS}\n\n${BUTEX_TAKWEEN_FONT_FACE_CSS}\n\n${BUTEX_MAGHRIBI_FONT_FACE_CSS}\n`.trim();\n","import { atomicCommandSpec, isSpacingCommandSpec, type AtomicCommandSpec, type SpacingCommandSpec } from '../atomicCommands.js';\nimport { BUTEX_DIWANI_FONT_STACK, BUTEX_DIWANI_OUTLINE_FONT_STACK } from '../../diwani-font.js';\nimport type { EditorNode, EditorSide } from '../types.js';\nimport type { ButexUiLocale } from '../../uiLocale.js';\nimport { atomicCommandTitle } from '../uiLocale.js';\n\nexport const ATOMIC_COMMAND_CSS = `\n/* Shared atomic-command display */\n.atomic-command {\n display: inline-flex;\n align-items: center;\n font-weight: 600;\n line-height: 1;\n}\n\n/* Function-style commands: sin/cos/tan families. */\n.atomic-command--arabic {\n font-family: ${BUTEX_DIWANI_FONT_STACK};\n font-size: 1.15em;\n direction: rtl;\n}\n\n.atomic-command--diwani-outline {\n font-family: ${BUTEX_DIWANI_OUTLINE_FONT_STACK};\n}\n\n.atomic-command--english {\n font-family: \"Cambria Math\", \"Times New Roman\", serif;\n font-size: 0.96em;\n}\n\n.atomic-command-label-with-sub {\n position: relative;\n display: inline-block;\n padding-inline-end: 0.45em;\n padding-block-end: 0.22em;\n line-height: 1;\n}\n\n.atomic-command-label-with-sub__sub {\n position: absolute;\n inset-inline-end: 0;\n inset-block-end: 0;\n font-size: 0.62em;\n line-height: 1;\n}\n\n/* Spacing commands: tiny selectable marker, real spacing remains in LaTeX preview. */\n.atomic-spacing {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 3px;\n min-width: 3px;\n height: 1em;\n color: var(--butex-accent, currentColor);\n opacity: 0.62;\n}\n\n.atomic-spacing__marker {\n display: inline-block;\n width: 3px;\n height: 0.85em;\n border-radius: 999px;\n background: currentColor;\n}\n\n.atomic-spacing--negative {\n color: var(--butex-danger, #dc2626);\n}\n`.trim();\n\nfunction spacingArrowForSide(spec: SpacingCommandSpec, side: EditorSide): string {\n const pointsWithFlow = spec.spacing.direction === 'positive';\n if (pointsWithFlow) {\n return side === 'arabic' ? '\\u2190' : '\\u2192';\n }\n return side === 'arabic' ? '\\u2192' : '\\u2190';\n}\n\nexport function spacingTooltipForSide(spec: SpacingCommandSpec, side: EditorSide, uiLocale: ButexUiLocale = 'ar'): string {\n return `${atomicCommandTitle(spec, uiLocale)} ${spacingArrowForSide(spec, side).repeat(spec.spacing.level)}`;\n}\n\nfunction buildFunctionAtomicCommandBody(node: EditorNode, side: EditorSide, spec: AtomicCommandSpec | null): HTMLElement {\n const value = document.createElement('span');\n value.className = `atomic-command atomic-command--${side}`;\n if (side === 'arabic' && spec?.category === 'groups') {\n value.classList.add('atomic-command--diwani-outline');\n }\n if (side === 'arabic' && node.expr === 'ln') {\n const label = document.createElement('span');\n label.className = 'atomic-command-label-with-sub';\n const base = document.createElement('span');\n base.className = 'atomic-command-label-with-sub__base';\n base.textContent = spec?.arabicLabel ?? node.expr;\n const sub = document.createElement('span');\n sub.className = 'atomic-command-label-with-sub__sub';\n sub.textContent = 'هـ';\n label.append(base, sub);\n value.appendChild(label);\n return value;\n }\n value.textContent = side === 'arabic'\n ? spec?.arabicLabel ?? node.expr\n : spec?.englishLabel ?? spec?.englishTex.replace(/^\\\\/, '') ?? node.expr;\n return value;\n}\n\nfunction buildSpacingAtomicCommandBody(spec: SpacingCommandSpec, side: EditorSide, uiLocale: ButexUiLocale): HTMLElement {\n const value = document.createElement('span');\n value.className = `atomic-spacing atomic-spacing--${spec.spacing.direction} atomic-spacing--level-${String(spec.spacing.level)}`;\n value.title = spacingTooltipForSide(spec, side, uiLocale);\n const marker = document.createElement('span');\n marker.className = 'atomic-spacing__marker';\n value.appendChild(marker);\n return value;\n}\n\nexport function buildAtomicCommandNodeBody(node: EditorNode, side: EditorSide, uiLocale: ButexUiLocale = 'ar'): HTMLElement {\n const spec = atomicCommandSpec(node.expr);\n if (isSpacingCommandSpec(spec)) {\n return buildSpacingAtomicCommandBody(spec, side, uiLocale);\n }\n return buildFunctionAtomicCommandBody(node, side, spec);\n}\n","import { atomicOperatorCommandSpec, shouldMirrorOperatorDisplay, type AtomicOperatorCommandSpec } from '../atomicCommandsOperators.js';\nimport type { EditorNode, EditorSide } from '../types.js';\nimport type { ButexUiLocale } from '../../uiLocale.js';\nimport { atomicOperatorCommandTitle } from '../uiLocale.js';\n\nexport const ATOMIC_OPERATOR_COMMAND_CSS = `\n.atomic-operator-command {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 0.9em;\n font-family: \"Cambria Math\", \"Times New Roman\", serif;\n font-size: 1.05em;\n font-weight: 600;\n line-height: 1;\n}\n\n.atomic-operator-command--mirrored {\n transform: scaleX(-1);\n}\n\n.atomic-operator-command__svg {\n width: 1em;\n height: 1em;\n background: currentColor;\n}\n`.trim();\n\nfunction buildOperatorLabel(spec: AtomicOperatorCommandSpec): HTMLElement {\n const value = document.createElement('span');\n value.className = 'atomic-operator-command__label';\n value.textContent = spec.Label;\n return value;\n}\n\nexport function buildAtomicOperatorCommandNodeBody(node: EditorNode, side: EditorSide, uiLocale: ButexUiLocale = 'ar'): HTMLElement {\n const spec = atomicOperatorCommandSpec(node.expr);\n const value = document.createElement('span');\n value.className = 'atomic-operator-command';\n value.title = spec ? atomicOperatorCommandTitle(spec, uiLocale) : node.expr;\n if (side === 'arabic' && shouldMirrorOperatorDisplay(spec)) {\n value.classList.add('atomic-operator-command--mirrored');\n }\n\n if (spec?.svg_path) {\n const icon = document.createElement('span');\n icon.className = 'atomic-operator-command__svg';\n icon.style.mask = `url(\"${spec.svg_path}\") center / contain no-repeat`;\n icon.style.webkitMask = `url(\"${spec.svg_path}\") center / contain no-repeat`;\n value.appendChild(icon);\n return value;\n }\n\n if (spec) {\n value.appendChild(buildOperatorLabel(spec));\n } else {\n const label = document.createElement('span');\n label.className = 'atomic-operator-command__label';\n label.textContent = node.expr;\n value.appendChild(label);\n }\n return value;\n}\n","import { DELIMITER_CSS } from './display/delimiter.js';\nimport { FRAC_CSS } from './display/frac.js';\nimport { SQRT_CSS } from './display/sqrt.js';\nimport { OVERSET_CSS } from './display/overset.js';\nimport { UNDERSET_CSS } from './display/underset.js';\nimport { ACCENT_CSS } from './display/accent.js';\nimport { MATRIX_ENV_CSS } from './display/env.js';\nimport { ATOMIC_COMMAND_CSS } from './display/atomicCommand.js';\nimport { ATOMIC_OPERATOR_COMMAND_CSS } from './display/atomicCommandsOperators.js';\nimport { BUTEX_FONT_FACE_CSS } from '../diwani-font.js';\nimport { NON_DEFAULT_CHARACTER_FONT_SPECS } from './characterFonts.js';\n\nconst CHARACTER_FONT_CSS = NON_DEFAULT_CHARACTER_FONT_SPECS\n .filter((font) => font.cssClass && font.browserFontStack)\n .map((font) => `.${font.cssClass} {\\n font-family: ${font.browserFontStack};\\n}`)\n .join('\\n\\n');\n\nexport const BUTEX_EDITOR_CSS = `\n${BUTEX_FONT_FACE_CSS}\n\n.surface {\n border: 1px solid var(--butex-border, #e2e8f0);\n border-radius: 12px;\n min-height: 100px;\n padding: 8px 10px;\n background: var(--butex-surface-bg, linear-gradient(180deg, #ffffff 0%, #fafbfc 100%));\n color: var(--butex-surface-fg, #0f172a);\n outline: none;\n cursor: text;\n transition: box-shadow 0.15s ease, border-color 0.15s ease;\n}\n\n.surface:focus,\n.surface.surface--typing-focus {\n border-color: var(--butex-focus-border, rgba(13, 148, 136, 0.45));\n box-shadow: 0 0 0 3px var(--butex-focus-shadow, rgba(13, 148, 136, 0.12));\n}\n\n.surface.surface--arabic {\n direction: rtl;\n}\n\n.surface.surface--english {\n direction: ltr;\n}\n\n${CHARACTER_FONT_CSS}\n\n.chain {\n display: inline-flex;\n align-items: center;\n gap: 0;\n min-height: 28px;\n flex-wrap: wrap;\n row-gap: 2px;\n}\n\n.slot {\n width: 5px;\n min-height: 28px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n border-radius: 3px;\n}\n\n.slot:hover {\n background: var(--butex-slot-hover, rgba(13, 148, 136, 0.08));\n}\n\n.slot.range-highlight {\n background: var(--butex-selection-bg, rgba(13, 148, 136, 0.34));\n width: 11px;\n min-height: 42px;\n border: 2px solid var(--butex-selection-border, rgba(15, 118, 110, 0.9));\n position: relative;\n z-index: 1;\n}\n\n.caret {\n display: inline-block;\n width: 2px;\n height: 20px;\n background: var(--butex-caret, #0f172a);\n border-radius: 1px;\n animation: butex-editor-blink 1s step-end infinite;\n}\n\n@keyframes butex-editor-blink {\n 50% { opacity: 0; }\n}\n\n.node {\n display: inline-flex;\n align-items: stretch;\n gap: 3px;\n border-radius: 8px;\n padding: 2px 4px;\n cursor: pointer;\n border: 1px solid transparent;\n user-select: none;\n}\n\n.node.node--atomic-spacing {\n padding-inline: 0;\n margin-inline: -2px;\n border-color: transparent;\n}\n\n.node:hover {\n border-color: var(--butex-border, #e2e8f0);\n background: var(--butex-node-hover, rgba(148, 163, 184, 0.08));\n}\n\n.node.selected {\n background: var(--butex-node-selected-bg, rgba(13, 148, 136, 0.14));\n border-color: var(--butex-node-selected-border, rgba(13, 148, 136, 0.45));\n}\n\n.node.range-highlight {\n background: var(--butex-selection-bg, rgba(13, 148, 136, 0.34));\n border-color: var(--butex-selection-border, rgba(15, 118, 110, 0.9));\n box-shadow: inset 0 0 0 3px var(--butex-selection-border, rgba(15, 118, 110, 0.9)),\n 0 0 0 1px var(--butex-selection-border, rgba(15, 118, 110, 0.9));\n position: relative;\n z-index: 2;\n}\n\n.chain .slot.range-highlight + .node.range-highlight,\n.chain .node.range-highlight + .slot.range-highlight {\n margin-inline: -1px;\n}\n\n.node-body {\n display: inline-flex;\n align-items: stretch;\n gap: 0;\n min-height: 1.6em;\n}\n\n.node-value {\n font-size: 16px;\n font-weight: 500;\n line-height: 1.25;\n display: inline-flex;\n align-items: center;\n}\n\n.scripts {\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n justify-content: space-between;\n align-items: center;\n padding: 1px 0;\n min-width: 0.75em;\n}\n\n.scripts.scripts--sup-only {\n justify-content: flex-start;\n padding-bottom: 2px;\n}\n\n.scripts.scripts--sub-only {\n justify-content: flex-end;\n padding-top: 2px;\n}\n\n.script-box {\n min-height: 12px;\n min-width: 10px;\n border-radius: 4px;\n border: 1px dashed var(--butex-script-border, #cbd5e1);\n padding: 0 2px;\n font-size: 0.68em;\n line-height: 1.15;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: var(--butex-script-bg, rgba(248, 250, 252, 0.95));\n color: var(--butex-script-color, #475569);\n}\n\n.script-box .chain {\n min-height: auto;\n}\n\n${DELIMITER_CSS}\n\n${FRAC_CSS}\n\n${SQRT_CSS}\n\n${OVERSET_CSS}\n\n${UNDERSET_CSS}\n\n${ACCENT_CSS}\n\n${MATRIX_ENV_CSS}\n\n${ATOMIC_COMMAND_CSS}\n\n${ATOMIC_OPERATOR_COMMAND_CSS}\n`.trim();\n\n/**\n * Injects BuTeX editor surface styles into `document.head` if not already present.\n * Browser-only; no-op if `document` is undefined (Node).\n */\nexport function injectBuTeXEditorStyles(doc?: Document): void {\n const d = doc ?? (typeof document !== 'undefined' ? document : undefined);\n if (!d) {\n return;\n }\n const id = 'butex-editor-styles';\n const existing = d.getElementById(id);\n if (existing) {\n existing.textContent = BUTEX_EDITOR_CSS;\n return;\n }\n const style = d.createElement('style');\n style.id = id;\n style.textContent = BUTEX_EDITOR_CSS;\n d.head.appendChild(style);\n}\n","import type { CharacterFontId } from '../editor/types.js';\nimport { NON_DEFAULT_CHARACTER_FONT_SPECS } from '../editor/characterFonts.js';\n\nexport type NormalizedCharImport = {\n expr: string;\n characterFont: CharacterFontId;\n};\n\ntype WrapperSpec = {\n prefix: string;\n font?: CharacterFontId;\n};\n\nconst WRAPPER_SPECS: WrapperSpec[] = [\n ...NON_DEFAULT_CHARACTER_FONT_SPECS.flatMap((font) => [\n { prefix: font.macro, font: font.id },\n ...(font.importAliases ?? []).map((alias) => ({ prefix: alias, font: font.id })),\n ]),\n { prefix: '\\\\text' },\n];\n\nfunction readBracedArg(source: string, openBraceIndex: number): { inner: string; end: number } | null {\n if (source[openBraceIndex] !== '{') {\n return null;\n }\n\n let depth = 0;\n for (let index = openBraceIndex; index < source.length; index += 1) {\n const char = source[index];\n if (char === '{') {\n depth += 1;\n } else if (char === '}') {\n depth -= 1;\n if (depth === 0) {\n return { inner: source.slice(openBraceIndex + 1, index), end: index + 1 };\n }\n }\n }\n\n return null;\n}\n\nfunction peelWrapper(source: string): { inner: string; font?: CharacterFontId } | null {\n for (const wrapper of WRAPPER_SPECS) {\n if (!source.startsWith(wrapper.prefix)) {\n continue;\n }\n\n const braced = readBracedArg(source, wrapper.prefix.length);\n if (!braced || braced.end !== source.length) {\n continue;\n }\n\n return { inner: braced.inner, font: wrapper.font };\n }\n\n return null;\n}\n\nexport function normalizeCharImportExpr(expr: string): NormalizedCharImport {\n const original = expr;\n let current = expr;\n let characterFont: CharacterFontId = 'default';\n let changed = false;\n\n while (true) {\n const peeled = peelWrapper(current);\n if (!peeled) {\n break;\n }\n\n current = peeled.inner;\n if (peeled.font) {\n characterFont = peeled.font;\n }\n changed = true;\n }\n\n if (!changed) {\n return { expr: original, characterFont: 'default' };\n }\n\n if (current.includes('\\\\')) {\n return { expr: original, characterFont: 'default' };\n }\n\n return { expr: current, characterFont };\n}\n","import {\n BaseAstNode,\n ChainNode,\n CharNode,\n CommandNode,\n DelimiterNode,\n EnvNode,\n NumberNode,\n OperatorNode,\n} from '../ast/arabic_ast.js';\nimport {\n accentCommandIdFromTex,\n accentCommandSpec,\n} from '../editor/accentCommands.js';\nimport {\n ATOMIC_COMMANDS,\n atomicCommandSpec,\n type AtomicCommandId,\n} from '../editor/atomicCommands.js';\nimport {\n ATOMIC_OPERATOR_COMMANDS,\n atomicOperatorCommandSpec,\n type AtomicOperatorCommandId,\n} from '../editor/atomicCommandsOperators.js';\nimport {\n buildInitialSyncMap,\n cloneEditorSession,\n createAccentNode,\n createDelimiterNode,\n createEditorChain,\n createEditorNode,\n createEditorSession,\n createFracNode,\n createGridEnvNode,\n createSqrtNode,\n createOversetNode,\n createUndersetNode,\n renderArabicLatexFromSession,\n} from '../editor/index.js';\nimport { NON_DEFAULT_CHARACTER_FONT_SPECS } from '../editor/characterFonts.js';\nimport type {\n CharacterFontId,\n EditorChain,\n EditorNode,\n EditorSession,\n EnvColumnAlignment,\n GridEnvName,\n MatrixEnvStyle,\n} from '../editor/index.js';\nimport { normalizeCharImportExpr } from './normalizeCharImport.js';\nimport type { MathNode } from './types.js';\n\ntype CommandFontPolicy = CharacterFontId | 'infer';\n\nconst COMMAND_FONT_MAP: Record<string, CommandFontPolicy> = Object.fromEntries([\n ['\\\\text', 'infer'],\n ...NON_DEFAULT_CHARACTER_FONT_SPECS.flatMap((font) => [\n [font.macro, font.id],\n ...(font.importAliases ?? []).map((alias) => [alias, font.id]),\n ]),\n]) as Record<string, CommandFontPolicy>;\n\nconst CHAR_FONT_EXPORT_TEX: Record<Exclude<CharacterFontId, 'default'>, string> = Object.fromEntries(\n NON_DEFAULT_CHARACTER_FONT_SPECS.map((font) => [font.id, font.macro]),\n) as Record<Exclude<CharacterFontId, 'default'>, string>;\n\nfunction charEditorNodeToAstNode(node: EditorNode): BaseAstNode {\n const font = node.characterFont ?? 'default';\n const charNode = new CharNode(node.expr);\n if (font === 'default') {\n return charNode;\n }\n return new CommandNode(CHAR_FONT_EXPORT_TEX[font], [], [new ChainNode([charNode])]);\n}\n\nexport type MathEditorAdapterResult =\n | { editable: true; session: EditorSession }\n | { editable: false; reason: string };\n\ntype NodeAdapterResult =\n | { editable: true; node: EditorNode }\n | { editable: false; reason: string };\n\ntype UnsupportedAdapterResult = { editable: false; reason: string };\n\nexport type MathNodeFromEditorResult =\n | { ok: true; math: MathNode }\n | { ok: false; reason: string };\n\nfunction commandIdForTex(tex: string): AtomicCommandId | null {\n for (const spec of Object.values(ATOMIC_COMMANDS)) {\n const renderTex = (spec as { arabicRenderTex?: string }).arabicRenderTex;\n if (spec.englishTex === tex || spec.arabicTex === tex || renderTex === tex) {\n return spec.id as AtomicCommandId;\n }\n }\n return null;\n}\n\nfunction operatorCommandIdForTex(tex: string): AtomicOperatorCommandId | null {\n for (const spec of Object.values(ATOMIC_OPERATOR_COMMANDS)) {\n if (spec.Tex === tex) {\n return spec.id as AtomicOperatorCommandId;\n }\n }\n return null;\n}\n\nfunction cloneChainWithFreshIds(chain: EditorChain): EditorChain {\n return structuredClone(chain);\n}\n\nfunction attachScripts(astNode: { superscript: ChainNode | null; subscript: ChainNode | null }, editorNode: EditorNode): UnsupportedAdapterResult | null {\n if (astNode.superscript) {\n const sup = chainToEditorChain(astNode.superscript);\n if (!sup.editable) {\n return sup;\n }\n editorNode.superscript = sup.chain;\n }\n if (astNode.subscript) {\n const sub = chainToEditorChain(astNode.subscript);\n if (!sub.editable) {\n return sub;\n }\n editorNode.subscript = sub.chain;\n }\n return null;\n}\n\ntype ChainAdapterResult =\n | { editable: true; chain: EditorChain }\n | { editable: false; reason: string };\n\nconst MATRIX_ENV_NAMES = new Set<GridEnvName>(['matrix', 'pmatrix', 'bmatrix', 'Bmatrix', 'vmatrix', 'Vmatrix']);\n\nfunction isGridEnvName(value: string): value is GridEnvName {\n return MATRIX_ENV_NAMES.has(value as GridEnvName) || value === 'array' || value === 'aligned';\n}\n\nfunction isMatrixEnvName(value: GridEnvName): value is MatrixEnvStyle {\n return MATRIX_ENV_NAMES.has(value);\n}\n\nfunction parseEnvOpening(opening: string): { envName: GridEnvName; alignments?: EnvColumnAlignment[] } | null {\n const match = /^\\\\begin\\{([^}]+)\\}(?:\\{([lcr]+)\\})?$/.exec(opening);\n if (!match) {\n return null;\n }\n\n const envName = match[1] ?? '';\n if (!isGridEnvName(envName)) {\n return null;\n }\n\n if (envName === 'array') {\n const spec = match[2] ?? 'c';\n return {\n envName,\n alignments: spec.split('').map((alignment) => alignment as EnvColumnAlignment),\n };\n }\n\n return { envName };\n}\n\nfunction splitEnvLine(line: ChainNode): ChainNode[] {\n const cells: ChainNode[] = [];\n let current: BaseAstNode[] = [];\n for (const node of line.chain) {\n if (node instanceof OperatorNode && node.expr === '&') {\n cells.push(new ChainNode(current));\n current = [];\n } else {\n current.push(node);\n }\n }\n cells.push(new ChainNode(current));\n return cells;\n}\n\nfunction envToEditorNode(node: EnvNode): NodeAdapterResult {\n const parsed = parseEnvOpening(node.opening);\n if (!parsed) {\n return { editable: false, reason: `بيئة رياضية غير مدعومة حاليا: ${node.opening}` };\n }\n\n const expectedClosing = `\\\\end{${parsed.envName}}`;\n if (node.closing !== expectedClosing) {\n return { editable: false, reason: `إغلاق بيئة رياضية غير مدعوم حاليا: ${node.closing}` };\n }\n\n const rowCells = node.lines.map(splitEnvLine);\n const rows = Math.max(1, rowCells.length);\n const columns = Math.max(1, ...rowCells.map((row) => row.length));\n const env = createGridEnvNode(parsed.envName, rows, columns, parsed.alignments);\n\n for (let rowIndex = 0; rowIndex < rows; rowIndex += 1) {\n const row = rowCells[rowIndex] ?? [];\n for (let columnIndex = 0; columnIndex < columns; columnIndex += 1) {\n const cell = chainToEditorChain(row[columnIndex] ?? new ChainNode());\n if (!cell.editable) {\n return cell;\n }\n env.matrixRows![rowIndex]![columnIndex] = cell.chain;\n }\n }\n\n if (parsed.envName === 'array') {\n env.columnAlignments = Array.from(\n { length: columns },\n (_, index) => parsed.alignments?.[index] ?? 'c',\n );\n }\n if (isMatrixEnvName(parsed.envName)) {\n env.matrixStyle = parsed.envName;\n }\n\n const scripts = attachScripts(node, env);\n return scripts ?? { editable: true, node: env };\n}\n\nfunction charFromTextLikeCommand(node: CommandNode): NodeAdapterResult | null {\n const commandFont = COMMAND_FONT_MAP[node.name];\n if (commandFont === undefined) {\n return null;\n }\n if (node.optionalArgs.length > 0 || node.mandatoryArgs.length !== 1) {\n return null;\n }\n\n const arg = node.mandatoryArgs[0]!;\n if (arg.chain.length !== 1) {\n return null;\n }\n\n const child = arg.chain[0]!;\n if (child instanceof CommandNode) {\n const nested = charFromTextLikeCommand(child);\n if (!nested?.editable) {\n return null;\n }\n if (commandFont !== 'infer') {\n nested.node.characterFont = commandFont;\n }\n const scripts = attachScripts(node, nested.node);\n return scripts ?? nested;\n }\n\n if (!(child instanceof CharNode)) {\n return null;\n }\n\n const normalized = normalizeCharImportExpr(child.expr);\n const characterFont = commandFont === 'infer' ? normalized.characterFont : commandFont;\n const editorNode = createEditorNode('char', normalized.expr);\n if (characterFont !== 'default') {\n editorNode.characterFont = characterFont;\n }\n const scripts = attachScripts(node, editorNode);\n return scripts ?? { editable: true, node: editorNode };\n}\n\nfunction commandToEditorNode(node: CommandNode): NodeAdapterResult {\n if (node.name === '\\\\frac' && node.mandatoryArgs.length >= 2) {\n const frac = createFracNode();\n const numerator = chainToEditorChain(node.mandatoryArgs[0]!);\n const denominator = chainToEditorChain(node.mandatoryArgs[1]!);\n if (!numerator.editable) {\n return numerator;\n }\n if (!denominator.editable) {\n return denominator;\n }\n frac.numerator = numerator.chain;\n frac.denominator = denominator.chain;\n const scripts = attachScripts(node, frac);\n if (scripts) {\n return scripts;\n }\n return { editable: true, node: frac };\n }\n\n if (\n (node.name === '\\\\sqrt' || node.name === '\\\\arabsqrt' || node.name === '\\\\arsqrt') &&\n node.mandatoryArgs.length >= 1\n ) {\n const sqrt = createSqrtNode();\n const radicand = chainToEditorChain(node.mandatoryArgs[0]!);\n if (!radicand.editable) {\n return radicand;\n }\n sqrt.radicand = radicand.chain;\n if (node.optionalArgs[0]) {\n const rootIndex = chainToEditorChain(node.optionalArgs[0]);\n if (!rootIndex.editable) {\n return rootIndex;\n }\n sqrt.rootIndex = rootIndex.chain;\n }\n const scripts = attachScripts(node, sqrt);\n if (scripts) {\n return scripts;\n }\n return { editable: true, node: sqrt };\n }\n\n if (node.name === '\\\\overset' && node.mandatoryArgs.length >= 2) {\n const overset = createOversetNode();\n const overExpr = chainToEditorChain(node.mandatoryArgs[0]!);\n const baseExpr = chainToEditorChain(node.mandatoryArgs[1]!);\n if (!overExpr.editable) {\n return overExpr;\n }\n if (!baseExpr.editable) {\n return baseExpr;\n }\n overset.overExpr = overExpr.chain;\n overset.baseExpr = baseExpr.chain;\n const scripts = attachScripts(node, overset);\n if (scripts) {\n return scripts;\n }\n return { editable: true, node: overset };\n }\n\n if (node.name === '\\\\underset' && node.mandatoryArgs.length >= 2) {\n const underset = createUndersetNode();\n const underExpr = chainToEditorChain(node.mandatoryArgs[0]!);\n const baseExpr = chainToEditorChain(node.mandatoryArgs[1]!);\n if (!underExpr.editable) {\n return underExpr;\n }\n if (!baseExpr.editable) {\n return baseExpr;\n }\n underset.underExpr = underExpr.chain;\n underset.baseExpr = baseExpr.chain;\n const scripts = attachScripts(node, underset);\n if (scripts) {\n return scripts;\n }\n return { editable: true, node: underset };\n }\n\n const accentId = accentCommandIdFromTex(node.name);\n if (accentId && node.mandatoryArgs.length >= 1) {\n const accent = createAccentNode(accentId);\n const baseExpr = chainToEditorChain(node.mandatoryArgs[0]!);\n if (!baseExpr.editable) {\n return baseExpr;\n }\n accent.baseExpr = baseExpr.chain;\n const scripts = attachScripts(node, accent);\n if (scripts) {\n return scripts;\n }\n return { editable: true, node: accent };\n }\n\n const atomicId = commandIdForTex(node.name);\n if (atomicId && node.optionalArgs.length === 0 && node.mandatoryArgs.length === 0) {\n const atomic = createEditorNode('atomicCommand', atomicId);\n const scripts = attachScripts(node, atomic);\n if (scripts) {\n return scripts;\n }\n return { editable: true, node: atomic };\n }\n\n const operatorId = operatorCommandIdForTex(node.name);\n if (operatorId && node.optionalArgs.length === 0 && node.mandatoryArgs.length === 0) {\n const atomicOperator = createEditorNode('atomicOperatorCommand', operatorId);\n const scripts = attachScripts(node, atomicOperator);\n if (scripts) {\n return scripts;\n }\n return { editable: true, node: atomicOperator };\n }\n\n const textLike = charFromTextLikeCommand(node);\n if (textLike) {\n return textLike;\n }\n\n return { editable: false, reason: `أمر رياضي غير مدعوم حاليا: ${node.name}` };\n}\n\nfunction astNodeToEditorNode(node: ChainNode['chain'][number]): NodeAdapterResult {\n if (node instanceof CharNode) {\n const normalized = normalizeCharImportExpr(node.expr);\n const editorNode = createEditorNode('char', normalized.expr);\n if (normalized.characterFont !== 'default') {\n editorNode.characterFont = normalized.characterFont;\n }\n const scripts = attachScripts(node, editorNode);\n return scripts ?? { editable: true, node: editorNode };\n }\n if (node instanceof NumberNode) {\n const editorNode = createEditorNode('number', node.expr);\n const scripts = attachScripts(node, editorNode);\n return scripts ?? { editable: true, node: editorNode };\n }\n if (node instanceof OperatorNode) {\n return { editable: true, node: createEditorNode('operator', node.expr) };\n }\n if (node instanceof DelimiterNode) {\n const editorNode = createDelimiterNode(node.leftDelimExpr, node.rightDelimExpr);\n const inner = chainToEditorChain(node.innerExpr);\n if (!inner.editable) {\n return inner;\n }\n editorNode.innerExpr = inner.chain;\n const scripts = attachScripts(node, editorNode);\n return scripts ?? { editable: true, node: editorNode };\n }\n if (node instanceof CommandNode) {\n return commandToEditorNode(node);\n }\n if (node instanceof EnvNode) {\n return envToEditorNode(node);\n }\n return { editable: false, reason: `عقدة رياضية غير مدعومة حاليا: ${node.nodeType}` };\n}\n\nfunction chainToEditorChain(chain: ChainNode): ChainAdapterResult {\n const nodes: EditorNode[] = [];\n for (const astNode of chain.chain) {\n const converted = astNodeToEditorNode(astNode);\n if (!converted.editable) {\n return converted;\n }\n nodes.push(converted.node);\n }\n return { editable: true, chain: createEditorChain(nodes) };\n}\n\nexport function mathObjectToEditorSession(math: MathNode): MathEditorAdapterResult {\n if (math.lines.length !== 1) {\n return { editable: false, reason: 'تحرير المعادلات متعددة الأسطر داخل المستند غير مدعوم بعد' };\n }\n\n const english = chainToEditorChain(math.lines[0]!);\n if (!english.editable) {\n return english;\n }\n\n const arabic = cloneChainWithFreshIds(english.chain);\n const session = createEditorSession(english.chain, arabic, 'english');\n session.sync = buildInitialSyncMap(session.englishTree, session.arabicTree);\n return { editable: true, session: cloneEditorSession(session) };\n}\n\ntype AstNodeResult =\n | { ok: true; node: BaseAstNode }\n | { ok: false; reason: string };\n\ntype AstChainResult =\n | { ok: true; chain: ChainNode }\n | { ok: false; reason: string };\n\nfunction attachAstScripts(editorNode: EditorNode, astNode: BaseAstNode): AstNodeResult | null {\n if (editorNode.superscript) {\n const sup = editorChainToAstChain(editorNode.superscript);\n if (!sup.ok) {\n return sup;\n }\n astNode.superscript = sup.chain;\n }\n if (editorNode.subscript) {\n const sub = editorChainToAstChain(editorNode.subscript);\n if (!sub.ok) {\n return sub;\n }\n astNode.subscript = sub.chain;\n }\n return null;\n}\n\nfunction editorEnvOpening(node: EditorNode): { opening: string; closing: string } | null {\n const envName = node.envName ?? node.matrixStyle;\n if (!envName) {\n return null;\n }\n if (envName === 'array') {\n const spec = (node.columnAlignments ?? []).slice(0, node.matrixRows?.[0]?.length ?? 0).join('') || 'c';\n return { opening: `\\\\begin{array}{${spec}}`, closing: '\\\\end{array}' };\n }\n return { opening: `\\\\begin{${envName}}`, closing: `\\\\end{${envName}}` };\n}\n\nfunction editorEnvToAstNode(node: EditorNode): AstNodeResult {\n const wrapper = editorEnvOpening(node);\n if (!wrapper || !node.matrixRows) {\n return { ok: false, reason: 'بيئة رياضية غير مدعومة حاليا' };\n }\n const lines: ChainNode[] = [];\n for (const row of node.matrixRows) {\n const lineNodes: BaseAstNode[] = [];\n for (let columnIndex = 0; columnIndex < row.length; columnIndex += 1) {\n if (columnIndex > 0) {\n lineNodes.push(new OperatorNode('&'));\n }\n const cell = editorChainToAstChain(row[columnIndex]!);\n if (!cell.ok) {\n return cell;\n }\n lineNodes.push(...cell.chain.chain);\n }\n lines.push(new ChainNode(lineNodes));\n }\n const env = new EnvNode(wrapper.opening, lines, wrapper.closing);\n const scripts = attachAstScripts(node, env);\n return scripts ?? { ok: true, node: env };\n}\n\nfunction accentChainForExport(accent: EditorChain | null): AstChainResult {\n if (!accent) {\n return { ok: true, chain: new ChainNode([]) };\n }\n return editorChainToAstChain(accent);\n}\n\n/** When accent is empty, unwrap to base (single node or invisible group). */\nfunction nodeFromAccentBase(\n command: '\\\\overset' | '\\\\underset',\n accent: ChainNode,\n base: ChainNode,\n): BaseAstNode {\n if (accent.chain.length > 0) {\n return new CommandNode(command, [], [accent, base]);\n }\n if (base.chain.length === 1) {\n return base.chain[0]!;\n }\n return new DelimiterNode('', base, '');\n}\n\nfunction editorNodeToAstNode(node: EditorNode): AstNodeResult {\n let astNode: BaseAstNode;\n\n if (node.kind === 'char') {\n astNode = charEditorNodeToAstNode(node);\n } else if (node.kind === 'number') {\n astNode = new NumberNode(node.expr);\n } else if (node.kind === 'operator') {\n astNode = new OperatorNode(node.expr);\n } else if (node.kind === 'delimiter' && node.innerExpr) {\n const inner = editorChainToAstChain(node.innerExpr);\n if (!inner.ok) {\n return inner;\n }\n astNode = new DelimiterNode(node.leftDelimExpr, inner.chain, node.rightDelimExpr);\n } else if (node.kind === 'frac' && node.numerator && node.denominator) {\n const numerator = editorChainToAstChain(node.numerator);\n const denominator = editorChainToAstChain(node.denominator);\n if (!numerator.ok) {\n return numerator;\n }\n if (!denominator.ok) {\n return denominator;\n }\n astNode = new CommandNode('\\\\frac', [], [numerator.chain, denominator.chain]);\n } else if (node.kind === 'sqrt' && node.radicand) {\n const radicand = editorChainToAstChain(node.radicand);\n if (!radicand.ok) {\n return radicand;\n }\n const optionalArgs: ChainNode[] = [];\n if (node.rootIndex && node.rootIndex.nodes.length > 0) {\n const rootIndex = editorChainToAstChain(node.rootIndex);\n if (!rootIndex.ok) {\n return rootIndex;\n }\n optionalArgs.push(rootIndex.chain);\n }\n astNode = new CommandNode('\\\\sqrt', optionalArgs, [radicand.chain]);\n } else if (node.kind === 'overset' && node.baseExpr) {\n const accent = accentChainForExport(node.overExpr);\n if (!accent.ok) {\n return accent;\n }\n const baseExpr = editorChainToAstChain(node.baseExpr);\n if (!baseExpr.ok) {\n return baseExpr;\n }\n astNode = nodeFromAccentBase('\\\\overset', accent.chain, baseExpr.chain);\n } else if (node.kind === 'underset' && node.baseExpr) {\n const accent = accentChainForExport(node.underExpr);\n if (!accent.ok) {\n return accent;\n }\n const baseExpr = editorChainToAstChain(node.baseExpr);\n if (!baseExpr.ok) {\n return baseExpr;\n }\n astNode = nodeFromAccentBase('\\\\underset', accent.chain, baseExpr.chain);\n } else if (node.kind === 'accent' && node.baseExpr) {\n const tex = accentCommandSpec(node.expr)?.englishTex;\n if (!tex) {\n return { ok: false, reason: `لكنة رياضية غير مدعومة حاليا: ${node.expr}` };\n }\n const baseExpr = editorChainToAstChain(node.baseExpr);\n if (!baseExpr.ok) {\n return baseExpr;\n }\n astNode = new CommandNode(tex, [], [baseExpr.chain]);\n } else if (node.kind === 'atomicCommand') {\n const tex = atomicCommandSpec(node.expr)?.englishTex;\n if (!tex) {\n return { ok: false, reason: `أمر رياضي غير مدعوم حاليا: ${node.expr}` };\n }\n astNode = new CommandNode(tex);\n } else if (node.kind === 'atomicOperatorCommand') {\n const tex = atomicOperatorCommandSpec(node.expr)?.Tex;\n if (!tex) {\n return { ok: false, reason: `رمز رياضي غير مدعوم حاليا: ${node.expr}` };\n }\n astNode = new CommandNode(tex);\n } else if (node.kind === 'env') {\n return editorEnvToAstNode(node);\n } else {\n return { ok: false, reason: `عقدة رياضية غير مدعومة حاليا: ${node.kind}` };\n }\n\n const scripts = attachAstScripts(node, astNode);\n return scripts ?? { ok: true, node: astNode };\n}\n\nfunction editorChainToAstChain(chain: EditorChain): AstChainResult {\n const nodes: BaseAstNode[] = [];\n for (const editorNode of chain.nodes) {\n const converted = editorNodeToAstNode(editorNode);\n if (!converted.ok) {\n return converted;\n }\n nodes.push(converted.node);\n }\n return { ok: true, chain: new ChainNode(nodes) };\n}\n\nexport function mathNodeFromEditorSession(\n session: EditorSession,\n mathMode = '$',\n closing = '$',\n): MathNodeFromEditorResult {\n const converted = editorChainToAstChain(session.englishTree);\n if (!converted.ok) {\n return converted;\n }\n return {\n ok: true,\n math: {\n nodeType: 'MathObject',\n mathMode,\n lines: [converted.chain],\n closing,\n },\n };\n}\n\n/** Delimited Arabic TeX for document text/preview — matches `<ButexEditor />` arabic output. */\nexport function mathSourceFromEditorSession(\n session: EditorSession,\n mathMode = '$',\n closing = '$',\n): string {\n const inner = renderArabicLatexFromSession(session);\n if (mathMode === '$' || mathMode === '\\\\(') {\n return mathMode + inner + closing;\n }\n if (mathMode === '$$' || mathMode === '\\\\[') {\n if (!inner.includes('\\n')) {\n return `${mathMode}\\n${inner}\\n${closing}`;\n }\n return `${mathMode}\\n${inner.split('\\n').map((line) => ` ${line}`).join(' \\\\\\\\\\n')}\\n${closing}`;\n }\n return `${mathMode}\\n ${inner}\\n${closing}`;\n}\n\nexport function mathSourceWithReplacement(source: string, replacementInnerLatex: string): string {\n if (source.startsWith('$$') && source.endsWith('$$')) {\n return `$$${replacementInnerLatex}$$`;\n }\n if (source.startsWith('$') && source.endsWith('$')) {\n return `$${replacementInnerLatex}$`;\n }\n if (source.startsWith('\\\\(') && source.endsWith('\\\\)')) {\n return `\\\\(${replacementInnerLatex}\\\\)`;\n }\n if (source.startsWith('\\\\[') && source.endsWith('\\\\]')) {\n return `\\\\[${replacementInnerLatex}\\\\]`;\n }\n const begin = /^\\\\begin\\{([A-Za-z*]+)\\}/.exec(source);\n if (begin) {\n const opening = begin[0] ?? '';\n const closing = `\\\\end{${begin[1] ?? ''}}`;\n if (source.endsWith(closing)) {\n return `${opening}${replacementInnerLatex}${closing}`;\n }\n }\n return replacementInnerLatex;\n}\n","import { document2Id } from './ids.js';\nimport { cloneDocument2Meta, emptyDocument2Meta, normalizeDocument2HijriDate } from './articleMeta.js';\nimport { createEmptyReference2 } from './citations.js';\nimport { createInlineField2 } from './importJson.js';\nimport { applyFloatMetaPatch, defaultFloatMeta, type FloatMetaPatch } from './labels.js';\nimport { mathNodeFromSession, mathSourceFromSession } from './mathBridge.js';\nimport type {\n BibliographyBlock2,\n CiteToken2,\n Document2Block,\n Document2Node,\n ImageBlock2,\n InlineField2,\n InlineToken2,\n ListBlock2,\n MathToken2,\n Reference2,\n Reference2Json,\n RefToken2,\n TableBlock2,\n TextStyle2,\n TextToken2,\n} from './types.js';\nimport type { Document2MetaProp } from './articleMeta.js';\nimport type { EditorSession, EditorSide } from '../editor/index.js';\n\nexport type Document2ImageAssetRef = {\n assetId: string;\n value?: string;\n};\n\ntype Document2ImageInput = string | Document2ImageAssetRef | undefined;\n\nfunction cloneToken(token: InlineToken2): InlineToken2 {\n return token.kind === 'text' ? { ...token } : { ...token };\n}\n\nfunction cloneField(field: InlineField2): InlineField2 {\n return { id: field.id, tokens: field.tokens.map(cloneToken) };\n}\n\nfunction cloneBlock(block: Document2Block): Document2Block {\n if (block.kind === 'textBlock') {\n return { ...block, field: cloneField(block.field) };\n }\n if (block.kind === 'list') {\n return {\n ...block,\n items: block.items.map((item) => ({\n ...item,\n field: cloneField(item.field),\n blocks: item.blocks.map(cloneBlock),\n })),\n };\n }\n if (block.kind === 'table') {\n return { ...block, rows: block.rows.map((row) => row.map(cloneField)) };\n }\n if (block.kind === 'image') {\n return { ...block, options: { ...block.options } };\n }\n return { ...block };\n}\n\nfunction cloneDocument(document: Document2Node): Document2Node {\n return {\n nodeType: 'DocumentObject',\n meta: cloneDocument2Meta(document.meta ?? emptyDocument2Meta()),\n references: document.references.map((reference) => ({ ...reference })),\n blocks: document.blocks.map(cloneBlock),\n diagnostics: document.diagnostics.map((diagnostic) => ({ ...diagnostic })),\n };\n}\n\nfunction visitFields(blocks: Document2Block[], visitor: (field: InlineField2) => boolean): boolean {\n for (const block of blocks) {\n if (block.kind === 'textBlock') {\n if (visitor(block.field)) {\n return true;\n }\n } else if (block.kind === 'list') {\n for (const item of block.items) {\n if (visitor(item.field) || visitFields(item.blocks, visitor)) {\n return true;\n }\n }\n } else if (block.kind === 'table') {\n for (const row of block.rows) {\n for (const cell of row) {\n if (visitor(cell)) {\n return true;\n }\n }\n }\n }\n }\n return false;\n}\n\nexport function findFirstInlineField(document: Document2Node): InlineField2 | null {\n let found: InlineField2 | null = null;\n visitFields(document.blocks, (field) => {\n found = field;\n return true;\n });\n return found;\n}\n\nexport function updateTextToken(document: Document2Node, fieldId: string, tokenId: string, text: string): Document2Node {\n const next = cloneDocument(document);\n visitFields(next.blocks, (field) => {\n if (field.id !== fieldId) {\n return false;\n }\n const token = field.tokens.find((entry): entry is TextToken2 => entry.id === tokenId && entry.kind === 'text');\n if (!token) {\n return true;\n }\n token.text = text;\n return true;\n });\n return next;\n}\n\nfunction mathTokenFromSession(session: EditorSession, opening = '$', closing = '$', side: EditorSide = 'arabic'): MathToken2 {\n return {\n id: document2Id('math'),\n kind: 'math',\n display: opening === '$$' || opening === '\\\\[' || opening.startsWith('\\\\begin{'),\n opening,\n closing,\n source: mathSourceFromSession(session, side, opening, closing),\n sourceSide: side,\n math: mathNodeFromSession(session, opening, closing),\n editable: true,\n sourceOwner: 'editor',\n };\n}\n\nfunction splitTextForInsertion(token: TextToken2): InlineToken2[] | null {\n const gap = token.text.indexOf(' ');\n if (gap < 0) {\n return null;\n }\n return [\n { id: token.id, kind: 'text', text: token.text.slice(0, gap + 1) },\n { id: document2Id('text'), kind: 'text', text: token.text.slice(gap + 1) },\n ];\n}\n\nexport function cloneDocument2Node(document: Document2Node): Document2Node {\n return cloneDocument(document);\n}\n\nfunction insertBlockAfter(blocks: Document2Block[], afterBlockId: string | null | undefined, block: Document2Block): void {\n if (!afterBlockId) {\n blocks.push(block);\n return;\n }\n const index = blocks.findIndex((entry) => entry.id === afterBlockId);\n if (index < 0) {\n blocks.push(block);\n return;\n }\n blocks.splice(index + 1, 0, block);\n}\n\nexport function insertDocument2BlockAfter(\n document: Document2Node,\n afterBlockId: string | null | undefined,\n block: Document2Block,\n): Document2Node {\n const next = cloneDocument(document);\n insertBlockAfter(next.blocks, afterBlockId, block);\n return next;\n}\n\nexport function moveDocument2BlockById(document: Document2Node, blockId: string, direction: -1 | 1): Document2Node {\n const next = cloneDocument(document);\n const index = next.blocks.findIndex((block) => block.id === blockId);\n const targetIndex = index + direction;\n if (index < 0 || targetIndex < 0 || targetIndex >= next.blocks.length) {\n return document;\n }\n const [block] = next.blocks.splice(index, 1);\n if (!block) {\n return document;\n }\n next.blocks.splice(targetIndex, 0, block);\n return next;\n}\n\nexport function moveDocument2BlockRange(\n document: Document2Node,\n from: number,\n to: number,\n direction: -1 | 1,\n): Document2Node {\n const count = document.blocks.length;\n if (from < 0 || to < 0 || from >= count || to >= count || from > to) {\n return document;\n }\n const insertAt = from + direction;\n if (insertAt < 0 || to + direction >= count) {\n return document;\n }\n const next = cloneDocument(document);\n const slice = next.blocks.splice(from, to - from + 1);\n next.blocks.splice(insertAt, 0, ...slice);\n return next;\n}\n\nexport function removeDocument2BlockRange(document: Document2Node, from: number, to: number): Document2Node {\n const count = document.blocks.length;\n if (from < 0 || to < 0 || from >= count || to >= count || from > to) {\n return document;\n }\n const next = cloneDocument(document);\n next.blocks = [...next.blocks.slice(0, from), ...next.blocks.slice(to + 1)];\n return next;\n}\n\nfunction normalizeFieldTokens(tokens: InlineToken2[]): InlineToken2[] {\n if (tokens.length === 0) {\n return [{ id: document2Id('text'), kind: 'text', text: '' }];\n }\n return tokens;\n}\n\nfunction textStylesEqual(a: TextStyle2 | undefined, b: TextStyle2 | undefined): boolean {\n return Boolean(a?.bold) === Boolean(b?.bold) && Boolean(a?.italic) === Boolean(b?.italic) && Boolean(a?.underline) === Boolean(b?.underline);\n}\n\nfunction compactAdjacentTextTokens(tokens: InlineToken2[]): InlineToken2[] {\n const compacted: InlineToken2[] = [];\n for (const token of tokens) {\n const previous = compacted[compacted.length - 1];\n if (previous?.kind === 'text' && token.kind === 'text' && textStylesEqual(previous.style, token.style)) {\n previous.text += token.text;\n } else {\n compacted.push(token);\n }\n }\n return normalizeFieldTokens(compacted);\n}\n\nfunction withoutEmptyStyle(style: TextStyle2): TextStyle2 | undefined {\n const next: TextStyle2 = {};\n if (style.bold) {\n next.bold = true;\n }\n if (style.italic) {\n next.italic = true;\n }\n if (style.underline) {\n next.underline = true;\n }\n return next.bold || next.italic || next.underline ? next : undefined;\n}\n\nfunction textTokenPart(text: string, style: TextStyle2 | undefined, id = document2Id('text')): TextToken2 {\n return { id, kind: 'text', text, ...(style ? { style } : {}) };\n}\n\nexport function toggleTextTokenStyle(\n document: Document2Node,\n fieldId: string,\n tokenId: string,\n selectionStart: number,\n selectionEnd: number,\n styleName: keyof TextStyle2,\n): Document2Node {\n if (selectionEnd <= selectionStart) {\n return document;\n }\n const next = cloneDocument(document);\n visitFields(next.blocks, (field) => {\n if (field.id !== fieldId) {\n return false;\n }\n const tokenIndex = field.tokens.findIndex((entry) => entry.id === tokenId && entry.kind === 'text');\n if (tokenIndex < 0) {\n return true;\n }\n const token = field.tokens[tokenIndex] as TextToken2;\n const start = Math.max(0, Math.min(token.text.length, selectionStart));\n const end = Math.max(0, Math.min(token.text.length, selectionEnd));\n if (end <= start) {\n return true;\n }\n const selectedStyle = token.style ?? {};\n const enabled = selectedStyle[styleName] === true;\n const nextStyle = withoutEmptyStyle({ ...selectedStyle, [styleName]: enabled ? undefined : true });\n const parts: InlineToken2[] = [];\n const before = token.text.slice(0, start);\n const selected = token.text.slice(start, end);\n const after = token.text.slice(end);\n if (before.length > 0) {\n parts.push(textTokenPart(before, token.style, token.id));\n }\n parts.push(textTokenPart(selected, nextStyle, before.length > 0 ? document2Id('text') : token.id));\n if (after.length > 0) {\n parts.push(textTokenPart(after, token.style));\n }\n field.tokens = compactAdjacentTextTokens([\n ...field.tokens.slice(0, tokenIndex),\n ...parts,\n ...field.tokens.slice(tokenIndex + 1),\n ]);\n return true;\n });\n return next;\n}\n\nfunction stitchTextAroundRemovedToken(tokens: InlineToken2[], index: number): InlineToken2[] {\n const before = tokens[index - 1];\n const after = tokens[index + 1];\n if (before?.kind === 'text' && after?.kind === 'text') {\n return [\n ...tokens.slice(0, index - 1),\n { ...before, text: before.text + after.text },\n ...tokens.slice(index + 2),\n ];\n }\n return [...tokens.slice(0, index), ...tokens.slice(index + 1)];\n}\n\nexport function removeMathTokenById(document: Document2Node, tokenId: string): Document2Node {\n const next = cloneDocument(document);\n visitFields(next.blocks, (field) => {\n const index = field.tokens.findIndex((token) => token.id === tokenId && token.kind === 'math');\n if (index < 0) {\n return false;\n }\n field.tokens = normalizeFieldTokens(stitchTextAroundRemovedToken(field.tokens, index));\n return true;\n });\n return next;\n}\n\nfunction splitTextTokenAt(token: TextToken2, offset: number): [TextToken2, TextToken2] {\n const safeOffset = Math.max(0, Math.min(offset, token.text.length));\n return [\n { id: token.id, kind: 'text', text: token.text.slice(0, safeOffset), ...(token.style ? { style: token.style } : {}) },\n { id: document2Id('text'), kind: 'text', text: token.text.slice(safeOffset), ...(token.style ? { style: token.style } : {}) },\n ];\n}\n\nexport function insertMathTokenAtCaret(\n document: Document2Node,\n fieldId: string,\n textTokenId: string | null,\n caretOffset: number,\n session: EditorSession,\n opening = '$',\n closing = '$',\n side: EditorSide = 'arabic',\n): Document2Node {\n const next = cloneDocument(document);\n const mathToken = mathTokenFromSession(session, opening, closing, side);\n visitFields(next.blocks, (field) => {\n if (field.id !== fieldId) {\n return false;\n }\n\n const textIndex = textTokenId\n ? field.tokens.findIndex((token) => token.id === textTokenId && token.kind === 'text')\n : field.tokens.findIndex((token) => token.kind === 'text');\n\n if (textIndex < 0) {\n field.tokens.push(mathToken);\n field.tokens.push({ id: document2Id('text'), kind: 'text', text: '' });\n return true;\n }\n\n const current = field.tokens[textIndex] as TextToken2;\n const [before, after] = splitTextTokenAt(current, caretOffset);\n const parts: InlineToken2[] = [...field.tokens.slice(0, textIndex)];\n if (before.text.length > 0) {\n parts.push(before);\n }\n parts.push(mathToken);\n parts.push(after);\n parts.push(...field.tokens.slice(textIndex + 1));\n field.tokens = normalizeFieldTokens(parts);\n return true;\n });\n return next;\n}\n\nexport function insertMathToken(\n document: Document2Node,\n fieldId: string,\n insertIndex: number,\n session: EditorSession,\n opening = '$',\n closing = '$',\n side: EditorSide = 'arabic',\n): Document2Node {\n const next = cloneDocument(document);\n const mathToken = mathTokenFromSession(session, opening, closing, side);\n visitFields(next.blocks, (field) => {\n if (field.id !== fieldId) {\n return false;\n }\n\n if (field.tokens.length === 1 && field.tokens[0]?.kind === 'text') {\n const split = splitTextForInsertion(field.tokens[0]);\n if (split) {\n field.tokens = [split[0]!, mathToken, split[1]!];\n return true;\n }\n }\n\n const safeIndex = Math.max(0, Math.min(insertIndex, field.tokens.length));\n field.tokens.splice(safeIndex, 0, mathToken);\n return true;\n });\n return next;\n}\n\nexport function replaceMathTokenFromSession(\n document: Document2Node,\n tokenId: string,\n session: EditorSession,\n opening?: string,\n closing?: string,\n side: EditorSide = 'arabic',\n): Document2Node {\n const next = cloneDocument(document);\n visitFields(next.blocks, (field) => {\n const index = field.tokens.findIndex((token) => token.id === tokenId && token.kind === 'math');\n if (index < 0) {\n return false;\n }\n const current = field.tokens[index] as MathToken2;\n const open = opening ?? current.opening;\n const close = closing ?? current.closing;\n const replaced = mathTokenFromSession(session, open, close, side);\n replaced.id = current.id;\n if (current.labelEnabled !== undefined) {\n replaced.labelEnabled = current.labelEnabled;\n }\n if (current.label !== undefined) {\n replaced.label = current.label;\n }\n field.tokens[index] = replaced;\n return true;\n });\n return next;\n}\n\nexport function addDocument2TextBlock(\n document: Document2Node,\n command: '\\\\section' | '\\\\subsection' | '\\\\subsubsection' | '\\\\paragraph' = '\\\\paragraph',\n afterBlockId?: string | null,\n): Document2Node {\n const block = {\n id: document2Id('block'),\n kind: 'textBlock' as const,\n command,\n field: createInlineField2(''),\n ...(command === '\\\\paragraph' ? { centered: false } : {}),\n };\n return insertDocument2BlockAfter(document, afterBlockId, block);\n}\n\nexport function updateDocument2TextBlockCentered(\n document: Document2Node,\n blockId: string,\n centered: boolean,\n): Document2Node {\n const next = cloneDocument(document);\n function visit(blocks: Document2Block[]): boolean {\n for (const block of blocks) {\n if (block.id === blockId && block.kind === 'textBlock' && block.command === '\\\\paragraph') {\n block.centered = centered;\n return true;\n }\n if (block.kind === 'list') {\n for (const item of block.items) {\n if (visit(item.blocks)) {\n return true;\n }\n }\n }\n }\n return false;\n }\n visit(next.blocks);\n return next;\n}\n\nexport function removeDocument2BlockById(document: Document2Node, blockId: string): Document2Node {\n const next = cloneDocument(document);\n next.blocks = next.blocks.filter((block) => block.id !== blockId);\n return next;\n}\n\nfunction newListBlock(ordered: boolean): ListBlock2 {\n const command: ListBlock2['command'] = ordered ? '\\\\begin{enumerate}' : '\\\\begin{itemize}';\n const closing = ordered ? '\\\\end{enumerate}' : '\\\\end{itemize}';\n return {\n id: document2Id('block'),\n kind: 'list',\n command,\n closing,\n items: [{ id: document2Id('item'), field: createInlineField2(''), blocks: [] }],\n };\n}\n\nexport function addDocument2ListBlock(document: Document2Node, ordered: boolean, afterBlockId?: string | null): Document2Node {\n return insertDocument2BlockAfter(document, afterBlockId, newListBlock(ordered));\n}\n\nexport function addDocument2TableBlock(\n document: Document2Node,\n columns = 'lll',\n rowCount = 3,\n colCount = 3,\n afterBlockId?: string | null,\n): Document2Node {\n const rows = Math.max(1, rowCount);\n const cols = Math.max(1, colCount);\n const tableRows: InlineField2[][] = [];\n for (let r = 0; r < rows; r += 1) {\n const row: InlineField2[] = [];\n for (let c = 0; c < cols; c += 1) {\n row.push(createInlineField2(''));\n }\n tableRows.push(row);\n }\n const block: TableBlock2 = {\n id: document2Id('block'),\n kind: 'table',\n command: '\\\\begin{tabular}',\n closing: '\\\\end{tabular}',\n columns: columns || 'l'.repeat(cols),\n rows: tableRows,\n ...defaultFloatMeta(),\n };\n return insertDocument2BlockAfter(document, afterBlockId, block);\n}\n\nfunction normalizeImageInput(srcOrAsset?: Document2ImageInput): { value: string; assetId?: string } {\n if (typeof srcOrAsset === 'string') {\n return srcOrAsset.length > 0 ? { value: srcOrAsset, assetId: srcOrAsset } : { value: '' };\n }\n if (srcOrAsset && srcOrAsset.assetId.length > 0) {\n return { value: srcOrAsset.value ?? srcOrAsset.assetId, assetId: srcOrAsset.assetId };\n }\n return { value: '' };\n}\n\nexport function addDocument2ImageBlock(\n document: Document2Node,\n srcOrAsset?: Document2ImageInput,\n afterBlockId?: string | null,\n): Document2Node {\n const image = normalizeImageInput(srcOrAsset);\n const block: ImageBlock2 = {\n id: document2Id('block'),\n kind: 'image',\n command: '\\\\includegraphics',\n value: image.value,\n ...(image.assetId !== undefined ? { assetId: image.assetId } : {}),\n options: { width: '0.8\\\\columnwidth' },\n ...defaultFloatMeta(),\n };\n return insertDocument2BlockAfter(document, afterBlockId, block);\n}\n\nexport function updateDocument2ImageValue(document: Document2Node, blockId: string, value: string): Document2Node {\n const next = cloneDocument(document);\n function visit(blocks: Document2Block[]): boolean {\n for (const block of blocks) {\n if (block.id === blockId && block.kind === 'image') {\n block.value = value;\n return true;\n }\n if (block.kind === 'list') {\n for (const item of block.items) {\n if (visit(item.blocks)) {\n return true;\n }\n }\n }\n }\n return false;\n }\n visit(next.blocks);\n return next;\n}\n\nexport function updateDocument2ImageAsset(document: Document2Node, blockId: string, asset: Document2ImageAssetRef): Document2Node {\n const next = cloneDocument(document);\n const image = normalizeImageInput(asset);\n function visit(blocks: Document2Block[]): boolean {\n for (const block of blocks) {\n if (block.id === blockId && block.kind === 'image') {\n block.value = image.value;\n if (image.assetId !== undefined) {\n block.assetId = image.assetId;\n } else {\n delete block.assetId;\n }\n return true;\n }\n if (block.kind === 'list') {\n for (const item of block.items) {\n if (visit(item.blocks)) {\n return true;\n }\n }\n }\n }\n return false;\n }\n visit(next.blocks);\n return next;\n}\n\nexport function clearDocument2ImageAsset(document: Document2Node, blockId: string): Document2Node {\n const next = cloneDocument(document);\n function visit(blocks: Document2Block[]): boolean {\n for (const block of blocks) {\n if (block.id === blockId && block.kind === 'image') {\n block.value = '';\n delete block.assetId;\n return true;\n }\n if (block.kind === 'list') {\n for (const item of block.items) {\n if (visit(item.blocks)) {\n return true;\n }\n }\n }\n }\n return false;\n }\n visit(next.blocks);\n return next;\n}\n\nexport function updateDocument2ImageMeta(document: Document2Node, blockId: string, patch: FloatMetaPatch): Document2Node {\n const next = cloneDocument(document);\n function visit(blocks: Document2Block[]): boolean {\n for (const block of blocks) {\n if (block.id === blockId && block.kind === 'image') {\n applyFloatMetaPatch(block, patch);\n return true;\n }\n if (block.kind === 'list') {\n for (const item of block.items) {\n if (visit(item.blocks)) {\n return true;\n }\n }\n }\n }\n return false;\n }\n visit(next.blocks);\n return next;\n}\n\nexport function updateDocument2TableMeta(document: Document2Node, blockId: string, patch: FloatMetaPatch): Document2Node {\n const next = cloneDocument(document);\n function visit(blocks: Document2Block[]): boolean {\n for (const block of blocks) {\n if (block.id === blockId && block.kind === 'table') {\n applyFloatMetaPatch(block, patch);\n return true;\n }\n if (block.kind === 'list') {\n for (const item of block.items) {\n if (visit(item.blocks)) {\n return true;\n }\n }\n }\n }\n return false;\n }\n visit(next.blocks);\n return next;\n}\n\nexport function updateMathTokenLabel(\n document: Document2Node,\n tokenId: string,\n patch: { labelEnabled?: boolean; label?: string },\n): Document2Node {\n const next = cloneDocument(document);\n visitFields(next.blocks, (field) => {\n const token = field.tokens.find((entry): entry is MathToken2 => entry.id === tokenId && entry.kind === 'math');\n if (!token) {\n return false;\n }\n if (typeof patch.labelEnabled === 'boolean') {\n token.labelEnabled = patch.labelEnabled;\n }\n if (typeof patch.label === 'string') {\n token.label = patch.label;\n }\n return true;\n });\n return next;\n}\n\nfunction refTokenFromKeys(keys: string[], refCommand: 'ref' | 'eqref'): RefToken2 {\n return { id: document2Id('ref'), kind: 'ref', keys: [...keys], refCommand };\n}\n\nexport function insertRefTokenAtCaret(\n document: Document2Node,\n fieldId: string,\n textTokenId: string | null,\n caretOffset: number,\n keys: string[],\n refCommand: 'ref' | 'eqref' = 'ref',\n): Document2Node {\n if (keys.length === 0) {\n return document;\n }\n const next = cloneDocument(document);\n const refToken = refTokenFromKeys(keys, refCommand);\n visitFields(next.blocks, (field) => {\n if (field.id !== fieldId) {\n return false;\n }\n\n const textIndex = textTokenId\n ? field.tokens.findIndex((token) => token.id === textTokenId && token.kind === 'text')\n : field.tokens.findIndex((token) => token.kind === 'text');\n\n if (textIndex < 0) {\n field.tokens.push(refToken);\n field.tokens.push({ id: document2Id('text'), kind: 'text', text: '' });\n return true;\n }\n\n const current = field.tokens[textIndex] as TextToken2;\n const [before, after] = splitTextTokenAt(current, caretOffset);\n const parts: InlineToken2[] = [...field.tokens.slice(0, textIndex)];\n if (before.text.length > 0) {\n parts.push(before);\n }\n parts.push(refToken);\n parts.push(after);\n parts.push(...field.tokens.slice(textIndex + 1));\n field.tokens = normalizeFieldTokens(parts);\n return true;\n });\n return next;\n}\n\nexport function updateRefTokenKeys(\n document: Document2Node,\n tokenId: string,\n keys: string[],\n refCommand?: 'ref' | 'eqref',\n): Document2Node {\n if (keys.length === 0) {\n return document;\n }\n const next = cloneDocument(document);\n visitFields(next.blocks, (field) => {\n const token = field.tokens.find((entry): entry is RefToken2 => entry.id === tokenId && entry.kind === 'ref');\n if (!token) {\n return false;\n }\n token.keys = [...keys];\n if (refCommand) {\n token.refCommand = refCommand;\n }\n return true;\n });\n return next;\n}\n\nexport function removeRefTokenById(document: Document2Node, tokenId: string): Document2Node {\n const next = cloneDocument(document);\n visitFields(next.blocks, (field) => {\n const index = field.tokens.findIndex((token) => token.id === tokenId && token.kind === 'ref');\n if (index < 0) {\n return false;\n }\n field.tokens = normalizeFieldTokens(stitchTextAroundRemovedToken(field.tokens, index));\n return true;\n });\n return next;\n}\n\nfunction mutateListBlockById(blocks: Document2Block[], listBlockId: string, mutator: (list: ListBlock2) => void): boolean {\n for (const block of blocks) {\n if (block.id === listBlockId && block.kind === 'list') {\n mutator(block);\n return true;\n }\n if (block.kind === 'list') {\n for (const item of block.items) {\n if (mutateListBlockById(item.blocks, listBlockId, mutator)) {\n return true;\n }\n }\n }\n }\n return false;\n}\n\nexport function addDocument2ListItem(document: Document2Node, listBlockId: string): Document2Node {\n const next = cloneDocument(document);\n mutateListBlockById(next.blocks, listBlockId, (list) => {\n list.items.push({ id: document2Id('item'), field: createInlineField2(''), blocks: [] });\n });\n return next;\n}\n\nexport function removeDocument2ListItem(document: Document2Node, listBlockId: string, itemId: string): Document2Node {\n const next = cloneDocument(document);\n mutateListBlockById(next.blocks, listBlockId, (list) => {\n if (list.items.length < 2) {\n return;\n }\n const index = list.items.findIndex((item) => item.id === itemId);\n if (index >= 0) {\n list.items.splice(index, 1);\n }\n });\n return next;\n}\n\nfunction citeTokenFromKeys(keys: string[]): CiteToken2 {\n return { id: document2Id('cite'), kind: 'cite', keys: [...keys] };\n}\n\nexport function insertCiteTokenAtCaret(\n document: Document2Node,\n fieldId: string,\n textTokenId: string | null,\n caretOffset: number,\n keys: string[],\n): Document2Node {\n if (keys.length === 0) {\n return document;\n }\n const next = cloneDocument(document);\n const citeToken = citeTokenFromKeys(keys);\n visitFields(next.blocks, (field) => {\n if (field.id !== fieldId) {\n return false;\n }\n\n const textIndex = textTokenId\n ? field.tokens.findIndex((token) => token.id === textTokenId && token.kind === 'text')\n : field.tokens.findIndex((token) => token.kind === 'text');\n\n if (textIndex < 0) {\n field.tokens.push(citeToken);\n field.tokens.push({ id: document2Id('text'), kind: 'text', text: '' });\n return true;\n }\n\n const current = field.tokens[textIndex] as TextToken2;\n const [before, after] = splitTextTokenAt(current, caretOffset);\n const parts: InlineToken2[] = [...field.tokens.slice(0, textIndex)];\n if (before.text.length > 0) {\n parts.push(before);\n }\n parts.push(citeToken);\n parts.push(after);\n parts.push(...field.tokens.slice(textIndex + 1));\n field.tokens = normalizeFieldTokens(parts);\n return true;\n });\n return next;\n}\n\nexport function updateCiteTokenKeys(document: Document2Node, tokenId: string, keys: string[]): Document2Node {\n if (keys.length === 0) {\n return document;\n }\n const next = cloneDocument(document);\n visitFields(next.blocks, (field) => {\n const token = field.tokens.find((entry): entry is CiteToken2 => entry.id === tokenId && entry.kind === 'cite');\n if (!token) {\n return false;\n }\n token.keys = [...keys];\n return true;\n });\n return next;\n}\n\nexport function removeCiteTokenById(document: Document2Node, tokenId: string): Document2Node {\n const next = cloneDocument(document);\n visitFields(next.blocks, (field) => {\n const index = field.tokens.findIndex((token) => token.id === tokenId && token.kind === 'cite');\n if (index < 0) {\n return false;\n }\n field.tokens = normalizeFieldTokens(stitchTextAroundRemovedToken(field.tokens, index));\n return true;\n });\n return next;\n}\n\nexport function ensureDocument2BibliographyBlock(document: Document2Node, afterBlockId?: string | null): Document2Node {\n if (document.blocks.some((block) => block.kind === 'bibliography')) {\n return document;\n }\n const block: BibliographyBlock2 = {\n id: document2Id('block'),\n kind: 'bibliography',\n command: '\\\\begin{thebibliography}',\n closing: '\\\\end{thebibliography}',\n };\n return insertDocument2BlockAfter(document, afterBlockId ?? null, block);\n}\n\nexport function addDocument2Reference(document: Document2Node, partial: Partial<Reference2Json> = {}): Document2Node {\n const next = cloneDocument(document);\n next.references.push(createEmptyReference2(partial));\n return next;\n}\n\nexport function updateDocument2Reference(document: Document2Node, referenceId: string, patch: Partial<Reference2Json>): Document2Node {\n const next = cloneDocument(document);\n const reference = next.references.find((entry) => entry.id === referenceId);\n if (!reference) {\n return document;\n }\n if (typeof patch.key === 'string' && patch.key.trim().length > 0) {\n reference.key = patch.key.trim();\n }\n if (typeof patch.authors === 'string') {\n reference.authors = patch.authors;\n }\n if (typeof patch.title === 'string') {\n reference.title = patch.title;\n }\n if (typeof patch.year === 'string') {\n reference.year = patch.year;\n }\n if (typeof patch.url === 'string') {\n reference.url = patch.url;\n }\n if (typeof patch.venue === 'string') {\n reference.venue = patch.venue;\n }\n if (patch.field_separator === ',' || patch.field_separator === '،') {\n reference.fieldSeparator = patch.field_separator;\n }\n return next;\n}\n\nexport function removeDocument2Reference(document: Document2Node, referenceId: string): Document2Node {\n const next = cloneDocument(document);\n next.references = next.references.filter((reference) => reference.id !== referenceId);\n return next;\n}\n\nexport function moveDocument2Reference(document: Document2Node, referenceId: string, direction: -1 | 1): Document2Node {\n const next = cloneDocument(document);\n const index = next.references.findIndex((reference) => reference.id === referenceId);\n const targetIndex = index + direction;\n if (index < 0 || targetIndex < 0 || targetIndex >= next.references.length) {\n return document;\n }\n const [reference] = next.references.splice(index, 1);\n if (!reference) {\n return document;\n }\n next.references.splice(targetIndex, 0, reference);\n return next;\n}\n\nexport function setDocument2References(document: Document2Node, references: Reference2[]): Document2Node {\n const next = cloneDocument(document);\n next.references = references.map((reference) => ({ ...reference }));\n return next;\n}\n\nexport function updateDocument2Meta(document: Document2Node, patch: Document2MetaProp): Document2Node {\n const next = cloneDocument(document);\n const current = next.meta ?? emptyDocument2Meta();\n next.meta = {\n title: typeof patch.title === 'string' ? patch.title : current.title,\n authors: typeof patch.authors === 'string' ? patch.authors : current.authors,\n abstract: typeof patch.abstract === 'string' ? patch.abstract : current.abstract,\n date: patch.date\n ? normalizeDocument2HijriDate({ ...current.date, ...patch.date })\n : { ...current.date },\n };\n return next;\n}\n","import { toMathObjectJson } from '../document/mathObject.js';\nimport { citeTokenLatex } from './citations.js';\nimport { refTokenLatex } from './labels.js';\nimport type {\n Document2Block,\n Document2BlockJson,\n Document2Json,\n Document2ListItemJson,\n Document2MathObjectJson,\n Document2Node,\n InlineField2,\n Reference2Json,\n TextFormatSpan2Json,\n} from './types.js';\n\ntype SerializedField2 = {\n value: string;\n formats: TextFormatSpan2Json[];\n mathObjects: Array<Document2MathObjectJson | null>;\n hasPersistedMath: boolean;\n};\n\nfunction serializeField(field: InlineField2): SerializedField2 {\n let value = '';\n let hasPersistedMath = false;\n const formats: TextFormatSpan2Json[] = [];\n const mathObjects: Array<Document2MathObjectJson | null> = [];\n\n for (const token of field.tokens) {\n if (token.kind === 'text') {\n const start = value.length;\n value += token.text;\n if (token.text.length > 0 && (token.style?.bold || token.style?.italic || token.style?.underline)) {\n formats.push({\n start,\n end: value.length,\n ...(token.style.bold ? { bold: true } : {}),\n ...(token.style.italic ? { italic: true } : {}),\n ...(token.style.underline ? { underline: true } : {}),\n });\n }\n continue;\n }\n if (token.kind === 'cite') {\n value += citeTokenLatex(token.keys);\n continue;\n }\n if (token.kind === 'ref') {\n value += refTokenLatex(token.keys, token.refCommand);\n continue;\n }\n\n value += token.source;\n if (!token.math || token.sourceOwner === 'raw') {\n if (token.labelEnabled !== undefined || token.label !== undefined) {\n hasPersistedMath = true;\n mathObjects.push({\n node_type: 'RawMathObject',\n ...(token.labelEnabled !== undefined ? { label_enabled: token.labelEnabled } : {}),\n ...(token.label !== undefined ? { label: token.label } : {}),\n });\n } else {\n mathObjects.push(null);\n }\n continue;\n }\n\n hasPersistedMath = true;\n mathObjects.push({\n ...toMathObjectJson(token.math),\n ...(token.sourceSide ? { source_side: token.sourceSide } : {}),\n source_owner: token.sourceOwner,\n ...(token.labelEnabled !== undefined ? { label_enabled: token.labelEnabled } : {}),\n ...(token.label !== undefined ? { label: token.label } : {}),\n });\n }\n\n return { value, formats, mathObjects, hasPersistedMath };\n}\n\nfunction fieldJson(field: InlineField2): Pick<Document2BlockJson, 'value' | 'formats' | 'math_objects'> {\n const serialized = serializeField(field);\n return {\n value: serialized.value,\n ...(serialized.formats.length > 0 ? { formats: serialized.formats } : {}),\n ...(serialized.hasPersistedMath ? { math_objects: serialized.mathObjects } : {}),\n };\n}\n\nfunction listItemJson(item: Extract<Document2Block, { kind: 'list' }>['items'][number]): Document2ListItemJson {\n const field = fieldJson(item.field);\n return {\n value: field.value ?? '',\n ...(field.formats ? { formats: field.formats } : {}),\n ...(field.math_objects ? { math_objects: field.math_objects } : {}),\n ...(item.blocks.length > 0 ? { blocks: item.blocks.map(blockJson) } : {}),\n };\n}\n\nfunction blockJson(block: Document2Block): Document2BlockJson {\n if (block.kind === 'textBlock') {\n return {\n id: block.id,\n command: block.command,\n ...fieldJson(block.field),\n ...(block.command === '\\\\paragraph' ? { centered: block.centered === true } : {}),\n };\n }\n if (block.kind === 'list') {\n return {\n id: block.id,\n command: block.command,\n closing: block.closing,\n items: block.items.map(listItemJson),\n };\n }\n if (block.kind === 'table') {\n const fields = block.rows.map((row) => row.map(serializeField));\n const hasPersistedMath = fields.some((row) => row.some((field) => field.hasPersistedMath));\n return {\n id: block.id,\n command: block.command,\n closing: block.closing,\n columns: block.columns,\n rows: fields.map((row) => row.map((field) => field.value)),\n ...(fields.some((row) => row.some((field) => field.formats.length > 0))\n ? { cell_formats: fields.map((row) => row.map((field) => field.formats)) }\n : {}),\n ...(hasPersistedMath\n ? { math_objects: fields.flatMap((row) => row.flatMap((field) => field.mathObjects)) }\n : {}),\n centered: block.centered,\n caption_enabled: block.captionEnabled,\n caption: block.caption,\n label_enabled: block.labelEnabled,\n label: block.label,\n };\n }\n if (block.kind === 'image') {\n return {\n id: block.id,\n command: block.command,\n value: block.value,\n ...(block.assetId !== undefined ? { asset_id: block.assetId } : {}),\n options: { ...block.options },\n centered: block.centered,\n caption_enabled: block.captionEnabled,\n caption: block.caption,\n label_enabled: block.labelEnabled,\n label: block.label,\n };\n }\n if (block.kind === 'bibliography') {\n return { id: block.id, command: block.command, closing: block.closing };\n }\n return { id: block.id, command: block.command, value: block.value };\n}\n\nfunction referenceJson(reference: Document2Node['references'][number]): Reference2Json {\n return {\n key: reference.key,\n authors: reference.authors,\n title: reference.title,\n year: reference.year,\n url: reference.url,\n venue: reference.venue,\n field_separator: reference.fieldSeparator,\n };\n}\n\n/** Convert the live editor AST to the canonical JSON wire format. */\nexport function toDocumentJson2(document: Document2Node): Document2Json {\n if (document.nodeType !== 'DocumentObject' || !Array.isArray(document.blocks)) {\n throw new Error('toDocumentJson2 requires a live Document2Node');\n }\n return {\n node_type: 'DocumentObject',\n meta: {\n title: document.meta.title,\n authors: document.meta.authors,\n date: { ...document.meta.date },\n abstract: document.meta.abstract,\n },\n references: document.references.map(referenceJson),\n blocks: document.blocks.map(blockJson),\n };\n}\n","import {\n addDocument2ImageBlock,\n addDocument2TextBlock,\n removeDocument2BlockById,\n} from './commands.js';\nimport { createInlineField2, fromDocumentJson2 } from './importJson.js';\nimport { toDocumentJson2 } from './exportJson.js';\nimport type { Document2Block, Document2Json, Document2Node, TextBlock2 } from './types.js';\n\nexport type Document2TextBlockKind = 'section' | 'subsection' | 'subsubsection' | 'paragraph';\n\nexport type Document2Anchor =\n | { after_block_id: string }\n | { end: true };\n\nexport type Document2Command =\n | {\n op: 'insert_text_block';\n kind: Document2TextBlockKind;\n text: string;\n anchor: Document2Anchor;\n }\n | {\n op: 'replace_text_block';\n block_id: string;\n text: string;\n }\n | {\n op: 'remove_block';\n block_id: string;\n }\n | {\n op: 'insert_figure';\n asset_id: string;\n value?: string;\n caption?: string;\n label?: string;\n anchor: Document2Anchor;\n };\n\nexport type Document2CommandErrorCode =\n | 'invalid_document'\n | 'invalid_command'\n | 'missing_block_id'\n | 'duplicate_block_id'\n | 'anchor_not_found'\n | 'block_not_found'\n | 'block_kind_mismatch'\n | 'unsupported_inline_content';\n\nexport class Document2CommandError extends Error {\n readonly code: Document2CommandErrorCode;\n\n constructor(code: Document2CommandErrorCode, message: string) {\n super(message);\n this.name = 'Document2CommandError';\n this.code = code;\n }\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction requireString(value: unknown, field: string, allowEmpty = true): string {\n if (typeof value !== 'string' || (!allowEmpty && value.trim().length === 0)) {\n throw new Document2CommandError('invalid_command', `${field} must be a${allowEmpty ? '' : ' non-empty'} string`);\n }\n return value;\n}\n\nfunction parseAnchor(value: unknown): Document2Anchor {\n if (!isObject(value)) {\n throw new Document2CommandError('invalid_command', 'anchor must be an object');\n }\n const hasEnd = value.end === true;\n const afterBlockId = typeof value.after_block_id === 'string' ? value.after_block_id.trim() : '';\n const hasAfterBlock = afterBlockId.length > 0;\n if (hasEnd && hasAfterBlock) {\n throw new Document2CommandError('invalid_command', 'anchor cannot contain both end and after_block_id');\n }\n if (hasEnd) {\n return { end: true };\n }\n if (hasAfterBlock) {\n return { after_block_id: afterBlockId };\n }\n throw new Document2CommandError('invalid_command', 'anchor requires end: true or a non-empty after_block_id');\n}\n\nfunction optionalString(value: Record<string, unknown>, field: string): string | undefined {\n if (!(field in value)) {\n return undefined;\n }\n if (typeof value[field] !== 'string') {\n throw new Document2CommandError('invalid_command', `${field} must be a string when provided`);\n }\n return value[field];\n}\n\nfunction parseTextBlockKind(value: unknown): Document2TextBlockKind {\n if (value === 'section' || value === 'subsection' || value === 'subsubsection' || value === 'paragraph') {\n return value;\n }\n throw new Document2CommandError('invalid_command', 'kind must be section, subsection, subsubsection, or paragraph');\n}\n\nfunction parseCommand(value: unknown): Document2Command {\n if (!isObject(value) || typeof value.op !== 'string') {\n throw new Document2CommandError('invalid_command', 'command requires an op');\n }\n\n if (value.op === 'insert_text_block') {\n return {\n op: value.op,\n kind: parseTextBlockKind(value.kind),\n text: requireString(value.text, 'text'),\n anchor: parseAnchor(value.anchor),\n };\n }\n if (value.op === 'replace_text_block') {\n return {\n op: value.op,\n block_id: requireString(value.block_id, 'block_id', false).trim(),\n text: requireString(value.text, 'text'),\n };\n }\n if (value.op === 'remove_block') {\n return {\n op: value.op,\n block_id: requireString(value.block_id, 'block_id', false).trim(),\n };\n }\n if (value.op === 'insert_figure') {\n const figureValue = optionalString(value, 'value');\n const caption = optionalString(value, 'caption');\n const label = optionalString(value, 'label');\n return {\n op: value.op,\n asset_id: requireString(value.asset_id, 'asset_id', false).trim(),\n ...(figureValue !== undefined ? { value: figureValue } : {}),\n ...(caption !== undefined ? { caption } : {}),\n ...(label !== undefined ? { label } : {}),\n anchor: parseAnchor(value.anchor),\n };\n }\n\n throw new Document2CommandError('invalid_command', `Unsupported document command: ${value.op}`);\n}\n\nfunction parseDocument(json: Document2Json): Document2Node {\n try {\n return fromDocumentJson2(json);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Invalid DocumentObject JSON';\n throw new Document2CommandError('invalid_document', message);\n }\n}\n\nfunction commandForKind(kind: Document2TextBlockKind): TextBlock2['command'] {\n if (kind === 'section') {\n return '\\\\section';\n }\n if (kind === 'subsection') {\n return '\\\\subsection';\n }\n if (kind === 'subsubsection') {\n return '\\\\subsubsection';\n }\n return '\\\\paragraph';\n}\n\nfunction insertionIndex(document: Document2Node, anchor: Document2Anchor): number {\n if ('end' in anchor) {\n return document.blocks.length;\n }\n const index = document.blocks.findIndex((block) => block.id === anchor.after_block_id);\n if (index < 0) {\n throw new Document2CommandError('anchor_not_found', `Anchor block was not found: ${anchor.after_block_id}`);\n }\n return index + 1;\n}\n\nfunction afterBlockId(document: Document2Node, index: number): string | null {\n return index > 0 ? document.blocks[index - 1]?.id ?? null : null;\n}\n\nfunction insertedBlock(document: Document2Node, index: number): Document2Block {\n const block = document.blocks[index];\n if (!block) {\n throw new Document2CommandError('invalid_command', 'Document command did not insert a block');\n }\n return block;\n}\n\nfunction insertTextBlock(document: Document2Node, command: Extract<Document2Command, { op: 'insert_text_block' }>): Document2Node {\n const index = insertionIndex(document, command.anchor);\n const next = addDocument2TextBlock(document, commandForKind(command.kind), afterBlockId(document, index));\n const block = insertedBlock(next, index);\n if (block.kind !== 'textBlock') {\n throw new Document2CommandError('block_kind_mismatch', 'Inserted block is not a text block');\n }\n block.field = createInlineField2(command.text);\n return next;\n}\n\nfunction replaceTextBlock(document: Document2Node, command: Extract<Document2Command, { op: 'replace_text_block' }>): Document2Node {\n const index = document.blocks.findIndex((block) => block.id === command.block_id);\n if (index < 0) {\n throw new Document2CommandError('block_not_found', `Document block was not found: ${command.block_id}`);\n }\n const block = document.blocks[index];\n if (!block || block.kind !== 'textBlock') {\n throw new Document2CommandError('block_kind_mismatch', `Document block is not a text block: ${command.block_id}`);\n }\n if (block.field.tokens.some((token) => token.kind !== 'text' || token.style !== undefined)) {\n throw new Document2CommandError(\n 'unsupported_inline_content',\n 'Whole-block replacement is not supported for formatted or structured inline content',\n );\n }\n const next = parseDocument(toDocumentJson2(document));\n const nextBlock = next.blocks[index];\n if (!nextBlock || nextBlock.kind !== 'textBlock') {\n throw new Document2CommandError('block_kind_mismatch', `Document block is not a text block: ${command.block_id}`);\n }\n nextBlock.field = createInlineField2(command.text);\n return next;\n}\n\nfunction removeBlock(document: Document2Node, command: Extract<Document2Command, { op: 'remove_block' }>): Document2Node {\n if (!document.blocks.some((block) => block.id === command.block_id)) {\n throw new Document2CommandError('block_not_found', `Document block was not found: ${command.block_id}`);\n }\n return removeDocument2BlockById(document, command.block_id);\n}\n\nfunction insertFigure(document: Document2Node, command: Extract<Document2Command, { op: 'insert_figure' }>): Document2Node {\n const index = insertionIndex(document, command.anchor);\n const next = addDocument2ImageBlock(\n document,\n { assetId: command.asset_id, ...(command.value !== undefined ? { value: command.value } : {}) },\n afterBlockId(document, index),\n );\n const block = insertedBlock(next, index);\n if (block.kind !== 'image') {\n throw new Document2CommandError('block_kind_mismatch', 'Inserted block is not a figure');\n }\n if (command.caption !== undefined) {\n block.caption = command.caption;\n block.captionEnabled = command.caption.trim().length > 0;\n }\n if (command.label !== undefined) {\n block.label = command.label;\n block.labelEnabled = command.label.trim().length > 0;\n }\n return next;\n}\n\n/** Apply one validated, top-level command and return canonical JSON. */\nexport function applyDocument2Command(json: Document2Json, commandInput: Document2Command): Document2Json {\n const document = parseDocument(json);\n const command = parseCommand(commandInput);\n let next: Document2Node;\n\n if (command.op === 'insert_text_block') {\n next = insertTextBlock(document, command);\n } else if (command.op === 'replace_text_block') {\n next = replaceTextBlock(document, command);\n } else if (command.op === 'remove_block') {\n next = removeBlock(document, command);\n } else {\n next = insertFigure(document, command);\n }\n\n return toDocumentJson2(next);\n}\n","import { Document2CommandError } from './jsonCommands.js';\nimport type { Document2BlockJson, Document2Json } from './types.js';\n\nexport type Document2OutlineKind =\n | 'section'\n | 'subsection'\n | 'subsubsection'\n | 'paragraph'\n | 'list'\n | 'table'\n | 'figure'\n | 'bibliography'\n | 'raw';\n\nexport type Document2OutlineEntry = {\n id: string;\n kind: Document2OutlineKind;\n command: string;\n excerpt: string;\n};\n\nconst EXCERPT_LIMIT = 160;\n\nfunction normalizeExcerpt(value: string): string {\n const normalized = value.replace(/\\s+/g, ' ').trim();\n if (normalized.length <= EXCERPT_LIMIT) {\n return normalized;\n }\n return `${normalized.slice(0, EXCERPT_LIMIT - 3)}...`;\n}\n\nfunction outlineKind(command: string): Document2OutlineKind {\n if (command === '\\\\section') {\n return 'section';\n }\n if (command === '\\\\subsection') {\n return 'subsection';\n }\n if (command === '\\\\subsubsection') {\n return 'subsubsection';\n }\n if (command === '\\\\paragraph') {\n return 'paragraph';\n }\n if (command === '\\\\begin{itemize}' || command === '\\\\begin{enumerate}') {\n return 'list';\n }\n if (command === '\\\\begin{tabular}') {\n return 'table';\n }\n if (command === '\\\\includegraphics') {\n return 'figure';\n }\n if (command === '\\\\begin{thebibliography}' || command === '\\\\bibliography') {\n return 'bibliography';\n }\n return 'raw';\n}\n\nfunction blockExcerpt(block: Document2BlockJson): string {\n if (block.command === '\\\\begin{itemize}' || block.command === '\\\\begin{enumerate}') {\n return normalizeExcerpt((block.items ?? []).map((item) => item.value).join(' '));\n }\n if (block.command === '\\\\begin{tabular}') {\n return normalizeExcerpt((block.rows ?? []).flat().join(' '));\n }\n if (block.command === '\\\\includegraphics') {\n return normalizeExcerpt(block.caption || block.asset_id || block.value || '');\n }\n return normalizeExcerpt(block.value ?? '');\n}\n\n/** Return a compact top-level outline for a canonical document. */\nexport function document2Outline(json: Document2Json): Document2OutlineEntry[] {\n if (!json || json.node_type !== 'DocumentObject' || !Array.isArray(json.blocks)) {\n throw new Document2CommandError('invalid_document', 'DocumentObject requires a blocks array');\n }\n\n const usedIds = new Set<string>();\n return json.blocks.map((block) => {\n if (!block || typeof block !== 'object' || typeof block.command !== 'string') {\n throw new Document2CommandError('invalid_document', 'Document outline requires blocks with string commands');\n }\n const id = typeof block.id === 'string' ? block.id.trim() : '';\n if (id.length === 0) {\n throw new Document2CommandError('missing_block_id', 'Document outline requires canonical block IDs');\n }\n if (usedIds.has(id)) {\n throw new Document2CommandError('duplicate_block_id', `Duplicate document block ID: ${id}`);\n }\n usedIds.add(id);\n return {\n id,\n kind: outlineKind(block.command),\n command: block.command,\n excerpt: blockExcerpt(block),\n };\n });\n}\n","import { Document2CommandError } from '../document2/index.js';\nimport type {\n Document2Command,\n Document2Json,\n Document2OutlineEntry,\n} from '../document2/index.js';\n\nexport type Document2WorkerRequest =\n | { action: 'normalize'; document: unknown }\n | { action: 'outline'; document: unknown }\n | { action: 'apply_command'; document: unknown; command: unknown };\n\nexport type Document2WorkerSuccess =\n | { ok: true; document: Document2Json }\n | { ok: true; outline: Document2OutlineEntry[] };\n\nexport type Document2WorkerFailure = {\n ok: false;\n error: {\n code: string;\n message: string;\n };\n};\n\nexport type Document2WorkerResponse = Document2WorkerSuccess | Document2WorkerFailure;\n\nexport class Document2WorkerProtocolError extends Error {\n readonly code: 'invalid_json' | 'invalid_request' | 'payload_too_large' | 'unauthorized' | 'not_found';\n\n constructor(code: Document2WorkerProtocolError['code'], message: string) {\n super(message);\n this.name = 'Document2WorkerProtocolError';\n this.code = code;\n }\n}\n\nexport type Document2WorkerErrorResult = {\n response: Document2WorkerFailure;\n status: number;\n unexpected?: unknown;\n};\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function parseDocument2WorkerRequest(value: unknown): Document2WorkerRequest {\n if (!isObject(value) || typeof value.action !== 'string') {\n throw new Document2WorkerProtocolError('invalid_request', 'Worker request requires an action');\n }\n if (!('document' in value)) {\n throw new Document2WorkerProtocolError('invalid_request', 'Worker request requires a document');\n }\n if (value.action === 'normalize' || value.action === 'outline') {\n return { action: value.action, document: value.document };\n }\n if (value.action === 'apply_command') {\n if (!('command' in value)) {\n throw new Document2WorkerProtocolError('invalid_request', 'apply_command requires a command');\n }\n return { action: value.action, document: value.document, command: value.command };\n }\n throw new Document2WorkerProtocolError('invalid_request', `Unsupported worker action: ${value.action}`);\n}\n\nexport function workerFailure(error: unknown): Document2WorkerErrorResult {\n if (error instanceof Document2CommandError) {\n return {\n response: { ok: false, error: { code: error.code, message: error.message } },\n status: 422,\n };\n }\n if (error instanceof Document2WorkerProtocolError) {\n let status = 400;\n if (error.code === 'payload_too_large') {\n status = 413;\n } else if (error.code === 'unauthorized') {\n status = 401;\n } else if (error.code === 'not_found') {\n status = 404;\n }\n return {\n response: { ok: false, error: { code: error.code, message: error.message } },\n status,\n };\n }\n return {\n response: { ok: false, error: { code: 'internal_error', message: 'Unexpected document worker failure' } },\n status: 500,\n unexpected: error,\n };\n}\n\nexport function asDocument2Json(value: unknown): Document2Json {\n return value as Document2Json;\n}\n\nexport function asDocument2Command(value: unknown): Document2Command {\n return value as Document2Command;\n}\n","import {\n applyDocument2Command,\n Document2CommandError,\n document2Outline,\n fromDocumentJson2,\n toDocumentJson2,\n} from '../document2/index.js';\nimport {\n asDocument2Command,\n asDocument2Json,\n parseDocument2WorkerRequest,\n} from './protocol.js';\nimport type { Document2WorkerSuccess } from './protocol.js';\n\nfunction normalizeDocument(document: unknown) {\n try {\n return toDocumentJson2(fromDocumentJson2(document));\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Invalid DocumentObject JSON';\n throw new Document2CommandError('invalid_document', message);\n }\n}\n\n/** Execute a stateless worker request. Expected failures are thrown with structured codes. */\nexport function executeDocument2WorkerRequest(input: unknown): Document2WorkerSuccess {\n const request = parseDocument2WorkerRequest(input);\n if (request.action === 'normalize') {\n return { ok: true, document: normalizeDocument(request.document) };\n }\n if (request.action === 'outline') {\n return { ok: true, outline: document2Outline(asDocument2Json(request.document)) };\n }\n return {\n ok: true,\n document: applyDocument2Command(asDocument2Json(request.document), asDocument2Command(request.command)),\n };\n}\n","import type { Readable, Writable } from 'node:stream';\nimport { executeDocument2WorkerRequest } from './execute.js';\nimport {\n Document2WorkerProtocolError,\n workerFailure,\n} from './protocol.js';\n\nexport const DOCUMENT2_WORKER_MAX_BODY_BYTES = 5 * 1024 * 1024;\n\nexport type Document2StdinResult = {\n output: string;\n exitCode: number;\n unexpected?: unknown;\n};\n\nfunction parseJson(input: string): unknown {\n try {\n return JSON.parse(input) as unknown;\n } catch {\n throw new Document2WorkerProtocolError('invalid_json', 'Input must be valid JSON');\n }\n}\n\nexport function executeDocument2StdinText(input: string): Document2StdinResult {\n try {\n const size = Buffer.byteLength(input);\n if (size > DOCUMENT2_WORKER_MAX_BODY_BYTES) {\n throw new Document2WorkerProtocolError('payload_too_large', 'Worker request exceeds the 5 MiB limit');\n }\n const response = executeDocument2WorkerRequest(parseJson(input));\n return { output: `${JSON.stringify(response)}\\n`, exitCode: 0 };\n } catch (error) {\n const failure = workerFailure(error);\n return {\n output: `${JSON.stringify(failure.response)}\\n`,\n exitCode: 1,\n ...(failure.unexpected !== undefined ? { unexpected: failure.unexpected } : {}),\n };\n }\n}\n\nasync function readAll(stream: Readable): Promise<string> {\n const chunks: Buffer[] = [];\n let size = 0;\n for await (const chunk of stream) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));\n size += buffer.length;\n if (size > DOCUMENT2_WORKER_MAX_BODY_BYTES) {\n throw new Document2WorkerProtocolError('payload_too_large', 'Worker request exceeds the 5 MiB limit');\n }\n chunks.push(buffer);\n }\n return Buffer.concat(chunks).toString('utf8');\n}\n\nfunction write(stream: Writable, value: string): Promise<void> {\n return new Promise((resolve, reject) => {\n stream.write(value, (error) => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n}\n\nexport async function runDocument2Stdin(\n input: Readable,\n output: Writable,\n errorOutput: Writable,\n): Promise<number> {\n let result: Document2StdinResult;\n try {\n result = executeDocument2StdinText(await readAll(input));\n } catch (error) {\n const failure = workerFailure(error);\n result = {\n output: `${JSON.stringify(failure.response)}\\n`,\n exitCode: 1,\n ...(failure.unexpected !== undefined ? { unexpected: failure.unexpected } : {}),\n };\n }\n await write(output, result.output);\n if (result.unexpected !== undefined) {\n const detail = result.unexpected instanceof Error ? result.unexpected.stack ?? result.unexpected.message : String(result.unexpected);\n await write(errorOutput, `${detail}\\n`);\n }\n return result.exitCode;\n}\n"],"mappings":"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","names":["node","parseChain","isObject","document","afterBlockId","document","document","afterBlockId","document","document","afterBlockId","document","isObject","requireString","afterBlockId","parseCommand","document","block","isObject","document"]}