CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-storybook--docs-tools

Shared utility functions for frameworks to implement docs in Storybook

Pending
Overview
Eval results
Files

type-conversion.mddocs/

Type System Conversion

Comprehensive type conversion system that transforms docgen type information between different type system representations including PropTypes, Flow, and TypeScript.

Capabilities

Universal Type Conversion

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' };
  }
}

Type System Enumeration

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);
  }
}

DocGen Type Interfaces

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})`);
  }
}

PropDef Factory Functions

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;
  }
}

Conversion System Architecture

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;
  };
}

Complex Type Handling

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

docs

argtypes-enhancement.md

component-extraction.md

constants.md

index.md

jsdoc-processing.md

type-conversion.md

utilities.md

tile.json