{
    "$schema": "http://json-schema.org/schema#",
    "type": "object",
    "title": "OmniGraph Compute Node Interface Description",
    "description": "Contains a description of the interfaces available on one or more OmniGraph Compute Nodes.",

    "$comments": "If any dictionary keyword begins with a '$' it will be treated as a comment",

    "definitions": {
        "commentType": {
          "description": "Pattern to allow $comment to be used with any data to annotate the file",
          "type": ["array", "boolean", "integer", "number", "object", "string"]
        },

        "languageType": {
          "description": "Values recognized as valid node language types",
          "pattern": "^(cpp|c\\+\\+|cu|cuda|py|python)$"
        },

        "tags": {
            "description": "Single value or list of value to use as tags on the node",
            "type": ["array", "string"]
          },

          "schedulingHints": {
            "description": "Values recognized as valid scheduling hints",
            "pattern": "^(global|global-read|global-write|static|static-read|static-write|threadsafe|topology|topology-read|topology-write|usd|usd-read|usd-write|compute-default|compute-on-request)$"
          },

          "color": {
            "description": "RGBA Color specification",
            "oneOf": [
                { "pattern": "^#[0-9a-fA-F]{8}$" },
                { "type": "array", "items": { "type": "integer", "minItems": 4, "maxItems": 4 } }
            ]
        },

        "iconDictionary": {
            "description": "Long form specifying icon properties by keyword",
            "type": "object",
            "properties": {
              "path": { "type": "string" },
              "color": { "$ref": "#/definitions/color" },
              "backgroundColor": { "$ref": "#/definitions/color" },
              "borderColor": { "$ref": "#/definitions/color" }
            }
        },
        "icon": {
            "description": "Single string path or dictionary of detailed information to override icon appearance",
            "oneOf": [
                { "type" : "string" },
                { "$ref": "#/definitions/iconDictionary" }
            ]
          },

        "attributeValue": {
          "description": "Simplified match for attribute values specified in the file (no type validation)",
          "type": ["array", "boolean", "integer", "number", "string"]
        },

        "attributeValueType": {
          "description": "Types of data recognized as valid attribute data in JSON form",
          "type": ["array", "boolean", "integer", "number", "string"]
        },

        "typedAttributeValue": {
            "description": "An attribute value that includes type information",
            "type": "object",
            "properties": {
                "type": { "$ref": "#/definitions/attributePattern" },
                "value": { "$ref": "#/definitions/attributeValueType" }
            }
        },

        "maybeTypedAttributeValue": {
            "description": "An attribute value that may be typed",
            "oneOf": [
                { "$ref": "#/definitions/attributeValueType" },
                { "$ref": "#/definitions/typedAttributeValue" }
            ]
        },

        "$subtypes": {"what":"Patterns for matching the attribute type declaration"},
        "simpleType": {
            "description": "Matches an attribute type pattern with no component counts or arrays",
            "pattern": "^[^\\[\\]]+$"
        },
        "componentType": {
            "description": "Matches an attribute type pattern with a simple value with a component count",
            "pattern": "^[^\\[\\]]+\\[[0-9]{1,3}\\]$"
        },
        "arrayType": {
            "description": "Matches an attribute type pattern for an array of simple values",
            "pattern": "^[^\\[\\]]+\\[\\]$"
        },
        "arrayOfArraysType": {
            "description": "Matches an attribute type pattern for an array of arrays of simple values",
            "pattern": "^[^\\[\\]]+\\[\\]\\[\\]$"
        },
        "componentArrayType": {
            "description": "Matches an attribute type pattern for an array of components",
            "pattern": "^[^\\[\\]]+\\[[0-9]{1,3}\\]\\[\\]$"
        },
        "componentArrayOfArraysType": {
            "description": "Matches an attribute type pattern for an array of arrays of components",
            "pattern": "^[^\\[\\]]+\\[[0-9]{1,3}\\]\\[\\]\\[\\]$"
        },
        "attributeTypeName": {
              "description": "Simple attribute type name portion of the pattern",
              "pattern": "^(any|bool|bundle|double|execution|float|half|int|int64|path|string|timecode|token|uchar|uint|uint64)"
        },
        "attributeTypeNameWithRoles": {
              "description": "Simple attribute type name portion of the pattern including role-based attributes",
              "pattern": "^(any|bool|bundle|double|execution|float|half|int|int64|objectId|string|timecode|token|uchar|uint|uint64|(color|normal|point|quat|path|texcoord|vector|(d|f|h))|matrixd|frame|transform)"
        },
        "numericAttributeTypeName": {
            "description": "Numeric attribute types supporting min/max values",
            "pattern": "^(double|float|half|int|int64|timecode|uchar|uint|uint64)"
        },
        "numericAttributeTypeNameWithRoles": {
          "description": "Numeric and role-based attribute types supporting min/max values",
          "pattern": "^(double|float|half|int|int64|timecode|uchar|uint|uint64|(color|normal|point|quat|texcoord|vector|(d|f|h))|(matrix(d|f))|frame|transform)"
        },



        "$allTypes": {"what":"Patterns for matching all valid attribute types and their component or array extensions"},
        "attributePatternSimple": {
            "description": "Simple attribute types, no components or arrays",
            "allOf": [
                { "$ref": "#/definitions/attributeTypeName" },
                { "$ref": "#/definitions/simpleType" }
            ]
        },
        "attributePatternComponent": {
            "description": "Simple attribute types with a non-zero component count, no arrays",
            "allOf": [
                { "$ref": "#/definitions/attributeTypeNameWithRoles" },
                { "$ref": "#/definitions/componentType" }
            ]
        },
        "attributePatternArray": {
            "description": "Array attribute types with no components",
            "allOf": [
                { "$ref": "#/definitions/attributeTypeName" },
                { "$ref": "#/definitions/arrayType" }
            ]
        },
        "attributePatternArrayOfArrays": {
            "description": "Array of arrays of attribute types with no components",
            "allOf": [
                { "$ref": "#/definitions/attributeTypeName" },
                { "$ref": "#/definitions/arrayOfArraysType" }
            ]
        },
        "attributePatternComponentArray": {
            "description": "Array attribute types with a non-zero component count",
            "allOf": [
                { "$ref": "#/definitions/attributeTypeNameWithRoles" },
                { "$ref": "#/definitions/componentArrayType" }
            ]
        },
        "attributePatternComponentArrayOfArrays": {
            "description": "Array of arrays of attribute types with a non-zero component count",
            "allOf": [
                { "$ref": "#/definitions/attributeTypeNameWithRoles" },
                { "$ref": "#/definitions/componentArrayOfArraysType" }
            ]
        },
        "attributePattern": {
            "description": "Match all of the simple types, plus an optional component count, and optional array type",
            "oneOf": [
                { "$ref": "#/definitions/attributePatternSimple" },
                { "$ref": "#/definitions/attributePatternComponent" },
                { "$ref": "#/definitions/attributePatternArray" },
                { "$ref": "#/definitions/attributePatternArrayOfArrays" },
                { "$ref": "#/definitions/attributePatternComponentArray" },
                { "$ref": "#/definitions/attributePatternComponentArrayOfArrays" }
            ]
        },



        "$numericTypes": {"what":"Patterns for recognizing the numeric types, for special handling"},
        "numericAttributePatternSimple": {
            "description": "Numeric attribute types, no components or arrays",
            "allOf": [
                { "$ref": "#/definitions/numericAttributeTypeName" },
                { "$ref": "#/definitions/simpleType" }
            ]
        },
        "numericAttributePatternComponent": {
            "description": "Numeric attribute types with a non-zero component count, no arrays",
            "allOf": [
                { "$ref": "#/definitions/numericAttributeTypeNameWithRoles" },
                { "$ref": "#/definitions/componentType" }
            ]
        },
        "numericAttributePatternArray": {
            "description": "Array of numeric attribute types with no components",
            "allOf": [
                { "$ref": "#/definitions/numericAttributeTypeName" },
                { "$ref": "#/definitions/arrayType" }
            ]
        },
        "numericAttributePatternArrayOfArrays": {
            "description": "Array of arrays of numeric attribute types with no components",
            "allOf": [
                { "$ref": "#/definitions/numericAttributeTypeName" },
                { "$ref": "#/definitions/arrayOfArraysType" }
            ]
        },
        "numericAttributePatternComponentArray": {
            "description": "Array of numeric attribute types with a non-zero component count",
            "allOf": [
                { "$ref": "#/definitions/numericAttributeTypeNameWithRoles" },
                { "$ref": "#/definitions/componentArrayType" }
            ]
        },
        "numericAttributePatternComponentArrayOfArrays": {
            "description": "Array of arrays of numeric attribute types with a non-zero component count",
            "allOf": [
                { "$ref": "#/definitions/numericAttributeTypeNameWithRoles" },
                { "$ref": "#/definitions/componentArrayOfArraysType" }
            ]
        },
        "numericAttributePattern": {
            "description": "Match all of the numeric types, plus an optional component count, and optional array type",
            "oneOf": [
                { "$ref": "#/definitions/numericAttributePatternSimple" },
                { "$ref": "#/definitions/numericAttributePatternComponent" },
                { "$ref": "#/definitions/numericAttributePatternArray" },
                { "$ref": "#/definitions/numericAttributePatternArrayOfArrays" },
                { "$ref": "#/definitions/numericAttributePatternComponentArray" },
                { "$ref": "#/definitions/numericAttributePatternComponentArrayOfArrays" }
            ]
        },

        "memoryTypeName": {
          "description": "Node or attribute-level specification of the memory location",
          "type": "string",
          "pattern": "^(cpu|cuda|any)$"
        },

        "metadata": {
          "description": "Key/Value pairs to be stored with the node or attribute type definition",
          "type": "object",
          "additionalProperties": false,
          "patternProperties": {
              "^\\$": { "$ref": "#/definitions/commentType" },
              "^[^\\$].*": { "type" : "string" }
          }
        },

        "attribute": {
            "type": "object",
            "description": "A single attribute on a node",
            "required": ["description", "type"],
            "properties": {
                "description": { "type": ["string", "array"], "items": { "type": "string" } },
                "array": { "type": "boolean", "default": false },
                "optional": { "type": "boolean", "default": false },
                "unvalidated": { "type": "boolean", "default": false },
                "memoryType": { "$ref": "#/definitions/memoryTypeName" },
                "metadata": { "$ref": "#/definitions/metadata" },
                "type": { "$ref": "#/definitions/attributePattern" },
                "uiName": { "type": "string" }
            },
            "patternProperties": {
                "^\\$": { "$ref": "#/definitions/commentType" }
            },

            "$extraProperties": "Collection of properties that are conditional on attribute types or other values",
            "allOf": [
                {
                    "$attributeDefaults": "Define attribute default types, where omission is okay if attribute is optional or an output",
                    "if" : {
                        "required": ["default"]
                    },
                    "then": {
                        "$comment": "If the default is provided then validate its type",
                        "$ref": "#/definitions/attributeValue"
                    }
                },
                {
                    "description": "A minimum value is only supported on certain attribute types",
                    "if": {
                        "required": ["minimum"]
                    },
                    "then": {
                        "$comment": "If the minimum is provided then validate its type",
                        "$ref": "#/definitions/attributeValue"
                    }
                },
                {
                    "description": "A maximum value is only supported on certain attribute types",
                    "if": {
                        "required": ["maximum"]
                    },
                    "then": {
                        "$comment": "If the maximum is provided then validate its type",
                        "$ref": "#/definitions/attributeValue"
                    }
                }
            ]
        },
        "attributes": {
            "type": "object",
            "default": {},
            "description": "A subset of attributes on a node",
            "$comment": "Attribute names are alphanumeric with underscores, not starting with a number, allowing periods and colons as separators",
            "additionalProperties": false,
            "patternProperties": {
                "^[A-Za-z_][A-Za-z0-9_.:]*$": { "$ref": "#/definitions/attribute" },
                "^\\$" : { "$ref": "#/definitions/commentType" }
            }
        },
        "tests": {
            "description": "Tests consist of a list of objects containing values for input and output attributes",
            "type": "array",
            "items": {
                "description": "Attribute values can either be namespaces as inputs:X/outputs:X/state:X or in objects with keys inputs/outputs/state",
                "type": "object",
                "patternProperties": {
                    "description": { "$ref": "#/definitions/commentType" },
                    "^inputs$": {
                      "type": "object",
                      "description": "Alternative way of specifying inputs without namespacing",
                      "patternProperties": {
                        "^[A-Za-z_][A-Za-z0-9_.:]*$": { "$ref": "#/definitions/maybeTypedAttributeValue" }
                      }
                    },
                    "^outputs$": {
                      "type": "object",
                      "description": "Alternative way of specifying outputs without namespacing",
                      "patternProperties": {
                        "^[A-Za-z_][A-Za-z0-9_.:]*$": { "$ref": "#/definitions/maybeTypedAttributeValue" }
                      }
                    },
                    "^state$": {
                      "type": "object",
                      "description": "Alternative way of specifying state without namespacing",
                      "patternProperties": {
                          "^[A-Za-z_][A-Za-z0-9_.:]*$": { "$ref": "#/definitions/maybeTypedAttributeValue" }
                      }
                    },
                    "^setup$": {
                      "type": "object",
                      "description": "Detailed graph setup prior to a test",
                      "properties": {
                        "nodes": { "type": "array" },
                        "connections": { "type": "array" },
                        "prims": { "type": "array" },
                        "values": { "type": "object" }
                      }
                    },
                    "^inputs:[A-Za-z_][A-Za-z0-9_.:]*$": { "$ref": "#/definitions/maybeTypedAttributeValue" },
                    "^outputs:[A-Za-z_][A-Za-z0-9_.:]*$": { "$ref": "#/definitions/maybeTypedAttributeValue" },
                    "^state:[A-Za-z_][A-Za-z0-9_.:]*$": { "$ref": "#/definitions/maybeTypedAttributeValue" },
                    "^\\$" : { "$ref": "#/definitions/commentType" }
                }
            }
        },
        "node": {
            "type": "object",
            "description": "Referenced schema for describing an OmniGraph Compute Node",
            "required": ["description"],
            "additionalProperties": false,
            "patternProperties": {
                "categories": { "$ref": "#/definitions/categoriesName" },
                "categoryType": { "$ref": "#/definitions/categoryTypeName" },
                "description": { "type": ["string", "array"], "items": { "type": "string" } },
                "exclude": { "type": ["string", "array"], "items": { "type": "string" } },
                "language": { "$ref": "#/definitions/languageType" },
                "inputs": { "$ref": "#/definitions/attributes" },
                "outputs": { "$ref": "#/definitions/attributes" },
                "state": { "$ref": "#/definitions/attributes" },
                "tests": { "$ref": "#/definitions/tests" },
                "version": { "type": "integer", "default": 1 },
                "metadata": { "$ref": "#/definitions/metadata" },
                "memoryType": { "$ref": "#/definitions/memoryTypeName" },
                "scheduling": {
                    "oneOf": [
                        { "type" : "string" },
                        { "$ref": "#/definitions/schedulingHints" }
                    ]
                },
                "uiName": { "type": "string" },
                "icon": { "$ref": "#/definitions/icon" },
                "tags": { "$ref": "#/definitions/tags" },
                "^\\$" : { "$ref": "#/definitions/commentType" }
            }
        }
    },

    "$limitation": "A valid file must have at least one node interface definition",
    "minProperties": 1,

    "additionalProperties": false,
    "patternProperties": {
        "^[A-Za-z_][A-Za-z0-9_]*$": { "$ref": "#/definitions/node" },
        "^\\$" : { "$ref": "#/definitions/commentType" }
    }
}
