@docx4j/core-ts 0.5.0 → 0.6.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.
Files changed (155) hide show
  1. package/NOTICE +4 -0
  2. package/README.md +32 -4
  3. package/dist/html/convert.mjs +2 -1
  4. package/dist/html/elements.mjs +2 -1
  5. package/dist/model/color/ColorMath.d.mts +29 -0
  6. package/dist/model/color/ColorMath.mjs +146 -0
  7. package/dist/model/color/ColorTables.d.mts +6 -0
  8. package/dist/model/color/ColorTables.mjs +83 -0
  9. package/dist/model/color/DrawingMLColors.d.mts +52 -0
  10. package/dist/model/color/DrawingMLColors.mjs +374 -0
  11. package/dist/model/color/ResolvedColor.d.mts +36 -0
  12. package/dist/model/color/ResolvedColor.mjs +65 -0
  13. package/dist/model/color/SpreadsheetColors.d.mts +36 -0
  14. package/dist/model/color/SpreadsheetColors.mjs +84 -0
  15. package/dist/model/color/StyleFill.d.mts +28 -0
  16. package/dist/model/color/StyleFill.mjs +21 -0
  17. package/dist/model/color/ThemeColors.d.mts +86 -0
  18. package/dist/model/color/ThemeColors.mjs +304 -0
  19. package/dist/model/color/WordColors.d.mts +71 -0
  20. package/dist/model/color/WordColors.mjs +121 -0
  21. package/dist/model/color/index.d.mts +6 -0
  22. package/dist/model/color/index.mjs +30 -0
  23. package/dist/model/content/Body.d.mts +145 -23
  24. package/dist/model/content/Body.mjs +509 -141
  25. package/dist/model/content/Comment.d.mts +21 -3
  26. package/dist/model/content/Comment.mjs +195 -19
  27. package/dist/model/content/ContentControl.d.mts +197 -18
  28. package/dist/model/content/ContentControl.mjs +664 -95
  29. package/dist/model/content/Font.d.mts +67 -17
  30. package/dist/model/content/Font.mjs +114 -35
  31. package/dist/model/content/InlinePicture.d.mts +11 -0
  32. package/dist/model/content/InlinePicture.mjs +21 -1
  33. package/dist/model/content/List.mjs +3 -0
  34. package/dist/model/content/Paragraph.d.mts +189 -13
  35. package/dist/model/content/Paragraph.mjs +870 -74
  36. package/dist/model/content/Range.d.mts +227 -12
  37. package/dist/model/content/Range.mjs +785 -59
  38. package/dist/model/content/ResolvedView.d.mts +104 -0
  39. package/dist/model/content/ResolvedView.mjs +596 -0
  40. package/dist/model/content/Table.d.mts +29 -3
  41. package/dist/model/content/Table.mjs +109 -33
  42. package/dist/model/content/TrackedChange.d.mts +172 -13
  43. package/dist/model/content/TrackedChange.mjs +728 -167
  44. package/dist/model/content/comments.d.mts +20 -6
  45. package/dist/model/content/comments.mjs +67 -57
  46. package/dist/model/content/generalException.d.mts +18 -0
  47. package/dist/model/content/generalException.mjs +24 -0
  48. package/dist/model/content/index.d.mts +8 -3
  49. package/dist/model/content/index.mjs +7 -2
  50. package/dist/model/content/mathText.d.mts +21 -0
  51. package/dist/model/content/mathText.mjs +267 -0
  52. package/dist/model/content/officeText.d.mts +27 -0
  53. package/dist/model/content/officeText.mjs +74 -0
  54. package/dist/model/content/outline.d.mts +5 -0
  55. package/dist/model/content/outline.mjs +13 -0
  56. package/dist/model/content/placeholders.d.mts +110 -0
  57. package/dist/model/content/placeholders.mjs +253 -0
  58. package/dist/model/content/search.d.mts +72 -0
  59. package/dist/model/content/search.mjs +204 -2
  60. package/dist/model/content/spanEdits.d.mts +159 -0
  61. package/dist/model/content/spanEdits.mjs +728 -0
  62. package/dist/model/content/story.d.mts +44 -0
  63. package/dist/model/content/story.mjs +92 -0
  64. package/dist/model/content/tableColumns.d.mts +1 -1
  65. package/dist/model/content/tableColumns.mjs +108 -80
  66. package/dist/model/content/tableRevisions.d.mts +11 -3
  67. package/dist/model/content/tableRevisions.mjs +72 -42
  68. package/dist/model/content/tableRules.d.mts +30 -0
  69. package/dist/model/content/tableRules.mjs +100 -0
  70. package/dist/model/content/textBoxes.d.mts +18 -0
  71. package/dist/model/content/textBoxes.mjs +105 -0
  72. package/dist/model/content/trackedChangeFilter.d.mts +39 -0
  73. package/dist/model/content/trackedChangeFilter.mjs +81 -0
  74. package/dist/model/content/tracking.d.mts +28 -0
  75. package/dist/model/content/tracking.mjs +149 -10
  76. package/dist/model/content/tree.d.mts +171 -22
  77. package/dist/model/content/tree.mjs +329 -53
  78. package/dist/model/customxml/CustomXmlPartCollection.d.mts +8 -0
  79. package/dist/model/customxml/CustomXmlPartCollection.mjs +34 -11
  80. package/dist/model/customxml/XmlMapping.d.mts +1 -1
  81. package/dist/model/customxml/XmlMapping.mjs +11 -0
  82. package/dist/model/customxml/bindings.d.mts +21 -2
  83. package/dist/model/customxml/bindings.mjs +76 -32
  84. package/dist/model/customxml/kinds.d.mts +8 -3
  85. package/dist/model/customxml/kinds.mjs +26 -5
  86. package/dist/model/customxml/picturePlaceholder.d.mts +17 -0
  87. package/dist/model/customxml/picturePlaceholder.mjs +32 -0
  88. package/dist/model/customxml/pictures.d.mts +4 -3
  89. package/dist/model/customxml/pictures.mjs +18 -6
  90. package/dist/model/customxml/xhtml.mjs +8 -2
  91. package/dist/model/index.d.mts +2 -0
  92. package/dist/model/index.mjs +4 -0
  93. package/dist/model/listnumbering/Emulator.d.mts +37 -5
  94. package/dist/model/listnumbering/Emulator.mjs +63 -9
  95. package/dist/model/properties/PropertyResolver.d.mts +60 -1
  96. package/dist/model/properties/PropertyResolver.mjs +115 -2
  97. package/dist/model/properties/catalogue.d.mts +19 -5
  98. package/dist/model/properties/catalogue.mjs +41 -15
  99. package/dist/model/properties/log.d.mts +1 -1
  100. package/dist/model/properties/log.mjs +5 -5
  101. package/dist/model/properties/table.mjs +4 -2
  102. package/dist/model/text/Extractor.d.mts +289 -0
  103. package/dist/model/text/Extractor.mjs +2162 -0
  104. package/dist/model/text/LinkTargets.d.mts +45 -0
  105. package/dist/model/text/LinkTargets.mjs +170 -0
  106. package/dist/model/text/MarkdownExporter.d.mts +140 -0
  107. package/dist/model/text/MarkdownExporter.mjs +255 -0
  108. package/dist/model/text/PlainText.d.mts +29 -0
  109. package/dist/model/text/PlainText.mjs +539 -0
  110. package/dist/model/text/TextContext.d.mts +161 -0
  111. package/dist/model/text/TextContext.mjs +425 -0
  112. package/dist/model/text/TextOptions.d.mts +150 -0
  113. package/dist/model/text/TextOptions.mjs +278 -0
  114. package/dist/model/text/TextResult.d.mts +504 -0
  115. package/dist/model/text/TextResult.mjs +526 -0
  116. package/dist/model/text/Texts.d.mts +99 -0
  117. package/dist/model/text/Texts.mjs +187 -0
  118. package/dist/model/text/WmlToMarkdown.d.mts +120 -0
  119. package/dist/model/text/WmlToMarkdown.mjs +911 -0
  120. package/dist/model/text/commonmark.d.mts +121 -0
  121. package/dist/model/text/commonmark.mjs +655 -0
  122. package/dist/model/text/index.d.mts +7 -0
  123. package/dist/model/text/index.mjs +8 -0
  124. package/dist/model/text/normalize.d.mts +8 -0
  125. package/dist/model/text/normalize.mjs +13 -0
  126. package/dist/model/text/outline.d.mts +4 -0
  127. package/dist/model/text/outline.mjs +71 -0
  128. package/dist/office-js/fragment.d.mts +7 -5
  129. package/dist/office-js/fragment.mjs +63 -14
  130. package/dist/office-js/proxy.d.mts +8 -0
  131. package/dist/office-js/proxy.mjs +29 -0
  132. package/dist/office-js/run.mjs +2 -0
  133. package/dist/office-js/supported.generated.mjs +16 -0
  134. package/dist/office-js/toApiScript.mjs +21 -5
  135. package/dist/opc/Save.d.mts +17 -0
  136. package/dist/opc/Save.mjs +12 -2
  137. package/dist/opc/index.d.mts +3 -3
  138. package/dist/opc/index.mjs +1 -1
  139. package/dist/opc/mce/preprocessor.d.mts +28 -3
  140. package/dist/opc/mce/preprocessor.mjs +4 -4
  141. package/dist/opc/mce/understood.d.mts +30 -6
  142. package/dist/opc/mce/understood.mjs +37 -7
  143. package/dist/packages/OpcPackage.d.mts +13 -0
  144. package/dist/packages/OpcPackage.mjs +1 -0
  145. package/dist/packages/WordprocessingMLPackage.d.mts +45 -8
  146. package/dist/packages/WordprocessingMLPackage.mjs +155 -20
  147. package/dist/parts/DefaultXmlPart.mjs +2 -2
  148. package/dist/parts/Part.d.mts +10 -2
  149. package/dist/parts/XmlPart.d.mts +12 -30
  150. package/dist/parts/XmlPart.mjs +44 -93
  151. package/dist/parts/wml/comments.mjs +30 -0
  152. package/dist/parts/wml/index.mjs +12 -0
  153. package/dist/xml/dom.d.mts +7 -0
  154. package/dist/xml/dom.mjs +18 -0
  155. package/package.json +2 -2
