@sametalmdr/word-editor 0.2.0-alpha → 0.3.0-alpha
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/CHANGELOG.md +108 -70
- package/LICENSE +21 -21
- package/README.md +286 -247
- package/dist/canvas/box-clipboard.js +238 -238
- package/dist/canvas/box-selection.js +80 -80
- package/dist/canvas/canvas-editor.js +502 -502
- package/dist/canvas/controller.js +717 -717
- package/dist/canvas/geometry.js +131 -131
- package/dist/canvas/gesture.d.ts +0 -1
- package/dist/canvas/gesture.js +289 -289
- package/dist/canvas/handles.js +212 -212
- package/dist/canvas/menu.js +82 -82
- package/dist/canvas/mode-controller.js +81 -81
- package/dist/canvas/nudge.js +108 -108
- package/dist/canvas/overlay.js +149 -149
- package/dist/canvas/snap.js +132 -132
- package/dist/canvas/viewport.js +112 -112
- package/dist/canvas/z-order.js +171 -171
- package/dist/commands/alignment.js +150 -150
- package/dist/commands/box.js +272 -272
- package/dist/commands/clipboard.js +93 -93
- package/dist/commands/graphemes.js +112 -112
- package/dist/commands/marks.js +153 -153
- package/dist/commands/paragraph-props.js +176 -176
- package/dist/commands/size.js +368 -368
- package/dist/commands/text.js +291 -291
- package/dist/docx.d.ts +1 -0
- package/dist/docx.js +15 -13
- package/dist/editor/editing-host.js +434 -434
- package/dist/element.js +41 -41
- package/dist/fonts/OFL-Carlito.txt +94 -0
- package/dist/fonts/calibri-metrics.d.ts +27 -0
- package/dist/fonts/calibri-metrics.js +88 -0
- package/dist/history/history.js +433 -433
- package/dist/index.js +63 -63
- package/dist/input/beforeinput.js +224 -224
- package/dist/input/clipboard.js +107 -107
- package/dist/input/composition.js +341 -341
- package/dist/input/keymap.js +54 -54
- package/dist/io/ooxml/custgeom.js +72 -72
- package/dist/io/ooxml/drawingml.js +232 -232
- package/dist/io/ooxml/edits.js +67 -67
- package/dist/io/ooxml/export-splice.js +880 -880
- package/dist/io/ooxml/export.js +365 -365
- package/dist/io/ooxml/fill.d.ts +93 -8
- package/dist/io/ooxml/fill.js +618 -562
- package/dist/io/ooxml/fit.d.ts +252 -0
- package/dist/io/ooxml/fit.js +598 -0
- package/dist/io/ooxml/import-gate.js +200 -200
- package/dist/io/ooxml/import.js +691 -691
- package/dist/io/ooxml/inflate.js +126 -126
- package/dist/io/ooxml/media.js +87 -87
- package/dist/io/ooxml/ns.d.ts +2 -0
- package/dist/io/ooxml/ns.js +26 -21
- package/dist/io/ooxml/numbering.js +290 -290
- package/dist/io/ooxml/opc-write.js +171 -171
- package/dist/io/ooxml/provenance.js +93 -93
- package/dist/io/ooxml/recipe.js +708 -708
- package/dist/io/ooxml/relationships.js +59 -59
- package/dist/io/ooxml/run-fonts.d.ts +89 -0
- package/dist/io/ooxml/run-fonts.js +378 -0
- package/dist/io/ooxml/slots.d.ts +4 -0
- package/dist/io/ooxml/slots.js +582 -581
- package/dist/io/ooxml/styles-resolve.js +257 -257
- package/dist/io/ooxml/units.js +43 -43
- package/dist/io/ooxml/value.js +120 -120
- package/dist/io/ooxml/xml-scan.js +616 -616
- package/dist/io/ooxml/zip-container.js +228 -228
- package/dist/io/ooxml/zip-reject.js +106 -106
- package/dist/measure/placement.js +83 -83
- package/dist/measure/report.js +75 -75
- package/dist/model/ids.js +70 -70
- package/dist/model/normalize.js +146 -146
- package/dist/model/position.js +283 -283
- package/dist/model/transaction.js +209 -209
- package/dist/platform/capabilities.js +25 -25
- package/dist/react/index.js +21 -21
- package/dist/selection/controller.js +315 -315
- package/dist/selection/dom-map.js +334 -334
- package/dist/state/editor-state.js +109 -109
- package/dist/styles.css +66 -66
- package/package.json +94 -93
|
@@ -1,200 +1,200 @@
|
|
|
1
|
-
// ADR-0010's two-granularity import gate, ported from check_group_identity()
|
|
2
|
-
// and convert()'s own `is_locked` computation — never re-decided here.
|
|
3
|
-
//
|
|
4
|
-
// 1. A class with ZERO corpus examples (non-identity group transform, a
|
|
5
|
-
// nested group) -> REJECT THE WHOLE DOCUMENT rather than silently
|
|
6
|
-
// mis-place one shape.
|
|
7
|
-
// 2. A class that DOES occur (a shape's own rotation/flip, independent of
|
|
8
|
-
// any group) -> never rejected, the shape is just marked `locked`.
|
|
9
|
-
|
|
10
|
-
import { WPG_NS, A_NS } from "./ns.js";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Plain Error, not a custom class — matches every other src/ file's
|
|
14
|
-
* convention (zip-reject.js, xml-scan.js): a distinguishing message, not a
|
|
15
|
-
* type hierarchy.
|
|
16
|
-
* @param {string} message
|
|
17
|
-
* @returns {never}
|
|
18
|
-
*/
|
|
19
|
-
function rejectImport(message) {
|
|
20
|
-
throw new Error(`import-gate: REJECTED — ${message}`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* @param {import("./xml-scan.js").XmlNode} el
|
|
25
|
-
* @returns {boolean}
|
|
26
|
-
*/
|
|
27
|
-
function isNestedGroup(el) {
|
|
28
|
-
if (el.kind === "element" && ((el.uri === WPG_NS && el.localName === "grpSp") || (el.uri === A_NS && el.localName === "grpSp"))) {
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
if (el.kind !== "element") return false;
|
|
32
|
-
for (const child of el.children) {
|
|
33
|
-
if (isNestedGroup(child)) return true;
|
|
34
|
-
}
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Raises if the group's OWN transform is not identity (scale != 1.0 on
|
|
40
|
-
* either axis, chOff != (0,0), rot != 0, or any flip), or if the group
|
|
41
|
-
* contains a nested group at any depth (`wpg:grpSp` or `a:grpSp` — corpus-
|
|
42
|
-
* measured as never occurring, but checked both ways since which spelling a
|
|
43
|
-
* document might use was exactly the kind of thing a prior regex pass in
|
|
44
|
-
* this project missed three times).
|
|
45
|
-
*
|
|
46
|
-
* A shape's OWN rotation (independent of its group) is NOT checked here —
|
|
47
|
-
* see `isShapeLocked`. This function is about the GROUP's transform only.
|
|
48
|
-
*
|
|
49
|
-
* @param {import("./drawingml.js").Xfrm} gXfrm
|
|
50
|
-
* @param {import("./xml-scan.js").XmlElement} groupEl
|
|
51
|
-
* @param {string} context
|
|
52
|
-
* @returns {{scaleX: number, scaleY: number}}
|
|
53
|
-
*/
|
|
54
|
-
export function checkGroupIdentity(gXfrm, groupEl, context) {
|
|
55
|
-
const scaleX = gXfrm.chExtCx ? gXfrm.extCx / gXfrm.chExtCx : 1.0;
|
|
56
|
-
const scaleY = gXfrm.chExtCy ? gXfrm.extCy / gXfrm.chExtCy : 1.0;
|
|
57
|
-
|
|
58
|
-
/** @type {string[]} */
|
|
59
|
-
const problems = [];
|
|
60
|
-
if (scaleX !== 1.0 || scaleY !== 1.0) {
|
|
61
|
-
problems.push(`non-identity scale (scale_x=${scaleX}, scale_y=${scaleY})`);
|
|
62
|
-
}
|
|
63
|
-
if (gXfrm.chOffX !== 0 || gXfrm.chOffY !== 0) {
|
|
64
|
-
problems.push(`chOff != (0,0): (${gXfrm.chOffX},${gXfrm.chOffY})`);
|
|
65
|
-
}
|
|
66
|
-
if (gXfrm.rot !== 0) {
|
|
67
|
-
problems.push(`group rot != 0: ${gXfrm.rot}`);
|
|
68
|
-
}
|
|
69
|
-
if (gXfrm.flipH || gXfrm.flipV) {
|
|
70
|
-
problems.push(`group flip: flipH=${gXfrm.flipH} flipV=${gXfrm.flipV}`);
|
|
71
|
-
}
|
|
72
|
-
if (isNestedGroup(groupEl)) {
|
|
73
|
-
problems.push("nested group found (wpg:grpSp or a:grpSp)");
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (problems.length > 0) {
|
|
77
|
-
rejectImport(`${context}: ${problems.join("; ")}`);
|
|
78
|
-
}
|
|
79
|
-
return { scaleX, scaleY };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* @param {{rot: number, flipH: boolean, flipV: boolean}} ownXfrm
|
|
84
|
-
* @returns {boolean}
|
|
85
|
-
*/
|
|
86
|
-
export function isShapeLocked(ownXfrm) {
|
|
87
|
-
return ownXfrm.rot !== 0 || ownXfrm.flipH || ownXfrm.flipV;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* An anchor without `wp:posOffset` under positionH/positionV (an
|
|
92
|
-
* alignment-based anchor using `wp:align` instead uses a different
|
|
93
|
-
* addressing scheme this importer does not interpret), or without
|
|
94
|
-
* `wp:extent`, has no safe on-page placement. Measured 2026-08-27: 0/8,737
|
|
95
|
-
* real corpus anchors trigger this — every anchor in all 46 documents uses
|
|
96
|
-
* absolute posOffset + extent. Silently dropping such an anchor (the
|
|
97
|
-
* pre-2026-08-27 behavior, a bare `continue`) risked discarding real,
|
|
98
|
-
* positioned content from a corpus-external document with no signal
|
|
99
|
-
* anywhere that anything was lost. Call only when at least one of the three
|
|
100
|
-
* booleans is true — matches the caller's own `if` guard, like `continue`
|
|
101
|
-
* did before it.
|
|
102
|
-
* @param {boolean} missingPosOffsetH
|
|
103
|
-
* @param {boolean} missingPosOffsetV
|
|
104
|
-
* @param {boolean} missingExtent
|
|
105
|
-
* @param {string} context
|
|
106
|
-
* @returns {never}
|
|
107
|
-
*/
|
|
108
|
-
export function rejectAnchorPlacement(missingPosOffsetH, missingPosOffsetV, missingExtent, context) {
|
|
109
|
-
/** @type {string[]} */
|
|
110
|
-
const problems = [];
|
|
111
|
-
if (missingPosOffsetH || missingPosOffsetV) {
|
|
112
|
-
problems.push("missing wp:posOffset under positionH/positionV (an alignment-based anchor, e.g. wp:align, is not supported)");
|
|
113
|
-
}
|
|
114
|
-
if (missingExtent) {
|
|
115
|
-
problems.push("missing wp:extent");
|
|
116
|
-
}
|
|
117
|
-
rejectImport(`${context}: ${problems.join("; ")}`);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* An anchor with no `a:graphic/a:graphicData` at all wraps nothing this
|
|
122
|
-
* importer can render. Measured 2026-08-27: 0/8,737 real corpus anchors
|
|
123
|
-
* trigger this.
|
|
124
|
-
* @param {string} context
|
|
125
|
-
* @returns {never}
|
|
126
|
-
*/
|
|
127
|
-
export function rejectMissingGraphicData(context) {
|
|
128
|
-
rejectImport(`${context}: anchor has no a:graphic/a:graphicData`);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* A group (`wpg:wgp`) with no parseable `a:xfrm` under its own
|
|
133
|
-
* `wpg:grpSpPr` has no chOff/chExt to place or scale its children by —
|
|
134
|
-
* `checkGroupIdentity` (which checks whether that transform IS identity)
|
|
135
|
-
* can only run once this passes. Measured 2026-08-27: 0/459 real corpus
|
|
136
|
-
* groups trigger this.
|
|
137
|
-
* @param {string} context
|
|
138
|
-
* @returns {never}
|
|
139
|
-
*/
|
|
140
|
-
export function rejectMissingGroupTransform(context) {
|
|
141
|
-
rejectImport(`${context}: group has no parseable a:xfrm under wpg:grpSpPr`);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* A shape (`wps:wsp`) inside a group with no parseable `a:xfrm` under its
|
|
146
|
-
* own `wps:spPr` has no off/ext to compute a position from — unlike a
|
|
147
|
-
* non-grouped wsp (whose absolute size comes from the anchor's own
|
|
148
|
-
* wp:extent instead, independent of spPr), a group child's position is
|
|
149
|
-
* defined ONLY relative to the group's chOff/chExt via its own xfrm.
|
|
150
|
-
* Measured 2026-08-27: 0/2,598 real corpus group-child shapes trigger this.
|
|
151
|
-
* @param {string} context
|
|
152
|
-
* @returns {never}
|
|
153
|
-
*/
|
|
154
|
-
export function rejectMissingShapeTransform(context) {
|
|
155
|
-
rejectImport(`${context}: group child shape has no parseable a:xfrm under wps:spPr`);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* A non-grouped anchor's `a:graphicData` holding none of `wpg:wgp`,
|
|
160
|
-
* `wps:wsp`, or `pic:pic` is some other graphic type this importer has no
|
|
161
|
-
* model for (a chart, SmartArt diagram, OLE object, or ink annotation —
|
|
162
|
-
* ADR-0020 §7's own reserved REJECTED class). Measured 2026-08-27: 0/8,278
|
|
163
|
-
* real corpus non-group anchors trigger this.
|
|
164
|
-
* @param {string} context
|
|
165
|
-
* @returns {never}
|
|
166
|
-
*/
|
|
167
|
-
export function rejectUnsupportedGraphicDataKind(context) {
|
|
168
|
-
rejectImport(`${context}: a:graphicData holds none of wpg:wgp, wps:wsp, pic:pic (unsupported graphic type — chart, diagram, OLE object, or ink)`);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* A `w:drawing` wrapping `wp:inline` (in-text-flow placement) instead of
|
|
173
|
-
* `wp:anchor` (floating placement) uses an addressing scheme this importer
|
|
174
|
-
* never reads any coordinate from — `collectAnchors` only walks for
|
|
175
|
-
* `wp:anchor` children, so an inline drawing was previously absent from the
|
|
176
|
-
* anchors array with no signal anywhere that anything had been dropped.
|
|
177
|
-
* ADR-0020 Karar 4's own table (`wp:inline` -> REJECTED, "corpus'ta 0")
|
|
178
|
-
* predates this function; measured again 2026-08-27 against the real
|
|
179
|
-
* corpus: 0/46 documents contain one.
|
|
180
|
-
* @param {string} context
|
|
181
|
-
* @returns {never}
|
|
182
|
-
*/
|
|
183
|
-
export function rejectInlineDrawing(context) {
|
|
184
|
-
rejectImport(`${context}: w:drawing wraps wp:inline (in-text-flow placement is not supported, only wp:anchor)`);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* A `w:rPr` carrying `w:rStyle` (a reference to a character style defined in
|
|
189
|
-
* styles.xml) is never resolved by this importer — `readRPr` reads direct
|
|
190
|
-
* toggles (b/i/u), size, and font only, and a character-style reference
|
|
191
|
-
* silently produced whatever the run's OWN direct properties happened to be,
|
|
192
|
-
* with no signal that the style's contribution was missing. ADR-0020 Karar
|
|
193
|
-
* 4's own table (`w:rStyle` -> REJECTED, "0/81.973" runs); measured again
|
|
194
|
-
* 2026-08-27 against the real corpus: still 0/46 documents contain one.
|
|
195
|
-
* @param {string} context
|
|
196
|
-
* @returns {never}
|
|
197
|
-
*/
|
|
198
|
-
export function rejectCharacterStyle(context) {
|
|
199
|
-
rejectImport(`${context}: w:rPr carries w:rStyle (character-style reference is not resolved)`);
|
|
200
|
-
}
|
|
1
|
+
// ADR-0010's two-granularity import gate, ported from check_group_identity()
|
|
2
|
+
// and convert()'s own `is_locked` computation — never re-decided here.
|
|
3
|
+
//
|
|
4
|
+
// 1. A class with ZERO corpus examples (non-identity group transform, a
|
|
5
|
+
// nested group) -> REJECT THE WHOLE DOCUMENT rather than silently
|
|
6
|
+
// mis-place one shape.
|
|
7
|
+
// 2. A class that DOES occur (a shape's own rotation/flip, independent of
|
|
8
|
+
// any group) -> never rejected, the shape is just marked `locked`.
|
|
9
|
+
|
|
10
|
+
import { WPG_NS, A_NS } from "./ns.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Plain Error, not a custom class — matches every other src/ file's
|
|
14
|
+
* convention (zip-reject.js, xml-scan.js): a distinguishing message, not a
|
|
15
|
+
* type hierarchy.
|
|
16
|
+
* @param {string} message
|
|
17
|
+
* @returns {never}
|
|
18
|
+
*/
|
|
19
|
+
function rejectImport(message) {
|
|
20
|
+
throw new Error(`import-gate: REJECTED — ${message}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {import("./xml-scan.js").XmlNode} el
|
|
25
|
+
* @returns {boolean}
|
|
26
|
+
*/
|
|
27
|
+
function isNestedGroup(el) {
|
|
28
|
+
if (el.kind === "element" && ((el.uri === WPG_NS && el.localName === "grpSp") || (el.uri === A_NS && el.localName === "grpSp"))) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
if (el.kind !== "element") return false;
|
|
32
|
+
for (const child of el.children) {
|
|
33
|
+
if (isNestedGroup(child)) return true;
|
|
34
|
+
}
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Raises if the group's OWN transform is not identity (scale != 1.0 on
|
|
40
|
+
* either axis, chOff != (0,0), rot != 0, or any flip), or if the group
|
|
41
|
+
* contains a nested group at any depth (`wpg:grpSp` or `a:grpSp` — corpus-
|
|
42
|
+
* measured as never occurring, but checked both ways since which spelling a
|
|
43
|
+
* document might use was exactly the kind of thing a prior regex pass in
|
|
44
|
+
* this project missed three times).
|
|
45
|
+
*
|
|
46
|
+
* A shape's OWN rotation (independent of its group) is NOT checked here —
|
|
47
|
+
* see `isShapeLocked`. This function is about the GROUP's transform only.
|
|
48
|
+
*
|
|
49
|
+
* @param {import("./drawingml.js").Xfrm} gXfrm
|
|
50
|
+
* @param {import("./xml-scan.js").XmlElement} groupEl
|
|
51
|
+
* @param {string} context
|
|
52
|
+
* @returns {{scaleX: number, scaleY: number}}
|
|
53
|
+
*/
|
|
54
|
+
export function checkGroupIdentity(gXfrm, groupEl, context) {
|
|
55
|
+
const scaleX = gXfrm.chExtCx ? gXfrm.extCx / gXfrm.chExtCx : 1.0;
|
|
56
|
+
const scaleY = gXfrm.chExtCy ? gXfrm.extCy / gXfrm.chExtCy : 1.0;
|
|
57
|
+
|
|
58
|
+
/** @type {string[]} */
|
|
59
|
+
const problems = [];
|
|
60
|
+
if (scaleX !== 1.0 || scaleY !== 1.0) {
|
|
61
|
+
problems.push(`non-identity scale (scale_x=${scaleX}, scale_y=${scaleY})`);
|
|
62
|
+
}
|
|
63
|
+
if (gXfrm.chOffX !== 0 || gXfrm.chOffY !== 0) {
|
|
64
|
+
problems.push(`chOff != (0,0): (${gXfrm.chOffX},${gXfrm.chOffY})`);
|
|
65
|
+
}
|
|
66
|
+
if (gXfrm.rot !== 0) {
|
|
67
|
+
problems.push(`group rot != 0: ${gXfrm.rot}`);
|
|
68
|
+
}
|
|
69
|
+
if (gXfrm.flipH || gXfrm.flipV) {
|
|
70
|
+
problems.push(`group flip: flipH=${gXfrm.flipH} flipV=${gXfrm.flipV}`);
|
|
71
|
+
}
|
|
72
|
+
if (isNestedGroup(groupEl)) {
|
|
73
|
+
problems.push("nested group found (wpg:grpSp or a:grpSp)");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (problems.length > 0) {
|
|
77
|
+
rejectImport(`${context}: ${problems.join("; ")}`);
|
|
78
|
+
}
|
|
79
|
+
return { scaleX, scaleY };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @param {{rot: number, flipH: boolean, flipV: boolean}} ownXfrm
|
|
84
|
+
* @returns {boolean}
|
|
85
|
+
*/
|
|
86
|
+
export function isShapeLocked(ownXfrm) {
|
|
87
|
+
return ownXfrm.rot !== 0 || ownXfrm.flipH || ownXfrm.flipV;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* An anchor without `wp:posOffset` under positionH/positionV (an
|
|
92
|
+
* alignment-based anchor using `wp:align` instead uses a different
|
|
93
|
+
* addressing scheme this importer does not interpret), or without
|
|
94
|
+
* `wp:extent`, has no safe on-page placement. Measured 2026-08-27: 0/8,737
|
|
95
|
+
* real corpus anchors trigger this — every anchor in all 46 documents uses
|
|
96
|
+
* absolute posOffset + extent. Silently dropping such an anchor (the
|
|
97
|
+
* pre-2026-08-27 behavior, a bare `continue`) risked discarding real,
|
|
98
|
+
* positioned content from a corpus-external document with no signal
|
|
99
|
+
* anywhere that anything was lost. Call only when at least one of the three
|
|
100
|
+
* booleans is true — matches the caller's own `if` guard, like `continue`
|
|
101
|
+
* did before it.
|
|
102
|
+
* @param {boolean} missingPosOffsetH
|
|
103
|
+
* @param {boolean} missingPosOffsetV
|
|
104
|
+
* @param {boolean} missingExtent
|
|
105
|
+
* @param {string} context
|
|
106
|
+
* @returns {never}
|
|
107
|
+
*/
|
|
108
|
+
export function rejectAnchorPlacement(missingPosOffsetH, missingPosOffsetV, missingExtent, context) {
|
|
109
|
+
/** @type {string[]} */
|
|
110
|
+
const problems = [];
|
|
111
|
+
if (missingPosOffsetH || missingPosOffsetV) {
|
|
112
|
+
problems.push("missing wp:posOffset under positionH/positionV (an alignment-based anchor, e.g. wp:align, is not supported)");
|
|
113
|
+
}
|
|
114
|
+
if (missingExtent) {
|
|
115
|
+
problems.push("missing wp:extent");
|
|
116
|
+
}
|
|
117
|
+
rejectImport(`${context}: ${problems.join("; ")}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* An anchor with no `a:graphic/a:graphicData` at all wraps nothing this
|
|
122
|
+
* importer can render. Measured 2026-08-27: 0/8,737 real corpus anchors
|
|
123
|
+
* trigger this.
|
|
124
|
+
* @param {string} context
|
|
125
|
+
* @returns {never}
|
|
126
|
+
*/
|
|
127
|
+
export function rejectMissingGraphicData(context) {
|
|
128
|
+
rejectImport(`${context}: anchor has no a:graphic/a:graphicData`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* A group (`wpg:wgp`) with no parseable `a:xfrm` under its own
|
|
133
|
+
* `wpg:grpSpPr` has no chOff/chExt to place or scale its children by —
|
|
134
|
+
* `checkGroupIdentity` (which checks whether that transform IS identity)
|
|
135
|
+
* can only run once this passes. Measured 2026-08-27: 0/459 real corpus
|
|
136
|
+
* groups trigger this.
|
|
137
|
+
* @param {string} context
|
|
138
|
+
* @returns {never}
|
|
139
|
+
*/
|
|
140
|
+
export function rejectMissingGroupTransform(context) {
|
|
141
|
+
rejectImport(`${context}: group has no parseable a:xfrm under wpg:grpSpPr`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* A shape (`wps:wsp`) inside a group with no parseable `a:xfrm` under its
|
|
146
|
+
* own `wps:spPr` has no off/ext to compute a position from — unlike a
|
|
147
|
+
* non-grouped wsp (whose absolute size comes from the anchor's own
|
|
148
|
+
* wp:extent instead, independent of spPr), a group child's position is
|
|
149
|
+
* defined ONLY relative to the group's chOff/chExt via its own xfrm.
|
|
150
|
+
* Measured 2026-08-27: 0/2,598 real corpus group-child shapes trigger this.
|
|
151
|
+
* @param {string} context
|
|
152
|
+
* @returns {never}
|
|
153
|
+
*/
|
|
154
|
+
export function rejectMissingShapeTransform(context) {
|
|
155
|
+
rejectImport(`${context}: group child shape has no parseable a:xfrm under wps:spPr`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* A non-grouped anchor's `a:graphicData` holding none of `wpg:wgp`,
|
|
160
|
+
* `wps:wsp`, or `pic:pic` is some other graphic type this importer has no
|
|
161
|
+
* model for (a chart, SmartArt diagram, OLE object, or ink annotation —
|
|
162
|
+
* ADR-0020 §7's own reserved REJECTED class). Measured 2026-08-27: 0/8,278
|
|
163
|
+
* real corpus non-group anchors trigger this.
|
|
164
|
+
* @param {string} context
|
|
165
|
+
* @returns {never}
|
|
166
|
+
*/
|
|
167
|
+
export function rejectUnsupportedGraphicDataKind(context) {
|
|
168
|
+
rejectImport(`${context}: a:graphicData holds none of wpg:wgp, wps:wsp, pic:pic (unsupported graphic type — chart, diagram, OLE object, or ink)`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* A `w:drawing` wrapping `wp:inline` (in-text-flow placement) instead of
|
|
173
|
+
* `wp:anchor` (floating placement) uses an addressing scheme this importer
|
|
174
|
+
* never reads any coordinate from — `collectAnchors` only walks for
|
|
175
|
+
* `wp:anchor` children, so an inline drawing was previously absent from the
|
|
176
|
+
* anchors array with no signal anywhere that anything had been dropped.
|
|
177
|
+
* ADR-0020 Karar 4's own table (`wp:inline` -> REJECTED, "corpus'ta 0")
|
|
178
|
+
* predates this function; measured again 2026-08-27 against the real
|
|
179
|
+
* corpus: 0/46 documents contain one.
|
|
180
|
+
* @param {string} context
|
|
181
|
+
* @returns {never}
|
|
182
|
+
*/
|
|
183
|
+
export function rejectInlineDrawing(context) {
|
|
184
|
+
rejectImport(`${context}: w:drawing wraps wp:inline (in-text-flow placement is not supported, only wp:anchor)`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* A `w:rPr` carrying `w:rStyle` (a reference to a character style defined in
|
|
189
|
+
* styles.xml) is never resolved by this importer — `readRPr` reads direct
|
|
190
|
+
* toggles (b/i/u), size, and font only, and a character-style reference
|
|
191
|
+
* silently produced whatever the run's OWN direct properties happened to be,
|
|
192
|
+
* with no signal that the style's contribution was missing. ADR-0020 Karar
|
|
193
|
+
* 4's own table (`w:rStyle` -> REJECTED, "0/81.973" runs); measured again
|
|
194
|
+
* 2026-08-27 against the real corpus: still 0/46 documents contain one.
|
|
195
|
+
* @param {string} context
|
|
196
|
+
* @returns {never}
|
|
197
|
+
*/
|
|
198
|
+
export function rejectCharacterStyle(context) {
|
|
199
|
+
rejectImport(`${context}: w:rPr carries w:rStyle (character-style reference is not resolved)`);
|
|
200
|
+
}
|