@drghaliasri/butex 5.5.2 → 5.5.3

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.
@@ -704,6 +704,66 @@ function fromMathObjectJson(json, mode = "english") {
704
704
  closing: json.closing
705
705
  };
706
706
  }
707
+ function scriptsToJson(node, path) {
708
+ return {
709
+ ...node.superscript ? { superscript: chainToJson(node.superscript, `${path}.superscript`) } : {},
710
+ ...node.subscript ? { subscript: chainToJson(node.subscript, `${path}.subscript`) } : {}
711
+ };
712
+ }
713
+ function nodeToJson(node, path) {
714
+ const scripts = scriptsToJson(node, path);
715
+ if (node instanceof CharNode || node instanceof NumberNode || node instanceof OperatorNode) {
716
+ return { node_type: node.nodeType, expr: node.expr, ...scripts };
717
+ }
718
+ if (node instanceof DelimiterNode) {
719
+ return {
720
+ node_type: "DelimiterObject",
721
+ left_delim_expr: node.leftDelimExpr,
722
+ inner_expr: chainToJson(node.innerExpr, `${path}.inner_expr`),
723
+ right_delim_expr: node.rightDelimExpr,
724
+ ...scripts
725
+ };
726
+ }
727
+ if (node instanceof CommandNode) {
728
+ return {
729
+ node_type: "CommandObject",
730
+ name: node.name,
731
+ optional_args: node.optionalArgs.map((arg, index) => chainToJson(arg, `${path}.optional_args[${String(index)}]`)),
732
+ mandatory_args: node.mandatoryArgs.map((arg, index) => chainToJson(arg, `${path}.mandatory_args[${String(index)}]`)),
733
+ ...scripts
734
+ };
735
+ }
736
+ if (node instanceof EnvNode) {
737
+ return {
738
+ node_type: "EnvObject",
739
+ opening: node.opening,
740
+ lines: node.lines.map((line, index) => chainToJson(line, `${path}.lines[${String(index)}]`)),
741
+ closing: node.closing,
742
+ ...scripts
743
+ };
744
+ }
745
+ throw new Error(`Unsupported runtime math node at ${path}: ${node.nodeType}`);
746
+ }
747
+ function chainToJson(chain, path) {
748
+ if (!(chain instanceof ChainNode)) {
749
+ throw new Error(`Expected live ChainNode at ${path}`);
750
+ }
751
+ return {
752
+ node_type: "ChainClass",
753
+ chain: chain.chain.map((node, index) => nodeToJson(node, `${path}.chain[${String(index)}]`))
754
+ };
755
+ }
756
+ function toMathObjectJson(math) {
757
+ if (math.nodeType !== "MathObject" || !Array.isArray(math.lines) || math.lines.length === 0) {
758
+ throw new Error("Cannot serialize invalid runtime MathObject");
759
+ }
760
+ return {
761
+ node_type: "MathObject",
762
+ math_mode: math.mathMode,
763
+ lines: math.lines.map((line, index) => chainToJson(line, `$.lines[${String(index)}]`)),
764
+ closing: math.closing
765
+ };
766
+ }
707
767
  function renderMathNodeLatex(math) {
708
768
  const lines = math.lines.map((line) => line.arabicLatex());
709
769
  if (math.mathMode === "$" || math.mathMode === "\\(") {
@@ -1168,10 +1228,11 @@ function createInlineField2(value = "", mathObjects = [], options = {}, path = "
1168
1228
  }
1169
1229
  const mathJson = mathObjects[mathObjectIndex];
1170
1230
  mathObjectIndex += 1;
1171
- if (mathJson && (mathJson.math_mode !== span.opening || mathJson.closing !== span.closing)) {
1231
+ const structuredMathJson = mathJson?.node_type === "MathObject" ? mathJson : null;
1232
+ if (structuredMathJson && (structuredMathJson.math_mode !== span.opening || structuredMathJson.closing !== span.closing)) {
1172
1233
  pushDiagnostic(diagnostics, options, path, "math_objects order mismatch");
1173
1234
  }
1174
- if (mathJson && mathJson.math_mode === span.opening && mathJson.closing === span.closing) {
1235
+ if (structuredMathJson && structuredMathJson.math_mode === span.opening && structuredMathJson.closing === span.closing) {
1175
1236
  tokens.push({
1176
1237
  id: document2Id("math"),
1177
1238
  kind: "math",
@@ -1179,10 +1240,12 @@ function createInlineField2(value = "", mathObjects = [], options = {}, path = "
1179
1240
  opening: span.opening,
1180
1241
  closing: span.closing,
1181
1242
  source: span.source,
1182
- sourceSide: mode,
1183
- math: fromMathObjectJson(mathJson, mode),
1243
+ sourceSide: structuredMathJson.source_side === "arabic" || structuredMathJson.source_side === "english" ? structuredMathJson.source_side : mode,
1244
+ math: fromMathObjectJson(structuredMathJson, mode),
1184
1245
  editable: true,
1185
- sourceOwner: "imported-structured"
1246
+ sourceOwner: structuredMathJson.source_owner === "editor" ? "editor" : "imported-structured",
1247
+ ...typeof structuredMathJson.label_enabled === "boolean" ? { labelEnabled: structuredMathJson.label_enabled } : {},
1248
+ ...typeof structuredMathJson.label === "string" ? { label: structuredMathJson.label } : {}
1186
1249
  });
1187
1250
  } else {
1188
1251
  tokens.push({
@@ -1195,7 +1258,9 @@ function createInlineField2(value = "", mathObjects = [], options = {}, path = "
1195
1258
  math: null,
1196
1259
  editable: false,
1197
1260
  reason: "\u0647\u0630\u0647 \u0627\u0644\u0645\u0639\u0627\u062F\u0644\u0629 \u0645\u062D\u0641\u0648\u0638\u0629 \u0643\u0646\u0635 \u062E\u0627\u0645 \u0641\u0642\u0637 \u062D\u0627\u0644\u064A\u0627",
1198
- sourceOwner: "raw"
1261
+ sourceOwner: "raw",
1262
+ ...mathJson?.node_type === "RawMathObject" && typeof mathJson.label_enabled === "boolean" ? { labelEnabled: mathJson.label_enabled } : {},
1263
+ ...mathJson?.node_type === "RawMathObject" && typeof mathJson.label === "string" ? { label: mathJson.label } : {}
1199
1264
  });
1200
1265
  }
1201
1266
  index = span.end;
@@ -9253,6 +9318,155 @@ ${body}
9253
9318
  `;
9254
9319
  }
9255
9320
 
9321
+ // src/document2/exportJson.ts
9322
+ function serializeField(field) {
9323
+ let value = "";
9324
+ let hasPersistedMath = false;
9325
+ const formats = [];
9326
+ const mathObjects = [];
9327
+ for (const token of field.tokens) {
9328
+ if (token.kind === "text") {
9329
+ const start = value.length;
9330
+ value += token.text;
9331
+ if (token.text.length > 0 && (token.style?.bold || token.style?.italic || token.style?.underline)) {
9332
+ formats.push({
9333
+ start,
9334
+ end: value.length,
9335
+ ...token.style.bold ? { bold: true } : {},
9336
+ ...token.style.italic ? { italic: true } : {},
9337
+ ...token.style.underline ? { underline: true } : {}
9338
+ });
9339
+ }
9340
+ continue;
9341
+ }
9342
+ if (token.kind === "cite") {
9343
+ value += citeTokenLatex(token.keys);
9344
+ continue;
9345
+ }
9346
+ if (token.kind === "ref") {
9347
+ value += refTokenLatex(token.keys, token.refCommand);
9348
+ continue;
9349
+ }
9350
+ value += token.source;
9351
+ if (!token.math || token.sourceOwner === "raw") {
9352
+ if (token.labelEnabled !== void 0 || token.label !== void 0) {
9353
+ hasPersistedMath = true;
9354
+ mathObjects.push({
9355
+ node_type: "RawMathObject",
9356
+ ...token.labelEnabled !== void 0 ? { label_enabled: token.labelEnabled } : {},
9357
+ ...token.label !== void 0 ? { label: token.label } : {}
9358
+ });
9359
+ } else {
9360
+ mathObjects.push(null);
9361
+ }
9362
+ continue;
9363
+ }
9364
+ hasPersistedMath = true;
9365
+ mathObjects.push({
9366
+ ...toMathObjectJson(token.math),
9367
+ ...token.sourceSide ? { source_side: token.sourceSide } : {},
9368
+ source_owner: token.sourceOwner,
9369
+ ...token.labelEnabled !== void 0 ? { label_enabled: token.labelEnabled } : {},
9370
+ ...token.label !== void 0 ? { label: token.label } : {}
9371
+ });
9372
+ }
9373
+ return { value, formats, mathObjects, hasPersistedMath };
9374
+ }
9375
+ function fieldJson(field) {
9376
+ const serialized = serializeField(field);
9377
+ return {
9378
+ value: serialized.value,
9379
+ ...serialized.formats.length > 0 ? { formats: serialized.formats } : {},
9380
+ ...serialized.hasPersistedMath ? { math_objects: serialized.mathObjects } : {}
9381
+ };
9382
+ }
9383
+ function listItemJson(item) {
9384
+ const field = fieldJson(item.field);
9385
+ return {
9386
+ value: field.value ?? "",
9387
+ ...field.formats ? { formats: field.formats } : {},
9388
+ ...field.math_objects ? { math_objects: field.math_objects } : {},
9389
+ ...item.blocks.length > 0 ? { blocks: item.blocks.map(blockJson) } : {}
9390
+ };
9391
+ }
9392
+ function blockJson(block) {
9393
+ if (block.kind === "textBlock") {
9394
+ return {
9395
+ command: block.command,
9396
+ ...fieldJson(block.field),
9397
+ ...block.command === "\\paragraph" ? { centered: block.centered === true } : {}
9398
+ };
9399
+ }
9400
+ if (block.kind === "list") {
9401
+ return {
9402
+ command: block.command,
9403
+ closing: block.closing,
9404
+ items: block.items.map(listItemJson)
9405
+ };
9406
+ }
9407
+ if (block.kind === "table") {
9408
+ const fields = block.rows.map((row) => row.map(serializeField));
9409
+ const hasPersistedMath = fields.some((row) => row.some((field) => field.hasPersistedMath));
9410
+ return {
9411
+ command: block.command,
9412
+ closing: block.closing,
9413
+ columns: block.columns,
9414
+ rows: fields.map((row) => row.map((field) => field.value)),
9415
+ ...fields.some((row) => row.some((field) => field.formats.length > 0)) ? { cell_formats: fields.map((row) => row.map((field) => field.formats)) } : {},
9416
+ ...hasPersistedMath ? { math_objects: fields.flatMap((row) => row.flatMap((field) => field.mathObjects)) } : {},
9417
+ centered: block.centered,
9418
+ caption_enabled: block.captionEnabled,
9419
+ caption: block.caption,
9420
+ label_enabled: block.labelEnabled,
9421
+ label: block.label
9422
+ };
9423
+ }
9424
+ if (block.kind === "image") {
9425
+ return {
9426
+ command: block.command,
9427
+ value: block.value,
9428
+ ...block.assetId !== void 0 ? { asset_id: block.assetId } : {},
9429
+ options: { ...block.options },
9430
+ centered: block.centered,
9431
+ caption_enabled: block.captionEnabled,
9432
+ caption: block.caption,
9433
+ label_enabled: block.labelEnabled,
9434
+ label: block.label
9435
+ };
9436
+ }
9437
+ if (block.kind === "bibliography") {
9438
+ return { command: block.command, closing: block.closing };
9439
+ }
9440
+ return { command: block.command, value: block.value };
9441
+ }
9442
+ function referenceJson(reference) {
9443
+ return {
9444
+ key: reference.key,
9445
+ authors: reference.authors,
9446
+ title: reference.title,
9447
+ year: reference.year,
9448
+ url: reference.url,
9449
+ venue: reference.venue,
9450
+ field_separator: reference.fieldSeparator
9451
+ };
9452
+ }
9453
+ function toDocumentJson2(document2) {
9454
+ if (document2.nodeType !== "DocumentObject" || !Array.isArray(document2.blocks)) {
9455
+ throw new Error("toDocumentJson2 requires a live Document2Node");
9456
+ }
9457
+ return {
9458
+ node_type: "DocumentObject",
9459
+ meta: {
9460
+ title: document2.meta.title,
9461
+ authors: document2.meta.authors,
9462
+ date: { ...document2.meta.date },
9463
+ abstract: document2.meta.abstract
9464
+ },
9465
+ references: document2.references.map(referenceJson),
9466
+ blocks: document2.blocks.map(blockJson)
9467
+ };
9468
+ }
9469
+
9256
9470
  // src/document2/history.ts
9257
9471
  var DEFAULT_DOCUMENT2_HISTORY_MAX_DEPTH = 100;
9258
9472
  function createDocument2History(maxDepth = DEFAULT_DOCUMENT2_HISTORY_MAX_DEPTH) {
@@ -9596,6 +9810,7 @@ var DOCUMENT2_MESSAGES = {
9596
9810
  imagePath: "\u0645\u0633\u0627\u0631 \u0645\u0644\u0641 \u0627\u0644\u0635\u0648\u0631\u0629",
9597
9811
  imagePathLabel: "\u0645\u0633\u0627\u0631 \u0627\u0644\u0635\u0648\u0631\u0629",
9598
9812
  loadDocumentError: "\u062A\u0639\u0630\u0631 \u062A\u062D\u0645\u064A\u0644 \u0627\u0644\u0645\u0633\u062A\u0646\u062F",
9813
+ runtimePersistenceError: "\u0644\u0627 \u064A\u0645\u0643\u0646 \u062A\u062D\u0645\u064A\u0644 Document2Node \u0628\u0639\u062F JSON.stringify. \u0627\u062D\u0641\u0638 Document2Json \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645 toDocumentJson2.",
9599
9814
  emptyImagePath: "\u0644\u0627 \u064A\u0648\u062C\u062F \u0645\u0633\u0627\u0631 \u0635\u0648\u0631\u0629",
9600
9815
  blockSelection: "\u062A\u062D\u062F\u064A\u062F \u0627\u0644\u0643\u062A\u0644",
9601
9816
  selectBlock: "\u062A\u062D\u062F\u064A\u062F \u0627\u0644\u0643\u062A\u0644\u0629",
@@ -9739,6 +9954,7 @@ var DOCUMENT2_MESSAGES = {
9739
9954
  imagePath: "File path (\\includegraphics)",
9740
9955
  imagePathLabel: "Image path",
9741
9956
  loadDocumentError: "Could not load document",
9957
+ runtimePersistenceError: "A Document2Node cannot be loaded after JSON.stringify. Persist Document2Json with toDocumentJson2 instead.",
9742
9958
  emptyImagePath: "Empty image path",
9743
9959
  blockSelection: "Block selection",
9744
9960
  selectBlock: "Select block",
@@ -17010,7 +17226,19 @@ function formatDocument2Diagnostic(d, messages) {
17010
17226
  return `${messages.importWarning}: ${d.message} \u2014 ${messages.path}: ${d.path}`;
17011
17227
  }
17012
17228
  function isDocument2Node(value) {
17013
- return typeof value === "object" && value !== null && value.nodeType === "DocumentObject" && Array.isArray(value.blocks) && Array.isArray(value.diagnostics);
17229
+ const hasRuntimeShape = typeof value === "object" && value !== null && value.nodeType === "DocumentObject" && Array.isArray(value.blocks) && Array.isArray(value.diagnostics);
17230
+ if (!hasRuntimeShape) {
17231
+ return false;
17232
+ }
17233
+ try {
17234
+ toDocumentJson2(value);
17235
+ return true;
17236
+ } catch {
17237
+ return false;
17238
+ }
17239
+ }
17240
+ function hasDocument2RuntimeShape(value) {
17241
+ return typeof value === "object" && value !== null && value.nodeType === "DocumentObject";
17014
17242
  }
17015
17243
  function applyDocumentMetaSeed(document2, documentMeta) {
17016
17244
  const current = document2.meta ?? emptyDocument2Meta();
@@ -17029,6 +17257,13 @@ function resolveInitialDocument2(initialDocument, uiLocale = "ar", documentMeta)
17029
17257
  if (isDocument2Node(initialDocument)) {
17030
17258
  return { document: applyDocumentMetaSeed(initialDocument, documentMeta), error: null };
17031
17259
  }
17260
+ if (hasDocument2RuntimeShape(initialDocument)) {
17261
+ const messages = document2Messages(uiLocale);
17262
+ return {
17263
+ document: applyDocumentMetaSeed(createEmptyDocument2(), documentMeta),
17264
+ error: `${messages.loadDocumentError}: ${messages.runtimePersistenceError}`
17265
+ };
17266
+ }
17032
17267
  try {
17033
17268
  const imported = fromDocumentJson2(initialDocument);
17034
17269
  return {
@@ -17061,6 +17296,7 @@ function ButexDocumentEditor2({
17061
17296
  onDigitFormChange,
17062
17297
  resolveImageUrl,
17063
17298
  onDocumentChange,
17299
+ onDocumentJsonChange,
17064
17300
  onLatexChange
17065
17301
  }) {
17066
17302
  const messages = document2Messages(uiLocale);
@@ -17092,6 +17328,7 @@ function ButexDocumentEditor2({
17092
17328
  const pendingFocusRef = useRef8(null);
17093
17329
  documentRef.current = documentNode;
17094
17330
  const latex = document2Latex(documentNode);
17331
+ const documentJson = useMemo2(() => toDocumentJson2(documentNode), [documentNode]);
17095
17332
  const documentLabels = useMemo2(() => collectDocument2Labels(documentNode), [documentNode]);
17096
17333
  const preview = useMemo2(
17097
17334
  () => document2Preview(documentNode, mathOutput, equationSide, {
@@ -17176,6 +17413,9 @@ function ButexDocumentEditor2({
17176
17413
  useEffect9(() => {
17177
17414
  onDocumentChange?.(documentNode);
17178
17415
  }, [documentNode, onDocumentChange]);
17416
+ useEffect9(() => {
17417
+ onDocumentJsonChange?.(documentJson);
17418
+ }, [documentJson, onDocumentJsonChange]);
17179
17419
  useEffect9(() => {
17180
17420
  onLatexChange?.(latex);
17181
17421
  }, [latex, onLatexChange]);