From bd85786a420f3fc8f5018a2a97556a8a9557da08 Mon Sep 17 00:00:00 2001 From: alexbainter Date: Tue, 6 Jan 2026 13:08:11 -0600 Subject: [PATCH] Augment Highlight.js's JSON highlighter with one that highlights JSON-schema keywords. --- .../js/initialize-syntax-highlighting.js | 96 ++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/core/static/js/initialize-syntax-highlighting.js b/core/static/js/initialize-syntax-highlighting.js index 7bd0d17..dd6099e 100644 --- a/core/static/js/initialize-syntax-highlighting.js +++ b/core/static/js/initialize-syntax-highlighting.js @@ -1,4 +1,91 @@ (() => { + // https://json-schema.org/understanding-json-schema/keywords + const JSON_SCHEMA_KEYWORDS = [ + '$anchor', + '$comment', + '$defs', + '$dynamicAnchor', + '$dynamicRef', + '$id', + '$ref', + '$schema', + '$vocabulary', + 'additionalProperties', + 'allOf', + 'anyOf', + 'const', + 'contains', + 'contentEncoding', + 'contentMediaType', + 'contentSchema', + 'default', + 'dependentRequired', + 'dependentSchemas', + 'deprecated', + 'description', + 'else', + 'enum', + 'examples', + 'exclusiveMaximum', + 'exclusiveMinimum', + 'format', + 'if', + 'items', + 'maxContains', + 'maximum', + 'maxItems', + 'maxLength', + 'maxProperties', + 'minContains', + 'minimum', + 'minItems', + 'minLength', + 'minProperties', + 'multipleOf', + 'not', + 'oneOf', + 'pattern', + 'patternProperties', + 'prefixItems', + 'properties', + 'propertyNames', + 'readOnly', + 'required', + 'then', + 'title', + 'type', + 'unevaluatedItems', + 'unevaluatedProperties', + 'uniqueItems', + 'writeOnly', + ]; + + /** + * Augments Highlight.js's built-in JSON language + * to specially highlight JSON Schema keywords. + * + * @import { HLJSApi } from 'highlight.js'; + * @param {HLJSApi} hljs + */ + const jsonSchemaLanguage = (hljs) => { + const jsonLanguage = hljs.getLanguage('json'); + if (!jsonLanguage) { + throw new Error('Highlight.js is missing a definition for JSON'); + } + const contains = jsonLanguage.contains.slice(); + contains.unshift({ + className: 'keyword', + begin: new RegExp( + `"(${JSON_SCHEMA_KEYWORDS.map((keyword) => keyword.replace('$', '\\$')).join('|')})"(?=\\s*:)` + ), + relevance: 2, + }); + + return Object.assign({}, jsonLanguage, { + contains, + }); + }; + document.addEventListener('DOMContentLoaded', () => { /** * @import { HLJSApi } from 'highlight.js'; @@ -23,7 +110,14 @@ }); }); hljsPromise - .then((hljs) => hljs.highlightAll()) + .then((hljs) => { + if (hljs.getLanguage('json')) { + // Override the built-in definition for JSON with our + // JSON schema-aware version. + hljs.registerLanguage('json', jsonSchemaLanguage); + } + hljs.highlightAll(); + }) .catch((err) => { console.error(err); });