@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,323 @@
1
+ import path from 'node:path';
2
+ import { parseXml, serializeXml } from './xml.js';
3
+ import { OOXML } from './namespaces.js';
4
+ import { REVISION_SIDE_PART_PATHS, REVISION_STORY_PART_PATHS, } from './revision-parts.js';
5
+ import { REVISION_RANGE_ELEMENT_NAMES, TRACKED_CHANGE_ELEMENT_NAMES, } from './revision-vocabulary.js';
6
+ import { collectFieldStructureIssues, } from '../shared/field-structure.js';
7
+ const W_NS = OOXML.W_NS;
8
+ const REL_NS = OOXML.REL_NS;
9
+ const CT_NS = OOXML.CT_NS;
10
+ const FULL_REVISION_ATTRS = ['id', 'author', 'date'];
11
+ const ID_ONLY_REVISION_ATTRS = ['id'];
12
+ /**
13
+ * Range-end milestones (OOXML CT_MarkupRange / CT_Markup) carry only w:id —
14
+ * unlike their *RangeStart counterparts (OOXML CT_TrackChange / CT_Bookmark),
15
+ * they have no w:author or w:date attribute.
16
+ */
17
+ const ID_ONLY_REVISION_ELEMENT_NAMES = new Set(REVISION_RANGE_ELEMENT_NAMES.filter((name) => name.endsWith('RangeEnd')));
18
+ const RANGE_PAIRS = [
19
+ { start: 'moveFromRangeStart', end: 'moveFromRangeEnd' },
20
+ { start: 'moveToRangeStart', end: 'moveToRangeEnd' },
21
+ { start: 'commentRangeStart', end: 'commentRangeEnd' },
22
+ { start: 'permStart', end: 'permEnd' },
23
+ { start: 'customXmlInsRangeStart', end: 'customXmlInsRangeEnd' },
24
+ { start: 'customXmlDelRangeStart', end: 'customXmlDelRangeEnd' },
25
+ { start: 'customXmlMoveFromRangeStart', end: 'customXmlMoveFromRangeEnd' },
26
+ { start: 'customXmlMoveToRangeStart', end: 'customXmlMoveToRangeEnd' },
27
+ { start: 'bookmarkStart', end: 'bookmarkEnd' },
28
+ ];
29
+ const TRACKED_CHANGE_PLACEMENTS = {
30
+ cellIns: ['tcPr'],
31
+ cellDel: ['tcPr'],
32
+ cellMerge: ['tcPr'],
33
+ tblGridChange: ['tblGrid'],
34
+ sectPrChange: ['sectPr'],
35
+ numberingChange: ['pPr', 'rPr'],
36
+ };
37
+ function toStringSet(values) {
38
+ const set = new Set();
39
+ if (!values)
40
+ return set;
41
+ for (const value of values)
42
+ set.add(String(value));
43
+ return set;
44
+ }
45
+ function getWAttr(el, localName) {
46
+ return el.getAttributeNS(W_NS, localName) ?? el.getAttribute(`w:${localName}`) ?? el.getAttribute(localName);
47
+ }
48
+ function allW(doc, localName) {
49
+ return Array.from(doc.getElementsByTagNameNS(W_NS, localName));
50
+ }
51
+ function parentLocalName(el) {
52
+ let node = el.parentNode;
53
+ while (node) {
54
+ if (node.nodeType === 1)
55
+ return node.localName;
56
+ node = node.parentNode;
57
+ }
58
+ return null;
59
+ }
60
+ function classifyRevision(el, aiAuthor, touchedRevisionIds) {
61
+ const author = getWAttr(el, 'author');
62
+ const id = getWAttr(el, 'id');
63
+ const isAi = author === aiAuthor || (id !== null && touchedRevisionIds.has(id));
64
+ return { severity: isAi ? 'error' : 'warning', author, id };
65
+ }
66
+ function push(out, diagnostic) {
67
+ out.push(diagnostic);
68
+ }
69
+ function isIntegerString(value) {
70
+ return value !== null && /^(?:0|[1-9]\d*)$/.test(value);
71
+ }
72
+ /**
73
+ * OOXML ST_DateTime is xsd:dateTime — full date-time with optional fractional
74
+ * seconds and timezone. Date.parse alone is too lax (it accepts "2026" and
75
+ * RFC 1123 dates, which Word rejects).
76
+ */
77
+ const XSD_DATETIME_PATTERN = /^-?\d{4,}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?$/;
78
+ function isValidDate(value) {
79
+ if (!value)
80
+ return false;
81
+ return XSD_DATETIME_PATTERN.test(value) && Number.isFinite(Date.parse(value));
82
+ }
83
+ function checkRevisionMetadata(story, aiAuthor, touchedRevisionIds, diagnostics, aiIds) {
84
+ const names = [...TRACKED_CHANGE_ELEMENT_NAMES, ...REVISION_RANGE_ELEMENT_NAMES];
85
+ for (const localName of names) {
86
+ const idOnly = ID_ONLY_REVISION_ELEMENT_NAMES.has(localName);
87
+ const requiredAttrs = idOnly ? ID_ONLY_REVISION_ATTRS : FULL_REVISION_ATTRS;
88
+ for (const el of allW(story.doc, localName)) {
89
+ const classified = classifyRevision(el, aiAuthor, touchedRevisionIds);
90
+ for (const attr of requiredAttrs) {
91
+ const value = getWAttr(el, attr);
92
+ if (!value) {
93
+ push(diagnostics, {
94
+ severity: classified.severity,
95
+ code: 'REVISION_METADATA_MISSING',
96
+ message: `<w:${localName}> missing required w:${attr}`,
97
+ part: story.part,
98
+ element: `w:${localName}`,
99
+ id: classified.id ?? undefined,
100
+ author: classified.author,
101
+ });
102
+ }
103
+ }
104
+ const id = getWAttr(el, 'id');
105
+ if (!isIntegerString(id)) {
106
+ push(diagnostics, {
107
+ severity: classified.severity,
108
+ code: 'REVISION_ID_INVALID',
109
+ message: `<w:${localName}> has non-integer w:id`,
110
+ part: story.part,
111
+ element: `w:${localName}`,
112
+ id: id ?? undefined,
113
+ author: classified.author,
114
+ });
115
+ }
116
+ const date = getWAttr(el, 'date');
117
+ if (!idOnly && !isValidDate(date)) {
118
+ push(diagnostics, {
119
+ severity: classified.severity,
120
+ code: 'REVISION_DATE_INVALID',
121
+ message: `<w:${localName}> has invalid w:date`,
122
+ part: story.part,
123
+ element: `w:${localName}`,
124
+ id: id ?? undefined,
125
+ author: classified.author,
126
+ });
127
+ }
128
+ if (classified.severity === 'error' && id) {
129
+ const previousPart = aiIds.get(id);
130
+ if (previousPart && previousPart !== story.part) {
131
+ push(diagnostics, {
132
+ severity: 'error',
133
+ code: 'AI_REVISION_ID_DUPLICATE',
134
+ message: `AI revision w:id="${id}" appears in both ${previousPart} and ${story.part}`,
135
+ part: story.part,
136
+ element: `w:${localName}`,
137
+ id,
138
+ author: classified.author,
139
+ });
140
+ }
141
+ else {
142
+ aiIds.set(id, story.part);
143
+ }
144
+ }
145
+ }
146
+ }
147
+ }
148
+ function checkRangePairs(story, aiAuthor, touchedRangeIds, diagnostics) {
149
+ const collect = (localName, into) => {
150
+ for (const el of allW(story.doc, localName)) {
151
+ const id = getWAttr(el, 'id');
152
+ if (!id || !isIntegerString(id)) {
153
+ const author = getWAttr(el, 'author');
154
+ push(diagnostics, {
155
+ severity: author === aiAuthor || (id !== null && touchedRangeIds.has(id)) ? 'error' : 'warning',
156
+ code: id === null ? 'RANGE_MARKER_ID_MISSING' : 'RANGE_MARKER_ID_INVALID',
157
+ message: id === null
158
+ ? `<w:${localName}> missing required w:id`
159
+ : `<w:${localName}> has non-integer w:id`,
160
+ part: story.part,
161
+ element: `w:${localName}`,
162
+ id: id ?? undefined,
163
+ author,
164
+ });
165
+ }
166
+ if (!id)
167
+ continue;
168
+ const list = into.get(id) ?? [];
169
+ list.push(el);
170
+ into.set(id, list);
171
+ }
172
+ };
173
+ for (const pair of RANGE_PAIRS) {
174
+ const starts = new Map();
175
+ const ends = new Map();
176
+ collect(pair.start, starts);
177
+ collect(pair.end, ends);
178
+ const ids = new Set([...starts.keys(), ...ends.keys()]);
179
+ for (const id of ids) {
180
+ const startCount = starts.get(id)?.length ?? 0;
181
+ const endCount = ends.get(id)?.length ?? 0;
182
+ if (startCount === endCount)
183
+ continue;
184
+ const representative = starts.get(id)?.[0] ?? ends.get(id)?.[0];
185
+ const author = representative ? getWAttr(representative, 'author') : null;
186
+ const severity = author === aiAuthor || touchedRangeIds.has(id) ? 'error' : 'warning';
187
+ push(diagnostics, {
188
+ severity,
189
+ code: 'RANGE_PAIR_UNBALANCED',
190
+ message: `<w:${pair.start}>/<w:${pair.end}> pair id="${id}" is unbalanced`,
191
+ part: story.part,
192
+ element: `w:${pair.start}`,
193
+ id,
194
+ author,
195
+ });
196
+ }
197
+ }
198
+ }
199
+ function checkFieldStructure(story, diagnostics) {
200
+ const fieldStory = { label: story.part, xml: serializeXml(story.doc) };
201
+ for (const issue of collectFieldStructureIssues([fieldStory])) {
202
+ push(diagnostics, {
203
+ severity: 'error',
204
+ code: issue.code,
205
+ message: issue.message,
206
+ part: story.part,
207
+ element: issue.element,
208
+ });
209
+ }
210
+ }
211
+ function checkPlacement(story, aiAuthor, touchedRevisionIds, diagnostics) {
212
+ for (const [localName, allowedParents] of Object.entries(TRACKED_CHANGE_PLACEMENTS)) {
213
+ for (const el of allW(story.doc, localName)) {
214
+ const parent = parentLocalName(el);
215
+ if (parent && allowedParents.includes(parent))
216
+ continue;
217
+ const classified = classifyRevision(el, aiAuthor, touchedRevisionIds);
218
+ push(diagnostics, {
219
+ severity: classified.severity,
220
+ code: 'REVISION_PLACEMENT_INVALID',
221
+ message: `<w:${localName}> must appear under ${allowedParents.map((x) => `w:${x}`).join(' or ')}`,
222
+ part: story.part,
223
+ element: `w:${localName}`,
224
+ id: classified.id ?? undefined,
225
+ author: classified.author,
226
+ });
227
+ }
228
+ }
229
+ }
230
+ function relsSourceBase(relsPath) {
231
+ if (relsPath === '_rels/.rels')
232
+ return '';
233
+ const marker = '/_rels/';
234
+ const idx = relsPath.indexOf(marker);
235
+ if (idx < 0)
236
+ return path.posix.dirname(relsPath);
237
+ return relsPath.slice(0, idx);
238
+ }
239
+ function resolveRelationshipTarget(relsPath, target) {
240
+ const base = relsSourceBase(relsPath);
241
+ return path.posix.normalize(path.posix.join(base, target)).replace(/^\.\//, '');
242
+ }
243
+ async function checkPackageInvariants(zip, touchedRelationshipParts, touchedSideParts, diagnostics) {
244
+ for (const fileName of zip.listFiles()) {
245
+ if (!fileName.endsWith('.rels'))
246
+ continue;
247
+ if (touchedRelationshipParts.size > 0 && !touchedRelationshipParts.has(fileName))
248
+ continue;
249
+ const relsXml = await zip.readTextOrNull(fileName);
250
+ if (!relsXml)
251
+ continue;
252
+ const relsDoc = parseXml(relsXml);
253
+ for (const rel of Array.from(relsDoc.getElementsByTagNameNS(REL_NS, 'Relationship'))) {
254
+ const target = rel.getAttribute('Target');
255
+ if (!target)
256
+ continue;
257
+ if (rel.getAttribute('TargetMode') === 'External')
258
+ continue;
259
+ const resolved = resolveRelationshipTarget(fileName, target);
260
+ if (!zip.hasFile(resolved)) {
261
+ push(diagnostics, {
262
+ severity: touchedRelationshipParts.has(fileName) ? 'error' : 'warning',
263
+ code: 'RELATIONSHIP_TARGET_MISSING',
264
+ message: `Relationship target '${target}' resolves to missing package part '${resolved}'`,
265
+ part: fileName,
266
+ });
267
+ }
268
+ }
269
+ }
270
+ const sidePartsToCheck = touchedSideParts.size > 0
271
+ ? [...touchedSideParts]
272
+ : REVISION_SIDE_PART_PATHS.filter((part) => zip.hasFile(part));
273
+ if (sidePartsToCheck.length === 0)
274
+ return;
275
+ const contentTypesXml = await zip.readTextOrNull('[Content_Types].xml');
276
+ const overrides = new Set();
277
+ if (contentTypesXml) {
278
+ const ctDoc = parseXml(contentTypesXml);
279
+ for (const override of Array.from(ctDoc.getElementsByTagNameNS(CT_NS, 'Override'))) {
280
+ const partName = override.getAttribute('PartName');
281
+ if (partName)
282
+ overrides.add(partName.replace(/^\//, ''));
283
+ }
284
+ }
285
+ for (const part of sidePartsToCheck) {
286
+ if (!zip.hasFile(part))
287
+ continue;
288
+ if (!overrides.has(part)) {
289
+ push(diagnostics, {
290
+ severity: touchedSideParts.has(part) ? 'error' : 'warning',
291
+ code: 'SIDE_PART_CONTENT_TYPE_MISSING',
292
+ message: `Created side part '${part}' is missing a [Content_Types].xml Override`,
293
+ part,
294
+ });
295
+ }
296
+ }
297
+ }
298
+ export async function validateAiRevisions(options) {
299
+ const touchedRevisionIds = toStringSet(options.touched?.revisionIds);
300
+ const touchedRangeIds = toStringSet(options.touched?.rangeIds);
301
+ const touchedRelationshipParts = toStringSet(options.touched?.relationshipParts);
302
+ const touchedSideParts = toStringSet(options.touched?.sideParts);
303
+ const diagnostics = [];
304
+ const aiIds = new Map();
305
+ for (const story of options.stories) {
306
+ checkRevisionMetadata(story, options.aiAuthor, touchedRevisionIds, diagnostics, aiIds);
307
+ checkRangePairs(story, options.aiAuthor, touchedRangeIds, diagnostics);
308
+ checkFieldStructure(story, diagnostics);
309
+ checkPlacement(story, options.aiAuthor, touchedRevisionIds, diagnostics);
310
+ }
311
+ if (options.packageZip) {
312
+ await checkPackageInvariants(options.packageZip, touchedRelationshipParts, touchedSideParts, diagnostics);
313
+ }
314
+ const errors = diagnostics.filter((d) => d.severity === 'error');
315
+ const warnings = diagnostics.filter((d) => d.severity === 'warning');
316
+ return {
317
+ valid: errors.length === 0,
318
+ errors,
319
+ warnings,
320
+ };
321
+ }
322
+ export const AI_REVISION_VALIDATION_STORY_PARTS = REVISION_STORY_PART_PATHS;
323
+ //# sourceMappingURL=validate_ai_revisions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate_ai_revisions.js","sourceRoot":"","sources":["../../src/primitives/validate_ai_revisions.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,9 @@
1
1
  export type XmlDoc = Document;
2
+ /**
3
+ * Standard XML declaration for serialized OOXML parts. xmldom's serializer
4
+ * omits the declaration, so every emitted part prepends this manually.
5
+ */
6
+ export declare const XML_DECL = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
2
7
  export declare function parseXml(xml: string): XmlDoc;
3
8
  export declare function serializeXml(doc: XmlDoc): string;
4
9
  export declare function textContent(node: Node | null | undefined): string;
@@ -1 +1 @@
1
- {"version":3,"file":"xml.d.ts","sourceRoot":"","sources":["../../src/primitives/xml.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,MAAM,GAAG,QAAQ,CAAC;AAE9B,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAa5C;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAEjE"}
1
+ {"version":3,"file":"xml.d.ts","sourceRoot":"","sources":["../../src/primitives/xml.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,MAAM,GAAG,QAAQ,CAAC;AAE9B;;;GAGG;AACH,eAAO,MAAM,QAAQ,kEAA4D,CAAC;AAElF,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAa5C;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAEjE"}
@@ -1,4 +1,9 @@
1
1
  import { DOMParser, XMLSerializer } from '@xmldom/xmldom';
2
+ /**
3
+ * Standard XML declaration for serialized OOXML parts. xmldom's serializer
4
+ * omits the declaration, so every emitted part prepends this manually.
5
+ */
6
+ export const XML_DECL = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
2
7
  export function parseXml(xml) {
3
8
  // application/xml ensures XML parsing rules (vs HTML-ish parsing).
4
9
  // xmldom 0.9.x returns its own module-scoped Document type; cast to global
@@ -1 +1 @@
1
- {"version":3,"file":"xml.js","sourceRoot":"","sources":["../../src/primitives/xml.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAI1D,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,mEAAmE;IACnE,2EAA2E;IAC3E,qDAAqD;IACrD,MAAM,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC,eAAe,CAAC,GAAG,EAAE,iBAAiB,CAAwB,CAAC;IAE3F,+EAA+E;IAC/E,MAAM,WAAW,GAAG,GAAG,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAC;IAC5D,IAAI,WAAW,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,iBAAiB,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO,IAAI,aAAa,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAA6B;IACvD,OAAO,IAAI,EAAE,WAAW,IAAI,EAAE,CAAC;AACjC,CAAC"}
1
+ {"version":3,"file":"xml.js","sourceRoot":"","sources":["../../src/primitives/xml.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAI1D;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,yDAAyD,CAAC;AAElF,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,mEAAmE;IACnE,2EAA2E;IAC3E,qDAAqD;IACrD,MAAM,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC,eAAe,CAAC,GAAG,EAAE,iBAAiB,CAAwB,CAAC;IAE3F,+EAA+E;IAC/E,MAAM,WAAW,GAAG,GAAG,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAC;IAC5D,IAAI,WAAW,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,iBAAiB,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO,IAAI,aAAa,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAA6B;IACvD,OAAO,IAAI,EAAE,WAAW,IAAI,EAAE,CAAC;AACjC,CAAC"}
@@ -19,6 +19,7 @@ export declare class DocxZip {
19
19
  export declare function createZipBuffer(files: Record<string, string | Buffer | Uint8Array>, opts?: {
20
20
  compression?: ZipCompression;
21
21
  compressionLevel?: number;
22
+ fileDate?: Date;
22
23
  }): Promise<Buffer>;
23
24
  export declare function readZipText(buffer: Buffer, path: string): Promise<string | null>;
24
25
  export declare function inspectZipEntries(buffer: Buffer): Promise<ZipEntryInfo[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"zip.d.ts","sourceRoot":"","sources":["../../src/primitives/zip.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,SAAS,CAAC;AAEjD,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAAC;AAaF,qBAAa,OAAO;IAClB,OAAO,CAAC,GAAG,CAAQ;IAEnB,OAAO;WAIM,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKnD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMjC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAM1D,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAI3C,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI9B,SAAS,IAAI,MAAM,EAAE;IAQf,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;CAIlC;AAED,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC,EACnD,IAAI,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,cAAc,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GACjE,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAKtF;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAW/E"}
1
+ {"version":3,"file":"zip.d.ts","sourceRoot":"","sources":["../../src/primitives/zip.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,SAAS,CAAC;AAEjD,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAAC;AAaF,qBAAa,OAAO;IAClB,OAAO,CAAC,GAAG,CAAQ;IAEnB,OAAO;WAIM,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKnD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMjC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAM1D,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAM3C,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI9B,SAAS,IAAI,MAAM,EAAE;IAQf,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;CAgBlC;AAED,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC,EACnD,IAAI,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,cAAc,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,IAAI,CAAA;CAAE,GAClF,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAKtF;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAW/E"}
@@ -27,7 +27,9 @@ export class DocxZip {
27
27
  return file.async('text');
28
28
  }
29
29
  writeText(path, text) {
30
- this.zip.file(path, text);
30
+ // createFolders defaults to true and would add a directory entry (e.g.
31
+ // `word/`) absent from the Word-authored input archive.
32
+ this.zip.file(path, text, { createFolders: false });
31
33
  }
32
34
  hasFile(path) {
33
35
  return this.zip.file(path) !== null;
@@ -40,14 +42,30 @@ export class DocxZip {
40
42
  return files;
41
43
  }
42
44
  async toBuffer() {
43
- const out = await this.zip.generateAsync({ type: 'nodebuffer' });
45
+ // OPC packages never need directory entries (Word does not emit them);
46
+ // drop any that came in via the source archive or earlier writes so the
47
+ // output contract is simply "zero directory entries". NOT zip.remove():
48
+ // that deletes a folder's contents recursively.
49
+ for (const file of Object.values(this.zip.files)) {
50
+ if (file.dir)
51
+ delete this.zip.files[file.name];
52
+ }
53
+ // jszip defaults to STORE, which inflated saves ~6x.
54
+ const out = await this.zip.generateAsync({
55
+ type: 'nodebuffer',
56
+ compression: 'DEFLATE',
57
+ compressionOptions: { level: 6 },
58
+ });
44
59
  return out;
45
60
  }
46
61
  }
47
62
  export async function createZipBuffer(files, opts) {
48
63
  const zip = new JSZip();
49
64
  for (const [name, value] of Object.entries(files)) {
50
- zip.file(name, value);
65
+ // JSZip stamps each entry with the current time by default, which makes
66
+ // otherwise-identical archives differ byte-for-byte across runs; callers
67
+ // needing deterministic output pass a fixed fileDate.
68
+ zip.file(name, value, opts?.fileDate ? { date: opts.fileDate } : undefined);
51
69
  }
52
70
  const out = await zip.generateAsync({
53
71
  type: 'nodebuffer',
@@ -1 +1 @@
1
- {"version":3,"file":"zip.js","sourceRoot":"","sources":["../../src/primitives/zip.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"zip.js","sourceRoot":"","sources":["../../src/primitives/zip.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface FieldStory {
2
+ label: string;
3
+ xml: string;
4
+ }
5
+ export type FieldStructureIssue = {
6
+ code: string;
7
+ message: string;
8
+ story?: string;
9
+ element?: string;
10
+ };
11
+ export declare function hasFldCharInsideDel(documentXml: string): boolean;
12
+ export declare function collectFieldStructureIssues(input: string | FieldStory[]): FieldStructureIssue[];
13
+ export declare function validateFieldStructure(input: string | FieldStory[]): boolean;
14
+ //# sourceMappingURL=field-structure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-structure.d.ts","sourceRoot":"","sources":["../../src/shared/field-structure.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAcF,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CA2BhE;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE,GAAG,mBAAmB,EAAE,CAU/F;AAaD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE,GAAG,OAAO,CAI5E"}
@@ -0,0 +1,166 @@
1
+ import { parseXml } from '../primitives/xml.js';
2
+ import { OOXML } from '../primitives/namespaces.js';
3
+ function isW(el, localName) {
4
+ return el.namespaceURI === OOXML.W_NS && el.localName === localName;
5
+ }
6
+ function getWAttr(el, localName) {
7
+ return el.getAttributeNS(OOXML.W_NS, localName) ?? el.getAttribute(`w:${localName}`);
8
+ }
9
+ function allW(root, localName) {
10
+ return Array.from(root.getElementsByTagNameNS(OOXML.W_NS, localName));
11
+ }
12
+ export function hasFldCharInsideDel(documentXml) {
13
+ const root = parseXml(documentXml).documentElement;
14
+ let insideDelDepth = 0;
15
+ let violation = false;
16
+ function scan(node) {
17
+ if (violation)
18
+ return;
19
+ for (let child = node.firstChild; child; child = child.nextSibling) {
20
+ if (child.nodeType !== 1)
21
+ continue;
22
+ const el = child;
23
+ if (isW(el, 'del')) {
24
+ insideDelDepth++;
25
+ scan(el);
26
+ insideDelDepth--;
27
+ if (violation)
28
+ return;
29
+ continue;
30
+ }
31
+ if (isW(el, 'fldChar') && insideDelDepth > 0) {
32
+ violation = true;
33
+ return;
34
+ }
35
+ scan(el);
36
+ }
37
+ }
38
+ scan(root);
39
+ return violation;
40
+ }
41
+ export function collectFieldStructureIssues(input) {
42
+ if (typeof input === 'string') {
43
+ return collectFieldStructureIssuesForStory(input, 'document');
44
+ }
45
+ const issues = [];
46
+ for (const story of input) {
47
+ issues.push(...collectFieldStructureIssuesForStory(story.xml, story.label));
48
+ }
49
+ return issues;
50
+ }
51
+ /**
52
+ * Text-placement rules added for the AI revision validator. They are NOT part
53
+ * of `validateFieldStructure`: that boolean is pinned extensionally against
54
+ * the Lean model (`Tier2.FieldStructure.validateFieldStructure`) by the Lean
55
+ * differential harness, so its rule set must not grow.
56
+ */
57
+ const TEXT_PLACEMENT_ISSUE_CODES = new Set([
58
+ 'TEXT_INSIDE_DELETION',
59
+ 'DELETED_TEXT_OUTSIDE_DELETION',
60
+ ]);
61
+ export function validateFieldStructure(input) {
62
+ return collectFieldStructureIssues(input)
63
+ .filter((issue) => !TEXT_PLACEMENT_ISSUE_CODES.has(issue.code))
64
+ .length === 0;
65
+ }
66
+ function collectFieldStructureIssuesForStory(documentXml, story) {
67
+ const issues = [];
68
+ const root = parseXml(documentXml).documentElement;
69
+ const allFldChars = allW(root, 'fldChar');
70
+ const allInstrTexts = allW(root, 'instrText');
71
+ const allDelInstrTexts = allW(root, 'delInstrText');
72
+ const allText = allW(root, 't');
73
+ let begins = 0;
74
+ let ends = 0;
75
+ for (const fc of allFldChars) {
76
+ const type = getWAttr(fc, 'fldCharType');
77
+ if (type === 'begin')
78
+ begins++;
79
+ else if (type === 'end')
80
+ ends++;
81
+ }
82
+ if (begins !== ends) {
83
+ issues.push({
84
+ code: 'FIELD_BEGIN_END_MISMATCH',
85
+ message: `Field begin/end count mismatch in ${story}: begin=${begins}, end=${ends}`,
86
+ story,
87
+ element: 'w:fldChar',
88
+ });
89
+ }
90
+ if (allFldChars.length === 0 &&
91
+ allInstrTexts.length === 0 &&
92
+ allDelInstrTexts.length === 0 &&
93
+ allText.length === 0) {
94
+ return issues;
95
+ }
96
+ let depth = 0;
97
+ const pastSeparatorAtDepth = [];
98
+ let insideDelDepth = 0;
99
+ // Move-sources (w:moveFrom) carry deletion-flavored content (w:delText)
100
+ // per the OOXML revision model; the text-placement rules treat them as
101
+ // deletion contexts. The Lean-pinned field rules above use only w:del.
102
+ let insideMoveFromDepth = 0;
103
+ function push(code, message, element) {
104
+ issues.push({ code, message, story, element });
105
+ }
106
+ function scan(node) {
107
+ for (let child = node.firstChild; child; child = child.nextSibling) {
108
+ if (child.nodeType !== 1)
109
+ continue;
110
+ const el = child;
111
+ if (isW(el, 'del')) {
112
+ insideDelDepth++;
113
+ scan(el);
114
+ insideDelDepth--;
115
+ continue;
116
+ }
117
+ if (isW(el, 'moveFrom')) {
118
+ insideMoveFromDepth++;
119
+ scan(el);
120
+ insideMoveFromDepth--;
121
+ continue;
122
+ }
123
+ if (isW(el, 'fldChar')) {
124
+ if (insideDelDepth > 0) {
125
+ push('FIELD_CHAR_INSIDE_DELETION', 'w:fldChar must not appear inside w:del', 'w:fldChar');
126
+ }
127
+ const type = getWAttr(el, 'fldCharType');
128
+ if (type === 'begin') {
129
+ depth++;
130
+ pastSeparatorAtDepth[depth] = 0;
131
+ }
132
+ else if (type === 'separate') {
133
+ if (depth > 0)
134
+ pastSeparatorAtDepth[depth] = 1;
135
+ }
136
+ else if (type === 'end') {
137
+ if (depth > 0)
138
+ depth--;
139
+ }
140
+ }
141
+ else if (isW(el, 'instrText')) {
142
+ if (depth === 0 || pastSeparatorAtDepth[depth]) {
143
+ push('INSTRUCTION_TEXT_OUTSIDE_FIELD_CODE', 'w:instrText must appear inside an open field code region', 'w:instrText');
144
+ }
145
+ }
146
+ else if (isW(el, 'delInstrText')) {
147
+ if (insideDelDepth === 0) {
148
+ push('DELETED_INSTRUCTION_TEXT_OUTSIDE_DELETION', 'w:delInstrText must appear inside w:del', 'w:delInstrText');
149
+ }
150
+ if (depth === 0 || pastSeparatorAtDepth[depth]) {
151
+ push('DELETED_INSTRUCTION_TEXT_OUTSIDE_FIELD_CODE', 'w:delInstrText must appear inside an open field code region', 'w:delInstrText');
152
+ }
153
+ }
154
+ else if (isW(el, 't') && (insideDelDepth > 0 || insideMoveFromDepth > 0)) {
155
+ push('TEXT_INSIDE_DELETION', 'w:t must not appear inside w:del or w:moveFrom; use w:delText', 'w:t');
156
+ }
157
+ else if (isW(el, 'delText') && insideDelDepth === 0 && insideMoveFromDepth === 0) {
158
+ push('DELETED_TEXT_OUTSIDE_DELETION', 'w:delText must appear inside w:del or w:moveFrom', 'w:delText');
159
+ }
160
+ scan(el);
161
+ }
162
+ }
163
+ scan(root);
164
+ return issues;
165
+ }
166
+ //# sourceMappingURL=field-structure.js.map