#!/usr/bin/env node | |
'use strict'; | |
const http = require( 'http' ); | |
http.get( 'http://localhost:8080/wp/wp-json?context=help', res => { | |
if ( res.statusCode !== 200 ) { | |
throw new Error( 'HTTP ' + res.statusCode ); | |
} | |
let index = ''; | |
res.on( 'data', d => index += d ); | |
res.on( 'end', () => parseIndex( JSON.parse( index ) ) ); | |
} ); | |
function parseIndex( index ) { | |
for ( let path in index.routes ) { | |
const route = index.routes[ path ]; | |
if ( path === '/wp/v2' || route.namespace !== 'wp/v2' ) { | |
continue; | |
} | |
route.endpoints.forEach( endpoint => { | |
const urlArgRegex = /\(\?P<([^>]+)>/g; | |
let urlArgMatch; | |
while ( ( urlArgMatch = urlArgRegex.exec( path ) ) !== null ) { | |
const urlArgName = urlArgMatch[ 1 ]; | |
if ( ! endpoint.args[ urlArgName ] ) { | |
console.error( | |
'URL arg without arg block:\n %s\n %s\n', | |
path, | |
urlArgName | |
); | |
} | |
} | |
for ( let argName in endpoint.args ) { | |
const arg = endpoint.args[ argName ]; | |
if ( ! arg.type ) { | |
console.error( | |
'arg without type:\n %s\n %s\n %s\n', | |
path, | |
argName, | |
JSON.stringify( arg ) | |
); | |
} | |
if ( ! arg.description ) { | |
console.error( | |
'arg without description:\n %s\n %s\n %s\n', | |
path, | |
argName, | |
JSON.stringify( arg ) | |
); | |
} | |
if ( argName === 'capabilities' && ( ! arg.readonly || arg.type !== 'object' ) ) { | |
console.error( | |
'capabilities arg should be readonly object:\n %s\n %s\n %s\n', | |
path, | |
argName, | |
JSON.stringify( arg ) | |
); | |
} | |
if ( argName === 'context' && ( arg.type !== 'string' || ! arg.enum ) ) { | |
console.error( | |
'type of context arg should be string with enum:\n %s\n %s\n %s\n', | |
path, | |
argName, | |
JSON.stringify( arg ) | |
); | |
} | |
let isRenderedRaw = false; | |
switch ( argName ) { | |
case 'title': | |
case 'content': | |
case 'excerpt': | |
case 'description': | |
case 'caption': | |
case 'guid': | |
if ( | |
( argName === 'description' && ! /media/.test( path ) ) || | |
( argName === 'title' && /settings/.test( path ) ) | |
) { | |
break; | |
} | |
isRenderedRaw = true; | |
break; | |
} | |
if ( ! isRenderedRaw && arg.type === 'object' && argName !== 'meta' ) { | |
console.error( | |
'unrecognized object arg:\n %s\n %s', | |
path, | |
argName | |
); | |
} | |
if ( isRenderedRaw && ( | |
arg.type !== 'object' || | |
arg.required !== false || | |
JSON.stringify( Object.keys( arg ).sort() ) !== '["description","required","type"]' | |
) ) { | |
console.error( | |
'content-like arg should be object with required=false:\n %s\n %s\n %s\n', | |
path, | |
argName, | |
JSON.stringify( arg ) | |
); | |
} | |
if ( arg.type !== 'array' ) { | |
continue; | |
} | |
if ( ! arg.items || ! arg.items.type ) { | |
console.error( | |
'array arg without item type:\n %s\n %s\n %s\n', | |
path, | |
argName, | |
JSON.stringify( arg ) | |
); | |
} | |
} | |
} ); | |
if ( ! route.schema ) { | |
console.error( | |
'no schema for %s', | |
path | |
); | |
continue; | |
} | |
for ( let propertyName in route.schema.properties ) { | |
const property = route.schema.properties[ propertyName ]; | |
if ( ! property.type ) { | |
console.error( | |
'property without type:\n %s\n %s\n %s\n', | |
path, | |
propertyName, | |
JSON.stringify( property ) | |
); | |
} | |
if ( ! property.description ) { | |
console.error( | |
'property without description:\n %s\n %s\n %s\n', | |
path, | |
propertyName, | |
JSON.stringify( property ) | |
); | |
} | |
if ( propertyName === 'capabilities' && ( ! property.readonly || property.type !== 'object' ) ) { | |
console.error( | |
'capabilities property should be readonly object:\n %s\n %s\n %s\n', | |
path, | |
propertyName, | |
JSON.stringify( property ) | |
); | |
} | |
if ( propertyName === 'context' && ( property.type !== 'string' || ! property.enum ) ) { | |
console.error( | |
'type of context property should be string with enum:\n %s\n %s\n %s\n', | |
path, | |
propertyName, | |
JSON.stringify( property ) | |
); | |
} | |
let isRenderedRaw = false; | |
switch ( propertyName ) { | |
case 'title': | |
case 'content': | |
case 'excerpt': | |
case 'description': | |
case 'caption': | |
case 'guid': | |
if ( | |
( propertyName === 'description' && ! /media/.test( path ) ) || | |
( propertyName === 'title' && /settings/.test( path ) ) | |
) { | |
break; | |
} | |
isRenderedRaw = true; | |
break; | |
} | |
if ( ! isRenderedRaw && property.properties && ( property.properties.rendered || property.properties.raw ) ) { | |
console.error( | |
'unrecognized content-like property:\n %s\n %s', | |
path, | |
propertyName | |
); | |
} | |
if ( isRenderedRaw && ( | |
property.type !== 'object' || | |
! property.properties.rendered || | |
property.properties.rendered.type !== 'string' || | |
! property.properties.rendered.readonly || | |
! Array.isArray( property.properties.rendered.context ) || | |
! property.properties.raw || | |
property.properties.raw.type !== 'string' || | |
( propertyName === 'guid' ? ! property.properties.raw.readonly : 'readonly' in property.properties.raw ) || | |
! Array.isArray( property.properties.raw.context ) || | |
( ! /title|guid/.test( propertyName ) && ! /media|comments/.test( path ) && ! property.properties.protected ) | |
) ) { | |
console.error( | |
'content-like property should be object with rendered/raw(/protected) fields:\n %s\n %s\n %s\n', | |
path, | |
propertyName, | |
JSON.stringify( property ) | |
); | |
} | |
if ( property.type !== 'array' ) { | |
continue; | |
} | |
if ( ! property.items || ! property.items.type ) { | |
console.error( | |
'array property in schema without item type:\n %s\n %s\n %s\n', | |
path, | |
propertyName, | |
JSON.stringify( property ) | |
); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment