@kimdayoun/hwpx-mcp 0.3.0 → 0.3.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.
@@ -59,6 +59,12 @@ export declare class HwpxDocument {
59
59
  private _zip;
60
60
  private _content;
61
61
  private _isDirty;
62
+ /**
63
+ * True once the section element list has changed shape since the XML was
64
+ * parsed (insert/delete/copy/move of paragraphs, tables or images).
65
+ * Parsed XML offsets are unusable from that point until the next save.
66
+ */
67
+ private _structureChanged;
62
68
  private _format;
63
69
  private _undoStack;
64
70
  private _redoStack;
@@ -69,6 +75,12 @@ export declare class HwpxDocument {
69
75
  private _pendingImageInserts;
70
76
  private _pendingCellImageInserts;
71
77
  private _pendingTableInserts;
78
+ /**
79
+ * Monotonic counter shared by paragraph and table inserts. Both kinds are
80
+ * replayed into XML in this order so each insert sees exactly the elements
81
+ * that existed when it was made. Replaying all tables before all paragraphs
82
+ * wrote "A, table, A-2, table" to disk as "A, A-2, table, table".
83
+ */
72
84
  private _tableInsertCounter;
73
85
  private _pendingImageDeletes;
74
86
  private _pendingTableDeletes;
@@ -107,6 +119,13 @@ export declare class HwpxDocument {
107
119
  static createNew(id: string, title?: string, creator?: string): HwpxDocument;
108
120
  get id(): string;
109
121
  get path(): string;
122
+ /** True once the document has a real location on disk. */
123
+ get hasPath(): boolean;
124
+ /**
125
+ * Record where the document now lives after a successful write, so the next
126
+ * save without an explicit path targets the same file.
127
+ */
128
+ setPath(newPath: string): void;
110
129
  get format(): DocumentFormat;
111
130
  get isDirty(): boolean;
112
131
  get zip(): JSZip | null;
@@ -128,6 +147,32 @@ export declare class HwpxDocument {
128
147
  * Call this after any modification that changes document structure or content.
129
148
  */
130
149
  private markModified;
150
+ /**
151
+ * Record that the section element list changed shape. Call from every method
152
+ * that inserts, removes, copies or moves a section-level element. Once set,
153
+ * paragraph edits stop trusting offsets cached at parse time and locate their
154
+ * target in the current XML instead.
155
+ */
156
+ private markStructureChanged;
157
+ /**
158
+ * Resolve "after element N" into an id-based anchor using the memory model
159
+ * as it is right now (before the new element is spliced in).
160
+ *
161
+ * Returns null for "before everything" (N < 0). Elements without an XML
162
+ * paragraph/table of their own (images, shapes) are skipped backwards to the
163
+ * nearest paragraph or table, which is what the XML placement needs.
164
+ *
165
+ * The parser turns a paragraph that is only a line of ─/━/═ into an 'hr'
166
+ * element with a fresh id. That paragraph is still in the XML, so it still
167
+ * takes an occurrence slot there: skipping it here put later anchors one
168
+ * paragraph early (measured on Hancom files with divider lines).
169
+ */
170
+ private resolveElementAnchor;
171
+ /**
172
+ * The XML node a memory element stands for, or null if it has none of its
173
+ * own. An 'hr' parsed from a divider paragraph stands for that paragraph.
174
+ */
175
+ private anchorKeyOf;
131
176
  getSerializableContent(): object;
132
177
  getAllText(): string;
133
178
  getStructure(): object;
@@ -137,11 +182,15 @@ export declare class HwpxDocument {
137
182
  index: number;
138
183
  text: string;
139
184
  style?: ParagraphStyle;
185
+ paraPrIDRef?: number;
186
+ charPrIDRef?: number;
140
187
  }>;
141
188
  getParagraph(sectionIndex: number, paragraphIndex: number): {
142
189
  text: string;
143
190
  runs: TextRun[];
144
191
  style?: ParagraphStyle;
192
+ paraPrIDRef?: number;
193
+ charPrIDRef?: number;
145
194
  } | null;
146
195
  updateParagraphText(sectionIndex: number, elementIndex: number, runIndex: number, text: string): void;
147
196
  updateParagraphRuns(sectionIndex: number, elementIndex: number, runs: TextRun[]): void;
@@ -433,6 +482,12 @@ export declare class HwpxDocument {
433
482
  col: number;
434
483
  value: string;
435
484
  }>;
485
+ failed: Array<{
486
+ row: number;
487
+ col: number;
488
+ value: string;
489
+ error: string;
490
+ }>;
436
491
  updated: Array<{
437
492
  row: number;
438
493
  col: number;
@@ -568,6 +623,12 @@ export declare class HwpxDocument {
568
623
  text: string;
569
624
  cell: TableCell;
570
625
  } | null;
626
+ /**
627
+ * Find the merged cell that covers (row, col), if that position is not itself
628
+ * a master cell. A covered cell has no <hp:tc> of its own in the saved XML,
629
+ * so writing to it succeeds in memory and then silently vanishes on save.
630
+ */
631
+ private findCoveringMergedCell;
571
632
  updateTableCell(sectionIndex: number, tableIndex: number, row: number, col: number, text: string, charShapeId?: number): boolean;
572
633
  setCellProperties(sectionIndex: number, tableIndex: number, row: number, col: number, props: Partial<TableCell>): boolean;
573
634
  insertTableRow(sectionIndex: number, tableIndex: number, afterRowIndex: number, cellTexts?: string[]): boolean;
@@ -880,10 +941,68 @@ export declare class HwpxDocument {
880
941
  */
881
942
  private applyParagraphDeletesToXml;
882
943
  /**
883
- * Apply table inserts to XML.
884
- * Inserts new tables into the section XML.
944
+ * Find the end offset of the section-level element an insert anchors to.
945
+ *
946
+ * Paragraphs are matched by their own <hp:p id>. Tables are matched by
947
+ * <hp:tbl id>, either wrapped in a paragraph (the insert goes after that
948
+ * paragraph) or placed directly in the section (move_table writes them that
949
+ * way).
950
+ *
951
+ * The returned offset is always the end of a TOP-LEVEL element, because that
952
+ * is the only place a new section-level element may go. But paragraph
953
+ * occurrences are counted over exactly the paragraphs the parser puts in the
954
+ * memory model (see parsedParagraphStarts), so they agree with the occurrence
955
+ * resolveElementAnchor recorded. The parser also lifts paragraphs out of
956
+ * headers, text boxes and shapes; Hancom reuses id="0" / id="2147483648"
957
+ * there too. Counting only top-level paragraphs put 47 of 131 sampled Hancom
958
+ * files' copies and moves on the wrong paragraph.
959
+ *
960
+ * Returns -1 if the anchor is not present in the current XML.
961
+ */
962
+ private findAnchorEnd;
963
+ /**
964
+ * The exact XML range of the memory paragraph a paragraph anchor names,
965
+ * found by id + occurrence among parsedParagraphStarts. For a paragraph in a
966
+ * header or text box this is that paragraph alone, not its container.
885
967
  */
886
- private applyTableInsertsToXml;
968
+ private findParsedParagraph;
969
+ /**
970
+ * Start offsets (in `xml`) of the paragraphs HwpxParser turns into memory
971
+ * paragraphs, in document order. Mirrors HwpxParser.parseSection:
972
+ *
973
+ * - MEMO fields, footnotes and endnotes are ignored;
974
+ * - paragraphs inside any table are skipped;
975
+ * - a paragraph that holds a table is kept only if it still has <hp:t>
976
+ * once its tables are removed.
977
+ *
978
+ * Offsets are mapped back to the original XML, so callers can slice it.
979
+ */
980
+ private parsedParagraphStarts;
981
+ /** Every <hp:tbl> range at any depth (outer tables before their nested ones). */
982
+ private findAllTablesDeep;
983
+ /** End offset of the paragraph opening at `start`, counting nested <hp:p>. */
984
+ private findBalancedParagraphEnd;
985
+ /** True if this paragraph directly (not via a nested table) holds <hp:tbl id>. */
986
+ private wrapsTopLevelTable;
987
+ /**
988
+ * Offset for an insert with no anchor ("before everything"). The first
989
+ * paragraph carries <hp:secPr> (page and section settings) and must stay
990
+ * first, so new content goes right after it.
991
+ */
992
+ private findSectionHeadEnd;
993
+ /** Build the XML for a table inserted by insertTable, wrapped in its own paragraph. */
994
+ private buildInsertedTableXml;
995
+ /**
996
+ * Replay structural edits — paragraph/table inserts and paragraph
997
+ * copies/moves — into the section XML in the order the calls were made.
998
+ *
999
+ * Every edit carries id-based anchors resolved at call time, so it lands
1000
+ * after the same element in the XML that it followed in memory. Replaying in
1001
+ * call order means each anchor already exists (or has already moved) by the
1002
+ * time a later edit needs it. Copies/moves may cross sections, so all
1003
+ * touched sections are held in memory and written once at the end.
1004
+ */
1005
+ private applyStructuralInsertsToXml;
887
1006
  /**
888
1007
  * Apply table move/copy operations to XML.
889
1008
  * Extracts table XML from source and inserts at target position.
@@ -898,11 +1017,6 @@ export declare class HwpxDocument {
898
1017
  * Returns the position after the closing tag of the element.
899
1018
  */
900
1019
  private findInsertPositionForElement;
901
- /**
902
- * Apply paragraph inserts to XML.
903
- * Inserts new paragraphs at the specified positions.
904
- */
905
- private applyParagraphInsertsToXml;
906
1020
  /**
907
1021
  * Apply nested table inserts to XML.
908
1022
  * Inserts a new table inside a cell of an existing table.
@@ -911,6 +1025,24 @@ export declare class HwpxDocument {
911
1025
  /**
912
1026
  * Generate XML for a nested table.
913
1027
  */
1028
+ /**
1029
+ * Usable width inside a table cell, in hwpunit.
1030
+ *
1031
+ * A cell with hasMargin="0" takes its padding from the table's inMargin, so
1032
+ * the cell's own cellMargin is only authoritative when hasMargin="1".
1033
+ *
1034
+ * Every lookup is scoped to the cell's (or table's) own markup. A nested
1035
+ * table inside the cell carries its own cellSz/cellMargin/inMargin, and a
1036
+ * first-match regex over the whole cell would read those instead — which
1037
+ * sized a second nested table to the first one's column (7086 vs 21260).
1038
+ */
1039
+ private getCellInnerWidth;
1040
+ /**
1041
+ * Generate XML for a nested table.
1042
+ *
1043
+ * @param innerWidth Usable width of the parent cell in hwpunit. The nested
1044
+ * table is sized to fit it exactly; columns share the width evenly.
1045
+ */
914
1046
  private generateNestedTableXml;
915
1047
  /**
916
1048
  * Insert a nested table XML into a cell XML.
@@ -1063,8 +1195,10 @@ export declare class HwpxDocument {
1063
1195
  */
1064
1196
  private replaceMultipleRunsInElement;
1065
1197
  /**
1066
- * Calculate the occurrence index for a paragraph with given ID.
1067
- * Returns how many paragraphs with the same ID appear before this one.
1198
+ * Occurrence index of the paragraph at `elementIndex` among paragraphs with
1199
+ * the same id — counted with the same rule as insert anchors
1200
+ * (resolveElementAnchor), so a text update finds the paragraph that
1201
+ * findParsedParagraph resolves. Divider paragraphs parsed as 'hr' count.
1068
1202
  */
1069
1203
  private getParagraphOccurrence;
1070
1204
  /**
@@ -1591,6 +1725,14 @@ export declare class HwpxDocument {
1591
1725
  * @returns Cell XML content and its position, or null if not found
1592
1726
  */
1593
1727
  private findTableCellInXml;
1728
+ /**
1729
+ * Clone a table cell for a newly inserted row: same cell attributes, same
1730
+ * first-paragraph formatting, but a single paragraph holding `text`.
1731
+ *
1732
+ * Nested tables and extra paragraphs are dropped. The first run's
1733
+ * charPrIDRef is kept so the new text matches the template cell's font.
1734
+ */
1735
+ private cloneCellWithText;
1594
1736
  private applyTableRowInsertsToXml;
1595
1737
  private applyTableRowDeletesToXml;
1596
1738
  private applyTableColumnInsertsToXml;
@@ -1600,8 +1742,6 @@ export declare class HwpxDocument {
1600
1742
  * Returns elements with their complete XML (including closing tags).
1601
1743
  */
1602
1744
  private findTopLevelFullElements;
1603
- private applyParagraphCopiesToXml;
1604
- private applyParagraphMovesToXml;
1605
1745
  private applyHeaderFooterUpdatesToXml;
1606
1746
  }
1607
1747
  export {};