Skip to content

proposal to add keyword metadata to vocabularies by defining a new vocabulary #1257

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 94 additions & 1 deletion meta/applicator.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"$schema": "https://json-schema.org/draft/next/schema",
"$id": "https://json-schema.org/draft/next/meta/applicator",
"$vocabulary": {
"https://json-schema.org/draft/next/vocab/applicator": true
"https://json-schema.org/draft/next/vocab/applicator": true,
"https://json-schema.org/draft/next/vocab/vocabulary": false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This says that schemas using https://json-schema.org/draft/next/meta/applicator as a meta-schema are able to use the vocabulary vocabulary, which I don't think is what you mean. You need this meta-schema's meta-schema (currently declared as https://json-schema.org/draft/next/schema) to include the vocabulary vocabulary in $vocabulary (buffalo buffalo buffalo buffalo buffalo...). In which case it probably would not be the default meta-schema because most schemas won't need to (and shouldn't) use the vocabulary vocabulary.

Copy link
Member Author

@gregsdennis gregsdennis Sep 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need this meta-schema's meta-schema (currently declared as https://json-schema.org/draft/next/schema) to include the vocabulary vocabulary in $vocabulary

But if that's just https://json-schema.org/draft/next/schema, it doesn't solve the problem you're describing.

What I want is for meta-schemas that describe vocabularies to be able to use these new keywords. Does that mean that we need a dedicated vocabulary-describing meta-schema? Then have (e.g.) applicator meta-schema reference that one in $schema?

So

{
  "$schema": "https://json-schema.org/draft/next/schema",
  "$id": "https://json-schema.org/draft/next/meta/vocabulary",
  "$vocabulary": {
    "https://json-schema.org/draft/next/vocab/core": true,
    "https://json-schema.org/draft/next/vocab/applicator": true,
    "https://json-schema.org/draft/next/vocab/unevaluated": true,
    "https://json-schema.org/draft/next/vocab/validation": true,
    "https://json-schema.org/draft/next/vocab/meta-data": true,
    "https://json-schema.org/draft/next/vocab/format-annotation": true,
    "https://json-schema.org/draft/next/vocab/content": true,
    "https://json-schema.org/draft/next/vocab/vocabulary": true
  },
  "$ref": "https://json-schema.org/draft/next/schema",
  ... // new vocab-vocab properties
}

Then https://json-schema.org/draft/next/meta/applicator and friends all have $schema: https://json-schema.org/draft/next/meta/vocabulary?

I think this also provides a pre-packaged meta-schema for other custom vocab meta-schemas to use.

Copy link
Member Author

@gregsdennis gregsdennis Sep 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But if it has $schema: https://json-schema.org/draft/next/schema then it can't itself use the keywords it defines. So does it need to be its own meta-schema? That line of logic leads us to needing to resolve Keyword for identifying bootstrapping rules #217 first.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$vocabulary is (effectively) an annotation. So when you use it in a meta-schema, it annotates the (non-meta-)schema and says "this schema can use this vocabulary".

If this were not the case, then every non-meta-schema would have to declare $vocabulary, which would be a mess.

So yes, if you want other vocab meta-schemas to use the vocabulary vocabulary (VV), then the VV needs to be in their meta-schema's $vocabulary. Since we would not want to put the VV in the default meta-schema, yes that means they would need a different meta-schema.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gregsdennis

This data is still mostly informational. I don't expect an implementation to be able to figure out what to do with an applicator or assertion without some additional coding, just like today. I don't think we'll ever get to the point where an implementation can "just know" what to do with a new keyword that's not a pure annotation.

If this isn't what you're talking about, perhaps you can elaborate on what you mean by "take action." What action would you expect from an implementation?

At minimum, we need to be able to use any vocabulary description to automatically determine what keywords are part of that vocabulary, which will let us distinguish known keywords from optional (and not directly-supported) vocabularies from completely unknown keywords. Otherwise, it's just JSON-formatted documentation, and that doesn't seem useful to me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So yes, if you want other vocab meta-schemas to use the vocabulary vocabulary (VV), then the VV needs to be in their meta-schema's $vocabulary. Since we would not want to put the VV in the default meta-schema, yes that means they would need a different meta-schema.

I think this means that you agree with my commented approach.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gregsdennis yes, I think so (I think I got confused by the next comment after that)

},
"$dynamicAnchor": "meta",

