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

component-extraction.mddocs/

Component Property Extraction

Tools for extracting and processing component properties from various docgen sources including react-docgen, vue-docgen-api, and other component analysis tools.

Capabilities

Component Property Extraction

Main function for extracting structured property information from components using docgen metadata.

/**
 * Extracts component properties from docgen information
 * @param component - Component with attached docgen metadata
 * @param section - Docgen section to extract (e.g., 'props', 'events')
 * @returns Array of extracted properties with metadata
 */
function extractComponentProps(
  component: Component, 
  section: string
): ExtractedProp[];

interface ExtractedProp {
  /** Property definition with all metadata */
  propDef: PropDef;
  /** Original docgen information */
  docgenInfo: DocgenInfo;
  /** Parsed JSDoc tags */
  jsDocTags?: ExtractedJsDoc;
  /** Detected type system */
  typeSystem: TypeSystem;
}

type ExtractProps = (component: Component, section: string) => ExtractedProp[];

The extraction process handles both array and object-based docgen formats, automatically detecting the type system and processing JSDoc comments.

Usage Examples:

import { extractComponentProps } from "@storybook/docs-tools";

// Extract props from React component
const reactComponent = {
  __docgenInfo: {
    props: {
      name: {
        type: { name: 'string' },
        required: true,
        description: 'User name @param name - The user identifier'
      },
      age: {
        type: { name: 'number' },
        required: false,
        description: 'User age in years',
        defaultValue: { value: '18' }
      }
    }
  }
};

const props = extractComponentProps(reactComponent, 'props');
console.log(props);
// [
//   {
//     propDef: { name: 'name', type: { summary: 'string' }, required: true, ... },
//     docgenInfo: { type: { name: 'string' }, required: true, ... },
//     jsDocTags: { params: [{ name: 'name', description: 'The user identifier' }] },
//     typeSystem: TypeSystem.JAVASCRIPT
//   },
//   { ... }
// ]

// Extract events from Vue component  
const vueComponent = {
  __docgenApi: [
    {
      name: 'click',
      type: { names: ['CustomEvent'] },
      description: 'Emitted when button is clicked'
    }
  ]
};

const events = extractComponentProps(vueComponent, 'events');

// Framework-agnostic extraction
function extractAllComponentInfo(component: Component) {
  const props = extractComponentProps(component, 'props');
  const events = extractComponentProps(component, 'events');
  const slots = extractComponentProps(component, 'slots');
  
  return { props, events, slots };
}

Component Description Extraction

Utility for extracting component-level descriptions from docgen metadata.

/**
 * Extracts component description from docgen metadata
 * @param component - Component with docgen information
 * @returns Component description string or empty string
 */
function extractComponentDescription(component?: Component): string;

Usage Examples:

import { extractComponentDescription } from "@storybook/docs-tools";

// Extract description from various docgen formats
const componentWithDescription = {
  __docgenInfo: {
    description: 'A reusable button component with multiple variants'
  }
};

const description = extractComponentDescription(componentWithDescription);
console.log(description); // "A reusable button component with multiple variants"

// Handle components without descriptions
const componentWithoutDescription = {};
const emptyDescription = extractComponentDescription(componentWithoutDescription);
console.log(emptyDescription); // ""

// Use in documentation generation
function generateComponentDocs(component: Component) {
  const description = extractComponentDescription(component);
  const props = extractComponentProps(component, 'props');
  
  return {
    name: component.displayName || component.name,
    description,
    properties: props.map(prop => prop.propDef)
  };
}

Section Processing Functions

Specialized functions for handling different docgen section formats.

/**
 * Processes docgen section when it's an array format (vue-docgen-api style)
 * @param docgenSection - Array of docgen entries
 * @returns Array of extracted properties
 */
function extractComponentSectionArray(docgenSection: any): ExtractedProp[];

/**
 * Processes docgen section when it's an object format (react-docgen style)
 * @param docgenSection - Object mapping prop names to docgen info
 * @returns Array of extracted properties
 */
function extractComponentSectionObject(docgenSection: any): ExtractedProp[];

Usage Examples:

// Handle array format (Vue docgen)
const vueDocgenArray = [
  {
    name: 'modelValue',
    type: { names: ['string', 'number'] },
    description: 'The input value'
  },
  {
    name: 'placeholder', 
    type: { names: ['string'] },
    description: 'Placeholder text'
  }
];

const vueProps = extractComponentSectionArray(vueDocgenArray);

// Handle object format (React docgen)
const reactDocgenObject = {
  value: {
    type: { name: 'string' },
    required: true,
    description: 'Input value'
  },
  onChange: {
    type: { name: 'func' },
    required: true,
    description: 'Change handler function'
  }
};

const reactProps = extractComponentSectionObject(reactDocgenObject);

// Unified processing
function processDocgenSection(section: any): ExtractedProp[] {
  if (Array.isArray(section)) {
    return extractComponentSectionArray(section);
  }
  return extractComponentSectionObject(section);
}

Property Definition Factory

The extraction system uses factory functions to create appropriate property definitions based on the detected type system.

/**
 * Factory function type for creating PropDef objects
 */
type PropDefFactory = (
  propName: string,
  docgenInfo: DocgenInfo,
  jsDocParsingResult?: JsDocParsingResult
) => PropDef;

