{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "id": "https://morphosjs.org/schemas/mapping.json",
    "title": "Mapping Schema for JSON Data Transformations",
    "description": "A schema defining a structure for JSON mappings. Field names in the mappings correspond to fields in the destination JSON format, while field values can be JavaScript expressions, wildcard current-context copies, or nested mapping instructions.",
    "oneOf": [
        {
            "$ref": "#/definitions/StrictMappingObject"
        },
        {
            "$ref": "#/definitions/ObjectFieldsMapping"
        }
    ],
    "definitions": {
        "AnyMapping": {
            "oneOf": [
                {
                    "title": "JavaScript Expression",
                    "$ref": "#/definitions/JsExpression"
                },
                {
                    "title": "Strict Mapping Object",
                    "$ref": "#/definitions/StrictMappingObject"
                },
                {
                    "title": "Object Fields Mapping",
                    "$ref": "#/definitions/ObjectFieldsMapping"
                }
            ]
        },
        "JsExpression": {
            "title": "JavaScript Expression",
            "description": "A valid JavaScript expression represented as a string. Will be evaluated in the context of the current source object. The expression \"*\" copies all fields/elements from the current source context.",
            "type": "string",
            "minLength": 1,
            "examples": [
                "`Invoice ${ID}`",
                "QTY * PRICE",
                "*",
                "true",
                "UPC.substring(0, 5)",
                "LINE_ITEMS.find(i => i.QTY == 0)"
            ]
        },
        "StrictMappingObject": {
            "oneOf": [
                {
                    "$ref": "#/definitions/ValueMapping"
                },
                {
                    "$ref": "#/definitions/ObjectFieldsExplicitMapping"
                },
                {
                    "$ref": "#/definitions/ContextSwitch"
                },
                {
                    "$ref": "#/definitions/ConditionalMapping"
                },
                {
                    "$ref": "#/definitions/ConcatMapping"
                },
                {
                    "$ref": "#/definitions/TupleMapping"
                },
                {
                    "$ref": "#/definitions/ArrayIterator"
                }
            ]
        },
        "ValueMapping": {
            "title": "Value Mapping",
            "description": "Maps the destination value. No wrapping object will be created. This can be useful for root element, arrays, or context switching, when `\"map\": {}` wrapper is required, but a simple type output is needed.",
            "type": "object",
            "minProperties": 1,
            "properties": {
                "*": {
                    "$ref": "#/definitions/AnyMapping"
                }
            },
            "required": [
                "*"
            ],
            "not": {
                "properties": {
                    "*": {
                        "const": "*"
                    }
                },
                "required": [
                    "*"
                ]
            },
            "additionalProperties": false
        },
        "ObjectFieldsMapping": {
            "title": "Object Fields Mapping",
            "description": "Maps the fields of a destination object. Each key-value pair in the mapping represents a field and its mapping expression. A \"*\": \"*\" entry copies all current source object fields or array elements before explicit mappings are applied.",
            "type": "object",
            "minProperties": 1,
            "properties": {
                "*": {
                    "title": "Wildcard Spread",
                    "description": "Copies all fields from the current source object or array before applying explicit field mappings.",
                    "const": "*"
                }
            },
            "patternProperties": {
                "^(?!(\\*|map|forEach|from|when|then|else|concat)$).+$": {
                    "$ref": "#/definitions/AnyMapping"
                }
            },
            "additionalProperties": false,
            "examples": [
                {
                    "code": "UPC.substring(0, 5)",
                    "qty": "QTY",
                    "price": "PRICE",
                    "amount": "QTY * PRICE"
                },
                {
                    "*": "*",
                    "mappedName": "NAME"
                },
                {
                    "rawData": "*",
                    "mappedName": "NAME"
                }
            ]
        },
        "ObjectFieldsExplicitMapping": {
            "title": "Object Explicit Mapping",
            "description": "Maps a source object to a destination object. Requires a 'map' property containing a mapping expression for the source object.",
            "type": "object",
            "properties": {
                "map": {
                    "$ref": "#/definitions/ObjectFieldsMapping"
                }
            },
            "required": [
                "map"
            ],
            "additionalProperties": false
        },
        "TupleMapping": {
            "title": "Tuple Mapping",
            "description": "Maps elements of a source array to a destination array. Each element in the mapping array is a mapping expression for corresponding elements in the source array.",
            "type": "array",
            "items": {
                "$ref": "#/definitions/AnyMapping"
            },
            "examples": [
                [
                    {
                        "foo": "'bar'"
                    },
                    "AMOUNT"
                ]
            ]
        },
        "ArrayIterator": {
            "title": "Array Iterator",
            "description": "Maps a source array to a destination array. Requires 'forEach' property to specify the selector of source values, and 'map' property containing a mapping expression for each element.",
            "type": "object",
            "properties": {
                "forEach": {
                    "title": "Source Selector",
                    "description": "A JavaScript expression that selects values from the source array which should be used as the primary source for destination values mapping.",
                    "$ref": "#/definitions/JsExpression"
                },
                "map": {
                    "$ref": "#/definitions/AnyMapping"
                }
            },
            "required": [
                "forEach",
                "map"
            ],
            "additionalProperties": false,
            "examples": [
                {
                    "forEach": "LINE_ITEMS",
                    "map": {
                        "code": "UPC.substring(0, 5)",
                        "qty": "QTY",
                        "price": "PRICE",
                        "amount": "QTY * PRICE"
                    }
                },
                {
                    "forEach": "LINE_ITEMS",
                    "map": {
                        "*": "*",
                        "amount": "QTY * PRICE"
                    }
                }
            ]
        },
        "ContextSwitch": {
            "title": "Context Switch",
            "description": "Switch context of the current source object. Source object values can be referenced in map directly.",
            "type": "object",
            "properties": {
                "from": {
                    "title": "Source Selector",
                    "description": "A JavaScript expression that selects the source object/value which should be used as the primary source for destination mapping.",
                    "$ref": "#/definitions/JsExpression"
                },
                "map": {
                    "$ref": "#/definitions/AnyMapping"
                }
            },
            "required": [
                "from",
                "map"
            ],
            "examples": [
                {
                    "from": "BUYER",
                    "map": {
                        "rawData": "*",
                        "mappedName": "NAME"
                    }
                },
                {
                    "from": "BUYER",
                    "map": {
                        "*": "*",
                        "mappedName": "NAME"
                    }
                }
            ],
            "additionalProperties": false
        },
        "ConditionalMapping": {
            "title": "Conditional Mapping",
            "description": "Maps a value only when a JavaScript condition is truthy. Without 'else', a false condition omits the destination field when used inside an object mapping.",
            "type": "object",
            "properties": {
                "when": {
                    "title": "Condition",
                    "description": "A JavaScript expression evaluated in the current source context.",
                    "$ref": "#/definitions/JsExpression"
                },
                "then": {
                    "$ref": "#/definitions/AnyMapping"
                },
                "else": {
                    "$ref": "#/definitions/AnyMapping"
                }
            },
            "required": [
                "when",
                "then"
            ],
            "additionalProperties": false,
            "examples": [
                {
                    "when": "shipment.billOfLadingNumber",
                    "then": "shipment.billOfLadingNumber"
                }
            ]
        },
        "ConcatMapping": {
            "title": "Concat Mapping",
            "description": "Builds an array by evaluating a list of mappings, skipping omitted conditional branches, and flattening array results.",
            "type": "object",
            "properties": {
                "concat": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/AnyMapping"
                    }
                }
            },
            "required": [
                "concat"
            ],
            "additionalProperties": false,
            "examples": [
                {
                    "concat": [
                        {
                            "when": "shipment.purchaseOrderNumber",
                            "then": {
                                "type": "'po'",
                                "bizTransaction": "shipment.purchaseOrderNumber"
                            }
                        }
                    ]
                }
            ]
        }
    }
}
