diff --git a/.eslintrc.js b/.eslintrc.js index 1949aa122..37479fa7a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -3,7 +3,7 @@ module.exports = { es2021: true, node: true, browser: true, - "cypress/globals": true + 'cypress/globals': true, }, settings: { react: { @@ -34,7 +34,10 @@ module.exports = { 'react/jsx-curly-spacing': ['error', { when: 'never', children: true }], indent: ['error', 2, { SwitchCase: 1 }], - 'linebreak-style': ['error', process.platform === 'win32' ? 'windows' : 'unix'], + 'linebreak-style': [ + 'error', + process.platform === 'win32' ? 'windows' : 'unix', + ], quotes: ['error', 'single'], 'jsx-quotes': ['error', 'prefer-single'], diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3f2e8a656..315f1b55e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,7 +64,7 @@ jobs: run: yarn run test:coverage:all - name: Upload coverage report to Codecov - uses: codecov/codecov-action@v5.1.1 + uses: codecov/codecov-action@v5.3.1 with: token: ${{ secrets.CODECOV_TOKEN }} name: ${{ env.CODECOV_UNIQUE_NAME }} diff --git a/INSTALLATION.md b/INSTALLATION.md index be3b2cb03..f78296c42 100644 --- a/INSTALLATION.md +++ b/INSTALLATION.md @@ -4,7 +4,7 @@ This guide provides step-by-step instructions for installing the JSON Schema Web ## Table of Contents -1. [Setting Up the Project](#setting-up-the-project) +1. [Setting Up the Project](#setting-up-project) - [Requirements](#requirements) - [Cloning the Repository](#cloning-the-repository) - [Setting Up Environment Variables](#setting-up-environment-variables) diff --git a/components/AmbassadorsCard.tsx b/components/AmbassadorsCard.tsx index ad287ce64..68b0b49c8 100644 --- a/components/AmbassadorsCard.tsx +++ b/components/AmbassadorsCard.tsx @@ -55,11 +55,11 @@ const SocialIcon = ({ platform }: { platform: SocialIcons }) => { twitter: ( - + ), linkedin: ( @@ -114,7 +114,7 @@ const AmbassadorCard = ({ ambassador }: { ambassador: Ambassador }) => { contributions = [], } = ambassador; - const SocialIconss: SocialIcons[] = [ + const SocialIcons: SocialIcons[] = [ 'github', 'twitter', 'mastodon', @@ -122,7 +122,7 @@ const AmbassadorCard = ({ ambassador }: { ambassador: Ambassador }) => { ]; return ( -
+
@@ -137,7 +137,7 @@ const AmbassadorCard = ({ ambassador }: { ambassador: Ambassador }) => { onError={() => setImgSrc(`/img/ambassadors/${name}.jpg`)} /> -
+

{name}

@@ -157,8 +157,8 @@ const AmbassadorCard = ({ ambassador }: { ambassador: Ambassador }) => {

)} -
- {SocialIconss.map((platform) => { +
+ {SocialIcons.map((platform) => { const username = ambassador[platform]; return username ? (
{image && ( - {title} @@ -46,9 +50,11 @@ const CardBody = ({
{icon && ( - {title} diff --git a/components/DarkModeToggle.tsx b/components/DarkModeToggle.tsx index 798a92646..cadf3b7ac 100644 --- a/components/DarkModeToggle.tsx +++ b/components/DarkModeToggle.tsx @@ -1,6 +1,7 @@ import { useTheme } from 'next-themes'; import { useEffect, useState } from 'react'; import React from 'react'; +import Image from 'next/image'; function ListItem({ children, @@ -52,7 +53,7 @@ export default function DarkModeToggle() { className='dark-mode-toggle rounded-md dark:hover:bg-gray-700 p-1.5 hover:bg-gray-100 transition duration-150 ' data-test='dark-mode-toggle' > - Dark Mode setTheme('system')} data-test='select-system-theme' > - System theme setTheme('light')} data-test='select-light-theme' > - System theme setTheme('dark')} data-test='select-dark-theme' > - System theme { return ( <> -
- +
+
+
Specification Details
+
+
- - + - - - - + + - - + - - -
- Specification +
+ Specification + - {' '} {frontmatter.Specification}
- Published - - {frontmatter.Published} +
+ Published {frontmatter.Published}
- Authors +
+ Authors - {frontmatter.authors.map((author: string, index: number) => { - return
{author}
; - })} +
+ {frontmatter.authors.map((author: string, index: number) => ( + + {author} + {index < frontmatter.authors.length - 1 ? ', ' : ''} + + ))}
- Metaschema + + Metaschema + {frontmatter.Metaschema} diff --git a/components/DocsHelp.tsx b/components/DocsHelp.tsx index 544189b77..8fa21d48b 100644 --- a/components/DocsHelp.tsx +++ b/components/DocsHelp.tsx @@ -3,18 +3,34 @@ import React, { FormEvent, useRef, useState } from 'react'; import extractPathWithoutFragment from '~/lib/extractPathWithoutFragment'; interface DocsHelpProps { - markdownFile?: string; + fileRenderType?: '_indexmd' | 'indexmd' | 'tsx' | '_md' | string; + showEditOption?: boolean; } - -export function DocsHelp({ markdownFile }: DocsHelpProps) { +export function DocsHelp({ + fileRenderType, + showEditOption = true, +}: DocsHelpProps) { const router = useRouter(); - const path = encodeURIComponent(router.pathname); const [isFormOpen, setIsFormOpen] = useState(false); const [feedbackStatus, setFeedbackStatus] = useState(''); const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(''); const feedbackFormRef = useRef(null); - + let gitredirect = ''; + if ( + typeof fileRenderType === 'string' && + fileRenderType.startsWith('https://') + ) { + gitredirect = fileRenderType; + } else if (fileRenderType === 'tsx') { + gitredirect = `https://github.com/json-schema-org/website/blob/main/pages${extractPathWithoutFragment(router.asPath) + '/index.page.tsx'}`; + } else if (fileRenderType === '_indexmd') { + gitredirect = `https://github.com/json-schema-org/website/blob/main/pages${extractPathWithoutFragment(router.asPath) + '/_index.md'}`; + } else if (fileRenderType === 'indexmd') { + gitredirect = `https://github.com/json-schema-org/website/blob/main/pages${extractPathWithoutFragment(router.asPath) + '/index.md'}`; + } else { + gitredirect = `https://github.com/json-schema-org/website/blob/main/pages${extractPathWithoutFragment(router.asPath) + '.md'}`; + } async function createFeedbackHandler(event: FormEvent) { event.preventDefault(); const formData = new FormData(feedbackFormRef.current!); @@ -296,28 +312,30 @@ export function DocsHelp({ markdownFile }: DocsHelpProps) { type of contribution!

- + + Edit this page on Github + + + )} diff --git a/components/JsonEditor.tsx b/components/JsonEditor.tsx index b16289f18..34fefe0cc 100644 --- a/components/JsonEditor.tsx +++ b/components/JsonEditor.tsx @@ -6,6 +6,7 @@ import getPartsOfJson, { SyntaxPart } from '~/lib/getPartsOfJson'; import jsonSchemaReferences from './jsonSchemaLinks'; import { useRouter } from 'next/router'; import { FullMarkdownContext } from '~/context'; +import Image from 'next/image'; import getScopesOfParsedJsonSchema, { JsonSchemaPathWithScope, JsonSchemaScope, @@ -294,16 +295,22 @@ export default function JsonEditor({ initialCode }: { initialCode: string }) { }} data-test='copy-clipboard-button' > - Copy icon - + Copied icon + />
{isJsonSchema ? ( <> - schema +  logo-white{' '} + schema ) : ( <>data @@ -319,6 +333,7 @@ export default function JsonEditor({ initialCode }: { initialCode: string }) {
{ e.preventDefault(); @@ -363,7 +378,6 @@ export default function JsonEditor({ initialCode }: { initialCode: string }) { (jsonPathsWithJsonScope) => jsonPathsWithJsonScope.jsonPath, ) .includes(leaf.syntaxPart?.parentJsonPath); - // console.log('jsonPathsWithJsonScope', jsonPathsWithJsonScope, leaf, leaf.syntaxPart?.parentJsonPath) if ( isJsonScope && jsonSchemaReferences.objectProperty[leaf.text] @@ -410,7 +424,7 @@ export default function JsonEditor({ initialCode }: { initialCode: string }) { if (!link) return; router.push(link); }} - className={classnames('pb-2', textStyles)} + className={classnames('pb-2', textStyles, 'whitespace-pre')} title={leaf.syntaxPart?.type} {...attributes} > @@ -451,7 +465,13 @@ export default function JsonEditor({ initialCode }: { initialCode: string }) { className='text-white px-4 py-3 font-sans flex flex-row justify-end items-center bg-red-500/30 text-sm' data-test='not-compliant-to-schema' > - + Error icon not compliant to schema )} @@ -460,7 +480,13 @@ export default function JsonEditor({ initialCode }: { initialCode: string }) { className='text-white px-4 py-3 font-sans flex flex-row justify-end items-center bg-slate-500/30 text-sm' data-test='compliant-to-schema' > - + Checkmark icon compliant to schema )} diff --git a/components/Layout.tsx b/components/Layout.tsx index 3a3b5bbd6..441b83188 100644 --- a/components/Layout.tsx +++ b/components/Layout.tsx @@ -10,6 +10,7 @@ import { useTheme } from 'next-themes'; import DarkModeToggle from './DarkModeToggle'; import extractPathWithoutFragment from '~/lib/extractPathWithoutFragment'; import ScrollButton from './ScrollButton'; +import Image from 'next/image'; type Props = { children: React.ReactNode; @@ -327,7 +328,13 @@ const Footer = () => ( >
- + logo-white
( href='https://json-schema.org/slack' className='flex items-center text-white' > - Slack logo Slack @@ -360,7 +370,14 @@ const Footer = () => ( href='https://x.com/jsonschema' className='flex items-center text-white' > - X + X logo{' '} + X
@@ -368,9 +385,12 @@ const Footer = () => ( href='https://linkedin.com/company/jsonschema/' className='flex items-center text-white' > - LinkedIn logo LinkedIn @@ -380,7 +400,13 @@ const Footer = () => ( href='https://www.youtube.com/@JSONSchemaOrgOfficial' className='flex items-center text-white' > - + YouTube logo Youtube
@@ -389,9 +415,12 @@ const Footer = () => ( href='https://github.com/json-schema-org' className='flex items-center text-white' > - GitHub logo GitHub @@ -400,7 +429,7 @@ const Footer = () => (

- Copyright © 2024 JSON Schema.  + Copyright © {new Date().getFullYear()} JSON Schema.  All rights reserved.

@@ -422,7 +451,13 @@ const Logo = () => { return (
- + Dynamic image
); diff --git a/components/NavigationButtons.tsx b/components/NavigationButtons.tsx new file mode 100644 index 000000000..8e8747577 --- /dev/null +++ b/components/NavigationButtons.tsx @@ -0,0 +1,93 @@ +import Image from 'next/image'; +import React from 'react'; +import Link from 'next/link'; + +/* +To use this component: +1) Add prev and next metadata to the markdown page following this format: + +--- +title: Creating your first schema +section: docs +prev: + label: prev + url: '#1' +next: + label: Miscellaneous examples + url: '#2' +--- + +2) Add the component to the typescript page: + +import NextPrevButton from '~/components/NextPrevButton'; + +3) Add the component to the body of the page: + + +*/ + +export default function NextPrevButton({ + prevLabel, + prevURL, + nextLabel, + nextURL, +}: any) { + return ( +
+ {prevURL && prevLabel ? ( +
+
+ +
+ prev icon +
+ Go Back +
+
+
+ {prevLabel} +
+ +
+
+ ) : ( +
+ )} + + {nextURL && nextLabel ? ( +
+
+ +
+ next icon +
+ Up Next +
+
+
+ {nextLabel} +
+ +
+
+ ) : ( +
+ )} +
+ ); +} diff --git a/components/NextPrevButton.tsx b/components/NextPrevButton.tsx deleted file mode 100644 index 6c88b641c..000000000 --- a/components/NextPrevButton.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import Image from 'next/image'; -import React from 'react'; -import Link from 'next/link'; - -/* -To use this component: -1) Add prev and next metadata to the markdown page following this format: - ---- -title: Creating your first schema -section: docs -prev: - label: prev - url: '#1' -next: - label: Miscellaneous examples - url: '#2' ---- - -2) Add the component to the typescript page: - -import NextPrevButton from '~/components/NextPrevButton'; - -3) Add the component to the body of the page: - - -*/ - -export default function NextPrevButton({ - prevLabel, - prevURL, - nextLabel, - nextURL, -}: any) { - return ( -
-
-
- -
- prev icon -
Go Back
-
-
- {prevLabel} -
- -
-
- -
-
- -
- next icon -
Up Next
-
-
- {nextLabel} -
- -
-
-
- ); -} diff --git a/components/Sidebar.tsx b/components/Sidebar.tsx index 6370bb406..e18c2f050 100644 --- a/components/Sidebar.tsx +++ b/components/Sidebar.tsx @@ -9,7 +9,7 @@ import extractPathWithoutFragment from '~/lib/extractPathWithoutFragment'; import CarbonAds from './CarbonsAds'; import { useTheme } from 'next-themes'; import ExternalLinkIcon from '../public/icons/external-link-black.svg'; - +import Image from 'next/image'; const DocLink = ({ uri, label, @@ -117,13 +117,19 @@ const getStartedPath = [ '/learn/file-system', '/learn/miscellaneous-examples', '/learn/getting-started-step-by-step', + '/understanding-json-schema/about', + '/understanding-json-schema/basics', + '/learn/glossary', +]; +const getGuidesPath = [ + '/learn/guides', + '/implementers', + '/implementers/interfaces', ]; const getReferencePath = [ '/understanding-json-schema', '/understanding-json-schema/keywords', - '/understanding-json-schema/basics', '/understanding-json-schema/conventions', - '/understanding-json-schema/about', '/understanding-json-schema/credits', '/understanding-json-schema/structuring', '/understanding-json-schema/reference/annotations', @@ -144,9 +150,6 @@ const getReferencePath = [ '/understanding-json-schema/reference/type', '/understanding-json-schema/reference/generic', '/understanding-json-schema/reference', - '/learn/glossary', - '/implementers', - '/implementers/interfaces', ]; const getSpecificationPath = [ '/draft/2020-12', @@ -181,7 +184,7 @@ export const SidebarLayout = ({ children }: { children: React.ReactNode }) => { return (
-
+
e.stopPropagation()} @@ -192,20 +195,20 @@ export const SidebarLayout = ({ children }: { children: React.ReactNode }) => { }} > {getDocsPath.includes(pathWtihoutFragment) && ( -

Overview

+

Introduction

)} {getStartedPath.includes(pathWtihoutFragment) && ( -

Getting Started

+

Get started

+ )} + {getGuidesPath.includes(pathWtihoutFragment) && ( +

Guides

)} - {getReferencePath.includes(pathWtihoutFragment) && (

Reference

)} - {getSpecificationPath.includes(pathWtihoutFragment) && (

Specification

)} - {router.pathname === null && (

Docs

)} @@ -232,17 +235,19 @@ export const SidebarLayout = ({ children }: { children: React.ReactNode }) => {
-
+
-
- - +
+
+ + +
{children} @@ -265,40 +270,90 @@ export const DocsNav = ({ const [active, setActive] = useState({ getDocs: false, getStarted: false, + getGuides: false, getReference: false, getSpecification: false, }); useEffect(() => { const pathWtihoutFragment = extractPathWithoutFragment(router.asPath); + const newActive = { + getDocs: false, + getStarted: false, + getGuides: false, + getReference: false, + getSpecification: false, + }; if (getDocsPath.includes(pathWtihoutFragment)) { - setActive({ ...active, getDocs: true }); + newActive.getDocs = true; } else if (getStartedPath.includes(pathWtihoutFragment)) { + newActive.getStarted = true; setActive({ ...active, getStarted: true }); + } else if (getGuidesPath.includes(pathWtihoutFragment)) { + setActive({ ...active, getGuides: true }); } else if (getReferencePath.includes(pathWtihoutFragment)) { - setActive({ ...active, getReference: true }); + newActive.getReference = true; } else if (getSpecificationPath.includes(pathWtihoutFragment)) { - setActive({ ...active, getSpecification: true }); + newActive.getSpecification = true; + } else if (getGuidesPath.includes(pathWtihoutFragment)) { + newActive.getGuides = true; } + + setActive(newActive); }, [router.asPath]); const handleClickDoc = () => { - setActive({ ...active, getDocs: !active.getDocs }); + setActive({ + getDocs: !active.getDocs, + getStarted: false, + getReference: false, + getSpecification: false, + getGuides: false, + }); }; const handleClickGet = () => { - setActive({ ...active, getStarted: !active.getStarted }); + setActive({ + getDocs: false, + getStarted: !active.getStarted, + getReference: false, + getSpecification: false, + getGuides: false, + }); }; const handleClickReference = () => { - setActive({ ...active, getReference: !active.getReference }); + setActive({ + getDocs: false, + getStarted: false, + getReference: !active.getReference, + getSpecification: false, + getGuides: false, + }); + }; + + const handleClickGuides = () => { + setActive({ + getDocs: false, + getStarted: false, + getGuides: !active.getGuides, + getReference: false, + getSpecification:false, + }); }; const handleClickSpec = () => { - setActive({ ...active, getSpecification: !active.getSpecification }); + setActive({ + getDocs: false, + getStarted: false, + getGuides: false, + getReference: false, + getSpecification: !active.getSpecification, + }); }; const rotate = active.getDocs ? 'rotate(180deg)' : 'rotate(0)'; const rotateG = active.getStarted ? 'rotate(180deg)' : 'rotate(0)'; + const rotateGui = active.getGuides ? 'rotate(180deg)' : 'rotate(0)'; const rotateR = active.getReference ? 'rotate(180deg)' : 'rotate(0)'; const rotateSpec = active.getSpecification ? 'rotate(180deg)' : 'rotate(0)'; @@ -308,30 +363,40 @@ export const DocsNav = ({ const [reference_icon, setReference_icon] = useState(''); const [spec_icon, setSpec_icon] = useState(''); const [overview_icon, setOverview_icon] = useState(''); + const [guides_icon, setGuides_icon] = useState(''); useEffect(() => { if (resolvedTheme === 'dark') { setOverview_icon('/icons/eye-dark.svg'); setLearn_icon('/icons/compass-dark.svg'); setReference_icon('/icons/book-dark.svg'); setSpec_icon('/icons/clipboard-dark.svg'); + setGuides_icon('/icons/grad-cap-dark.svg'); } else { setOverview_icon('/icons/eye.svg'); setLearn_icon('/icons/compass.svg'); setReference_icon('/icons/book.svg'); setSpec_icon('/icons/clipboard.svg'); + setGuides_icon('/icons/grad-cap.svg'); } }, [resolvedTheme]); return ( {' '} + {/*Closing div: Introduction*/} + {/* Get started */}
- compass icon - + compass icon +
+ + +
-
+
{' '} + {/* Closing div: Get started */} + {/* Guides */} +
+
+
+ grad cap icon + +
+ + + +
+
+ + +
+ +
+ {/*Closing div tag: for implementers*/} +
+
{' '} + {/* Closing div: Guides */} {/* Reference */} -
- book icon + book icon
+ {/*Opening div: inner reference div */}
- - -
- */} + {/*
*/} + {/* - - - */} + {/* -
+ /> +
Opening div tag: understanding JSON*/} + +
{/*Opening div: JSON data types*/} -
- - - - - - - -
-
- - - - -
-
+ +
{/*Closing div: JSON data types*/} + + +
{/*Opening div: Schema constraints*/} -
+ +
{/*Closing div: Schema constraints*/}
+ {/*Opening div: Schema metadata*/} -
+ +
{/*Closing div: Schema metadata*/} + + +
{/*Opening div: Schema composition*/} + + +
{/*Closing div: Schema composition*/} + +
-
+
{' '} + {/*Closing div: inner reference div */} {/* Specification */} -
- clipboard icon + clipboard icon
@@ -703,7 +885,7 @@ export const DocsNav = ({ @@ -714,7 +896,7 @@ export const DocsNav = ({ /> diff --git a/components/StyledMarkdown.tsx b/components/StyledMarkdown.tsx index e856d5010..916aa97ae 100644 --- a/components/StyledMarkdown.tsx +++ b/components/StyledMarkdown.tsx @@ -173,7 +173,7 @@ const StyledMarkdownBlock = ({ markdown }: { markdown: string }) => { h4: { component: Headline4 }, strong: { component: ({ children }) => ( - + {children} ), @@ -307,34 +307,25 @@ const StyledMarkdownBlock = ({ markdown }: { markdown: string }) => { } return ( -
- {/* definitely not the best way to prevent overflowing. found no better way that worked */} +
{ - const isHighlighted = false; - return { - className: `${isHighlighted ? 'bg-code-editor-dark-highlight block ml-10 w-full' : ''} pr-8`, - }; + lineNumberStyle={{ + color: '#64748B', + fontSize: '16px', + paddingRight: '10px', + }} + customStyle={{ + padding: '12px', + fontFamily: 'monospace', + fontSize: '16px', }} codeTagProps={{ - className: 'mr-8', + style: { + fontFamily: 'monospace', + }, }} > {code} @@ -388,7 +379,13 @@ const StyledMarkdownBlock = ({ markdown }: { markdown: string }) => { component: ({ label }) => { return (
- + star {label}
); @@ -398,7 +395,13 @@ const StyledMarkdownBlock = ({ markdown }: { markdown: string }) => { component: ({ label }) => { return (
- + info yellow {label}
); @@ -414,10 +417,12 @@ const StyledMarkdownBlock = ({ markdown }: { markdown: string }) => {
)}
-
{children}
@@ -435,10 +440,12 @@ const StyledMarkdownBlock = ({ markdown }: { markdown: string }) => {
)}
-
{children}
@@ -456,10 +463,12 @@ const StyledMarkdownBlock = ({ markdown }: { markdown: string }) => {
)}
-
{children}
@@ -477,10 +486,12 @@ const StyledMarkdownBlock = ({ markdown }: { markdown: string }) => {
)}
-
{children}
@@ -519,8 +530,8 @@ const StyledMarkdownBlock = ({ markdown }: { markdown: string }) => {
menu-icon diff --git a/context.ts b/context.ts index 2d7bbee79..9f8022ea5 100644 --- a/context.ts +++ b/context.ts @@ -21,6 +21,7 @@ export const SectionContext = React.createContext< | 'reference' | 'roadmap' | 'ambassador' + | 'pro-help' >(null); export const BlockContext = React.createContext(null); export const FullMarkdownContext = React.createContext(null); diff --git a/cypress/components/DocsHelp.cy.tsx b/cypress/components/DocsHelp.cy.tsx index cfd9acc80..e8c6a1c6d 100644 --- a/cypress/components/DocsHelp.cy.tsx +++ b/cypress/components/DocsHelp.cy.tsx @@ -20,29 +20,31 @@ const FEEDBACK_FORM_GITHUB_SUCCESS_MESSAGE = describe('DocsHelp Component', () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars let mockRouter: MockRouter; + const extractPathWithoutFragment = (path: any) => path.split('#')[0]; // Note: we are not using the mockRouter in this test file, but it is required to mock the router in the component file beforeEach(() => { - const markdownFile = '_index'; + const fileRenderType = 'indexmd'; mockRouter = mockNextRouter(); cy.viewport(1200, 800); - cy.mount(); + cy.mount(); }); // should render the component correctly it('should render the component correctly', () => { // Check if the main component wrapper is present + cy.mount(); cy.get(DOCS_HELP).should('exist'); // "Need Help?" header cy.get('[data-test="need-help-heading"]') .should('have.prop', 'tagName', 'H2') - .and('contains', /Need Help?/i); + .and('contain.text', 'Need Help?'); // Main feedback question cy.get('[data-test="feedback-main-heading"]') .should('have.prop', 'tagName', 'H3') - .and('contains', /Did you find these docs helpful?/i); + .and('contain.text', 'Did you find these docs helpful?'); // Feedback form element cy.get(FEEDBACK_FORM).should('have.prop', 'tagName', 'FORM'); @@ -50,20 +52,17 @@ describe('DocsHelp Component', () => { // "Help us improve" section header cy.get('[data-test="contribute-docs-heading"]') .should('have.prop', 'tagName', 'H3') - .and('contains', /Help us make our docs great!/i); + .and('contain.text', 'Help us make our docs great!'); // Contribution encouragement text cy.get('[data-test="contribute-docs-description"]') .should('have.prop', 'tagName', 'P') - .and( - 'contains', - /At JSON Schema, we value docs contributions as much as every other type of contribution!/i, - ); + .and('contain.text', 'At JSON Schema, we value docs contributions'); // "Edit on GitHub" link cy.get('[data-test="edit-on-github-link"]') .should('have.prop', 'tagName', 'A') - .and('contains', /Edit this page on Github/i); + .and('contain.text', 'Edit this page on Github'); // "Learn to contribute" link cy.get('[data-test="learn-to-contribute-link"]') @@ -73,20 +72,17 @@ describe('DocsHelp Component', () => { 'href', 'https://github.com/json-schema-org/website/blob/main/CONTRIBUTING.md', ) - .and('contains', /Learn how to contribute/i); + .and('contain.text', 'Learn how to contribute'); // "Still Need Help?" section header cy.get('[data-test="additional-help-heading"]') .should('have.prop', 'tagName', 'H3') - .and('contains', /Still Need Help?/i); + .and('contain.text', 'Still Need Help?'); // Additional help description cy.get('[data-test="additional-help-description"]') .should('have.prop', 'tagName', 'P') - .should( - 'contains', - /Learning JSON Schema is often confusing, but don't worry, we are here to help!./i, - ); + .and('contain.text', 'Learning JSON Schema is often confusing'); // GitHub community link cy.get('[ data-test="ask-on-github-link"]') @@ -96,7 +92,7 @@ describe('DocsHelp Component', () => { 'href', 'https://github.com/orgs/json-schema-org/discussions/new?category=q-a', ) - .and('contains', /Ask the community on GitHub/i); + .and('contain.text', 'Ask the community on GitHub'); // Slack community link cy.get('[data-test="ask-on-slack-link"]') @@ -237,15 +233,51 @@ describe('DocsHelp Component', () => { }); // This test is to check component render correctly with different markdown files - it('should render component with different markdown files', () => { - /* Note: Already checking with _index markdown file in the first test case */ - - // render with _indexPage markdown file - const markdownFile = '_indexPage'; - cy.mount(); - cy.get(DOCS_HELP).should('exist'); - - // render without any markdown file - cy.mount(); + it('should render component with different markdown files and validate gitredirect', () => { + const fileRenderTypes: ('tsx' | 'indexmd' | '_indexmd' | '_md')[] = [ + 'tsx', + '_indexmd', + 'indexmd', + '_md', + ]; + + fileRenderTypes.forEach((type) => { + let expectedGitRedirect = ''; + if (typeof type === 'string' && type.startsWith('https://')) { + expectedGitRedirect = type; + } else if (type === 'tsx') { + expectedGitRedirect = `https://github.com/json-schema-org/website/blob/main/pages${extractPathWithoutFragment(mockRouter.asPath) + '/index.page.tsx'}`; + } else if (type === '_indexmd') { + expectedGitRedirect = `https://github.com/json-schema-org/website/blob/main/pages${extractPathWithoutFragment(mockRouter.asPath) + '/_index.md'}`; + } else if (type === 'indexmd') { + expectedGitRedirect = `https://github.com/json-schema-org/website/blob/main/pages${extractPathWithoutFragment(mockRouter.asPath) + '/index.md'}`; + } else { + expectedGitRedirect = `https://github.com/json-schema-org/website/blob/main/pages${extractPathWithoutFragment(mockRouter.asPath) + '.md'}`; + } + cy.mount(); + + cy.get('[data-test="edit-on-github-link"]').should( + 'have.attr', + 'href', + expectedGitRedirect, + ); + }); + const customLink = 'https://example.com/custom-docs'; + cy.mount(); + cy.get('[data-test="edit-on-github-link"]').should( + 'have.attr', + 'href', + customLink, + ); + }); + // Check if the "Edit on GitHub" link is present when showEditOption is true + it('should render the "Edit on GitHub" link when showEditOption is true', () => { + cy.mount(); + cy.get('[data-test="edit-on-github-link"]').should('exist'); + }); + // Check if the "Edit on GitHub" link is not present when showEditOption is false + it('should not render the "Edit on GitHub" link when showEditOption is false', () => { + cy.mount(); + cy.get('[data-test="edit-on-github-link"]').should('not.exist'); }); }); diff --git a/data/community.json b/data/community.json deleted file mode 100644 index 09ad7a953..000000000 --- a/data/community.json +++ /dev/null @@ -1,302 +0,0 @@ -[ - { - "id": "item", - "img": "./img/avatars/benhutton.webp", - "alt": "benhutton" - }, - { - "id": "item", - "img": "./img/avatars/benjagm.webp", - "alt": "benjagm" - }, - { - "id": "item", - "img": "./img/avatars/gregsdennis.webp", - "alt": "gregs" - }, - { - "id": "item", - "img": "./img/avatars/jasondesrosiers.jpeg", - "alt": "jason" - }, - { - "id": "item", - "img": "./img/avatars/julian.webp", - "alt": "julian" - }, - { - "id": "item", - "img": "./img/contributers/melinda.png", - "alt": "melinda" - }, - { - "id": "item", - "img": "./img/avatars/jviotti.webp", - "alt": "jviotti" - }, - { - "id": "item", - "img": "./img/contributers/musemind.png", - "alt": "musemind" - }, - { - "id": "item-2", - "img": "./img/contributers/akanksha-kushwaha.jpeg", - "alt": "aku1310" - }, - { - "id": "item-2", - "img": "./img/contributers/OlliesWorld.jpeg", - "alt": "roni" - }, - { - "id": "item-2", - "img": "./img/contributers/darhkvoyd.jpeg", - "alt": "DV" - }, - { - "id": "item-2", - "img": "./img/contributers/dhairya.jpeg", - "alt": "dhairya" - }, - { - "id": "item-2", - "img": "./img/contributers/paul-waller.jpeg", - "alt": "paul-waller" - }, - { - "id": "item-2", - "img": "./img/contributers/officeneerajsaini.jpeg", - "alt": "neeraj" - }, - { - "id": "item-2", - "img": "./img/contributers/jeel-rajodiya.jpeg", - "alt": "jeel" - }, - { - "id": "item-2", - "img": "./img/contributers/tamanna-verma.jpeg", - "alt": "tamana" - }, - { - "id": "item-3", - "img": "./img/contributers/mintu-gogoi.jpeg", - "alt": "mintu" - }, - { - "id": "item-3", - "img": "./img/contributers/aditya-sharma.jpeg", - "alt": "aditya" - }, - { - "id": "item-3", - "img": "./img/contributers/satyam-kumar.jpeg", - "alt": "satyam" - }, - { - "id": "item-3", - "img": "./img/contributers/ayush_tiwari.jpeg", - "alt": "ayush" - }, - { - "id": "item-3", - "img": "./img/contributers/sahil_shadwal.jpeg", - "alt": "sahil" - }, - { - "id": "item-3", - "img": "./img/contributers/julian-cataldo.jpeg", - "alt": "julian" - }, - { - "id": "item-3", - "img": "./img/contributers/sandrina.jpeg", - "alt": "sandrina" - }, - { - "id": "item-3", - "img": "./img/contributers/lateapexe.jpeg", - "alt": "late" - }, - { - "id": "item-4", - "img": "./img/contributers/alok-gupta.jpeg", - "alt": "alok" - }, - { - "id": "item-4", - "img": "./img/contributers/michael-sharber.jpeg", - "alt": "michael" - }, - { - "id": "item-4", - "img": "./img/contributers/gabengar.png", - "alt": "gabengar" - }, - { - "id": "item-4", - "img": "./img/contributers/ali_haider.jpeg", - "alt": "ali" - }, - { - "id": "item-4", - "img": "./img/contributers/saksham_mishra.jpeg", - "alt": "saksham" - }, - { - "id": "item-4", - "img": "./img/contributers/sarthak.jpeg", - "alt": "sarthak" - }, - { - "id": "item-4", - "img": "./img/contributers/jayprakash.jpeg", - "alt": "jayprakash" - }, - { - "id": "item-4", - "img": "./img/contributers/vinitpandit.jpeg", - "alt": "vinit" - }, - { - "id": "item-5", - "img": "./img/contributers/dauinh.jpeg", - "alt": "linh" - }, - { - "id": "item-5", - "img": "./img/contributers/kalivtrope.jpeg", - "alt": "kalivtrope" - }, - { - "id": "item-5", - "img": "./img/contributers/adityasingh.jpeg", - "alt": "aditya" - }, - { - "id": "item-5", - "img": "./img/contributers/Maykkkk.jpeg", - "alt": "maykkkk" - }, - { - "id": "item-5", - "img": "./img/contributers/bcherny.jpeg", - "alt": "boris" - }, - { - "id": "item-5", - "img": "./img/contributers/Saumya40-codes.jpeg", - "alt": "saumya" - }, - { - "id": "item-5", - "img": "./img/contributers/prajjwalyd.jpeg", - "alt": "prajjwal" - }, - { - "id": "item-5", - "img": "./img/contributers/abhishek-403.png", - "alt": "abhishek" - }, - { - "id": "item-6", - "img": "./img/contributers/CarstenWickner.jpeg", - "alt": "Carsten" - }, - { - "id": "item-6", - "img": "./img/contributers/kx412764776.jpeg", - "alt": "kx412764776" - }, - { - "id": "item-6", - "img": "./img/contributers/unguul.jpeg", - "alt": "unguul" - }, - { - "id": "item-6", - "img": "./img/contributers/Akshaybagai52.jpeg", - "alt": "akshay" - }, - { - "id": "item-6", - "img": "./img/contributers/Michael-Obele.jpeg", - "alt": "michael" - }, - { - "id": "item-6", - "img": "./img/contributers/karenetheridge.jpeg", - "alt": "karene" - }, - { - "id": "item-6", - "img": "./img/contributers/eddyashton.jpeg", - "alt": "eddy" - }, - { - "id": "item-6", - "img": "./img/contributers/lalitkumawat1m.png", - "alt": "lalit" - }, - { - "id": "item-7", - "img": "./img/contributers/justin-tay.png", - "alt": "justin" - }, - { - "id": "item-7", - "img": "./img/contributers/ThomasAribart.jpeg", - "alt": "thomas" - }, - { - "id": "item-7", - "img": "./img/contributers/Viicos.jpeg", - "alt": "viicos" - }, - { - "id": "item-7", - "img": "./img/contributers/vm-001.png", - "alt": "vm-001" - }, - { - "id": "item-7", - "img": "./img/contributers/big-andy-coates.png", - "alt": "big-andy-coates" - }, - { - "id": "item-7", - "img": "./img/contributers/smoya.jpeg", - "alt": "smoya" - }, - { - "id": "item-7", - "img": "./img/contributers/ota-meshi.jpeg", - "alt": "ota-meshi" - }, - { - "id": "item-7", - "img": "./img/contributers/michaelmior.jpeg", - "alt": "michaelmior" - }, - { - "id": "item-8", - "img": "./img/contributers/maverox.jpeg", - "alt": "maverox" - }, - { - "id": "item-8", - "img": "./img/contributers/kurtmckee.png", - "alt": "kurtmckee" - }, - { - "id": "item-8", - "img": "./img/contributers/Mvishal123.jpeg", - "alt": "vishal" - }, - { - "id": "item-8", - "img": "./img/contributers/SimonDMC.png", - "alt": "simon" - } -] diff --git a/data/hyper-libraries-obsolete.yml b/data/hyper-libraries-obsolete.yml deleted file mode 100644 index 10a55c4a8..000000000 --- a/data/hyper-libraries-obsolete.yml +++ /dev/null @@ -1,15 +0,0 @@ -- name: JavaScript - implementations: - - name: Jsonary - url: "http://jsonary.com/" - license: MIT - date-draft: [] - draft: [4] -- name: Python - implementations: - - name: Core API Hyper-Schema codec - url: "https://github.com/core-api/python-jsonhyperschema-codec" - notes: "Draft-06+ progress: issue [12](https://github.com/core-api/python-jsonhyperschema-codec/issues/12)" - date-draft: [] - draft: [4] - license: BSD-2-Clause diff --git a/data/keywords.yml b/data/keywords.yml index 04e71df01..daf1b7ebe 100644 --- a/data/keywords.yml +++ b/data/keywords.yml @@ -13,7 +13,7 @@ learnjsonschemalink: 'https://www.learnjsonschema.com/2020-12/core/comment' links: - url: 'https://json-schema.org/understanding-json-schema/reference/comments#comments' - title: Generic Keyowrds ($comment) + title: Generic Keywords ($comment) - url: 'https://json-schema.org/draft/2020-12/json-schema-core#name-comments-with-comment' title: Draft 2020-12 - name: $defs @@ -43,9 +43,9 @@ learnjsonschemalink: 'https://www.learnjsonschema.com/2020-12/core/id' links: - url: 'https://json-schema.org/learn/getting-started-step-by-step#create-a-schema-definition' - title: Create a schema defination + title: Create a schema definition - url: 'https://json-schema.org/understanding-json-schema/basics#declaring-a-unique-identifier' - title: Declaring a unique identifer + title: Declaring a unique identifier - url: 'https://json-schema.org/draft/2020-12/json-schema-core#name-the-id-keyword' title: Draft 2020-12 - name: $ref @@ -55,7 +55,7 @@ - url: 'https://json-schema.org/understanding-json-schema/basics#declaring-a-json-schema' title: Declaring a JSON Schema - url: 'https://json-schema.org/learn/getting-started-step-by-step#create-a-schema-definition' - title: Create a schema defination + title: Create a schema definition - url: 'https://json-schema.org/understanding-json-schema/reference/array#unevaluateditems' title: Unevaluated Items - url: 'https://json-schema.org/understanding-json-schema/structuring#dollarref' @@ -149,7 +149,7 @@ learnjsonschemalink: 'https://www.learnjsonschema.com/2020-12/applicator/not' links: - url: 'https://json-schema.org/understanding-json-schema/reference/combining#schema-composition' - title: Schema Compositon + title: Schema Composition - url: 'https://json-schema.org/draft/2020-12/json-schema-core#name-not' title: Draft 2020-12 - name: oneOf @@ -159,9 +159,9 @@ - url: 'https://json-schema.org/learn/file-system#modeling-a-file-system-with-json-schema' title: Modeling a file system with JSON Schema - url: 'https://json-schema.org/understanding-json-schema/reference/array#unevaluateditems' - title: Unevaluted Items + title: Unevaluated Items - url: 'https://json-schema.org/understanding-json-schema/reference/combining#schema-composition' - title: Schema Compositon + title: Schema Composition - url: 'https://json-schema.org/draft/2020-12/json-schema-core#name-oneof' title: Draft 2020-12 - name: patternProperties @@ -189,7 +189,7 @@ - url: 'https://json-schema.org/understanding-json-schema/reference/object#properties' title: Properties - url: 'https://json-schema.org/learn/getting-started-step-by-step#create-a-schema-definition' - title: Schema Defination + title: Schema Definition - url: 'https://json-schema.org/draft/2020-12/json-schema-core#name-properties' title: Draft 2020-12 - name: propertyNames @@ -389,7 +389,7 @@ - url: 'https://json-schema.org/understanding-json-schema/basics#the-type-keyword' title: The type keyword - url: 'https://json-schema.org/learn/getting-started-step-by-step#create-a-schema-definition' - title: Create a Schema Defination + title: Create a Schema Definition - url: 'https://json-schema.org/draft/2020-12/json-schema-validation#name-type' title: Draft 2020-12 - name: uniqueItems diff --git a/data/tooling-data.schema.json b/data/tooling-data.schema.json index b91ae2365..75d0d435c 100644 --- a/data/tooling-data.schema.json +++ b/data/tooling-data.schema.json @@ -121,7 +121,7 @@ "C#", "Go", "C++", - "JavaScript", + "JavaScript", "Julia" ] ] @@ -280,6 +280,11 @@ "description": "The date when the tool was most recently updated. The date should be in the format YYYY-MM-DD, representing the year, month, and day of the update.", "type": "string", "format": "date" + }, + "status": { + "description": "Current status of the project, indicating its phase of development or maintenance.", + "type": "string", + "enum": ["active", "obsolete"] } }, "required": ["name", "toolingTypes"], diff --git a/data/tooling-data.yaml b/data/tooling-data.yaml index 46c551e64..e267b599f 100644 --- a/data/tooling-data.yaml +++ b/data/tooling-data.yaml @@ -1106,6 +1106,7 @@ supportedDialects: draft: ['4', '6', '7'] lastUpdated: '2020-11-30' + status: 'obsolete' - name: php-json-schema-bench description: 'Comparative benchmark for JSON-schema PHP validators using JSON-Schema Test Suite and z-schema/JSCK.' @@ -1471,7 +1472,7 @@ - name: cypress-ajv-schema-validator description: 'Cypress plugin that validates API responses against Plain JSON schemas, and whole Swagger and OpenAPI documents using the Ajv JSON Schema validator. It provides a user-friendly view of validated data, highlighting each validation error and the exact reason for the mismatch. Seamless integration, fast and lightweight.' toolingTypes: ['validator', 'util-testing'] - languages: ['Javascript'] + languages: ['JavaScript'] maintainers: - name: 'Sebastian Clavijo Suero' username: 'sclavijosuero' @@ -2435,3 +2436,705 @@ supportedDialects: draft: ['7'] lastUpdated: '2024-10-24' + +- name: Jsonary + description: 'Quickly assemble clients for JSON-based APIs (powered by JSON Schema)' + toolingTypes: ['hyper-schema'] + languages: ['Javascript'] + license: 'MIT' + source: 'https://github.com/jsonary-js/jsonary' + supportedDialects: + draft: ['4'] + status: 'obsolete' + lastUpdated: '2015-05-08' + +- name: Core API Hyper-Schema codec + description: 'A JSON Hyperschema codec for Core API.' + toolingTypes: ['hyper-schema'] + languages: ['Python'] + maintainers: + - name: 'Tom Christie' + username: 'tomchristie' + platform: 'github' + license: 'BSD-2-Clause' + source: 'https://github.com/core-api/python-jsonhyperschema-codec' + supportedDialects: + draft: ['4'] + status: 'obsolete' + lastUpdated: '2018-02-27' + +- name: NJsonSchema + description: 'JSON Schema reader, generator and validator for .NET' + toolingTypes: [validator] + languages: ['.NET'] + license: 'Ms-PL' + source: http://NJsonSchema.org + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: Manatee.Json + toolingTypes: ['validator'] + languages: ['.NET'] + license: MIT + source: https://github.com/gregsdennis/Manatee.Json + supportedDialects: + draft: ['4', '6', '7'] + status: 'obsolete' + +- name: WJElement + toolingTypes: ['validator'] + languages: ['C'] + license: 'AGPL-3.0' + source: https://github.com/netmail-open/wjelement + supportedDialects: + draft: ['3', '4'] + toolingListingNotes: 'Draft-06+ progress: issue 17' + status: 'obsolete' + +- name: wjelement-cpp + toolingTypes: ['validator'] + languages: ['C++'] + license: 'AGPL-3.0' + source: https://github.com/petehug/wjelement-cpp + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: Header-only C++ library for JSON Schema validation + toolingTypes: ['validator'] + languages: ['C++'] + license: BSD-2-Clause + source: https://github.com/tristanpenman/valijson + supportedDialects: + draft: ['3', '4'] + status: 'obsolete' + +- name: Modern C++ JSON schema validator + toolingTypes: ['validator'] + languages: ['C++'] + license: MIT + source: https://github.com/pboettch/json-schema-validator + supportedDialects: + draft: ['4'] + toolingListingNotes: 'based on JSON for Modern C++' + status: 'obsolete' + +- name: scjsv + toolingTypes: ['validator'] + languages: ['Clojure'] + license: 'EPL-1.0' + source: https://github.com/metosin/scjsv + supportedDialects: + draft: ['4'] + toolingListingNotes: '(wrapper for java-json-tools/json-schema-validator)' + status: 'obsolete' + +- name: json-schema validator + toolingTypes: ['validator'] + languages: ['Clojure'] + license: MIT + source: https://github.com/tatut/json-schema + supportedDialects: + draft: ['3', '4'] + status: 'obsolete' + +- name: JSCK + toolingTypes: ['validator'] + languages: ['CoffeeScript'] + license: MIT + source: https://github.com/pandastrike/jsck + supportedDialects: + draft: ['3', '4'] + status: 'obsolete' + +- name: json_schema + toolingTypes: ['validator'] + languages: ['Dart'] + license: 'BSL-1.0' + source: https://github.com/patefacio/json_schema + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: Elixir JSON Schema validator + toolingTypes: ['validator'] + languages: ['Elixir'] + license: MIT + source: https://github.com/jonasschmidt/ex_json_schema + supportedDialects: + draft: ['4'] + toolingListingNotes: 'Draft-06+ progress: issue 24; branch multi-draft-support' + status: 'obsolete' + +- name: validate-json + toolingTypes: ['validator'] + languages: ['Go'] + license: GPL-2.0 + source: https://github.com/cesanta/validate-json + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: hjsonschema + toolingTypes: ['validator'] + languages: ['Haskell'] + license: MIT + source: https://github.com/seagreen/hjsonschema + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: json-schema-validator + toolingTypes: ['validator'] + languages: ['Java'] + license: 'LGPL-3.0' + source: https://github.com/java-json-tools/json-schema-validator + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: jsonschema + toolingTypes: ['validator'] + languages: ['JavaScript'] + license: MIT + source: https://github.com/tdegrunt/jsonschema + supportedDialects: + draft: ['4'] + toolingListingNotes: 'for Node.js' + status: 'obsolete' + +- name: tv4 + toolingTypes: ['validator'] + languages: ['JavaScript'] + license: 'MIT' + source: http://geraintluff.github.com/tv4/ + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: is-my-json-valid + toolingTypes: ['validator'] + languages: ['JavaScript'] + license: 'MIT' + source: https://github.com/mafintosh/is-my-json-valid + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: JaySchema + toolingTypes: ['validator'] + languages: ['JavaScript'] + license: 'BSD-3-Clause' + source: https://github.com/natesilva/jayschema + supportedDialects: + draft: ['4'] + toolingListingNotes: 'for Node.js' + status: 'obsolete' + +- name: z-schema + toolingTypes: ['validator'] + languages: ['JavaScript'] + license: 'MIT' + source: https://github.com/zaggino/z-schema + supportedDialects: + draft: ['4'] + toolingListingNotes: 'for Node.js' + status: 'obsolete' + +- name: direct-schema + toolingTypes: ['validator'] + languages: ['JavaScript'] + license: 'BSD-3-Clause' + source: http://github.com/IreneKnapp/direct-schema + supportedDialects: + draft: ['3'] + status: 'obsolete' + +- name: JSV + toolingTypes: ['validator'] + languages: ['JavaScript'] + license: 'BSD-3-Clause' + source: http://github.com/garycourt/JSV + supportedDialects: + draft: ['1', '2', '3'] + status: 'obsolete' + +- name: json-schema + toolingTypes: ['validator'] + languages: ['JavaScript'] + license: 'BSD-3-Clause' + source: https://github.com/kriszyp/json-schema + supportedDialects: + draft: ['4'] + toolingListingNotes: 'part of the [Persevere](http://github.com/kriszyp/json-schema) project' + status: 'obsolete' + +- name: schema.js + toolingTypes: ['validator'] + languages: ['JavaScript'] + license: 'MIT' + source: https://github.com/akidee/schema.js + supportedDialects: + draft: ['2'] + status: 'obsolete' + +- name: json-gate + toolingTypes: ['validator'] + languages: ['JavaScript'] + license: 'MIT' + source: https://github.com/oferei/json-gate + supportedDialects: + draft: ['3'] + status: 'obsolete' + +- name: JSEN + toolingTypes: ['validator'] + languages: ['JavaScript'] + license: 'MIT' + source: https://github.com/bugventure/jsen + supportedDialects: + draft: ['3'] + toolingListingNotes: 'for Node.js' + status: 'obsolete' + +- name: Skeemas + toolingTypes: ['validator'] + languages: ['JavaScript'] + license: 'MIT' + source: https://github.com/ericgj/json-schema-valid + supportedDialects: + draft: ['3', '4'] + status: 'obsolete' + +- name: Jassi + toolingTypes: ['validator'] + languages: ['JavaScript'] + license: 'GPL-3.0' + source: https://github.com/iclanzan/jassi + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: json-schema-valid + toolingTypes: ['validator'] + languages: ['JavaScript'] + license: 'MIT' + source: https://github.com/ericgj/json-schema-valid + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: jsv4-php + toolingTypes: ['validator'] + languages: ['PHP'] + license: 'MIT' + source: https://github.com/geraintluff/jsv4-php + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: JVal + toolingTypes: ['validator'] + languages: ['PHP'] + license: 'MIT' + source: https://github.com/stefk/jval + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: JSON Guard + toolingTypes: ['validator'] + languages: ['PHP'] + license: 'MIT' + source: https://github.com/thephpleague/json-guard + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: JSV::Validator + toolingTypes: ['validator'] + languages: ['Perl'] + license: MIT + source: https://metacpan.org/module/JSV::Validator + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: postgres-json-schema + toolingTypes: ['validator'] + languages: ['PostgreSQL'] + license: 'PostgreSQL' + source: https://github.com/gavinwahl/postgres-json-schema + supportedDialects: + draft: ['4'] + toolingListingNotes: 'PL/pgSQL implementation, no remote (http) references' + status: 'obsolete' + +- name: json_schema + toolingTypes: ['validator'] + languages: ['Ruby'] + license: MIT + source: https://github.com/brandur/json_schema + supportedDialects: + draft: ['4'] + toolingListingNotes: 'Schema parser and validator, with hyper-schema support' + status: 'obsolete' + +- name: json-schema + toolingTypes: ['validator'] + languages: ['Ruby'] + license: MIT + source: https://github.com/hoxworth/json-schema + supportedDialects: + draft: ['1', '2', '3', '4'] + status: 'obsolete' + +- name: valico + toolingTypes: ['validator'] + languages: ['Rust'] + license: MIT + source: https://github.com/rustless/valico + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: json-schema-parser + toolingTypes: ['validator'] + languages: ['Scala'] + license: Apache-2.0 + source: https://github.com/VoxSupplyChain/json-schema-parser + supportedDialects: + draft: ['4'] + toolingListingNotes: 'Schema parser and validator' + status: 'obsolete' + +- name: JSONSchema + toolingTypes: ['validator'] + languages: ['Swift'] + license: BSD-3-Clause + source: https://github.com/kylef/JSONSchema.swift + supportedDialects: + draft: ['4'] + status: 'obsolete' + +- name: 'JSL' + description: 'a Python DSL for defining JSON Schemas' + toolingTypes: [code-to-schema] + languages: ['Python'] + license: 'BSD-3-Clause' + source: 'https://github.com/aromanovich/jsl' + status: 'obsolete' + +- name: 'json-schema-generator' + description: 'Node.js library usable both as a CLI util and as a Node module' + toolingTypes: [code-to-schema] + languages: ['JavaScript'] + license: 'MIT' + source: 'https://github.com/krg7880/json-schema-generator' + status: 'obsolete' + +- name: 'Typson' + toolingTypes: ['code-to-schema'] + languages: ['TypeScript'] + source: 'https://github.com/lbovet/typson' + license: 'Apache-2.0' + status: 'obsolete' + +- name: 'JSON Schema Generator' + description: 'Free extension' + toolingTypes: ['code-to-schema', 'editor-plugins'] + homepage: 'https://visualstudiogallery.msdn.microsoft.com/b4515ef8-a518-41ca-b48c-bb1fd4e6faf7' + status: 'obsolete' + +- name: 'API-Add-In' + description: 'Sparx EA extension for exporting JSON Schema from UML models' + toolingTypes: ['code-to-schema'] + source: 'https://github.com/bayeslife/api-add-in' + status: 'obsolete' + +- name: 'json-schema-generator' + description: 'JSON-Schema + fake data generators' + toolingTypes: ['schema-to-data'] + languages: ['JavaScript'] + source: 'https://github.com/json-schema-faker' + license: 'MIT' + status: 'obsolete' + +- name: 'DJsonSchema' + description: 'JSON Schema reader and code generator for Delphi' + toolingTypes: ['schema-to-code'] + languages: ['Delphi'] + source: 'https://github.com/schlothauer-wauer/DJsonSchema' + license: 'MIT' + status: 'obsolete' + +- name: 'aeson-schema' + description: 'Generates code for a parser' + toolingTypes: ['schema-to-code'] + languages: ['Haskell'] + source: 'https://github.com/Fuuzetsu/aeson-schema' + license: 'MIT' + status: 'obsolete' + +- name: 'autoparse' + toolingTypes: ['schema-to-code'] + languages: ['Ruby'] + source: 'https://github.com/google/autoparse' + license: 'Apache-2.0' + status: 'obsolete' + +- name: 'json-schema-codegen' + description: 'Tool and SBT plugin for generating Scala, TypeScript models and parsers from JSON-Schema definitions, supports draft 4' + toolingTypes: ['schema-to-code'] + languages: ['Scala'] + source: 'https://github.com/VoxSupplyChain/json-schema-codegen' + license: 'Apache-2.0' + status: 'obsolete' + +- name: 'Argus' + description: 'Macros for building models from JSON Schemas' + toolingTypes: ['schema-to-code'] + languages: ['Scala'] + source: 'https://github.com/aishfenton/argus' + license: 'MIT' + status: 'obsolete' + +- name: 'Bric-à-brac' + description: 'Generates idiomatic swift structs and parser/serializer from JSON schemas' + toolingTypes: ['schema-to-code'] + languages: ['Swift'] + source: 'https://github.com/glimpseio/BricBrac' + license: 'MIT' + status: 'obsolete' + +- name: 'gojsonschema' + description: 'Golang package for generating Golang structs, support for Draft 4. [Demo](http://json.golang.chinazt.cc)' + toolingTypes: ['schema-to-code'] + languages: ['Go'] + source: 'https://github.com/andy-zhangtao/gojsonschema' + homepage: 'http://json.golang.chinazt.cc' + license: 'Apache-2.0' + status: 'obsolete' + +- name: 'JSON Editor' + toolingTypes: ['schema-to-web-UI'] + languages: ['JavaScript'] + source: 'https://github.com/jdorn/json-editor' + license: 'MIT' + status: 'obsolete' + +- name: 'JSONForms' + description: 'Developed by EclipseSource' + toolingTypes: ['schema-to-web-UI'] + languages: ['JavaScript'] + homepage: 'https://jsonforms.io' + license: 'MIT' + status: 'obsolete' + +- name: 'Jsonary' + toolingTypes: ['schema-to-web-UI'] + languages: ['JavaScript'] + homepage: 'https://jsonary.com/' + license: 'MIT' + status: 'obsolete' + +- name: 'Metawidget' + toolingTypes: ['schema-to-web-UI'] + languages: ['JavaScript'] + homepage: 'https://metawidget.org/' + license: 'LGPL-2.1' + status: 'obsolete' + +- name: 'pure-form webcomponent' + toolingTypes: ['schema-to-web-UI'] + languages: ['JavaScript'] + source: 'https://github.com/john-doherty/pure-form' + license: 'MIT' + status: 'obsolete' + +- name: 'Liquid XML Studio 2016' + description: 'Graphical JSON schema editor for draft 4, context-sensitive IntelliSense for JSON documents' + toolingTypes: ['editor'] + homepage: 'https://www.liquid-technologies.com/json-schema-editor' + status: 'obsolete' + +- name: 'ReSharper 2016.1' + description: 'Code completion, inspections, and quick fixes for JSON schema in Visual Studio 2010 - 2015, including support for JSON Path and regular expressions for schema editing. Supports draft-4' + toolingTypes: ['editor'] + homepage: 'https://www.jetbrains.com/resharper/' + status: 'obsolete' + +- name: 'Visual Studio 2013' + description: 'Auto-completion and tooltips based on JSON schema draft 3 and draft 4' + toolingTypes: ['editor'] + homepage: 'http://www.visualstudio.com/' + status: 'obsolete' + +- name: 'JSON Schema Editor' + description: 'An intuitive editor for JSON schema online' + toolingTypes: ['editor'] + homepage: 'https://json-schema-editor.tangramjs.com' + status: 'obsolete' + +- name: 'JSON Editor (Tangram)' + description: 'An online, schema-aware editor for JSON document' + toolingTypes: ['editor'] + homepage: 'https://json-editor.tangramjs.com' + status: 'obsolete' + +- name: 'JSON Schema Compatibility' + description: 'Converts draft 3 to draft 4' + toolingTypes: ['util-draft-migration'] + languages: ['JavaScript'] + source: 'https://github.com/geraintluff/json-schema-compatability' + license: 'CC0-1.0' + status: 'obsolete' + +- name: 'Matic' + toolingTypes: ['documentation'] + languages: ['JavaScript'] + source: 'https://github.com/mattyod/matic' + license: 'MIT' + status: 'obsolete' + +- name: 'Docson' + toolingTypes: ['documentation'] + languages: ['JavaScript'] + source: 'https://github.com/lbovet/docson' + license: 'Apache-2.0' + status: 'obsolete' + +- name: 'doca' + description: 'See @cloudflare/doca for draft-06+ support' + toolingTypes: ['documentation'] + languages: ['JavaScript'] + source: 'https://github.com/cloudflare/doca/' + license: 'BSD-2-Clause' + status: 'obsolete' + +- name: 'prmd' + toolingTypes: ['documentation'] + languages: ['JavaScript'] + source: 'https://github.com/interagent/prmd' + license: 'MIT' + status: 'obsolete' + +- name: 'Dojo' + description: 'Supports some aspects of JSON Schema' + toolingTypes: ['util-general-processing'] + languages: ['JavaScript'] + homepage: 'https://www.dojotoolkit.org/' + license: 'AFL-2.1 OR BSD-3-Clause' + status: 'obsolete' + +- name: 'JSON Schema Random' + toolingTypes: ['schema-to-data'] + languages: ['JavaScript'] + source: 'https://github.com/andreineculau/json-schema-random' + license: 'Apache-2.0' + status: 'obsolete' + +- name: Jaronuinga + description: > + Jaronuinga is a simple JSON Schema validator written in Java 17. It is based on JSONP 1.1 and has no other dependencies. + The library's primary purpose is to intercept the parsing process for additional custom analysis (e.g., verifying "foreign keys" on data submission). + It may also be used for schema analysis via `getParent()` and `getChildren()` methods. + toolingTypes: ['validator'] + languages: ['Java'] + maintainers: + - name: 'Dmitry Repchevsky' + username: 'Dmitry Repchevsky' + platform: 'github' + license: 'LGPL 2.1 or later' + source: 'https://github.com/elixir-europe/java-json-schema-validator' + supportedDialects: + draft: ['4', '6', '7', '2019-09', '2020-12'] + lastUpdated: '2024-10-01' + +- name: protoc-gen-jsonschema + description: 'JsonSchema generator plugin for Google Protocol Buffers' + toolingTypes: ['model-to-schema'] + languages: ['Protocol Buffers'] + maintainers: + - name: 'Uanid' + username: 'uanid' + platform: 'github' + license: 'Apache-2.0' + source: 'https://github.com/pubg/protoc-gen-jsonschema' + supportedDialects: + draft: ['4', '6', '7', '2019-09', '2020-12'] + +- name: swift-json-schema + description: 'swift-json-schema support generating JSON schema using Swift result builders or from Swift types directly using macros.' + environments: ['macOS', 'iOS', 'tvOS', 'watchOS', 'visionOS', 'Linux'] + toolingTypes: ['validator', 'code-to-schema', 'model-to-schema'] + languages: ['Swift'] + maintainers: + - name: 'Austin Evans' + username: 'ajevans99' + platform: 'github' + license: 'MIT' + source: 'https://github.com/ajevans99/swift-json-schema' + supportedDialects: + draft: ['2020-12'] + +- name: 'Liquid JSON Schema Editor' + description: 'Graphical JSON Schema editor for draft-04, draft-06, draft-07, 2019-09 and 2020-12, with split source code and graphical editing. Includes validation of JSON files based on JSON Schema, JSON Sample Generator and JSON Schema Documentation Generator.' + toolingTypes: ['validator', 'documentation', 'editor'] + languages: ['C#', '.NET'] + environments: ['Microsoft Windows'] + maintainers: + - name: 'Liquid Technologies Ltd' + platform: 'other' + creators: + - name: 'Liquid Technologies Ltd' + platform: 'other' + homepage: 'https://www.liquid-technologies.com/json-schema-editor' + license: 'Proprietary and Freeware' + supportedDialects: + draft: ['4', '6', '7', '2019-09', '2020-12'] + +- name: 'JSON Schema Editor' + description: 'The JSON schema editor provides an easy UI for building JSON Schema. In addition, users can convert their json schema into SQL, GraphQL, and Protocol Buffers formats. Lastly this tool allows users to generate sample data that conforms to the json schema they have defined.' + toolingTypes: ['editor'] + maintainers: + - name: 'robclarabase' + username: 'robclarabase' + platform: 'github' + license: 'MIT' + source: 'https://github.com/Clarabase/json-schema-editor' + homepage: 'https://json-schema-editor.onrender.com/' + supportedDialects: + draft: ['2020-12'] + +- name: JSV + description: 'A generic JSON Schema validator for Elixir' + environments: ['Linux', 'MacOS', 'Windows','Embedded platform'] + toolingTypes: ['validator'] + languages: ['Elixir', 'Erlang'] + maintainers: + - name: 'Ludovic Demblans' + username: 'lud' + platform: 'github' + license: 'MIT' + source: 'https://github.com/lud/jsv' + homepage: 'https://hex.pm/packages/jsv' + supportedDialects: + draft: ['2020-12', '7'] + toolingListingNotes: 'JSON Schema Validation for Elixir according to the latest specifications. Supports compile-time schema builds, custom dialects and custom formats.' + +- name: '@imhonglu/json-schema' + description: 'The tool supports static type inference for schema definitions and ensures validation based on the JSON-Schema-test-suite.' + toolingTypes: ['validator'] + languages: ['TypeScript'] + maintainers: + - name: 'Beom-Ku Jung' + username: 'imhonglu' + platform: 'github' + license: 'MIT' + source: 'https://github.com/imhonglu/new-wheels/tree/main/libs/json-schema' + homepage: 'https://github.com/imhonglu/new-wheels/tree/main/libs/json-schema' + supportedDialects: + draft: ['2020-12'] + toolingListingNotes: 'Built for Node.js and browsers, it supports static type inference for schema definitions.' diff --git a/data/validator-libraries-obsolete.yml b/data/validator-libraries-obsolete.yml deleted file mode 100644 index 127fb16e6..000000000 --- a/data/validator-libraries-obsolete.yml +++ /dev/null @@ -1,250 +0,0 @@ -- name: .NET - anchor-name: dotnet - implementations: - - name: NJsonSchema - url: http://NJsonSchema.org - date-draft: [] - draft: [4] - license: Ms-PL - - name: Manatee.Json - url: https://github.com/gregsdennis/Manatee.Json - date-draft: [2019-09] - draft: [7, 6, 4] - license: MIT -- name: C - implementations: - - name: WJElement - url: https://github.com/netmail-open/wjelement - date-draft: [] - draft: [4, 3] - license: LGPL-3.0 - notes: "Draft-06+ progress: issue [17](https://github.com/netmail-open/wjelement/issues/17#issuecomment-390899432)" -- name: C++ - anchor-name: cpp - implementations: - - name: wjelement-cpp - url: https://github.com/petehug/wjelement-cpp - date-draft: [] - draft: [4] - license: LGPLv3 - - name: Header-only C++ library for JSON Schema validation - url: https://github.com/tristanpenman/valijson - date-draft: [] - draft: [4, 3] - license: BSD-2-Clause - - name: Modern C++ JSON schema validator - url: https://github.com/pboettch/json-schema-validator - notes: "based on JSON for Modern C++" - date-draft: [] - draft: [4] - license: "MIT" -- name: Clojure - implementations: - - name: scjsv - url: https://github.com/metosin/scjsv - notes: "(wrapper for [java-json-tools/json-schema-validator](https://github.com/java-json-tools/json-schema-validator))" - date-draft: [] - draft: [4] - license: Eclipse Public License v1.0 - - name: json-schema validator - url: https://github.com/tatut/json-schema - date-draft: [] - draft: [3, 4] - license: MIT -- name: CoffeeScript - implementations: - - name: JSCK - url: https://github.com/pandastrike/jsck - date-draft: [] - draft: [4, 3] - license: MIT -- name: Dart - implementations: - - name: json_schema - url: https://github.com/patefacio/json_schema - date-draft: [] - draft: [4] - license: BSL-1.0 -- name: Elixir - implementations: - - name: Elixir JSON Schema validator - url: https://github.com/jonasschmidt/ex_json_schema - date-draft: [] - draft: [4] - notes: "Draft-06+ progress: issue [24](https://github.com/jonasschmidt/ex_json_schema/issues/24); branch [multi-draft-support](https://github.com/jonasschmidt/ex_json_schema/tree/multi-draft-support)" - license: MIT -- name: Go - implementations: - - name: validate-json - url: https://github.com/cesanta/validate-json - date-draft: [] - draft: [4] - license: GPLv2 -- name: Haskell - implementations: - - name: hjsonschema - url: https://github.com/seagreen/hjsonschema - date-draft: [] - draft: [4] - license: MIT -- name: Java - implementations: - - name: json-schema-validator - url: https://github.com/java-json-tools/json-schema-validator - date-draft: [] - draft: [4] - license: LGPLv3 -- name: JavaScript - implementations: - - name: jsonschema - url: https://github.com/tdegrunt/jsonschema - notes: "for Node.js" - date-draft: [] - draft: [4] - license: MIT - - name: tv4 - url: http://geraintluff.github.com/tv4/ - date-draft: [] - draft: [4] - license: Public Domain, MIT - - name: is-my-json-valid - url: https://github.com/mafintosh/is-my-json-valid - date-draft: [] - draft: [4] - license: MIT - - name: JaySchema - url: https://github.com/natesilva/jayschema - notes: "for Node.js" - date-draft: [] - draft: [4] - license: BSD - - name: z-schema - url: https://github.com/zaggino/z-schema - notes: "for Node.js" - date-draft: [] - draft: [4] - license: MIT - - name: direct-schema - url: http://github.com/IreneKnapp/direct-schema - date-draft: [] - draft: [3] - license: "BSD" - - name: JSV - url: http://github.com/garycourt/JSV - date-draft: [] - draft: [1, 2, 3] - license: "BSD" - - name: json-schema - url: https://github.com/kriszyp/json-schema - date-draft: [] - draft: [4] - notes: "part of the [Persevere](http://github.com/kriszyp/json-schema) project" - license: AFL, BSD - - name: schema.js - url: https://github.com/akidee/schema.js - date-draft: [] - draft: [2] - license: "MIT" - - name: json-gate - url: https://github.com/oferei/json-gate - date-draft: [] - draft: [3] - license: "MIT" - - name: JSEN - url: https://github.com/bugventure/jsen - notes: "for Node.js" - date-draft: [] - draft: [4] - license: "MIT" - - name: Skeemas - url: https://github.com/ericgj/json-schema-valid - date-draft: [] - draft: [3, 4] - license: MIT - - name: Jassi - url: https://github.com/iclanzan/jassi - date-draft: [] - draft: [4] - license: GPLv3 - - name: json-schema-valid - url: https://github.com/ericgj/json-schema-valid - date-draft: [] - draft: [4] - license: MIT -- name: PHP - implementations: - - name: json-schema - url: https://github.com/justinrainbow/json-schema - date-draft: [] - draft: [4, 3] - license: "Berkeley" - - name: jsv4-php - url: https://github.com/geraintluff/jsv4-php - date-draft: [] - draft: [4] - license: Public Domain, MIT - - name: JVal - url: https://github.com/stefk/jval - date-draft: [] - draft: [4] - license: "MIT" - - name: JSON Guard - url: https://github.com/thephpleague/json-guard - date-draft: [] - draft: [4] - license: "MIT" - - name: Swaggest Json Schema - url: https://github.com/swaggest/php-json-schema - date-draft: [] - draft: [4] - license: "MIT" -- name: Perl - implementations: - - name: JSV::Validator - url: https://metacpan.org/module/JSV::Validator - date-draft: [] - draft: [4] - license: "MIT" -- name: PostgreSQL - implementations: - - name: postgres-json-schema - url: https://github.com/gavinwahl/postgres-json-schema - notes: "PL/pgSQL implementation, no remote (http) references" - date-draft: [] - draft: [4] - license: PostgreSQL -- name: Ruby - implementations: - - name: json_schema - url: https://github.com/brandur/json_schema - notes: "Schema parser and validator, with hyper-schema support" - date-draft: [] - draft: [4] - license: MIT - - name: json-schema - url: https://github.com/hoxworth/json-schema - date-draft: [] - draft: [4, 3, 2, 1] - license: MIT -- name: Rust - implementations: - - name: valico - url: https://github.com/rustless/valico - date-draft: [] - draft: [4] - license: MIT -- name: Scala - implementations: - - name: json-schema-parser - url: https://github.com/VoxSupplyChain/json-schema-parser - notes: "Schema parser and validator" - date-draft: [] - draft: [4] - license: Apache 2.0 -- name: Swift - implementations: - - name: JSONSchema - url: https://github.com/kylef/JSONSchema.swift - date-draft: [] - draft: [4] - license: BSD-3-Clause diff --git a/lib/getPartsOfJson.ts b/lib/getPartsOfJson.ts index ace72790e..d8b741ccb 100644 --- a/lib/getPartsOfJson.ts +++ b/lib/getPartsOfJson.ts @@ -366,21 +366,30 @@ const getPartsOfArrayContent = ( const length = match.index - arrayPayloadIndex; const payload = serializedJson.substr(arrayPayloadIndex, length); - //ToDo filter brackets in strings + const stringMatches = getFindResultsByGlobalRegExp(payload, regexString); + let filteredPayload = payload; + + // Replace content of strings with placeholders to avoid counting brackets inside them + stringMatches.forEach((stringMatch) => { + const stringContent = stringMatch.match; + const placeholder = '_'.repeat(stringContent.length); + filteredPayload = filteredPayload.replace(stringContent, placeholder); + }); + const countOpenCurlyBracketsInPayload = getFindResultsByGlobalRegExp( - payload, + filteredPayload, /\{/g, ).length; const countClosedCurlyBracketsInPayload = getFindResultsByGlobalRegExp( - payload, + filteredPayload, /\}/g, ).length; const countOpenSquaredBracketsInPayload = getFindResultsByGlobalRegExp( - payload, + filteredPayload, /\[/g, ).length; const countClosedSquaredBracketsInPayload = getFindResultsByGlobalRegExp( - payload, + filteredPayload, /\]/g, ).length; const openCurlyBrackets = diff --git a/package.json b/package.json index 907665250..662304e73 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@docsearch/react": "3.8.0", "@types/jsonpath": "^0.2.4", "axios": "1.7.7", - "babel-loader": "^9.1.3", + "babel-loader": "^9.2.1", "classnames": "^2.5.1", "feed": "^4.2.2", "file-saver": "^2.0.5", @@ -38,18 +38,18 @@ "js-yaml": "^4.1.0", "jsonpath": "^1.1.1", "jszip": "^3.10.1", - "markdown-to-jsx": "^7.6.2", + "markdown-to-jsx": "^7.7.3", "moment": "2.30.1", "next": "14.2.14", "next-sitemap": "^4.2.3", - "next-themes": "^0.3.0", - "node-ical": "0.19.0", + "next-themes": "^0.4.4", + "node-ical": "0.20.1", "react": "18.3.1", "react-dom": "18.3.1", "react-syntax-highlighter": "^15.6.1", "react-text-truncate": "^0.19.0", "reading-time": "^1.5.0", - "slate": "^0.110.2", + "slate": "^0.112.0", "slate-react": "^0.108.0", "slugify": "^1.6.5", "yarn": "1.22.22", @@ -66,7 +66,7 @@ "@types/babel__preset-env": "^7", "@types/file-saver": "^2.0.7", "@types/js-yaml": "^4.0.5", - "@types/node": "^22.4.2", + "@types/node": "^22.10.10", "@types/react": "18.3.5", "@types/react-syntax-highlighter": "^15.5.13", "@types/react-text-truncate": "^0.19.0", diff --git a/pages/[slug].page.tsx b/pages/[slug].page.tsx index 4bd646418..7a9e7726e 100644 --- a/pages/[slug].page.tsx +++ b/pages/[slug].page.tsx @@ -7,6 +7,7 @@ import getStaticMarkdownProps from '~/lib/getStaticMarkdownProps'; import { Headline1 } from '~/components/Headlines'; import { SectionContext } from '~/context'; import { DocsHelp } from '~/components/DocsHelp'; +import NextPrevButton from '~/components/NavigationButtons'; export async function getStaticPaths() { return getStaticMarkdownPaths('pages'); @@ -22,7 +23,7 @@ export default function StaticMarkdownPage({ frontmatter: any; content: any; }) { - const markdownFile = '_index'; + const fileRenderType = '_md'; const newTitle = 'JSON Schema - ' + frontmatter.title; return ( @@ -31,7 +32,13 @@ export default function StaticMarkdownPage({ {frontmatter.title} - + + ); } diff --git a/pages/blog/index.page.tsx b/pages/blog/index.page.tsx index 67aaf5e74..1fd6c34ed 100644 --- a/pages/blog/index.page.tsx +++ b/pages/blog/index.page.tsx @@ -9,8 +9,8 @@ const PATH = 'pages/blog/posts'; import TextTruncate from 'react-text-truncate'; import generateRssFeed from './generateRssFeed'; import { useRouter } from 'next/router'; -import useSetUrlParam from '~/lib/useSetUrlParam'; import { SectionContext } from '~/context'; +import Image from 'next/image'; type Author = { name: string; @@ -64,6 +64,7 @@ function isValidCategory(category: any): category is blogCategories { 'Engineering', 'Update', 'Opinion', + 'Documentation', ].includes(category); } @@ -75,7 +76,6 @@ export default function StaticMarkdownPage({ filterTag: any; }) { const router = useRouter(); - const setParam = useSetUrlParam(); const [currentFilterTag, setCurrentFilterTag] = useState( filterTag || 'All', ); @@ -92,36 +92,17 @@ export default function StaticMarkdownPage({ setCurrentFilterTag(filterTag); }, [filterTag]); - const handleClick = (event: { currentTarget: { value: any } }) => { - const clickedTag = event.currentTarget.value; - setParam('type', clickedTag); - + const handleClick = (event: React.MouseEvent) => { + event.preventDefault(); // Prevent default scrolling behavior + const clickedTag = event.currentTarget.value as blogCategories; if (clickedTag === 'All') { - setParam('type', null); - } else { - setCurrentFilterTag(clickedTag); - } - - // Check if the user is already on the "/blog" page - if (router.pathname === '/blog') { - if (router.query.type) { - // Remove the 'type' query parameter from the URL - setParam( - 'type', - router.query.type === clickedTag ? undefined : clickedTag, - ); - } + setCurrentFilterTag('All'); + history.replaceState(null, '', '/blog'); // Update the URL without causing a scroll + } else if (isValidCategory(clickedTag)) { setCurrentFilterTag(clickedTag); - } else { - // If not on the "/blog" page, navigate to the "/blog" page with the type tag as a query parameter - router.replace( - { pathname: '/blog', query: { type: clickedTag } }, - undefined, - { shallow: true }, - ); + history.replaceState(null, '', `/blog?type=${clickedTag}`); // Update URL } }; - const recentBlog = blogPosts.sort((a, b) => { const dateA = new Date(a.frontmatter.date).getTime(); const dateB = new Date(b.frontmatter.date).getTime(); @@ -145,8 +126,10 @@ export default function StaticMarkdownPage({ {recentBlog[0] && (
- hero image example @@ -210,7 +193,13 @@ export default function StaticMarkdownPage({ href='/rss/feed.xml' className='flex items-center text-blue-500 hover:text-blue-600 cursor-pointer' > - + rss RSS Feed
@@ -274,10 +263,18 @@ export default function StaticMarkdownPage({ onClick={(e) => { e.preventDefault(); e.stopPropagation(); - setParam('type', frontmatter.type); + + if (frontmatter.type) { + setCurrentFilterTag(frontmatter.type); + history.replaceState( + null, + '', + `/blog?type=${frontmatter.type}`, + ); + } }} > - {frontmatter.type} + {frontmatter.type || 'Unknown Type'}
diff --git a/pages/blog/posts/[slug].page.tsx b/pages/blog/posts/[slug].page.tsx index 5f9615ffd..14301176d 100644 --- a/pages/blog/posts/[slug].page.tsx +++ b/pages/blog/posts/[slug].page.tsx @@ -12,6 +12,7 @@ import readingTime from 'reading-time'; import { Headline1 } from '~/components/Headlines'; import { SectionContext } from '~/context'; import CarbonAds from '~/components/CarbonsAds'; +import Image from 'next/image'; export async function getStaticPaths() { return getStaticMarkdownPaths('pages/blog/posts'); @@ -60,7 +61,13 @@ export default function StaticMarkdownPage({ href='/blog' className='font-semibold text-sm pb-0 lg:pb-5 text-slate-700 dark:text-slate-300 dark:hover:text-slate-100 hover:text-slate-800 inline-flex flex-row items-center' > - {' '} + Left arrow icon Go back to blog
diff --git a/pages/blog/posts/gsoc24-wrapup.md b/pages/blog/posts/gsoc24-wrapup.md new file mode 100644 index 000000000..4a17a35e4 --- /dev/null +++ b/pages/blog/posts/gsoc24-wrapup.md @@ -0,0 +1,112 @@ +--- +title: "Celebrating JSON Schema’s Google Summer of Code 2024 Journey" +date: "2025-01-17" +tags: + - News +type: Community +cover: /img/posts/2025/gsoc24/gsoc24-banner-main.png +authors: + - name: Onyedikachi Hope Amaechi-Okorie + photo: /img/avatars/onyedikachi.jpg + link: https://www.linkedin.com/in/amaechihope/ + byline: Community and Developer Relations Manager +excerpt: "Discover the projects, mentors, and contributors that shaped Google Summer of Code (GSoC) 2024!" +--- + +Last year, JSON Schema proudly participated in Google Summer of Code (GSoC) 2024, a global program designed to bring fresh talent into open-source communities. Through this initiative, we tackled some of our most exciting projects yet, creating opportunities for contributors to make meaningful impacts while gaining valuable experience. + +We’re thrilled to share the highlights of this journey and the incredible work our contributors and mentors achieved together. + +## A Unique Start: Setting the Stage for Success +For JSON Schema, GSoC 2024 wasn’t just about welcoming contributors but about setting a high standard. Before selection, applicants underwent a qualification test, allowing us to assess technical skills and alignment with project goals. This ensured each participant had the tools and mindset to thrive. + +Here’s what stood out in our journey: + +* 8 projects completed across diverse aspects of JSON Schema. +* A record number of applicants, with a community brimming with enthusiasm. +* Returning mentors and contributors, bringing experience and new perspectives. + +## Transformative Projects and Talent Contributors + +### 1. Bowtie-Trend: Long-Term Reporting With Bowtie + +* Contributor: [Adwait Godbole](https://github.com/adwait-godbole) +* Mentors: [Julian Berman](https://github.com/Julian), [Agnivesh Chaubey](https://github.com/AgniveshChaubey) +* [Idea on GitHub](https://github.com/json-schema-org/community/issues/607) + +The project aims to enhance [Bowtie](https://github.com/bowtie-json-schema/bowtie), a meta-validator for the JSON Schema specification that coordinates the execution of validator implementations and reports their results. While Bowtie already generates compliance reports accessible [here](https://bowtie.report), this project introduces a mechanism to track compliance metrics over time. The goal is to enable graphing and querying of how test results evolve as implementations fix bugs or new tests are added. Key outcomes include a new bowtie trend command to aggregate results into trend reports and a dedicated webpage displaying graphs of failed tests over time, providing deeper insights into long-term compliance trends. + +### 2. Bowtie-Perf: A Performance Tester for JSON Schema Implementations + +* Contributor: [Dhruv Singh](https://github.com/sudo-jarvis) +* Mentors: [Julian Berman](https://github.com/Julian), [Agnivesh Chaubey](https://github.com/AgniveshChaubey) +* [Idea on Github](https://github.com/json-schema-org/community/issues/605) + +The project enhances [Bowtie](https://github.com/bowtie-json-schema/bowtie), a meta-validator of the JSON Schema specification. Bowtie provides universal access to JSON Schema implementations, enabling users to validate instances and identify bugs or gaps in functionality. Currently, Bowtie supports validating instances against schemas and comparing implementations based on correctness. This project expands its capabilities by developing a performance tester integrated within Bowtie. This addition provides a critical dimension for performance optimization and enables more comprehensive comparisons across JSON Schema implementations. + +### 3. Setting up the CI/CD Pipeline for the JSON Schema Website + +* Contributor: [Alok Gupta](https://github.com/aialok) +* Mentor: [Benjamin Granados](https://github.com/benjagm) +* [Idea on Github](https://github.com/json-schema-org/community/issues/603) + +The Improved CI/CD Workflow for the [website](https://github.com/json-schema-org/website) project with GitHub Actions project focuses on enhancing the existing CI/CD pipelines by adding essential features like linting, formatting, unit testing, UI testing, broken link checks, and build processes. The project involves streamlining workflows for pull requests, pushes, and issues, with special emphasis on first-time contributors. Key deliverables include creating and optimizing workflows such as PR workflows, push workflows, issue workflows, stale issue and PR reminders, unauthorized file detection, and CodeQL for security analysis. Additionally, the project aims to provide clear documentation on workflow roles and guidelines for updates, ensuring smoother community operation integration and more efficient code management. + +### 4. Building a New Version of the JSON Schema Tooling Page + +* Contributor: [DV](http://github.com/darhkvoyd) +* Mentor: [Benjamin Granados](https://github.com/benjagm) +* [Idea on Github](https://github.com/json-schema-org/community/issues/602) + +The JSON Schema [Tooling Page](https://json-schema.org/tools) plays a vital role in helping developers explore the ecosystem of JSON Schema tools and implementations. However, its current design presents usability challenges that hinder adoption. This project aims to rebuild the tooling page using a data-driven approach while adhering to the updated UI/UX standards of the JSON Schema website. By improving accessibility, simplifying navigation, and enhancing clarity, the revamped tooling page will make JSON Schema implementations more discoverable and user-friendly, ultimately reducing friction and encouraging broader adoption within the developer community. + +### 5. JSON Schema Language Server Contributions + +* Contributor: [Diya Solanki](https://github.com/diyaayay) +* Mentor: [Jason Desrosiers](https://github.com/jdesrosiers) +* [Idea on Github](https://github.com/json-schema-org/community/issues/601) + +The project focuses on enhancing the [Language Server Protocol (LSP)](https://github.com/hyperjump-io/json-schema-language-tools) for JSON Schema, enabling improved support for various editors and IDEs. Unlike the existing VSCode integration, which lacks support for recent JSON Schema versions and struggles with performance for large schemas, this project aims to expand functionality. Key improvements include inline diagnostics for invalid schemas, semantic highlighting for JSON Schema and deprecated keywords, support for multiple drafts (04/06/07/2019-09/2020-12), and enhanced configuration management. The project also focuses on adding code completion for $schema, making JSON Schema development more efficient and accessible across platforms. + +### 6. Define Upgrade/Downgrade Language-Agnostic Declarative Transformation Rules for all JSON Schema Dialects + +* Contributor: [Suprith KG](https://github.com/suprith-hub) +* Mentor: [Juan Cruz Viotti](https://github.com/jviotti) +* [Idea on Github](https://github.com/json-schema-org/community/issues/599) + +The project addresses the challenges of maintaining software compatibility across different schema versions. It focuses on creating declarative, language-agnostic rules to streamline the process of [upgrading or downgrading JSON Schemas](https://github.com/json-schema-org/upgrade-downgrade-rules). This is crucial for users working with high-level languages like Python, managing large documents, or navigating diverse network communication setups such as HTTP, WebSocket, microservices, or IoT. By simplifying schema transformations and introducing standardized procedures, this project aims to save time, ensure reliability, and improve JSON Schema’s versatility across various implementations and use cases. + +### 7. Source Generation Analyzer Powered by Corvus.JsonSchema (.NET) + +* Contributor: [Pranay Joshi](https://github.com/pranayjoshi) +* Mentors: [Matthew Adams (Endjin)](https://github.com/mwadams), [Greg Dennis](https://github.com/gregsdennis) +* [Idea on Github](https://github.com/json-schema-org/community/issues/614) + +The project focuses on creating a source generator that integrates seamlessly with [Corvus.JsonSchema](https://github.com/corvus-dotnet/corvus.jsonschema). This tool will automatically generate code from JSON Schema files within a .NET project at compile time, streamlining the development process. The ultimate goal is to foster collaboration and consistency across software development teams using diverse technology stacks by establishing JSON Schema as a unified source of truth for data modeling. This ensures that generated code adheres to a standardized data structure, improving efficiency and alignment within organizations. + +### 8. A Tour of JSON Schema + +* Contributor: [Zeel Rajodiya](https://github.com/JeelRajodiya) +* Mentors: [Bence Eros](https://github.com/erosb), [Benjamin Granados](https://github.com/benjagm) +* [Idea on Github](https://github.com/json-schema-org/community/issues/645) + +The [Tour of JSON Schema](https://github.com/json-schema-org/tour) project is an interactive learning platform designed to help beginners quickly grasp JSON Schema concepts and best practices. Through step-by-step lessons and hands-on exercises, users can learn by doing, using a simple interface and built-in code editor. The platform provides practical examples, real-time validation of JSON Schema, and immediate feedback, making the learning process engaging and effective. By following structured lessons, users will gain the confidence to create and work with JSON Schemas independently. + +## Mentorship: A Two-Way Learning Process + +The success of GSoC 2024 for JSON Schema wouldn’t have been possible without our dedicated mentors. They not only guided contributors but also gained fresh perspectives from working closely with emerging talent. + +## Watch the Journey + +Want to hear more about the contributors’ stories? Watch our [YouTube presentation](https://www.youtube.com/watch?v=2V9k1Hqhgnw) where contributors reflect on their challenges, successes, and learning moments. + +## Looking Forward + +GSoC 2024 has left an indelible mark on JSON Schema. From automation to tooling, each project has strengthened our ecosystem and laid a foundation for continued innovation. +We are excited about the future and invite developers from around the world to join us in shaping it. + +## Ready to contribute? +Explore our [GitHub repository](https://github.com/json-schema-org), get involved in discussions, and be a part of the JSON Schema community! + +Background photo by Jess Bailey +on Unsplash diff --git a/pages/blog/posts/oracle-case-study.md b/pages/blog/posts/oracle-case-study.md new file mode 100644 index 000000000..9171e1afe --- /dev/null +++ b/pages/blog/posts/oracle-case-study.md @@ -0,0 +1,1116 @@ +--- +title: "How Oracle is Bridging the Gap Between JSON Schema and Relational Databases" +date: "2025-02-07" +tags: + - database + - relational +type: Case Study +cover: /img/posts/2025/oracle-case-study/blog_frontpage.webp +authors: + - name: Loïc Lefèvre + photo: /img/avatars/loiclefevre.webp + link: https://www.linkedin.com/in/loiclefevre/ + byline: Oracle Database Senior Product Manager +excerpt: "As modern multi-model databases increasingly support JSON, it's time to explore what role JSON schema will play." +--- + +As modern multi-model databases increasingly support JSON, it's time to explore what role [JSON schema](https://json-schema.org/) will play. In this post, we'll dive into the newly developed ["Database Vocabulary"](https://github.com/json-schema-org/vocab-database/blob/main/database.md), a proposed extension to the official JSON schema specification, developed by Oracle (with inputs from the MySQL and PostgreSQL teams). This vocabulary addresses key database tasks, including validation, type coercion/casting, and metadata preservation, making it easier to manage JSON in databases effectively and bridging the gap with existing relational data. Regardless of whether you are a JSON developer or a relational model developer, you'll learn something reading this post! + +Oracle Database 23ai fully implements this new vocabulary, and we'll describe not only the concepts but we'll also see real-world examples of JSON schema validation in action and how to describe database objects in JSON schema. + +## JSON Data Guide + +With Oracle Database 12cR2 (2017), we've introduced the concept of a [JSON data guide](https://docs.oracle.com/en/database/oracle/oracle-database/23/adjsn/json-data-guide.html); that lets you **discover** information about the structure and content of *existing* JSON documents stored in JSON columns inside the database. + +Let's look at the following example which creates a table `blog_posts` with a column `data` of type `JSON` and inserts one JSON document: + +```sql +create table blog_posts ( + data json -- BINARY JSON +); + +insert into blog_posts( data ) values ( + json { + 'title': 'New Blog Post', + 'content': 'This is the content of the blog post...', + 'publishedDate': '2023-08-25T15:00:00Z', + 'author': { + 'username': 'authoruser', + 'email': 'author@example.com' + }, + 'tags': ['Technology', 'Programming'] + } +); +commit; +``` + +We can query the table and retrieve JSON values using the SQL dot notation to navigate the JSON document hierarchy. Attributes within the JSON document can simply be referenced by `.`: + +```sql +select -- field names are case sensitive + p.data.title, + p.data.author.username.string() as username, + p.data.tags[1].string() as "array_field[1]" + from blog_posts p; +``` + +The [item method](https://docs.oracle.com/en/database/oracle/oracle-database/23/adjsn/sql-json-path-expression-item-methods.html) `string()` allows explicit casting of the JSON field value. Alongside `string()` are other casting methods like `number()`, `date()`, etc. + +However, nothing prevents us from inserting unexpected data! + +```sql +insert into blog_posts( data ) values( '{ "garbageDocument":true }' ); +commit; + +select data from blog_posts; +``` +Results: + +| DATA | +|-| +| {
  "title": "New Blog Post",
  "content": "This is the content of the blog post...",
  "publishedDate":"2023-08-25T15:00:00Z",
  "author": {
    "username":"authoruser",
    "email":"author@example.com"
  },
  "tags": [ "Technology", "Programming" ]
} | +| {
  "garbageDocument":true
} | + +This is where, JSON schemas can help, and the [`JSON_DATAGUIDE()`](https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/JSON_DATAGUIDE.html) function can generate one from a set of already existing JSON document(s): + +```sql +select json_dataguide( + data, + dbms_json.format_schema, + dbms_json.pretty + ) as json_schema + from blog_posts; +``` +Results: + +```json +{ + "type": "object", + "o:length": 1, + "properties": { + "tags": { + "type": "array", + "o:length": 1, + "items": { + "type": "string", + "o:length": 16 + } + }, + "title": { + "type": "string", + "o:length": 16 + }, + "author": { + "type": "object", + "o:length": 1, + "properties": { + "email": { + "type": "string", + "o:length": 32 + }, + "username": { + "type": "string", + "o:length": 16 + } + } + }, + "content": { + "type": "string", + "o:length": 64 + }, + "publishedDate": { + "type": "string", + "o:length": 32 + }, + "garbageDocument": { + "type": "boolean", + "o:length": 4 + } + } +} +``` + +We can see that the `garbageDocument` field was properly detected and added to the set of accepted JSON fields for the JSON schema. + +## Data Validation + +The most obvious use case for JSON schema is JSON data validation. The Oracle Database 23ai brings the new PL/SQL package [`DBMS_JSON_SCHEMA`](https://docs.oracle.com/en/database/oracle/oracle-database/23/arpls/DBMS_JSON_SCHEMA.html#GUID-89B9C48D-D905-482C-A78C-8DB314EDF072) which can be used to validate JSON schemas and JSON data. + +The `dbms_json_schema.is_schema_valid()` function can tell us if a given JSON schema itself is valid: + +```sql +-- Validate the generated JSON schema +select dbms_json_schema.is_schema_valid( + ( + -- Generate JSON Data Guide/Schema from data column + select json_dataguide( + data, + dbms_json.format_schema, + dbms_json.pretty + ) as json_schema + from blog_posts + ) +) = 1 as is_schema_valid; +``` + +Another function `dbms_json_schema.validate_report()` validates a JSON document against a JSON schema and generates a validation report, including validation errors, if there are any: + +```sql +-- Validate current JSON data with a simple JSON schema +select dbms_json_schema.validate_report( + data, + json( '{ + "type": "object", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + } + }' ) + ) as report +from blog_posts; +``` +Results: + +| REPORT | +|------------------------------------------------------------| +| {
  "valid": true,
  "errors": []
} | +| {
  "valid": true,
  "errors": []
} | + +With the simplistic JSON schema, no validation errors are present. Let's use a more complex JSON schema (based on the [Blog post](https://json-schema.org/learn/json-schema-examples#blog-post) example from the JSON schema website itself): + +```sql +select dbms_json_schema.validate_report( + data, + json('{ + "$id": "https://example.com/blog-post.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "A representation of a blog post", + "type": "object", + "required": ["title", "content", "author"], + "properties": { + "title": { + "type": "string" + }, + "content": { + "type": "string" + }, + "publishedDate": { + "type": "string", + "format": "date-time" + }, + "author": { + "$ref": "https://example.com/user-profile.schema.json" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "$def": { + "$id": "https://example.com/user-profile.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "A representation of a user profile", + "type": "object", + "required": ["username", "email"], + "properties": { + "username": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + }, + "fullName": { + "type": "string" + }, + "age": { + "type": "integer", + "minimum": 0 + }, + "location": { + "type": "string" + }, + "interests": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }') +) as report +from blog_posts; +``` +Results: + +| REPORT | +|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| {
  "valid": true,
  "errors": []
} | +| {
  "valid": false,
  "errors": [
    {
      "schemaPath": "\$",
      "instancePath": "\$",
      "code": "JZN-00501",
      "error": "JSON schema validation failed"
    }, {
      "schemaPath": "\$.required",
      "instancePath": "\$",
      "code": "JZN-00515",
      "error": "required properties not found: 'title', 'content', 'author'"
    }
  ]
} | + +Now we can see that the second JSON document shows several validation errors, namely the missing fields `title`, `content` and `author`. + +If you don't want or need to know the validation error details, you may simply use the `dbms_json_schema.is_valid()` function. + +Finally, you can leverage the `dbms_json_schema.describe()` function to generate JSON schemas from existing relational objects such as tables, views, and JSON Relational Duality Views (more on that later). + +```sql +-- Get the JSON schema from a relational table! +select dbms_json_schema.describe( 'BLOG_POSTS' ) as json_schema; +``` +Results: + +| JSON_SCHEMA | +|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| {
  "title": "BLOG_POSTS",
  "dbObject": "APIDAYS.BLOG_POSTS",
  "type": "object",
  "dbObjectType": "table",
  "properties": {
    "DATA": {}
  }
} | + +### Client-side validation using JSON Schema + +Now that we are able to create and retrieve JSON schemas from the database, we may consider the database as a central repository for JSON schemas that can be used by clients (backends and frontends) to validate JSON data. + +Below, you can see a quick overview of a demo available in this [GitHub repository](https://github.com/loiclefevre/apidays-paris-2024): + +![React frontend form created from the json-schema-form library.](/img/posts/2025/oracle-case-study/json-schema-form.webp) + +Using [Oracle REST Data Services](https://download.oracle.com/otn_software/java/ords/ords-latest.zip), we can indeed expose a JSON schema to a frontend via REST. Below, we are using the `json-schema-form` [library](https://github.com/remoteoss/json-schema-form) to build an input form from a JSON schema where `title`, `description`, and check constraints are used to define input fields and associated validation rules. Let's drill down into this example: + +We'll start by creating a basic relational table that will store products: + +```sql +-- drop table if exists products purge; + +create table products ( + name varchar2(100) not null primary key + constraint minimal_name_length check (length(name) >= 3), + price number not null + constraint strictly_positive_price check (price > 0), + quantity number not null + constraint non_negative_quantity check (quantity >= 0) +); + +insert into products (name, price, quantity) +values ('Cake mould', 9.99, 15), + ('Wooden spatula', 4.99, 42); +commit; +``` + +This table has 3 columns. Each column has a named check constraint ensuring inserted values are conform with business rules (strictly positive prices, etc.). + +If we retrieve the JSON schema corresponding to this relational table using `dbms_json_schema.describe()`, we'll also get these check constraints *translated* into the JSON schema format: + +```sql +-- JSON Schema of PRODUCTS table +-- Contains check constraints! +select dbms_json_schema.describe( 'PRODUCTS' ) as json_schema; +``` +Results: + +```json +{ + "title": "PRODUCTS", + "dbObject": "APIDAYS.PRODUCTS", + "type": "object", + "dbObjectType": "table", + "properties": { + "NAME": { + "type": "string", + "extendedType": "string", + "maxLength": 100, + "allOf": [ + { + "minLength": 3 + } + ] + }, + "PRICE": { + "type": "number", + "extendedType": "number", + "allOf": [ + { + "exclusiveMinimum": 0 + } + ] + }, + "QUANTITY": { + "type": "number", + "extendedType": "number", + "allOf": [ + { + "minimum": 0 + } + ] + } + }, + "required": [ + "NAME", + "PRICE", + "QUANTITY" + ], + "dbPrimaryKey": [ + "NAME" + ] +} +``` + +One thing we remark is the absence of `title` and `description` attributes for our 3 columns but considering JSON schemas are also JSON documents, we may enrich the JSON schema with the missing values. + +#### Database Schema Annotations + +Starting with the Oracle Database 23ai, you can leverage [Schema Annotations](https://docs.oracle.com/en/database/oracle/oracle-database/23/adfns/registering-application-data-usage-database.html#GUID-2DAF069E-0938-40AF-B05B-75AFE71D666C) to annotate database objects (columns, tables, views, indexes, etc.). + +Consider the following schema annotations: + +```sql +ALTER TABLE products MODIFY name ANNOTATIONS ( + ADD OR REPLACE "title" 'Name', + ADD OR REPLACE "description" 'Product name (max length: 100)', + ADD OR REPLACE "minLength" '3' +); + +ALTER TABLE products MODIFY price ANNOTATIONS ( + ADD OR REPLACE "title" 'Price', + ADD OR REPLACE "description" 'Product price strictly positive', + ADD OR REPLACE "minimum" '0.01' +); + +ALTER TABLE products MODIFY quantity ANNOTATIONS ( + ADD OR REPLACE "title" 'Quantity', + ADD OR REPLACE "description" 'Quantity of products >= 0', + ADD OR REPLACE "minimum" '0' +); +``` + +These schema annotations provide additional information for each relational columns. Note that the `minimum` and `minLength` ones are here to work around a current `json-schema-form` library limitation (hopefully, this [open issue](https://github.com/remoteoss/json-schema-form/issues/102) will be solved soon). + +These annotations are stored inside the database dictionary and can be retrieved via the `user_annotations_usage` dictionary view: + +```sql +-- View annotations +select column_name, annotation_name, annotation_value + from user_annotations_usage + where object_name='PRODUCTS' + and object_type='TABLE' +order by 1, 2; +``` +Results: + +|COLUMN_NAME|ANNOTATION_NAME|ANNOTATION_VALUE| +|-|-|-| +|NAME|description|Product name (max length: 100)| +|NAME|minLength|3| +|NAME|title|Name| +|PRICE|description|Product price strictly positive| +|PRICE|minimum|0.01| +|PRICE|title|Price| +|QUANTITY|description|Quantity of products >= 0| +|QUANTITY|minimum|0| +|QUANTITY|title|Quantity| + +To mix both, the table JSON schema with these column level annotations, we can use the following PL/SQL function: + +```sql +-- Annotate JSON Schema with column level annotations +-- p_table_name: the table name to work on +create or replace function getAnnotatedJSONSchema( p_table_name in varchar2 ) +return json +as + schema clob; -- the original JSON schema + l_schema JSON_OBJECT_T; -- the JSON schema as DOM to modify + l_properties JSON_OBJECT_T; -- the "properties" JSON object entry of the JSON schema + l_keys JSON_KEY_LIST; -- the list of JSON field names of "properties" JSON object + l_column JSON_OBJECT_T; -- the JSON object to modify (for each column of the table) +begin + -- get JSON schema of table + select json_serialize( dbms_json_schema.describe( p_table_name ) + returning clob ) into schema; + + -- create a DOM object + l_schema := JSON_OBJECT_T.parse( schema ); + -- access the "properties" JSON schema field that lists all the table columns + l_properties := l_schema.get_Object('properties'); + -- get all the field names of this "properties" DOM: the table columns + l_keys := l_properties.get_Keys(); + + -- loop over all the columns... + for i in 1..l_keys.count loop + l_column := l_properties.get_Object( l_keys(i) ); + + -- now retrieve from the database dictionary, all the annotations + -- associated with this table column + for c in (select ANNOTATION_NAME, ANNOTATION_VALUE + from user_annotations_usage + where object_name=p_table_name + and object_type='TABLE' + and column_name=l_keys(i)) + loop + -- add each annotation found as a new key/value pair to the JSON schema + -- for that table column + l_column.put( c.ANNOTATION_NAME, c.ANNOTATION_VALUE ); + end loop; + end loop; + + -- returns the annotated JSON schema + return l_schema.to_json; +end; +/ +``` + +Then one can use the function as below: + +```sql +select getAnnotatedJSONSchema( 'PRODUCTS' ); +``` +Results: + +```json +{ + "title": "PRODUCTS", + "dbObject": "APIDAYS.PRODUCTS", + "type": "object", + "dbObjectType": "table", + "properties": { + "NAME": { + "type": "string", + "extendedType": "string", + "maxLength": 100, + "allOf": [ + { + "minLength": 3 + } + ], + "title": "Name", + "description": "Product name (max length: 100)", + "minLength": "3" + }, + "PRICE": { + "type": "number", + "extendedType": "number", + "allOf": [ + { + "exclusiveMinimum": 0 + } + ], + "description": "Product price strictly positive", + "minimum": "0.01", + "title": "Price" + }, + "QUANTITY": { + "type": "number", + "extendedType": "number", + "allOf": [ + { + "minimum": 0 + } + ], + "title": "Quantity", + "description": "Quantity of products >= 0", + "minimum": "0" + } + }, + "required": [ + "NAME", + "PRICE", + "QUANTITY" + ], + "dbPrimaryKey": [ + "NAME" + ] +} +``` + +#### GET method + +The previous SQL query can then be used as the parameterized template for our REST end point for the GET method: + +```sql +-- Run only once: +BEGIN + ORDS.ENABLE_SCHEMA( + p_enabled => TRUE, + -- database user/schema + p_schema => 'APIDAYS', + p_url_mapping_type => 'BASE_PATH', + p_url_mapping_pattern => 'apidays', + p_auto_rest_auth => FALSE); + + ORDS.DEFINE_MODULE( + p_module_name => 'apidays', + p_base_path => '/schema_repository/', + p_items_per_page => 25, + p_status => 'PUBLISHED', + p_comments => NULL); + + ORDS.DEFINE_TEMPLATE( + p_module_name => 'apidays', + p_pattern => 'products', + p_priority => 0, + p_etag_type => 'HASH', + p_etag_query => NULL, + p_comments => NULL); + + ORDS.DEFINE_HANDLER( + p_module_name => 'apidays', + p_pattern => 'products', + p_method => 'GET', + p_source_type => 'json/item', + p_mimes_allowed => NULL, + p_comments => NULL, + p_source => +'select getAnnotatedJSONSchema( ''PRODUCTS'' ) as schema'); + +COMMIT; + +END; +/ +``` + +In the [GitHub repositoy](https://github.com/loiclefevre/apidays-paris-2024/blob/main/src/ORDS.js), you'll find the `src/ORDS.js` module that demonstrates using this REST method: + +```js +import axios from 'axios'; + +function ORDS() {} + +ORDS.prototype.getSchema = async function() { + return await axios.get( + 'http://localhost/ords/apidays/schema_repository/products', + {} + ) + .then( res => res.data.schema ) + .catch(err => err); +} + +export default new ORDS(); +``` + +With all this in place, our React frontend can now create the following form: + +![React frontend with input form generated from an annotated Oracle Database 23ai JSON schema.](/img/posts/2025/oracle-case-study/form.webp) + +> Interestingly, whenever you change the schema annotation in the database, it is immediately reflected inside your browser once you refreshed it. You can try with: +> ```sql +> ALTER TABLE products MODIFY name ANNOTATIONS ( +> REPLACE "title" 'Product name' +> ); +> ``` +> + + +#### JSON Relational Duality View + +Once the new product has been validated inside the frontend, it is sent to the database for insertion into the relational table. To ease this process, we'll leverage one of the greatest 23ai new features: **JSON Relational Duality View**. + +This new type of view acts as a gateway between the JSON and relational worlds. Basically, one can insert JSON documents into a JSON relational duality view and the database will automatically map the proper JSON fields to the relational columns. From a retrieval perspective, whenever a JSON relational duality view is queried, a JSON document will be constructed from the underlying relational model at runtime. + +Consider this *very simple* example (not even involving relationships between tables, nor flex fields, etc.): + +```sql +-- GraphQL notation (SQL notation also exists) +create or replace json relational duality view products_dv as +products @insert { + _id: NAME + PRICE + QUANTITY +}; +``` + +Here we ask the view to accept `INSERT` SQL statements (via `@insert`) and remap the JSON `_id` attribute (mandatory JSON unique key) to the relational column `NAME` (note that JSON fields are case-sensitive). The other two attributes are automatically mapped because the JSON attributes and relational table column names are the same. + +You can find hereunder the JSON schema of this JSON relational duality view: + +```sql +-- Get JSON Schema from JSON Relational Duality View +select dbms_json_schema.describe( 'PRODUCTS_DV' ); +``` +Results: + +```json +{ + "title": "PRODUCTS_DV", + "dbObject": "APIDAYS.PRODUCTS_DV", + "dbObjectType": "dualityView", + "dbObjectProperties": [ "insert", "check" ], + "type": "object", + "properties": { + "_metadata": { + "etag": { + "type": "string", + "extendedType": "string", + "maxLength": 200 + }, + "asof": { + "type": "string", + "extendedType": "string", + "maxLength": 20 + } + }, + "_id": { + "type": "string", + "extendedType": "string", + "maxLength": 100, + "dbFieldProperties": [ "check" ] + }, + "PRICE": { + "type": "number", + "extendedType": "number", + "dbFieldProperties": [ "check" ] + }, + "QUANTITY": { + "type": "number", + "extendedType": "number", + "dbFieldProperties": [ "check" ] + } + }, + "dbPrimaryKey": [ + "_id" + ], + "required": [ + "_id", + "PRICE", + "QUANTITY" + ], + "additionalProperties": false +} +``` + +So now we can run such an `INSERT` statement: + +```sql +-- Insert JSON in a Relational table (Bridging the Gap...) +-- by using the JSON Relational Duality View +insert into PRODUCTS_DV(data) values( + json_transform( '{ + "NAME": "Other nice product", + "PRICE": 5, + "QUANTITY": 10 + }', + RENAME '$.NAME' = '_id' + ) +); + +commit; +``` + +You will notice that we are using the [`JSON_TRANSFORM()`](https://docs.oracle.com/en/database/oracle/oracle-database/23/adjsn/oracle-sql-function-json_transform.html) function to rename the `NAME` JSON attribute to `_id` expected by the `PRODUCTS_DV` JSON relational duality view. + +```sql +select * from products_dv; +select * from products; +``` + +Running the 2 queries above respectively returns the data in JSON format: + +| DATA | +|----------------------------------------------------------------------------------------------------------------------| +| {
  "_id": "Cake mould",
  "PRICE": 9.99,
  "QUANTITY": 15,
  "_metadata": { ... }
} | +| {
  "_id": "Wooden spatula",
  "PRICE": 4.99,
  "QUANTITY": 42,
  "_metadata": { ... }
} | +| {
  "_id": "Other nice product",
  "PRICE": 5,
  "QUANTITY": 10,
  "_metadata": { ... }
} | + +...and relational format: + +|NAME|PRICE|QUANTITY| +|-|-|-| +|Cake mould|9.99|15| +|Wooden spatula|4.99|42| +|Other nice product|5|10| + +> The `_metadata` object will contain additional information such as an `etag` that can be used for [optimistic concurrency control](https://docs.oracle.com/en/database/oracle/oracle-database/23/jsnvu/using-optimistic-concurrency-control-duality-views.html). + +#### POST method + +With the JSON relational duality view in place, we can now implement the REST POST method by adding another ORDS handler: + +```sql +BEGIN + ORDS.DEFINE_HANDLER( + p_module_name => 'apidays', + p_pattern => 'products', + p_method => 'POST', + p_source_type => 'plsql/block', + p_mimes_allowed => NULL, + p_comments => NULL, + p_source => +'begin + insert into PRODUCTS_DV( data ) values( json_transform(:body_text, RENAME ''$.NAME'' = ''_id'') ); + commit; +end;'); + +COMMIT; + +END; + +/ +``` + +#### Precheck Check Constraints + +With 23ai, a check constraint can now be marked as [`PRECHECK`](https://docs.oracle.com/en/database/oracle/oracle-database/23/adfns/data-integrity.html#GUID-278AD7DD-C45D-4F43-8D60-8ABA2B062296). Doing so tells the database that a relational check constraint has a corresponding JSON schema constraint that preserves the semantics of the constraint and hence the database doesn't need to verify the check again. An example of a constraint that has no corresponding JSON schema constraint could be a foreign key. + +Once a check constraint is marked as `PRECHECK`, you have the choice whether or not to disable the check constraint on the table as the retrieved JSON schema with `dbms_json_schema.describe()` will contain the check constraints as well. + +> We do **NOT** advise to disable check constraints as it would allow inserting bad data into the relational tables directly. The remark about `PRECHECK` constraints is here to provide as much information as possible. + +```sql +-- Mark check constraints as PRECHECK +alter table products modify constraint strictly_positive_price precheck; +alter table products modify constraint non_negative_quantity precheck; + +-- Now disable the constraints at the database level +-- They are checked in the clients +-- +-- Warning: do that at your own risks! +alter table products modify constraint strictly_positive_price disable; +alter table products modify constraint non_negative_quantity disable; + +-- Check constraints still present inside the JSON Schema +select dbms_json_schema.describe( 'PRODUCTS' ); + +-- but following INSERT will work and insert bad data +insert into products (name, price, quantity) +values ('Bad product', 0, -1); + +commit; + +select * from products; +``` + +### Data Use Case Domains + +Another way to validate JSON data is to associate a JSON schema with a JSON column. In 23ai, an extension of the ISO standard Domains is available: [Data Use Case Domains](https://docs.oracle.com/en/database/oracle/oracle-database/23/adfns/registering-application-data-usage-database.html#GUID-4743FDE1-7C6E-471B-BC9D-442383CCA2F9). + +Consider the following very simple data use case domain that could be considered as a scalar JSON data type alias: + +```sql +-- Introducing Data Use Case Domains +create domain if not exists jsonb as json; + +create table test ( + data jsonb -- JSON alias +); +``` + +Domains also allow for [centralizing JSON schema](https://docs.oracle.com/en/database/oracle/oracle-database/23/adjsn/json-schema.html#GUID-7D67DF73-CB21-4878-AF93-D1A213411EC0) so that they can be reused across tables and columns. The example below demonstrates how to associate a JSON schema within a data use case domain: + +```sql +-- drop table if exists posts purge; +-- drop domain if exists BlogPost; +create domain if not exists BlogPost as json +validate '{ + "$id": "https://example.com/blog-post.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "A representation of a blog post", + "type": "object", + "required": ["title", "content", "author"], + "properties": { + "title": { + "type": "string" + }, + "content": { + "type": "string" + }, + "publishedDate": { + "type": "string", + "format": "date-time" + }, + "author": { + "$ref": "https://example.com/user-profile.schema.json" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "$def": { + "$id": "https://example.com/user-profile.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "A representation of a user profile", + "type": "object", + "required": ["username", "email"], + "properties": { + "username": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + }, + "fullName": { + "type": "string" + }, + "age": { + "type": "integer", + "minimum": 0 + }, + "location": { + "type": "string" + }, + "interests": { + "type": "array", + "items": { + "type": "string" + } + } + } + } +}'; + +-- Now use the Domain as a new column data type! +create table posts ( content BlogPost ); + +-- fails +insert into posts values (json{ 'garbageDocument' : true }); + +-- works +insert into posts values ( + json { + 'title': 'Best brownies recipe ever!', + 'content': 'Take chocolate...', + 'publishedDate': '2024-12-05T13:00:00Z', + 'author': { + 'username': 'Bob', + 'email': 'bob@blogs.com' + }, + 'tags': ['Cooking', 'Chocolate', 'Cocooning'] + } +); + +commit; +``` + +Now let's look closer at the `publishedDate` field: + +```sql +select p.content.publishedDate + from posts p; + +-- the binary encoded data type is 'string' +select p.content.publishedDate.type() as type + from posts p; +``` +Results: + +|TYPE| +|-| +|string| + +Using the `type()` [item method](https://docs.oracle.com/en/database/oracle/oracle-database/23/adjsn/sql-json-path-expression-item-methods.html), we can see the date is in fact stored as a string. + +## Performance Improvement + +With data use case domains, the Oracle Database 23ai can not only use JSON schema for JSON data validation but it can also improve performance by leveraging the [`CAST`](https://docs.oracle.com/en/database/oracle/oracle-database/23/adjsn/json-schema.html#GUID-50DD1C0D-A1C1-49BA-88A5-977EB1B734FA) functionality. Consider the following data use case domain example: + +```sql +drop table if exists posts purge; + +drop domain if exists BlogPost; + +-- Recreate the Domain with CAST/Type coercion enabled +create domain BlogPost as json +validate CAST using '{ + "$id": "https://example.com/blog-post.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "A representation of a blog post", + "type": "object", + "required": ["title", "content", "author"], + "properties": { + "title": { + "type": "string" + }, + "content": { + "type": "string" + }, + "publishedDate": { + "extendedType": "timestamp", + "format": "date-time" + }, + "author": { + "$ref": "https://example.com/user-profile.schema.json" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "$def": { + "$id": "https://example.com/user-profile.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "A representation of a user profile", + "type": "object", + "required": ["username", "email"], + "properties": { + "username": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + }, + "fullName": { + "type": "string" + }, + "age": { + "type": "integer", + "minimum": 0 + }, + "location": { + "type": "string" + }, + "interests": { + "type": "array", + "items": { + "type": "string" + } + } + } + } +}'; + +create table posts ( content BlogPost ); +``` + +By enabling the JSON schema for type **CAST**ing, we can request the database to use the new `extendedType` during the binary JSON encoding process. In the example above, this would mean that the encoded type would be a `timestamp` and no longer a `string` resulting in less parsing overhead compared to the previous version: from `string` to `timestamp` each time we retrieve the field for SQL processing (`WHERE` clause filtering, `SELECT` projection, etc.). + +Let's check this: + +```sql +create table posts ( content BlogPost ); + +-- We can retrieve the JSON schema associated to the column +-- via the Data Use Case Domain +select dbms_json_schema.describe( 'POSTS' ); + +-- works +insert into posts values ( +'{ + "title": "Best brownies recipe ever!", + "content": "Take chocolate...", + "publishedDate": "2024-12-05T13:00:00Z", + "author": { + "username": "Bob", + "email": "bob@blogs.com" + }, + "tags": ["Cooking", "Chocolate", "Cocooning"] + }' +); +commit; + +-- Now let's look at the publishedDate field... +select p.content.publishedDate from posts p; + +-- ...its binary encoded data type is 'timestamp' +select p.content.publishedDate.type() from posts p; + +-- I can add 5 days to this date... +select p.content.publishedDate.timestamp() + interval '5' day +from posts p; +``` + +> We use the item method `timestamp()` in the last statement above because otherwise the SQL dot notation would return a SQL `JSON` (by default in 23ai) on which we cannot apply an interval operation. However, because the value is already stored as `TIMESTAMP` inside the binary JSON format, there will be *no conversion* from `JSON` to `timestamp` here. + +Last but not least, by enabling type casting, native SQL data type checks are also performed ensuring 100% fidelity between stored binary values in the encoded JSON and SQL data types. As a result, we can store not just the standard JSON data types but also the SQL data types inside the encoded binary JSON such as `NUMBER`, `DATE`, `TIMESTAMP`, `TIMESTAMP WITH TIME ZONE`, `INTERVAL`, `RAW`, `VECTOR`, etc. + +## Relational Model Evolution + +Our last use case that leverages JSON schema inside the Oracle Database is available since version 12cR2. Imagine, you are a data analyst and the only tool you have to build charts only allows you to see tables and columns. Each time a new data attribute is added, you know that it will take time before you see it appearing inside your BI tool because of the involved development processes. + +Now, imagine this is no more the case... + +Let's look at the following example: + +```sql +create table orders ( j json ); + +insert into orders(j) values ( + json { 'firstName': 'Bob', 'address': 'Paris' } +); +commit; + +select j from orders; +``` +Results: + +| J | +|------------------------------------------------------------------------| +| {
  "firstName": "Bob",
  "address": "Paris"
} | + +We have an `orders` table with one column containing a JSON document. The JSON document itself has 2 fields and 2 values. Now, we'll create a [**JSON Search index**](https://docs.oracle.com/en/database/oracle/oracle-database/23/adjsn/json-search-index-ad-hoc-queries-and-full-text-search.html) (that can perform Full-Text search). This index can optionally maintain a JSON Data Guide in real-time, meaning the JSON schema for the JSON documents stored inside the JSON column. + +With this ability comes another one: [Change Triggers For Data Guide-Enabled Search Index](https://docs.oracle.com/en/database/oracle/oracle-database/23/adjsn/change-triggers-data-guide-enabled-search-index.html#GUID-2F4C6F52-0D96-4405-8F85-CDA0B234D0D5) which, based on the maintained JSON schema, can react to any newly added JSON attributes and dynamically expose these by adding the corresponding virtual columns. + +The example below demonstrates this behavior: + +```sql +-- drop index s_idx force; + +-- Create a Full-Text Search index for JSON with Data Guide +-- enabled and add_vc stored procedure enabled to change +-- table structure: add virtual column for JSON fields, +-- helpful for Analytics => you directly have the existing +-- JSON fields listed as columns! +create search index s_idx on orders(j) for json +parameters('dataguide on change add_vc'); + +select * from orders; +``` +Results: + +| J |J$address|J$firstName| +|-------------------------------------------------------------------|-|-| +| {
  "firstName": "Bob",
  "address": "Paris"
} |Paris|Bob| + +```sql +insert into orders(j) values ( + json { 'firstName': 'Bob', 'address': 'Paris', 'vat': false } +); +commit; + +select * from orders; +``` +Results: + +| J |J$address|J$firstName|J$vat| +|--------------------------------------------------------------------------------------|-|-|-| +| {
  "firstName": "Bob",
  "address": "Paris"
} |Paris|Bob|null| +| {
  "firstName": "Bob",
  "address": "Paris",
  "vat": false
} |Paris|Bob|false| + +```sql + +insert into orders(j) values ( + json { 'firstName': 'Bob', 'address': 'Paris', 'vat': false, 'tableEvolve': true } +); +commit; + +select * from orders; +``` +Results: + +| J |J$address|J$firstName|J$vat|J$tableEvolve| +|----------------------------------------------------------------------------------------------------------------------|-|-|-|-| +| {
  "firstName": "Bob",
  "address": "Paris"
} |Paris|Bob|null|null| +| {
  "firstName": "Bob",
  "address": "Paris",
  "vat": false
} |Paris|Bob|false|null| +| {
  "firstName": "Bob",
  "address": "Paris",
  "vat": false,
  "tableEvolve": true
} |Paris|Bob|false|true| + +> The trigger executes asynchronously, hence not delaying DML response times, however, because of it being asynchronous, it may take a second before you will see the new virtual column. + +## Conclusion + +We have shown lots of features inside the Oracle Database 23ai which provide powerful capabilities to have JSON data coexist with relational data, and JSON schema clearly strengthens this even more. But this is only the beginning and as you discover more and more features that work the same way regardless of the data model, or that allow going back and forth from one model to another, you'll understand the true value of a converged database which has one goal: removing barriers, simplifying architecture and making developers more productive! + +![Oracle Database 23ai is a converged database now supporting JSON schema.](/img/posts/2025/oracle-case-study/converged_database.webp) + +Lean more: +- [Oracle Database 23ai `DBMS_JSON_SCHEMA` PL/SQL package](https://docs.oracle.com/en/database/oracle/oracle-database/23/arpls/DBMS_JSON_SCHEMA.html#GUID-89B9C48D-D905-482C-A78C-8DB314EDF072) +- [Oracle Database 23ai JSON Developer Guide](https://docs.oracle.com/en/database/oracle/oracle-database/23/adjsn/index.html) +- [Getting started with Oracle Database 23ai](https://medium.com/db-one/oracle-database-download-install-tutorial-my-getting-started-guide-044925c10ca2) +- [Oracle Database 23ai JSON Feature Highlights](https://www.oracle.com/database/23ai/#json) diff --git a/pages/blog/posts/stable-json-schema.md b/pages/blog/posts/stable-json-schema.md new file mode 100644 index 000000000..e1d32f7eb --- /dev/null +++ b/pages/blog/posts/stable-json-schema.md @@ -0,0 +1,90 @@ +--- +title: "Moving Toward a Stable Spec" +date: "2025-01-13" +tags: + - specification + - stable +type: Update +cover: /img/posts/2025/stable-json-schema/mt-taranaki.webp +authors: + - name: Greg Dennis + photo: /img/avatars/gregsdennis.webp + link: https://www.linkedin.com/in/gregdennis/ + byline: Specification Author & JSON Tooling Implementer +excerpt: "Amidst all of the change at JSON Schema, what's happening with the spec?" +--- + +Many of you may have noticed a lot of changes happening around the JSON Schema community. This website has had a facelift, we've started appearing at developer conferences, and we even participated in Google's Summer of Code & Summer of Docs programs. But many of you may be asking, "What's happening with the spec?" + +In this post I'll be providing an update on specification development and our new publication process. + +## Publication Process + +In a [previous post](./json-schema-joins-the-openjsf), we announced that we were no longer publishing our specifications through the IETF. At the time, the intent was to join the OpenJS Foundation, however for multiple reasons, the onboarding process was not able to be completed. As such, currently we are independent. In the future, we may again seek to join a foundation (we may even try OpenJS again), but for now, independence seems to be the best place for us. + +When we last published a specification, we used the IETF's [Internet-Draft Publication Process](https://authors.ietf.org/en/rfc-publication-process). This meant that our documents were required to retain the "draft" moniker, even though we considered them fully fledged and ready for use in production systems. Publishing independently, we're no longer bound by this requirement, however it does mean that we can no longer rely on the IETF document publishing infrastructure. We have to build our own. + +The foundation of our publication process is built on several ideals, and I'll cover the major ones in the next few sections. By focusing on these pillars, we can ensure a safe and easy upgrade path for our users as the specification continues to evolve. + +### Minimize Backward-Incompatible Changes Between Releases + +One of the primary complaints we received about releasing a new specification over the last few iterations, particularly between Drafts 2019-09 and 2020-12, is the lack of consideration for backward compatibility. + +Just to highlight a few of the breaking changes introduced with the latest version: + +- `$recursiveRef` / `$recursiveAnchor` became `$dynamicRef` / `$dynamicAnchor` +- Array-form `items` became `prefixItems` +- `additionalItems` was removed; use schema-form `items` now + +These changes meant that a schema written for Draft 2019-09 could validate completely differently when processed under Draft 2020-12 rules. This creates a very poor upgrade experience. + +In defending our decision to include these breaking changes, we hid behind our own advice to schema authors to include the `$schema` keyword, which identifies the dialect (specification version), instead of designing a [pit of success](https://blog.codinghorror.com/falling-into-the-pit-of-success/) that allowed them to continue their current behavior in a system that "just works". + +**_Moving forward, upgrade compatibility is our #1 concern when developing a new release._** + +That doesn't mean that a breaking change will _never_ happen, but we will make every effort to ensure that it doesn't. + +### Maximize Forward Compatibility + +**_We need to protect ourselves from potential future changes that would harm or prevent backward compatibility._** + +Ironically, this means introducing a breaking change. (I had [posted](./the-last-breaking-change) about this a couple of years ago, and the reception wasn't awesome, which led to a [follow-up post](./custom-annotations-will-continue).) + +In short, to preserve future compatibility, we need to ensure that schemas can't contain extra properties which may one day be proposed as legitimate keywords. This means that extra data in schemas can no longer be acceptable. To accommodate our users' need to include meta-data and other values in their schemas, the specification will define a convention or namespace for property names that are to be ignored, and we guarantee that no future proposed keyword may follow this convention in order to keep the namespace protected. + +As it stands today, the convention is that your property name should start with `x-`. If you like, you can read about alternative ideas and how we decided on this approach in [the ADR](https://github.com/json-schema-org/json-schema-spec/blob/main/adr/2023-04-sva-prefix.md). + +### Formally Define a Feature Proposal Process + +In the past, new features would just be added to the specification and released with the next version. We held it as acceptable that a feature may not be fully finished when we released the specification. We expected to receive feedback, and the feature would be updated in the next version. + +However, this approach puts a large burden on tooling maintainers who want to support multiple versions of the specification, which is basically all of them. They'd have to support many different behaviors, sometimes for the same keyword. + +The perfect example of this is Draft 2019-09's `$recursiveRef` & `$recursiveAnchor`. The idea was solid and had a lot going for it. In 2019 when we were working on it, we developed the concept as best we could, but we needed actual user feedback, so we added it to the specification, knowing that it wasn't quite complete. Prior to releasing the specification, a few of us who had implementations also added it as an optional feature to let our users try it out. But after the specification was released, we found that many users were confused as to how it should work, and we identified several ways that we could make it better. Those improvements became `$dynamicRef` & `$dynamicAnchor` in Draft 2020-12. Even though the "recursive" keywords weren't part of the latest specification, many implementations wanted to support Draft 2020-12 while continuing to support Draft 2019-09. Furthermore, schemas which contained the "recursive" keywords couldn't be processed under the Draft 2020-12 rules, which takes us back to the backward compatibiility problem. + +**_We need a feature proposal process that encourages tool support while also allowing continued feature development._** + +By introducing a feature proposal process, all tooling maintainers can add support as they elect to do so. And because these proposals aren't considered a hard requirement of the specification, we can continue to iterate on them (including breaking changes). Finally, by actively encouraging tooling support, we can obtain the real-world feedback that we need to ensure that the feature is the best it can be before we officially integrate it into the specification. + +## Compatibility with Draft 2020-12 + +To close this out, and with all of the above in mind, I want to cover what the upcoming release will entail as it stands now. + +First, the incompatibilities: + +- As mentioned before, we won't be supporting arbitrary properties anymore. Any extra data you wish to include will need to use the `x-` property name convention. +- The `$dynamicRef` / `$dynamicAnchor` referencing system will be completely disjoint from the `$ref` / `$id` / `$anchor` system. In Draft 2020-12, `$dynamicRef` could sometimes fall back to a normal `$ref` behavior. This has been very confusing, so we've just isolated the two referencing systems. This is _technically_ a breaking change, but we're pretty certain no one ever used `$dynamicRef` expecting it to work like `$ref`. +- `format` will validate by default. There was a lot of [discussion](https://github.com/json-schema-org/json-schema-spec/issues/1520) on this topic, but the deciding factor was that users generally expect it to validate, and we wanted to meet that expectation. +- Vocabularies are being demoted to a feature proposal. This was one of those ideas that wasn't completely finished when it was added to the spec in Draft 2019-09. It's likely that this feature will change substantially before being merged back into the specification. As a proposal, the feature can still be supported as development continues, but it's not a hard requirement. + +Additionally, but not breaking: + +- The recommended output format introduced in Draft 2019-09 has been extracted to its own specification. The two driving factors for this decision were that different output formats could be more beneficial to different consumers and having the output versioned separately from the specification would more easily allow them to evolve independently. +- Many keyword interaction behaviors were defined by the annotations that were produced at various levels of evaluation. This led to some confusion and unnecessary requirements, so we've loosened the language around this to allow tooling to figure out how they want to implement the behavior rather than prescribing a particular approach. +- General clean-up and clarifications to more accurately define behavior. + +Beyond that, we still have a lot to do, but not nearly as much as we had this time last year, and we still have to figure out the actual publication piece, i.e. how we want it on the website. We have the IETF-published documents mirrored here, and the new ones will likely go up next to those. It's just another thing we need to do. You can track our list of items on the [GitHub project board](https://github.com/orgs/json-schema-org/projects/15/views/1). + +It's been four years since we published a new version, but we're getting really close, and I'm very excited. Stay tuned! + +_Cover image is of Mt. Taranaki in New Zealand, by [Sophie Turner](https://unsplash.com/@sophie_turner) on [Unsplash](https://unsplash.com/photos/mountain-near-body-of-water-during-daytime-LZVmvKlchM0)._ diff --git a/pages/community/index.page.tsx b/pages/community/index.page.tsx index 11692b016..576467680 100644 --- a/pages/community/index.page.tsx +++ b/pages/community/index.page.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { getLayout } from '~/components/SiteLayout'; import { SectionContext } from '~/context'; -import imageData from '~/data/community.json'; +import imageData from '~/data/community-users.json'; import fs from 'fs'; import matter from 'gray-matter'; import readingTime from 'reading-time'; @@ -100,17 +100,28 @@ export default function communityPages(props: any) {
- {imageData.map((avatar, index) => ( - {avatar.alt} - ))} + {imageData + .filter( + (contributor) => + contributor.login !== 'the-json-schema-bot[bot]' && + contributor.login !== 'dependabot[bot]', + ) + .sort(() => Math.random() - 0.5) + .slice(0, 60) + .map((avatar, index) => ( + {avatar.login} + ))}
@@ -287,9 +298,12 @@ export default function communityPages(props: any) {
- {blogPosts[0].frontmatter.title}

{blogPosts[0].frontmatter.title} diff --git a/pages/docs/index.page.tsx b/pages/docs/index.page.tsx index 635f55cf1..d68ed0c93 100644 --- a/pages/docs/index.page.tsx +++ b/pages/docs/index.page.tsx @@ -8,6 +8,7 @@ import { DocsHelp } from '~/components/DocsHelp'; export default function Welcome() { const newTitle = 'Welcome'; + const fileRenderType = 'tsx'; return ( @@ -16,33 +17,43 @@ export default function Welcome() { {newTitle}

JSON Schema is a declarative language for annotating and validating JSON - documents' structure, constraints, and data types. It provides a way to + documents' structure, constraints, and data types. It helps you standardize and define expectations for JSON data.
+ Our documentation will guide you through the basics and beyond of + defining and validating JSON data.
Explore the docs

+
- +
); } diff --git a/pages/draft-05/index.page.tsx b/pages/draft-05/index.page.tsx index 1d619e0b4..a792cfc05 100644 --- a/pages/draft-05/index.page.tsx +++ b/pages/draft-05/index.page.tsx @@ -33,13 +33,14 @@ export default function ImplementationsPages({ blocks: any; frontmatter: any; }) { + const fileRenderType = 'indexmd'; return ( {frontmatter.title} - + ); } diff --git a/pages/draft-06/[slug].page.tsx b/pages/draft-06/[slug].page.tsx index fc447db63..64655ed3c 100644 --- a/pages/draft-06/[slug].page.tsx +++ b/pages/draft-06/[slug].page.tsx @@ -22,7 +22,7 @@ export default function StaticMarkdownPage({ frontmatter: any; content: any; }) { - const markdownFile = '_index'; + const fileRenderType = '_md'; const newTitle = 'JSON Schema - ' + frontmatter.title; return ( @@ -32,7 +32,7 @@ export default function StaticMarkdownPage({ {frontmatter.title} - + ); } diff --git a/pages/draft-06/index.page.tsx b/pages/draft-06/index.page.tsx index 12127285b..b328e38ae 100644 --- a/pages/draft-06/index.page.tsx +++ b/pages/draft-06/index.page.tsx @@ -31,12 +31,13 @@ export default function ImplementationsPages({ blocks: any; frontmatter: any; }) { + const fileRenderType = 'indexmd'; return ( {frontmatter.title} - + ); } diff --git a/pages/draft-06/json-hyper-schema-release-notes.md b/pages/draft-06/json-hyper-schema-release-notes.md index 19735c3a3..d6a0860ec 100644 --- a/pages/draft-06/json-hyper-schema-release-notes.md +++ b/pages/draft-06/json-hyper-schema-release-notes.md @@ -31,8 +31,8 @@ While we knew that there were still major gaps in draft-06, we felt that it was #### Changes from draft-04 to draft-05 -keyword | change | consequence ----- | ---- | ---- +| keyword | change | consequence +| ---- | ---- | ---- `"base"` | replaces looking up the nearest "self" link to determine the base URI for `"href"` | if you were relying on "self" links to change the base, set `"base"` explicitly `"rel"` | "full" relation removed | use ["item"](https://github.com/json-schema-org/json-schema-spec/issues/295) `"rel"` | "instances" and "create" relations removed | use ["collection"](https://github.com/json-schema-org/json-schema-spec/issues/295) @@ -43,8 +43,8 @@ keyword | change | consequence #### Changes from draft-05 to draft-06 -keyword | change | consequence ----- | ---- | ---- +| keyword | change | consequence +| ---- | ---- | ---- `"method"` | *removed* | for HTTP method proposals, see issues [#73](https://github.com/json-schema-org/json-schema-spec/issues/73) and [#296](https://github.com/json-schema-org/json-schema-spec/issues/296) (use either `"method"` or `"allow"` as an extension keyword if needed); indication of how to use `"schema"` and `"encType"` no longer necessary `"schema"` | *removed* | use `"hrefSchema"`, `"submissionSchema"`, or `"targetSchema"` | `"encType"` | *removed* | use `"submissionEncType"` for request bodies; no longer needed for URI query strings diff --git a/pages/draft-06/json-schema-release-notes.md b/pages/draft-06/json-schema-release-notes.md index d7632ed23..a495138c5 100644 --- a/pages/draft-06/json-schema-release-notes.md +++ b/pages/draft-06/json-schema-release-notes.md @@ -21,8 +21,8 @@ For more information, see that draft's [migration notes](../../draft-07/json-sch #### Backwards-incompatible changes -keyword | change | consequence ----- | ---- | ---- +| keyword | change | consequence +| ---- | ---- | ---- `"id"` | replaced by `"$id"` | no longer easily confused with instance properties named `"id"` `"$id"` | replaces `"id"` | behavior is identical, `$` prefix matches the other two core keywords `"$ref"` | only allowed where a schema is expected | it is now possible to describe instance properties named `"$ref"` @@ -31,8 +31,8 @@ keyword | change | consequence #### Additions and backwards-compatible changes -keyword | change | consequence ----- | ---- | ---- +| keyword | change | consequence +| ---- | ---- | ---- booleans as schemas | allowable anywhere, not just `"additionalProperties"` and `"additionalItems"` | `true` is equivalent to `{}`, `false` is equivalent to `{"not": {}}`, but the intent is more clear and implementations can optimize these cases more easily `"propertyNames"` | added | takes a schema which validates the *names* of all properties rather than their values `"contains"` | added | array keyword that passes validation if its schema validates at least one array item diff --git a/pages/draft-07/[slug].page.tsx b/pages/draft-07/[slug].page.tsx index be10dfdba..f4ef2b082 100644 --- a/pages/draft-07/[slug].page.tsx +++ b/pages/draft-07/[slug].page.tsx @@ -22,7 +22,7 @@ export default function StaticMarkdownPage({ frontmatter: any; content: any; }) { - const markdownFile = '_index'; + const fileRenderType = '_md'; const newTitle = 'JSON Schema - ' + frontmatter.title; return ( @@ -32,7 +32,7 @@ export default function StaticMarkdownPage({ {frontmatter.title} - + ); } diff --git a/pages/draft-07/index.page.tsx b/pages/draft-07/index.page.tsx index 91d52a981..c057e259c 100644 --- a/pages/draft-07/index.page.tsx +++ b/pages/draft-07/index.page.tsx @@ -31,12 +31,13 @@ export default function ImplementationsPages({ blocks: any; frontmatter: any; }) { + const fileRenderType = 'indexmd'; return ( {frontmatter.title} - + ); } diff --git a/pages/draft-07/json-schema-release-notes.md b/pages/draft-07/json-schema-release-notes.md index 5d4fcbc89..8cb32f359 100644 --- a/pages/draft-07/json-schema-release-notes.md +++ b/pages/draft-07/json-schema-release-notes.md @@ -26,8 +26,8 @@ more clearly than before. * No keywords were removed * Some keywords were moved from Hyper-Schema, and two of those were renamed -keyword | change | notes ----- | ---- | ---- +| keyword | change | notes +| ---- | ---- | ---- [`"$comment"`](../../draft-07/json-schema-core.html#rfc.section.9) | added to Core | Intended for notes to schema maintainers, as opposed to [`"description"`](../../draft-07/json-schema-validation.html#rfc.section.10.1) which is suitable for display to end users [`"if"`, `"then"`, `"else"`](../../draft-07/json-schema-validation.html#rfc.section.6.6) | added to Validation | explicit conditional schema evaluation [`"readOnly"`](../../draft-07/json-schema-validation.html#rfc.section.10.3) | moved from Hyper-Schema to Validation | not limited to hypermedia environments @@ -41,8 +41,8 @@ Note that the `"content*"` keywords do not _require_ validation. Numerous formats were added, clarified, or restored from older drafts. -format | change | notes ----- | ---- | ---- +| format | change | notes +| ---- | ---- | ---- [`"iri"`](../../draft-07/json-schema-validation.html#rfc.section.7.3.5) | added | I18N equivalent of `"uri"` [`"iri-reference"`](../../draft-07/json-schema-validation.html#rfc.section.7.3.5) | added | I18N equivalent of `"uri-reference"` [`"uri-template"`](../../draft-07/json-schema-validation.html#rfc.section.7.3.6) | noted IRI support | There is no separate IRI Template standard @@ -102,8 +102,8 @@ that its use for JSON Schema was not correct. The new guidance for [what relations to use](../../draft-07/json-schema-core.html#rfc.section.11.1) to link instances to schemas is: -link relation | change | notes ----- | ---- | ---- +| link relation | change | notes +| ---- | ---- | ---- "describedBy" | no change | network-accessible URL "profile" | removed; use "schema" | opaque identifying URI "schema" | added | opaque identifying URI diff --git a/pages/draft/2019-09/[slug].page.tsx b/pages/draft/2019-09/[slug].page.tsx index d7d289a2e..26acaf0e1 100644 --- a/pages/draft/2019-09/[slug].page.tsx +++ b/pages/draft/2019-09/[slug].page.tsx @@ -22,7 +22,7 @@ export default function StaticMarkdownPage({ frontmatter: any; content: any; }) { - const markdownFile = '_index'; + const fileRenderType = '_md'; const newTitle = 'JSON Schema - ' + frontmatter.title; return ( @@ -32,7 +32,7 @@ export default function StaticMarkdownPage({ {frontmatter.title} - + ); } diff --git a/pages/draft/2019-09/index.page.tsx b/pages/draft/2019-09/index.page.tsx index 14fb022f2..c8e7f3e2d 100644 --- a/pages/draft/2019-09/index.page.tsx +++ b/pages/draft/2019-09/index.page.tsx @@ -30,12 +30,13 @@ export default function ImplementationsPages({ blocks: any; frontmatter: any; }) { + const fileRenderType = 'indexmd'; return ( {frontmatter.title} - + ); } diff --git a/pages/draft/2019-09/release-notes.md b/pages/draft/2019-09/release-notes.md index a71d397b5..a77476ffe 100644 --- a/pages/draft/2019-09/release-notes.md +++ b/pages/draft/2019-09/release-notes.md @@ -55,8 +55,8 @@ All keywords have now been organized into [vocabularies](../../draft/2019-09/jso [Core Specification, Section 8](../../draft/2019-09/json-schema-core.html#rfc.section.8) -keyword | change | notes ----- | ---- | ---- +| keyword | change | notes +| ---- | ---- | ---- [`$anchor`](../../draft/2019-09/json-schema-core.html#rfc.section.8.2.3) | **new** | Replaces the `#plain-name` form of `$id`, with a different syntax and approach [`$defs` (renamed from `definitions`)](../../draft/2019-09/json-schema-core.html#rfc.section.8.2.5) | **renamed** | Note that the standard meta-schema still reserves `definitions` for backwards compatibility [`$id`](../../draft/2019-09/json-schema-core.html#rfc.section.8.2.2) | **changed** | Only URI-references without fragments are allowed; see `$anchor` for a replacement for plain-name fragments; all other fragments in `$id` had undefined behavior previously @@ -70,8 +70,8 @@ keyword | change | notes These keywords were formerly found in the Validation Specification. -keyword | change | notes ----- | ---- | ---- +| keyword | change | notes +| ---- | ---- | ---- [`dependentSchemas` (split from `dependencies`)](../../draft/2019-09/json-schema-core.html#rfc.section.9.2.2.4) | **split** | This is the schema form of `dependencies`; note that the standard meta-schema still reserves `dependencies` for backwards compatibility [`unevaluatedItems`](../../draft/2019-09/json-schema-core.html#rfc.section.9.3.1.3) | **new** | Similar to `additionalItems`, but can "see" into subschemas and across references [`unevaluatedProperties`](../../draft/2019-09/json-schema-core.html#rfc.section.9.3.2.4) | **new** | Similar to `additionalProperties`, but can "see" into subschemas and across references @@ -82,8 +82,8 @@ The other applicator vocabulary keywords are `items`, `additionalItems`, `proper [Validation Specification, Section 6](../../draft/2019-09/json-schema-validation.html#rfc.section.6) -keyword | change | notes ----- | ---- | ---- +| keyword | change | notes +| ---- | ---- | ---- [`dependentRequired` (split from `dependencies`)](../../draft/2019-09/json-schema-validation.html#rfc.section.6.5.4) | **split** | This is the string array form of `dependencies`; note that the standard meta-schema still reserves `dependencies` for backwards compatibility [`maxContains` and `minContains`](../../draft/2019-09/json-schema-validation.html#rfc.section.6.4.4) | **new** | Assertion for controlling how many times a subschema must be matched within an array @@ -102,11 +102,11 @@ In the following charts, the "supported" column refers to whether and (for `2019 **Summary of draft-07 behavior** -supported | configuration | outcome ------------ | ------------- | ------------- -no | n/a | not validated -yes | _default_ (on)| inconsistently validated -yes | off | not validated +| supported | configuration | outcome +| ----------- | ------------- | ------------- +| no | n/a | not validated +| yes | _default_ (on)| inconsistently validated +| yes | off | not validated Obviously, each implementation will behave consistently from schema to schema, although some formats may be supported more thoroughly than others despite the wording in the specification. However, complex formats are, in practice, supported to different degrees in each implementation. If they are supported at all. @@ -120,28 +120,28 @@ The goal with this draft is to make the default behavior predictable, with the i * An outcome of _vocabulary error_ means that the implementation will refuse to process the schema as it cannot satisfy the vocabulary requirement. -supported | configuration | vocabulary | outcome ------------ | -------------- | ------------- | ------------- -no | n/a | false | not validated -no | n/a | true | _vocabulary error_ -best effort | _default_ (off)| false | not validated -best effort | _default_ (off)| true | _vocabulary error_ -best effort | on | false | best effort validation -best effort | on | true | _vocabulary error_ -full syntax | _default_ (off)| false | not validated -full syntax | _default_ (off)| true | full syntax validation -full syntax | on | false | full syntax validation -full syntax | on | true | full syntax validation +| supported | configuration | vocabulary | outcome +| ----------- | -------------- | ------------- | ------------- +| no | n/a | false | not validated +| no | n/a | true | _vocabulary error_ +| best effort | _default_ (off)| false | not validated +| best effort | _default_ (off)| true | _vocabulary error_ +| best effort | on | false | best effort validation +| best effort | on | true | _vocabulary error_ +| full syntax | _default_ (off)| false | not validated +| full syntax | _default_ (off)| true | full syntax validation +| full syntax | on | false | full syntax validation +| full syntax | on | true | full syntax validation Note that, given that almost no draft-07 or earlier implementations have offered strict and complete validation of every single format, it seems unlikely that any implementations will support option 3 option in practice. Additionally, two new formats were added, and a specification reference was updated: -format | change | notes ----- | ---- | ---- -[`"duration"`](../../draft/2019-09/json-schema-validation.html#rfc.section.7.3.1) | **added** | The duration format is from the ISO 8601 ABNF as given in Appendix A of RFC 3339 -[`"hostname"` and `"idn-hostname"`](../../draft/2019-09/json-schema-validation.html#rfc.section.7.3.3) | **updated** | Use RFC 1123 instead of RFC 1034; this allows for a leading digit -[`"uuid"`](../../draft/2019-09/json-schema-validation.html#rfc.section.7.3.5) | **added** | A string instance is valid against this attribute if it is a valid string representation of a UUID, according to RFC4122 +|format | change | notes +| ---- | ---- | ---- +| [`"duration"`](../../draft/2019-09/json-schema-validation.html#rfc.section.7.3.1) | **added** | The duration format is from the ISO 8601 ABNF as given in Appendix A of RFC 3339 +| [`"hostname"` and `"idn-hostname"`](../../draft/2019-09/json-schema-validation.html#rfc.section.7.3.3) | **updated** | Use RFC 1123 instead of RFC 1034; this allows for a leading digit +| [`"uuid"`](../../draft/2019-09/json-schema-validation.html#rfc.section.7.3.5) | **added** | A string instance is valid against this attribute if it is a valid string representation of a UUID, according to RFC4122 #### Content Vocabulary @@ -150,23 +150,23 @@ format | change | notes These keywords are now specified purely as annotations, and never assertions. Some guidance is provided around how an implementation can optionally offer further automatic processing of this information outside of the validation process. -keyword | change | notes ----- | ---- | ---- -[`contentEncoding`](../../draft/2019-09/json-schema-validation.html#rfc.section.8.3) | **updated** | Encodings from RFC 4648 are now allowed, and take precedence over RFC 2045 when there is a difference -[`contentSchema`](../../draft/2019-09/json-schema-validation.html#rfc.section.8.5) | **added** | Schema for use with the decoded content string; note that it is _not_ automatically applied as not all content media types can be understood in advance +| keyword | change | notes +| ---- | ---- | ---- +| [`contentEncoding`](../../draft/2019-09/json-schema-validation.html#rfc.section.8.3) | **updated** | Encodings from RFC 4648 are now allowed, and take precedence over RFC 2045 when there is a difference +| [`contentSchema`](../../draft/2019-09/json-schema-validation.html#rfc.section.8.5) | **added** | Schema for use with the decoded content string; note that it is _not_ automatically applied as not all content media types can be understood in advance #### Meta-Data Vocabulary [Validation Specification, Section 9](../../draft/2019-09/json-schema-validation.html#rfc.section.9) -keyword | change | notes ----- | ---- | ---- -[`deprecated`](../../draft/2019-09/json-schema-validation.html#rfc.section.9.3) | **added** | Used to indicate that a field is deprecated in some application-specific manner +| keyword | change | notes +| ---- | ---- | ---- +| [`deprecated`](../../draft/2019-09/json-schema-validation.html#rfc.section.9.3) | **added** | Used to indicate that a field is deprecated in some application-specific manner #### Hyper-Schema Vocabulary [Hyper-Schema Specification, Sections 5 and 6](../../draft/2019-09/json-schema-hypermedia.html#rfc.section.5) -keyword | change | notes ----- | ---- | ---- -[`rel`](../../draft/2019-09/json-schema-hypermedia.html#rfc.section.6.2.1) | **changed** | Can now be an array of values instead of just a string +| keyword | change | notes +| ---- | ---- | ---- +| [`rel`](../../draft/2019-09/json-schema-hypermedia.html#rfc.section.6.2.1) | **changed** | Can now be an array of values instead of just a string diff --git a/pages/draft/2020-12/[slug].page.tsx b/pages/draft/2020-12/[slug].page.tsx index 52734da09..cc2331502 100644 --- a/pages/draft/2020-12/[slug].page.tsx +++ b/pages/draft/2020-12/[slug].page.tsx @@ -22,7 +22,7 @@ export default function StaticMarkdownPage({ frontmatter: any; content: any; }) { - const markdownFile = '_index'; + const fileRenderType = '_md'; const newTitle = 'JSON Schema - ' + frontmatter.title; return ( @@ -32,7 +32,7 @@ export default function StaticMarkdownPage({ {frontmatter.title} - + ); } diff --git a/pages/draft/2020-12/index.page.tsx b/pages/draft/2020-12/index.page.tsx index 4446b9c1b..30e21a5bd 100644 --- a/pages/draft/2020-12/index.page.tsx +++ b/pages/draft/2020-12/index.page.tsx @@ -30,12 +30,13 @@ export default function ImplementationsPages({ blocks: any; frontmatter: any; }) { + const fileRenderType = 'indexmd'; return ( {frontmatter.title} - + ); } diff --git a/pages/draft/2020-12/release-notes.md b/pages/draft/2020-12/release-notes.md index cd04ba966..72780f4fe 100644 --- a/pages/draft/2020-12/release-notes.md +++ b/pages/draft/2020-12/release-notes.md @@ -162,7 +162,6 @@ Here's how you would covert a schema using `$recursiveRef` to use `$dynamicRef`.

- ```jsonc // tree schema, extensible { @@ -189,7 +188,6 @@ Here's how you would covert a schema using `$recursiveRef` to use `$dynamicRef`. ``` - ```jsonc // tree schema, extensible { diff --git a/pages/implementers/[slug].page.tsx b/pages/implementers/[slug].page.tsx index c86202c00..c149e95eb 100644 --- a/pages/implementers/[slug].page.tsx +++ b/pages/implementers/[slug].page.tsx @@ -7,6 +7,7 @@ import getStaticMarkdownProps from '~/lib/getStaticMarkdownProps'; import { Headline1 } from '~/components/Headlines'; import { SectionContext } from '~/context'; import { DocsHelp } from '~/components/DocsHelp'; +import NextPrevButton from '~/components/NavigationButtons'; export async function getStaticPaths() { return getStaticMarkdownPaths('pages/implementers'); @@ -22,7 +23,7 @@ export default function StaticMarkdownPage({ frontmatter: any; content: any; }) { - const markdownFile = '_index'; + const fileRenderType = '_md'; const newTitle = 'JSON Schema - ' + frontmatter.title; return ( @@ -31,7 +32,13 @@ export default function StaticMarkdownPage({ {frontmatter.title} - + + ); } diff --git a/pages/implementers/_index.md b/pages/implementers/_index.md index 4468d75d0..96d0d08e3 100644 --- a/pages/implementers/_index.md +++ b/pages/implementers/_index.md @@ -1,9 +1,16 @@ --- title: "For Implementers" section: docs +prev: + label: Structuring a complex schema + url: /understanding-json-schema/structuring +next: + label: Common Interfaces across Implementations + url: /implementers/interfaces --- -For Implementers +Implement JSON Schema ========================= -Welcome to the **Implementers** section! The place for implementation maintainers' Docs. +Dive into the technical details of implementing JSON Schema. +This section is for developers building tools and libraries that work with JSON Schema. \ No newline at end of file diff --git a/pages/implementers/index.page.tsx b/pages/implementers/index.page.tsx index 425d1f4c9..f62aace0e 100644 --- a/pages/implementers/index.page.tsx +++ b/pages/implementers/index.page.tsx @@ -6,6 +6,7 @@ import StyledMarkdown from '~/components/StyledMarkdown'; import { DocsHelp } from '~/components/DocsHelp'; import { SectionContext } from '~/context'; import Card from '~/components/Card'; +import NextPrevButton from '~/components/NavigationButtons'; export async function getStaticProps() { const block1 = fs.readFileSync('pages/implementers/_index.md', 'utf-8'); @@ -16,20 +17,24 @@ export async function getStaticProps() { }, }; } - -export default function ContentExample({ blocks }: { blocks: any[] }) { - const markdownFile = '_indexPage'; - +export default function ContentExample({ + blocks, +}: { + blocks: any[]; + frontmatter: any; + content: any; +}) { + const fileRenderType = '_indexmd'; return ( -
+
- + + ); } diff --git a/pages/implementers/interfaces.md b/pages/implementers/interfaces.md index c0a54629b..e357e7345 100644 --- a/pages/implementers/interfaces.md +++ b/pages/implementers/interfaces.md @@ -1,6 +1,12 @@ --- -title: Common Interfaces across JSON Schema Implementations +title: Common interfaces across JSON Schema implementations section: implementers +prev: + label: For Implementers + url: /implementers +next: + label: Reference + url: /understanding-json-schema/reference --- JSON Schema is extremely widely used and nearly equally widely implemented. diff --git a/pages/index.page.tsx b/pages/index.page.tsx index 0b4dd2e9c..ab35d29d8 100644 --- a/pages/index.page.tsx +++ b/pages/index.page.tsx @@ -7,6 +7,7 @@ const PATH = 'pages/blog/posts'; import readingTime from 'reading-time'; import Link from 'next/link'; import TextTruncate from 'react-text-truncate'; +import Image from 'next/image'; import { fetchRemoteICalFile, printEventsForNextWeeks, @@ -106,9 +107,16 @@ const Home = (props: any) => { const [common_room_logo, setCommon_room_logo] = useState(''); const [slack_logo, setSlack_logo] = useState(''); const [ccopter_logo, setCCopter_logo] = useState(''); + const [isClient, setIsClient] = useState(false); const [octue_logo, setOctue_logo] = useState(''); const [apideck_logo, setApideck_logo] = useState(''); + const [rxdb_logo, setRxdb_logo] = useState(''); + const [wda_logo, setWDA_logo] = useState(''); + useEffect(() => { + // Ensure the component is only rendered client-side + setIsClient(true); + }, []); useEffect(() => { if (resolvedTheme === 'dark') { setAsyncapi_logo('/img/logos/dark-mode/asyncapi_white.svg'); @@ -125,6 +133,8 @@ const Home = (props: any) => { setCCopter_logo('/img/logos/sponsors/copycopter-white.png'); setOctue_logo('/img/logos/sponsors/octue-white.svg'); setApideck_logo('/img/logos/sponsors/apideck-white.svg'); + setRxdb_logo('/img/logos/sponsors/rxdb.svg'); + setWDA_logo('/img/logos/sponsors/wda-dark.svg'); } else { setAsyncapi_logo('/img/logos/sponsors/asyncapi-logo-dark.svg'); setAirbnb_logo('/img/logos/sponsors/airbnb-logo.png'); @@ -140,6 +150,8 @@ const Home = (props: any) => { setCCopter_logo('/img/logos/sponsors/copycopter.png'); setOctue_logo('/img/logos/sponsors/octue-black.svg'); setApideck_logo('/img/logos/sponsors/apideck.svg'); + setRxdb_logo('/img/logos/sponsors/rxdb.svg'); + setWDA_logo('/img/logos/sponsors/wda.svg'); } }, [resolvedTheme]); return ( @@ -177,22 +189,38 @@ const Home = (props: any) => {

Used by

- - - - + {isClient && ( + <> + zapier + microsoft + postman + github + + )}

@@ -281,10 +309,17 @@ const Home = (props: any) => { {/* SidebySide section*/}

- + {isClient && ( + <> + community + + )}

Explore the JSON Schema Ecosystem @@ -323,12 +358,30 @@ const Home = (props: any) => {

Join the JSON Schema Slack Workspace! - + {isClient && ( + <> + slack + + )}

- + {isClient && ( + <> + slack-json-schema + + )} + {/*

Event

*/}

Join our Slack to ask questions, get feedback on your @@ -340,10 +393,17 @@ const Home = (props: any) => { href='https://json-schema.org/slack' className='flex items-center ' > - + {isClient && ( + <> + slack + + )} Join Slack @@ -354,10 +414,17 @@ const Home = (props: any) => {

The JSON Schema Blog

- + {isClient && ( + <> + blog + + )}

{' '} {blogPosts[0].frontmatter.title} @@ -512,23 +579,30 @@ const Home = (props: any) => { If you ❤️ JSON Schema consider becoming a{' '} sponsor - {' '} - or a{' '} + + , a{' '} backer + {' '} + or hiring our{' '} + + pro services .

Support us! @@ -594,54 +668,154 @@ const Home = (props: any) => { target='_blank' rel='noreferrer' > - + {isClient && ( + <> + asyncapi + + )} - + {isClient && ( + <> + airbnb + + )} - + {isClient && ( + <> + postman + + )} - + {isClient && ( + <> + endjin + + )} - + {isClient && ( + <> + llc + + )} - + {isClient && ( + <> + vpsserver + + )} - + {isClient && ( + <> + itflashcards + + )} - + {isClient && ( + <> + route4me + + )} - + {isClient && ( + <> + n8n + + )} - + {isClient && ( + <> + ccopter + + )} @@ -651,7 +825,34 @@ const Home = (props: any) => { target='_blank' rel='noreferrer' > - + The Realtime Unified API
+for Accounting integrations + + + The local Database for JavaScript Applications + + + best website design agencies {
Email us {' '} @@ -701,10 +902,30 @@ const Home = (props: any) => {

{' '}
diff --git a/pages/learn/[slug].page.tsx b/pages/learn/[slug].page.tsx index f110ff75d..d186f1a4d 100644 --- a/pages/learn/[slug].page.tsx +++ b/pages/learn/[slug].page.tsx @@ -7,6 +7,7 @@ import getStaticMarkdownProps from '~/lib/getStaticMarkdownProps'; import { Headline1 } from '~/components/Headlines'; import { SectionContext } from '~/context'; import { DocsHelp } from '~/components/DocsHelp'; +import NextPrevButton from '~/components/NavigationButtons'; export async function getStaticPaths() { return getStaticMarkdownPaths('pages/learn'); @@ -22,7 +23,7 @@ export default function StaticMarkdownPage({ frontmatter: any; content: any; }) { - const markdownFile = '_index'; + const fileRenderType = '_md'; const newTitle = 'JSON Schema - ' + frontmatter.title; return ( @@ -31,7 +32,13 @@ export default function StaticMarkdownPage({ {frontmatter.title} - + + ); } diff --git a/pages/learn/file-system.md b/pages/learn/file-system.md index a408b70b1..f6ae14331 100644 --- a/pages/learn/file-system.md +++ b/pages/learn/file-system.md @@ -1,6 +1,12 @@ --- section: docs title: Modeling a file system with JSON Schema +prev: + label: Miscellaneous examples + url: /learn/miscellaneous-examples +next: + label: Other examples + url: /learn/json-schema-examples --- In this step-by-step guide you will learn how to design a JSON Schema that mirrors the structure of an `/etc/fstab` file. diff --git a/pages/learn/getting-started-step-by-step/getting-started-step-by-step.md b/pages/learn/getting-started-step-by-step/getting-started-step-by-step.md index 5926ddb1c..9fc957fbb 100644 --- a/pages/learn/getting-started-step-by-step/getting-started-step-by-step.md +++ b/pages/learn/getting-started-step-by-step/getting-started-step-by-step.md @@ -581,4 +581,4 @@ A Validator is a tool that implements the JSON Schema specification. All validat ![How JSON Schema works](https://json-schema.org/img/json_schema.svg) -To try it yourself, please visit [Tools](https://json-schema.org/tools#validators) and select the validator that better suit your needs, our use the editors available below to explore the different Schemas and Instances and see the different validation results. +To try it yourself, please visit [Tools](https://json-schema.org/tools#validators) and select the validator that better suit your needs, or use the editors available below to explore the different Schemas and Instances and see the different validation results. diff --git a/pages/learn/getting-started-step-by-step/index.page.tsx b/pages/learn/getting-started-step-by-step/index.page.tsx index b1b8b7eb2..de2cab73f 100644 --- a/pages/learn/getting-started-step-by-step/index.page.tsx +++ b/pages/learn/getting-started-step-by-step/index.page.tsx @@ -9,6 +9,7 @@ import StyledMarkdown from '~/components/StyledMarkdown'; import { SectionContext } from '~/context'; import { DocsHelp } from '~/components/DocsHelp'; import GettingStarted from '~/components/GettingStarted'; +import NextPrevButton from '~/components/NavigationButtons'; export async function getStaticProps() { const block1 = fs.readFileSync( @@ -28,9 +29,15 @@ export async function getStaticProps() { }; } -export default function StyledValidator({ blocks }: { blocks: any[] }) { +export default function StyledValidator({ + blocks, +}: { + blocks: any[]; + frontmatter: any; + content: any; +}) { const newTitle = 'Creating your first schema'; - + const fileRenderType = 'tsx'; return ( @@ -40,7 +47,13 @@ export default function StyledValidator({ blocks }: { blocks: any[] }) { - + + ); } diff --git a/pages/learn/glossary.md b/pages/learn/glossary.md index 6668ef2a6..028dc2866 100644 --- a/pages/learn/glossary.md +++ b/pages/learn/glossary.md @@ -1,6 +1,12 @@ --- -title: JSON Schema Glossary +title: JSON Schema glossary section: docs +prev: + label: Creating your first schema + url: /learn/getting-started-step-by-step +next: + label: Miscellaneous Examples + url: /learn/miscellaneous-examples --- This document collects short explanations of terminology one may encounter within the JSON Schema community. @@ -121,7 +127,7 @@ For example, the `not` keyword takes a subschema value and inverts its result, s Some subschemas may appear in more complex nested locations within a parent schema. The `allOf` keyword, for instance, takes an array of multiple subschemas and succeeds whenever all of the subschemas do individually. -Whether something that otherwise *appears* to be a schema (based on its contents) actually *is* a subschema can be misleading at first glance without context or knowlege about its location within the parent schema. +Whether something that otherwise *appears* to be a schema (based on its contents) actually *is* a subschema can be misleading at first glance without context or knowledge about its location within the parent schema. Specifically, in our above example, `{"type": "string"}` was a subschema of a larger schema, but in the schema `{"const": {"type": "string"}}`, it is *not* a subschema. Even though as a value it looks the same, the `const` keyword, which compares instances against a specific expected value, does *not* take a subschema as its value, its value is an opaque value with no particular meaning (such that in this schema, the number 12 would be invalid, but the precise instance `{"type": "string"}` is valid). Said more plainly, whether a particular value is a subschema or not depends on its precise location within a parent schema, as interpretation of the value depends on the defined behavior of the keyword(s) it lives under. diff --git a/pages/learn/guides/index.page.tsx b/pages/learn/guides/index.page.tsx new file mode 100644 index 000000000..03e6612b0 --- /dev/null +++ b/pages/learn/guides/index.page.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { getLayout } from '~/components/Sidebar'; +import Head from 'next/head'; +import { Headline1 } from '~/components/Headlines'; +import { SectionContext } from '~/context'; +import { DocsHelp } from '~/components/DocsHelp'; +import NextPrevButton from '~/components/NavigationButtons'; +import Card from '~/components/Card'; + +export default function Welcome() { + const fileRenderType = 'tsx'; + + const newTitle = 'Guides'; + return ( + + + {newTitle} + + {newTitle} +

+ Welcome to our new Guides section! +
+

+
+ +
+ + +
+ ); +} +Welcome.getLayout = getLayout; diff --git a/pages/learn/index.page.tsx b/pages/learn/index.page.tsx index 1cac2c83d..07b48be20 100644 --- a/pages/learn/index.page.tsx +++ b/pages/learn/index.page.tsx @@ -5,11 +5,11 @@ import { Headline1 } from '~/components/Headlines'; import { SectionContext } from '~/context'; import Card from '~/components/Card'; import { DocsHelp } from '~/components/DocsHelp'; +import NextPrevButton from '~/components/NavigationButtons'; export default function Welcome() { - const markdownFile = '_indexPage'; - - const newTitle = 'Getting Started'; + const fileRenderType = 'tsx'; + const newTitle = 'Get started'; return ( @@ -17,14 +17,30 @@ export default function Welcome() { {newTitle}

- New to JSON Schema and don't know where to start? -
+ New to JSON Schema and don't know where to start? Explore our learning + resources and get started with JSON Schema.

+ + + +
- + +
); } diff --git a/pages/learn/json-schema-examples.md b/pages/learn/json-schema-examples.md index d86b9656b..d775d0fdc 100644 --- a/pages/learn/json-schema-examples.md +++ b/pages/learn/json-schema-examples.md @@ -1,6 +1,12 @@ --- section: docs title: JSON Schema examples +prev: + label: Modeling a file system + url: /learn/file-system +next: + label: Guides + url: /learn/guides --- In this page, you will find examples illustrating different use cases to help you get the most out of your JSON Schemas. These examples cover a wide range of scenarios, and each example comes with accompanying JSON data and explanation, showcasing how JSON Schemas can be applied to various domains. You can modify these examples to suit your specific needs, as this is just one of the many ways you can utilize JSON Schemas. diff --git a/pages/learn/miscellaneous-examples.md b/pages/learn/miscellaneous-examples.md index ba63f03b1..80c747717 100644 --- a/pages/learn/miscellaneous-examples.md +++ b/pages/learn/miscellaneous-examples.md @@ -1,9 +1,15 @@ --- section: docs title: Miscellaneous Examples +prev : + label: Creating your first Schema + url: /learn/getting-started-step-by-step +next: + label: Modelling a file system + url: /learn/file-system --- -In this page, you will find miscellaneous examples illustrating different uses cases to help you get the most out of your JSON Schemas. Each example comes with accompanying JSON data and explanation. +In this page, you will find miscellaneous examples illustrating different use cases to help you get the most out of your JSON Schemas. Each example comes with accompanying JSON data and explanation. - [A typical minimum schema](#basic) - [Arrays of things](#arrays-of-things) diff --git a/pages/obsolete-implementations/index.page.tsx b/pages/obsolete-implementations/index.page.tsx deleted file mode 100644 index f63b7a20f..000000000 --- a/pages/obsolete-implementations/index.page.tsx +++ /dev/null @@ -1,217 +0,0 @@ -import React from 'react'; -import { getLayout } from '~/components/SiteLayout'; -import fs from 'fs'; -import matter from 'gray-matter'; -import StyledMarkdown from '~/components/StyledMarkdown'; -import yaml from 'js-yaml'; -import { Headline1, Headline2, Headline3 } from 'components/Headlines'; -import slugify from 'slugify'; -import { useRouter } from 'next/router'; -import classnames from 'classnames'; -import { SectionContext } from '~/context'; -import { DRAFT_ORDER } from '~/lib/config'; - -// @ts-ignore -import zeroFill from 'zero-fill'; - -export async function getStaticProps() { - const validators = yaml.load( - fs.readFileSync('data/validator-libraries-obsolete.yml', 'utf-8'), - ); - const hyperLibaries = yaml.load( - fs.readFileSync('data/hyper-libraries-obsolete.yml', 'utf-8'), - ); - - const intro = fs.readFileSync( - 'pages/obsolete-implementations/intro.md', - 'utf-8', - ); - const main = fs.readFileSync( - 'pages/obsolete-implementations/main.md', - 'utf-8', - ); - const main2 = fs.readFileSync( - 'pages/obsolete-implementations/main2.md', - 'utf-8', - ); - const { content: introContent } = matter(intro); - const { content: mainContent } = matter(main); - const { content: main2Content } = matter(main2); - return { - props: { - blocks: { - intro: introContent, - main: mainContent, - main2: main2Content, - }, - validators, - hyperLibaries, - }, - }; -} - -type ImplementationByLanguage = { name: string }; - -export default function ImplementationsPages({ - blocks, - validators, - hyperLibaries, -}: { - blocks: any; - validators: ImplementationByLanguage[]; - hyperLibaries: ImplementationByLanguage[]; -}) { - return ( - -
- Obsolete Tools - - Validators - - - - -
-
- ); -} -ImplementationsPages.getLayout = getLayout; -function ImplementationTable({ - implementationsByLanguage, - prefix, -}: { - implementationsByLanguage: any; - prefix: string; -}) { - const router = useRouter(); - return ( - <> -
- {implementationsByLanguage.map( - (implementationByLanguage: any, index: number) => { - const slug = - prefix + - slugify(implementationByLanguage.name, { - lower: true, - trim: true, - }); - const isActive = router.query.language === slug; - return ( - - {implementationByLanguage.name} - - ); - }, - )} -
-
- - - - - - - - - - {implementationsByLanguage.map( - (implementationByLanguage: any, index: number) => { - const slug = - prefix + - slugify(implementationByLanguage.name, { - lower: true, - trim: true, - }); - const isActive = router.query.language === slug; - if (router.query.language && !isActive) return null; - - return ( - - - - - {implementationByLanguage.implementations.map( - (implementation: any, index: number) => { - const allDrafts = [ - ...(implementation['date-draft'] || []), - ...(implementation['draft'] || []), - ]; - return ( - - - - - - - ); - }, - )} - - ); - }, - )} - -
- - About - - Drafts - - License -
- - {implementationByLanguage.name} - -
- - {implementation.name} - - - - - {allDrafts - ?.sort((a, b) => - DRAFT_ORDER.indexOf(a.toString()) < - DRAFT_ORDER.indexOf(b.toString()) - ? -1 - : 1, - ) - ?.map((draft: string | number) => ( - - {typeof draft === 'number' - ? zeroFill(2, draft) - : draft} - - ))} - - {implementation.license} -
-
- - ); -} diff --git a/pages/obsolete-implementations/intro.md b/pages/obsolete-implementations/intro.md deleted file mode 100644 index e58a83a1b..000000000 --- a/pages/obsolete-implementations/intro.md +++ /dev/null @@ -1,9 +0,0 @@ -_**NOTE:** Due to the long gap after draft-04, many projects that implemented that draft became inactive by the time draft-06 was published, or are looking for new contributors to move forward. Such projects are listed here_ - -_For implementations supporting (or actively working towards) draft-06 or later, see the main [Implementations](implementations) page._ - -Implementations below are written in different languages, and support part, or all, of the specification. - -Implementations are classified based on their functionality. When known, the license of the project is also mentioned. - -If you have updates to this list, make a pull request on the [GitHub repo](https://github.com/json-schema-org/website). diff --git a/pages/obsolete-implementations/main.md b/pages/obsolete-implementations/main.md deleted file mode 100644 index 5a00e407d..000000000 --- a/pages/obsolete-implementations/main.md +++ /dev/null @@ -1,11 +0,0 @@ - -### Benchmarks - -- Java - - [json-schema-validator-benchmark](https://github.com/networknt/json-schema-validator-perftest) - compares performance of three JSON schema validator implementations (only one of which supports draft-06+) in Java(Apache 2.0) - -- JavaScript - - [z-schema validator benchmark](https://github.com/zaggino/z-schema#benchmarks) - compares performance in the individual tests from JSON-Schema Test Suite (MIT) - - [JSCK validator benchmark](https://github.com/pandastrike/jsck#benchmarks) - shows performance for JSON-schemas of different complexity (MIT) - -## Hyper-Schema \ No newline at end of file diff --git a/pages/obsolete-implementations/main2.md b/pages/obsolete-implementations/main2.md deleted file mode 100644 index 01925db16..000000000 --- a/pages/obsolete-implementations/main2.md +++ /dev/null @@ -1,85 +0,0 @@ - -Schema Generators ------------------ - -- Python - - [JSL](https://github.com/aromanovich/jsl) (BSD) - a Python DSL for defining JSON Schemas -- JavaScript - - [json-schema-generator](https://github.com/krg7880/json-schema-generator) (MIT) - Node.js library usable both as a CLI util and as a Node module -- TypeScript - - [Typson](https://github.com/lbovet/typson) (Apache 2.0) -- Visual Studio - - [JSON Schema Generator](https://visualstudiogallery.msdn.microsoft.com/b4515ef8-a518-41ca-b48c-bb1fd4e6faf7) - free extension -- Sparx Enterprise Architect - - [API-Add-In](https://github.com/bayeslife/api-add-in) - Sparx EA extension for exporting JSON Schema from UML models - -Generators from schemas ------------------------ - -#### Data from schemas - -- JavaScript - - [json-schema-generator](https://github.com/json-schema-faker) (MIT) - JSON-Schema + fake data generators - -Data Parsing and Code Generation --------------------------------- - -- Delphi - - [DJsonSchema](https://github.com/schlothauer-wauer/DJsonSchema) (MIT) - JSON Schema reader and code generator for Delphi. -- Haskell - - [aeson-schema](https://github.com/Fuuzetsu/aeson-schema) (MIT) - generates code for a parser -- Ruby - - [autoparse](https://github.com/google/autoparse) (ASL 2.0) -- Scala - - [json-schema-codegen](https://github.com/VoxSupplyChain/json-schema-codegen) - Tool and SBT plugin for generating Scala, TypeScript models and parsers from Json-Schema definitions, *supports draft 4* (Apache 2.0) - - [Argus](https://github.com/aishfenton/argus) (MIT) - Macros for building models from JSON Schemas -- Swift - - [Bric-à-brac](https://github.com/glimpseio/BricBrac) (MIT) - generates idiomatic swift structs and parser/serializer from JSON schemas -- Golang - - [gojsonschema](https://github.com/andy-zhangtao/gojsonschema)(Apache 2.0) - golang package for generating golang struct *support for Draft 4*. [Demo](http://json.golang.chinazt.cc) - -UI Generation -------------- - -_TODO: Sort by draft support._ - -Various levels of support for UI generation primarily from the validation vocabulary or combined with UI specific definition. - -- JavaScript - - [JSON Editor](https://github.com/jdorn/json-editor) (MIT) - - [JSONForms](https://jsonforms.io) (EclipseSource) (MIT) - - [Jsonary](https://jsonary.com/) (MIT) - - [Metawidget](https://metawidget.org/) (LGPL) - - [pure-form webcomponent](https://github.com/john-doherty/pure-form) (MIT) - -Editors -------- - -- [Liquid XML Studio 2016](https://www.liquid-technologies.com/json-schema-editor) - *Graphical JSON schema editor for draft 4, context sensitive intellisense for JSON documents.* -- [ReSharper 2016.1](https://www.jetbrains.com/resharper/) - *code completion, inspections and quick fixes for JSON schema in Visual Studio 2010 - 2015, including support for JSON Path and regular expressions for schema editing. Support for draft-4* -- [Visual Studio 2013](http://www.visualstudio.com/) - *Auto-completion and tooltips based on JSON schema draft 3 and draft 4* -- [JSON Schema Editor](https://json-schema-editor.tangramjs.com) - *An intuitive editor for JSON schema online* -- [JSON Editor](https://json-editor.tangramjs.com) - *An online, schema-aware editor for JSON document* - -Compatibility -------------- - -- JavaScript - - [JSON Schema Compatibility](https://github.com/geraintluff/json-schema-compatability) - *converts draft 3 to draft 4* (Public Domain) - - -Documentation generation ------------------------- - -- JavaScript - - [Matic](https://github.com/mattyod/matic) (MIT) - - [Docson](https://github.com/lbovet/docson) (Apache 2.0) - - [doca](https://github.com/cloudflare/doca/) (BSD) See [@cloudflare/doca](https://github.com/cloudflare/json-schema-tools/tree/master/workspaces/doca) for draft-06+ support - - [prmd](https://github.com/interagent/prmd) (MIT) - -Other ------ - -- JavaScript - - [Dojo](https://www.dojotoolkit.org/) (AFL or BSD) - supports some aspects of JSON Schema - - [JSON Schema Random](https://github.com/andreineculau/json-schema-random) (Apache 2.0) diff --git a/pages/overview/[slug].page.tsx b/pages/overview/[slug].page.tsx index e4d5476d7..c50fa4f39 100644 --- a/pages/overview/[slug].page.tsx +++ b/pages/overview/[slug].page.tsx @@ -7,6 +7,7 @@ import getStaticMarkdownProps from '~/lib/getStaticMarkdownProps'; import { Headline1 } from '~/components/Headlines'; import { SectionContext } from '~/context'; import { DocsHelp } from '~/components/DocsHelp'; +import NextPrevButton from '~/components/NavigationButtons'; export async function getStaticPaths() { return getStaticMarkdownPaths('pages/overview'); @@ -22,7 +23,7 @@ export default function StaticMarkdownPage({ frontmatter: any; content: any; }) { - const markdownFile = '_index'; + const fileRenderType = '_md'; const newTitle = 'JSON Schema - ' + frontmatter.title; return ( @@ -32,7 +33,13 @@ export default function StaticMarkdownPage({ {frontmatter.title} - + + ); } diff --git a/pages/overview/case-studies/index.page.tsx b/pages/overview/case-studies/index.page.tsx index 81c761ca6..239d551cd 100644 --- a/pages/overview/case-studies/index.page.tsx +++ b/pages/overview/case-studies/index.page.tsx @@ -7,10 +7,11 @@ import data from 'data/case-studies.json'; import Card from '~/components/Card'; import { DocsHelp } from '~/components/DocsHelp'; import { useTheme } from 'next-themes'; +import NextPrevButton from '~/components/NavigationButtons'; export default function ContentExample() { const newTitle = 'Case Studies'; - const markdownFile = '_indexPage'; + const fileRenderType = 'tsx'; const { resolvedTheme } = useTheme(); const imgUrl = (src: string): string => { @@ -30,10 +31,8 @@ export default function ContentExample() { {newTitle}

- {/* Please fix below dummy text and make it two to three liner so that we can remove the bug of layout shifting :) */} - Learn how organizations are adopting and benefiting from JSON Schema. - Please replace this text with a two to three liner so that we can avoid - the layout shifting bug. + Learn how organizations are adopting JSON Schema to improve data + management, ensure consistency, and streamline workflows across systems.

{data.map((element, index) => ( @@ -47,7 +46,13 @@ export default function ContentExample() { /> ))}
- + + ); } diff --git a/pages/overview/code-of-conduct/index.page.tsx b/pages/overview/code-of-conduct/index.page.tsx index c4d74033e..75e6000f2 100644 --- a/pages/overview/code-of-conduct/index.page.tsx +++ b/pages/overview/code-of-conduct/index.page.tsx @@ -6,6 +6,7 @@ import matter from 'gray-matter'; import StyledMarkdown from '~/components/StyledMarkdown'; import { SectionContext } from '~/context'; import { DocsHelp } from '~/components/DocsHelp'; +import NextPrevButton from '~/components/NavigationButtons'; export async function getStaticProps() { const block = fs.readFileSync( @@ -20,16 +21,29 @@ export async function getStaticProps() { }; } -export default function Content({ blocks }: { blocks: any[] }) { +export default function Content({ + blocks, +}: { + blocks: any[]; + frontmatter: any; + content: any; +}) { const newTitle = 'Code of Conduct'; - + const fileRenderType = + 'https://github.com/json-schema-org/.github/blob/main/CODE_OF_CONDUCT.md'; return ( {newTitle} - + + ); } diff --git a/pages/overview/faq/index.page.tsx b/pages/overview/faq/index.page.tsx index 283edf29e..10bb260cb 100644 --- a/pages/overview/faq/index.page.tsx +++ b/pages/overview/faq/index.page.tsx @@ -5,10 +5,11 @@ import { SectionContext } from '~/context'; import Faq from '~/components/Faq'; import { Headline1 } from '~/components/Headlines'; import { DocsHelp } from '~/components/DocsHelp'; +import NextPrevButton from '~/components/NavigationButtons'; export default function Content() { const newTitle = 'FAQ'; - const markdownFile = '_indexPage'; + const fileRenderType = 'tsx'; return ( @@ -20,8 +21,15 @@ export default function Content() { Below you'll find answers to questions we get asked the most about JSON Schema.

+ - + +
); } diff --git a/pages/overview/pro-help/index.page.tsx b/pages/overview/pro-help/index.page.tsx new file mode 100644 index 000000000..61e33cc97 --- /dev/null +++ b/pages/overview/pro-help/index.page.tsx @@ -0,0 +1,223 @@ +import React from 'react'; +import fs from 'fs'; +import { getLayout } from '~/components/Sidebar'; +import Head from 'next/head'; +import { Headline1 } from '~/components/Headlines'; +import { SectionContext } from '~/context'; +import { DocsHelp } from '~/components/DocsHelp'; +import NextPrevButton from '~/components/NavigationButtons'; + +interface ContractorLink { + title: string; + url: string; +} + +interface Contractor { + name: string; + bio: string; + email?: string; + website?: string; + github: string; + x?: string; + mastodon?: string; + linkedin?: string; + incorporatedIn: string[]; + type: string; + links: ContractorLink[]; +} + +export async function getStaticProps() { + const contractorData = JSON.parse( + fs.readFileSync( + '_includes/community/programs/contractors/contractors.json', + 'utf-8', + ), + ) as Contractor[]; + + return { + props: { + contractorData, + }, + }; +} + +interface ProHelpPageProps { + contractorData: Contractor[]; +} + +export default function ProHelp({ contractorData }: ProHelpPageProps) { + const newTitle = 'Need pro help with JSON Schema?'; + + return ( + + + {newTitle} + +
+
+ {newTitle} +

+ Whether you need training, personalized advice, or custom JSON + Schema solutions, some members of the JSON Schema Technical Steering + Committee (TSC) and Ambassadors programs offer pro services beyond + community support. Don't hesitate in reaching out to discuss + further. +

+
+

+ Hiring our top contributors also helps funding the JSON Schema + open-source organization, and as a consequence, the specifications + that build on top of it, such as{' '} + + OpenAPI + + , + + AsyncAPI + + , + + RAML + + , + + W3C WoT + + , and many more. +

+
+ Available Members +
+ {contractorData.map((contractor) => ( +
+

+ {contractor.name} + + {contractor.type} + +

+ +
+ +
+

{contractor.bio}

+

+ Previous work and relevant links +

+ +
+
+
+ ))} +
+
+
+
+
+ + +
+
+ ); +} + +ProHelp.getLayout = getLayout; diff --git a/pages/overview/roadmap/index.page.tsx b/pages/overview/roadmap/index.page.tsx index 8f3c0d92a..e22e358f5 100644 --- a/pages/overview/roadmap/index.page.tsx +++ b/pages/overview/roadmap/index.page.tsx @@ -5,6 +5,7 @@ import Head from 'next/head'; import { Headline1 } from '~/components/Headlines'; import { SectionContext } from '~/context'; import roadmap from '~/data/roadmap.json'; +import NextPrevButton from '~/components/NavigationButtons'; const statusColors = { 'In Progress': 'bg-green-600 text-white dark:bg-green-500', @@ -34,7 +35,7 @@ const impactColors = { export default function Roadmap() { const newTitle = 'JSON Schema Roadmap'; - const markdownFile = '_indexPage'; + const fileRenderType = 'tsx'; return ( @@ -130,7 +131,13 @@ export default function Roadmap() { - + + ); } diff --git a/pages/overview/similar-technologies.md b/pages/overview/similar-technologies.md index c4693704f..88603abe5 100644 --- a/pages/overview/similar-technologies.md +++ b/pages/overview/similar-technologies.md @@ -1,6 +1,12 @@ --- section: docs title: Similar Technologies +prev: + label: Pro Help + url: '/overview/pro-help' +next: + label: Code of Conduct + url: '/overview/code-of-conduct' --- While we think that JSON Schema has a unique value proposition, we'd like to provide visibility to other technologies that share similar goals: diff --git a/pages/overview/sponsors/index.page.tsx b/pages/overview/sponsors/index.page.tsx index a26f1dfe7..c3c59d4ee 100644 --- a/pages/overview/sponsors/index.page.tsx +++ b/pages/overview/sponsors/index.page.tsx @@ -7,6 +7,7 @@ import matter from 'gray-matter'; import StyledMarkdown from '~/components/StyledMarkdown'; import { SectionContext } from '~/context'; import { DocsHelp } from '~/components/DocsHelp'; +import NextPrevButton from '~/components/NavigationButtons'; export async function getStaticProps() { const block1 = fs.readFileSync('pages/overview/sponsors/_index.md', 'utf-8'); @@ -20,7 +21,8 @@ export async function getStaticProps() { export default function ContentExample({ blocks }: { blocks: any[] }) { const newTitle = 'Sponsors'; - + const fileRenderType = + 'https://github.com/json-schema-org/community/blob/main/programs/sponsors/sponsors.md'; return ( @@ -28,7 +30,13 @@ export default function ContentExample({ blocks }: { blocks: any[] }) { {newTitle} - + + ); } diff --git a/pages/overview/use-cases/index.page.tsx b/pages/overview/use-cases/index.page.tsx index 6e2811a51..466a59158 100644 --- a/pages/overview/use-cases/index.page.tsx +++ b/pages/overview/use-cases/index.page.tsx @@ -6,10 +6,11 @@ import { Headline1 } from '~/components/Headlines'; import Card from '~/components/Card'; import data from '~/data/use-cases.json'; import { DocsHelp } from '~/components/DocsHelp'; +import NextPrevButton from '~/components/NavigationButtons'; export default function Content() { const newTitle = 'Use Cases'; - const markdownFile = '_indexPage'; + const fileRenderType = 'tsx'; return ( @@ -19,8 +20,8 @@ export default function Content() { {newTitle}

Discover everything you can do with JSON Schema. This section presents - the most common use cases for JSON Schema, but but there may be many - more applications waiting to be discovered. + the most common use cases for JSON Schema, but there may be many more + applications waiting to be discovered.

{data.map((element, index) => ( @@ -29,13 +30,19 @@ export default function Content() { title={element.title} body={element.summary} icon='/icons/bulb2.svg' - headerSize={'medium'} - extended={true} - bodyTextSize={'small'} + headerSize='medium' + extended + bodyTextSize='small' /> ))}
- + +
); } diff --git a/pages/overview/what-is-jsonschema.md b/pages/overview/what-is-jsonschema.md index 4c1ccc826..b5c48c16e 100644 --- a/pages/overview/what-is-jsonschema.md +++ b/pages/overview/what-is-jsonschema.md @@ -1,6 +1,9 @@ --- section: docs title: What is JSON Schema? +next: + label: Roadmap + url: '/overview/roadmap' --- > JSON Schema is a declarative language for defining structure and constraints for JSON data.
diff --git a/pages/specification-links.md b/pages/specification-links.md index a327ef50d..18bf4a524 100644 --- a/pages/specification-links.md +++ b/pages/specification-links.md @@ -1,6 +1,12 @@ --- title: Specification Links section: docs +prev: + label: Specification + url: /specification +next: + label: Migration + url: /specification/migration --- @@ -498,8 +504,8 @@ The next unreleased draft is a work in progress. You can [give feedback and get The specification links here link to the raw sources. We do not provide rendered [work-in-progress](work-in-progress) drafts except near the very end of a publication cycle, during the final review period. - - Core: [jsonschema-core.md](https://github.com/json-schema-org/json-schema-spec/blob/main/jsonschema-core.md) - - Validation: [jsonschema-validation.md](https://github.com/json-schema-org/json-schema-spec/blob/main/jsonschema-validation.md) + - Core: [jsonschema-core.md](https://github.com/json-schema-org/json-schema-spec/blob/main/specs/jsonschema-core.md) + - Validation: [jsonschema-validation.md](https://github.com/json-schema-org/json-schema-spec/blob/main/specs/jsonschema-validation.md) - Hyper-Schema: [jsonschema-hyperschema.xml](https://github.com/json-schema-org/json-hyperschema-spec/blob/main/jsonschema-hyperschema.xml) - Relative JSON Pointer: [relative-json-pointer.xml](https://github.com/json-schema-org/json-schema-spec/blob/master/relative-json-pointer.xml) - [JSON Schema meta-schema](https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json) diff --git a/pages/specification.md b/pages/specification.md index 1f449f52f..f013bd903 100644 --- a/pages/specification.md +++ b/pages/specification.md @@ -1,6 +1,12 @@ --- title: Specification [#section] section: docs +prev: + label: Common Interfaces across Implementations + url: /implementers/interfaces +next: + label: Specification Links + url: /specification-links --- The current version is *2020-12*! diff --git a/pages/specification/json-hyper-schema/_index.md b/pages/specification/json-hyper-schema/_index.md index 585f10464..298abdb71 100644 --- a/pages/specification/json-hyper-schema/_index.md +++ b/pages/specification/json-hyper-schema/_index.md @@ -1,5 +1,11 @@ --- title: JSON Hyper-Schema +prev: + label: Release Notes + url: /specification/release-notes +next: + label: What is JSON Schema? + url: /overview/what-is-jsonschema --- ### Introduction diff --git a/pages/specification/json-hyper-schema/index.page.tsx b/pages/specification/json-hyper-schema/index.page.tsx index b1ce3264f..83d5376d8 100644 --- a/pages/specification/json-hyper-schema/index.page.tsx +++ b/pages/specification/json-hyper-schema/index.page.tsx @@ -6,6 +6,7 @@ import StyledMarkdown from '~/components/StyledMarkdown'; import { SectionContext } from '~/context'; import { Headline1 } from '~/components/Headlines'; import { DocsHelp } from '~/components/DocsHelp'; +import NextPrevButton from '~/components/NavigationButtons'; export async function getStaticProps() { const index = fs.readFileSync( @@ -35,7 +36,7 @@ export default function ImplementationsPages({ blocks: any; frontmatter: any; }) { - const markdownFile = '_indexPage'; + const fileRenderType = '_indexmd'; return ( {frontmatter.title} @@ -44,7 +45,13 @@ export default function ImplementationsPages({ - + + ); } diff --git a/pages/specification/migration/_index.md b/pages/specification/migration/_index.md index 734bd0b33..f6e44d8a5 100644 --- a/pages/specification/migration/_index.md +++ b/pages/specification/migration/_index.md @@ -1,6 +1,12 @@ --- title: Migrating from older drafts section: docs +prev: + label: Specification Links + url: /specification-links +next: + label: Release Notes + url: /specification/release-notes --- The release notes discuss the changes impacting users and implementers: diff --git a/pages/specification/migration/index.page.tsx b/pages/specification/migration/index.page.tsx index fbba9bd33..8afad3be4 100644 --- a/pages/specification/migration/index.page.tsx +++ b/pages/specification/migration/index.page.tsx @@ -7,6 +7,7 @@ import { Headline1 } from '~/components/Headlines'; import { SectionContext } from '~/context'; import Card from '~/components/Card'; import { DocsHelp } from '~/components/DocsHelp'; +import NextPrevButton from '~/components/NavigationButtons'; export async function getStaticProps() { const index = fs.readFileSync( @@ -36,13 +37,13 @@ export default function ImplementationsPages({ blocks: any; frontmatter: any; }) { - const markdownFile = '_indexPage'; + const fileRenderType = '_indexmd'; return ( {frontmatter.title} -
+
- + + ); } diff --git a/pages/specification/release-notes/_index.md b/pages/specification/release-notes/_index.md index bfe2815c1..33276297c 100644 --- a/pages/specification/release-notes/_index.md +++ b/pages/specification/release-notes/_index.md @@ -1,6 +1,12 @@ --- title: Release notes type: docs +prev: + label: Migration + url: /specification/migration +next: + label: JSON Hyper-Schema + url: /specification/json-hyper-schema --- Find below the Release Notes of all JSON Schema drafts: diff --git a/pages/specification/release-notes/index.page.tsx b/pages/specification/release-notes/index.page.tsx index 50ea7f7d5..bce092d47 100644 --- a/pages/specification/release-notes/index.page.tsx +++ b/pages/specification/release-notes/index.page.tsx @@ -7,6 +7,7 @@ import { Headline1 } from '~/components/Headlines'; import { SectionContext } from '~/context'; import Card from '~/components/Card'; import { DocsHelp } from '~/components/DocsHelp'; +import NextPrevButton from '~/components/NavigationButtons'; export async function getStaticProps() { const index = fs.readFileSync( @@ -36,13 +37,13 @@ export default function ImplementationsPages({ blocks: any; frontmatter: any; }) { - const markdownFile = '_indexPage'; + const fileRenderType = '_indexmd'; return ( {frontmatter.title} -
+
- + + ); } diff --git a/pages/tools/JSONSchemaTool.ts b/pages/tools/JSONSchemaTool.ts index 6cdc016c4..b700edac7 100644 --- a/pages/tools/JSONSchemaTool.ts +++ b/pages/tools/JSONSchemaTool.ts @@ -34,6 +34,7 @@ export interface JSONSchemaTool { optOut?: boolean; }; lastUpdated?: string; + status?: 'obsolete'; } export interface Person { diff --git a/pages/tools/components/Sidebar.tsx b/pages/tools/components/Sidebar.tsx index 69f97e325..5a1c75717 100644 --- a/pages/tools/components/Sidebar.tsx +++ b/pages/tools/components/Sidebar.tsx @@ -54,7 +54,11 @@ export default function Sidebar({ environments: formData .getAll('environments') .map((value) => value as string), - }; + showObsolete: + (formData.get('showObsolete') as string) === 'showObsolete' + ? 'true' + : 'false', + } satisfies Transform; postAnalytics({ eventType: 'query', eventPayload: newTransform }); return newTransform; }); @@ -95,6 +99,12 @@ export default function Sidebar({ ); })} +
{tool.landscape?.logo && (
- landscape logos
)}
-

{tool.name}

+

+ {tool.name} + {tool.status === 'obsolete' && ( + {tool.status} + )} +

{tool.description && (

{tool.description} @@ -123,7 +146,7 @@ export default function ToolingDetailModal({ {tool.toolingListingNotes && (

Tooling Listing Notes

-

{tool.toolingListingNotes}

+
)} @@ -330,22 +353,40 @@ const BowtieReportBadge = ({ uri }: { uri: string }) => { const [loading, setLoading] = useState(true); const [error, setError] = useState(false); + useEffect(() => { + const checkImage = async () => { + try { + const response = await fetch( + `https://img.shields.io/endpoint?url=${encodeURIComponent(uri)}`, + ); + if (response.ok) { + setLoading(false); + } else { + setLoading(false); + setError(true); + } + } catch (err) { + setLoading(false); + setError(true); + } + }; + checkImage(); + }, [uri]); + return (
{loading && !error && (
)} - setLoading(false)} - onError={() => { - setLoading(false); - setError(true); - }} - style={{ display: loading ? 'none' : 'block' }} - alt='Bowtie Badge' - className='my-1' - /> + {!loading && !error && ( + Bowtie Badge + )} {error && (
Failed to load badge
)} diff --git a/pages/tools/components/ToolingTable.tsx b/pages/tools/components/ToolingTable.tsx index 16b549013..01aec8678 100644 --- a/pages/tools/components/ToolingTable.tsx +++ b/pages/tools/components/ToolingTable.tsx @@ -18,6 +18,7 @@ import Badge from './ui/Badge'; import ToolingDetailModal from './ToolingDetailModal'; import classnames from 'classnames'; import { postAnalytics } from '../lib/postAnalytics'; +import Tag from './ui/Tag'; interface ToolingTableProps { toolsByGroup: GroupedTools; @@ -177,16 +178,19 @@ const ToolingTable = ({ > segment.length > 25) ? 'break-all' : ''}`, + className: `${tool.name.split(' ').some((segment) => segment.length > 25) ? 'break-all' : ''} gap-x-2 gap-y-1`, style: { flexBasis: '240px', - flexShrink: 0, + flexShrink: 1, flexGrow: 0, }, title: 'See details', }} > {tool.name} + {tool.status === 'obsolete' && ( + {tool.status} + )} {transform.groupBy !== 'toolingTypes' && ( diff --git a/pages/tools/components/ui/Checkbox.tsx b/pages/tools/components/ui/Checkbox.tsx index 4f7daaed6..2fc7dea6d 100644 --- a/pages/tools/components/ui/Checkbox.tsx +++ b/pages/tools/components/ui/Checkbox.tsx @@ -22,7 +22,7 @@ export default function Checkbox({ }; return ( -