doc-codec 2.2.5 → 2.3.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 CHANGED
@@ -32,19 +32,19 @@ Built and shipped, on the write side — see [Writing](#writing) for the full sc
32
32
 
33
33
  **Not built, and not approximated, on either side.** Each of these is a genuine layer of [MS-DOC] that this package does not implement; none is silently faked, and a document using one reads (or fails to write) as though it did not:
34
34
 
35
- | Absent | Consequence |
36
- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
37
- | **Nested tables** | A table inside a table cell (table depth greater than 1) is a genuinely different [MS-DOC] structure — `sprmPFInnerTableCell`/`sprmPFInnerTtp` mark its cell/row ends rather than `sprmPFInTable`/`sprmPFTtp`, and `sprmPItap`/`sprmPDtap` state the depth. Neither side of this package descends into one: `readDocContent` refuses with `DocUnsupportedError` the moment it detects a table depth greater than 1, and `writeDocContent` refuses a `ContentTable` block found inside a table cell's own blocks the same way. See [Tables](#tables) for the full scope of what a depth-1 table does resolve. |
38
- | **Images and drawn objects** | The anchor characters (`U+0001`, `U+0008`) are dropped rather than emitted as control characters. No picture data is read. `writeDocContent` refuses an image block. |
39
- | **Style-inherited formatting on write** | A style's own property sets (`STD.grLPUpxSw`) are now resolved and folded on read ([ExaDev/documents.js#1005](https://github.com/ExaDev/documents.js/issues/1005)): a paragraph's formatting is its style's own grpprlPapx/grpprlChpx (walked up the full `istdBase` inheritance chain, most-specific style winning) plus its own direct exceptions on top, and a run's own referenced character style (`sprmCIstd`) folds in the same way. `writeDocContent` still writes no paragraph styles at all (every paragraph is `istd` 0) and does not round-trip `styleId`/`headingLevel` -- a genuinely separate write-side gap, since doc-codec's flat `ContentDocument` carries no style-vs-direct-formatting split to mint real style entries from. Tracked in [ExaDev/documents.js#1059](https://github.com/ExaDev/documents.js/issues/1059). |
40
- | **Table and numbering style formatting** | `STD.grLPUpxSw` is resolved only for paragraph and character styles (`stk` 1/2, see the row above) -- a table style's `StkTableGRLPUPX` (its own `TAPX` plus `CNFC`-conditional per-region formatting, [MS-DOC] 2.4.6.6's own table-specific steps 6-9) and a numbering style's `StkListGRLPUPX` are neither read nor written. A table applying a named table style, or a paragraph using a numbering style rather than direct list formatting, reports none of the formatting either would supply. |
41
- | **Subdocuments** | Only the main document (character positions 0 to `ccpText`) is converted. Footnotes, endnotes, headers, footers, comments and text boxes are not, in either direction. |
42
- | **Section boundaries** | Section boundaries themselves are not read — the whole document is always treated as one section, spanning the entire main document — so a multi-section `.doc`'s later sections' own page size and margins are never consulted, only the first's (see the read-side page-size/margins bullet above for what is now read of that one section). `writeDocContent` refuses a `ContentDocument` with more than one section, rather than silently merging their content into what would read back as one. |
43
- | **Extended and user-defined document properties** | `title`/`subject`/`author`/`keywords`/`createdIso`/`modifiedIso` are read from and written to a `"\x05SummaryInformation"` stream when present (see [Metadata](#metadata)); the sibling `"\x05DocumentSummaryInformation"` stream (company, manager, and custom user-defined properties) is not read or written at all. |
44
- | **Encryption** | An encrypted or XOR-obfuscated document is refused with a `DocUnsupportedError` rather than read as plaintext. `writeDocContent` never encrypts. |
45
- | **`sprmPHugePapx` / `sprmPTableProps`** | Paragraph properties stored indirectly in the Data stream are not followed, so such a paragraph reads with fewer properties than it states. [MS-DOC] 2.4.3's own Overview of Tables text names `sprmPTableProps` as a real, legal alternative to `sprmTDefTable` some applications process — but a real producer's row mark is not shown to prefer it: a genuine LibreOffice-authored `.doc` table's own row mark states its TAP through the identical direct `sprmTDefTable` this package's reader and writer already use (confirmed by parsing a LibreOffice 26.2.5.2-authored table's raw `PapxFkp` bytes; see [ExaDev/documents.js#892](https://github.com/ExaDev/documents.js/issues/892)), matching 2.4.3's own compatibility guidance ("An application SHOULD use sprmTDefTable to define table cells for applications that do not process sprmPTableProps"). `writeDocContent` never writes an indirect Papx. |
46
- | **Hyperlinks and fields** | `ContentRun.hyperlink`, footnote/comment/annotation references, and every other field or anchor character are read as plain text or dropped (see [What is converted](#what-is-converted)) and are not written. |
47
- | **Every FIB field beyond what this package's own reader needs** | `writeDocContent` populates only the fc/lcb pairs its own reader consults (the style sheet, the two property bin tables, the Clx, the font table). Roughly 140 other `FibRgFcLcb97` pairs — `SttbfAssoc`, `Dop`, the printer-driver structures among them — are left zero, which is the format's own "undefined, MUST be ignored" contract for most of them, but not a certification that every third-party [MS-DOC] reader accepts the result; see `fib/write.ts`'s own note. |
35
+ | Absent | Consequence |
36
+ | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
37
+ | **Nested tables** | A table inside a table cell (table depth greater than 1) is a genuinely different [MS-DOC] structure — `sprmPFInnerTableCell`/`sprmPFInnerTtp` mark its cell/row ends rather than `sprmPFInTable`/`sprmPFTtp`, and `sprmPItap`/`sprmPDtap` state the depth. Neither side of this package descends into one: `readDocContent` refuses with `DocUnsupportedError` the moment it detects a table depth greater than 1, and `writeDocContent` refuses a `ContentTable` block found inside a table cell's own blocks the same way. See [Tables](#tables) for the full scope of what a depth-1 table does resolve. |
38
+ | **Images and drawn objects** | The anchor characters (`U+0001`, `U+0008`) are dropped rather than emitted as control characters. No picture data is read. `writeDocContent` refuses an image block. |
39
+ | **A style's own formatting on write** | A style's own property sets (`STD.grLPUpxSw`) are resolved and folded on read ([ExaDev/documents.js#1005](https://github.com/ExaDev/documents.js/issues/1005)): a paragraph's formatting is its style's own grpprlPapx/grpprlChpx (walked up the full `istdBase` inheritance chain, most-specific style winning) plus its own direct exceptions on top, and a run's own referenced character style (`sprmCIstd`) folds in the same way. `writeDocContent` mints a real STSH entry for every distinct `styleId`/`headingLevel` a document's paragraphs use ([ExaDev/documents.js#1059](https://github.com/ExaDev/documents.js/issues/1059)), so style IDENTITY round-trips -- but every minted entry carries an empty `grLPUpxSw` (no formatting of its own), since doc-codec's flat `ContentDocument` has no style-vs-direct-formatting split to draw a real one from: every property this writer emits is already, unconditionally, a direct exception. A style's own inherited formatting therefore never round-trips through a write -- only its name and istd position do. |
40
+ | **Table and numbering style formatting** | `STD.grLPUpxSw` is resolved only for paragraph and character styles (`stk` 1/2, see the row above) -- a table style's `StkTableGRLPUPX` (its own `TAPX` plus `CNFC`-conditional per-region formatting, [MS-DOC] 2.4.6.6's own table-specific steps 6-9) and a numbering style's `StkListGRLPUPX` are neither read nor written. A table applying a named table style, or a paragraph using a numbering style rather than direct list formatting, reports none of the formatting either would supply. |
41
+ | **Subdocuments** | Only the main document (character positions 0 to `ccpText`) is converted. Footnotes, endnotes, headers, footers, comments and text boxes are not, in either direction. |
42
+ | **Section boundaries** | Section boundaries themselves are not read — the whole document is always treated as one section, spanning the entire main document — so a multi-section `.doc`'s later sections' own page size and margins are never consulted, only the first's (see the read-side page-size/margins bullet above for what is now read of that one section). `writeDocContent` refuses a `ContentDocument` with more than one section, rather than silently merging their content into what would read back as one. |
43
+ | **Extended and user-defined document properties** | `title`/`subject`/`author`/`keywords`/`createdIso`/`modifiedIso` are read from and written to a `"\x05SummaryInformation"` stream when present (see [Metadata](#metadata)); the sibling `"\x05DocumentSummaryInformation"` stream (company, manager, and custom user-defined properties) is not read or written at all. |
44
+ | **Encryption** | An encrypted or XOR-obfuscated document is refused with a `DocUnsupportedError` rather than read as plaintext. `writeDocContent` never encrypts. |
45
+ | **`sprmPHugePapx` / `sprmPTableProps`** | Paragraph properties stored indirectly in the Data stream are not followed, so such a paragraph reads with fewer properties than it states. [MS-DOC] 2.4.3's own Overview of Tables text names `sprmPTableProps` as a real, legal alternative to `sprmTDefTable` some applications process — but a real producer's row mark is not shown to prefer it: a genuine LibreOffice-authored `.doc` table's own row mark states its TAP through the identical direct `sprmTDefTable` this package's reader and writer already use (confirmed by parsing a LibreOffice 26.2.5.2-authored table's raw `PapxFkp` bytes; see [ExaDev/documents.js#892](https://github.com/ExaDev/documents.js/issues/892)), matching 2.4.3's own compatibility guidance ("An application SHOULD use sprmTDefTable to define table cells for applications that do not process sprmPTableProps"). `writeDocContent` never writes an indirect Papx. |
46
+ | **Hyperlinks and fields** | `ContentRun.hyperlink`, footnote/comment/annotation references, and every other field or anchor character are read as plain text or dropped (see [What is converted](#what-is-converted)) and are not written. |
47
+ | **Every FIB field beyond what this package's own reader needs** | `writeDocContent` populates only the fc/lcb pairs its own reader consults (the style sheet, the two property bin tables, the Clx, the font table). Roughly 140 other `FibRgFcLcb97` pairs — `SttbfAssoc`, `Dop`, the printer-driver structures among them — are left zero, which is the format's own "undefined, MUST be ignored" contract for most of them, but not a certification that every third-party [MS-DOC] reader accepts the result; see `fib/write.ts`'s own note. |
48
48
 
49
49
  One construct is refused rather than mis-read: a `sprmPChgTabs` whose `cb` is the `255` sentinel encodes its own length as a formula over tab-stop counts this package does not parse, and its length is needed to find the next `Prl`. Rather than guess and silently mis-read every property after it, `operandSize` throws.
50
50
 
@@ -172,7 +172,7 @@ Only the fixed SummaryInformation property set is read or written — the siblin
172
172
 
173
173
  ## Writing
174
174
 
175
- `writeDocContent` takes a `'wordprocessing'` `ContentDocument` with exactly one section, an optional `WriteDocContentOptions`, and produces real [MS-DOC] bytes wrapped in a real [MS-CFB] compound file, inverting every read-side structure listed above: a real piece table (`text/piece-table-write.ts`, always one uncompressed 16-bit piece — see [Why always uncompressed](#why-the-writer-always-writes-uncompressed-text)), `Sprm`-encoded grpprls for each run's and paragraph's own direct formatting (`prop/chp-write.ts`, `prop/pap-write.ts`), `ChpxFkp`/`PapxFkp` pages packed and split across as many 512-byte pages as the content needs (`prop/fkp-write.ts`), a spec-conformant style sheet carrying zero styles (`style/stsh.ts`'s `buildEmptyStsh` — `FibRgFcLcb97.lcbStshf` "MUST be a nonzero value", so a document is never written without one, even though this package's own reader tolerates a missing one), and a font table when at least one run names a font (`style/fonts.ts`). `WriteDocContentOptions.onWarning`, when given, is called for a non-fatal write-time degradation this writer chooses over throwing — today, only the lost-boundary fallback's own per-row budget check (see [Tables](#tables)'s own note on [ExaDev/documents.js#1013](https://github.com/ExaDev/documents.js/issues/1013)) — but that is not a guarantee the write itself goes on to succeed: a row whose own assigned lost boundaries cannot be trimmed down to a split that fits at all still reports one warning, describing its boundaries as unrecoverable and its fully-unsplit encoding as the fallback being attempted — and, should that unsplit encoding also overflow the row's own byte budget once `buildPapxPages` actually packs it, `writeDocContent` can still throw further down the same pipeline, after any rows still to come have had their own chance to report a warning: a caller can genuinely see this warning followed by a hard failure, but not necessarily right away, and not necessarily for the row whose warning it just read, since `buildPapxPages` packs paragraphs in document order and can fail first on an earlier row that also overflowed. Every genuine refusal this writer makes outright — the kinds named in the table below — still throws `DocFormatError`/`DocUnsupportedError` directly, with no warning first.
175
+ `writeDocContent` takes a `'wordprocessing'` `ContentDocument` with exactly one section, an optional `WriteDocContentOptions`, and produces real [MS-DOC] bytes wrapped in a real [MS-CFB] compound file, inverting every read-side structure listed above: a real piece table (`text/piece-table-write.ts`, always one uncompressed 16-bit piece — see [Why always uncompressed](#why-the-writer-always-writes-uncompressed-text)), `Sprm`-encoded grpprls for each run's and paragraph's own direct formatting (`prop/chp-write.ts`, `prop/pap-write.ts`), `ChpxFkp`/`PapxFkp` pages packed and split across as many 512-byte pages as the content needs (`prop/fkp-write.ts`), a real style sheet minting one entry per distinct `styleId`/`headingLevel` a document's paragraphs actually use (`style/stsh.ts`'s `buildStshForStyles`, [ExaDev/documents.js#1059](https://github.com/ExaDev/documents.js/issues/1059) identity only, no formatting of a style's own; `FibRgFcLcb97.lcbStshf` "MUST be a nonzero value", so a document is never written without one, even one carrying zero styles, though this package's own reader tolerates a missing one), and a font table when at least one run names a font (`style/fonts.ts`). `WriteDocContentOptions.onWarning`, when given, is called for a non-fatal write-time degradation this writer chooses over throwing — today, only the lost-boundary fallback's own per-row budget check (see [Tables](#tables)'s own note on [ExaDev/documents.js#1013](https://github.com/ExaDev/documents.js/issues/1013)) — but that is not a guarantee the write itself goes on to succeed: a row whose own assigned lost boundaries cannot be trimmed down to a split that fits at all still reports one warning, describing its boundaries as unrecoverable and its fully-unsplit encoding as the fallback being attempted — and, should that unsplit encoding also overflow the row's own byte budget once `buildPapxPages` actually packs it, `writeDocContent` can still throw further down the same pipeline, after any rows still to come have had their own chance to report a warning: a caller can genuinely see this warning followed by a hard failure, but not necessarily right away, and not necessarily for the row whose warning it just read, since `buildPapxPages` packs paragraphs in document order and can fail first on an earlier row that also overflowed. Every genuine refusal this writer makes outright — the kinds named in the table below — still throws `DocFormatError`/`DocUnsupportedError` directly, with no warning first.
176
176
 
177
177
  Character properties this writer converts, the exact inverse of [What is converted](#what-is-converted)'s character table above: `bold`, `italic`, `strike`, `underline` (as `kulSingle`, the only style a plain boolean can express), `sizePt`, `color` (via `sprmCCv`'s exact `COLORREF`, never the lossy 17-entry `sprmCIco` palette), and `fontFamily`. Paragraph properties: `alignment` (the four `ST_Jc`-aligned values this package's reader itself maps — `left`/`center`/`right`/`justify`), `indentLeftPt`, `indentRightPt`, `indentFirstLinePt`, `spacingBeforePt`, `spacingAfterPt`, `lineSpacing` (only `LSPD`'s multiplier form, matching the reader), `pageBreakBefore`, and `list` membership (`sprmPIlfo`/`sprmPIlvl` — see [Numbering definitions](#numbering-definitions) for the numbering tables this depends on).
178
178
 
package/dist/index.cjs CHANGED
@@ -66,13 +66,13 @@ exports.applyCharacterSprms = require_prop_chp.applyCharacterSprms;
66
66
  exports.applyParagraphSprms = require_prop_pap.applyParagraphSprms;
67
67
  exports.applySectionSprms = require_prop_sep.applySectionSprms;
68
68
  exports.buildChpxPages = require_prop_fkp_write.buildChpxPages;
69
- exports.buildEmptyStsh = require_style_stsh.buildEmptyStsh;
70
69
  exports.buildFib = require_fib_write.buildFib;
71
70
  exports.buildFontTable = require_style_fonts.buildFontTable;
72
71
  exports.buildPapxPages = require_prop_fkp_write.buildPapxPages;
73
72
  exports.buildPlcfSed = require_prop_sep_write.buildPlcfSed;
74
73
  exports.buildPropertyBinTable = require_prop_fkp_write.buildPropertyBinTable;
75
74
  exports.buildSepx = require_prop_sep_write.buildSepx;
75
+ exports.buildStshForStyles = require_style_stsh.buildStshForStyles;
76
76
  exports.buildTextClx = require_text_piece_table_write.buildTextClx;
77
77
  exports.characterIstdFromGrpprl = require_prop_chp.characterIstdFromGrpprl;
78
78
  exports.characterOffset = require_text_piece_table.characterOffset;
package/dist/index.d.cts CHANGED
@@ -19,9 +19,9 @@ import { n as applyParagraphSprms, t as ParagraphProperties } from "./pap-BT1p0u
19
19
  import { encodeParagraphGrpprl } from "./prop/pap-write.cjs";
20
20
  import { SectionProperties, applySectionSprms, readSectionProperties } from "./prop/sep.cjs";
21
21
  import { buildPlcfSed, buildSepx, encodeSectionGrpprl } from "./prop/sep-write.cjs";
22
- import { ResolvedStyleFormatting, STI_USER_DEFINED, STK, Style, StyleSheet, buildEmptyStsh, headingLevelFromIstd, parseStsh, resolveStyleFormatting } from "./style/stsh.cjs";
22
+ import { ResolvedStyleFormatting, STI_USER_DEFINED, STK, Style, StyleSheet, buildStshForStyles, headingLevelFromIstd, parseStsh, resolveStyleFormatting } from "./style/stsh.cjs";
23
23
  import { buildFontTable, parseFontTable } from "./style/fonts.cjs";
24
24
  import { a as readNumberingDefinitions, i as NumberingLevel, n as NumberingDefinition, r as NumberingDefinitions, t as NUMBER_FORMAT_BY_NFC } from "./numbering-Bivayss4.cjs";
25
25
  import { DocContent, DocStreams, ParagraphEntry, readDocContent, readDocStreams } from "./read.cjs";
26
26
  import { WriteDocContentOptions, writeDocContent } from "./write.cjs";
27
- export { ANNOTATION_REFERENCE, CELL_MARK, COMPRESSED_CHARACTER_MAP, CharacterProperties, ChpxFkp, ChpxRunToWrite, DRAWN_OBJECT, DocContent, DocFormatError, DocStreams, DocUnsupportedError, FC_LCB_VALUE_INDEX, FIB_BASE_FLAG, FIB_BASE_SIZE, FIB_CB_RG_FC_LCB_OFFSET, FIB_CSLW_OFFSET, FIB_CSLW_REQUIRED, FIB_CSW_REQUIRED, FIB_FC_LCB_BLOB_OFFSET, FIB_RG_LW_OFFSET, FIB_RG_LW_SIZE, FIB_RG_W_OFFSET, FIB_RG_W_SIZE, FIB_W_IDENT, FIELD_BEGIN, FIELD_END, FIELD_SEPARATOR, FKP_PAGE_SIZE, FOOTNOTE_REFERENCE, Fib, FibWriteSpec, INLINE_PICTURE, LINE_BREAK, LW_OFFSET, NUMBER_FORMAT_BY_NFC, NumberingDefinition, NumberingDefinitions, NumberingLevel, PARAGRAPH_MARK, PapxFkp, PapxLookup, PapxParagraphToWrite, PapxRecord, ParagraphEntry, ParagraphProperties, Piece, PieceTable, Plc, Prl, PropertyBinTable, ResolvedStyleFormatting, SECTION_MARK, SGC, STI_USER_DEFINED, STK, SUMMARY_INFORMATION_STREAM, SYMBOL_ANCHOR, SectionProperties, Sprm, Style, StyleSheet, TextRange, WORD_DOCUMENT_STREAM, WriteDocContentOptions, applyCharacterSprms, applyParagraphSprms, applySectionSprms, buildChpxPages, buildEmptyStsh, buildFib, buildFontTable, buildPapxPages, buildPlcfSed, buildPropertyBinTable, buildSepx, buildTextClx, characterIstdFromGrpprl, characterOffset, characterSize, decodeSprm, encodeCharacterGrpprl, encodeParagraphGrpprl, encodeSectionGrpprl, endsParagraph, findLargestAtMost, firstFcOfPage, fitsAloneOnPapxPage, headingLevelFromIstd, isAnchorOnly, isDocBytes, layoutMetadataToSummaryInformation, operandSize, parseChpxFkp, parseClx, parseFib, parseFontTable, parsePapxFkp, parsePlc, parseStsh, readDocContent, readDocStreams, readGrpprl, readInt16LE, readInt32LE, readNumberingDefinitions, readSectionProperties, readTextRange, readUint16LE, readUint32LE, readUint8, resolveStyleFormatting, slice, tableStreamName, writeDocContent };
27
+ export { ANNOTATION_REFERENCE, CELL_MARK, COMPRESSED_CHARACTER_MAP, CharacterProperties, ChpxFkp, ChpxRunToWrite, DRAWN_OBJECT, DocContent, DocFormatError, DocStreams, DocUnsupportedError, FC_LCB_VALUE_INDEX, FIB_BASE_FLAG, FIB_BASE_SIZE, FIB_CB_RG_FC_LCB_OFFSET, FIB_CSLW_OFFSET, FIB_CSLW_REQUIRED, FIB_CSW_REQUIRED, FIB_FC_LCB_BLOB_OFFSET, FIB_RG_LW_OFFSET, FIB_RG_LW_SIZE, FIB_RG_W_OFFSET, FIB_RG_W_SIZE, FIB_W_IDENT, FIELD_BEGIN, FIELD_END, FIELD_SEPARATOR, FKP_PAGE_SIZE, FOOTNOTE_REFERENCE, Fib, FibWriteSpec, INLINE_PICTURE, LINE_BREAK, LW_OFFSET, NUMBER_FORMAT_BY_NFC, NumberingDefinition, NumberingDefinitions, NumberingLevel, PARAGRAPH_MARK, PapxFkp, PapxLookup, PapxParagraphToWrite, PapxRecord, ParagraphEntry, ParagraphProperties, Piece, PieceTable, Plc, Prl, PropertyBinTable, ResolvedStyleFormatting, SECTION_MARK, SGC, STI_USER_DEFINED, STK, SUMMARY_INFORMATION_STREAM, SYMBOL_ANCHOR, SectionProperties, Sprm, Style, StyleSheet, TextRange, WORD_DOCUMENT_STREAM, WriteDocContentOptions, applyCharacterSprms, applyParagraphSprms, applySectionSprms, buildChpxPages, buildFib, buildFontTable, buildPapxPages, buildPlcfSed, buildPropertyBinTable, buildSepx, buildStshForStyles, buildTextClx, characterIstdFromGrpprl, characterOffset, characterSize, decodeSprm, encodeCharacterGrpprl, encodeParagraphGrpprl, encodeSectionGrpprl, endsParagraph, findLargestAtMost, firstFcOfPage, fitsAloneOnPapxPage, headingLevelFromIstd, isAnchorOnly, isDocBytes, layoutMetadataToSummaryInformation, operandSize, parseChpxFkp, parseClx, parseFib, parseFontTable, parsePapxFkp, parsePlc, parseStsh, readDocContent, readDocStreams, readGrpprl, readInt16LE, readInt32LE, readNumberingDefinitions, readSectionProperties, readTextRange, readUint16LE, readUint32LE, readUint8, resolveStyleFormatting, slice, tableStreamName, writeDocContent };
package/dist/index.d.ts CHANGED
@@ -19,9 +19,9 @@ import { n as applyParagraphSprms, t as ParagraphProperties } from "./pap-DOFLMW
19
19
  import { encodeParagraphGrpprl } from "./prop/pap-write.js";
20
20
  import { SectionProperties, applySectionSprms, readSectionProperties } from "./prop/sep.js";
21
21
  import { buildPlcfSed, buildSepx, encodeSectionGrpprl } from "./prop/sep-write.js";
22
- import { ResolvedStyleFormatting, STI_USER_DEFINED, STK, Style, StyleSheet, buildEmptyStsh, headingLevelFromIstd, parseStsh, resolveStyleFormatting } from "./style/stsh.js";
22
+ import { ResolvedStyleFormatting, STI_USER_DEFINED, STK, Style, StyleSheet, buildStshForStyles, headingLevelFromIstd, parseStsh, resolveStyleFormatting } from "./style/stsh.js";
23
23
  import { buildFontTable, parseFontTable } from "./style/fonts.js";
24
24
  import { a as readNumberingDefinitions, i as NumberingLevel, n as NumberingDefinition, r as NumberingDefinitions, t as NUMBER_FORMAT_BY_NFC } from "./numbering-Co4jssbG.js";
25
25
  import { DocContent, DocStreams, ParagraphEntry, readDocContent, readDocStreams } from "./read.js";
26
26
  import { WriteDocContentOptions, writeDocContent } from "./write.js";
27
- export { ANNOTATION_REFERENCE, CELL_MARK, COMPRESSED_CHARACTER_MAP, CharacterProperties, ChpxFkp, ChpxRunToWrite, DRAWN_OBJECT, DocContent, DocFormatError, DocStreams, DocUnsupportedError, FC_LCB_VALUE_INDEX, FIB_BASE_FLAG, FIB_BASE_SIZE, FIB_CB_RG_FC_LCB_OFFSET, FIB_CSLW_OFFSET, FIB_CSLW_REQUIRED, FIB_CSW_REQUIRED, FIB_FC_LCB_BLOB_OFFSET, FIB_RG_LW_OFFSET, FIB_RG_LW_SIZE, FIB_RG_W_OFFSET, FIB_RG_W_SIZE, FIB_W_IDENT, FIELD_BEGIN, FIELD_END, FIELD_SEPARATOR, FKP_PAGE_SIZE, FOOTNOTE_REFERENCE, Fib, FibWriteSpec, INLINE_PICTURE, LINE_BREAK, LW_OFFSET, NUMBER_FORMAT_BY_NFC, NumberingDefinition, NumberingDefinitions, NumberingLevel, PARAGRAPH_MARK, PapxFkp, PapxLookup, PapxParagraphToWrite, PapxRecord, ParagraphEntry, ParagraphProperties, Piece, PieceTable, Plc, Prl, PropertyBinTable, ResolvedStyleFormatting, SECTION_MARK, SGC, STI_USER_DEFINED, STK, SUMMARY_INFORMATION_STREAM, SYMBOL_ANCHOR, SectionProperties, Sprm, Style, StyleSheet, TextRange, WORD_DOCUMENT_STREAM, WriteDocContentOptions, applyCharacterSprms, applyParagraphSprms, applySectionSprms, buildChpxPages, buildEmptyStsh, buildFib, buildFontTable, buildPapxPages, buildPlcfSed, buildPropertyBinTable, buildSepx, buildTextClx, characterIstdFromGrpprl, characterOffset, characterSize, decodeSprm, encodeCharacterGrpprl, encodeParagraphGrpprl, encodeSectionGrpprl, endsParagraph, findLargestAtMost, firstFcOfPage, fitsAloneOnPapxPage, headingLevelFromIstd, isAnchorOnly, isDocBytes, layoutMetadataToSummaryInformation, operandSize, parseChpxFkp, parseClx, parseFib, parseFontTable, parsePapxFkp, parsePlc, parseStsh, readDocContent, readDocStreams, readGrpprl, readInt16LE, readInt32LE, readNumberingDefinitions, readSectionProperties, readTextRange, readUint16LE, readUint32LE, readUint8, resolveStyleFormatting, slice, tableStreamName, writeDocContent };
27
+ export { ANNOTATION_REFERENCE, CELL_MARK, COMPRESSED_CHARACTER_MAP, CharacterProperties, ChpxFkp, ChpxRunToWrite, DRAWN_OBJECT, DocContent, DocFormatError, DocStreams, DocUnsupportedError, FC_LCB_VALUE_INDEX, FIB_BASE_FLAG, FIB_BASE_SIZE, FIB_CB_RG_FC_LCB_OFFSET, FIB_CSLW_OFFSET, FIB_CSLW_REQUIRED, FIB_CSW_REQUIRED, FIB_FC_LCB_BLOB_OFFSET, FIB_RG_LW_OFFSET, FIB_RG_LW_SIZE, FIB_RG_W_OFFSET, FIB_RG_W_SIZE, FIB_W_IDENT, FIELD_BEGIN, FIELD_END, FIELD_SEPARATOR, FKP_PAGE_SIZE, FOOTNOTE_REFERENCE, Fib, FibWriteSpec, INLINE_PICTURE, LINE_BREAK, LW_OFFSET, NUMBER_FORMAT_BY_NFC, NumberingDefinition, NumberingDefinitions, NumberingLevel, PARAGRAPH_MARK, PapxFkp, PapxLookup, PapxParagraphToWrite, PapxRecord, ParagraphEntry, ParagraphProperties, Piece, PieceTable, Plc, Prl, PropertyBinTable, ResolvedStyleFormatting, SECTION_MARK, SGC, STI_USER_DEFINED, STK, SUMMARY_INFORMATION_STREAM, SYMBOL_ANCHOR, SectionProperties, Sprm, Style, StyleSheet, TextRange, WORD_DOCUMENT_STREAM, WriteDocContentOptions, applyCharacterSprms, applyParagraphSprms, applySectionSprms, buildChpxPages, buildFib, buildFontTable, buildPapxPages, buildPlcfSed, buildPropertyBinTable, buildSepx, buildStshForStyles, buildTextClx, characterIstdFromGrpprl, characterOffset, characterSize, decodeSprm, encodeCharacterGrpprl, encodeParagraphGrpprl, encodeSectionGrpprl, endsParagraph, findLargestAtMost, firstFcOfPage, fitsAloneOnPapxPage, headingLevelFromIstd, isAnchorOnly, isDocBytes, layoutMetadataToSummaryInformation, operandSize, parseChpxFkp, parseClx, parseFib, parseFontTable, parsePapxFkp, parsePlc, parseStsh, readDocContent, readDocStreams, readGrpprl, readInt16LE, readInt32LE, readNumberingDefinitions, readSectionProperties, readTextRange, readUint16LE, readUint32LE, readUint8, resolveStyleFormatting, slice, tableStreamName, writeDocContent };
package/dist/index.js CHANGED
@@ -19,9 +19,9 @@ import { applyParagraphSprms } from "./prop/pap.js";
19
19
  import { encodeParagraphGrpprl } from "./prop/pap-write.js";
20
20
  import { applySectionSprms, readSectionProperties } from "./prop/sep.js";
21
21
  import { buildPlcfSed, buildSepx, encodeSectionGrpprl } from "./prop/sep-write.js";
22
- import { STI_USER_DEFINED, STK, buildEmptyStsh, headingLevelFromIstd, parseStsh, resolveStyleFormatting } from "./style/stsh.js";
22
+ import { STI_USER_DEFINED, STK, buildStshForStyles, headingLevelFromIstd, parseStsh, resolveStyleFormatting } from "./style/stsh.js";
23
23
  import { buildFontTable, parseFontTable } from "./style/fonts.js";
24
24
  import { NUMBER_FORMAT_BY_NFC, readNumberingDefinitions } from "./list/numbering.js";
25
25
  import { readDocContent, readDocStreams } from "./read.js";
26
26
  import { writeDocContent } from "./write.js";
27
- export { ANNOTATION_REFERENCE, CELL_MARK, COMPRESSED_CHARACTER_MAP, DRAWN_OBJECT, DocFormatError, DocUnsupportedError, FC_LCB_VALUE_INDEX, FIB_BASE_FLAG, FIB_BASE_SIZE, FIB_CB_RG_FC_LCB_OFFSET, FIB_CSLW_OFFSET, FIB_CSLW_REQUIRED, FIB_CSW_REQUIRED, FIB_FC_LCB_BLOB_OFFSET, FIB_RG_LW_OFFSET, FIB_RG_LW_SIZE, FIB_RG_W_OFFSET, FIB_RG_W_SIZE, FIB_W_IDENT, FIELD_BEGIN, FIELD_END, FIELD_SEPARATOR, FKP_PAGE_SIZE, FOOTNOTE_REFERENCE, INLINE_PICTURE, LINE_BREAK, LW_OFFSET, NUMBER_FORMAT_BY_NFC, PARAGRAPH_MARK, PropertyBinTable, SECTION_MARK, SGC, STI_USER_DEFINED, STK, SUMMARY_INFORMATION_STREAM, SYMBOL_ANCHOR, WORD_DOCUMENT_STREAM, applyCharacterSprms, applyParagraphSprms, applySectionSprms, buildChpxPages, buildEmptyStsh, buildFib, buildFontTable, buildPapxPages, buildPlcfSed, buildPropertyBinTable, buildSepx, buildTextClx, characterIstdFromGrpprl, characterOffset, characterSize, decodeSprm, encodeCharacterGrpprl, encodeParagraphGrpprl, encodeSectionGrpprl, endsParagraph, findLargestAtMost, firstFcOfPage, fitsAloneOnPapxPage, headingLevelFromIstd, isAnchorOnly, isDocBytes, layoutMetadataToSummaryInformation, operandSize, parseChpxFkp, parseClx, parseFib, parseFontTable, parsePapxFkp, parsePlc, parseStsh, readDocContent, readDocStreams, readGrpprl, readInt16LE, readInt32LE, readNumberingDefinitions, readSectionProperties, readTextRange, readUint16LE, readUint32LE, readUint8, resolveStyleFormatting, slice, tableStreamName, writeDocContent };
27
+ export { ANNOTATION_REFERENCE, CELL_MARK, COMPRESSED_CHARACTER_MAP, DRAWN_OBJECT, DocFormatError, DocUnsupportedError, FC_LCB_VALUE_INDEX, FIB_BASE_FLAG, FIB_BASE_SIZE, FIB_CB_RG_FC_LCB_OFFSET, FIB_CSLW_OFFSET, FIB_CSLW_REQUIRED, FIB_CSW_REQUIRED, FIB_FC_LCB_BLOB_OFFSET, FIB_RG_LW_OFFSET, FIB_RG_LW_SIZE, FIB_RG_W_OFFSET, FIB_RG_W_SIZE, FIB_W_IDENT, FIELD_BEGIN, FIELD_END, FIELD_SEPARATOR, FKP_PAGE_SIZE, FOOTNOTE_REFERENCE, INLINE_PICTURE, LINE_BREAK, LW_OFFSET, NUMBER_FORMAT_BY_NFC, PARAGRAPH_MARK, PropertyBinTable, SECTION_MARK, SGC, STI_USER_DEFINED, STK, SUMMARY_INFORMATION_STREAM, SYMBOL_ANCHOR, WORD_DOCUMENT_STREAM, applyCharacterSprms, applyParagraphSprms, applySectionSprms, buildChpxPages, buildFib, buildFontTable, buildPapxPages, buildPlcfSed, buildPropertyBinTable, buildSepx, buildStshForStyles, buildTextClx, characterIstdFromGrpprl, characterOffset, characterSize, decodeSprm, encodeCharacterGrpprl, encodeParagraphGrpprl, encodeSectionGrpprl, endsParagraph, findLargestAtMost, firstFcOfPage, fitsAloneOnPapxPage, headingLevelFromIstd, isAnchorOnly, isDocBytes, layoutMetadataToSummaryInformation, operandSize, parseChpxFkp, parseClx, parseFib, parseFontTable, parsePapxFkp, parsePlc, parseStsh, readDocContent, readDocStreams, readGrpprl, readInt16LE, readInt32LE, readNumberingDefinitions, readSectionProperties, readTextRange, readUint16LE, readUint32LE, readUint8, resolveStyleFormatting, slice, tableStreamName, writeDocContent };
@@ -119,32 +119,62 @@ function resolveStyleFormatting(styleSheet, istd) {
119
119
  function headingLevelFromIstd(istd) {
120
120
  return istd >= 1 && istd <= 9 ? istd : void 0;
121
121
  }
122
- function buildEmptyStsh() {
122
+ function buildStshForStyles(names) {
123
+ const cstd = names.size === 0 ? 0 : Math.max(...names.keys()) + 1;
123
124
  const stshi = [];
124
- const push16 = (value) => {
125
- stshi.push(value & 255, value >> 8 & 255);
125
+ const push16 = (target, value) => {
126
+ target.push(value & 255, value >> 8 & 255);
126
127
  };
127
- push16(0);
128
- push16(STDF_SIZE_WITHOUT_POST_2000);
129
- push16(1);
130
- push16(0);
131
- push16(15);
132
- push16(0);
133
- push16(0);
134
- push16(0);
135
- push16(0);
136
- push16(0);
137
- push16(4);
138
- return new Uint8Array([
128
+ push16(stshi, cstd);
129
+ push16(stshi, STDF_SIZE_WITHOUT_POST_2000);
130
+ push16(stshi, 1);
131
+ push16(stshi, 0);
132
+ push16(stshi, 15);
133
+ push16(stshi, 0);
134
+ push16(stshi, 0);
135
+ push16(stshi, 0);
136
+ push16(stshi, 0);
137
+ push16(stshi, 0);
138
+ push16(stshi, 4);
139
+ const out = [
139
140
  stshi.length & 255,
140
141
  stshi.length >> 8 & 255,
141
142
  ...stshi
142
- ]);
143
+ ];
144
+ const pushLpUpx = (target, payload) => {
145
+ push16(target, payload.length);
146
+ target.push(...payload);
147
+ if (payload.length % 2 === 1) target.push(0);
148
+ };
149
+ for (let istd = 0; istd < cstd; istd += 1) {
150
+ const name = names.get(istd);
151
+ if (name === void 0) {
152
+ out.push(0, 0);
153
+ continue;
154
+ }
155
+ const std = [];
156
+ const word0 = 4094;
157
+ const word1 = STK.paragraph & 15 | 65520;
158
+ push16(std, word0);
159
+ push16(std, word1);
160
+ push16(std, 0);
161
+ push16(std, 0);
162
+ push16(std, 0);
163
+ push16(std, name.length);
164
+ for (const character of name) push16(std, character.charCodeAt(0));
165
+ push16(std, 0);
166
+ pushLpUpx(std, [istd & 255, istd >> 8 & 255]);
167
+ pushLpUpx(std, []);
168
+ push16(out, std.length);
169
+ out.push(...std);
170
+ if (std.length % 2 === 1) out.push(0);
171
+ }
172
+ return new Uint8Array(out);
143
173
  }
144
174
  //#endregion
145
175
  exports.STI_USER_DEFINED = STI_USER_DEFINED;
146
176
  exports.STK = STK;
147
- exports.buildEmptyStsh = buildEmptyStsh;
177
+ exports.buildStshForStyles = buildStshForStyles;
148
178
  exports.headingLevelFromIstd = headingLevelFromIstd;
149
179
  exports.parseStsh = parseStsh;
150
180
  exports.resolveStyleFormatting = resolveStyleFormatting;
@@ -35,6 +35,6 @@ interface ResolvedStyleFormatting {
35
35
  }
36
36
  declare function resolveStyleFormatting(styleSheet: StyleSheet, istd: number): ResolvedStyleFormatting;
37
37
  declare function headingLevelFromIstd(istd: number): number | undefined;
38
- declare function buildEmptyStsh(): Uint8Array;
38
+ declare function buildStshForStyles(names: ReadonlyMap<number, string>): Uint8Array;
39
39
  //#endregion
40
- export { ResolvedStyleFormatting, STI_USER_DEFINED, STK, Style, StyleSheet, buildEmptyStsh, headingLevelFromIstd, parseStsh, resolveStyleFormatting };
40
+ export { ResolvedStyleFormatting, STI_USER_DEFINED, STK, Style, StyleSheet, buildStshForStyles, headingLevelFromIstd, parseStsh, resolveStyleFormatting };
@@ -35,6 +35,6 @@ interface ResolvedStyleFormatting {
35
35
  }
36
36
  declare function resolveStyleFormatting(styleSheet: StyleSheet, istd: number): ResolvedStyleFormatting;
37
37
  declare function headingLevelFromIstd(istd: number): number | undefined;
38
- declare function buildEmptyStsh(): Uint8Array;
38
+ declare function buildStshForStyles(names: ReadonlyMap<number, string>): Uint8Array;
39
39
  //#endregion
40
- export { ResolvedStyleFormatting, STI_USER_DEFINED, STK, Style, StyleSheet, buildEmptyStsh, headingLevelFromIstd, parseStsh, resolveStyleFormatting };
40
+ export { ResolvedStyleFormatting, STI_USER_DEFINED, STK, Style, StyleSheet, buildStshForStyles, headingLevelFromIstd, parseStsh, resolveStyleFormatting };
@@ -118,27 +118,57 @@ function resolveStyleFormatting(styleSheet, istd) {
118
118
  function headingLevelFromIstd(istd) {
119
119
  return istd >= 1 && istd <= 9 ? istd : void 0;
120
120
  }
121
- function buildEmptyStsh() {
121
+ function buildStshForStyles(names) {
122
+ const cstd = names.size === 0 ? 0 : Math.max(...names.keys()) + 1;
122
123
  const stshi = [];
123
- const push16 = (value) => {
124
- stshi.push(value & 255, value >> 8 & 255);
124
+ const push16 = (target, value) => {
125
+ target.push(value & 255, value >> 8 & 255);
125
126
  };
126
- push16(0);
127
- push16(STDF_SIZE_WITHOUT_POST_2000);
128
- push16(1);
129
- push16(0);
130
- push16(15);
131
- push16(0);
132
- push16(0);
133
- push16(0);
134
- push16(0);
135
- push16(0);
136
- push16(4);
137
- return new Uint8Array([
127
+ push16(stshi, cstd);
128
+ push16(stshi, STDF_SIZE_WITHOUT_POST_2000);
129
+ push16(stshi, 1);
130
+ push16(stshi, 0);
131
+ push16(stshi, 15);
132
+ push16(stshi, 0);
133
+ push16(stshi, 0);
134
+ push16(stshi, 0);
135
+ push16(stshi, 0);
136
+ push16(stshi, 0);
137
+ push16(stshi, 4);
138
+ const out = [
138
139
  stshi.length & 255,
139
140
  stshi.length >> 8 & 255,
140
141
  ...stshi
141
- ]);
142
+ ];
143
+ const pushLpUpx = (target, payload) => {
144
+ push16(target, payload.length);
145
+ target.push(...payload);
146
+ if (payload.length % 2 === 1) target.push(0);
147
+ };
148
+ for (let istd = 0; istd < cstd; istd += 1) {
149
+ const name = names.get(istd);
150
+ if (name === void 0) {
151
+ out.push(0, 0);
152
+ continue;
153
+ }
154
+ const std = [];
155
+ const word0 = 4094;
156
+ const word1 = STK.paragraph & 15 | 65520;
157
+ push16(std, word0);
158
+ push16(std, word1);
159
+ push16(std, 0);
160
+ push16(std, 0);
161
+ push16(std, 0);
162
+ push16(std, name.length);
163
+ for (const character of name) push16(std, character.charCodeAt(0));
164
+ push16(std, 0);
165
+ pushLpUpx(std, [istd & 255, istd >> 8 & 255]);
166
+ pushLpUpx(std, []);
167
+ push16(out, std.length);
168
+ out.push(...std);
169
+ if (std.length % 2 === 1) out.push(0);
170
+ }
171
+ return new Uint8Array(out);
142
172
  }
143
173
  //#endregion
144
- export { STI_USER_DEFINED, STK, buildEmptyStsh, headingLevelFromIstd, parseStsh, resolveStyleFormatting };
174
+ export { STI_USER_DEFINED, STK, buildStshForStyles, headingLevelFromIstd, parseStsh, resolveStyleFormatting };
@@ -1,2 +1,2 @@
1
- import { n as WriteWarning, r as flattenSectionBlocks, t as WriteParagraph } from "../write-C9XbykDf.cjs";
1
+ import { n as WriteWarning, r as flattenSectionBlocks, t as WriteParagraph } from "../write-SN_aIwyF.cjs";
2
2
  export { WriteParagraph, WriteWarning, flattenSectionBlocks };
@@ -1,2 +1,2 @@
1
- import { n as WriteWarning, r as flattenSectionBlocks, t as WriteParagraph } from "../write-C9XbykDf.js";
1
+ import { n as WriteWarning, r as flattenSectionBlocks, t as WriteParagraph } from "../write-SN_aIwyF.js";
2
2
  export { WriteParagraph, WriteWarning, flattenSectionBlocks };
@@ -4,7 +4,7 @@ import { ContentBlock, ContentParagraph, ContentRun } from "document-schema.js";
4
4
  type WriteWarning = (message: string) => void;
5
5
  interface WriteParagraph {
6
6
  readonly runs: readonly ContentRun[];
7
- readonly properties: Pick<ContentParagraph, "alignment" | "indentLeftPt" | "indentRightPt" | "indentFirstLinePt" | "spacingBeforePt" | "spacingAfterPt" | "lineSpacing" | "pageBreakBefore" | "list">;
7
+ readonly properties: Pick<ContentParagraph, "alignment" | "indentLeftPt" | "indentRightPt" | "indentFirstLinePt" | "spacingBeforePt" | "spacingAfterPt" | "lineSpacing" | "pageBreakBefore" | "list" | "styleId" | "headingLevel">;
8
8
  /** Extra grpprl bytes appended after encodeParagraphGrpprl's own output -- sprmPFInTable on every table paragraph, plus sprmPFTtp and the row's own TAP on a row's trailing mark. */
9
9
  readonly extraGrpprl: readonly number[];
10
10
  /** The character terminating this paragraph in the text stream: PARAGRAPH_MARK normally, CELL_MARK for a table cell or row mark. */
@@ -4,7 +4,7 @@ import { ContentBlock, ContentParagraph, ContentRun } from "document-schema.js";
4
4
  type WriteWarning = (message: string) => void;
5
5
  interface WriteParagraph {
6
6
  readonly runs: readonly ContentRun[];
7
- readonly properties: Pick<ContentParagraph, "alignment" | "indentLeftPt" | "indentRightPt" | "indentFirstLinePt" | "spacingBeforePt" | "spacingAfterPt" | "lineSpacing" | "pageBreakBefore" | "list">;
7
+ readonly properties: Pick<ContentParagraph, "alignment" | "indentLeftPt" | "indentRightPt" | "indentFirstLinePt" | "spacingBeforePt" | "spacingAfterPt" | "lineSpacing" | "pageBreakBefore" | "list" | "styleId" | "headingLevel">;
8
8
  /** Extra grpprl bytes appended after encodeParagraphGrpprl's own output -- sprmPFInTable on every table paragraph, plus sprmPFTtp and the row's own TAP on a row's trailing mark. */
9
9
  readonly extraGrpprl: readonly number[];
10
10
  /** The character terminating this paragraph in the text stream: PARAGRAPH_MARK normally, CELL_MARK for a table cell or row mark. */
package/dist/write.cjs CHANGED
@@ -32,6 +32,28 @@ function writeDocContent(document, options = {}) {
32
32
  extraGrpprl: [],
33
33
  terminator: 13
34
34
  });
35
+ const FIRST_NON_HEADING_ISTD = 10;
36
+ const MAX_HEADING_ISTD = 9;
37
+ const styleNames = /* @__PURE__ */ new Map();
38
+ const istdByStyleId = /* @__PURE__ */ new Map();
39
+ let nextNonHeadingIstd = FIRST_NON_HEADING_ISTD;
40
+ const istdOf = (properties) => {
41
+ const heading = properties.headingLevel;
42
+ if (heading !== void 0 && heading >= 1 && heading <= MAX_HEADING_ISTD) {
43
+ if (!styleNames.has(heading)) styleNames.set(heading, properties.styleId ?? `Heading ${String(heading)}`);
44
+ return heading;
45
+ }
46
+ const styleId = properties.styleId;
47
+ if (styleId === void 0) return 0;
48
+ const existing = istdByStyleId.get(styleId);
49
+ if (existing !== void 0) return existing;
50
+ const istd = nextNonHeadingIstd;
51
+ nextNonHeadingIstd += 1;
52
+ istdByStyleId.set(styleId, istd);
53
+ styleNames.set(istd, styleId);
54
+ return istd;
55
+ };
56
+ const istds = writeParagraphs.map((entry) => istdOf(entry.properties));
35
57
  const fontNames = [];
36
58
  const fontIndexByName = /* @__PURE__ */ new Map();
37
59
  const fontIndexOf = (name) => {
@@ -101,9 +123,11 @@ function writeDocContent(document, options = {}) {
101
123
  const papxParagraphSpecs = formatted.map((paragraph, index) => {
102
124
  const start = paragraphStarts[index];
103
125
  if (start === void 0) throw new require_errors.DocFormatError("internal defect: writeDocContent lost a paragraph's own start position");
126
+ const istd = istds[index];
127
+ if (istd === void 0) throw new require_errors.DocFormatError("internal defect: writeDocContent lost a paragraph's own minted istd");
104
128
  return {
105
129
  fc: characterFc(start),
106
- istd: 0,
130
+ istd,
107
131
  grpprl: paragraph.grpprl
108
132
  };
109
133
  });
@@ -123,7 +147,7 @@ function writeDocContent(document, options = {}) {
123
147
  const clx = require_text_piece_table_write.buildTextClx(text.length, TEXT_FC);
124
148
  const chpxBinTable = require_prop_fkp_write.buildPropertyBinTable([...chpxPages.map(require_prop_fkp_write.firstFcOfPage), textFcLim], chpxPages.map((_, index) => chpxPageStart + index));
125
149
  const papxBinTable = require_prop_fkp_write.buildPropertyBinTable([...papxPages.map(require_prop_fkp_write.firstFcOfPage), textFcLim], papxPages.map((_, index) => papxPageStart + index));
126
- const stsh = require_style_stsh.buildEmptyStsh();
150
+ const stsh = require_style_stsh.buildStshForStyles(styleNames);
127
151
  const fontTable = fontNames.length > 0 ? require_style_fonts.buildFontTable(fontNames) : void 0;
128
152
  const plcfSed = require_prop_sep_write.buildPlcfSed(text.length, fcSepx);
129
153
  let cursor = 0;
package/dist/write.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as WriteWarning } from "./write-C9XbykDf.cjs";
1
+ import { n as WriteWarning } from "./write-SN_aIwyF.cjs";
2
2
  import { ContentDocument } from "document-schema.js";
3
3
  //#region src/write.d.ts
4
4
  interface WriteDocContentOptions {
package/dist/write.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as WriteWarning } from "./write-C9XbykDf.js";
1
+ import { n as WriteWarning } from "./write-SN_aIwyF.js";
2
2
  import { ContentDocument } from "document-schema.js";
3
3
  //#region src/write.d.ts
4
4
  interface WriteDocContentOptions {
package/dist/write.js CHANGED
@@ -9,7 +9,7 @@ import { buildChpxPages, buildPapxPages, buildPropertyBinTable, firstFcOfPage }
9
9
  import { encodeCharacterGrpprl } from "./prop/chp-write.js";
10
10
  import { encodeParagraphGrpprl } from "./prop/pap-write.js";
11
11
  import { buildPlcfSed, buildSepx, encodeSectionGrpprl } from "./prop/sep-write.js";
12
- import { buildEmptyStsh } from "./style/stsh.js";
12
+ import { buildStshForStyles } from "./style/stsh.js";
13
13
  import { buildFontTable } from "./style/fonts.js";
14
14
  import { buildNumberingTables, gatherListUsage } from "./list/numbering-write.js";
15
15
  import { flattenSectionBlocks } from "./table/write.js";
@@ -31,6 +31,28 @@ function writeDocContent(document, options = {}) {
31
31
  extraGrpprl: [],
32
32
  terminator: 13
33
33
  });
34
+ const FIRST_NON_HEADING_ISTD = 10;
35
+ const MAX_HEADING_ISTD = 9;
36
+ const styleNames = /* @__PURE__ */ new Map();
37
+ const istdByStyleId = /* @__PURE__ */ new Map();
38
+ let nextNonHeadingIstd = FIRST_NON_HEADING_ISTD;
39
+ const istdOf = (properties) => {
40
+ const heading = properties.headingLevel;
41
+ if (heading !== void 0 && heading >= 1 && heading <= MAX_HEADING_ISTD) {
42
+ if (!styleNames.has(heading)) styleNames.set(heading, properties.styleId ?? `Heading ${String(heading)}`);
43
+ return heading;
44
+ }
45
+ const styleId = properties.styleId;
46
+ if (styleId === void 0) return 0;
47
+ const existing = istdByStyleId.get(styleId);
48
+ if (existing !== void 0) return existing;
49
+ const istd = nextNonHeadingIstd;
50
+ nextNonHeadingIstd += 1;
51
+ istdByStyleId.set(styleId, istd);
52
+ styleNames.set(istd, styleId);
53
+ return istd;
54
+ };
55
+ const istds = writeParagraphs.map((entry) => istdOf(entry.properties));
34
56
  const fontNames = [];
35
57
  const fontIndexByName = /* @__PURE__ */ new Map();
36
58
  const fontIndexOf = (name) => {
@@ -100,9 +122,11 @@ function writeDocContent(document, options = {}) {
100
122
  const papxParagraphSpecs = formatted.map((paragraph, index) => {
101
123
  const start = paragraphStarts[index];
102
124
  if (start === void 0) throw new DocFormatError("internal defect: writeDocContent lost a paragraph's own start position");
125
+ const istd = istds[index];
126
+ if (istd === void 0) throw new DocFormatError("internal defect: writeDocContent lost a paragraph's own minted istd");
103
127
  return {
104
128
  fc: characterFc(start),
105
- istd: 0,
129
+ istd,
106
130
  grpprl: paragraph.grpprl
107
131
  };
108
132
  });
@@ -122,7 +146,7 @@ function writeDocContent(document, options = {}) {
122
146
  const clx = buildTextClx(text.length, TEXT_FC);
123
147
  const chpxBinTable = buildPropertyBinTable([...chpxPages.map(firstFcOfPage), textFcLim], chpxPages.map((_, index) => chpxPageStart + index));
124
148
  const papxBinTable = buildPropertyBinTable([...papxPages.map(firstFcOfPage), textFcLim], papxPages.map((_, index) => papxPageStart + index));
125
- const stsh = buildEmptyStsh();
149
+ const stsh = buildStshForStyles(styleNames);
126
150
  const fontTable = fontNames.length > 0 ? buildFontTable(fontNames) : void 0;
127
151
  const plcfSed = buildPlcfSed(text.length, fcSepx);
128
152
  let cursor = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doc-codec",
3
- "version": "2.2.5",
3
+ "version": "2.3.0",
4
4
  "description": "A hand-written reader for the Word Binary File Format ([MS-DOC], .doc) against the shared document-schema.js content pivot: FIB parsing, piece-table text reconstruction, and CHPX/PAPX formatting exceptions.",
5
5
  "type": "module",
6
6
  "repository": {