doc-codec 2.1.1 → 2.2.1

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 (54) hide show
  1. package/README.md +16 -10
  2. package/dist/fib/write.cjs +2 -0
  3. package/dist/fib/write.d.cts +5 -0
  4. package/dist/fib/write.d.ts +5 -0
  5. package/dist/fib/write.js +2 -0
  6. package/dist/index.cjs +1 -0
  7. package/dist/index.d.cts +4 -4
  8. package/dist/index.d.ts +4 -4
  9. package/dist/index.js +2 -2
  10. package/dist/list/numbering-write.cjs +165 -0
  11. package/dist/list/numbering-write.d.cts +21 -0
  12. package/dist/list/numbering-write.d.ts +21 -0
  13. package/dist/list/numbering-write.js +163 -0
  14. package/dist/list/numbering.cjs +11 -10
  15. package/dist/list/numbering.d.cts +2 -2
  16. package/dist/list/numbering.d.ts +2 -2
  17. package/dist/list/numbering.js +11 -11
  18. package/dist/{numbering-Cir-uGdc.d.cts → numbering-Bivayss4.d.cts} +5 -3
  19. package/dist/{numbering-DF1z1PyG.d.ts → numbering-Co4jssbG.d.ts} +5 -3
  20. package/dist/{pap-BmelEYEP.d.cts → pap-BT1p0uzu.d.cts} +1 -1
  21. package/dist/{pap-BkFo8dZO.d.ts → pap-DOFLMWcG.d.ts} +1 -1
  22. package/dist/prop/chp-write.cjs +1 -1
  23. package/dist/prop/chp-write.js +1 -1
  24. package/dist/prop/chp.d.cts +1 -1
  25. package/dist/prop/chp.d.ts +1 -1
  26. package/dist/prop/pap-write.cjs +15 -2
  27. package/dist/prop/pap-write.d.cts +1 -1
  28. package/dist/prop/pap-write.d.ts +1 -1
  29. package/dist/prop/pap-write.js +15 -2
  30. package/dist/prop/pap.d.cts +1 -1
  31. package/dist/prop/pap.d.ts +1 -1
  32. package/dist/prop/sep.d.cts +1 -1
  33. package/dist/prop/sep.d.ts +1 -1
  34. package/dist/prop/sprm.cjs +1 -1
  35. package/dist/prop/sprm.d.cts +1 -1
  36. package/dist/prop/sprm.d.ts +1 -1
  37. package/dist/prop/sprm.js +1 -1
  38. package/dist/read.cjs +1 -0
  39. package/dist/read.d.cts +3 -3
  40. package/dist/read.d.ts +3 -3
  41. package/dist/read.js +1 -0
  42. package/dist/{sprm-Djg5RNiq.d.cts → sprm-DEyvdOo0.d.cts} +1 -1
  43. package/dist/{sprm-Djg5RNiq.d.ts → sprm-DEyvdOo0.d.ts} +1 -1
  44. package/dist/table/tap.d.cts +1 -1
  45. package/dist/table/tap.d.ts +1 -1
  46. package/dist/table/write.d.cts +1 -1
  47. package/dist/table/write.d.ts +1 -1
  48. package/dist/{write-C_vJizAM.d.cts → write-C9XbykDf.d.cts} +1 -1
  49. package/dist/{write-C_vJizAM.d.ts → write-C9XbykDf.d.ts} +1 -1
  50. package/dist/write.cjs +20 -2
  51. package/dist/write.d.cts +1 -1
  52. package/dist/write.d.ts +1 -1
  53. package/dist/write.js +20 -2
  54. package/package.json +3 -3
