Shared utility functions for frameworks to implement docs in Storybook
—
Comprehensive type conversion system that transforms docgen type information between different type system representations including PropTypes, Flow, and TypeScript.
Main conversion function that handles type information from any supported type system.
/**
* Converts docgen type information to Storybook-compatible format
* @param docgenInfo - Type information from docgen tools
* @returns Converted type information or null if conversion fails
*/
function convert(docgenInfo: DocgenInfo): any | null;
interface DocgenInfo {
/** PropTypes type information */
type: DocgenPropType;
/** Flow type information (optional) */
flowType?: DocgenFlowType;
/** TypeScript type information (optional) */
tsType?: DocgenTypeScriptType;
/** Whether the property is required */
required: boolean;
/** Property description */
description: string;
/** Default value information */
defaultValue: DocgenPropDefaultValue;
}The conversion function automatically detects the available type system and applies the appropriate conversion logic, with graceful fallback handling.
Usage Examples:
import { convert } from "@storybook/docs-tools";
// Convert TypeScript type information
const tsDocgenInfo = {
type: null,
tsType: {
name: 'string | number',
raw: 'string | number'
},
required: true,
description: 'Input value',
defaultValue: { value: '""' }
};
const convertedType = convert(tsDocgenInfo);
console.log(convertedType);
// { summary: 'string | number', detail: 'string | number' }
// Convert PropTypes information
const propTypesInfo = {
type: {
name: 'union',
value: [
{ name: 'string' },
{ name: 'number' }
]
},
required: false,
description: 'Value can be string or number',
defaultValue: { value: 'null' }
};
const propTypesConverted = convert(propTypesInfo);
// Convert Flow type information
const flowInfo = {
type: null,
flowType: {
name: 'Array',
elements: [{ name: 'string' }],
raw: 'Array<string>'
},
required: true,
description: 'Array of strings',
defaultValue: { value: '[]' }
};
const flowConverted = convert(flowInfo);
// Handle conversion failures gracefully
function safeConvert(docgenInfo: DocgenInfo) {
try {
const result = convert(docgenInfo);
return result || { summary: 'unknown' };
} catch (error) {
console.warn('Type conversion failed:', error);
return { summary: 'any' };
}
}Enumeration defining the supported type systems for component analysis.
/**
* Supported type systems for component documentation
*/
enum TypeSystem {
/** Standard JavaScript with PropTypes */
JAVASCRIPT = "JavaScript",
/** Flow static type checker */
FLOW = "Flow",
/** TypeScript static type system */
TYPESCRIPT = "TypeScript",
/** Unable to determine type system */
UNKNOWN = "Unknown"
}Usage Examples:
import { TypeSystem } from "@storybook/docs-tools";
// Type system detection
function detectComponentTypeSystem(component: any): TypeSystem {
if (component.__docgenInfo?.props) {
const firstProp = Object.values(component.__docgenInfo.props)[0] as any;
if (firstProp?.tsType) {
return TypeSystem.TYPESCRIPT;
}
if (firstProp?.flowType) {
return TypeSystem.FLOW;
}
if (firstProp?.type) {
return TypeSystem.JAVASCRIPT;
}
}
return TypeSystem.UNKNOWN;
}
// Framework-specific handling
function processComponentByTypeSystem(component: any, typeSystem: TypeSystem) {
switch (typeSystem) {
case TypeSystem.TYPESCRIPT:
return processTypeScriptComponent(component);
case TypeSystem.FLOW:
return processFlowComponent(component);
case TypeSystem.JAVASCRIPT:
return processJavaScriptComponent(component);
default:
return processGenericComponent(component);
}
}Detailed interfaces that define the structure of type information from different docgen tools.
interface DocgenType {
/** Type name */
name: string;
/** Type description */
description?: string;
/** Whether the type is required */
required?: boolean;
/** Type value information */
value?: any;
}
interface DocgenPropType extends DocgenType {
/** Type value (varies by type) */
value?: any;
/** Raw type string */
raw?: string;
/** Whether type is computed */
computed?: boolean;
}
interface DocgenFlowType extends DocgenType {
/** Flow type category */
type?: string;
/** Raw Flow type string */
raw?: string;
/** Function signature information */
signature?: any;
/** Array/object element types */
elements?: any[];
}
interface DocgenTypeScriptType extends DocgenType {
/** Raw TypeScript type string */
raw?: string;
}
interface DocgenPropDefaultValue {
/** Default value as string */
value: string;
/** Whether value is computed */
computed?: boolean;
/** Whether value is a function */
func?: boolean;
}Usage Examples:
// Process different type formats
function processDocgenType(docgenInfo: DocgenInfo) {
// Handle TypeScript types
if (docgenInfo.tsType) {
const tsType: DocgenTypeScriptType = docgenInfo.tsType;
console.log(`TS Type: ${tsType.name} (${tsType.raw})`);
}
// Handle Flow types
if (docgenInfo.flowType) {
const flowType: DocgenFlowType = docgenInfo.flowType;
console.log(`Flow Type: ${flowType.name}`);
if (flowType.elements) {
console.log('Element types:', flowType.elements);
}
}
// Handle PropTypes
if (docgenInfo.type) {
const propType: DocgenPropType = docgenInfo.type;
console.log(`PropType: ${propType.name}`);
if (propType.value) {
console.log('Type value:', propType.value);
}
}
// Process default values
if (docgenInfo.defaultValue) {
const defaultVal = docgenInfo.defaultValue;
console.log(`Default: ${defaultVal.value} (computed: ${defaultVal.computed})`);
}
}Specialized factory functions for creating PropDef objects from different type systems.
/**
* Creates PropDef for JavaScript/PropTypes components
* @param propName - Name of the property
* @param docgenInfo - Docgen information for the prop
* @param jsDocTags - Optional JSDoc tag information
* @returns PropDef object for JavaScript component
*/
const javaScriptFactory: PropDefFactory;
/**
* Creates PropDef for TypeScript components
* @param propName - Name of the property
* @param docgenInfo - Docgen information for the prop
* @param jsDocTags - Optional JSDoc tag information
* @returns PropDef object for TypeScript component with TS type information
*/
const tsFactory: PropDefFactory;
/**
* Creates PropDef for Flow components
* @param propName - Name of the property
* @param docgenInfo - Docgen information for the prop
* @param jsDocTags - Optional JSDoc tag information
* @returns PropDef object for Flow component with Flow type information
*/
const flowFactory: PropDefFactory;
/**
* Creates PropDef for components with unknown type systems
* @param propName - Name of the property
* @param docgenInfo - Docgen information for the prop
* @param jsDocTags - Optional JSDoc tag information
* @returns Basic PropDef object with fallback type information
*/
const unknownFactory: PropDefFactory;
/**
* Gets the appropriate PropDef factory based on type system
* @param typeSystem - Detected or specified type system
* @returns Factory function for the given type system
*/
function getPropDefFactory(typeSystem: TypeSystem): PropDefFactory;
/**
* Creates PropDef for Flow type components (alias for flowFactory)
* @param propName - Name of the property
* @param docgenInfo - Docgen information for the prop
* @param jsDocTags - Optional JSDoc tag information
* @returns PropDef object for Flow component
*/
const createFlowPropDef: PropDefFactory;
/**
* Creates PropDef for TypeScript components (alias for tsFactory)
* @param propName - Name of the property
* @param docgenInfo - Docgen information for the prop
* @param jsDocTags - Optional JSDoc tag information
* @returns PropDef object for TypeScript component
*/
const createTsPropDef: PropDefFactory;Usage Examples:
import {
getPropDefFactory,
javaScriptFactory,
tsFactory,
flowFactory,
TypeSystem
} from "@storybook/docs-tools";
// Using factory selection
function createPropDef(propName: string, docgenInfo: DocgenInfo, typeSystem: TypeSystem) {
const factory = getPropDefFactory(typeSystem);
return factory(propName, docgenInfo);
}
// Direct factory usage
const tsDocgenInfo = {
type: { name: 'string' },
tsType: { name: 'string', raw: 'string' },
required: true,
description: 'User name input',
defaultValue: { value: '""', computed: false }
};
const tsPropDef = tsFactory('userName', tsDocgenInfo);
console.log(tsPropDef);
// {
// name: 'userName',
// type: { summary: 'string' },
// required: true,
// description: 'User name input',
// defaultValue: { summary: '""' }
// }
// Flow factory usage
const flowDocgenInfo = {
type: { name: 'number' },
flowType: { name: 'number', raw: 'number' },
required: false,
description: 'Item count',
defaultValue: { value: '0', computed: false }
};
const flowPropDef = flowFactory('count', flowDocgenInfo);
// JavaScript/PropTypes factory usage
const jsDocgenInfo = {
type: {
name: 'union',
value: [{ name: 'string' }, { name: 'number' }]
},
required: true,
description: 'Mixed type value',
defaultValue: null
};
const jsPropDef = javaScriptFactory('mixedValue', jsDocgenInfo);
// Framework integration
function processFrameworkComponent(component: any, framework: string) {
const props = component.__docgenInfo?.props || {};
const typeSystem = detectTypeSystemFromFramework(framework);
const factory = getPropDefFactory(typeSystem);
return Object.entries(props).map(([propName, propInfo]) => {
return factory(propName, propInfo as DocgenInfo);
});
}
// Type system detection helper
function detectTypeSystemFromFramework(framework: string): TypeSystem {
switch (framework) {
case 'react-ts':
case 'vue-ts':
return TypeSystem.TYPESCRIPT;
case 'react-flow':
return TypeSystem.FLOW;
case 'react':
case 'vue':
default:
return TypeSystem.JAVASCRIPT;
}
}The conversion system uses specialized converters for each type system with shared utilities.
// Type-specific conversion functions (internal)
interface TypeConverter {
convert(typeInfo: any): { summary: string; detail?: string } | null;
}
// Example usage patterns
const processConversionResult = (result: any) => {
if (!result) {
return { summary: 'unknown' };
}
return {
summary: result.summary || 'any',
detail: result.detail
};
};
// Framework integration
function createTypeConverter(framework: string) {
return (docgenInfo: DocgenInfo) => {
const converted = convert(docgenInfo);
if (!converted) {
// Framework-specific fallback
return getFrameworkFallbackType(framework);
}
return converted;
};
}The conversion system handles complex type structures including unions, intersections, generics, and nested objects.
// Example complex type conversions
const complexTypes = {
// Union types
stringOrNumber: {
type: {
name: 'union',
value: [{ name: 'string' }, { name: 'number' }]
}
},
// Generic types
arrayOfStrings: {
tsType: {
name: 'Array<string>',
raw: 'Array<string>'
}
},
// Object types
configObject: {
type: {
name: 'shape',
value: {
enabled: { name: 'bool' },
count: { name: 'number' }
}
}
},
// Function types
eventHandler: {
type: {
name: 'func',
signature: {
arguments: [{ name: 'event' }],
return: { name: 'void' }
}
}
}
};
// Process complex types
Object.entries(complexTypes).forEach(([name, docgenInfo]) => {
const converted = convert(docgenInfo as DocgenInfo);
console.log(`${name}:`, converted);
});Install with Tessl CLI
npx tessl i tessl/npm-storybook--docs-tools