Skip to content

Instantly share code, notes, and snippets.

@nylen nylen/args-audit.js
Last active Feb 7, 2017

Embed
What would you like to do?
#!/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
You can’t perform that action at this time.