diff --git a/json/targeting.json b/json/targeting.json index 88867c3..40e4858 100644 --- a/json/targeting.json +++ b/json/targeting.json @@ -37,6 +37,10 @@ { "description": "When returned from rules, strings are used to as keys to retrieve the associated value from the \"variants\" object. Be sure that the returned string is present as a key in the variants!.", "type": "string" + }, + { + "description": "When returned from rules, strings are used to as keys to retrieve the associated value from the \"variants\" object. Be sure that the returned string is present as a key in the variants!.", + "type": "array" } ] }, @@ -129,19 +133,35 @@ } } }, - "ifRule": { + "binaryOrTernaryOp": { + "type": "array", + "minItems": 2, + "maxItems": 3, + "items": { + "$ref": "#/$defs/args" + } + }, + "binaryOrTernaryRule": { "type": "object", "additionalProperties": false, "properties": { "if": { "title": "If Operator", - "description": "The if statement takes 3 arguments: a condition (if), what to do if its true (then), and what to do if its false (else). Note that the form accepting more than 3 arguments (if/else) is not supported in flagd; use nesting instead.", - "type": "array", - "minItems": 2, - "maxItems": 3, - "items": { - "$ref": "#/$defs/args" - } + "description": "The if statement takes 3 arguments: a condition (if), what to do if its true (then), and what to do if its false (else, optional). Note that the form accepting more than 3 arguments (if/else) is not supported in flagd; use nesting instead.", + "$ref": "#/$defs/binaryOrTernaryOp" + }, + "substr": { + "title": "Substring Operation", + "description": "Get a portion of a string. Give a positive start position to return everything beginning at that index. Give a negative start position to work backwards from the end of the string, then return everything. Give a positive length to express how many characters to return.", + "$ref": "#/$defs/binaryOrTernaryOp" + }, + "<": { + "title": "Less-Than/Between Operation. Can be used to test that one value is between two others.", + "$ref": "#/$defs/binaryOrTernaryOp" + }, + "<=": { + "title": "Less-Than-Or-Equal-To/Between Operation. Can be used to test that one value is between two others.", + "$ref": "#/$defs/binaryOrTernaryOp" } } }, @@ -192,16 +212,15 @@ "description": "Finds the remainder after the first argument is divided by the second argument.", "$ref": "#/$defs/binaryOp" }, + "/": { + "title": "Division Operation", + "$ref": "#/$defs/binaryOp" + }, "map": { "title": "Map Operation", "description": "Perform an action on every member of an array. Note, that inside the logic being used to map, var operations are relative to the array element being worked on.", "$ref": "#/$defs/binaryOp" }, - "reduce": { - "title": "Reduce Operation", - "description": "Combine all the elements in an array into a single value, like adding up a list of numbers. Note, that inside the logic being used to reduce, var operations only have access to an object with a \"current\" and a \"accumulator\".", - "$ref": "#/$defs/binaryOp" - }, "filter": { "title": "Filter Operation", "description": "Keep only elements of the array that pass a test. Note, that inside the logic being used to filter, var operations are relative to the array element being worked on.", @@ -226,11 +245,22 @@ "title": "In Operation", "description": "If the second argument is an array, tests that the first argument is a member of the array.", "$ref": "#/$defs/binaryOp" - }, - "substr": { - "title": "Substring Operation", - "description": "Get a portion of a string, given a positive start position as an index (indexes of course start at zero).", - "$ref": "#/$defs/binaryOp" + } + } + }, + "reduceRule": { + "type": "object", + "additionalProperties": false, + "properties": { + "reduce": { + "title": "Reduce Operation", + "description": "Combine all the elements in an array into a single value, like adding up a list of numbers. Note, that inside the logic being used to reduce, var operations only have access to an object with a \"current\" and a \"accumulator\".", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": { + "$ref": "#/$defs/args" + } } } }, @@ -247,11 +277,6 @@ "type": "object", "additionalProperties": false, "properties": { - "+": { - "title": "Addition Operation", - "description": "Addition; associative, will accept and unlimited amount of arguments.", - "$ref": "#/$defs/associativeOp" - }, "*": { "title": "Multiplication Operation", "description": "Multiplication; associative, will accept and unlimited amount of arguments.", @@ -282,16 +307,6 @@ "title": "Double Negation Operation", "description": "Double negation, or 'cast to a boolean'. Takes a single argument.", "$ref": "#/$defs/unaryOp" - }, - "max": { - "title": "Maximum Operation", - "description": "Return the maximum from a list of values.", - "$ref": "#/$defs/unaryOp" - }, - "min": { - "title": "Minimum Operation", - "description": "Return the minimum from a list of values.", - "$ref": "#/$defs/unaryOp" } } }, @@ -317,22 +332,27 @@ "description": "Simple boolean test, with 1 or more arguments. At a more sophisticated level, \"and\" returns the first falsy argument, or the last argument.", "$ref": "#/$defs/variadicOp" }, - "<": { - "title": "Less-Than/Between Operation. Can be used to test that one value is between two others.", - "description": "", - "$ref": "#/$defs/variadicOp" - }, - "<=": { - "title": "Less-Than-Or-Equal-To/Between Operation. Can be used to test that one value is between two others.", - "description": "", + "+": { + "title": "Addition Operation", + "description": "Addition; associative, will accept and unlimited amount of arguments.", "$ref": "#/$defs/variadicOp" }, "-": { "title": "Subtraction Operation", "$ref": "#/$defs/variadicOp" }, + "max": { + "title": "Maximum Operation", + "description": "Return the maximum from a list of values.", + "$ref": "#/$defs/variadicOp" + }, + "min": { + "title": "Minimum Operation", + "description": "Return the minimum from a list of values.", + "$ref": "#/$defs/variadicOp" + }, "merge": { - "title": "Subtraction Operation", + "title": "Merge Operation", "description": "Takes one or more arrays, and merges them into one array. If arguments aren't arrays, they get cast to arrays.", "$ref": "#/$defs/variadicOp" }, @@ -432,7 +452,7 @@ } }, "fractionalWeightArg": { - "$comment": "if we remove the \"some to 100\" restriction, update the descriptions below!", + "$comment": "if we remove the \"sum to 100\" restriction, update the descriptions below!", "description": "Distribution for all possible variants, with their associated weighting out of 100.", "type": "array", "minItems": 2, @@ -529,10 +549,10 @@ "$ref": "#/$defs/missingSomeRule" }, { - "$ref": "#/$defs/ifRule" + "$ref": "#/$defs/binaryRule" }, { - "$ref": "#/$defs/binaryRule" + "$ref": "#/$defs/binaryOrTernaryRule" }, { "$ref": "#/$defs/associativeRule" @@ -543,6 +563,9 @@ { "$ref": "#/$defs/variadicRule" }, + { + "$ref": "#/$defs/reduceRule" + }, { "$ref": "#/$defs/stringCompareRule" }, diff --git a/json/targeting.yaml b/json/targeting.yaml index 4feac38..5a38bc6 100644 --- a/json/targeting.yaml +++ b/json/targeting.yaml @@ -32,6 +32,10 @@ type: object the associated value from the "variants" object. Be sure that the returned string is present as a key in the variants!. type: string + - description: When returned from rules, strings are used to as keys to retrieve + the associated value from the "variants" object. Be sure that the returned + string is present as a key in the variants!. + type: array varRule: title: Var Operation description: Retrieve data from the provided data object. @@ -93,21 +97,37 @@ type: object - type: array items: type: string - ifRule: + binaryOrTernaryOp: + type: array + minItems: 2 + maxItems: 3 + items: + $ref: "#/$defs/args" + binaryOrTernaryRule: type: object additionalProperties: false properties: if: title: If Operator description: 'The if statement takes 3 arguments: a condition (if), what to - do if its true (then), and what to do if its false (else). Note that the + do if its true (then), and what to do if its false (else, optional). Note that the form accepting more than 3 arguments (if/else) is not supported in flagd; use nesting instead.' - type: array - minItems: 2 - maxItems: 3 - items: - $ref: "#/$defs/args" + $ref: "#/$defs/binaryOrTernaryOp" + substr: + title: Substring Operation + description: Get a portion of a string. Give a positive start position to return everything beginning at that index. + Give a negative start position to work backwards from the end of the string, then return everything. + Give a positive length to express how many characters to return. + $ref: "#/$defs/binaryOrTernaryOp" + "<": + title: Less-Than/Between Operation. Can be used to test that one value is + between two others. + $ref: "#/$defs/binaryOrTernaryOp" + "<=": + title: Less-Than-Or-Equal-To/Between Operation. Can be used to test that one + value is between two others. + $ref: "#/$defs/binaryOrTernaryOp" binaryOp: type: array minItems: 2 @@ -147,18 +167,15 @@ type: object description: Finds the remainder after the first argument is divided by the second argument. $ref: "#/$defs/binaryOp" + "/": + title: Division Operation + $ref: "#/$defs/binaryOp" map: title: Map Operation description: Perform an action on every member of an array. Note, that inside the logic being used to map, var operations are relative to the array element being worked on. $ref: "#/$defs/binaryOp" - reduce: - title: Reduce Operation - description: Combine all the elements in an array into a single value, like - adding up a list of numbers. Note, that inside the logic being used to reduce, - var operations only have access to an object with a "current" and a "accumulator". - $ref: "#/$defs/binaryOp" filter: title: Filter Operation description: Keep only elements of the array that pass a test. Note, that @@ -188,11 +205,20 @@ type: object description: If the second argument is an array, tests that the first argument is a member of the array. $ref: "#/$defs/binaryOp" - substr: - title: Substring Operation - description: Get a portion of a string, given a positive start position as - an index (indexes of course start at zero). - $ref: "#/$defs/binaryOp" + reduceRule: + type: object + additionalProperties: false + properties: + reduce: + title: Reduce Operation + description: Combine all the elements in an array into a single value, like + adding up a list of numbers. Note, that inside the logic being used to reduce, + var operations only have access to an object with a "current" and a "accumulator". + type: array + minItems: 3 + maxItems: 3 + items: + $ref: "#/$defs/args" associativeOp: type: array minItems: 2 @@ -204,10 +230,6 @@ type: object type: object additionalProperties: false properties: - "+": - title: Addition Operation - description: Addition; associative, will accept and unlimited amount of arguments. - $ref: "#/$defs/associativeOp" "*": title: Multiplication Operation description: Multiplication; associative, will accept and unlimited amount @@ -233,14 +255,6 @@ type: object title: Double Negation Operation description: Double negation, or 'cast to a boolean'. Takes a single argument. $ref: "#/$defs/unaryOp" - max: - title: Maximum Operation - description: Return the maximum from a list of values. - $ref: "#/$defs/unaryOp" - min: - title: Minimum Operation - description: Return the minimum from a list of values. - $ref: "#/$defs/unaryOp" variadicOp: type: array minItems: 1 @@ -261,21 +275,23 @@ type: object description: Simple boolean test, with 1 or more arguments. At a more sophisticated level, "and" returns the first falsy argument, or the last argument. $ref: "#/$defs/variadicOp" - "<": - title: Less-Than/Between Operation. Can be used to test that one value is - between two others. - description: '' - $ref: "#/$defs/variadicOp" - "<=": - title: Less-Than-Or-Equal-To/Between Operation. Can be used to test that one - value is between two others. - description: '' + "+": + title: Addition Operation + description: Addition; associative, will accept and unlimited amount of arguments. $ref: "#/$defs/variadicOp" "-": title: Subtraction Operation $ref: "#/$defs/variadicOp" + max: + title: Maximum Operation + description: Return the maximum from a list of values. + $ref: "#/$defs/variadicOp" + min: + title: Minimum Operation + description: Return the minimum from a list of values. + $ref: "#/$defs/variadicOp" merge: - title: Subtraction Operation + title: Merge Operation description: Takes one or more arrays, and merges them into one array. If arguments aren't arrays, they get cast to arrays. $ref: "#/$defs/variadicOp" @@ -343,7 +359,7 @@ type: object - $ref: "#/$defs/semVerString" - $ref: "#/$defs/varRule" fractionalWeightArg: - $comment: if we remove the "some to 100" restriction, update the descriptions + $comment: if we remove the "sum to 100" restriction, update the descriptions below! description: Distribution for all possible variants, with their associated weighting out of 100. @@ -402,11 +418,12 @@ type: object - $ref: "#/$defs/varRule" - $ref: "#/$defs/missingRule" - $ref: "#/$defs/missingSomeRule" - - $ref: "#/$defs/ifRule" - $ref: "#/$defs/binaryRule" + - $ref: "#/$defs/binaryOrTernaryRule" - $ref: "#/$defs/associativeRule" - $ref: "#/$defs/unaryRule" - $ref: "#/$defs/variadicRule" + - $ref: "#/$defs/reduceRule" - $ref: "#/$defs/stringCompareRule" - $ref: "#/$defs/ruleSemVer" - $ref: "#/$defs/fractionalRule" diff --git a/json/test/negative/empty-variants.json b/json/test/negative/empty-variants.json index 5a7681c..0e43365 100644 --- a/json/test/negative/empty-variants.json +++ b/json/test/negative/empty-variants.json @@ -1,4 +1,5 @@ { + "$schema": "../../flagd-definitions.json", "flags": { "myBoolFlag": { "state": "ENABLED", diff --git a/json/test/negative/malformed-flag.json b/json/test/negative/malformed-flag.json index 584e57a..28063e7 100644 --- a/json/test/negative/malformed-flag.json +++ b/json/test/negative/malformed-flag.json @@ -1,13 +1,14 @@ { - "flags": { - "myBoolFlag": { - "state": "ENABLED", - "variants": { - "on": "false", - "off": "false" - }, - "defaultVariant": "on" + "$schema": "../../flagd-definitions.json", + "flags": { + "myBoolFlag": { + "state": "ENABLED", + "variants": { + "on": "false", + "off": "false" }, - "not-a-flag": {} - } - } \ No newline at end of file + "defaultVariant": "on" + }, + "not-a-flag": {} + } +} diff --git a/json/test/negative/missing-variants.json b/json/test/negative/missing-variants.json index 8768eb3..ccf493c 100644 --- a/json/test/negative/missing-variants.json +++ b/json/test/negative/missing-variants.json @@ -1,8 +1,10 @@ { - "flags": { - "myBoolFlag": { - "state": "ENABLED", - "defaultVariant": "on" - } + "$schema": "../../flagd-definitions.json", + + "flags": { + "myBoolFlag": { + "state": "ENABLED", + "defaultVariant": "on" } - } \ No newline at end of file + } +} diff --git a/json/test/negative/mixed-variant-types.ffconfig.json b/json/test/negative/mixed-variant-types.ffconfig.json index 6a31c62..c4b64ae 100644 --- a/json/test/negative/mixed-variant-types.ffconfig.json +++ b/json/test/negative/mixed-variant-types.ffconfig.json @@ -1,4 +1,5 @@ { + "$schema": "../../flagd-definitions.json", "flags": { "myBoolFlag": { "state": "ENABLED", diff --git a/json/test/negative/no-default-variant.json b/json/test/negative/no-default-variant.json index 78e69a4..e4bf012 100644 --- a/json/test/negative/no-default-variant.json +++ b/json/test/negative/no-default-variant.json @@ -1,11 +1,12 @@ { - "flags": { - "myBoolFlag": { - "state": "ENABLED", - "variants": { - "on": true, - "off": false - } + "$schema": "../../flagd-definitions.json", + "flags": { + "myBoolFlag": { + "state": "ENABLED", + "variants": { + "on": true, + "off": false } } -} \ No newline at end of file + } +} diff --git a/json/test/negative/state-set-incorrectly.json b/json/test/negative/state-set-incorrectly.json index 5e7304e..2555a88 100644 --- a/json/test/negative/state-set-incorrectly.json +++ b/json/test/negative/state-set-incorrectly.json @@ -1,12 +1,13 @@ { - "flags": { - "myBoolFlag": { - "state": "WILL-FAIL", - "variants": { - "on": true, - "off": false - }, - "defaultVariant": "on" - } + "$schema": "../../flagd-definitions.json", + "flags": { + "myBoolFlag": { + "state": "WILL-FAIL", + "variants": { + "on": true, + "off": false + }, + "defaultVariant": "on" } - } \ No newline at end of file + } +} diff --git a/json/test/positive/basic-json-ops.json b/json/test/positive/basic-json-ops.json new file mode 100644 index 0000000..fa1def0 --- /dev/null +++ b/json/test/positive/basic-json-ops.json @@ -0,0 +1,70 @@ +{ + "$schema": "../../flagd-definitions.json", + "flags": { + "basic-json-ops": { + "state": "ENABLED", + "variants": { + "on": true, + "off": false + }, + "defaultVariant": "on", + "targeting": { + "*" : [ + {"if" : [ true, "yes", "no" ]}, + {"==" : [1, 1]}, + {"===" : [1, 1]}, + {"!=" : [1, 2]}, + {"!==" : [1, 2]}, + {"!": [true]}, + {"!!": ["0"] }, + {"or": [true, false]}, + {"or":[false, 0, "a"]}, + {"and": [true, true]}, + {"and":[true, "a", 3]}, + {">" : [2, 1]}, + {">=" : [1, 1]}, + {"<" : [1, 2]}, + {"<=" : [1, 1]}, + {"<" : [1, 2, 3]}, + {"<" : [1, 4, 3]}, + {"<=" : [1, 2, 3]}, + {"<=" : [1, 1, 3]}, + {"max":[1,2,3]}, + {"min":[1,2,3]}, + {"+":[4,2]}, + {"+":[2,2,2,2,2]}, + {"+" : [ "3.14" ]}, + {"/":[4,2]}, + {"*":[2,2,2,2,2]}, + {"-": [ 2 ]}, + {"-":[4, 2]}, + {"%": [101,2]}, + {"map":[ + {"var":"integers"}, + {"*":[{"var":""},2]} + ]}, + {"filter":[ + {"var":"integers"}, + {"%":[{"var":""},2]} + ]}, + {"reduce":[ + {"var":"integers"}, + {"+":[{"var":"current"}, {"var":"accumulator"}]}, + 0 + ]}, + {"all" : [ [1,2,3], {">":[{"var":""}, 0]} ]}, + {"some" : [ [-1,0,1], {">":[{"var":""}, 0]} ]}, + {"none" : [ [-3,-2,-1], {">":[{"var":""}, 0]} ]}, + {"some" : [ {"var":"pies"}, {"==":[{"var":"filling"}, "apple"]} ]}, + {"merge":[ [1,2], [3,4] ]}, + {"merge":[ 1, 2, [3,4] ]}, + {"in":[ "Ringo", ["John", "Paul", "George", "Ringo"] ]}, + {"in":["Spring", "Springfield"]}, + {"cat": ["I love", " pie"]}, + {"substr": ["jsonlogic", 4]}, + {"substr": ["jsonlogic", 1, 3]} + ] + } + } + } +}