Skip to content

Instantly share code, notes, and snippets.

@ajlende
Last active June 26, 2024 01:52
Show Gist options
  • Save ajlende/dd52732f313f9c8abdd8245f41855957 to your computer and use it in GitHub Desktop.
Save ajlende/dd52732f313f9c8abdd8245f41855957 to your computer and use it in GitHub Desktop.
WordPres JSON Schema Tools

WordPress JSON Schema Tools

Provides a few utility commands for managing WordPress JSON files with schemas.

Configure Schema Validation

Initializes AJV-based JSON Schema validation for WordPress schemas for 'theme' or 'block' projects.

It supports schemas using both draft-04 and draft-07 JSON Schema metaschemas.

WARNING: This script will update your package.json file. ⚠️

  • If you do not have a package.json file yet, make sure to update the author, license, and version fields to match your theme or plugin.
  • If you already have a package.json file, you may revert any changes made to the dependencies list. Only devDependencies are installed, but npm init will add everything from node_modules to dependencies if node_modules already exists.

Requiremens

Node 20.10.0 or later and npm 10.2.3 or later. https://nodejs.org/en/download/

Download

curl -O https://gist.githubusercontent.com/ajlende/dd52732f313f9c8abdd8245f41855957/raw/init-validation.sh

Block Theme Usage

Validates block theme JSON files:

  • theme.json
  • styles/*.json
  • assets/fonts/*.json
bash -x init-validation.sh theme

Block Plugin Usage

Validates block plugin JSON files

  • blocks/**/block.json
bash -x init-validation.sh block

Update WordPress Schema Versions

Updates the $schema to use the given WordPress version for all WordPress files that support it in block themes and block plugins.

Only works on files that already declare a $schema.

Download

curl -O https://gist.githubusercontent.com/ajlende/dd52732f313f9c8abdd8245f41855957/raw/update-schema.sh

Block Theme Usage

Updates block theme JSON files:

  • theme.json
  • styles/*.json
  • assets/fonts/*.json
bash -x update-schema.sh 6.6

Block Plugin Usage

Updates block theme JSON files:

  • blocks/**/block.json
bash -x update-schema.sh 6.6
#!/usr/bin/env bash
# Description: Initializes AJV-based JSON Schema validation for WordPress
# schemas for 'theme' or 'block' projects.
# Usage: bash -x init-validation.sh <type>
# Example: bash -x init-validation.sh theme
# Install node and npm if you haven't already.
if ! command -v node &> /dev/null; then
echo "Please install Node.js and npm. https://nodejs.org/en/download/"
exit 1
fi
# Get the array of files to validate based on the type.
case "$1" in
theme)
files=(theme.json 'styles/*.json' 'assets/fonts/*.json')
;;
block)
files=('blocks/**/block.json')
;;
*)
echo "Please provide a type. Use 'theme' or 'block'."
exit 1
;;
esac
# Initialize an npm project if you haven't already.
npm init --yes
# Scripts are written for Node 20.10.0 and npm 10.2.3.
npm pkg set \
engines.node='>=20.10.0' \
engines.npm='>=10.2.3'
# Install the Ajv JSON Schema validator used in the validation script.
npm install --save-dev ajv ajv-draft-04
# Update the test script to run the validation script for all files for the given type.
npm pkg set scripts.test="node validate-schema.mjs ${files[*]}"
# Create the validation script.
curl -O https://gist.githubusercontent.com/ajlende/dd52732f313f9c8abdd8245f41855957/raw/validate-schema.mjs
# Remainder of the commands only work if you're in a git repository.
[ -d .git ] || exit 0
# Create or edit .gitignore file to ignore the node_modules directory.
grep -q "node_modules" .gitignore &> /dev/null; [ $? -eq 0 ] || echo "node_modules" >> .gitignore
# Install Husky and Lint-Staged to run the validation script on commit.
npm install --save-dev husky lint-staged
# Allow the prepare script to run without Husky installed.
npm pkg set \
scripts.prepare='husky || true'
# Create the Husky configuration and pre-commit hook.
cat > .husky/pre-commit << EOF
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
EOF
# Configure Lint-Staged to run the validation scripts on the given type of files.
cat > .lintstagedrc.json << EOF
{
"{$(IFS=,; echo "${files[*]}")}": "node validate-schema.mjs"
}
EOF
# Run the prepare script to install Husky scripts.
npm run prepare
#!/usr/bin/env bash
# Description: Updates the $schema to use the given WordPress version for all
# WordPress files that support it. Only works on files that already
# declare a $schema.
# Usage: bash -x update-schema.sh <version>
# Example: bash -x update-schema.sh 6.6
# theme.json and variations
for file in theme.json styles/*.json; do
echo "Updating $file"
perl -pi -e 's/"\$schema":\s*"[^"]*"/"\$schema": "https:\/\/schemas\.wp\.org\/wp\/'$1'\/theme.json"/' $file
done
# font collection files
for file in assets/fonts/*.json; do
echo "Updating $file"
perl -pi -e 's/"\$schema":\s*"[^"]*"/"\$schema": "https:\/\/schemas\.wp\.org\/wp\/'$1'\/font-collection.json"/' $file
done
# block.json files in the blocks directory
for file in blocks/**/block.json; do
echo "Updating $file"
perl -pi -e 's/"\$schema":\s*"[^"]*"/"\$schema": "https:\/\/schemas\.wp\.org\/wp\/'$1'\/block.json"/' $file
done
import fs from 'node:fs';
import path from 'node:path';
import process from 'node:process';
import Ajv from 'ajv';
import AjvDraft04 from 'ajv-draft-04';
async function validateSchema( files ) {
function readJson( file ) {
return fs.promises.readFile( file, 'utf-8' ).then( JSON.parse );
}
async function loadSchema( uri, dirname = '' ) {
if ( ! uri ) {
return {
$schema: 'http://json-schema.org/draft-07/schema#',
type: 'object',
required: [ '$schema' ],
};
}
if ( ! URL.canParse( uri ) ) {
return readJson( path.resolve( dirname, uri ) );
}
const url = new URL( uri );
if ( url.protocol === 'http:' || url.protocol === 'https:' ) {
return fetch( url ).then( ( res ) => res.json() );
}
if ( url.protocol === 'file:' ) {
return readJson( path.resolve( dirname, url.href.slice( 7 ) ) );
}
throw new Error( `Unsupported schema protocol: ${ url.protocol }` );
}
const ajvOptions = {
allowMatchingProperties: true,
allErrors: true,
loadSchema,
};
const ajv = {
'http://json-schema.org/draft-07/schema#': new Ajv( ajvOptions ),
'http://json-schema.org/draft-04/schema#': new AjvDraft04( ajvOptions ),
};
const errors = [];
for ( const file of files ) {
let schemaUri;
try {
const data = await readJson( file );
schemaUri = data.$schema;
const schema = await loadSchema( schemaUri, path.dirname( file ) );
const validate = await ajv[ schema.$schema ].compileAsync( schema );
if ( ! validate( data ) ) {
throw validate.errors;
}
} catch ( error ) {
errors.push( { file, schema: schemaUri, error } );
}
}
if ( errors.length ) {
console.dir( errors, { depth: null } );
process.exit( 1 );
}
}
validateSchema( process.argv.slice( 2 ) );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment