@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.
Files changed (232) hide show
  1. package/LICENSE +202 -21
  2. package/NOTICE +2 -0
  3. package/README.md +2 -2
  4. package/dist/.tsbuildinfo +1 -1
  5. package/dist/atomizer.d.ts +13 -7
  6. package/dist/atomizer.d.ts.map +1 -1
  7. package/dist/atomizer.js +59 -24
  8. package/dist/atomizer.js.map +1 -1
  9. package/dist/baselines/atomizer/auxiliaryIdCollision.d.ts +99 -0
  10. package/dist/baselines/atomizer/auxiliaryIdCollision.d.ts.map +1 -0
  11. package/dist/baselines/atomizer/auxiliaryIdCollision.js +415 -0
  12. package/dist/baselines/atomizer/auxiliaryIdCollision.js.map +1 -0
  13. package/dist/baselines/atomizer/documentReconstructor.d.ts.map +1 -1
  14. package/dist/baselines/atomizer/documentReconstructor.js +120 -27
  15. package/dist/baselines/atomizer/documentReconstructor.js.map +1 -1
  16. package/dist/baselines/atomizer/inPlaceModifier-wrappers.d.ts +9 -0
  17. package/dist/baselines/atomizer/inPlaceModifier-wrappers.d.ts.map +1 -1
  18. package/dist/baselines/atomizer/inPlaceModifier-wrappers.js +52 -4
  19. package/dist/baselines/atomizer/inPlaceModifier-wrappers.js.map +1 -1
  20. package/dist/baselines/atomizer/pipeline.d.ts +12 -53
  21. package/dist/baselines/atomizer/pipeline.d.ts.map +1 -1
  22. package/dist/baselines/atomizer/pipeline.js +126 -231
  23. package/dist/baselines/atomizer/pipeline.js.map +1 -1
  24. package/dist/baselines/atomizer/trackChangesAcceptorAst.d.ts.map +1 -1
  25. package/dist/baselines/atomizer/trackChangesAcceptorAst.js +153 -23
  26. package/dist/baselines/atomizer/trackChangesAcceptorAst.js.map +1 -1
  27. package/dist/baselines/wmlcomparer/DotnetCli.d.ts.map +1 -1
  28. package/dist/baselines/wmlcomparer/DotnetCli.js +7 -0
  29. package/dist/baselines/wmlcomparer/DotnetCli.js.map +1 -1
  30. package/dist/cli/compare-two.d.ts.map +1 -1
  31. package/dist/cli/compare-two.js +3 -1
  32. package/dist/cli/compare-two.js.map +1 -1
  33. package/dist/cli/conformance-adapter.d.ts +3 -0
  34. package/dist/cli/conformance-adapter.d.ts.map +1 -0
  35. package/dist/cli/conformance-adapter.js +93 -0
  36. package/dist/cli/conformance-adapter.js.map +1 -0
  37. package/dist/cli/index.d.ts.map +1 -1
  38. package/dist/cli/index.js +5 -1
  39. package/dist/cli/index.js.map +1 -1
  40. package/dist/compare-types.d.ts +46 -0
  41. package/dist/compare-types.d.ts.map +1 -1
  42. package/dist/generation/compile.d.ts +21 -0
  43. package/dist/generation/compile.d.ts.map +1 -0
  44. package/dist/generation/compile.js +46 -0
  45. package/dist/generation/compile.js.map +1 -0
  46. package/dist/generation/context.d.ts +42 -0
  47. package/dist/generation/context.d.ts.map +1 -0
  48. package/dist/generation/context.js +65 -0
  49. package/dist/generation/context.js.map +1 -0
  50. package/dist/generation/emit/comments-part.d.ts +36 -0
  51. package/dist/generation/emit/comments-part.d.ts.map +1 -0
  52. package/dist/generation/emit/comments-part.js +116 -0
  53. package/dist/generation/emit/comments-part.js.map +1 -0
  54. package/dist/generation/emit/document-part.d.ts +24 -0
  55. package/dist/generation/emit/document-part.d.ts.map +1 -0
  56. package/dist/generation/emit/document-part.js +60 -0
  57. package/dist/generation/emit/document-part.js.map +1 -0
  58. package/dist/generation/emit/emit-context.d.ts +26 -0
  59. package/dist/generation/emit/emit-context.d.ts.map +1 -0
  60. package/dist/generation/emit/emit-context.js +19 -0
  61. package/dist/generation/emit/emit-context.js.map +1 -0
  62. package/dist/generation/emit/header-footer-part.d.ts +23 -0
  63. package/dist/generation/emit/header-footer-part.d.ts.map +1 -0
  64. package/dist/generation/emit/header-footer-part.js +57 -0
  65. package/dist/generation/emit/header-footer-part.js.map +1 -0
  66. package/dist/generation/emit/numbering-part.d.ts +29 -0
  67. package/dist/generation/emit/numbering-part.d.ts.map +1 -0
  68. package/dist/generation/emit/numbering-part.js +100 -0
  69. package/dist/generation/emit/numbering-part.js.map +1 -0
  70. package/dist/generation/emit/package-parts.d.ts +24 -0
  71. package/dist/generation/emit/package-parts.d.ts.map +1 -0
  72. package/dist/generation/emit/package-parts.js +121 -0
  73. package/dist/generation/emit/package-parts.js.map +1 -0
  74. package/dist/generation/emit/paragraph.d.ts +24 -0
  75. package/dist/generation/emit/paragraph.d.ts.map +1 -0
  76. package/dist/generation/emit/paragraph.js +63 -0
  77. package/dist/generation/emit/paragraph.js.map +1 -0
  78. package/dist/generation/emit/properties.d.ts +34 -0
  79. package/dist/generation/emit/properties.d.ts.map +1 -0
  80. package/dist/generation/emit/properties.js +138 -0
  81. package/dist/generation/emit/properties.js.map +1 -0
  82. package/dist/generation/emit/run.d.ts +15 -0
  83. package/dist/generation/emit/run.d.ts.map +1 -0
  84. package/dist/generation/emit/run.js +71 -0
  85. package/dist/generation/emit/run.js.map +1 -0
  86. package/dist/generation/emit/section.d.ts +29 -0
  87. package/dist/generation/emit/section.d.ts.map +1 -0
  88. package/dist/generation/emit/section.js +117 -0
  89. package/dist/generation/emit/section.js.map +1 -0
  90. package/dist/generation/emit/settings-part.d.ts +13 -0
  91. package/dist/generation/emit/settings-part.d.ts.map +1 -0
  92. package/dist/generation/emit/settings-part.js +24 -0
  93. package/dist/generation/emit/settings-part.js.map +1 -0
  94. package/dist/generation/emit/styles-part.d.ts +16 -0
  95. package/dist/generation/emit/styles-part.d.ts.map +1 -0
  96. package/dist/generation/emit/styles-part.js +80 -0
  97. package/dist/generation/emit/styles-part.js.map +1 -0
  98. package/dist/generation/emit/table.d.ts +26 -0
  99. package/dist/generation/emit/table.d.ts.map +1 -0
  100. package/dist/generation/emit/table.js +196 -0
  101. package/dist/generation/emit/table.js.map +1 -0
  102. package/dist/generation/errors.d.ts +22 -0
  103. package/dist/generation/errors.d.ts.map +1 -0
  104. package/dist/generation/errors.js +29 -0
  105. package/dist/generation/errors.js.map +1 -0
  106. package/dist/generation/index.d.ts +13 -0
  107. package/dist/generation/index.d.ts.map +1 -0
  108. package/dist/generation/index.js +12 -0
  109. package/dist/generation/index.js.map +1 -0
  110. package/dist/generation/ordering.d.ts +46 -0
  111. package/dist/generation/ordering.d.ts.map +1 -0
  112. package/dist/generation/ordering.js +119 -0
  113. package/dist/generation/ordering.js.map +1 -0
  114. package/dist/generation/recipes.d.ts +47 -0
  115. package/dist/generation/recipes.d.ts.map +1 -0
  116. package/dist/generation/recipes.js +84 -0
  117. package/dist/generation/recipes.js.map +1 -0
  118. package/dist/generation/structural-checks.d.ts +24 -0
  119. package/dist/generation/structural-checks.d.ts.map +1 -0
  120. package/dist/generation/structural-checks.js +318 -0
  121. package/dist/generation/structural-checks.js.map +1 -0
  122. package/dist/generation/types.d.ts +217 -0
  123. package/dist/generation/types.d.ts.map +1 -0
  124. package/dist/generation/types.js +16 -0
  125. package/dist/generation/types.js.map +1 -0
  126. package/dist/generation/validate-spec.d.ts +27 -0
  127. package/dist/generation/validate-spec.d.ts.map +1 -0
  128. package/dist/generation/validate-spec.js +307 -0
  129. package/dist/generation/validate-spec.js.map +1 -0
  130. package/dist/index.d.ts +3 -0
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +8 -0
  133. package/dist/index.js.map +1 -1
  134. package/dist/integration/generation-probes.d.ts +15 -0
  135. package/dist/integration/generation-probes.d.ts.map +1 -0
  136. package/dist/integration/generation-probes.js +84 -0
  137. package/dist/integration/generation-probes.js.map +1 -0
  138. package/dist/integration/libreoffice-oracle.d.ts +8 -0
  139. package/dist/integration/libreoffice-oracle.d.ts.map +1 -1
  140. package/dist/integration/libreoffice-oracle.js +14 -6
  141. package/dist/integration/libreoffice-oracle.js.map +1 -1
  142. package/dist/integration/synthetic-docx-fixture.d.ts +72 -0
  143. package/dist/integration/synthetic-docx-fixture.d.ts.map +1 -1
  144. package/dist/integration/synthetic-docx-fixture.js +131 -4
  145. package/dist/integration/synthetic-docx-fixture.js.map +1 -1
  146. package/dist/primitives/accept_changes.d.ts +2 -1
  147. package/dist/primitives/accept_changes.d.ts.map +1 -1
  148. package/dist/primitives/accept_changes.js +153 -12
  149. package/dist/primitives/accept_changes.js.map +1 -1
  150. package/dist/primitives/document.d.ts +38 -0
  151. package/dist/primitives/document.d.ts.map +1 -1
  152. package/dist/primitives/document.js +75 -9
  153. package/dist/primitives/document.js.map +1 -1
  154. package/dist/primitives/document_view-comments.d.ts.map +1 -1
  155. package/dist/primitives/document_view-comments.js +4 -3
  156. package/dist/primitives/document_view-comments.js.map +1 -1
  157. package/dist/primitives/document_view-types.d.ts +15 -0
  158. package/dist/primitives/document_view-types.d.ts.map +1 -1
  159. package/dist/primitives/document_view.d.ts.map +1 -1
  160. package/dist/primitives/document_view.js +21 -13
  161. package/dist/primitives/document_view.js.map +1 -1
  162. package/dist/primitives/formatting_tags.d.ts +1 -0
  163. package/dist/primitives/formatting_tags.d.ts.map +1 -1
  164. package/dist/primitives/formatting_tags.js +16 -10
  165. package/dist/primitives/formatting_tags.js.map +1 -1
  166. package/dist/primitives/index.d.ts +4 -0
  167. package/dist/primitives/index.d.ts.map +1 -1
  168. package/dist/primitives/index.js +4 -0
  169. package/dist/primitives/index.js.map +1 -1
  170. package/dist/primitives/layout.d.ts.map +1 -1
  171. package/dist/primitives/layout.js +13 -0
  172. package/dist/primitives/layout.js.map +1 -1
  173. package/dist/primitives/minimal_save.d.ts +38 -0
  174. package/dist/primitives/minimal_save.d.ts.map +1 -0
  175. package/dist/primitives/minimal_save.js +323 -0
  176. package/dist/primitives/minimal_save.js.map +1 -0
  177. package/dist/primitives/namespaces.d.ts +41 -0
  178. package/dist/primitives/namespaces.d.ts.map +1 -1
  179. package/dist/primitives/namespaces.js +43 -0
  180. package/dist/primitives/namespaces.js.map +1 -1
  181. package/dist/primitives/reject_changes.d.ts +4 -2
  182. package/dist/primitives/reject_changes.d.ts.map +1 -1
  183. package/dist/primitives/reject_changes.js +177 -24
  184. package/dist/primitives/reject_changes.js.map +1 -1
  185. package/dist/primitives/revision-parts.d.ts +7 -0
  186. package/dist/primitives/revision-parts.d.ts.map +1 -0
  187. package/dist/primitives/revision-parts.js +27 -0
  188. package/dist/primitives/revision-parts.js.map +1 -0
  189. package/dist/primitives/revision-vocabulary.d.ts +7 -0
  190. package/dist/primitives/revision-vocabulary.d.ts.map +1 -0
  191. package/dist/primitives/revision-vocabulary.js +39 -0
  192. package/dist/primitives/revision-vocabulary.js.map +1 -0
  193. package/dist/primitives/schema-corpus-capture.d.ts +19 -0
  194. package/dist/primitives/schema-corpus-capture.d.ts.map +1 -0
  195. package/dist/primitives/schema-corpus-capture.js +29 -0
  196. package/dist/primitives/schema-corpus-capture.js.map +1 -0
  197. package/dist/primitives/sectPrAudit.d.ts +19 -0
  198. package/dist/primitives/sectPrAudit.d.ts.map +1 -0
  199. package/dist/primitives/sectPrAudit.js +165 -0
  200. package/dist/primitives/sectPrAudit.js.map +1 -0
  201. package/dist/primitives/semantic_tags.d.ts.map +1 -1
  202. package/dist/primitives/semantic_tags.js +2 -1
  203. package/dist/primitives/semantic_tags.js.map +1 -1
  204. package/dist/primitives/serialize_html.d.ts +1 -0
  205. package/dist/primitives/serialize_html.d.ts.map +1 -1
  206. package/dist/primitives/serialize_html.js +4 -2
  207. package/dist/primitives/serialize_html.js.map +1 -1
  208. package/dist/primitives/styles.d.ts +15 -0
  209. package/dist/primitives/styles.d.ts.map +1 -1
  210. package/dist/primitives/styles.js +11 -0
  211. package/dist/primitives/styles.js.map +1 -1
  212. package/dist/primitives/track-changes-emitter.d.ts +9 -0
  213. package/dist/primitives/track-changes-emitter.d.ts.map +1 -1
  214. package/dist/primitives/track-changes-emitter.js +54 -4
  215. package/dist/primitives/track-changes-emitter.js.map +1 -1
  216. package/dist/primitives/validate_ai_revisions.d.ts +35 -0
  217. package/dist/primitives/validate_ai_revisions.d.ts.map +1 -0
  218. package/dist/primitives/validate_ai_revisions.js +323 -0
  219. package/dist/primitives/validate_ai_revisions.js.map +1 -0
  220. package/dist/primitives/xml.d.ts +5 -0
  221. package/dist/primitives/xml.d.ts.map +1 -1
  222. package/dist/primitives/xml.js +5 -0
  223. package/dist/primitives/xml.js.map +1 -1
  224. package/dist/primitives/zip.d.ts +1 -0
  225. package/dist/primitives/zip.d.ts.map +1 -1
  226. package/dist/primitives/zip.js +21 -3
  227. package/dist/primitives/zip.js.map +1 -1
  228. package/dist/shared/field-structure.d.ts +14 -0
  229. package/dist/shared/field-structure.d.ts.map +1 -0
  230. package/dist/shared/field-structure.js +166 -0
  231. package/dist/shared/field-structure.js.map +1 -0
  232. package/package.json +7 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structural-checks.d.ts","sourceRoot":"","sources":["../../src/generation/structural-checks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAQH,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EACD,iBAAiB,GACjB,uBAAuB,GACvB,qBAAqB,GACrB,gBAAgB,GAChB,QAAQ,GACR,eAAe,GACf,OAAO,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B,CAAC;AAEF,qEAAqE;AACrE,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAkB1F"}
@@ -0,0 +1,318 @@
1
+ /**
2
+ * Post-build structural validation of a generated package — the
3
+ * "no recovery dialog" gate. Each check targets a concrete repair trigger in
4
+ * reading applications: missing content types, dangling relationship targets,
5
+ * unresolvable r:id references, malformed section properties, and unbalanced
6
+ * field characters.
7
+ *
8
+ * `auditSectPr` is reused as one component: it flags duplicated or misplaced
9
+ * body-level sectPr and dangling header/footer references, but tolerates the
10
+ * zero-sectPr case (legal for parsed third-party documents), so the
11
+ * required-final-sectPr check lives here.
12
+ */
13
+ import { auditSectPr } from '../primitives/sectPrAudit.js';
14
+ import { NODE_TYPE } from '../primitives/dom-helpers.js';
15
+ import { OOXML } from '../primitives/namespaces.js';
16
+ import { parseXml } from '../primitives/xml.js';
17
+ import { DocxZip } from '../primitives/zip.js';
18
+ /** Run every structural check against a generated package buffer. */
19
+ export async function checkGeneratedPackage(buffer) {
20
+ const zip = await DocxZip.load(buffer);
21
+ const files = zip.listFiles().filter((name) => !name.endsWith('/'));
22
+ const contents = new Map();
23
+ for (const name of files) {
24
+ contents.set(name, await zip.readText(name));
25
+ }
26
+ const issues = [
27
+ ...checkXmlDeclarations(contents),
28
+ ...checkContentTypeCoverage(contents),
29
+ ...checkRelationshipTargets(contents),
30
+ ...checkRidResolution(contents),
31
+ ...checkSectPr(contents),
32
+ ...checkFieldPairing(contents),
33
+ ...checkTables(contents),
34
+ ];
35
+ return { ok: issues.length === 0, issues };
36
+ }
37
+ function isXmlPart(name) {
38
+ return name.endsWith('.xml') || name.endsWith('.rels');
39
+ }
40
+ function checkXmlDeclarations(contents) {
41
+ const issues = [];
42
+ for (const [name, text] of contents) {
43
+ if (!isXmlPart(name))
44
+ continue;
45
+ if (!text.startsWith('<?xml')) {
46
+ issues.push({
47
+ check: 'xml_declaration',
48
+ part: name,
49
+ message: 'XML part does not begin with an <?xml declaration',
50
+ });
51
+ }
52
+ }
53
+ return issues;
54
+ }
55
+ function checkContentTypeCoverage(contents) {
56
+ const issues = [];
57
+ const contentTypes = contents.get('[Content_Types].xml');
58
+ if (!contentTypes) {
59
+ return [{ check: 'content_type_coverage', part: '[Content_Types].xml', message: 'Part is missing' }];
60
+ }
61
+ const doc = parseXml(contentTypes);
62
+ const defaults = new Set();
63
+ const overrides = new Set();
64
+ for (const el of Array.from(doc.getElementsByTagName('Default'))) {
65
+ const ext = el.getAttribute('Extension');
66
+ if (ext)
67
+ defaults.add(ext.toLowerCase());
68
+ }
69
+ for (const el of Array.from(doc.getElementsByTagName('Override'))) {
70
+ const part = el.getAttribute('PartName');
71
+ if (part)
72
+ overrides.add(part);
73
+ }
74
+ for (const name of contents.keys()) {
75
+ if (name === '[Content_Types].xml')
76
+ continue;
77
+ const extension = name.split('.').pop()?.toLowerCase() ?? '';
78
+ if (!overrides.has(`/${name}`) && !defaults.has(extension)) {
79
+ issues.push({
80
+ check: 'content_type_coverage',
81
+ part: name,
82
+ message: 'Part is covered by neither a content-type Default nor an Override',
83
+ });
84
+ }
85
+ }
86
+ return issues;
87
+ }
88
+ /** Directory ('word/' or '') whose relationships a .rels part declares. */
89
+ function relsOwnerDir(relsName) {
90
+ const marker = '_rels/';
91
+ const idx = relsName.lastIndexOf(marker);
92
+ return idx <= 0 ? '' : relsName.slice(0, idx);
93
+ }
94
+ function resolveTarget(ownerDir, target) {
95
+ const joined = target.startsWith('/') ? target.slice(1) : ownerDir + target;
96
+ const segments = [];
97
+ for (const segment of joined.split('/')) {
98
+ if (segment === '' || segment === '.')
99
+ continue;
100
+ if (segment === '..')
101
+ segments.pop();
102
+ else
103
+ segments.push(segment);
104
+ }
105
+ return segments.join('/');
106
+ }
107
+ function checkRelationshipTargets(contents) {
108
+ const issues = [];
109
+ for (const [name, text] of contents) {
110
+ if (!name.endsWith('.rels'))
111
+ continue;
112
+ const ownerDir = relsOwnerDir(name);
113
+ const doc = parseXml(text);
114
+ for (const rel of Array.from(doc.getElementsByTagName('Relationship'))) {
115
+ if (rel.getAttribute('TargetMode') === 'External')
116
+ continue;
117
+ const target = rel.getAttribute('Target');
118
+ if (!target) {
119
+ issues.push({ check: 'relationship_target', part: name, message: 'Relationship without Target' });
120
+ continue;
121
+ }
122
+ const resolved = resolveTarget(ownerDir, target);
123
+ if (!contents.has(resolved)) {
124
+ issues.push({
125
+ check: 'relationship_target',
126
+ part: name,
127
+ message: `Relationship target '${target}' resolves to missing part '${resolved}'`,
128
+ });
129
+ }
130
+ }
131
+ }
132
+ return issues;
133
+ }
134
+ function relsIdsFor(contents, partName) {
135
+ const dir = partName.includes('/') ? partName.slice(0, partName.lastIndexOf('/') + 1) : '';
136
+ const base = partName.slice(dir.length);
137
+ const relsName = `${dir}_rels/${base}.rels`;
138
+ const ids = new Set();
139
+ const text = contents.get(relsName);
140
+ if (!text)
141
+ return ids;
142
+ const doc = parseXml(text);
143
+ for (const rel of Array.from(doc.getElementsByTagName('Relationship'))) {
144
+ const id = rel.getAttribute('Id');
145
+ if (id)
146
+ ids.add(id);
147
+ }
148
+ return ids;
149
+ }
150
+ function checkRidResolution(contents) {
151
+ const issues = [];
152
+ for (const [name, text] of contents) {
153
+ if (!name.startsWith('word/') || !name.endsWith('.xml'))
154
+ continue;
155
+ const ids = relsIdsFor(contents, name);
156
+ const doc = parseXml(text);
157
+ const visit = (el) => {
158
+ for (let i = 0; i < el.attributes.length; i++) {
159
+ const attr = el.attributes[i];
160
+ const isRid = attr.namespaceURI === OOXML.R_NS || attr.name === 'r:id' || attr.name === 'r:embed';
161
+ if (!isRid)
162
+ continue;
163
+ if (!ids.has(attr.value)) {
164
+ issues.push({
165
+ check: 'rid_resolution',
166
+ part: name,
167
+ message: `<${el.tagName}> references relationship '${attr.value}' missing from this part's rels`,
168
+ });
169
+ }
170
+ }
171
+ for (let i = 0; i < el.childNodes.length; i++) {
172
+ const child = el.childNodes[i];
173
+ if (child.nodeType === NODE_TYPE.ELEMENT)
174
+ visit(child);
175
+ }
176
+ };
177
+ if (doc.documentElement)
178
+ visit(doc.documentElement);
179
+ }
180
+ return issues;
181
+ }
182
+ /**
183
+ * Generated documents must bind their final section explicitly: exactly one
184
+ * body-level w:sectPr, positioned last. auditSectPr supplies the placement
185
+ * and reference checks but allows the zero-sectPr case, hence the count
186
+ * assertion here.
187
+ *
188
+ * @conformance ECMA-376 edition 5, Part 1 § 17.6.17
189
+ */
190
+ function checkSectPr(contents) {
191
+ const issues = [];
192
+ const documentXml = contents.get('word/document.xml');
193
+ if (!documentXml) {
194
+ return [{ check: 'sectpr', part: 'word/document.xml', message: 'Part is missing' }];
195
+ }
196
+ const audit = auditSectPr(documentXml, contents.get('word/_rels/document.xml.rels') ?? null);
197
+ for (const issue of audit.issues) {
198
+ issues.push({ check: 'sectpr', part: 'word/document.xml', message: `${issue.type}: ${issue.message}` });
199
+ }
200
+ if (audit.stats.bodyLevelSectPrCount !== 1) {
201
+ issues.push({
202
+ check: 'sectpr',
203
+ part: 'word/document.xml',
204
+ message: `Expected exactly one body-level w:sectPr, found ${audit.stats.bodyLevelSectPrCount}`,
205
+ });
206
+ }
207
+ return issues;
208
+ }
209
+ function isStoryPart(name) {
210
+ return (name === 'word/document.xml' ||
211
+ /^word\/header\d+\.xml$/.test(name) ||
212
+ /^word\/footer\d+\.xml$/.test(name) ||
213
+ name === 'word/footnotes.xml' ||
214
+ name === 'word/endnotes.xml' ||
215
+ name === 'word/comments.xml');
216
+ }
217
+ function checkFieldPairing(contents) {
218
+ const issues = [];
219
+ for (const [name, text] of contents) {
220
+ if (!isStoryPart(name))
221
+ continue;
222
+ const doc = parseXml(text);
223
+ // Document-order walk over field-relevant leaves; fldChar transitions
224
+ // drive a begin → separate → end state machine per story part.
225
+ let state = 'idle';
226
+ const visit = (el) => {
227
+ if (el.tagName === 'w:fldChar') {
228
+ const type = el.getAttribute('w:fldCharType');
229
+ if (type === 'begin') {
230
+ if (state !== 'idle') {
231
+ issues.push({ check: 'field_pairing', part: name, message: 'fldChar begin while a field is already open' });
232
+ }
233
+ state = 'instr';
234
+ }
235
+ else if (type === 'separate') {
236
+ if (state !== 'instr') {
237
+ issues.push({ check: 'field_pairing', part: name, message: 'fldChar separate without a matching begin' });
238
+ }
239
+ state = 'result';
240
+ }
241
+ else if (type === 'end') {
242
+ if (state === 'idle') {
243
+ issues.push({ check: 'field_pairing', part: name, message: 'fldChar end without a matching begin' });
244
+ }
245
+ state = 'idle';
246
+ }
247
+ }
248
+ else if (el.tagName === 'w:instrText') {
249
+ if (state !== 'instr') {
250
+ issues.push({
251
+ check: 'field_pairing',
252
+ part: name,
253
+ message: 'w:instrText outside a begin→separate range',
254
+ });
255
+ }
256
+ }
257
+ for (let i = 0; i < el.childNodes.length; i++) {
258
+ const child = el.childNodes[i];
259
+ if (child.nodeType === NODE_TYPE.ELEMENT)
260
+ visit(child);
261
+ }
262
+ };
263
+ if (doc.documentElement)
264
+ visit(doc.documentElement);
265
+ if (state !== 'idle') {
266
+ issues.push({ check: 'field_pairing', part: name, message: 'Unclosed field at end of story part' });
267
+ }
268
+ }
269
+ return issues;
270
+ }
271
+ /**
272
+ * Table invariants readers actually enforce: every cell ends with a w:p,
273
+ * and the document body never ends with a table (the element preceding the
274
+ * body-level sectPr, or the last body child, must not be w:tbl).
275
+ *
276
+ * @conformance ECMA-376 edition 5, Part 1 § 17.4.65
277
+ */
278
+ function checkTables(contents) {
279
+ const issues = [];
280
+ for (const [name, text] of contents) {
281
+ if (!isStoryPart(name))
282
+ continue;
283
+ const doc = parseXml(text);
284
+ for (const tc of Array.from(doc.getElementsByTagName('w:tc'))) {
285
+ let last = null;
286
+ for (let child = tc.firstChild; child; child = child.nextSibling) {
287
+ if (child.nodeType === NODE_TYPE.ELEMENT)
288
+ last = child;
289
+ }
290
+ if (!last || last.tagName !== 'w:p') {
291
+ issues.push({
292
+ check: 'table',
293
+ part: name,
294
+ message: `Table cell ends with <${last?.tagName ?? 'nothing'}> instead of a w:p`,
295
+ });
296
+ }
297
+ }
298
+ if (name !== 'word/document.xml')
299
+ continue;
300
+ const body = doc.getElementsByTagName('w:body').item(0);
301
+ if (!body)
302
+ continue;
303
+ let lastContent = null;
304
+ for (let child = body.firstChild; child; child = child.nextSibling) {
305
+ if (child.nodeType !== NODE_TYPE.ELEMENT)
306
+ continue;
307
+ const el = child;
308
+ if (el.tagName === 'w:sectPr')
309
+ continue;
310
+ lastContent = el;
311
+ }
312
+ if (lastContent && lastContent.tagName === 'w:tbl') {
313
+ issues.push({ check: 'table', part: name, message: 'Document body ends with a w:tbl' });
314
+ }
315
+ }
316
+ return issues;
317
+ }
318
+ //# sourceMappingURL=structural-checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structural-checks.js","sourceRoot":"","sources":["../../src/generation/structural-checks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Declarative document specification for from-scratch DOCX generation.
3
+ *
4
+ * The entire surface is plain data: discriminated unions on `kind`, no Map /
5
+ * Date / class instances, explicit unit suffixes (`...Twips`, `...Pt`) instead
6
+ * of bare numbers. `JSON.parse(JSON.stringify(spec))` is identity over any
7
+ * valid spec, which is what lets a stored recipe (or, later, an MCP payload)
8
+ * compile without translation.
9
+ *
10
+ * The type surface intentionally covers the full feature set of the
11
+ * add-docx-generation change even though emitters land in phases; the
12
+ * compiler rejects any spec feature whose emitter has not shipped yet
13
+ * (see validate-spec.ts) rather than silently ignoring it.
14
+ */
15
+ export type DocumentSpec = {
16
+ meta?: DocumentMetaSpec;
17
+ /** Emitted to word/styles.xml. Document defaults + Normal are always emitted. */
18
+ styles?: StyleSpec[];
19
+ /** Emitted to word/numbering.xml when non-empty. */
20
+ numbering?: NumberingSpec[];
21
+ /** At least one section. The final section's properties bind at body level. */
22
+ sections: SectionSpec[];
23
+ options?: {
24
+ /** Default true. When false, drafting notes compile to nothing. */
25
+ includeDraftingNotes?: boolean;
26
+ };
27
+ };
28
+ export type DocumentMetaSpec = {
29
+ title?: string;
30
+ author?: string;
31
+ /** ISO-8601 timestamp used for docProps dates. Generation never reads the clock. */
32
+ createdIso?: string;
33
+ };
34
+ export type SectionSpec = {
35
+ page?: {
36
+ /** Defaults to US Letter (12240 × 15840). */
37
+ sizeTwips?: {
38
+ w: number;
39
+ h: number;
40
+ };
41
+ orientation?: 'portrait' | 'landscape';
42
+ marginsTwips?: {
43
+ top?: number;
44
+ right?: number;
45
+ bottom?: number;
46
+ left?: number;
47
+ header?: number;
48
+ footer?: number;
49
+ gutter?: number;
50
+ };
51
+ };
52
+ /** Section-break type for non-final sections (w:type). */
53
+ breakType?: 'nextPage' | 'continuous' | 'oddPage' | 'evenPage';
54
+ pageNumbering?: {
55
+ start?: number;
56
+ format?: 'decimal' | 'lowerRoman' | 'upperRoman' | 'lowerLetter' | 'upperLetter';
57
+ };
58
+ /** Auto-implied when headers.first or footers.first is present. */
59
+ titlePg?: boolean;
60
+ headers?: HeaderFooterSet;
61
+ footers?: HeaderFooterSet;
62
+ blocks: BlockSpec[];
63
+ };
64
+ export type HeaderFooterSet = {
65
+ default?: HeaderFooterSpec;
66
+ first?: HeaderFooterSpec;
67
+ even?: HeaderFooterSpec;
68
+ };
69
+ export type HeaderFooterSpec = {
70
+ blocks: BlockSpec[];
71
+ };
72
+ export type BlockSpec = ParagraphSpec | TableSpec;
73
+ export type ParagraphSpec = {
74
+ kind: 'paragraph';
75
+ /** Must resolve to a declared style (or the implicit Normal). */
76
+ styleId?: string;
77
+ alignment?: 'left' | 'center' | 'right' | 'justify';
78
+ spacing?: {
79
+ beforeTwips?: number;
80
+ afterTwips?: number;
81
+ lineTwips?: number;
82
+ lineRule?: 'auto' | 'exact' | 'atLeast';
83
+ };
84
+ indent?: {
85
+ leftTwips?: number;
86
+ rightTwips?: number;
87
+ firstLineTwips?: number;
88
+ hangingTwips?: number;
89
+ };
90
+ /** Must resolve to a declared numbering definition. */
91
+ list?: {
92
+ numId: string;
93
+ ilvl: number;
94
+ };
95
+ pageBreakBefore?: boolean;
96
+ keepNext?: boolean;
97
+ tabs?: Array<{
98
+ posTwips: number;
99
+ align: 'left' | 'center' | 'right';
100
+ leader?: 'none' | 'dot' | 'underscore';
101
+ }>;
102
+ runs: InlineSpec[];
103
+ /** Drafting-note annotation anchored to this paragraph (separable layer). */
104
+ note?: DraftingNoteSpec;
105
+ };
106
+ export type InlineSpec = RunSpec | FieldSpec | TabSpec | BreakSpec;
107
+ /** Run-level formatting shared by text runs, fields, and style definitions. */
108
+ export type RunProps = {
109
+ bold?: boolean;
110
+ italic?: boolean;
111
+ underline?: 'single' | 'double' | 'none';
112
+ /** Six-digit hex without '#', e.g. 'FF0000'. */
113
+ colorHex?: string;
114
+ /** Applied to ascii + hAnsi + cs so all script ranges agree. */
115
+ font?: string;
116
+ sizePt?: number;
117
+ caps?: boolean;
118
+ smallCaps?: boolean;
119
+ };
120
+ export type RunSpec = {
121
+ kind: 'text';
122
+ text: string;
123
+ } & RunProps;
124
+ export type FieldSpec = {
125
+ kind: 'field';
126
+ field: 'PAGE' | 'NUMPAGES';
127
+ /**
128
+ * Cached field result text, required so readers display a value without
129
+ * recomputation prompts. The no-recovery-dialog guarantee is
130
+ * unrepresentable-by-omission.
131
+ */
132
+ cachedResult: string;
133
+ } & RunProps;
134
+ export type TabSpec = {
135
+ kind: 'tab';
136
+ };
137
+ export type BreakSpec = {
138
+ kind: 'break';
139
+ breakType?: 'line' | 'page';
140
+ };
141
+ export type TableSpec = {
142
+ kind: 'table';
143
+ /** Defaults to 'fixed'. */
144
+ layout?: 'fixed' | 'autofit';
145
+ /** Defines w:tblGrid; the sum drives w:tblW. */
146
+ columnWidthsTwips: number[];
147
+ borders?: TableBorders;
148
+ rows: TableRowSpec[];
149
+ };
150
+ export type BorderSpec = {
151
+ style: 'single' | 'double' | 'none';
152
+ sizeEighthPt?: number;
153
+ colorHex?: string;
154
+ };
155
+ export type TableBorders = {
156
+ top?: BorderSpec;
157
+ bottom?: BorderSpec;
158
+ left?: BorderSpec;
159
+ right?: BorderSpec;
160
+ insideH?: BorderSpec;
161
+ insideV?: BorderSpec;
162
+ };
163
+ export type TableRowSpec = {
164
+ heightTwips?: number;
165
+ heightRule?: 'atLeast' | 'exact';
166
+ /** Marks the row as a repeating header row (w:tblHeader). */
167
+ header?: boolean;
168
+ cells: TableCellSpec[];
169
+ };
170
+ export type TableCellSpec = {
171
+ widthTwips?: number;
172
+ gridSpan?: number;
173
+ vMerge?: 'restart' | 'continue';
174
+ borders?: TableBorders;
175
+ shadingHex?: string;
176
+ vAlign?: 'top' | 'center' | 'bottom';
177
+ marginsTwips?: {
178
+ top?: number;
179
+ right?: number;
180
+ bottom?: number;
181
+ left?: number;
182
+ };
183
+ blocks: BlockSpec[];
184
+ };
185
+ export type StyleSpec = {
186
+ styleId: string;
187
+ name: string;
188
+ type: 'paragraph' | 'character';
189
+ basedOn?: string;
190
+ next?: string;
191
+ paragraph?: Omit<ParagraphSpec, 'kind' | 'runs' | 'list' | 'note' | 'styleId'>;
192
+ run?: RunProps;
193
+ };
194
+ export type NumberingSpec = {
195
+ /** Spec-level handle; the compiler assigns numeric w:numId / abstractNumId. */
196
+ numId: string;
197
+ levels: Array<{
198
+ ilvl: number;
199
+ start?: number;
200
+ numFmt: 'decimal' | 'lowerLetter' | 'upperLetter' | 'lowerRoman' | 'upperRoman' | 'bullet' | 'none';
201
+ /** Level text pattern, e.g. '%1.' or '%1.%2' or a bullet glyph. */
202
+ lvlText: string;
203
+ suff?: 'tab' | 'space' | 'nothing';
204
+ indentTwips?: {
205
+ left?: number;
206
+ hanging?: number;
207
+ };
208
+ runProps?: RunProps;
209
+ }>;
210
+ };
211
+ export type DraftingNoteSpec = {
212
+ text: string;
213
+ author?: string;
214
+ /** ISO-8601; comment metadata is deterministic, never wall-clock. */
215
+ dateIso?: string;
216
+ };
217
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/generation/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Declarative document specification for from-scratch DOCX generation.
3
+ *
4
+ * The entire surface is plain data: discriminated unions on `kind`, no Map /
5
+ * Date / class instances, explicit unit suffixes (`...Twips`, `...Pt`) instead
6
+ * of bare numbers. `JSON.parse(JSON.stringify(spec))` is identity over any
7
+ * valid spec, which is what lets a stored recipe (or, later, an MCP payload)
8
+ * compile without translation.
9
+ *
10
+ * The type surface intentionally covers the full feature set of the
11
+ * add-docx-generation change even though emitters land in phases; the
12
+ * compiler rejects any spec feature whose emitter has not shipped yet
13
+ * (see validate-spec.ts) rather than silently ignoring it.
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/generation/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Pre-compile validation of a DocumentSpec.
3
+ *
4
+ * Two jobs:
5
+ * 1. Shape/referential checks for the spec subset whose emitters have shipped.
6
+ * 2. Loud rejection of declared-but-not-yet-implemented spec features. The
7
+ * type surface covers the full add-docx-generation change; emitters land
8
+ * in phases, and a spec feature without an emitter must fail compilation
9
+ * with a typed error naming the feature and its path — never be silently
10
+ * dropped (scenario SDX-GEN-003).
11
+ *
12
+ * Shipped so far: formatted text/tab/break runs, five-part PAGE/NUMPAGES
13
+ * fields, paragraph formatting, named styles + styles.xml, multi-section
14
+ * documents with per-section page setup, page numbering, break types,
15
+ * default/first/even headers and footers, tables (grid, spans, vertical
16
+ * merges, cell decoration, nesting), multi-level numbering with w:numPr
17
+ * list references, and drafting notes compiled to anchored comments (body
18
+ * story only — header/footer paragraphs cannot carry notes).
19
+ *
20
+ * Every declared feature now has an emitter; the loud-rejection contract
21
+ * (SDX-GEN-003) lives on as runtime guards against unrecognized block and
22
+ * inline kinds, which protect callers handing in JSON that the TypeScript
23
+ * surface never saw.
24
+ */
25
+ import type { DocumentSpec } from './types.js';
26
+ export declare function validateSpec(spec: DocumentSpec): void;
27
+ //# sourceMappingURL=validate-spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-spec.d.ts","sourceRoot":"","sources":["../../src/generation/validate-spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,EAGV,YAAY,EASb,MAAM,YAAY,CAAC;AAapB,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAWrD"}