katex4arabic 1.1.1

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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +303 -0
  3. package/dist/cdn/katex-arabic.min.cjs +258 -0
  4. package/dist/cdn/katex-arabic.min.css +9 -0
  5. package/dist/cdn/katex-arabic.min.js +258 -0
  6. package/dist/cdn/katex-arabic.min.mjs +11878 -0
  7. package/dist/lib/arabicFunctions.d.ts +87 -0
  8. package/dist/lib/arabicFunctions.d.ts.map +1 -0
  9. package/dist/lib/arabicNumerals.d.ts +50 -0
  10. package/dist/lib/arabicNumerals.d.ts.map +1 -0
  11. package/dist/lib/arabicSymbols.d.ts +52 -0
  12. package/dist/lib/arabicSymbols.d.ts.map +1 -0
  13. package/dist/lib/cdn.d.ts +18 -0
  14. package/dist/lib/cdn.d.ts.map +1 -0
  15. package/dist/lib/hooks.cjs +41 -0
  16. package/dist/lib/hooks.cjs.map +1 -0
  17. package/dist/lib/hooks.d.cts +61 -0
  18. package/dist/lib/hooks.d.ts +61 -0
  19. package/dist/lib/hooks.d.ts.map +1 -0
  20. package/dist/lib/hooks.mjs +41 -0
  21. package/dist/lib/hooks.mjs.map +1 -0
  22. package/dist/lib/index.cjs +71 -0
  23. package/dist/lib/index.cjs.map +1 -0
  24. package/dist/lib/index.d.cts +53 -0
  25. package/dist/lib/index.d.ts +53 -0
  26. package/dist/lib/index.d.ts.map +1 -0
  27. package/dist/lib/index.mjs +72 -0
  28. package/dist/lib/index.mjs.map +1 -0
  29. package/dist/lib/katex-arabic.css +458 -0
  30. package/dist/lib/protectedRegions.d.ts +26 -0
  31. package/dist/lib/protectedRegions.d.ts.map +1 -0
  32. package/dist/lib/render.cjs +811 -0
  33. package/dist/lib/render.cjs.map +1 -0
  34. package/dist/lib/render.d.ts +65 -0
  35. package/dist/lib/render.d.ts.map +1 -0
  36. package/dist/lib/render.mjs +812 -0
  37. package/dist/lib/render.mjs.map +1 -0
  38. package/dist/lib/rtlRenderer.d.ts +100 -0
  39. package/dist/lib/rtlRenderer.d.ts.map +1 -0
  40. package/dist/lib/types.d.ts +98 -0
  41. package/dist/lib/types.d.ts.map +1 -0
  42. package/docs/INSTALL.md +314 -0
  43. package/package.json +119 -0
