@usejunior/docx-core 0.10.0 → 0.11.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/LICENSE +202 -21
- package/NOTICE +2 -0
- package/README.md +2 -2
- package/dist/.tsbuildinfo +1 -1
- package/dist/atomizer.d.ts +13 -7
- package/dist/atomizer.d.ts.map +1 -1
- package/dist/atomizer.js +59 -24
- package/dist/atomizer.js.map +1 -1
- package/dist/baselines/atomizer/auxiliaryIdCollision.d.ts +99 -0
- package/dist/baselines/atomizer/auxiliaryIdCollision.d.ts.map +1 -0
- package/dist/baselines/atomizer/auxiliaryIdCollision.js +415 -0
- package/dist/baselines/atomizer/auxiliaryIdCollision.js.map +1 -0
- package/dist/baselines/atomizer/documentReconstructor.d.ts.map +1 -1
- package/dist/baselines/atomizer/documentReconstructor.js +120 -27
- package/dist/baselines/atomizer/documentReconstructor.js.map +1 -1
- package/dist/baselines/atomizer/inPlaceModifier-wrappers.d.ts +9 -0
- package/dist/baselines/atomizer/inPlaceModifier-wrappers.d.ts.map +1 -1
- package/dist/baselines/atomizer/inPlaceModifier-wrappers.js +52 -4
- package/dist/baselines/atomizer/inPlaceModifier-wrappers.js.map +1 -1
- package/dist/baselines/atomizer/pipeline.d.ts +12 -53
- package/dist/baselines/atomizer/pipeline.d.ts.map +1 -1
- package/dist/baselines/atomizer/pipeline.js +126 -231
- package/dist/baselines/atomizer/pipeline.js.map +1 -1
- package/dist/baselines/atomizer/trackChangesAcceptorAst.d.ts.map +1 -1
- package/dist/baselines/atomizer/trackChangesAcceptorAst.js +153 -23
- package/dist/baselines/atomizer/trackChangesAcceptorAst.js.map +1 -1
- package/dist/baselines/wmlcomparer/DotnetCli.d.ts.map +1 -1
- package/dist/baselines/wmlcomparer/DotnetCli.js +7 -0
- package/dist/baselines/wmlcomparer/DotnetCli.js.map +1 -1
- package/dist/cli/compare-two.d.ts.map +1 -1
- package/dist/cli/compare-two.js +3 -1
- package/dist/cli/compare-two.js.map +1 -1
- package/dist/cli/conformance-adapter.d.ts +3 -0
- package/dist/cli/conformance-adapter.d.ts.map +1 -0
- package/dist/cli/conformance-adapter.js +93 -0
- package/dist/cli/conformance-adapter.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +5 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/compare-types.d.ts +46 -0
- package/dist/compare-types.d.ts.map +1 -1
- package/dist/generation/compile.d.ts +21 -0
- package/dist/generation/compile.d.ts.map +1 -0
- package/dist/generation/compile.js +46 -0
- package/dist/generation/compile.js.map +1 -0
- package/dist/generation/context.d.ts +42 -0
- package/dist/generation/context.d.ts.map +1 -0
- package/dist/generation/context.js +65 -0
- package/dist/generation/context.js.map +1 -0
- package/dist/generation/emit/comments-part.d.ts +36 -0
- package/dist/generation/emit/comments-part.d.ts.map +1 -0
- package/dist/generation/emit/comments-part.js +116 -0
- package/dist/generation/emit/comments-part.js.map +1 -0
- package/dist/generation/emit/document-part.d.ts +24 -0
- package/dist/generation/emit/document-part.d.ts.map +1 -0
- package/dist/generation/emit/document-part.js +60 -0
- package/dist/generation/emit/document-part.js.map +1 -0
- package/dist/generation/emit/emit-context.d.ts +26 -0
- package/dist/generation/emit/emit-context.d.ts.map +1 -0
- package/dist/generation/emit/emit-context.js +19 -0
- package/dist/generation/emit/emit-context.js.map +1 -0
- package/dist/generation/emit/header-footer-part.d.ts +23 -0
- package/dist/generation/emit/header-footer-part.d.ts.map +1 -0
- package/dist/generation/emit/header-footer-part.js +57 -0
- package/dist/generation/emit/header-footer-part.js.map +1 -0
- package/dist/generation/emit/numbering-part.d.ts +29 -0
- package/dist/generation/emit/numbering-part.d.ts.map +1 -0
- package/dist/generation/emit/numbering-part.js +100 -0
- package/dist/generation/emit/numbering-part.js.map +1 -0
- package/dist/generation/emit/package-parts.d.ts +24 -0
- package/dist/generation/emit/package-parts.d.ts.map +1 -0
- package/dist/generation/emit/package-parts.js +121 -0
- package/dist/generation/emit/package-parts.js.map +1 -0
- package/dist/generation/emit/paragraph.d.ts +24 -0
- package/dist/generation/emit/paragraph.d.ts.map +1 -0
- package/dist/generation/emit/paragraph.js +63 -0
- package/dist/generation/emit/paragraph.js.map +1 -0
- package/dist/generation/emit/properties.d.ts +34 -0
- package/dist/generation/emit/properties.d.ts.map +1 -0
- package/dist/generation/emit/properties.js +138 -0
- package/dist/generation/emit/properties.js.map +1 -0
- package/dist/generation/emit/run.d.ts +15 -0
- package/dist/generation/emit/run.d.ts.map +1 -0
- package/dist/generation/emit/run.js +71 -0
- package/dist/generation/emit/run.js.map +1 -0
- package/dist/generation/emit/section.d.ts +29 -0
- package/dist/generation/emit/section.d.ts.map +1 -0
- package/dist/generation/emit/section.js +117 -0
- package/dist/generation/emit/section.js.map +1 -0
- package/dist/generation/emit/settings-part.d.ts +13 -0
- package/dist/generation/emit/settings-part.d.ts.map +1 -0
- package/dist/generation/emit/settings-part.js +24 -0
- package/dist/generation/emit/settings-part.js.map +1 -0
- package/dist/generation/emit/styles-part.d.ts +16 -0
- package/dist/generation/emit/styles-part.d.ts.map +1 -0
- package/dist/generation/emit/styles-part.js +80 -0
- package/dist/generation/emit/styles-part.js.map +1 -0
- package/dist/generation/emit/table.d.ts +26 -0
- package/dist/generation/emit/table.d.ts.map +1 -0
- package/dist/generation/emit/table.js +196 -0
- package/dist/generation/emit/table.js.map +1 -0
- package/dist/generation/errors.d.ts +22 -0
- package/dist/generation/errors.d.ts.map +1 -0
- package/dist/generation/errors.js +29 -0
- package/dist/generation/errors.js.map +1 -0
- package/dist/generation/index.d.ts +13 -0
- package/dist/generation/index.d.ts.map +1 -0
- package/dist/generation/index.js +12 -0
- package/dist/generation/index.js.map +1 -0
- package/dist/generation/ordering.d.ts +46 -0
- package/dist/generation/ordering.d.ts.map +1 -0
- package/dist/generation/ordering.js +119 -0
- package/dist/generation/ordering.js.map +1 -0
- package/dist/generation/recipes.d.ts +47 -0
- package/dist/generation/recipes.d.ts.map +1 -0
- package/dist/generation/recipes.js +84 -0
- package/dist/generation/recipes.js.map +1 -0
- package/dist/generation/structural-checks.d.ts +24 -0
- package/dist/generation/structural-checks.d.ts.map +1 -0
- package/dist/generation/structural-checks.js +318 -0
- package/dist/generation/structural-checks.js.map +1 -0
- package/dist/generation/types.d.ts +217 -0
- package/dist/generation/types.d.ts.map +1 -0
- package/dist/generation/types.js +16 -0
- package/dist/generation/types.js.map +1 -0
- package/dist/generation/validate-spec.d.ts +27 -0
- package/dist/generation/validate-spec.d.ts.map +1 -0
- package/dist/generation/validate-spec.js +307 -0
- package/dist/generation/validate-spec.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/integration/generation-probes.d.ts +15 -0
- package/dist/integration/generation-probes.d.ts.map +1 -0
- package/dist/integration/generation-probes.js +84 -0
- package/dist/integration/generation-probes.js.map +1 -0
- package/dist/integration/libreoffice-oracle.d.ts +8 -0
- package/dist/integration/libreoffice-oracle.d.ts.map +1 -1
- package/dist/integration/libreoffice-oracle.js +14 -6
- package/dist/integration/libreoffice-oracle.js.map +1 -1
- package/dist/integration/synthetic-docx-fixture.d.ts +72 -0
- package/dist/integration/synthetic-docx-fixture.d.ts.map +1 -1
- package/dist/integration/synthetic-docx-fixture.js +131 -4
- package/dist/integration/synthetic-docx-fixture.js.map +1 -1
- package/dist/primitives/accept_changes.d.ts +2 -1
- package/dist/primitives/accept_changes.d.ts.map +1 -1
- package/dist/primitives/accept_changes.js +153 -12
- package/dist/primitives/accept_changes.js.map +1 -1
- package/dist/primitives/document.d.ts +38 -0
- package/dist/primitives/document.d.ts.map +1 -1
- package/dist/primitives/document.js +75 -9
- package/dist/primitives/document.js.map +1 -1
- package/dist/primitives/document_view-comments.d.ts.map +1 -1
- package/dist/primitives/document_view-comments.js +4 -3
- package/dist/primitives/document_view-comments.js.map +1 -1
- package/dist/primitives/document_view-types.d.ts +15 -0
- package/dist/primitives/document_view-types.d.ts.map +1 -1
- package/dist/primitives/document_view.d.ts.map +1 -1
- package/dist/primitives/document_view.js +21 -13
- package/dist/primitives/document_view.js.map +1 -1
- package/dist/primitives/formatting_tags.d.ts +1 -0
- package/dist/primitives/formatting_tags.d.ts.map +1 -1
- package/dist/primitives/formatting_tags.js +16 -10
- package/dist/primitives/formatting_tags.js.map +1 -1
- package/dist/primitives/index.d.ts +4 -0
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/index.js +4 -0
- package/dist/primitives/index.js.map +1 -1
- package/dist/primitives/layout.d.ts.map +1 -1
- package/dist/primitives/layout.js +13 -0
- package/dist/primitives/layout.js.map +1 -1
- package/dist/primitives/minimal_save.d.ts +38 -0
- package/dist/primitives/minimal_save.d.ts.map +1 -0
- package/dist/primitives/minimal_save.js +323 -0
- package/dist/primitives/minimal_save.js.map +1 -0
- package/dist/primitives/namespaces.d.ts +41 -0
- package/dist/primitives/namespaces.d.ts.map +1 -1
- package/dist/primitives/namespaces.js +43 -0
- package/dist/primitives/namespaces.js.map +1 -1
- package/dist/primitives/reject_changes.d.ts +4 -2
- package/dist/primitives/reject_changes.d.ts.map +1 -1
- package/dist/primitives/reject_changes.js +177 -24
- package/dist/primitives/reject_changes.js.map +1 -1
- package/dist/primitives/revision-parts.d.ts +7 -0
- package/dist/primitives/revision-parts.d.ts.map +1 -0
- package/dist/primitives/revision-parts.js +27 -0
- package/dist/primitives/revision-parts.js.map +1 -0
- package/dist/primitives/revision-vocabulary.d.ts +7 -0
- package/dist/primitives/revision-vocabulary.d.ts.map +1 -0
- package/dist/primitives/revision-vocabulary.js +39 -0
- package/dist/primitives/revision-vocabulary.js.map +1 -0
- package/dist/primitives/schema-corpus-capture.d.ts +19 -0
- package/dist/primitives/schema-corpus-capture.d.ts.map +1 -0
- package/dist/primitives/schema-corpus-capture.js +29 -0
- package/dist/primitives/schema-corpus-capture.js.map +1 -0
- package/dist/primitives/sectPrAudit.d.ts +19 -0
- package/dist/primitives/sectPrAudit.d.ts.map +1 -0
- package/dist/primitives/sectPrAudit.js +165 -0
- package/dist/primitives/sectPrAudit.js.map +1 -0
- package/dist/primitives/semantic_tags.d.ts.map +1 -1
- package/dist/primitives/semantic_tags.js +2 -1
- package/dist/primitives/semantic_tags.js.map +1 -1
- package/dist/primitives/serialize_html.d.ts +1 -0
- package/dist/primitives/serialize_html.d.ts.map +1 -1
- package/dist/primitives/serialize_html.js +4 -2
- package/dist/primitives/serialize_html.js.map +1 -1
- package/dist/primitives/styles.d.ts +15 -0
- package/dist/primitives/styles.d.ts.map +1 -1
- package/dist/primitives/styles.js +11 -0
- package/dist/primitives/styles.js.map +1 -1
- package/dist/primitives/track-changes-emitter.d.ts +9 -0
- package/dist/primitives/track-changes-emitter.d.ts.map +1 -1
- package/dist/primitives/track-changes-emitter.js +54 -4
- package/dist/primitives/track-changes-emitter.js.map +1 -1
- package/dist/primitives/validate_ai_revisions.d.ts +35 -0
- package/dist/primitives/validate_ai_revisions.d.ts.map +1 -0
- package/dist/primitives/validate_ai_revisions.js +323 -0
- package/dist/primitives/validate_ai_revisions.js.map +1 -0
- package/dist/primitives/xml.d.ts +5 -0
- package/dist/primitives/xml.d.ts.map +1 -1
- package/dist/primitives/xml.js +5 -0
- package/dist/primitives/xml.js.map +1 -1
- package/dist/primitives/zip.d.ts +1 -0
- package/dist/primitives/zip.d.ts.map +1 -1
- package/dist/primitives/zip.js +21 -3
- package/dist/primitives/zip.js.map +1 -1
- package/dist/shared/field-structure.d.ts +14 -0
- package/dist/shared/field-structure.d.ts.map +1 -0
- package/dist/shared/field-structure.js +166 -0
- package/dist/shared/field-structure.js.map +1 -0
- package/package.json +7 -4
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* docx-platform-tests adapter protocol v1 entrypoint.
|
|
4
|
+
*
|
|
5
|
+
* Invoked by the suite runner as:
|
|
6
|
+
* safe-docx-conformance-adapter --protocol-version 1 \
|
|
7
|
+
* --operation operation.json --input input.docx --output output.docx
|
|
8
|
+
*
|
|
9
|
+
* Exit codes (per the suite's docs/adapter-protocol.md):
|
|
10
|
+
* 0 success, 1 error, 2 unsupported operation, 3 protocol mismatch.
|
|
11
|
+
* Declining with 2 is mandatory for operations outside the implemented
|
|
12
|
+
* set — the suite's design treats honest gaps as data, never approximate.
|
|
13
|
+
*/
|
|
14
|
+
import { readFileSync, realpathSync, writeFileSync } from 'node:fs';
|
|
15
|
+
import { pathToFileURL } from 'node:url';
|
|
16
|
+
import { DocxDocument } from '../primitives/document.js';
|
|
17
|
+
import { getParagraphText, replaceParagraphTextRange } from '../primitives/text.js';
|
|
18
|
+
const SUPPORTED_PROTOCOL_VERSION = '1';
|
|
19
|
+
const SUPPORTED_OPERATIONS = new Set([
|
|
20
|
+
'acceptAllTrackedChanges',
|
|
21
|
+
'rejectAllTrackedChanges',
|
|
22
|
+
'replaceFirstTextOccurrence',
|
|
23
|
+
]);
|
|
24
|
+
function argValue(argv, flag) {
|
|
25
|
+
const idx = argv.indexOf(flag);
|
|
26
|
+
return idx !== -1 ? argv[idx + 1] : undefined;
|
|
27
|
+
}
|
|
28
|
+
export async function runConformanceAdapter(argv) {
|
|
29
|
+
const protocolVersion = argValue(argv, '--protocol-version');
|
|
30
|
+
const operationPath = argValue(argv, '--operation');
|
|
31
|
+
const inputPath = argValue(argv, '--input');
|
|
32
|
+
const outputPath = argValue(argv, '--output');
|
|
33
|
+
if (protocolVersion !== SUPPORTED_PROTOCOL_VERSION) {
|
|
34
|
+
console.log(`safe-docx-conformance-adapter speaks protocol v${SUPPORTED_PROTOCOL_VERSION}, got ${protocolVersion ?? 'none'}`);
|
|
35
|
+
return 3;
|
|
36
|
+
}
|
|
37
|
+
if (!operationPath || !inputPath || !outputPath) {
|
|
38
|
+
console.error('usage: --protocol-version 1 --operation <json> --input <docx> --output <docx>');
|
|
39
|
+
return 1;
|
|
40
|
+
}
|
|
41
|
+
const operation = JSON.parse(readFileSync(operationPath, 'utf8'));
|
|
42
|
+
// Decline before touching the input: unsupported must not depend on the
|
|
43
|
+
// document being readable.
|
|
44
|
+
if (!SUPPORTED_OPERATIONS.has(operation.operationName)) {
|
|
45
|
+
console.log(`safe-docx adapter does not implement operation '${operation.operationName}'`);
|
|
46
|
+
return 2;
|
|
47
|
+
}
|
|
48
|
+
const doc = await DocxDocument.load(readFileSync(inputPath));
|
|
49
|
+
switch (operation.operationName) {
|
|
50
|
+
case 'acceptAllTrackedChanges':
|
|
51
|
+
await doc.acceptChanges();
|
|
52
|
+
break;
|
|
53
|
+
case 'rejectAllTrackedChanges':
|
|
54
|
+
await doc.rejectChanges();
|
|
55
|
+
break;
|
|
56
|
+
case 'replaceFirstTextOccurrence': {
|
|
57
|
+
const { findText, replaceText } = operation;
|
|
58
|
+
if (typeof findText !== 'string' || typeof replaceText !== 'string') {
|
|
59
|
+
console.error('replaceFirstTextOccurrence requires findText and replaceText');
|
|
60
|
+
return 1;
|
|
61
|
+
}
|
|
62
|
+
// DSL 1.0 match scope: first paragraph-local occurrence in document
|
|
63
|
+
// order; the replacement is a plain edit, not a tracked change.
|
|
64
|
+
const paragraph = doc
|
|
65
|
+
.getParagraphs()
|
|
66
|
+
.find((p) => getParagraphText(p).includes(findText));
|
|
67
|
+
if (!paragraph) {
|
|
68
|
+
console.error(`findText not present in any paragraph: ${JSON.stringify(findText)}`);
|
|
69
|
+
return 1;
|
|
70
|
+
}
|
|
71
|
+
const start = getParagraphText(paragraph).indexOf(findText);
|
|
72
|
+
replaceParagraphTextRange(paragraph, start, start + findText.length, replaceText);
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
default:
|
|
76
|
+
// Unreachable: membership was checked above.
|
|
77
|
+
return 2;
|
|
78
|
+
}
|
|
79
|
+
const { buffer } = await doc.toBuffer();
|
|
80
|
+
writeFileSync(outputPath, buffer);
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
// realpathSync: when invoked through the node_modules/.bin symlink,
|
|
84
|
+
// process.argv[1] is the symlink while import.meta.url is the real file.
|
|
85
|
+
if (process.argv[1] && pathToFileURL(realpathSync(process.argv[1])).href === import.meta.url) {
|
|
86
|
+
runConformanceAdapter(process.argv.slice(2))
|
|
87
|
+
.then((code) => process.exit(code))
|
|
88
|
+
.catch((err) => {
|
|
89
|
+
console.error(err?.message ?? String(err));
|
|
90
|
+
process.exit(1);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=conformance-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conformance-adapter.js","sourceRoot":"","sources":["../../src/cli/conformance-adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAKA,wBAAsB,MAAM,CAAC,IAAI,WAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAU/D"}
|
package/dist/cli/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { realpathSync } from 'node:fs';
|
|
2
3
|
import { pathToFileURL } from 'node:url';
|
|
3
4
|
import { runCompareCli } from './compare-two.js';
|
|
4
5
|
export async function runCli(argv = process.argv) {
|
|
@@ -11,7 +12,10 @@ export async function runCli(argv = process.argv) {
|
|
|
11
12
|
// eslint-disable-next-line no-console
|
|
12
13
|
console.log(JSON.stringify(result));
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
+
// npm installs bins as node_modules/.bin symlinks, so argv[1] must be
|
|
16
|
+
// realpath-resolved before comparing against import.meta.url (which node
|
|
17
|
+
// always resolves to the real dist file). See #398.
|
|
18
|
+
if (process.argv[1] && pathToFileURL(realpathSync(process.argv[1])).href === import.meta.url) {
|
|
15
19
|
runCli(process.argv).catch((err) => {
|
|
16
20
|
// eslint-disable-next-line no-console
|
|
17
21
|
console.error(err?.message ?? String(err));
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI;IAC9C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QACpC,sCAAsC;QACtC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACzB,OAAO;IACT,CAAC;IAED,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AACtC,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI;IAC9C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QACpC,sCAAsC;QACtC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACzB,OAAO;IACT,CAAC;IAED,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AACtC,CAAC;AAED,sEAAsE;AACtE,yEAAyE;AACzE,oDAAoD;AACpD,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7F,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACjC,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/compare-types.d.ts
CHANGED
|
@@ -34,9 +34,35 @@ export interface CompareOptions {
|
|
|
34
34
|
engine?: 'wmlcomparer' | 'atomizer' | 'auto';
|
|
35
35
|
}
|
|
36
36
|
export interface CompareStats {
|
|
37
|
+
/**
|
|
38
|
+
* Human-facing inserted change ranges. This counts contiguous inserted atom
|
|
39
|
+
* runs, matching the coalesced w:ins regions emitted in OOXML.
|
|
40
|
+
*/
|
|
37
41
|
insertions: number;
|
|
42
|
+
/**
|
|
43
|
+
* Human-facing deleted change ranges. This counts contiguous deleted atom
|
|
44
|
+
* runs, matching the coalesced w:del regions emitted in OOXML.
|
|
45
|
+
*/
|
|
38
46
|
deletions: number;
|
|
47
|
+
/**
|
|
48
|
+
* Paragraphs containing both inserted and deleted content. Format-only
|
|
49
|
+
* changes are reported separately in formatChanges.
|
|
50
|
+
*/
|
|
39
51
|
modifications: number;
|
|
52
|
+
/** Same value as insertions, exposed with explicit range-level semantics. */
|
|
53
|
+
insertedRanges: number;
|
|
54
|
+
/** Same value as deletions, exposed with explicit range-level semantics. */
|
|
55
|
+
deletedRanges: number;
|
|
56
|
+
/** Atom-level inserted units for granular/benchmark consumers. */
|
|
57
|
+
insertedAtoms: number;
|
|
58
|
+
/** Atom-level deleted units for granular/benchmark consumers. */
|
|
59
|
+
deletedAtoms: number;
|
|
60
|
+
/** Same value as modifications, exposed without overloading the term. */
|
|
61
|
+
modifiedParagraphs: number;
|
|
62
|
+
/** Contiguous format-only change ranges. */
|
|
63
|
+
formatChanges: number;
|
|
64
|
+
/** Atom-level format-only units for granular/benchmark consumers. */
|
|
65
|
+
formatChangeAtoms: number;
|
|
40
66
|
}
|
|
41
67
|
export type ReconstructionMode = 'rebuild' | 'inplace';
|
|
42
68
|
export type ReconstructionFallbackReason = 'round_trip_safety_check_failed';
|
|
@@ -122,6 +148,20 @@ export interface ReconstructionAttemptDiagnostics {
|
|
|
122
148
|
export interface ReconstructionFallbackDiagnostics {
|
|
123
149
|
attempts: ReconstructionAttemptDiagnostics[];
|
|
124
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Round-trip safety evaluation of rebuild output. Rebuild is the terminal
|
|
153
|
+
* reconstruction strategy — there is no further fallback — so a failed check
|
|
154
|
+
* cannot reroute the pipeline. The document is returned anyway and the
|
|
155
|
+
* failures are surfaced here as a caller-visible warning.
|
|
156
|
+
*
|
|
157
|
+
* @see https://github.com/UseJunior/safe-docx/issues/226
|
|
158
|
+
*/
|
|
159
|
+
export interface ReconstructionRebuildSafetyDiagnostics {
|
|
160
|
+
checks: ReconstructionSafetyChecks;
|
|
161
|
+
failedChecks: ReconstructionSafetyCheckName[];
|
|
162
|
+
failureDetails?: ReconstructionSafetyFailureDetails;
|
|
163
|
+
firstDiffSummary?: ReconstructionSafetyFailureSummary;
|
|
164
|
+
}
|
|
125
165
|
export interface CompareResult {
|
|
126
166
|
/** The resulting DOCX with track changes */
|
|
127
167
|
document: Buffer;
|
|
@@ -147,5 +187,11 @@ export interface CompareResult {
|
|
|
147
187
|
* Present only when atomizer falls back.
|
|
148
188
|
*/
|
|
149
189
|
fallbackDiagnostics?: ReconstructionFallbackDiagnostics;
|
|
190
|
+
/**
|
|
191
|
+
* Safety-check failures observed on rebuild output — whether rebuild was
|
|
192
|
+
* requested explicitly (the default mode) or reached via inplace fallback.
|
|
193
|
+
* Present only when at least one check failed.
|
|
194
|
+
*/
|
|
195
|
+
rebuildSafetyDiagnostics?: ReconstructionRebuildSafetyDiagnostics;
|
|
150
196
|
}
|
|
151
197
|
//# sourceMappingURL=compare-types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare-types.d.ts","sourceRoot":"","sources":["../src/compare-types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,aAAa,GAAG,UAAU,GAAG,MAAM,CAAC;CAC9C;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"compare-types.d.ts","sourceRoot":"","sources":["../src/compare-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The generation compiler: DocumentSpec → validated spec → per-part emitters
|
|
3
|
+
* → ordered file record → zip buffer.
|
|
4
|
+
*
|
|
5
|
+
* Determinism contract: identical specs compile to byte-identical buffers.
|
|
6
|
+
* No emitter reads the clock or randomness; zip entry dates are pinned to a
|
|
7
|
+
* fixed epoch (document-facing dates come from spec.meta.createdIso).
|
|
8
|
+
*
|
|
9
|
+
* Ordering: header/footer parts are allocated first so their relationship
|
|
10
|
+
* ids exist when the document part binds section references; the package
|
|
11
|
+
* plumbing runs last because [Content_Types].xml is assembled from the part
|
|
12
|
+
* registry.
|
|
13
|
+
*/
|
|
14
|
+
import type { DocumentSpec } from './types.js';
|
|
15
|
+
export type GenerateDocxOptions = {
|
|
16
|
+
/** Overrides spec.options.includeDraftingNotes when provided. */
|
|
17
|
+
includeDraftingNotes?: boolean;
|
|
18
|
+
};
|
|
19
|
+
/** Compile a DocumentSpec into a complete DOCX package. */
|
|
20
|
+
export declare function generateDocx(spec: DocumentSpec, opts?: GenerateDocxOptions): Promise<Buffer>;
|
|
21
|
+
//# sourceMappingURL=compile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/generation/compile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAaH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C,MAAM,MAAM,mBAAmB,GAAG;IAChC,iEAAiE;IACjE,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,2DAA2D;AAC3D,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBlG"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The generation compiler: DocumentSpec → validated spec → per-part emitters
|
|
3
|
+
* → ordered file record → zip buffer.
|
|
4
|
+
*
|
|
5
|
+
* Determinism contract: identical specs compile to byte-identical buffers.
|
|
6
|
+
* No emitter reads the clock or randomness; zip entry dates are pinned to a
|
|
7
|
+
* fixed epoch (document-facing dates come from spec.meta.createdIso).
|
|
8
|
+
*
|
|
9
|
+
* Ordering: header/footer parts are allocated first so their relationship
|
|
10
|
+
* ids exist when the document part binds section references; the package
|
|
11
|
+
* plumbing runs last because [Content_Types].xml is assembled from the part
|
|
12
|
+
* registry.
|
|
13
|
+
*/
|
|
14
|
+
import { createZipBuffer } from '../primitives/zip.js';
|
|
15
|
+
import { maybeCaptureEmittedDocumentXml } from '../primitives/schema-corpus-capture.js';
|
|
16
|
+
import { CompileContext } from './context.js';
|
|
17
|
+
import { emitCommentsPartsIfNeeded } from './emit/comments-part.js';
|
|
18
|
+
import { DraftingNoteCollector } from './emit/emit-context.js';
|
|
19
|
+
import { emitDocumentPart } from './emit/document-part.js';
|
|
20
|
+
import { emitHeaderFooterParts } from './emit/header-footer-part.js';
|
|
21
|
+
import { emitNumberingPartIfNeeded } from './emit/numbering-part.js';
|
|
22
|
+
import { emitPackageParts } from './emit/package-parts.js';
|
|
23
|
+
import { emitSettingsPartIfNeeded } from './emit/settings-part.js';
|
|
24
|
+
import { emitStylesPart } from './emit/styles-part.js';
|
|
25
|
+
import { validateSpec } from './validate-spec.js';
|
|
26
|
+
/** Fixed zip-entry timestamp (2006-01-01T00:00:00Z, the OOXML vintage). */
|
|
27
|
+
const ZIP_EPOCH = new Date(Date.UTC(2006, 0, 1));
|
|
28
|
+
/** Compile a DocumentSpec into a complete DOCX package. */
|
|
29
|
+
export async function generateDocx(spec, opts) {
|
|
30
|
+
validateSpec(spec);
|
|
31
|
+
const notesEnabled = opts?.includeDraftingNotes ?? spec.options?.includeDraftingNotes ?? true;
|
|
32
|
+
const ctx = new CompileContext();
|
|
33
|
+
const numberingIds = emitNumberingPartIfNeeded(spec, ctx);
|
|
34
|
+
const headerFooterRefs = emitHeaderFooterParts(spec, ctx, { numberingIds });
|
|
35
|
+
const notes = notesEnabled ? new DraftingNoteCollector() : undefined;
|
|
36
|
+
const documentPartXml = emitDocumentPart(spec, headerFooterRefs, { numberingIds, notes });
|
|
37
|
+
maybeCaptureEmittedDocumentXml(documentPartXml);
|
|
38
|
+
ctx.setFileContent('word/document.xml', documentPartXml);
|
|
39
|
+
if (notes)
|
|
40
|
+
emitCommentsPartsIfNeeded(spec, ctx, notes);
|
|
41
|
+
emitStylesPart(spec, ctx);
|
|
42
|
+
emitSettingsPartIfNeeded(spec, ctx);
|
|
43
|
+
emitPackageParts(spec, ctx);
|
|
44
|
+
return createZipBuffer(ctx.toFileRecord(), { fileDate: ZIP_EPOCH });
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=compile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.js","sourceRoot":"","sources":["../../src/generation/compile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,8BAA8B,EAAE,MAAM,wCAAwC,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,2EAA2E;AAC3E,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAOjD,2DAA2D;AAC3D,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAkB,EAAE,IAA0B;IAC/E,YAAY,CAAC,IAAI,CAAC,CAAC;IAEnB,MAAM,YAAY,GAAG,IAAI,EAAE,oBAAoB,IAAI,IAAI,CAAC,OAAO,EAAE,oBAAoB,IAAI,IAAI,CAAC;IAC9F,MAAM,GAAG,GAAG,IAAI,cAAc,EAAE,CAAC;IACjC,MAAM,YAAY,GAAG,yBAAyB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC1D,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;IAC5E,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,qBAAqB,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACrE,MAAM,eAAe,GAAG,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1F,8BAA8B,CAAC,eAAe,CAAC,CAAC;IAChD,GAAG,CAAC,cAAc,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC;IACzD,IAAI,KAAK;QAAE,yBAAyB,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACvD,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC1B,wBAAwB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACpC,gBAAgB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAE5B,OAAO,eAAe,CAAC,GAAG,CAAC,YAAY,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compile-time state shared by the part emitters.
|
|
3
|
+
*
|
|
4
|
+
* The context owns the part registry (part name → content type + optional
|
|
5
|
+
* document-level relationship), the relationship-id allocator, and the
|
|
6
|
+
* ordered file map handed to the zip assembler. All allocation is
|
|
7
|
+
* deterministic: ids are sequential counters, never random, and no part of
|
|
8
|
+
* the compiler reads the clock.
|
|
9
|
+
*/
|
|
10
|
+
export type RegisteredPart = {
|
|
11
|
+
/** Zip path, e.g. 'word/header1.xml'. */
|
|
12
|
+
name: string;
|
|
13
|
+
/** Content type registered as an Override in [Content_Types].xml. */
|
|
14
|
+
contentType: string;
|
|
15
|
+
/** Relationship from word/document.xml, when the part is document-attached. */
|
|
16
|
+
documentRel?: {
|
|
17
|
+
type: string;
|
|
18
|
+
rId: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export declare class CompileContext {
|
|
22
|
+
private readonly partsByName;
|
|
23
|
+
private readonly fileContents;
|
|
24
|
+
private nextRid;
|
|
25
|
+
private nextHeaderIndex;
|
|
26
|
+
private nextFooterIndex;
|
|
27
|
+
/** Register a part that needs a content-type Override (content set separately). */
|
|
28
|
+
registerPart(name: string, contentType: string, documentRelType?: string): RegisteredPart;
|
|
29
|
+
allocateRid(): string;
|
|
30
|
+
allocateHeaderPartName(): string;
|
|
31
|
+
allocateFooterPartName(): string;
|
|
32
|
+
setFileContent(name: string, content: string): void;
|
|
33
|
+
registeredParts(): RegisteredPart[];
|
|
34
|
+
documentRelParts(): RegisteredPart[];
|
|
35
|
+
/**
|
|
36
|
+
* Assemble the final zip-file record. [Content_Types].xml is placed first —
|
|
37
|
+
* createZipBuffer preserves insertion order but does not enforce ordering
|
|
38
|
+
* itself, so the contract lives here.
|
|
39
|
+
*/
|
|
40
|
+
toFileRecord(): Record<string, string>;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/generation/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,cAAc,GAAG;IAC3B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,WAAW,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C,CAAC;AAEF,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqC;IACjE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAC1D,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,eAAe,CAAK;IAE5B,mFAAmF;IACnF,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,cAAc;IAYzF,WAAW,IAAI,MAAM;IAIrB,sBAAsB,IAAI,MAAM;IAIhC,sBAAsB,IAAI,MAAM;IAIhC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAInD,eAAe,IAAI,cAAc,EAAE;IAInC,gBAAgB,IAAI,cAAc,EAAE;IAIpC;;;;OAIG;IACH,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAYvC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compile-time state shared by the part emitters.
|
|
3
|
+
*
|
|
4
|
+
* The context owns the part registry (part name → content type + optional
|
|
5
|
+
* document-level relationship), the relationship-id allocator, and the
|
|
6
|
+
* ordered file map handed to the zip assembler. All allocation is
|
|
7
|
+
* deterministic: ids are sequential counters, never random, and no part of
|
|
8
|
+
* the compiler reads the clock.
|
|
9
|
+
*/
|
|
10
|
+
export class CompileContext {
|
|
11
|
+
partsByName = new Map();
|
|
12
|
+
fileContents = new Map();
|
|
13
|
+
nextRid = 1;
|
|
14
|
+
nextHeaderIndex = 1;
|
|
15
|
+
nextFooterIndex = 1;
|
|
16
|
+
/** Register a part that needs a content-type Override (content set separately). */
|
|
17
|
+
registerPart(name, contentType, documentRelType) {
|
|
18
|
+
if (this.partsByName.has(name)) {
|
|
19
|
+
return this.partsByName.get(name);
|
|
20
|
+
}
|
|
21
|
+
const part = { name, contentType };
|
|
22
|
+
if (documentRelType) {
|
|
23
|
+
part.documentRel = { type: documentRelType, rId: this.allocateRid() };
|
|
24
|
+
}
|
|
25
|
+
this.partsByName.set(name, part);
|
|
26
|
+
return part;
|
|
27
|
+
}
|
|
28
|
+
allocateRid() {
|
|
29
|
+
return `rId${this.nextRid++}`;
|
|
30
|
+
}
|
|
31
|
+
allocateHeaderPartName() {
|
|
32
|
+
return `word/header${this.nextHeaderIndex++}.xml`;
|
|
33
|
+
}
|
|
34
|
+
allocateFooterPartName() {
|
|
35
|
+
return `word/footer${this.nextFooterIndex++}.xml`;
|
|
36
|
+
}
|
|
37
|
+
setFileContent(name, content) {
|
|
38
|
+
this.fileContents.set(name, content);
|
|
39
|
+
}
|
|
40
|
+
registeredParts() {
|
|
41
|
+
return Array.from(this.partsByName.values());
|
|
42
|
+
}
|
|
43
|
+
documentRelParts() {
|
|
44
|
+
return this.registeredParts().filter((p) => p.documentRel);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Assemble the final zip-file record. [Content_Types].xml is placed first —
|
|
48
|
+
* createZipBuffer preserves insertion order but does not enforce ordering
|
|
49
|
+
* itself, so the contract lives here.
|
|
50
|
+
*/
|
|
51
|
+
toFileRecord() {
|
|
52
|
+
const contentTypes = this.fileContents.get('[Content_Types].xml');
|
|
53
|
+
if (contentTypes === undefined) {
|
|
54
|
+
throw new Error('compile bug: [Content_Types].xml was never emitted');
|
|
55
|
+
}
|
|
56
|
+
const record = { '[Content_Types].xml': contentTypes };
|
|
57
|
+
for (const [name, content] of this.fileContents) {
|
|
58
|
+
if (name === '[Content_Types].xml')
|
|
59
|
+
continue;
|
|
60
|
+
record[name] = content;
|
|
61
|
+
}
|
|
62
|
+
return record;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/generation/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAWH,MAAM,OAAO,cAAc;IACR,WAAW,GAAG,IAAI,GAAG,EAA0B,CAAC;IAChD,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;IAClD,OAAO,GAAG,CAAC,CAAC;IACZ,eAAe,GAAG,CAAC,CAAC;IACpB,eAAe,GAAG,CAAC,CAAC;IAE5B,mFAAmF;IACnF,YAAY,CAAC,IAAY,EAAE,WAAmB,EAAE,eAAwB;QACtE,IAAI,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;QACrC,CAAC;QACD,MAAM,IAAI,GAAmB,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;QACnD,IAAI,eAAe,EAAE,CAAC;YACpB,IAAI,CAAC,WAAW,GAAG,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACxE,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,WAAW;QACT,OAAO,MAAM,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;IAChC,CAAC;IAED,sBAAsB;QACpB,OAAO,cAAc,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC;IACpD,CAAC;IAED,sBAAsB;QACpB,OAAO,cAAc,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC;IACpD,CAAC;IAED,cAAc,CAAC,IAAY,EAAE,OAAe;QAC1C,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAED,eAAe;QACb,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,gBAAgB;QACd,OAAO,IAAI,CAAC,eAAe,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC7D,CAAC;IAED;;;;OAIG;IACH,YAAY;QACV,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;QAClE,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACxE,CAAC;QACD,MAAM,MAAM,GAA2B,EAAE,qBAAqB,EAAE,YAAY,EAAE,CAAC;QAC/E,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YAChD,IAAI,IAAI,KAAK,qBAAqB;gBAAE,SAAS;YAC7C,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;QACzB,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drafting-note comment parts: word/comments.xml plus the Word-extension
|
|
3
|
+
* ancillary parts word/commentsExtended.xml and word/people.xml.
|
|
4
|
+
*
|
|
5
|
+
* All three are always emitted together when notes are enabled. The
|
|
6
|
+
* ancillary pair is deliberately on by default: plain comments.xml loads in
|
|
7
|
+
* every reader we test, but Word 2013+ writes the trio and its own comment
|
|
8
|
+
* UI degrades (no resolve state, no people presence) without them. Content
|
|
9
|
+
* and relationship types match what Word itself writes — verified against
|
|
10
|
+
* the Open XML SDK's WordprocessingCommentsExPart/WordprocessingPeoplePart
|
|
11
|
+
* constants (the `application/vnd.ms-word.commentsExtended+xml` variant
|
|
12
|
+
* found in some third-party packages is NOT what Word emits). They also
|
|
13
|
+
* match the editing path in primitives/comments.ts, so a generated document
|
|
14
|
+
* is indistinguishable from an edited one to the comment APIs.
|
|
15
|
+
*
|
|
16
|
+
* Determinism: comment ids are allocated in document order by the
|
|
17
|
+
* DraftingNoteCollector; w14:paraId values derive from those ids; dates come
|
|
18
|
+
* only from DraftingNoteSpec.dateIso (falling back to meta.createdIso);
|
|
19
|
+
* authors fall back note.author → meta.author → 'safe-docx'. No clock, no
|
|
20
|
+
* randomness — identical specs produce byte-identical comment parts.
|
|
21
|
+
*
|
|
22
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.13.4.6
|
|
23
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.13.4.2
|
|
24
|
+
*/
|
|
25
|
+
import type { CompileContext } from '../context.js';
|
|
26
|
+
import type { DocumentSpec } from '../types.js';
|
|
27
|
+
import type { DraftingNoteCollector } from './emit-context.js';
|
|
28
|
+
export declare const COMMENTS_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml";
|
|
29
|
+
export declare const COMMENTS_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
|
|
30
|
+
export declare const COMMENTS_EXTENDED_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml";
|
|
31
|
+
export declare const COMMENTS_EXTENDED_REL_TYPE = "http://schemas.microsoft.com/office/2011/relationships/commentsExtended";
|
|
32
|
+
export declare const PEOPLE_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.people+xml";
|
|
33
|
+
export declare const PEOPLE_REL_TYPE = "http://schemas.microsoft.com/office/2011/relationships/people";
|
|
34
|
+
/** Emit the comment trio from the notes collected during body emission. */
|
|
35
|
+
export declare function emitCommentsPartsIfNeeded(spec: DocumentSpec, ctx: CompileContext, collector: DraftingNoteCollector): void;
|
|
36
|
+
//# sourceMappingURL=comments-part.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comments-part.d.ts","sourceRoot":"","sources":["../../../src/generation/emit/comments-part.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE/D,eAAO,MAAM,qBAAqB,gFAAgF,CAAC;AACnH,eAAO,MAAM,iBAAiB,iFAAiF,CAAC;AAChH,eAAO,MAAM,8BAA8B,wFAC4C,CAAC;AACxF,eAAO,MAAM,0BAA0B,4EAA4E,CAAC;AACpH,eAAO,MAAM,mBAAmB,8EAA8E,CAAC;AAC/G,eAAO,MAAM,eAAe,kEAAkE,CAAC;AAyB/F,2EAA2E;AAC3E,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,YAAY,EAClB,GAAG,EAAE,cAAc,EACnB,SAAS,EAAE,qBAAqB,GAC/B,IAAI,CAUN"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drafting-note comment parts: word/comments.xml plus the Word-extension
|
|
3
|
+
* ancillary parts word/commentsExtended.xml and word/people.xml.
|
|
4
|
+
*
|
|
5
|
+
* All three are always emitted together when notes are enabled. The
|
|
6
|
+
* ancillary pair is deliberately on by default: plain comments.xml loads in
|
|
7
|
+
* every reader we test, but Word 2013+ writes the trio and its own comment
|
|
8
|
+
* UI degrades (no resolve state, no people presence) without them. Content
|
|
9
|
+
* and relationship types match what Word itself writes — verified against
|
|
10
|
+
* the Open XML SDK's WordprocessingCommentsExPart/WordprocessingPeoplePart
|
|
11
|
+
* constants (the `application/vnd.ms-word.commentsExtended+xml` variant
|
|
12
|
+
* found in some third-party packages is NOT what Word emits). They also
|
|
13
|
+
* match the editing path in primitives/comments.ts, so a generated document
|
|
14
|
+
* is indistinguishable from an edited one to the comment APIs.
|
|
15
|
+
*
|
|
16
|
+
* Determinism: comment ids are allocated in document order by the
|
|
17
|
+
* DraftingNoteCollector; w14:paraId values derive from those ids; dates come
|
|
18
|
+
* only from DraftingNoteSpec.dateIso (falling back to meta.createdIso);
|
|
19
|
+
* authors fall back note.author → meta.author → 'safe-docx'. No clock, no
|
|
20
|
+
* randomness — identical specs produce byte-identical comment parts.
|
|
21
|
+
*
|
|
22
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.13.4.6
|
|
23
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.13.4.2
|
|
24
|
+
*/
|
|
25
|
+
import { createWmlElement, createWmlTextElement } from '../../primitives/dom-helpers.js';
|
|
26
|
+
import { OOXML, W } from '../../primitives/namespaces.js';
|
|
27
|
+
import { parseXml, serializeXml, XML_DECL } from '../../primitives/xml.js';
|
|
28
|
+
export const COMMENTS_CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml';
|
|
29
|
+
export const COMMENTS_REL_TYPE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments';
|
|
30
|
+
export const COMMENTS_EXTENDED_CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml';
|
|
31
|
+
export const COMMENTS_EXTENDED_REL_TYPE = 'http://schemas.microsoft.com/office/2011/relationships/commentsExtended';
|
|
32
|
+
export const PEOPLE_CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.wordprocessingml.people+xml';
|
|
33
|
+
export const PEOPLE_REL_TYPE = 'http://schemas.microsoft.com/office/2011/relationships/people';
|
|
34
|
+
const COMMENTS_SKELETON = `<w:comments xmlns:w="${OOXML.W_NS}" xmlns:w14="${OOXML.W14_NS}"/>`;
|
|
35
|
+
const DEFAULT_AUTHOR = 'safe-docx';
|
|
36
|
+
/** Deterministic w14:paraId for a comment id: zero-padded uppercase hex. */
|
|
37
|
+
function paraIdFor(id) {
|
|
38
|
+
return id.toString(16).toUpperCase().padStart(8, '0');
|
|
39
|
+
}
|
|
40
|
+
function authorFor(spec, note) {
|
|
41
|
+
return note.author ?? spec.meta?.author ?? DEFAULT_AUTHOR;
|
|
42
|
+
}
|
|
43
|
+
/** Up-to-three-letter initials from the author's words, deterministic. */
|
|
44
|
+
function initialsFor(author) {
|
|
45
|
+
const letters = author
|
|
46
|
+
.split(/\s+/)
|
|
47
|
+
.map((word) => word.replace(/[^\p{L}\p{N}]/gu, '').charAt(0))
|
|
48
|
+
.filter((c) => c.length > 0);
|
|
49
|
+
const initials = letters.slice(0, 3).join('').toUpperCase();
|
|
50
|
+
return initials.length > 0 ? initials : 'SD';
|
|
51
|
+
}
|
|
52
|
+
/** Emit the comment trio from the notes collected during body emission. */
|
|
53
|
+
export function emitCommentsPartsIfNeeded(spec, ctx, collector) {
|
|
54
|
+
if (collector.collected.length === 0)
|
|
55
|
+
return;
|
|
56
|
+
ctx.registerPart('word/comments.xml', COMMENTS_CONTENT_TYPE, COMMENTS_REL_TYPE);
|
|
57
|
+
ctx.registerPart('word/commentsExtended.xml', COMMENTS_EXTENDED_CONTENT_TYPE, COMMENTS_EXTENDED_REL_TYPE);
|
|
58
|
+
ctx.registerPart('word/people.xml', PEOPLE_CONTENT_TYPE, PEOPLE_REL_TYPE);
|
|
59
|
+
ctx.setFileContent('word/comments.xml', emitCommentsXml(spec, collector));
|
|
60
|
+
ctx.setFileContent('word/commentsExtended.xml', emitCommentsExtendedXml(collector));
|
|
61
|
+
ctx.setFileContent('word/people.xml', emitPeopleXml(spec, collector));
|
|
62
|
+
}
|
|
63
|
+
function emitCommentsXml(spec, collector) {
|
|
64
|
+
const doc = parseXml(COMMENTS_SKELETON);
|
|
65
|
+
const root = doc.documentElement;
|
|
66
|
+
for (const { id, note } of collector.collected) {
|
|
67
|
+
const attrs = {
|
|
68
|
+
'w:id': String(id),
|
|
69
|
+
'w:author': authorFor(spec, note),
|
|
70
|
+
'w:initials': initialsFor(authorFor(spec, note)),
|
|
71
|
+
};
|
|
72
|
+
const dateIso = note.dateIso ?? spec.meta?.createdIso;
|
|
73
|
+
if (dateIso !== undefined)
|
|
74
|
+
attrs['w:date'] = dateIso;
|
|
75
|
+
const comment = createWmlElement(doc, W.comment, attrs);
|
|
76
|
+
const p = createWmlElement(doc, W.p);
|
|
77
|
+
p.setAttributeNS(OOXML.W14_NS, 'w14:paraId', paraIdFor(id));
|
|
78
|
+
const run = createWmlElement(doc, W.r);
|
|
79
|
+
run.appendChild(createWmlTextElement(doc, note.text));
|
|
80
|
+
p.appendChild(run);
|
|
81
|
+
comment.appendChild(p);
|
|
82
|
+
root.appendChild(comment);
|
|
83
|
+
}
|
|
84
|
+
return XML_DECL + serializeXml(doc);
|
|
85
|
+
}
|
|
86
|
+
function emitCommentsExtendedXml(collector) {
|
|
87
|
+
const doc = parseXml(`<w15:commentsEx xmlns:w15="${OOXML.W15_NS}"/>`);
|
|
88
|
+
const root = doc.documentElement;
|
|
89
|
+
for (const { id } of collector.collected) {
|
|
90
|
+
const commentEx = doc.createElementNS(OOXML.W15_NS, 'w15:commentEx');
|
|
91
|
+
commentEx.setAttributeNS(OOXML.W15_NS, 'w15:paraId', paraIdFor(id));
|
|
92
|
+
commentEx.setAttributeNS(OOXML.W15_NS, 'w15:done', '0');
|
|
93
|
+
root.appendChild(commentEx);
|
|
94
|
+
}
|
|
95
|
+
return XML_DECL + serializeXml(doc);
|
|
96
|
+
}
|
|
97
|
+
function emitPeopleXml(spec, collector) {
|
|
98
|
+
const doc = parseXml(`<w15:people xmlns:w15="${OOXML.W15_NS}"/>`);
|
|
99
|
+
const root = doc.documentElement;
|
|
100
|
+
const seen = new Set();
|
|
101
|
+
for (const { note } of collector.collected) {
|
|
102
|
+
const author = authorFor(spec, note);
|
|
103
|
+
if (seen.has(author))
|
|
104
|
+
continue;
|
|
105
|
+
seen.add(author);
|
|
106
|
+
const person = doc.createElementNS(OOXML.W15_NS, 'w15:person');
|
|
107
|
+
person.setAttributeNS(OOXML.W15_NS, 'w15:author', author);
|
|
108
|
+
const presence = doc.createElementNS(OOXML.W15_NS, 'w15:presenceInfo');
|
|
109
|
+
presence.setAttributeNS(OOXML.W15_NS, 'w15:providerId', 'None');
|
|
110
|
+
presence.setAttributeNS(OOXML.W15_NS, 'w15:userId', author);
|
|
111
|
+
person.appendChild(presence);
|
|
112
|
+
root.appendChild(person);
|
|
113
|
+
}
|
|
114
|
+
return XML_DECL + serializeXml(doc);
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=comments-part.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comments-part.js","sourceRoot":"","sources":["../../../src/generation/emit/comments-part.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* word/document.xml emitter.
|
|
3
|
+
*
|
|
4
|
+
* Builds the main document part from a namespace-declaring skeleton: the
|
|
5
|
+
* skeleton string carries every namespace the part uses on the root element,
|
|
6
|
+
* and all children are created through the namespace-safe DOM helpers.
|
|
7
|
+
* xmldom's serializer omits the XML declaration, so it is prepended here;
|
|
8
|
+
* the structural validator asserts every part starts with one.
|
|
9
|
+
*/
|
|
10
|
+
import type { DocumentSpec } from '../types.js';
|
|
11
|
+
import type { BlockEmitContext } from './emit-context.js';
|
|
12
|
+
import { type SectionHeaderFooterRefs } from './section.js';
|
|
13
|
+
/**
|
|
14
|
+
* Compile the body: each section's blocks in order. Every non-final section
|
|
15
|
+
* ends with a dedicated break paragraph whose pPr contains only that
|
|
16
|
+
* section's sectPr (what Word itself emits on Insert → Section Break; it
|
|
17
|
+
* also sidesteps the trailing-table case), and the final section's
|
|
18
|
+
* properties bind as the body's last child.
|
|
19
|
+
*
|
|
20
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.6.18
|
|
21
|
+
* @conformance ECMA-376 edition 5, Part 1 § 17.6.17
|
|
22
|
+
*/
|
|
23
|
+
export declare function emitDocumentPart(spec: DocumentSpec, refs?: SectionHeaderFooterRefs[], ctx?: BlockEmitContext): string;
|
|
24
|
+
//# sourceMappingURL=document-part.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-part.d.ts","sourceRoot":"","sources":["../../../src/generation/emit/document-part.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAe,KAAK,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAOzE;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAgCrH"}
|