@beyondwork/docx-react-component 1.0.110 → 1.0.111
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/package.json +1 -1
- package/src/api/public-types.ts +3 -0
- package/src/model/layout/page-graph-types.ts +33 -0
- package/src/runtime/geometry/adjacent-geometry-intake.ts +373 -5
- package/src/runtime/geometry/caret-geometry.ts +219 -7
- package/src/runtime/geometry/geometry-index.ts +35 -10
- package/src/runtime/geometry/object-handles.ts +42 -1
- package/src/runtime/layout/index.ts +3 -0
- package/src/runtime/layout/inert-layout-facet.ts +13 -0
- package/src/runtime/layout/layout-engine-instance.ts +2 -0
- package/src/runtime/layout/layout-engine-version.ts +32 -2
- package/src/runtime/layout/layout-facet-types.ts +3 -0
- package/src/runtime/layout/page-graph.ts +81 -7
- package/src/runtime/layout/project-block-fragments.ts +144 -1
- package/src/runtime/layout/public-facet.ts +160 -0
- package/src/runtime/scopes/adjacent-geometry-evidence.ts +456 -0
- package/src/runtime/scopes/compile-scope-bundle.ts +8 -0
- package/src/runtime/scopes/evidence.ts +16 -0
- package/src/runtime/scopes/index.ts +13 -0
- package/src/runtime/scopes/semantic-scope-types.ts +67 -0
- package/src/ui-tailwind/debug/layer11-consumer-readiness.ts +104 -0
- package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +50 -5
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +26 -0
- package/src/README.md +0 -85
- package/src/api/README.md +0 -26
- package/src/api/v3/README.md +0 -91
- package/src/component-inventory.md +0 -99
- package/src/core/README.md +0 -10
- package/src/core/commands/README.md +0 -3
- package/src/core/schema/README.md +0 -3
- package/src/core/selection/README.md +0 -3
- package/src/core/state/README.md +0 -3
- package/src/io/README.md +0 -10
- package/src/io/export/README.md +0 -3
- package/src/io/normalize/README.md +0 -3
- package/src/io/ooxml/README.md +0 -3
- package/src/io/opc/README.md +0 -3
- package/src/model/README.md +0 -3
- package/src/preservation/README.md +0 -3
- package/src/review/README.md +0 -16
- package/src/review/store/README.md +0 -3
- package/src/runtime/README.md +0 -3
- package/src/ui/README.md +0 -30
- package/src/ui/comments/README.md +0 -3
- package/src/ui/compatibility/README.md +0 -3
- package/src/ui/editor-surface/README.md +0 -3
- package/src/ui/review/README.md +0 -3
- package/src/ui/status/README.md +0 -3
- package/src/ui/theme/README.md +0 -3
- package/src/ui/toolbar/README.md +0 -3
- package/src/ui-tailwind/debug/README.md +0 -22
- package/src/validation/README.md +0 -3
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded adjacent geometry evidence from Layer 05.
|
|
3
|
+
*
|
|
4
|
+
* L08 consumes only compositor-ready `frame-px` rows from the L05 adjacent
|
|
5
|
+
* geometry intake. This evidence is read-side scope-bundle context; it is not
|
|
6
|
+
* replacement-envelope geometry and must not widen mutation capability.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { FieldEnumeratedScope, EnumeratedScope } from "./enumerate-scopes.ts";
|
|
10
|
+
import type {
|
|
11
|
+
ScopeAdjacentGeometryEvidence,
|
|
12
|
+
ScopeAdjacentGeometryFramePixelPoint,
|
|
13
|
+
ScopeAdjacentGeometryFramePixelRect,
|
|
14
|
+
ScopeAdjacentGeometryRowEvidence,
|
|
15
|
+
SemanticScope,
|
|
16
|
+
} from "./semantic-scope-types.ts";
|
|
17
|
+
|
|
18
|
+
interface FramePixelScaleLike {
|
|
19
|
+
readonly source?: unknown;
|
|
20
|
+
readonly renderFrameRevision?: unknown;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface FramePixelProjectionLike {
|
|
24
|
+
readonly status?: unknown;
|
|
25
|
+
readonly coordinateSpace?: unknown;
|
|
26
|
+
readonly precision?: unknown;
|
|
27
|
+
readonly pageIndex?: unknown;
|
|
28
|
+
readonly pageId?: unknown;
|
|
29
|
+
readonly frameId?: unknown;
|
|
30
|
+
readonly scale?: FramePixelScaleLike;
|
|
31
|
+
readonly markerLane?: unknown;
|
|
32
|
+
readonly textColumn?: unknown;
|
|
33
|
+
readonly fieldStartAnchorPx?: unknown;
|
|
34
|
+
readonly fieldEndAnchorPx?: unknown;
|
|
35
|
+
readonly fieldResultRangePx?: unknown;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface AdjacentPageLocalGeometryLike {
|
|
39
|
+
readonly compositorReady?: unknown;
|
|
40
|
+
readonly framePixelProjection?: FramePixelProjectionLike;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface AdjacentNumberingRowLike {
|
|
44
|
+
readonly docId?: unknown;
|
|
45
|
+
readonly canonicalBlockId?: unknown;
|
|
46
|
+
readonly runtimeBlockId?: unknown;
|
|
47
|
+
readonly runtimeFragmentId?: unknown;
|
|
48
|
+
readonly runtimeNumberingId?: unknown;
|
|
49
|
+
readonly canonicalNumberingInstanceId?: unknown;
|
|
50
|
+
readonly canonicalLevel?: unknown;
|
|
51
|
+
readonly markerKind?: unknown;
|
|
52
|
+
readonly markerSuffix?: unknown;
|
|
53
|
+
readonly pageLocalGeometry?: AdjacentPageLocalGeometryLike;
|
|
54
|
+
readonly compositorReady?: unknown;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface AdjacentFieldRegionRowLike {
|
|
58
|
+
readonly docId?: unknown;
|
|
59
|
+
readonly canonicalBlockId?: unknown;
|
|
60
|
+
readonly canonicalFieldId?: unknown;
|
|
61
|
+
readonly runtimeFieldRegionId?: unknown;
|
|
62
|
+
readonly runtimeFragmentId?: unknown;
|
|
63
|
+
readonly instructionFamily?: unknown;
|
|
64
|
+
readonly pageLocalGeometry?: AdjacentPageLocalGeometryLike;
|
|
65
|
+
readonly compositorReady?: unknown;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface AdjacentGeometryIntakeLike {
|
|
69
|
+
readonly schemaVersion?: unknown;
|
|
70
|
+
readonly pageLocalNormalization?: {
|
|
71
|
+
readonly framePixelCoordinateSpace?: unknown;
|
|
72
|
+
readonly compositorReady?: unknown;
|
|
73
|
+
};
|
|
74
|
+
readonly numberingRows?: readonly AdjacentNumberingRowLike[];
|
|
75
|
+
readonly fieldRegionRows?: readonly AdjacentFieldRegionRowLike[];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface ScopeAdjacentGeometryEvidenceProvider {
|
|
79
|
+
getScopeAdjacentGeometryEvidence(
|
|
80
|
+
scope: SemanticScope,
|
|
81
|
+
entry: EnumeratedScope | null,
|
|
82
|
+
): ScopeAdjacentGeometryEvidence | null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface ScopeAdjacentGeometryIntakeSummary {
|
|
86
|
+
readonly schemaVersion: string | null;
|
|
87
|
+
readonly intakeReady: boolean;
|
|
88
|
+
readonly numberingCompositorReadyRows: number;
|
|
89
|
+
readonly fieldRegionCompositorReadyRows: number;
|
|
90
|
+
readonly eligibleRowCount: number;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function stringValue(value: unknown): string | undefined {
|
|
94
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function numberValue(value: unknown): number | undefined {
|
|
98
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function parseParagraphBlockIndex(value: unknown): number | undefined {
|
|
102
|
+
const raw = stringValue(value);
|
|
103
|
+
if (!raw) return undefined;
|
|
104
|
+
const match = /^paragraph-(\d+)$/.exec(raw);
|
|
105
|
+
return match ? Number(match[1]) : undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function docMatches(scope: SemanticScope, docId: string | undefined): boolean {
|
|
109
|
+
return !docId || !scope.handle.documentId || scope.handle.documentId === docId;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isCompositorReady(geometry: AdjacentPageLocalGeometryLike | undefined): boolean {
|
|
113
|
+
const projection = geometry?.framePixelProjection;
|
|
114
|
+
return (
|
|
115
|
+
geometry?.compositorReady === true &&
|
|
116
|
+
projection?.status === "projected-frame-pixels" &&
|
|
117
|
+
projection.coordinateSpace === "frame-px" &&
|
|
118
|
+
projection.precision === "word-page-local-calibration"
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function normalizeRect(value: unknown): ScopeAdjacentGeometryFramePixelRect | undefined {
|
|
123
|
+
const rect = value as
|
|
124
|
+
| {
|
|
125
|
+
readonly leftPx?: unknown;
|
|
126
|
+
readonly topPx?: unknown;
|
|
127
|
+
readonly widthPx?: unknown;
|
|
128
|
+
readonly heightPx?: unknown;
|
|
129
|
+
readonly coordinateSpace?: unknown;
|
|
130
|
+
}
|
|
131
|
+
| undefined;
|
|
132
|
+
const leftPx = numberValue(rect?.leftPx);
|
|
133
|
+
const topPx = numberValue(rect?.topPx);
|
|
134
|
+
const widthPx = numberValue(rect?.widthPx);
|
|
135
|
+
const heightPx = numberValue(rect?.heightPx);
|
|
136
|
+
if (
|
|
137
|
+
leftPx === undefined ||
|
|
138
|
+
topPx === undefined ||
|
|
139
|
+
widthPx === undefined ||
|
|
140
|
+
heightPx === undefined ||
|
|
141
|
+
rect?.coordinateSpace !== "frame-px"
|
|
142
|
+
) {
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
return { leftPx, topPx, widthPx, heightPx, coordinateSpace: "frame-px" };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function normalizePoint(value: unknown): ScopeAdjacentGeometryFramePixelPoint | undefined {
|
|
149
|
+
const point = value as
|
|
150
|
+
| {
|
|
151
|
+
readonly xPx?: unknown;
|
|
152
|
+
readonly yPx?: unknown;
|
|
153
|
+
readonly coordinateSpace?: unknown;
|
|
154
|
+
}
|
|
155
|
+
| undefined;
|
|
156
|
+
const xPx = numberValue(point?.xPx);
|
|
157
|
+
const yPx = numberValue(point?.yPx);
|
|
158
|
+
if (xPx === undefined || yPx === undefined || point?.coordinateSpace !== "frame-px") {
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
161
|
+
return { xPx, yPx, coordinateSpace: "frame-px" };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function baseRow(
|
|
165
|
+
axis: ScopeAdjacentGeometryRowEvidence["axis"],
|
|
166
|
+
input: {
|
|
167
|
+
readonly docId?: string;
|
|
168
|
+
readonly canonicalBlockId?: string;
|
|
169
|
+
readonly runtimeFragmentId?: string;
|
|
170
|
+
readonly projection: FramePixelProjectionLike;
|
|
171
|
+
},
|
|
172
|
+
): Omit<ScopeAdjacentGeometryRowEvidence, "numbering" | "fieldRegion"> {
|
|
173
|
+
return {
|
|
174
|
+
axis,
|
|
175
|
+
source: "l05-adjacent-geometry-intake",
|
|
176
|
+
...(input.docId ? { docId: input.docId } : {}),
|
|
177
|
+
...(input.canonicalBlockId ? { canonicalBlockId: input.canonicalBlockId } : {}),
|
|
178
|
+
...(input.runtimeFragmentId ? { runtimeFragmentId: input.runtimeFragmentId } : {}),
|
|
179
|
+
...(typeof input.projection.pageId === "string"
|
|
180
|
+
? { pageId: input.projection.pageId }
|
|
181
|
+
: {}),
|
|
182
|
+
...(typeof input.projection.frameId === "string"
|
|
183
|
+
? { frameId: input.projection.frameId }
|
|
184
|
+
: {}),
|
|
185
|
+
...(numberValue(input.projection.pageIndex) !== undefined
|
|
186
|
+
? { pageIndex: numberValue(input.projection.pageIndex) }
|
|
187
|
+
: {}),
|
|
188
|
+
precision: "word-page-local-calibration",
|
|
189
|
+
coordinateSpace: "frame-px",
|
|
190
|
+
compositorReady: true,
|
|
191
|
+
...(input.projection.scale?.source === "runtime-render-frame-page-rect"
|
|
192
|
+
? { scaleSource: "runtime-render-frame-page-rect" as const }
|
|
193
|
+
: {}),
|
|
194
|
+
...(numberValue(input.projection.scale?.renderFrameRevision) !== undefined
|
|
195
|
+
? { renderFrameRevision: numberValue(input.projection.scale?.renderFrameRevision) }
|
|
196
|
+
: {}),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function projectNumberingRow(row: AdjacentNumberingRowLike): ScopeAdjacentGeometryRowEvidence | null {
|
|
201
|
+
if (row.compositorReady !== true || !isCompositorReady(row.pageLocalGeometry)) return null;
|
|
202
|
+
const projection = row.pageLocalGeometry!.framePixelProjection!;
|
|
203
|
+
const docId = stringValue(row.docId);
|
|
204
|
+
const canonicalBlockId = stringValue(row.canonicalBlockId) ?? stringValue(row.runtimeBlockId);
|
|
205
|
+
return {
|
|
206
|
+
...baseRow("numbering-marker", {
|
|
207
|
+
docId,
|
|
208
|
+
canonicalBlockId,
|
|
209
|
+
runtimeFragmentId: stringValue(row.runtimeFragmentId),
|
|
210
|
+
projection,
|
|
211
|
+
}),
|
|
212
|
+
numbering: {
|
|
213
|
+
...(stringValue(row.runtimeNumberingId)
|
|
214
|
+
? { runtimeNumberingId: stringValue(row.runtimeNumberingId) }
|
|
215
|
+
: {}),
|
|
216
|
+
...(stringValue(row.canonicalNumberingInstanceId)
|
|
217
|
+
? { canonicalNumberingInstanceId: stringValue(row.canonicalNumberingInstanceId) }
|
|
218
|
+
: {}),
|
|
219
|
+
...(numberValue(row.canonicalLevel) !== undefined
|
|
220
|
+
? { canonicalLevel: numberValue(row.canonicalLevel) }
|
|
221
|
+
: {}),
|
|
222
|
+
...(stringValue(row.markerKind) ? { markerKind: stringValue(row.markerKind) } : {}),
|
|
223
|
+
...(stringValue(row.markerSuffix) ? { markerSuffix: stringValue(row.markerSuffix) } : {}),
|
|
224
|
+
...(normalizeRect(projection.markerLane)
|
|
225
|
+
? { markerLane: normalizeRect(projection.markerLane) }
|
|
226
|
+
: {}),
|
|
227
|
+
...(normalizeRect(projection.textColumn)
|
|
228
|
+
? { textColumn: normalizeRect(projection.textColumn) }
|
|
229
|
+
: {}),
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function projectFieldRegionRow(
|
|
235
|
+
row: AdjacentFieldRegionRowLike,
|
|
236
|
+
): ScopeAdjacentGeometryRowEvidence | null {
|
|
237
|
+
if (row.compositorReady !== true || !isCompositorReady(row.pageLocalGeometry)) return null;
|
|
238
|
+
const projection = row.pageLocalGeometry!.framePixelProjection!;
|
|
239
|
+
const docId = stringValue(row.docId);
|
|
240
|
+
const canonicalBlockId = stringValue(row.canonicalBlockId);
|
|
241
|
+
return {
|
|
242
|
+
...baseRow("field-region", {
|
|
243
|
+
docId,
|
|
244
|
+
canonicalBlockId,
|
|
245
|
+
runtimeFragmentId: stringValue(row.runtimeFragmentId),
|
|
246
|
+
projection,
|
|
247
|
+
}),
|
|
248
|
+
fieldRegion: {
|
|
249
|
+
...(stringValue(row.canonicalFieldId)
|
|
250
|
+
? { canonicalFieldId: stringValue(row.canonicalFieldId) }
|
|
251
|
+
: {}),
|
|
252
|
+
...(stringValue(row.runtimeFieldRegionId)
|
|
253
|
+
? { runtimeFieldRegionId: stringValue(row.runtimeFieldRegionId) }
|
|
254
|
+
: {}),
|
|
255
|
+
...(stringValue(row.instructionFamily)
|
|
256
|
+
? { instructionFamily: stringValue(row.instructionFamily) }
|
|
257
|
+
: {}),
|
|
258
|
+
...(normalizePoint(projection.fieldStartAnchorPx)
|
|
259
|
+
? { fieldStartAnchorPx: normalizePoint(projection.fieldStartAnchorPx) }
|
|
260
|
+
: {}),
|
|
261
|
+
...(normalizePoint(projection.fieldEndAnchorPx)
|
|
262
|
+
? { fieldEndAnchorPx: normalizePoint(projection.fieldEndAnchorPx) }
|
|
263
|
+
: {}),
|
|
264
|
+
...(normalizeRect(projection.fieldResultRangePx)
|
|
265
|
+
? { fieldResultRangePx: normalizeRect(projection.fieldResultRangePx) }
|
|
266
|
+
: {}),
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function numberingRowMatchesScope(
|
|
272
|
+
row: ScopeAdjacentGeometryRowEvidence,
|
|
273
|
+
scope: SemanticScope,
|
|
274
|
+
entry: EnumeratedScope | null,
|
|
275
|
+
): boolean {
|
|
276
|
+
if (scope.kind !== "list-item" || entry?.kind !== "list-item") return false;
|
|
277
|
+
if (!docMatches(scope, row.docId)) return false;
|
|
278
|
+
const rowBlockIndex = parseParagraphBlockIndex(row.canonicalBlockId);
|
|
279
|
+
if (rowBlockIndex !== undefined && rowBlockIndex !== entry.blockIndex) return false;
|
|
280
|
+
const numbering = row.numbering;
|
|
281
|
+
if (
|
|
282
|
+
numbering?.canonicalNumberingInstanceId &&
|
|
283
|
+
scope.formatting.numbering?.numberingInstanceId &&
|
|
284
|
+
numbering.canonicalNumberingInstanceId !== scope.formatting.numbering.numberingInstanceId
|
|
285
|
+
) {
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
if (
|
|
289
|
+
numbering?.canonicalLevel !== undefined &&
|
|
290
|
+
scope.formatting.numbering?.level !== undefined &&
|
|
291
|
+
numbering.canonicalLevel !== scope.formatting.numbering.level
|
|
292
|
+
) {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
return rowBlockIndex !== undefined;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function fieldRowMatchesScope(
|
|
299
|
+
row: ScopeAdjacentGeometryRowEvidence,
|
|
300
|
+
scope: SemanticScope,
|
|
301
|
+
entry: EnumeratedScope | null,
|
|
302
|
+
): boolean {
|
|
303
|
+
if (scope.kind !== "field" || entry?.kind !== "field") return false;
|
|
304
|
+
if (!docMatches(scope, row.docId)) return false;
|
|
305
|
+
const fieldEntry = entry as FieldEnumeratedScope;
|
|
306
|
+
const rowCanonicalFieldId = row.fieldRegion?.canonicalFieldId;
|
|
307
|
+
if (rowCanonicalFieldId && fieldEntry.field.canonicalFieldId) {
|
|
308
|
+
return rowCanonicalFieldId === fieldEntry.field.canonicalFieldId;
|
|
309
|
+
}
|
|
310
|
+
const rowBlockIndex = parseParagraphBlockIndex(row.canonicalBlockId);
|
|
311
|
+
return rowBlockIndex !== undefined && rowBlockIndex === fieldEntry.blockIndex;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export function createAdjacentGeometryScopeEvidenceProvider(
|
|
315
|
+
intake: AdjacentGeometryIntakeLike,
|
|
316
|
+
): ScopeAdjacentGeometryEvidenceProvider {
|
|
317
|
+
const intakeReady = isIntakeReady(intake);
|
|
318
|
+
const numberingRows = intakeReady
|
|
319
|
+
? (intake.numberingRows ?? []).map(projectNumberingRow).filter(isEvidenceRow)
|
|
320
|
+
: [];
|
|
321
|
+
const fieldRegionRows = intakeReady
|
|
322
|
+
? (intake.fieldRegionRows ?? []).map(projectFieldRegionRow).filter(isEvidenceRow)
|
|
323
|
+
: [];
|
|
324
|
+
const allRows = Object.freeze([...numberingRows, ...fieldRegionRows]);
|
|
325
|
+
|
|
326
|
+
return {
|
|
327
|
+
getScopeAdjacentGeometryEvidence(scope, entry) {
|
|
328
|
+
if (!intakeReady) {
|
|
329
|
+
return {
|
|
330
|
+
status: "unavailable",
|
|
331
|
+
source: "l05-adjacent-geometry-intake",
|
|
332
|
+
rowCount: 0,
|
|
333
|
+
reason: "l05-adjacent-intake-not-compositor-ready",
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
const rows = allRows.filter(
|
|
337
|
+
(row) =>
|
|
338
|
+
numberingRowMatchesScope(row, scope, entry) ||
|
|
339
|
+
fieldRowMatchesScope(row, scope, entry),
|
|
340
|
+
);
|
|
341
|
+
if (rows.length === 0) return null;
|
|
342
|
+
return {
|
|
343
|
+
status: "available",
|
|
344
|
+
source: "l05-adjacent-geometry-intake",
|
|
345
|
+
schemaVersion: "layer-05-adjacent-geometry-intake/v2",
|
|
346
|
+
rowCount: rows.length,
|
|
347
|
+
rows: Object.freeze(rows.map(cloneAdjacentGeometryRow)),
|
|
348
|
+
};
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export function summarizeAdjacentGeometryEvidenceIntake(
|
|
354
|
+
intake: AdjacentGeometryIntakeLike,
|
|
355
|
+
): ScopeAdjacentGeometryIntakeSummary {
|
|
356
|
+
const intakeReady = isIntakeReady(intake);
|
|
357
|
+
const numberingCompositorReadyRows = intakeReady
|
|
358
|
+
? (intake.numberingRows ?? []).map(projectNumberingRow).filter(isEvidenceRow).length
|
|
359
|
+
: 0;
|
|
360
|
+
const fieldRegionCompositorReadyRows = intakeReady
|
|
361
|
+
? (intake.fieldRegionRows ?? []).map(projectFieldRegionRow).filter(isEvidenceRow).length
|
|
362
|
+
: 0;
|
|
363
|
+
return {
|
|
364
|
+
schemaVersion: typeof intake.schemaVersion === "string" ? intake.schemaVersion : null,
|
|
365
|
+
intakeReady,
|
|
366
|
+
numberingCompositorReadyRows,
|
|
367
|
+
fieldRegionCompositorReadyRows,
|
|
368
|
+
eligibleRowCount: numberingCompositorReadyRows + fieldRegionCompositorReadyRows,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function isIntakeReady(intake: AdjacentGeometryIntakeLike): boolean {
|
|
373
|
+
return (
|
|
374
|
+
intake.schemaVersion === "layer-05-adjacent-geometry-intake/v2" &&
|
|
375
|
+
intake.pageLocalNormalization?.framePixelCoordinateSpace === "frame-px" &&
|
|
376
|
+
intake.pageLocalNormalization.compositorReady === true
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function isEvidenceRow(
|
|
381
|
+
row: ScopeAdjacentGeometryRowEvidence | null,
|
|
382
|
+
): row is ScopeAdjacentGeometryRowEvidence {
|
|
383
|
+
return row !== null;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function cloneRect(
|
|
387
|
+
rect: ScopeAdjacentGeometryFramePixelRect | undefined,
|
|
388
|
+
): ScopeAdjacentGeometryFramePixelRect | undefined {
|
|
389
|
+
return rect ? { ...rect } : undefined;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function clonePoint(
|
|
393
|
+
point: ScopeAdjacentGeometryFramePixelPoint | undefined,
|
|
394
|
+
): ScopeAdjacentGeometryFramePixelPoint | undefined {
|
|
395
|
+
return point ? { ...point } : undefined;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function cloneAdjacentGeometryRow(
|
|
399
|
+
row: ScopeAdjacentGeometryRowEvidence,
|
|
400
|
+
): ScopeAdjacentGeometryRowEvidence {
|
|
401
|
+
return {
|
|
402
|
+
...row,
|
|
403
|
+
...(row.numbering
|
|
404
|
+
? {
|
|
405
|
+
numbering: {
|
|
406
|
+
...row.numbering,
|
|
407
|
+
...(row.numbering.markerLane
|
|
408
|
+
? { markerLane: cloneRect(row.numbering.markerLane) }
|
|
409
|
+
: {}),
|
|
410
|
+
...(row.numbering.textColumn
|
|
411
|
+
? { textColumn: cloneRect(row.numbering.textColumn) }
|
|
412
|
+
: {}),
|
|
413
|
+
},
|
|
414
|
+
}
|
|
415
|
+
: {}),
|
|
416
|
+
...(row.fieldRegion
|
|
417
|
+
? {
|
|
418
|
+
fieldRegion: {
|
|
419
|
+
...row.fieldRegion,
|
|
420
|
+
...(row.fieldRegion.fieldStartAnchorPx
|
|
421
|
+
? { fieldStartAnchorPx: clonePoint(row.fieldRegion.fieldStartAnchorPx) }
|
|
422
|
+
: {}),
|
|
423
|
+
...(row.fieldRegion.fieldEndAnchorPx
|
|
424
|
+
? { fieldEndAnchorPx: clonePoint(row.fieldRegion.fieldEndAnchorPx) }
|
|
425
|
+
: {}),
|
|
426
|
+
...(row.fieldRegion.fieldResultRangePx
|
|
427
|
+
? { fieldResultRangePx: cloneRect(row.fieldRegion.fieldResultRangePx) }
|
|
428
|
+
: {}),
|
|
429
|
+
},
|
|
430
|
+
}
|
|
431
|
+
: {}),
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
export function deriveScopeAdjacentGeometryEvidence(
|
|
436
|
+
scope: SemanticScope,
|
|
437
|
+
entry: EnumeratedScope | null,
|
|
438
|
+
provider?: ScopeAdjacentGeometryEvidenceProvider,
|
|
439
|
+
): ScopeAdjacentGeometryEvidence | undefined {
|
|
440
|
+
if (!provider) return undefined;
|
|
441
|
+
const evidence = provider.getScopeAdjacentGeometryEvidence(scope, entry);
|
|
442
|
+
if (!evidence) {
|
|
443
|
+
return {
|
|
444
|
+
status: "unavailable",
|
|
445
|
+
source: "l05-adjacent-geometry-intake",
|
|
446
|
+
rowCount: 0,
|
|
447
|
+
reason: "scope-adjacent-frame-pixel-row-unavailable",
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
return {
|
|
451
|
+
...evidence,
|
|
452
|
+
...(evidence.rows
|
|
453
|
+
? { rows: Object.freeze(evidence.rows.map(cloneAdjacentGeometryRow)) }
|
|
454
|
+
: {}),
|
|
455
|
+
};
|
|
456
|
+
}
|
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
WorkflowOverlay,
|
|
19
19
|
} from "./_scope-dependencies.ts";
|
|
20
20
|
import type { ScopeGeometryEvidenceProvider } from "./geometry-evidence.ts";
|
|
21
|
+
import type { ScopeAdjacentGeometryEvidenceProvider } from "./adjacent-geometry-evidence.ts";
|
|
21
22
|
|
|
22
23
|
import {
|
|
23
24
|
buildParagraphIndexMap,
|
|
@@ -59,6 +60,12 @@ export interface ScopeBundleInputs {
|
|
|
59
60
|
* records layout as unavailable instead of deriving page slices in L08.
|
|
60
61
|
*/
|
|
61
62
|
readonly layout?: ScopeLayoutEvidenceProvider;
|
|
63
|
+
/**
|
|
64
|
+
* Optional Layer-05 adjacent geometry intake seam for compositor-ready
|
|
65
|
+
* `frame-px` rows. Kept separate from replacement-envelope geometry so it
|
|
66
|
+
* cannot widen edit capability.
|
|
67
|
+
*/
|
|
68
|
+
readonly adjacentGeometry?: ScopeAdjacentGeometryEvidenceProvider;
|
|
62
69
|
}
|
|
63
70
|
|
|
64
71
|
/**
|
|
@@ -140,6 +147,7 @@ export function compileScopeBundle(
|
|
|
140
147
|
: {}),
|
|
141
148
|
...(inputs.geometry ? { geometry: inputs.geometry } : {}),
|
|
142
149
|
...(inputs.layout ? { layout: inputs.layout } : {}),
|
|
150
|
+
...(inputs.adjacentGeometry ? { adjacentGeometry: inputs.adjacentGeometry } : {}),
|
|
143
151
|
});
|
|
144
152
|
return {
|
|
145
153
|
scope,
|
|
@@ -24,6 +24,10 @@ import type {
|
|
|
24
24
|
} from "./_scope-dependencies.ts";
|
|
25
25
|
|
|
26
26
|
import { AI_EXPLANATION_METADATA_ID } from "./attach-explanation.ts";
|
|
27
|
+
import {
|
|
28
|
+
deriveScopeAdjacentGeometryEvidence,
|
|
29
|
+
type ScopeAdjacentGeometryEvidenceProvider,
|
|
30
|
+
} from "./adjacent-geometry-evidence.ts";
|
|
27
31
|
import { deriveScopeCapabilities } from "./capabilities.ts";
|
|
28
32
|
import { deriveScopeContentControlEvidence } from "./content-control-evidence.ts";
|
|
29
33
|
import { AI_ISSUE_METADATA_ID } from "./create-issue.ts";
|
|
@@ -107,6 +111,12 @@ export interface EvidenceInputs {
|
|
|
107
111
|
* rows are surfaced explicitly in `ScopeBundleEvidence.layout`.
|
|
108
112
|
*/
|
|
109
113
|
readonly layout?: ScopeLayoutEvidenceProvider;
|
|
114
|
+
/**
|
|
115
|
+
* Optional Layer-05 adjacent geometry intake seam. This is bounded
|
|
116
|
+
* compositor/read evidence and does not participate in replacement
|
|
117
|
+
* capability derivation.
|
|
118
|
+
*/
|
|
119
|
+
readonly adjacentGeometry?: ScopeAdjacentGeometryEvidenceProvider;
|
|
110
120
|
}
|
|
111
121
|
|
|
112
122
|
function normalizeSeverity(raw: unknown): AIIssueSummary["severity"] {
|
|
@@ -301,6 +311,11 @@ export function composeEvidence(inputs: EvidenceInputs): ScopeBundleEvidence {
|
|
|
301
311
|
|
|
302
312
|
const layout = deriveScopeLayoutEvidence(scope.handle.scopeId, inputs.layout);
|
|
303
313
|
const geometry = deriveScopeGeometryEvidence(scope.handle.scopeId, inputs.geometry);
|
|
314
|
+
const adjacentGeometry = deriveScopeAdjacentGeometryEvidence(
|
|
315
|
+
scope,
|
|
316
|
+
entry,
|
|
317
|
+
inputs.adjacentGeometry,
|
|
318
|
+
);
|
|
304
319
|
const contentControls = deriveScopeContentControlEvidence(document, selfRange);
|
|
305
320
|
|
|
306
321
|
return {
|
|
@@ -310,6 +325,7 @@ export function composeEvidence(inputs: EvidenceInputs): ScopeBundleEvidence {
|
|
|
310
325
|
compatibilityFlags,
|
|
311
326
|
layout,
|
|
312
327
|
geometry,
|
|
328
|
+
...(adjacentGeometry ? { adjacentGeometry } : {}),
|
|
313
329
|
visualization: deriveScopeVisualization(scope),
|
|
314
330
|
contentControls,
|
|
315
331
|
capabilities: deriveScopeCapabilities(scope, {
|
|
@@ -52,6 +52,11 @@ export type {
|
|
|
52
52
|
ScopeFormattingClearTarget,
|
|
53
53
|
ScopeFormattingScope,
|
|
54
54
|
ScopeActionPosture,
|
|
55
|
+
ScopeAdjacentGeometryAxis,
|
|
56
|
+
ScopeAdjacentGeometryEvidence,
|
|
57
|
+
ScopeAdjacentGeometryFramePixelPoint,
|
|
58
|
+
ScopeAdjacentGeometryFramePixelRect,
|
|
59
|
+
ScopeAdjacentGeometryRowEvidence,
|
|
55
60
|
ScopeBundle,
|
|
56
61
|
ScopeBundleEvidence,
|
|
57
62
|
ScopeBundleNeighborhood,
|
|
@@ -73,6 +78,14 @@ export type {
|
|
|
73
78
|
ValidationIssue,
|
|
74
79
|
ValidationResult,
|
|
75
80
|
} from "./semantic-scope-types.ts";
|
|
81
|
+
export {
|
|
82
|
+
createAdjacentGeometryScopeEvidenceProvider,
|
|
83
|
+
deriveScopeAdjacentGeometryEvidence,
|
|
84
|
+
summarizeAdjacentGeometryEvidenceIntake,
|
|
85
|
+
type AdjacentGeometryIntakeLike,
|
|
86
|
+
type ScopeAdjacentGeometryIntakeSummary,
|
|
87
|
+
type ScopeAdjacentGeometryEvidenceProvider,
|
|
88
|
+
} from "./adjacent-geometry-evidence.ts";
|
|
76
89
|
export { deriveScopeCapabilities } from "./capabilities.ts";
|
|
77
90
|
export type { ScopeCapabilityContext } from "./capabilities.ts";
|
|
78
91
|
export {
|
|
@@ -289,6 +289,12 @@ export interface ScopeBundleEvidence {
|
|
|
289
289
|
* `requires-rehydration` or `unavailable`; Layer 08 never fabricates rects.
|
|
290
290
|
*/
|
|
291
291
|
readonly geometry?: ScopeGeometryEvidence;
|
|
292
|
+
/**
|
|
293
|
+
* Bounded Layer-05 adjacent geometry evidence. This is compositor/read
|
|
294
|
+
* evidence only; it does not make a scope replaceable. Rows are present only
|
|
295
|
+
* when L05 marked them `compositorReady` in `frame-px` space.
|
|
296
|
+
*/
|
|
297
|
+
readonly adjacentGeometry?: ScopeAdjacentGeometryEvidence;
|
|
292
298
|
/**
|
|
293
299
|
* Presentation hint only. Consumers may use this to choose a cheap inline
|
|
294
300
|
* treatment for field-like scopes versus a broader overlay treatment for
|
|
@@ -449,6 +455,67 @@ export interface ScopeGeometryEvidence {
|
|
|
449
455
|
};
|
|
450
456
|
}
|
|
451
457
|
|
|
458
|
+
export type ScopeAdjacentGeometryAxis = "numbering-marker" | "field-region";
|
|
459
|
+
|
|
460
|
+
export interface ScopeAdjacentGeometryFramePixelRect {
|
|
461
|
+
readonly leftPx: number;
|
|
462
|
+
readonly topPx: number;
|
|
463
|
+
readonly widthPx: number;
|
|
464
|
+
readonly heightPx: number;
|
|
465
|
+
readonly coordinateSpace: "frame-px";
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export interface ScopeAdjacentGeometryFramePixelPoint {
|
|
469
|
+
readonly xPx: number;
|
|
470
|
+
readonly yPx: number;
|
|
471
|
+
readonly coordinateSpace: "frame-px";
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export interface ScopeAdjacentGeometryRowEvidence {
|
|
475
|
+
readonly axis: ScopeAdjacentGeometryAxis;
|
|
476
|
+
readonly source: "l05-adjacent-geometry-intake";
|
|
477
|
+
readonly docId?: string;
|
|
478
|
+
readonly canonicalBlockId?: string;
|
|
479
|
+
readonly runtimeFragmentId?: string;
|
|
480
|
+
readonly pageId?: string;
|
|
481
|
+
readonly pageIndex?: number;
|
|
482
|
+
readonly frameId?: string;
|
|
483
|
+
readonly precision: "word-page-local-calibration";
|
|
484
|
+
readonly coordinateSpace: "frame-px";
|
|
485
|
+
readonly compositorReady: true;
|
|
486
|
+
readonly scaleSource?: "runtime-render-frame-page-rect";
|
|
487
|
+
readonly renderFrameRevision?: number;
|
|
488
|
+
readonly numbering?: {
|
|
489
|
+
readonly runtimeNumberingId?: string;
|
|
490
|
+
readonly canonicalNumberingInstanceId?: string;
|
|
491
|
+
readonly canonicalLevel?: number;
|
|
492
|
+
readonly markerKind?: string;
|
|
493
|
+
readonly markerSuffix?: string;
|
|
494
|
+
readonly markerLane?: ScopeAdjacentGeometryFramePixelRect;
|
|
495
|
+
readonly textColumn?: ScopeAdjacentGeometryFramePixelRect;
|
|
496
|
+
};
|
|
497
|
+
readonly fieldRegion?: {
|
|
498
|
+
readonly canonicalFieldId?: string;
|
|
499
|
+
readonly runtimeFieldRegionId?: string;
|
|
500
|
+
readonly instructionFamily?: string;
|
|
501
|
+
readonly fieldStartAnchorPx?: ScopeAdjacentGeometryFramePixelPoint;
|
|
502
|
+
readonly fieldEndAnchorPx?: ScopeAdjacentGeometryFramePixelPoint;
|
|
503
|
+
readonly fieldResultRangePx?: ScopeAdjacentGeometryFramePixelRect;
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
export interface ScopeAdjacentGeometryEvidence {
|
|
508
|
+
readonly status: "available" | "unavailable";
|
|
509
|
+
readonly source: "l05-adjacent-geometry-intake";
|
|
510
|
+
readonly schemaVersion?: "layer-05-adjacent-geometry-intake/v2";
|
|
511
|
+
readonly rowCount: number;
|
|
512
|
+
readonly rows?: readonly ScopeAdjacentGeometryRowEvidence[];
|
|
513
|
+
readonly reason?:
|
|
514
|
+
| "adjacent-geometry-provider-unavailable"
|
|
515
|
+
| "scope-adjacent-frame-pixel-row-unavailable"
|
|
516
|
+
| "l05-adjacent-intake-not-compositor-ready";
|
|
517
|
+
}
|
|
518
|
+
|
|
452
519
|
export type ScopeVisualizationClass = "field" | "broad";
|
|
453
520
|
|
|
454
521
|
export interface ScopeVisualizationHint {
|