@@ -0,0 +1,811 @@
1
+ "use strict";
2
+ const katex = require("katex");
3
+ const ARABIC_INDIC = ["٠", "١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩"];
4
+ const EXTENDED_ARABIC = ["۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹"];
5
+ const DIGIT_MAP = {
6
+ arabic: ARABIC_INDIC,
7
+ extended: EXTENDED_ARABIC
8
+ };
9
+ function toArabicNumerals(input, style = "arabic") {
10
+ if (style === "latin") return String(input);
11
+ const digits = DIGIT_MAP[style];
12
+ return String(input).replace(/[0-9]/g, (d) => digits[Number(d)]);
13
+ }
14
+ function fromArabicNumerals(input) {
15
+ return String(input).replace(/[٠-٩]/g, (d) => String(ARABIC_INDIC.indexOf(d))).replace(/[۰-۹]/g, (d) => String(EXTENDED_ARABIC.indexOf(d)));
16
+ }
17
+ function formatArabicNumber(numStr) {
18
+ return numStr.replace(/,/g, "٬").replace(/\./g, "٫").replace(/[0-9]/g, (d) => ARABIC_INDIC[Number(d)]);
19
+ }
20
+ function convertNumbersInText(text, style = "arabic", formatSeparators = true) {
21
+ if (style === "latin") return text;
22
+ return text.replace(/\d+(?:[.,]\d+)*/g, (match) => {
23
+ if (formatSeparators) {
24
+ return formatArabicNumber(match);
25
+ }
26
+ return toArabicNumerals(match, style);
27
+ });
28
+ }
29
+ function isArabicDigit(ch) {
30
+ return /[٠-٩۰-۹]/.test(ch);
31
+ }
32
+ const VERBATIM_MACROS = [
33
+ "text",
34
+ "textnormal",
35
+ "textbf",
36
+ "textit",
37
+ "textrm",
38
+ "mathrm",
39
+ "mathbf",
40
+ "mathit",
41
+ "mathtt",
42
+ "mathsf",
43
+ "mathscr",
44
+ "mathfrak",
45
+ "mathbb",
46
+ "mathcal",
47
+ "color",
48
+ "textcolor",
49
+ "operatorname",
50
+ "operatorname*",
51
+ "operatornamewithlimits"
52
+ ];
53
+ const VERBATIM_PATTERN = new RegExp(
54
+ `\\\\(?:${VERBATIM_MACROS.join("|")})\\{[^}]*\\}`,
55
+ "g"
56
+ );
57
+ function collectProtectedRegions(latex) {
58
+ const regions = [];
59
+ let m;
60
+ VERBATIM_PATTERN.lastIndex = 0;
61
+ while ((m = VERBATIM_PATTERN.exec(latex)) !== null) {
62
+ regions.push({ start: m.index, end: m.index + m[0].length });
63
+ }
64
+ regions.sort((a, b) => a.start - b.start);
65
+ const merged = [];
66
+ for (const r of regions) {
67
+ const last = merged[merged.length - 1];
68
+ if (last && r.start <= last.end) {
69
+ last.end = Math.max(last.end, r.end);
70
+ } else {
71
+ merged.push({ ...r });
72
+ }
73
+ }
74
+ return merged;
75
+ }
76
+ function isInsideRegions(pos, regions) {
77
+ for (const r of regions) {
78
+ if (pos >= r.start && pos < r.end) return true;
79
+ if (r.start > pos) break;
80
+ }
81
+ return false;
82
+ }
83
+ const FUNCTION_MAP = {
84
+ // ─── Basic trigonometric ─────────────────────────────────
85
+ "\\sin": "\\operatorname{جا}",
86
+ "\\cos": "\\operatorname{جتا}",
87
+ "\\tan": "\\operatorname{ظا}",
88
+ "\\cot": "\\operatorname{ظتا}",
89
+ "\\sec": "\\operatorname{قا}",
90
+ "\\csc": "\\operatorname{قتا}",
91
+ // ─── Inverse trigonometric ───────────────────────────────
92
+ "\\arcsin": "\\operatorname{جا}^{-1}",
93
+ "\\arccos": "\\operatorname{جتا}^{-1}",
94
+ "\\arctan": "\\operatorname{ظا}^{-1}",
95
+ "\\arccot": "\\operatorname{ظتا}^{-1}",
96
+ "\\arcsec": "\\operatorname{قا}^{-1}",
97
+ "\\arccsc": "\\operatorname{قتا}^{-1}",
98
+ // ─── Hyperbolic ──────────────────────────────────────────
99
+ "\\sinh": "\\operatorname{جـا}",
100
+ // جيب زائدي
101
+ "\\cosh": "\\operatorname{جتـا}",
102
+ // جيب تمام زائدي
103
+ "\\tanh": "\\operatorname{ظـا}",
104
+ // ظل زائدي
105
+ "\\coth": "\\operatorname{ظتـا}",
106
+ // ظل تمام زائدي
107
+ "\\sech": "\\operatorname{قـا}",
108
+ // قاطع زائدي
109
+ "\\csch": "\\operatorname{قتـا}",
110
+ // قاطع تمام زائدي
111
+ // ─── Logarithms & exponentials ───────────────────────────
112
+ "\\ln": "\\operatorname{لو}",
113
+ "\\log": "\\operatorname{لغ}",
114
+ "\\lg": "\\operatorname{لغ}",
115
+ // ─── Limits (kept as \arabiLim; translated separately) ───
116
+ "\\liminf": "\\operatorname*{نها}",
117
+ // ─── Maxima / minima ─────────────────────────────────────
118
+ "\\max": "\\operatorname*{أقصى}",
119
+ "\\min": "\\operatorname*{أدنى}",
120
+ "\\sup": "\\operatorname*{حد\\,أعلى}",
121
+ "\\inf": "\\operatorname*{حد\\,أدنى}",
122
+ // ─── Linear algebra ──────────────────────────────────────
123
+ "\\det": "\\operatorname{محدد}",
124
+ "\\dim": "\\operatorname{بعد}",
125
+ "\\ker": "\\operatorname{نواة}",
126
+ "\\rank": "\\operatorname{رتبة}",
127
+ "\\tr": "\\operatorname{أثر}",
128
+ "\\diag": "\\operatorname{قطري}",
129
+ "\\span": "\\operatorname{مدى}",
130
+ "\\null": "\\operatorname{فضاء\\,صفري}",
131
+ // ─── Number theory ───────────────────────────────────────
132
+ "\\gcd": "\\operatorname{ق.م.أ}",
133
+ "\\lcm": "\\operatorname{م.م.أ}",
134
+ "\\mod": "\\operatorname{باقي}",
135
+ "\\bmod": "\\operatorname{باقي}",
136
+ // ─── Probability & statistics ────────────────────────────
137
+ "\\Pr": "\\operatorname{حا}",
138
+ "\\P": "\\operatorname{حا}",
139
+ // ─── Complex & argument ──────────────────────────────────
140
+ "\\arg": "\\operatorname{سعة}",
141
+ "\\deg": "\\operatorname{درجة}",
142
+ "\\sgn": "\\operatorname{إشا}",
143
+ "\\Re": "\\operatorname{حق}",
144
+ "\\Im": "\\operatorname{تخ}",
145
+ "\\hom": "\\operatorname{تشا}",
146
+ "\\Hom": "\\operatorname{تشا}",
147
+ // ─── Special operator forms (preserved as-is) ────────────
148
+ // \sum, \prod, \int stay — they are mirrored visually via CSS.
149
+ "\\sum": "\\sum",
150
+ "\\prod": "\\prod",
151
+ "\\coprod": "\\coprod",
152
+ "\\int": "\\int",
153
+ "\\iint": "\\iint",
154
+ "\\iiint": "\\iiint",
155
+ "\\oint": "\\oint",
156
+ "\\partial": "\\partial",
157
+ "\\nabla": "\\nabla",
158
+ "\\infty": "\\infty",
159
+ "\\lim": "\\lim",
160
+ // processed via arabiLim pathway
161
+ "\\limsup": "\\operatorname*{نها}",
162
+ // ─── Special marker used internally for limit translation ─
163
+ // \arabiLim is a sentinel that the translator pipeline replaces
164
+ // with the proper \operatorname* form. Users normally do not write this.
165
+ "\\arabiLim": "\\operatorname*{نها}"
166
+ // '\\lim': '\\operatorname*{نها}',
167
+ };
168
+ const VARIABLE_MAP = {
169
+ // ─── Lowercase ───────────────────────────────────────────
170
+ x: "س",
171
+ y: "ص",
172
+ z: "ع",
173
+ a: "أ",
174
+ b: "ب",
175
+ c: "جـ",
176
+ d: "د",
177
+ e: "هـ",
178
+ // Euler's number
179
+ f: "ف",
180
+ g: "ق",
181
+ h: "ح",
182
+ i: "ت",
183
+ // imaginary unit
184
+ j: "ج",
185
+ k: "ك",
186
+ l: "ل",
187
+ m: "م",
188
+ n: "ن",
189
+ o: "ع",
190
+ p: "ب",
191
+ q: "ق",
192
+ r: "ر",
193
+ s: "ز",
194
+ t: "ت",
195
+ // u: 'ث',
196
+ // v: 'ڤ',
197
+ // w: 'و',
198
+ // ─── Uppercase ───────────────────────────────────────────
199
+ A: "أ",
200
+ B: "ب",
201
+ C: "جـ",
202
+ D: "د",
203
+ E: "هـ",
204
+ F: "ف",
205
+ G: "ق",
206
+ H: "ح",
207
+ I: "ت",
208
+ J: "ج",
209
+ K: "ك",
210
+ L: "ل",
211
+ M: "م",
212
+ N: "ن",
213
+ O: "ع",
214
+ P: "ح",
215
+ Q: "ق",
216
+ R: "ر",
217
+ S: "ز",
218
+ T: "ت",
219
+ U: "ث",
220
+ V: "ڤ",
221
+ W: "و",
222
+ X: "س",
223
+ Y: "ص",
224
+ Z: "ز"
225
+ };
226
+ const GREEK_MAP = {
227
+ "\\alpha": "α",
228
+ "\\beta": "β",
229
+ "\\gamma": "γ",
230
+ "\\delta": "δ",
231
+ "\\epsilon": "ε",
232
+ "\\varepsilon": "ε",
233
+ "\\zeta": "ζ",
234
+ "\\eta": "η",
235
+ "\\theta": "θ",
236
+ "\\vartheta": "ϑ",
237
+ "\\iota": "ι",
238
+ "\\kappa": "κ",
239
+ "\\lambda": "λ",
240
+ "\\mu": "μ",
241
+ "\\nu": "ν",
242
+ "\\xi": "ξ",
243
+ "\\pi": "π",
244
+ "\\varpi": "ϖ",
245
+ "\\rho": "ρ",
246
+ "\\varrho": "ϱ",
247
+ "\\sigma": "σ",
248
+ "\\varsigma": "ς",
249
+ "\\tau": "τ",
250
+ "\\upsilon": "υ",
251
+ "\\phi": "φ",
252
+ "\\varphi": "ϕ",
253
+ "\\chi": "χ",
254
+ "\\psi": "ψ",
255
+ "\\omega": "ω",
256
+ "\\Gamma": "Γ",
257
+ "\\Delta": "Δ",
258
+ "\\Theta": "Θ",
259
+ "\\Lambda": "Λ",
260
+ "\\Xi": "Ξ",
261
+ "\\Pi": "Π",
262
+ "\\Sigma": "Σ",
263
+ "\\Upsilon": "Υ",
264
+ "\\Phi": "Φ",
265
+ "\\Psi": "Ψ",
266
+ "\\Omega": "Ω"
267
+ };
268
+ const DIFFERENTIAL_PATTERNS = {
269
+ dx: "\\text{د}\\text{س}",
270
+ dy: "\\text{د}\\text{ص}",
271
+ dz: "\\text{د}\\text{ع}",
272
+ dt: "\\text{د}\\text{ز}",
273
+ dr: "\\text{د}\\text{ر}",
274
+ du: "\\text{د}\\text{ث}",
275
+ dv: "\\text{د}\\text{ڤ}",
276
+ ds: "\\text{د}\\text{س}",
277
+ dA: "\\text{د}\\text{أ}",
278
+ dV: "\\text{د}\\text{ح}",
279
+ dS: "\\text{د}\\text{س}"
280
+ };
281
+ function escapeRegex$1(input) {
282
+ return input.replace(/[\\^$*+?.()|[\]{}]/g, "\\$&");
283
+ }
284
+ function translateFunctions(latex, customMap = {}) {
285
+ const merged = { ...FUNCTION_MAP, ...customMap };
286
+ const protectedRegions = collectProtectedRegions(latex);
287
+ const cmdPattern = /\\[a-zA-Z]+/g;
288
+ let result = "";
289
+ let cursor = 0;
290
+ let m;
291
+ while ((m = cmdPattern.exec(latex)) !== null) {
292
+ const command = m[0];
293
+ const end = m.index + command.length;
294
+ const next = latex[end];
295
+ const followedByLetter = !!next && /[A-Za-z]/.test(next);
296
+ const replacement = followedByLetter ? void 0 : merged[command];
297
+ if (replacement !== void 0 && !isInsideRegions(m.index, protectedRegions)) {
298
+ result += latex.slice(cursor, m.index) + replacement;
299
+ cursor = end;
300
+ continue;
301
+ }
302
+ result += latex.slice(cursor, end);
303
+ cursor = end;
304
+ }
305
+ result += latex.slice(cursor);
306
+ return result;
307
+ }
308
+ function translateDifferentials(latex) {
309
+ let result = latex;
310
+ result = result.replace(
311
+ /\bd([xyztruvs])\b/g,
312
+ (_match, letter) => {
313
+ const arabic = VARIABLE_MAP[letter] ?? letter;
314
+ return `\\text{د}\\text{${arabic}}`;
315
+ }
316
+ );
317
+ result = result.replace(
318
+ /d\\(theta|phi|rho|alpha|beta|gamma|delta)\b/g,
319
+ (_match, greek) => `\\text{د}\\${greek}`
320
+ );
321
+ result = result.replace(
322
+ /\bd([AVS])\b/g,
323
+ (_match, letter) => {
324
+ const arabic = VARIABLE_MAP[letter] ?? letter;
325
+ return `\\text{د}\\text{${arabic}}`;
326
+ }
327
+ );
328
+ return result;
329
+ }
330
+ function translateVariables(latex, customMap = {}) {
331
+ const merged = { ...VARIABLE_MAP, ...customMap };
332
+ const keys = Object.keys(merged);
333
+ if (keys.length === 0) return latex;
334
+ const sorted = keys.sort((a, b) => b.length - a.length);
335
+ const protectedRegions = collectProtectedRegions(latex);
336
+ const pattern = new RegExp(
337
+ `(?<![A-Za-z\\\\])(${sorted.map(escapeRegex$1).join("|")})(?![A-Za-z])`,
338
+ "g"
339
+ );
340
+ return latex.replace(pattern, (match, _p1, offset, _string) => {
341
+ const pos = Number(offset);
342
+ if (isInsideRegions(pos, protectedRegions)) return match;
343
+ return `\\text{${merged[match]}}`;
344
+ });
345
+ }
346
+ function translateSpecialPatterns(latex) {
347
+ return translateDifferentials(latex);
348
+ }
349
+ function translateAll(latex, options = {}) {
350
+ const {
351
+ functions = true,
352
+ variables = true,
353
+ differentials = true,
354
+ customFunctionMap = {},
355
+ customVariableMap = {}
356
+ } = options;
357
+ let result = latex;
358
+ if (differentials) {
359
+ result = translateDifferentials(result);
360
+ }
361
+ if (functions) {
362
+ result = translateFunctions(result, customFunctionMap);
363
+ }
364
+ if (variables) {
365
+ result = translateVariables(result, customVariableMap);
366
+ }
367
+ return result;
368
+ }
369
+ const COMPARISON_MIRRORS = {
370
+ "<": ">",
371
+ ">": "<",
372
+ "\\lt": "\\gt",
373
+ "\\gt": "\\lt",
374
+ "\\leq": "\\geq",
375
+ "\\geq": "\\leq",
376
+ "\\le": "\\ge",
377
+ "\\ge": "\\le",
378
+ "\\leqslant": "\\geqslant",
379
+ "\\geqslant": "\\leqslant",
380
+ "\\lesssim": "\\gtrsim",
381
+ "\\gtrsim": "\\lesssim",
382
+ "\\ll": "\\gg",
383
+ "\\gg": "\\ll",
384
+ "\\nless": "\\ngtr",
385
+ "\\ngtr": "\\nless",
386
+ "\\nleq": "\\ngeq",
387
+ "\\ngeq": "\\nleq"
388
+ };
389
+ const ARROW_MIRRORS = {
390
+ "\\to": "\\gets",
391
+ "\\gets": "\\to",
392
+ "\\rightarrow": "\\leftarrow",
393
+ "\\leftarrow": "\\rightarrow",
394
+ "\\longrightarrow": "\\longleftarrow",
395
+ "\\longleftarrow": "\\longrightarrow",
396
+ "\\Rightarrow": "\\Leftarrow",
397
+ "\\Leftarrow": "\\Rightarrow",
398
+ "\\Longrightarrow": "\\Longleftarrow",
399
+ "\\Longleftarrow": "\\Longrightarrow",
400
+ "\\hookrightarrow": "\\hookleftarrow",
401
+ "\\hookleftarrow": "\\hookrightarrow",
402
+ "\\mapsto": "\\mapsfrom",
403
+ "\\mapsfrom": "\\mapsto",
404
+ "\\rightleftharpoons": "\\leftrightharpoons",
405
+ "\\leftrightharpoons": "\\rightleftharpoons"
406
+ };
407
+ const BRACKET_MIRRORS = {
408
+ "\\langle": "\\rangle",
409
+ "\\rangle": "\\langle",
410
+ "\\lceil": "\\rceil",
411
+ "\\rceil": "\\lceil",
412
+ "\\lfloor": "\\rfloor",
413
+ "\\rfloor": "\\lfloor",
414
+ "\\lbrace": "\\rbrace",
415
+ "\\rbrace": "\\lbrace",
416
+ "\\lbrack": "\\rbrack",
417
+ "\\rbrack": "\\lbrack"
418
+ };
419
+ const BIG_OP_MIRRORS = {
420
+ "\\sum": "\\sum",
421
+ // mirrored via CSS
422
+ "\\prod": "\\prod",
423
+ // mirrored via CSS
424
+ "\\int": "\\int",
425
+ // mirrored via CSS
426
+ "\\iint": "\\iint",
427
+ "\\iiint": "\\iiint",
428
+ "\\oint": "\\oint"
429
+ };
430
+ const MIRRORED_SYMBOLS = {
431
+ ...COMPARISON_MIRRORS,
432
+ ...ARROW_MIRRORS,
433
+ ...BRACKET_MIRRORS,
434
+ ...BIG_OP_MIRRORS
435
+ };
436
+ const COMPARISON_SYMBOLS = COMPARISON_MIRRORS;
437
+ const ARROW_SYMBOLS = ARROW_MIRRORS;
438
+ const BRACKET_SYMBOLS = BRACKET_MIRRORS;
439
+ const ARABIC_MATH_UNICODE = {
440
+ alef: "𞸀",
441
+ ba: "𞸁",
442
+ jeem: "𞸂",
443
+ dal: "𞸃",
444
+ waw: "𞸅",
445
+ zain: "𞸆",
446
+ ha: "𞸇",
447
+ tah: "𞸈",
448
+ ya: "𞸉",
449
+ kaf: "𞸊",
450
+ lam: "𞸋",
451
+ meem: "𞸌",
452
+ noon: "𞸍",
453
+ seen: "𞸎",
454
+ ain: "𞸏",
455
+ fa: "𞸐",
456
+ sad: "𞸑",
457
+ qaf: "𞸒",
458
+ ra: "𞸓",
459
+ sheen: "𞸔",
460
+ ta: "𞸕",
461
+ tha: "𞸖",
462
+ kha: "𞸗",
463
+ dhal: "𞸘",
464
+ dad: "𞸙",
465
+ ghayn: "𞸚"
466
+ };
467
+ const SPECIAL_ARABIC_SYMBOLS = {
468
+ arabicFractionSlash: "/",
469
+ integralMaghribi: "\\int"
470
+ // mirrored visually via CSS
471
+ };
472
+ function escapeRegex(input) {
473
+ return input.replace(/[\\^$*+?.()|[\]{}]/g, "\\$&");
474
+ }
475
+ function buildMirrorRegex(key) {
476
+ const escaped = escapeRegex(key);
477
+ if (key.length === 1) {
478
+ return new RegExp(`(?<![A-Za-z\\\\])${escaped}(?![A-Za-z])`, "g");
479
+ }
480
+ return new RegExp(escaped + "(?![A-Za-z])", "g");
481
+ }
482
+ function applyMirroredSymbols(latex, enabled = true) {
483
+ if (!enabled) return latex;
484
+ const sorted = Object.entries(MIRRORED_SYMBOLS).sort(
485
+ (a, b) => b[0].length - a[0].length
486
+ );
487
+ const pattern = new RegExp(
488
+ sorted.map(([key]) => `(?:${buildMirrorRegex(key).source})`).join("|"),
489
+ "g"
490
+ );
491
+ const mirrorByText = new Map(
492
+ sorted.map(([key, value]) => [key, value])
493
+ );
494
+ const protectedRegions = collectProtectedRegions(latex);
495
+ return latex.replace(pattern, (...args) => {
496
+ const match = args[0];
497
+ const offset = args[1];
498
+ if (isInsideRegions(offset, protectedRegions)) return match;
499
+ return mirrorByText.get(match) ?? match;
500
+ });
501
+ }
502
+ const MAX_INPUT_LENGTH = 2e4;
503
+ const CACHE_CAPACITY = 256;
504
+ class LruCache {
505
+ constructor(capacity) {
506
+ this.capacity = capacity;
507
+ }
508
+ capacity;
509
+ map = /* @__PURE__ */ new Map();
510
+ get(key) {
511
+ const value = this.map.get(key);
512
+ if (value !== void 0) {
513
+ this.map.delete(key);
514
+ this.map.set(key, value);
515
+ }
516
+ return value;
517
+ }
518
+ set(key, value) {
519
+ if (this.map.has(key)) {
520
+ this.map.delete(key);
521
+ } else if (this.map.size >= this.capacity) {
522
+ const firstKey = this.map.keys().next().value;
523
+ if (firstKey !== void 0) this.map.delete(firstKey);
524
+ }
525
+ this.map.set(key, value);
526
+ }
527
+ clear() {
528
+ this.map.clear();
529
+ }
530
+ get size() {
531
+ return this.map.size;
532
+ }
533
+ }
534
+ const renderCache = new LruCache(CACHE_CAPACITY);
535
+ function clearRenderCache() {
536
+ renderCache.clear();
537
+ }
538
+ function buildCacheKey(latex, opts) {
539
+ return [
540
+ latex,
541
+ opts.numerals,
542
+ opts.formatNumbers,
543
+ opts.translateFuncs,
544
+ opts.translateVars,
545
+ opts.translateDiffs,
546
+ JSON.stringify(opts.customFunctionMap),
547
+ JSON.stringify(opts.customVariableMap),
548
+ opts.mirrorSymbols,
549
+ opts.mirrorBigOperators,
550
+ opts.mirrorSqrt,
551
+ opts.mirrorBrackets,
552
+ opts.direction,
553
+ opts.fontFamily,
554
+ opts.displayMode,
555
+ opts.fullArabicMode,
556
+ opts.operatorScale,
557
+ JSON.stringify(opts.macros),
558
+ opts.output,
559
+ String(opts.strict),
560
+ opts.trust,
561
+ opts.minRuleThickness
562
+ ].join("|");
563
+ }
564
+ const DEFAULT_OPTIONS = {
565
+ // Numerals
566
+ numerals: "arabic",
567
+ formatNumbers: true,
568
+ // Translation
569
+ translateFuncs: true,
570
+ translateVars: true,
571
+ translateDiffs: true,
572
+ customFunctionMap: {},
573
+ customVariableMap: {},
574
+ // Mirroring
575
+ mirrorSymbols: true,
576
+ mirrorBigOperators: true,
577
+ mirrorSqrt: true,
578
+ mirrorBrackets: true,
579
+ // Rendering
580
+ direction: "rtl",
581
+ fontFamily: "Amiri",
582
+ displayMode: false,
583
+ fullArabicMode: true,
584
+ // 1.05 compensates for the x-height difference between Arabic fonts
585
+ // (Amiri et al.) and KaTeX_Main, so Arabic operator names (جا، جتا…)
586
+ // visually match the size of their Latin counterparts out of the box.
587
+ operatorScale: 1.05,
588
+ // KaTeX
589
+ macros: {},
590
+ throwOnError: false,
591
+ output: "html",
592
+ strict: false,
593
+ trust: false,
594
+ minRuleThickness: 0.04
595
+ };
596
+ function resolveOptions(overrides = {}) {
597
+ return { ...DEFAULT_OPTIONS, ...overrides };
598
+ }
599
+ function processArabicLatex(latex, options = {}) {
600
+ const opts = resolveOptions(options);
601
+ let processed = latex.length > MAX_INPUT_LENGTH ? latex.slice(0, MAX_INPUT_LENGTH) : latex;
602
+ if (!processed.trim()) return processed;
603
+ if (opts.translateFuncs) {
604
+ processed = processed.replace(/\\lim(?![A-Za-z])/g, "\\arabiLim");
605
+ }
606
+ if (opts.translateDiffs) {
607
+ processed = translateDifferentials(processed);
608
+ }
609
+ if (opts.translateFuncs) {
610
+ processed = translateFunctions(processed, opts.customFunctionMap);
611
+ }
612
+ if (opts.translateVars) {
613
+ processed = translateVariables(processed, opts.customVariableMap);
614
+ }
615
+ if (opts.mirrorSymbols) {
616
+ processed = applyMirroredSymbols(processed, true);
617
+ }
618
+ if (opts.numerals !== "latin") {
619
+ processed = convertNumbersInLatex(processed, opts.numerals, opts.formatNumbers);
620
+ }
621
+ return processed;
622
+ }
623
+ function convertNumbersInLatex(latex, style, formatSeparators) {
624
+ let result = "";
625
+ let i = 0;
626
+ while (i < latex.length) {
627
+ const ch = latex[i];
628
+ if (ch && /[0-9]/.test(ch)) {
629
+ const prev = i > 0 ? latex[i - 1] : "";
630
+ if (prev && /[A-Za-z]/.test(prev)) {
631
+ result += ch;
632
+ } else {
633
+ let j = i;
634
+ while (j < latex.length) {
635
+ const cj = latex[j];
636
+ if (cj && /[0-9.,]/.test(cj)) {
637
+ j++;
638
+ } else {
639
+ break;
640
+ }
641
+ }
642
+ const run = latex.slice(i, j);
643
+ result += formatSeparators ? formatArabicNumber(run) : toArabicNumerals(run, style);
644
+ i = j;
645
+ continue;
646
+ }
647
+ } else {
648
+ result += ch ?? "";
649
+ }
650
+ i++;
651
+ }
652
+ return result;
653
+ }
654
+ function getArabicMacros(customMacros = {}) {
655
+ return {
656
+ // Trigonometric
657
+ "\\جا": "\\operatorname{جا}",
658
+ "\\جتا": "\\operatorname{جتا}",
659
+ "\\ظا": "\\operatorname{ظا}",
660
+ "\\ظتا": "\\operatorname{ظتا}",
661
+ "\\قا": "\\operatorname{قا}",
662
+ "\\قتا": "\\operatorname{قتا}",
663
+ // Logarithms
664
+ "\\لو": "\\operatorname{لو}",
665
+ "\\لغ": "\\operatorname{لغ}",
666
+ // Limits
667
+ "\\نها": "\\operatorname*{نها}",
668
+ "\\نهى": "\\operatorname*{نها}",
669
+ // Max/min
670
+ "\\اقصى": "\\operatorname*{أقصى}",
671
+ "\\ادنى": "\\operatorname*{أدنى}",
672
+ // Imaginary / constants
673
+ "\\ت": "\\text{ت}",
674
+ "\\هـ": "\\text{هـ}",
675
+ ...customMacros
676
+ };
677
+ }
678
+ function buildCssClasses(options) {
679
+ const opts = resolveOptions(options);
680
+ const classes = ["katex-arabic"];
681
+ if (opts.mirrorBigOperators) classes.push("mirror-big-ops");
682
+ if (opts.mirrorSqrt) classes.push("mirror-sqrt");
683
+ if (opts.mirrorBrackets) classes.push("mirror-brackets");
684
+ if (opts.mirrorSymbols) classes.push("mirror-symbols");
685
+ if (opts.fullArabicMode) classes.push("full-rtl-mode");
686
+ if (opts.displayMode) classes.push("is-display");
687
+ else classes.push("is-inline");
688
+ return classes;
689
+ }
690
+ function wrapWithArabicStyles(html, options) {
691
+ const opts = resolveOptions(options);
692
+ const classes = buildCssClasses(opts);
693
+ return `<span class="${classes.join(" ")}" dir="${opts.direction}" style="font-family:'${opts.fontFamily}','KaTeX_Main',serif;direction:${opts.direction};--ka-op-scale:${opts.operatorScale};">${html}</span>`;
694
+ }
695
+ function escapeHtml(text) {
696
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
697
+ }
698
+ function renderArabicToString(latex, options = {}) {
699
+ return renderArabicWithMeta(latex, options).html;
700
+ }
701
+ function renderArabicWithMeta(latex, options = {}) {
702
+ const opts = resolveOptions(options);
703
+ const cacheKey = buildCacheKey(latex, opts);
704
+ const cached = renderCache.get(cacheKey);
705
+ if (cached !== void 0) {
706
+ return { html: cached, error: null };
707
+ }
708
+ const processedLatex = processArabicLatex(latex, opts);
709
+ try {
710
+ const html = katex.renderToString(processedLatex, {
711
+ displayMode: opts.displayMode,
712
+ throwOnError: true,
713
+ output: opts.output,
714
+ strict: opts.strict,
715
+ trust: opts.trust,
716
+ minRuleThickness: opts.minRuleThickness,
717
+ macros: {
718
+ ...getArabicMacros(opts.macros),
719
+ ...opts.macros ?? {}
720
+ }
721
+ });
722
+ const wrapped = wrapWithArabicStyles(html, opts);
723
+ renderCache.set(cacheKey, wrapped);
724
+ return { html: wrapped, error: null };
725
+ } catch (error) {
726
+ const message = error instanceof Error ? error.message : String(error);
727
+ if (opts.throwOnError) {
728
+ throw error instanceof Error ? error : new Error(message);
729
+ }
730
+ console.error("[katex-arabic] render failed:", message, "\nLaTeX:", latex);
731
+ return {
732
+ html: `<span class="katex-arabic katex-arabic--error" dir="rtl" role="alert" style="color:#dc2626;font-family:monospace;"><span class="katex-arabic__error-icon" aria-hidden="true">⚠</span> <span class="katex-arabic__error-text">${escapeHtml(latex)}</span></span>`,
733
+ error: message
734
+ };
735
+ }
736
+ }
737
+ function renderArabic(latex, element, options = {}) {
738
+ const html = renderArabicToString(latex, options);
739
+ element.innerHTML = html;
740
+ applyDomStyles(element, options);
741
+ }
742
+ function renderArabicBatch(items, options = {}) {
743
+ return items.map((item) => {
744
+ if (typeof item === "string") {
745
+ return renderArabicWithMeta(item, options);
746
+ }
747
+ return renderArabicWithMeta(item.latex, { ...options, ...item.options });
748
+ });
749
+ }
750
+ function processLatex(latex, options = {}) {
751
+ return processArabicLatex(latex, options);
752
+ }
753
+ function validateLatex(latex, options = {}) {
754
+ const opts = resolveOptions(options);
755
+ const processed = processArabicLatex(latex, opts);
756
+ try {
757
+ katex.renderToString(processed, {
758
+ displayMode: opts.displayMode,
759
+ throwOnError: true,
760
+ strict: opts.strict,
761
+ trust: opts.trust
762
+ });
763
+ return null;
764
+ } catch (error) {
765
+ return error instanceof Error ? error.message : String(error);
766
+ }
767
+ }
768
+ function applyDomStyles(element, options) {
769
+ const opts = resolveOptions(options);
770
+ const katexEl = element.querySelector(".katex");
771
+ if (katexEl) {
772
+ katexEl.setAttribute("dir", opts.direction);
773
+ katexEl.style.fontFamily = `'${opts.fontFamily}', 'KaTeX_Main', serif`;
774
+ katexEl.style.direction = opts.direction;
775
+ }
776
+ }
777
+ exports.ARABIC_MATH_UNICODE = ARABIC_MATH_UNICODE;
778
+ exports.ARROW_SYMBOLS = ARROW_SYMBOLS;
779
+ exports.BRACKET_SYMBOLS = BRACKET_SYMBOLS;
780
+ exports.COMPARISON_SYMBOLS = COMPARISON_SYMBOLS;
781
+ exports.DEFAULT_OPTIONS = DEFAULT_OPTIONS;
782
+ exports.DIFFERENTIAL_PATTERNS = DIFFERENTIAL_PATTERNS;
783
+ exports.FUNCTION_MAP = FUNCTION_MAP;
784
+ exports.GREEK_MAP = GREEK_MAP;
785
+ exports.MAX_INPUT_LENGTH = MAX_INPUT_LENGTH;
786
+ exports.MIRRORED_SYMBOLS = MIRRORED_SYMBOLS;
787
+ exports.SPECIAL_ARABIC_SYMBOLS = SPECIAL_ARABIC_SYMBOLS;
788
+ exports.VARIABLE_MAP = VARIABLE_MAP;
789
+ exports.applyMirroredSymbols = applyMirroredSymbols;
790
+ exports.buildCssClasses = buildCssClasses;
791
+ exports.clearRenderCache = clearRenderCache;
792
+ exports.convertNumbersInText = convertNumbersInText;
793
+ exports.formatArabicNumber = formatArabicNumber;
794
+ exports.fromArabicNumerals = fromArabicNumerals;
795
+ exports.getArabicMacros = getArabicMacros;
796
+ exports.isArabicDigit = isArabicDigit;
797
+ exports.processArabicLatex = processArabicLatex;
798
+ exports.processLatex = processLatex;
799
+ exports.renderArabic = renderArabic;
800
+ exports.renderArabicBatch = renderArabicBatch;
801
+ exports.renderArabicToString = renderArabicToString;
802
+ exports.renderArabicWithMeta = renderArabicWithMeta;
803
+ exports.resolveOptions = resolveOptions;
804
+ exports.toArabicNumerals = toArabicNumerals;
805
+ exports.translateAll = translateAll;
806
+ exports.translateDifferentials = translateDifferentials;
807
+ exports.translateFunctions = translateFunctions;
808
+ exports.translateSpecialPatterns = translateSpecialPatterns;
809
+ exports.translateVariables = translateVariables;
810
+ exports.validateLatex = validateLatex;
811
+ //# sourceMappingURL=render.cjs.map