Skip to content

Commit

Permalink
Added JSON Schema.
Browse files Browse the repository at this point in the history
This updates the docgenerator system to be able to generate
a JSON Schema based on the data in the database.

A schema for MNX has been created, as docs/mnx-schema.json.
It's now linked-to from the left sidebar of each docs page.

Going forward, that schema will be automatically updated
each time we make any changes to the docs.
  • Loading branch information
adrianholovaty committed Dec 21, 2023
1 parent dd2faae commit 5bf366d
Show file tree
Hide file tree
Showing 208 changed files with 1,279 additions and 1 deletion.
2 changes: 1 addition & 1 deletion docgenerator/data.json
Expand Up @@ -32,7 +32,7 @@
"fields": {
"site_name": "MNX specification",
"xml_format_name": "MNX",
"sidebar_html": "<ul>\r\n<li><a href=\"/\">Home</a></li>\r\n<li><a href=\"/mnx-reference/objects/\">Reference</a>\r\n <ul>\r\n <li><a href=\"/mnx-reference/objects/\">Objects</a></li>\r\n <li><a href=\"/mnx-reference/examples/\">Example documents</a></li>\r\n </ul>\r\n</li>\r\n<li><a href=\"/comparisons/musicxml/\">MNX and MusicXML</a></li>\r\n</ul>"
"sidebar_html": "<ul>\r\n<li><a href=\"/\">Home</a></li>\r\n<li><a href=\"/mnx-reference/objects/\">Reference</a>\r\n <ul>\r\n <li><a href=\"/mnx-reference/objects/\">Objects</a></li>\r\n <li><a href=\"/mnx-reference/examples/\">Example documents</a></li>\r\n <li><a href=\"/mnx-schema.json\">Raw JSON Schema</a></li>\r\n </ul>\r\n</li>\r\n<li><a href=\"/comparisons/musicxml/\">MNX and MusicXML</a></li>\r\n</ul>"
}
},
{
Expand Down
1 change: 1 addition & 0 deletions docgenerator/docgenerator/urls.py
Expand Up @@ -14,6 +14,7 @@
path('<slug:schema_slug>-reference/examples/<slug:slug>/', views.example_detail, name='example_detail'),
path('<slug:schema_slug>-reference/objects/', views.json_object_list, name='json_object_list'),
path('<slug:schema_slug>-reference/objects/<slug:slug>/', views.json_object_detail, name='json_object_detail'),
path('<slug:schema_slug>-schema.json', views.json_schema, name='json_schema'),
path('concepts/', views.concept_list, name='concept_list'),
path('concepts/<slug:slug>/', views.concept_detail, name='concept_detail'),
path('comparisons/<slug:slug>/', views.format_comparison_detail, name='format_comparison_detail'),
Expand Down
1 change: 1 addition & 0 deletions docgenerator/spec/management/commands/makesite.py
Expand Up @@ -36,6 +36,7 @@ def generate(self):
self.generate_url(schema.data_types_url())
if schema.is_json:
self.generate_url(schema.json_objects_url())
self.generate_view('json_schema', schema.slug)
else:
self.generate_url(schema.elements_url())
self.generate_url(schema.element_tree_url())
Expand Down
92 changes: 92 additions & 0 deletions docgenerator/spec/utils/jsonschema.py
@@ -0,0 +1,92 @@
from spec.models import *

# Each of these types is a native JSONSchema type and also exists as a
# JSONObject.slug.
NATIVE_TYPES = set(['boolean'])

def make_json_schema(schema_slug='mnx'):
"""
Creates a JSON schema by looking at the JSONObject information
in the database. The result is a Python data structure that, if
serialized to JSON, is a correct JSON schema.
"""
# First, add the root object.
root_object = JSONObject.objects.filter(
schema__slug=schema_slug,
name=JSONObject.ROOT_OBJECT_NAME
)[0]
result = get_schema_for_db_object(root_object)
result.update({
'$schema': 'https://json-schema.org/draft/2020-12/schema',
'$id': 'https://w3c.github.io/mnx/docs/mnx-schema.json',
'title': 'MNX document',
'description': 'An encoding of Common Western Music Notation.',
})

# Next, add any defs. We do this for any JSONObject that appears as
# JSONRelationship.child more than once.
defs = {}
def_objects = JSONObject.objects.filter(schema__slug=schema_slug)
for def_object in def_objects:
if def_object.slug not in NATIVE_TYPES and JSONObjectRelationship.objects.filter(child=def_object).count() > 1:
defs[def_object.slug] = get_schema_for_db_object(def_object, use_defs=False)
if defs:
result['$defs'] = defs

return result

def get_schema_for_db_object(db_object, use_defs=True):
"""
Given a JSONObject instance, returns its JSON schema definition
as a Python dictionary.
"""
if db_object.slug in NATIVE_TYPES:
return {
'type': db_object.slug
}
if use_defs and JSONObjectRelationship.objects.filter(child=db_object).count() > 1:
return {
'$ref': f'#/$defs/{db_object.slug}'
}
object_type = db_object.object_type
if object_type == JSONObject.OBJECT_TYPE_DICT:
props = dict([(childrel.child_key, get_schema_for_db_object(childrel.child)) for childrel in db_object.get_child_relationships()])
required = [childrel.child_key for childrel in db_object.get_child_relationships() if childrel.is_required]
result = {
'type': 'object',
'properties': props,
'additionalProperties': False
}
if required:
result['required'] = list(sorted(required))
return result
elif object_type == JSONObject.OBJECT_TYPE_ARRAY:
childrels = db_object.get_child_relationships()
if len(childrels) == 1:
items = get_schema_for_db_object(childrels[0].child)
else:
items = {
'anyOf': [get_schema_for_db_object(childrel.child) for childrel in childrels],
}
result = {
'type': 'array',
'items': items
}
return result
elif object_type == JSONObject.OBJECT_TYPE_NUMBER:
return {
'type': 'integer'
}
elif object_type == JSONObject.OBJECT_TYPE_BOOLEAN:
return {
'type': 'boolean'
}
elif object_type == JSONObject.OBJECT_TYPE_STRING:
return {
'type': 'string'
}
elif object_type == JSONObject.OBJECT_TYPE_LITERAL_STRING:
return {
'type': 'string',
'const': db_object.description
}
7 changes: 7 additions & 0 deletions docgenerator/spec/views.py
Expand Up @@ -86,6 +86,13 @@ def json_object_detail(request, schema_slug, slug):
'examples': ExampleDocumentObject.objects.filter(json_object=json_object).select_related('example').order_by(Lower('example__name')),
})

