mirror of
https://github.com/RevenueCat/purchases-ios
synced 2026-11-09 22:35:56 +05:45
* Add rc.sortBy custom operator Orders an array by a key computed per item, ascending, with ties keeping their input order. Keys must be all strings or all numbers so the two engines never have to invent a cross-type ordering. Co-authored-by: Cursor <cursoragent@cursor.com> * Reject non-finite rc.sortBy keys A NaN key compares false in both directions, so every pair tied and the input came back unsorted with no error. Negating a string key to attempt a descending sort produced exactly that. Co-authored-by: Cursor <cursoragent@cursor.com> * Note ascending order in the rc.sortBy summary Co-authored-by: Cursor <cursoragent@cursor.com> * Trim the rc.sortBy doc comment Co-authored-by: Cursor <cursoragent@cursor.com> * Trim the rc.sortBy stability comment Co-authored-by: Cursor <cursoragent@cursor.com> * Order rc.sortBy string keys by UTF-16 code unit Swift's < orders by Unicode scalar and treats canonically equivalent strings as equal, while JS and Kotlin order by UTF-16 code unit. The two disagree once a scalar above the surrogate range meets an astral one, so the same rule would sort differently on iOS and Android. Co-authored-by: Cursor <cursoragent@cursor.com> * Keep the rc.sortBy ordering fixtures platform-neutral The fixture files are byte-identical across the iOS and Android engines, so a description that explains the contract in terms of one host language's string comparison does not read correctly in the other repository. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
54 lines
1.6 KiB
Swift
54 lines
1.6 KiB
Swift
//
|
|
// CustomOperators.swift
|
|
//
|
|
// Created by Antonio Pallares.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
extension RulesEngine {
|
|
|
|
/// RevenueCat-specific JSON Logic operators.
|
|
///
|
|
/// Operators here are namespaced under `rc.` so they cannot collide with a
|
|
/// future standard JSON Logic operator.
|
|
enum CustomOperators {
|
|
|
|
static func dispatch(
|
|
op operatorName: String,
|
|
args: Value,
|
|
vars: Scope
|
|
) throws -> Value {
|
|
switch operatorName {
|
|
case "rc.entries":
|
|
return try EntriesOperators.opEntries(args: args, vars: vars)
|
|
case "rc.fromEntries":
|
|
return try EntriesOperators.opFromEntries(args: args, vars: vars)
|
|
|
|
case "rc.length":
|
|
return try LengthOperator.opLength(args: args, vars: vars)
|
|
|
|
case "rc.lower":
|
|
return try CaseOperators.opLower(args: args, vars: vars)
|
|
case "rc.upper":
|
|
return try CaseOperators.opUpper(args: args, vars: vars)
|
|
|
|
case "rc.rootVar":
|
|
return try RootVarOperator.opRootVar(args: args, vars: vars)
|
|
|
|
case "rc.semverCompare":
|
|
return try SemverOperator.opSemverCompare(args: args, vars: vars)
|
|
|
|
case "rc.sortBy":
|
|
return try SortByOperator.opSortBy(args: args, vars: vars)
|
|
|
|
case "rc.split":
|
|
return try SplitOperator.opSplit(args: args, vars: vars)
|
|
|
|
default:
|
|
throw EvaluationError.unsupportedOperator(name: operatorName)
|
|
}
|
|
}
|
|
}
|
|
}
|