@@ -0,0 +1,27 @@
1
+ import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
2
+ import { type Element } from './tree.mjs';
3
+ /** The text without the characters XML 1.0 excludes (E3). */
4
+ export declare function dropExcluded(text: string): string;
5
+ /** True when the text holds a character a writer writes as an element. */
6
+ export declare function holdsElementCharacters(text: string): boolean;
7
+ /**
8
+ * How a writer takes a line feed and a carriage return:
9
+ * - `paragraphs`: a paragraph break each, `\r\n` one (E1: `insertText` and every writer through `Paragraph.splice`);
10
+ * the caller splits the text into lines (`linesOf`);
11
+ * - `one-paragraph`: `\n` and `\r\n` a `w:br`, `\r` a `w:cr` (E2: `insertParagraph`, `Paragraph.text =`), a recorded
12
+ * departure from Word, which writes their escapes as text;
13
+ * - `multi-line`: each a `w:br` (a multi-line plain-text control, or a bound block control of one: section 61 item 3);
14
+ * - `single-line`: none, and no break either (a single-line plain-text control: F3).
15
+ */
16
+ export type LineBreaks = 'paragraphs' | 'one-paragraph' | 'multi-line' | 'single-line';
17
+ /** The text a writer of that kind writes, its line feeds and carriage returns turned into its characters. */
18
+ export declare function forWriter(text: string, lineBreaks: LineBreaks): string;
19
+ /** The text's lines, at each line feed, carriage return or `\r\n` (E1). */
20
+ export declare function linesOf(text: string): string[];
21
+ /** A run's items for a text: a `w:t` for each plain stretch, the element each mapped character reads as. */
22
+ export declare function officeItems(text: string): Element[];
23
+ /**
24
+ * A run of text a writer keeps in one paragraph (E2: `insertParagraph`, `Paragraph.text =`), or in a plain-text control
25
+ * as its kind takes it: the excluded characters dropped, every other character that is an element written as it.
26
+ */
27
+ export declare function oneParagraphRun(text: string, rPr?: wml.RPr, lineBreaks?: LineBreaks): Element<wml.R>;
@@ -0,0 +1,74 @@
1
+ // Office JS's characters written back (CR-002 section 60). The readers give Word's character stream (CR-012 phase 4,
2
+ // `officeItemText`): a `w:br` U+000B, a page break U+000C, a column break U+000E, a `w:cr` U+000D, the non-breaking and
3
+ // optional hyphens U+001E and U+001F, a note reference U+0002. A writer turns each back into the element it reads as
4
+ // (D1, as Word 365's writers do in check 55), drops the characters XML 1.0 excludes (E3: Word drops them too), and
5
+ // takes a line feed or carriage return as its kind of writer does: a paragraph break for `insertText` (E1), a break
6
+ // for `insertParagraph` (E2), a break or nothing in a bound or plain-text control (section 61 item 3, F3).
7
+ import * as el from '@docx4j/generated-objects-ts/el/org_docx4j_wml';
8
+ import { t as textItem, br as breakItem, tab as tabItem } from '@docx4j/generated-objects-ts/builders/wml';
9
+ import { runOf } from './tree.mjs';
10
+ /**
11
+ * The characters XML 1.0 excludes that are no element: U+0002 (a note reference, which no text makes) and the other C0
12
+ * controls but tab, line feed, carriage return and the five that are elements, U+FFFE, U+FFFF and an unpaired surrogate.
13
+ */
14
+ const EXCLUDED = /[\u0000-\u0008\u000F-\u001D￾￿]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
15
+ /** The characters a writer writes as elements: tab, the three breaks, a carriage return, a line feed, the two hyphens. */
16
+ const ELEMENT_CHARACTERS = /[\t\n\r\u000B\u000C\u000E\u001E\u001F]/;
17
+ /** The text without the characters XML 1.0 excludes (E3). */
18
+ export function dropExcluded(text) {
19
+ return text.replace(EXCLUDED, '');
20
+ }
21
+ /** True when the text holds a character a writer writes as an element. */
22
+ export function holdsElementCharacters(text) {
23
+ return ELEMENT_CHARACTERS.test(text);
24
+ }
25
+ /** The text a writer of that kind writes, its line feeds and carriage returns turned into its characters. */
26
+ export function forWriter(text, lineBreaks) {
27
+ switch (lineBreaks) {
28
+ case 'one-paragraph': return text.replace(/\r\n|\n/g, '\u000B');
29
+ case 'multi-line': return text.replace(/\r\n|\r|\n/g, '\u000B');
30
+ case 'single-line': return text.replace(/\r\n|[\r\n\u000B\u000C\u000E]/g, '');
31
+ default: return text;
32
+ }
33
+ }
34
+ /** The text's lines, at each line feed, carriage return or `\r\n` (E1). */
35
+ export function linesOf(text) {
36
+ return text.split(/\r\n|\r|\n/);
37
+ }
38
+ /** The element a character reads as (`officeItemText` in reverse); a line feed a `w:br`. */
39
+ function elementFor(c) {
40
+ switch (c) {
41
+ case '\t': return tabItem();
42
+ case '\u000C': return breakItem('page');
43
+ case '\u000E': return breakItem('column');
44
+ case '\r': return el.cr({});
45
+ case '\u001E': return el.noBreakHyphen({});
46
+ case '\u001F': return el.softHyphen({});
47
+ default: return breakItem(); // U+000B, and a line feed a writer left
48
+ }
49
+ }
50
+ /** A run's items for a text: a `w:t` for each plain stretch, the element each mapped character reads as. */
51
+ export function officeItems(text) {
52
+ const out = [];
53
+ let plain = '';
54
+ for (const c of text) {
55
+ if (ELEMENT_CHARACTERS.test(c)) {
56
+ if (plain !== '')
57
+ out.push(textItem(plain));
58
+ plain = '';
59
+ out.push(elementFor(c));
60
+ }
61
+ else
62
+ plain += c;
63
+ }
64
+ if (plain !== '')
65
+ out.push(textItem(plain));
66
+ return out;
67
+ }
68
+ /**
69
+ * A run of text a writer keeps in one paragraph (E2: `insertParagraph`, `Paragraph.text =`), or in a plain-text control
70
+ * as its kind takes it: the excluded characters dropped, every other character that is an element written as it.
71
+ */
72
+ export function oneParagraphRun(text, rPr, lineBreaks = 'one-paragraph') {
73
+ return runOf(officeItems(forWriter(dropExcluded(text), lineBreaks)), rPr);
74
+ }
@@ -0,0 +1,5 @@
1
+ import type { Body, Outline } from './Body.mjs';
2
+ /** What `Body.outline` asks of the text model: the outline of a body, or of its top-level blocks at these indices, under these options and context. */
3
+ export type OutlineReader = (body: Body, options: unknown, context: unknown, blocks?: readonly number[]) => Promise<Outline>;
4
+ export declare function setOutlineReader(implementation: OutlineReader): void;
5
+ export declare function outlineReader(): OutlineReader;
@@ -0,0 +1,13 @@
1
+ // The outline's reader (CR-012 D3): the text model's, which this module can't import, since the text model
2
+ // imports the content API. The text model registers it (`model/text/outline.mts`), and the package classes
3
+ // load that module, as the comment parts register themselves (CR-002 phase G).
4
+ import { Docx4JException } from '../../opc/exceptions.mjs';
5
+ let reader;
6
+ export function setOutlineReader(implementation) {
7
+ reader = implementation;
8
+ }
9
+ export function outlineReader() {
10
+ if (!reader)
11
+ throw new Docx4JException('The text model is not loaded: import @docx4j/core-ts, @docx4j/core-ts/model or @docx4j/core-ts/packages');
12
+ return reader;
13
+ }
@@ -0,0 +1,110 @@
1
+ import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
2
+ import { type Element } from './tree.mjs';
3
+ import type { XmlPart } from '../../parts/XmlPart.mjs';
4
+ import type { Part } from '../../parts/Part.mjs';
5
+ /** Word's default placeholder entry, which a control Word makes names (checks 64 to 66). */
6
+ export declare const DEFAULT_PLACEHOLDER_ENTRY = "DefaultPlaceholder_-1854013440";
7
+ /** The default entry's text, as Word 365 writes it. */
8
+ export declare const DEFAULT_PLACEHOLDER_TEXT = "Click or tap here to enter text.";
9
+ /** A default placeholder entry: its name and its text. */
10
+ export interface DefaultEntry {
11
+ name: string;
12
+ text: string;
13
+ }
14
+ /**
15
+ * Word's default placeholder entry for each kind of control that has one, as Word 365 makes them from the Developer tab
16
+ * (Jason's `placeholders.docx`, 2026-10-25; CR-002 section 63.22, as docx4j's CR-063 D8 has it): each in the glossary
17
+ * with the default entry's `w:docPartPr`, its body one run in the Placeholder Text style. A picture, a check box and a
18
+ * repeating section have none; the group, citation, equation, bibliography and `w:docPartObj` kinds are unmeasured.
19
+ */
20
+ export declare const DEFAULT_ENTRIES: {
21
+ readonly text: {
22
+ readonly name: "DefaultPlaceholder_-1854013440";
23
+ readonly text: "Click or tap here to enter text.";
24
+ };
25
+ readonly date: {
26
+ readonly name: "DefaultPlaceholder_-1854013437";
27
+ readonly text: "Click or tap to enter a date.";
28
+ };
29
+ readonly list: {
30
+ readonly name: "DefaultPlaceholder_-1854013438";
31
+ readonly text: "Choose an item.";
32
+ };
33
+ readonly buildingBlock: {
34
+ readonly name: "DefaultPlaceholder_-1854013436";
35
+ readonly text: "Choose a building block.";
36
+ };
37
+ readonly repeatingSectionItem: {
38
+ readonly name: "DefaultPlaceholder_-1854013435";
39
+ readonly text: "Enter any content that you want to repeat, including other content controls. You can also insert this control around table rows in order to repeat parts of a table.";
40
+ };
41
+ };
42
+ /** The default entry Word gives a control of this kind (`DEFAULT_ENTRIES`); undefined for a kind it gives none. */
43
+ export declare function defaultEntryFor(sdtPr: wml.SdtPr | undefined): DefaultEntry | undefined;
44
+ /** The glossary entry a control's `w:placeholder` names; undefined where it names none (the bare form). */
45
+ export declare function placeholderEntryOf(sdtPr: wml.SdtPr | undefined): string | undefined;
46
+ /**
47
+ * Names `entry` in the control's `w:placeholder`, where Word writes it: after `w:id`, before `w:showingPlcHdr` and the
48
+ * binding (check 64's controls, as Word saved them).
49
+ */
50
+ export declare function namePlaceholderEntry(sdtPr: wml.SdtPr, entry: string): void;
51
+ /** A new entry's name, as Word names one: 32 upper-case hex digits, a new GUID's (check 65). */
52
+ export declare function newEntryName(): string;
53
+ /** What a package's glossary gives: an entry's text by name. */
54
+ export interface GlossaryHost {
55
+ getMainDocumentPart(): {
56
+ glossaryDocumentPart: XmlPart<wml.GlossaryDocument> | undefined;
57
+ addTargetPart(part: Part): unknown;
58
+ };
59
+ }
60
+ /**
61
+ * The placeholder entries of a package's glossary: those its glossary document part holds, read privately (the part
62
+ * stays untouched), and those written since, which go into the glossary when the package is saved (`flush`).
63
+ */
64
+ export declare class GlossaryEntries {
65
+ /** Entries by name, as the glossary part was last read; undefined until `load`. */
66
+ private read;
67
+ /** The part they were read from. */
68
+ private source;
69
+ /** Entries to write on save: name, text. */
70
+ private readonly pending;
71
+ /** Reads the glossary's entries, privately; again only where the part changed. */
72
+ load(glossary: XmlPart<wml.GlossaryDocument> | undefined): Promise<void>;
73
+ /**
74
+ * An entry's text, `null` where neither the glossary nor this session holds it, as Office JS reads it (check 65). An
75
+ * entry's paragraphs are a `\r` apart, as a control's are.
76
+ */
77
+ textOf(name: string): string | null;
78
+ /**
79
+ * An entry's body, the blocks of its `w:docPartBody` (not copies), `null` where neither the glossary nor this session
80
+ * holds it; an entry written this session is one paragraph, one run of its text in the Placeholder Text style.
81
+ */
82
+ bodyOf(name: string): Element[] | null;
83
+ /** True once the glossary has been read (`load`): until then an entry it holds reads as missing. */
84
+ get loaded(): boolean;
85
+ private entry;
86
+ /** Whether the glossary holds an entry of this name, or one is waiting to be written. */
87
+ has(name: string): boolean;
88
+ /** An entry to write on save, where the glossary doesn't hold one of that name. */
89
+ require(name: string, text: string): void;
90
+ /** True while entries wait for the save. */
91
+ get waiting(): boolean;
92
+ /** Entries waiting for the save, for a clone. */
93
+ copyTo(target: GlossaryEntries): void;
94
+ /**
95
+ * Writes the waiting entries into the glossary, making it where the file has none (D9 (a): the glossary document
96
+ * part and a styles part holding Placeholder Text, related from it), and puts Placeholder Text into a glossary's
97
+ * styles part that lacks it: an entry whose style its glossary lacks loses it in Word's save (check 65's 65b).
98
+ */
99
+ flush(host: GlossaryHost, make: {
100
+ glossary: () => XmlPart<wml.GlossaryDocument>;
101
+ styles: () => XmlPart<wml.Styles>;
102
+ }): Promise<void>;
103
+ }
104
+ /**
105
+ * What a control shows of an entry (CR-002 section 63.18, as revised by 63.21): a copy of each of its body's paragraphs'
106
+ * run-level content, every run as the glossary holds it. Word brought an entry back so, the control's own run properties
107
+ * not over it (check 68, cases 21 to 24), and doesn't restyle it (check 65's 65b, case 9). The paragraphs' properties stay
108
+ * in the glossary, whose styles they name.
109
+ */
110
+ export declare function entryContentOf(body: Element[]): Element[][];
@@ -0,0 +1,253 @@
1
+ import * as el from '@docx4j/generated-objects-ts/el/org_docx4j_wml';
2
+ import * as f from '@docx4j/generated-objects-ts/factory/org_docx4j_wml';
3
+ import { sdtProperty, sdtKindOf, textOf } from '@docx4j/generated-objects-ts/builders/wml';
4
+ import { deepCopy } from '@docx4j/generated-objects-ts';
5
+ import { linkParents } from './tree.mjs';
6
+ import { uuid } from '../customxml/CustomXmlPartCollection.mjs';
7
+ import { PLACEHOLDER_STYLE, placeholderRun } from '../customxml/bindings.mjs';
8
+ import { placeholderStyle } from '../../parts/wml/placeholderStyle.mjs';
9
+ /** Word's default placeholder entry, which a control Word makes names (checks 64 to 66). */
10
+ export const DEFAULT_PLACEHOLDER_ENTRY = 'DefaultPlaceholder_-1854013440';
11
+ /** The default entry's text, as Word 365 writes it. */
12
+ export const DEFAULT_PLACEHOLDER_TEXT = 'Click or tap here to enter text.';
13
+ /**
14
+ * Word's default placeholder entry for each kind of control that has one, as Word 365 makes them from the Developer tab
15
+ * (Jason's `placeholders.docx`, 2026-10-25; CR-002 section 63.22, as docx4j's CR-063 D8 has it): each in the glossary
16
+ * with the default entry's `w:docPartPr`, its body one run in the Placeholder Text style. A picture, a check box and a
17
+ * repeating section have none; the group, citation, equation, bibliography and `w:docPartObj` kinds are unmeasured.
18
+ */
19
+ export const DEFAULT_ENTRIES = {
20
+ text: { name: DEFAULT_PLACEHOLDER_ENTRY, text: DEFAULT_PLACEHOLDER_TEXT },
21
+ date: { name: 'DefaultPlaceholder_-1854013437', text: 'Click or tap to enter a date.' },
22
+ list: { name: 'DefaultPlaceholder_-1854013438', text: 'Choose an item.' },
23
+ buildingBlock: { name: 'DefaultPlaceholder_-1854013436', text: 'Choose a building block.' },
24
+ repeatingSectionItem: {
25
+ name: 'DefaultPlaceholder_-1854013435',
26
+ text: 'Enter any content that you want to repeat, including other content controls. You can also insert this control around table rows in order to repeat parts of a table.',
27
+ },
28
+ };
29
+ /** The default entry Word gives a control of this kind (`DEFAULT_ENTRIES`); undefined for a kind it gives none. */
30
+ export function defaultEntryFor(sdtPr) {
31
+ switch (sdtKindOf(sdtPr)) {
32
+ case 'RichText':
33
+ case 'PlainText': return DEFAULT_ENTRIES.text;
34
+ case 'DatePicker': return DEFAULT_ENTRIES.date;
35
+ case 'DropDownList':
36
+ case 'ComboBox': return DEFAULT_ENTRIES.list;
37
+ case 'BuildingBlockGallery': return sdtProperty(sdtPr, 'docPartList') ? DEFAULT_ENTRIES.buildingBlock : undefined;
38
+ case 'RepeatingSectionItem': return DEFAULT_ENTRIES.repeatingSectionItem;
39
+ default: return undefined;
40
+ }
41
+ }
42
+ /** The glossary entry a control's `w:placeholder` names; undefined where it names none (the bare form). */
43
+ export function placeholderEntryOf(sdtPr) {
44
+ var _a, _b, _c;
45
+ const value = (_a = sdtProperty(sdtPr, 'placeholder')) === null || _a === void 0 ? void 0 : _a.value;
46
+ return value === undefined ? undefined : (_c = (_b = value.docPart) === null || _b === void 0 ? void 0 : _b.val) !== null && _c !== void 0 ? _c : '';
47
+ }
48
+ /**
49
+ * Names `entry` in the control's `w:placeholder`, where Word writes it: after `w:id`, before `w:showingPlcHdr` and the
50
+ * binding (check 64's controls, as Word saved them).
51
+ */
52
+ export function namePlaceholderEntry(sdtPr, entry) {
53
+ var _a;
54
+ const items = ((_a = sdtPr.rPrOrAliasOrLock) !== null && _a !== void 0 ? _a : (sdtPr.rPrOrAliasOrLock = []));
55
+ const element = el.placeholder(f.createCTPlaceholder({ docPart: f.createCTPlaceholderDocPart({ val: entry }) }));
56
+ const at = items.findIndex((i) => i.name.localPart === 'placeholder');
57
+ if (at >= 0) {
58
+ items[at] = element;
59
+ linkParents(element, sdtPr);
60
+ return;
61
+ }
62
+ const after = new Set(['showingPlcHdr', 'dataBinding', 'temporary']);
63
+ const before = items.findIndex((i) => after.has(i.name.localPart));
64
+ items.splice(before < 0 ? items.length : before, 0, element);
65
+ linkParents(element, sdtPr);
66
+ }
67
+ /** A new entry's name, as Word names one: 32 upper-case hex digits, a new GUID's (check 65). */
68
+ export function newEntryName() {
69
+ return uuid().replace(/-/g, '').toUpperCase();
70
+ }
71
+ /**
72
+ * The placeholder entries of a package's glossary: those its glossary document part holds, read privately (the part
73
+ * stays untouched), and those written since, which go into the glossary when the package is saved (`flush`).
74
+ */
75
+ export class GlossaryEntries {
76
+ constructor() {
77
+ /** Entries to write on save: name, text. */
78
+ this.pending = new Map();
79
+ }
80
+ /** Reads the glossary's entries, privately; again only where the part changed. */
81
+ async load(glossary) {
82
+ if (glossary === this.source && this.read !== undefined)
83
+ return;
84
+ this.source = glossary;
85
+ this.read = glossary ? entriesOf(await glossary.readContents().catch(() => undefined)) : new Map();
86
+ }
87
+ /**
88
+ * An entry's text, `null` where neither the glossary nor this session holds it, as Office JS reads it (check 65). An
89
+ * entry's paragraphs are a `\r` apart, as a control's are.
90
+ */
91
+ textOf(name) {
92
+ var _a, _b;
93
+ return (_b = (_a = this.entry(name)) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : null;
94
+ }
95
+ /**
96
+ * An entry's body, the blocks of its `w:docPartBody` (not copies), `null` where neither the glossary nor this session
97
+ * holds it; an entry written this session is one paragraph, one run of its text in the Placeholder Text style.
98
+ */
99
+ bodyOf(name) {
100
+ var _a, _b;
101
+ return (_b = (_a = this.entry(name)) === null || _a === void 0 ? void 0 : _a.body) !== null && _b !== void 0 ? _b : null;
102
+ }
103
+ /** True once the glossary has been read (`load`): until then an entry it holds reads as missing. */
104
+ get loaded() {
105
+ var _a;
106
+ return this.read !== undefined || ((_a = this.source) === null || _a === void 0 ? void 0 : _a.isUnmarshalled) === true;
107
+ }
108
+ entry(name) {
109
+ var _a;
110
+ const pending = this.pending.get(name);
111
+ if (pending !== undefined)
112
+ return { text: pending, body: [el.p({ content: [placeholderRun(undefined, pending)] })] };
113
+ const part = this.source;
114
+ if (part === null || part === void 0 ? void 0 : part.isUnmarshalled)
115
+ return entriesOf(part.contents).get(name);
116
+ return (_a = this.read) === null || _a === void 0 ? void 0 : _a.get(name);
117
+ }
118
+ /** Whether the glossary holds an entry of this name, or one is waiting to be written. */
119
+ has(name) {
120
+ return this.textOf(name) !== null;
121
+ }
122
+ /** An entry to write on save, where the glossary doesn't hold one of that name. */
123
+ require(name, text) {
124
+ if (!this.has(name))
125
+ this.pending.set(name, text);
126
+ }
127
+ /** True while entries wait for the save. */
128
+ get waiting() {
129
+ return this.pending.size > 0;
130
+ }
131
+ /** Entries waiting for the save, for a clone. */
132
+ copyTo(target) {
133
+ for (const [name, text] of this.pending)
134
+ target.pending.set(name, text);
135
+ }
136
+ /**
137
+ * Writes the waiting entries into the glossary, making it where the file has none (D9 (a): the glossary document
138
+ * part and a styles part holding Placeholder Text, related from it), and puts Placeholder Text into a glossary's
139
+ * styles part that lacks it: an entry whose style its glossary lacks loses it in Word's save (check 65's 65b).
140
+ */
141
+ async flush(host, make) {
142
+ var _a;
143
+ if (this.pending.size === 0)
144
+ return;
145
+ const main = host.getMainDocumentPart();
146
+ let glossary = main.glossaryDocumentPart;
147
+ if (!glossary) {
148
+ glossary = make.glossary();
149
+ glossary.setContents(f.createGlossaryDocument({ docParts: f.createCTDocParts({ docPart: [] }) }));
150
+ main.addTargetPart(glossary);
151
+ }
152
+ const doc = await glossary.getContents();
153
+ const docParts = ((_a = doc.docParts) !== null && _a !== void 0 ? _a : (doc.docParts = f.createCTDocParts({ docPart: [] })));
154
+ linkParents(docParts, doc);
155
+ const present = entriesOf(doc);
156
+ for (const [name, text] of this.pending) {
157
+ if (present.has(name))
158
+ continue;
159
+ const part = docPartOf(name, text);
160
+ docParts.docPart.push(part);
161
+ linkParents(part, docParts);
162
+ }
163
+ this.pending.clear();
164
+ this.source = glossary;
165
+ await ensureGlossaryStyles(glossary, make.styles);
166
+ }
167
+ }
168
+ /** A glossary's entries by name. */
169
+ function entriesOf(doc) {
170
+ var _a, _b, _c, _d, _e;
171
+ const out = new Map();
172
+ for (const part of (_b = (_a = doc === null || doc === void 0 ? void 0 : doc.docParts) === null || _a === void 0 ? void 0 : _a.docPart) !== null && _b !== void 0 ? _b : []) {
173
+ const name = (_c = part.docPartPr) === null || _c === void 0 ? void 0 : _c.nameOrStyleOrCategory.find((i) => i.TYPE_NAME === 'org_docx4j_wml.CTDocPartName');
174
+ if (!(name === null || name === void 0 ? void 0 : name.val))
175
+ continue;
176
+ const body = ((_e = (_d = part.docPartBody) === null || _d === void 0 ? void 0 : _d.content) !== null && _e !== void 0 ? _e : []);
177
+ const paragraphs = body.filter((e) => e.value.TYPE_NAME === 'org_docx4j_wml.P');
178
+ out.set(name.val, { text: paragraphs.map((p) => textOf(p.value)).join('\r'), body });
179
+ }
180
+ return out;
181
+ }
182
+ /**
183
+ * What a control shows of an entry (CR-002 section 63.18, as revised by 63.21): a copy of each of its body's paragraphs'
184
+ * run-level content, every run as the glossary holds it. Word brought an entry back so, the control's own run properties
185
+ * not over it (check 68, cases 21 to 24), and doesn't restyle it (check 65's 65b, case 9). The paragraphs' properties stay
186
+ * in the glossary, whose styles they name.
187
+ */
188
+ export function entryContentOf(body) {
189
+ var _a;
190
+ const out = [];
191
+ for (const block of body) {
192
+ if (block.value.TYPE_NAME !== 'org_docx4j_wml.P')
193
+ continue;
194
+ const items = ((_a = block.value.content) !== null && _a !== void 0 ? _a : []).filter((e) => { var _a, _b; return !['proofErr', 'bookmarkStart', 'bookmarkEnd'].includes((_b = (_a = e.name) === null || _a === void 0 ? void 0 : _a.localPart) !== null && _b !== void 0 ? _b : ''); });
195
+ out.push(items.map((item) => ({ name: item.name, value: deepCopy(item.value) })));
196
+ }
197
+ return out;
198
+ }
199
+ /**
200
+ * A placeholder entry as Word writes one (check 65): the default entry's `w:docPartPr` (category General, gallery
201
+ * placeholder, type `bbPlcHdr`, behaviour content) with a `w:guid` of its own, and a body of one paragraph, one run in
202
+ * the Placeholder Text style.
203
+ */
204
+ function docPartOf(name, text) {
205
+ const pr = f.createCTDocPartPr({
206
+ nameOrStyleOrCategory: [
207
+ f.createCTDocPartName({ val: name }),
208
+ f.createCTDocPartCategory({ name: f.createCTDocPartCategoryName({ val: 'General' }), gallery: f.createCTDocPartGallery({ val: 'placeholder' }) }),
209
+ f.createCTDocPartTypes({ type: [f.createCTDocPartType({ val: 'bbPlcHdr' })] }),
210
+ f.createCTDocPartBehaviors({ behavior: [f.createCTDocPartBehavior({ val: 'content' })] }),
211
+ f.createCTGuid({ val: `{${uuid().toUpperCase()}}` }),
212
+ ],
213
+ });
214
+ const body = f.createBody({ content: [el.p({ content: [placeholderRun(undefined, text)] })] });
215
+ return f.createCTDocPart({ docPartPr: pr, docPartBody: body });
216
+ }
217
+ /** Default Paragraph Font as Word defines it, which Placeholder Text is based on (check 34's glossary). */
218
+ function defaultParagraphFont() {
219
+ return f.createStyle({
220
+ type: 'character', _default: true, styleId: 'DefaultParagraphFont',
221
+ name: f.createStyleName({ val: 'Default Paragraph Font' }),
222
+ uiPriority: f.createStyleUiPriority({ val: 1 }),
223
+ semiHidden: f.createBooleanDefaultTrue(),
224
+ unhideWhenUsed: f.createBooleanDefaultTrue(),
225
+ });
226
+ }
227
+ /** The glossary's styles part holds Placeholder Text and the style it is based on, made where the glossary has none. */
228
+ async function ensureGlossaryStyles(glossary, make) {
229
+ var _a, _b;
230
+ const holder = glossary;
231
+ let part = holder.styleDefinitionsPart;
232
+ if (!part) {
233
+ part = make();
234
+ part.setContents(f.createStyles({ style: [] }));
235
+ holder.addTargetPart(part);
236
+ }
237
+ else {
238
+ // a styles part that has them already stays untouched
239
+ const read = await part.readContents().catch(() => undefined);
240
+ const ids = new Set(((_a = read === null || read === void 0 ? void 0 : read.style) !== null && _a !== void 0 ? _a : []).map((s) => s.styleId));
241
+ if (ids.has('DefaultParagraphFont') && ids.has(PLACEHOLDER_STYLE))
242
+ return;
243
+ }
244
+ const styles = await part.getContents();
245
+ const list = ((_b = styles.style) !== null && _b !== void 0 ? _b : (styles.style = []));
246
+ const ids = new Set(list.map((s) => s.styleId));
247
+ for (const style of [defaultParagraphFont(), placeholderStyle()]) {
248
+ if (ids.has(style.styleId))
249
+ continue;
250
+ list.push(style);
251
+ linkParents(style, styles);
252
+ }
253
+ }
@@ -43,3 +43,75 @@ export declare function matchesOf(text: string, pattern: RegExp): RegExpExecArra
43
43
  * to nothing, as both languages do.
44
44
  */
45
45
  export declare function expandReplacement(replacement: string, match: RegExpExecArray, options?: SearchOptions): string;
46
+ /** What `officeMatches` reads of a paragraph: its segments in Office JS's characters, the objects and hidden items listed. */
47
+ export interface SearchSegment {
48
+ text: string;
49
+ start: number;
50
+ object?: boolean;
51
+ hidden?: boolean;
52
+ item: {
53
+ name: {
54
+ localPart: string;
55
+ };
56
+ };
57
+ }
58
+ /** One match, as offsets in `Paragraph.text`, with the expression's match over the search's own text. */
59
+ export interface OfficeMatch {
60
+ start: number;
61
+ end: number;
62
+ match: RegExpExecArray;
63
+ }
64
+ /**
65
+ * Every match of a query in a paragraph's text by Office JS's rules (check 48, Word's default view): the
66
+ * text is `Paragraph.text` (hidden text left out, so a query matches across it and never in it), where a
67
+ * picture is a place of no text that a plain query doesn't match across and `^g` matches, and an optional
68
+ * hyphen is passed over unless the query names it (`^-`). A plain query takes Word's Find codes
69
+ * (`FIND_CODES`), and its `-` matches a non-breaking hyphen too. Wildcards read the same text, the codes
70
+ * not translated; a regular expression (`matchRegExp`, this package's extension) reads `Paragraph.text`
71
+ * itself. Only text in [from, to) is read: a range's search.
72
+ */
73
+ export declare function officeMatches(segments: readonly SearchSegment[], query: string, options?: SearchOptions, from?: number, to?: number): OfficeMatch[];
74
+ /** A paragraph's part in a wildcard search across its marks: its segments, the [from, to) of its text read, its text's length, whether its mark follows. */
75
+ export interface MarkedSegments {
76
+ segments: readonly SearchSegment[];
77
+ from: number;
78
+ to: number;
79
+ length: number;
80
+ mark: boolean;
81
+ }
82
+ /** A hit of a wildcard search across marks: from offset `start` in piece `first` to `end` in piece `last`, which holds its mark where `mark`. */
83
+ export interface MarkedMatch {
84
+ first: number;
85
+ start: number;
86
+ last: number;
87
+ end: number;
88
+ mark: boolean;
89
+ match: RegExpExecArray;
90
+ }
91
+ /**
92
+ * A wildcard query's hits over consecutive paragraphs, each followed by its mark where `mark` says, as Word's wildcards
93
+ * match a paragraph mark (check 59; CR-002 section 32, K7): `?`, `*` and a class cross one, `^13` is one. The text read
94
+ * in each paragraph is `officeMatches`' for wildcards; the caller gives only paragraphs a hit may span (one cell's, or
95
+ * none's) and only the marks it may hold (a paragraph's own, never a cell's or a row's end).
96
+ */
97
+ export declare function wildcardMatchesAcross(pieces: readonly MarkedSegments[], query: string, options: SearchOptions): MarkedMatch[];
98
+ /**
99
+ * Refuses a wildcard replacement where a hit holds a paragraph mark (CR-002 section 32, K7): `search` finds it, as
100
+ * Word's does (check 59), but what replacing a mark leaves isn't measured, as for a plain `^p` (`refuseMarkReplacement`).
101
+ */
102
+ export declare function refuseWildcardMarkReplacement(className: string, hits: readonly {
103
+ spansParagraphs: boolean;
104
+ holdsEndMark: boolean;
105
+ }[]): void;
106
+ /**
107
+ * A plain query split at Word's paragraph mark code, `^p`: its pieces, one more than the marks, each a plain
108
+ * query of its own (`^^` stays an escaped caret); undefined where the query holds no `^p`. What a `Range`'s search
109
+ * across paragraphs matches piece by piece (CR-014 phase 3).
110
+ */
111
+ export declare function paragraphMarkPieces(query: string): string[] | undefined;
112
+ /**
113
+ * Refuses a replacement whose query holds `^p` (CR-014 phase 3): `search` finds such a hit, but what Office JS's
114
+ * replacement of a paragraph mark leaves isn't measured, and `insertText('Replace')` keeps a last mark (check 52).
115
+ * Until phase 3 such a query matched the two characters `^p`, where Word matches a mark.
116
+ */
117
+ export declare function refuseMarkReplacement(className: string, find: string, options?: SearchOptions): void;