def json_schema(request, schema_slug):
from spec.utils.jsonschema import make_json_schema
import json
schema_obj = make_json_schema(schema_slug)
schema_str = json.dumps(schema_obj, indent=4, sort_keys=True)
return http.HttpResponse(schema_str, content_type='text/plain')

def data_type_list(request, schema_slug):
schema = get_object_or_404(XMLSchema, slug=schema_slug)
return render(request, 'data_type_list.html', {
Expand Down
1 change: 1 addition & 0 deletions docs/concepts/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../mnx-reference/objects/">Objects</a></li>
<li><a href="../mnx-reference/examples/">Example documents</a></li>
<li><a href="../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="mnx-reference/objects/">Objects</a></li>
<li><a href="mnx-reference/examples/">Example documents</a></li>
<li><a href="mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/infrastructure/direction-content/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../mnx-reference/objects/">Objects</a></li>
<li><a href="../../mnx-reference/examples/">Example documents</a></li>
<li><a href="../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/infrastructure/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../mnx-reference/objects/">Objects</a></li>
<li><a href="../mnx-reference/examples/">Example documents</a></li>
<li><a href="../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/infrastructure/notational-concepts/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../mnx-reference/objects/">Objects</a></li>
<li><a href="../../mnx-reference/examples/">Example documents</a></li>
<li><a href="../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/infrastructure/sequence-content/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../mnx-reference/objects/">Objects</a></li>
<li><a href="../../mnx-reference/examples/">Example documents</a></li>
<li><a href="../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/infrastructure/styling/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../mnx-reference/objects/">Objects</a></li>
<li><a href="../../mnx-reference/examples/">Example documents</a></li>
<li><a href="../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/accidental/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/barline/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/chromatic-pitch/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/clef-sign/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/css-selector/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/display-option/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/dynamic-type/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/element-location/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/ending-number/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/ending-type/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/event-id-list/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/event-id/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/grace-note-type/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/grouping-symbol/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../objects/">Objects</a></li>
<li><a href="../examples/">Example documents</a></li>
<li><a href="../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/integer-signed/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/jump-type/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/line-type/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/measure-count/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/measure-location/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/measure-number/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/note-id/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down
1 change: 1 addition & 0 deletions docs/mnx-reference/data-types/note-value/index.html
Expand Up @@ -32,6 +32,7 @@
<ul>
<li><a href="../../objects/">Objects</a></li>
<li><a href="../../examples/">Example documents</a></li>
<li><a href="../../../mnx-schema.json">Raw JSON Schema</a></li>
</ul>
</li>
<li><a href="../../../comparisons/musicxml/">MNX and MusicXML</a></li>
Expand Down

0 comments on commit 5bf366d

Please sign in to comment.