{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://geojason.com/data/geojson.schema.json",
  "title": "GeoJSON (RFC 7946)",
  "description": "RFC 7946 expressed as JSON Schema. Rules this file does not carry are listed in notExpressible, which no schema can state, and notChecked, which this file leaves open.",
  "$comment": "Foreign members are permitted by RFC 7946 section 6.1, so no object in this schema sets additionalProperties to false.",
  "stricterThanSpec": [
    "A position may carry at most three elements. RFC 7946 says implementations SHOULD NOT go beyond three, which is advice rather than a rule, so this schema refuses a document the specification does not call invalid."
  ],
  "notExpressible": [
    "Ring closure: the first and last position of a linear ring must hold identical values. Comparing one value in the document with another is outside what a schema states.",
    "Whether a hole sits inside the exterior ring that should contain it.",
    "The right-hand rule: exterior rings counter-clockwise, holes clockwise.",
    "Antimeridian cutting.",
    "Self-intersection and other geometric validity, which RFC 7946 does not cover at all.",
    "Agreement between a bbox and the geometry it describes."
  ],
  "notChecked": [
    "Coordinate range: longitude within -180 to 180, latitude within -90 to 90. Draft 2020-12 can state this with prefixItems on the position definition, bounding the first two elements while still allowing a third for height, and ajv compiles it with strict mode off. It is left open here because the conformance run measured this file as published, and changing one row of that table outside a full rerun would make the table disagree with itself. Bounding the position catches three more malformed fixtures in that corpus, plus a projected crs member that turns metres into degrees, and refuses no valid document."
  ],
  "$ref": "#/$defs/GeoJSON",
  "$defs": {
    "GeoJSON": {
      "oneOf": [
        { "$ref": "#/$defs/Geometry" },
        { "$ref": "#/$defs/Feature" },
        { "$ref": "#/$defs/FeatureCollection" }
      ]
    },

    "position": {
      "description": "Longitude, latitude, and an optional height in metres above the WGS 84 ellipsoid.",
      "$comment": "maxItems is the one place this schema is deliberately stricter than RFC 7946. The specification says implementations SHOULD NOT extend positions beyond three elements and that parsers MAY ignore extra ones, so a fourth element is discouraged rather than invalid. It is refused here because a fourth element is usually a timestamp or a measure that nothing downstream will read correctly. Remove maxItems to match the specification exactly.",
      "type": "array",
      "items": { "type": "number" },
      "minItems": 2,
      "maxItems": 3
    },

    "bbox": {
      "description": "Two positions flattened: all axes of the southwesterly point, then all axes of the northeasterly point.",
      "type": "array",
      "items": { "type": "number" },
      "oneOf": [
        { "minItems": 4, "maxItems": 4 },
        { "minItems": 6, "maxItems": 6 }
      ]
    },

    "linearRing": {
      "description": "A closed LineString with four or more positions. Closure itself cannot be expressed in JSON Schema.",
      "type": "array",
      "items": { "$ref": "#/$defs/position" },
      "minItems": 4
    },

    "Point": {
      "type": "object",
      "required": ["type", "coordinates"],
      "properties": {
        "type": { "const": "Point" },
        "coordinates": { "$ref": "#/$defs/position" },
        "bbox": { "$ref": "#/$defs/bbox" }
      }
    },

    "MultiPoint": {
      "type": "object",
      "required": ["type", "coordinates"],
      "properties": {
        "type": { "const": "MultiPoint" },
        "coordinates": { "type": "array", "items": { "$ref": "#/$defs/position" } },
        "bbox": { "$ref": "#/$defs/bbox" }
      }
    },

    "LineString": {
      "type": "object",
      "required": ["type", "coordinates"],
      "properties": {
        "type": { "const": "LineString" },
        "coordinates": {
          "type": "array",
          "items": { "$ref": "#/$defs/position" },
          "minItems": 2
        },
        "bbox": { "$ref": "#/$defs/bbox" }
      }
    },

    "MultiLineString": {
      "type": "object",
      "required": ["type", "coordinates"],
      "properties": {
        "type": { "const": "MultiLineString" },
        "coordinates": {
          "type": "array",
          "items": {
            "type": "array",
            "items": { "$ref": "#/$defs/position" },
            "minItems": 2
          }
        },
        "bbox": { "$ref": "#/$defs/bbox" }
      }
    },

    "Polygon": {
      "type": "object",
      "required": ["type", "coordinates"],
      "properties": {
        "type": { "const": "Polygon" },
        "coordinates": { "type": "array", "items": { "$ref": "#/$defs/linearRing" } },
        "bbox": { "$ref": "#/$defs/bbox" }
      }
    },

    "MultiPolygon": {
      "type": "object",
      "required": ["type", "coordinates"],
      "properties": {
        "type": { "const": "MultiPolygon" },
        "coordinates": {
          "type": "array",
          "items": { "type": "array", "items": { "$ref": "#/$defs/linearRing" } }
        },
        "bbox": { "$ref": "#/$defs/bbox" }
      }
    },

    "GeometryCollection": {
      "$comment": "RFC 7946 says implementations SHOULD avoid nesting these. Discouraged is not forbidden, so the recursion stays.",
      "type": "object",
      "required": ["type", "geometries"],
      "properties": {
        "type": { "const": "GeometryCollection" },
        "geometries": { "type": "array", "items": { "$ref": "#/$defs/Geometry" } },
        "bbox": { "$ref": "#/$defs/bbox" }
      }
    },

    "Geometry": {
      "oneOf": [
        { "$ref": "#/$defs/Point" },
        { "$ref": "#/$defs/MultiPoint" },
        { "$ref": "#/$defs/LineString" },
        { "$ref": "#/$defs/MultiLineString" },
        { "$ref": "#/$defs/Polygon" },
        { "$ref": "#/$defs/MultiPolygon" },
        { "$ref": "#/$defs/GeometryCollection" }
      ]
    },

    "Feature": {
      "type": "object",
      "required": ["type", "geometry", "properties"],
      "properties": {
        "type": { "const": "Feature" },
        "geometry": {
          "oneOf": [{ "$ref": "#/$defs/Geometry" }, { "type": "null" }]
        },
        "properties": {
          "oneOf": [{ "type": "object" }, { "type": "null" }]
        },
        "id": { "type": ["string", "number"] },
        "bbox": { "$ref": "#/$defs/bbox" }
      }
    },

    "FeatureCollection": {
      "type": "object",
      "required": ["type", "features"],
      "properties": {
        "type": { "const": "FeatureCollection" },
        "features": { "type": "array", "items": { "$ref": "#/$defs/Feature" } },
        "bbox": { "$ref": "#/$defs/bbox" }
      }
    }
  }
}
