177 lines
4.3 KiB
TypeScript
177 lines
4.3 KiB
TypeScript
/**
|
|
* World builder for Playwright-extracted elements.
|
|
*
|
|
* Converts raw extracted element data (from page.evaluate bounding boxes)
|
|
* into a solver-compatible GeometryWorld. All rect math lives here —
|
|
* public.ts delegates to this module so that coordinate arithmetic is
|
|
* isolated from the FOL compilation path.
|
|
*/
|
|
|
|
import type { GeometryWorld } from 'imhotep-solver'
|
|
|
|
export interface ExtractedElement {
|
|
tagName: string
|
|
rect: { x: number; y: number; width: number; height: number }
|
|
}
|
|
|
|
/**
|
|
* Build a GeometryWorld from a flat list of extracted elements.
|
|
*
|
|
* Each element receives a sequential subject ID starting at 1.
|
|
* Boxes, rects, and subject tables are populated from the visual rects.
|
|
*/
|
|
export function buildGeometryWorld(elements: ExtractedElement[]): GeometryWorld {
|
|
const ids: number[] = []
|
|
const borderLeft: number[] = []
|
|
const borderTop: number[] = []
|
|
const borderRight: number[] = []
|
|
const borderBottom: number[] = []
|
|
const paddingLeft: number[] = []
|
|
const paddingTop: number[] = []
|
|
const paddingRight: number[] = []
|
|
const paddingBottom: number[] = []
|
|
const contentLeft: number[] = []
|
|
const contentTop: number[] = []
|
|
const contentRight: number[] = []
|
|
const contentBottom: number[] = []
|
|
|
|
for (let i = 0; i < elements.length; i++) {
|
|
const id = i + 1
|
|
const el = elements[i]
|
|
const r = el.rect
|
|
|
|
ids.push(id)
|
|
borderLeft.push(r.x)
|
|
borderTop.push(r.y)
|
|
borderRight.push(r.x + r.width)
|
|
borderBottom.push(r.y + r.height)
|
|
paddingLeft.push(0)
|
|
paddingTop.push(0)
|
|
paddingRight.push(0)
|
|
paddingBottom.push(0)
|
|
contentLeft.push(r.x)
|
|
contentTop.push(r.y)
|
|
contentRight.push(r.x + r.width)
|
|
contentBottom.push(r.y + r.height)
|
|
}
|
|
|
|
return {
|
|
sceneId: 'scene',
|
|
snapshotId: 'snapshot',
|
|
env: {
|
|
viewportWidth: 800,
|
|
viewportHeight: 600,
|
|
deviceScaleFactor: 1,
|
|
colorScheme: 'light',
|
|
pointer: 'fine',
|
|
hover: false,
|
|
reducedMotion: false,
|
|
locale: 'en',
|
|
writingMode: 'horizontal-tb',
|
|
},
|
|
strings: { values: [] },
|
|
subjects: {
|
|
ids,
|
|
domNodeId: [...ids],
|
|
subjectKind: ids.map(() => 0),
|
|
primaryBoxId: [...ids],
|
|
firstFragmentId: ids.map(() => 0),
|
|
fragmentCount: ids.map(() => 0),
|
|
},
|
|
dom: {
|
|
nodeId: [],
|
|
parentNodeId: [],
|
|
childCount: [],
|
|
tagNameStringId: [],
|
|
},
|
|
boxes: {
|
|
boxId: [...ids],
|
|
subjectId: [...ids],
|
|
frameId: ids.map(() => 0),
|
|
borderLeft,
|
|
borderTop,
|
|
borderRight,
|
|
borderBottom,
|
|
paddingLeft,
|
|
paddingTop,
|
|
paddingRight,
|
|
paddingBottom,
|
|
contentLeft,
|
|
contentTop,
|
|
contentRight,
|
|
contentBottom,
|
|
},
|
|
visualBoxes: {
|
|
boxId: [...ids],
|
|
subjectId: [...ids],
|
|
frameId: ids.map(() => 0),
|
|
borderLeft: [...borderLeft],
|
|
borderTop: [...borderTop],
|
|
borderRight: [...borderRight],
|
|
borderBottom: [...borderBottom],
|
|
paddingLeft: [...paddingLeft],
|
|
paddingTop: [...paddingTop],
|
|
paddingRight: [...paddingRight],
|
|
paddingBottom: [...paddingBottom],
|
|
contentLeft: [...contentLeft],
|
|
contentTop: [...contentTop],
|
|
contentRight: [...contentRight],
|
|
contentBottom: [...contentBottom],
|
|
},
|
|
transforms: {
|
|
transformId: [],
|
|
subjectId: [],
|
|
matrixStart: [],
|
|
matrixLength: [],
|
|
originX: [],
|
|
originY: [],
|
|
},
|
|
matrices: {
|
|
values: [],
|
|
},
|
|
rects: {
|
|
rectId: [...ids],
|
|
left: [...borderLeft],
|
|
top: [...borderTop],
|
|
right: [...borderRight],
|
|
bottom: [...borderBottom],
|
|
},
|
|
topology: {
|
|
containingBlockOf: [],
|
|
nearestPositionedAncestorOf: [],
|
|
scrollContainerOf: [],
|
|
stackingContextOf: [],
|
|
formattingContextOf: [],
|
|
clippingRootOf: [],
|
|
paintOrderBucket: [],
|
|
paintOrderIndex: [],
|
|
},
|
|
scroll: {
|
|
containerId: [],
|
|
scrollLeft: [],
|
|
scrollTop: [],
|
|
scrollWidth: [],
|
|
scrollHeight: [],
|
|
clientWidth: [],
|
|
clientHeight: [],
|
|
},
|
|
clipping: {
|
|
clipNodeId: [],
|
|
subjectId: [],
|
|
clipKind: [],
|
|
clipLeft: [],
|
|
clipTop: [],
|
|
clipRight: [],
|
|
clipBottom: [],
|
|
parentClipNodeId: [],
|
|
},
|
|
visibility: {
|
|
subjectId: [],
|
|
isRendered: [],
|
|
isVisible: [],
|
|
visibleArea: [],
|
|
clippedArea: [],
|
|
},
|
|
}
|
|
}
|