@@ -0,0 +1,163 @@
1
+ import { DocFormatError } from "../errors.js";
2
+ import { NUMBER_FORMAT_BY_NFC } from "./numbering.js";
3
+ //#region src/list/numbering-write.ts
4
+ const LSTF_SIZE = 28;
5
+ const LVLF_SIZE = 28;
6
+ const LFO_SIZE = 16;
7
+ const LSTF_FLAG_SIMPLE_LIST = 1;
8
+ /** The LVLF flags-byte bit numbering.ts's own reader treats as fNoRestart -- restated here for the reason pap-write.ts's own top comment gives for restating pap.ts's opcodes: this module's own byte layout is coupled to the specification's field table, not to a sibling module's private constant name. */
9
+ const LVLF_FLAG_NO_RESTART = 2;
10
+ /** A non-simple LSTF always carries exactly nine LVLs ([MS-DOC] 2.9.191); sprmPIlvl's own operand range this writer's caller (pap-write.ts) validates against is the same fact restated at the paragraph-property layer. */
11
+ const MAX_LIST_LEVEL = 8;
12
+ const LEVELS_PER_MULTI_LEVEL_LIST = 9;
13
+ /** The format every level this writer invents for a paragraph that leaves ContentListMembership.format unstated, and every level a multi-level list's own dense 0..8 run needs filling but no paragraph ever actually used -- an arbitrary but harmless choice, since an unused level's own appearance is never read back into a context that renders it. */
14
+ const DEFAULT_FORMAT = "decimal";
15
+ /** The glyph this writer states for format 'bullet'. A real Word-format producer typically uses a Private Use Area code point from a symbol font (the README's own "Numbering definitions" section records LibreOffice writing U+F0B7) -- this writer uses the plain, portable Unicode bullet instead, since this is a synthesised definition rather than a captured one, and it round-trips exactly through this package's own reader either way. */
16
+ const BULLET_GLYPH = "•";
17
+ /** The inverse of numbering.ts's own NUMBER_FORMAT_BY_NFC, restricted to whichever of its entries a format string can actually reach -- built once by inverting the single source of truth rather than hand-maintaining a second table that could silently drift from it. Where two nfc values map to the same format string (0x00 and 0x28 both mean "decimal"), the lower one wins, because Object.entries on an object whose own keys are non-negative integer strings iterates in ascending numeric order regardless of insertion order (the one case JavaScript's own key-ordering rules give a numeric guarantee), so the first entry visited for "decimal" is 0x00. */
18
+ const NFC_BY_FORMAT = (() => {
19
+ const byFormat = /* @__PURE__ */ new Map();
20
+ for (const [nfcKey, format] of Object.entries(NUMBER_FORMAT_BY_NFC)) if (!byFormat.has(format)) byFormat.set(format, Number(nfcKey));
21
+ return byFormat;
22
+ })();
23
+ function push16(bytes, value) {
24
+ bytes.push(value & 255, value >> 8 & 255);
25
+ }
26
+ function push32(bytes, value) {
27
+ const unsigned = value >>> 0;
28
+ bytes.push(unsigned & 255, unsigned >> 8 & 255, unsigned >> 16 & 255, unsigned >>> 24 & 255);
29
+ }
30
+ function writeUint32LE(target, offset, value) {
31
+ const unsigned = value >>> 0;
32
+ target[offset] = unsigned & 255;
33
+ target[offset + 1] = unsigned >> 8 & 255;
34
+ target[offset + 2] = unsigned >> 16 & 255;
35
+ target[offset + 3] = unsigned >>> 24 & 255;
36
+ }
37
+ function encodeXst(text) {
38
+ const bytes = [];
39
+ push16(bytes, text.length);
40
+ for (let index = 0; index < text.length; index += 1) push16(bytes, text.charCodeAt(index));
41
+ return bytes;
42
+ }
43
+ /** The exact inverse of numbering.ts's own readLevelText: for a numbered format, a single placeholder for the level's own zero-based index (encoded as a raw code unit, per Xst's own placeholder convention) followed by a literal '.', reproducing readLevelText's '%1.'-style output ('%N' where N = level+1) on a subsequent read; for 'bullet', the literal glyph with no placeholder at all. */
44
+ function buildLevelXst(level, format) {
45
+ if (format === "bullet") return {
46
+ xstText: BULLET_GLYPH,
47
+ positions: []
48
+ };
49
+ return {
50
+ xstText: `${String.fromCharCode(level)}.`,
51
+ positions: [1]
52
+ };
53
+ }
54
+ function levelText(level, format) {
55
+ return format === "bullet" ? BULLET_GLYPH : `%${level + 1}.`;
56
+ }
57
+ function defaultLevel(level, format) {
58
+ return {
59
+ format,
60
+ text: levelText(level, format),
61
+ startAt: 1
62
+ };
63
+ }
64
+ function gatherListUsage(memberships) {
65
+ const ilfoByNumId = /* @__PURE__ */ new Map();
66
+ const usedLevelsByIlfo = /* @__PURE__ */ new Map();
67
+ for (const membership of memberships) {
68
+ if (membership?.numId === void 0) continue;
69
+ if (membership.level > MAX_LIST_LEVEL) throw new DocFormatError(`paragraph list numId ${JSON.stringify(membership.numId)} names level ${membership.level}, outside the 0..${MAX_LIST_LEVEL} range a non-simple LSTF's fixed nine LVLs ([MS-DOC] 2.9.191) can address`);
70
+ let ilfo = ilfoByNumId.get(membership.numId);
71
+ if (ilfo === void 0) {
72
+ ilfo = ilfoByNumId.size + 1;
73
+ ilfoByNumId.set(membership.numId, ilfo);
74
+ usedLevelsByIlfo.set(ilfo, /* @__PURE__ */ new Map());
75
+ }
76
+ const used = usedLevelsByIlfo.get(ilfo);
77
+ if (used === void 0) throw new DocFormatError("internal defect: gatherListUsage minted an ilfo with no levels map of its own");
78
+ if (!used.has(membership.level)) used.set(membership.level, defaultLevel(membership.level, membership.format ?? DEFAULT_FORMAT));
79
+ }
80
+ const definitions = {};
81
+ for (const [ilfo, used] of usedLevelsByIlfo) {
82
+ const levelCount = Math.max(...used.keys()) === 0 ? 1 : LEVELS_PER_MULTI_LEVEL_LIST;
83
+ const levels = {};
84
+ for (let level = 0; level < levelCount; level += 1) levels[String(level)] = used.get(level) ?? defaultLevel(level, DEFAULT_FORMAT);
85
+ definitions[String(ilfo)] = { levels };
86
+ }
87
+ return {
88
+ definitions,
89
+ ilfoByNumId
90
+ };
91
+ }
92
+ function buildLstfBytes(lsid, fSimpleList) {
93
+ const lstf = new Array(LSTF_SIZE).fill(0);
94
+ writeUint32LE(lstf, 0, lsid);
95
+ lstf[26] = fSimpleList ? LSTF_FLAG_SIMPLE_LIST : 0;
96
+ return lstf;
97
+ }
98
+ function buildLvlBytes(level, numberingLevel) {
99
+ const nfc = NFC_BY_FORMAT.get(numberingLevel.format);
100
+ if (nfc === void 0) throw new DocFormatError(`numbering level format ${JSON.stringify(numberingLevel.format)} has no [MS-OSHARED] 2.2.1.3 MSONFC mapping this writer can state -- only ${JSON.stringify([...NFC_BY_FORMAT.keys()])} round-trip through ContentListMembership.format`);
101
+ const { xstText, positions } = buildLevelXst(level, numberingLevel.format);
102
+ const lvlf = new Array(LVLF_SIZE).fill(0);
103
+ writeUint32LE(lvlf, 0, numberingLevel.startAt);
104
+ lvlf[4] = nfc;
105
+ if (numberingLevel.restart !== void 0) {
106
+ lvlf[5] = LVLF_FLAG_NO_RESTART;
107
+ lvlf[26] = numberingLevel.restart;
108
+ }
109
+ positions.forEach((position, index) => {
110
+ lvlf[6 + index] = position;
111
+ });
112
+ return [...lvlf, ...encodeXst(xstText)];
113
+ }
114
+ /** Encodes a NumberingDefinitions into real PlfLst/PlfLfo bytes -- undefined when it names no lists at all, so writeDocContent can skip both fc/lcb pairs entirely rather than writing an empty-but-present structure no paragraph ever references. Independent of gatherListUsage: any NumberingDefinitions this package's own numbering.ts could produce from a real .doc encodes here too, including a startAt other than 1 or a restart rule, since every LVLF field this function writes comes from the definition's own NumberingLevel rather than an assumed default. */
115
+ function buildNumberingTables(definitions) {
116
+ const keys = Object.keys(definitions);
117
+ const keyByIlfo = /* @__PURE__ */ new Map();
118
+ for (const key of keys) {
119
+ const ilfo = Number(key);
120
+ const collidingKey = keyByIlfo.get(ilfo);
121
+ if (collidingKey !== void 0) throw new DocFormatError(`numbering definition keys ${JSON.stringify(collidingKey)} and ${JSON.stringify(key)} both name lsid ${ilfo} once converted to a number -- [MS-DOC] 2.9.147 requires lsid to be unique for each LSTF`);
122
+ keyByIlfo.set(ilfo, key);
123
+ }
124
+ const ilfos = [...keyByIlfo.keys()].sort((a, b) => a - b);
125
+ if (ilfos.length === 0) return void 0;
126
+ const lstfBytes = [];
127
+ const lvlBytes = [];
128
+ const rgLfoBytes = [];
129
+ for (const ilfo of ilfos) {
130
+ const definition = definitions[String(ilfo)];
131
+ if (definition === void 0) throw new DocFormatError("internal defect: buildNumberingTables lost a definition for an ilfo its own key list just named");
132
+ const levelKeys = Object.keys(definition.levels).map(Number).sort((a, b) => a - b);
133
+ const fSimpleList = levelKeys.length === 1 && levelKeys[0] === 0;
134
+ const isDenseMultiLevel = levelKeys.length === LEVELS_PER_MULTI_LEVEL_LIST && levelKeys.every((level, index) => level === index);
135
+ if (!fSimpleList && !isDenseMultiLevel) throw new DocFormatError(`numbering definition for ilfo ${ilfo} names levels ${JSON.stringify(levelKeys)}, but [MS-DOC] 2.9.191's own LSTF states either exactly level 0 alone (a simple list) or a dense 0..${MAX_LIST_LEVEL} run of all nine -- there is no partial shape to write`);
136
+ lstfBytes.push(...buildLstfBytes(ilfo, fSimpleList));
137
+ for (const level of levelKeys) {
138
+ const numberingLevel = definition.levels[String(level)];
139
+ if (numberingLevel === void 0) throw new DocFormatError("internal defect: buildNumberingTables lost a level its own key list just named");
140
+ lvlBytes.push(...buildLvlBytes(level, numberingLevel));
141
+ }
142
+ const lfo = new Array(LFO_SIZE).fill(0);
143
+ writeUint32LE(lfo, 0, ilfo);
144
+ rgLfoBytes.push(...lfo);
145
+ }
146
+ const plfLstHeader = [];
147
+ push16(plfLstHeader, ilfos.length);
148
+ const plfLst = new Uint8Array([
149
+ ...plfLstHeader,
150
+ ...lstfBytes,
151
+ ...lvlBytes
152
+ ]);
153
+ const plfLfoHeader = [];
154
+ push32(plfLfoHeader, ilfos.length);
155
+ const plfLfo = new Uint8Array([...plfLfoHeader, ...rgLfoBytes]);
156
+ return {
157
+ plfLst,
158
+ lcbPlfLst: plfLstHeader.length + lstfBytes.length,
159
+ plfLfo
160
+ };
161
+ }
162
+ //#endregion
163
+ export { buildNumberingTables, gatherListUsage };
@@ -5,7 +5,7 @@ const require_bytes = require("../bytes.cjs");
5
5
  const LSTF_SIZE = 28;
6
6
  const LVLF_SIZE = 28;
7
7
  const LFO_SIZE = 16;
8
- /** LSTF's own flags byte ([MS-DOC] 2.9.191), bit 0: "this LSTF represents a simple (one-level) list that has one corresponding LVL. Otherwise... a multi-level list that has nine corresponding LVLs." */
8
+ /** LSTF's own flags byte ([MS-DOC] 2.9.147), bit 0: "this LSTF represents a simple (one-level) list that has one corresponding LVL. Otherwise... a multi-level list that has nine corresponding LVLs." */
9
9
  const LSTF_FLAG_SIMPLE_LIST = 1;
