Skip to content

Minimalist vocabulary file for expressing keyword dependencies. #996

Closed
@handrews

Description

@handrews

NOTE: It is 2020. The world has gone to shit, and I'm barely functioning as a human being. But we have a draft to get out and a vague deadline in the form of OAS 3.1. So I'm trying to get this done. HOWEVER I do not have the capacity to debate things in detail. The only things I'm looking for here are:

  • Will it work?
  • Will it make our lives difficult in a significant way in the future?

If you think you have a substantially better idea, please file it as its own issue and if it is better we will do that. Feel free to cut-and-paste this issue and just change whatever you want to change if it's not completely different.

I am specifically not up for a debate on naming. If a group of people want to go off on slack and reach a consensus that includes at minimum @Relequestual and @gregsdennis on a single proposal of alternative names and bring that back, we'll switch to those. Just don't debate it here.

I am also not interested in what else we could do with a vocabulary file. I have a much more complex idea in my head that would even allow a generic implementation to automatically implement certain classes of keyword straight from the file. But now is not the time for that.

And I am very much not at all interested in revisiting the question of per-vocabulary meta-schemas. I understand that there are redundancies. I understand that not everyone "gets" why I set them up that way. But that discussion is out of scope for this issue, and really for this whole draft.

Yes, I'm being unreasonably dictatorial. None of us are getting what we want this year, are we?


This is an alternative to #995 about a plugin architecture appendix. This approach would support the plugin architecture sketched out there but is more precise.

The format (as I have long said would be the case) is not a schema. There are two top-level keywords:

  • vocabulary: this MUST match the URI used in the meta-schema's $vocabulary keyword
  • keywords: the object of keywords defined by this vocabulary.

Within the keywords object, for each schema keyword there is an object with the following vocabulary file keywords:

  • inPlaceApplicator: if true, this keyword is an in-place applicator, and MUST run before any other keyword that depends on annotations collected through adjacent in-place applicators defaults to false
  • dependsOn: list of annotation names (which are also keyword names) on which this keyword depends; there is no way to distinguish which vocabulary provides the annotation, and as always (yes this is in the spec) combining vocabularies with conflicting semantics produces undefined behavior so just don't defaults to an empty list []
  • throughInPlaceApplicators: if true, the annotations in dependsOn need to be examined both as adjacent keywords, and as annotation propagating up through adjacent in-place applicators; if false only adjacent keywords noted in dependsOn are to be considered. defaults to false
  • dependsOnValidity: object of keywords (although really it should only be one but that's should and not SHOULD) that MUST be present and MUST produce the given boolean value assertion result in order for this keyword to be processed

All the usual stuff about $vocabulary key names / vocabulary values being URIs and not URLs etc. etc. is the same as for all of the other stuff like this. Furthermore, implementations are welcome to hardcode behavior for well-known vocabularies (e.g. the ones in our spec documents).

This is intended to manage keyword-level dependencies. I am NOT OPEN to vocabulary-level dependencies. Vocabularies are semantic units of convenience that facilitate a plugin architecture. Vocabularies are "aware" of keywords, keywords are not aware of vocabularies. Because reasons.

Since we're documenting dependencies, I wanted to handle if/then/else, and realized I want annotation dependencies and validation dependencies to be handled separately. There's no concept of validation results interacting in a special way with in-place applicators, they just work at the immediately adjacent level. You could in theory depend on both validity and annotations but I wouldn't.

I am open to ONE naming question and only this one: if folks would rather put a $ in front of all of the vocabulary file keywords I'd be OK with that. But this format is not intended to be extensible so idk it just seemed simpler to not bother.

I'm not 100% sure I got all of the keywords here but you get the idea and it shows the dependency stuff.

{
  "vocabulary": "https://json-schema.org/2019-09/vocab/core",
  "keywords": {
    "$schema": {},
    "$vocabulary": {},
    "$id": {},
    "$anchor": {},
    "$ref": {
      "inPlaceApplicator": true
    },
    "$dynamicAnchor": {},
    "$dynamicRef": {
      "inPlaceApplicator": true
    },
    "$defs": {},
    "$comment": {}
  }
}
{
  "vocabulary": "https://json-schema.org/2019-09/vocab/applicator",
  "keywords": {
    "allOf": {
      "inPlaceApplicator": true
    },
    "anyOf": {
      "inPlaceApplicator": true
    },
    "oneOf": {
      "inPlaceApplicator": true
    },
    "not": {
      "inPlaceApplicator": true
    },
    "if": {
      "inPlaceApplicator": true
    },
    "then": {
      "inPlaceApplicator": true,
      "dependsOnValidity": {"if": true}
    },
    "else": {
      "inPlaceApplicator": true,
      "dependsOnValidity": {"if": false}
    },
    "dependentSchemas": {
      "inPlaceApplicator": true
    }, 
   "prefixItems": {},
    "items": {
      "dependsOn": ["prefixItems"],
      "throughInPlaceApplicators": false
    },
    "contains": {},
    "properties": {},
    "patternProperties": {},
    "additionalProperties": {
      "dependsOn": ["properties", "patternProperties"],
      "throughInPlaceApplicators": false
    },
    "propertyNames": {}
  }
}
{
  "vocabulary": "https://json-schema.org/2019-09/vocab/unevaluated",
  "keywords": {
    "unevaluatedProperties": {
      "dependsOn": ["properties", "patternProperties", "additionalProperties", "unevaluatedProperties"],
      "throughInPlaceApplicators": true
    },
    "unevaluatedItems": {
      "dependsOn": ["prefixItems", "items", "contains", "unevaluatedItems"],
      "throughInPlaceApplicators": true
    }
  }
}
{
  "vocabulary": "https://json-schema.org/2019-09/vocab/validation",
  "keywords": {
    "type": {},
    "enum": {},
    "const": {},
    "minimum": {},
    "maximum": {},
    "exclusiveMinimum": {},
    "exclusiveMaximum": {},
    "multipleOf": {},
    "minLength": {},
    "maxLength": {},
    "pattern": {},
    "minItems": {},
    "maxItems": {},
    "minContains": {
      "dependsOn": ["contains"]
    },
    "maxContains": {
      "dependsOn": ["contains"]
    },
    "required": {},
    "dependentRequired": {},
    "minProperties": {},
    "maxProperties": {}
  }
}
{
  "vocabulary": "https://json-schema.org/2019-09/vocab/meta-data",
  "keywords": {
    "title": {},
    "description": {},
    "readOnly": {},
    "writeOnly": {},
    "deprecated": {},
    "examples": {},
    "default": {}
  }
}
{
  "vocabulary": "https://json-schema.org/2019-09/vocab/format",
  "keywords": {
    "format": {}
  }
}
{
  "vocabulary": "https://json-schema.org/2019-09/vocab/content",
  "keywords": {
    "contentMediaType": {},
    "contentEncoding": {},
    "contentSchema": {}
  }
}
{
  "vocabulary": "https://json-schema.org/2019-09/vocab/hyper-schema",
  "keywords": {
    "base": {},
    "links": {}
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Closed

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions