{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "JSON Recipe",
    "description": "A schema for recipes.",
    "type": "object",
    "definitions": {
        "source": {
            "description": "The source of the recipe (e.g. the person who wrote it and the book where it was found).",
            "type": "object",
            "required": ["author"],
            "properties": {
                "author": {
                    "description": "The full name of the author of the recipe.",
                    "type": "string"
                },
                "location": {
                    "description": "The location from which the recipe was retrived (e.g. a website or a book).",
                    "type": "object",
                    "oneOf": [{ "$ref": "#/definitions/webLocation" }]
                }
            }
        },
        "webLocation": {
            "description": "A website or other source accessible online.",
            "type": "object",
            "required": ["url"],
            "properties": {
                "url": {
                    "description": "The URL of the source material.",
                    "type": "string",
                    "format": "uri"
                },
                "retrievalDate": {
                    "description": "The date on which the recipe was retrieved from the source.",
                    "type": "string",
                    "format": "date"
                }
            }
        },
        "quantity": {
            "oneOf": [
                { "type": "integer" },
                {
                    "description": "The quantity as a fractional string, such as \"1 1/3\".",
                    "type": "string",
                    "pattern": "^[1-9][0-9]* ?((/| [1-9][0-9]* ?/) ?[1-9][0-9]*)?$"
                }
            ]
        },
        "ingredient": {
            "oneOf": [
                {
                    "description": "An ingredient listing as a string, in the format \"<quantity> <unit> <item>[, <preparation>]*\".",
                    "type": "string",
                    "pattern": "^[1-9][0-9]* ?((/| [1-9][0-9]* ?/) ?[1-9][0-9]*)? [^ ]+ [^,]*[^, ](, [^,]*[^, ])*$"
                },
                {
                    "description": "An ingredient listing as an object.",
                    "type": "object",
                    "required": ["quantity", "item"],
                    "additionalProperties": false,
                    "properties": {
                        "quantity": {
                            "description": "The quantity of the specified item, in terms of the specified unit.",
                            "allOf": [{ "$ref": "#/definitions/quantity" }]
                        },
                        "unit": {
                            "description": "The unit of measurement which the specified quantity uses (e.g. \"cup\").",
                            "type": "string",
                            "default": "each"
                        },
                        "item": {
                            "description": "The item of which this ingredient consists (e.g. \"apple\").",
                            "type": "string"
                        },
                        "preparation": {
                            "description": "How the ingredient should be prepared prior to use (e.g. \"chopped\").",
                            "anyOf": [
                                { "type": "string" },
                                { "type": "array", "items": { "type": "string" } }
                            ]
                        }
                    }
                }
            ]
        },
        "ingredientGroup": {
            "description": "A group of ingredients under a single heading.",
            "type": "object",
            "required": ["heading", "ingredients"],
            "additionalProperties": false,
            "properties": {
                "heading": {
                    "description": "The heading for this group of ingredients.",
                    "type": "string"
                },
                "ingredients": {
                    "description": "The ingredients under this heading.",
                    "type": "array",
                    "items": { "$ref": "#/definitions/ingredient" }
                }
            }
        },
        "direction": {
            "description": "A single step in the preparation of the recipe.",
            "type": "string"
        },
        "directionGroup": {
            "description": "A group of directions under a single heading.",
            "type": "object",
            "required": ["heading", "directions"],
            "additionalProperties": false,
            "properties": {
                "heading": {
                    "description": "The heading for this group of directions.",
                    "type": "string"
                },
                "directions": {
                    "description": "The directions under this heading.",
                    "type": "array",
                    "items": { "$ref": "#/definitions/direction" }
                }
            }
        }
    },
    "required": ["title", "ingredients", "directions"],
    "properties": {
        "meta": {
            "description": "Meta information that does not relate directly to the recipe itself, such as the schema version used.",
            "type": "object",
            "properties": {
                "schemaVersion": {
                    "description": "The version of this schema under which the recipe was written. The schema follows semantic versioning, so recipes written under version 1.2.3 will be compatible with schema version 1.4.5, but not necessarily the other way around.",
                    "type": "string",
                    "const": "0.0.0"
                }
            }
        },
        "title": {
            "description": "The title of the recipe.",
            "type": "string"
        },
        "source": { "$ref": "#/definitions/source" },
        "ingredients": {
            "description": "The ingredients of the recipe.",
            "type": "array",
            "items": {
                "oneOf": [
                    { "$ref": "#/definitions/ingredient" },
                    { "$ref": "#/definitions/ingredientGroup" }
                ]
            }
        },
        "directions": {
            "description": "The instructions for preparing the finished product from the ingredients.",
            "type": "array",
            "items": {
                "oneOf": [
                    { "$ref": "#/definitions/direction" },
                    { "$ref": "#/definitions/directionGroup" }
                ]
            }
        }
    }
}
