diff --git a/Makefile b/Makefile index d1b2e39..052b3f3 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ PYTHON_OUTPUT_DIR := sdk/python/mp_audience_sdk/models SCHEMA_FILE := schema/audience-definition-schema.json PYTHON_OUTPUT_FILE := $(PYTHON_OUTPUT_DIR)/audience_models.py TYPESCRIPT_SCHEMA_DIR := sdk/typescript-schema +PYTHON_FIX_TYPE_FILE := sdk/python/fixup_types.py build: build-typescript generate-python-models test @@ -23,7 +24,9 @@ generate-python-models: --output-model-type pydantic_v2.BaseModel \ --field-constraints \ --snake-case-field \ - --encoding utf-8 + --encoding utf-8 \ + --use-union-operator + python $(PYTHON_FIX_TYPE_FILE) $(PYTHON_OUTPUT_FILE) black $(PYTHON_OUTPUT_DIR) test: diff --git a/schema/audience-definition-schema.json b/schema/audience-definition-schema.json index d424a9c..9f1c58a 100644 --- a/schema/audience-definition-schema.json +++ b/schema/audience-definition-schema.json @@ -3,7 +3,7 @@ "definitions": { "AbsoluteDate": { "additionalProperties": false, - "description": "Represents an absolute date/time value. Examples: 1. ISO 8601 date: { absolute: \"2023-01-01T00:00:00Z\" }\n\n2. Date only: { absolute: \"2023-01-01\" }\n\n3. Date with timezone: { absolute: \"2023-01-01T00:00:00-05:00\" }", + "description": "Represents an absolute date/time value.\nExamples:\n1. ISO 8601 date:\n{ absolute: \"2023-01-01T00:00:00Z\" }\n\n2. Date only:\n{ absolute: \"2023-01-01\" }\n\n3. Date with timezone:\n{ absolute: \"2023-01-01T00:00:00-05:00\" }", "properties": { "absolute": { "type": "string" @@ -12,9 +12,34 @@ "required": [ "absolute" ], + "title": "AbsoluteDate", "type": "object" }, - "AggregationOperator": { + "AggregateNumberExpression": { + "additionalProperties": false, + "properties": { + "condition": { + "$ref": "#/definitions/BoolExpression" + }, + "group_by_model": { + "type": "string" + }, + "operand": { + "$ref": "#/definitions/NumberExpression" + }, + "operator": { + "$ref": "#/definitions/AggregationNumberOperator" + } + }, + "required": [ + "group_by_model", + "operand", + "operator" + ], + "title": "AggregateNumberExpression", + "type": "object" + }, + "AggregationNumberOperator": { "description": "Represents operators for aggregating multiple values. Examples:\n- \"min\": [1, 2, 3] // result: 1\n- \"max\": [1, 2, 3] // result: 3\n- \"avg\": [1, 2, 3] // result: 2\n- \"count\": [1, 2, 3] // result: 3", "enum": [ "min", @@ -26,23 +51,12 @@ ], "type": "string" }, - "ArithmeticOperator": { - "description": "Represents mathematical operators for numeric calculations. Examples:\n- \"plus\": { value1: 5, value2: 3 } // result: 8\n- \"multiply\": { value1: 4, value2: 2 } // result: 8\n- \"mod\": { value1: 10, value2: 3 } // result: 1", - "enum": [ - "plus", - "minus", - "multiply", - "divide", - "mod" - ], - "type": "string" - }, "Audience": { "additionalProperties": false, - "description": "Represents a complete audience definition with a root logical expression. Examples: 1. Simple audience: { \"schema_version\": \"1.0.0\", \"audience\": { \"operator\": \"and\", \"expressions\": [ { \"model\": \"user\", \"expression\": { \"operator\": \"exists\", \"operand\": { \"path\": \"id\" } } }, { \"model\": \"purchase\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"status\" }, \"right\": \"completed\" } } ] } }\n\n2. Audience with nested logic: { \"schema_version\": \"1.0.0\", \"audience\": { \"operator\": \"or\", \"expressions\": [ { \"model\": \"user\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"country\" }, \"right\": \"US\" } }, { \"operator\": \"and\", \"expressions\": [ { \"model\": \"signup\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"status\" }, \"right\": \"completed\" } }, { \"model\": \"user\", \"expression\": { \"operator\": \"greater_than\", \"left\": { \"path\": \"age\" }, \"right\": 18 } } ] } ] } }", + "description": "Represents a complete audience definition with a root logical expression.\nExamples:\n1. Simple audience:\n{\n\"schema_version\": \"1.0.0\",\n\"audience\": {\n\"operator\": \"and\",\n\"expressions\": [\n{ \"model\": \"user\", \"expression\": { \"operator\": \"exists\", \"operand\": { \"path\": \"id\" } } },\n{ \"model\": \"purchase\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"status\" }, \"right\": \"completed\" } }\n]\n}\n}\n\n2. Audience with nested logic:\n{\n\"schema_version\": \"1.0.0\",\n\"audience\": {\n\"operator\": \"or\",\n\"expressions\": [\n{ \"model\": \"user\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"country\" }, \"right\": \"US\" } },\n{\n\"operator\": \"and\",\n\"expressions\": [\n{ \"model\": \"signup\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"status\" }, \"right\": \"completed\" } },\n{ \"model\": \"user\", \"expression\": { \"operator\": \"greater_than\", \"left\": { \"path\": \"age\" }, \"right\": 18 } }\n]\n}\n]\n}\n}", "properties": { "audience": { - "$ref": "#/definitions/Expression", + "$ref": "#/definitions/BoolExpression", "title": "Audience" }, "schema_version": { @@ -53,20 +67,28 @@ "schema_version", "audience" ], - "type": "object", - "title": "AudienceDefinition" + "title": "AudienceDefinition", + "type": "object" }, - "AudienceOperand": { + "AudienceBoolExpression": { "additionalProperties": false, - "description": "Represents an audience. Audience is identified by a string ID. Example: { \"audience\": \"12345\" }", "properties": { - "audience": { - "type": "string" + "left": { + "$ref": "#/definitions/ModelReference" + }, + "operator": { + "$ref": "#/definitions/AudienceOperator" + }, + "right": { + "$ref": "#/definitions/AudienceReference" } }, "required": [ - "audience" + "left", + "operator", + "right" ], + "title": "AudienceBoolExpression", "type": "object" }, "AudienceOperator": { @@ -77,156 +99,128 @@ ], "type": "string" }, - "BinaryOperator": { - "description": "Represents binary operators that compare two values. Examples:\n- \"equals\": { value1: 5, value2: 5 }\n- \"less_than\": { value1: 3, value2: 5 }\n- \"matches\": { value1: \"pattern\", value2: \"text\" }\n- \"contains\": { value1: \"string\", value2: \"substring\" }", - "enum": [ - "equals", - "not_equals", - "less_than", - "less_than_equal", - "greater_than", - "greater_than_equal", - "matches", - "contains", - "not_contains", - "starts_with", - "not_starts_with", - "ends_with", - "not_ends_with", - "in", - "not_in" + "AudienceReference": { + "additionalProperties": false, + "description": "Represents an audience. Audience is identified by a string ID.\nExample:\n{ \"audience\": \"12345\" }", + "properties": { + "audience": { + "type": "string" + } + }, + "required": [ + "audience" ], - "type": "string" + "title": "AudienceReference", + "type": "object" }, - "CountExpression": { + "BinaryBoolExpression": { "anyOf": [ { - "type": "number" + "$ref": "#/definitions/AudienceBoolExpression" }, { - "additionalProperties": false, - "properties": { - "operand": { - "$ref": "#/definitions/Operand" - }, - "operator": { - "$ref": "#/definitions/BinaryOperator" - } - }, - "required": [ - "operator", - "operand" - ], - "type": "object" + "$ref": "#/definitions/LocationBoolExpression" }, { - "additionalProperties": false, - "properties": { - "expressions": { - "items": { - "$ref": "#/definitions/CountExpression" - }, - "type": "array" - }, - "operator": { - "$ref": "#/definitions/LogicalOperator" - } - }, - "required": [ - "operator", - "expressions" - ], - "type": "object" + "$ref": "#/definitions/DateBoolExpression" + }, + { + "$ref": "#/definitions/StringBoolExpression" + }, + { + "$ref": "#/definitions/NumberBoolExpression" } ], - "description": "Represents a count expression, which can be a number, a binary operation, or a logical group. Examples: 1. Simple count: 5\n\n2. Binary count expression: { operator: \"greater_than\", operand: { path: \"event.count\" } }\n\n3. Logical group of count expressions: { operator: \"and\", expressions: [ 1, { operator: \"greater_than\", operand: { path: \"event.count\" } } ] }" + "title": "BoolBinaryExpression" }, - "DateExpression": { + "BinaryNumberExpression": { + "additionalProperties": false, + "properties": { + "left": { + "$ref": "#/definitions/NumberExpression" + }, + "operator": { + "$ref": "#/definitions/BinaryNumberOperator" + }, + "right": { + "$ref": "#/definitions/NumberExpression" + } + }, + "required": [ + "left", + "operator", + "right" + ], + "title": "BinaryNumberExpression", + "type": "object" + }, + "BinaryNumberOperator": { + "description": "Represents mathematical operators for numeric calculations. Examples:\n- \"plus\": { value1: 5, value2: 3 } // result: 8\n- \"multiply\": { value1: 4, value2: 2 } // result: 8\n- \"mod\": { value1: 10, value2: 3 } // result: 1", + "enum": [ + "plus", + "minus", + "multiply", + "divide", + "mod" + ], + "type": "string" + }, + "BoolExpression": { "anyOf": [ { - "$ref": "#/definitions/AbsoluteDate" + "$ref": "#/definitions/ValueBoolExpression" }, { - "$ref": "#/definitions/RelativeDate" + "$ref": "#/definitions/UnaryBoolExpression" }, { - "additionalProperties": false, - "properties": { - "operand": { - "anyOf": [ - { - "$ref": "#/definitions/AbsoluteDate" - }, - { - "$ref": "#/definitions/RelativeDate" - } - ] - }, - "operator": { - "$ref": "#/definitions/BinaryOperator" - } - }, - "required": [ - "operator", - "operand" - ], - "type": "object" + "$ref": "#/definitions/BinaryBoolExpression" }, { - "additionalProperties": false, - "properties": { - "expressions": { - "items": { - "$ref": "#/definitions/DateExpression" - }, - "type": "array" - }, - "operator": { - "$ref": "#/definitions/LogicalOperator" - } - }, - "required": [ - "operator", - "expressions" - ], - "type": "object" + "$ref": "#/definitions/ManyBoolExpression" } ], - "description": "Represents an expression that evaluates to a date or date-based condition. Examples: 1. Absolute date: { absolute: \"2023-01-01T00:00:00Z\" }\n\n2. Relative date: { relative: { offset: -30, unit: \"day\" } }\n\n3. Date with binary operator: { operator: \"greater_than\", operand: { absolute: \"2023-01-01T00:00:00Z\" } }\n\n4. Logical combination of dates: { operator: \"and\", expressions: [ { absolute: \"2023-01-01T00:00:00Z\" }, { operator: \"less_than\", operand: { relative: { offset: 0, unit: \"month\", boundary: \"end\" } } } ] }" + "title": "BoolExpression" }, - "DateOperand": { + "DateBoolExpression": { + "additionalProperties": false, + "properties": { + "left": { + "$ref": "#/definitions/DateExpression" + }, + "operator": { + "$ref": "#/definitions/NumberBoolOperator" + }, + "right": { + "$ref": "#/definitions/DateExpression" + } + }, + "required": [ + "left", + "operator", + "right" + ], + "title": "DateBoolExpression", + "type": "object" + }, + "DateExpression": { + "$ref": "#/definitions/ValueDateExpression", + "description": "Represents an expression that evaluates to a date", + "title": "DateExpression" + }, + "DateLiteral": { "anyOf": [ { - "additionalProperties": false, - "properties": { - "date": { - "$ref": "#/definitions/AbsoluteDate" - } - }, - "required": [ - "date" - ], - "type": "object", - "title": "AbsoluteDateOperand" + "$ref": "#/definitions/AbsoluteDate" }, { - "additionalProperties": false, - "properties": { - "date": { - "$ref": "#/definitions/RelativeDate" - } - }, - "required": [ - "date" - ], - "type": "object", - "title": "RelativeDateOperand" + "$ref": "#/definitions/RelativeDate" } ], - "description": "Represents a date value that can be either absolute or relative. Examples: 1. Absolute date: { date: { absolute: \"2023-01-01T00:00:00Z\" } }\n\n2. Relative date (30 days ago): { date: { relative: { offset: -30, unit: \"day\" } } }\n\n3. Relative date (start of current month): { date: { relative: { offset: 0, unit: \"month\", boundary: \"start\" } } }" + "title": "DateLiteral" }, "DateUnit": { - "description": "Represents units of time that can be used in relative date calculations. Examples:\n- 'second': 1 second\n- 'minute': 60 seconds\n- 'hour': 60 minutes\n- 'day': 24 hours\n- 'week': 7 days\n- 'month': ~30 days\n- 'quarter': 3 months\n- 'year': 12 months", + "description": "Represents units of time that can be used in relative date calculations.\nExamples:\n- 'second': 1 second\n- 'minute': 60 seconds\n- 'hour': 60 minutes\n- 'day': 24 hours\n- 'week': 7 days\n- 'month': ~30 days\n- 'quarter': 3 months\n- 'year': 12 months", "enum": [ "second", "minute", @@ -237,6 +231,7 @@ "quarter", "year" ], + "title": "DateUnit", "type": "string" }, "DistanceUnit": { @@ -245,72 +240,127 @@ "miles", "kilometers" ], + "title": "DistanceUnit", "type": "string" }, "Expression": { "anyOf": [ { - "additionalProperties": false, - "properties": { - "operand": { - "$ref": "#/definitions/Operand" - }, - "operator": { - "$ref": "#/definitions/UnaryOperator" - } - }, - "required": [ - "operator", - "operand" - ], - "type": "object", - "title": "UnaryExpression" + "$ref": "#/definitions/ValueExpression" }, { - "additionalProperties": false, - "properties": { - "left": { - "$ref": "#/definitions/Operand" - }, - "operator": { - "$ref": "#/definitions/BinaryOperator" - }, - "right": { - "$ref": "#/definitions/Operand" - } - }, - "required": [ - "operator", - "left", - "right" - ], - "type": "object", - "title": "BinaryExpression" + "$ref": "#/definitions/IUnaryExpression" }, { - "additionalProperties": false, - "properties": { - "expressions": { - "items": { - "$ref": "#/definitions/Expression" - }, - "type": "array" - }, - "operator": { - "$ref": "#/definitions/LogicalOperator" - } + "$ref": "#/definitions/IBinaryExpression" + }, + { + "$ref": "#/definitions/IManyExpression" + }, + { + "$ref": "#/definitions/IAggregateExpression" + }, + { + "$ref": "#/definitions/BoolExpression" + }, + { + "$ref": "#/definitions/NumberExpression" + }, + { + "$ref": "#/definitions/StringExpression" + }, + { + "$ref": "#/definitions/LocationExpression" + }, + { + "$ref": "#/definitions/DateExpression" + }, + { + "$ref": "#/definitions/Literal" + } + ], + "description": "Represents an expression that accepts a variety of arguments and evaluates to a value.", + "title": "Expression" + }, + "IAggregateExpression": { + "additionalProperties": false, + "properties": { + "condition": { + "$ref": "#/definitions/Expression" + }, + "group_by_model": { + "type": "string" + }, + "operand": { + "$ref": "#/definitions/Expression" + }, + "operator": { + "$ref": "#/definitions/Operator" + } + }, + "required": [ + "group_by_model", + "operand", + "operator" + ], + "type": "object" + }, + "IBinaryExpression": { + "additionalProperties": false, + "properties": { + "left": { + "$ref": "#/definitions/Expression" + }, + "operator": { + "$ref": "#/definitions/Operator" + }, + "right": { + "$ref": "#/definitions/Expression" + } + }, + "required": [ + "left", + "operator", + "right" + ], + "type": "object" + }, + "IManyExpression": { + "additionalProperties": false, + "properties": { + "expressions": { + "items": { + "$ref": "#/definitions/Expression" }, - "required": [ - "operator", - "expressions" - ], - "type": "object", - "title": "LogicalExpression" + "type": "array" + }, + "operator": { + "$ref": "#/definitions/Operator" } + }, + "required": [ + "expressions", + "operator" ], - "description": "Represents a complex expression that can evaluate to true, false, or noop. Examples: 1. Join expression (combining expressions from different models): { \"model\": \"user\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"age\" }, \"right\": 18 } }\n\n2. Logical expression (AND): { \"operator\": \"and\", \"expressions\": [ { \"operator\": \"equals\", \"left\": { \"path\": \"country\" }, \"right\": \"US\" }, { \"operator\": \"greater_than\", \"left\": { \"path\": \"age\" }, \"right\": 18 } ] }\n\n3. Location expression: { \"operator\": \"within\", \"left\": { \"location\": { \"latitude\": 37.7749, \"longitude\": -122.4194, \"distance\": { \"value\": 10, \"unit\": \"miles\" } } }, \"right\": { \"model\": \"user\", \"path\": \"location\" } }" + "type": "object" }, - "ListOperator": { + "IUnaryExpression": { + "additionalProperties": false, + "properties": { + "operand": { + "$ref": "#/definitions/Expression" + }, + "operator": { + "$ref": "#/definitions/Operator" + } + }, + "required": [ + "operand", + "operator" + ], + "type": "object" + }, + "ListBoolOperator": { "description": "Represents operators that work with lists of values. Examples:\n- \"contains\": { list: [1, 2, 3], value: 2 }\n- \"between\": { list: [1, 10], value: 5 }\n- \"match_any\": { list: [\"a\", \"b\"], value: \"a\" }\n- \"in\": { list: [1, 2, 3], value: 2 }", "enum": [ "contains", @@ -322,9 +372,39 @@ ], "type": "string" }, + "Literal": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "$ref": "#/definitions/DateLiteral" + }, + { + "$ref": "#/definitions/ModelPath" + }, + { + "$ref": "#/definitions/Location" + }, + { + "$ref": "#/definitions/ModelReference" + }, + { + "$ref": "#/definitions/AudienceReference" + } + ], + "description": "Represents a value that can be used in expressions, including primitive values, paths, and arithmetic operations.\nExamples:\n1. Primitive values:\ntrue\n42\n\"hello\"\n\n2. Path reference:\n{ path: \"user.age\" }\n\n3. Arithmetic operation:\n{\noperator: \"plus\",\nleft: { path: \"price\" },\nright: { path: \"tax\" }\n}\n\n4. Nested arithmetic operation:\n{\noperator: \"multiply\",\nleft: { operator: \"plus\", left: { path: \"base_price\" }, right: { path: \"shipping\" } },\nright: 1.1\n}\n\n5. Date operand:\n{ date: { absolute: \"2023-01-01T00:00:00Z\" } }", + "title": "Literal" + }, "Location": { "additionalProperties": false, - "description": "Represents a geographic location, optionally with a distance constraint. Examples: 1. Simple location: { \"latitude\": 37.7749, \"longitude\": -122.4194 }\n\n2. Location with distance in miles: { \"latitude\": 40.7128, \"longitude\": -74.0060, \"distance\": { \"value\": 10, \"unit\": \"miles\" } }\n\n3. Location with distance in kilometers: { \"latitude\": 51.5074, \"longitude\": -0.1278, \"distance\": { \"value\": 5, \"unit\": \"kilometers\" } }", + "description": "Represents a geographic location, optionally with a distance constraint.\nExamples:\n1. Simple location:\n{ \"latitude\": 37.7749, \"longitude\": -122.4194 }\n\n2. Location with distance in miles:\n{ \"latitude\": 40.7128, \"longitude\": -74.0060, \"distance\": { \"value\": 10, \"unit\": \"miles\" } }\n\n3. Location with distance in kilometers:\n{ \"latitude\": 51.5074, \"longitude\": -0.1278, \"distance\": { \"value\": 5, \"unit\": \"kilometers\" } }", "properties": { "distance": { "additionalProperties": false, @@ -353,65 +433,31 @@ "latitude", "longitude" ], + "title": "Location", "type": "object" }, - "LocationExpression": { - "anyOf": [ - { - "$ref": "#/definitions/Location" - }, - { - "additionalProperties": false, - "properties": { - "operand": { - "$ref": "#/definitions/Location" - }, - "operator": { - "$ref": "#/definitions/LocationOperator" - } - }, - "required": [ - "operator", - "operand" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "expressions": { - "items": { - "$ref": "#/definitions/LocationExpression" - }, - "type": "array" - }, - "operator": { - "$ref": "#/definitions/LogicalOperator" - } - }, - "required": [ - "operator", - "expressions" - ], - "type": "object" - } - ], - "description": "Represents an expression that evaluates to a location or location-based condition. Examples: 1. Simple location: { latitude: 40.7128, longitude: -74.0060, distance: { value: 5, unit: \"miles\" } }\n\n2. Location with operator: { operator: \"within\", operand: { latitude: 40.7128, longitude: -74.0060, distance: { value: 5, unit: \"miles\" } } }\n\n3. Logical combination of locations: { operator: \"or\", expressions: [ { latitude: 40.7128, longitude: -74.0060, distance: { value: 5, unit: \"miles\" } }, { operator: \"within\", operand: { latitude: 34.0522, longitude: -118.2437, distance: { value: 10, unit: \"miles\" } } } ] }" - }, - "LocationOperand": { + "LocationBoolExpression": { "additionalProperties": false, - "description": "Represents a location value that can be used in location-based expressions. Examples: 1. Simple location (latitude/longitude only): { location: { latitude: 40.7128, longitude: -74.0060 } }\n\n2. Location with distance in miles: { location: { latitude: 40.7128, longitude: -74.0060, distance: { value: 5, unit: \"miles\" } } }\n\n3. Location with distance in meters: { location: { latitude: 40.7128, longitude: -74.0060, distance: { value: 1000, unit: \"meters\" } } }", "properties": { - "location": { - "$ref": "#/definitions/Location" + "left": { + "$ref": "#/definitions/LocationExpression" + }, + "operator": { + "$ref": "#/definitions/LocationBoolOperator" + }, + "right": { + "$ref": "#/definitions/LocationExpression" } }, "required": [ - "location" + "left", + "operator", + "right" ], + "title": "LocationBoolExpression", "type": "object" }, - "LocationOperator": { + "LocationBoolOperator": { "description": "Represents operators for location-based comparisons. Examples:\n- \"within\": { location1: { lat: 40, lng: -74 }, location2: { lat: 40, lng: -74 }, radius: 5 }\n- \"equals\": { location1: { lat: 40, lng: -74 }, location2: { lat: 40, lng: -74 } }", "enum": [ "within", @@ -419,7 +465,33 @@ ], "type": "string" }, - "LogicalOperator": { + "LocationExpression": { + "$ref": "#/definitions/ValueLocationExpression", + "description": "Represents an expression that evaluates to a location or location-based condition.", + "title": "LocationExpression" + }, + "LogicalBoolExpression": { + "additionalProperties": false, + "properties": { + "left": { + "$ref": "#/definitions/BoolExpression" + }, + "operator": { + "$ref": "#/definitions/LogicalBoolOperator" + }, + "right": { + "$ref": "#/definitions/BoolExpression" + } + }, + "required": [ + "left", + "operator", + "right" + ], + "title": "LogicalBoolExpression", + "type": "object" + }, + "LogicalBoolOperator": { "description": "Represents logical operators for combining multiple conditions. Examples:\n- \"and\": { condition1: true, condition2: true } // result: true\n- \"or\": { condition1: true, condition2: false } // result: true", "enum": [ "and", @@ -427,21 +499,33 @@ ], "type": "string" }, - "ModelOperand": { + "LogicalManyBoolExpression": { "additionalProperties": false, "properties": { - "model": { - "type": "string" + "expressions": { + "items": { + "$ref": "#/definitions/BoolExpression" + }, + "type": "array" + }, + "operator": { + "$ref": "#/definitions/LogicalBoolOperator" } }, "required": [ - "model" + "expressions", + "operator" ], + "title": "LogicalManyBoolExpression", "type": "object" }, + "ManyBoolExpression": { + "$ref": "#/definitions/LogicalManyBoolExpression", + "title": "ManyBoolExpression" + }, "ModelPath": { "additionalProperties": false, - "description": "Represents a model path reference within a data model. Examples: 1. Simple model path: { \"model\": \"user\", \"path\": \"email\" }\n\n2. Nested model path: { \"model\": \"order\", \"path\": \"items.productId\" }\n\n3. Deeply nested model path: { \"model\": \"event\", \"path\": \"attributes.purchase.amount\" }", + "description": "Represents a model path reference within a data model.\nExamples:\n1. Simple model path:\n{ \"model\": \"user\", \"path\": \"email\" }\n\n2. Nested model path:\n{ \"model\": \"order\", \"path\": \"items.productId\" }\n\n3. Deeply nested model path:\n{ \"model\": \"event\", \"path\": \"attributes.purchase.amount\" }", "properties": { "model": { "type": "string" @@ -454,112 +538,105 @@ "model", "path" ], + "title": "ModelPath", "type": "object" }, - "Operand": { + "ModelReference": { + "additionalProperties": false, + "description": "Represents a model reference within a data model", + "properties": { + "model": { + "type": "string" + } + }, + "required": [ + "model" + ], + "title": "ModelReference", + "type": "object" + }, + "NumberBoolExpression": { + "additionalProperties": false, + "properties": { + "left": { + "$ref": "#/definitions/NumberExpression" + }, + "operator": { + "$ref": "#/definitions/NumberBoolOperator" + }, + "right": { + "$ref": "#/definitions/NumberExpression" + } + }, + "required": [ + "left", + "operator", + "right" + ], + "title": "NumberBoolExpression", + "type": "object" + }, + "NumberBoolOperator": { + "description": "Represents binary operators that compare two values. Examples:\n- \"equals\": { value1: 5, value2: 5 }\n- \"less_than\": { value1: 3, value2: 5 }\n- \"matches\": { value1: \"pattern\", value2: \"text\" }\n- \"contains\": { value1: \"string\", value2: \"substring\" }", + "enum": [ + "equals", + "not_equals", + "less_than", + "less_than_equal", + "greater_than", + "greater_than_equal" + ], + "type": "string" + }, + "NumberExpression": { "anyOf": [ { - "type": "boolean" + "$ref": "#/definitions/ValueNumberExpression" }, { - "type": "number" + "$ref": "#/definitions/BinaryNumberExpression" }, { - "type": "string" - }, + "$ref": "#/definitions/AggregateNumberExpression" + } + ], + "description": "Represents an expression that evaluates to a number.", + "title": "NumberExpression" + }, + "Operator": { + "anyOf": [ { - "$ref": "#/definitions/DateOperand" + "$ref": "#/definitions/LogicalBoolOperator" }, { - "$ref": "#/definitions/ModelPath" + "$ref": "#/definitions/LocationBoolOperator" }, { - "$ref": "#/definitions/ModelOperand" + "$ref": "#/definitions/AggregationNumberOperator" }, { - "$ref": "#/definitions/AudienceOperand" + "$ref": "#/definitions/BinaryNumberOperator" }, { - "additionalProperties": false, - "properties": { - "condition": { - "$ref": "#/definitions/Expression" - }, - "group_by_model": { - "type": "string" - }, - "operand": { - "$ref": "#/definitions/Operand" - }, - "operator": { - "$ref": "#/definitions/AggregationOperator" - } - }, - "required": [ - "operator", - "group_by_model", - "operand" - ], - "type": "object", - "title": "ModelAggregationOperand" - } - ], - "description": "Represents a value that can be used in expressions, including primitive values, paths, and arithmetic operations. Examples: 1. Primitive values: true 42 \"hello\"\n\n2. Path reference: { path: \"user.age\" }\n\n3. Arithmetic operation: { operator: \"plus\", left: { path: \"price\" }, right: { path: \"tax\" } }\n\n4. Nested arithmetic operation: { operator: \"multiply\", left: { operator: \"plus\", left: { path: \"base_price\" }, right: { path: \"shipping\" } }, right: 1.1 }\n\n5. Date operand: { date: { absolute: \"2023-01-01T00:00:00Z\" } }" - }, - "PathExpression": { - "anyOf": [ - { - "type": "boolean", - "title": "BooleanPathExpression" + "$ref": "#/definitions/AudienceOperator" }, { - "type": "number", - "title": "NumberPathExpression" + "$ref": "#/definitions/ListBoolOperator" }, { - "type": "string", - "title": "StringPathExpression" + "$ref": "#/definitions/StringBoolOperator" }, { - "additionalProperties": false, - "properties": { - "expression": { - "$ref": "#/definitions/PathExpression" - }, - "operator": { - "$ref": "#/definitions/UnaryOperator" - } - }, - "required": [ - "operator", - "expression" - ], - "type": "object", - "title": "UnaryPathExpression" + "$ref": "#/definitions/NumberBoolOperator" }, { - "additionalProperties": false, - "properties": { - "operand": { - "$ref": "#/definitions/Operand" - }, - "operator": { - "$ref": "#/definitions/BinaryOperator" - } - }, - "required": [ - "operator", - "operand" - ], - "type": "object", - "title": "BinaryPathExpression" + "$ref": "#/definitions/UnaryBoolOperator" } - ], - "description": "Represents an expression that evaluates to a path or value. Examples: 1. Primitive values: true 42 \"hello\"\n\n2. Unary expression (NOT): { operator: \"not\", expression: { operator: \"equals\", operand: { path: \"status\" } } }\n\n3. Binary expression (comparing a path to a value): { operator: \"equals\", operand: { path: \"user.age\" } }" + ] }, "RelativeDate": { "additionalProperties": false, - "description": "Represents a date/time relative to the current time. Examples: 1. 7 days ago: { relative: { offset: -7, unit: \"day\" } }\n\n2. Start of current month: { relative: { offset: 0, unit: \"month\", boundary: \"start\" } }\n\n3. End of previous quarter: { relative: { offset: -1, unit: \"quarter\", boundary: \"end\" } }", + "description": "Represents a date/time relative to the current time.\nExamples:\n1. 7 days ago:\n{ relative: { offset: -7, unit: \"day\" } }\n\n2. Start of current month:\n{ relative: { offset: 0, unit: \"month\", boundary: \"start\" } }\n\n3. End of previous quarter:\n{ relative: { offset: -1, unit: \"quarter\", boundary: \"end\" } }", "properties": { "relative": { "additionalProperties": false, @@ -588,9 +665,68 @@ "required": [ "relative" ], + "title": "RelativeDate", + "type": "object" + }, + "StringBoolExpression": { + "additionalProperties": false, + "properties": { + "left": { + "$ref": "#/definitions/StringExpression" + }, + "operator": { + "$ref": "#/definitions/StringBoolOperator" + }, + "right": { + "$ref": "#/definitions/StringExpression" + } + }, + "required": [ + "left", + "operator", + "right" + ], + "title": "StringBoolExpression", + "type": "object" + }, + "StringBoolOperator": { + "enum": [ + "equals", + "not_equals", + "matches", + "contains", + "not_contains", + "starts_with", + "not_starts_with", + "ends_with", + "not_ends_with", + "in", + "not_in" + ], + "type": "string" + }, + "StringExpression": { + "$ref": "#/definitions/ValueStringExpression", + "title": "StringExpression" + }, + "UnaryBoolExpression": { + "additionalProperties": false, + "properties": { + "operand": { + "$ref": "#/definitions/Expression" + }, + "operator": { + "$ref": "#/definitions/UnaryBoolOperator" + } + }, + "required": [ + "operand", + "operator" + ], + "title": "UnaryBoolExpression", "type": "object" }, - "UnaryOperator": { + "UnaryBoolOperator": { "description": "Represents unary operators that operate on a single value. Examples:\n- \"not\": Negates a boolean expression\n- \"exist\": Checks if a value exists", "enum": [ "null", @@ -600,6 +736,90 @@ ], "type": "string" }, + "ValueBoolExpression": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/definitions/ModelPath" + } + ], + "title": "ValueBoolExpression" + }, + "ValueDateExpression": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "date": { + "$ref": "#/definitions/DateLiteral" + } + }, + "required": [ + "date" + ], + "type": "object" + }, + { + "$ref": "#/definitions/ModelPath" + } + ], + "title": "ValueDateExpression" + }, + "ValueExpression": { + "anyOf": [ + { + "$ref": "#/definitions/ValueBoolExpression" + }, + { + "$ref": "#/definitions/ValueDateExpression" + }, + { + "$ref": "#/definitions/ValueLocationExpression" + }, + { + "$ref": "#/definitions/ValueNumberExpression" + }, + { + "$ref": "#/definitions/ValueStringExpression" + } + ], + "title": "ValueExpression" + }, + "ValueLocationExpression": { + "anyOf": [ + { + "$ref": "#/definitions/Location" + }, + { + "$ref": "#/definitions/ModelPath" + } + ], + "title": "ValueLocationExpression" + }, + "ValueNumberExpression": { + "anyOf": [ + { + "type": "number" + }, + { + "$ref": "#/definitions/ModelPath" + } + ], + "title": "ValueNumberExpression" + }, + "ValueStringExpression": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/ModelPath" + } + ], + "title": "ValueStringExpression" + }, "Version": { "type": [ "string" @@ -624,4 +844,4 @@ "type": "object" } } -} +} \ No newline at end of file diff --git a/sdk/python/fixup_types.py b/sdk/python/fixup_types.py new file mode 100644 index 0000000..2192ac3 --- /dev/null +++ b/sdk/python/fixup_types.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 + +""" +Script to fix RootModel[...] types by wrapping the content in quotes. +Handles both single-line and multi-line type definitions. +Usage: python fixup_types.py +""" + +from collections.abc import Iterable +import sys +import os +import re +import argparse +from pathlib import Path + +ROOT_MODEL_TEXT = "RootModel[" + +def quote_root_model_types(lines: Iterable[str]) -> Iterable[str]: + bracket_count = 0 + acc_line = "" + for line in lines: + cur_idx = 0 + if bracket_count == 0: + root_model_idx = line.find(ROOT_MODEL_TEXT) + + if root_model_idx == -1: + yield line + continue + + cur_idx = root_model_idx + len(ROOT_MODEL_TEXT) + bracket_count = 1 + yield line[:cur_idx] + + for i in range(cur_idx, len(line)): + c = line[i] + + if c == "[": + bracket_count += 1 + elif c == "]": + bracket_count -= 1 + + if bracket_count == 0: + cleaned_line = re.sub(r'[ \t]+', " ", acc_line).replace("\n", "").strip() + yield f'"{cleaned_line}"]' + line[i + 1:] + acc_line = "" + break + + else: + acc_line += c + + +def process_file(file_path: Path): + """Process a single Python file.""" + print(f"Processing: {file_path}") + + try: + # Read the file + with open(file_path, 'r', encoding='utf-8') as f: + original_lines = f.readlines() + + # Fix RootModel types + fixed_lines = list(quote_root_model_types(original_lines)) + + if original_lines != fixed_lines: + # Write the fixed content back + with open(file_path, 'w', encoding='utf-8') as f: + f.writelines(fixed_lines) + + else: + print(f" - No RootModel types found in {file_path}") + + except Exception as e: + print(f" Error processing {file_path}: {e}") + + +def main(): + parser = argparse.ArgumentParser( + description="Fix RootModel[...] types by wrapping content in quotes" + ) + parser.add_argument( + 'target', + help='File or directory to process' + ) + parser.add_argument( + '--dry-run', + action='store_true', + help='Show what would be changed without making changes' + ) + + args = parser.parse_args() + target_path = Path(args.target) + + if not target_path.exists(): + print(f"Error: {target_path} does not exist") + sys.exit(1) + + if target_path.is_file(): + # Single file + if target_path.suffix == '.py': + process_file(target_path) + else: + print(f"Warning: {target_path} is not a Python file") + + elif target_path.is_dir(): + # Directory - find all .py files + print(f"Searching for Python files in: {target_path}") + py_files = list(target_path.rglob('*.py')) + + if not py_files: + print("No Python files found") + return + + for py_file in py_files: + process_file(py_file) + + else: + print(f"Error: {target_path} is neither a file nor a directory") + sys.exit(1) + + print("Done!") + + +if __name__ == "__main__": + main() diff --git a/sdk/python/mp_audience_sdk/models/audience_models.py b/sdk/python/mp_audience_sdk/models/audience_models.py index f1bf975..ee53e53 100644 --- a/sdk/python/mp_audience_sdk/models/audience_models.py +++ b/sdk/python/mp_audience_sdk/models/audience_models.py @@ -1,16 +1,16 @@ # generated by datamodel-codegen: # filename: audience-definition-schema.json -# timestamp: 2025-06-27T23:21:24+00:00 +# timestamp: 2025-07-01T01:01:04+00:00 from __future__ import annotations from enum import Enum -from typing import Any, List, Optional, Union +from typing import Any, List from pydantic import BaseModel, ConfigDict, Field, RootModel -class Model(RootModel[Any]): +class Model(RootModel["Any"]): root: Any @@ -21,7 +21,7 @@ class AbsoluteDate(BaseModel): absolute: str -class AggregationOperator(Enum): +class AggregationNumberOperator(Enum): min = "min" max = "max" sum = "sum" @@ -30,49 +30,24 @@ class AggregationOperator(Enum): count = "count" -class ArithmeticOperator(Enum): - plus = "plus" - minus = "minus" - multiply = "multiply" - divide = "divide" - mod = "mod" - - -class AudienceOperand(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - audience: str - - class AudienceOperator(Enum): in_ = "in" not_in = "not_in" -class BinaryOperator(Enum): - equals = "equals" - not_equals = "not_equals" - less_than = "less_than" - less_than_equal = "less_than_equal" - greater_than = "greater_than" - greater_than_equal = "greater_than_equal" - matches = "matches" - contains = "contains" - not_contains = "not_contains" - starts_with = "starts_with" - not_starts_with = "not_starts_with" - ends_with = "ends_with" - not_ends_with = "not_ends_with" - in_ = "in" - not_in = "not_in" - - -class AbsoluteDateOperand(BaseModel): +class AudienceReference(BaseModel): model_config = ConfigDict( extra="forbid", ) - date: AbsoluteDate + audience: str + + +class BinaryNumberOperator(Enum): + plus = "plus" + minus = "minus" + multiply = "multiply" + divide = "divide" + mod = "mod" class DateUnit(Enum): @@ -92,7 +67,7 @@ class DistanceUnit(Enum): kilometers = "kilometers" -class ListOperator(Enum): +class ListBoolOperator(Enum): contains = "contains" between = "between" match_any = "match_any" @@ -113,41 +88,43 @@ class Location(BaseModel): model_config = ConfigDict( extra="forbid", ) - distance: Optional[Distance] = None + distance: Distance | None = None latitude: float longitude: float -class LocationOperand(BaseModel): - model_config = ConfigDict( - extra="forbid", - ) - location: Location - - -class LocationOperator(Enum): +class LocationBoolOperator(Enum): within = "within" equals = "equals" -class LogicalOperator(Enum): +class LogicalBoolOperator(Enum): and_ = "and" or_ = "or" -class ModelOperand(BaseModel): +class ModelPath(BaseModel): model_config = ConfigDict( extra="forbid", ) model: str + path: str -class ModelPath(BaseModel): +class ModelReference(BaseModel): model_config = ConfigDict( extra="forbid", ) model: str - path: str + + +class NumberBoolOperator(Enum): + equals = "equals" + not_equals = "not_equals" + less_than = "less_than" + less_than_equal = "less_than_equal" + greater_than = "greater_than" + greater_than_equal = "greater_than_equal" class Boundary(Enum): @@ -159,7 +136,7 @@ class Relative(BaseModel): model_config = ConfigDict( extra="forbid", ) - boundary: Optional[Boundary] = None + boundary: Boundary | None = None offset: float unit: DateUnit @@ -171,14 +148,44 @@ class RelativeDate(BaseModel): relative: Relative -class UnaryOperator(Enum): +class StringBoolOperator(Enum): + equals = "equals" + not_equals = "not_equals" + matches = "matches" + contains = "contains" + not_contains = "not_contains" + starts_with = "starts_with" + not_starts_with = "not_starts_with" + ends_with = "ends_with" + not_ends_with = "not_ends_with" + in_ = "in" + not_in = "not_in" + + +class UnaryBoolOperator(Enum): null = "null" not_null = "not_null" exists = "exists" not_exists = "not_exists" -class Version(RootModel[str]): +class ValueBoolExpression(RootModel["bool | ModelPath"]): + root: bool | ModelPath = Field(..., title="ValueBoolExpression") + + +class ValueLocationExpression(RootModel["Location | ModelPath"]): + root: Location | ModelPath = Field(..., title="ValueLocationExpression") + + +class ValueNumberExpression(RootModel["float | ModelPath"]): + root: float | ModelPath = Field(..., title="ValueNumberExpression") + + +class ValueStringExpression(RootModel["str | ModelPath"]): + root: str | ModelPath = Field(..., title="ValueStringExpression") + + +class Version(RootModel["str"]): root: str @@ -190,209 +197,302 @@ class NamedArgs(BaseModel): class IsValidAudienceObject(BaseModel): - named_args: Optional[NamedArgs] = Field(None, alias="namedArgs") + named_args: NamedArgs | None = Field(None, alias="namedArgs") -class DateExpression1(BaseModel): +class AudienceBoolExpression(BaseModel): model_config = ConfigDict( extra="forbid", ) - operand: Union[AbsoluteDate, RelativeDate] - operator: BinaryOperator + left: ModelReference + operator: AudienceOperator + right: AudienceReference + + +class DateLiteral(RootModel["AbsoluteDate | RelativeDate"]): + root: AbsoluteDate | RelativeDate = Field(..., title="DateLiteral") + + +class Literal( + RootModel[ + "bool | float | str | DateLiteral | ModelPath | Location | ModelReference | AudienceReference" + ] +): + root: ( + bool + | float + | str + | DateLiteral + | ModelPath + | Location + | ModelReference + | AudienceReference + ) = Field( + ..., + description='Represents a value that can be used in expressions, including primitive values, paths, and arithmetic operations.\nExamples:\n1. Primitive values:\ntrue\n42\n"hello"\n\n2. Path reference:\n{ path: "user.age" }\n\n3. Arithmetic operation:\n{\noperator: "plus",\nleft: { path: "price" },\nright: { path: "tax" }\n}\n\n4. Nested arithmetic operation:\n{\noperator: "multiply",\nleft: { operator: "plus", left: { path: "base_price" }, right: { path: "shipping" } },\nright: 1.1\n}\n\n5. Date operand:\n{ date: { absolute: "2023-01-01T00:00:00Z" } }', + title="Literal", + ) -class RelativeDateOperand(BaseModel): +class LocationExpression(RootModel["ValueLocationExpression"]): + root: ValueLocationExpression = Field( + ..., + description="Represents an expression that evaluates to a location or location-based condition.", + title="LocationExpression", + ) + + +class Operator( + RootModel[ + "LogicalBoolOperator | LocationBoolOperator | AggregationNumberOperator | BinaryNumberOperator | AudienceOperator | ListBoolOperator | StringBoolOperator | NumberBoolOperator | UnaryBoolOperator" + ] +): + root: ( + LogicalBoolOperator + | LocationBoolOperator + | AggregationNumberOperator + | BinaryNumberOperator + | AudienceOperator + | ListBoolOperator + | StringBoolOperator + | NumberBoolOperator + | UnaryBoolOperator + ) + + +class StringExpression(RootModel["ValueStringExpression"]): + root: ValueStringExpression = Field(..., title="StringExpression") + + +class ValueDateExpression1(BaseModel): model_config = ConfigDict( extra="forbid", ) - date: RelativeDate + date: DateLiteral + + +class ValueDateExpression(RootModel["ValueDateExpression1 | ModelPath"]): + root: ValueDateExpression1 | ModelPath = Field(..., title="ValueDateExpression") + + +class ValueExpression( + RootModel[ + "ValueBoolExpression | ValueDateExpression | ValueLocationExpression | ValueNumberExpression | ValueStringExpression" + ] +): + root: ( + ValueBoolExpression + | ValueDateExpression + | ValueLocationExpression + | ValueNumberExpression + | ValueStringExpression + ) = Field(..., title="ValueExpression") -class DateOperand(RootModel[Union[AbsoluteDateOperand, RelativeDateOperand]]): - root: Union[AbsoluteDateOperand, RelativeDateOperand] = Field( +class DateExpression(RootModel["ValueDateExpression"]): + root: ValueDateExpression = Field( ..., - description='Represents a date value that can be either absolute or relative. Examples: 1. Absolute date: { date: { absolute: "2023-01-01T00:00:00Z" } }\n\n2. Relative date (30 days ago): { date: { relative: { offset: -30, unit: "day" } } }\n\n3. Relative date (start of current month): { date: { relative: { offset: 0, unit: "month", boundary: "start" } } }', + description="Represents an expression that evaluates to a date", + title="DateExpression", ) -class LocationExpression1(BaseModel): +class LocationBoolExpression(BaseModel): model_config = ConfigDict( extra="forbid", ) - operand: Location - operator: LocationOperator + left: LocationExpression + operator: LocationBoolOperator + right: LocationExpression -class AudienceDefinition(BaseModel): +class StringBoolExpression(BaseModel): model_config = ConfigDict( extra="forbid", ) - audience: Expression = Field(..., title="Audience") - schema_version: Version + left: StringExpression + operator: StringBoolOperator + right: StringExpression -class CountExpression1(BaseModel): +class DateBoolExpression(BaseModel): model_config = ConfigDict( extra="forbid", ) - operand: Operand - operator: BinaryOperator + left: DateExpression + operator: NumberBoolOperator + right: DateExpression -class CountExpression2(BaseModel): +class AggregateNumberExpression(BaseModel): model_config = ConfigDict( extra="forbid", ) - expressions: List[CountExpression] - operator: LogicalOperator + condition: BoolExpression | None = None + group_by_model: str + operand: NumberExpression + operator: AggregationNumberOperator -class CountExpression(RootModel[Union[float, CountExpression1, CountExpression2]]): - root: Union[float, CountExpression1, CountExpression2] = Field( - ..., - description='Represents a count expression, which can be a number, a binary operation, or a logical group. Examples: 1. Simple count: 5\n\n2. Binary count expression: { operator: "greater_than", operand: { path: "event.count" } }\n\n3. Logical group of count expressions: { operator: "and", expressions: [ 1, { operator: "greater_than", operand: { path: "event.count" } } ] }', +class AudienceDefinition(BaseModel): + model_config = ConfigDict( + extra="forbid", ) + audience: BoolExpression = Field(..., title="Audience") + schema_version: Version -class DateExpression2(BaseModel): +class BinaryBoolExpression( + RootModel[ + "AudienceBoolExpression | LocationBoolExpression | DateBoolExpression | StringBoolExpression | NumberBoolExpression" + ] +): + root: ( + AudienceBoolExpression + | LocationBoolExpression + | DateBoolExpression + | StringBoolExpression + | NumberBoolExpression + ) = Field(..., title="BoolBinaryExpression") + + +class BinaryNumberExpression(BaseModel): model_config = ConfigDict( extra="forbid", ) - expressions: List[DateExpression] - operator: LogicalOperator + left: NumberExpression + operator: BinaryNumberOperator + right: NumberExpression -class DateExpression( - RootModel[Union[AbsoluteDate, RelativeDate, DateExpression1, DateExpression2]] +class BoolExpression( + RootModel[ + "ValueBoolExpression | UnaryBoolExpression | BinaryBoolExpression | ManyBoolExpression" + ] ): - root: Union[AbsoluteDate, RelativeDate, DateExpression1, DateExpression2] = Field( + root: ( + ValueBoolExpression + | UnaryBoolExpression + | BinaryBoolExpression + | ManyBoolExpression + ) = Field(..., title="BoolExpression") + + +class Expression( + RootModel[ + "ValueExpression | IUnaryExpression | IBinaryExpression | IManyExpression | IAggregateExpression | BoolExpression | NumberExpression | StringExpression | LocationExpression | DateExpression | Literal" + ] +): + root: ( + ValueExpression + | IUnaryExpression + | IBinaryExpression + | IManyExpression + | IAggregateExpression + | BoolExpression + | NumberExpression + | StringExpression + | LocationExpression + | DateExpression + | Literal + ) = Field( ..., - description='Represents an expression that evaluates to a date or date-based condition. Examples: 1. Absolute date: { absolute: "2023-01-01T00:00:00Z" }\n\n2. Relative date: { relative: { offset: -30, unit: "day" } }\n\n3. Date with binary operator: { operator: "greater_than", operand: { absolute: "2023-01-01T00:00:00Z" } }\n\n4. Logical combination of dates: { operator: "and", expressions: [ { absolute: "2023-01-01T00:00:00Z" }, { operator: "less_than", operand: { relative: { offset: 0, unit: "month", boundary: "end" } } } ] }', + description="Represents an expression that accepts a variety of arguments and evaluates to a value.", + title="Expression", ) -class UnaryExpression(BaseModel): +class IAggregateExpression(BaseModel): model_config = ConfigDict( extra="forbid", ) - operand: Operand - operator: UnaryOperator + condition: Expression | None = None + group_by_model: str + operand: Expression + operator: Operator -class BinaryExpression(BaseModel): +class IBinaryExpression(BaseModel): model_config = ConfigDict( extra="forbid", ) - left: Operand - operator: BinaryOperator - right: Operand + left: Expression + operator: Operator + right: Expression -class LogicalExpression(BaseModel): +class IManyExpression(BaseModel): model_config = ConfigDict( extra="forbid", ) expressions: List[Expression] - operator: LogicalOperator + operator: Operator -class Expression( - RootModel[Union[UnaryExpression, BinaryExpression, LogicalExpression]] -): - root: Union[UnaryExpression, BinaryExpression, LogicalExpression] = Field( - ..., - description='Represents a complex expression that can evaluate to true, false, or noop. Examples: 1. Join expression (combining expressions from different models): { "model": "user", "expression": { "operator": "equals", "left": { "path": "age" }, "right": 18 } }\n\n2. Logical expression (AND): { "operator": "and", "expressions": [ { "operator": "equals", "left": { "path": "country" }, "right": "US" }, { "operator": "greater_than", "left": { "path": "age" }, "right": 18 } ] }\n\n3. Location expression: { "operator": "within", "left": { "location": { "latitude": 37.7749, "longitude": -122.4194, "distance": { "value": 10, "unit": "miles" } } }, "right": { "model": "user", "path": "location" } }', +class IUnaryExpression(BaseModel): + model_config = ConfigDict( + extra="forbid", ) + operand: Expression + operator: Operator -class LocationExpression2(BaseModel): +class LogicalBoolExpression(BaseModel): model_config = ConfigDict( extra="forbid", ) - expressions: List[LocationExpression] - operator: LogicalOperator + left: BoolExpression + operator: LogicalBoolOperator + right: BoolExpression -class LocationExpression( - RootModel[Union[Location, LocationExpression1, LocationExpression2]] -): - root: Union[Location, LocationExpression1, LocationExpression2] = Field( - ..., - description='Represents an expression that evaluates to a location or location-based condition. Examples: 1. Simple location: { latitude: 40.7128, longitude: -74.0060, distance: { value: 5, unit: "miles" } }\n\n2. Location with operator: { operator: "within", operand: { latitude: 40.7128, longitude: -74.0060, distance: { value: 5, unit: "miles" } } }\n\n3. Logical combination of locations: { operator: "or", expressions: [ { latitude: 40.7128, longitude: -74.0060, distance: { value: 5, unit: "miles" } }, { operator: "within", operand: { latitude: 34.0522, longitude: -118.2437, distance: { value: 10, unit: "miles" } } } ] }', +class LogicalManyBoolExpression(BaseModel): + model_config = ConfigDict( + extra="forbid", ) + expressions: List[BoolExpression] + operator: LogicalBoolOperator + +class ManyBoolExpression(RootModel["LogicalManyBoolExpression"]): + root: LogicalManyBoolExpression = Field(..., title="ManyBoolExpression") -class ModelAggregationOperand(BaseModel): + +class NumberBoolExpression(BaseModel): model_config = ConfigDict( extra="forbid", ) - condition: Optional[Expression] = None - group_by_model: str - operand: Operand - operator: AggregationOperator + left: NumberExpression + operator: NumberBoolOperator + right: NumberExpression -class Operand( +class NumberExpression( RootModel[ - Union[ - bool, - float, - str, - DateOperand, - ModelPath, - ModelOperand, - AudienceOperand, - ModelAggregationOperand, - ] + "ValueNumberExpression | BinaryNumberExpression | AggregateNumberExpression" ] ): - root: Union[ - bool, - float, - str, - DateOperand, - ModelPath, - ModelOperand, - AudienceOperand, - ModelAggregationOperand, - ] = Field( - ..., - description='Represents a value that can be used in expressions, including primitive values, paths, and arithmetic operations. Examples: 1. Primitive values: true 42 "hello"\n\n2. Path reference: { path: "user.age" }\n\n3. Arithmetic operation: { operator: "plus", left: { path: "price" }, right: { path: "tax" } }\n\n4. Nested arithmetic operation: { operator: "multiply", left: { operator: "plus", left: { path: "base_price" }, right: { path: "shipping" } }, right: 1.1 }\n\n5. Date operand: { date: { absolute: "2023-01-01T00:00:00Z" } }', - ) - - -class UnaryPathExpression(BaseModel): - model_config = ConfigDict( - extra="forbid", + root: ValueNumberExpression | BinaryNumberExpression | AggregateNumberExpression = ( + Field( + ..., + description="Represents an expression that evaluates to a number.", + title="NumberExpression", + ) ) - expression: PathExpression - operator: UnaryOperator -class BinaryPathExpression(BaseModel): +class UnaryBoolExpression(BaseModel): model_config = ConfigDict( extra="forbid", ) - operand: Operand - operator: BinaryOperator - - -class PathExpression( - RootModel[Union[bool, float, str, UnaryPathExpression, BinaryPathExpression]] -): - root: Union[bool, float, str, UnaryPathExpression, BinaryPathExpression] = Field( - ..., - description='Represents an expression that evaluates to a path or value. Examples: 1. Primitive values: true 42 "hello"\n\n2. Unary expression (NOT): { operator: "not", expression: { operator: "equals", operand: { path: "status" } } }\n\n3. Binary expression (comparing a path to a value): { operator: "equals", operand: { path: "user.age" } }', - ) + operand: Expression + operator: UnaryBoolOperator +AggregateNumberExpression.model_rebuild() AudienceDefinition.model_rebuild() -CountExpression1.model_rebuild() -CountExpression2.model_rebuild() -DateExpression2.model_rebuild() -UnaryExpression.model_rebuild() -BinaryExpression.model_rebuild() -LogicalExpression.model_rebuild() -LocationExpression2.model_rebuild() -ModelAggregationOperand.model_rebuild() -UnaryPathExpression.model_rebuild() +BinaryBoolExpression.model_rebuild() +BinaryNumberExpression.model_rebuild() +BoolExpression.model_rebuild() +Expression.model_rebuild() +NumberBoolExpression.model_rebuild() diff --git a/sdk/python/pyproject.toml b/sdk/python/pyproject.toml index ed71aba..43747bc 100644 --- a/sdk/python/pyproject.toml +++ b/sdk/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "mp_audience_sdk" -version = "0.2.7" +version = "0.3.0" description = "mParticle Audience SDK" readme = "README.md" requires-python = ">=3.11" diff --git a/sdk/python/tests/test_audience_models.py b/sdk/python/tests/test_audience_models.py index a16e377..551adf3 100644 --- a/sdk/python/tests/test_audience_models.py +++ b/sdk/python/tests/test_audience_models.py @@ -1,22 +1,22 @@ -# type: ignore import json from mp_audience_sdk.models.audience_models import ( AbsoluteDate, - AbsoluteDateOperand, - AggregationOperator, + AggregateNumberExpression, + AggregationNumberOperator, AudienceDefinition, - BinaryExpression, - BinaryOperator, + DateBoolExpression, DateUnit, - LogicalExpression, - LogicalOperator, - ModelAggregationOperand, + LogicalBoolOperator, + LogicalManyBoolExpression, ModelPath, + NumberBoolExpression, + NumberBoolOperator, Relative, RelativeDate, - RelativeDateOperand, - Version, + ValueDateExpression, + StringBoolExpression, + StringBoolOperator, ) @@ -39,12 +39,12 @@ def test_user_query(): deserialized_obj = AudienceDefinition.model_validate(json_dict) audience_defintion = AudienceDefinition( - audience=BinaryExpression( - operator=BinaryOperator.greater_than_equal, + audience=NumberBoolExpression( + operator=NumberBoolOperator.greater_than_equal, left=ModelPath(model="user", path="product_id"), right=3, ), - schema_version=Version("1.0"), + schema_version="1.0", ) assert audience_defintion == deserialized_obj @@ -143,57 +143,63 @@ def test_user_query_with_single_model(): "schema_version": "1.0" } """ - deserialized_obj = AudienceDefinition.model_validate(json.loads(audience_definition_json)) + deserialized_obj = AudienceDefinition.model_validate( + json.loads(audience_definition_json) + ) - color_or_expr = LogicalExpression( - operator=LogicalOperator.or_, + color_or_expr = LogicalManyBoolExpression( + operator=LogicalBoolOperator.or_, expressions=[ - BinaryExpression( - operator=BinaryOperator.equals, + StringBoolExpression( + operator=StringBoolOperator.equals, left=ModelPath(model="user", path="color"), right="blue", ), - BinaryExpression( - operator=BinaryOperator.equals, + StringBoolExpression( + operator=StringBoolOperator.equals, left=ModelPath(model="user", path="color"), right="yellow", ), - BinaryExpression( - operator=BinaryOperator.equals, left=ModelPath(model="user", path="color"), right="green" + StringBoolExpression( + operator=StringBoolOperator.equals, + left=ModelPath(model="user", path="color"), + right="green", ), ], ) - age_between_expr = LogicalExpression( - operator=LogicalOperator.and_, + age_between_expr = LogicalManyBoolExpression( + operator=LogicalBoolOperator.and_, expressions=[ - BinaryExpression( - operator=BinaryOperator.greater_than_equal, + NumberBoolExpression( + operator=NumberBoolOperator.greater_than_equal, left=ModelPath(model="user", path="age"), right=20.0, ), - BinaryExpression( - operator=BinaryOperator.less_than_equal, + NumberBoolExpression( + operator=NumberBoolOperator.less_than_equal, left=ModelPath(model="user", path="age"), right=40.0, ), ], ) - absolute_date_expr = BinaryExpression( - operator=BinaryOperator.equals, + absolute_date_expr = DateBoolExpression( + operator=NumberBoolOperator.equals, left=ModelPath(model="user", path="registration_date"), - right=AbsoluteDateOperand(date=AbsoluteDate(absolute="2024-01-15T00:00:00Z")), + right=ValueDateExpression(date=AbsoluteDate(absolute="2024-01-15T00:00:00Z")), ) - relative_date_expr = BinaryExpression( - operator=BinaryOperator.greater_than_equal, + relative_date_expr = DateBoolExpression( + operator=NumberBoolOperator.greater_than_equal, left=ModelPath(model="user", path="last_seen_date"), - right=RelativeDateOperand(date=RelativeDate(relative=Relative(offset=-30, unit=DateUnit.day))), + right=ValueDateExpression( + date=RelativeDate(relative=Relative(offset=-30, unit=DateUnit.day)) + ), ) - user_query = LogicalExpression( - operator=LogicalOperator.and_, + user_query = LogicalManyBoolExpression( + operator=LogicalBoolOperator.and_, expressions=[ color_or_expr, age_between_expr, @@ -203,11 +209,11 @@ def test_user_query_with_single_model(): ) audience_defintion = AudienceDefinition( - audience=LogicalExpression( - operator=LogicalOperator.and_, + audience=LogicalManyBoolExpression( + operator=LogicalBoolOperator.and_, expressions=[user_query], ), - schema_version=Version("1.0"), + schema_version="1.0", ) assert deserialized_obj == audience_defintion @@ -240,20 +246,26 @@ def test_user_query_with_aggregate(): } """ - deserialized_obj = AudienceDefinition.model_validate(json.loads(audience_definition_json)) + deserialized_obj = AudienceDefinition.model_validate( + json.loads(audience_definition_json) + ) - aggregate_expr = ModelAggregationOperand( - operator=AggregationOperator.min, + aggregate_expr = AggregateNumberExpression( + operator=AggregationNumberOperator.min, group_by_model="user", operand=ModelPath(model="order", path="total"), - condition=BinaryExpression( - left=ModelPath(model="order", path="item_count"), operator=BinaryOperator.greater_than, right=2 + condition=NumberBoolExpression( + left=ModelPath(model="order", path="item_count"), + operator=NumberBoolOperator.greater_than, + right=2, ), ) audience_defintion = AudienceDefinition( - audience=BinaryExpression(operator=BinaryOperator.greater_than_equal, left=aggregate_expr, right=100), - schema_version=Version("1.0"), + audience=NumberBoolExpression( + operator=NumberBoolOperator.greater_than_equal, left=aggregate_expr, right=100 + ), + schema_version="1.0", ) assert deserialized_obj == audience_defintion diff --git a/sdk/typescript-schema/audience.ts b/sdk/typescript-schema/audience.ts index 2904f94..dbec840 100644 --- a/sdk/typescript-schema/audience.ts +++ b/sdk/typescript-schema/audience.ts @@ -1,5 +1,5 @@ import { Version } from "./common/version"; -import { Expression } from "./expression/expression"; +import { BoolExpression } from "./expression/boolean-expression"; /** * Represents a logical combination of audience expressions using AND/OR operators. @@ -45,7 +45,8 @@ import { Expression } from "./expression/expression"; */ /** - * Represents a complete audience definition with a root logical expression. + * @title AudienceDefinition + * @description Represents a complete audience definition with a root logical expression. * Examples: * 1. Simple audience: * { @@ -79,5 +80,8 @@ import { Expression } from "./expression/expression"; */ export type Audience = { schema_version: Version, - audience: Expression -} \ No newline at end of file + /** + * @title Audience + */ + audience: BoolExpression +} diff --git a/sdk/typescript-schema/common/guards.spec.ts b/sdk/typescript-schema/common/guards.spec.ts index c6ea803..79004e3 100644 --- a/sdk/typescript-schema/common/guards.spec.ts +++ b/sdk/typescript-schema/common/guards.spec.ts @@ -1,6 +1,6 @@ import { isValidAudienceObject } from './guards'; import { Audience } from '../audience'; -import { UnaryOperator } from './operator'; +import { UnaryBoolOperator } from './operator'; describe('Guard Functions', () => { describe('isValidAudienceObject', () => { @@ -9,7 +9,7 @@ describe('Guard Functions', () => { const validAudience: Audience = { schema_version: '1.0.0', audience: { - operator: UnaryOperator.Exists, + operator: UnaryBoolOperator.Exists, operand: { model: 'user', path: 'id' } } }; @@ -37,7 +37,7 @@ describe('Guard Functions', () => { operator: 'and', expressions: [ { - operator: UnaryOperator.Exists, + operator: UnaryBoolOperator.Exists, operand: { model: 'user', path: 'id' } }, { @@ -82,7 +82,7 @@ describe('Guard Functions', () => { operator: 'and', expressions: [ { - operator: UnaryOperator.Exists, + operator: UnaryBoolOperator.Exists, operand: { model: 'user', path: 'id' } }, { @@ -111,7 +111,7 @@ describe('Guard Functions', () => { const validAudience: Audience = { schema_version: '1.0.0-beta.1', audience: { - operator: UnaryOperator.Exists, + operator: UnaryBoolOperator.Exists, operand: { model: 'user', path: 'id' } } }; diff --git a/sdk/typescript-schema/common/operator.ts b/sdk/typescript-schema/common/operator.ts index f5c299f..5232c20 100644 --- a/sdk/typescript-schema/common/operator.ts +++ b/sdk/typescript-schema/common/operator.ts @@ -4,7 +4,7 @@ * - "not": Negates a boolean expression * - "exist": Checks if a value exists */ -export enum UnaryOperator { +export enum UnaryBoolOperator { Null = "null", NotNull = "not_null", Exists = "exists", @@ -19,13 +19,17 @@ export enum UnaryOperator { * - "matches": { value1: "pattern", value2: "text" } * - "contains": { value1: "string", value2: "substring" } */ -export type BinaryOperator = +export type NumberBoolOperator = "equals" | "not_equals" | "less_than" | "less_than_equal" | "greater_than" | "greater_than_equal" + +export type StringBoolOperator = + "equals" + | "not_equals" | "matches" | "contains" | "not_contains" @@ -44,7 +48,7 @@ export type BinaryOperator = * - "match_any": { list: ["a", "b"], value: "a" } * - "in": { list: [1, 2, 3], value: 2 } */ -export type ListOperator = +export type ListBoolOperator = "contains" | "between" | "match_any" @@ -68,7 +72,7 @@ export type AudienceOperator = * - "multiply": { value1: 4, value2: 2 } // result: 8 * - "mod": { value1: 10, value2: 3 } // result: 1 */ -export type ArithmeticOperator = +export type BinaryNumberOperator = "plus" | "minus" | "multiply" @@ -83,7 +87,7 @@ export type ArithmeticOperator = * - "avg": [1, 2, 3] // result: 2 * - "count": [1, 2, 3] // result: 3 */ -export type AggregationOperator = +export type AggregationNumberOperator = "min" | "max" | "sum" @@ -97,7 +101,7 @@ export type AggregationOperator = * - "within": { location1: { lat: 40, lng: -74 }, location2: { lat: 40, lng: -74 }, radius: 5 } * - "equals": { location1: { lat: 40, lng: -74 }, location2: { lat: 40, lng: -74 } } */ -export type LocationOperator = +export type LocationBoolOperator = "within" | "equals" @@ -107,6 +111,8 @@ export type LocationOperator = * - "and": { condition1: true, condition2: true } // result: true * - "or": { condition1: true, condition2: false } // result: true */ -export type LogicalOperator = +export type LogicalBoolOperator = "and" | "or" + +export type Operator = LogicalBoolOperator | LocationBoolOperator | AggregationNumberOperator | BinaryNumberOperator | AudienceOperator | ListBoolOperator | StringBoolOperator | NumberBoolOperator | UnaryBoolOperator diff --git a/sdk/typescript-schema/expression/audience-expression.ts b/sdk/typescript-schema/expression/audience-expression.ts deleted file mode 100644 index eadf521..0000000 --- a/sdk/typescript-schema/expression/audience-expression.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { AudienceOperand } from "../operand/audience-operand"; -import { ModelOperand } from "../operand/model-operand"; -import { AudienceOperator } from "../common/operator"; - - -/** - * Represents an expression that operates on an audience and returns a boolean. - * Example: - * { - * operator: "in", - * expression: { operator: "in", left: { model: "user" }, right": { audience: 12345 } } - * } - */ -export type AudienceExpression = - { operator: AudienceOperator, left: ModelOperand, right: AudienceOperand } diff --git a/sdk/typescript-schema/expression/boolean-expression.ts b/sdk/typescript-schema/expression/boolean-expression.ts new file mode 100644 index 0000000..0ddacc2 --- /dev/null +++ b/sdk/typescript-schema/expression/boolean-expression.ts @@ -0,0 +1,111 @@ +import { AudienceOperator as AudienceBoolOperator, LocationBoolOperator, LogicalBoolOperator, NumberBoolOperator, StringBoolOperator, UnaryBoolOperator } from "../common/operator"; +import { AudienceReference } from "../literal/audience"; +import { ModelPath, ModelReference } from "../literal/model-path"; +import { DateExpression } from "./date-expression"; +import { Expression } from "./expression"; +import { IBinaryExpression, IManyExpression, IUnaryExpression } from "./expression-interfaces"; +import { LocationExpression } from "./location-expression"; +import { NumberExpression } from "./number-expression"; +import { StringExpression } from "./string-expression"; + +/** + * @title ValueBoolExpression + */ +export type ValueBoolExpression = boolean | ModelPath + +/** + * @title UnaryBoolExpression + */ +export class UnaryBoolExpression implements IUnaryExpression { + operator: UnaryBoolOperator + operand: Expression + +} + +/** + * @title NumberBoolExpression + */ +export class NumberBoolExpression implements IBinaryExpression { + operator: NumberBoolOperator + left: NumberExpression + right: NumberExpression + +} + +/** + * @title StringBoolExpression + */ +export class StringBoolExpression implements IBinaryExpression { + operator: StringBoolOperator + left: StringExpression + right: StringExpression + +} + +/** + * @title DateBoolExpression + */ +export class DateBoolExpression implements IBinaryExpression { + operator: NumberBoolOperator + left: DateExpression + right: DateExpression + +} + +/** + * @title LogicalBoolExpression + */ +export class LogicalBoolExpression implements IBinaryExpression { + operator: LogicalBoolOperator + left: BoolExpression + right: BoolExpression + +} + +/** + * @title LocationBoolExpression + */ +export class LocationBoolExpression implements IBinaryExpression { + operator: LocationBoolOperator + left: LocationExpression + right: LocationExpression + +} + +/** +* @title AudienceBoolExpression + */ +export class AudienceBoolExpression implements IBinaryExpression { + operator: AudienceBoolOperator + left: ModelReference + right: AudienceReference + +} + +/** + * @title BoolBinaryExpression + */ +export type BinaryBoolExpression = AudienceBoolExpression | LocationBoolExpression | LocationBoolExpression | DateBoolExpression | StringBoolExpression | NumberBoolExpression; + +/** + * @title LogicalManyBoolExpression + */ +export class LogicalManyBoolExpression implements IManyExpression { + operator: LogicalBoolOperator + expressions: BoolExpression[] + +} + +/** + * @title ManyBoolExpression + */ +export type ManyBoolExpression = LogicalManyBoolExpression + +/** + * @title BoolExpression + */ +export type BoolExpression = + ValueBoolExpression + | UnaryBoolExpression + | BinaryBoolExpression + | ManyBoolExpression diff --git a/sdk/typescript-schema/expression/count-expression.ts b/sdk/typescript-schema/expression/count-expression.ts deleted file mode 100644 index 13345b9..0000000 --- a/sdk/typescript-schema/expression/count-expression.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Operand } from "../operand/operand"; -import { BinaryOperator, LogicalOperator } from "../common/operator"; - -/** - * Represents a count expression, which can be a number, a binary operation, or a logical group. - * Examples: - * 1. Simple count: - * 5 - * - * 2. Binary count expression: - * { operator: "greater_than", operand: { path: "event.count" } } - * - * 3. Logical group of count expressions: - * { - * operator: "and", - * expressions: [ - * 1, - * { operator: "greater_than", operand: { path: "event.count" } } - * ] - * } - */ -export type CountExpression = - number - | - { operator: BinaryOperator, operand: Operand } - | // logical expression group - { operator: LogicalOperator, expressions: CountExpression[] } \ No newline at end of file diff --git a/sdk/typescript-schema/expression/date-expression.ts b/sdk/typescript-schema/expression/date-expression.ts index b946032..29ef3aa 100644 --- a/sdk/typescript-schema/expression/date-expression.ts +++ b/sdk/typescript-schema/expression/date-expression.ts @@ -1,31 +1,14 @@ -import { BinaryOperator, LogicalOperator } from "../common/operator"; -import { AbsoluteDate, RelativeDate } from "../operand/date-operand"; +import { DateLiteral } from "../literal/date"; +import { ModelPath } from "../literal/model-path"; /** - * Represents an expression that evaluates to a date or date-based condition. - * Examples: - * 1. Absolute date: - * { absolute: "2023-01-01T00:00:00Z" } - * - * 2. Relative date: - * { relative: { offset: -30, unit: "day" } } - * - * 3. Date with binary operator: - * { operator: "greater_than", operand: { absolute: "2023-01-01T00:00:00Z" } } - * - * 4. Logical combination of dates: - * { - * operator: "and", - * expressions: [ - * { absolute: "2023-01-01T00:00:00Z" }, - * { operator: "less_than", operand: { relative: { offset: 0, unit: "month", boundary: "end" } } } - * ] - * } + * @title ValueDateExpression + */ +export type ValueDateExpression = { date: DateLiteral } | ModelPath + +/** + * @title DateExpression + * @description Represents an expression that evaluates to a date */ export type DateExpression = - AbsoluteDate - | RelativeDate - | - { operator: BinaryOperator, operand: AbsoluteDate | RelativeDate } - | // logical expression group - { operator: LogicalOperator, expressions: DateExpression[] } \ No newline at end of file + ValueDateExpression diff --git a/sdk/typescript-schema/expression/expression-interfaces.ts b/sdk/typescript-schema/expression/expression-interfaces.ts new file mode 100644 index 0000000..caeb006 --- /dev/null +++ b/sdk/typescript-schema/expression/expression-interfaces.ts @@ -0,0 +1,25 @@ +import { Operator } from "../common/operator" +import { Expression } from "./expression" + +interface IExpression { + operator: Operator +} + +export interface IUnaryExpression extends IExpression { + operand: Expression +} + +export interface IBinaryExpression extends IExpression { + left: Expression + right: Expression +} + +export interface IManyExpression extends IExpression { + expressions: Expression[] +} + +export interface IAggregateExpression extends IExpression { + condition?: Expression + operand: Expression + group_by_model: string +} diff --git a/sdk/typescript-schema/expression/expression.ts b/sdk/typescript-schema/expression/expression.ts index 5752742..cf851a6 100644 --- a/sdk/typescript-schema/expression/expression.ts +++ b/sdk/typescript-schema/expression/expression.ts @@ -1,39 +1,56 @@ -import { Operand } from "../operand/operand"; -import { BinaryOperator, LogicalOperator, UnaryOperator } from "../common/operator"; +import { BoolExpression, ValueBoolExpression } from "./boolean-expression"; +import { DateExpression, ValueDateExpression } from "./date-expression"; +import { NumberExpression, ValueNumberExpression } from "./number-expression"; +import { LocationExpression, ValueLocationExpression } from "./location-expression"; +import { StringExpression, ValueStringExpression } from "./string-expression"; +import { IAggregateExpression, IBinaryExpression, IManyExpression, IUnaryExpression } from "./expression-interfaces"; +import { Literal } from "../literal/literal"; /** - * Represents a complex expression that can evaluate to true, false, or noop. - * Examples: - * 1. Join expression (combining expressions from different models): - * { - * "model": "user", - * "expression": { - * "operator": "equals", - * "left": { "path": "age" }, - * "right": 18 - * } - * } - * - * 2. Logical expression (AND): - * { - * "operator": "and", - * "expressions": [ - * { "operator": "equals", "left": { "path": "country" }, "right": "US" }, - * { "operator": "greater_than", "left": { "path": "age" }, "right": 18 } - * ] - * } - * - * 3. Location expression: - * { - * "operator": "within", - * "left": { "location": { "latitude": 37.7749, "longitude": -122.4194, "distance": { "value": 10, "unit": "miles" } } }, - * "right": { "model": "user", "path": "location" } - * } + * @title ValueExpression + */ +export type ValueExpression = + ValueBoolExpression + | ValueDateExpression + | ValueLocationExpression + | ValueNumberExpression + | ValueStringExpression + +/** +// * @title UnaryExpression +// */ +// export type UnaryExpression = UnaryBoolExpression + +// /** +// * @title BinaryExpression +// */ +// export type BinaryExpression = BinaryBoolExpression | BinaryNumberExpression + +// /** +// * @title ManyExpression +// */ +// export type ManyExpression = ManyBoolExpression + + + +// /** +// * @title AggregateExpression +// */ +// export type AggregateExpression = AggregateNumberExpression + +/** + * @title Expression + * @description Represents an expression that accepts a variety of arguments and evaluates to a value. */ export type Expression = - // unary expression - { operator: UnaryOperator, operand: Operand } - | // binary expression - { operator: BinaryOperator, left: Operand, right: Operand } - | // logical expression group - { operator: LogicalOperator, expressions: Expression[] } + ValueExpression + | IUnaryExpression + | IBinaryExpression + | IManyExpression + | IAggregateExpression + | BoolExpression + | NumberExpression + | StringExpression + | LocationExpression + | DateExpression + | Literal diff --git a/sdk/typescript-schema/expression/location-expression.ts b/sdk/typescript-schema/expression/location-expression.ts index 8f413f6..4b82a99 100644 --- a/sdk/typescript-schema/expression/location-expression.ts +++ b/sdk/typescript-schema/expression/location-expression.ts @@ -1,27 +1,14 @@ -import { Location } from "../common/location"; -import { LocationOperator, LogicalOperator } from "../common/operator"; +import { Location } from "../literal/location"; +import { ModelPath } from "../literal/model-path"; /** - * Represents an expression that evaluates to a location or location-based condition. - * Examples: - * 1. Simple location: - * { latitude: 40.7128, longitude: -74.0060, distance: { value: 5, unit: "miles" } } - * - * 2. Location with operator: - * { operator: "within", operand: { latitude: 40.7128, longitude: -74.0060, distance: { value: 5, unit: "miles" } } } - * - * 3. Logical combination of locations: - * { - * operator: "or", - * expressions: [ - * { latitude: 40.7128, longitude: -74.0060, distance: { value: 5, unit: "miles" } }, - * { operator: "within", operand: { latitude: 34.0522, longitude: -118.2437, distance: { value: 10, unit: "miles" } } } - * ] - * } + * @title ValueLocationExpression */ -export type LocationExpression = - Location - | // location (left) expression - { operator: LocationOperator, operand: Location } - | // logical expression group - { operator: LogicalOperator, expressions: LocationExpression[] } \ No newline at end of file +export type ValueLocationExpression = Location + | ModelPath + +/** + * @title LocationExpression + * @description Represents an expression that evaluates to a location or location-based condition. + */ +export type LocationExpression = ValueLocationExpression diff --git a/sdk/typescript-schema/expression/number-expression.ts b/sdk/typescript-schema/expression/number-expression.ts new file mode 100644 index 0000000..f565c1b --- /dev/null +++ b/sdk/typescript-schema/expression/number-expression.ts @@ -0,0 +1,37 @@ +import { AggregationNumberOperator, BinaryNumberOperator } from "../common/operator"; +import { BoolExpression } from "./boolean-expression"; +import { ModelPath } from "../literal/model-path"; +import { IAggregateExpression, IBinaryExpression } from "./expression-interfaces"; + +/** + * @title ValueNumberExpression + */ +export type ValueNumberExpression = number | ModelPath + +/** + * @title BinaryNumberExpression + */ +export class BinaryNumberExpression implements IBinaryExpression { + operator: BinaryNumberOperator; + left: NumberExpression; + right: NumberExpression +} + +/** + * @title AggregateNumberExpression + */ +export class AggregateNumberExpression implements IAggregateExpression { + operator: AggregationNumberOperator + group_by_model: string + operand: NumberExpression + condition?: BoolExpression +} + +/** + * @title NumberExpression + * @description Represents an expression that evaluates to a number. + */ +export type NumberExpression = + ValueNumberExpression + | BinaryNumberExpression + | AggregateNumberExpression diff --git a/sdk/typescript-schema/expression/path-expression.ts b/sdk/typescript-schema/expression/path-expression.ts deleted file mode 100644 index 8d72ad5..0000000 --- a/sdk/typescript-schema/expression/path-expression.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Operand } from "../operand/operand"; -import { UnaryOperator, BinaryOperator } from "../common/operator"; - -/** - * Represents an expression that evaluates to a path or value. - * Examples: - * 1. Primitive values: - * true - * 42 - * "hello" - * - * 2. Unary expression (NOT): - * { - * operator: "not", - * expression: { operator: "equals", operand: { path: "status" } } - * } - * - * 3. Binary expression (comparing a path to a value): - * { - * operator: "equals", - * operand: { path: "user.age" } - * } - */ -export type PathExpression = - boolean - | number - | string - | // unary expression - { operator: UnaryOperator, expression: PathExpression } - | // binary expression - { operator: BinaryOperator, operand: Operand }; \ No newline at end of file diff --git a/sdk/typescript-schema/expression/string-expression.ts b/sdk/typescript-schema/expression/string-expression.ts new file mode 100644 index 0000000..80e3f45 --- /dev/null +++ b/sdk/typescript-schema/expression/string-expression.ts @@ -0,0 +1,11 @@ +import { ModelPath } from "../literal/model-path"; + +/** + * @title ValueStringExpression + */ +export type ValueStringExpression = string | ModelPath + +/** + * @title StringExpression + */ +export type StringExpression = ValueStringExpression diff --git a/sdk/typescript-schema/index.ts b/sdk/typescript-schema/index.ts index dd6e5d2..ca334ca 100644 --- a/sdk/typescript-schema/index.ts +++ b/sdk/typescript-schema/index.ts @@ -6,20 +6,21 @@ export * from './audience'; // Export expression types export * from './expression/expression'; -export * from './expression/count-expression'; +export * from './expression/number-expression'; export * from './expression/date-expression'; export * from './expression/location-expression'; -export * from './expression/path-expression'; +export * from './expression/string-expression'; +export * from './expression/boolean-expression'; -// Export operand types -export * from './operand/operand'; -export * from './operand/location-operand'; -export * from './operand/date-operand'; +// Export literal types +export * from './literal/literal'; +export * from './literal/location'; +export * from './literal/date'; +export * from './literal/model-path'; // Export common types -export * from './common/location'; export * from './common/operator'; export * from './common/version'; // Export type guards -export * from './common/guards'; \ No newline at end of file +export * from './common/guards'; diff --git a/sdk/typescript-schema/literal/audience.ts b/sdk/typescript-schema/literal/audience.ts new file mode 100644 index 0000000..7097a81 --- /dev/null +++ b/sdk/typescript-schema/literal/audience.ts @@ -0,0 +1,9 @@ +/** + * @title AudienceReference + * @description Represents an audience. Audience is identified by a string ID. + * Example: + * { "audience": "12345" } + */ +export type AudienceReference = { + audience: string +} diff --git a/sdk/typescript-schema/operand/date-operand.ts b/sdk/typescript-schema/literal/date.ts similarity index 63% rename from sdk/typescript-schema/operand/date-operand.ts rename to sdk/typescript-schema/literal/date.ts index f07f27f..45c089d 100644 --- a/sdk/typescript-schema/operand/date-operand.ts +++ b/sdk/typescript-schema/literal/date.ts @@ -1,5 +1,6 @@ /** - * Represents units of time that can be used in relative date calculations. + * @title DateUnit + * @description Represents units of time that can be used in relative date calculations. * Examples: * - 'second': 1 second * - 'minute': 60 seconds @@ -21,7 +22,8 @@ export type DateUnit = | 'year'; /** - * Represents an absolute date/time value. + * @title AbsoluteDate + * @description Represents an absolute date/time value. * Examples: * 1. ISO 8601 date: * { absolute: "2023-01-01T00:00:00Z" } @@ -38,7 +40,8 @@ export type AbsoluteDate = }; /** - * Represents a date/time relative to the current time. + * @title RelativeDate + * @description Represents a date/time relative to the current time. * Examples: * 1. 7 days ago: * { relative: { offset: -7, unit: "day" } } @@ -57,19 +60,9 @@ export type RelativeDate = boundary?: "start" | "end" } }; - /** - * Represents a date value that can be either absolute or relative. - * Examples: - * 1. Absolute date: - * { date: { absolute: "2023-01-01T00:00:00Z" } } - * - * 2. Relative date (30 days ago): - * { date: { relative: { offset: -30, unit: "day" } } } - * - * 3. Relative date (start of current month): - * { date: { relative: { offset: 0, unit: "month", boundary: "start" } } } + * @title DateLiteral */ -export type DateOperand = - { date: AbsoluteDate } - | { date: RelativeDate } \ No newline at end of file +export type DateLiteral = + AbsoluteDate + | RelativeDate diff --git a/sdk/typescript-schema/literal/literal.ts b/sdk/typescript-schema/literal/literal.ts new file mode 100644 index 0000000..b493e26 --- /dev/null +++ b/sdk/typescript-schema/literal/literal.ts @@ -0,0 +1,43 @@ +import { DateLiteral } from "./date"; +import { ModelPath, ModelReference } from "./model-path"; +import { Location } from "./location"; +import { AudienceReference } from "./audience"; + +/** + * @title Literal + * @description Represents a value that can be used in expressions, including primitive values, paths, and arithmetic operations. + * Examples: + * 1. Primitive values: + * true + * 42 + * "hello" + * + * 2. Path reference: + * { path: "user.age" } + * + * 3. Arithmetic operation: + * { + * operator: "plus", + * left: { path: "price" }, + * right: { path: "tax" } + * } + * + * 4. Nested arithmetic operation: + * { + * operator: "multiply", + * left: { operator: "plus", left: { path: "base_price" }, right: { path: "shipping" } }, + * right: 1.1 + * } + * + * 5. Date operand: + * { date: { absolute: "2023-01-01T00:00:00Z" } } + */ +export type Literal = + boolean + | number + | string + | DateLiteral + | ModelPath + | Location + | ModelReference + | AudienceReference diff --git a/sdk/typescript-schema/common/location.ts b/sdk/typescript-schema/literal/location.ts similarity index 81% rename from sdk/typescript-schema/common/location.ts rename to sdk/typescript-schema/literal/location.ts index 6b78117..56eb242 100644 --- a/sdk/typescript-schema/common/location.ts +++ b/sdk/typescript-schema/literal/location.ts @@ -1,10 +1,14 @@ +/** + * @title DistanceUnit + */ export type DistanceUnit = "meters" | "miles" | "kilometers"; /** - * Represents a geographic location, optionally with a distance constraint. + * @title Location + * @description Represents a geographic location, optionally with a distance constraint. * Examples: * 1. Simple location: * { "latitude": 37.7749, "longitude": -122.4194 } @@ -22,4 +26,4 @@ export type Location = { value: number, unit: DistanceUnit } -} \ No newline at end of file +} diff --git a/sdk/typescript-schema/common/model-path.ts b/sdk/typescript-schema/literal/model-path.ts similarity index 58% rename from sdk/typescript-schema/common/model-path.ts rename to sdk/typescript-schema/literal/model-path.ts index 1cef16c..66eafff 100644 --- a/sdk/typescript-schema/common/model-path.ts +++ b/sdk/typescript-schema/literal/model-path.ts @@ -1,5 +1,6 @@ /** - * Represents a model path reference within a data model. + * @title ModelPath + * @description Represents a model path reference within a data model. * Examples: * 1. Simple model path: * { "model": "user", "path": "email" } @@ -14,3 +15,11 @@ export type ModelPath = { model: string, path: string } + +/** + * @title ModelReference + * @description Represents a model reference within a data model + */ +export type ModelReference = { + model: string +} diff --git a/sdk/typescript-schema/operand/audience-operand.ts b/sdk/typescript-schema/operand/audience-operand.ts deleted file mode 100644 index e234404..0000000 --- a/sdk/typescript-schema/operand/audience-operand.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Represents an audience. Audience is identified by a string ID. - * Example: - * { "audience": "12345" } - */ -export type AudienceOperand = { - audience: string -} diff --git a/sdk/typescript-schema/operand/location-operand.ts b/sdk/typescript-schema/operand/location-operand.ts deleted file mode 100644 index eed5fbe..0000000 --- a/sdk/typescript-schema/operand/location-operand.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Location } from "../common/location"; - -/** - * Represents a location value that can be used in location-based expressions. - * Examples: - * 1. Simple location (latitude/longitude only): - * { location: { latitude: 40.7128, longitude: -74.0060 } } - * - * 2. Location with distance in miles: - * { location: { latitude: 40.7128, longitude: -74.0060, distance: { value: 5, unit: "miles" } } } - * - * 3. Location with distance in meters: - * { location: { latitude: 40.7128, longitude: -74.0060, distance: { value: 1000, unit: "meters" } } } - */ -export type LocationOperand = { - location: Location -} \ No newline at end of file diff --git a/sdk/typescript-schema/operand/model-operand.ts b/sdk/typescript-schema/operand/model-operand.ts deleted file mode 100644 index 6615940..0000000 --- a/sdk/typescript-schema/operand/model-operand.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type ModelOperand = { - model: string -} diff --git a/sdk/typescript-schema/operand/operand.ts b/sdk/typescript-schema/operand/operand.ts deleted file mode 100644 index 6e4810f..0000000 --- a/sdk/typescript-schema/operand/operand.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { DateOperand } from "./date-operand"; -import { ModelPath } from "../common/model-path"; -import { AggregationOperator } from "../common/operator"; -import { Expression } from "../expression/expression"; -import { AudienceOperand } from "./audience-operand"; -import { ModelOperand } from "./model-operand"; - -/** - * Represents a value that can be used in expressions, including primitive values, paths, and arithmetic operations. - * Examples: - * 1. Primitive values: - * true - * 42 - * "hello" - * - * 2. Path reference: - * { path: "user.age" } - * - * 3. Arithmetic operation: - * { - * operator: "plus", - * left: { path: "price" }, - * right: { path: "tax" } - * } - * - * 4. Nested arithmetic operation: - * { - * operator: "multiply", - * left: { operator: "plus", left: { path: "base_price" }, right: { path: "shipping" } }, - * right: 1.1 - * } - * - * 5. Date operand: - * { date: { absolute: "2023-01-01T00:00:00Z" } } - */ -export type Operand = - boolean - | number - | string - | DateOperand - | ModelPath - | ModelOperand - | AudienceOperand - | { operator: AggregationOperator, group_by_model: string, operand: Operand, condition?: Expression }; -// | { operator: ArithmeticOperator, left: Operand, right: Operand }; diff --git a/sdk/typescript-schema/schema/audience-schema.json b/sdk/typescript-schema/schema/audience-schema.json index d424a9c..9f1c58a 100644 --- a/sdk/typescript-schema/schema/audience-schema.json +++ b/sdk/typescript-schema/schema/audience-schema.json @@ -3,7 +3,7 @@ "definitions": { "AbsoluteDate": { "additionalProperties": false, - "description": "Represents an absolute date/time value. Examples: 1. ISO 8601 date: { absolute: \"2023-01-01T00:00:00Z\" }\n\n2. Date only: { absolute: \"2023-01-01\" }\n\n3. Date with timezone: { absolute: \"2023-01-01T00:00:00-05:00\" }", + "description": "Represents an absolute date/time value.\nExamples:\n1. ISO 8601 date:\n{ absolute: \"2023-01-01T00:00:00Z\" }\n\n2. Date only:\n{ absolute: \"2023-01-01\" }\n\n3. Date with timezone:\n{ absolute: \"2023-01-01T00:00:00-05:00\" }", "properties": { "absolute": { "type": "string" @@ -12,9 +12,34 @@ "required": [ "absolute" ], + "title": "AbsoluteDate", "type": "object" }, - "AggregationOperator": { + "AggregateNumberExpression": { + "additionalProperties": false, + "properties": { + "condition": { + "$ref": "#/definitions/BoolExpression" + }, + "group_by_model": { + "type": "string" + }, + "operand": { + "$ref": "#/definitions/NumberExpression" + }, + "operator": { + "$ref": "#/definitions/AggregationNumberOperator" + } + }, + "required": [ + "group_by_model", + "operand", + "operator" + ], + "title": "AggregateNumberExpression", + "type": "object" + }, + "AggregationNumberOperator": { "description": "Represents operators for aggregating multiple values. Examples:\n- \"min\": [1, 2, 3] // result: 1\n- \"max\": [1, 2, 3] // result: 3\n- \"avg\": [1, 2, 3] // result: 2\n- \"count\": [1, 2, 3] // result: 3", "enum": [ "min", @@ -26,23 +51,12 @@ ], "type": "string" }, - "ArithmeticOperator": { - "description": "Represents mathematical operators for numeric calculations. Examples:\n- \"plus\": { value1: 5, value2: 3 } // result: 8\n- \"multiply\": { value1: 4, value2: 2 } // result: 8\n- \"mod\": { value1: 10, value2: 3 } // result: 1", - "enum": [ - "plus", - "minus", - "multiply", - "divide", - "mod" - ], - "type": "string" - }, "Audience": { "additionalProperties": false, - "description": "Represents a complete audience definition with a root logical expression. Examples: 1. Simple audience: { \"schema_version\": \"1.0.0\", \"audience\": { \"operator\": \"and\", \"expressions\": [ { \"model\": \"user\", \"expression\": { \"operator\": \"exists\", \"operand\": { \"path\": \"id\" } } }, { \"model\": \"purchase\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"status\" }, \"right\": \"completed\" } } ] } }\n\n2. Audience with nested logic: { \"schema_version\": \"1.0.0\", \"audience\": { \"operator\": \"or\", \"expressions\": [ { \"model\": \"user\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"country\" }, \"right\": \"US\" } }, { \"operator\": \"and\", \"expressions\": [ { \"model\": \"signup\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"status\" }, \"right\": \"completed\" } }, { \"model\": \"user\", \"expression\": { \"operator\": \"greater_than\", \"left\": { \"path\": \"age\" }, \"right\": 18 } } ] } ] } }", + "description": "Represents a complete audience definition with a root logical expression.\nExamples:\n1. Simple audience:\n{\n\"schema_version\": \"1.0.0\",\n\"audience\": {\n\"operator\": \"and\",\n\"expressions\": [\n{ \"model\": \"user\", \"expression\": { \"operator\": \"exists\", \"operand\": { \"path\": \"id\" } } },\n{ \"model\": \"purchase\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"status\" }, \"right\": \"completed\" } }\n]\n}\n}\n\n2. Audience with nested logic:\n{\n\"schema_version\": \"1.0.0\",\n\"audience\": {\n\"operator\": \"or\",\n\"expressions\": [\n{ \"model\": \"user\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"country\" }, \"right\": \"US\" } },\n{\n\"operator\": \"and\",\n\"expressions\": [\n{ \"model\": \"signup\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"status\" }, \"right\": \"completed\" } },\n{ \"model\": \"user\", \"expression\": { \"operator\": \"greater_than\", \"left\": { \"path\": \"age\" }, \"right\": 18 } }\n]\n}\n]\n}\n}", "properties": { "audience": { - "$ref": "#/definitions/Expression", + "$ref": "#/definitions/BoolExpression", "title": "Audience" }, "schema_version": { @@ -53,20 +67,28 @@ "schema_version", "audience" ], - "type": "object", - "title": "AudienceDefinition" + "title": "AudienceDefinition", + "type": "object" }, - "AudienceOperand": { + "AudienceBoolExpression": { "additionalProperties": false, - "description": "Represents an audience. Audience is identified by a string ID. Example: { \"audience\": \"12345\" }", "properties": { - "audience": { - "type": "string" + "left": { + "$ref": "#/definitions/ModelReference" + }, + "operator": { + "$ref": "#/definitions/AudienceOperator" + }, + "right": { + "$ref": "#/definitions/AudienceReference" } }, "required": [ - "audience" + "left", + "operator", + "right" ], + "title": "AudienceBoolExpression", "type": "object" }, "AudienceOperator": { @@ -77,156 +99,128 @@ ], "type": "string" }, - "BinaryOperator": { - "description": "Represents binary operators that compare two values. Examples:\n- \"equals\": { value1: 5, value2: 5 }\n- \"less_than\": { value1: 3, value2: 5 }\n- \"matches\": { value1: \"pattern\", value2: \"text\" }\n- \"contains\": { value1: \"string\", value2: \"substring\" }", - "enum": [ - "equals", - "not_equals", - "less_than", - "less_than_equal", - "greater_than", - "greater_than_equal", - "matches", - "contains", - "not_contains", - "starts_with", - "not_starts_with", - "ends_with", - "not_ends_with", - "in", - "not_in" + "AudienceReference": { + "additionalProperties": false, + "description": "Represents an audience. Audience is identified by a string ID.\nExample:\n{ \"audience\": \"12345\" }", + "properties": { + "audience": { + "type": "string" + } + }, + "required": [ + "audience" ], - "type": "string" + "title": "AudienceReference", + "type": "object" }, - "CountExpression": { + "BinaryBoolExpression": { "anyOf": [ { - "type": "number" + "$ref": "#/definitions/AudienceBoolExpression" }, { - "additionalProperties": false, - "properties": { - "operand": { - "$ref": "#/definitions/Operand" - }, - "operator": { - "$ref": "#/definitions/BinaryOperator" - } - }, - "required": [ - "operator", - "operand" - ], - "type": "object" + "$ref": "#/definitions/LocationBoolExpression" }, { - "additionalProperties": false, - "properties": { - "expressions": { - "items": { - "$ref": "#/definitions/CountExpression" - }, - "type": "array" - }, - "operator": { - "$ref": "#/definitions/LogicalOperator" - } - }, - "required": [ - "operator", - "expressions" - ], - "type": "object" + "$ref": "#/definitions/DateBoolExpression" + }, + { + "$ref": "#/definitions/StringBoolExpression" + }, + { + "$ref": "#/definitions/NumberBoolExpression" } ], - "description": "Represents a count expression, which can be a number, a binary operation, or a logical group. Examples: 1. Simple count: 5\n\n2. Binary count expression: { operator: \"greater_than\", operand: { path: \"event.count\" } }\n\n3. Logical group of count expressions: { operator: \"and\", expressions: [ 1, { operator: \"greater_than\", operand: { path: \"event.count\" } } ] }" + "title": "BoolBinaryExpression" }, - "DateExpression": { + "BinaryNumberExpression": { + "additionalProperties": false, + "properties": { + "left": { + "$ref": "#/definitions/NumberExpression" + }, + "operator": { + "$ref": "#/definitions/BinaryNumberOperator" + }, + "right": { + "$ref": "#/definitions/NumberExpression" + } + }, + "required": [ + "left", + "operator", + "right" + ], + "title": "BinaryNumberExpression", + "type": "object" + }, + "BinaryNumberOperator": { + "description": "Represents mathematical operators for numeric calculations. Examples:\n- \"plus\": { value1: 5, value2: 3 } // result: 8\n- \"multiply\": { value1: 4, value2: 2 } // result: 8\n- \"mod\": { value1: 10, value2: 3 } // result: 1", + "enum": [ + "plus", + "minus", + "multiply", + "divide", + "mod" + ], + "type": "string" + }, + "BoolExpression": { "anyOf": [ { - "$ref": "#/definitions/AbsoluteDate" + "$ref": "#/definitions/ValueBoolExpression" }, { - "$ref": "#/definitions/RelativeDate" + "$ref": "#/definitions/UnaryBoolExpression" }, { - "additionalProperties": false, - "properties": { - "operand": { - "anyOf": [ - { - "$ref": "#/definitions/AbsoluteDate" - }, - { - "$ref": "#/definitions/RelativeDate" - } - ] - }, - "operator": { - "$ref": "#/definitions/BinaryOperator" - } - }, - "required": [ - "operator", - "operand" - ], - "type": "object" + "$ref": "#/definitions/BinaryBoolExpression" }, { - "additionalProperties": false, - "properties": { - "expressions": { - "items": { - "$ref": "#/definitions/DateExpression" - }, - "type": "array" - }, - "operator": { - "$ref": "#/definitions/LogicalOperator" - } - }, - "required": [ - "operator", - "expressions" - ], - "type": "object" + "$ref": "#/definitions/ManyBoolExpression" } ], - "description": "Represents an expression that evaluates to a date or date-based condition. Examples: 1. Absolute date: { absolute: \"2023-01-01T00:00:00Z\" }\n\n2. Relative date: { relative: { offset: -30, unit: \"day\" } }\n\n3. Date with binary operator: { operator: \"greater_than\", operand: { absolute: \"2023-01-01T00:00:00Z\" } }\n\n4. Logical combination of dates: { operator: \"and\", expressions: [ { absolute: \"2023-01-01T00:00:00Z\" }, { operator: \"less_than\", operand: { relative: { offset: 0, unit: \"month\", boundary: \"end\" } } } ] }" + "title": "BoolExpression" }, - "DateOperand": { + "DateBoolExpression": { + "additionalProperties": false, + "properties": { + "left": { + "$ref": "#/definitions/DateExpression" + }, + "operator": { + "$ref": "#/definitions/NumberBoolOperator" + }, + "right": { + "$ref": "#/definitions/DateExpression" + } + }, + "required": [ + "left", + "operator", + "right" + ], + "title": "DateBoolExpression", + "type": "object" + }, + "DateExpression": { + "$ref": "#/definitions/ValueDateExpression", + "description": "Represents an expression that evaluates to a date", + "title": "DateExpression" + }, + "DateLiteral": { "anyOf": [ { - "additionalProperties": false, - "properties": { - "date": { - "$ref": "#/definitions/AbsoluteDate" - } - }, - "required": [ - "date" - ], - "type": "object", - "title": "AbsoluteDateOperand" + "$ref": "#/definitions/AbsoluteDate" }, { - "additionalProperties": false, - "properties": { - "date": { - "$ref": "#/definitions/RelativeDate" - } - }, - "required": [ - "date" - ], - "type": "object", - "title": "RelativeDateOperand" + "$ref": "#/definitions/RelativeDate" } ], - "description": "Represents a date value that can be either absolute or relative. Examples: 1. Absolute date: { date: { absolute: \"2023-01-01T00:00:00Z\" } }\n\n2. Relative date (30 days ago): { date: { relative: { offset: -30, unit: \"day\" } } }\n\n3. Relative date (start of current month): { date: { relative: { offset: 0, unit: \"month\", boundary: \"start\" } } }" + "title": "DateLiteral" }, "DateUnit": { - "description": "Represents units of time that can be used in relative date calculations. Examples:\n- 'second': 1 second\n- 'minute': 60 seconds\n- 'hour': 60 minutes\n- 'day': 24 hours\n- 'week': 7 days\n- 'month': ~30 days\n- 'quarter': 3 months\n- 'year': 12 months", + "description": "Represents units of time that can be used in relative date calculations.\nExamples:\n- 'second': 1 second\n- 'minute': 60 seconds\n- 'hour': 60 minutes\n- 'day': 24 hours\n- 'week': 7 days\n- 'month': ~30 days\n- 'quarter': 3 months\n- 'year': 12 months", "enum": [ "second", "minute", @@ -237,6 +231,7 @@ "quarter", "year" ], + "title": "DateUnit", "type": "string" }, "DistanceUnit": { @@ -245,72 +240,127 @@ "miles", "kilometers" ], + "title": "DistanceUnit", "type": "string" }, "Expression": { "anyOf": [ { - "additionalProperties": false, - "properties": { - "operand": { - "$ref": "#/definitions/Operand" - }, - "operator": { - "$ref": "#/definitions/UnaryOperator" - } - }, - "required": [ - "operator", - "operand" - ], - "type": "object", - "title": "UnaryExpression" + "$ref": "#/definitions/ValueExpression" }, { - "additionalProperties": false, - "properties": { - "left": { - "$ref": "#/definitions/Operand" - }, - "operator": { - "$ref": "#/definitions/BinaryOperator" - }, - "right": { - "$ref": "#/definitions/Operand" - } - }, - "required": [ - "operator", - "left", - "right" - ], - "type": "object", - "title": "BinaryExpression" + "$ref": "#/definitions/IUnaryExpression" }, { - "additionalProperties": false, - "properties": { - "expressions": { - "items": { - "$ref": "#/definitions/Expression" - }, - "type": "array" - }, - "operator": { - "$ref": "#/definitions/LogicalOperator" - } + "$ref": "#/definitions/IBinaryExpression" + }, + { + "$ref": "#/definitions/IManyExpression" + }, + { + "$ref": "#/definitions/IAggregateExpression" + }, + { + "$ref": "#/definitions/BoolExpression" + }, + { + "$ref": "#/definitions/NumberExpression" + }, + { + "$ref": "#/definitions/StringExpression" + }, + { + "$ref": "#/definitions/LocationExpression" + }, + { + "$ref": "#/definitions/DateExpression" + }, + { + "$ref": "#/definitions/Literal" + } + ], + "description": "Represents an expression that accepts a variety of arguments and evaluates to a value.", + "title": "Expression" + }, + "IAggregateExpression": { + "additionalProperties": false, + "properties": { + "condition": { + "$ref": "#/definitions/Expression" + }, + "group_by_model": { + "type": "string" + }, + "operand": { + "$ref": "#/definitions/Expression" + }, + "operator": { + "$ref": "#/definitions/Operator" + } + }, + "required": [ + "group_by_model", + "operand", + "operator" + ], + "type": "object" + }, + "IBinaryExpression": { + "additionalProperties": false, + "properties": { + "left": { + "$ref": "#/definitions/Expression" + }, + "operator": { + "$ref": "#/definitions/Operator" + }, + "right": { + "$ref": "#/definitions/Expression" + } + }, + "required": [ + "left", + "operator", + "right" + ], + "type": "object" + }, + "IManyExpression": { + "additionalProperties": false, + "properties": { + "expressions": { + "items": { + "$ref": "#/definitions/Expression" }, - "required": [ - "operator", - "expressions" - ], - "type": "object", - "title": "LogicalExpression" + "type": "array" + }, + "operator": { + "$ref": "#/definitions/Operator" } + }, + "required": [ + "expressions", + "operator" ], - "description": "Represents a complex expression that can evaluate to true, false, or noop. Examples: 1. Join expression (combining expressions from different models): { \"model\": \"user\", \"expression\": { \"operator\": \"equals\", \"left\": { \"path\": \"age\" }, \"right\": 18 } }\n\n2. Logical expression (AND): { \"operator\": \"and\", \"expressions\": [ { \"operator\": \"equals\", \"left\": { \"path\": \"country\" }, \"right\": \"US\" }, { \"operator\": \"greater_than\", \"left\": { \"path\": \"age\" }, \"right\": 18 } ] }\n\n3. Location expression: { \"operator\": \"within\", \"left\": { \"location\": { \"latitude\": 37.7749, \"longitude\": -122.4194, \"distance\": { \"value\": 10, \"unit\": \"miles\" } } }, \"right\": { \"model\": \"user\", \"path\": \"location\" } }" + "type": "object" }, - "ListOperator": { + "IUnaryExpression": { + "additionalProperties": false, + "properties": { + "operand": { + "$ref": "#/definitions/Expression" + }, + "operator": { + "$ref": "#/definitions/Operator" + } + }, + "required": [ + "operand", + "operator" + ], + "type": "object" + }, + "ListBoolOperator": { "description": "Represents operators that work with lists of values. Examples:\n- \"contains\": { list: [1, 2, 3], value: 2 }\n- \"between\": { list: [1, 10], value: 5 }\n- \"match_any\": { list: [\"a\", \"b\"], value: \"a\" }\n- \"in\": { list: [1, 2, 3], value: 2 }", "enum": [ "contains", @@ -322,9 +372,39 @@ ], "type": "string" }, + "Literal": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "$ref": "#/definitions/DateLiteral" + }, + { + "$ref": "#/definitions/ModelPath" + }, + { + "$ref": "#/definitions/Location" + }, + { + "$ref": "#/definitions/ModelReference" + }, + { + "$ref": "#/definitions/AudienceReference" + } + ], + "description": "Represents a value that can be used in expressions, including primitive values, paths, and arithmetic operations.\nExamples:\n1. Primitive values:\ntrue\n42\n\"hello\"\n\n2. Path reference:\n{ path: \"user.age\" }\n\n3. Arithmetic operation:\n{\noperator: \"plus\",\nleft: { path: \"price\" },\nright: { path: \"tax\" }\n}\n\n4. Nested arithmetic operation:\n{\noperator: \"multiply\",\nleft: { operator: \"plus\", left: { path: \"base_price\" }, right: { path: \"shipping\" } },\nright: 1.1\n}\n\n5. Date operand:\n{ date: { absolute: \"2023-01-01T00:00:00Z\" } }", + "title": "Literal" + }, "Location": { "additionalProperties": false, - "description": "Represents a geographic location, optionally with a distance constraint. Examples: 1. Simple location: { \"latitude\": 37.7749, \"longitude\": -122.4194 }\n\n2. Location with distance in miles: { \"latitude\": 40.7128, \"longitude\": -74.0060, \"distance\": { \"value\": 10, \"unit\": \"miles\" } }\n\n3. Location with distance in kilometers: { \"latitude\": 51.5074, \"longitude\": -0.1278, \"distance\": { \"value\": 5, \"unit\": \"kilometers\" } }", + "description": "Represents a geographic location, optionally with a distance constraint.\nExamples:\n1. Simple location:\n{ \"latitude\": 37.7749, \"longitude\": -122.4194 }\n\n2. Location with distance in miles:\n{ \"latitude\": 40.7128, \"longitude\": -74.0060, \"distance\": { \"value\": 10, \"unit\": \"miles\" } }\n\n3. Location with distance in kilometers:\n{ \"latitude\": 51.5074, \"longitude\": -0.1278, \"distance\": { \"value\": 5, \"unit\": \"kilometers\" } }", "properties": { "distance": { "additionalProperties": false, @@ -353,65 +433,31 @@ "latitude", "longitude" ], + "title": "Location", "type": "object" }, - "LocationExpression": { - "anyOf": [ - { - "$ref": "#/definitions/Location" - }, - { - "additionalProperties": false, - "properties": { - "operand": { - "$ref": "#/definitions/Location" - }, - "operator": { - "$ref": "#/definitions/LocationOperator" - } - }, - "required": [ - "operator", - "operand" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "expressions": { - "items": { - "$ref": "#/definitions/LocationExpression" - }, - "type": "array" - }, - "operator": { - "$ref": "#/definitions/LogicalOperator" - } - }, - "required": [ - "operator", - "expressions" - ], - "type": "object" - } - ], - "description": "Represents an expression that evaluates to a location or location-based condition. Examples: 1. Simple location: { latitude: 40.7128, longitude: -74.0060, distance: { value: 5, unit: \"miles\" } }\n\n2. Location with operator: { operator: \"within\", operand: { latitude: 40.7128, longitude: -74.0060, distance: { value: 5, unit: \"miles\" } } }\n\n3. Logical combination of locations: { operator: \"or\", expressions: [ { latitude: 40.7128, longitude: -74.0060, distance: { value: 5, unit: \"miles\" } }, { operator: \"within\", operand: { latitude: 34.0522, longitude: -118.2437, distance: { value: 10, unit: \"miles\" } } } ] }" - }, - "LocationOperand": { + "LocationBoolExpression": { "additionalProperties": false, - "description": "Represents a location value that can be used in location-based expressions. Examples: 1. Simple location (latitude/longitude only): { location: { latitude: 40.7128, longitude: -74.0060 } }\n\n2. Location with distance in miles: { location: { latitude: 40.7128, longitude: -74.0060, distance: { value: 5, unit: \"miles\" } } }\n\n3. Location with distance in meters: { location: { latitude: 40.7128, longitude: -74.0060, distance: { value: 1000, unit: \"meters\" } } }", "properties": { - "location": { - "$ref": "#/definitions/Location" + "left": { + "$ref": "#/definitions/LocationExpression" + }, + "operator": { + "$ref": "#/definitions/LocationBoolOperator" + }, + "right": { + "$ref": "#/definitions/LocationExpression" } }, "required": [ - "location" + "left", + "operator", + "right" ], + "title": "LocationBoolExpression", "type": "object" }, - "LocationOperator": { + "LocationBoolOperator": { "description": "Represents operators for location-based comparisons. Examples:\n- \"within\": { location1: { lat: 40, lng: -74 }, location2: { lat: 40, lng: -74 }, radius: 5 }\n- \"equals\": { location1: { lat: 40, lng: -74 }, location2: { lat: 40, lng: -74 } }", "enum": [ "within", @@ -419,7 +465,33 @@ ], "type": "string" }, - "LogicalOperator": { + "LocationExpression": { + "$ref": "#/definitions/ValueLocationExpression", + "description": "Represents an expression that evaluates to a location or location-based condition.", + "title": "LocationExpression" + }, + "LogicalBoolExpression": { + "additionalProperties": false, + "properties": { + "left": { + "$ref": "#/definitions/BoolExpression" + }, + "operator": { + "$ref": "#/definitions/LogicalBoolOperator" + }, + "right": { + "$ref": "#/definitions/BoolExpression" + } + }, + "required": [ + "left", + "operator", + "right" + ], + "title": "LogicalBoolExpression", + "type": "object" + }, + "LogicalBoolOperator": { "description": "Represents logical operators for combining multiple conditions. Examples:\n- \"and\": { condition1: true, condition2: true } // result: true\n- \"or\": { condition1: true, condition2: false } // result: true", "enum": [ "and", @@ -427,21 +499,33 @@ ], "type": "string" }, - "ModelOperand": { + "LogicalManyBoolExpression": { "additionalProperties": false, "properties": { - "model": { - "type": "string" + "expressions": { + "items": { + "$ref": "#/definitions/BoolExpression" + }, + "type": "array" + }, + "operator": { + "$ref": "#/definitions/LogicalBoolOperator" } }, "required": [ - "model" + "expressions", + "operator" ], + "title": "LogicalManyBoolExpression", "type": "object" }, + "ManyBoolExpression": { + "$ref": "#/definitions/LogicalManyBoolExpression", + "title": "ManyBoolExpression" + }, "ModelPath": { "additionalProperties": false, - "description": "Represents a model path reference within a data model. Examples: 1. Simple model path: { \"model\": \"user\", \"path\": \"email\" }\n\n2. Nested model path: { \"model\": \"order\", \"path\": \"items.productId\" }\n\n3. Deeply nested model path: { \"model\": \"event\", \"path\": \"attributes.purchase.amount\" }", + "description": "Represents a model path reference within a data model.\nExamples:\n1. Simple model path:\n{ \"model\": \"user\", \"path\": \"email\" }\n\n2. Nested model path:\n{ \"model\": \"order\", \"path\": \"items.productId\" }\n\n3. Deeply nested model path:\n{ \"model\": \"event\", \"path\": \"attributes.purchase.amount\" }", "properties": { "model": { "type": "string" @@ -454,112 +538,105 @@ "model", "path" ], + "title": "ModelPath", "type": "object" }, - "Operand": { + "ModelReference": { + "additionalProperties": false, + "description": "Represents a model reference within a data model", + "properties": { + "model": { + "type": "string" + } + }, + "required": [ + "model" + ], + "title": "ModelReference", + "type": "object" + }, + "NumberBoolExpression": { + "additionalProperties": false, + "properties": { + "left": { + "$ref": "#/definitions/NumberExpression" + }, + "operator": { + "$ref": "#/definitions/NumberBoolOperator" + }, + "right": { + "$ref": "#/definitions/NumberExpression" + } + }, + "required": [ + "left", + "operator", + "right" + ], + "title": "NumberBoolExpression", + "type": "object" + }, + "NumberBoolOperator": { + "description": "Represents binary operators that compare two values. Examples:\n- \"equals\": { value1: 5, value2: 5 }\n- \"less_than\": { value1: 3, value2: 5 }\n- \"matches\": { value1: \"pattern\", value2: \"text\" }\n- \"contains\": { value1: \"string\", value2: \"substring\" }", + "enum": [ + "equals", + "not_equals", + "less_than", + "less_than_equal", + "greater_than", + "greater_than_equal" + ], + "type": "string" + }, + "NumberExpression": { "anyOf": [ { - "type": "boolean" + "$ref": "#/definitions/ValueNumberExpression" }, { - "type": "number" + "$ref": "#/definitions/BinaryNumberExpression" }, { - "type": "string" - }, + "$ref": "#/definitions/AggregateNumberExpression" + } + ], + "description": "Represents an expression that evaluates to a number.", + "title": "NumberExpression" + }, + "Operator": { + "anyOf": [ { - "$ref": "#/definitions/DateOperand" + "$ref": "#/definitions/LogicalBoolOperator" }, { - "$ref": "#/definitions/ModelPath" + "$ref": "#/definitions/LocationBoolOperator" }, { - "$ref": "#/definitions/ModelOperand" + "$ref": "#/definitions/AggregationNumberOperator" }, { - "$ref": "#/definitions/AudienceOperand" + "$ref": "#/definitions/BinaryNumberOperator" }, { - "additionalProperties": false, - "properties": { - "condition": { - "$ref": "#/definitions/Expression" - }, - "group_by_model": { - "type": "string" - }, - "operand": { - "$ref": "#/definitions/Operand" - }, - "operator": { - "$ref": "#/definitions/AggregationOperator" - } - }, - "required": [ - "operator", - "group_by_model", - "operand" - ], - "type": "object", - "title": "ModelAggregationOperand" - } - ], - "description": "Represents a value that can be used in expressions, including primitive values, paths, and arithmetic operations. Examples: 1. Primitive values: true 42 \"hello\"\n\n2. Path reference: { path: \"user.age\" }\n\n3. Arithmetic operation: { operator: \"plus\", left: { path: \"price\" }, right: { path: \"tax\" } }\n\n4. Nested arithmetic operation: { operator: \"multiply\", left: { operator: \"plus\", left: { path: \"base_price\" }, right: { path: \"shipping\" } }, right: 1.1 }\n\n5. Date operand: { date: { absolute: \"2023-01-01T00:00:00Z\" } }" - }, - "PathExpression": { - "anyOf": [ - { - "type": "boolean", - "title": "BooleanPathExpression" + "$ref": "#/definitions/AudienceOperator" }, { - "type": "number", - "title": "NumberPathExpression" + "$ref": "#/definitions/ListBoolOperator" }, { - "type": "string", - "title": "StringPathExpression" + "$ref": "#/definitions/StringBoolOperator" }, { - "additionalProperties": false, - "properties": { - "expression": { - "$ref": "#/definitions/PathExpression" - }, - "operator": { - "$ref": "#/definitions/UnaryOperator" - } - }, - "required": [ - "operator", - "expression" - ], - "type": "object", - "title": "UnaryPathExpression" + "$ref": "#/definitions/NumberBoolOperator" }, { - "additionalProperties": false, - "properties": { - "operand": { - "$ref": "#/definitions/Operand" - }, - "operator": { - "$ref": "#/definitions/BinaryOperator" - } - }, - "required": [ - "operator", - "operand" - ], - "type": "object", - "title": "BinaryPathExpression" + "$ref": "#/definitions/UnaryBoolOperator" } - ], - "description": "Represents an expression that evaluates to a path or value. Examples: 1. Primitive values: true 42 \"hello\"\n\n2. Unary expression (NOT): { operator: \"not\", expression: { operator: \"equals\", operand: { path: \"status\" } } }\n\n3. Binary expression (comparing a path to a value): { operator: \"equals\", operand: { path: \"user.age\" } }" + ] }, "RelativeDate": { "additionalProperties": false, - "description": "Represents a date/time relative to the current time. Examples: 1. 7 days ago: { relative: { offset: -7, unit: \"day\" } }\n\n2. Start of current month: { relative: { offset: 0, unit: \"month\", boundary: \"start\" } }\n\n3. End of previous quarter: { relative: { offset: -1, unit: \"quarter\", boundary: \"end\" } }", + "description": "Represents a date/time relative to the current time.\nExamples:\n1. 7 days ago:\n{ relative: { offset: -7, unit: \"day\" } }\n\n2. Start of current month:\n{ relative: { offset: 0, unit: \"month\", boundary: \"start\" } }\n\n3. End of previous quarter:\n{ relative: { offset: -1, unit: \"quarter\", boundary: \"end\" } }", "properties": { "relative": { "additionalProperties": false, @@ -588,9 +665,68 @@ "required": [ "relative" ], + "title": "RelativeDate", + "type": "object" + }, + "StringBoolExpression": { + "additionalProperties": false, + "properties": { + "left": { + "$ref": "#/definitions/StringExpression" + }, + "operator": { + "$ref": "#/definitions/StringBoolOperator" + }, + "right": { + "$ref": "#/definitions/StringExpression" + } + }, + "required": [ + "left", + "operator", + "right" + ], + "title": "StringBoolExpression", + "type": "object" + }, + "StringBoolOperator": { + "enum": [ + "equals", + "not_equals", + "matches", + "contains", + "not_contains", + "starts_with", + "not_starts_with", + "ends_with", + "not_ends_with", + "in", + "not_in" + ], + "type": "string" + }, + "StringExpression": { + "$ref": "#/definitions/ValueStringExpression", + "title": "StringExpression" + }, + "UnaryBoolExpression": { + "additionalProperties": false, + "properties": { + "operand": { + "$ref": "#/definitions/Expression" + }, + "operator": { + "$ref": "#/definitions/UnaryBoolOperator" + } + }, + "required": [ + "operand", + "operator" + ], + "title": "UnaryBoolExpression", "type": "object" }, - "UnaryOperator": { + "UnaryBoolOperator": { "description": "Represents unary operators that operate on a single value. Examples:\n- \"not\": Negates a boolean expression\n- \"exist\": Checks if a value exists", "enum": [ "null", @@ -600,6 +736,90 @@ ], "type": "string" }, + "ValueBoolExpression": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/definitions/ModelPath" + } + ], + "title": "ValueBoolExpression" + }, + "ValueDateExpression": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "date": { + "$ref": "#/definitions/DateLiteral" + } + }, + "required": [ + "date" + ], + "type": "object" + }, + { + "$ref": "#/definitions/ModelPath" + } + ], + "title": "ValueDateExpression" + }, + "ValueExpression": { + "anyOf": [ + { + "$ref": "#/definitions/ValueBoolExpression" + }, + { + "$ref": "#/definitions/ValueDateExpression" + }, + { + "$ref": "#/definitions/ValueLocationExpression" + }, + { + "$ref": "#/definitions/ValueNumberExpression" + }, + { + "$ref": "#/definitions/ValueStringExpression" + } + ], + "title": "ValueExpression" + }, + "ValueLocationExpression": { + "anyOf": [ + { + "$ref": "#/definitions/Location" + }, + { + "$ref": "#/definitions/ModelPath" + } + ], + "title": "ValueLocationExpression" + }, + "ValueNumberExpression": { + "anyOf": [ + { + "type": "number" + }, + { + "$ref": "#/definitions/ModelPath" + } + ], + "title": "ValueNumberExpression" + }, + "ValueStringExpression": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/ModelPath" + } + ], + "title": "ValueStringExpression" + }, "Version": { "type": [ "string" @@ -624,4 +844,4 @@ "type": "object" } } -} +} \ No newline at end of file diff --git a/sdk/typescript-schema/scripts/add_titles_to_schema.sh b/sdk/typescript-schema/scripts/add_titles_to_schema.sh deleted file mode 100755 index 563cfea..0000000 --- a/sdk/typescript-schema/scripts/add_titles_to_schema.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/bash - -# Usage: -# ./add_titles_to_schema.sh [input.json] > output.json - -INPUT_FILE="${1:-schema/audience-schema.json}" - -if [[ ! -f "$INPUT_FILE" ]]; then - echo "Error: File '$INPUT_FILE' not found." >&2 - exit 1 -fi - -# Use global jq -JQ="jq" - -# Define mappings: JSONPath-like path | title -read -r -d '' MAPPINGS < tmp.tsconfig.json && mv tmp.tsconfig.json "$TSCONFIG" echo "Generating JSON schema..." -./node_modules/.bin/ts-json-schema-generator --path index.ts --out schema/audience-schema.tmp.json - -echo "Adding titles to schema..." -./scripts/add_titles_to_schema.sh schema/audience-schema.tmp.json > schema/audience-schema.json +./node_modules/.bin/ts-json-schema-generator --path index.ts --out schema/audience-schema.json cp -f schema/audience-schema.json ../../schema/audience-definition-schema.json -rm -f schema/audience-schema.tmp.json echo "Schema generation complete." diff --git a/sdk/typescript/.nvmrc b/sdk/typescript/.nvmrc deleted file mode 100644 index 0f394a5..0000000 --- a/sdk/typescript/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -20.18.0 \ No newline at end of file diff --git a/sdk/typescript/README.md b/sdk/typescript/README.md deleted file mode 100644 index d7fe24c..0000000 --- a/sdk/typescript/README.md +++ /dev/null @@ -1,354 +0,0 @@ -# mParticle Audience SDK - -A TypeScript SDK for building and managing mParticle Audiences. - -## Installation - -```bash -npm install @mparticle/audience-sdk -``` - -## Usage - -### Creating a Simple Audience - -```typescript -import { createAudience, createEventQueryBuilder } from '@mparticle/audience-sdk'; - -// Create an event query -const eventQuery = createEventQueryBuilder() - .setModels(['event']) - .setEventName({ path: 'purchase' }) - .build(); - -// Create an audience with the event query -const audience = createAudience() - .addQuery({ event: eventQuery }) - .build(); - -// Convert to JSON -const json = JSON.stringify(audience, null, 2); -``` - -### Creating a Complex Audience with Logical Combinations - -```typescript -import { - createAudience, - createEventQueryBuilder, - createUserQueryBuilder, - createLogicalQuery -} from '@mparticle/audience-sdk'; - -// Create an event query for purchases -const purchaseQuery = createEventQueryBuilder() - .setModels(['event']) - .setEventName({ path: 'purchase' }) - .build(); - -// Create a user query for premium users -const premiumUserQuery = createUserQueryBuilder() - .setModels(['user']) - .addAttribute('subscription_tier', { path: 'premium' }) - .build(); - -// Create a logical query combining both conditions -const logicalQuery = createLogicalQuery() - .setOperator('and') - .addQuery({ event: purchaseQuery }) - .addQuery({ user: premiumUserQuery }) - .build(); - -// Create the final audience -const audience = createAudience() - .setOperator('or') - .addQuery({ event: purchaseQuery }) - .addLogicalQuery(logicalQuery) - .build(); -``` - -### Building Operands - -```typescript -import { - OperandFactory, - DateOperandFactory, - LocationOperandFactory -} from '@mparticle/audience-sdk'; - -// Create primitive operands -const stringOperand = OperandFactory.createPrimitive('value'); -const numberOperand = OperandFactory.createPrimitive(42); -const booleanOperand = OperandFactory.createPrimitive(true); - -// Create path operands -const pathOperand = OperandFactory.createPath('user.profile.age'); - -// Create date operands -const absoluteDate = OperandFactory.createAbsoluteDate('2023-01-01T00:00:00Z'); -const relativeDate = OperandFactory.createRelativeDate(-7, 'day', 'start'); - -// Create location operands -const locationPoint = OperandFactory.createLocationPoint(37.7749, -122.4194); -const locationWithRadius = OperandFactory.createLocationWithMiles(37.7749, -122.4194, 10); - -// Create arithmetic operands -const arithmeticOperand = OperandFactory.createArithmetic( - 'add', - OperandFactory.createPath('user.profile.age'), - OperandFactory.createPrimitive(5) -); -``` - -### Building Expressions - -```typescript -import { - ExpressionFactory, - OperandFactory -} from '@mparticle/audience-sdk'; - -// Create binary expressions -const equalsExpression = ExpressionFactory.createBinary( - 'eq', - OperandFactory.createPath('user.profile.age'), - OperandFactory.createPrimitive(18) -); - -const greaterThanExpression = ExpressionFactory.createBinary( - 'gt', - OperandFactory.createPath('user.profile.age'), - OperandFactory.createPrimitive(21) -); - -// Create logical expressions (AND/OR) -const andExpression = ExpressionFactory.createAnd([ - equalsExpression, - greaterThanExpression -]); - -const orExpression = ExpressionFactory.createOr([ - equalsExpression, - greaterThanExpression -]); - -// Create NOT expressions -const notExpression = ExpressionFactory.createNot(equalsExpression); - -// Create EXISTS expressions -const existsExpression = ExpressionFactory.createExists( - OperandFactory.createPath('user.profile.email') -); - -// Create location expressions -const locationExpression = ExpressionFactory.createLocation( - 'within', - OperandFactory.createLocationWithMiles(37.7749, -122.4194, 10), - { path: 'user.location' } -); -``` - -### Building Event Queries - -```typescript -import { - createEventQueryBuilder, - ExpressionFactory, - OperandFactory -} from '@mparticle/audience-sdk'; - -// Simple event query -const simpleEventQuery = createEventQueryBuilder() - .setModels(['event']) - .setEventName({ path: 'purchase' }) - .build(); - -// Event query with attributes -const eventQueryWithAttributes = createEventQueryBuilder() - .setModels(['event']) - .setEventName({ path: 'purchase' }) - .setAttributeOperator('and') - .addAttributesExpression( - ExpressionFactory.createBinary( - 'gt', - OperandFactory.createPath('event.properties.amount'), - OperandFactory.createPrimitive(100) - ) - ) - .build(); - -// Event query with count -const eventQueryWithCount = createEventQueryBuilder() - .setModels(['event']) - .setEventName({ path: 'purchase' }) - .setCountValue(5) - .build(); - -// Event query with date -const eventQueryWithDate = createEventQueryBuilder() - .setModels(['event']) - .setEventName({ path: 'purchase' }) - .setRelativeDate(-30, 'day', 'start') - .build(); - -// Event query with location -const eventQueryWithLocation = createEventQueryBuilder() - .setModels(['event']) - .setEventName({ path: 'purchase' }) - .setLocation( - ExpressionFactory.createLocation( - 'within', - OperandFactory.createLocationWithMiles(37.7749, -122.4194, 10), - { path: 'event.location' } - ) - ) - .build(); -``` - -### Building User Queries - -```typescript -import { - createUserQueryBuilder, - ExpressionFactory, - OperandFactory -} from '@mparticle/audience-sdk'; - -// Simple user query -const simpleUserQuery = createUserQueryBuilder() - .setModels(['user']) - .setAttributeOperator('and') - .addAttributesExpression( - ExpressionFactory.createBinary( - 'eq', - OperandFactory.createPath('user.profile.subscription_tier'), - OperandFactory.createPrimitive('premium') - ) - ) - .build(); - -// Complex user query with multiple conditions -const complexUserQuery = createUserQueryBuilder() - .setModels(['user']) - .setAttributeOperator('and') - .addAttributesExpression( - ExpressionFactory.createBinary( - 'eq', - OperandFactory.createPath('user.profile.subscription_tier'), - OperandFactory.createPrimitive('premium') - ) - ) - .addAttributesExpression( - ExpressionFactory.createBinary( - 'gt', - OperandFactory.createPath('user.profile.age'), - OperandFactory.createPrimitive(21) - ) - ) - .addAttributesExpression( - ExpressionFactory.createExists( - OperandFactory.createPath('user.profile.email') - ) - ) - .build(); -``` - -### Parsing and Validating Audiences - -```typescript -import { parseAudience, validateAudience, stringifyAudience } from '@mparticle/audience-sdk'; - -// Parse an audience from JSON -const jsonString = '{"audience":{"operator":"and","queries":[{"event":{"model":"event","event_name":{"path":"purchase"}}}]}}'; -const audience = parseAudience(jsonString); - -// Validate an audience -const isValid = validateAudience(audience); - -// Convert an audience to JSON -const json = stringifyAudience(audience); -``` - -## API Reference - -### AudienceBuilder - -The main builder for creating Audience objects. - -- `setOperator(operator: 'and' | 'or')`: Sets the logical operator for combining queries -- `addQuery(query: AudienceQuery)`: Adds a query to the audience -- `addLogicalQuery(logicalQuery: LogicalAudienceQueries)`: Adds a nested logical query -- `build()`: Builds and returns the final Audience object - -### QueryBuilders - -#### GeneralQueryBuilder - -- `setModels(models: Model[])`: Sets the models for the query -- `setExpression(expression: Expression)`: Sets the expression for the query -- `build()`: Builds and returns the query - -#### EventQueryBuilder - -- `setModels(models: Model[])`: Sets the models for the event query -- `setEventName(eventName: PathExpression)`: Sets the event name -- `setAttributeOperator(operator: LogicalOperator)`: Sets the operator for combining attribute expressions -- `addAttributesExpression(expression: SingleModelExpression)`: Adds an expression to the query -- `setCountValue(count: number)`: Sets a simple numeric count value -- `setCountBinary(operator: BinaryOperator, operand: Operand)`: Sets a binary operator count expression -- `setCountLogical(operator: LogicalOperator, expressions: CountExpression[])`: Sets a logical combination of count expressions -- `setAbsoluteDate(absoluteDate: string)`: Sets an absolute date -- `setRelativeDate(offset: number, unit: DateUnit, boundary?: 'start' | 'end')`: Sets a relative date -- `setDateBinary(operator: BinaryOperator, operand: AbsoluteDate | RelativeDate)`: Sets a binary operator date expression -- `setDateLogical(operator: LogicalOperator, expressions: DateExpression[])`: Sets a logical combination of date expressions -- `setLocation(location: LocationExpression)`: Sets the location -- `setEventType(eventType: PathExpression)`: Sets the event type -- `build()`: Builds and returns the event query - -#### UserQueryBuilder - -- `setModels(models: Model[])`: Sets the models for the user query -- `setAttributeOperator(operator: LogicalOperator)`: Sets the operator for combining attribute expressions -- `addAttributesExpression(expression: SingleModelExpression)`: Adds an expression to the query -- `build()`: Builds and returns the user query - -### Expression Factory - -- `createJoin(model: Model, expression: Expression)`: Creates a join expression -- `createNot(expression: Expression, model?: Model)`: Creates a unary expression (NOT) -- `createExists(operand: Operand, model?: Model)`: Creates an exists expression -- `createBinary(operator: BinaryOperator, left: Operand, right: Operand, model?: Model)`: Creates a binary expression -- `createModelAggregation(model: Model, operator: BinaryOperator, expression: Expression, aggregation: { operator: AggregationOperator, path: string }, right: Operand | { model: string, operator: AggregationOperator, path: string, expression: Expression })`: Creates a model aggregation expression -- `createLogical(operator: LogicalOperator, expressions: Expression[], model?: Model)`: Creates a logical expression (AND/OR) -- `createLocation(operator: LocationOperator, location: LocationOperand, path: { path: string }, model?: Model)`: Creates a location expression -- `createAnd(expressions: Expression[], model?: Model)`: Creates an AND expression -- `createOr(expressions: Expression[], model?: Model)`: Creates an OR expression - -### Operand Factory - -- `createPath(path: string)`: Creates a path operand -- `createDate(dateOperand: DateOperand)`: Creates a date operand -- `createArithmetic(operator: ArithmeticOperator, left: Operand, right: Operand)`: Creates an arithmetic operand -- `createAbsoluteDate(dateString: string)`: Creates an absolute date operand -- `createRelativeDate(offset: number, unit: string, boundary?: 'start' | 'end')`: Creates a relative date operand -- `createLocationPoint(latitude: number, longitude: number)`: Creates a location operand with latitude and longitude -- `createLocationWithMeters(latitude: number, longitude: number, meters: number)`: Creates a location operand with latitude, longitude, and distance in meters -- `createLocationWithMiles(latitude: number, longitude: number, miles: number)`: Creates a location operand with latitude, longitude, and distance in miles -- `createLocationWithKilometers(latitude: number, longitude: number, kilometers: number)`: Creates a location operand with latitude, longitude, and distance in kilometers - -### Model Factory - -- `createWithId(id: number, type: string)`: Creates a model with an ID and type -- `createWithName(name: string, type: string)`: Creates a model with a name and type -- `createModel(type: string, id: number, name?: string)`: Creates a model with type, ID, and optional name - -### Utility Functions - -- `createAudience()`: Creates a new AudienceBuilder instance -- `createLogicalQuery()`: Creates a new LogicalQueryBuilder instance -- `createGeneralQueryBuilder()`: Creates a new GeneralQueryBuilder instance -- `createEventQueryBuilder()`: Creates a new EventQueryBuilder instance -- `createUserQueryBuilder()`: Creates a new UserQueryBuilder instance -- `validateAudience(audience: Audience)`: Validates an Audience object -- `parseAudience(json: string)`: Parses a JSON string into an Audience object -- `stringifyAudience(audience: Audience)`: Converts an Audience object to a JSON string \ No newline at end of file diff --git a/sdk/typescript/package-lock.json b/sdk/typescript/package-lock.json deleted file mode 100644 index 5ecb05b..0000000 --- a/sdk/typescript/package-lock.json +++ /dev/null @@ -1,1628 +0,0 @@ -{ - "name": "@mparticle/audience-sdk-typescript", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@mparticle/audience-sdk-typescript", - "version": "1.0.0", - "license": "Apache-2.0", - "dependencies": { - "@mparticle/audience-typescript-schema": "file:../typescript-schema" - }, - "devDependencies": { - "@typescript-eslint/eslint-plugin": "^5.59.0", - "@typescript-eslint/parser": "^5.59.0", - "eslint": "^8.38.0", - "typescript": "^5.0.4" - } - }, - "../typescript-schema": { - "name": "@mparticle/audience-typescript-schema", - "version": "1.0.0", - "license": "Apache-2.0", - "devDependencies": { - "@semantic-release/changelog": "^6.0.3", - "@semantic-release/git": "^10.0.1", - "@semantic-release/github": "^9.2.6", - "@semantic-release/npm": "^11.0.2", - "semantic-release": "^23.0.2", - "typescript": "^5.0.4" - }, - "engines": { - "node": ">=20.8.1" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.1.tgz", - "integrity": "sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true - }, - "node_modules/@mparticle/audience-typescript-schema": { - "resolved": "../typescript-schema", - "link": true - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz", - "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", - "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/type-utils": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", - "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", - "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/sdk/typescript/package.json b/sdk/typescript/package.json deleted file mode 100644 index 3c5c0af..0000000 --- a/sdk/typescript/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "@mparticle/audience-sdk-typescript", - "version": "1.0.0", - "description": "TypeScript SDK for building and managing mParticle Audiences", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "repository": { - "type": "git", - "url": "git+https://github.com/mParticle/audience-sdk.git" - }, - "keywords": [ - "audience" - ], - "license": "Apache-2.0", - "scripts": { - "build": "tsc", - "lint": "eslint src/**/*.ts" - }, - "dependencies": { - "@mparticle/audience-typescript-schema": "file:../typescript-schema" - }, - "devDependencies": { - "@typescript-eslint/eslint-plugin": "^5.59.0", - "@typescript-eslint/parser": "^5.59.0", - "eslint": "^8.38.0", - "typescript": "^5.0.4" - } - } \ No newline at end of file diff --git a/sdk/typescript/src/audience-builder.ts b/sdk/typescript/src/audience-builder.ts deleted file mode 100644 index 73d2923..0000000 --- a/sdk/typescript/src/audience-builder.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { Audience, LogicalAudienceExpression, Expression } from '@mparticle/audience-typescript-schema/audience'; -import { LogicalOperator } from '@mparticle/audience-typescript-schema/common/operator'; -import { VERSION } from '@mparticle/audience-typescript-schema/version'; - -export class AudienceBuilder { - private expressions: (LogicalAudienceExpression | Expression)[] = []; - private currentOperator: LogicalOperator = 'and'; - - /** - * Creates a new AudienceBuilder instance - */ - constructor() { } - - /** - * Sets the logical operator for combining queries - * @param operator The logical operator to use ('and' or 'or') - */ - setOperator(operator: LogicalOperator): this { - this.currentOperator = operator; - return this; - } - - /** - * Adds an expression to the audience - * @param expression The expression to add - */ - addExpression(expression: Expression): this { - this.expressions.push(expression); - return this; - } - - /** - * Adds a nested logical expression to the audience - * @param logicalExpression The logical expression to add - */ - addLogicalExpression(logicalExpression: LogicalAudienceExpression): this { - this.expressions.push(logicalExpression); - return this; - } - - /** - * Builds and returns the final Audience object - */ - build(): Audience { - if (this.expressions.length === 0) { - throw new Error('Cannot build an audience with no expressions'); - } - - return { - schema_version: VERSION, - audience: { - operator: this.currentOperator, - expressions: this.expressions - } - }; - } - - /** - * Creates a new logical query builder - */ - static createLogicalExpression(): LogicalExpressionBuilder { - return new LogicalExpressionBuilder(); - } -} - -export class LogicalExpressionBuilder { - private expressions: (LogicalAudienceExpression | Expression)[] = []; - private operator: LogicalOperator = 'and'; - - /** - * Sets the logical operator for the query - * @param operator The logical operator to use ('and' or 'or') - */ - setOperator(operator: LogicalOperator): this { - this.operator = operator; - return this; - } - - /** - * Adds an expression to the logical expression - * @param expression The expression to add - */ - addExpression(expression: Expression): this { - this.expressions.push(expression); - return this; - } - - /** - * Adds a nested logical expression - * @param logicalExpression The logical expression to add - */ - addLogicalExpression(logicalExpression: LogicalAudienceExpression): this { - this.expressions.push(logicalExpression); - return this; - } - - /** - * Builds and returns the logical query - */ - build(): LogicalAudienceExpression { - if (this.expressions.length === 0) { - throw new Error('Cannot build a logical expression with no expressions'); - } - - return { - operator: this.operator, - expressions: this.expressions - }; - } -} \ No newline at end of file diff --git a/sdk/typescript/src/expression-factory/count-expression-factory.ts b/sdk/typescript/src/expression-factory/count-expression-factory.ts deleted file mode 100644 index 0bc530e..0000000 --- a/sdk/typescript/src/expression-factory/count-expression-factory.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { CountExpression } from '@mparticle/audience-typescript-schema/expression/count-expression'; -import { Operand } from '@mparticle/audience-typescript-schema/operand/operand'; -import { BinaryOperator, LogicalOperator } from '@mparticle/audience-typescript-schema/common/operator'; - -/** - * Factory class for creating different types of count expressions - */ -export class CountExpressionFactory { - /** - * Creates a count expression with a binary operator - * @param operator The binary operator - * @param operand The operand to compare against - * @returns A count expression - */ - static createBinary( - operator: BinaryOperator, - operand: Operand - ): CountExpression { - return { operator, operand }; - } - - /** - * Creates a logical combination of count expressions - * @param operator The logical operator ('and' or 'or') - * @param expressions The count expressions to combine - * @returns A logical count expression - */ - static createLogical( - operator: LogicalOperator, - expressions: CountExpression[] - ): CountExpression { - return { operator, expressions }; - } - - /** - * Creates an AND logical combination of count expressions - * @param expressions The count expressions to combine - * @returns An AND logical count expression - */ - static createAnd(expressions: CountExpression[]): CountExpression { - return this.createLogical('and', expressions); - } - - /** - * Creates an OR logical combination of count expressions - * @param expressions The count expressions to combine - * @returns An OR logical count expression - */ - static createOr(expressions: CountExpression[]): CountExpression { - return this.createLogical('or', expressions); - } - - /** - * Creates a count expression with the specified operator and operand - * @param operator The operator to use - * @param operand The operand to compare against - * @returns A count expression - */ - static createWithOperator(operator: BinaryOperator, operand: Operand): CountExpression { - return this.createBinary(operator, operand); - } - - /** - * Creates a unary count expression - * @param operator The unary operator - * @param expression The expression to operate on - * @returns A unary count expression - */ - private static createUnary( - operator: 'not', - expression: CountExpression - ): CountExpression { - // This is a workaround since CountExpression doesn't directly support unary operators - // We'll create a logical expression with a single expression - return this.createAnd([expression]); - } -} \ No newline at end of file diff --git a/sdk/typescript/src/expression-factory/date-operand-factory.ts b/sdk/typescript/src/expression-factory/date-operand-factory.ts deleted file mode 100644 index b2df406..0000000 --- a/sdk/typescript/src/expression-factory/date-operand-factory.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { DateOperand, AbsoluteDate, RelativeDate, DateUnit } from '@mparticle/audience-typescript-schema/operand/date-operand'; - -export class DateOperandFactory { - /** - * Creates an absolute date operand - * @param dateString The ISO 8601 date string - */ - static createAbsoluteDate(dateString: string): DateOperand { - const absoluteDate: AbsoluteDate = { - absolute: dateString - }; - return { date: absoluteDate }; - } - - /** - * Creates a relative date operand - * @param offset The number of units to offset - * @param unit The unit of time - * @param boundary Optional boundary specification - */ - static createRelativeDate( - offset: number, - unit: DateUnit, - boundary?: 'start' | 'end' - ): DateOperand { - const relativeDate: RelativeDate = { - relative: { - offset, - unit, - ...(boundary && { boundary }) - } - }; - return { date: relativeDate }; - } - - /** - * Creates a date operand for a specific number of days ago - * @param days The number of days ago - * @param boundary Optional boundary specification - */ - static daysAgo(days: number, boundary?: 'start' | 'end'): DateOperand { - return this.createRelativeDate(-days, 'day', boundary); - } - - /** - * Creates a date operand for a specific number of days in the future - * @param days The number of days in the future - * @param boundary Optional boundary specification - */ - static daysFromNow(days: number, boundary?: 'start' | 'end'): DateOperand { - return this.createRelativeDate(days, 'day', boundary); - } - - /** - * Creates a date operand for a specific number of months ago - * @param months The number of months ago - * @param boundary Optional boundary specification - */ - static monthsAgo(months: number, boundary?: 'start' | 'end'): DateOperand { - return this.createRelativeDate(-months, 'month', boundary); - } - - /** - * Creates a date operand for a specific number of months in the future - * @param months The number of months in the future - * @param boundary Optional boundary specification - */ - static monthsFromNow(months: number, boundary?: 'start' | 'end'): DateOperand { - return this.createRelativeDate(months, 'month', boundary); - } - - /** - * Creates a date operand for a specific number of years ago - * @param years The number of years ago - * @param boundary Optional boundary specification - */ - static yearsAgo(years: number, boundary?: 'start' | 'end'): DateOperand { - return this.createRelativeDate(-years, 'year', boundary); - } - - /** - * Creates a date operand for a specific number of years in the future - * @param years The number of years in the future - * @param boundary Optional boundary specification - */ - static yearsFromNow(years: number, boundary?: 'start' | 'end'): DateOperand { - return this.createRelativeDate(years, 'year', boundary); - } -} \ No newline at end of file diff --git a/sdk/typescript/src/expression-factory/expression-factory.ts b/sdk/typescript/src/expression-factory/expression-factory.ts deleted file mode 100644 index 10f4911..0000000 --- a/sdk/typescript/src/expression-factory/expression-factory.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { Expression } from '@mparticle/audience-typescript-schema/expression/expression'; -import { Operand } from '@mparticle/audience-typescript-schema/operand/operand'; -import { BinaryOperator, LogicalOperator, LocationOperator, AggregationOperator } from '@mparticle/audience-typescript-schema/common/operator'; -import { LocationOperand } from '@mparticle/audience-typescript-schema/operand/location-operand'; -import { ModelPath } from '@mparticle/audience-typescript-schema/common/model-path'; - -/** - * Factory class for creating different types of expressions - */ -export class ExpressionFactory { - - /** - * Creates a unary expression (NOT) - * @param expression The expression to negate - * @param model Optional model - * @returns A unary expression - */ - static createNot(expression: Expression, model?: string): Expression { - return { model, operator: 'not', expression }; - } - - /** - * Creates an exists expression - * @param operand The operand to check for existence - * @param model Optional model - * @returns An exists expression - */ - static createExists(operand: Operand, model?: string): Expression { - return { model, operator: 'exists', operand }; - } - - /** - * Creates a binary expression - * @param operator The binary operator - * @param left The left operand - * @param right The right operand - * @param model Optional model - * @returns A binary expression - */ - static createBinary( - operator: BinaryOperator, - left: Operand, - right: Operand, - model?: string - ): Expression { - return { model, operator, left, right }; - } - - /** - * Creates a logical expression (AND/OR) - * @param operator The logical operator - * @param expressions The expressions to combine - * @param model Optional model - * @returns A logical expression - */ - static createLogical( - operator: LogicalOperator, - expressions: Expression[] - ): Expression { - return { operator, expressions }; - } - - /** - * Creates a location expression - * @param operator The location operator - * @param location The location operand - * @param model model - * @param path The path to compare against - * @returns A location expression - */ - static createLocation( - operator: LocationOperator, - location: LocationOperand, - model: string, - path: string, - ): Expression { - return { operator, left: location, right: { model, path } }; - } - - /** - * Creates an AND expression - * @param expressions The expressions to combine - * @returns An AND expression - */ - static createAnd(expressions: Expression[]): Expression { - return this.createLogical('and', expressions); - } - - /** - * Creates an OR expression - * @param expressions The expressions to combine - * @returns An OR expression - */ - static createOr(expressions: Expression[]): Expression { - return this.createLogical('or', expressions); - } - - /** - * Creates an aggregate expression - * @param operator The aggregation operator - * @param group_by The group by field - * @param expression The model path to aggregate - * @param condition The condition expression - * @returns An aggregate expression - */ - static createAggregate( - operator: AggregationOperator, - group_by: string, - expression: ModelPath, - condition: Expression - ): Expression { - return { operator, group_by, expression, condition }; - } -} \ No newline at end of file diff --git a/sdk/typescript/src/expression-factory/location-operand-factory.ts b/sdk/typescript/src/expression-factory/location-operand-factory.ts deleted file mode 100644 index 430df53..0000000 --- a/sdk/typescript/src/expression-factory/location-operand-factory.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { LocationOperand } from '@mparticle/audience-typescript-schema/operand/location-operand'; -import { Location, DistanceUnit } from '@mparticle/audience-typescript-schema/common/location'; - -export class LocationOperandFactory { - /** - * Creates a location operand with latitude and longitude - * @param latitude The latitude - * @param longitude The longitude - */ - static createLocation(latitude: number, longitude: number): LocationOperand { - const location: Location = { - latitude, - longitude - }; - return { location }; - } - - /** - * Creates a location operand with latitude, longitude, and distance - * @param latitude The latitude - * @param longitude The longitude - * @param distanceValue The distance value - * @param distanceUnit The distance unit - */ - static createLocationWithDistance( - latitude: number, - longitude: number, - distanceValue: number, - distanceUnit: DistanceUnit - ): LocationOperand { - const location: Location = { - latitude, - longitude, - distance: { - value: distanceValue, - unit: distanceUnit - } - }; - return { location }; - } - - /** - * Creates a location operand with latitude, longitude, and distance in meters - * @param latitude The latitude - * @param longitude The longitude - * @param meters The distance in meters - */ - static createLocationWithMeters( - latitude: number, - longitude: number, - meters: number - ): LocationOperand { - return this.createLocationWithDistance(latitude, longitude, meters, 'meters'); - } - - /** - * Creates a location operand with latitude, longitude, and distance in miles - * @param latitude The latitude - * @param longitude The longitude - * @param miles The distance in miles - */ - static createLocationWithMiles( - latitude: number, - longitude: number, - miles: number - ): LocationOperand { - return this.createLocationWithDistance(latitude, longitude, miles, 'miles'); - } - - /** - * Creates a location operand with latitude, longitude, and distance in kilometers - * @param latitude The latitude - * @param longitude The longitude - * @param kilometers The distance in kilometers - */ - static createLocationWithKilometers( - latitude: number, - longitude: number, - kilometers: number - ): LocationOperand { - return this.createLocationWithDistance(latitude, longitude, kilometers, 'kilometers'); - } -} \ No newline at end of file diff --git a/sdk/typescript/src/expression-factory/operand-factory.ts b/sdk/typescript/src/expression-factory/operand-factory.ts deleted file mode 100644 index dbc43a3..0000000 --- a/sdk/typescript/src/expression-factory/operand-factory.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { Operand } from '@mparticle/audience-typescript-schema/operand/operand'; -import { DateOperand } from '@mparticle/audience-typescript-schema/operand/date-operand'; -import { LocationOperand } from '@mparticle/audience-typescript-schema/operand/location-operand'; -import { ArithmeticOperator } from '@mparticle/audience-typescript-schema/common/operator'; -import { DateOperandFactory } from './date-operand-factory'; -import { LocationOperandFactory } from './location-operand-factory'; -/** - * Factory class for creating different types of operands - */ -export class OperandFactory { - - /** - * Creates a model and path operand - * @param path The path to reference - * @returns A path operand - */ - static createModelPath(model: string, path: string): Operand { - return { model, path }; - } - - /** - * Creates a date operand - * @param dateOperand The date operand - * @returns A date operand - */ - static createDate(dateOperand: DateOperand): Operand { - return dateOperand; - } - - /** - * Creates an arithmetic operand - * @param operator The arithmetic operator - * @param left The left operand - * @param right The right operand - * @returns An arithmetic operand - */ - static createArithmetic( - operator: ArithmeticOperator, - left: Operand, - right: Operand - ): Operand { - return { - operator, - left, - right - }; - } - - /** - * Creates an absolute date operand - * @param dateString The ISO 8601 date string - * @returns A date operand - */ - static createAbsoluteDate(dateString: string): DateOperand { - return DateOperandFactory.createAbsoluteDate(dateString); - } - - /** - * Creates a relative date operand - * @param offset The number of units to offset - * @param unit The unit of time - * @param boundary Optional boundary specification - * @returns A date operand - */ - static createRelativeDate( - offset: number, - unit: string, - boundary?: 'start' | 'end' - ): DateOperand { - return DateOperandFactory.createRelativeDate(offset, unit as any, boundary); - } - - /** - * Creates a location operand with latitude and longitude - * @param latitude The latitude - * @param longitude The longitude - * @returns A location operand - */ - static createLocationPoint(latitude: number, longitude: number): LocationOperand { - return LocationOperandFactory.createLocation(latitude, longitude); - } - - /** - * Creates a location operand with latitude, longitude, and distance in meters - * @param latitude The latitude - * @param longitude The longitude - * @param meters The distance in meters - * @returns A location operand - */ - static createLocationWithMeters( - latitude: number, - longitude: number, - meters: number - ): LocationOperand { - return LocationOperandFactory.createLocationWithMeters(latitude, longitude, meters); - } - - /** - * Creates a location operand with latitude, longitude, and distance in miles - * @param latitude The latitude - * @param longitude The longitude - * @param miles The distance in miles - * @returns A location operand - */ - static createLocationWithMiles( - latitude: number, - longitude: number, - miles: number - ): LocationOperand { - return LocationOperandFactory.createLocationWithMiles(latitude, longitude, miles); - } - - /** - * Creates a location operand with latitude, longitude, and distance in kilometers - * @param latitude The latitude - * @param longitude The longitude - * @param kilometers The distance in kilometers - * @returns A location operand - */ - static createLocationWithKilometers( - latitude: number, - longitude: number, - kilometers: number - ): LocationOperand { - return LocationOperandFactory.createLocationWithKilometers(latitude, longitude, kilometers); - } -} \ No newline at end of file diff --git a/sdk/typescript/src/expression-factory/path-expression-factory.ts b/sdk/typescript/src/expression-factory/path-expression-factory.ts deleted file mode 100644 index a337964..0000000 --- a/sdk/typescript/src/expression-factory/path-expression-factory.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { PathExpression } from '@mparticle/audience-typescript-schema/expression/path-expression'; -import { Operand } from '@mparticle/audience-typescript-schema/operand/operand'; -import { UnaryOperator, BinaryOperator } from '@mparticle/audience-typescript-schema/common/operator'; -import { Expression } from '@mparticle/audience-typescript-schema/expression/expression'; - -/** - * Factory class for creating different types of path expressions - */ -export class PathExpressionFactory { - - /** - * Creates a unary path expression - * @param operator The unary operator - * @param expression The expression to operate on - * @returns A unary path expression - */ - static createUnary( - operator: UnaryOperator, - expression: PathExpression - ): PathExpression { - return { operator, expression }; - } - - /** - * Creates a binary path expression - * @param operator The binary operator - * @param operand The operand to operate on - * @returns A binary path expression - */ - static createBinary( - operator: BinaryOperator, - operand: Operand - ): PathExpression { - return { operator, operand }; - } - - /** - * Creates a NOT path expression - * @param expression The expression to negate - * @returns A NOT path expression - */ - static createNot(expression: PathExpression): PathExpression { - return this.createUnary('not', expression); - } -} \ No newline at end of file diff --git a/sdk/typescript/src/index.ts b/sdk/typescript/src/index.ts deleted file mode 100644 index a035801..0000000 --- a/sdk/typescript/src/index.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { AudienceBuilder } from './audience-builder'; -import { LogicalExpressionBuilder } from './audience-builder'; -import { QueryBuilder } from './query-builders/query-builder'; -import { Audience } from '@mparticle/audience-typescript-schema'; -/** - * Validates an Audience object - * @param audience The audience to validate - * @returns true if the audience is valid, false otherwise - */ -export function validateAudience(audience: Audience): boolean { - try { - // Ensure the audience has the required structure - if (!audience.schema_version || !audience.audience || !audience.audience.operator || !audience.audience.queries) { - return false; - } - - // Validate that there is at least one query - if (audience.audience.queries.length === 0) { - return false; - } - - // Validate that the operator is either 'and' or 'or' - if (audience.audience.operator !== 'and' && audience.audience.operator !== 'or') { - return false; - } - - return true; - } catch (error) { - return false; - } -} - -/** - * Parses a JSON string into an Audience object - * @param json The JSON string to parse - * @returns The parsed Audience object - * @throws Error if the JSON is invalid or doesn't match the Audience type - */ -export function parseAudience(json: string): Audience { - try { - const audience = JSON.parse(json) as Audience; - if (!validateAudience(audience)) { - throw new Error('Invalid audience structure'); - } - return audience; - } catch (error) { - throw new Error('Failed to parse audience JSON'); - } -} - -/** - * Converts an Audience object to a JSON string - * @param audience The audience to convert - * @returns The JSON string representation of the audience - * @throws Error if the audience is invalid - */ -export function stringifyAudience(audience: Audience): string { - if (!validateAudience(audience)) { - throw new Error('Invalid audience'); - } - return JSON.stringify(audience, null, 2); -} - -export { CountExpressionFactory } from './expression-factory/count-expression-factory'; -export { DateOperandFactory } from './expression-factory/date-operand-factory'; -export { ExpressionFactory } from './expression-factory/expression-factory'; -export { LocationOperandFactory } from './expression-factory/location-operand-factory'; -export { OperandFactory } from './expression-factory/operand-factory'; -export { PathExpressionFactory } from './expression-factory/path-expression-factory'; - -export { QueryBuilder } from './query-builders/query-builder'; - -export { AudienceBuilder } from './audience-builder'; \ No newline at end of file diff --git a/sdk/typescript/src/query-builders/query-builder.ts b/sdk/typescript/src/query-builders/query-builder.ts deleted file mode 100644 index 55afc54..0000000 --- a/sdk/typescript/src/query-builders/query-builder.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Query } from '@mparticle/audience-typescript-schema/query/query'; -import { Expression } from '@mparticle/audience-typescript-schema/expression/expression'; - -export class QueryBuilder { - protected model?: string; - protected expression?: Expression; - - /** - * Sets the models for the query - * @param models The model names, IDs, or model objects with type - */ - setModel(model: string): this { - this.model = model; - return this; - } - - /** - * Sets the expression for the query - * @param expression The expression to use - */ - setExpression(expression: Expression): this { - this.expression = expression; - return this; - } - - /** - * Builds and returns the query - */ - build(): Query { - if (!this.model) { - throw new Error('Model is required for a general query'); - } - - return { - model: this.model, - ...(this.expression && { expression: this.expression }) - }; - } -} \ No newline at end of file diff --git a/sdk/typescript/tsconfig.json b/sdk/typescript/tsconfig.json deleted file mode 100644 index c88826f..0000000 --- a/sdk/typescript/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "es2018", - "module": "commonjs", - "declaration": true, - "outDir": "./dist", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "**/*.test.ts"] -} \ No newline at end of file