| 108 | } |
| 109 | |
| 110 | export function expr(source: string): ConstraintExpr { |
| 111 | const cached = EXPR_CACHE.get(source); |
| 112 | if (cached !== undefined) { |
| 113 | // Refresh simple LRU access order. |
| 114 | EXPR_CACHE.delete(source); |
| 115 | EXPR_CACHE.set(source, cached); |
| 116 | return cached; |
| 117 | } |
| 118 | |
| 119 | const parsed = parse(source); |
| 120 | const ast = freezeAst(parsed); |
| 121 | const refs = freezeReadonlySet(extractRefs(ast)); |
| 122 | const hasIntrinsic = detectIntrinsicRefs(ast); |
| 123 | const hasSiblingAggregation = detectSiblingAggregation(ast); |
| 124 | // Keep call-site analysis hot-path free by validating usage here once. |
| 125 | void collectWidgetRefUsages(ast); |
| 126 | const out = Object.freeze({ |
| 127 | __brand: "ConstraintExpr" as const, |
| 128 | source, |
| 129 | ast, |
| 130 | refs, |
| 131 | hasIntrinsic, |
| 132 | hasSiblingAggregation, |
| 133 | }); |
| 134 | EXPR_CACHE.set(source, out); |
| 135 | while (EXPR_CACHE.size > EXPR_CACHE_MAX) { |
| 136 | const oldest = EXPR_CACHE.keys().next().value; |
| 137 | if (typeof oldest !== "string") break; |
| 138 | EXPR_CACHE.delete(oldest); |
| 139 | } |
| 140 | return out; |
| 141 | } |
| 142 | |
| 143 | export function isConstraintExpr(value: unknown): value is ConstraintExpr { |
| 144 | if (typeof value !== "object" || value === null) return false; |