Expand Down Expand Up @@ -47,11 +48,103 @@
"oneOf": { "$ref": "#/$defs/schemaArray" },
"not": { "$dynamicRef": "#meta" }
},
"applicators": {
"prefixItems": "arrayChild",
"items": "arrayChild",
"contains": [ "objectChild", "arrayChild" ],
"additionalProperties": "objectChild",
"properties": "objectChild",
"patternProperties": "objectChild",
"dependentSchemas": "inPlace",
"propertyDependencies": "inPlace",
"propertyNames": "objectChild",
"if": "inPlace",
"then": "inPlace",
"else": "inPlace",
"allOf": "inPlace",
"anyOf": "inPlace",
"oneOf": "inPlace",
"not": "inPlace"
},
"assertions": [
"prefixItems",
"items",
"contains",
"additionalProperties",
"properties",
"patternProperties",
"dependentSchemas",
"propertyDependencies",
"propertyNames",
"then",
"else",
"allOf",
"anyOf",
"oneOf",
"not"
],
"annotations": {
"prefixItems": {
"kind": [ "producer", "collector" ],
"producedValue": {
"oneOf": [
{ "$ref": "#/$defs/nonNegativeInteger" },
{ "type": "boolean" }
]
}
},
"items": {
"kind": [ "producer", "collector" ],
"producedValue": { "const": true }
},
"contains": {
"kind": [ "producer", "collector" ],
"producedValue": {
"type": "array",
"items": { "$ref": "#/$defs/nonNegativeInteger" }
}
},
"additionalProperties": {
"kind": [ "producer", "collector" ],
"producedValue": {
"type": "array",
"items": { "type": "string" }
}
},
"properties": {
"kind": [ "producer", "collector" ],
"producedValue": {
"type": "array",
"items": { "type": "string" }
}
},
"patternProperties": {
"kind": [ "producer", "collector" ],
"producedValue": {
"type": "array",
"items": { "type": "string" }
}
},
"dependentSchemas": { "kind": "collector" },
"propertyDependencies": { "kind": "collector" },
"propertyNames": { "kind": "collector" },
"if": { "kind": "collector" },
"then": { "kind": "collector" },
"else": { "kind": "collector" },
"allOf": { "kind": "collector" },
"anyOf": { "kind": "collector" },
"oneOf": { "kind": "collector" },
"not": { "kind": "collector" }
},
"$defs": {
"schemaArray": {
"type": "array",
"minItems": 1,
"items": { "$dynamicRef": "#meta" }
},
"nonNegativeInteger": {
"type": "integer",
"minimum": 0
}
}
}
8 changes: 7 additions & 1 deletion meta/content.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"$schema": "https://json-schema.org/draft/next/schema",
"$id": "https://json-schema.org/draft/next/meta/content",
"$vocabulary": {
"https://json-schema.org/draft/next/vocab/content": true
"https://json-schema.org/draft/next/vocab/content": true,
"https://json-schema.org/draft/next/vocab/vocabulary": false
},
"$dynamicAnchor": "meta",

Expand All @@ -13,5 +14,10 @@
"contentEncoding": { "type": "string" },
"contentMediaType": { "type": "string" },
"contentSchema": { "$dynamicRef": "#meta" }
},
"annotations": {
"contentEncoding": { "kind": "producer" },
"contentMediaType": { "kind": "producer" },
"contentSchema": { "kind": "producer" }
}
}
6 changes: 5 additions & 1 deletion meta/format-annotation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
"$schema": "https://json-schema.org/draft/next/schema",
"$id": "https://json-schema.org/draft/next/meta/format-annotation",
"$vocabulary": {
"https://json-schema.org/draft/next/vocab/format-annotation": true
"https://json-schema.org/draft/next/vocab/format-annotation": true,
"https://json-schema.org/draft/next/vocab/vocabulary": false
},
"$dynamicAnchor": "meta",

"title": "Format vocabulary meta-schema for annotation results",
"type": ["object", "boolean"],
"properties": {
"format": { "type": "string" }
},
"annotations": {
"format": { "kind": "producer" }
}
}
7 changes: 6 additions & 1 deletion meta/format-assertion.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@
"$schema": "https://json-schema.org/draft/next/schema",
"$id": "https://json-schema.org/draft/next/meta/format-assertion",
"$vocabulary": {
"https://json-schema.org/draft/next/vocab/format-assertion": true
"https://json-schema.org/draft/next/vocab/format-assertion": true,
"https://json-schema.org/draft/next/vocab/vocabulary": false
},
"$dynamicAnchor": "meta",

