@bendyline/squisq-formats 0.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.
Files changed (61) hide show
  1. package/dist/chunk-532L4D5D.js +21 -0
  2. package/dist/chunk-532L4D5D.js.map +1 -0
  3. package/dist/chunk-67KIJHV2.js +21 -0
  4. package/dist/chunk-67KIJHV2.js.map +1 -0
  5. package/dist/chunk-KAK4V57E.js +387 -0
  6. package/dist/chunk-KAK4V57E.js.map +1 -0
  7. package/dist/chunk-MQHCXI56.js +1035 -0
  8. package/dist/chunk-MQHCXI56.js.map +1 -0
  9. package/dist/chunk-TBPD5PCU.js +1136 -0
  10. package/dist/chunk-TBPD5PCU.js.map +1 -0
  11. package/dist/chunk-ULLIPBEJ.js +271 -0
  12. package/dist/chunk-ULLIPBEJ.js.map +1 -0
  13. package/dist/docx/index.d.ts +108 -0
  14. package/dist/docx/index.js +14 -0
  15. package/dist/docx/index.js.map +1 -0
  16. package/dist/html/index.d.ts +166 -0
  17. package/dist/html/index.js +17 -0
  18. package/dist/html/index.js.map +1 -0
  19. package/dist/index.d.ts +7 -0
  20. package/dist/index.js +54 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/ooxml/index.d.ts +351 -0
  23. package/dist/ooxml/index.js +99 -0
  24. package/dist/ooxml/index.js.map +1 -0
  25. package/dist/pdf/index.d.ts +130 -0
  26. package/dist/pdf/index.js +15 -0
  27. package/dist/pdf/index.js.map +1 -0
  28. package/dist/pptx/index.d.ts +58 -0
  29. package/dist/pptx/index.js +13 -0
  30. package/dist/pptx/index.js.map +1 -0
  31. package/dist/xlsx/index.d.ts +58 -0
  32. package/dist/xlsx/index.js +13 -0
  33. package/dist/xlsx/index.js.map +1 -0
  34. package/package.json +85 -0
  35. package/src/__tests__/docxExport.test.ts +457 -0
  36. package/src/__tests__/docxImport.test.ts +410 -0
  37. package/src/__tests__/html.test.ts +295 -0
  38. package/src/__tests__/ooxml.test.ts +197 -0
  39. package/src/__tests__/pdfExport.test.ts +322 -0
  40. package/src/__tests__/pdfImport.test.ts +290 -0
  41. package/src/__tests__/roundTrip.test.ts +201 -0
  42. package/src/docx/export.ts +978 -0
  43. package/src/docx/import.ts +909 -0
  44. package/src/docx/index.ts +26 -0
  45. package/src/docx/styles.ts +145 -0
  46. package/src/html/htmlTemplate.ts +307 -0
  47. package/src/html/imageUtils.ts +66 -0
  48. package/src/html/index.ts +168 -0
  49. package/src/index.ts +51 -0
  50. package/src/ooxml/index.ts +87 -0
  51. package/src/ooxml/namespaces.ts +160 -0
  52. package/src/ooxml/reader.ts +218 -0
  53. package/src/ooxml/types.ts +104 -0
  54. package/src/ooxml/writer.ts +321 -0
  55. package/src/ooxml/xmlUtils.ts +123 -0
  56. package/src/pdf/export.ts +1029 -0
  57. package/src/pdf/import.ts +835 -0
  58. package/src/pdf/index.ts +29 -0
  59. package/src/pdf/styles.ts +180 -0
  60. package/src/pptx/index.ts +78 -0
  61. package/src/xlsx/index.ts +78 -0
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Round-trip tests: MarkdownDocument → DOCX → MarkdownDocument.
3
+ *
4
+ * Verifies that core document structures survive the export → import cycle.
5
+ */
6
+
7
+ import { describe, it, expect } from 'vitest';
8
+ import type {
9
+ MarkdownDocument,
10
+ MarkdownHeading,
11
+ MarkdownParagraph,
12
+ MarkdownStrong,
13
+ MarkdownEmphasis,
14
+ MarkdownInlineNode,
15
+ MarkdownBlockNode,
16
+ } from '@bendyline/squisq/markdown';
17
+
18
+ import { markdownDocToDocx } from '../docx/export';
19
+ import { docxToMarkdownDoc } from '../docx/import';
20
+
21
+ // ============================================
22
+ // Helpers
23
+ // ============================================
24
+
25
+ async function roundTrip(doc: MarkdownDocument): Promise<MarkdownDocument> {
26
+ const buffer = await markdownDocToDocx(doc);
27
+ return docxToMarkdownDoc(buffer);
28
+ }
29
+
30
+ /**
31
+ * Extract plain text from an inline node tree.
32
+ */
33
+ function extractText(node: MarkdownInlineNode): string {
34
+ if (node.type === 'text') return node.value;
35
+ if ('children' in node) return (node.children as MarkdownInlineNode[]).map(extractText).join('');
36
+ if ('value' in node) return node.value as string;
37
+ return '';
38
+ }
39
+
40
+ function extractBlockText(block: MarkdownBlockNode): string {
41
+ if ('children' in block)
42
+ return (block.children as MarkdownInlineNode[]).map(extractText).join('');
43
+ if ('value' in block) return block.value as string;
44
+ return '';
45
+ }
46
+
47
+ // ============================================
48
+ // Round-trip Tests
49
+ // ============================================
50
+
51
+ describe('DOCX round-trip', () => {
52
+ it('round-trips headings', async () => {
53
+ const original: MarkdownDocument = {
54
+ type: 'document',
55
+ children: [
56
+ {
57
+ type: 'heading',
58
+ depth: 1,
59
+ children: [{ type: 'text', value: 'Main Title' }],
60
+ } satisfies MarkdownHeading,
61
+ {
62
+ type: 'heading',
63
+ depth: 2,
64
+ children: [{ type: 'text', value: 'Section' }],
65
+ } satisfies MarkdownHeading,
66
+ ],
67
+ };
68
+
69
+ const result = await roundTrip(original);
70
+
71
+ expect(result.children.length).toBeGreaterThanOrEqual(2);
72
+ expect(result.children[0].type).toBe('heading');
73
+ expect((result.children[0] as MarkdownHeading).depth).toBe(1);
74
+ expect(extractBlockText(result.children[0])).toBe('Main Title');
75
+
76
+ expect(result.children[1].type).toBe('heading');
77
+ expect((result.children[1] as MarkdownHeading).depth).toBe(2);
78
+ expect(extractBlockText(result.children[1])).toBe('Section');
79
+ });
80
+
81
+ it('round-trips paragraphs', async () => {
82
+ const original: MarkdownDocument = {
83
+ type: 'document',
84
+ children: [
85
+ {
86
+ type: 'paragraph',
87
+ children: [{ type: 'text', value: 'Hello world' }],
88
+ } satisfies MarkdownParagraph,
89
+ {
90
+ type: 'paragraph',
91
+ children: [{ type: 'text', value: 'Second paragraph' }],
92
+ } satisfies MarkdownParagraph,
93
+ ],
94
+ };
95
+
96
+ const result = await roundTrip(original);
97
+
98
+ expect(result.children.length).toBe(2);
99
+ expect(extractBlockText(result.children[0])).toBe('Hello world');
100
+ expect(extractBlockText(result.children[1])).toBe('Second paragraph');
101
+ });
102
+
103
+ it('round-trips bold text', async () => {
104
+ const original: MarkdownDocument = {
105
+ type: 'document',
106
+ children: [
107
+ {
108
+ type: 'paragraph',
109
+ children: [
110
+ { type: 'text', value: 'Normal ' },
111
+ {
112
+ type: 'strong',
113
+ children: [{ type: 'text', value: 'bold' }],
114
+ } satisfies MarkdownStrong,
115
+ { type: 'text', value: ' text' },
116
+ ],
117
+ },
118
+ ],
119
+ };
120
+
121
+ const result = await roundTrip(original);
122
+ const para = result.children[0] as MarkdownParagraph;
123
+ expect(para.type).toBe('paragraph');
124
+
125
+ // Find the bold node
126
+ const boldNode = para.children.find((c: MarkdownInlineNode) => c.type === 'strong');
127
+ expect(boldNode).toBeDefined();
128
+ expect(extractText(boldNode!)).toBe('bold');
129
+ });
130
+
131
+ it('round-trips italic text', async () => {
132
+ const original: MarkdownDocument = {
133
+ type: 'document',
134
+ children: [
135
+ {
136
+ type: 'paragraph',
137
+ children: [
138
+ {
139
+ type: 'emphasis',
140
+ children: [{ type: 'text', value: 'italic' }],
141
+ } satisfies MarkdownEmphasis,
142
+ ],
143
+ },
144
+ ],
145
+ };
146
+
147
+ const result = await roundTrip(original);
148
+ const para = result.children[0] as MarkdownParagraph;
149
+ const italicNode = para.children.find((c: MarkdownInlineNode) => c.type === 'emphasis');
150
+ expect(italicNode).toBeDefined();
151
+ expect(extractText(italicNode!)).toBe('italic');
152
+ });
153
+
154
+ it('round-trips mixed content document', async () => {
155
+ const original: MarkdownDocument = {
156
+ type: 'document',
157
+ children: [
158
+ {
159
+ type: 'heading',
160
+ depth: 1,
161
+ children: [{ type: 'text', value: 'Document Title' }],
162
+ } satisfies MarkdownHeading,
163
+ {
164
+ type: 'paragraph',
165
+ children: [
166
+ { type: 'text', value: 'This is ' },
167
+ {
168
+ type: 'strong',
169
+ children: [{ type: 'text', value: 'important' }],
170
+ },
171
+ { type: 'text', value: ' content.' },
172
+ ],
173
+ },
174
+ {
175
+ type: 'heading',
176
+ depth: 2,
177
+ children: [{ type: 'text', value: 'Details' }],
178
+ } satisfies MarkdownHeading,
179
+ {
180
+ type: 'paragraph',
181
+ children: [{ type: 'text', value: 'More info here.' }],
182
+ },
183
+ ],
184
+ };
185
+
186
+ const result = await roundTrip(original);
187
+
188
+ // Should have at least 4 blocks
189
+ expect(result.children.length).toBeGreaterThanOrEqual(4);
190
+
191
+ // First should be heading
192
+ expect(result.children[0].type).toBe('heading');
193
+ expect(extractBlockText(result.children[0])).toBe('Document Title');
194
+
195
+ // Then paragraph with mixed content
196
+ expect(result.children[1].type).toBe('paragraph');
197
+ const fullText = (result.children[1] as MarkdownParagraph).children.map(extractText).join('');
198
+ expect(fullText).toContain('important');
199
+ expect(fullText).toContain('content');
200
+ });
201
+ });