mirror of
https://github.com/RevenueCat/purchases-ios
synced 2026-11-09 22:35:56 +05:45
* Add Scope plumbing and custom operator extension point Thread evaluation scope through the rules engine and delegate unknown operators to an empty CustomOperators dispatcher, without changing behavior. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix project.pbxproj: restore RewardedAdTrackingMetadata entries The RulesEngine registration edit accidentally dropped four RewardedAdTrackingMetadata.swift entries from the Xcode project. Restore them and normalize CustomOperators identifiers to 24 hex chars. Co-authored-by: Cursor <cursoragent@cursor.com> * Promote firstArgEvaluated to shared Operators helpers Move the unary-arg helper from LogicOperators to Operators so custom operators can use the same json-logic-js spread convention. Co-authored-by: Cursor <cursoragent@cursor.com> * Address review comments on custom operator extension point Drop the cross-engine registration note from CustomOperators, and restore the single-line var extra-args warning that was reflowed without changing its text. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
53 lines
2.0 KiB
Swift
53 lines
2.0 KiB
Swift
//
|
|
// MinMaxOperators.swift
|
|
//
|
|
// Created by Antonio Pallares.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
extension RulesEngine {
|
|
|
|
/// Numeric extrema: `min`, `max`.
|
|
///
|
|
/// Variadic over a flat list of values (`{"max": [v1, v2, ...]}` /
|
|
/// `{"min": [v1, v2, ...]}`), matching JS `Math.max` / `Math.min`. Each
|
|
/// operand goes through `Value.asNumber` (JS `Number()`), so
|
|
/// single-element arrays bridge to a number via `toString`
|
|
/// (`Math.max(1, [2]) === 2`); multi-element arrays, objects, and
|
|
/// unparseable strings become `Double.nan` and poison the result.
|
|
///
|
|
/// Empty input mirrors `Math.max()` / `Math.min()`: `max` → `-∞`,
|
|
/// `min` → `+∞`.
|
|
enum MinMaxOperators {
|
|
|
|
/// `{"max": [v1, v2, ...]}` — variadic numeric maximum.
|
|
static func opMax(args: Value, vars: Scope) throws -> Value {
|
|
try reduceExtremum(args, vars: vars, empty: -.infinity) { Swift.max($0, $1) }
|
|
}
|
|
|
|
/// `{"min": [v1, v2, ...]}` — variadic numeric minimum.
|
|
static func opMin(args: Value, vars: Scope) throws -> Value {
|
|
try reduceExtremum(args, vars: vars, empty: .infinity) { Swift.min($0, $1) }
|
|
}
|
|
|
|
/// Evaluate each operand to a `Double` (non-numeric → `nan`) and fold
|
|
/// it into a single extremum in one pass. `empty` is the no-operand
|
|
/// result (`Math.max()` → `-∞`, `Math.min()` → `+∞`); any `nan`
|
|
/// operand poisons the accumulator, mirroring `Math.max` / `Math.min`.
|
|
private static func reduceExtremum(
|
|
_ args: Value,
|
|
vars: Scope,
|
|
empty: Double,
|
|
combine: (Double, Double) -> Double
|
|
) throws -> Value {
|
|
let result = try Operators.evalArgs(args, vars: vars).reduce(empty) { accumulator, value in
|
|
let number = value.asNumber ?? .nan
|
|
guard !accumulator.isNaN, !number.isNaN else { return .nan }
|
|
return combine(accumulator, number)
|
|
}
|
|
return .float(result)
|
|
}
|
|
}
|
|
}
|