197 lines
4.5 KiB
JavaScript
197 lines
4.5 KiB
JavaScript
/**
|
|
* External dependencies
|
|
*/
|
|
const { map } = require( 'lodash' );
|
|
|
|
/**
|
|
* Given a string, returns a new string with dash separators converted to
|
|
* camel-case equivalent. This is not as aggressive as `_.camelCase` in
|
|
* converting to uppercase, where Lodash will convert letters following
|
|
* numbers.
|
|
*
|
|
* @param {string} string Input dash-delimited string.
|
|
*
|
|
* @return {string} Camel-cased string.
|
|
*/
|
|
function camelCaseDash( string ) {
|
|
return string
|
|
.replace( /^([a-z])/g, ( match, letter ) => letter.toUpperCase() )
|
|
.replace( /-([a-z])/g, ( match, letter ) => letter.toUpperCase() );
|
|
}
|
|
|
|
/**
|
|
* Get a formatted description string.
|
|
*
|
|
* @param { string } description Component description as retrieved from component docs.
|
|
* @return { string } Formatted string.
|
|
*/
|
|
function getDescription( description = '' ) {
|
|
// eslint requires valid jsdoc, but we can remove this because it's implicit.
|
|
description = description
|
|
.replace( '@return { object } -', '' )
|
|
.replace( '@param { object } props -', '' );
|
|
return description + '\n';
|
|
}
|
|
|
|
/**
|
|
* Get a single prop's details formatted for markdown.
|
|
*
|
|
* @param { string } propName Prop name.
|
|
* @param {Object} prop Prop details as retrieved from component docs.
|
|
* @return { string } Formatted string.
|
|
*/
|
|
function getProp( propName, prop ) {
|
|
const cols = [ '`' + propName + '`' ];
|
|
|
|
cols.push( getPropType( prop.type, propName ) );
|
|
cols.push( '`' + getPropDefaultValue( prop.defaultValue ) + '`' );
|
|
|
|
let description = ( prop.description || '' )
|
|
.replace( /(\r\n|\n|\r)+/gm, ' ' )
|
|
.replace( /\.$/, '' );
|
|
|
|
if ( prop.required ) {
|
|
description = '(required) ' + description;
|
|
}
|
|
|
|
cols.push( description );
|
|
|
|
return cols.join( ' | ' );
|
|
}
|
|
|
|
/**
|
|
* Get a single prop's default value.
|
|
*
|
|
* @param {Object} value Default value as retrieved from component docs.
|
|
* @return { string } Formatted string.
|
|
*/
|
|
function getPropDefaultValue( value ) {
|
|
if ( value && value.value ) {
|
|
return '`' + value.value + '`';
|
|
}
|
|
return '`null`';
|
|
}
|
|
|
|
/**
|
|
* Get props and prop details formatted for markdown.
|
|
*
|
|
* @param {Object} props Component props as retrieved from component docs.
|
|
* @return { string } Formatted string.
|
|
*/
|
|
function getProps( props = {} ) {
|
|
if ( Object.keys( props ).length < 1 ) {
|
|
return '';
|
|
}
|
|
const title = '### Props';
|
|
const lines = [
|
|
title,
|
|
'',
|
|
'Name | Type | Default | Description',
|
|
'--- | --- | --- | ---',
|
|
];
|
|
Object.keys( props ).forEach( ( key ) => {
|
|
lines.push( getProp( key, props[ key ] ) );
|
|
} );
|
|
|
|
return lines.join( '\n' );
|
|
}
|
|
|
|
/**
|
|
* Get a single prop's type.
|
|
*
|
|
* @param {Object} type Prop type as retrieved from component docs.
|
|
* @return { string } Formatted string.
|
|
*/
|
|
function getPropType( type ) {
|
|
if ( ! type ) {
|
|
return;
|
|
}
|
|
|
|
const labels = {
|
|
func: 'Function',
|
|
array: 'Array',
|
|
object: 'Object',
|
|
string: 'String',
|
|
number: 'Number',
|
|
bool: 'Boolean',
|
|
node: 'ReactNode',
|
|
element: 'ReactElement',
|
|
any: '*',
|
|
custom: '(custom validator)',
|
|
};
|
|
|
|
let value = '';
|
|
switch ( type.name ) {
|
|
case 'arrayOf':
|
|
// replacing "Object" is a hack for shape proptypes.
|
|
value =
|
|
'Array\n' + getPropType( type.value ).replace( 'Object\n', '' );
|
|
break;
|
|
case 'objectOf':
|
|
// replacing "Object" is a hack for shape proptypes.
|
|
value =
|
|
'Object\n' +
|
|
getPropType( type.value ).replace( 'Object\n', '' );
|
|
break;
|
|
case 'shape':
|
|
value = map(
|
|
type.value,
|
|
( v, key ) => `\n - ${ key }: ` + getPropType( v )
|
|
).join( '' );
|
|
value = 'Object\n' + value.replace( /^\n/, '' );
|
|
break;
|
|
case 'enum':
|
|
value =
|
|
'One of: ' + type.value.map( ( v ) => v.value ).join( ', ' );
|
|
break;
|
|
case 'union':
|
|
value =
|
|
'One of type: ' +
|
|
type.value.map( ( v ) => v.name ).join( ', ' );
|
|
break;
|
|
default:
|
|
value =
|
|
( labels[ type.name ] || type.name ) +
|
|
( type.description ? ` - ${ type.description }` : '' );
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Get a formatted title string.
|
|
*
|
|
* @param { string } name Component title as retrieved from component docs.
|
|
* @return { string } Formatted string.
|
|
*/
|
|
function getTitle( name ) {
|
|
return name + '\n===\n';
|
|
}
|
|
|
|
/**
|
|
* Repeat a string n times. If the string is 1 character long,
|
|
* this will return a string of length n.
|
|
*
|
|
* @param { string } string String to repeat.
|
|
* @param { number } n Number to repeat the string.
|
|
* @return { string } New string.
|
|
*/
|
|
function stringOfLength( string, n ) {
|
|
let newString = '';
|
|
for ( let i = 0; i < n; i++ ) {
|
|
newString += string;
|
|
}
|
|
return newString;
|
|
}
|
|
|
|
module.exports = {
|
|
camelCaseDash,
|
|
getDescription,
|
|
getProp,
|
|
getPropDefaultValue,
|
|
getProps,
|
|
getPropType,
|
|
getTitle,
|
|
stringOfLength,
|
|
};
|