├── web └── .gitkeep ├── docker-compose.yml ├── .github ├── config.yaml ├── workflows │ ├── pr-dependencies.yml │ ├── minimum-open-time.yml │ └── ci.yml ├── ISSUE_TEMPLATE │ ├── proposal.yml │ └── clarification.yml ├── PULL_REQUEST_TEMPLATE.md └── SECURITY.md ├── .gitignore ├── .remarkrc.js ├── specs ├── .remarkrc.js ├── .remarkrc-specs.js ├── .remarkrc-build.js ├── meta │ ├── README.md │ └── meta.json ├── schema.json ├── output │ └── schema.json ├── proposals │ ├── proposal-template.md │ ├── vocabularies-adr.md │ ├── propertyDependencies.md │ ├── propertyDependencies-adr.md │ └── vocabularies.md ├── registries │ └── format.json └── spec.css ├── ietf ├── .remarkrc.js ├── json-schema-media-types.md └── relative-json-pointer.xml ├── Dockerfile ├── remark ├── rehype-link-transformer.js ├── remark-reference-links.js ├── remark-table-of-contents.js ├── remark-code-titles.js └── remark-headings.js ├── adr ├── README.md ├── template.md ├── 2024-05-08-extract-unstable-keywords.md ├── 2024-11-2-assertion-format.md ├── 2024-02-object-contains.md ├── 2023-04-sva-prefix.md ├── 2022-04-08-cref-for-ambiguity-and-fix-later-gh-spec-issue-1172.md ├── 2022-09-decouple-from-ietf.md └── 2022-11-stable-spec.md ├── .remarkrc-lint.js ├── package.json ├── eslint.config.js ├── CONTRIBUTING.md ├── README.md ├── PROCESS.md └── LICENSE /web/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | build: 3 | build: 4 | context: . 5 | working_dir: /app 6 | volumes: 7 | - .:/app:Z 8 | -------------------------------------------------------------------------------- /.github/config.yaml: -------------------------------------------------------------------------------- 1 | helpr: 2 | opened: 'Status: RP Review Required' 3 | merged: 'Status: PR Merged' 4 | rejected: 'Status: PR Revision Required' 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Markdown builds 2 | web/ 3 | 4 | # IETF builds 5 | .refcache/ 6 | ietf/json-schema-media-types.xml 7 | 8 | # For the node-based build tools 9 | node_modules/ 10 | -------------------------------------------------------------------------------- /.remarkrc.js: -------------------------------------------------------------------------------- 1 | import remarkGfm from "remark-gfm"; 2 | import lintPreset from "./.remarkrc-lint.js"; 3 | 4 | 5 | export default { 6 | plugins: [ 7 | remarkGfm, 8 | lintPreset 9 | ] 10 | }; 11 | -------------------------------------------------------------------------------- /specs/.remarkrc.js: -------------------------------------------------------------------------------- 1 | import specPreset from "./.remarkrc-specs.js"; 2 | import lintPreset from "../.remarkrc-lint.js"; 3 | 4 | 5 | export default { 6 | plugins: [ 7 | specPreset, 8 | lintPreset 9 | ] 10 | }; 11 | -------------------------------------------------------------------------------- /.github/workflows/pr-dependencies.yml: -------------------------------------------------------------------------------- 1 | name: Check PR Dependencies 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | check_dependencies: 7 | runs-on: ubuntu-latest 8 | name: Check Dependencies 9 | steps: 10 | - uses: gregsdennis/dependencies-action@main 11 | env: 12 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /ietf/.remarkrc.js: -------------------------------------------------------------------------------- 1 | import lintPreset from "../.remarkrc-lint.js"; 2 | import remarkLintNoMultipleToplevelHeadings from "remark-lint-no-multiple-toplevel-headings"; 3 | import remarkLintFencedCodeMarker from "remark-lint-fenced-code-marker"; 4 | 5 | 6 | export default { 7 | plugins: [ 8 | lintPreset, 9 | [remarkLintNoMultipleToplevelHeadings, false], 10 | [remarkLintFencedCodeMarker, "~"] 11 | ] 12 | }; 13 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora 2 | 3 | RUN dnf install -y ruby python3-pip 4 | RUN gem install kramdown-rfc 5 | RUN pip install xml2rfc 6 | 7 | WORKDIR /app 8 | 9 | COPY . . 10 | 11 | # First covert md to xml. Then convert xml to html 12 | CMD sh -c "xml2rfc --version \ 13 | && ls ietf/*.md | xargs -n1 sh -c 'kramdown-rfc \"\$0\" > \"\${0%.md}.xml\"' \ 14 | && ls ietf/*.xml | xargs -n1 sh -c 'xml2rfc --html \"\$0\" -p web'" 15 | -------------------------------------------------------------------------------- /.github/workflows/minimum-open-time.yml: -------------------------------------------------------------------------------- 1 | name: PR Policy 2 | on: 3 | pull_request: 4 | workflow_dispatch: 5 | # scheduling only on PRs is not directly supported. See https://github.com/orgs/community/discussions/49960 6 | schedule: 7 | - cron: '0 0 * * *' # once daily 8 | 9 | jobs: 10 | require-minimum-open-time: 11 | if: github.event_name == 'pull_request' 12 | runs-on: ubuntu-latest 13 | name: Require Minimum Open Time 14 | steps: 15 | - uses: actions/checkout@v2 16 | - uses: gregsdennis/minimum-open-time@main 17 | with: 18 | time: 2w # see below for options 19 | env: 20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: JSON Schema 2 | on: 3 | - push 4 | - pull_request 5 | 6 | jobs: 7 | specs-markdown: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | - uses: actions/setup-node@v4 12 | with: 13 | node-version: latest 14 | cache: npm 15 | - run: npm ci 16 | - run: npm run lint 17 | - run: npm run build -- specs 18 | 19 | specs-ietf: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - name: Install docker-compose 23 | run: | 24 | sudo apt-get update 25 | sudo apt-get install -y docker-compose 26 | - uses: actions/checkout@v4 27 | - run: npm run build-ietf 28 | -------------------------------------------------------------------------------- /remark/rehype-link-transformer.js: -------------------------------------------------------------------------------- 1 | import { existsSync } from "node:fs"; 2 | import { basename } from "node:path"; 3 | import url from "node:url"; 4 | import { visit } from "unist-util-visit"; 5 | 6 | 7 | const rehypeLinkTransformer = () => (tree, vfile) => { 8 | visit(tree, "element", (node) => { 9 | if (node.tagName === "a") { 10 | const href = url.parse(node.properties.href); 11 | if (href.hostname === null && href.pathname?.endsWith(".md") && existsSync(vfile.history[0])) { 12 | href.pathname = basename(href.pathname).replace(/.md$/, ".html"); 13 | node.properties.href = url.format(href); 14 | } 15 | } 16 | }); 17 | }; 18 | 19 | export default rehypeLinkTransformer; 20 | -------------------------------------------------------------------------------- /remark/remark-reference-links.js: -------------------------------------------------------------------------------- 1 | import { text, link } from "mdast-builder"; 2 | import { toString as nodeToString } from "mdast-util-to-string"; 3 | import { findAndReplace } from "mdast-util-find-and-replace"; 4 | 5 | 6 | const referenceLink = /\{\{(?.*?)\}\}/ug; 7 | 8 | const remarkReferenceLinks = () => (tree, file) => { 9 | findAndReplace(tree, [referenceLink, (value, id) => { 10 | // file.data.headings comes from ./remark-headings.js 11 | if (!(id in file.data.headings)) { 12 | throw Error(`ReferenceLinkError: No header found with id "${id}"`); 13 | } 14 | 15 | const headerText = nodeToString(file.data.headings[id]); 16 | const linkText = text(file.data.headings[id].data.section); 17 | return link(`#${id}`, headerText, [linkText]); 18 | }]); 19 | }; 20 | 21 | export default remarkReferenceLinks; 22 | -------------------------------------------------------------------------------- /adr/README.md: -------------------------------------------------------------------------------- 1 | # Architectural Decision Log 2 | 3 | This log lists the architectural decisions for the JSON Schema specification. 4 | 5 | 6 | 7 | - [ADR-2022-04-08](2022-04-08-cref-for-ambiguity-and-fix-later-gh-spec-issue-1172.md) 8 | \- Acknowledge ambiguity in additionalProperties behaviour and fix after patch 9 | release 10 | 11 | 12 | 13 | You can find the ADR for using ADRs in our [community repo ADR log](https://github.com/json-schema-org/community/tree/HEAD/docs/adr). 14 | 15 | For new ADRs, please use [template.md](template.md) as basis. More information 16 | on MADR is available at . General information about 17 | architectural decision records is available at . 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/proposal.yml: -------------------------------------------------------------------------------- 1 | name: ⭐️ Proposal 2 | description: Suggest an idea for a new feature 3 | title: "✨ Proposal: " 4 | labels: ["proposal", "Status: Triage"] 5 | body: 6 | - type: textarea 7 | attributes: 8 | label: Describe the inspiration for your proposal 9 | description: Does the proposal address a problem you're facing? 10 | validations: 11 | required: true 12 | - type: textarea 13 | attributes: 14 | label: Describe the proposal 15 | description: Please be as clear as possible and use examples. 16 | validations: 17 | required: true 18 | - type: textarea 19 | attributes: 20 | label: Describe alternatives you've considered 21 | description: Can the functionality you're proposal be achieved with the features available today? 22 | validations: 23 | required: false 24 | - type: textarea 25 | attributes: 26 | label: Additional context 27 | description: Is there anything else related to your proposal that you'd like to cover? 28 | validations: 29 | required: false 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/clarification.yml: -------------------------------------------------------------------------------- 1 | name: 🧹 Clarification Needed 2 | description: Something in the specification is unclear 3 | title: "🧹 Clarification: " 4 | labels: ["🧹 Clarification", "Status: Triage"] 5 | body: 6 | - type: textarea 7 | attributes: 8 | label: Specification section 9 | description: Which specification document needs clarification? Which section? 10 | placeholder: | 11 | [Core | Validation], Section: ? 12 | validations: 13 | required: true 14 | - type: textarea 15 | attributes: 16 | label: What is unclear? 17 | description: Please quote the current text and explain why it's unclear. 18 | validations: 19 | required: true 20 | - type: textarea 21 | attributes: 22 | label: Proposal 23 | description: Do you have an idea to make the text more clear? 24 | validations: 25 | required: true 26 | - type: dropdown 27 | attributes: 28 | label: Do you think this work might require an [Architectural Decision Record (ADR)]? (significant or noteworthy) 29 | options: 30 | - 'Yes' 31 | - 'No' 32 | validations: 33 | required: true -------------------------------------------------------------------------------- /.remarkrc-lint.js: -------------------------------------------------------------------------------- 1 | import remarkValidateLinks from "remark-validate-links"; 2 | import remarkPresetLintConsistent from "remark-preset-lint-consistent"; 3 | import remarkPresetLintRecommended from "remark-preset-lint-recommended"; 4 | import remarkPresetLintMarkdownStyleGuide from "remark-preset-lint-markdown-style-guide"; 5 | import remarkLintDefinitionCase from "remark-lint-definition-case"; 6 | import remarkLintListItemIndent from "remark-lint-list-item-indent"; 7 | import remarkLintListItemSpacing from "remark-lint-list-item-spacing"; 8 | import remarkLintNoFileNameMixedCase from "remark-lint-no-file-name-mixed-case"; 9 | import remarkLintNoFileNameIrregularCharacters from "remark-lint-no-file-name-irregular-characters"; 10 | 11 | 12 | export default { 13 | plugins: [ 14 | remarkValidateLinks, 15 | remarkPresetLintConsistent, 16 | remarkPresetLintRecommended, 17 | remarkPresetLintMarkdownStyleGuide, 18 | [remarkLintDefinitionCase, false], 19 | [remarkLintListItemIndent, "one"], 20 | [remarkLintListItemSpacing, { checkBlanks: true }], 21 | [remarkLintNoFileNameMixedCase, false], 22 | [remarkLintNoFileNameIrregularCharacters, false] 23 | ] 24 | }; 25 | -------------------------------------------------------------------------------- /specs/.remarkrc-specs.js: -------------------------------------------------------------------------------- 1 | import remarkGfm from "remark-gfm"; 2 | import remarkHeadingId from "remark-heading-id"; 3 | import remarkFlexibleContainers from "remark-flexible-containers"; 4 | import remarkCodeTitles from "../remark/remark-code-titles.js"; 5 | import remarkHeadings from "../remark/remark-headings.js"; 6 | import remarkReferenceLinks from "../remark/remark-reference-links.js"; 7 | import remarkTableOfContents from "../remark/remark-table-of-contents.js"; 8 | 9 | 10 | export default { 11 | plugins: [ 12 | remarkGfm, 13 | remarkHeadingId, 14 | [remarkHeadings, { 15 | startDepth: 2, 16 | skip: [ 17 | "Abstract", 18 | "Status", 19 | "Note to Readers", 20 | "Table of Contents", 21 | "Contributors", 22 | "Champions", 23 | "\\[.*\\]", 24 | "draft-.*" 25 | ] 26 | }], 27 | remarkReferenceLinks, 28 | [remarkTableOfContents, { 29 | startDepth: 2, 30 | skip: [ 31 | "Abstract", 32 | "Note to Readers", 33 | "Authors' Addresses", 34 | "Champions", 35 | "\\[.*\\]", 36 | "draft-.*" 37 | ] 38 | }], 39 | remarkFlexibleContainers, 40 | remarkCodeTitles 41 | ] 42 | }; 43 | -------------------------------------------------------------------------------- /specs/.remarkrc-build.js: -------------------------------------------------------------------------------- 1 | import { readFileSync } from "node:fs"; 2 | import { resolve } from "node:path"; 3 | import rehypeHighlight from "rehype-highlight"; 4 | import { all } from "lowlight"; 5 | import rehypeHighlightCodeLines from "rehype-highlight-code-lines"; 6 | import remarkRehype from "remark-rehype"; 7 | import rehypeStringify from "rehype-stringify"; 8 | import rehypeDocument from "rehype-document"; 9 | import specsPreset from "./.remarkrc-specs.js"; 10 | import rehypeLinkTransformer from "../remark/rehype-link-transformer.js"; 11 | 12 | 13 | export default { 14 | plugins: [ 15 | specsPreset, 16 | remarkRehype, 17 | [rehypeHighlight, { languages: all }], 18 | [rehypeHighlightCodeLines, { showLineNumbers: true }], 19 | rehypeLinkTransformer, 20 | [rehypeDocument, { 21 | css: [ 22 | "https://cdn.jsdelivr.net/npm/water.css@2/out/dark.css", 23 | "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.0/styles/github-dark-dimmed.min.css" 24 | ], 25 | style: readFileSync(resolve(import.meta.dirname, "spec.css"), "utf8") 26 | }], 27 | rehypeStringify, 28 | () => (_tree, file) => { 29 | if (file.extname) { 30 | file.extname = ".html"; 31 | } 32 | } 33 | ] 34 | }; 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@json-schema-org/json-schema-spec", 3 | "version": "1.0.0", 4 | "description": "The JSON Schema Specification", 5 | "type": "module", 6 | "main": "index.js", 7 | "scripts": { 8 | "lint": "eslint . ; remark --no-stdout --frail .", 9 | "build": "remark --rc-path specs/.remarkrc-build.js --output web/", 10 | "build-ietf": "docker-compose run --rm build" 11 | }, 12 | "license": "MIT", 13 | "devDependencies": { 14 | "@stylistic/eslint-plugin": "^2.9.0", 15 | "eslint": "^9.13.0", 16 | "eslint-import-resolver-node": "^0.3.9", 17 | "eslint-plugin-import": "^2.31.0", 18 | "mdast-builder": "^1.1.1", 19 | "mdast-util-find-and-replace": "^3.0.1", 20 | "mdast-util-to-string": "^4.0.0", 21 | "rehype-document": "^7.0.3", 22 | "rehype-highlight": "^7.0.2", 23 | "rehype-highlight-code-lines": "^1.1.3", 24 | "rehype-stringify": "^10.0.1", 25 | "remark-cli": "^12.0.1", 26 | "remark-flexible-containers": "^1.2.1", 27 | "remark-gfm": "^4.0.0", 28 | "remark-heading-id": "^1.0.1", 29 | "remark-preset-lint-consistent": "^6.0.0", 30 | "remark-preset-lint-markdown-style-guide": "^6.0.0", 31 | "remark-preset-lint-recommended": "^7.0.0", 32 | "remark-rehype": "^11.1.1", 33 | "remark-validate-links": "^13.0.1" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | ### What kind of change does this PR introduce? 12 | 13 | 14 | 15 | ### Issue & Discussion References 16 | 17 | 18 | - Closes #___ 19 | - Related to #___ 20 | - Others? 21 | 22 | ### Summary 23 | 24 | 25 | 26 | ### Does this PR introduce a breaking change? 27 | 28 | 29 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from "@eslint/js"; 2 | import globals from "globals"; 3 | import stylistic from "@stylistic/eslint-plugin"; 4 | import importPlugin from "eslint-plugin-import"; 5 | 6 | 7 | export default [ 8 | js.configs.recommended, 9 | importPlugin.flatConfigs.recommended, 10 | stylistic.configs.customize({ 11 | arrowParens: true, 12 | braceStyle: "1tbs", 13 | commaDangle: "never", 14 | flat: true, 15 | jsx: false, 16 | quotes: "double", 17 | semi: true 18 | }), 19 | { 20 | languageOptions: { 21 | ecmaVersion: "latest", 22 | globals: { 23 | ...globals.node 24 | } 25 | }, 26 | settings: { 27 | "import/resolver": { 28 | node: {} 29 | } 30 | }, 31 | rules: { 32 | "no-unused-vars": ["error", { caughtErrorsIgnorePattern: "^_" }], 33 | "no-empty-function": "off", 34 | "no-console": ["error"], 35 | 36 | // Imports 37 | "import/extensions": ["error", "ignorePackages"], 38 | "import/newline-after-import": ["error", { count: 2, exactCount: false, considerComments: true }], 39 | 40 | // Stylistic 41 | "@stylistic/yield-star-spacing": ["error", "after"], 42 | "@stylistic/multiline-ternary": "off", 43 | "@stylistic/no-multiple-empty-lines": ["error", { max: 2, maxEOF: 0, maxBOF: 0 }] // Allow max=2 for imports 44 | } 45 | } 46 | ]; 47 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting Security Issues 2 | 3 | The JSON Schema project does not house any implementation of JSON Schema itself. 4 | If you have found a security issue in any implementation of JSON Schema, please 5 | contact the appropriate maintainers, per the projects security reporting 6 | guidelines, if any. 7 | 8 | To report a security issue, please use the GitHub Security Advisory 9 | "" 10 | tab. 11 | 12 | If you find a security issue in relation to the JSON Schema specification or 13 | another repository within this GitHub organization, please use the above. 14 | 15 | The JSON Schema project TSC will review and respond to all security reports. 16 | Please follow [coordinated disclosure](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/about-coordinated-disclosure-of-security-vulnerabilities). 17 | 18 | If you are a maintainer of an implementation, please consider [adding a security 19 | policy](https://docs.github.com/en/code-security/getting-started/adding-a-security-policy-to-your-repository). 20 | If you need assistance in understanding a report, or remediation of a confirmed 21 | issue, please feel free to reach out to us on our Slack server, in the 22 | `#implementations` channel, and ask for a temporary private channel to discuss 23 | your situation or concerns. 24 | 25 | -------------------------------------------------------------------------------- /remark/remark-table-of-contents.js: -------------------------------------------------------------------------------- 1 | import { visit } from "unist-util-visit"; 2 | import { list, listItem } from "mdast-builder"; 3 | import { toString as nodeToString } from "mdast-util-to-string"; 4 | 5 | 6 | const defaultOptions = { 7 | heading: "Table of Contents", 8 | startDepth: 1, 9 | skip: [] 10 | }; 11 | 12 | const remarkTableOfContents = (options) => (tree, file) => { 13 | options = { ...defaultOptions, ...options }; 14 | options.skip.push(options.heading); 15 | options.skip = new RegExp(`^(${options.skip.join("|")})$`, "u"); 16 | 17 | let insertTableOfContents; 18 | 19 | const tableOfContents = list("unordered"); 20 | let currentList = tableOfContents; 21 | const listStack = [currentList]; 22 | let currentDepth = options.startDepth; 23 | 24 | visit(tree, "heading", (headingNode, index, parent) => { 25 | const headingText = nodeToString(headingNode); 26 | 27 | if (headingText === options.heading) { 28 | insertTableOfContents = () => { 29 | parent.children.splice(index + 1, 0, tableOfContents); 30 | }; 31 | } 32 | 33 | if (headingNode.depth < options.startDepth) { 34 | return; 35 | } 36 | 37 | while (headingNode.depth > currentDepth) { 38 | const newList = list("unordered"); 39 | listStack.push(newList); 40 | currentList.children.push(newList); 41 | currentList = newList; 42 | currentDepth++; 43 | } 44 | 45 | while (headingNode.depth < currentDepth) { 46 | listStack.pop(); 47 | currentList = listStack[listStack.length - 1]; 48 | currentDepth--; 49 | } 50 | 51 | if (options.skip.test(headingText)) { 52 | return; 53 | } 54 | 55 | currentList.children.push(listItem(headingNode.children)); 56 | }); 57 | 58 | if (insertTableOfContents) { 59 | insertTableOfContents(); 60 | } else { 61 | file.message(`Table of Contents not added. Add a heading with the text "${options.heading}" or set the 'heading' option to use a different heading.`); 62 | } 63 | }; 64 | 65 | export default remarkTableOfContents; 66 | -------------------------------------------------------------------------------- /remark/remark-code-titles.js: -------------------------------------------------------------------------------- 1 | import { visit } from "unist-util-visit"; 2 | import { text } from "mdast-builder"; 3 | 4 | 5 | const hexdig = `[0-9a-fA-F]`; 6 | const char = `(?:\\\\["\\/\\\\brfnt]|\\\\u${hexdig}{4}|[^"\\\\])`; 7 | const jsonStringPattern = new RegExp(`^"${char}*"`); 8 | 9 | const remarkNumberHeadings = () => (tree) => { 10 | visit(tree, "code", (codeNode, index, parent) => { 11 | // Support title without a language 12 | if (codeNode.lang && codeNode.lang[0] === "\"") { 13 | codeNode.meta = `${codeNode.lang} ${codeNode.meta}`; 14 | codeNode.lang = null; 15 | } 16 | 17 | let title = ""; 18 | const titleClasses = ["remark-code-title"]; 19 | 20 | const language = codeNode.lang ?? ""; 21 | if (language.toLowerCase() === "jsonschema") { 22 | codeNode.lang = "json"; 23 | title = "JSON Schema"; 24 | titleClasses.push("code-title-jsonschema"); 25 | } else if (language.toLowerCase() === "json") { 26 | title = "JSON"; 27 | titleClasses.push("code-title-json"); 28 | } else if (language.toLowerCase() === "jsonc") { 29 | title = "JSON"; 30 | titleClasses.push("code-title-json"); 31 | } else { 32 | titleClasses.push("code-title-unknown"); 33 | } 34 | 35 | if ("meta" in codeNode) { 36 | const match = jsonStringPattern.exec(codeNode.meta); 37 | if (match) { 38 | const customTitle = JSON.parse(match[0]); 39 | title = title ? `${title} - ${customTitle}` : customTitle; 40 | codeNode.meta = codeNode.meta.slice(match[0].length).trim(); 41 | } 42 | } 43 | 44 | const containerChildren = []; 45 | if (title) { 46 | const titleNode = div([text(title)], { className: titleClasses }); 47 | containerChildren.push(titleNode); 48 | } 49 | containerChildren.push(codeNode); 50 | 51 | const wrappedCodeNode = div(containerChildren, { className: ["remark-code-container"] }); 52 | 53 | parent.children.splice(index, 1, wrappedCodeNode); 54 | }); 55 | }; 56 | 57 | const div = (children, properties) => { 58 | return { 59 | type: "container", 60 | children, 61 | data: { 62 | hName: "div", 63 | hProperties: properties 64 | } 65 | }; 66 | }; 67 | 68 | export default remarkNumberHeadings; 69 | -------------------------------------------------------------------------------- /adr/template.md: -------------------------------------------------------------------------------- 1 | # \[short title of solved problem and solution] 2 | 3 | - Status: \[proposed | rejected | accepted | deprecated | ... | superseded by 4 | \[ADR-0005](0005-example.md)] 5 | - Deciders: \[list everyone involved in the decision] 6 | - Date: \[YYYY-MM-DD when the decision was last updated] 7 | 8 | Technical Story: \[description | ticket/issue URL] 9 | 10 | ## Context and Problem Statement 11 | 12 | \[Describe the context and problem statement, e.g., in free form using two to 13 | three sentences. You may want to articulate the problem in form of a question.] 14 | 15 | ## Decision Drivers 16 | 17 | - \[driver 1, e.g., a force, facing concern, ...] 18 | - \[driver 2, e.g., a force, facing concern, ...] 19 | - … 20 | 21 | ## Considered Options 22 | 23 | ### \[option 1] 24 | 25 | \[example | description | pointer to more information | ...] 26 | 27 | - Good, because \[argument a] 28 | - Good, because \[argument b] 29 | - Bad, because \[argument c] 30 | - … 31 | 32 | ### \[option 2] 33 | 34 | \[example | description | pointer to more information | ...] 35 | 36 | - Good, because \[argument a] 37 | - Good, because \[argument b] 38 | - Bad, because \[argument c] 39 | - … 40 | 41 | ### \[option 3] 42 | 43 | \[example | description | pointer to more information | ...] 44 | 45 | - Good, because \[argument a] 46 | - Good, because \[argument b] 47 | - Bad, because \[argument c] 48 | - … 49 | 50 | ## Decision Outcome 51 | 52 | "\[option 1]" was chosen because \[justification. e.g., only option, which meets 53 | k.o. criterion decision driver | which resolves force force | ... | comes out 54 | best (see below)]. 55 | 56 | ### Positive Consequences 57 | 58 | - \[e.g., improvement of quality attribute satisfaction, follow-up decisions 59 | required, ...] 60 | - ... 61 | 62 | ### Negative Consequences 63 | 64 | - \[e.g., compromising quality attribute, follow-up decisions required, ...] 65 | - ... 66 | 67 | ## Links 68 | 69 | - \[Link type] \[Link to ADR] 70 | - ... 71 | -------------------------------------------------------------------------------- /specs/meta/README.md: -------------------------------------------------------------------------------- 1 | # JSON Schema Meta-Schema 2 | 3 | The *meta.json* file contains the meta-schema for the in-progress JSON Schema 4 | specifications. You can find the latest published version on the [JSON Schema 5 | website](https://json-schema.org). 6 | 7 | ## Table of Contents 8 | 9 | ## Meta-Schemas 10 | 11 | A meta-schema is a schema that itself describes a schema. This is possible 12 | because JSON Schema can be written as JSON. 13 | 14 | Furthermore, the JSON Schema meta-schema is self-validating. That is, its JSON 15 | form validates against the meta-schema. 16 | 17 | ## Extensions and Unknown Keywords 18 | 19 | The JSON Schema specification allows for extension keywords to be introduced, 20 | however it also disallows unknown keywords. While seemingly contradictory, the 21 | meta-schema has been set up to allow for extension. 22 | 23 | For this example, we'll add two hypothetical keywords: `odds` and `evens`, which 24 | validate the odd and even indexed values in an array, respectively. 25 | 26 | First, create a schema that just defines the new keywords. 27 | 28 | ```json 29 | { 30 | "$schema": "https://json-schema.org/v1", 31 | "$id": "https://example.com/schema/odds-evens", 32 | 33 | "properties": { 34 | "odds": { "$dynamicRef": "#meta" }, 35 | "evens": { "$dynamicRef": "#meta" } 36 | } 37 | } 38 | ``` 39 | 40 | Second, create a new meta-schema that 41 | 42 | - references the above schema 43 | - references the JSON Schema meta-schema 44 | - includes an extension point in a `$defs` 45 | 46 | ```json 47 | { 48 | "$schema": "https://json-schema.org/v1", 49 | "$id": "https://example.com/schema/odds-evens-extension", 50 | 51 | "$ref": "https://json-schema.org/v1", 52 | 53 | "$defs": { 54 | "extension": { 55 | "$dynamicAnchor": "extension", 56 | "$ref": "https://example.com/schema/odds-evens" 57 | } 58 | } 59 | } 60 | ``` 61 | 62 | Now you can use `https://example.com/schema/odds-evens-extension` in your 63 | schemas to make use of the new `odds` and `evens` keywords. 64 | 65 | ```json 66 | { 67 | "$schema": "https://example.com/schema/odds-evens-extension", 68 | "$id": "https://example.com/schema/model", 69 | 70 | "type": "array", 71 | "odds": { "type": "string" }, 72 | "evens": { "type": "number" } 73 | } 74 | ``` 75 | 76 | This schema will validate arrays whose items alternate between strings and 77 | numbers. 78 | -------------------------------------------------------------------------------- /specs/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/next/schema", 3 | "$id": "https://json-schema.org/draft/next/schema", 4 | "$vocabulary": { 5 | "https://json-schema.org/draft/next/vocab/core": true, 6 | "https://json-schema.org/draft/next/vocab/applicator": true, 7 | "https://json-schema.org/draft/next/vocab/unevaluated": true, 8 | "https://json-schema.org/draft/next/vocab/validation": true, 9 | "https://json-schema.org/draft/next/vocab/meta-data": true, 10 | "https://json-schema.org/draft/next/vocab/format-annotation": true, 11 | "https://json-schema.org/draft/next/vocab/content": true 12 | }, 13 | "$dynamicAnchor": "meta", 14 | 15 | "title": "Core and Validation specifications meta-schema", 16 | "allOf": [ 17 | {"$ref": "meta/core"}, 18 | {"$ref": "meta/applicator"}, 19 | {"$ref": "meta/unevaluated"}, 20 | {"$ref": "meta/validation"}, 21 | {"$ref": "meta/meta-data"}, 22 | {"$ref": "meta/format-annotation"}, 23 | {"$ref": "meta/content"} 24 | ], 25 | "type": ["object", "boolean"], 26 | "$comment": "This meta-schema also defines keywords that have appeared in previous drafts in order to prevent incompatible extensions as they remain in common use.", 27 | "properties": { 28 | "definitions": { 29 | "$comment": "\"definitions\" has been replaced by \"$defs\".", 30 | "type": "object", 31 | "additionalProperties": { "$dynamicRef": "#meta" }, 32 | "deprecated": true, 33 | "default": {} 34 | }, 35 | "dependencies": { 36 | "$comment": "\"dependencies\" has been split and replaced by \"dependentSchemas\" and \"dependentRequired\" in order to serve their differing semantics.", 37 | "type": "object", 38 | "additionalProperties": { 39 | "anyOf": [ 40 | { "$dynamicRef": "#meta" }, 41 | { "$ref": "meta/validation#/$defs/stringArray" } 42 | ] 43 | }, 44 | "deprecated": true, 45 | "default": {} 46 | }, 47 | "$recursiveAnchor": { 48 | "$comment": "\"$recursiveAnchor\" has been replaced by \"$dynamicAnchor\".", 49 | "type": "boolean", 50 | "deprecated": true 51 | }, 52 | "$recursiveRef": { 53 | "$comment": "\"$recursiveRef\" has been replaced by \"$dynamicRef\".", 54 | "type": "string", 55 | "format": "uri-reference", 56 | "deprecated": true 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /specs/output/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/next/schema", 3 | "$id": "https://json-schema.org/draft/next/output/schema", 4 | "description": "A schema that validates the minimum requirements for validation output", 5 | 6 | "anyOf": [ 7 | { "$ref": "#/$defs/flag" }, 8 | { "$ref": "#/$defs/list" }, 9 | { "$ref": "#/$defs/hierarchical" } 10 | ], 11 | "$defs": { 12 | "outputUnit":{ 13 | "properties": { 14 | "valid": { "type": "boolean" }, 15 | "evaluationPath": { 16 | "type": "string", 17 | "format": "json-pointer" 18 | }, 19 | "schemaLocation": { 20 | "type": "string", 21 | "format": "uri" 22 | }, 23 | "instanceLocation": { 24 | "type": "string", 25 | "format": "json-pointer" 26 | }, 27 | "details": { 28 | "$ref": "#/$defs/outputUnitArray" 29 | }, 30 | "annotations": { 31 | "type": "object", 32 | "additionalProperties": true 33 | }, 34 | "droppedAnnotations": { 35 | "type": "object", 36 | "additionalProperties": true 37 | }, 38 | "errors": { 39 | "type": "object", 40 | "additionalProperties": { "type": "string" } 41 | } 42 | }, 43 | "required": [ "valid", "evaluationPath", "schemaLocation", "instanceLocation" ], 44 | "allOf": [ 45 | { 46 | "if": { 47 | "anyOf": [ 48 | { 49 | "required": [ "errors" ] 50 | }, 51 | { 52 | "required": [ "droppedAnnotations" ] 53 | } 54 | ] 55 | }, 56 | "then": { 57 | "properties": { 58 | "valid": { "const": false } 59 | } 60 | } 61 | }, 62 | { 63 | "if": { 64 | "required": [ "annotations" ] 65 | }, 66 | "then": { 67 | "properties": { 68 | "valid": { "const": true } 69 | } 70 | } 71 | } 72 | ] 73 | }, 74 | "outputUnitArray": { 75 | "type": "array", 76 | "items": { "$ref": "#/$defs/outputUnit" } 77 | }, 78 | "flag": { 79 | "properties": { 80 | "valid": { "type": "boolean" } 81 | }, 82 | "required": [ "valid" ] 83 | }, 84 | "list": { 85 | "properties": { 86 | "valid": { "type": "boolean" }, 87 | "details": { 88 | "$ref": "#/$defs/outputUnitArray" 89 | } 90 | }, 91 | "required": [ "valid", "details" ] 92 | }, 93 | "hierarchical": { "$ref": "#/$defs/outputUnit" } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /specs/proposals/proposal-template.md: -------------------------------------------------------------------------------- 1 | # JSON Schema Proposal: 2 | 3 | ## Abstract 4 | 5 | 15 | 16 | This document proposes a change to the ??? specification by adding ???. 17 | 18 | ## Current Status 19 | 20 | 24 | 25 | ## Note to Readers 26 | 27 | 31 | 32 | The issues list for this proposal can be found at 33 | . 34 | 35 | For additional information, see . 36 | 37 | To provide feedback, use this issue tracker or any of the communication methods 38 | listed on the homepage. 39 | 40 | ## Table of Contents 41 | 42 | ## Conventions and Terminology 43 | 44 | All conventions and terms used and defined by the JSON Schema Core specification 45 | also apply to this document. 46 | 47 | ## Overview 48 | 49 | ### Problem Statement 50 | 51 | 52 | 53 | ### Solution 54 | 55 | 56 | 57 | ### Limitations 58 | 59 | 60 | 61 | ## Change Details 62 | 63 | 83 | 84 | ## %appendix% Change Log 85 | 86 | - \[MMMM YYYY\] Created 87 | 88 | ## %appendix% Champions 89 | 90 | | Champion | Company | Email | URI | 91 | | -------------------------- | ------- | ----------------------- | -------------------------------- | 92 | | Your Name | | | < GitHub profile page > | 93 | -------------------------------------------------------------------------------- /specs/proposals/vocabularies-adr.md: -------------------------------------------------------------------------------- 1 | # Add Vocabulary System 2 | 3 | - Status: proposed 4 | - Deciders: @gregsdennis, @jdesrosiers 5 | - Date: 2024-06-10 6 | 7 | Technical Story: 8 | 9 | - Issues discussing feature - 10 | - ADR to extract from the spec and use feature life cycle - 11 | 12 | ## Table of Contents 13 | 14 | ## Context and Problem Statement 15 | 16 | The current approach to extending JSON Schema by providing custom keywords is 17 | very implementation-specific and therefore not interoperable. 18 | 19 | To address this deficiency, this document proposes vocabularies as a concept 20 | and a new Core keyword, `$vocabulary` to support it. 21 | 22 | ## Decision Drivers 23 | 24 | - Language-agnostic 25 | - Ease of use 26 | - Ease of implementation 27 | 28 | ## Considered Options 29 | 30 | ### Current design as included in 2019-09 and 2020-12. 31 | 32 | A vocabulary is a collection of keywords and is defined by a vocabulary 33 | document. For the 2019-09 and 2020-12 vocabularies, the documents are integrated 34 | into the specifications themselves. 35 | 36 | With vocabularies as the primary method for defining individual keywords, 37 | dialects can be created by combining different vocabularies. 38 | 39 | Users must confirm with an implementation's documentation whether a given 40 | vocabulary is supported. 41 | 42 | `$vocabulary` keyword is an object with URI keys and boolean values. The URIs 43 | identify each vocab, and the values indicate whether the implementation must 44 | "understand" that vocab in order to process the schema. This keyword is only 45 | processed when it is found as part of a meta-schema. 46 | 47 | - Good because it provides a language-agnostic method of defining extension 48 | keywords that's built into JSON Schema itself 49 | - Bad because unknown keywords are now unsupported, which implies that 50 | [unknown vocabularies are implicitly 51 | unsupported](https://github.com/orgs/json-schema-org/discussions/342) 52 | 53 | ### [option 2] 54 | 55 | [example | description | pointer to more information | …] 56 | 57 | - Good, because [argument a] 58 | - Good, because [argument b] 59 | - Bad, because [argument c] 60 | - ... 61 | 62 | ### [option 3] 63 | 64 | [example | description | pointer to more information | …] 65 | 66 | - Good, because [argument a] 67 | - Good, because [argument b] 68 | - Bad, because [argument c] 69 | - ... 70 | 71 | ## Decision Outcome 72 | 73 | *TBD* 74 | 75 | ### Positive Consequences 76 | 77 | *TBD* 78 | 79 | ### Negative Consequences 80 | 81 | *TBD* 82 | -------------------------------------------------------------------------------- /adr/2024-05-08-extract-unstable-keywords.md: -------------------------------------------------------------------------------- 1 | # Extract Unstable Features for Initial Release 2 | 3 | - Status: accepted 4 | - Deciders: @gregsdennis @jdesrosiers @bhutton 5 | - Date: 2024-05-08 6 | 7 | Technical Story: 8 | 9 | @gregsdennis [proposed](https://github.com/json-schema-org/json-schema-spec/issues/1443#issuecomment-2099427543) 10 | that an ADR be created to document that unstable features be extracted before 11 | the stable release. 12 | 13 | Also the [SDLC proposal](https://github.com/orgs/json-schema-org/discussions/671) 14 | which lists features that need to be put into the proposal process. 15 | 16 | ## Context and Problem Statement 17 | 18 | In creating a stable spec release, it's important that all included features are 19 | well-developed and their behaviors are finalized. As such, the following 20 | features will be extracted before the stable release. 21 | 22 | - `$vocabulary` - This feature is still in development. 23 | - Output formats - This feature is being extracted to its own spec anyway. (See 24 | [PR](https://github.com/json-schema-org/json-schema-spec/pull/1429) for more 25 | info and link to discussion.) 26 | - `propertyDependencies` - This feature is not technically in the spec and 27 | should go through the proposal process. 28 | 29 | ## Decision Drivers 30 | 31 | We can't publish a stable spec that contains unstable features. Thus we need to 32 | remove them. 33 | 34 | ## Considered Options 35 | 36 | 1. Extract unfinished features and put them through the proposal process. 37 | 1. Complete the features before releasing the spec. 38 | 39 | ## Decision Outcome 40 | 41 | Chosen option: Extract unfinished features and put them through the proposal 42 | process. 43 | 44 | This allows us to release a stable version of the specification while continuing 45 | to develop these features. 46 | 47 | ### Positive Consequences 48 | 49 | - We can release a spec earlier that fulfills our users' needs. 50 | - We can continue to develop these features. 51 | 52 | ### Negative Consequences 53 | 54 | - These feature will be considered experimental until their proposals are 55 | accepted. This may be a hindrance to adoption. 56 | 57 | ## Pros and Cons of the Options 58 | 59 | 60 | ### Extract unfinished features and put them through the proposal process 61 | 62 | - Good, because we can release a spec earlier that fulfills our users' needs. 63 | - Good, because we can continue to develop these features. 64 | - Bad, because these features are experimental now. 65 | 66 | ### Complete the features before releasing the spec 67 | 68 | - Good, because the features will be ready to use when the spec releases. 69 | - Bad, because the spec may not release if we can't finalize the features. 70 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Guidelines for contributing to the JSON Schema project 2 | 3 | ## Contributing to JSON Schema Specification 4 | 5 | Thanks for taking the time to contribute! 🎉👍 6 | 7 | JSON Schema is an evolving language. This repository contains the specification 8 | text as well as Pull Requests with suggested improvements and contributions. 9 | 10 | Contributions that do not change the interpretation of the spec but instead 11 | improve legibility, fix editorial errors, clear up ambiguity and improve 12 | examples are encouraged and are often merged by a spec editor with little 13 | process. 14 | 15 | However, contributions that *do* meaningfully change the interpretation of the 16 | spec must follow the [Specification Development Process](./PROCESS.md). 17 | 18 | ## Issues 19 | 20 | Issues should identify a problem, enhancement, or use case; and propose some 21 | course of action for the draft. For alternate support channels, see the 22 | [SUPPORT.md](https://github.com/json-schema-org/.github/blob/main/SUPPORT.md). 23 | 24 | ## Pull Requests 25 | 26 | We welcome pull requests, both for editorial suggestions and to resolve open 27 | issues. 28 | 29 | If the pull request would solve a particular issue, reference the issue in the 30 | pull request description. 31 | 32 | Changes that would affect implementation behavior should typically be opened as 33 | an issue first. 34 | 35 | Generally, pull requests should be made to the `main` branch unless it is a 36 | patch update and we are in a patch phase. In that case there will be a branch 37 | named something like `2020-12-patch` that the PR should target instead. 38 | 39 | Most PRs, including all PRs that impact implementation behavior, will be left 40 | open for a minimum of 14 days. Minor wording fixes may be merged more quickly 41 | once approved by a project member. 42 | 43 | ## Milestones 44 | 45 | Each milestone is an estimation of the work that will be done for the next 46 | draft. Milestones are typically named after the meta-schema draft number, and 47 | the *open* milestone with the lowest draft number is the current active project. 48 | 49 | Issues may be removed from a milestoned due to lack of consensus, lack of anyone 50 | with the correct expertise to make a PR, or simply because we wish to publish a 51 | draft and defer the remaining issues to the next draft. 52 | 53 | Numbered milestones other than the lowest-numbered one are used to tentatively 54 | organize future work, but may be completely reorganized once work on that draft 55 | actually begins. 56 | 57 | The `draft-future` milestone is for issues for which there is an agreement that 58 | they should be addressed, but no specific timeline. 59 | 60 | ## Code of Conduct 61 | 62 | All official channels including the mailing list, GitHub organization and Slack 63 | server, follow our 64 | [Code of Conduct](https://github.com/json-schema-org/.github/blob/main/CODE_OF_CONDUCT.md). 65 | 66 | ## Have Questions? 67 | 68 | You can join the `#specification` channel in our 69 | [Slack workspace](https://json-schema.org/slack) to interact with other 70 | community members involved in the Specification development, share new ideas and 71 | ask questions. 72 | 73 | -------------------------------------------------------------------------------- /remark/remark-headings.js: -------------------------------------------------------------------------------- 1 | import { visit } from "unist-util-visit"; 2 | import { link, text } from "mdast-builder"; 3 | import { findAndReplace } from "mdast-util-find-and-replace"; 4 | import { toString as nodeToString } from "mdast-util-to-string"; 5 | 6 | 7 | const defaultOptions = { 8 | startDepth: 1, 9 | skip: [], 10 | appendixToken: "%appendix%", 11 | appendixPrefix: "Appendix" 12 | }; 13 | 14 | const remarkNumberHeadings = (options) => (tree, file) => { 15 | options = { ...defaultOptions, ...options }; 16 | options.skip = new RegExp(`^(${options.skip.join("|")})$`, "u"); 17 | 18 | // Auto-number headings 19 | let sectionNumbers = []; 20 | 21 | visit(tree, "heading", (headingNode) => { 22 | if (headingNode.depth < options.startDepth) { 23 | return; 24 | } 25 | 26 | const headingText = nodeToString(headingNode); 27 | if (options.skip.test(headingText)) { 28 | return; 29 | } 30 | 31 | if (!("data" in headingNode)) { 32 | headingNode.data = {}; 33 | } 34 | 35 | if (!("hProperties" in headingNode.data)) { 36 | headingNode.data.hProperties = {}; 37 | } 38 | 39 | if (headingText.startsWith(options.appendixToken)) { 40 | findAndReplace(headingNode, [options.appendixToken]); 41 | 42 | const currentIndex = typeof sectionNumbers[headingNode.depth] === "string" 43 | ? sectionNumbers[headingNode.depth] 44 | : "@"; 45 | sectionNumbers[headingNode.depth] = String.fromCharCode(currentIndex.charCodeAt(0) + 1); 46 | sectionNumbers = sectionNumbers.slice(0, headingNode.depth + 1); 47 | 48 | const sectionNumber = sectionNumbers.slice(options.startDepth, headingNode.depth + 1).join("."); 49 | headingNode.data.section = `${options.appendixPrefix} ${sectionNumber}`; 50 | 51 | headingNode.children.splice(0, 0, text(`${headingNode.data.section}. `)); 52 | } else { 53 | sectionNumbers[headingNode.depth] = (sectionNumbers[headingNode.depth] ?? 0) + 1; 54 | sectionNumbers = sectionNumbers.slice(0, headingNode.depth + 1); 55 | 56 | const sectionNumber = sectionNumbers.slice(options.startDepth, headingNode.depth + 1).join("."); 57 | const prefix = typeof sectionNumbers[options.startDepth] === "string" 58 | ? options.appendixPrefix 59 | : "Section"; 60 | headingNode.data.section = `${prefix} ${sectionNumber}`; 61 | 62 | headingNode.children.splice(0, 0, text(`${sectionNumber}. `)); 63 | } 64 | 65 | if (!("id" in headingNode.data)) { 66 | const sectionSlug = headingNode.data?.id 67 | ?? headingNode.data.section.replaceAll(/[ .]/g, "-").toLowerCase(); 68 | headingNode.data.hProperties.id = sectionSlug; 69 | headingNode.data.id = sectionSlug; 70 | } 71 | }); 72 | 73 | // Build headings data used by ./remark-reference-links.js 74 | if (!("data" in file)) { 75 | file.data = {}; 76 | } 77 | 78 | file.data.headings = {}; 79 | 80 | visit(tree, "heading", (headingNode) => { 81 | if (headingNode.data?.id) { 82 | if (headingNode.data.id in file.data.headings) { 83 | file.message(`Found duplicate heading id "${headingNode.data.id}"`); 84 | } 85 | file.data.headings[headingNode.data.id] = headingNode; 86 | } 87 | }); 88 | 89 | // Make heading a link 90 | visit(tree, "heading", (headingNode) => { 91 | if (headingNode.data?.id) { 92 | headingNode.children = [link(`#${headingNode.data.id}`, "", headingNode.children)]; 93 | } 94 | }); 95 | }; 96 | 97 | export default remarkNumberHeadings; 98 | -------------------------------------------------------------------------------- /adr/2024-11-2-assertion-format.md: -------------------------------------------------------------------------------- 1 | # `format` as an assertion 2 | 3 | - Status: proposed 4 | 5 | - Deciders: @gregsdennis @jdesrosiers @julian @jviotti @mwadams @karenetheridge 6 | @relequestual 7 | - Date: 2024-11-02 8 | - Technical Story: 9 | - Voting issue: 10 | - For - @gregsdennis @jdesrosiers @jviotti @mwadams @karenetheridge 11 | - Neutral - @relequestual 12 | - Against - @julian 13 | 14 | ## Context and Problem Statement 15 | 16 | There's a long and sticky history around format. 17 | 18 | 1. Going back all the way to Draft 01, format has never required validation. 19 | 1. Whether to support format validation has always been the decision of the 20 | implementation. 21 | 1. The extent to which formats are validated has also been the decision of the 22 | implementation. 23 | 24 | The result of all of this is that implementation support for validation has been 25 | spotty at best. Despite the JSON Schema specs referencing very concretely 26 | defined formats (by referencing other specs), implementations that do support 27 | validation don't all support each format equally. This has been the primary 28 | driving force behind keeping format as an opt-in validation. 29 | 30 | With 2019-09, we decided that it was time to give the option of format 31 | validation to the schema author. They could enable validation by using a 32 | meta-schema which listed the Format Vocabulary with a true value, which meant, 33 | "format validation is required to process this schema." 34 | 35 | In 2020-12, we further refined this by offering two separate vocabularies, one 36 | that treats the keyword as an annotation and one that treats it as an assertion. 37 | The argument was that the behavior of a keyword shouldn't change based on 38 | whether the vocabulary was required or not. 39 | 40 | However, the fact remains that our users consistently report (via questions in 41 | Slack, GitHub, and StackOverflow) that they expect format to validate. (The most 42 | recent case I can think of was only last week, in .Net's effort to build a 43 | short-term solution for schema generation from types.) 44 | 45 | Due to this consistency in user expectations, we have decided to: 46 | 47 | 1. make format an assertion keyword, and 48 | 1. strictly enforce it by moving the appropriate tests into the required section 49 | of the Test Suite and building them more completely. 50 | 51 | ## Decision Drivers 52 | 53 | - User expectation 54 | - Current behavior 55 | - Historical context 56 | - Disparity of current implementation support vs the proposed requirements 57 | 58 | ## Considered Options 59 | 60 | ### `format` remains an annotation keyword by default 61 | 62 | This is the current state. The primary benefit is that we don't need to make a 63 | breaking change. 64 | 65 | The primary downside is that the current system of (1) configuring the tool or 66 | (2) incluing the `format-assertion` vocab[^1] is confusing for many and doesn't 67 | align with user expectations. 68 | 69 | ### `format` becomes an assertion keyword by default 70 | 71 | We change the spec to require `format` validation. Furthermore: 72 | 73 | - Implementations SHOULD support `format` with the defined values 74 | - Implementations MAY support others, but only by explicit config 75 | - Implementations MUST refuse to process a schema that contains an unsupported 76 | format 77 | 78 | ## Decision Outcome 79 | 80 | The TSC has decided via vote (see voting issue above) that we should change 81 | `format` to act as an assertion by default, in line with option (2). 82 | 83 | ### Positive Consequences 84 | 85 | - Aligns with user expectations. 86 | - Users are still able to have purely annotative behavior through use of 87 | something like `x-format`. 88 | - Increased consistency for `format` validation across implementations. 89 | 90 | ### Negative Consequences 91 | 92 | - This is a breaking change, which means that we will likely have to re-educate 93 | the users who correctly treat it as an annotation. 94 | - Older schemas which do not specify a version (`$schema`) may change their 95 | validation outcome. 96 | - The burden on implementations will be greater since format validation was 97 | previously optional. 98 | 99 | [^1]: The `format-assertion` vocabulary will no longer be an option since we 100 | have demoted vocabularies to a proposal for the stable release. This leaves tool 101 | configuration as the only option to enable `format` validation. 102 | -------------------------------------------------------------------------------- /adr/2024-02-object-contains.md: -------------------------------------------------------------------------------- 1 | # `contains` and JSON Objects 2 | 3 | - Status: Proposed, accepted, reconsidered, and ultimately reverted. 4 | - Deciders: @gregsdennis, @jdesrosiers, @handrews, @awwright, @karenetheridge, 5 | @relequestual (with input from a couple non-core members) 6 | - Date: 2023-11-14 (documented 2024-02-09) 7 | 8 | Technical Story: 9 | 10 | - Original proposal 11 | [#1077](https://github.com/json-schema-org/json-schema-spec/issues/1077) and 12 | [PR](https://github.com/json-schema-org/json-schema-spec/pull/1092) 13 | - Reversion discussion 14 | [#1358](https://github.com/json-schema-org/json-schema-spec/issues/1358) and 15 | [PR](https://github.com/json-schema-org/json-schema-spec/pull/1452) 16 | 17 | ## Context and Problem Statement 18 | 19 | \[2021-02] 20 | The original proposal was for `contains` to apply to objects as well as arrays 21 | since there was no functionality to do so. The discussion covered the options of 22 | modifying `contains` or introducing a new `objectContains` (or similar) keyword 23 | set (also needs separate min/max). The decision was voted on and modifying 24 | `contains` won. 25 | 26 | \[2021-06] 27 | A change was applied. 28 | 29 | \[2022-12] 30 | With the team shifting focus to stability between spec releases, the question 31 | was raised again with the argument that allowing `contains` to apply to objects 32 | is a breaking change. It was conceded that the better approach would be to 33 | retain `contains` only for arrays and introduce a new keyword set to apply to 34 | objects. 35 | 36 | \[2023-11] 37 | The change was applied (reverted to previous behavior). 38 | 39 | ## Decision Drivers 40 | 41 | - The original decision to allow `contains` to apply to objects was driven by 42 | the fact that no such functionality existed. 43 | - The decision to revert was driven by a desire to not break current usages of 44 | `contains`. 45 | 46 | ## Considered Options 47 | 48 | - `contains` could be modified to apply to objects. 49 | - a new keyword set (e.g. `objectContains` along with associated min/max) could 50 | be added. 51 | 52 | ## Decision Outcome 53 | 54 | Ultimately, `contains` will continue to apply to only arrays. New keywords will 55 | need to be introduced to apply to objects. (Such a proposal has not yet been 56 | made.) 57 | 58 | ### Positive Consequences 59 | 60 | - Schemas which currently use `contains` without a `type: array` specifier will 61 | not suddenly start applying to objects also. 62 | 63 | ### Negative Consequences 64 | 65 | - The functionality of `contains` as applied to objects is still unsupported. 66 | 67 | ## Pros and Cons of the Options 68 | 69 | ### Change `contains` 70 | 71 | (Example provided recently by a user in [Slack](https://json-schema.slack.com/archives/C5CF75URH/p1707258032879409)) 72 | 73 | The requirement is that an object may contain any number of properties, but one 74 | and only one of them must contain an object with a `title` property. 75 | 76 | ✔️ valid 77 | ```json 78 | { 79 | "foo": { "title": "a title" }, 80 | "bar": { "baz": 42 } 81 | } 82 | ``` 83 | 84 | ❌ invalid 85 | ```json 86 | { 87 | "foo": { "quux": false }, 88 | "bar": { "baz": 42 } 89 | } 90 | ``` 91 | 92 | ❌ invalid 93 | ```json 94 | { 95 | "foo": { "title": "a title" }, 96 | "bar": { "title": "a title" } 97 | } 98 | ``` 99 | 100 | Currently, this is impossible since there is no way to conditionally count 101 | property values. However, with `contains` applying to objects, the following is 102 | possible: 103 | 104 | ```json 105 | { 106 | "type": "object", 107 | "contains": { 108 | "type": "object", 109 | "required": ["title"] 110 | }, 111 | "minContains": 1, 112 | "maxContains": 1 113 | } 114 | ``` 115 | 116 | - Good, because it provides functionality that previously did not exist 117 | - Bad, because is can potentially break some schemas 118 | - ... 119 | 120 | ### New keywords 121 | 122 | Same examples as [changing `contains`](#change-contains), except we use new 123 | keywords instead. 124 | 125 | The schema would be something like this instead: 126 | 127 | ```json 128 | { 129 | "type": "object", 130 | "objectContains": { 131 | "type": "object", 132 | "required": ["title"] 133 | }, 134 | "objectMinContains": 1, 135 | "objectMaxContains": 1 136 | } 137 | ``` 138 | 139 | - Good, because it provides functionality that previously did not exist 140 | - Good, because it doesn't break anyone 141 | - Bad, because we have to introduce three new keywords 142 | - ... 143 | -------------------------------------------------------------------------------- /adr/2023-04-sva-prefix.md: -------------------------------------------------------------------------------- 1 | # Supporting Single-Value Annotations via a Defined Prefix 2 | 3 | - Status: accepted 4 | - Deciders: @relequestual, @gregsdennis, @jdesrosiers, @karenetheridge, 5 | @awwright, @julian 6 | - Date: 2023-04-04 7 | 8 | Related: 9 | 10 | - Discussions: 11 | - Disallow Unknown Keywords - 12 | - Support SVAs - 13 | - PRs: 14 | - (proposal) 15 | 16 | ## Context and Problem Statement 17 | 18 | Dropping support for unknown keywords was a necessary step toward providing 19 | stability guarantees. However, the community's reaction to this news was not 20 | encouraging. How can we still support keywords that are merely collected as 21 | annotations and provide no functionality (single-value annotations, or SVAs)? 22 | 23 | ## Decision Drivers 24 | 25 | - Future-proofing - We want to ensure that we can still add keywords to the spec 26 | without breaking existing schemas. 27 | - Implementation supportability - Is the proposal feasible to implement? 28 | - Community preference 29 | 30 | ## Considered Options 31 | 32 | 1. A defined prefix or other convention for SVAs 33 | 1. Optionally defined by a new `$sigil` keyword 34 | 1. Inlined vocabularies that can define SVAs 35 | 1. A new core keyword that lists SVAs, e.g. `$ignored` 36 | 1. A defined configuration option to allow/forbid unknown keywords 37 | 1. A new core keyword designed for "extra" data 38 | 39 | ## Decision Outcome 40 | 41 | Chosen option: A defined prefix or other convention. 42 | 43 | This option was chosen because it solves the problem in a clean way that can be 44 | easily implemented. It was also the favorite solution among the team members as 45 | well as the community. 46 | 47 | Specifically, the prefix `x-` has been selected. 48 | 49 | ### Positive Consequences 50 | 51 | - It solves the problem by allowing users to include custom data in their 52 | schemas. 53 | - Many developers will be familiar with using `x-` for custom data. 54 | - It's a simple way to differentiate SVAs from other keywords. 55 | 56 | ### Negative Consequences 57 | 58 | - Some people preferred a different prefix as `x-` in some other contexts 59 | denotes "experimental" behavior. 60 | 61 | ## Pros and Cons of the Options 62 | 63 | ### Option 1 - A defined prefix or other convention for SVAs 64 | 65 | [Discussion](https://github.com/orgs/json-schema-org/discussions/329#discussioncomment-4988859) 66 | 67 | - Good, because it's simple and easy to understand. 68 | - Good, because `x-` specifically is familiar to many developers as an 69 | identifying prefix for custom data. 70 | - Good, because it's easily supportable by the meta-schema (i.e. 71 | `patternProperties`) 72 | - Bad, because `x-` in some other contexts can denote "experimental" behavior, 73 | which is not our meaning. 74 | 75 | #### Option 1a - Optionally defined by a new `$sigil` keyword 76 | 77 | [Discussion](https://github.com/orgs/json-schema-org/discussions/329#discussioncomment-5357549) 78 | 79 | - Good, because it can give users flexibility for the prefix that they want to 80 | use. 81 | - Bad, because it cannot be supported by the meta-schema without other changes, 82 | which may be difficult to define and/or implement. 83 | 84 | High level of effort 85 | 86 | ### Option 2 - Inlined vocabularies that can define SVAs 87 | 88 | [Discussion](https://github.com/orgs/json-schema-org/discussions/329#discussioncomment-4988882) 89 | 90 | - Good, because it defines the SVAs in a vocabulary which means they are 91 | regarded as "known." 92 | - Bad, because we don't have any support for inlined vocabularies at the moment 93 | and would have to build that. 94 | 95 | ### Option 3 - A new core keyword that lists SVAs, e.g. `$ignored` 96 | 97 | [Discussion](https://github.com/orgs/json-schema-org/discussions/329#discussioncomment-4988904) 98 | 99 | - Good, because it provides a way to define SVAs. 100 | - Bad, because it cannot be supported by the meta-schema without other changes, 101 | which may be difficult to define and/or implement. 102 | 103 | High level of effort 104 | 105 | 106 | ### Option 4 - A defined configuration option to allow/forbid unknown keywords 107 | 108 | [Discussion](https://github.com/orgs/json-schema-org/discussions/329#discussioncomment-4999789) 109 | 110 | - Good, because it returns previous functionality (i.e. allowing unknown 111 | keywords) to the user. 112 | - Bad, because that previous functionality removes/circumvents stability 113 | guarantees. 114 | 115 | ### Option 5 - A new core keyword designed for "extra" data 116 | 117 | [Discussion](https://github.com/orgs/json-schema-org/discussions/329#discussioncomment-5374873) 118 | 119 | - Good, because it provides a place for users to add extra data. 120 | - Bad, because it's an extra depth level that users need to create. 121 | - Bad, because it can only generate a single annotation instead of multiple. 122 | -------------------------------------------------------------------------------- /specs/proposals/propertyDependencies.md: -------------------------------------------------------------------------------- 1 | # JSON Schema Proposal: The `propertyDependencies` Keyword 2 | 3 | ## Abstract 4 | 5 | The `propertyDependencies` keyword is a more friendly way to select between two 6 | or more schemas to validate an instance against than is currently supported by 7 | JSON Schema. 8 | 9 | ## Current Status 10 | 11 | This proposal is complete and awaiting integration into the specification. 12 | 13 | As some additional context, this proposal has been written prior to the stable 14 | specification's initial release. As such, it will not be integrated until at 15 | least the spec's second release at the earliest. It is also operating as a 16 | proving grounds, of sorts, for the SDLC's Feature Life Cycle. 17 | 18 | ## Note to Readers 19 | 20 | The issues list for this document can be found at 21 | . 22 | 23 | For additional information, see . 24 | 25 | To provide feedback, use this issue tracker or any of the communication methods 26 | listed on the homepage. 27 | 28 | ## Table of Contents 29 | 30 | ## Conventions and Terminology 31 | 32 | All conventions and terms used and defined by the [JSON Schema Core 33 | specification](../jsonschema-core.md) also apply to this document. 34 | 35 | ## Overview 36 | 37 | ### Problem Statement 38 | 39 | A common need in JSON Schema is to select between one schema or another to 40 | validate an instance based on the value of some property in the JSON instance. 41 | There are a several patterns people use to accomplish this, but they all have 42 | significant [problems](propertyDependencies-adr.md#problems). 44 | 45 | OpenAPI solves this problem with the `discriminator` keyword. However, their 46 | approach is more oriented toward code generation concerns, is poorly specified 47 | when it comes to validation, and is coupled to OpenAPI concepts that don't exist 48 | is JSON Schema. Therefore, it's necessary to define something new rather than 49 | adopt or redefine `discriminator`. 50 | 51 | ### Solution 52 | 53 | The `dependentSchemas` keyword is very close to what is needed except it checks 54 | for the presence of a property rather than it's value. The chosen solution is to 55 | build on that concept to solve this problem. 56 | 57 | ```json 58 | { 59 | "propertyDependencies": { 60 | "foo": { 61 | "aaa": { "$ref": "#/$defs/foo-aaa" } 62 | } 63 | } 64 | } 65 | ``` 66 | 67 | The validation result is equivalent to the following schema. 68 | 69 | ```json 70 | { 71 | "if": { 72 | "properties": { 73 | "foo": { "const": "aaa" } 74 | }, 75 | "required": ["foo"] 76 | }, 77 | "then": { "$ref": "#/$defs/foo-aaa" } 78 | } 79 | ``` 80 | 81 | ### Limitations 82 | 83 | The problem of choosing an alternative based on a property value could apply for 84 | a value of any JSON type, but `propertyDependencies` only solves this problem 85 | when the value is a string. One of the main goals of this keyword is to define 86 | something that's intuitive enough and easy enough to use that people will 87 | actually use it rather than fallback to `oneOf` because it's simple. Achieving 88 | those goals means that some trade-offs need to be made. 89 | 90 | ## Change Description 91 | 92 | The `propertyDependencies` keyword will be added to the 93 | `https://json-schema.org/vocab/applicator` [applicator 94 | vocabulary](../jsonschema-core.md#applicators). 95 | 96 | 1. The following will be added to the JSON Schema Core specification as a 97 | subsection of "Keywords for Applying Subschemas Conditionally". 98 | 99 | > ### `propertyDependencies` 100 | > 101 | > This keyword specifies subschemas that are evaluated if the instance is an 102 | > object and contains a certain property with a certain string value. 103 | > 104 | > This keyword's value MUST be an object. Each value in the object MUST be 105 | > an object whose values MUST be valid JSON Schemas. 106 | > 107 | > If the outer object key is a property in the instance and the inner object 108 | > key is equal to the value of that property, the entire instance must 109 | > validate against the schema. Its use is dependent on the presence and 110 | > value of the property. 111 | > 112 | > Omitting this keyword has the same behavior as an empty object. 113 | 114 | 1. The following subschema will be added to the Applicator Vocabulary schema, 115 | `https://json-schema.org///meta/applicator` at 116 | `/properties/propertyDependencies`: 117 | 118 | ```json 119 | { 120 | "type": "object", 121 | "additionalProperties": { 122 | "type": "object", 123 | "additionalProperties": { 124 | "$dynamicRef": "#meta", 125 | "default": true 126 | }, 127 | "default": {} 128 | } 129 | } 130 | ``` 131 | 132 | ## %appendix% Change Log 133 | 134 | - \[March 2021\] - Initially proposed 135 | - \[October 2021\] Added to specification document 136 | - \[May 2024\] Extracted from specification document as experimental feature 137 | 138 | ## Champions 139 | 140 | | Champion | Company | Email | URI | 141 | | ---------------- | ------------------------ | -------------------- | -------------------------------- | 142 | | Jason Desrosiers | Hyperjump Software, Inc. | | | 143 | -------------------------------------------------------------------------------- /adr/2022-04-08-cref-for-ambiguity-and-fix-later-gh-spec-issue-1172.md: -------------------------------------------------------------------------------- 1 | 2 | # Acknowledge ambiguity in additionalProperties behaviour and fix after patch release 3 | 4 | - Status: accepted 5 | - Deciders: @relequestual @gregsdennis, @jdesrosiers, @karenetheridge 6 | - Date: 2022-05-19 7 | 8 | Related... 9 | 10 | Issue: 11 | 12 | Discussion: 13 | 14 | Pull Request: 15 | 16 | ## Context and Problem Statement 17 | 18 | When we changed the specification to use annotations as the context in which 19 | some keywords behave, we included a clause that allowed implementations which 20 | didn't use annotations to optimize the processing of `additionalProperties` in 21 | another way which produces the same effect as the prior behaviour. This section 22 | created an ambiguity in terms of the resulting output format, but not 23 | validation. 24 | 25 | We needed to decide on how to proceed for the patch release of the 2020-12 26 | version of the specification. 27 | 28 | The two above links are to a GitHub Discussion and a GitHub Issue detailing the 29 | problems. Details with an example of the problem can be seen in the Discussion's 30 | opening post specifically. 31 | 32 | ## Decision Drivers 33 | 34 | - The "patch release" should not change anything functionally 35 | - Annotations as they are, are confusing to users, implementers, and 36 | specification editors alike 37 | - Patch release is behind schedule 38 | - There are currently no tests for the output format 39 | - It's hard to see any immediate consensus on changing the annotation based 40 | behaviour 41 | 42 | ## Considered Options 43 | 44 | - [Leaving it "as is" and do nothing](https://github.com/json-schema-org/community/discussions/57#discussioncomment-1413777) 45 | - [Pick one](https://github.com/json-schema-org/community/discussions/57#discussioncomment-1416683) 46 | of the behaviours 47 | - [Revert back to draft-07 behaviour](https://github.com/json-schema-org/community/discussions/57#discussioncomment-1453723) 48 | - [Reinterpret how we understand annotation collection](https://github.com/json-schema-org/json-schema-spec/issues/1172#issuecomment-1049686478) 49 | to allow reading annotations within the same schema object regardless of 50 | assertion results 51 | - [Acknowledge and accept that two approaches and results are allowable](https://github.com/json-schema-org/community/issues/161#issue-1173742930) 52 | - Redefine annotation collection behaviour and/or how `additionalProperties` 53 | works 54 | 55 | ## Decision Outcome 56 | 57 | Chosen option: "Acknowledge and accept that two approaches and results are 58 | allowable", because 59 | 60 | - Leaving it "as is" will continue to cause confusion 61 | - The change is non-functional which is required for the patch release 62 | - The patch release is behind schedule 63 | - Finding consensus of other solutions proved to be difficult 64 | - There's no test suite for the output format, so it's not easy to see 65 | unintended consequences of a functional change 66 | - We need to properly re-evaluate annotation collection and how annotations are 67 | used by other keywords 68 | 69 | ### Positive Consequences 70 | 71 | - Patch release can move forward 72 | - Validation result is not impacted 73 | - Confusion is at least seen and acknowledged 74 | - Implementations which pick either approach are seen to be compliant 75 | 76 | ### Negative Consequences 77 | 78 | - May have an impact for downstream tools which process full output data 79 | - A test suite (not yet developed) which covers this situation needs to allow 80 | for multiple valid answers 81 | 82 | ## Pros and Cons of the Options 83 | 84 | ### Leaving it "as is" and do nothing 85 | 86 | Agree to do nothing and hope for the best. There isn't any downstream tooling 87 | yet anyway. 88 | 89 | - Good, because no functional change 90 | - Good, because no impact on downstream tooling 91 | - Bad, because leaves a known ambiguity in the specification 92 | 93 | 94 | ### Pick one / Revert to draft-07 behaviour / Reinterpret annotation collection 95 | 96 | - Good, because ambiguity is removed 97 | - Good, because not many tools will be effected 98 | - Bad, because it can be seen as a functional change (not really allowed for the 99 | patch release) 100 | - Bad, because it can break existing implementations and downstream tools 101 | - Bad, because without a test suite it's hard to see unexpected consequences 102 | 103 | ## Links 104 | 105 | - Issue: [Ambiguous behaviour of additionalProperties when invalid](https://github.com/json-schema-org/json-schema-spec/issues/1172) 106 | - Discussion: [The meaning of "additionalProperties" has changed](https://github.com/json-schema-org/community/discussions/57) 107 | - Resolving Pull Request: [Add CREF about ambiguous behaviour of additionalProperties](https://github.com/json-schema-org/json-schema-spec/pull/1203) 108 | - Alternative solution proposal: [Resolve contradictions in the described 109 | behaviour of "additionalProperties" and "items"](https://github.com/json-schema-org/json-schema-spec/pull/1154) 110 | - [Result of discussing](https://github.com/json-schema-org/json-schema-spec/issues/1172#issuecomment-1063962900) 111 | on an Open Community Working Meeting call - @jdesrosiers proposed a less 112 | controversial and more agreeable solution to add a comment that both are 113 | allowable 114 | - [Related GitHub Discussion](https://github.com/json-schema-org/community/discussions/67) 115 | on alternative behaviour for `unevaluated*` keywords 116 | -------------------------------------------------------------------------------- /specs/meta/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/v1/2026", 3 | "$id": "https://json-schema.org/v1/2026", 4 | "$dynamicAnchor": "meta", 5 | 6 | "title": "JSON Schema Core and Validation specification meta-schema", 7 | "type": ["object", "boolean"], 8 | "properties": { 9 | "$id": { 10 | "$ref": "#/$defs/iriReferenceString", 11 | "$comment": "Fragments not allowed.", 12 | "pattern": "^[^#]*$" 13 | }, 14 | "$schema": { "$ref": "#/$defs/iriString" }, 15 | "$ref": { "$ref": "#/$defs/iriReferenceString" }, 16 | "$anchor": { "$ref": "#/$defs/anchorString" }, 17 | "$dynamicRef": { "$ref": "#/$defs/iriReferenceString" }, 18 | "$dynamicAnchor": { "$ref": "#/$defs/anchorString" }, 19 | "$comment": { 20 | "type": "string" 21 | }, 22 | "$defs": { 23 | "type": "object", 24 | "additionalProperties": { "$dynamicRef": "#meta" } 25 | }, 26 | "title": { 27 | "type": "string" 28 | }, 29 | "description": { 30 | "type": "string" 31 | }, 32 | "default": true, 33 | "deprecated": { 34 | "type": "boolean", 35 | "default": false 36 | }, 37 | "readOnly": { 38 | "type": "boolean", 39 | "default": false 40 | }, 41 | "writeOnly": { 42 | "type": "boolean", 43 | "default": false 44 | }, 45 | "examples": { 46 | "type": "array", 47 | "items": true 48 | }, 49 | "prefixItems": { "$ref": "#/$defs/schemaArray" }, 50 | "items": { "$dynamicRef": "#meta" }, 51 | "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, 52 | "minContains": { 53 | "$ref": "#/$defs/nonNegativeInteger", 54 | "default": 1 55 | }, 56 | "contains": { "$dynamicRef": "#meta" }, 57 | "additionalProperties": { "$dynamicRef": "#meta" }, 58 | "properties": { 59 | "type": "object", 60 | "additionalProperties": { "$dynamicRef": "#meta" }, 61 | "default": {} 62 | }, 63 | "patternProperties": { 64 | "type": "object", 65 | "additionalProperties": { "$dynamicRef": "#meta" }, 66 | "propertyNames": { "format": "regex" }, 67 | "default": {} 68 | }, 69 | "dependentSchemas": { 70 | "type": "object", 71 | "additionalProperties": { "$dynamicRef": "#meta" }, 72 | "default": {} 73 | }, 74 | "propertyNames": { "$dynamicRef": "#meta" }, 75 | "if": { "$dynamicRef": "#meta" }, 76 | "then": { "$dynamicRef": "#meta" }, 77 | "else": { "$dynamicRef": "#meta" }, 78 | "allOf": { "$ref": "#/$defs/schemaArray" }, 79 | "anyOf": { "$ref": "#/$defs/schemaArray" }, 80 | "oneOf": { "$ref": "#/$defs/schemaArray" }, 81 | "not": { "$dynamicRef": "#meta" }, 82 | "unevaluatedItems": { "$dynamicRef": "#meta" }, 83 | "unevaluatedProperties": { "$dynamicRef": "#meta" }, 84 | "type": { 85 | "anyOf": [ 86 | { "$ref": "#/$defs/simpleTypes" }, 87 | { 88 | "type": "array", 89 | "items": { "$ref": "#/$defs/simpleTypes" }, 90 | "minItems": 1, 91 | "uniqueItems": true 92 | } 93 | ] 94 | }, 95 | "const": true, 96 | "enum": { 97 | "type": "array", 98 | "items": true 99 | }, 100 | "multipleOf": { 101 | "type": "number", 102 | "exclusiveMinimum": 0 103 | }, 104 | "maximum": { 105 | "type": "number" 106 | }, 107 | "exclusiveMaximum": { 108 | "type": "number" 109 | }, 110 | "minimum": { 111 | "type": "number" 112 | }, 113 | "exclusiveMinimum": { 114 | "type": "number" 115 | }, 116 | "maxLength": { "$ref": "#/$defs/nonNegativeInteger" }, 117 | "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, 118 | "pattern": { 119 | "type": "string", 120 | "format": "regex" 121 | }, 122 | "maxItems": { "$ref": "#/$defs/nonNegativeInteger" }, 123 | "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, 124 | "uniqueItems": { 125 | "type": "boolean", 126 | "default": false 127 | }, 128 | "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, 129 | "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, 130 | "required": { "$ref": "#/$defs/stringArray" }, 131 | "dependentRequired": { 132 | "type": "object", 133 | "additionalProperties": { 134 | "$ref": "#/$defs/stringArray" 135 | } 136 | }, 137 | "format": { "type": "string" }, 138 | "contentEncoding": { "type": "string" }, 139 | "contentMediaType": { "type": "string" }, 140 | "contentSchema": { "$dynamicRef": "#meta" }, 141 | 142 | "$vocabulary": { 143 | "$comment": "Proposed keyword: https://github.com/json-schema-org/json-schema-spec/blob/main/specs/proposals/vocabularies.md" 144 | }, 145 | "propertyDependencies": { 146 | "$comment": "Proposed keyword: https://github.com/json-schema-org/json-schema-spec/blob/main/specs/proposals/propertyDependencies.md" 147 | } 148 | }, 149 | "patternProperties": { 150 | "^x-": true 151 | }, 152 | "propertyNames": { 153 | "pattern": "^[^$]|^\\$(id|schema|ref|anchor|dynamicRef|dynamicAnchor|comment|defs)$" 154 | }, 155 | "$dynamicRef": "#extension", 156 | "unevaluatedProperties": false, 157 | "$defs": { 158 | "extension": { 159 | "$dynamicAnchor": "extension" 160 | }, 161 | "anchorString": { 162 | "type": "string", 163 | "pattern": "^[A-Za-z_][-A-Za-z0-9._]*$" 164 | }, 165 | "iriString": { 166 | "type": "string", 167 | "format": "iri" 168 | }, 169 | "iriReferenceString": { 170 | "type": "string", 171 | "format": "iri-reference" 172 | }, 173 | "nonNegativeInteger": { 174 | "type": "integer", 175 | "minimum": 0 176 | }, 177 | "nonNegativeIntegerDefault0": { 178 | "$ref": "#/$defs/nonNegativeInteger", 179 | "default": 0 180 | }, 181 | "schemaArray": { 182 | "type": "array", 183 | "minItems": 1, 184 | "items": { "$dynamicRef": "#meta" } 185 | }, 186 | "simpleTypes": { 187 | "enum": [ 188 | "array", 189 | "boolean", 190 | "integer", 191 | "null", 192 | "number", 193 | "object", 194 | "string" 195 | ] 196 | }, 197 | "stringArray": { 198 | "type": "array", 199 | "items": { "type": "string" }, 200 | "uniqueItems": true, 201 | "default": [] 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to JSON Schema 2 | [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](https://github.com/json-schema-org/.github/blob/main/CODE_OF_CONDUCT.md) 3 | [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) 4 | [![Financial Contributors on Open Collective](https://opencollective.com/json-schema/all/badge.svg?label=financial+contributors)](https://opencollective.com/json-schema) 5 | 6 | JSON Schema is a vocabulary that allows you to validate, annotate, and 7 | manipulate JSON documents. 8 | 9 | This repository contains the sources for the **work in progress** of the next 10 | set of JSON Schema IETF Internet Draft (I-D) documents. For the latest released 11 | I-Ds, please see the 12 | [Specification page](http://json-schema.org/specification.html) on the website. 13 | 14 | ## Call for contributions and feedback 15 | 16 | Reviews, comments and suggestions are most welcome! 17 | Please read our [guidelines for contributing](CONTRIBUTING.md). 18 | 19 | ## Status 20 | 21 | For the current status of issues and pull requests, please see the following 22 | labels 23 | 24 | [![Available](https://img.shields.io/github/issues/json-schema-org/json-schema-spec/Status:%20Available.svg?color=brightgreen)](https://github.com/json-schema-org/json-schema-spec/issues?q=is%3Aopen+is%3Aissue+label%3A%22Status%3A+Available%22) 25 | [![In Progress](https://img.shields.io/github/issues/json-schema-org/json-schema-spec/Status:%20In%20Progress.svg)](https://github.com/json-schema-org/json-schema-spec/labels/Status:%20In%20Progress) 26 | [![Review Needed](https://img.shields.io/github/issues/json-schema-org/json-schema-spec/Status:%20Review%20Needed.svg)](https://github.com/json-schema-org/json-schema-spec/labels/Status%3A%20Review%20Needed) 27 | [![Critical](https://img.shields.io/github/issues/json-schema-org/json-schema-spec/Priority:%20Critical.svg?color=critical 28 | )](https://github.com/json-schema-org/json-schema-spec/labels/Priority%3A%20Critical) 29 | [![High](https://img.shields.io/github/issues/json-schema-org/json-schema-spec/Priority:%20High.svg?color=important)](https://github.com/json-schema-org/json-schema-spec/labels/Priority%3A%20High) 30 | [![Medium](https://img.shields.io/github/issues/json-schema-org/json-schema-spec/Priority:%20Medium.svg)](https://github.com/json-schema-org/json-schema-spec/labels/Priority%3A%20Medium) 31 | [![Low](https://img.shields.io/github/issues/json-schema-org/json-schema-spec/Priority:%20Low.svg)](https://github.com/json-schema-org/json-schema-spec/labels/Priority%3A%20Low) 32 | 33 | Labels are assigned based on 34 | [Sensible Github Labels](https://github.com/Relequestual/sensible-github-labels). 35 | 36 | ## Authoring and Building 37 | 38 | ### Specification 39 | To build all the spec files to HTML from the Markdown sources, run `npm run 40 | build -- specs`. You can also build each individually with `npm run build -- 41 | specs/filename.md` (Example: `npm run build -- specs/jsonschema-core.md`). You 42 | can also use wildcards to build multiple specs at the same time: `npm run build 43 | -- specs/jsonschema-*.md`. The HTML files will be available in the `web` folder. 44 | 45 | The spec is built using [Remark](https://remark.js.org/), a markdown engine with 46 | good support for plugins and lots of existing plugins we can use. Remark also 47 | has a [language server](https://github.com/remarkjs/remark-language-server) and 48 | a [VSCode extension](https://github.com/remarkjs/vscode-remark) we can use to 49 | get linting an link checking while developing the spec. 50 | 51 | #### Plugins 52 | 53 | The following is a not-necessarily-complete list of configured plugins and the 54 | features they make available to you. 55 | 56 | - [remark-lint](https://github.com/remarkjs/remark-lint) -- Enforce markdown 57 | styles guide. 58 | - [remark-validate-links](https://github.com/remarkjs/remark-validate-links) -- 59 | Check for broken links. 60 | - [remark-gfm](https://github.com/remarkjs/remark-gfm) -- Adds support for 61 | Github Flavored Markdown specific markdown features such as autolink literals, 62 | footnotes, strikethrough, tables, and tasklists. 63 | - [remark-heading-id](https://github.com/imcuttle/remark-heading-id) -- Adds 64 | support for `{#my-anchor}` syntax to add an `id` to an element so it can be 65 | referenced using URI fragment syntax. 66 | - [remark-headings](./remark/remark-headings.js) 67 | -- A collection of enhancements for headings. 68 | - Adds hierarchical section numbers to headings. 69 | - Use the `%appendix%` prefix on headings that should be numbered as an 70 | appendix. 71 | - Adds id anchors to headers that don't have one 72 | - Example: `#section-2-13` 73 | - Example: `#appendix-a` 74 | - Makes the heading a link utilizing its anchor 75 | - [remark-reference-links](./remark/remark-reference-links.js) 76 | -- Adds new syntax for referencing a section of the spec using the section 77 | number as the link text. 78 | - Example: 79 | ```markdown 80 | ## Foo {#foo} 81 | ## Bar 82 | This is covered in {{foo}} // --> Renders to "This is covered in [Section 2.3](#foo)" 83 | - Link text will use "Section" or "Appendix" as needed 84 | ``` 85 | - [remark-table-of-contents](./remark/remark-table-of-contents.js) 86 | -- Adds a table of contents in a section with a header called "Table of 87 | Contents". 88 | - [remark-code-titles](./remark/remark-code-titles.js) 89 | -- Add titles to code blocks 90 | - Example: 91 | ```markdown 92 | \`\`\`jsonschema "My Fun Title" 93 | { "type": "string" } 94 | \`\`\` 95 | ``` 96 | - The languages `jsonschema` and `json` have special styling 97 | - The title will be parsed as a JSON string, but you have to double escape 98 | escaped characters. So, to get `My "quoted" title`, you would need to be 99 | `"My \\\\"quoted\\\\" title"`. 100 | - [rehype-highlight](https://github.com/rehypejs/rehype-highlight) -- 101 | Syntax highlighting. 102 | - [rehype-highlight-code-lines](https://github.com/ipikuka/rehype-highlight-code-lines) 103 | -- Adds line numbers to code blocks. Supports ranges. 104 | - [remark-flexible-containers](https://github.com/ipikuka/remark-flexible-containers) 105 | -- Add a callout box using the following syntax. Supported container types are 106 | `warning`, `note`, and `experimental`. 107 | ```markdown 108 | ::: {type} {title} 109 | {content} 110 | ::: 111 | ``` 112 | 113 | ### Internet-Drafts 114 | 115 | To build components that are being maintained as IETF Internet-Drafts, run 116 | `npm run build-ietf`. 117 | 118 | Descriptions of the xml2rfc, I-D documents, and RFC processes: 119 | 120 | - 121 | - 122 | - 123 | - 124 | 125 | ## Test suites 126 | 127 | Conformance tests for JSON Schema and its vocabularies may be found 128 | [in their own repository](https://github.com/json-schema-org/JSON-Schema-Test-Suite). 129 | 130 | ## The website 131 | 132 | The JSON Schema web site is at 133 | 134 | The source for the website is [maintained in a separate repository](https://github.com/json-schema-org/website). 135 | 136 | ## Contributors 137 | 138 | ### Code Contributors 139 | 140 | This project exists thanks to all the people who contribute. \[[Contribute](CONTRIBUTING.md)]. 141 | 142 | 143 | ### Financial Contributors 144 | 145 | Become a financial contributor and help us sustain our community. \[[Contribute](https://opencollective.com/json-schema/contribute)] 146 | 147 | #### Sponsors 148 | 149 | Here are our top sponsors. You could be next! \[[Become a sponsor](https://opencollective.com/json-schema#sponsor)] 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | #### Individuals 163 | 164 | 165 | 166 | ## License 167 | 168 | The contents of this repository are [licensed under](./LICENSE) either the BSD 169 | 3-clause license *or* the Academic Free License v3.0. 170 | -------------------------------------------------------------------------------- /specs/proposals/propertyDependencies-adr.md: -------------------------------------------------------------------------------- 1 | # Add New Keyword: `propertyDependencies` 2 | 3 | - Status: proposed 4 | - Deciders: @gregsdennis, @jdesrosiers, @relequestual 5 | - Date: 2022-04-07 6 | 7 | Technical Story: 8 | 9 | - Issue discussing feature - 10 | - PR to add to the spec - 11 | - ADR to extract from the spec and use feature life cycle - 12 | 13 | ## Table of Contents 14 | 15 | ## Context and Problem Statement 16 | 17 | A common need in JSON Schema is to select between one schema or another to 18 | validate an instance based on the value of some property in the JSON instance. 19 | There are a several patterns people use to accomplish this, but they all have 20 | significant [problems](#problems). 21 | 22 | OpenAPI solves this problem with the `discriminator` keyword. However, their 23 | approach is more oriented toward code generation concerns, is poorly specified 24 | when it comes to validation, and is coupled to OpenAPI concepts that don't exist 25 | is JSON Schema. Therefore, it's necessary to define something new rather than 26 | adopt or redefine `discriminator`. 27 | 28 | ## Decision Drivers 29 | 30 | - Ease of use 31 | - Readability 32 | - Coverage of most common use cases 33 | - Coverage of all use cases 34 | - Ease of implementation 35 | 36 | ## Considered Options 37 | 38 | All of the following options have the same validation result as the following 39 | schema. 40 | 41 | ```json 42 | { 43 | "if": { 44 | "properties": { 45 | "foo": { "const": "aaa" } 46 | }, 47 | "required": ["foo"] 48 | }, 49 | "then": { "$ref": "#/$defs/foo-aaa" } 50 | } 51 | ``` 52 | 53 | 54 | ### Option 1 55 | 56 | The `dependentSchemas` keyword is very close to what is needed except it checks 57 | for the presence of a property rather than it's value. This option builds on 58 | that concept to solve this problem. 59 | 60 | ```json 61 | { 62 | "propertyDependencies": { 63 | "foo": { 64 | "aaa": { "$ref": "#/$defs/foo-aaa" } 65 | } 66 | } 67 | } 68 | ``` 69 | 70 | - Good, because it handle the most common use case: string property values 71 | - Good, because all property values are grouped together 72 | - Good, because it's less verbose 73 | - Bad, because it doesn't handle non-string property values 74 | 75 | ### Option 2 76 | 77 | This version uses an array of objects. Each object is a collection of the 78 | variables needed to express a property dependency. This doesn't fit the style of 79 | JSON Schema. There aren't any keywords remotely like this. It's also still too 80 | verbose. It's a little more intuitive than `if`/`then` and definitely less error 81 | prone. 82 | 83 | ```jsonschema 84 | { 85 | "propertyDependencies": [ 86 | { 87 | "propertyName": "foo", 88 | "propertySchema": { "const": "aaa" }, 89 | "apply": { "$ref": "#/$defs/foo-aaa" } 90 | }, 91 | { 92 | "propertyName": "foo", 93 | "propertySchema": { "const": "bbb" }, 94 | "apply": { "$ref": "#/$defs/foo-bbb" } 95 | } 96 | ] 97 | } 98 | ``` 99 | 100 | * Good, because it supports all use cases 101 | * Bad, because properties are not naturally grouped together 102 | * Bad, because it's quite verbose 103 | * Bad, because we have no precedent for a keyword which explicitly defines its 104 | own properties. This would be new operational functionality, which we try to 105 | avoid if we can. 106 | 107 | ### Option 3 108 | 109 | A slight variation on that example is to make it a map of keyword to dependency 110 | object. It's still too verbose. 111 | 112 | ```jsonschema 113 | { 114 | "propertyDependencies": { 115 | "foo": [ 116 | { 117 | "propertySchema": { "const": "aaa" }, 118 | "apply": { "$ref": "#/$defs/foo-aaa" } 119 | }, 120 | { 121 | "propertySchema": { "const": "bbb" }, 122 | "apply": { "$ref": "#/$defs/foo-bbb" } 123 | } 124 | ] 125 | } 126 | } 127 | ``` 128 | 129 | * Good, because it supports all use cases 130 | * Good, because all property values are grouped together 131 | * Bad, because it's quite verbose 132 | * Bad, because we have no precedent for a keyword which explicitly defines its 133 | own properties. This would be new operational functionality, which we try to 134 | avoid if we can. 135 | 136 | ### Option 4 137 | 138 | This one is a little more consistent with the JSON Schema style (poor keyword 139 | naming aside), but otherwise has all the same problems as the other examples. 140 | 141 | ```jsonschema 142 | { 143 | "allOf": [ 144 | { 145 | "propertyDependencyName": "foo", 146 | "propertyDependencySchema": { "const": "aaa" }, 147 | "propertyDependencyApply": { "$ref": "#/$defs/foo-aaa" } 148 | }, 149 | { 150 | "propertyDependencyName": "foo", 151 | "propertyDependencySchema": { "const": "bbb" }, 152 | "propertyDependencyApply": { "$ref": "#/$defs/foo-bbb" } 153 | } 154 | ] 155 | } 156 | ``` 157 | 158 | - Good, because it supports all use cases 159 | - Bad, because properties are not naturally grouped together 160 | - Bad, because it's very verbose 161 | - Bad, because it introduces a lot of inter-keyword dependencies, which we'd 162 | have to exhaustively define 163 | 164 | ### Option 5 165 | 166 | This one is a variation of `if` that combines `if`, `properties`, and `required` 167 | to reduce boilerplate. It's also essentially a variation of the previous example 168 | with better names. This avoids to error proneness problem, but it's still too 169 | verbose. 170 | 171 | ```jsonschema 172 | { 173 | "allOf": [ 174 | { 175 | "ifProperties": { 176 | "foo": { "const": "aaa" } 177 | }, 178 | "then": { "$ref": "#/$defs/foo-aaa" } 179 | }, 180 | { 181 | "ifProperties": { 182 | "foo": { "const": "bbb" } 183 | }, 184 | "then": { "$ref": "#/$defs/foo-aaa" } 185 | } 186 | ] 187 | } 188 | ``` 189 | 190 | * Good, because it supports all use cases 191 | * Good, because it's a familiar syntax 192 | * Bad, because properties are not naturally grouped together 193 | * Bad, because it's very verbose 194 | * Bad, because `ifProperties` is very niche. Will this spawn a new series of 195 | `if*` keywords? How would it interact with `if`? 196 | 197 | ### Option 6 198 | 199 | All of the previous alternatives use a schema as the discriminator. This 200 | alternative is a little less powerful in that it can only match on exact values, 201 | but it successfully addresses the problems we're concerned about with the 202 | current approaches. The only issue with this alternative is that it's not as 203 | intuitive as the chosen solution. 204 | 205 | ```jsonschema 206 | { 207 | "propertyDependencies": { 208 | "foo": [ 209 | ["aaa", { "$ref": "#/$defs/foo-aaa" }], 210 | ["bbb", { "$ref": "#/$defs/foo-bbb" }] 211 | ] 212 | } 213 | } 214 | ``` 215 | 216 | * Good, because it supports all use cases 217 | * Bad, because it's an unintuitive syntax and easy to get wrong 218 | * Bad, because properties are not naturally grouped together 219 | 220 | ## Decision Outcome 221 | 222 | Option 1 was chosen because it satisfies the most common use cases while being 223 | sufficiently readable and easy to implement, even though it does not satisfy 224 | _all_ use cases, such as those where the property value is not a string. As 225 | these cases are significantly less common, the requirement to support all use 226 | cases carried a lower priority. 227 | 228 | ### Positive Consequences 229 | 230 | - Some level of built-in support for a `discriminator`-like keyword that aligns 231 | with the existing operation of JSON Schema. 232 | 233 | ### Negative Consequences 234 | 235 | - Properties with non-string values cannot be supported using this keyword and 236 | the `allOf`-`if`-`then` pattern must still be used. 237 | 238 | ## %appendix% Problems With Existing Patterns {#problems} 239 | 240 | ### `oneOf`/`anyOf` 241 | 242 | The pattern of using `oneOf` to describe a choice between two schemas has become 243 | ubiquitous. 244 | 245 | ```jsonschema 246 | { 247 | "oneOf": [ 248 | { "$ref": "#/$defs/aaa" }, 249 | { "$ref": "#/$defs/bbb" } 250 | ] 251 | } 252 | ``` 253 | 254 | However, this pattern has several shortcomings. The main problem is that it 255 | tends to produce confusing error messages. Some implementations employ 256 | heuristics to guess the user's intent and provide better messaging, but that's 257 | not wide-spread or consistent behavior, nor is it expected or required from 258 | implementations. 259 | 260 | This pattern is also inefficient. Generally, there is a single value in the 261 | object that determines which alternative to chose, but the `oneOf` pattern has 262 | no way to specify what that value is and therefore needs to evaluate the entire 263 | schema. This is made worse in that every alternative needs to be fully validated 264 | to ensure that only one of the alternative passes and all the others fail. This 265 | last problem can be avoided by using `anyOf` instead, but that pattern is much 266 | less used. 267 | 268 | ### `if`/`then` 269 | 270 | We can describe this kind of constraint more efficiently and with with better 271 | error messaging by using `if`/`then`. This allows the user to explicitly specify 272 | the constraint to be used to select which alternative the schema should be used 273 | to validate the schema. However, this pattern has problems of it's own. It's 274 | verbose, error prone, and not particularly intuitive, which leads most people to 275 | avoid it. 276 | 277 | ```jsonschema 278 | { 279 | "allOf": [ 280 | { 281 | "if": { 282 | "properties": { 283 | "foo": { "const": "aaa" } 284 | }, 285 | "required": ["foo"] 286 | }, 287 | "then": { "$ref": "#/$defs/foo-aaa" } 288 | }, 289 | { 290 | "if": { 291 | "properties": { 292 | "foo": { "const": "bbb" } 293 | }, 294 | "required": ["foo"] 295 | }, 296 | "then": { "$ref": "#/$defs/foo-bbb" } 297 | } 298 | ] 299 | } 300 | ``` 301 | -------------------------------------------------------------------------------- /adr/2022-09-decouple-from-ietf.md: -------------------------------------------------------------------------------- 1 | # Decoupling from IETF 2 | 3 | - Status: accepted 4 | - Deciders: @jdesrosiers @relequestual @awwright @handrews @gregsdennis 5 | - Date: 2022-09-27 6 | 7 | Related Issues: 8 | - - This issue is about 9 | dropping the "draft" prefix from our releases. This ADR doesn't cover that, 10 | but much of the discussion about whether or not to decouple from IETF is in 11 | that discussion. 12 | - This topic has been discussed in many other places as well that are difficult 13 | to link to here including Slack, Twitter, OCWMs, and conference discussions. 14 | 15 | ## Context and Problem Statement 16 | 17 | Currently JSON Schema loosely follows the IETF Internet-Draft (I-D) process for 18 | spec development and releases but isn't associated with any IETF working group. 19 | JSON Schema is an individual draft. That means it isn't on a standards track 20 | with IETF and IETF is not involved nor supports the spec in any way other than 21 | hosting the canonical version of our I-Ds. Our perceived involvement with IETF 22 | causes confusion and misunderstanding within our community in the cases were our 23 | practices and the realities of our situation deviate from a typical IETF I-D 24 | lifecycle. The thing that makes our situation different than a typical I-D is 25 | that our "drafts" are intended for use in production. 26 | 27 | ## Decision Drivers 28 | 29 | - IETF's draft versioning system doesn't work for JSON Schema and we stopped 30 | using it to version our releases a while ago. We now use date based versioning 31 | and even have more than one draft submission per release (the initial release 32 | and the patch release). 33 | - The IETF process is optimized for working on a draft until it's done and then 34 | disbanding. In some cases, the RFC may be revisited and revised in the future, 35 | but this is rare and generally contains little more than clarifications and 36 | reference updates. JSON Schema is not like that. JSON Schema is more like a 37 | programming language. When it stops evolving, it will lose its relevance. 38 | When we finish a release of JSON Schema, we don't disband, we start work on 39 | the next release. 40 | - Since the project resumed activity after the gap following draft-04, every one 41 | of our releases is expected to be used in production and will be depended on 42 | for many years forward. This is not consistent with normal IETF drafts. Even 43 | if we don't publicly use the term "draft", we're still using the IETF I-D 44 | system in a way that's not intended. 45 | - Under IETF, JSON Schema fits under the category of "draft". The community has 46 | repeatedly told us that they perceive this to meant that JSON Schema 47 | "incomplete" and not "not ready for production use". This is the wrong message 48 | for us to be sending as all of our releases are intended to be used in 49 | production. This ADR doesn't decide whether or not to drop the "draft" from 50 | our releases, but decoupling from IETF gives us that option. 51 | - Several members of the JSON Schema team have interacted with JSON-related IETF 52 | working groups. Some of these interactions demonstrated an indifference or 53 | hostility to JSON Schema, and a preference for projects taking a different 54 | approach. Equally important was a lack of any active interest or constructive 55 | engagement. Finally, we were informed that any schema project for JSON would 56 | not necessarily start from JSON Schema as a base, indicating that a "JSON 57 | Schema" working group would quite likely not involve JSON Schema itself. This 58 | impression has been reinforced by observing the amount of change introduced to 59 | JSON Path as a consequence of its adoption by an IETF working group. While we 60 | have a good relationship with the relatively new HTTPAPIs working group, the 61 | combination of these other experiences with other mismatches between our 62 | project and the IETF process contributes to our reluctance to move forward 63 | through the iETF. 64 | 65 | ## Considered Options 66 | 67 | 1. Continue to submit I-Ds, while using our customized process with no intention 68 | of pursing standards track RFC status. 69 | 1. Go all-in with IETF and pursue a standards track RFC with the IETF. The 70 | approach would be to describe the essential characteristics of evaluating a 71 | JSON Schema: the keywords that everybody is guaranteed to support, and any 72 | extension mechanisms. 73 | 1. Join W3C and pursue a standards track with them using their process. 74 | 1. Decouple completely from any standards organization and come up with our own 75 | specification development lifecycle (SDLC) model inspired by well established 76 | projects with an SDLC that more closely meets or needs. 77 | 78 | ## Decision Outcome 79 | 80 | Our decision is to go with Option 4 and decouple from standards organizations 81 | that don't fit our needs. We don't currently have a plan for what to replace 82 | IETF with, but we are currently investigating how other established projects do 83 | their SDLC and will likely choose one to emulate and adapt to our needs. 84 | Although we don't have a replacement solution in place yet, we are confident 85 | that continuing to abuse the IETF I-D process or conforming to a standards 86 | organization process that doesn't fit our needs is not the way to go. 87 | 88 | However, we still plan to use the IETF process to register the media types 89 | defined by JSON Schema with IANA. This effort is currently in progress with the 90 | HTTPAPIs working group. 91 | 92 | The decision to not use IETF applies only to the main specification documents 93 | and not necessarily supporting components we have defined or will define in the 94 | future. Currently our only such component is Relative JSON Pointer, but there 95 | could be others in the future. These components will be examined on a case by 96 | case basis and we may choose an IETF standards path for those components if it 97 | makes sense. 98 | 99 | Option 2 and 3 are still on the table if we feel it makes sense when we get to a 100 | more stable place in the future. The main concern is the pain this process is 101 | causing while we are in this unusual phase of simultaneous unstable growth and 102 | production use. Standardization isn't out of the question, it's just not 103 | productive for us to be developing JSON Schema within the constraints of a 104 | standards organizations procedures. 105 | 106 | Option 1 was rejected because it ignores the problems we've been facing and 107 | provides no solution. No one wants this. 108 | 109 | Option 2 was rejected for several reasons. If we go all in with IETF, we would 110 | have to join a working group and treat JSON Schema like a normal I-D. That means 111 | we would have to start treating drafts as drafts, which means not recommending 112 | production use until we are ready for RFC and not releasing a new 113 | production-ready version of JSON Schema until we've reached RFC status. Most of 114 | the core contributors don't believe that we are close enough to an RFC-ready 115 | release that we want to commit to not being able to issue another release until 116 | that happens. 117 | 118 | There are other concerns including skepticism that even with an extension 119 | mechanism that the RFC wouldn't need regular updates, which is not normal 120 | practice for an RFC and would require significant effort to issue a replacing 121 | RFC. Without a concrete proposal on the scope of the RFC and the extension 122 | mechanisms, it's hard to commit to this path. 123 | 124 | Additionally, many of the core contributors have found working with the IETF 125 | unproductive and have concerns about JSON Schema getting deeper involved without 126 | compelling enough reason. Most agree that the reasons are not sufficiently 127 | compelling at this point. 128 | 129 | Option 3 was rejected because it has the same problems as Option 2 except that 130 | we don't have the same unpleasant history with W3C than we do with IETF. 131 | Additionally, the W3C is a "pay to play" standards organization. Organizations 132 | must pay to contribute to specifications the W3C publish, which doesn't match 133 | the JSON Schema Org's open ethos. 134 | 135 | Ben Hutton has had multiple calls with various individuals at different levels 136 | within the W3C, and has a friendly contact should we wish to investigate again 137 | at a later point. The W3C does have an "invited expert" solution for when 138 | a persons employer doesn't want to be a paying member, however this is supposed 139 | to be an exception to the rule, and not frequently used. 140 | 141 | ### Positive Consequences 142 | 143 | - Decoupling from IETF allows us to distance ourselves from the assumptions that 144 | people make about JSON Schema because they assume it works like a typical I-D. 145 | - Decoupling from IETF allows us to customize our SDLC model to what works best 146 | for JSON Schema. 147 | 148 | ### Negative Consequences 149 | 150 | - If we don't go the standardization route with IETF or W3C, we lose access to 151 | their expert review process. 152 | - Not being associated with a recognized standards organization such as IETF, 153 | W3C, or IEEE reduces the credibility of JSON Schema in the eyes of some. 154 | However, we have received feedback that our membership with OpenJS/Linux 155 | Foundation provides the credibility that we need. 156 | - One of the benefits of an RFC is other standards can normatively reference it, 157 | and use JSON Schema to define their JSON-based syntaxes. However, we have 158 | received feedback from people involved in standards development that told us 159 | that they were comfortable referencing OpenAPI's self published specification 160 | in their standards and that OpenAPI's membership with the Linux Foundation was 161 | an important aspect of what makes them comfortable doing so. JSON Schema is a 162 | member of the OpenJS Foundation, which is a sub-group of the Linux Foundation, 163 | so we expect standards developers to be just as comfortable referencing JSON 164 | Schema as they are referencing OpenAPI. 165 | - Defining our own SLDC process will be a lot of work and none of us have 166 | expertise in defining such a process. However, we can take inspiration from 167 | existing well established projects and we would have the freedom to update our 168 | process as we learn what works and what doesn't. 169 | -------------------------------------------------------------------------------- /PROCESS.md: -------------------------------------------------------------------------------- 1 | 2 | # JSON Schema Specification Development and Publication Process 3 | 4 | ## Purpose 5 | 6 | This document describes the development and publication process for the JSON 7 | Schema specifications contained within this repository. 8 | 9 | - [JSON Schema Core](./specs/jsonschema-core.md) 10 | - [JSON Schema Validation](./specs/jsonschema-validation.md) 11 | 12 | ## Definitions 13 | 14 | ### Defined Behavior 15 | 16 | Some behaviors within JSON Schema may be explicitly or implicitly undefined by 17 | the specifications for various reasons. How to handle these behaviors is 18 | generally left to implementations. 19 | 20 | A defined behavior is one that is fully and unambiguously defined by the 21 | specifications. 22 | 23 | An undefined behavior is said to have an "indeterminate" validation result since 24 | implementations may resolve the behavior in different ways. 25 | 26 | ### Stability and Breaking Changes 27 | 28 | Stability is defined using the level of compatibility between sequential 29 | releases. If all schemas which are written to one release produce the same 30 | defined behavior under the following release, then those releases are 31 | compatible, and the specification is said to be stable between them. 32 | 33 | If an existing schema under the new release exhibits defined behavior that is 34 | contrary to defined behavior under the previous release, the new release is said 35 | to contain breaking changes and the specification is unstable between those 36 | releases. 37 | 38 | If a new release fully defines a previously undefined (or under-defined) 39 | behavior, the new release is still considered compatible, even if it contradicts 40 | the decision of any particular implementation. 41 | 42 | For reference, this table shows the validation results of a hypothetical schema 43 | and instance across two consecutive releases to illustrate the compatibility of 44 | those releases: 45 | 46 | | *Next* ➡️
⬇️ *Current* | pass | fail | indeterminate | 47 | | :-----------------------: | :--: | :--: | :-----------: | 48 | | **pass** | ✅ | ❌ | ❌ | 49 | | **fail** | ❌ | ✅ | ❌ | 50 | | **indeterminate** | ✅ | ✅ | ✅ | 51 | 52 | ### Release 53 | 54 | A release is any single publication of the JSON Schema specifications (as a 55 | group). 56 | 57 | ### Version 58 | 59 | Consecutive releases which maintain compatibility with each other comprise a 60 | version. 61 | 62 | ## Release and Version 63 | 64 | The JSON Schema specification will aim to publish annually on or about the First 65 | of January each year. Releases are identified by the year they are published. 66 | 67 | When a new release contains breaking changes, that release begins a new version 68 | of JSON Schema. 69 | 70 | The version will be identified as an integer, starting with `1` and incrementing 71 | as needed. 72 | 73 | Stability will be prioritized when making changes to the specification. Breaking 74 | changes are undesired and should be avoided when possible. 75 | 76 | ## Publication 77 | 78 | ### Specifications 79 | 80 | The specifications will be published on the JSON Schema website, 81 | , using a path comprised of the version, year, and 82 | document name. For example, 83 | 84 | - `https://json-schema.org/v1/2026/core.html` 85 | - `https://json-schema.org/v1/2026/validation.html` 86 | 87 | Once a specification document has been published, neither the document (save for 88 | minor errata such as spelling mistakes) nor its publication URL may change. If 89 | the TSC elects to alter the above URL scheme, the new scheme only applies to 90 | future publications and are not retroactive. 91 | 92 | ### Meta-schemas 93 | 94 | A release meta-schema will be published under the same path using `schema.json` 95 | as the file name. 96 | 97 | - `https://json-schema.org/v1/2026/schema.json` 98 | 99 | The website will also be configured to: 100 | 101 | - serve the meta-schema from its release folder: 102 | `https://json-schema.org/v1/2026/` 103 | - serve the meta-schema for the latest release in a version from its version 104 | folder: `https://json-schema.org/v1/` 105 | 106 | The latest-release meta-schemas will be updated with proposals as indicated by 107 | the [Proposal section](#proposal) of this document. 108 | 109 | > \[!IMPORTANT] 110 | > These are only publication and availability URLs. The specification will 111 | > define the `$id` values for the meta-schemas. 112 | 113 | ## Feature Life Cycle 114 | 115 | New features will progress through a sequence of stages before being added to 116 | the specification, and existing stable features must be formally deprecated 117 | before being removed. The stages of the life cycle, in order, are: 118 | 119 | - Concept 120 | - Proposal 121 | - Experimentation 122 | - Stable 123 | - Deprecated 124 | - Removed 125 | 126 | The flow through these stages is depicted below: 127 | 128 | ```mermaid 129 | stateDiagram-v2 130 | direction LR 131 | Concept --> Proposal 132 | state Development { 133 | Proposal --> Experimentation 134 | Experimentation --> Proposal 135 | } 136 | Development --> Stable 137 | Stable --> Deprectated 138 | Deprectated --> Removed 139 | ``` 140 | 141 | ### Concept 142 | 143 | The feature life cycle begins with an idea expressed in a GitHub issue in this 144 | repository. Initial discussion may occur in Slack or another space, but the life 145 | cycle does not formally begin until a GitHub issue is created. 146 | 147 | The discussion should cover how the feature could work, use cases, syntax, 148 | alternatives, whether it’s a breaking change, etc., with a goal of deciding 149 | rough requirements. 150 | 151 | During this stage, members of the Core Team will implement private prototypes of 152 | the ideas expressed in the issue to get a feel for how it integrates with the 153 | stable features. Questions to address may include: 154 | 155 | - Does the idea operate within the confines of existing JSON Schema evaluation 156 | processes, or does it define something new? 157 | - Is the idea merely a shortcut for some existing functionality (syntactic 158 | sugar), or does it solve a previously unsolvable problem? 159 | - What is the expected complexity for implementing the feature? 160 | 161 | At least two (2) Core Team members must have implemented prototypes before the 162 | concept can continue to the formal proposal process. 163 | 164 | ### Proposal 165 | 166 | Once a rough consensus for the idea has been reached, a formal proposal will be 167 | written, separate from the specification, with the goal of precisely defining 168 | specification changes. 169 | 170 | The proposal will use the [Proposal 171 | Template](./specs/proposals/proposal-template.md) and be stored in this 172 | repository's `proposals` folder. 173 | 174 | Additionally, a draft ADR will be included using the file name of the proposal 175 | document with an `-adr` suffix: `{proposal-file-name}-adr.md`. This ADR will 176 | include additional information from the "Concept" discussion. 177 | 178 | Proposed keywords will be added to the appropriate vocabulary meta-schemas in: 179 | 180 | - latest published release and 181 | - the `main` branch of this repository. 182 | 183 | The subschema for the proposed keyword will contain only a `$comment` keyword 184 | indicating that the feature is experimental and containing a link to the 185 | proposal document. Aside from the `$comment` keyword, the subschema will be 186 | empty. 187 | 188 | > \[!NOTE] 189 | > This is done so that a proposed keyword is allowed but not validated as its 190 | > syntax may change during the proposal/experimentation process. It also permits 191 | > different implementations to support different variations of each proposal 192 | > separately throughout this process. It will be up to the implementation to 193 | > validate these keywords in accordance with their support. 194 | 195 | Tests for the proposal are added to the JSON Schema Test Suite. 196 | 197 | ```diff 198 | @@ TODO: Identify a location within the test suite for proposals. @@ 199 | ``` 200 | 201 | Once an initial draft of the proposal has been completed and published, the 202 | feature moves into Experimentation. 203 | 204 | ### Experimentation 205 | 206 | Implementations may begin to support the new feature. 207 | 208 | Feedback from implementers and users are expected to result in refinements to 209 | the proposal, which will then be updated in the implementations. 210 | 211 | Breaking changes to a proposed feature MAY occur, but are highly discouraged. 212 | 213 | In order to proceed to the next stage ([Stable](#stable)): 214 | 215 | - at least five (5) implementations support the feature 216 | - there is sufficient evidence of use 217 | - no changes are requested for a period of six (6) weeks 218 | 219 | ```diff 220 | @@ TODO: Determine usage metrics. @@ 221 | ``` 222 | 223 | Experimental features are not considered to be interoperable across 224 | implementations. 225 | 226 | If a proposal cannot advance to the next stage, it may be removed. The proposal 227 | document is moved to an `archive` subfolder, the keyword is removed from the 228 | meta-schemas, and any tests are moved to an `archive` subfolder. The removal of 229 | a feature which has not reached the stable state is not considered a breaking 230 | change. 231 | 232 | ### Stable 233 | 234 | The feature is incorporated into the specification in the `main` branch as 235 | specified by the proposal document, and the feature will be required as of the 236 | next release. 237 | 238 | The draft ADR is completed, dated, and moved to the `adr` folder. 239 | 240 | The appropriate vocabulary meta-schema in the `main` branch is updated to 241 | include a subschema that validates the feature's syntax requirements. This will 242 | be made available with the next release. 243 | 244 | Upon publication of the new release, the meta-schema for the lapsed release will 245 | have the keyword removed. 246 | 247 | The appropriate tests are incorporated into the main suite. 248 | 249 | ### Deprecated 250 | 251 | If a feature is no longer useful, e.g. it has been replaced, it may be 252 | deprecated by indicating it as such in the specification. 253 | 254 | Implementations must support deprecated features. 255 | 256 | ### Removed 257 | 258 | A feature must have been published as deprecated for at least one release before 259 | it can be considered for removal. 260 | 261 | Feature removal is considered a breaking change. 262 | -------------------------------------------------------------------------------- /adr/2022-11-stable-spec.md: -------------------------------------------------------------------------------- 1 | # Selecting a new specification development process 2 | 3 | - Status: accepted 4 | - Deciders: @jdesrosiers @relequestual @awwright @handrews @gregsdennis 5 | - Date: 2022-11-02 6 | 7 | ## Context and Problem Statement 8 | 9 | We've chosen to decouple our process from IETF, so we need to choose a new 10 | specification development process to replace it. 11 | 12 | ## Decision Drivers 13 | 14 | - Dropping the "draft" label is an important driver of this change. It's mostly 15 | an artifact of the IETF process and has proven to be confusing for the 16 | community. 17 | - The community wants a stable version of JSON Schema. 18 | - There is a need for JSON Schema to continue to evolve to meet evolving 19 | needs. 20 | - There is a demand for custom keywords/vocabularies/dialects and we want to 21 | continue to support those use cases. 22 | - There is a need to ease the burden of implementations supporting multiple 23 | versions of JSON Schema. 24 | 25 | ## Considered Options 26 | 27 | There have been two proposals put forward. Both address the goal of a stable 28 | specification with the ability to evolve. The third option represents sticking 29 | with the status quo. 30 | 31 | ### Option 1 - TC-39 Inspired 32 | 33 | The spec would be converted from I-D XML to Markdown, but can otherwise be 34 | structured however we choose. A system would be put in place to allow us to flag 35 | the stability level of any feature in the spec. There would be only one version 36 | of the spec and that version can change at any time, but changes to stable 37 | features must follow strict backward and forward compatibility requirements. 38 | 39 | New features must go through a hardening process to ensure that they are very 40 | unlikely to change before they are considered stable and subject to 41 | compatibility requirements. This process will impose strict requirements 42 | including tests, implementations, documentation, and real world vetting before a 43 | feature or new keyword can be made stable in the spec. 44 | 45 | Since the spec is constantly evolving, a "release" is just a matter of promoting 46 | unstable features to "stable" status. Releases would happen once a year and be 47 | designated by the year they were released. 48 | 49 | ### Option 2 - IETF Inspired 50 | 51 | The spec would be reorganized into two parts: "Core Semantics" and "Standard 52 | Extensions". Changes to either spec are subject to strict backward and forward 53 | compatibility requirements and would be released as a new spec that replaces and 54 | obsoletes past versions of the spec. 55 | 56 | The "Core Semantics" spec would contain the bare minimum rules that must be 57 | implemented for validators to not produce inaccurate results regardless of 58 | future revisions or extensions. Among other necessities, this would include a 59 | core set of keywords necessary to fully support structural validation and an 60 | extension mechanism. This spec should rarely change. New features would be added 61 | through additional specifications that define extensions to the "Core Semantics" 62 | spec. 63 | 64 | The "Standard Extensions" spec is an example of one of these extension 65 | specifications. This spec would be authored by the JSON Schema Org, but 66 | extension specifications could be authored by anyone. The "Standard Extensions" 67 | spec would include everything from the current spec that isn't included in the 68 | "Core Semantics" spec. Features and keywords included in this spec are so 69 | ubiquitous that they should be considered essential for implementations to 70 | support. 71 | 72 | ### Option 3 - Minimal Change 73 | 74 | Option 3 represents the minimal amount of change to our process from what we 75 | have been doing. The spec would need to be converted from I-D XML to a Markdown 76 | version that would be served on the website, but otherwise we would continue to 77 | work the way we have been. We would aim for new version releases every year with 78 | patch releases mid-cycle. Each release is a distinct version of JSON Schema and 79 | has no compatibility guarantees between versions. 80 | 81 | ## Decision Outcome 82 | 83 | The decision is to go with Option 1 while leaving discussion open for aspects of 84 | Option 2 that could be adopted within the constraints of Option 1. 85 | 86 | Option 2 uses an immutable spec where each release replaces the last while 87 | Option 1 uses a mutable spec. The outcome of having only one current version of 88 | the spec is achieved with either option, but the mutable spec allows us to 89 | remove some unnecessary roadblocks in our development processes and allows us to 90 | release a stable spec much sooner. 91 | 92 | Option 2's restructuring of the spec into "Core Semantics" and "Standard 93 | Extensions" isn't specifically ruled out, but spec evolution is expected to be 94 | done primarily through mutation of the spec guided by the stability process 95 | rather than through extension. Option 1 puts no constraint on the structure of 96 | the spec and restructuring is allowed at any time as long as it doesn't break 97 | compatibility requirements. 98 | 99 | ## Pros and Cons of the Options 100 | 101 | The biggest benefit is shared between Option 1 and Option 2. Both approaches 102 | result in a stable spec. This will have benefits for both implementers and 103 | users. Because of the compatibility requirements, whenever you write a schema, 104 | you will never need to change it just to keep up with changes to JSON Schema. 105 | This is also better for implementers because they don't have to maintain 106 | separate code with different semantics in different versions. They just need to 107 | code for the current release and they will automatically have support for past 108 | releases (not including "draft" releases). 109 | 110 | 111 | ### Option 1 - TC-39 Inspired 112 | 113 | The two things that make this option stand out are the stability model governing 114 | spec evolution and the mutability of the spec document. 115 | 116 | Having a mutable spec allows us to make clarifications and bug fixes immediately 117 | rather than having to wait months or years for the next release to go out. It 118 | also allows us to iterate faster on unstable features which would allow us to 119 | get them to a stable state much sooner. For example, we have changes to dynamic 120 | references that have been agreed upon and ready to go for over a year, but users 121 | can't benefit from the change until we can get the next full release published. 122 | With this model, the change could have been made available for over a year now 123 | and we would have a years worth of feedback on it's use. Having a mutable spec 124 | also allows us to introduce new features without having to wait for a release. 125 | For example, the `propertyDependencies` keyword has also been waiting for months 126 | for a release. Users could have been benefiting from it for months and providing 127 | feedback. 128 | 129 | The downside of a mutable spec is that it can be more difficult for implementers 130 | and users to track when changes happen. We will need to be better at 131 | communicating changes in blog posts or equivalent. 132 | 133 | The stability model allows us to ensure we don't make incompatible changes to 134 | stable features, but it also allows us to introduce new features and get real 135 | world feedback without committing to full compatibility requirements. This makes 136 | it much more likely that we don't get stuck with something that doesn't work out 137 | or could be done better. 138 | 139 | The stability model also makes it clear to users which features are stable and 140 | how likely a feature is to change in the future. Whether they prefer to stick 141 | with stable features or want to use a new keyword, users have the information 142 | they need to make that decision. 143 | 144 | The stability model sets a very high barrier for a feature to make it into 145 | stable status. This is on purpose so we can be very sure features won't change 146 | once they are stable, but this process can take a long time. It would typically 147 | take two years for a feature to reach stability which could be a long time to 148 | wait for users who need to stick to the stable feature set but could benefit 149 | greatly from a new feature. 150 | 151 | 152 | ### Option 2 - IETF Inspired 153 | 154 | The benefit of this approach is that it's compatible with the IETF process 155 | without imposing some of the constraints and perception issues that we had with 156 | our previous process. We can pursue an RFC in the future if we choose to without 157 | significant changes or spec restructuring. 158 | 159 | With this proposal, releases are done as a new document that replaces the 160 | previous documents. Compared to the constantly evolving spec in Option 1, 161 | changes from non-functional clarifications and bug fixes to adding and evolving 162 | new features takes much longer if you have to wait for the next release to make 163 | a change. This lengthens the feedback loop slowing spec development progress. 164 | 165 | The main downside of this approach compared to Option 1 is that it will likely 166 | take quite a while to get to a stable release. The spec restructuring is 167 | controversial and it proposes several new keywords that are also controversial. 168 | Discussing, achieving consensus, specifying, and implementing these changes will 169 | take time. Introducing new features and keywords is much more risky with the new 170 | compatibility requirements, so we have to go extra slow to make sure we get it 171 | right. 172 | 173 | ### Option 3 - Minimal Changes 174 | 175 | The benefit of this solution is that we don't have the overhead of defining 176 | and/or learning a new process. In the short term, we can put more effort into 177 | improving JSON Schema if we don't have the distraction of defining a whole new 178 | process. The problem with this approach is that it doesn't solve the problem 179 | with the "draft" label and doesn't provide the stability the community is 180 | looking for. 181 | 182 | ## Links 183 | - 184 | \- The ADR for the decision to decouple from IETF 185 | - - Proposal submitted 186 | by @jdesrosiers for a process to replace the IETF based process we'd been 187 | using. 188 | - - @awwright's vision 189 | for JSON Schema including how it can continue to evolve while still having a 190 | stable core. 191 | - - When we first 192 | started talking about forward compatibility and a stable spec. 193 | - - User friendly 194 | comments on decoupling from the IETF. 195 | -------------------------------------------------------------------------------- /specs/proposals/vocabularies.md: -------------------------------------------------------------------------------- 1 | # JSON Schema Proposal: 2 | 3 | ## Abstract 4 | 5 | The current approach to extending JSON Schema by providing custom keywords is 6 | very implementation-specific and therefore not interoperable. 7 | 8 | To address this deficiency, this document proposes vocabularies as a concept 9 | and a new Core keyword, `$vocabulary`, to support it. 10 | 11 | While the Core specification will define and describe vocabularies in general, 12 | the Validation specification will also need to change to incorporate some of 13 | these ideas. This proposal will be updated as necessary to reflect the changes 14 | in both documents. 15 | 16 | ## Current Status 17 | 18 | This proposal was originally integrated into both specifications, starting with 19 | the 2019-09 release. For the upcoming stable release, the feature has been 20 | extracted as it is incomplete. The feature, at best effort, was extracted in 21 | such a way as to retain the functionality present in the 2020-12 release. 22 | 23 | Trying to fit the 2020-12 version into the current specification, however, 24 | raises some problems, and further discussion around the design of 25 | this concept is needed. 26 | 27 | ## Note to Readers 28 | 29 | The issues list for this proposal can be found at 30 | . 31 | 32 | For additional information, see . 33 | 34 | To provide feedback, use this issue tracker or any of the communication methods 35 | listed on the homepage. 36 | 37 | ## Table of Contents 38 | 39 | ## Conventions and Terminology 40 | 41 | All conventions and terms used and defined by the JSON Schema Core specification 42 | also apply to this document. 43 | 44 | ## Overview 45 | 46 | ### Problem Statement 47 | 48 | To support extensibility, the specification allows implementations to support 49 | keywords that are not defined in the specifications themselves. However, this 50 | vague and open allowance has drawbacks. 51 | 52 | 1. Such support is not a requirement; it is a permission. An implementation 53 | could just as easily (_more_ easily) choose _not_ to support extension 54 | keywords. 55 | 2. There is no prescribed mechanism by which an implementation should provide 56 | this support. As a result, each implementation that _does_ have the feature 57 | supports it in different ways. 58 | 3. Support for any given user-defined keyword will be limited to the 59 | implementations which are explicitly configured for that keyword. For a user 60 | defining their own keyword, this becomes difficult and/or impossible 61 | depending on the varying support for extension keywords offered by the 62 | implementations the user is using. 63 | 64 | This exposes a need for an implementation-agnostic approach to 65 | externally-defined keywords as well as a way for implementations to declare 66 | support for them. 67 | 68 | ### Solution 69 | 70 | This proposal introduces vocabularies as a new concept to be added to the Core 71 | specification. 72 | 73 | A vocabulary is identified by an absolute URI and is used to define a set of 74 | keywords. A vocabulary is generally defined in a human-readable _vocabulary 75 | description document_. (The URI for the vocabulary may be the same as the URL of 76 | where this vocabulary description document can be found, but no recommendation 77 | is made either for or against this practice.) 78 | 79 | A new keyword, `$vocabulary`, will be introduced into the Core specification as 80 | well. This keyword's value is an object with vocabulary URIs as keys and 81 | booleans as values. This keyword only has meaning within a meta-schema. A 82 | meta-schema which includes a vocabulary's URI in its `$vocabulary` keyword is 83 | said to "include" that vocabulary. 84 | 85 | ```jsonc 86 | { 87 | "$schema": "https://example.org/draft/next/schema", 88 | "$id": "https://example.org/schema", 89 | "$vocabulary": { 90 | "https://example.org/vocab/vocab1": true, 91 | "https://example.org/vocab/vocab2": true, 92 | "https://example.org/vocab/vocab3": false 93 | }, 94 | // ... 95 | } 96 | ``` 97 | 98 | Whereas in the current specification, a dialect is merely the set of keywords 99 | used by a schema, with this proposal a dialect is defined by the set of 100 | vocabularies listed by a meta-schema. It is ephemeral and carries no identifier. 101 | 102 | _**NOTE** It is possible for two meta-schemas, which would have different `$id` 103 | values, to share a common dialect if they both declare the same set of 104 | vocabularies._ 105 | 106 | A schema that declares a meta-schema (via `$schema`) which contains 107 | `$vocabulary` is declaring that only those keywords defined by the included 108 | vocabularies are to be processed when evaluating the schema. All other keywords 109 | are to be considered "unknown" and handled accordingly. 110 | 111 | The boolean values in `$vocabulary` signify implementation requirements for each 112 | vocabulary. 113 | 114 | - A `true` value indicates that the implementation must recognize the vocabulary 115 | and be able to process each of the keywords defined in it. If an 116 | implementation does not recognize the vocabulary or cannot process all of its 117 | defined keywords, the implementation must refuse to process the schema. These 118 | vocabularies are also known as "required" vocabularies. 119 | - A `false` value indicates that the implementation is not required to recognize 120 | the vocabulary or its keywords and may continue processing the schema anyway. 121 | However, keywords that are not recognized or supported must be considered 122 | "unknown" and handled accordingly. These vocabularies are also known as 123 | "optional" vocabularies. 124 | 125 | Typically, but not required, a schema will accompany the vocabulary description 126 | document. This _vocabulary schema_ should carry an `$id` value which is distinct 127 | from the vocabulary URI. The purpose of the vocabulary schema is to provide 128 | syntactic validation for the the vocabulary's keywords' values for when the 129 | schema is being validated by a meta-schema that includes the vocabulary. (A 130 | vocabulary schema is not itself a meta-schema since it does not validate entire 131 | schemas.) To facilitate this extra validation, when a vocabulary schema is 132 | provided, any meta-schema which includes the vocabulary should also contain a 133 | reference (via `$ref`) to the vocabulary schema's `$id` value. 134 | 135 | ```jsonc 136 | { 137 | "$schema": "https://example.org/draft/next/schema", 138 | "$id": "https://example.org/schema", 139 | "$vocabulary": { 140 | "https://example.org/vocab/vocab1": true, 141 | "https://example.org/vocab/vocab2": true, 142 | "https://example.org/vocab/vocab3": false 143 | }, 144 | "allOf": { 145 | {"$ref": "meta/vocab1"}, // https://example.org/meta/vocab1 146 | {"$ref": "meta/vocab2"}, // https://example.org/meta/vocab2 147 | {"$ref": "meta/vocab3"} // https://example.org/meta/vocab3 148 | } 149 | // ... 150 | } 151 | ``` 152 | 153 | Finally, the keywords in both the Core and Validation specifications will be 154 | divided into multiple vocabularies. The keyword definitions will be removed from 155 | the meta-schema and added to vocabulary schemas to which the meta-schema will 156 | contain references. In this way, the meta-schema's functionality remains the 157 | same. 158 | 159 | ```json 160 | { 161 | "$schema": "https://json-schema.org/draft/next/schema", 162 | "$id": "https://json-schema.org/draft/next/schema", 163 | "$vocabulary": { 164 | "https://json-schema.org/draft/next/vocab/core": true, 165 | "https://json-schema.org/draft/next/vocab/applicator": true, 166 | "https://json-schema.org/draft/next/vocab/unevaluated": true, 167 | "https://json-schema.org/draft/next/vocab/validation": true, 168 | "https://json-schema.org/draft/next/vocab/meta-data": true, 169 | "https://json-schema.org/draft/next/vocab/format-annotation": true, 170 | "https://json-schema.org/draft/next/vocab/content": true 171 | }, 172 | "$dynamicAnchor": "meta", 173 | 174 | "title": "Core and Validation specifications meta-schema", 175 | "allOf": [ 176 | {"$ref": "meta/core"}, 177 | {"$ref": "meta/applicator"}, 178 | {"$ref": "meta/unevaluated"}, 179 | {"$ref": "meta/validation"}, 180 | {"$ref": "meta/meta-data"}, 181 | {"$ref": "meta/format-annotation"}, 182 | {"$ref": "meta/content"} 183 | ], 184 | } 185 | ``` 186 | 187 | The division of keywords among the vocabularies will be in accordance with the 188 | 2020-12 specification (for now). 189 | 190 | ### Limitations 191 | 192 | #### Unknown Keywords and Unsupported Vocabularies 193 | 194 | This proposal, in its current state, seeks to mimic the behavior defined in the 195 | 2020-12 specification. However, the current specification's disallowance of 196 | unknown keywords presents a problem for schemas that use keywords from optional 197 | vocabularies. (This is the topic of the discussion at 198 | https://github.com/orgs/json-schema-org/discussions/342.) 199 | 200 | #### Machine Readability 201 | 202 | The vocabulary URI is an opaque value. There is no data that an implementation 203 | can reference to identify the keywords defined by the vocabulary. The vocabulary 204 | schema _implies_ this, but scanning a `properties` keyword isn't very reliable. 205 | Moreover, such a system cannot provide metadata about the keywords. 206 | 207 | Having some sort of "vocabulary definition" file could alleviate this. 208 | 209 | One reason for _not_ having such a file is that, at least for functional 210 | keywords, the user generally needs to provide custom code to the implementation 211 | to process the keywords, thus performing that same explicit configuration 212 | anyway. (Such information cannot be gleaned from a vocabulary specification. For 213 | example, an implementation can't know what to do with a hypothetical `minDate` 214 | keyword.) 215 | 216 | Several ideas have been offered for this sort of document: 217 | 218 | - https://github.com/json-schema-org/json-schema-spec/issues/1523 219 | - https://github.com/json-schema-org/json-schema-spec/issues/1423 220 | - https://github.com/json-schema-org/json-schema-spec/pull/1257 221 | 222 | #### Implicit Inclusion of Core Vocabulary 223 | 224 | Because the Core keywords (the ones that start with `$`) instruct an 225 | implementation on how a schema should be processed, its inclusion is mandatory 226 | and assumed. As such, while excluding the Core Vocabulary from the `$vocabulary` 227 | keyword has no effect, it is generally advised as common practice to include the 228 | Core Vocabulary explicitly. 229 | 230 | This can be confusing and difficult to use/implement, and we probably need 231 | something better here. 232 | 233 | ## Change Details 234 | 235 | 255 | 256 | ***NOTE** Since the design of vocabularies will be changing anyway, it's not 257 | worth the time and effort to fill in this section just yet. As such, please 258 | read the above sections for loose requirements. For tighter requirements, 259 | please assume conformance with the 2020-12 Core and Validation specifications.* 260 | 261 | ## %appendix% Change Log 262 | 263 | - 2024-06-10 - Created 264 | 265 | ## %appendix% Champions 266 | 267 | | Champion | Company | Email | URI | 268 | | ----------- | ------- | ------------------------------ | ------------------------------- | 269 | | Greg Dennis | | | | 270 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022 JSON Schema Specification Authors 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of the copyright holder nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | --- 31 | 32 | This Academic Free License (the "License") applies to any original work 33 | of authorship (the "Original Work") whose owner (the "Licensor") has 34 | placed the following licensing notice adjacent to the copyright notice 35 | for the Original Work: 36 | 37 | Licensed under the Academic Free License version 3.0 38 | 39 | 1) Grant of Copyright License. Licensor grants You a worldwide, 40 | royalty-free, non-exclusive, sublicensable license, for the duration of 41 | the copyright, to do the following: 42 | 43 | a) to reproduce the Original Work in copies, either alone or as part of 44 | a collective work; 45 | 46 | b) to translate, adapt, alter, transform, modify, or arrange the 47 | Original Work, thereby creating derivative works ("Derivative Works") 48 | based upon the Original Work; 49 | 50 | c) to distribute or communicate copies of the Original Work and 51 | Derivative Works to the public, under any license of your choice that 52 | does not contradict the terms and conditions, including Licensor's 53 | reserved rights and remedies, in this Academic Free License; 54 | 55 | d) to perform the Original Work publicly; and 56 | 57 | e) to display the Original Work publicly. 58 | 59 | 2) Grant of Patent License. Licensor grants You a worldwide, 60 | royalty-free, non-exclusive, sublicensable license, under patent claims 61 | owned or controlled by the Licensor that are embodied in the Original 62 | Work as furnished by the Licensor, for the duration of the patents, to 63 | make, use, sell, offer for sale, have made, and import the Original Work 64 | and Derivative Works. 65 | 66 | 3) Grant of Source Code License. The term "Source Code" means the 67 | preferred form of the Original Work for making modifications to it 68 | and all available documentation describing how to modify the Original 69 | Work. Licensor agrees to provide a machine-readable copy of the Source 70 | Code of the Original Work along with each copy of the Original Work 71 | that Licensor distributes. Licensor reserves the right to satisfy this 72 | obligation by placing a machine-readable copy of the Source Code in an 73 | information repository reasonably calculated to permit inexpensive and 74 | convenient access by You for as long as Licensor continues to distribute 75 | the Original Work. 76 | 77 | 4) Exclusions From License Grant. Neither the names of Licensor, nor 78 | the names of any contributors to the Original Work, nor any of their 79 | trademarks or service marks, may be used to endorse or promote products 80 | derived from this Original Work without express prior permission of the 81 | Licensor. Except as expressly stated herein, nothing in this License 82 | grants any license to Licensor's trademarks, copyrights, patents, trade 83 | secrets or any other intellectual property. No patent license is granted 84 | to make, use, sell, offer for sale, have made, or import embodiments 85 | of any patent claims other than the licensed claims defined in Section 86 | 2. No license is granted to the trademarks of Licensor even if such 87 | marks are included in the Original Work. Nothing in this License shall 88 | be interpreted to prohibit Licensor from licensing under terms different 89 | from this License any Original Work that Licensor otherwise would have a 90 | right to license. 91 | 92 | 5) External Deployment. The term "External Deployment" means the use, 93 | distribution, or communication of the Original Work or Derivative 94 | Works in any way such that the Original Work or Derivative Works may 95 | be used by anyone other than You, whether those works are distributed 96 | or communicated to those persons or made available as an application 97 | intended for use over a network. As an express condition for the grants 98 | of license hereunder, You must treat any External Deployment by You of 99 | the Original Work or a Derivative Work as a distribution under section 100 | 1(c). 101 | 102 | 6) Attribution Rights. You must retain, in the Source Code of any 103 | Derivative Works that You create, all copyright, patent, or trademark 104 | notices from the Source Code of the Original Work, as well as any 105 | notices of licensing and any descriptive text identified therein as an 106 | "Attribution Notice." You must cause the Source Code for any Derivative 107 | Works that You create to carry a prominent Attribution Notice reasonably 108 | calculated to inform recipients that You have modified the Original 109 | Work. 110 | 111 | 7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants 112 | that the copyright in and to the Original Work and the patent rights 113 | granted herein by Licensor are owned by the Licensor or are sublicensed 114 | to You under the terms of this License with the permission of the 115 | contributor(s) of those copyrights and patent rights. Except as 116 | expressly stated in the immediately preceding sentence, the Original 117 | Work is provided under this License on an "AS IS" BASIS and WITHOUT 118 | WARRANTY, either express or implied, including, without limitation, 119 | the warranties of non-infringement, merchantability or fitness for a 120 | particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL 121 | WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential 122 | part of this License. No license to the Original Work is granted by this 123 | License except under this disclaimer. 124 | 125 | 8) Limitation of Liability. Under no circumstances and under no legal 126 | theory, whether in tort (including negligence), contract, or otherwise, 127 | shall the Licensor be liable to anyone for any indirect, special, 128 | incidental, or consequential damages of any character arising as a 129 | result of this License or the use of the Original Work including, 130 | without limitation, damages for loss of goodwill, work stoppage, 131 | computer failure or malfunction, or any and all other commercial damages 132 | or losses. This limitation of liability shall not apply to the extent 133 | applicable law prohibits such limitation. 134 | 135 | 9) Acceptance and Termination. If, at any time, You expressly 136 | assented to this License, that assent indicates your clear and 137 | irrevocable acceptance of this License and all of its terms and 138 | conditions. If You distribute or communicate copies of the Original 139 | Work or a Derivative Work, You must make a reasonable effort under the 140 | circumstances to obtain the express assent of recipients to the terms 141 | of this License. This License conditions your rights to undertake 142 | the activities listed in Section 1, including your right to create 143 | Derivative Works based upon the Original Work, and doing so without 144 | honoring these terms and conditions is prohibited by copyright law and 145 | international treaty. Nothing in this License is intended to affect 146 | copyright exceptions and limitations (including "fair use" or "fair 147 | dealing"). This License shall terminate immediately and You may no 148 | longer exercise any of the rights granted to You by this License upon 149 | your failure to honor the conditions in Section 1(c). 150 | 151 | 10) Termination for Patent Action. This License shall terminate 152 | automatically and You may no longer exercise any of the rights granted 153 | to You by this License as of the date You commence an action, including 154 | a cross-claim or counterclaim, against Licensor or any licensee 155 | alleging that the Original Work infringes a patent. This termination 156 | provision shall not apply for an action alleging patent infringement by 157 | combinations of the Original Work with other software or hardware. 158 | 159 | 11) Jurisdiction, Venue and Governing Law. Any action or suit relating 160 | to this License may be brought only in the courts of a jurisdiction 161 | wherein the Licensor resides or in which Licensor conducts its primary 162 | business, and under the laws of that jurisdiction excluding its 163 | conflict-of-law provisions. The application of the United Nations 164 | Convention on Contracts for the International Sale of Goods is 165 | expressly excluded. Any use of the Original Work outside the scope 166 | of this License or after its termination shall be subject to the 167 | requirements and penalties of copyright or patent law in the appropriate 168 | jurisdiction. This section shall survive the termination of this 169 | License. 170 | 171 | 12) Attorneys' Fees. In any action to enforce the terms of this License 172 | or seeking damages relating thereto, the prevailing party shall 173 | be entitled to recover its costs and expenses, including, without 174 | limitation, reasonable attorneys' fees and costs incurred in connection 175 | with such action, including any appeal of such action. This section 176 | shall survive the termination of this License. 177 | 178 | 13) Miscellaneous. If any provision of this License is held to be 179 | unenforceable, such provision shall be reformed only to the extent 180 | necessary to make it enforceable. 181 | 182 | 14) Definition of "You" in This License. "You" throughout this License, 183 | whether in upper or lower case, means an individual or a legal entity 184 | exercising rights under, and complying with all of the terms of, this 185 | License. For legal entities, "You" includes any entity that controls, 186 | is controlled by, or is under common control with you. For purposes of 187 | this definition, "control" means (i) the power, direct or indirect, to 188 | cause the direction or management of such entity, whether by contract 189 | or otherwise, or (ii) ownership of fifty percent (50%) or more of the 190 | outstanding shares, or (iii) beneficial ownership of such entity. 191 | 192 | 15) Right to Use. You may use the Original Work in all ways not 193 | otherwise restricted or conditioned by this License or by law, and 194 | Licensor promises not to interfere with or be responsible for such uses 195 | by You. 196 | 197 | 16) Modification of This License. This License is Copyright © 198 | 2005 Lawrence Rosen. Permission is granted to copy, distribute, or 199 | communicate this License without modification. Nothing in this License 200 | permits You to modify this License as applied to the Original Work or 201 | to Derivative Works. However, You may modify the text of this License 202 | and copy, distribute or communicate your modified version (the "Modified 203 | License") and apply it to other original works of authorship subject 204 | to the following conditions: (i) You may not indicate in any way that 205 | your Modified License is the "Academic Free License" or "AFL" and you 206 | may not use those names in the name of your Modified License; (ii) You 207 | must replace the notice specified in the first paragraph above with 208 | the notice "Licensed under " or with a 209 | notice of your own that is not confusingly similar to the notice in 210 | this License; and (iii) You may not claim that your original works are 211 | open source software unless your Modified License has been approved by 212 | Open Source Initiative (OSI) and You comply with its license review and 213 | certification process. 214 | -------------------------------------------------------------------------------- /ietf/json-schema-media-types.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | stand_alone: true 4 | ipr: trust200902 5 | submissiontype: independent 6 | category: info 7 | 8 | title: JSON Schema Media Types 9 | author: 10 | - name: Jason Desrosiers 11 | email: jdesrosi@gmail.com 12 | role: editor 13 | 14 | normative: 15 | # TODO: Update to the stable release 16 | JSON-Schema: 17 | title: JSON Schema Core 18 | target: "https://json-schema.org/specification.html" 19 | HTTP: RFC9110 20 | JSON: RFC8259 21 | JSON-Pointer: RFC6901 22 | IRI: RFC3987 23 | 24 | informative: 25 | draft-2020-12: 26 | title: JSON Schema - draft-2020-12 27 | date: 2022-06-16 28 | target: "https://json-schema.org/draft/2020-12" 29 | author: 30 | - ins: A. Wright 31 | - ins: H. Andrews 32 | - ins: B. Hutton 33 | - ins: G. Dennis 34 | draft-2019-09: 35 | title: JSON Schema - draft-2019-09 36 | date: 2019-09-17 37 | target: "https://json-schema.org/draft/2019-09" 38 | author: 39 | - ins: A. Wright 40 | - ins: H. Andrews 41 | - ins: B. Hutton 42 | - ins: G. Dennis 43 | draft-07: 44 | title: JSON Schema - draft-07 45 | date: 2018-03-19 46 | target: "https://json-schema.org/draft-07" 47 | author: 48 | - ins: A. Wright 49 | - ins: H. Andrews 50 | draft-03: 51 | title: JSON Schema - draft-03 52 | date: 2018-03-19 53 | target: "https://json-schema.org/draft-03/draft-zyp-json-schema-03.pdf" 54 | author: 55 | - ins: K. Zyp 56 | - ins: G. Court 57 | profile: RFC6906 58 | 59 | --- abstract 60 | 61 | This document registers the following media types associated with 62 | {{JSON-Schema}} to the IANA Media Types registry: `application/schema+json` and 63 | `application/schema-instance+json`. 64 | 65 | --- middle 66 | 67 | # Introduction 68 | 69 | {{JSON-Schema}} is a declarative domain-specific language for validating and 70 | annotating {{JSON}} documents. This document registers media types that can be 71 | used with schemas (`application/schema+json`) and instances 72 | (`application/schema-instance+json`) that are represented as JSON. 73 | 74 | Although there is now a stable version of {{JSON-Schema}}, there are still many 75 | dialects of JSON Schema in wide use today including {{draft-07}} and 76 | {{draft-2020-12}}. There are also several third-party JSON Schema dialects as 77 | well including the ones defined for use in 78 | [OpenAPI](https://spec.openapis.org/oas/latest.html#schema-object) and 79 | [MongoDB](https://www.mongodb.com/docs/manual/core/schema-validation). 80 | 81 | The media types defined in this document can be used with any dialect of JSON 82 | Schema including obsolete draft dialects and third-party dialects. The draft 83 | dialects include media type definitions in their specification. This document 84 | obsoletes those definitions while remaining compatible as much as is possible 85 | and reasonable. 86 | 87 | ## Notational Conventions 88 | 89 | {::boilerplate bcp14+} 90 | 91 | The terms "content", "content negotiation", "resource", and "user agent" in this 92 | document are to be interpreted as in {{HTTP}}. 93 | 94 | # Media Type application/schema+json {#schema-json} 95 | 96 | The `application/schema+json` media type is an extension of the JSON {{JSON}} 97 | media type and is used for JSON Schemas represented as JSON. It defines two 98 | types of fragment identifiers as well as a media type parameter that can be used 99 | for content negotiation or as a fallback mechanism for identifying the dialect 100 | of the schema. 101 | 102 | The following information serves as the registration form for the 103 | `application/schema+json` media type. 104 | 105 | Type name: 106 | : application 107 | 108 | Subtype name: 109 | : schema+json 110 | 111 | Required parameters: 112 | : N/A 113 | 114 | Optional parameters: 115 | 116 | - schema: An {{IRI}} identifying the JSON Schema dialect the schema was written 117 | for. If this value conflicts with the value of the `$schema` keyword in the 118 | schema, the `$schema` keyword takes precedence. 119 | - profile: **(deprecated)** An alias of the `schema` parameter included for 120 | compatibility with older versions of JSON Schema. 121 | 122 | Encoding considerations: 123 | : Same as "application/json" 124 | 125 | Security considerations: 126 | : See the "Security Considerations" section of {{JSON-Schema}} 127 | 128 | Interoperability considerations: 129 | : See the "General Considerations" section of {{JSON-Schema}} 130 | 131 | Published specification: 132 | : this document 133 | 134 | Applications that use this media type: 135 | : JSON Schema is used in a variety of applications including API servers and 136 | clients that validate JSON requests and responses, IDEs that valid 137 | configuration files, and databases that store JSON. 138 | 139 | Fragment identifier considerations: 140 | : This media type uses the JSON Pointer and plain-name fragment identifier 141 | structures defined in the "Fragment Identifiers" section of {{JSON-Schema}}. 142 | 143 | Additional information: 144 | 145 | - Deprecated alias names for this type: N/A 146 | - Magic number(s): N/A 147 | - File extension(s): json, schema.json 148 | - Macintosh file type code(s): N/A 149 | 150 | Person and email address to contact for further information: 151 | : See Authors' Addresses section. 152 | 153 | Intended usage: 154 | : COMMON 155 | 156 | Restrictions on usage: 157 | : N/A. 158 | 159 | Author: 160 | : See Authors' Addresses section. 161 | 162 | Change controller: 163 | : N/A 164 | 165 | ## Identifying the dialect 166 | 167 | If the resource includes the `$schema` keyword, the value of that keyword 168 | determines the dialect of the schema. As a fallback, the `schema` media type 169 | parameter can be used to determine the dialect of the schema. 170 | 171 | ## Content negotiation based on dialect 172 | 173 | The `schema` media type parameter can also be used for content negotiation (see 174 | {{Section 12 of HTTP}}). In the following example, the user agent is able to 175 | accept two possible dialects of JSON Schema and the server replies with the 176 | latest one it supports. 177 | 178 | Request: 179 | 180 | ~~~ http-message 181 | NOTE: '\' line wrapping per RFC 8792 182 | 183 | GET /schemas/v2/pet HTTP/1.1 184 | Host: foo.example 185 | Accept: application/schema+json; \ 186 | schema="https://json-schema.org/v1/2025", \ 187 | application/schema+json; \ 188 | schema="http://json-schema.org/draft-07/schema#" 189 | ~~~ 190 | 191 | Response: 192 | 193 | ~~~ http-message 194 | NOTE: '\' line wrapping per RFC 8792 195 | 196 | HTTP/1.1 200 OK 197 | Content-Type: \ 198 | application/schema+json; schema="https://json-schema.org/v1/2025" 199 | 200 | { 201 | "$id": "https://json-schema.org/v1/2025", 202 | "$schema": "https://json-schema.org/v1/2025", 203 | ... 204 | } 205 | ~~~ 206 | 207 | 208 | # Media Type application/schema-instance+json {#schema-instance-json} 209 | 210 | The `application/schema-instance+json` media type is an extension of the 211 | {{JSON}} media type and is used for instances represented as JSON. It defines a 212 | fragment identifier and a media type parameter that can be used for content 213 | negotiation or as a way to declare a schema the instance conforms to. 214 | 215 | The following information serves as the registration form for the 216 | `application/schema-instance+json` media type. 217 | 218 | Type name: 219 | : application 220 | 221 | Subtype name: 222 | : schema-instance+json 223 | 224 | Required parameters: 225 | : N/A 226 | 227 | Optional parameters: 228 | 229 | - schema: 230 | : An IRI-reference {{IRI}} identifying a JSON Schema that the resource 231 | conforms to. If the IRIs is relative, the base URI is the retrieval URI of the 232 | retrieved resource. **(deprecated)** A whitespace-separated list of IRIs is 233 | also allowed, but discouraged due to conflicting semantics in different 234 | dialects of JSON Schema (see {{multiple-schemas}}). If multiple IRIs are 235 | given, the resource conforms to all of the schemas listed. 236 | 237 | Encoding considerations: 238 | : Same as {{JSON}} 239 | 240 | Security considerations: 241 | : Same as {{JSON}} 242 | 243 | Interoperability considerations: 244 | : Same as {{JSON}} 245 | 246 | Published specification: 247 | : this document 248 | 249 | Applications that use this media type: 250 | : JSON Schema is used in a variety of applications including API servers and 251 | clients that validate JSON requests and responses, IDEs that valid 252 | configuration files, databases that store JSON, and more. 253 | 254 | Fragment identifier considerations: 255 | : Fragment identifiers MUST be interpreted as JSON Pointers. The use of JSON 256 | Pointers as URI fragment identifiers is described in {{JSON-Pointer}}. 257 | 258 | Additional information: 259 | 260 | - Deprecated alias names for this type: N/A 261 | - Magic number(s): N/A 262 | - File extension(s): json 263 | - Macintosh file type code(s): N/A 264 | 265 | Person and email address to contact for further information: 266 | : See Authors' Addresses section. 267 | 268 | Intended usage: 269 | : COMMON 270 | 271 | Restrictions on usage: 272 | : N/A 273 | 274 | Author: 275 | : See Authors' Addresses section. 276 | 277 | Change controller: 278 | : N/A 279 | 280 | ## Identifying a schema 281 | 282 | It is a common convention for schemas to use `$schema` in an instance to declare 283 | the schema the instance conforms to. However, this is not an official behavior 284 | defined for JSON Schema and has limitations such the inability to declare the 285 | schema of an instance that isn't an object. 286 | 287 | The `schema` media type parameter serves the same purpose of declaring the 288 | instance's schema without the limitations. It also allows for content 289 | negotiation (see {{Section 12 of HTTP}}). 290 | 291 | The following is an example of content negotiation where a user agent can accept 292 | two different versions of a "pet" resource. Each resource version is identified 293 | by a unique JSON Schema. 294 | 295 | Request: 296 | 297 | ~~~ http-message 298 | NOTE: '\' line wrapping per RFC 8792 299 | 300 | GET /pet/1234 HTTP/1.1 301 | Host: foo.example 302 | Accept: \ 303 | application/schema-instance+json; schema="/schemas/v2/pet"; q=0.2, \ 304 | application/schema-instance+json; schema="/schemas/v1/pet"; q=0.1 305 | ~~~ 306 | 307 | Response: 308 | 309 | ~~~ http-message 310 | NOTE: '\' line wrapping per RFC 8792 311 | 312 | HTTP/1.1 200 Ok 313 | Content-Type: \ 314 | application/schema-instance+json; schema="/schemas/v2/pet" 315 | 316 | { 317 | "petId": "1234", 318 | "name": "Pluto", 319 | ... 320 | } 321 | ~~~ 322 | 323 | # Interoperability Considerations 324 | 325 | In its various iterations, JSON Schema has made several changes to how it 326 | defines its media types and how it recommends the use of media types. This has 327 | led to some differences in how these media types have been used in the wild. 328 | 329 | The media types defined in this document are designed to be compatible with as 330 | many of those iterations as possible with special consideration for what has 331 | been seen in use in the wild. However, there are some things that couldn't be 332 | included. Implementations MAY consider supporting a "compatibility mode" to 333 | support behaviors that aren't officially supported yet might be encountered in 334 | the wild. 335 | 336 | ## The `profile` parameter {#profile-parameter} 337 | 338 | Earlier drafts of JSON Schema suggest the use of the `profile` media type 339 | parameter as defined by {{profile}} to associate an instance with a schema or a 340 | schema with a meta-schema. There was some debate about whether a schema can be 341 | considered a profile, so the parameter was renamed to `schema`. 342 | 343 | The `profile` parameter is included for the `application/schema+json` media type 344 | for compatibility with older systems. It's not included for the 345 | `application/schema-instance+json` media type because there was never a time 346 | where the `profile` parameter was defined for that media type. 347 | 348 | ## A Media Type for Instances 349 | 350 | Earlier drafts of JSON Schema suggest the use of `application/json` with the 351 | {{profile-parameter}} to associate an instance with a schema. However, it isn't 352 | allowed to use media type parameters that aren't defined to be used by the media 353 | type. The `application/schema-instance+json` media type was introduced to 354 | address that problem. In {{draft-07}}, the specification started suggesting the 355 | new media type be used instead of `application/json` for instances so a media 356 | type parameter can be used correctly. 357 | 358 | Implementations MAY consider supporting the `profile` parameter with 359 | `application/json` if compatibility with older systems is necessary. Supporting 360 | the `schema` parameter with `application/json` should not be necessary because 361 | that parameter was not introduced before the `application/schema-instance+json` 362 | media type was introduced. 363 | 364 | ## Multiple `schema` IRIs {#multiple-schemas} 365 | 366 | The semantics of the `schema` parameter when it contains multiple IRIs has 367 | conflicting definitions in different releases of JSON Schema. {{draft-07}} 368 | defines that the instance conforms to at least one of the schemas. 369 | {{draft-2019-09}} contradicts itself saying in different places that the 370 | instance conforms to all of the schemas and that it conforms to at least one of 371 | the schemas. The `schema` parameter was removed entirely for {{draft-2020-12}} 372 | with the intention of sorting out the contradiction later. 373 | 374 | The `application/schema-instance+json` media type uses the "all of" semantics as 375 | that was the most recent intention. It's also more logical, more useful, and in 376 | alignment with how `profile` is defined. However, due to the contradicting 377 | definitions and unclear use case, using multiple IRIs is considered deprecated 378 | going forward. 379 | 380 | Implementations MAY consider supporting the "any of" definition through 381 | configuration of some kind to switch between the "all of" and "any of" 382 | definitions if they think their users might depend on the "any of" definition. 383 | 384 | The `application/schema+json` media type doesn't allow for multiple IRIs because 385 | a schema can only have one dialect. Technically the {{draft-2019-09}} 386 | specification allows the `schema` parameter to have multiple values, but since 387 | that doesn't make sense, it was considered safe to leave that option out. 388 | 389 | Implementations MAY consider supporting the "any of" definition for multiple 390 | values in `schema` if they think their users might depend on it. 391 | 392 | ## The `schema` Link Relation 393 | 394 | {{draft-07}} and {{draft-2019-09}} specify that the `schema` media type 395 | parameter can also be used as a link relation. However, there's no mention of 396 | registering the relation or any evidence that anyone has used it in this way. 397 | Therefore, it was decided not to register `schema` as a link relation. 398 | 399 | Implementations MAY consider supporting the `schema` link relation if they think 400 | their users might depend on it. 401 | 402 | ## Fragment Identifiers 403 | 404 | Through {{draft-03}}, JSON Schema defined a dot-notation alternative to JSON 405 | Pointer fragment identifiers. Implementations MAY consider supporting the 406 | dot-notation syntax if they think their users might depend on it. 407 | 408 | # Security Considerations 409 | 410 | See the "Security Considerations" for each registered media type. 411 | 412 | # IANA Considerations 413 | 414 | IANA is asked to update the ["Media Types" 415 | registry](https://www.iana.org/assignments/media-types) with the registration 416 | information in {{schema-json}} for the media types `application/schema+json` 417 | and `application/schema-instance+json`. 418 | 419 | --- back 420 | 421 | -------------------------------------------------------------------------------- /specs/registries/format.json: -------------------------------------------------------------------------------- 1 | { 2 | "base64url": { 3 | "description": "Binary data encoded as a url-safe string as defined in RFC4648", 4 | "types": ["string"], 5 | "examples": ["U3dhZ2dlciByb2Nrcw"], 6 | "deprecated": true, 7 | "supportedBy": [] 8 | }, 9 | "binary": { 10 | "description": "Any sequence of octets", 11 | "definingBody": "OpenAPI", 12 | "definition": "https://spec.openapis.org/oas/v3.0.3.html#data-types", 13 | "types": ["string"], 14 | "examples": ["binary data"], 15 | "deprecated": true, 16 | "supportedBy": [] 17 | }, 18 | "byte": { 19 | "description": "Base64 encoded data as defined in RFC4648", 20 | "definingBody": "OpenAPI", 21 | "definition": "https://spec.openapis.org/oas/v3.0.3.html#data-types", 22 | "types": ["string"], 23 | "examples": ["U3dhZ2dlciByb2Nrcw=="], 24 | "deprecated": true, 25 | "supportedBy": [] 26 | }, 27 | "char": { 28 | "description": "A single character", 29 | "types": ["string"], 30 | "examples": ["a"], 31 | "deprecated": false, 32 | "supportedBy": [] 33 | }, 34 | "commonmark": { 35 | "description": "Commonmark-formatted text", 36 | "definingBody": "OpenAPI", 37 | "definition": "https://spec.openapis.org/oas/latest.html#data-types", 38 | "types": ["string"], 39 | "examples": ["# Heading\n\nSome **bold** text."], 40 | "deprecated": false, 41 | "supportedBy": [] 42 | }, 43 | "date": { 44 | "description": "Date as defined by full-date - RFC3339", 45 | "definingBody": "JSON Schema", 46 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-dates-times-and-duration", 47 | "types": ["string"], 48 | "examples": ["2017-07-21"], 49 | "deprecated": false, 50 | "supportedBy": [] 51 | }, 52 | "date-time": { 53 | "description": "Date and time as defined by date-time - RFC3339", 54 | "definingBody": "JSON Schema", 55 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-dates-times-and-duration", 56 | "types": ["string"], 57 | "examples": ["2017-07-21T17:32:28Z"], 58 | "deprecated": false, 59 | "supportedBy": [] 60 | }, 61 | "decimal": { 62 | "description": "A fixed point decimal number of unspecified precision and range", 63 | "types": ["string", "number"], 64 | "examples": ["123.45"], 65 | "deprecated": false, 66 | "supportedBy": [] 67 | }, 68 | "decimal128": { 69 | "description": "A decimal floating-point number with 34 significant decimal digits", 70 | "types": ["string", "number"], 71 | "examples": ["123.4567890123456789012345678901234"], 72 | "deprecated": false, 73 | "supportedBy": [] 74 | }, 75 | "double": { 76 | "description": "Double precision floating point number", 77 | "definingBody": "OpenAPI", 78 | "definition": "https://spec.openapis.org/oas/latest.html#data-types", 79 | "types": ["number"], 80 | "examples": [-1.7976931348623157e+308, -1, -4.9406564584124654e-324, 0, 4.9406564584124654e-324, 1, 1.7976931348623157e+308], 81 | "deprecated": false, 82 | "supportedBy": [] 83 | }, 84 | "double-int": { 85 | "description": "An integer that can be stored in an IEEE 754 double-precision number without loss of precision", 86 | "types": ["number"], 87 | "examples": [9007199254740991], 88 | "deprecated": false, 89 | "supportedBy": [] 90 | }, 91 | "duration": { 92 | "description": "Duration as defined by duration - RFC3339", 93 | "definingBody": "JSON Schema", 94 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-dates-times-and-duration", 95 | "types": ["string"], 96 | "examples": ["P3Y6M4DT12H30M5S"], 97 | "deprecated": false, 98 | "supportedBy": [] 99 | }, 100 | "email": { 101 | "description": "An email address as defined as Mailbox in RFC5321", 102 | "definingBody": "JSON Schema", 103 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-email-addresses", 104 | "types": ["string"], 105 | "examples": ["user@example.com"], 106 | "deprecated": false, 107 | "supportedBy": [] 108 | }, 109 | "float": { 110 | "description": "Single precision floating point number", 111 | "definingBody": "OpenAPI", 112 | "definition": "https://spec.openapis.org/oas/latest.html#data-types", 113 | "types": ["number"], 114 | "examples": [-3.40282347e+38, -1, -1.17549435e-38, 0, 1.17549435e-38, 1, 3.40282347e+38], 115 | "deprecated": false, 116 | "supportedBy": [] 117 | }, 118 | "hostname": { 119 | "description": "A host name as defined by RFC1123", 120 | "definingBody": "JSON Schema", 121 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-hostnames", 122 | "types": ["string"], 123 | "examples": ["example.com"], 124 | "deprecated": false, 125 | "supportedBy": [] 126 | }, 127 | "html": { 128 | "description": "HTML-formatted text", 129 | "definingBody": "OpenAPI", 130 | "definition": "https://spec.openapis.org/oas/latest.html#data-types", 131 | "types": ["string"], 132 | "examples": ["

