refactor: replace smuggled compound properties with typed FluentRelation API

fluent.ts: Add public getters isCompound, compoundOperator, compoundParts
  to FluentRelation. Add optional CompoundState to constructor. Add
  CompoundPart/CompoundState interfaces. Replace 4 (this as any)._xxx
  property smuggles in FluentCompoundBuilder._addPart() with properly
  typed constructor initialization via CompoundState.

fol-compiler.ts: Replace 3 (relation as any)._compoundParts /
  ._compoundOperator / ._isCompound duck-type reads with direct
  relation.compoundParts / relation.compoundOperator / relation.isCompound.

extraction.ts: Replace (rel as any)._compoundParts read in
  getSelectorsFromAssertion with typed compoundRel.isCompound /
  compoundRel.compoundParts access.

Eliminates 7 (as any) casts across 3 production files. Zero remaining
_compoundParts/_compoundOperator/_isCompound/_originalFirstRelation
smuggled references in any production source file.

598 SDK + 3 conformance + 57 E2E = 658 tests pass.
This commit is contained in:
John Dvorak
2026-05-22 13:31:34 -07:00
parent 9df295b915
commit 1bc0c8e6df
3 changed files with 68 additions and 36 deletions
@@ -1318,8 +1318,9 @@ export function getSelectorsFromAssertion(assertion: FluentRelation | FluentAsse
selectors.add(rel.referenceSelector)
}
// Extract selectors from compound relation parts (.and / .or chaining)
if (Array.isArray(rel._compoundParts)) {
for (const part of rel._compoundParts) {
const compoundRel = assertion as FluentRelation
if (compoundRel.isCompound) {
for (const part of compoundRel.compoundParts) {
if (part.referenceSelector) {
selectors.add(part.referenceSelector)
}
@@ -228,8 +228,8 @@ function compileRelation(
}
// Handle compound relations (.and / .or chaining)
const compoundParts = (relation as any)._compoundParts as Array<{ relation: string; referenceSelector: string; options: Record<string, unknown> }> | undefined
const compoundOperator = (relation as any)._compoundOperator as 'and' | 'or' | undefined
const compoundParts = relation.compoundParts
const compoundOperator = relation.compoundOperator
if (compoundParts && compoundParts.length > 1 && compoundOperator) {
const assertionSpace = getAssertionSpace()
@@ -415,7 +415,7 @@ function compileSingleAssertion(
const refSel = rel.referenceSelector
const quantifier = rel.assertion.getQuantifier()
const isCompound = !!(rel as any)._compoundParts && (rel as any)._compoundParts.length > 1
const isCompound = rel.isCompound
const subjectVar = makeVar('$subject')
const refVar = makeVar('$reference')