fix: children($var) domain compilation and resolver support

- Add children branch in convertDomain() alongside descendants —
  children() now correctly maps to parentVar: '$parent'
  instead of falling through to the default branch which reversed
  the parentVar/selector mapping.
- SelectorDomainResolver now handles parentVar domains with no
  CSS selector filter (children domain collects all registered
  subject IDs, then filters by parent via ancestor index).
- All 1072 tests pass across 14 packages.
This commit is contained in:
John Dvorak
2026-05-21 20:13:57 -07:00
parent 35c5dbd153
commit b4ae8e9134
2 changed files with 19 additions and 7 deletions
+1 -1
View File
@@ -938,7 +938,7 @@ function convertDomain(domain: DslDomainRef): DomainRef {
// Descendant domains use the first argument as parent and second as filter: // Descendant domains use the first argument as parent and second as filter:
// descendants($card, '.title') => parentVar: '$card', selector: '.title' // descendants($card, '.title') => parentVar: '$card', selector: '.title'
if (domain.kind === 'descendants') { if (domain.kind === 'descendants' || domain.kind === 'children') {
const parentVar = selectorFromVar ?? domain.selector const parentVar = selectorFromVar ?? domain.selector
const selector = extraArgFromVar ?? (domain as any).extraArg const selector = extraArgFromVar ?? (domain as any).extraArg
return { return {
+18 -6
View File
@@ -1021,26 +1021,38 @@ export class SelectorDomainResolver implements DomainResolver {
}) })
} }
private allRegisteredSubjectIds(): number[] {
const seen = new Set<number>()
for (const d of this.domains.values()) {
for (const id of d.subjectIds) {
seen.add(id)
}
}
return Array.from(seen)
}
resolve(domain: DomainRef, env?: BindingEnv): DomainValue | undefined { resolve(domain: DomainRef, env?: BindingEnv): DomainValue | undefined {
if (domain.parentVar) { if (domain.parentVar) {
if (!env || !this.ancestorIndex) return undefined if (!env || !this.ancestorIndex) return undefined
const parentId = env.lookup(domain.parentVar) const parentId = env.lookup(domain.parentVar)
if (parentId === undefined) return undefined if (parentId === undefined) return undefined
const selector = domain.selector ?? domain.domain const selector = domain.selector
const globalDomain = this.domains.get(selector) const candidateIds = selector
if (!globalDomain) return undefined ? this.domains.get(selector)?.subjectIds
: this.allRegisteredSubjectIds()
if (!candidateIds || candidateIds.length === 0) return undefined
const filtered: number[] = [] const filtered: number[] = []
for (const id of globalDomain.subjectIds) { for (const id of candidateIds) {
const ancestors = this.ancestorIndex.get(id) const ancestors = this.ancestorIndex.get(id)
if (ancestors?.has(parentId)) { if (ancestors?.has(parentId)) {
filtered.push(id) filtered.push(id)
} }
} }
const key = `descendants_p${parentId}_${selector}` const key = `descendants_p${parentId}_${selector ?? '*'}`
return { return {
domainId: `dom_${key}`, domainId: `dom_${key}`,
subjectIds: new Uint32Array(filtered), subjectIds: new Uint32Array(filtered),
provenance: `descendants(parentId=${parentId}, ${selector})`, provenance: `descendants(parentId=${parentId}, ${selector ?? '*'})`,
closed: true, closed: true,
} }
} }