"title": "Format vocabulary meta-schema for assertion results",
"type": ["object", "boolean"],
"properties": {
"format": { "type": "string" }
},
"assertions": [ "format" ],
"annotations": {
"format": { "kind": "producer" }
}
}
12 changes: 11 additions & 1 deletion meta/meta-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"$schema": "https://json-schema.org/draft/next/schema",
"$id": "https://json-schema.org/draft/next/meta/meta-data",
"$vocabulary": {
"https://json-schema.org/draft/next/vocab/meta-data": true
"https://json-schema.org/draft/next/vocab/meta-data": true,
"https://json-schema.org/draft/next/vocab/vocabulary": false
},
"$dynamicAnchor": "meta",

Expand Down Expand Up @@ -33,5 +34,14 @@
"type": "array",
"items": true
}
},
"annotations": {
"title": { "kind": "producer" },
"description": { "kind": "producer" },
"default": { "kind": "producer" },
"deprecated": { "kind": "producer" },
"readOnly": { "kind": "producer" },
"writeOnly": { "kind": "producer" },
"examples": { "kind": "producer" }
}
}
15 changes: 14 additions & 1 deletion meta/unevaluated.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"$schema": "https://json-schema.org/draft/next/schema",
"$id": "https://json-schema.org/draft/next/meta/unevaluated",
"$vocabulary": {
"https://json-schema.org/draft/next/vocab/unevaluated": true
"https://json-schema.org/draft/next/vocab/unevaluated": true,
"https://json-schema.org/draft/next/vocab/vocabulary": false
},
"$dynamicAnchor": "meta",

Expand All @@ -11,5 +12,17 @@
"properties": {
"unevaluatedItems": { "$dynamicRef": "#meta" },
"unevaluatedProperties": { "$dynamicRef": "#meta" }
},
"applicators": {
"unevaluatedItems": "arrayChild",
"unevaluatedProperties": "objectChild"
},
"assertions": [
"unevaluatedItems",
"unevaluatedProperties"
],
"annotations": {
"unevaluatedItems": { "kind": "collector" },
"unevaluatedProperties": { "kind": "collector" }
}
}
24 changes: 23 additions & 1 deletion meta/validation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"$schema": "https://json-schema.org/draft/next/schema",
"$id": "https://json-schema.org/draft/next/meta/validation",
"$vocabulary": {
"https://json-schema.org/draft/next/vocab/validation": true
"https://json-schema.org/draft/next/vocab/validation": true,
"https://json-schema.org/draft/next/vocab/vocabulary": false
},
"$dynamicAnchor": "meta",

Expand Down Expand Up @@ -68,6 +69,27 @@
}
}
},
"assertions": [
"type",
"const",
"multipleOf",
"maximum",
"exclusiveMaximum",
"minimum",
"exclusiveMinimum",
"maxLength",
"minLength",
"pattern",
"maxItems",
"minItems",
"uniqueItems",
"maxContains",
"minContains",
"maxProperties",
"minProperties",
"required",
"dependentRequired"
],
"$defs": {
"nonNegativeInteger": {
"type": "integer",
Expand Down
66 changes: 66 additions & 0 deletions meta/vocabulary.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"$schema": "https://json-schema.org/draft/next/schema",
"$id": "https://json-schema.org/draft/next/meta/vocabulary",
"$vocabulary": {
"https://json-schema.org/draft/next/vocab/core": true,
"https://json-schema.org/draft/next/vocab/vocabulary": false
},

"title": "Vocabulary meta-data vocabulary meta-schema",
"description": "Defines keywords for use in vocabulary meta-schemas to provide additional information for their keywords",
"type": [ "object", "boolean" ],
"properties": {
"applicators": {
"type": "object",
"additionalProperties": {
"oneOf": [
{"$ref": "#/$defs/applicatorKind"},
{
"type": "array",
"items": { "$ref": "#/$defs/applicatorKind" },
"minItems": 1,
"uniqueItems": true
}
]
}
},
"assertions": {
"type": "array",
"items": { "type": "string" }
},
"annotations": {
"type": "object",
"properties": {
"kind": {
"type": "object",
"additionalProperties": {
"oneOf": [
{ "$ref": "#/$defs/annotationKind" },
{
"type": "array",
"items": { "$ref": "#/$defs/annotationKind" },
"minItems": 1,
"uniqueItems": true
}
]
}
},
"producedValue": { "$dynamicRef": "#meta" }
},
"required": [ "kind" ]
}
},
"annotations": {
"applicators": { "kind": "producer" },
"assertions": { "kind": "producer" },
"annotations": { "kind": "producer" }
},
"$defs": {
"applicatorKind": {
"enum": [ "objectChild", "arrayChild", "inPlace" ]
},
"annotationKind": {
"enum": [ "producer", "collector" ]
}
}
}