docxmlater 10.3.5 → 10.4.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.
- package/README.md +158 -7
- package/dist/core/Document.d.ts +102 -3
- package/dist/core/Document.d.ts.map +1 -1
- package/dist/core/Document.js +775 -50
- package/dist/core/Document.js.map +1 -1
- package/dist/core/DocumentContent.d.ts.map +1 -1
- package/dist/core/DocumentContent.js +0 -8
- package/dist/core/DocumentContent.js.map +1 -1
- package/dist/core/DocumentGenerator.d.ts.map +1 -1
- package/dist/core/DocumentGenerator.js +9 -5
- package/dist/core/DocumentGenerator.js.map +1 -1
- package/dist/core/DocumentParser.d.ts.map +1 -1
- package/dist/core/DocumentParser.js +588 -102
- package/dist/core/DocumentParser.js.map +1 -1
- package/dist/core/RelationshipManager.d.ts.map +1 -1
- package/dist/core/RelationshipManager.js +4 -3
- package/dist/core/RelationshipManager.js.map +1 -1
- package/dist/elements/Bookmark.d.ts +7 -0
- package/dist/elements/Bookmark.d.ts.map +1 -1
- package/dist/elements/Bookmark.js +24 -4
- package/dist/elements/Bookmark.js.map +1 -1
- package/dist/elements/BookmarkManager.d.ts.map +1 -1
- package/dist/elements/BookmarkManager.js +4 -3
- package/dist/elements/BookmarkManager.js.map +1 -1
- package/dist/elements/CommonTypes.d.ts +2 -2
- package/dist/elements/CommonTypes.d.ts.map +1 -1
- package/dist/elements/CommonTypes.js +14 -1
- package/dist/elements/CommonTypes.js.map +1 -1
- package/dist/elements/Field.d.ts +1 -1
- package/dist/elements/Field.d.ts.map +1 -1
- package/dist/elements/Field.js +1 -1
- package/dist/elements/Field.js.map +1 -1
- package/dist/elements/Footer.d.ts +2 -0
- package/dist/elements/Footer.d.ts.map +1 -1
- package/dist/elements/Footer.js +6 -0
- package/dist/elements/Footer.js.map +1 -1
- package/dist/elements/Header.d.ts +2 -0
- package/dist/elements/Header.d.ts.map +1 -1
- package/dist/elements/Header.js +6 -0
- package/dist/elements/Header.js.map +1 -1
- package/dist/elements/Image.d.ts +1 -0
- package/dist/elements/Image.d.ts.map +1 -1
- package/dist/elements/Image.js +17 -2
- package/dist/elements/Image.js.map +1 -1
- package/dist/elements/Paragraph.d.ts +81 -1
- package/dist/elements/Paragraph.d.ts.map +1 -1
- package/dist/elements/Paragraph.js +515 -21
- package/dist/elements/Paragraph.js.map +1 -1
- package/dist/elements/Revision.d.ts +0 -1
- package/dist/elements/Revision.d.ts.map +1 -1
- package/dist/elements/Revision.js +0 -12
- package/dist/elements/Revision.js.map +1 -1
- package/dist/elements/RevisionManager.d.ts +0 -1
- package/dist/elements/RevisionManager.d.ts.map +1 -1
- package/dist/elements/RevisionManager.js +0 -2
- package/dist/elements/RevisionManager.js.map +1 -1
- package/dist/elements/Run.d.ts +16 -4
- package/dist/elements/Run.d.ts.map +1 -1
- package/dist/elements/Run.js +114 -22
- package/dist/elements/Run.js.map +1 -1
- package/dist/elements/Section.d.ts +7 -1
- package/dist/elements/Section.d.ts.map +1 -1
- package/dist/elements/Section.js +185 -4
- package/dist/elements/Section.js.map +1 -1
- package/dist/elements/Shape.js.map +1 -1
- package/dist/elements/Table.d.ts +30 -1
- package/dist/elements/Table.d.ts.map +1 -1
- package/dist/elements/Table.js +357 -40
- package/dist/elements/Table.js.map +1 -1
- package/dist/elements/TableCell.d.ts +3 -0
- package/dist/elements/TableCell.d.ts.map +1 -1
- package/dist/elements/TableCell.js +30 -3
- package/dist/elements/TableCell.js.map +1 -1
- package/dist/elements/TableGridChange.d.ts +0 -1
- package/dist/elements/TableGridChange.d.ts.map +1 -1
- package/dist/elements/TableGridChange.js +0 -10
- package/dist/elements/TableGridChange.js.map +1 -1
- package/dist/elements/TableRow.d.ts +4 -0
- package/dist/elements/TableRow.d.ts.map +1 -1
- package/dist/elements/TableRow.js +31 -3
- package/dist/elements/TableRow.js.map +1 -1
- package/dist/formatting/AbstractNumbering.d.ts +5 -0
- package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
- package/dist/formatting/AbstractNumbering.js +22 -0
- package/dist/formatting/AbstractNumbering.js.map +1 -1
- package/dist/formatting/NumberingLevel.d.ts.map +1 -1
- package/dist/formatting/NumberingLevel.js +3 -3
- package/dist/formatting/NumberingLevel.js.map +1 -1
- package/dist/formatting/Style.d.ts +1 -0
- package/dist/formatting/Style.d.ts.map +1 -1
- package/dist/formatting/Style.js +25 -59
- package/dist/formatting/Style.js.map +1 -1
- package/dist/formatting/StylesManager.d.ts +1 -0
- package/dist/formatting/StylesManager.d.ts.map +1 -1
- package/dist/formatting/StylesManager.js +12 -0
- package/dist/formatting/StylesManager.js.map +1 -1
- package/dist/helpers/CleanupHelper.js.map +1 -1
- package/dist/images/ImageOptimizer.d.ts.map +1 -1
- package/dist/images/ImageOptimizer.js +0 -1
- package/dist/images/ImageOptimizer.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/managers/DrawingManager.d.ts.map +1 -1
- package/dist/managers/DrawingManager.js +4 -2
- package/dist/managers/DrawingManager.js.map +1 -1
- package/dist/types/formatting.d.ts +2 -2
- package/dist/types/formatting.d.ts.map +1 -1
- package/dist/types/formatting.js.map +1 -1
- package/dist/utils/ChangelogGenerator.d.ts +2 -2
- package/dist/utils/ChangelogGenerator.d.ts.map +1 -1
- package/dist/utils/ChangelogGenerator.js +4 -5
- package/dist/utils/ChangelogGenerator.js.map +1 -1
- package/dist/utils/InMemoryRevisionAcceptor.d.ts.map +1 -1
- package/dist/utils/InMemoryRevisionAcceptor.js +0 -1
- package/dist/utils/InMemoryRevisionAcceptor.js.map +1 -1
- package/dist/utils/RevisionAwareProcessor.d.ts +2 -2
- package/dist/utils/RevisionAwareProcessor.d.ts.map +1 -1
- package/dist/utils/RevisionAwareProcessor.js +2 -2
- package/dist/utils/RevisionAwareProcessor.js.map +1 -1
- package/dist/utils/SelectiveRevisionAcceptor.d.ts +0 -2
- package/dist/utils/SelectiveRevisionAcceptor.d.ts.map +1 -1
- package/dist/utils/SelectiveRevisionAcceptor.js +0 -26
- package/dist/utils/SelectiveRevisionAcceptor.js.map +1 -1
- package/dist/utils/ShadingResolver.d.ts.map +1 -1
- package/dist/utils/ShadingResolver.js.map +1 -1
- package/dist/utils/acceptRevisions.js +1 -1
- package/dist/utils/acceptRevisions.js.map +1 -1
- package/dist/utils/stripTrackedChanges.js +1 -1
- package/dist/utils/stripTrackedChanges.js.map +1 -1
- package/dist/utils/units.d.ts.map +1 -1
- package/dist/utils/units.js +1 -1
- package/dist/utils/units.js.map +1 -1
- package/dist/validation/RevisionAutoFixer.d.ts +2 -1
- package/dist/validation/RevisionAutoFixer.d.ts.map +1 -1
- package/dist/validation/RevisionAutoFixer.js.map +1 -1
- package/package.json +10 -1
- package/src/constants/CLAUDE.md +28 -0
- package/src/core/CLAUDE.md +4 -0
- package/src/core/Document.ts +1888 -137
- package/src/core/DocumentContent.ts +0 -11
- package/src/core/DocumentGenerator.ts +11 -12
- package/src/core/DocumentParser.ts +620 -139
- package/src/core/RelationshipManager.ts +6 -3
- package/src/elements/Bookmark.ts +39 -4
- package/src/elements/BookmarkManager.ts +4 -3
- package/src/elements/CLAUDE.md +18 -2
- package/src/elements/CommonTypes.ts +35 -8
- package/src/elements/Field.ts +1 -1
- package/src/elements/Footer.ts +23 -0
- package/src/elements/Header.ts +25 -0
- package/src/elements/Image.ts +28 -5
- package/src/elements/Paragraph.ts +1069 -41
- package/src/elements/Revision.ts +0 -19
- package/src/elements/RevisionManager.ts +1 -3
- package/src/elements/Run.ts +265 -35
- package/src/elements/Section.ts +214 -8
- package/src/elements/Shape.ts +1 -1
- package/src/elements/Table.ts +850 -61
- package/src/elements/TableCell.ts +84 -10
- package/src/elements/TableGridChange.ts +2 -16
- package/src/elements/TableRow.ts +94 -9
- package/src/formatting/AbstractNumbering.ts +42 -1
- package/src/formatting/CLAUDE.md +4 -0
- package/src/formatting/NumberingLevel.ts +11 -7
- package/src/formatting/Style.ts +39 -71
- package/src/formatting/StylesManager.ts +36 -0
- package/src/helpers/CleanupHelper.ts +1 -1
- package/src/images/ImageOptimizer.ts +0 -3
- package/src/index.ts +1 -1
- package/src/managers/DrawingManager.ts +5 -3
- package/src/tracking/CLAUDE.md +30 -0
- package/src/types/CLAUDE.md +39 -0
- package/src/types/formatting.ts +2 -2
- package/src/utils/CLAUDE.md +15 -0
- package/src/utils/ChangelogGenerator.ts +4 -5
- package/src/utils/InMemoryRevisionAcceptor.ts +0 -9
- package/src/utils/RevisionAwareProcessor.ts +2 -3
- package/src/utils/SelectiveRevisionAcceptor.ts +0 -39
- package/src/utils/ShadingResolver.ts +0 -1
- package/src/utils/acceptRevisions.ts +1 -1
- package/src/utils/stripTrackedChanges.ts +1 -1
- package/src/utils/units.ts +2 -1
- package/src/validation/CLAUDE.md +40 -0
- package/src/validation/RevisionAutoFixer.ts +2 -1
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { Relationship, RelationshipType } from './Relationship';
|
|
9
9
|
import { XMLParser } from '../xml/XMLParser';
|
|
10
10
|
import { sanitizeHyperlinkUrl } from '../utils/validation';
|
|
11
|
+
import { InvalidDocxError, CorruptedArchiveError } from '../zip/errors';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Manages relationships for a document or document part
|
|
@@ -221,7 +222,7 @@ export class RelationshipManager {
|
|
|
221
222
|
|
|
222
223
|
// Verify this is a hyperlink relationship
|
|
223
224
|
if (relationship.getType() !== RelationshipType.HYPERLINK) {
|
|
224
|
-
throw new
|
|
225
|
+
throw new InvalidDocxError(
|
|
225
226
|
`Relationship ${relationshipId} is not a hyperlink relationship. ` +
|
|
226
227
|
`Type is ${relationship.getType()}, expected ${RelationshipType.HYPERLINK}`
|
|
227
228
|
);
|
|
@@ -384,7 +385,7 @@ export class RelationshipManager {
|
|
|
384
385
|
|
|
385
386
|
// Prevent ReDoS: validate input size (typical .rels files are < 10KB, max 10MB)
|
|
386
387
|
if (xml.length > 10000000) {
|
|
387
|
-
throw new
|
|
388
|
+
throw new CorruptedArchiveError(
|
|
388
389
|
'Relationships XML file too large (>10MB). Possible malicious input or corrupted file.'
|
|
389
390
|
);
|
|
390
391
|
}
|
|
@@ -394,7 +395,9 @@ export class RelationshipManager {
|
|
|
394
395
|
|
|
395
396
|
// Prevent infinite loops: check relationship count
|
|
396
397
|
if (relationshipElements.length > 1000) {
|
|
397
|
-
throw new
|
|
398
|
+
throw new CorruptedArchiveError(
|
|
399
|
+
'Too many relationships in XML file (>1000). Possible malicious input.'
|
|
400
|
+
);
|
|
398
401
|
}
|
|
399
402
|
|
|
400
403
|
// Process each relationship element
|
package/src/elements/Bookmark.ts
CHANGED
|
@@ -17,6 +17,10 @@ export interface BookmarkProperties {
|
|
|
17
17
|
name: string;
|
|
18
18
|
/** Skip name normalization (used when loading from existing documents) */
|
|
19
19
|
skipNormalization?: boolean;
|
|
20
|
+
/** First column in table bookmark range (ECMA-376 §17.16.5) */
|
|
21
|
+
colFirst?: number;
|
|
22
|
+
/** Last column in table bookmark range (ECMA-376 §17.16.5) */
|
|
23
|
+
colLast?: number;
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
/**
|
|
@@ -25,6 +29,8 @@ export interface BookmarkProperties {
|
|
|
25
29
|
export class Bookmark {
|
|
26
30
|
private id: number;
|
|
27
31
|
private name: string;
|
|
32
|
+
private colFirst?: number;
|
|
33
|
+
private colLast?: number;
|
|
28
34
|
|
|
29
35
|
/**
|
|
30
36
|
* Creates a new Bookmark
|
|
@@ -37,6 +43,8 @@ export class Bookmark {
|
|
|
37
43
|
this.name = properties.skipNormalization
|
|
38
44
|
? properties.name
|
|
39
45
|
: this.normalizeName(properties.name);
|
|
46
|
+
this.colFirst = properties.colFirst;
|
|
47
|
+
this.colLast = properties.colLast;
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
/**
|
|
@@ -136,17 +144,44 @@ export class Bookmark {
|
|
|
136
144
|
return this;
|
|
137
145
|
}
|
|
138
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Gets the first column in a table bookmark range
|
|
149
|
+
*/
|
|
150
|
+
getColFirst(): number | undefined {
|
|
151
|
+
return this.colFirst;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Gets the last column in a table bookmark range
|
|
156
|
+
*/
|
|
157
|
+
getColLast(): number | undefined {
|
|
158
|
+
return this.colLast;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Sets the column range for a table bookmark (ECMA-376 §17.16.5)
|
|
163
|
+
*/
|
|
164
|
+
setColumnRange(colFirst: number, colLast: number): this {
|
|
165
|
+
this.colFirst = colFirst;
|
|
166
|
+
this.colLast = colLast;
|
|
167
|
+
return this;
|
|
168
|
+
}
|
|
169
|
+
|
|
139
170
|
/**
|
|
140
171
|
* Generates XML for the bookmark start marker
|
|
141
172
|
* @returns XMLElement for bookmarkStart
|
|
142
173
|
*/
|
|
143
174
|
toStartXML(): XMLElement {
|
|
175
|
+
const attrs: Record<string, string | number> = {
|
|
176
|
+
'w:id': this.id.toString(),
|
|
177
|
+
'w:name': this.name,
|
|
178
|
+
};
|
|
179
|
+
// Table bookmark column range per ECMA-376 §17.16.5
|
|
180
|
+
if (this.colFirst !== undefined) attrs['w:colFirst'] = this.colFirst.toString();
|
|
181
|
+
if (this.colLast !== undefined) attrs['w:colLast'] = this.colLast.toString();
|
|
144
182
|
return {
|
|
145
183
|
name: 'w:bookmarkStart',
|
|
146
|
-
attributes:
|
|
147
|
-
'w:id': this.id.toString(),
|
|
148
|
-
'w:name': this.name,
|
|
149
|
-
},
|
|
184
|
+
attributes: attrs,
|
|
150
185
|
selfClosing: true,
|
|
151
186
|
};
|
|
152
187
|
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { Bookmark } from './Bookmark';
|
|
11
|
+
import { InvalidDocxError } from '../zip/errors';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Type for the centralized ID provider callback.
|
|
@@ -55,7 +56,7 @@ export class BookmarkManager {
|
|
|
55
56
|
|
|
56
57
|
// Check for duplicate names
|
|
57
58
|
if (this.bookmarks.has(name)) {
|
|
58
|
-
throw new
|
|
59
|
+
throw new InvalidDocxError(
|
|
59
60
|
`Bookmark with name "${name}" already exists. Bookmark names must be unique within a document.`
|
|
60
61
|
);
|
|
61
62
|
}
|
|
@@ -83,7 +84,7 @@ export class BookmarkManager {
|
|
|
83
84
|
|
|
84
85
|
// Check for duplicate names
|
|
85
86
|
if (this.bookmarks.has(name)) {
|
|
86
|
-
throw new
|
|
87
|
+
throw new InvalidDocxError(
|
|
87
88
|
`Bookmark with name "${name}" already exists. Bookmark names must be unique within a document.`
|
|
88
89
|
);
|
|
89
90
|
}
|
|
@@ -194,7 +195,7 @@ export class BookmarkManager {
|
|
|
194
195
|
counter++;
|
|
195
196
|
}
|
|
196
197
|
|
|
197
|
-
throw new
|
|
198
|
+
throw new InvalidDocxError(`Could not generate unique bookmark name from base "${baseName}"`);
|
|
198
199
|
}
|
|
199
200
|
|
|
200
201
|
/**
|
package/src/elements/CLAUDE.md
CHANGED
|
@@ -38,19 +38,31 @@ Header/Footer Elements
|
|
|
38
38
|
|
|
39
39
|
Container for text and inline content. Key formatting: `alignment`, `spacing`, `indentation`, `pPrChange` (revision tracking), `keepNext`/`keepLines`/`pageBreakBefore` (pagination).
|
|
40
40
|
|
|
41
|
-
**
|
|
41
|
+
**CT_OnOff properties:** `keepNext`, `keepLines`, `pageBreakBefore`, `suppressLineNumbers`, `suppressAutoHyphens`, `contextualSpacing`, `mirrorIndents`, `suppressOverlap` all use `!== undefined` semantics with `w:val` attribute, supporting explicit `false` to override style inheritance.
|
|
42
|
+
|
|
43
|
+
**Rule:** `setKeepNext(true)` / `setKeepLines(true)` auto-clears `pageBreakBefore` to `undefined` (absent, not explicit false).
|
|
44
|
+
|
|
45
|
+
**Alignment:** `ParagraphAlignment` includes bidi-aware values (`start`, `end`), CJK (`distribute`), Arabic kashida (`mediumKashida`, `highKashida`, `lowKashida`), and Thai (`thaiDistribute`).
|
|
46
|
+
|
|
47
|
+
**w14 attributes:** `paraId` and `textId` (Word 2010+) are auto-generated for new paragraphs during `prepareSave()`. Values are 8-char hex, must be < `0x80000000`.
|
|
42
48
|
|
|
43
49
|
CJK methods: `setKinsoku()`, `setWordWrap()`, `setOverflowPunct()`, `setTopLinePunct()`, `setAutoSpaceDE()`, `setAutoSpaceDN()`.
|
|
44
50
|
|
|
45
51
|
### Run (`Run.ts`)
|
|
46
52
|
|
|
47
|
-
Formatted text span. Character formatting (bold, italic, underline, strikethrough), font properties, color (
|
|
53
|
+
Formatted text span. Character formatting (bold, italic, underline, strikethrough), font properties, color (hex or `'auto'`), highlight, special chars (tabs, breaks, symbols), complex script support.
|
|
54
|
+
|
|
55
|
+
**CT_OnOff properties:** Boolean properties use `!== undefined` semantics: `undefined` = inherit from style, `true` = on, `false` = explicitly off (`w:val="0"`). This applies to: bold, bCs, italic, iCs, caps, smallCaps, strike, dstrike, snapToGrid.
|
|
56
|
+
|
|
57
|
+
**Vertical alignment:** `setSubscript()`, `setSuperscript()`, and `vertAlignBaseline` field for explicit baseline reset per ST_VerticalAlignRun.
|
|
48
58
|
|
|
49
59
|
Theme fonts: `setFontAsciiTheme()`, `setFontHAnsiTheme()`, `setFontEastAsiaTheme()`, `setFontCsTheme()`.
|
|
50
60
|
Underline: `setUnderlineColor()`, `setUnderlineThemeColor()`.
|
|
51
61
|
w14 effects: `addRawW14Property(xml)` for Word 2010+ ligatures, numForm, textOutline.
|
|
52
62
|
Form fields: `FormFieldData`, `FormFieldTextInput`, `FormFieldCheckBox`, `FormFieldDropDownList` interfaces.
|
|
53
63
|
|
|
64
|
+
**Static helper:** `Run.generateRunPropertiesXML(formatting)` — generates `w:rPr` with all 38+ CT_RPr elements in strict ECMA-376 order. Used by both Run and Style serialization.
|
|
65
|
+
|
|
54
66
|
### Table (`Table.ts`, `TableRow.ts`, `TableCell.ts`)
|
|
55
67
|
|
|
56
68
|
Row/column management, cell merging (horizontal + vertical), border styling, property change tracking (`w:tblPrChange`), inter-row content preservation (bookmarks, comments between rows).
|
|
@@ -59,6 +71,10 @@ Navigation: `getFirstParagraph()`, `getLastParagraph()`.
|
|
|
59
71
|
Layout: `getLayout()` returns `'fixed'` or `'auto'`.
|
|
60
72
|
Legacy merge: `setHorizontalMerge()` / `getHorizontalMerge()` (hMerge).
|
|
61
73
|
|
|
74
|
+
**Constraints:** `removeRow()` prevents removing the last row (ECMA-376 requires >= 1 row). `insertRow()`/`insertRows()` use grid span count for correct column count with merged cells. `tblPrEx` is serialized before `trPr` in `w:tr` per CT_Row.
|
|
75
|
+
|
|
76
|
+
**TableRow:** `setHeightRule(rule)` sets height rule independently. When `w:hRule` is absent, the spec default is `"auto"` (not `"atLeast"`).
|
|
77
|
+
|
|
62
78
|
**Nested Tables:** Raw XML passthrough via `TableCell.rawNestedContent[]`.
|
|
63
79
|
```typescript
|
|
64
80
|
cell.addRawNestedContent(position, xml, "table")
|
|
@@ -223,19 +223,33 @@ export type PageVerticalAlignment = 'top' | 'center' | 'bottom' | 'both';
|
|
|
223
223
|
export type CellVerticalAlignment = 'top' | 'center' | 'bottom';
|
|
224
224
|
|
|
225
225
|
/**
|
|
226
|
-
* Paragraph text alignment
|
|
226
|
+
* Paragraph text alignment per ECMA-376 §17.18.44 (ST_Jc)
|
|
227
227
|
*
|
|
228
228
|
* From: Paragraph.ts (ParagraphAlignment)
|
|
229
|
-
* Note: 'both' is
|
|
229
|
+
* Note: 'both' is the OOXML name for justified text; 'justify' is accepted as an alias.
|
|
230
|
+
* 'start'/'end' are bidi-aware alternatives to 'left'/'right'.
|
|
230
231
|
*/
|
|
231
|
-
export type ParagraphAlignment =
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
232
|
+
export type ParagraphAlignment =
|
|
233
|
+
| 'left'
|
|
234
|
+
| 'center'
|
|
235
|
+
| 'right'
|
|
236
|
+
| 'justify'
|
|
237
|
+
| 'both'
|
|
238
|
+
| 'start'
|
|
239
|
+
| 'end'
|
|
240
|
+
| 'distribute'
|
|
241
|
+
| 'mediumKashida'
|
|
242
|
+
| 'highKashida'
|
|
243
|
+
| 'lowKashida'
|
|
244
|
+
| 'thaiDistribute';
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Table alignment (horizontal positioning) per ECMA-376 §17.18.45 (ST_JcTable)
|
|
235
248
|
*
|
|
236
249
|
* From: Table.ts (TableAlignment)
|
|
250
|
+
* 'start'/'end' are bidi-aware alternatives to 'left'/'right'.
|
|
237
251
|
*/
|
|
238
|
-
export type TableAlignment = 'left' | 'center' | 'right';
|
|
252
|
+
export type TableAlignment = 'left' | 'center' | 'right' | 'start' | 'end';
|
|
239
253
|
|
|
240
254
|
/**
|
|
241
255
|
* Row justification/alignment options
|
|
@@ -466,7 +480,20 @@ export function isVerticalAlignment(value: string): value is VerticalAlignment {
|
|
|
466
480
|
* Check if a value is a valid ParagraphAlignment
|
|
467
481
|
*/
|
|
468
482
|
export function isParagraphAlignment(value: string): value is ParagraphAlignment {
|
|
469
|
-
return [
|
|
483
|
+
return [
|
|
484
|
+
'left',
|
|
485
|
+
'center',
|
|
486
|
+
'right',
|
|
487
|
+
'justify',
|
|
488
|
+
'both',
|
|
489
|
+
'start',
|
|
490
|
+
'end',
|
|
491
|
+
'distribute',
|
|
492
|
+
'mediumKashida',
|
|
493
|
+
'highKashida',
|
|
494
|
+
'lowKashida',
|
|
495
|
+
'thaiDistribute',
|
|
496
|
+
].includes(value);
|
|
470
497
|
}
|
|
471
498
|
|
|
472
499
|
/**
|
package/src/elements/Field.ts
CHANGED
package/src/elements/Footer.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { XMLElement } from '../xml/XMLBuilder';
|
|
9
9
|
import { Paragraph } from './Paragraph';
|
|
10
|
+
import { RunFormatting } from './Run';
|
|
10
11
|
import { Table } from './Table';
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -105,6 +106,28 @@ export class Footer {
|
|
|
105
106
|
return para;
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Adds formatted text to the footer as a new paragraph
|
|
111
|
+
*
|
|
112
|
+
* Convenience method that creates a paragraph with a single formatted run.
|
|
113
|
+
*
|
|
114
|
+
* @param text - Text content
|
|
115
|
+
* @param formatting - Optional run formatting (bold, font, size, etc.)
|
|
116
|
+
* @returns The created Paragraph for further customization
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* footer.addText('Page ', { size: 8 });
|
|
121
|
+
* footer.addText('Confidential', { italic: true, color: '888888' });
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
addText(text: string, formatting?: RunFormatting): Paragraph {
|
|
125
|
+
const para = new Paragraph();
|
|
126
|
+
para.addText(text, formatting);
|
|
127
|
+
this.elements.push(para);
|
|
128
|
+
return para;
|
|
129
|
+
}
|
|
130
|
+
|
|
108
131
|
/**
|
|
109
132
|
* Adds a table to the footer
|
|
110
133
|
* @param table Table to add
|
package/src/elements/Header.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { XMLElement } from '../xml/XMLBuilder';
|
|
9
9
|
import { Paragraph } from './Paragraph';
|
|
10
|
+
import { RunFormatting } from './Run';
|
|
10
11
|
import { Table } from './Table';
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -105,6 +106,30 @@ export class Header {
|
|
|
105
106
|
return para;
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Adds formatted text to the header as a new paragraph
|
|
111
|
+
*
|
|
112
|
+
* Convenience method that creates a paragraph with a single formatted run.
|
|
113
|
+
* For headers with multiple runs or complex content, use `createParagraph()`
|
|
114
|
+
* and build content manually.
|
|
115
|
+
*
|
|
116
|
+
* @param text - Text content
|
|
117
|
+
* @param formatting - Optional run formatting (bold, font, size, etc.)
|
|
118
|
+
* @returns The created Paragraph for further customization
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* header.addText('Company Name', { bold: true, font: 'Arial', size: 10 });
|
|
123
|
+
* header.addText('Confidential', { italic: true, color: 'FF0000' });
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
addText(text: string, formatting?: RunFormatting): Paragraph {
|
|
127
|
+
const para = new Paragraph();
|
|
128
|
+
para.addText(text, formatting);
|
|
129
|
+
this.elements.push(para);
|
|
130
|
+
return para;
|
|
131
|
+
}
|
|
132
|
+
|
|
108
133
|
/**
|
|
109
134
|
* Adds a table to the header
|
|
110
135
|
* @param table Table to add
|
package/src/elements/Image.ts
CHANGED
|
@@ -80,6 +80,8 @@ export interface ImageBorder {
|
|
|
80
80
|
headEnd?: { type?: string; width?: string; length?: string };
|
|
81
81
|
/** Tail end decoration */
|
|
82
82
|
tailEnd?: { type?: string; width?: string; length?: string };
|
|
83
|
+
/** @internal Set by parser to suppress default fill in generator */
|
|
84
|
+
_fromParsed?: boolean;
|
|
83
85
|
}
|
|
84
86
|
|
|
85
87
|
/**
|
|
@@ -1486,9 +1488,14 @@ export class Image {
|
|
|
1486
1488
|
if (typeof thicknessOrOptions === 'number') {
|
|
1487
1489
|
this.border = { width: thicknessOrOptions };
|
|
1488
1490
|
} else {
|
|
1489
|
-
this.border = thicknessOrOptions;
|
|
1491
|
+
this.border = { ...thicknessOrOptions };
|
|
1492
|
+
delete this.border._fromParsed;
|
|
1490
1493
|
}
|
|
1491
1494
|
|
|
1495
|
+
// Clear passthrough slots that conflict with explicit border
|
|
1496
|
+
this._rawPassthrough.delete('zero-width-ln');
|
|
1497
|
+
this._rawPassthrough.delete('spPr-noFill');
|
|
1498
|
+
|
|
1492
1499
|
// Calculate space needed for border (half-width on each side)
|
|
1493
1500
|
// Border is drawn centered on the edge
|
|
1494
1501
|
const borderEmu = this.border.width * UNITS.EMUS_PER_POINT;
|
|
@@ -1512,6 +1519,7 @@ export class Image {
|
|
|
1512
1519
|
*/
|
|
1513
1520
|
removeBorder(): this {
|
|
1514
1521
|
this.border = undefined;
|
|
1522
|
+
this._rawPassthrough.delete('zero-width-ln');
|
|
1515
1523
|
return this;
|
|
1516
1524
|
}
|
|
1517
1525
|
|
|
@@ -1626,11 +1634,17 @@ export class Image {
|
|
|
1626
1634
|
);
|
|
1627
1635
|
}
|
|
1628
1636
|
|
|
1629
|
-
//
|
|
1637
|
+
// Fill group: a:noFill (before a:ln per ECMA-376 CT_ShapeProperties ordering)
|
|
1630
1638
|
if (this.border) {
|
|
1631
|
-
//
|
|
1639
|
+
// Bordered images use noFill for shape fill
|
|
1640
|
+
spPrChildren.push(XMLBuilder.a('noFill'));
|
|
1641
|
+
} else if (this._rawPassthrough.has('spPr-noFill')) {
|
|
1642
|
+
// Preserve spPr-level a:noFill from loaded document (Bug C fix)
|
|
1632
1643
|
spPrChildren.push(XMLBuilder.a('noFill'));
|
|
1644
|
+
}
|
|
1633
1645
|
|
|
1646
|
+
// Border (a:ln) - full model (Group C)
|
|
1647
|
+
if (this.border) {
|
|
1634
1648
|
const ptToEmu = 12700;
|
|
1635
1649
|
const widthEmu = this.border.width * ptToEmu;
|
|
1636
1650
|
const lnAttrs: Record<string, string> = { w: widthEmu.toString() };
|
|
@@ -1655,8 +1669,9 @@ export class Image {
|
|
|
1655
1669
|
? XMLBuilder.a(this.border.fill.type, { val: this.border.fill.value }, colorChildren)
|
|
1656
1670
|
: XMLBuilder.a(this.border.fill.type, { val: this.border.fill.value });
|
|
1657
1671
|
lnChildren.push(XMLBuilder.a('solidFill', undefined, [colorEl]));
|
|
1658
|
-
} else {
|
|
1659
|
-
// Default
|
|
1672
|
+
} else if (!this.border._fromParsed) {
|
|
1673
|
+
// Default fill for programmatic borders only (setBorder API backward compat).
|
|
1674
|
+
// Parsed borders without fill are intentionally left as-is.
|
|
1660
1675
|
lnChildren.push(
|
|
1661
1676
|
XMLBuilder.a('solidFill', undefined, [XMLBuilder.a('schemeClr', { val: 'tx1' })])
|
|
1662
1677
|
);
|
|
@@ -1689,6 +1704,14 @@ export class Image {
|
|
|
1689
1704
|
spPrChildren.push(XMLBuilder.a('ln', lnAttrs, lnChildren));
|
|
1690
1705
|
}
|
|
1691
1706
|
|
|
1707
|
+
// Zero-width a:ln passthrough (e.g., <a:ln><a:noFill/></a:ln>) (BUG 8 fix)
|
|
1708
|
+
if (!this.border && this._rawPassthrough.has('zero-width-ln')) {
|
|
1709
|
+
spPrChildren.push({
|
|
1710
|
+
name: '__rawXml',
|
|
1711
|
+
rawXml: this._rawPassthrough.get('zero-width-ln')!,
|
|
1712
|
+
} as XMLElement);
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1692
1715
|
// Group B: Inject raw spPr effects passthrough (effectLst, scene3d, sp3d, etc.)
|
|
1693
1716
|
if (this._rawPassthrough.has('spPr-effects')) {
|
|
1694
1717
|
spPrChildren.push({
|