v1.1.0: pooled runtime, 959 tests, production hardening (0 squash)
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
// Domain index query APIs for deterministic first-order logic enumeration (V1.1)
|
||||
// All returned arrays are owned by the index — no copies on read.
|
||||
|
||||
import { GeometryWorld } from './world.js'
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Selector queries
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return all element subject IDs that match the given CSS selector string.
|
||||
* Supported selector forms:
|
||||
* - tag name: "div", "button", "span"
|
||||
* - class: ".button", ".card"
|
||||
* Returns a sorted array owned by the world selectorIndex.
|
||||
* If the selector is not indexed, returns an empty array.
|
||||
*/
|
||||
export function getElementsBySelector(world: GeometryWorld, selector: string): number[] {
|
||||
const normalized = selector.trim().toLowerCase()
|
||||
return world.selectorIndex.get(normalized) ?? []
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Ancestor / descendant queries
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return all descendant element subject IDs of `parentId`.
|
||||
* If `selector` is provided, filter to those matching the selector.
|
||||
* Returns a sorted array owned by the world ancestorIndex (or a filtered copy).
|
||||
*/
|
||||
export function getDescendants(world: GeometryWorld, parentId: number, selector?: string): number[] {
|
||||
const all = world.ancestorIndex.get(parentId) ?? []
|
||||
if (!selector) {
|
||||
return all
|
||||
}
|
||||
const matched = getElementsBySelector(world, selector)
|
||||
if (matched.length === 0) {
|
||||
return []
|
||||
}
|
||||
// Intersect two sorted arrays without allocating intermediates.
|
||||
const out: number[] = []
|
||||
let i = 0
|
||||
let j = 0
|
||||
while (i < all.length && j < matched.length) {
|
||||
const a = all[i]
|
||||
const b = matched[j]
|
||||
if (a === b) {
|
||||
out.push(a)
|
||||
i++
|
||||
j++
|
||||
} else if (a < b) {
|
||||
i++
|
||||
} else {
|
||||
j++
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Text geometry queries
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return line box fragment IDs for the given text node subject ID.
|
||||
* Returns a sorted array owned by the world lineBoxIndex.
|
||||
*/
|
||||
export function getLineBoxes(world: GeometryWorld, textNodeId: number): number[] {
|
||||
return world.lineBoxIndex.get(textNodeId) ?? []
|
||||
}
|
||||
|
||||
/**
|
||||
* Return text run IDs for the given text node subject ID.
|
||||
* Returns a sorted array owned by the world textRunIndex.
|
||||
*/
|
||||
export function getTextRuns(world: GeometryWorld, textNodeId: number): number[] {
|
||||
return world.textRunIndex.get(textNodeId) ?? []
|
||||
}
|
||||
Reference in New Issue
Block a user