@bendyline/squisq-formats 2.0.0 → 2.1.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/dist/{chunk-CX3LH47J.js → chunk-74GO3FVS.js} +3 -3
- package/dist/{chunk-4HJ6AK2Q.js → chunk-7ARKUCQT.js} +52 -13
- package/dist/chunk-7ARKUCQT.js.map +1 -0
- package/dist/{chunk-LXYLOOST.js → chunk-DTDF6QDP.js} +3 -3
- package/dist/chunk-DTDF6QDP.js.map +1 -0
- package/dist/{chunk-ZZ7D4DN6.js → chunk-EW54IRRS.js} +39 -9
- package/dist/chunk-EW54IRRS.js.map +1 -0
- package/dist/{chunk-H7T5DXUU.js → chunk-FE6OJV6O.js} +95 -14
- package/dist/chunk-FE6OJV6O.js.map +1 -0
- package/dist/{chunk-XTLQXR4U.js → chunk-KURGXM4I.js} +3 -3
- package/dist/{chunk-2CSZJEAL.js → chunk-NNHKUXKA.js} +292 -70
- package/dist/chunk-NNHKUXKA.js.map +1 -0
- package/dist/{chunk-2PRVLAU3.js → chunk-QFLDYKCR.js} +55 -17
- package/dist/chunk-QFLDYKCR.js.map +1 -0
- package/dist/{chunk-CVNVD7VH.js → chunk-RLU7UFYU.js} +5 -5
- package/dist/{chunk-X4USWOQ2.js → chunk-SC67HYQJ.js} +2 -2
- package/dist/{chunk-HBSCRS5P.js → chunk-UGYF5AZE.js} +3 -3
- package/dist/{chunk-2EFDWKC6.js → chunk-WQSHGBLN.js} +86 -23
- package/dist/chunk-WQSHGBLN.js.map +1 -0
- package/dist/container/index.d.ts +10 -4
- package/dist/container/index.js +9 -4
- package/dist/container/index.js.map +1 -1
- package/dist/docx/index.d.ts +2 -2
- package/dist/docx/index.js +5 -4
- package/dist/{export-Djev9BLU.d.ts → export-D2NkylDT.d.ts} +1 -1
- package/dist/{extract-LNOA7DBK.js → extract-OJ7ZQV6P.js} +5 -5
- package/dist/html/index.js +1 -1
- package/dist/{import-Yivc3kZM.d.ts → import-K8mfc0fz.d.ts} +1 -1
- package/dist/index.d.ts +8 -7
- package/dist/index.js +15 -13
- package/dist/infer/index.d.ts +4 -4
- package/dist/infer/index.js +5 -5
- package/dist/{layouts-7OUUVAGU.js → layouts-5VDIRPIJ.js} +4 -4
- package/dist/{layouts-CZ0bdsNL.d.ts → layouts-BHrgZ5FS.d.ts} +1 -1
- package/dist/ooxml/index.d.ts +4 -4
- package/dist/ooxml/index.js +4 -4
- package/dist/pptx/index.d.ts +5 -5
- package/dist/pptx/index.js +5 -5
- package/dist/{reader-Gof6OrJX.d.ts → reader-B9L8Ucbj.d.ts} +3 -3
- package/dist/registry/index.d.ts +20 -6
- package/dist/registry/index.js +6 -4
- package/dist/{themeReader-DPw4J5Ss.d.ts → themeReader-DJKErl_j.d.ts} +1 -1
- package/dist/xlsx/index.d.ts +4 -4
- package/dist/xlsx/index.js +4 -4
- package/dist/{zipLimits-bGYMS9cI.d.ts → zipLimits-BOKCB7qk.d.ts} +2 -0
- package/package.json +2 -2
- package/src/__tests__/convert.test.ts +143 -1
- package/src/__tests__/docxExport.test.ts +34 -0
- package/src/__tests__/docxImport.test.ts +121 -0
- package/src/__tests__/html.test.ts +4 -0
- package/src/__tests__/ooxml.test.ts +17 -0
- package/src/__tests__/ooxmlCancellation.test.ts +113 -0
- package/src/container/index.ts +17 -3
- package/src/docx/export.ts +113 -5
- package/src/docx/import.ts +324 -69
- package/src/html/htmlTemplate.ts +2 -2
- package/src/index.ts +3 -0
- package/src/infer/index.ts +35 -4
- package/src/ooxml/namespaces.ts +21 -0
- package/src/ooxml/reader.ts +55 -14
- package/src/pptx/layouts.ts +68 -14
- package/src/registry/convert.ts +115 -31
- package/src/registry/defaultFormats.ts +5 -2
- package/src/registry/index.ts +3 -1
- package/src/registry/types.ts +18 -1
- package/src/shared/boundedZipArchive.ts +49 -8
- package/src/shared/zipEntryCount.ts +59 -5
- package/src/shared/zipLimits.ts +10 -0
- package/dist/chunk-2CSZJEAL.js.map +0 -1
- package/dist/chunk-2EFDWKC6.js.map +0 -1
- package/dist/chunk-2PRVLAU3.js.map +0 -1
- package/dist/chunk-4HJ6AK2Q.js.map +0 -1
- package/dist/chunk-H7T5DXUU.js.map +0 -1
- package/dist/chunk-LXYLOOST.js.map +0 -1
- package/dist/chunk-ZZ7D4DN6.js.map +0 -1
- /package/dist/{chunk-CX3LH47J.js.map → chunk-74GO3FVS.js.map} +0 -0
- /package/dist/{chunk-XTLQXR4U.js.map → chunk-KURGXM4I.js.map} +0 -0
- /package/dist/{chunk-CVNVD7VH.js.map → chunk-RLU7UFYU.js.map} +0 -0
- /package/dist/{chunk-X4USWOQ2.js.map → chunk-SC67HYQJ.js.map} +0 -0
- /package/dist/{chunk-HBSCRS5P.js.map → chunk-UGYF5AZE.js.map} +0 -0
- /package/dist/{extract-LNOA7DBK.js.map → extract-OJ7ZQV6P.js.map} +0 -0
- /package/dist/{layouts-7OUUVAGU.js.map → layouts-5VDIRPIJ.js.map} +0 -0
package/src/docx/export.ts
CHANGED
|
@@ -62,12 +62,16 @@ import {
|
|
|
62
62
|
REL_HYPERLINK,
|
|
63
63
|
REL_IMAGE,
|
|
64
64
|
REL_FOOTNOTES,
|
|
65
|
+
REL_HEADER,
|
|
66
|
+
REL_FOOTER,
|
|
65
67
|
CONTENT_TYPE_DOCX_DOCUMENT,
|
|
66
68
|
CONTENT_TYPE_DOCX_STYLES,
|
|
67
69
|
CONTENT_TYPE_DOCX_NUMBERING,
|
|
68
70
|
CONTENT_TYPE_DOCX_SETTINGS,
|
|
69
71
|
CONTENT_TYPE_DOCX_FONT_TABLE,
|
|
70
72
|
CONTENT_TYPE_DOCX_FOOTNOTES,
|
|
73
|
+
CONTENT_TYPE_DOCX_HEADER,
|
|
74
|
+
CONTENT_TYPE_DOCX_FOOTER,
|
|
71
75
|
} from '../ooxml/namespaces.js';
|
|
72
76
|
import {
|
|
73
77
|
DEPTH_TO_STYLE_ID,
|
|
@@ -135,8 +139,35 @@ export async function markdownDocToDocx(
|
|
|
135
139
|
? options
|
|
136
140
|
: { ...options, themeId: readFrontmatterThemeId(doc.frontmatter) };
|
|
137
141
|
const ctx = new ExportContext(resolvedOptions, doc);
|
|
138
|
-
const
|
|
139
|
-
|
|
142
|
+
const stories = partitionDocumentStories(doc.children);
|
|
143
|
+
ctx.setRelationshipSource('document');
|
|
144
|
+
const bodyXml = convertBlocks(stories.body, ctx);
|
|
145
|
+
ctx.setRelationshipSource('header');
|
|
146
|
+
const headerXml = convertBlocks(stories.header, ctx);
|
|
147
|
+
ctx.setRelationshipSource('footer');
|
|
148
|
+
const footerXml = convertBlocks(stories.footer, ctx);
|
|
149
|
+
ctx.setRelationshipSource('document');
|
|
150
|
+
return buildDocxPackage(bodyXml, headerXml, footerXml, ctx, resolvedOptions);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
interface DocumentStories {
|
|
154
|
+
body: MarkdownBlockNode[];
|
|
155
|
+
header: MarkdownBlockNode[];
|
|
156
|
+
footer: MarkdownBlockNode[];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function partitionDocumentStories(nodes: MarkdownBlockNode[]): DocumentStories {
|
|
160
|
+
const stories: DocumentStories = { body: [], header: [], footer: [] };
|
|
161
|
+
for (const node of nodes) {
|
|
162
|
+
if (node.type === 'containerDirective' && node.name === 'docx-header') {
|
|
163
|
+
stories.header.push(...node.children);
|
|
164
|
+
} else if (node.type === 'containerDirective' && node.name === 'docx-footer') {
|
|
165
|
+
stories.footer.push(...node.children);
|
|
166
|
+
} else {
|
|
167
|
+
stories.body.push(node);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return stories;
|
|
140
171
|
}
|
|
141
172
|
|
|
142
173
|
/**
|
|
@@ -172,8 +203,11 @@ class ExportContext {
|
|
|
172
203
|
type: string;
|
|
173
204
|
target: string;
|
|
174
205
|
targetMode?: 'External';
|
|
206
|
+
source: DocxStoryPart;
|
|
175
207
|
}> = [];
|
|
176
208
|
|
|
209
|
+
private relationshipSource: DocxStoryPart = 'document';
|
|
210
|
+
|
|
177
211
|
/** Numbering definitions (abstract + num) */
|
|
178
212
|
readonly numberingDefs: NumberingDef[] = [];
|
|
179
213
|
|
|
@@ -257,6 +291,10 @@ class ExportContext {
|
|
|
257
291
|
return `rId${this.nextRelId++}`;
|
|
258
292
|
}
|
|
259
293
|
|
|
294
|
+
setRelationshipSource(source: DocxStoryPart): void {
|
|
295
|
+
this.relationshipSource = source;
|
|
296
|
+
}
|
|
297
|
+
|
|
260
298
|
/** Add a hyperlink relationship and return the rId */
|
|
261
299
|
addHyperlink(url: string): string {
|
|
262
300
|
const id = this.allocRelId();
|
|
@@ -265,6 +303,7 @@ class ExportContext {
|
|
|
265
303
|
type: REL_HYPERLINK,
|
|
266
304
|
target: url,
|
|
267
305
|
targetMode: 'External',
|
|
306
|
+
source: this.relationshipSource,
|
|
268
307
|
});
|
|
269
308
|
return id;
|
|
270
309
|
}
|
|
@@ -284,6 +323,7 @@ class ExportContext {
|
|
|
284
323
|
id: relId,
|
|
285
324
|
type: REL_IMAGE,
|
|
286
325
|
target: `media/${filename}`,
|
|
326
|
+
source: this.relationshipSource,
|
|
287
327
|
});
|
|
288
328
|
|
|
289
329
|
return { relId, docPrId };
|
|
@@ -309,6 +349,8 @@ class ExportContext {
|
|
|
309
349
|
}
|
|
310
350
|
}
|
|
311
351
|
|
|
352
|
+
type DocxStoryPart = 'document' | 'header' | 'footer';
|
|
353
|
+
|
|
312
354
|
interface NumberingDef {
|
|
313
355
|
numId: number;
|
|
314
356
|
ordered: boolean;
|
|
@@ -384,6 +426,10 @@ function convertBlock(node: MarkdownBlockNode, ctx: ExportContext, listDepth: nu
|
|
|
384
426
|
return convertMathBlock(node);
|
|
385
427
|
case 'footnoteDefinition':
|
|
386
428
|
return convertFootnoteDefinition(node, ctx);
|
|
429
|
+
case 'containerDirective':
|
|
430
|
+
// Non-DOCX directives have no native Word wrapper. Preserve their
|
|
431
|
+
// contents rather than silently dropping the entire subtree.
|
|
432
|
+
return convertBlocks(node.children, ctx);
|
|
387
433
|
default:
|
|
388
434
|
// Definition lists, directives, link definitions — skip or emit as plain text
|
|
389
435
|
return '';
|
|
@@ -858,6 +904,8 @@ function convertFootnoteRef(node: MarkdownFootnoteReference, ctx: ExportContext)
|
|
|
858
904
|
|
|
859
905
|
async function buildDocxPackage(
|
|
860
906
|
bodyXml: string,
|
|
907
|
+
headerXml: string,
|
|
908
|
+
footerXml: string,
|
|
861
909
|
ctx: ExportContext,
|
|
862
910
|
options: DocxExportOptions,
|
|
863
911
|
): Promise<ArrayBuffer> {
|
|
@@ -870,11 +918,27 @@ async function buildDocxPackage(
|
|
|
870
918
|
const settingsRelId = `rId${relCounter++}`;
|
|
871
919
|
const fontTableRelId = `rId${relCounter++}`;
|
|
872
920
|
const footnotesRelId = `rId${relCounter++}`;
|
|
921
|
+
const headerRelId = `rId${relCounter++}`;
|
|
922
|
+
const footerRelId = `rId${relCounter++}`;
|
|
923
|
+
const hasHeader = headerXml.trim().length > 0;
|
|
924
|
+
const hasFooter = footerXml.trim().length > 0;
|
|
873
925
|
|
|
874
926
|
// --- word/document.xml ---
|
|
875
|
-
const documentXml = buildDocumentXml(
|
|
927
|
+
const documentXml = buildDocumentXml(
|
|
928
|
+
bodyXml,
|
|
929
|
+
ctx.backgroundColor,
|
|
930
|
+
hasHeader ? headerRelId : undefined,
|
|
931
|
+
hasFooter ? footerRelId : undefined,
|
|
932
|
+
);
|
|
876
933
|
pkg.addPart('word/document.xml', documentXml, CONTENT_TYPE_DOCX_DOCUMENT);
|
|
877
934
|
|
|
935
|
+
if (hasHeader) {
|
|
936
|
+
pkg.addPart('word/header1.xml', buildStoryXml('header', headerXml), CONTENT_TYPE_DOCX_HEADER);
|
|
937
|
+
}
|
|
938
|
+
if (hasFooter) {
|
|
939
|
+
pkg.addPart('word/footer1.xml', buildStoryXml('footer', footerXml), CONTENT_TYPE_DOCX_FOOTER);
|
|
940
|
+
}
|
|
941
|
+
|
|
878
942
|
// --- word/styles.xml ---
|
|
879
943
|
const stylesXml = buildStylesXml(options, ctx);
|
|
880
944
|
pkg.addPart('word/styles.xml', stylesXml, CONTENT_TYPE_DOCX_STYLES);
|
|
@@ -942,9 +1006,31 @@ async function buildDocxPackage(
|
|
|
942
1006
|
});
|
|
943
1007
|
}
|
|
944
1008
|
|
|
1009
|
+
if (hasHeader) {
|
|
1010
|
+
pkg.addRelationship('word/document.xml', {
|
|
1011
|
+
id: headerRelId,
|
|
1012
|
+
type: REL_HEADER,
|
|
1013
|
+
target: 'header1.xml',
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
if (hasFooter) {
|
|
1018
|
+
pkg.addRelationship('word/document.xml', {
|
|
1019
|
+
id: footerRelId,
|
|
1020
|
+
type: REL_FOOTER,
|
|
1021
|
+
target: 'footer1.xml',
|
|
1022
|
+
});
|
|
1023
|
+
}
|
|
1024
|
+
|
|
945
1025
|
// --- Dynamic relationships (hyperlinks, images) ---
|
|
946
1026
|
for (const rel of ctx.relationships) {
|
|
947
|
-
|
|
1027
|
+
const sourcePart =
|
|
1028
|
+
rel.source === 'header'
|
|
1029
|
+
? 'word/header1.xml'
|
|
1030
|
+
: rel.source === 'footer'
|
|
1031
|
+
? 'word/footer1.xml'
|
|
1032
|
+
: 'word/document.xml';
|
|
1033
|
+
pkg.addRelationship(sourcePart, {
|
|
948
1034
|
id: rel.id,
|
|
949
1035
|
type: rel.type,
|
|
950
1036
|
target: rel.target,
|
|
@@ -975,11 +1061,19 @@ async function buildDocxPackage(
|
|
|
975
1061
|
// XML Part Generators
|
|
976
1062
|
// ============================================
|
|
977
1063
|
|
|
978
|
-
function buildDocumentXml(
|
|
1064
|
+
function buildDocumentXml(
|
|
1065
|
+
bodyXml: string,
|
|
1066
|
+
backgroundColor?: string,
|
|
1067
|
+
headerRelId?: string,
|
|
1068
|
+
footerRelId?: string,
|
|
1069
|
+
): string {
|
|
979
1070
|
// `<w:background>` must be the FIRST child of `<w:document>` per the
|
|
980
1071
|
// WordprocessingML schema. Word also requires `<w:displayBackgroundShape/>`
|
|
981
1072
|
// in settings.xml before the bg actually paints (see buildSettingsXml).
|
|
982
1073
|
const backgroundEl = backgroundColor ? `<w:background w:color="${backgroundColor}"/>` : '';
|
|
1074
|
+
const storyReferences =
|
|
1075
|
+
(headerRelId ? `<w:headerReference w:type="default" r:id="${headerRelId}"/>` : '') +
|
|
1076
|
+
(footerRelId ? `<w:footerReference w:type="default" r:id="${footerRelId}"/>` : '');
|
|
983
1077
|
return (
|
|
984
1078
|
xmlDeclaration() +
|
|
985
1079
|
`<w:document` +
|
|
@@ -997,6 +1091,7 @@ function buildDocumentXml(bodyXml: string, backgroundColor?: string): string {
|
|
|
997
1091
|
`<w:body>` +
|
|
998
1092
|
bodyXml +
|
|
999
1093
|
`<w:sectPr>` +
|
|
1094
|
+
storyReferences +
|
|
1000
1095
|
`<w:pgSz w:w="12240" w:h="15840"/>` +
|
|
1001
1096
|
`<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="720" w:footer="720" w:gutter="0"/>` +
|
|
1002
1097
|
`<w:cols w:space="720"/>` +
|
|
@@ -1006,6 +1101,19 @@ function buildDocumentXml(bodyXml: string, backgroundColor?: string): string {
|
|
|
1006
1101
|
);
|
|
1007
1102
|
}
|
|
1008
1103
|
|
|
1104
|
+
function buildStoryXml(kind: 'header' | 'footer', bodyXml: string): string {
|
|
1105
|
+
const element = kind === 'header' ? 'hdr' : 'ftr';
|
|
1106
|
+
return (
|
|
1107
|
+
xmlDeclaration() +
|
|
1108
|
+
`<w:${element}` +
|
|
1109
|
+
` xmlns:w="${NS_WML}"` +
|
|
1110
|
+
` xmlns:r="${NS_R}"` +
|
|
1111
|
+
` xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing">` +
|
|
1112
|
+
bodyXml +
|
|
1113
|
+
`</w:${element}>`
|
|
1114
|
+
);
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1009
1117
|
function buildStylesXml(options: DocxExportOptions, ctx: ExportContext): string {
|
|
1010
1118
|
const font = ctx.font;
|
|
1011
1119
|
const headingFont = ctx.headingFont;
|