Skip to content

Instantly share code, notes, and snippets.

@adamziel
Last active February 9, 2022 12:43
Show Gist options
  • Save adamziel/5919335be693bb45ae03019b7bcf5a96 to your computer and use it in GitHub Desktop.
Save adamziel/5919335be693bb45ae03019b7bcf5a96 to your computer and use it in GitHub Desktop.
Compile WordPress API JSON Schema to TypeScript type definitions for entity records
const __ = (x) => x;
export const defaultEntities = [
{
label: __( 'Base' ),
name: '__unstableBase',
kind: 'root',
baseURL: '/',
},
{
label: __( 'Site' ),
name: 'site',
kind: 'root',
baseURL: '/wp/v2/settings',
getTitle: ( record ) => {
return get( record, [ 'title' ], __( 'Site Title' ) );
},
},
{
label: __( 'Post Type' ),
name: 'postType',
kind: 'root',
key: 'slug',
baseURL: '/wp/v2/types',
baseURLParams: { context: 'edit' },
},
{
name: 'media',
kind: 'root',
baseURL: '/wp/v2/media',
baseURLParams: { context: 'edit' },
plural: 'mediaItems',
label: __( 'Media' ),
},
{
name: 'taxonomy',
kind: 'root',
key: 'slug',
baseURL: '/wp/v2/taxonomies',
baseURLParams: { context: 'edit' },
plural: 'taxonomies',
label: __( 'Taxonomy' ),
},
{
name: 'sidebar',
kind: 'root',
baseURL: '/wp/v2/sidebars',
plural: 'sidebars',
transientEdits: { blocks: true },
label: __( 'Widget areas' ),
},
{
name: 'widget',
kind: 'root',
baseURL: '/wp/v2/widgets',
baseURLParams: { context: 'edit' },
plural: 'widgets',
transientEdits: { blocks: true },
label: __( 'Widgets' ),
},
{
name: 'widgetType',
kind: 'root',
baseURL: '/wp/v2/widget-types',
baseURLParams: { context: 'edit' },
plural: 'widgetTypes',
label: __( 'Widget types' ),
},
{
label: __( 'User' ),
name: 'user',
kind: 'root',
baseURL: '/wp/v2/users',
baseURLParams: { context: 'edit' },
plural: 'users',
},
{
name: 'comment',
kind: 'root',
baseURL: '/wp/v2/comments',
baseURLParams: { context: 'edit' },
plural: 'comments',
label: __( 'Comment' ),
},
{
name: 'menu',
kind: 'root',
baseURL: '/wp/v2/menus',
baseURLParams: { context: 'edit' },
plural: 'menus',
label: __( 'Menu' ),
},
{
name: 'menuItem',
kind: 'root',
baseURL: '/wp/v2/menu-items',
baseURLParams: { context: 'edit' },
plural: 'menuItems',
label: __( 'Menu Item' ),
rawAttributes: [ 'title', 'content' ],
},
{
name: 'menuLocation',
kind: 'root',
baseURL: '/wp/v2/menu-locations',
baseURLParams: { context: 'edit' },
plural: 'menuLocations',
label: __( 'Menu Location' ),
key: 'name',
},
{
name: 'navigationArea',
kind: 'root',
baseURL: '/wp/v2/block-navigation-areas',
baseURLParams: { context: 'edit' },
plural: 'navigationAreas',
label: __( 'Navigation Area' ),
key: 'name',
getTitle: ( record ) => record?.description,
},
{
label: __( 'Global Styles' ),
name: 'globalStyles',
kind: 'root',
baseURL: '/wp/v2/global-styles',
baseURLParams: { context: 'edit' },
plural: 'globalStylesVariations', // should be different than name
getTitle: ( record ) => record?.title?.rendered || record?.title,
},
{
label: __( 'Themes' ),
name: 'theme',
kind: 'root',
baseURL: '/wp/v2/themes',
baseURLParams: { context: 'edit' },
key: 'stylesheet',
},
{
label: __( 'Plugins' ),
name: 'plugin',
kind: 'root',
baseURL: '/wp/v2/plugins',
baseURLParams: { context: 'edit' },
key: 'plugin',
},
];
import { defaultEntities } from "./entities.mjs";
import fetch from 'node-fetch';
import { compile } from 'json-schema-to-typescript';
const SITE_URL = 'http://localhost:8888';
const results = [];
for ( const entity of defaultEntities ) {
if ( ['Base'].includes( entity?.label ) ) {
continue;
}
const url = `${ SITE_URL }/wp-json${ entity.baseURL }`;
const response = await fetch( url, { method: 'OPTIONS' } );
const json = await response.json();
let schema = json.schema;
if ( !schema ) {
continue;
}
schema = fixEnums( schema );
let ts = await compile( schema, 'MySchema', {
bannerComment: false,
} );
ts = ts.replace( /\n\s+\[k: string\]: unknown;/gm, '' );
results.push( { title: schema.title, code: ts } );
}
const allEntityNames = results.map(
( { code } ) => code.split( 'interface ' )[ 1 ].split( '{' )[ 0 ].trim() );
console.log(
results
.sort( ( a, b ) => a.title?.localeCompare( b.title ) )
.map( e => e.code )
.join( "\n" ),
);
console.log( 'export type EntityRecord = ' + allEntityNames.join( ' | ' ) + ';' );
console.log('');
/* json-schema-to-typescript can't deal with object enums, it requires an array */
function fixEnums( obj ) {
const isArray = Array.isArray( obj );
const newObj = isArray ? [] : {};
const push = ( key, value ) => {
if ( isArray ) {
newObj.push( value );
} else {
newObj[ key ] = value;
}
};
for ( const key in obj ) {
const entry = obj[ key ];
if ( key === "enum" ) {
if ( typeof entry === 'object' ) {
push( key, Object.values( entry ) );
} else {
push( key, entry );
}
} else if ( Array.isArray( entry ) || typeof entry === 'object' ) {
push( key, fixEnums( entry ) );
} else {
push( key, entry );
}
}
return newObj;
}
{
"name": "json-schema-generator",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Adam Zielinski <adam@adamziel.com> (http://adamziel.com)",
"license": "ISC",
"type": "module",
"dependencies": {
"json-schema-to-typescript": "^10.1.5",
"node-fetch": "^3.2.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment