@wordinweb/agent 0.2.5 → 0.2.6

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.
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  isSuggestable,
8
8
  isSuggestableTableOp,
9
9
  stretchShareCode
10
- } from "./chunk-QDZRRLHW.js";
10
+ } from "./chunk-32YIZ3LI.js";
11
11
 
12
12
  // src/cli.ts
13
13
  import { webcrypto } from "crypto";
package/dist/index.d.ts CHANGED
@@ -1,13 +1,3 @@
1
- /**
2
- * Minimal, fast XML parser producing a lightweight element tree.
3
- *
4
- * OOXML parts are machine-generated, namespace-prefixed, well-formed XML with
5
- * no DTDs. This parser handles exactly that subset: elements, attributes,
6
- * text, CDATA, comments, processing instructions, and the built-in + numeric
7
- * character entities. Namespace prefixes are kept verbatim (`w:p`), and
8
- * lookups match on either the full name or the local name, which is robust
9
- * for every mainstream producer (Word, LibreOffice, Google Docs export).
10
- */
11
1
  interface XmlElement {
12
2
  name: string;
13
3
  attrs: Record<string, string>;
@@ -45,6 +35,8 @@ interface Border {
45
35
  * sz-4 rule contributes 0.5pt, not the floored 0.5625pt (phase23 p66:
46
36
  * 45 rows drift 2.5px down without it). */
47
37
  rawWidth?: number;
38
+ /** w:shadow: a strip outside the right and bottom borders. */
39
+ shadow?: boolean;
48
40
  }
49
41
  interface ParagraphBorders {
50
42
  top?: Border;
@@ -139,6 +131,8 @@ interface RunProps {
139
131
  /** Character style id (w:rStyle). */
140
132
  styleId?: string;
141
133
  lang?: string;
134
+ /** w:lang w:bidi — the language of the run's complex-script text (Arabic, Hebrew, Indic, Thai, ...). */
135
+ langBidi?: string;
142
136
  }
143
137
  interface NumberingRef {
144
138
  numId: number;
@@ -324,6 +318,11 @@ type MathNode = ({
324
318
  /** m:func function name (cos, log, …): Word kerns a thin space on
325
319
  * both sides of the name. */
326
320
  fname?: boolean;
321
+ /** The run's w:rPr color (hex, no #), strike and underline, when set:
322
+ * a redline marks an equation's runs with them. */
323
+ color?: string;
324
+ strike?: boolean;
325
+ underline?: string;
327
326
  } | {
328
327
  t: "sup" | "sub";
329
328
  base: MathNode[];
@@ -417,6 +416,9 @@ interface FieldContent {
417
416
  kind: "field";
418
417
  /** Raw field instruction, e.g. ` PAGE \\* MERGEFORMAT `. */
419
418
  instruction: string;
419
+ /** Instruction text and nested fields in source order. `instruction` uses
420
+ * their stored results; layout evaluates these parts to build the code. */
421
+ instructionParts?: (string | FieldContent)[];
420
422
  /** Last cached result text from the file, used for unsupported fields. */
421
423
  cachedResult: string;
422
424
  /** When this field is a legacy FORMCHECKBOX, the source `w:checkBox` element
@@ -478,6 +480,8 @@ interface ShapeTextbox {
478
480
  pctHeightRel?: "page" | "margin";
479
481
  /** Vertical anchoring of the text INSIDE the box (v-text-anchor). */
480
482
  textAnchor?: "top" | "middle" | "bottom";
483
+ /** Text direction: clockwise top-to-bottom or counter-clockwise bottom-to-top. */
484
+ vert?: "vert" | "vert270";
481
485
  /** How body text flows around a DrawingML textbox (wp:wrap*). */
482
486
  wrap?: WrapMode;
483
487
  /** behindDoc: paint under the body text, never displace it. */
@@ -607,8 +611,8 @@ interface ShapeArt {
607
611
  behind?: boolean;
608
612
  /** a:xfrm rotation, degrees clockwise. */
609
613
  rotation?: number;
610
- /** wp:wrapSquare/.../wrapTopAndBottom on the anchor. Only FRAME stories
611
- * (header/footer/cell) act on it - body flow ignores art wrap, as before. */
614
+ /** wp:wrapSquare/.../wrapTopAndBottom on the anchor (w10:wrap on a VML
615
+ * group): text wraps around the art as around a text box. */
612
616
  wrap?: WrapMode;
613
617
  /** wp:anchor dist* in px, used with `wrap`. */
614
618
  dist?: {
@@ -670,6 +674,14 @@ interface ShapeImage {
670
674
  type Shape = (ShapeLine | ShapeTextbox | ShapeImage | ShapeArt | ShapeWordArt) & {
671
675
  /** wp:anchor relativeHeight, used for object stacking order. */
672
676
  z?: number;
677
+ /** Print with markup only: the shape's run is a tracked change, so the
678
+ * layout frames the shape's box in the author's color, struck through
679
+ * when the change is a deletion or a move away. The balloon and the
680
+ * change bar come from the run's changes, at the anchor's line. */
681
+ revision?: {
682
+ color: string;
683
+ struck: boolean;
684
+ };
673
685
  };
674
686
  /**
675
687
  * Floating/anchored object: does not occupy inline space; positioned against
@@ -915,12 +927,34 @@ interface RubyContent {
915
927
  align?: "center" | "distributeLetter" | "distributeSpace" | "left" | "right" | "rightVertical";
916
928
  }
917
929
  type RunContent = MathContent | TextContent | BreakContent | TabContent | PTabContent | ImageContent | FieldContent | AnchorContent | DrawingContent | NoteRefContent | RubyContent;
930
+ /**
931
+ * A tracked change a printed markup page shows beside its text (see
932
+ * pdf/comments.ts): what it is, in Word's words, and who made it when.
933
+ * Set only when the document is parsed for print with author colors.
934
+ */
935
+ interface Revision {
936
+ /** Unique over the document: the element's kind and w:id. */
937
+ id: string;
938
+ kind: "ins" | "del" | "moveTo" | "moveFrom" | "format";
939
+ author: string;
940
+ /** w:date, verbatim: Word writes local time there (see word-date.ts). */
941
+ date?: string;
942
+ /** True UTC time from the w16du:dateUtc attribute, when present. */
943
+ dateUtc?: string;
944
+ /** The balloon's text: "Inserted", "Deleted", "Moved from", "Moved to",
945
+ * "Inserted row", "Deleted row", "Formatted: Font: Bold", ... */
946
+ label: string;
947
+ }
918
948
  interface Run {
919
949
  type: "run";
920
950
  props: RunProps;
921
951
  content: RunContent[];
922
952
  /** Source w:r element. */
923
953
  src?: XmlElement;
954
+ /** The tracked changes this run is part of, or whose balloon anchors at
955
+ * it (a paragraph's, row's or table's format change is put on each of its
956
+ * runs). Print with markup only. */
957
+ changes?: Revision[];
924
958
  /** Element whose children array contains src (w:p, w:hyperlink, …). */
925
959
  srcParent?: XmlElement;
926
960
  }
@@ -928,6 +962,8 @@ interface Hyperlink {
928
962
  type: "hyperlink";
929
963
  href?: string;
930
964
  anchor?: string;
965
+ /** Complex HYPERLINK whose target contains nested fields. */
966
+ field?: FieldContent;
931
967
  runs: Run[];
932
968
  }
933
969
  type ParaChild = Run | Hyperlink;
@@ -947,6 +983,13 @@ interface Paragraph {
947
983
  * as a pilcrow in the revision's colors after the paragraph's content; it is
948
984
  * not text, so find, word count and the like never see it. */
949
985
  markRevision?: "ins" | "del";
986
+ /** The mark's pilcrow color when the markup is printed with author colors. */
987
+ markRevisionColor?: string;
988
+ /** Print with markup only: the tracked changes anchored at the paragraph
989
+ * mark, which the layout's mark run carries so they get a balloon and a
990
+ * change bar — the mark's own insertion or deletion, and the body's final
991
+ * section change (w:sectPrChange) on the last paragraph. */
992
+ markChanges?: Revision[];
950
993
  /** Source w:p element. */
951
994
  src?: XmlElement;
952
995
  }
@@ -983,6 +1026,12 @@ interface TableCell {
983
1026
  blocks: Block[];
984
1027
  }
985
1028
  interface TableRowProps {
1029
+ /** Empty grid columns before/after the row's cells. */
1030
+ gridBefore?: number;
1031
+ gridAfter?: number;
1032
+ /** Preferred widths in px of the omitted columns (wBefore/wAfter). */
1033
+ widthBefore?: number;
1034
+ widthAfter?: number;
986
1035
  /** px; undefined = auto */
987
1036
  height?: number;
988
1037
  heightRule?: "auto" | "atLeast" | "exact";
@@ -1165,8 +1214,10 @@ interface DocComment {
1165
1214
  id: string;
1166
1215
  author: string;
1167
1216
  initials?: string;
1168
- /** ISO timestamp from w:date, verbatim. */
1217
+ /** w:date, verbatim: Word writes local time there (see word-date.ts). */
1169
1218
  date?: string;
1219
+ /** True UTC time from commentsExtensible.xml (w16cex:dateUtc), when present. */
1220
+ dateUtc?: string;
1170
1221
  /** Plain text of the comment body (paragraphs joined with newlines). */
1171
1222
  text: string;
1172
1223
  /** w14:paraId of the comment's last body paragraph (threading key). */
@@ -1178,6 +1229,26 @@ interface DocComment {
1178
1229
  * thread parent; Word grays the whole thread from the parent's flag. */
1179
1230
  resolved?: boolean;
1180
1231
  }
1232
+ /** A reviewer from word/people.xml (w15:person): the display name, and the
1233
+ * identity the presence provider knows them by (w15:presenceInfo). */
1234
+ interface DocPerson {
1235
+ author: string;
1236
+ providerId?: string;
1237
+ userId?: string;
1238
+ }
1239
+ /** A font file the package embeds (word/fonts/*.odttf), from fontTable.xml:
1240
+ * a w:font's w:embedRegular, w:embedBold, w:embedItalic or w:embedBoldItalic. */
1241
+ interface DocEmbeddedFont {
1242
+ /** The family the document names (w:font w:name). */
1243
+ family: string;
1244
+ bold: boolean;
1245
+ italic: boolean;
1246
+ /** The package part that holds the file. */
1247
+ part: string;
1248
+ /** The w:fontKey GUID the file is obfuscated with (ECMA-376 Part 1
1249
+ * §17.8.1); absent when the file is a plain font. */
1250
+ key?: string;
1251
+ }
1181
1252
  interface HeaderFooter {
1182
1253
  blocks: Block[];
1183
1254
  }
@@ -1268,6 +1339,11 @@ interface Theme {
1268
1339
  /** A read-only view over the OPC (zip) package inside a .docx file. */
1269
1340
  declare class Package {
1270
1341
  private files;
1342
+ /** Every entry is held to ZipBudget before any is inflated. fflate
1343
+ * inflates an entry into a buffer of the size the directory gives, so an
1344
+ * entry whose data holds more stops there: memory stays within the
1345
+ * budget, and the entry fails, or comes out cut short (an XML part then
1346
+ * fails to parse). */
1271
1347
  constructor(data: Uint8Array);
1272
1348
  static from(data: ArrayBuffer | Uint8Array): Package;
1273
1349
  /** A package over an already-unzipped entry map (DocxDocument.clone). */
@@ -1412,6 +1488,18 @@ declare class StableIds {
1412
1488
  } | null;
1413
1489
  }
1414
1490
 
1491
+ interface ParseContext {
1492
+ theme?: Theme;
1493
+ /** Tracked-changes display: "final" hides deletions and shows insertions
1494
+ * plain (default); "markup" colors both. */
1495
+ revisionView?: "final" | "markup";
1496
+ /** Markup printed with Word's author colors: each author's color, in the
1497
+ * order the authors first appear; a run in a change records the change
1498
+ * (Run.changes). Absent, the markup view colors insertions green and
1499
+ * deletions red for every author, as the editor shows them. */
1500
+ revisionColor?: (author: string) => string;
1501
+ }
1502
+
1415
1503
  interface Relationship {
1416
1504
  id: string;
1417
1505
  type: string;
@@ -1420,13 +1508,41 @@ interface Relationship {
1420
1508
  }
1421
1509
  type Relationships = Map<string, Relationship>;
1422
1510
 
1511
+ interface DocParseContext extends ParseContext {
1512
+ rels: Relationships;
1513
+ /** Text boxes parsed from a header/footer part edit as independent stories. */
1514
+ independentTextboxStories?: boolean;
1515
+ /** Read another package part's XML (SmartArt cached drawings live in
1516
+ * word/diagrams/drawing*.xml, reachable only through the data part). */
1517
+ readPart?: (part: string) => XmlElement | undefined;
1518
+ /** Cross-reference bookmark capture: Word's Insert-Cross-Reference targets
1519
+ * are `_RefNNN` bookmarks whose range delimits the referenced text (e.g. a
1520
+ * caption's "Figure " + SEQ field). REF fields re-render that text at
1521
+ * layout time — the docx cache is stale. `open` is keyed by bookmark id
1522
+ * while the range is unclosed; `byName` keeps the finished run lists. */
1523
+ refBookmarks?: {
1524
+ open: Map<string, Run[]>;
1525
+ byName: Map<string, Run[]>;
1526
+ };
1527
+ }
1528
+
1423
1529
  /** The two note parts a document can carry — see notePartsHolding. */
1424
1530
  type NotePart = "footnotes" | "endnotes";
1425
- /**
1426
- * A fully parsed .docx: sections of blocks, styles, numbering, theme, and
1427
- * header/footer parts, with helpers to resolve effective formatting.
1428
- */
1429
- declare class DocxDocument {
1531
+ interface FromFilesOptions {
1532
+ /** Build the header and footer block models (`headers`, `footers`). Default true. */
1533
+ headerFooterBlocks?: boolean;
1534
+ /** Tracked-changes display from the start, so the parts parsed at load
1535
+ * (headers, footers, notes) follow it too. Default "final". */
1536
+ revisionView?: "final" | "markup";
1537
+ /** Print markup: each author's changes in Word's color for that author,
1538
+ * and every change recorded on its runs (see Revision). */
1539
+ revisionColors?: boolean;
1540
+ /** With revisionColors: false gives every author's changes the first
1541
+ * color, red, so that no color tells one author from another (print
1542
+ * without authors). Default true. */
1543
+ revisionAuthors?: boolean;
1544
+ }
1545
+ declare class DocxDocument$1 {
1430
1546
  /** Changes whenever refresh() rebuilds the parsed model. Plain in-place text
1431
1547
  * edits can keep this stable so incremental layout reuses model-only caches. */
1432
1548
  private _modelVersion;
@@ -1439,15 +1555,20 @@ declare class DocxDocument {
1439
1555
  styles: Styles;
1440
1556
  numbering: Numbering;
1441
1557
  sections: Section[];
1442
- /** Header/footer parts keyed by relationship id from document.xml.rels. */
1558
+ /** Header/footer parts keyed by relationship id from document.xml.rels.
1559
+ * Empty when the document was opened without them (fromFiles). */
1443
1560
  readonly headers: Map<string, HeaderFooter>;
1444
1561
  readonly footers: Map<string, HeaderFooter>;
1562
+ private readonly headerFooterBlocks;
1445
1563
  /** Note content by note id. */
1446
1564
  readonly footnotes: Map<number, Block[]>;
1447
1565
  readonly endnotes: Map<number, Block[]>;
1448
1566
  /** The separator paragraph controls the gap between its rule and the first
1449
1567
  * footnote. */
1450
1568
  readonly footnoteSeparator: Block[];
1569
+ /** The w:continuationSeparator footnote: it opens a note area that starts
1570
+ * with a note continued from the previous page. */
1571
+ readonly footnoteContinuationSeparator: Block[];
1451
1572
  /** `_Ref` cross-reference bookmark ranges (name → captured runs). REF
1452
1573
  * fields re-render the referenced text from these — Word recomputes REF on
1453
1574
  * open, so the cached field result in the file is stale. */
@@ -1499,12 +1620,18 @@ declare class DocxDocument {
1499
1620
  /** Review comments from word/comments.xml (empty when the part is absent).
1500
1621
  * Re-derived from the retained comments XML on every refresh(). */
1501
1622
  comments: DocComment[];
1623
+ /** The reviewers word/people.xml names (empty when the part is absent). */
1624
+ readonly people: DocPerson[];
1625
+ /** The font files the package embeds, as fontTable.xml lists them (empty when it embeds none). */
1626
+ readonly embeddedFonts: DocEmbeddedFont[];
1502
1627
  /** Retained comments.xml tree (editing + save round-trip), when present. */
1503
1628
  private commentsPart;
1504
1629
  private commentsRoot;
1505
1630
  /** Retained commentsExtended.xml tree (comment threading), when present. */
1506
1631
  private commentsExtPart;
1507
1632
  private commentsExtRoot;
1633
+ /** True UTC comment times from commentsExtensible.xml, by the comment's last w14:paraId. */
1634
+ private readonly commentDateUtc;
1508
1635
  private commentsExtDirty;
1509
1636
  /** Conditional table formats per table style id, keyed by the Styles object
1510
1637
  * so re-parsing styles.xml (edits) naturally invalidates the cache. */
@@ -1564,12 +1691,18 @@ declare class DocxDocument {
1564
1691
  private readonly ctxBase;
1565
1692
  /** Tracked-changes display mode; refresh() re-derives after changes. */
1566
1693
  revisionView: "final" | "markup";
1694
+ /** The revision authors in the order they first appeared, for revisionColor. */
1695
+ private readonly revisionAuthors;
1696
+ /** FromFilesOptions.revisionAuthors. */
1697
+ private revisionAuthorColors;
1567
1698
  private readonly relsPath;
1568
1699
  private relsRoot;
1569
1700
  private contentTypesRoot;
1570
- /** Canonical XML as first parsed from each always-modeled package part.
1571
- * If the retained tree still matches on save, keep the part's original
1572
- * bytes instead of replacing producer formatting such as CRLF line ends. */
1701
+ /** A fingerprint of the canonical XML first parsed from each always-modeled
1702
+ * package part. If the retained tree still matches on save, keep the part's
1703
+ * original bytes instead of replacing producer formatting such as CRLF line
1704
+ * ends. A fingerprint and not the XML itself: the XML was a second copy of
1705
+ * every document part, 30 MB for a 0.85 MB .docx. */
1573
1706
  private readonly originalModeledXml;
1574
1707
  private docPrIdCounter;
1575
1708
  /** Transient layout state: set by the engine while laying out a docGrid
@@ -1578,7 +1711,11 @@ declare class DocxDocument {
1578
1711
  * section. Safe as document-scoped mutable state because layout is
1579
1712
  * single-threaded and sequential per section. */
1580
1713
  charGridEa: boolean;
1581
- private constructor();
1714
+ protected constructor(pkg: Package, options?: FromFilesOptions);
1715
+ private readonly coreProperties;
1716
+ /** Resolve the content controls under `root` as the document's own were
1717
+ * resolved when it loaded, for body XML parsed outside it (stream/body.ts). */
1718
+ hydrateControls(root: XmlElement): void;
1582
1719
  /** Resolve content controls mapped to standard package core properties.
1583
1720
  * Word refreshes these bindings on open, so the serialized sdtContent can
1584
1721
  * be stale even though the visible value comes from docProps/core.xml. */
@@ -1589,6 +1726,12 @@ declare class DocxDocument {
1589
1726
  * Re-derive the document model from the retained XML trees. Called after
1590
1727
  * edit commands mutate the XML.
1591
1728
  */
1729
+ /** An author's revision color: Word's "by author" palette, given out in
1730
+ * the order the authors first appear (the parts parsed at load, headers,
1731
+ * footers and notes, before the body), the ninth author taking the first
1732
+ * color again. Without authors (FromFilesOptions.revisionAuthors), the
1733
+ * first color for all. */
1734
+ revisionColor(author: string): string;
1592
1735
  /** Switch tracked-changes display and re-derive the model. */
1593
1736
  setRevisionView(view: "final" | "markup"): void;
1594
1737
  /** Invalidated on refresh; see layoutGlobalSig. */
@@ -1769,6 +1912,13 @@ declare class DocxDocument {
1769
1912
  * type keep it — and its part's content. True when anything was added.
1770
1913
  */
1771
1914
  ensureHfVariantParts(type: "first" | "even"): boolean;
1915
+ /**
1916
+ * A new empty header or footer part, referenced as `type` from `sectPr`
1917
+ * alone. Returns the part's target, as headerFooterRoot and
1918
+ * relationshipsOf take it. compareDocuments gives a header the revised
1919
+ * document lost one of these, to hold the original's content struck.
1920
+ */
1921
+ addHfPart(kind: "header" | "footer", type: "default" | "first" | "even", sectPr: XmlElement): string;
1772
1922
  /** Create and register a new empty header/footer part — package part,
1773
1923
  * document relationship, content-type override, hfParts entry — with no
1774
1924
  * section references of its own; the caller decides which sectPrs point at
@@ -1917,7 +2067,13 @@ declare class DocxDocument {
1917
2067
  * copy of the revised document, and the round trip through the zip was a
1918
2068
  * third of its time on a document that had not changed at all.
1919
2069
  */
1920
- clone(): DocxDocument;
2070
+ clone(): DocxDocument$1;
2071
+ /**
2072
+ * The package's parts as save() writes them, before they are zipped: a
2073
+ * writer that streams the zip to disk (compare-cli) takes them one at a
2074
+ * time, without a zip of them all in memory and its unzip.
2075
+ */
2076
+ saveFiles(): Record<string, Uint8Array>;
1921
2077
  saveAsync(): Promise<Uint8Array>;
1922
2078
  private buildPackage;
1923
2079
  private buildPackageFiles;
@@ -1969,7 +2125,7 @@ declare class DocxDocument {
1969
2125
  * its w:drawing, and without its image part the result's reject-all
1970
2126
  * brought the picture back as an empty frame.
1971
2127
  */
1972
- adoptRelFrom(source: DocxDocument, relId: string, scope?: {
2128
+ adoptRelFrom(source: DocxDocument$1, relId: string, scope?: {
1973
2129
  from?: string | null;
1974
2130
  into?: string | null;
1975
2131
  }): string | null;
@@ -2029,7 +2185,21 @@ declare class DocxDocument {
2029
2185
  colorsRelId: string;
2030
2186
  drawingRelId: string;
2031
2187
  };
2032
- static load(data: ArrayBuffer | Uint8Array): DocxDocument;
2188
+ /** A document from .docx bytes, including Strict Open XML packages. */
2189
+ static load(data: ArrayBuffer | Uint8Array): DocxDocument$1;
2190
+ /** A document over parts already unzipped (stream/body.ts's shell). */
2191
+ /**
2192
+ * A document over an already-unzipped entry map. With `headerFooterBlocks`
2193
+ * false, `headers` and `footers` stay empty: their XML is still read,
2194
+ * compared and saved, but no block models are built from it (about 1 KB a
2195
+ * paragraph), for a caller that compares the document and never lays it out
2196
+ * (compare-cli).
2197
+ */
2198
+ static fromFiles(files: Record<string, Uint8Array>, options?: FromFilesOptions): DocxDocument$1;
2199
+ /** The context the body's blocks are parsed with, for a caller that keeps
2200
+ * the body outside the document (stream/body.ts). Its REF bookmark capture
2201
+ * starts empty; the caller decides whether `refBookmarks` reads from it. */
2202
+ bodyParseContext(): DocParseContext;
2033
2203
  media(part: string): Uint8Array | undefined;
2034
2204
  /**
2035
2205
  * Pending-media registry (plan doc 05 change 1 / doc 16 §6): parts whose
@@ -2101,6 +2271,17 @@ declare class DocxDocument {
2101
2271
  numberingInstance(numId: number): NumInstance | undefined;
2102
2272
  private findDocumentPart;
2103
2273
  private readXmlOptional;
2274
+ /** A part Word prints (the document, a header or footer, the notes, the
2275
+ * comments), refused when it holds a w:altChunk anywhere. */
2276
+ private readPrintedXml;
2277
+ }
2278
+
2279
+ /** Word documents, including binary .doc and the oldest Word formats. */
2280
+ declare class DocxDocument extends DocxDocument$1 {
2281
+ private constructor();
2282
+ static load(data: ArrayBuffer | Uint8Array): DocxDocument;
2283
+ static fromFiles(files: Record<string, Uint8Array>, options?: FromFilesOptions): DocxDocument;
2284
+ clone(): DocxDocument;
2104
2285
  }
2105
2286
 
2106
2287
  /** Outline/shadow for an ordinary run — Word's Home-tab "Text Effects and
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  validateAgentComposeRequest,
18
18
  validateAgentOperationShape,
19
19
  validateIntent
20
- } from "./chunk-QDZRRLHW.js";
20
+ } from "./chunk-32YIZ3LI.js";
21
21
 
22
22
  // src/session.ts
23
23
  var LocalDocumentSession = class {
@@ -60,6 +60,9 @@ function isMathTypeEscape(bytes, offset, length) {
60
60
  const name = [77, 97, 116, 104, 84, 121, 112, 101];
61
61
  return name.every((value, i) => bytes[offset + 10 + i] === value);
62
62
  }
63
+ function isEmbeddedEmfEscape(view, params, end) {
64
+ return params + 8 <= end && view.getUint16(params, true) === 15 && view.getUint32(params + 4, true) === 1128680791;
65
+ }
63
66
  function hasMathTypeEscapes(bytes) {
64
67
  const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
65
68
  let offset = 18;
@@ -129,7 +132,7 @@ function prepareWmf(input) {
129
132
  }
130
133
  append(copy);
131
134
  }
132
- } else if (fn === META_ESCAPE && mathType) {
135
+ } else if (fn === META_ESCAPE && (mathType || !isEmbeddedEmfEscape(view, params, offset + length))) {
133
136
  } else if (fn !== META_SETBKCOLOR) {
134
137
  append(bytes.slice(offset, offset + length));
135
138
  }
@@ -190,4 +193,4 @@ export {
190
193
  prepareWmf,
191
194
  renderWmf
192
195
  };
193
- //# sourceMappingURL=wmf-KUCU4S75.js.map
196
+ //# sourceMappingURL=wmf-AG7P5P7E.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../core/src/render/wmf.ts"],"sourcesContent":["import * as WmfModule from \"wmf\";\n\nconst WMF = (WmfModule.default ?? WmfModule) as typeof WmfModule.default;\n\nconst META_EOF = 0x0000;\nconst META_SETBKCOLOR = 0x0201;\nconst META_SETTEXTALIGN = 0x012e;\nconst META_MOVETO = 0x0214;\nconst META_LINETO = 0x0213;\nconst META_POLYLINE = 0x0325;\nconst META_ESCAPE = 0x0626;\nconst META_EXTTEXTOUT = 0x0a32;\nconst PLACEABLE_KEY = 0x9ac6cdd7;\n\nconst SYMBOL_TEXT: Record<string, string> = {\n p: \"π\",\n \"¥\": \"∞\",\n \"¶\": \"∂\",\n å: \"∑\",\n D: \"Δ\",\n};\n\nexport function decodeWmfText(text: string, family: string): { text: string; family: string } {\n if (family === \"Symbol\") {\n return { text: [...text].map((char) => SYMBOL_TEXT[char] ?? char).join(\"\"), family };\n }\n if (family === \"ËÎÌå\") {\n return { text: text.replace(/£¨/g, \"(\").replace(/£©/g, \")\"), family: \"SimSun\" };\n }\n return { text, family };\n}\n\nfunction record(fn: number, params: Uint8Array): Uint8Array {\n const length = 6 + params.length + (params.length & 1);\n const out = new Uint8Array(length);\n const view = new DataView(out.buffer);\n view.setUint32(0, length / 2, true);\n view.setUint16(4, fn, true);\n out.set(params, 6);\n return out;\n}\n\nfunction polyline(from: [number, number], to: [number, number]): Uint8Array {\n const params = new Uint8Array(10);\n const view = new DataView(params.buffer);\n view.setUint16(0, 2, true);\n view.setInt16(2, from[0], true);\n view.setInt16(4, from[1], true);\n view.setInt16(6, to[0], true);\n view.setInt16(8, to[1], true);\n return record(META_POLYLINE, params);\n}\n\nfunction textRecord(char: number, x: number, y: number, advance: number): Uint8Array {\n const params = new Uint8Array(12);\n const view = new DataView(params.buffer);\n view.setInt16(0, y, true);\n view.setInt16(2, x, true);\n view.setUint16(4, 1, true);\n params[8] = char;\n view.setInt16(10, advance, true);\n return record(META_EXTTEXTOUT, params);\n}\n\nfunction isMathTypeEscape(bytes: Uint8Array, offset: number, length: number): boolean {\n if (length < 18) return false;\n const name = [0x4d, 0x61, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65];\n return name.every((value, i) => bytes[offset + 10 + i] === value);\n}\n\n/** A META_ESCAPE MFCOMMENT that carries part of an embedded EMF (comment identifier \"WMFC\"). */\nfunction isEmbeddedEmfEscape(view: DataView, params: number, end: number): boolean {\n return params + 8 <= end && view.getUint16(params, true) === 0x000f && view.getUint32(params + 4, true) === 0x43464d57;\n}\n\nfunction hasMathTypeEscapes(bytes: Uint8Array): boolean {\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n let offset = 18;\n while (offset + 6 <= bytes.length) {\n const length = view.getUint32(offset, true) * 2;\n if (length < 6 || offset + length > bytes.length) return false;\n const fn = view.getUint16(offset + 4, true);\n if (fn === META_ESCAPE && isMathTypeEscape(bytes, offset, length)) return true;\n offset += length;\n if (fn === META_EOF) break;\n }\n return false;\n}\n\n/**\n * Make MathType's legacy WMF records consumable by the small `wmf` renderer.\n * MathType positions text through TA_UPDATECP + MOVETO and draws fraction bars\n * with LINETO. The dependency does not implement those records, so translate\n * them to the equivalent absolute EXTTEXTOUT and POLYLINE records first.\n */\nexport function prepareWmf(input: Uint8Array): Uint8Array | null {\n let bytes = input;\n if (bytes.length >= 22 && new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(0, true) === PLACEABLE_KEY) {\n bytes = bytes.subarray(22);\n }\n if (bytes.length < 18) return null;\n\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n const mathType = hasMathTypeEscapes(bytes);\n const parts: Uint8Array[] = [bytes.slice(0, 18)];\n let offset = 18;\n let textAlign = 0;\n let current: [number, number] = [0, 0];\n let maxRecordWords = 0;\n\n const append = (part: Uint8Array) => {\n parts.push(part);\n maxRecordWords = Math.max(maxRecordWords, part.length / 2);\n };\n\n while (offset + 6 <= bytes.length) {\n const length = view.getUint32(offset, true) * 2;\n if (length < 6 || offset + length > bytes.length) return null;\n const fn = view.getUint16(offset + 4, true);\n const params = offset + 6;\n\n if (fn === META_SETTEXTALIGN) {\n textAlign = view.getUint16(params, true);\n append(bytes.slice(offset, offset + length));\n } else if (fn === META_MOVETO) {\n current = [view.getInt16(params + 2, true), view.getInt16(params, true)];\n } else if (fn === META_LINETO) {\n const next: [number, number] = [view.getInt16(params + 2, true), view.getInt16(params, true)];\n append(polyline(current, next));\n current = next;\n } else if (fn === META_EXTTEXTOUT) {\n const y = view.getInt16(params, true);\n const x = view.getInt16(params + 2, true);\n const count = view.getUint16(params + 4, true);\n const options = view.getUint16(params + 6, true);\n let charsAt = params + 8 + (options & 6 ? 8 : 0);\n const advancesAt = charsAt + count + (count & 1);\n const hasAdvances = options === 0 && advancesAt + count * 2 <= offset + length;\n\n if (hasAdvances) {\n let position: [number, number] = textAlign & 1 ? current : [x, y];\n for (let i = 0; i < count; i++) {\n const advance = view.getInt16(advancesAt + i * 2, true);\n append(textRecord(bytes[charsAt + i], position[0], position[1], advance));\n position = [position[0] + advance, position[1]];\n }\n if (textAlign & 1) current = position;\n } else {\n const copy = bytes.slice(offset, offset + length);\n if (textAlign & 1) {\n const copyView = new DataView(copy.buffer, copy.byteOffset, copy.byteLength);\n copyView.setInt16(6, current[1], true);\n copyView.setInt16(8, current[0], true);\n }\n append(copy);\n }\n } else if (fn === META_ESCAPE && (mathType || !isEmbeddedEmfEscape(view, params, offset + length))) {\n // An escape other than an embedded EMF (MathType metadata, printer\n // escapes, other comments) is not a drawing command. The dependency\n // otherwise rejects the whole image on it.\n } else if (fn !== META_SETBKCOLOR) {\n append(bytes.slice(offset, offset + length));\n }\n\n offset += length;\n if (fn === META_EOF) break;\n }\n\n const total = parts.reduce((sum, part) => sum + part.length, 0);\n const out = new Uint8Array(total);\n let at = 0;\n for (const part of parts) {\n out.set(part, at);\n at += part.length;\n }\n const outView = new DataView(out.buffer);\n outView.setUint32(6, total / 2, true);\n outView.setUint32(12, maxRecordWords, true);\n return out;\n}\n\nexport function renderWmf(bytes: Uint8Array, width: number, height: number): string | null {\n try {\n const prepared = prepareWmf(bytes);\n if (!prepared) return null;\n const [rawWidth, rawHeight] = WMF.image_size(prepared).map(Math.abs);\n if (!rawWidth || !rawHeight) return null;\n\n const scale = Math.max(1, window.devicePixelRatio || 1);\n const canvas = document.createElement(\"canvas\");\n canvas.width = Math.max(1, Math.round(width * scale));\n canvas.height = Math.max(1, Math.round(height * scale));\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n ctx.fillStyle = \"#fff\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.fillStyle = \"#000\";\n ctx.scale(canvas.width / rawWidth, canvas.height / rawHeight);\n\n const actions = WMF.get_actions(prepared);\n for (const action of actions) {\n if (!action.s) continue;\n delete action.s.Extent;\n if (action.t === \"text\" && action.v !== undefined && action.s.Font) {\n const decoded = decodeWmfText(action.v, action.s.Font.Name);\n action.v = decoded.text;\n action.s.Font.Name = decoded.family;\n }\n if (action.t === \"poly\") {\n action.s.Pen ??= { Style: 0, Width: 1, Color: 0 };\n action.s.Brush ??= { Style: 1, Color: 0 };\n }\n }\n WMF.render_canvas(actions, canvas);\n return canvas.toDataURL(\"image/png\");\n } catch {\n return null;\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordinweb/agent",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Complete, schema-enforced DOCX creation, inspection, and editing tools for AI agents",
5
5
  "license": "MIT",
6
6
  "repository": {