10
10
  /** MSONFC ([MS-OSHARED] 2.2.1.3), mapped to its own documented ST_NumberFormat equivalent -- the identical vocabulary ooxml.js's NumberingLevel.format carries verbatim from word/numbering.xml's own w:numFmt/@w:val. Every member through msonfcUCRus (0x3B) is a real numbered/lettered/ideograph format; 0x17 (msonfcBullet) is handled separately below since PlfLfo also treats it as the "no number sequence, but has bullets" case LVLF's own field text calls out by name. */
11
11
  const NUMBER_FORMAT_BY_NFC = {
@@ -78,14 +78,14 @@ function numberFormatFor(nfc) {
78
78
  if (format === void 0) throw new require_errors.DocFormatError(`LVLF.nfc is 0x${nfc.toString(16).padStart(2, "0")}, not a recognised MSONFC value ([MS-OSHARED] 2.2.1.3)`);
79
79
  return format;
80
80
  }
81
- /** LSTF ([MS-DOC] 2.9.191): lsid(4) + tplc(4, ignored -- UI-only) + rgistdPara(18, ignored -- this reader has no per-level style cascade to link into) + a flags byte (only fSimpleList, bit 0, acted on) + grfhic(1, ignored -- HTML-export-only incompatibility flags). Fixed 28 bytes. */
81
+ /** LSTF ([MS-DOC] 2.9.147): lsid(4) + tplc(4, ignored -- UI-only) + rgistdPara(18, ignored -- this reader has no per-level style cascade to link into) + a flags byte (only fSimpleList, bit 0, acted on) + grfhic(1, ignored -- HTML-export-only incompatibility flags). Fixed 28 bytes. */
82
82
  function readLstf(bytes, offset) {
83
83
  return {
84
84
  lsid: require_bytes.readInt32LE(bytes, offset),
85
85
  fSimpleList: (require_bytes.readUint8(bytes, offset + 26) & LSTF_FLAG_SIMPLE_LIST) !== 0
86
86
  };
87
87
  }
88
- /** Xst ([MS-DOC] 2.9.343): cch(2 bytes) then that many raw 16-bit code units, prefixed-length and not null-terminated. Decoded as a plain UTF-16 string -- readLevelText below re-inspects specific character positions afterward for placeholders, which round-trips exactly through String.fromCharCode/charCodeAt since every placeholder value (0-8) sits well within one UTF-16 code unit and never needs a surrogate pair. Returns the decoded text and the byte length consumed, since the caller must advance past it to reach grpprlPapx/grpprlChpx or the next LVL. */
88
+ /** Xst ([MS-DOC] 2.9.353): cch(2 bytes) then that many raw 16-bit code units, prefixed-length and not null-terminated. Decoded as a plain UTF-16 string -- readLevelText below re-inspects specific character positions afterward for placeholders, which round-trips exactly through String.fromCharCode/charCodeAt since every placeholder value (0-8) sits well within one UTF-16 code unit and never needs a surrogate pair. Returns the decoded text and the byte length consumed, since the caller must advance past it to reach grpprlPapx/grpprlChpx or the next LVL. */
89
89
  function readXst(bytes, offset) {
90
90
  const cch = require_bytes.readUint16LE(bytes, offset);
91
91
  let text = "";
@@ -95,7 +95,7 @@ function readXst(bytes, offset) {
95
95
  byteLength: 2 + cch * 2
96
96
  };
97
97
  }
98
- /** rgbxchNums ([MS-DOC] 2.9.148's own LVLF field): nine 8-bit one-based character offsets into the LVL's own xst.rgtchar, zero-terminated (a 0 entry, or the end of the fixed 9-byte array, ends the list). Each offset it names is a POSITION in the string, not a value -- readLevelText is what turns a position into the placeholder it names. */
98
+ /** rgbxchNums ([MS-DOC] 2.9.150's own LVLF field): nine 8-bit one-based character offsets into the LVL's own xst.rgtchar, zero-terminated (a 0 entry, or the end of the fixed 9-byte array, ends the list). Each offset it names is a POSITION in the string, not a value -- readLevelText is what turns a position into the placeholder it names. */
99
99
  function readRgbxchNums(bytes, offset) {
100
100
  const positions = [];
101
101
  for (let index = 0; index < 9; index += 1) {
@@ -105,7 +105,7 @@ function readRgbxchNums(bytes, offset) {
105
105
  }
106
106
  return positions;
107
107
  }
108
- /** Turns an Xst's own decoded text plus its rgbxchNums positions into the '%1.'-style placeholder text NumberingLevel.text states -- the mirror of readXst/readRgbxchNums together. [MS-DOC]'s own Xst field text: "Each placeholder is an unsigned 2-byte integer that specifies the zero-based level that the placeholder is for" -- so the character AT a named position is not a literal code point at all, but a raw level index (0-8) String.fromCharCode/charCodeAt round-trips losslessly; every other position is decoded as ordinary text. A one-based placeholder ('%1' for level 0) matches ooxml.js's own w:lvlText convention, so a consumer already resolving '%1.'/'%2)' style docx templates resolves this reader's templates identically. */
108
+ /** Turns an Xst's own decoded text plus its rgbxchNums positions into the '%1.'-style placeholder text NumberingLevel.text states -- the mirror of readXst/readRgbxchNums together. [MS-DOC] 2.9.149's own LVL field text (not Xst's -- Xst is a generic length-prefixed string used all over the format for unrelated fields too): "Each placeholder is an unsigned 2-byte integer that specifies the zero-based level that the placeholder is for" -- so the character AT a named position is not a literal code point at all, but a raw level index (0-8) String.fromCharCode/charCodeAt round-trips losslessly; every other position is decoded as ordinary text. A one-based placeholder ('%1' for level 0) matches ooxml.js's own w:lvlText convention, so a consumer already resolving '%1.'/'%2)' style docx templates resolves this reader's templates identically. */
109
109
  function readLevelText(xstText, placeholderPositions) {
110
110
  const placeholders = new Set(placeholderPositions);
111
111
  let result = "";
@@ -118,7 +118,7 @@ function readLevelText(xstText, placeholderPositions) {
118
118
  }
119
119
  return result;
120
120
  }
121
- /** LVL ([MS-DOC] 2.9.196): a 28-byte LVLF, then grpprlPapx (cbGrpprlPapx bytes, skipped -- see this module's own top comment), grpprlChpx (cbGrpprlChpx bytes, skipped), then the level's own Xst. Every LVL is variable-length, so the caller must use byteLength to advance to the next one in the array -- there is no outer length field to skip by instead. */
121
+ /** LVL ([MS-DOC] 2.9.149): a 28-byte LVLF, then grpprlPapx (cbGrpprlPapx bytes, skipped -- see this module's own top comment), grpprlChpx (cbGrpprlChpx bytes, skipped), then the level's own Xst. Every LVL is variable-length, so the caller must use byteLength to advance to the next one in the array -- there is no outer length field to skip by instead. */
122
122
  function readLvl(bytes, offset) {
123
123
  if (offset + LVLF_SIZE > bytes.length) throw new require_errors.DocFormatError(`PlfLst's own appended LVL array runs past the end of its ${bytes.length}-byte buffer at offset ${offset}, ${LVLF_SIZE} bytes short of one LVLF`);
124
124
  const iStartAt = require_bytes.readInt32LE(bytes, offset);
@@ -142,11 +142,11 @@ function readLvl(bytes, offset) {
142
142
  byteLength: LVLF_SIZE + cbGrpprlPapx + cbGrpprlChpx + xstByteLength
143
143
  };
144
144
  }
145
- /** PlfLst ([MS-DOC] 2.9.226): cLst(2 bytes, signed) then that many 28-byte LSTF entries -- followed IMMEDIATELY by the appended LVL array FibRgFcLcb97's own fcPlfLst field describes, which lcbPlfLst does not account for and which this function therefore reads past the declared PlfLst length to reach. */
145
+ /** PlfLst ([MS-DOC] 2.9.201): cLst(2 bytes, signed) then that many 28-byte LSTF entries -- followed IMMEDIATELY by the appended LVL array FibRgFcLcb97's own fcPlfLst field describes, which lcbPlfLst does not account for and which this function therefore reads past the declared PlfLst length to reach. */
146
146
  function parsePlfLst(table, fc, lcb) {
147
147
  const plfLst = require_bytes.slice(table, fc, lcb, "PlfLst");
148
148
  const cLst = require_bytes.readInt16LE(plfLst, 0);
149
- if (cLst < 0) throw new require_errors.DocFormatError(`PlfLst.cLst is ${cLst}, a negative LSTF count [MS-DOC] 2.9.226 never permits`);
149
+ if (cLst < 0) throw new require_errors.DocFormatError(`PlfLst.cLst is ${cLst}, a negative LSTF count [MS-DOC] 2.9.201 never permits`);
150
150
  const lstfs = [];
151
151
  for (let index = 0; index < cLst; index += 1) lstfs.push(readLstf(plfLst, 2 + index * LSTF_SIZE));
152
152
  let cursor = fc + lcb;
@@ -166,11 +166,11 @@ function parsePlfLst(table, fc, lcb) {
166
166
  levelsByLstf
167
167
  };
168
168
  }
169
- /** PlfLfo ([MS-DOC] 2.9.225): lfoMac(4 bytes) then that many 16-byte LFO entries (rgLfo), then rgLfoData -- this reader's own scope stops at rgLfo, since resolving ilfo to a list needs only each LFO's own lsid (rgLfoData carries LFOLVL overrides this reader deliberately does not apply; see this module's own top comment). rgLfo sits entirely before rgLfoData in the stream, so not reading rgLfoData at all is a real, not merely partial, saving -- no cursor needs to walk past it. */
169
+ /** PlfLfo ([MS-DOC] 2.9.200): lfoMac(4 bytes) then that many 16-byte LFO entries (rgLfo), then rgLfoData -- this reader's own scope stops at rgLfo, since resolving ilfo to a list needs only each LFO's own lsid (rgLfoData carries LFOLVL overrides this reader deliberately does not apply; see this module's own top comment). rgLfo sits entirely before rgLfoData in the stream, so not reading rgLfoData at all is a real, not merely partial, saving -- no cursor needs to walk past it. */
170
170
  function parseLfoLsids(table, fc, lcb) {
171
171
  const plfLfo = require_bytes.slice(table, fc, lcb, "PlfLfo");
172
172
  const lfoMac = require_bytes.readInt32LE(plfLfo, 0);
173
- if (lfoMac < 0) throw new require_errors.DocFormatError(`PlfLfo.lfoMac is ${lfoMac}, a negative LFO count [MS-DOC] 2.9.225 never permits`);
173
+ if (lfoMac < 0) throw new require_errors.DocFormatError(`PlfLfo.lfoMac is ${lfoMac}, a negative LFO count [MS-DOC] 2.9.200 never permits`);
174
174
  const lsids = [];
175
175
  for (let index = 0; index < lfoMac; index += 1) {
176
176
  const offset = 4 + index * LFO_SIZE;
@@ -203,4 +203,5 @@ function readNumberingDefinitions(table, fib) {
203
203
  return definitions;
204
204
  }
205
205
  //#endregion
206
+ exports.NUMBER_FORMAT_BY_NFC = NUMBER_FORMAT_BY_NFC;
206
207
  exports.readNumberingDefinitions = readNumberingDefinitions;
@@ -1,2 +1,2 @@
1
- import { i as readNumberingDefinitions, n as NumberingDefinitions, r as NumberingLevel, t as NumberingDefinition } from "../numbering-Cir-uGdc.cjs";
2
- export { NumberingDefinition, NumberingDefinitions, NumberingLevel, readNumberingDefinitions };
1
+ import { a as readNumberingDefinitions, i as NumberingLevel, n as NumberingDefinition, r as NumberingDefinitions, t as NUMBER_FORMAT_BY_NFC } from "../numbering-Bivayss4.cjs";
2
+ export { NUMBER_FORMAT_BY_NFC, NumberingDefinition, NumberingDefinitions, NumberingLevel, readNumberingDefinitions };
@@ -1,2 +1,2 @@
1
- import { i as readNumberingDefinitions, n as NumberingDefinitions, r as NumberingLevel, t as NumberingDefinition } from "../numbering-DF1z1PyG.js";
2
- export { NumberingDefinition, NumberingDefinitions, NumberingLevel, readNumberingDefinitions };
1
+ import { a as readNumberingDefinitions, i as NumberingLevel, n as NumberingDefinition, r as NumberingDefinitions, t as NUMBER_FORMAT_BY_NFC } from "../numbering-Co4jssbG.js";
2
+ export { NUMBER_FORMAT_BY_NFC, NumberingDefinition, NumberingDefinitions, NumberingLevel, readNumberingDefinitions };
@@ -4,7 +4,7 @@ import { readInt16LE, readInt32LE, readUint16LE, readUint8, slice } from "../byt
4
4
  const LSTF_SIZE = 28;
5
5
  const LVLF_SIZE = 28;
6
6
  const LFO_SIZE = 16;
7
- /** LSTF's own flags byte ([MS-DOC] 2.9.191), bit 0: "this LSTF represents a simple (one-level) list that has one corresponding LVL. Otherwise... a multi-level list that has nine corresponding LVLs." */
7
+ /** LSTF's own flags byte ([MS-DOC] 2.9.147), bit 0: "this LSTF represents a simple (one-level) list that has one corresponding LVL. Otherwise... a multi-level list that has nine corresponding LVLs." */
8
8
  const LSTF_FLAG_SIMPLE_LIST = 1;
9
9
  /** MSONFC ([MS-OSHARED] 2.2.1.3), mapped to its own documented ST_NumberFormat equivalent -- the identical vocabulary ooxml.js's NumberingLevel.format carries verbatim from word/numbering.xml's own w:numFmt/@w:val. Every member through msonfcUCRus (0x3B) is a real numbered/lettered/ideograph format; 0x17 (msonfcBullet) is handled separately below since PlfLfo also treats it as the "no number sequence, but has bullets" case LVLF's own field text calls out by name. */
10
10
  const NUMBER_FORMAT_BY_NFC = {
@@ -77,14 +77,14 @@ function numberFormatFor(nfc) {
77
77
  if (format === void 0) throw new DocFormatError(`LVLF.nfc is 0x${nfc.toString(16).padStart(2, "0")}, not a recognised MSONFC value ([MS-OSHARED] 2.2.1.3)`);
78
78
  return format;
79
79
  }
80
- /** LSTF ([MS-DOC] 2.9.191): lsid(4) + tplc(4, ignored -- UI-only) + rgistdPara(18, ignored -- this reader has no per-level style cascade to link into) + a flags byte (only fSimpleList, bit 0, acted on) + grfhic(1, ignored -- HTML-export-only incompatibility flags). Fixed 28 bytes. */
80
+ /** LSTF ([MS-DOC] 2.9.147): lsid(4) + tplc(4, ignored -- UI-only) + rgistdPara(18, ignored -- this reader has no per-level style cascade to link into) + a flags byte (only fSimpleList, bit 0, acted on) + grfhic(1, ignored -- HTML-export-only incompatibility flags). Fixed 28 bytes. */
81
81
  function readLstf(bytes, offset) {
82
82
  return {
83
83
  lsid: readInt32LE(bytes, offset),
84
84
  fSimpleList: (readUint8(bytes, offset + 26) & LSTF_FLAG_SIMPLE_LIST) !== 0
85
85
  };
86
86
  }
87
- /** Xst ([MS-DOC] 2.9.343): cch(2 bytes) then that many raw 16-bit code units, prefixed-length and not null-terminated. Decoded as a plain UTF-16 string -- readLevelText below re-inspects specific character positions afterward for placeholders, which round-trips exactly through String.fromCharCode/charCodeAt since every placeholder value (0-8) sits well within one UTF-16 code unit and never needs a surrogate pair. Returns the decoded text and the byte length consumed, since the caller must advance past it to reach grpprlPapx/grpprlChpx or the next LVL. */
87
+ /** Xst ([MS-DOC] 2.9.353): cch(2 bytes) then that many raw 16-bit code units, prefixed-length and not null-terminated. Decoded as a plain UTF-16 string -- readLevelText below re-inspects specific character positions afterward for placeholders, which round-trips exactly through String.fromCharCode/charCodeAt since every placeholder value (0-8) sits well within one UTF-16 code unit and never needs a surrogate pair. Returns the decoded text and the byte length consumed, since the caller must advance past it to reach grpprlPapx/grpprlChpx or the next LVL. */
88
88
  function readXst(bytes, offset) {
89
89
  const cch = readUint16LE(bytes, offset);
90
90
  let text = "";
@@ -94,7 +94,7 @@ function readXst(bytes, offset) {
94
94
  byteLength: 2 + cch * 2
95
95
  };
96
96
  }
97
- /** rgbxchNums ([MS-DOC] 2.9.148's own LVLF field): nine 8-bit one-based character offsets into the LVL's own xst.rgtchar, zero-terminated (a 0 entry, or the end of the fixed 9-byte array, ends the list). Each offset it names is a POSITION in the string, not a value -- readLevelText is what turns a position into the placeholder it names. */
97
+ /** rgbxchNums ([MS-DOC] 2.9.150's own LVLF field): nine 8-bit one-based character offsets into the LVL's own xst.rgtchar, zero-terminated (a 0 entry, or the end of the fixed 9-byte array, ends the list). Each offset it names is a POSITION in the string, not a value -- readLevelText is what turns a position into the placeholder it names. */
98
98
  function readRgbxchNums(bytes, offset) {
99
99
  const positions = [];
100
100
  for (let index = 0; index < 9; index += 1) {
@@ -104,7 +104,7 @@ function readRgbxchNums(bytes, offset) {
104
104
  }
105
105
  return positions;
106
106
  }
107
- /** Turns an Xst's own decoded text plus its rgbxchNums positions into the '%1.'-style placeholder text NumberingLevel.text states -- the mirror of readXst/readRgbxchNums together. [MS-DOC]'s own Xst field text: "Each placeholder is an unsigned 2-byte integer that specifies the zero-based level that the placeholder is for" -- so the character AT a named position is not a literal code point at all, but a raw level index (0-8) String.fromCharCode/charCodeAt round-trips losslessly; every other position is decoded as ordinary text. A one-based placeholder ('%1' for level 0) matches ooxml.js's own w:lvlText convention, so a consumer already resolving '%1.'/'%2)' style docx templates resolves this reader's templates identically. */
107
+ /** Turns an Xst's own decoded text plus its rgbxchNums positions into the '%1.'-style placeholder text NumberingLevel.text states -- the mirror of readXst/readRgbxchNums together. [MS-DOC] 2.9.149's own LVL field text (not Xst's -- Xst is a generic length-prefixed string used all over the format for unrelated fields too): "Each placeholder is an unsigned 2-byte integer that specifies the zero-based level that the placeholder is for" -- so the character AT a named position is not a literal code point at all, but a raw level index (0-8) String.fromCharCode/charCodeAt round-trips losslessly; every other position is decoded as ordinary text. A one-based placeholder ('%1' for level 0) matches ooxml.js's own w:lvlText convention, so a consumer already resolving '%1.'/'%2)' style docx templates resolves this reader's templates identically. */
108
108
  function readLevelText(xstText, placeholderPositions) {
109
109
  const placeholders = new Set(placeholderPositions);
110
110
  let result = "";
@@ -117,7 +117,7 @@ function readLevelText(xstText, placeholderPositions) {
117
117
  }
118
118
  return result;
119
119
  }
120
- /** LVL ([MS-DOC] 2.9.196): a 28-byte LVLF, then grpprlPapx (cbGrpprlPapx bytes, skipped -- see this module's own top comment), grpprlChpx (cbGrpprlChpx bytes, skipped), then the level's own Xst. Every LVL is variable-length, so the caller must use byteLength to advance to the next one in the array -- there is no outer length field to skip by instead. */
120
+ /** LVL ([MS-DOC] 2.9.149): a 28-byte LVLF, then grpprlPapx (cbGrpprlPapx bytes, skipped -- see this module's own top comment), grpprlChpx (cbGrpprlChpx bytes, skipped), then the level's own Xst. Every LVL is variable-length, so the caller must use byteLength to advance to the next one in the array -- there is no outer length field to skip by instead. */
121
121
  function readLvl(bytes, offset) {
122
122
  if (offset + LVLF_SIZE > bytes.length) throw new DocFormatError(`PlfLst's own appended LVL array runs past the end of its ${bytes.length}-byte buffer at offset ${offset}, ${LVLF_SIZE} bytes short of one LVLF`);
123
123
  const iStartAt = readInt32LE(bytes, offset);
@@ -141,11 +141,11 @@ function readLvl(bytes, offset) {
141
141
  byteLength: LVLF_SIZE + cbGrpprlPapx + cbGrpprlChpx + xstByteLength
142
142
  };
143
143
  }
144
- /** PlfLst ([MS-DOC] 2.9.226): cLst(2 bytes, signed) then that many 28-byte LSTF entries -- followed IMMEDIATELY by the appended LVL array FibRgFcLcb97's own fcPlfLst field describes, which lcbPlfLst does not account for and which this function therefore reads past the declared PlfLst length to reach. */
144
+ /** PlfLst ([MS-DOC] 2.9.201): cLst(2 bytes, signed) then that many 28-byte LSTF entries -- followed IMMEDIATELY by the appended LVL array FibRgFcLcb97's own fcPlfLst field describes, which lcbPlfLst does not account for and which this function therefore reads past the declared PlfLst length to reach. */
145
145
  function parsePlfLst(table, fc, lcb) {
146
146
  const plfLst = slice(table, fc, lcb, "PlfLst");
147
147
  const cLst = readInt16LE(plfLst, 0);
148
- if (cLst < 0) throw new DocFormatError(`PlfLst.cLst is ${cLst}, a negative LSTF count [MS-DOC] 2.9.226 never permits`);
148
+ if (cLst < 0) throw new DocFormatError(`PlfLst.cLst is ${cLst}, a negative LSTF count [MS-DOC] 2.9.201 never permits`);
149
149
  const lstfs = [];
150
150
  for (let index = 0; index < cLst; index += 1) lstfs.push(readLstf(plfLst, 2 + index * LSTF_SIZE));
151
151
  let cursor = fc + lcb;
@@ -165,11 +165,11 @@ function parsePlfLst(table, fc, lcb) {
165
165
  levelsByLstf
166
166
  };
167
167
  }
168
- /** PlfLfo ([MS-DOC] 2.9.225): lfoMac(4 bytes) then that many 16-byte LFO entries (rgLfo), then rgLfoData -- this reader's own scope stops at rgLfo, since resolving ilfo to a list needs only each LFO's own lsid (rgLfoData carries LFOLVL overrides this reader deliberately does not apply; see this module's own top comment). rgLfo sits entirely before rgLfoData in the stream, so not reading rgLfoData at all is a real, not merely partial, saving -- no cursor needs to walk past it. */
168
+ /** PlfLfo ([MS-DOC] 2.9.200): lfoMac(4 bytes) then that many 16-byte LFO entries (rgLfo), then rgLfoData -- this reader's own scope stops at rgLfo, since resolving ilfo to a list needs only each LFO's own lsid (rgLfoData carries LFOLVL overrides this reader deliberately does not apply; see this module's own top comment). rgLfo sits entirely before rgLfoData in the stream, so not reading rgLfoData at all is a real, not merely partial, saving -- no cursor needs to walk past it. */
169
169
  function parseLfoLsids(table, fc, lcb) {
170
170
  const plfLfo = slice(table, fc, lcb, "PlfLfo");
171
171
  const lfoMac = readInt32LE(plfLfo, 0);
172
- if (lfoMac < 0) throw new DocFormatError(`PlfLfo.lfoMac is ${lfoMac}, a negative LFO count [MS-DOC] 2.9.225 never permits`);
172
+ if (lfoMac < 0) throw new DocFormatError(`PlfLfo.lfoMac is ${lfoMac}, a negative LFO count [MS-DOC] 2.9.200 never permits`);
173
173
  const lsids = [];
174
174
  for (let index = 0; index < lfoMac; index += 1) {
175
175
  const offset = 4 + index * LFO_SIZE;
@@ -202,4 +202,4 @@ function readNumberingDefinitions(table, fib) {
202
202
  return definitions;
203
203
  }
204
204
  //#endregion
205
- export { readNumberingDefinitions };
205
+ export { NUMBER_FORMAT_BY_NFC, readNumberingDefinitions };
@@ -1,13 +1,15 @@
1
1
  import { t as Fib } from "./fib-CtsLtF96.cjs";
2
2
  //#region src/list/numbering.d.ts
3
+ /** MSONFC ([MS-OSHARED] 2.2.1.3), mapped to its own documented ST_NumberFormat equivalent -- the identical vocabulary ooxml.js's NumberingLevel.format carries verbatim from word/numbering.xml's own w:numFmt/@w:val. Every member through msonfcUCRus (0x3B) is a real numbered/lettered/ideograph format; 0x17 (msonfcBullet) is handled separately below since PlfLfo also treats it as the "no number sequence, but has bullets" case LVLF's own field text calls out by name. */
4
+ declare const NUMBER_FORMAT_BY_NFC: Readonly<Record<number, string>>;
3
5
  interface NumberingLevel {
4
- /** The ST_NumberFormat-equivalent string MSONFC's own value maps to ("decimal", "upperRoman", "bullet", ...), or "none" for a level with no number sequence at all ([MS-DOC] 2.9.148's own nfc field text: "If this is equal to 0xFF..., this level does not have a number sequence"). */
6
+ /** The ST_NumberFormat-equivalent string MSONFC's own value maps to ("decimal", "upperRoman", "bullet", ...), or "none" for a level with no number sequence at all ([MS-DOC] 2.9.150's own nfc field text: "If this is equal to 0xFF..., this level does not have a number sequence"). */
5
7
  readonly format: string;
6
8
  /** The level's own text template: a placeholder pattern like '%1.' or '%2)' for a numbered format (the digit names which zero-based level's own counter substitutes at that position, one-based in the placeholder itself) -- the identical convention ooxml.js's own NumberingLevel.text carries verbatim from w:lvlText/@w:val -- or a literal bullet glyph string for format 'bullet'. Decoded from the level's own Xst (a raw UTF-16 string) plus its rgbxchNums array, which names which character POSITIONS in that string are placeholders rather than literal text -- see readLevelText below. */
7
9
  readonly text: string;
8
10
  /** iStartAt: the value this level's counter begins from. Meaningless (and not read as anything but 1) for a level with no number sequence. */
9
11
  readonly startAt: number;
10
- /** ilvlRestartLim ([MS-DOC] 2.9.148), only when fNoRestart is set: the first (most-significant) zero-based level after which this level's own number sequence does NOT restart. Absent (undefined) is the spec's own default behaviour -- "restarts when a more significant level is encountered" -- not "never restarts". */
12
+ /** ilvlRestartLim ([MS-DOC] 2.9.150), only when fNoRestart is set: the first (most-significant) zero-based level after which this level's own number sequence does NOT restart. Absent (undefined) is the spec's own default behaviour -- "restarts when a more significant level is encountered" -- not "never restarts". */
11
13
  readonly restart?: number;
12
14
  }
13
15
  interface NumberingDefinition {
@@ -19,4 +21,4 @@ type NumberingDefinitions = Readonly<Record<string, NumberingDefinition>>;
19
21
  /** Resolves PlfLst and PlfLfo into NumberingDefinitions, keyed by the one-based ilfo every listId already is (prop/pap.ts's own Math.abs(ilfo)) -- absent entirely when the file carries neither (fcPlfLst/fcPlfLfo both 0, a document with no lists at all, the common case this reader must not fail on). */
20
22
  declare function readNumberingDefinitions(table: Uint8Array, fib: Fib): NumberingDefinitions;
21
23
  //#endregion
22
- export { readNumberingDefinitions as i, NumberingDefinitions as n, NumberingLevel as r, NumberingDefinition as t };
24
+ export { readNumberingDefinitions as a, NumberingLevel as i, NumberingDefinition as n, NumberingDefinitions as r, NUMBER_FORMAT_BY_NFC as t };
@@ -1,13 +1,15 @@
1
1
  import { t as Fib } from "./fib-CtsLtF96.js";
2
2
  //#region src/list/numbering.d.ts
3
+ /** MSONFC ([MS-OSHARED] 2.2.1.3), mapped to its own documented ST_NumberFormat equivalent -- the identical vocabulary ooxml.js's NumberingLevel.format carries verbatim from word/numbering.xml's own w:numFmt/@w:val. Every member through msonfcUCRus (0x3B) is a real numbered/lettered/ideograph format; 0x17 (msonfcBullet) is handled separately below since PlfLfo also treats it as the "no number sequence, but has bullets" case LVLF's own field text calls out by name. */
4
+ declare const NUMBER_FORMAT_BY_NFC: Readonly<Record<number, string>>;
3
5
  interface NumberingLevel {
4
- /** The ST_NumberFormat-equivalent string MSONFC's own value maps to ("decimal", "upperRoman", "bullet", ...), or "none" for a level with no number sequence at all ([MS-DOC] 2.9.148's own nfc field text: "If this is equal to 0xFF..., this level does not have a number sequence"). */
6
+ /** The ST_NumberFormat-equivalent string MSONFC's own value maps to ("decimal", "upperRoman", "bullet", ...), or "none" for a level with no number sequence at all ([MS-DOC] 2.9.150's own nfc field text: "If this is equal to 0xFF..., this level does not have a number sequence"). */
5
7
  readonly format: string;
6
8
  /** The level's own text template: a placeholder pattern like '%1.' or '%2)' for a numbered format (the digit names which zero-based level's own counter substitutes at that position, one-based in the placeholder itself) -- the identical convention ooxml.js's own NumberingLevel.text carries verbatim from w:lvlText/@w:val -- or a literal bullet glyph string for format 'bullet'. Decoded from the level's own Xst (a raw UTF-16 string) plus its rgbxchNums array, which names which character POSITIONS in that string are placeholders rather than literal text -- see readLevelText below. */
7
9
  readonly text: string;
8
10
  /** iStartAt: the value this level's counter begins from. Meaningless (and not read as anything but 1) for a level with no number sequence. */
9
11
  readonly startAt: number;
10
- /** ilvlRestartLim ([MS-DOC] 2.9.148), only when fNoRestart is set: the first (most-significant) zero-based level after which this level's own number sequence does NOT restart. Absent (undefined) is the spec's own default behaviour -- "restarts when a more significant level is encountered" -- not "never restarts". */
12
+ /** ilvlRestartLim ([MS-DOC] 2.9.150), only when fNoRestart is set: the first (most-significant) zero-based level after which this level's own number sequence does NOT restart. Absent (undefined) is the spec's own default behaviour -- "restarts when a more significant level is encountered" -- not "never restarts". */
11
13
  readonly restart?: number;
12
14
  }
13
15
  interface NumberingDefinition {
@@ -19,4 +21,4 @@ type NumberingDefinitions = Readonly<Record<string, NumberingDefinition>>;
19
21
  /** Resolves PlfLst and PlfLfo into NumberingDefinitions, keyed by the one-based ilfo every listId already is (prop/pap.ts's own Math.abs(ilfo)) -- absent entirely when the file carries neither (fcPlfLst/fcPlfLfo both 0, a document with no lists at all, the common case this reader must not fail on). */
20
22
  declare function readNumberingDefinitions(table: Uint8Array, fib: Fib): NumberingDefinitions;
21
23
  //#endregion
22
- export { readNumberingDefinitions as i, NumberingDefinitions as n, NumberingLevel as r, NumberingDefinition as t };
24
+ export { readNumberingDefinitions as a, NumberingLevel as i, NumberingDefinition as n, NumberingDefinitions as r, NUMBER_FORMAT_BY_NFC as t };
@@ -1,4 +1,4 @@
1
- import { t as Prl } from "./sprm-Djg5RNiq.cjs";
1
+ import { t as Prl } from "./sprm-DEyvdOo0.cjs";
2
2
  import { Alignment } from "document-schema.js";
3
3
  //#region src/prop/pap.d.ts
4
4
  interface ParagraphProperties {
@@ -1,4 +1,4 @@
1
- import { t as Prl } from "./sprm-Djg5RNiq.js";
1
+ import { t as Prl } from "./sprm-DEyvdOo0.js";
2
2
  import { Alignment } from "document-schema.js";
3
3
  //#region src/prop/pap.d.ts
4
4
  interface ParagraphProperties {
@@ -14,7 +14,7 @@ const KUL_SINGLE = 1;
14
14
  const SPRM_C_HPS = 19011;
15
15
  /** sprmCCv: a 4-byte COLORREF (r, g, b, fAuto). fAuto 0x00 means "use these components", the only form this writer emits. */
16
16
  const SPRM_C_CV = 26736;
17
- /** sprmCRgFtc0: a 2-byte signed index into the font table, [MS-DOC] 2.6.2 -- see style/fonts.ts. */
17
+ /** sprmCRgFtc0: a 2-byte signed index into the font table, [MS-DOC] 2.6.1 -- see style/fonts.ts. */
18
18
  const SPRM_C_RG_FTC_0 = 19023;
19
19
  const HALF_POINTS_PER_POINT = 2;
20
20
  /** sprmCHps's own operand range: an unsigned 2-byte half-point value. */
@@ -13,7 +13,7 @@ const KUL_SINGLE = 1;
13
13
  const SPRM_C_HPS = 19011;
14
14
  /** sprmCCv: a 4-byte COLORREF (r, g, b, fAuto). fAuto 0x00 means "use these components", the only form this writer emits. */
15
15
  const SPRM_C_CV = 26736;
16
- /** sprmCRgFtc0: a 2-byte signed index into the font table, [MS-DOC] 2.6.2 -- see style/fonts.ts. */
16
+ /** sprmCRgFtc0: a 2-byte signed index into the font table, [MS-DOC] 2.6.1 -- see style/fonts.ts. */
17
17
  const SPRM_C_RG_FTC_0 = 19023;
18
18
  const HALF_POINTS_PER_POINT = 2;
19
19
  /** sprmCHps's own operand range: an unsigned 2-byte half-point value. */
@@ -1,4 +1,4 @@
1
- import { t as Prl } from "../sprm-Djg5RNiq.cjs";
1
+ import { t as Prl } from "../sprm-DEyvdOo0.cjs";
2
2
  import { Color } from "document-schema.js";
3
3
  //#region src/prop/chp.d.ts
4
4
  interface CharacterProperties {
@@ -1,4 +1,4 @@
1
- import { t as Prl } from "../sprm-Djg5RNiq.js";
1
+ import { t as Prl } from "../sprm-DEyvdOo0.js";
2
2
  import { Color } from "document-schema.js";
3
3
  //#region src/prop/chp.d.ts
4
4
  interface CharacterProperties {
@@ -3,9 +3,10 @@ const require_errors = require("../errors.cjs");
3
3
  //#region src/prop/pap-write.ts
4
4
  /** sprmPJc: a 1-byte logical justification. */
5
5
  const SPRM_P_JC = 9313;
6
- /** sprmPDxaLeft / sprmPDxaLeft1: 2-byte signed twips. There is no writer-side counterpart for sprmPDxaRight (indent from the right margin): pap.ts's own reader folds it into a ParagraphProperties.indentRightPt field, but ContentParagraphSchema (document-schema.js) carries no such field for any writer to round-trip -- the right-indent value the reader computes is simply not part of the shared schema's paragraph vocabulary. */
6
+ /** sprmPDxaLeft / sprmPDxaLeft1 / sprmPDxaRight: 2-byte signed twips. */
7
7
  const SPRM_P_DXA_LEFT = 33886;
8
8
  const SPRM_P_DXA_LEFT1 = 33888;
9
+ const SPRM_P_DXA_RIGHT = 33885;
9
10
  /** sprmPDyaBefore / sprmPDyaAfter: 2-byte unsigned twips. */
10
11
  const SPRM_P_DYA_BEFORE = 42003;
11
12
  const SPRM_P_DYA_AFTER = 42004;
@@ -13,6 +14,12 @@ const SPRM_P_DYA_AFTER = 42004;
13
14
  const SPRM_P_DYA_LINE = 25618;
14
15
  /** sprmPFPageBreakBefore: a 1-byte Bool8. */
15
16
  const SPRM_P_F_PAGE_BREAK_BEFORE = 9223;
17
+ /** sprmPIlfo: a 2-byte signed one-based index into PlfLfo.rgLfo -- which list membership names. */
18
+ const SPRM_P_ILFO = 17931;
19
+ /** sprmPIlvl: a 1-byte zero-based list level. */
20
+ const SPRM_P_ILVL = 9738;
21
+ /** sprmPIlvl's own 0..8 range: a non-simple list's LSTF always carries exactly nine LVLs ([MS-DOC] 2.9.148), so a level outside it names a depth this format cannot express at all. */
22
+ const MAX_LIST_LEVEL = 8;
16
23
  const TWIPS_PER_POINT = 20;
17
24
  const LSPD_MULTIPLE_DIVISOR = 240;
18
25
  const LSPD_MAX_MULTIPLE_DYA_LINE = 31680;
@@ -44,10 +51,11 @@ function uint16(value, what) {
44
51
  function pointsToTwips(pt) {
45
52
  return pt * TWIPS_PER_POINT;
46
53
  }
47
- function encodeParagraphGrpprl(paragraph) {
54
+ function encodeParagraphGrpprl(paragraph, ilfoOf) {
48
55
  const bytes = [];
49
56
  if (paragraph.alignment !== void 0) pushSprm(bytes, SPRM_P_JC, [JC_VALUE[paragraph.alignment]]);
50
57
  if (paragraph.indentLeftPt !== void 0) pushSprm(bytes, SPRM_P_DXA_LEFT, int16(pointsToTwips(paragraph.indentLeftPt), "paragraph indentLeftPt"));
58
+ if (paragraph.indentRightPt !== void 0) pushSprm(bytes, SPRM_P_DXA_RIGHT, int16(pointsToTwips(paragraph.indentRightPt), "paragraph indentRightPt"));
51
59
  if (paragraph.indentFirstLinePt !== void 0) pushSprm(bytes, SPRM_P_DXA_LEFT1, int16(pointsToTwips(paragraph.indentFirstLinePt), "paragraph indentFirstLinePt"));
52
60
  if (paragraph.spacingBeforePt !== void 0) pushSprm(bytes, SPRM_P_DYA_BEFORE, uint16(pointsToTwips(paragraph.spacingBeforePt), "paragraph spacingBeforePt"));
53
61
  if (paragraph.spacingAfterPt !== void 0) pushSprm(bytes, SPRM_P_DYA_AFTER, uint16(pointsToTwips(paragraph.spacingAfterPt), "paragraph spacingAfterPt"));
@@ -61,6 +69,11 @@ function encodeParagraphGrpprl(paragraph) {
61
69
  ]);
62
70
  }
63
71
  if (paragraph.pageBreakBefore === true) pushSprm(bytes, SPRM_P_F_PAGE_BREAK_BEFORE, [1]);
72
+ if (paragraph.list?.numId !== void 0) {
73
+ if (paragraph.list.level > MAX_LIST_LEVEL) throw new require_errors.DocFormatError(`paragraph list level ${paragraph.list.level} is outside the 0..${MAX_LIST_LEVEL} range a non-simple LSTF's fixed nine LVLs can address`);
74
+ pushSprm(bytes, SPRM_P_ILFO, int16(ilfoOf(paragraph.list.numId), "paragraph list ilfo"));
75
+ pushSprm(bytes, SPRM_P_ILVL, [paragraph.list.level]);
76
+ }
64
77
  return bytes;
65
78
  }
66
79
  //#endregion
@@ -1,5 +1,5 @@
1
1
  import { ContentParagraph } from "document-schema.js";
2
2
  //#region src/prop/pap-write.d.ts
3
- declare function encodeParagraphGrpprl(paragraph: Pick<ContentParagraph, "alignment" | "indentLeftPt" | "indentFirstLinePt" | "spacingBeforePt" | "spacingAfterPt" | "lineSpacing" | "pageBreakBefore">): number[];
3
+ declare function encodeParagraphGrpprl(paragraph: Pick<ContentParagraph, "alignment" | "indentLeftPt" | "indentRightPt" | "indentFirstLinePt" | "spacingBeforePt" | "spacingAfterPt" | "lineSpacing" | "pageBreakBefore" | "list">, ilfoOf: (numId: string) => number): number[];
4
4
  //#endregion
5
5
  export { encodeParagraphGrpprl };
@@ -1,5 +1,5 @@
1
1
  import { ContentParagraph } from "document-schema.js";
2
2
  //#region src/prop/pap-write.d.ts
3
- declare function encodeParagraphGrpprl(paragraph: Pick<ContentParagraph, "alignment" | "indentLeftPt" | "indentFirstLinePt" | "spacingBeforePt" | "spacingAfterPt" | "lineSpacing" | "pageBreakBefore">): number[];
3
+ declare function encodeParagraphGrpprl(paragraph: Pick<ContentParagraph, "alignment" | "indentLeftPt" | "indentRightPt" | "indentFirstLinePt" | "spacingBeforePt" | "spacingAfterPt" | "lineSpacing" | "pageBreakBefore" | "list">, ilfoOf: (numId: string) => number): number[];
4
4
  //#endregion
5
5
  export { encodeParagraphGrpprl };
@@ -2,9 +2,10 @@ import { DocFormatError } from "../errors.js";
2
2
  //#region src/prop/pap-write.ts
3
3
  /** sprmPJc: a 1-byte logical justification. */
4
4
  const SPRM_P_JC = 9313;
5
- /** sprmPDxaLeft / sprmPDxaLeft1: 2-byte signed twips. There is no writer-side counterpart for sprmPDxaRight (indent from the right margin): pap.ts's own reader folds it into a ParagraphProperties.indentRightPt field, but ContentParagraphSchema (document-schema.js) carries no such field for any writer to round-trip -- the right-indent value the reader computes is simply not part of the shared schema's paragraph vocabulary. */
5
+ /** sprmPDxaLeft / sprmPDxaLeft1 / sprmPDxaRight: 2-byte signed twips. */
6
6
  const SPRM_P_DXA_LEFT = 33886;
7
7
  const SPRM_P_DXA_LEFT1 = 33888;
8
+ const SPRM_P_DXA_RIGHT = 33885;
8
9
  /** sprmPDyaBefore / sprmPDyaAfter: 2-byte unsigned twips. */
9
10
  const SPRM_P_DYA_BEFORE = 42003;
10
11
  const SPRM_P_DYA_AFTER = 42004;
@@ -12,6 +13,12 @@ const SPRM_P_DYA_AFTER = 42004;
12
13
  const SPRM_P_DYA_LINE = 25618;
13
14
  /** sprmPFPageBreakBefore: a 1-byte Bool8. */
14
15
  const SPRM_P_F_PAGE_BREAK_BEFORE = 9223;
16
+ /** sprmPIlfo: a 2-byte signed one-based index into PlfLfo.rgLfo -- which list membership names. */
17
+ const SPRM_P_ILFO = 17931;
18
+ /** sprmPIlvl: a 1-byte zero-based list level. */
19
+ const SPRM_P_ILVL = 9738;
20
+ /** sprmPIlvl's own 0..8 range: a non-simple list's LSTF always carries exactly nine LVLs ([MS-DOC] 2.9.148), so a level outside it names a depth this format cannot express at all. */
21
+ const MAX_LIST_LEVEL = 8;
15
22
  const TWIPS_PER_POINT = 20;
16
23
  const LSPD_MULTIPLE_DIVISOR = 240;
17
24
  const LSPD_MAX_MULTIPLE_DYA_LINE = 31680;
@@ -43,10 +50,11 @@ function uint16(value, what) {
43
50
  function pointsToTwips(pt) {
44
51
  return pt * TWIPS_PER_POINT;
45
52
  }
46
- function encodeParagraphGrpprl(paragraph) {
53
+ function encodeParagraphGrpprl(paragraph, ilfoOf) {
47
54
  const bytes = [];
48
55
  if (paragraph.alignment !== void 0) pushSprm(bytes, SPRM_P_JC, [JC_VALUE[paragraph.alignment]]);
49
56
  if (paragraph.indentLeftPt !== void 0) pushSprm(bytes, SPRM_P_DXA_LEFT, int16(pointsToTwips(paragraph.indentLeftPt), "paragraph indentLeftPt"));
57
+ if (paragraph.indentRightPt !== void 0) pushSprm(bytes, SPRM_P_DXA_RIGHT, int16(pointsToTwips(paragraph.indentRightPt), "paragraph indentRightPt"));
50
58
  if (paragraph.indentFirstLinePt !== void 0) pushSprm(bytes, SPRM_P_DXA_LEFT1, int16(pointsToTwips(paragraph.indentFirstLinePt), "paragraph indentFirstLinePt"));
51
59
  if (paragraph.spacingBeforePt !== void 0) pushSprm(bytes, SPRM_P_DYA_BEFORE, uint16(pointsToTwips(paragraph.spacingBeforePt), "paragraph spacingBeforePt"));
52
60
  if (paragraph.spacingAfterPt !== void 0) pushSprm(bytes, SPRM_P_DYA_AFTER, uint16(pointsToTwips(paragraph.spacingAfterPt), "paragraph spacingAfterPt"));
@@ -60,6 +68,11 @@ function encodeParagraphGrpprl(paragraph) {
60
68
  ]);
61
69
  }
62
70
  if (paragraph.pageBreakBefore === true) pushSprm(bytes, SPRM_P_F_PAGE_BREAK_BEFORE, [1]);
71
+ if (paragraph.list?.numId !== void 0) {
72
+ if (paragraph.list.level > MAX_LIST_LEVEL) throw new DocFormatError(`paragraph list level ${paragraph.list.level} is outside the 0..${MAX_LIST_LEVEL} range a non-simple LSTF's fixed nine LVLs can address`);
73
+ pushSprm(bytes, SPRM_P_ILFO, int16(ilfoOf(paragraph.list.numId), "paragraph list ilfo"));
74
+ pushSprm(bytes, SPRM_P_ILVL, [paragraph.list.level]);
75
+ }
63
76
  return bytes;
64
77
  }
65
78
  //#endregion
@@ -1,2 +1,2 @@
1
- import { n as applyParagraphSprms, t as ParagraphProperties } from "../pap-BmelEYEP.cjs";
1
+ import { n as applyParagraphSprms, t as ParagraphProperties } from "../pap-BT1p0uzu.cjs";
2
2
  export { ParagraphProperties, applyParagraphSprms };
@@ -1,2 +1,2 @@
1
- import { n as applyParagraphSprms, t as ParagraphProperties } from "../pap-BkFo8dZO.js";
1
+ import { n as applyParagraphSprms, t as ParagraphProperties } from "../pap-DOFLMWcG.js";
2
2
  export { ParagraphProperties, applyParagraphSprms };
@@ -1,5 +1,5 @@
1
1
  import { t as Fib } from "../fib-CtsLtF96.cjs";
2
- import { t as Prl } from "../sprm-Djg5RNiq.cjs";
2
+ import { t as Prl } from "../sprm-DEyvdOo0.cjs";
3
3
  //#region src/prop/sep.d.ts
4
4
  interface SectionProperties {
5
5
  pageWidthPt?: number;
@@ -1,5 +1,5 @@
1
1
  import { t as Fib } from "../fib-CtsLtF96.js";
2
- import { t as Prl } from "../sprm-Djg5RNiq.js";
2
+ import { t as Prl } from "../sprm-DEyvdOo0.js";
3
3
  //#region src/prop/sep.d.ts
4
4
  interface SectionProperties {
5
5
  pageWidthPt?: number;