doc-codec 2.5.0 → 2.7.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 +38 -29
- package/dist/base64.cjs +48 -0
- package/dist/base64.d.cts +5 -0
- package/dist/base64.d.ts +5 -0
- package/dist/base64.js +46 -0
- package/dist/data-stream-BLCj4-V1.d.cts +11 -0
- package/dist/data-stream-BLCj4-V1.d.ts +11 -0
- package/dist/data-stream.cjs +25 -0
- package/dist/data-stream.d.cts +2 -0
- package/dist/data-stream.d.ts +2 -0
- package/dist/data-stream.js +24 -0
- package/dist/encryption.cjs +44 -10
- package/dist/encryption.d.cts +2 -2
- package/dist/encryption.d.ts +2 -2
- package/dist/encryption.js +45 -11
- package/dist/index.cjs +5 -0
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/pictures-write.cjs +85 -0
- package/dist/pictures-write.d.cts +12 -0
- package/dist/pictures-write.d.ts +12 -0
- package/dist/pictures-write.js +84 -0
- package/dist/pictures.cjs +3 -16
- package/dist/pictures.js +3 -16
- package/dist/prop/sep-write.cjs +16 -9
- package/dist/prop/sep-write.d.cts +2 -2
- package/dist/prop/sep-write.d.ts +2 -2
- package/dist/prop/sep-write.js +16 -9
- package/dist/read.cjs +1 -2
- package/dist/read.js +2 -3
- package/dist/table/write.cjs +28 -3
- package/dist/table/write.d.cts +2 -2
- package/dist/table/write.d.ts +2 -2
- package/dist/table/write.js +28 -3
- package/dist/{write-SN_aIwyF.d.ts → write-CMB3qF4i.d.cts} +9 -3
- package/dist/{write-SN_aIwyF.d.cts → write-t4rFgnA-.d.ts} +9 -3
- package/dist/write.cjs +65 -17
- package/dist/write.d.cts +1 -1
- package/dist/write.d.ts +1 -1
- package/dist/write.js +66 -18
- package/package.json +2 -2
package/dist/table/write.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_errors = require("../errors.cjs");
|
|
3
|
+
require("../data-stream.cjs");
|
|
3
4
|
require("../text/special.cjs");
|
|
4
5
|
const require_prop_fkp_write = require("../prop/fkp-write.cjs");
|
|
6
|
+
const require_pictures_write = require("../pictures-write.cjs");
|
|
5
7
|
const require_table_tap_write = require("./tap-write.cjs");
|
|
6
8
|
//#region src/table/write.ts
|
|
7
9
|
/** sprmPFInTable (0x2416): a Bool8, "MUST be 1 any time the table depth is greater than zero". */
|
|
@@ -9,6 +11,12 @@ const SPRM_P_F_IN_TABLE = 9238;
|
|
|
9
11
|
/** sprmPFTtp (0x2417): a Bool8 marking a cell mark as the row's own Table Terminating Paragraph mark. */
|
|
10
12
|
const SPRM_P_F_TTP = 9239;
|
|
11
13
|
const TWIPS_PER_POINT = 20;
|
|
14
|
+
function plainRuns(runs) {
|
|
15
|
+
return runs.map((run) => ({
|
|
16
|
+
run,
|
|
17
|
+
extraGrpprl: []
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
12
20
|
function pushSprm(bytes, opcode, operand) {
|
|
13
21
|
bytes.push(opcode & 255, opcode >> 8 & 255, ...operand);
|
|
14
22
|
}
|
|
@@ -33,7 +41,7 @@ function cellParagraphs(blocks) {
|
|
|
33
41
|
return blocks.map((block, index) => {
|
|
34
42
|
if (block.kind !== "paragraph") throw new require_errors.DocUnsupportedError(`doc-codec's writer does not support a '${block.kind}' block inside a table cell (only paragraphs are; nested tables are a separately-tracked gap -- see the README's scope note)`);
|
|
35
43
|
return {
|
|
36
|
-
runs: block.runs,
|
|
44
|
+
runs: plainRuns(block.runs),
|
|
37
45
|
properties: block,
|
|
38
46
|
extraGrpprl: inTableGrpprl(),
|
|
39
47
|
terminator: index === blocks.length - 1 ? 7 : 13
|
|
@@ -189,12 +197,25 @@ function flattenTable(table, blockIndex, onWarning) {
|
|
|
189
197
|
});
|
|
190
198
|
return output;
|
|
191
199
|
}
|
|
192
|
-
function
|
|
200
|
+
function imageParagraph(image, dataStream) {
|
|
201
|
+
const { data, buildGrpprl } = require_pictures_write.buildInlinePicture(image);
|
|
202
|
+
const offset = dataStream.append(data);
|
|
203
|
+
return {
|
|
204
|
+
runs: [{
|
|
205
|
+
run: { text: String.fromCharCode(1) },
|
|
206
|
+
extraGrpprl: buildGrpprl(offset)
|
|
207
|
+
}],
|
|
208
|
+
properties: {},
|
|
209
|
+
extraGrpprl: [],
|
|
210
|
+
terminator: 13
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function flattenSectionBlocks(blocks, dataStream, onWarning) {
|
|
193
214
|
const output = [];
|
|
194
215
|
blocks.forEach((block, blockIndex) => {
|
|
195
216
|
if (block.kind === "paragraph") {
|
|
196
217
|
output.push({
|
|
197
|
-
runs: block.runs,
|
|
218
|
+
runs: plainRuns(block.runs),
|
|
198
219
|
properties: block,
|
|
199
220
|
extraGrpprl: [],
|
|
200
221
|
terminator: 13
|
|
@@ -205,6 +226,10 @@ function flattenSectionBlocks(blocks, onWarning) {
|
|
|
205
226
|
output.push(...flattenTable(block, blockIndex, onWarning));
|
|
206
227
|
return;
|
|
207
228
|
}
|
|
229
|
+
if (block.kind === "image") {
|
|
230
|
+
output.push(imageParagraph(block, dataStream));
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
208
233
|
throw new require_errors.DocUnsupportedError(`doc-codec's writer does not yet support '${block.kind}' blocks (see README's scope note)`);
|
|
209
234
|
});
|
|
210
235
|
return output;
|
package/dist/table/write.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
export { WriteParagraph, WriteWarning, flattenSectionBlocks };
|
|
1
|
+
import { i as flattenSectionBlocks, n as WriteRun, r as WriteWarning, t as WriteParagraph } from "../write-CMB3qF4i.cjs";
|
|
2
|
+
export { WriteParagraph, WriteRun, WriteWarning, flattenSectionBlocks };
|
package/dist/table/write.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
export { WriteParagraph, WriteWarning, flattenSectionBlocks };
|
|
1
|
+
import { i as flattenSectionBlocks, n as WriteRun, r as WriteWarning, t as WriteParagraph } from "../write-t4rFgnA-.js";
|
|
2
|
+
export { WriteParagraph, WriteRun, WriteWarning, flattenSectionBlocks };
|
package/dist/table/write.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { DocFormatError, DocUnsupportedError } from "../errors.js";
|
|
2
|
+
import "../data-stream.js";
|
|
2
3
|
import "../text/special.js";
|
|
3
4
|
import { fitsAloneOnPapxPage } from "../prop/fkp-write.js";
|
|
5
|
+
import { buildInlinePicture } from "../pictures-write.js";
|
|
4
6
|
import { encodeTableRowGrpprl } from "./tap-write.js";
|
|
5
7
|
//#region src/table/write.ts
|
|
6
8
|
/** sprmPFInTable (0x2416): a Bool8, "MUST be 1 any time the table depth is greater than zero". */
|
|
@@ -8,6 +10,12 @@ const SPRM_P_F_IN_TABLE = 9238;
|
|
|
8
10
|
/** sprmPFTtp (0x2417): a Bool8 marking a cell mark as the row's own Table Terminating Paragraph mark. */
|
|
9
11
|
const SPRM_P_F_TTP = 9239;
|
|
10
12
|
const TWIPS_PER_POINT = 20;
|
|
13
|
+
function plainRuns(runs) {
|
|
14
|
+
return runs.map((run) => ({
|
|
15
|
+
run,
|
|
16
|
+
extraGrpprl: []
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
11
19
|
function pushSprm(bytes, opcode, operand) {
|
|
12
20
|
bytes.push(opcode & 255, opcode >> 8 & 255, ...operand);
|
|
13
21
|
}
|
|
@@ -32,7 +40,7 @@ function cellParagraphs(blocks) {
|
|
|
32
40
|
return blocks.map((block, index) => {
|
|
33
41
|
if (block.kind !== "paragraph") throw new DocUnsupportedError(`doc-codec's writer does not support a '${block.kind}' block inside a table cell (only paragraphs are; nested tables are a separately-tracked gap -- see the README's scope note)`);
|
|
34
42
|
return {
|
|
35
|
-
runs: block.runs,
|
|
43
|
+
runs: plainRuns(block.runs),
|
|
36
44
|
properties: block,
|
|
37
45
|
extraGrpprl: inTableGrpprl(),
|
|
38
46
|
terminator: index === blocks.length - 1 ? 7 : 13
|
|
@@ -188,12 +196,25 @@ function flattenTable(table, blockIndex, onWarning) {
|
|
|
188
196
|
});
|
|
189
197
|
return output;
|
|
190
198
|
}
|
|
191
|
-
function
|
|
199
|
+
function imageParagraph(image, dataStream) {
|
|
200
|
+
const { data, buildGrpprl } = buildInlinePicture(image);
|
|
201
|
+
const offset = dataStream.append(data);
|
|
202
|
+
return {
|
|
203
|
+
runs: [{
|
|
204
|
+
run: { text: String.fromCharCode(1) },
|
|
205
|
+
extraGrpprl: buildGrpprl(offset)
|
|
206
|
+
}],
|
|
207
|
+
properties: {},
|
|
208
|
+
extraGrpprl: [],
|
|
209
|
+
terminator: 13
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function flattenSectionBlocks(blocks, dataStream, onWarning) {
|
|
192
213
|
const output = [];
|
|
193
214
|
blocks.forEach((block, blockIndex) => {
|
|
194
215
|
if (block.kind === "paragraph") {
|
|
195
216
|
output.push({
|
|
196
|
-
runs: block.runs,
|
|
217
|
+
runs: plainRuns(block.runs),
|
|
197
218
|
properties: block,
|
|
198
219
|
extraGrpprl: [],
|
|
199
220
|
terminator: 13
|
|
@@ -204,6 +225,10 @@ function flattenSectionBlocks(blocks, onWarning) {
|
|
|
204
225
|
output.push(...flattenTable(block, blockIndex, onWarning));
|
|
205
226
|
return;
|
|
206
227
|
}
|
|
228
|
+
if (block.kind === "image") {
|
|
229
|
+
output.push(imageParagraph(block, dataStream));
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
207
232
|
throw new DocUnsupportedError(`doc-codec's writer does not yet support '${block.kind}' blocks (see README's scope note)`);
|
|
208
233
|
});
|
|
209
234
|
return output;
|
|
@@ -1,15 +1,21 @@
|
|
|
1
|
+
import { t as DataStreamBuilder } from "./data-stream-BLCj4-V1.cjs";
|
|
1
2
|
import { ContentBlock, ContentParagraph, ContentRun } from "document-schema.js";
|
|
2
3
|
//#region src/table/write.d.ts
|
|
3
4
|
/** Reports a non-fatal write-time degradation -- this package's own analogue of byte-codec's/pdf-codec's `onWarning`, adopted here rather than a new shape of its own so a caller already handling one already handles the other. */
|
|
4
5
|
type WriteWarning = (message: string) => void;
|
|
6
|
+
/** One run to write, alongside grpprl bytes appended after encodeCharacterGrpprl's own output for it -- the run-level analogue of WriteParagraph.extraGrpprl below. Every ordinary run carries none (its whole grpprl comes from its own ContentRun fields); imageParagraph's own picture-anchor run is the one exception, since sprmCPicLocation is not a ContentRun field encodeCharacterGrpprl could ever derive on its own. */
|
|
7
|
+
interface WriteRun {
|
|
8
|
+
readonly run: ContentRun;
|
|
9
|
+
readonly extraGrpprl: readonly number[];
|
|
10
|
+
}
|
|
5
11
|
interface WriteParagraph {
|
|
6
|
-
readonly runs: readonly
|
|
12
|
+
readonly runs: readonly WriteRun[];
|
|
7
13
|
readonly properties: Pick<ContentParagraph, "alignment" | "indentLeftPt" | "indentRightPt" | "indentFirstLinePt" | "spacingBeforePt" | "spacingAfterPt" | "lineSpacing" | "pageBreakBefore" | "list" | "styleId" | "headingLevel">;
|
|
8
14
|
/** 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
15
|
readonly extraGrpprl: readonly number[];
|
|
10
16
|
/** The character terminating this paragraph in the text stream: PARAGRAPH_MARK normally, CELL_MARK for a table cell or row mark. */
|
|
11
17
|
readonly terminator: number;
|
|
12
18
|
}
|
|
13
|
-
declare function flattenSectionBlocks(blocks: readonly ContentBlock[], onWarning?: WriteWarning): WriteParagraph[];
|
|
19
|
+
declare function flattenSectionBlocks(blocks: readonly ContentBlock[], dataStream: DataStreamBuilder, onWarning?: WriteWarning): WriteParagraph[];
|
|
14
20
|
//#endregion
|
|
15
|
-
export {
|
|
21
|
+
export { flattenSectionBlocks as i, WriteRun as n, WriteWarning as r, WriteParagraph as t };
|
|
@@ -1,15 +1,21 @@
|
|
|
1
|
+
import { t as DataStreamBuilder } from "./data-stream-BLCj4-V1.js";
|
|
1
2
|
import { ContentBlock, ContentParagraph, ContentRun } from "document-schema.js";
|
|
2
3
|
//#region src/table/write.d.ts
|
|
3
4
|
/** Reports a non-fatal write-time degradation -- this package's own analogue of byte-codec's/pdf-codec's `onWarning`, adopted here rather than a new shape of its own so a caller already handling one already handles the other. */
|
|
4
5
|
type WriteWarning = (message: string) => void;
|
|
6
|
+
/** One run to write, alongside grpprl bytes appended after encodeCharacterGrpprl's own output for it -- the run-level analogue of WriteParagraph.extraGrpprl below. Every ordinary run carries none (its whole grpprl comes from its own ContentRun fields); imageParagraph's own picture-anchor run is the one exception, since sprmCPicLocation is not a ContentRun field encodeCharacterGrpprl could ever derive on its own. */
|
|
7
|
+
interface WriteRun {
|
|
8
|
+
readonly run: ContentRun;
|
|
9
|
+
readonly extraGrpprl: readonly number[];
|
|
10
|
+
}
|
|
5
11
|
interface WriteParagraph {
|
|
6
|
-
readonly runs: readonly
|
|
12
|
+
readonly runs: readonly WriteRun[];
|
|
7
13
|
readonly properties: Pick<ContentParagraph, "alignment" | "indentLeftPt" | "indentRightPt" | "indentFirstLinePt" | "spacingBeforePt" | "spacingAfterPt" | "lineSpacing" | "pageBreakBefore" | "list" | "styleId" | "headingLevel">;
|
|
8
14
|
/** 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
15
|
readonly extraGrpprl: readonly number[];
|
|
10
16
|
/** The character terminating this paragraph in the text stream: PARAGRAPH_MARK normally, CELL_MARK for a table cell or row mark. */
|
|
11
17
|
readonly terminator: number;
|
|
12
18
|
}
|
|
13
|
-
declare function flattenSectionBlocks(blocks: readonly ContentBlock[], onWarning?: WriteWarning): WriteParagraph[];
|
|
19
|
+
declare function flattenSectionBlocks(blocks: readonly ContentBlock[], dataStream: DataStreamBuilder, onWarning?: WriteWarning): WriteParagraph[];
|
|
14
20
|
//#endregion
|
|
15
|
-
export {
|
|
21
|
+
export { flattenSectionBlocks as i, WriteRun as n, WriteWarning as r, WriteParagraph as t };
|
package/dist/write.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_errors = require("./errors.cjs");
|
|
3
|
+
const require_data_stream = require("./data-stream.cjs");
|
|
3
4
|
const require_detect = require("./detect.cjs");
|
|
4
5
|
require("./prop/fkp.cjs");
|
|
5
6
|
const require_style_stsh = require("./style/stsh.cjs");
|
|
@@ -22,16 +23,22 @@ const TEXT_FC = 1024;
|
|
|
22
23
|
const BYTES_PER_CHARACTER = 2;
|
|
23
24
|
function writeDocContent(document, options = {}) {
|
|
24
25
|
if (document.kind !== "wordprocessing") throw new require_errors.DocUnsupportedError(`doc-codec writes wordprocessing documents only; got a '${document.kind}' document`);
|
|
25
|
-
if (document.sections.length
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
properties: {},
|
|
32
|
-
extraGrpprl: [],
|
|
33
|
-
terminator: 13
|
|
26
|
+
if (document.sections.length === 0) throw new require_errors.DocFormatError("a wordprocessing document must carry at least one section");
|
|
27
|
+
const dataStream = new require_data_stream.DataStreamBuilder();
|
|
28
|
+
const sectionParagraphLists = document.sections.map((section, index) => {
|
|
29
|
+
const paragraphs = require_table_write.flattenSectionBlocks(section.blocks, dataStream, options.onWarning);
|
|
30
|
+
closeSection(paragraphs, index === document.sections.length - 1 ? 13 : 12);
|
|
31
|
+
return paragraphs;
|
|
34
32
|
});
|
|
33
|
+
const sectionStartIndices = [];
|
|
34
|
+
{
|
|
35
|
+
let runningIndex = 0;
|
|
36
|
+
for (const paragraphs of sectionParagraphLists) {
|
|
37
|
+
sectionStartIndices.push(runningIndex);
|
|
38
|
+
runningIndex += paragraphs.length;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const writeParagraphs = sectionParagraphLists.flat();
|
|
35
42
|
const FIRST_NON_HEADING_ISTD = 10;
|
|
36
43
|
const MAX_HEADING_ISTD = 9;
|
|
37
44
|
const styleNames = /* @__PURE__ */ new Map();
|
|
@@ -72,9 +79,9 @@ function writeDocContent(document, options = {}) {
|
|
|
72
79
|
};
|
|
73
80
|
const numberingTables = require_list_numbering_write.buildNumberingTables(listUsage.definitions);
|
|
74
81
|
const formatted = writeParagraphs.map((entry) => ({
|
|
75
|
-
runs: entry.runs.map((
|
|
76
|
-
text: run.text,
|
|
77
|
-
grpprl: require_prop_chp_write.encodeCharacterGrpprl(run, fontIndexOf)
|
|
82
|
+
runs: entry.runs.map((writeRun) => ({
|
|
83
|
+
text: writeRun.run.text,
|
|
84
|
+
grpprl: [...require_prop_chp_write.encodeCharacterGrpprl(writeRun.run, fontIndexOf), ...writeRun.extraGrpprl]
|
|
78
85
|
})),
|
|
79
86
|
grpprl: [...require_prop_pap_write.encodeParagraphGrpprl(entry.properties, ilfoOf), ...entry.extraGrpprl]
|
|
80
87
|
}));
|
|
@@ -132,9 +139,20 @@ function writeDocContent(document, options = {}) {
|
|
|
132
139
|
};
|
|
133
140
|
});
|
|
134
141
|
const papxPages = require_prop_fkp_write.buildPapxPages(papxParagraphSpecs, textFcLim);
|
|
135
|
-
const
|
|
136
|
-
const
|
|
137
|
-
const
|
|
142
|
+
const sepxPageStart = (papxPageStart + papxPages.length) * 512;
|
|
143
|
+
const sepxList = document.sections.map((section) => require_prop_sep_write.buildSepx(require_prop_sep_write.encodeSectionGrpprl(section)));
|
|
144
|
+
const fcSepxList = [];
|
|
145
|
+
{
|
|
146
|
+
let sepxCursor = sepxPageStart;
|
|
147
|
+
for (const sepx of sepxList) {
|
|
148
|
+
fcSepxList.push(sepxCursor);
|
|
149
|
+
sepxCursor += sepx.length;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const lastFcSepx = fcSepxList[fcSepxList.length - 1];
|
|
153
|
+
const lastSepx = sepxList[sepxList.length - 1];
|
|
154
|
+
if (lastFcSepx === void 0 || lastSepx === void 0) throw new require_errors.DocFormatError("internal defect: writeDocContent built an empty section list despite the earlier at-least-one-section guard");
|
|
155
|
+
const wordDocument = new Uint8Array(lastFcSepx + lastSepx.length);
|
|
138
156
|
const wordView = new DataView(wordDocument.buffer);
|
|
139
157
|
for (let index = 0; index < text.length; index += 1) wordView.setUint16(characterFc(index), text.charCodeAt(index), true);
|
|
140
158
|
chpxPages.forEach((page, index) => {
|
|
@@ -143,13 +161,22 @@ function writeDocContent(document, options = {}) {
|
|
|
143
161
|
papxPages.forEach((page, index) => {
|
|
144
162
|
wordDocument.set(page, (papxPageStart + index) * 512);
|
|
145
163
|
});
|
|
146
|
-
|
|
164
|
+
sepxList.forEach((sepx, index) => {
|
|
165
|
+
const fcSepx = fcSepxList[index];
|
|
166
|
+
if (fcSepx === void 0) throw new require_errors.DocFormatError(`internal defect: writeDocContent lost section ${String(index)}'s own Sepx placement`);
|
|
167
|
+
wordDocument.set(sepx, fcSepx);
|
|
168
|
+
});
|
|
169
|
+
const sectionStartCps = sectionStartIndices.map((paragraphIndex, index) => {
|
|
170
|
+
const startCp = paragraphStarts[paragraphIndex];
|
|
171
|
+
if (startCp === void 0) throw new require_errors.DocFormatError(`internal defect: writeDocContent lost section ${String(index)}'s own start CP`);
|
|
172
|
+
return startCp;
|
|
173
|
+
});
|
|
147
174
|
const clx = require_text_piece_table_write.buildTextClx(text.length, TEXT_FC);
|
|
148
175
|
const chpxBinTable = require_prop_fkp_write.buildPropertyBinTable([...chpxPages.map(require_prop_fkp_write.firstFcOfPage), textFcLim], chpxPages.map((_, index) => chpxPageStart + index));
|
|
149
176
|
const papxBinTable = require_prop_fkp_write.buildPropertyBinTable([...papxPages.map(require_prop_fkp_write.firstFcOfPage), textFcLim], papxPages.map((_, index) => papxPageStart + index));
|
|
150
177
|
const stsh = require_style_stsh.buildStshForStyles(styleNames);
|
|
151
178
|
const fontTable = fontNames.length > 0 ? require_style_fonts.buildFontTable(fontNames) : void 0;
|
|
152
|
-
const plcfSed = require_prop_sep_write.buildPlcfSed(text.length,
|
|
179
|
+
const plcfSed = require_prop_sep_write.buildPlcfSed(sectionStartCps, text.length, fcSepxList);
|
|
153
180
|
let cursor = 0;
|
|
154
181
|
const place = (bytes) => {
|
|
155
182
|
const offset = cursor;
|
|
@@ -207,11 +234,32 @@ function writeDocContent(document, options = {}) {
|
|
|
207
234
|
path: require_detect.SUMMARY_INFORMATION_STREAM,
|
|
208
235
|
bytes: (0, archive_codec.writeSummaryInformationStream)(require_metadata.layoutMetadataToSummaryInformation(document.metadata))
|
|
209
236
|
});
|
|
237
|
+
const dataStreamBytes = dataStream.build();
|
|
238
|
+
if (dataStreamBytes.length > 0) streams.push({
|
|
239
|
+
path: require_detect.DATA_STREAM,
|
|
240
|
+
bytes: dataStreamBytes
|
|
241
|
+
});
|
|
210
242
|
return (0, archive_codec.writeCompoundFile)(streams);
|
|
211
243
|
}
|
|
212
244
|
function sameGrpprl(a, b) {
|
|
213
245
|
if (a === void 0 || b === void 0) return a === b;
|
|
214
246
|
return a.length === b.length && a.every((byte, index) => byte === b[index]);
|
|
215
247
|
}
|
|
248
|
+
function closeSection(paragraphs, terminator) {
|
|
249
|
+
if (paragraphs[paragraphs.length - 1]?.terminator !== 13) paragraphs.push({
|
|
250
|
+
runs: [],
|
|
251
|
+
properties: {},
|
|
252
|
+
extraGrpprl: [],
|
|
253
|
+
terminator: 13
|
|
254
|
+
});
|
|
255
|
+
if (terminator === 13) return;
|
|
256
|
+
const index = paragraphs.length - 1;
|
|
257
|
+
const target = paragraphs[index];
|
|
258
|
+
if (target === void 0) throw new require_errors.DocFormatError("internal defect: closeSection lost its own just-ensured trailing paragraph");
|
|
259
|
+
paragraphs[index] = {
|
|
260
|
+
...target,
|
|
261
|
+
terminator
|
|
262
|
+
};
|
|
263
|
+
}
|
|
216
264
|
//#endregion
|
|
217
265
|
exports.writeDocContent = writeDocContent;
|
package/dist/write.d.cts
CHANGED
package/dist/write.d.ts
CHANGED
package/dist/write.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DocFormatError, DocUnsupportedError } from "./errors.js";
|
|
2
|
-
import {
|
|
2
|
+
import { DataStreamBuilder } from "./data-stream.js";
|
|
3
|
+
import { DATA_STREAM, SUMMARY_INFORMATION_STREAM, WORD_DOCUMENT_STREAM } from "./detect.js";
|
|
3
4
|
import "./prop/fkp.js";
|
|
4
5
|
import { buildStshForStyles } from "./style/stsh.js";
|
|
5
6
|
import "./text/special.js";
|
|
@@ -21,16 +22,22 @@ const TEXT_FC = 1024;
|
|
|
21
22
|
const BYTES_PER_CHARACTER = 2;
|
|
22
23
|
function writeDocContent(document, options = {}) {
|
|
23
24
|
if (document.kind !== "wordprocessing") throw new DocUnsupportedError(`doc-codec writes wordprocessing documents only; got a '${document.kind}' document`);
|
|
24
|
-
if (document.sections.length
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
properties: {},
|
|
31
|
-
extraGrpprl: [],
|
|
32
|
-
terminator: 13
|
|
25
|
+
if (document.sections.length === 0) throw new DocFormatError("a wordprocessing document must carry at least one section");
|
|
26
|
+
const dataStream = new DataStreamBuilder();
|
|
27
|
+
const sectionParagraphLists = document.sections.map((section, index) => {
|
|
28
|
+
const paragraphs = flattenSectionBlocks(section.blocks, dataStream, options.onWarning);
|
|
29
|
+
closeSection(paragraphs, index === document.sections.length - 1 ? 13 : 12);
|
|
30
|
+
return paragraphs;
|
|
33
31
|
});
|
|
32
|
+
const sectionStartIndices = [];
|
|
33
|
+
{
|
|
34
|
+
let runningIndex = 0;
|
|
35
|
+
for (const paragraphs of sectionParagraphLists) {
|
|
36
|
+
sectionStartIndices.push(runningIndex);
|
|
37
|
+
runningIndex += paragraphs.length;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const writeParagraphs = sectionParagraphLists.flat();
|
|
34
41
|
const FIRST_NON_HEADING_ISTD = 10;
|
|
35
42
|
const MAX_HEADING_ISTD = 9;
|
|
36
43
|
const styleNames = /* @__PURE__ */ new Map();
|
|
@@ -71,9 +78,9 @@ function writeDocContent(document, options = {}) {
|
|
|
71
78
|
};
|
|
72
79
|
const numberingTables = buildNumberingTables(listUsage.definitions);
|
|
73
80
|
const formatted = writeParagraphs.map((entry) => ({
|
|
74
|
-
runs: entry.runs.map((
|
|
75
|
-
text: run.text,
|
|
76
|
-
grpprl: encodeCharacterGrpprl(run, fontIndexOf)
|
|
81
|
+
runs: entry.runs.map((writeRun) => ({
|
|
82
|
+
text: writeRun.run.text,
|
|
83
|
+
grpprl: [...encodeCharacterGrpprl(writeRun.run, fontIndexOf), ...writeRun.extraGrpprl]
|
|
77
84
|
})),
|
|
78
85
|
grpprl: [...encodeParagraphGrpprl(entry.properties, ilfoOf), ...entry.extraGrpprl]
|
|
79
86
|
}));
|
|
@@ -131,9 +138,20 @@ function writeDocContent(document, options = {}) {
|
|
|
131
138
|
};
|
|
132
139
|
});
|
|
133
140
|
const papxPages = buildPapxPages(papxParagraphSpecs, textFcLim);
|
|
134
|
-
const
|
|
135
|
-
const
|
|
136
|
-
const
|
|
141
|
+
const sepxPageStart = (papxPageStart + papxPages.length) * 512;
|
|
142
|
+
const sepxList = document.sections.map((section) => buildSepx(encodeSectionGrpprl(section)));
|
|
143
|
+
const fcSepxList = [];
|
|
144
|
+
{
|
|
145
|
+
let sepxCursor = sepxPageStart;
|
|
146
|
+
for (const sepx of sepxList) {
|
|
147
|
+
fcSepxList.push(sepxCursor);
|
|
148
|
+
sepxCursor += sepx.length;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const lastFcSepx = fcSepxList[fcSepxList.length - 1];
|
|
152
|
+
const lastSepx = sepxList[sepxList.length - 1];
|
|
153
|
+
if (lastFcSepx === void 0 || lastSepx === void 0) throw new DocFormatError("internal defect: writeDocContent built an empty section list despite the earlier at-least-one-section guard");
|
|
154
|
+
const wordDocument = new Uint8Array(lastFcSepx + lastSepx.length);
|
|
137
155
|
const wordView = new DataView(wordDocument.buffer);
|
|
138
156
|
for (let index = 0; index < text.length; index += 1) wordView.setUint16(characterFc(index), text.charCodeAt(index), true);
|
|
139
157
|
chpxPages.forEach((page, index) => {
|
|
@@ -142,13 +160,22 @@ function writeDocContent(document, options = {}) {
|
|
|
142
160
|
papxPages.forEach((page, index) => {
|
|
143
161
|
wordDocument.set(page, (papxPageStart + index) * 512);
|
|
144
162
|
});
|
|
145
|
-
|
|
163
|
+
sepxList.forEach((sepx, index) => {
|
|
164
|
+
const fcSepx = fcSepxList[index];
|
|
165
|
+
if (fcSepx === void 0) throw new DocFormatError(`internal defect: writeDocContent lost section ${String(index)}'s own Sepx placement`);
|
|
166
|
+
wordDocument.set(sepx, fcSepx);
|
|
167
|
+
});
|
|
168
|
+
const sectionStartCps = sectionStartIndices.map((paragraphIndex, index) => {
|
|
169
|
+
const startCp = paragraphStarts[paragraphIndex];
|
|
170
|
+
if (startCp === void 0) throw new DocFormatError(`internal defect: writeDocContent lost section ${String(index)}'s own start CP`);
|
|
171
|
+
return startCp;
|
|
172
|
+
});
|
|
146
173
|
const clx = buildTextClx(text.length, TEXT_FC);
|
|
147
174
|
const chpxBinTable = buildPropertyBinTable([...chpxPages.map(firstFcOfPage), textFcLim], chpxPages.map((_, index) => chpxPageStart + index));
|
|
148
175
|
const papxBinTable = buildPropertyBinTable([...papxPages.map(firstFcOfPage), textFcLim], papxPages.map((_, index) => papxPageStart + index));
|
|
149
176
|
const stsh = buildStshForStyles(styleNames);
|
|
150
177
|
const fontTable = fontNames.length > 0 ? buildFontTable(fontNames) : void 0;
|
|
151
|
-
const plcfSed = buildPlcfSed(text.length,
|
|
178
|
+
const plcfSed = buildPlcfSed(sectionStartCps, text.length, fcSepxList);
|
|
152
179
|
let cursor = 0;
|
|
153
180
|
const place = (bytes) => {
|
|
154
181
|
const offset = cursor;
|
|
@@ -206,11 +233,32 @@ function writeDocContent(document, options = {}) {
|
|
|
206
233
|
path: SUMMARY_INFORMATION_STREAM,
|
|
207
234
|
bytes: writeSummaryInformationStream(layoutMetadataToSummaryInformation$1(document.metadata))
|
|
208
235
|
});
|
|
236
|
+
const dataStreamBytes = dataStream.build();
|
|
237
|
+
if (dataStreamBytes.length > 0) streams.push({
|
|
238
|
+
path: DATA_STREAM,
|
|
239
|
+
bytes: dataStreamBytes
|
|
240
|
+
});
|
|
209
241
|
return writeCompoundFile(streams);
|
|
210
242
|
}
|
|
211
243
|
function sameGrpprl(a, b) {
|
|
212
244
|
if (a === void 0 || b === void 0) return a === b;
|
|
213
245
|
return a.length === b.length && a.every((byte, index) => byte === b[index]);
|
|
214
246
|
}
|
|
247
|
+
function closeSection(paragraphs, terminator) {
|
|
248
|
+
if (paragraphs[paragraphs.length - 1]?.terminator !== 13) paragraphs.push({
|
|
249
|
+
runs: [],
|
|
250
|
+
properties: {},
|
|
251
|
+
extraGrpprl: [],
|
|
252
|
+
terminator: 13
|
|
253
|
+
});
|
|
254
|
+
if (terminator === 13) return;
|
|
255
|
+
const index = paragraphs.length - 1;
|
|
256
|
+
const target = paragraphs[index];
|
|
257
|
+
if (target === void 0) throw new DocFormatError("internal defect: closeSection lost its own just-ensured trailing paragraph");
|
|
258
|
+
paragraphs[index] = {
|
|
259
|
+
...target,
|
|
260
|
+
terminator
|
|
261
|
+
};
|
|
262
|
+
}
|
|
215
263
|
//#endregion
|
|
216
264
|
export { writeDocContent };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "doc-codec",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.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": {
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"license": "MIT",
|
|
79
79
|
"packageManager": "pnpm@11.6.0",
|
|
80
80
|
"dependencies": {
|
|
81
|
-
"archive-codec": "1.
|
|
81
|
+
"archive-codec": "1.10.0",
|
|
82
82
|
"document-schema.js": "7.5.0"
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|