This is a paragraph.

"], 133 | "deprecated": false, 134 | "supportedBy": [] 135 | }, 136 | "http-date": { 137 | "description": "Date and time as defined by HTTP-date - RFC7231", 138 | "types": ["string"], 139 | "examples": ["Sun, 06 Nov 1994 08:49:37 GMT"], 140 | "deprecated": false, 141 | "supportedBy": [] 142 | }, 143 | "idn-email": { 144 | "description": "An email address as defined as Mailbox in RFC6531", 145 | "definingBody": "JSON Schema", 146 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-email-addresses", 147 | "types": ["string"], 148 | "examples": ["user@exämple.com"], 149 | "deprecated": false, 150 | "supportedBy": [] 151 | }, 152 | "idn-hostname": { 153 | "description": "An internationalized host name as defined by RFC5890", 154 | "definingBody": "JSON Schema", 155 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-hostnames", 156 | "types": ["string"], 157 | "examples": ["exämple.com"], 158 | "deprecated": false, 159 | "supportedBy": [] 160 | }, 161 | "int16": { 162 | "description": "Signed 16-bit integer", 163 | "types": ["number"], 164 | "examples": [-32768, -1, 0, 1, 32767], 165 | "deprecated": false, 166 | "supportedBy": [] 167 | }, 168 | "int32": { 169 | "description": "Signed 32-bit integer", 170 | "definingBody": "OpenAPI", 171 | "definition": "https://spec.openapis.org/oas/v3.1.1.html#data-type-format", 172 | "types": ["number"], 173 | "examples": [-2147483648, -1, 0, 1, 2147483647], 174 | "deprecated": false, 175 | "supportedBy": [] 176 | }, 177 | "int64": { 178 | "description": "Signed 64-bit integer", 179 | "definingBody": "OpenAPI", 180 | "definition": "https://spec.openapis.org/oas/v3.1.1.html#data-type-format", 181 | "types": ["number"], 182 | "examples": [-9223372036854775808, -1, 0, 1, 9223372036854775807], 183 | "deprecated": false, 184 | "supportedBy": [] 185 | }, 186 | "int8": { 187 | "description": "Signed 8-bit integer", 188 | "definingBody": "OpenAPI", 189 | "definition": "https://spec.openapis.org/oas/latest.html#data-types", 190 | "types": ["number"], 191 | "examples": [-128, -1, 0, 1, 127], 192 | "deprecated": false, 193 | "supportedBy": [] 194 | }, 195 | "ipv4": { 196 | "description": "An IPv4 address as defined as dotted-quad by RFC2673", 197 | "definingBody": "JSON Schema", 198 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-ip-addresses", 199 | "types": ["string"], 200 | "examples": ["192.168.0.1"], 201 | "deprecated": false, 202 | "supportedBy": [] 203 | }, 204 | "ipv6": { 205 | "description": "An IPv6 address as defined by RFC4673", 206 | "definingBody": "JSON Schema", 207 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-ip-addresses", 208 | "types": ["string"], 209 | "examples": ["2001:0db8:85a3:0000:0000:8a2e:0370:7334"], 210 | "deprecated": false, 211 | "supportedBy": [] 212 | }, 213 | "iri": { 214 | "description": "An Internationalized Resource Identifier as defined in RFC3987", 215 | "definingBody": "JSON Schema", 216 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-resource-identifiers", 217 | "types": ["string"], 218 | "examples": ["https://example.com/rosé"], 219 | "deprecated": false, 220 | "supportedBy": [] 221 | }, 222 | "iri-reference": { 223 | "description": "An Internationalized Resource Identifier as defined in RFC3987", 224 | "definingBody": "JSON Schema", 225 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-resource-identifiers", 226 | "types": ["string"], 227 | "examples": ["../resource.json"], 228 | "deprecated": false, 229 | "supportedBy": [] 230 | }, 231 | "json-pointer": { 232 | "description": "A JSON string representation of a JSON Pointer as defined in RFC6901", 233 | "definingBody": "JSON Schema", 234 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-json-pointers", 235 | "types": ["string"], 236 | "examples": ["/foo/bar"], 237 | "deprecated": false, 238 | "supportedBy": [] 239 | }, 240 | "media-range": { 241 | "description": "A media type as defined by the media-range ABNF production in RFC9110.", 242 | "definingBody": "OpenAPI", 243 | "definition": "https://www.rfc-editor.org/rfc/rfc9110#field.accept", 244 | "types": ["string"], 245 | "examples": ["text/html"], 246 | "deprecated": false, 247 | "supportedBy": [] 248 | }, 249 | "regex": { 250 | "description": "A regular expression as defined in ECMA-262", 251 | "definingBody": "JSON Schema", 252 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-regex", 253 | "types": ["string"], 254 | "examples": ["^[a-zA-Z0-9]+$"], 255 | "deprecated": false, 256 | "supportedBy": [] 257 | }, 258 | "relative-json-pointer": { 259 | "description": "A JSON string representation of a relative JSON Pointer as defined in draft RFC 01", 260 | "definingBody": "JSON Schema", 261 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-json-pointers", 262 | "types": ["string"], 263 | "examples": ["1/0"], 264 | "deprecated": false, 265 | "supportedBy": [] 266 | }, 267 | "sf-binary": { 268 | "description": "Structured fields byte sequence as defined in RFC8941", 269 | "definingBody": "RFC 8941", 270 | "definition": "https://www.rfc-editor.org/rfc/rfc8941#name-byte-sequences", 271 | "types": ["string"], 272 | "examples": ["U3dhZ2dlciByb2Nrcw=="], 273 | "deprecated": false, 274 | "supportedBy": [] 275 | }, 276 | "sf-boolean": { 277 | "description": "Structured fields boolean as defined in RFC8941", 278 | "definingBody": "RFC 8941", 279 | "definition": "https://www.rfc-editor.org/rfc/rfc8941#name-booleans", 280 | "types": ["string"], 281 | "examples": ["true", "false"], 282 | "deprecated": false, 283 | "supportedBy": [] 284 | }, 285 | "sf-decimal": { 286 | "description": "Structured fields decimal as defined in RFC8941", 287 | "definingBody": "RFC 8941", 288 | "definition": "https://www.rfc-editor.org/rfc/rfc8941#name-decimals", 289 | "types": ["number"], 290 | "examples": ["123.45"], 291 | "deprecated": false, 292 | "supportedBy": [] 293 | }, 294 | "sf-integer": { 295 | "description": "Structured fields integer as defined in RFC8941", 296 | "definingBody": "RFC 8941", 297 | "definition": "https://www.rfc-editor.org/rfc/rfc8941#name-integers", 298 | "types": ["number"], 299 | "examples": [123], 300 | "deprecated": false, 301 | "supportedBy": [] 302 | }, 303 | "sf-string": { 304 | "description": "Structured fields string as defined in RFC8941", 305 | "definingBody": "RFC 8941", 306 | "definition": "https://www.rfc-editor.org/rfc/rfc8941#name-strings", 307 | "types": ["string"], 308 | "examples": ["example"], 309 | "deprecated": false, 310 | "supportedBy": [] 311 | }, 312 | "sf-token": { 313 | "description": "Structured fields token as defined in RFC8941", 314 | "definingBody": "RFC 8941", 315 | "definition": "https://www.rfc-editor.org/rfc/rfc8941#name-tokens", 316 | "types": ["string"], 317 | "examples": ["token"], 318 | "deprecated": false, 319 | "supportedBy": [] 320 | }, 321 | "time": { 322 | "description": "Time as defined by full-time - RFC3339", 323 | "definingBody": "JSON Schema", 324 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-dates-times-and-duration", 325 | "types": ["string"], 326 | "examples": ["13:45:30Z", "13:45:30+01:00"], 327 | "deprecated": false, 328 | "supportedBy": [] 329 | }, 330 | "uint8": { 331 | "description": "Unsigned 8-bit integer", 332 | "definingBody": "OpenAPI", 333 | "definition": "https://spec.openapis.org/oas/latest.html#data-types", 334 | "types": ["number"], 335 | "examples": [0, 1, 255], 336 | "deprecated": false, 337 | "supportedBy": [] 338 | }, 339 | "uri": { 340 | "description": "A Uniform Resource Identifier as defined in RFC3986", 341 | "definingBody": "JSON Schema", 342 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-resource-identifiers", 343 | "types": ["string"], 344 | "examples": ["https://example.com"], 345 | "deprecated": false, 346 | "supportedBy": [] 347 | }, 348 | "uri-reference": { 349 | "description": "A URI reference as defined in RFC3986", 350 | "definingBody": "JSON Schema", 351 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-resource-identifiers", 352 | "types": ["string"], 353 | "examples": ["../resource.json"], 354 | "deprecated": false, 355 | "supportedBy": [] 356 | }, 357 | "uri-template": { 358 | "description": "A URI Template as defined in RFC6570", 359 | "definingBody": "JSON Schema", 360 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-uri-template", 361 | "types": ["string"], 362 | "examples": ["https://example.com/{id}"], 363 | "deprecated": false, 364 | "supportedBy": [] 365 | }, 366 | "uuid": { 367 | "description": "A Universally Unique IDentifier as defined in RFC4122", 368 | "definingBody": "JSON Schema", 369 | "definition": "https://json-schema.org/draft/2020-12/json-schema-validation.html#name-resource-identifiers", 370 | "types": ["string"], 371 | "examples": ["f81d4fae-7dec-11d0-a765-00a0c91e6bf6"], 372 | "deprecated": false, 373 | "supportedBy": [] 374 | } 375 | } -------------------------------------------------------------------------------- /ietf/relative-json-pointer.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | ]> 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Relative JSON Pointers 18 | 19 | 20 |
21 | 22 | 23 | Cambridge 24 | UK 25 | 26 | luffgd@gmail.com 27 |
28 |
29 | 30 | 31 |
32 | andrews_henry@yahoo.com 33 |
34 |
35 | 36 | 37 |
38 | ben@jsonschema.dev 39 | https://jsonschema.dev 40 |
41 |
42 | 43 | 44 | Internet Engineering Task Force 45 | JSON 46 | JavaScript 47 | Object 48 | Notation 49 | 50 | 51 | 52 | 53 | JSON Pointer is a syntax for specifying locations in a JSON document, 54 | starting from the document root. This document defines an extension 55 | to the JSON Pointer syntax, allowing relative locations from within 56 | the document. 57 | 58 | 59 |
60 | 61 | 62 |
63 | 64 | JSON Pointer (RFC 6901) is a syntax for specifying 65 | locations in a JSON document, starting from the document root. This 66 | document defines a related syntax allowing identification of relative locations 67 | from within the document. 68 | 69 |
70 | 71 |
72 | 73 | 75 | 76 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", 77 | "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be 78 | interpreted as described in RFC 2119. 79 | 80 |
81 | 82 |
83 | 84 | A Relative JSON Pointer is a Unicode string in UTF-8 encoding (see RFC 8259, 85 | Section 8), comprising a non-negative integer, 86 | an optional index adjustment consisting of '+' (%x2B) or '-' (%x2D) followed 87 | by a positive integer, followed by either a '#' (%x23) character or 88 | a JSON Pointer (RFC 6901). 89 | 90 | 91 | The separation between the integer prefix (with optional adjustment) 92 | and the JSON Pointer will 93 | always be unambiguous, because a JSON Pointer must be either zero- 94 | length or start with a '/' (%x2F). Similarly, a JSON Pointer will 95 | never be ambiguous with the '#'. 96 | 97 | 98 | The ABNF syntax of a Relative JSON Pointer is: 99 | 100 | 110 |
111 | 112 |
113 | 114 | Evaluation of a Relative JSON Pointer begins with a reference to a 115 | value within a JSON document, and completes with either a value 116 | within that document, a string corresponding to an object member, or 117 | integer value representing an array index. 118 | 119 | 120 | Evaluation begins by processing the non-negative-integer prefix. 121 | This can be found by taking the longest continuous sequence of decimal 122 | digits available, starting from the beginning of the string, taking 123 | the decimal numerical value. If the value is zero, the following steps 124 | are skipped. If this value is more than zero, then the following steps 125 | are repeated that number of times: 126 | 127 | 128 | If the current referenced value is the root of the document, then 129 | evaluation fails (see below). 130 | 131 | 132 | If the referenced value is an item within an array, then the new 133 | referenced value is that array. 134 | 135 | 136 | If the referenced value is an object member within an object, then 137 | the new referenced value is that object. 138 | 139 | 140 | 141 | 142 | If the next character is a plus ("+") or minus ("-"), followed by another 143 | continuous sequence of decimal digits, the following steps 144 | are taken using the decimal numeric value of that plus or minus sign 145 | and decimal sequence: 146 | 147 | 148 | If the current referenced value is not an item of an array, 149 | then evaluation fails (see below). 150 | 151 | 152 | If the referenced value is an item of an array, then the 153 | new referenced value is the item of the array indexed by 154 | adding the decimal value (which may be negative), to the 155 | index of the current referenced value. 156 | 157 | 158 | 159 | 160 | If the remainder of the Relative JSON Pointer is a JSON Pointer, then 161 | evaluation proceeds as per 162 | RFC 6901, Section 5 163 | with the modification that the initial reference 164 | being used is the reference currently being held (which may not be 165 | root of the document). 166 | 167 | 168 | Otherwise (when the remainder of the Relative JSON Pointer is the 169 | character '#'), the final result is determined as follows: 170 | 171 | 172 | If the current referenced value is the root of the document, then 173 | evaluation fails (see below). 174 | 175 | 176 | If the referenced value is an item within an array, then the final 177 | evaluation result is the value's index position within the array. 178 | 179 | 180 | If the referenced value is an object member within an object, then 181 | the new referenced value is the corresponding member name. 182 | 183 | 184 | 185 |
186 | 187 |
188 | 189 | The concerns surrounding JSON String representation of a Relative 190 | JSON Pointer are identical to those laid out in 191 | RFC 6901, Section 5. 192 | 193 |
194 |
195 | 196 | For example, given the JSON document: 197 | 198 | 199 | 209 | 210 |
211 |
212 | 213 | Starting from the value "baz" (inside "foo"), the following JSON 214 | strings evaluate to the accompanying values: 215 | 216 | 217 | 226 | 227 |
228 |
229 | 230 | Starting from the value {"objects":true} (corresponding to the member 231 | key "nested"), the following JSON strings evaluate to the 232 | accompanying values: 233 | 234 | 235 | 242 | 243 |
244 |
245 |
246 | 247 |
248 | 249 | Unlike a JSON Pointer, a Relative JSON Pointer can not be used in a 250 | URI fragment identifier. Such fragments specify exact positions 251 | within a document, and therefore Relative JSON Pointers are not 252 | suitable. 253 | 254 |
255 | 256 |
257 | 258 | In the event of an error condition, evaluation of the JSON Pointer 259 | fails to complete. 260 | 261 | 262 | Evaluation may fail due to invalid syntax, or referencing a non- 263 | existent value. This specification does not define how errors are 264 | handled. An application of JSON Relative Pointer SHOULD specify the 265 | impact and handling of each type of error. 266 | 267 |
268 | 269 |
270 | 271 | Relative JSON Pointers are intended as a companion to JSON Pointers. 272 | Applications MUST specify the use of each syntax separately. 273 | Defining either JSON Pointer or Relative JSON Pointer as an acceptable 274 | syntax does not imply that the other syntax is also acceptable. 275 | 276 |
277 | 278 |
279 | 280 | The language and structure of this specification are based heavily on 281 | , sometimes quoting it outright. 282 | 283 | 284 | This draft remains primarily as written and published by Geraint Luff, 285 | with only minor subsequent alterations under new editorship. 286 | 287 |
288 | 289 |
290 | 291 | Evaluation of a given Relative JSON Pointer is not guaranteed to 292 | reference an actual JSON value. Applications using Relative JSON 293 | Pointer should anticipate this situation by defining how a pointer 294 | that does not resolve ought to be handled. 295 | 296 | 297 | As part of processing, a composite data structure may be assembled 298 | from multiple JSON documents (in part or in full). In such cases, 299 | applications SHOULD ensure that a Relative JSON Pointer does not 300 | evaluate to a value outside the document for which is was written. 301 | 302 | 303 | Note that JSON pointers can contain the NUL (Unicode U+0000) 304 | character. Care is needed not to misinterpret this character in 305 | programming languages that use NUL to mark the end of a string. 306 | 307 |
308 | 309 |
310 | 311 | This document has no IANA actions. 312 | 313 |
314 |
315 | 316 | 317 | 318 | 319 | &RFC2119; 320 | &RFC6901; 321 | 322 | 323 | 324 | &RFC8259; 325 | 326 | 327 |
328 | 329 | This section to be removed before leaving Internet-Draft status. 330 | 331 | 332 | 333 | 334 | 335 | Fix ABNF omission for using # with index manipulation 336 | Clarify handling of leading "0" 337 | 338 | 339 | 340 | 341 | Add array forward and backward index manipulation 342 | 343 | 344 | 345 | 346 | Update to the latest JSON RFC 347 | 348 | 349 | 350 | 351 | The initial number is "non-negative", not "positive" 352 | 353 | 354 | 355 | 356 | Revived draft with identical wording and structure. 357 | Clarified how to use alongside JSON Pointer. 358 | 359 | 360 | 361 | 362 | Initial draft. 363 | 364 | 365 | 366 | 367 |
368 |
369 |
370 | -------------------------------------------------------------------------------- /specs/spec.css: -------------------------------------------------------------------------------- 1 | svg { 2 | fill: currentColor; 3 | } 4 | 5 | /* Torchlight */ 6 | pre { 7 | border-radius: 0.5rem; 8 | overflow-x: auto; 9 | margin: 0; 10 | } 11 | 12 | pre.torchlight code { 13 | display: block; 14 | min-width: -webkit-max-content; 15 | min-width: -moz-max-content; 16 | min-width: max-content; 17 | border-radius: 0.5rem; 18 | } 19 | 20 | pre.torchlight code .line { 21 | padding-left: 1rem; 22 | padding-right: 1rem; 23 | } 24 | 25 | pre.torchlight code .line-number, 26 | pre.torchlight code .summary-caret { 27 | margin-right: 1rem; 28 | } 29 | 30 | /* Flexible Code Titles */ 31 | .remark-code-container{ 32 | border-radius: 0.5rem; 33 | margin-top: 1rem; 34 | margin-bottom: 1rem; 35 | } 36 | 37 | .remark-code-title { 38 | height: 1.25rem; 39 | border-radius: 0.5rem 0.5rem 0 0; 40 | position: relative; 41 | top: 0.5rem; 42 | background-color: var(--background-alt); 43 | padding: 0.5rem 0.5rem 0.5rem 2.5rem; 44 | background-repeat: no-repeat; 45 | background-size: 1.25rem; 46 | background-position-y: center; 47 | background-position-x: 0.75rem; 48 | } 49 | 50 | .code-title-unknown { 51 | padding-left: 1rem; 52 | } 53 | 54 | .code-title-jsonschema { 55 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' viewBox='0 0 70.423268 70.42326'%3E%3Cg transform='translate(-104.22785,-45.507923)' id='layer1' fill='%23ffffff'%3E%3Cpath id='path4544' d='m 122.99401,114.18985 c -4.32897,-0.9404 -7.58044,-3.47848 -8.71251,-6.80095 -0.78921,-2.31618 -0.67682,-6.07238 0.33363,-11.150598 0.48507,-2.437836 0.88169,-5.347843 0.88139,-6.466688 -9.8e-4,-3.718098 -1.71106,-5.735418 -5.1001,-6.016462 l -1.9549,-0.162116 v -2.392655 -2.392657 l 1.85208,-0.250855 c 2.70243,-0.366031 3.74441,-1.02838 4.57629,-2.908984 0.61121,-1.381726 0.68884,-2.068648 0.50552,-4.472869 -0.11913,-1.562244 -0.53527,-4.348568 -0.92477,-6.191832 -0.98954,-4.682868 -0.94822,-8.485471 0.11707,-10.773163 1.56862,-3.368589 5.43705,-5.854553 9.93248,-6.382903 l 1.93299,-0.227185 v 2.518015 2.518015 h -1.29973 c -1.77186,0 -4.2497,1.262413 -4.8835,2.488054 -0.60797,1.175674 -0.65405,2.864146 -0.15834,5.802223 0.78343,4.643508 1.04707,9.098344 0.67592,11.421636 -0.42464,2.658142 -1.97477,5.796328 -3.6791,7.448236 l -1.18012,1.143813 1.61497,1.982752 c 1.99051,2.443801 2.76458,4.148744 3.24284,7.142561 0.37835,2.368341 0.0844,7.282673 -0.67072,11.213982 -1.05359,5.48514 0.1623,7.65141 4.66209,8.30613 l 1.67569,0.24382 v 2.44782 c 0,2.79211 0.17086,2.69708 -3.43917,1.91286 z' style='fill:stroke-width:0.35277775'/%3E%3Cpath id='path4546' d='m 152.2304,112.24932 v -2.42987 l 2.04969,-0.42336 c 2.26276,-0.46736 4.054,-1.8634 4.45842,-3.47475 0.1274,-0.50758 -0.11267,-3.16398 -0.53347,-5.90311 -1.37183,-8.929552 -0.6114,-13.537042 2.85482,-17.297452 l 1.48237,-1.60818 -1.1108,-1.26512 c -3.97855,-4.53132 -4.66885,-8.552208 -3.15364,-18.369547 0.76342,-4.946305 0.76409,-4.994322 0.087,-6.173611 -0.79713,-1.388278 -3.28385,-2.776033 -4.97438,-2.776033 h -1.15997 v -2.469445 c 0,-2.811057 -0.0583,-2.773846 3.24583,-2.072788 3.9645,0.841179 6.80448,2.853272 8.27787,5.864775 0.84544,1.728026 0.97275,2.400136 0.94911,5.010889 -0.015,1.658349 -0.35758,4.682054 -0.76125,6.719346 -1.49867,7.563594 -1.3651,9.576204 0.7654,11.532814 0.98915,0.90842 1.64012,1.17274 3.37032,1.36849 l 2.14439,0.24261 v 2.42387 2.42388 l -1.6757,7.1e-4 c -2.1517,7e-4 -3.9323,0.90924 -4.83869,2.46889 -0.95194,1.63803 -0.89239,5.20675 0.17364,10.40695 0.90648,4.421902 1.05253,8.458452 0.3882,10.728752 -0.70059,2.39406 -3.81995,5.29609 -6.74745,6.27718 -1.26118,0.42266 -2.96775,0.87096 -3.79236,0.99623 l -1.49931,0.22775 z' style='stroke-width:0.35277778'/%3E%3Cpath id='path4548' d='m 131.74239,108.26592 c -1.02163,-1.2988 -0.87294,-3.53652 0.38087,-5.73185 0.92776,-1.62446 4.80862,-6.948549 7.61066,-10.440949 l 1.13094,-1.40958 -1.80213,-5.22523 c -2.02147,-5.86123 -2.0098,-5.97467 0.65581,-6.37225 l 1.46834,-0.219 1.64076,3.3506 c 0.90242,1.84283 1.76982,3.35061 1.92755,3.35061 0.15774,0 1.77489,-1.75542 3.59368,-3.90092 3.15918,-3.72667 3.35688,-3.89165 4.42591,-3.69334 0.64552,0.11974 1.21858,0.0465 1.35432,-0.17316 0.31818,-0.51481 1.23083,0.24704 1.23083,1.02746 0,0.32009 -0.45438,1.13409 -1.00972,1.80888 -2.26771,2.75549 -7.10417,9.27155 -7.10417,9.5713 0,0.17685 0.97502,2.45302 2.16671,5.05816 l 2.1667,4.736609 -0.65823,0.98459 c -0.36203,0.54152 -0.66236,1.12603 -0.6674,1.29891 -0.005,0.17288 -0.27769,0.48371 -0.60588,0.69073 -0.83174,0.52464 -1.44656,-0.11541 -3.9894,-4.153119 -1.16417,-1.84856 -2.23163,-3.36491 -2.37215,-3.36967 -0.31309,-0.0106 -3.7911,5.131969 -6.47955,9.580639 -2.37093,3.92324 -1.93885,3.4204 -3.26614,3.80106 -0.95533,0.27398 -1.19348,0.19843 -1.79831,-0.57048 z' style='stroke-width:0.35277775'/%3E%3Cpath id='path4550' d='m 131.98567,83.677091 c -2.15148,-3.8472 -6.0183,-9.42829 -7.57842,-10.93815 -0.79252,-0.76698 -1.44094,-1.57494 -1.44094,-1.79546 0,-0.6016 1.61695,-1.21975 3.19058,-1.21975 1.69822,0 3.49597,1.47777 5.0997,4.19203 0.58208,0.98515 1.15641,1.79434 1.27629,1.79819 0.11988,0.004 0.80873,-1.65116 1.53078,-3.67779 1.5464,-4.34039 5.62351,-12.777999 7.22453,-14.951229 1.3726,-1.86316 3.42936,-2.865165 5.90274,-2.875676 3.23375,-0.01374 3.24268,0.130067 0.20474,3.296663 -4.63599,4.832327 -6.76321,8.809632 -11.25155,21.037252 -1.24637,3.39549 -2.39032,6.47895 -2.54212,6.85214 -0.23022,0.56597 -0.49833,0.28096 -1.61633,-1.71822 z' style='stroke-width:0.35277775'/%3E%3C/g%3E%3C/svg%3E"); 56 | } 57 | 58 | .code-title-json { 59 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' viewBox='0 0 70.423268 70.42326'%3E%3Cg transform='translate(-104.22785,-45.507923)' id='layer1' fill='%23ffffff'%3E%3Cpath id='path4544' d='m 122.99401,114.18985 c -4.32897,-0.9404 -7.58044,-3.47848 -8.71251,-6.80095 -0.78921,-2.31618 -0.67682,-6.07238 0.33363,-11.150598 0.48507,-2.437836 0.88169,-5.347843 0.88139,-6.466688 -9.8e-4,-3.718098 -1.71106,-5.735418 -5.1001,-6.016462 l -1.9549,-0.162116 v -2.392655 -2.392657 l 1.85208,-0.250855 c 2.70243,-0.366031 3.74441,-1.02838 4.57629,-2.908984 0.61121,-1.381726 0.68884,-2.068648 0.50552,-4.472869 -0.11913,-1.562244 -0.53527,-4.348568 -0.92477,-6.191832 -0.98954,-4.682868 -0.94822,-8.485471 0.11707,-10.773163 1.56862,-3.368589 5.43705,-5.854553 9.93248,-6.382903 l 1.93299,-0.227185 v 2.518015 2.518015 h -1.29973 c -1.77186,0 -4.2497,1.262413 -4.8835,2.488054 -0.60797,1.175674 -0.65405,2.864146 -0.15834,5.802223 0.78343,4.643508 1.04707,9.098344 0.67592,11.421636 -0.42464,2.658142 -1.97477,5.796328 -3.6791,7.448236 l -1.18012,1.143813 1.61497,1.982752 c 1.99051,2.443801 2.76458,4.148744 3.24284,7.142561 0.37835,2.368341 0.0844,7.282673 -0.67072,11.213982 -1.05359,5.48514 0.1623,7.65141 4.66209,8.30613 l 1.67569,0.24382 v 2.44782 c 0,2.79211 0.17086,2.69708 -3.43917,1.91286 z' style='fill:stroke-width:0.35277775'/%3E%3Cpath id='path4546' d='m 152.2304,112.24932 v -2.42987 l 2.04969,-0.42336 c 2.26276,-0.46736 4.054,-1.8634 4.45842,-3.47475 0.1274,-0.50758 -0.11267,-3.16398 -0.53347,-5.90311 -1.37183,-8.929552 -0.6114,-13.537042 2.85482,-17.297452 l 1.48237,-1.60818 -1.1108,-1.26512 c -3.97855,-4.53132 -4.66885,-8.552208 -3.15364,-18.369547 0.76342,-4.946305 0.76409,-4.994322 0.087,-6.173611 -0.79713,-1.388278 -3.28385,-2.776033 -4.97438,-2.776033 h -1.15997 v -2.469445 c 0,-2.811057 -0.0583,-2.773846 3.24583,-2.072788 3.9645,0.841179 6.80448,2.853272 8.27787,5.864775 0.84544,1.728026 0.97275,2.400136 0.94911,5.010889 -0.015,1.658349 -0.35758,4.682054 -0.76125,6.719346 -1.49867,7.563594 -1.3651,9.576204 0.7654,11.532814 0.98915,0.90842 1.64012,1.17274 3.37032,1.36849 l 2.14439,0.24261 v 2.42387 2.42388 l -1.6757,7.1e-4 c -2.1517,7e-4 -3.9323,0.90924 -4.83869,2.46889 -0.95194,1.63803 -0.89239,5.20675 0.17364,10.40695 0.90648,4.421902 1.05253,8.458452 0.3882,10.728752 -0.70059,2.39406 -3.81995,5.29609 -6.74745,6.27718 -1.26118,0.42266 -2.96775,0.87096 -3.79236,0.99623 l -1.49931,0.22775 z' style='stroke-width:0.35277778'/%3E%3C/g%3E%3C/svg%3E"); 60 | } 61 | 62 | /* Flexible Containers */ 63 | .remark-container { 64 | border: thin solid black; 65 | border-radius: 1rem; 66 | margin-bottom: 1rem; 67 | } 68 | 69 | .remark-container-title { 70 | border-radius: 1rem 1rem 0 0; 71 | position: relative; 72 | padding: .5rem 0 .5rem 2.5rem; 73 | background-color: var(--background); 74 | background-repeat: no-repeat; 75 | background-size: 1.75rem; 76 | background-position-y: center; 77 | background-position-x: .25rem; 78 | } 79 | 80 | .remark-container > :not(.remark-container-title) { 81 | padding: 0 1rem 0 1rem; 82 | } 83 | 84 | .remark-container-title.warning { 85 | background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cg id='SVGRepo_bgCarrier' stroke-width='0'%3E%3C/g%3E%3Cg id='SVGRepo_tracerCarrier' stroke-linecap='round' stroke-linejoin='round'%3E%3C/g%3E%3Cg id='SVGRepo_iconCarrier'%3E%3Ccircle cx='12' cy='17' r='1' fill='%23ffffff'%3E%3C/circle%3E%3Cpath d='M12 10L12 14' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3C/path%3E%3Cpath d='M3.44722 18.1056L10.2111 4.57771C10.9482 3.10361 13.0518 3.10362 13.7889 4.57771L20.5528 18.1056C21.2177 19.4354 20.2507 21 18.7639 21H5.23607C3.7493 21 2.78231 19.4354 3.44722 18.1056Z' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3C/path%3E%3C/g%3E%3C/svg%3E"); 86 | } 87 | 88 | .remark-container-title.note { 89 | background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 32 32' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:sketch='http://www.bohemiancoding.com/sketch/ns' fill='%23ffffff'%3E%3Cg id='SVGRepo_bgCarrier' stroke-width='0'%3E%3C/g%3E%3Cg id='SVGRepo_tracerCarrier' stroke-linecap='round' stroke-linejoin='round'%3E%3C/g%3E%3Cg id='SVGRepo_iconCarrier'%3E%3Ctitle%3Enote-text%3C/title%3E%3Cdesc%3ECreated with Sketch Beta.%3C/desc%3E%3Cdefs%3E%3C/defs%3E%3Cg id='Page-1' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd' sketch:type='MSPage'%3E%3Cg id='Icon-Set' sketch:type='MSLayerGroup' transform='translate(-308.000000, -99.000000)' fill='%23ffffff'%3E%3Cpath d='M332,107 L316,107 C315.447,107 315,107.448 315,108 C315,108.553 315.447,109 316,109 L332,109 C332.553,109 333,108.553 333,108 C333,107.448 332.553,107 332,107 L332,107 Z M338,127 C338,128.099 336.914,129.012 335.817,129.012 L311.974,129.012 C310.877,129.012 309.987,128.122 309.987,127.023 L309.987,103.165 C309.987,102.066 310.902,101 312,101 L336,101 C337.098,101 338,101.902 338,103 L338,127 L338,127 Z M336,99 L312,99 C309.806,99 308,100.969 308,103.165 L308,127.023 C308,129.22 309.779,131 311.974,131 L335.817,131 C338.012,131 340,129.196 340,127 L340,103 C340,100.804 338.194,99 336,99 L336,99 Z M332,119 L316,119 C315.447,119 315,119.448 315,120 C315,120.553 315.447,121 316,121 L332,121 C332.553,121 333,120.553 333,120 C333,119.448 332.553,119 332,119 L332,119 Z M332,113 L316,113 C315.447,113 315,113.448 315,114 C315,114.553 315.447,115 316,115 L332,115 C332.553,115 333,114.553 333,114 C333,113.448 332.553,113 332,113 L332,113 Z' id='note-text' sketch:type='MSShapeGroup'%3E%3C/path%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); 90 | } 91 | 92 | .remark-container-title.experimental { 93 | background-image: url("data:image/svg+xml,%3Csvg version='1.1' id='designs' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 32 32' xml:space='preserve' fill='%23ffffff'%3E%3Cg id='SVGRepo_bgCarrier' stroke-width='0'%3E%3C/g%3E%3Cg id='SVGRepo_tracerCarrier' stroke-linecap='round' stroke-linejoin='round'%3E%3C/g%3E%3Cg id='SVGRepo_iconCarrier'%3E%3Cstyle type='text/css'%3E .sketchy_een%7Bfill:%23ffffff;%7D %3C/style%3E%3Cpath class='sketchy_een' d='M27.958,26.693c-0.023-0.207-0.066-0.377-0.22-0.531c-0.006-0.006-0.015-0.008-0.021-0.014 c0.06-0.187,0.051-0.395-0.057-0.573c-0.326-0.538-0.64-1.08-0.942-1.631c-0.345-0.629-0.716-1.241-1.059-1.87 c-0.351-0.642-0.676-1.296-1.016-1.942c-0.352-0.675-0.773-1.309-1.142-1.974c-0.506-0.907-0.961-1.842-1.47-2.749 c-0.494-0.88-0.958-1.772-1.422-2.667c0.008-0.161-0.007-0.328-0.012-0.488c-0.004-0.168-0.009-0.337-0.017-0.506 c-0.015-0.364-0.042-0.726-0.064-1.087c-0.045-0.722-0.102-1.444-0.133-2.167c-0.062-1.561-0.036-3.121,0.043-4.68 c0.159,0.001,0.318,0.002,0.478,0.001c0.26-0.004,0.519-0.023,0.779-0.011c0.485,0.023,0.89-0.422,0.89-0.89 c0-0.235-0.095-0.462-0.261-0.629c-0.176-0.178-0.386-0.242-0.629-0.261C21.443,2.005,21.202,2,20.96,2 c-0.264,0-0.528,0.006-0.789,0.008C20.05,2.01,19.929,2.01,19.808,2.01c-0.201,0-0.402,0-0.602,0.002 c-0.347,0.004-0.695,0.026-1.042,0.034c-0.39,0.006-0.782,0.002-1.173,0.01c-0.402,0.01-0.803,0.028-1.203,0.042 c-0.769,0.025-1.536,0.068-2.308,0.068c-0.441,0-0.883,0.004-1.322,0c-0.5-0.004-0.998-0.045-1.499-0.066 c-0.445-0.021-0.818,0.386-0.818,0.818c0,0.458,0.373,0.805,0.818,0.82c0.12,0.004,0.24,0.003,0.36,0.006 c0.038,0.704,0.098,1.408,0.133,2.114c0.036,0.722,0.028,1.444,0.049,2.165c0.021,0.68,0.04,1.362,0.061,2.042 c0.019,0.608,0.055,1.214,0.07,1.822c-0.354,0.653-0.68,1.32-1.049,1.964c-0.195,0.341-0.385,0.682-0.563,1.031 c-0.172,0.333-0.316,0.68-0.468,1.023c-0.15,0.337-0.296,0.676-0.46,1.006c-0.165,0.328-0.333,0.656-0.489,0.987 c-0.165,0.352-0.324,0.708-0.493,1.061c-0.155,0.33-0.328,0.652-0.489,0.979c-0.263,0.534-0.496,1.082-0.746,1.622 c-0.267,0.58-0.525,1.165-0.777,1.752c-0.241,0.561-0.519,1.104-0.758,1.665c-0.225,0.529-0.428,1.068-0.647,1.6 c-0.039,0.093-0.079,0.184-0.118,0.278c-0.052,0.117-0.081,0.229-0.091,0.344c-0.087,0.136-0.152,0.288-0.159,0.459 c-0.019,0.46-0.019,0.911,0.218,1.324c0.159,0.281,0.358,0.478,0.618,0.663c0.135,0.095,0.305,0.14,0.457,0.199 c0.241,0.095,0.519,0.097,0.777,0.114c0.368,0.023,0.733,0.002,1.101-0.009c0.402-0.013,0.801-0.034,1.203-0.062 c0.405-0.03,0.813-0.036,1.218-0.047c0.801-0.025,1.605-0.019,2.406-0.004c0.762,0.013,1.519,0.038,2.279,0.1 c0.765,0.064,1.525,0.066,2.292,0.064c0.159,0,0.32,0,0.479,0c0.64,0.002,1.281,0.002,1.923-0.032 c0.756-0.042,1.514-0.053,2.271-0.085c0.392-0.017,0.781-0.055,1.169-0.093c0.377-0.036,0.756-0.047,1.133-0.062 c0.686-0.027,1.37-0.023,2.05-0.117c0.138-0.019,0.277-0.042,0.415-0.07c0.195-0.042,0.369-0.116,0.551-0.195 c0.282-0.121,0.527-0.314,0.748-0.525c0.275-0.261,0.421-0.599,0.53-0.957c0.097-0.314,0.138-0.656,0.114-0.983 C27.973,26.817,27.965,26.756,27.958,26.693z M15.375,3.768c0.449-0.004,0.9-0.002,1.351,0.002c0.322,0.002,0.644,0.006,0.966,0.004 c0.385-0.001,0.77,0.01,1.154,0.021c-0.028,0.789-0.017,1.581-0.015,2.372c0,0.754-0.009,1.51,0.01,2.264 c0.019,0.716,0.047,1.434,0.1,2.15c0.019,0.259,0.042,0.521,0.062,0.782c-0.342,0.013-0.685,0.025-1.027,0.039 c-0.572,0.021-1.146,0.025-1.718,0.068c-1.152,0.088-2.305,0.091-3.46,0.077c-0.036-0.807-0.057-1.615-0.065-2.424 c0.384-0.011,0.768-0.021,1.152-0.032c0.424-0.013,0.781-0.345,0.781-0.781c0-0.42-0.352-0.781-0.774-0.781 c-0.002,0-0.004,0-0.007,0c-0.389,0.004-0.779,0.008-1.168,0.011c-0.002-0.539,0.001-1.077-0.023-1.615 c-0.032-0.719-0.05-1.437-0.076-2.154C13.537,3.779,14.456,3.778,15.375,3.768z M26.457,27.054c-0.021,0.106-0.049,0.21-0.085,0.312 c-0.036,0.076-0.077,0.15-0.122,0.221c-0.054,0.056-0.112,0.108-0.172,0.159c-0.078,0.053-0.159,0.1-0.243,0.141 c-0.225,0.079-0.462,0.123-0.698,0.158c-0.307,0.032-0.615,0.033-0.922,0.049c-0.311,0.015-0.62,0.043-0.928,0.059 c-0.771,0.034-1.535,0.121-2.306,0.154c-0.758,0.032-1.519,0.034-2.279,0.061c-0.803,0.028-1.608,0.028-2.412,0.019 c-0.377-0.004-0.754-0.002-1.131-0.011c-0.366-0.008-0.729-0.034-1.095-0.059c-0.779-0.049-1.557-0.042-2.338-0.03 c-0.799,0.011-1.599,0.04-2.398,0.057c-0.798,0.017-1.591,0.055-2.389,0.055c-0.263,0.002-0.525-0.011-0.786-0.034 c-0.09-0.015-0.179-0.033-0.266-0.059c-0.03-0.015-0.059-0.032-0.087-0.049c-0.01-0.01-0.021-0.02-0.031-0.03 c-0.011-0.018-0.022-0.036-0.032-0.054c-0.005-0.17,0.01-0.342,0.017-0.511c0.005-0.097-0.021-0.188-0.051-0.275 c0.126-0.329,0.26-0.655,0.383-0.984c0.13-0.346,0.26-0.691,0.401-1.033c0.134-0.304,0.277-0.606,0.412-0.91 c0.007-0.015,0.013-0.031,0.02-0.046c0.333,0.005,0.668,0.002,1-0.004c0.582-0.008,1.165-0.017,1.749,0.021 c0.404,0.027,0.741-0.356,0.741-0.741c0-0.411-0.337-0.731-0.741-0.741c-0.692-0.016-1.384-0.045-2.076-0.07 c0.233-0.516,0.471-1.031,0.707-1.547c0.116-0.252,0.241-0.499,0.365-0.746c0.093,0.037,0.192,0.061,0.296,0.058 c0.36-0.008,0.722-0.021,1.082-0.04c0.258-0.013,0.523-0.049,0.782-0.032c0.436,0.03,0.801-0.386,0.801-0.801 c0-0.458-0.366-0.777-0.801-0.803c-0.023-0.002-0.045-0.002-0.068-0.002c-0.083,0-0.165,0.009-0.249,0.014 c-0.15,0.006-0.301,0.006-0.451,0.008c-0.209,0.002-0.419,0.003-0.628,0.004c0.099-0.22,0.198-0.441,0.301-0.66 c0.157-0.33,0.32-0.654,0.468-0.987c0.078-0.177,0.155-0.354,0.232-0.532c0.057,0.012,0.111,0.034,0.171,0.031 c0.754-0.044,1.506-0.097,2.262-0.14c0.419-0.023,0.771-0.333,0.771-0.771c0-0.426-0.35-0.765-0.771-0.773 c-0.067-0.001-0.133-0.001-0.2-0.001c-0.495,0-0.991,0.026-1.486,0.054c0.052-0.101,0.095-0.206,0.15-0.305 c0.34-0.613,0.68-1.226,1.023-1.838c0.055,0.013,0.107,0.034,0.166,0.034c1.25,0.002,2.497-0.082,3.745-0.146 c0.572-0.028,1.146-0.036,1.718-0.049c0.246-0.006,0.494-0.002,0.741,0c0.059,0.002,0.119,0.002,0.18,0.002 c0.034,0,0.069,0.003,0.103,0.003c0,0.14,0.021,0.28,0.091,0.41c0.383,0.71,0.799,1.404,1.203,2.101 c0.385,0.669,0.763,1.338,1.122,2.021c0.356,0.676,0.709,1.355,1.097,2.012c0.189,0.318,0.4,0.623,0.584,0.945 c0.188,0.324,0.358,0.657,0.53,0.991c0.466,0.89,0.949,1.77,1.47,2.631c0.241,0.398,0.468,0.803,0.703,1.205 c0.21,0.356,0.441,0.705,0.629,1.072c0.021,0.042,0.058,0.068,0.088,0.103c-0.04,0.091-0.062,0.19-0.059,0.295 C26.462,26.814,26.465,26.934,26.457,27.054z M24.139,25.03c0.191,0.358,0.093,0.807-0.267,1.017 c-0.172,0.1-0.381,0.129-0.572,0.076c-0.172-0.047-0.368-0.174-0.445-0.341c-0.481-1.029-1.029-2.027-1.555-3.031 c-0.286-0.546-0.557-1.099-0.852-1.641c-0.313-0.576-0.61-1.157-0.894-1.747c-0.093-0.193-0.136-0.383-0.078-0.593 c0.053-0.193,0.182-0.36,0.354-0.46c0.117-0.069,0.253-0.105,0.389-0.105c0.069,0,0.137,0.009,0.204,0.027 c0.178,0.049,0.379,0.182,0.458,0.354c0.28,0.593,0.557,1.186,0.851,1.771c0.277,0.551,0.54,1.11,0.832,1.654 c0.28,0.521,0.57,1.038,0.839,1.565c0.131,0.26,0.26,0.519,0.396,0.773C23.917,24.575,24.02,24.807,24.139,25.03z'%3E%3C/path%3E%3C/g%3E%3C/svg%3E"); 94 | } 95 | 96 | /* remark-highlight-code-lines */ 97 | 98 | .code-line.inserted { 99 | background-color: var(--color-inserted-line); /* inserted code-line (+) */ 100 | } 101 | 102 | .code-line.deleted { 103 | background-color: var(--color-deleted-line); /* deleted code-line (-) */ 104 | } 105 | 106 | .highlighted-code-line { 107 | background-color: var(--color-highlighted-line); 108 | border-left: 4px solid var(--color-highlighted-line-indicator); 109 | } 110 | 111 | .numbered-code-line::before { 112 | content: attr(data-line-number); 113 | 114 | margin-left: -8px; 115 | margin-right: 16px; 116 | width: 1rem; 117 | color: var(--color-text-weak); 118 | text-align: right; 119 | 120 | display: inline-block; 121 | } 122 | --------------------------------------------------------------------------------