/**
 * Gets appropriate PropDef factory for the detected type system
 * @param typeSystem - Detected type system
 * @returns Factory function for creating PropDef objects
 */
function getPropDefFactory(typeSystem: TypeSystem): PropDefFactory;

Usage Examples:

import { getPropDefFactory, TypeSystem } from "@storybook/docs-tools";

// Create factory for TypeScript components
const tsFactory = getPropDefFactory(TypeSystem.TYPESCRIPT);

const tsPropDef = tsFactory('userName', {
  type: { name: 'string' },
  tsType: { name: 'string', raw: 'string' },
  required: true,
  description: 'The user name',
  defaultValue: { value: '""' }
});

// Create factory for Flow components
const flowFactory = getPropDefFactory(TypeSystem.FLOW);

const flowPropDef = flowFactory('count', {
  type: { name: 'number' },
  flowType: { name: 'number', raw: 'number' },
  required: false,
  description: 'Item count',
  defaultValue: { value: '0' }
});

// Framework integration
function createFrameworkExtractor(framework: string) {
  return (component: Component, section: string) => {
    const docgenSection = getDocgenSection(component, section);
    
    if (!docgenSection) return [];
    
    const typeSystem = detectTypeSystem(component, framework);
    const factory = getPropDefFactory(typeSystem);
    
    return processDocgenWithFactory(docgenSection, factory);
  };
}

Docgen Utility Functions

Lower-level utilities for working directly with docgen information attached to components.

/**
 * Checks if a component has docgen information attached
 * @param component - Component to check
 * @returns true if component has docgen info
 */
function hasDocgen<T>(component: Component): boolean;

/**
 * Validates that a docgen section contains valid information
 * @param docgenSection - Section to validate
 * @returns true if section is valid
 */
function isValidDocgenSection(docgenSection: any): boolean;

/**
 * Extracts a specific docgen section from a component
 * @param component - Component with docgen information
 * @param section - Section name to extract (e.g., 'props', 'events')
 * @returns Docgen section data or undefined
 */
function getDocgenSection(component: Component, section: string): any;

/**
 * Extracts component description from docgen information
 * @param component - Component to extract description from
 * @returns Component description string
 */
function getDocgenDescription(component: Component): string;

/**
 * Safely converts objects to strings for display
 * @param obj - Object to convert
 * @returns String representation
 */
function str(obj: any): string;

/**
 * Checks if a default value should be ignored in documentation
 * @param value - Default value to check
 * @returns true if value should be ignored
 */
function isDefaultValueBlacklisted(value: string): boolean;

Usage Examples:

import { 
  hasDocgen, 
  isValidDocgenSection, 
  getDocgenSection, 
  getDocgenDescription,
  str,
  isDefaultValueBlacklisted 
} from "@storybook/docs-tools";

// Check if component has docgen information
function processComponent(component: Component) {
  if (!hasDocgen(component)) {
    console.log('No docgen information found');
    return null;
  }
  
  // Extract description
  const description = getDocgenDescription(component);
  console.log('Component description:', description);
  
  // Get props section
  const propsSection = getDocgenSection(component, 'props');
  
  if (isValidDocgenSection(propsSection)) {
    // Process props
    Object.entries(propsSection).forEach(([propName, propInfo]) => {
      const propData = propInfo as any;
      
      // Convert to string safely
      const typeString = str(propData.type);
      
      // Check default value
      if (propData.defaultValue && !isDefaultValueBlacklisted(propData.defaultValue.value)) {
        console.log(`${propName}: ${typeString} = ${propData.defaultValue.value}`);
      } else {
        console.log(`${propName}: ${typeString}`);
      }
    });
  }
}

// Framework-specific processing
function processReactComponent(component: any) {
  const docgenInfo = component.__docgenInfo;
  
  if (hasDocgen({ __docgenInfo: docgenInfo })) {
    const description = getDocgenDescription({ __docgenInfo: docgenInfo });
    const props = getDocgenSection({ __docgenInfo: docgenInfo }, 'props');
    
    return {
      description,
      hasProps: isValidDocgenSection(props),
      propsCount: props ? Object.keys(props).length : 0
    };
  }
  
  return null;
}

// Safe value processing
function processDefaultValue(defaultValue: any) {
  const valueString = str(defaultValue);
  
  if (isDefaultValueBlacklisted(valueString)) {
    return null; // Don't show blacklisted values
  }
  
  return valueString;
}

Type System Detection

The extraction system automatically detects which type system is being used based on available docgen information.

// Type system detection logic
function detectTypeSystem(docgenInfo: DocgenInfo): TypeSystem {
  if (docgenInfo.type != null) {
    return TypeSystem.JAVASCRIPT;
  }
  
  if (docgenInfo.flowType != null) {
    return TypeSystem.FLOW;
  }
  
  if (docgenInfo.tsType != null) {
    return TypeSystem.TYPESCRIPT;
  }
  
  return TypeSystem.UNKNOWN;
}

// Usage in extraction
const extractedProps = extractComponentProps(component, 'props');
extractedProps.forEach(prop => {
  console.log(`${prop.propDef.name}: ${prop.typeSystem}`);
});

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