mirror of
https://github.com/RevenueCat/purchases-ios
synced 2026-11-11 22:55:55 +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> * Add rc.length operator for string and array lengths UTF-16 code-unit count for strings (JS String.length parity), element count for arrays, typeMismatch for other inputs. Thirteen new fixtures. 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> * Trim rc.length doc comment Drop the rationale contrasting rc.length's throwing behavior with rc.entries' lenient empty result. Co-authored-by: Cursor <cursoragent@cursor.com> * Pin that rc.length ignores extra arguments The doc comment claimed extra args are silently ignored but no fixture covered it. Under single-operand semantics ["abc", "ignored"] would measure the arg list itself and yield 2, so the fixture fails if the spread convention regresses. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
50 lines
1.8 KiB
Swift
50 lines
1.8 KiB
Swift
//
|
|
// LengthOperator.swift
|
|
//
|
|
// Created by Antonio Pallares.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
extension RulesEngine {
|
|
|
|
/// `rc.length` — element count for arrays, UTF-16 code-unit count for
|
|
/// strings (JS `String.length` parity).
|
|
enum LengthOperator {
|
|
|
|
/// `{"rc.length": value}` — returns a numeric length suitable for
|
|
/// arithmetic and comparisons.
|
|
///
|
|
/// - **String**: length in **UTF-16 code units**, not Swift grapheme
|
|
/// clusters — matches JS `String.length` and the same choice in
|
|
/// `AccessorOperators.opMissingSome` (`string.utf16.count`).
|
|
/// - **Array**: element count (`.count`).
|
|
/// - **Anything else**: throws `EvaluationError.typeMismatch`.
|
|
///
|
|
/// Non-string/non-array inputs throw rather than defaulting to `0`.
|
|
/// A silent zero would make `{"==": [{"rc.length": {"var": "missing"}},
|
|
/// 0]}` quietly true when a key is absent.
|
|
///
|
|
/// Uses `Operators.firstArgEvaluated` spread semantics; extra arguments
|
|
/// are silently ignored. Literal array operands must be wrapped
|
|
/// (e.g. `{"rc.length": [[1, 2, 3]]}`), not passed as a multi-element
|
|
/// arg list.
|
|
static func opLength(args: Value, vars: Scope) throws -> Value {
|
|
let input = try Operators.firstArgEvaluated(args, vars: vars)
|
|
|
|
switch input {
|
|
case .string(let string):
|
|
return .int(Int64(string.utf16.count))
|
|
|
|
case .array(let items):
|
|
return .int(Int64(items.count))
|
|
|
|
default:
|
|
throw EvaluationError.typeMismatch(
|
|
message: "operator 'rc.length' expected string or array, got \(input)"
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|