fix: topology array reordering by subject order + unary inStackingContext
Topology array order mismatch (critical bug): - CDP browser script iterates elements in document order (querySelectorAll), but solver accesses topology arrays by selector-resolution order. - Fix: add subjectIds array to TopologyRecord tracking the backendNodeId at each document-order position; remapTopologyIds now reorders all 6 topology arrays before remapping backendNodeIds to solver IDs. - Fallback: when subjectIds is missing (cached pre-fix data), falls back to simple remap without reordering. Unary inStackingContext compilation: - compileCanonicalClauseToFormula treated inStackingContext as always binary, creating referenceBinding with undefined selector for unary assertions. - Fix: add (inStackingContext && !clause.reference) to unaryPredicate/isUnary. Hard test fixture (fixtures package): - 29-element geometric fixture with 10 scenarios - 57 assertions (54 spatial + 3 topology) all pass end-to-end
This commit is contained in:
@@ -546,6 +546,7 @@ export class CDPExtractor {
|
|||||||
scroll: [],
|
scroll: [],
|
||||||
clipping: [],
|
clipping: [],
|
||||||
topology: {
|
topology: {
|
||||||
|
subjectIds: [],
|
||||||
containingBlockOf: [],
|
containingBlockOf: [],
|
||||||
nearestPositionedAncestorOf: [],
|
nearestPositionedAncestorOf: [],
|
||||||
scrollContainerOf: [],
|
scrollContainerOf: [],
|
||||||
@@ -557,6 +558,9 @@ export class CDPExtractor {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ... etc until the next empty topology at line ~964
|
||||||
|
|
||||||
|
|
||||||
if (request.requiredFacts.topology !== false && backendNodeIds.length > 0) {
|
if (request.requiredFacts.topology !== false && backendNodeIds.length > 0) {
|
||||||
try {
|
try {
|
||||||
const { result, errors } = await extractTopology(session, backendNodeIds, subjectIds)
|
const { result, errors } = await extractTopology(session, backendNodeIds, subjectIds)
|
||||||
@@ -956,6 +960,7 @@ function createEmptySnapshot(request: ExtractorRequest): GeometryWorldSnapshot {
|
|||||||
fontWeight: [],
|
fontWeight: [],
|
||||||
},
|
},
|
||||||
topology: {
|
topology: {
|
||||||
|
subjectIds: [],
|
||||||
containingBlockOf: [],
|
containingBlockOf: [],
|
||||||
nearestPositionedAncestorOf: [],
|
nearestPositionedAncestorOf: [],
|
||||||
scrollContainerOf: [],
|
scrollContainerOf: [],
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export interface ClippingRecord {
|
|||||||
* Topology relation record.
|
* Topology relation record.
|
||||||
*/
|
*/
|
||||||
export interface TopologyRecord {
|
export interface TopologyRecord {
|
||||||
|
subjectIds: number[]
|
||||||
containingBlockOf: number[]
|
containingBlockOf: number[]
|
||||||
nearestPositionedAncestorOf: number[]
|
nearestPositionedAncestorOf: number[]
|
||||||
scrollContainerOf: number[]
|
scrollContainerOf: number[]
|
||||||
@@ -83,6 +84,7 @@ export async function extractTopology(
|
|||||||
scroll: [],
|
scroll: [],
|
||||||
clipping: [],
|
clipping: [],
|
||||||
topology: {
|
topology: {
|
||||||
|
subjectIds: [],
|
||||||
containingBlockOf: [],
|
containingBlockOf: [],
|
||||||
nearestPositionedAncestorOf: [],
|
nearestPositionedAncestorOf: [],
|
||||||
scrollContainerOf: [],
|
scrollContainerOf: [],
|
||||||
@@ -138,6 +140,7 @@ export async function extractTopology(
|
|||||||
scroll: [],
|
scroll: [],
|
||||||
clipping: [],
|
clipping: [],
|
||||||
topology: {
|
topology: {
|
||||||
|
subjectIds: [],
|
||||||
containingBlockOf: [],
|
containingBlockOf: [],
|
||||||
nearestPositionedAncestorOf: [],
|
nearestPositionedAncestorOf: [],
|
||||||
scrollContainerOf: [],
|
scrollContainerOf: [],
|
||||||
@@ -269,6 +272,7 @@ export async function extractTopology(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
results.topology.subjectIds.push(subjectId)
|
||||||
results.topology.containingBlockOf.push(getId(getContainingBlock(el)))
|
results.topology.containingBlockOf.push(getId(getContainingBlock(el)))
|
||||||
results.topology.nearestPositionedAncestorOf.push(getId(getNearestPositionedAncestor(el)))
|
results.topology.nearestPositionedAncestorOf.push(getId(getNearestPositionedAncestor(el)))
|
||||||
results.topology.scrollContainerOf.push(getId(getScrollContainer(el)))
|
results.topology.scrollContainerOf.push(getId(getScrollContainer(el)))
|
||||||
@@ -301,6 +305,7 @@ export async function extractTopology(
|
|||||||
scroll: [],
|
scroll: [],
|
||||||
clipping: [],
|
clipping: [],
|
||||||
topology: {
|
topology: {
|
||||||
|
subjectIds: [],
|
||||||
containingBlockOf: [],
|
containingBlockOf: [],
|
||||||
nearestPositionedAncestorOf: [],
|
nearestPositionedAncestorOf: [],
|
||||||
scrollContainerOf: [],
|
scrollContainerOf: [],
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Imhotep Hard Geometric Fixture</title>
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
body { background: #1a1a2e; color: #e0e0e0; font-family: monospace; padding: 20px; }
|
||||||
|
.legend { margin-bottom: 16px; font-size: 13px; line-height: 1.6; }
|
||||||
|
.legend strong { color: #ffcc00; }
|
||||||
|
|
||||||
|
/* 1. TRANSFORMS */
|
||||||
|
.transform-container {
|
||||||
|
position: absolute; left: 30px; top: 80px; width: 220px; height: 160px;
|
||||||
|
background: rgba(100,100,255,0.15); border: 2px dashed #6666ff;
|
||||||
|
transform: rotate(15deg) scale(1.5); transform-origin: top left;
|
||||||
|
}
|
||||||
|
.rotated-box-a { position: absolute; left: 10px; top: 10px; width: 60px; height: 40px; background: #ff6b6b; border: 2px solid #ff4444; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #fff; }
|
||||||
|
.rotated-box-b { position: absolute; left: 120px; top: 80px; width: 60px; height: 40px; background: #51cf66; border: 2px solid #2f9e44; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #fff; }
|
||||||
|
|
||||||
|
/* 2. SCROLL CLIP */
|
||||||
|
.scroll-clip-container { position: absolute; left: 400px; top: 80px; width: 200px; height: 200px; overflow: hidden; background: rgba(255,200,100,0.1); border: 2px solid #ffa500; }
|
||||||
|
.clipped-child { width: 80px; height: 80px; background: #ff6b6b; border: 1px solid #fff; margin: 10px; }
|
||||||
|
.overflown-child { width: 50px; height: 250px; background: linear-gradient(to bottom, #ffa500, #ffd43b); border: 1px solid #fff; margin: 10px; }
|
||||||
|
|
||||||
|
/* 3. NESTED POSITIONING */
|
||||||
|
.relative-container { position: absolute; left: 30px; top: 320px; width: 250px; height: 180px; background: rgba(150,100,255,0.12); border: 2px dashed #9c36b5; contain: paint; }
|
||||||
|
.absolute-child { position: absolute; left: 20px; top: 15px; width: 180px; height: 120px; background: rgba(255,150,255,0.2); border: 2px solid #cc5de8; }
|
||||||
|
.fixed-nested-child { position: fixed; left: 70px; top: 355px; width: 60px; height: 50px; background: #20c997; border: 2px solid #099268; display: flex; align-items: center; justify-content: center; font-size: 9px; color: #fff; z-index: 10; }
|
||||||
|
|
||||||
|
/* 4. OVERLAPPING Z-INDEX */
|
||||||
|
.z-box { position: absolute; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #fff; font-weight: bold; }
|
||||||
|
.z1-box { left: 400px; top: 320px; width: 130px; height: 130px; background: rgba(255,107,107,0.7); border: 2px solid #ff4444; z-index: 1; }
|
||||||
|
.z2-box { left: 430px; top: 350px; width: 130px; height: 130px; background: rgba(81,207,102,0.7); border: 2px solid #2f9e44; z-index: 2; }
|
||||||
|
.z3-box { left: 460px; top: 380px; width: 130px; height: 130px; background: rgba(74,144,226,0.7); border: 2px solid #2266cc; z-index: 3; }
|
||||||
|
|
||||||
|
/* 5. ZERO-SIZE / HIDDEN */
|
||||||
|
.zero-size-box { position: absolute; left: 30px; top: 570px; width: 0; height: 0; background: #ff0000; border: 1px solid #ff0000; }
|
||||||
|
.display-none-box { position: absolute; left: 100px; top: 570px; width: 60px; height: 40px; background: #ffa500; border: 2px solid #ff8c00; display: none; }
|
||||||
|
.visibility-hidden-box { position: absolute; left: 180px; top: 570px; width: 60px; height: 40px; background: #ffd43b; border: 2px solid #fab005; visibility: hidden; }
|
||||||
|
.opacity-zero-box { position: absolute; left: 260px; top: 570px; width: 60px; height: 40px; background: #51cf66; border: 2px solid #2f9e44; opacity: 0; }
|
||||||
|
|
||||||
|
/* 6. FLEXBOX GAP */
|
||||||
|
.flex-container { position: absolute; left: 30px; top: 660px; display: flex; gap: 20px; width: 440px; height: 80px; background: rgba(100,200,255,0.1); border: 2px dashed #4a90e2; padding: 10px; }
|
||||||
|
.flex-item { width: 80px; height: 60px; display: flex; align-items: center; justify-content: center; font-size: 13px; color: #fff; font-weight: bold; border: 2px solid; }
|
||||||
|
.flex-item-1 { background: #ff6b6b; border-color: #ff4444; }
|
||||||
|
.flex-item-2 { background: #51cf66; border-color: #2f9e44; }
|
||||||
|
.flex-item-3 { background: #4a90e2; border-color: #2266cc; }
|
||||||
|
|
||||||
|
/* 7. BORDER / PADDING */
|
||||||
|
.border-box-el { position: absolute; left: 30px; top: 800px; width: 140px; height: 100px; background: #fab005; border: 12px solid #e67700; padding: 20px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #1a1a2e; font-weight: bold; }
|
||||||
|
|
||||||
|
/* 8. ALIGNMENT EDGES */
|
||||||
|
.alignment-reference { position: absolute; left: 250px; top: 800px; width: 100px; height: 100px; background: rgba(200,200,200,0.15); border: 2px dashed #aaa; display: flex; align-items: center; justify-content: center; font-size: 10px; }
|
||||||
|
.left-aligned { position: absolute; left: 250px; top: 930px; width: 40px; height: 30px; background: #ff6b6b; border: 2px solid #ff4444; display: flex; align-items: center; justify-content: center; font-size: 8px; color: #fff; }
|
||||||
|
.right-aligned { position: absolute; left: 310px; top: 930px; width: 40px; height: 30px; background: #51cf66; border: 2px solid #2f9e44; display: flex; align-items: center; justify-content: center; font-size: 8px; color: #fff; }
|
||||||
|
.top-aligned { position: absolute; left: 380px; top: 800px; width: 30px; height: 40px; background: #4a90e2; border: 2px solid #2266cc; display: flex; align-items: center; justify-content: center; font-size: 8px; color: #fff; }
|
||||||
|
.bottom-aligned { position: absolute; left: 380px; top: 860px; width: 30px; height: 40px; background: #fab005; border: 2px solid #e67700; display: flex; align-items: center; justify-content: center; font-size: 8px; color: #1a1a2e; }
|
||||||
|
|
||||||
|
/* 9. DIAGONAL SEPARATION */
|
||||||
|
.diagonal-top-left { position: absolute; left: 480px; top: 640px; width: 60px; height: 40px; background: #e599f7; border: 2px solid #ae3ec9; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #1a1a2e; }
|
||||||
|
.diagonal-bottom-right { position: absolute; left: 620px; top: 800px; width: 60px; height: 40px; background: #63e6be; border: 2px solid #099268; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #1a1a2e; }
|
||||||
|
|
||||||
|
/* 10. ADJACENT / TOUCHING / CENTERED */
|
||||||
|
.adjacent-a { position: absolute; left: 600px; top: 860px; width: 50px; height: 50px; background: #ff922b; border: 2px solid #e67700; display: flex; align-items: center; justify-content: center; font-size: 9px; color: #fff; }
|
||||||
|
.adjacent-b { position: absolute; left: 650px; top: 860px; width: 50px; height: 50px; background: #ff6b6b; border: 2px solid #ff4444; display: flex; align-items: center; justify-content: center; font-size: 9px; color: #fff; }
|
||||||
|
.center-container { position: absolute; left: 700px; top: 640px; width: 160px; height: 160px; background: rgba(255,255,255,0.05); border: 2px dashed #888; display: flex; align-items: center; justify-content: center; }
|
||||||
|
.center-child { width: 40px; height: 40px; background: #fab005; border: 2px solid #e67700; }
|
||||||
|
|
||||||
|
.scene-label { position: absolute; font-size: 11px; color: #888; pointer-events: none; white-space: nowrap; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="legend">
|
||||||
|
<strong>Imhotep Hard Geometric Fixture</strong><br>
|
||||||
|
Open DevTools Console to see bounding rects of all <code>data-testid</code> elements.<br>
|
||||||
|
All elements are absolutely positioned for deterministic layout.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 1. TRANSFORMS -->
|
||||||
|
<div class="scene-label" style="left:30px;top:60px;">1. TRANSFORM (rotate 15deg + scale 1.5)</div>
|
||||||
|
<div class="transform-container" data-testid="transform-container">
|
||||||
|
<div class="rotated-box-a" data-testid="rotated-box-a">A</div>
|
||||||
|
<div class="rotated-box-b" data-testid="rotated-box-b">B</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 2. SCROLL CLIP -->
|
||||||
|
<div class="scene-label" style="left:400px;top:60px;">2. overflown-childChild 50x250 in 200x200 container</div>
|
||||||
|
<div class="scroll-clip-container" data-testid="scroll-clip-container">
|
||||||
|
<div class="clipped-child" data-testid="clipped-child"></div>
|
||||||
|
<div class="overflown-child" data-testid="overflown-child"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 3. NESTED POSITIONING -->
|
||||||
|
<div class="scene-label" style="left:30px;top:300px;">3. NESTED (relative > absolute > fixed, contain:paint)</div>
|
||||||
|
<div class="relative-container" data-testid="relative-container">
|
||||||
|
<div class="absolute-child" data-testid="absolute-child">
|
||||||
|
<div class="fixed-nested-child" data-testid="fixed-nested-child">fixed</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 4. OVERLAPPING Z-INDEX -->
|
||||||
|
<div class="scene-label" style="left:400px;top:300px;">4. OVERLAPPING Z-INDEX (z:1,2,3)</div>
|
||||||
|
<div class="z-box z1-box" data-testid="z1-box">z=1</div>
|
||||||
|
<div class="z-box z2-box" data-testid="z2-box">z=2</div>
|
||||||
|
<div class="z-box z3-box" data-testid="z3-box">z=3</div>
|
||||||
|
|
||||||
|
<!-- 5. ZERO-SIZE / HIDDEN -->
|
||||||
|
<div class="scene-label" style="left:30px;top:550px;">5. ZERO-SIZE / HIDDEN</div>
|
||||||
|
<div class="zero-size-box" data-testid="zero-size-box"></div>
|
||||||
|
<div class="display-none-box" data-testid="display-none-box">none</div>
|
||||||
|
<div class="visibility-hidden-box" data-testid="visibility-hidden-box">hidden</div>
|
||||||
|
<div class="opacity-zero-box" data-testid="opacity-zero-box">opacity:0</div>
|
||||||
|
|
||||||
|
<!-- 6. FLEXBOX GAP -->
|
||||||
|
<div class="scene-label" style="left:30px;top:638px;">6. FLEXBOX GAP (gap:20px)</div>
|
||||||
|
<div class="flex-container" data-testid="flex-container">
|
||||||
|
<div class="flex-item flex-item-1" data-testid="flex-item-1">1</div>
|
||||||
|
<div class="flex-item flex-item-2" data-testid="flex-item-2">2</div>
|
||||||
|
<div class="flex-item flex-item-3" data-testid="flex-item-3">3</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 7. BORDER / PADDING -->
|
||||||
|
<div class="scene-label" style="left:30px;top:780px;">7. BORDER (12px) + PADDING (20px) border-box</div>
|
||||||
|
<div class="border-box-el" data-testid="border-box-el">border-box</div>
|
||||||
|
|
||||||
|
<!-- 8. ALIGNMENT EDGES -->
|
||||||
|
<div class="scene-label" style="left:250px;top:780px;">8. EDGE ALIGNMENT</div>
|
||||||
|
<div class="alignment-reference" data-testid="alignment-reference">ref</div>
|
||||||
|
<div class="left-aligned" data-testid="left-aligned">L</div>
|
||||||
|
<div class="right-aligned" data-testid="right-aligned">R</div>
|
||||||
|
<div class="top-aligned" data-testid="top-aligned">T</div>
|
||||||
|
<div class="bottom-aligned" data-testid="bottom-aligned">B</div>
|
||||||
|
|
||||||
|
<!-- 9. DIAGONAL SEPARATION -->
|
||||||
|
<div class="scene-label" style="left:480px;top:622px;">9. DIAGONAL SEPARATION</div>
|
||||||
|
<div class="diagonal-top-left" data-testid="diagonal-top-left">TL</div>
|
||||||
|
<div class="diagonal-bottom-right" data-testid="diagonal-bottom-right">BR</div>
|
||||||
|
|
||||||
|
<!-- 10. ADJACENT / TOUCHING / CENTERED -->
|
||||||
|
<div class="scene-label" style="left:600px;top:842px;">10. ADJACENT pair (edge touch)</div>
|
||||||
|
<div class="adjacent-a" data-testid="adjacent-a">A</div>
|
||||||
|
<div class="adjacent-b" data-testid="adjacent-b">B</div>
|
||||||
|
<div class="scene-label" style="left:700px;top:620px;">CENTERED child</div>
|
||||||
|
<div class="center-container" data-testid="center-container">
|
||||||
|
<div class="center-child" data-testid="center-child"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var elements = document.querySelectorAll('[data-testid]');
|
||||||
|
console.group('Imhotep Hard Fixture — Bounding Rects');
|
||||||
|
console.log('Element count with data-testid:', elements.length);
|
||||||
|
elements.forEach(function (el) {
|
||||||
|
var testid = el.getAttribute('data-testid');
|
||||||
|
var rect = el.getBoundingClientRect();
|
||||||
|
var cs = window.getComputedStyle(el);
|
||||||
|
console.log(
|
||||||
|
'%c' + testid + '%c ' +
|
||||||
|
JSON.stringify({ x: rect.left.toFixed(1), y: rect.top.toFixed(1), w: rect.width.toFixed(1), h: rect.height.toFixed(1), display: cs.display, visibility: cs.visibility, opacity: cs.opacity }),
|
||||||
|
'color: #ffcc00; font-weight: bold;', 'color: #aaa;'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
console.groupEnd();
|
||||||
|
})();
|
||||||
|
</script></body></html>
|
||||||
@@ -744,7 +744,28 @@ function remapTopologyIds(world: GeometryWorld): void {
|
|||||||
backendToSolver.set(world.subjects.domNodeId[i], world.subjects.ids[i])
|
backendToSolver.set(world.subjects.domNodeId[i], world.subjects.ids[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
const remap = (src: ArrayLike<number>): number[] => {
|
const rawSubjectIds = (world as any)._topologySubjectIds as number[] | undefined
|
||||||
|
|
||||||
|
function reorderAndRemap(rawValues: ArrayLike<number>, targetLength: number): number[] {
|
||||||
|
if (!rawSubjectIds || rawSubjectIds.length === 0) {
|
||||||
|
return remapSimple(rawValues)
|
||||||
|
}
|
||||||
|
|
||||||
|
const rawToValue = new Map<number, number>()
|
||||||
|
for (let j = 0; j < rawSubjectIds.length; j++) {
|
||||||
|
rawToValue.set(rawSubjectIds[j], rawValues[j] ?? 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const out = new Array<number>(targetLength)
|
||||||
|
for (let i = 0; i < targetLength; i++) {
|
||||||
|
const backendId = world.subjects.domNodeId[i]
|
||||||
|
const rawVal = rawToValue.get(backendId) ?? 0
|
||||||
|
out[i] = rawVal > 0 ? (backendToSolver.get(rawVal) ?? 0) : 0
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
function remapSimple(src: ArrayLike<number>): number[] {
|
||||||
const out = new Array<number>(src.length)
|
const out = new Array<number>(src.length)
|
||||||
for (let i = 0; i < src.length; i++) {
|
for (let i = 0; i < src.length; i++) {
|
||||||
const backendId = src[i]
|
const backendId = src[i]
|
||||||
@@ -754,19 +775,21 @@ function remapTopologyIds(world: GeometryWorld): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const t = world.topology
|
const t = world.topology
|
||||||
t.containingBlockOf = remap(t.containingBlockOf)
|
t.containingBlockOf = reorderAndRemap(t.containingBlockOf, nSubjects)
|
||||||
t.nearestPositionedAncestorOf = remap(t.nearestPositionedAncestorOf)
|
t.nearestPositionedAncestorOf = reorderAndRemap(t.nearestPositionedAncestorOf, nSubjects)
|
||||||
t.scrollContainerOf = remap(t.scrollContainerOf)
|
t.scrollContainerOf = reorderAndRemap(t.scrollContainerOf, nSubjects)
|
||||||
t.stackingContextOf = remap(t.stackingContextOf)
|
t.stackingContextOf = reorderAndRemap(t.stackingContextOf, nSubjects)
|
||||||
t.formattingContextOf = remap(t.formattingContextOf)
|
t.formattingContextOf = reorderAndRemap(t.formattingContextOf, nSubjects)
|
||||||
t.clippingRootOf = remap(t.clippingRootOf)
|
t.clippingRootOf = reorderAndRemap(t.clippingRootOf, nSubjects)
|
||||||
|
|
||||||
if (world.clipping) {
|
if (world.clipping) {
|
||||||
world.clipping.subjectId = remap(world.clipping.subjectId)
|
world.clipping.subjectId = remapSimple(world.clipping.subjectId)
|
||||||
}
|
}
|
||||||
if (world.scroll) {
|
if (world.scroll) {
|
||||||
world.scroll.containerId = remap(world.scroll.containerId)
|
world.scroll.containerId = remapSimple(world.scroll.containerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete (world as any)._topologySubjectIds
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function extractWorldCdp(
|
export async function extractWorldCdp(
|
||||||
@@ -865,6 +888,8 @@ export async function extractWorldCdp(
|
|||||||
fontWeight: Array.from(canonical.styles.fontWeight),
|
fontWeight: Array.from(canonical.styles.fontWeight),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
;(world as any)._topologySubjectIds = (canonical as any).topology?.subjectIds
|
||||||
|
|
||||||
remapTopologyIds(world)
|
remapTopologyIds(world)
|
||||||
|
|
||||||
const selectorToIds = new Map<string, number[]>()
|
const selectorToIds = new Map<string, number[]>()
|
||||||
@@ -1166,6 +1191,7 @@ export function compileCanonicalClauseToFormula(clause: CanonicalClauseDescripto
|
|||||||
const unaryPredicate = clause.relation === 'atLeast'
|
const unaryPredicate = clause.relation === 'atLeast'
|
||||||
|| clause.relation === 'atMost'
|
|| clause.relation === 'atMost'
|
||||||
|| clause.relation === 'aspectRatio'
|
|| clause.relation === 'aspectRatio'
|
||||||
|
|| (clause.relation === 'inStackingContext' && !clause.reference)
|
||||||
|
|
||||||
body = {
|
body = {
|
||||||
type: 'FormulaNode',
|
type: 'FormulaNode',
|
||||||
@@ -1213,6 +1239,7 @@ export function compileCanonicalClauseToFormula(clause: CanonicalClauseDescripto
|
|||||||
|| clause.relation === 'atMost'
|
|| clause.relation === 'atMost'
|
||||||
|| clause.relation === 'between'
|
|| clause.relation === 'between'
|
||||||
|| clause.relation === 'aspectRatio'
|
|| clause.relation === 'aspectRatio'
|
||||||
|
|| (clause.relation === 'inStackingContext' && !clause.reference)
|
||||||
|
|
||||||
if (isUnary) {
|
if (isUnary) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user