CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-storybook--core-common

Deprecated compatibility shim for Storybook's framework-agnostic API utilities

Pending
Overview
Eval results
Files

story-processing.mddocs/

Story Processing

Story entry normalization and metadata generation for Storybook's story indexing system. These utilities handle glob patterns, directory mapping, story ID generation, and story metadata processing.

Capabilities

Story Entry Normalization

Convert and normalize story entry configurations from various formats into a standardized structure.

/**
 * Normalize array of story entries with configuration options
 * @param entries - Array of story entry configurations
 * @param options - Normalization options including working directory context
 * @returns Array of normalized story entries
 */
function normalizeStories(
  entries: StoriesEntry[],
  options: NormalizeOptions
): NormalizedStoriesEntry[];

/**
 * Normalize individual story entry configuration
 * @param entry - Single story entry configuration
 * @param options - Normalization options
 * @returns Normalized story entry
 */
function normalizeStoriesEntry(
  entry: StoriesEntry,
  options: NormalizeOptions
): NormalizedStoriesEntry;

interface NormalizeOptions {
  configDir: string;
  workingDir?: string;
}

Usage Examples:

import { normalizeStories } from "@storybook/core-common";

// Normalize story entries from main config
const stories = normalizeStories([
  './src/**/*.stories.@(js|jsx|ts|tsx)',
  {
    directory: '../shared/components',
    files: '**/*.stories.@(js|jsx|ts|tsx)',
    titlePrefix: 'Shared'
  }
], {
  configDir: '.storybook',
  workingDir: process.cwd()
});

console.log(stories);
// [
//   {
//     directory: './src',
//     files: '**/*.stories.@(js|jsx|ts|tsx)',
//     importPathMatcher: /^\.\/src\/(.*)\.stories\.(js|jsx|ts|tsx)$/,
//     normalizedPath: './src',
//     titlePrefix: undefined
//   },
//   ...
// ]

Story ID Generation

Generate unique story IDs from file paths and story exports.

/**
 * Generate unique story ID from story data and options
 * @param data - Story identification data
 * @param options - Story ID generation options
 * @returns Generated story ID string
 */
function getStoryId(data: StoryIdData, options: GetStoryIdOptions): string;

interface StoryIdData {
  title: string;
  name: string;
  story?: string;
}

interface GetStoryIdOptions {
  directory: string;
  importPath: string;
  normalizedPath: string;
  titlePrefix?: string;
}

Usage Example:

import { getStoryId } from "@storybook/core-common";

// Generate story ID
const storyId = getStoryId(
  {
    title: 'Button',
    name: 'Primary',
    story: 'primary'
  },
  {
    directory: './src/components',
    importPath: './src/components/Button.stories.js',
    normalizedPath: './src/components',
    titlePrefix: 'UI'
  }
);

console.log(storyId); // 'ui-button--primary'

Story Title Generation

Generate story titles from file paths and component information.

/**
 * Generate story title from file path and component specifier
 * @param options - Title generation options
 * @returns Generated story title
 */
function getStoryTitle(options: {
  specifier: {
    title?: string;
    component?: string;
  };
  filepath: string;
  normalizedPath: string;
}): string;

Usage Example:

import { getStoryTitle } from "@storybook/core-common";

// Generate title from component
const title = getStoryTitle({
  specifier: { component: 'Button' },
  filepath: './src/components/Button/Button.stories.js',
  normalizedPath: './src/components'
});

console.log(title); // 'Button/Button'

// Generate title with explicit title
const explicitTitle = getStoryTitle({
  specifier: { title: 'Design System/Button' },
  filepath: './src/components/Button.stories.js',
  normalizedPath: './src'
});

console.log(explicitTitle); // 'Design System/Button'

Directory Path Utilities

Convert between different path representations and resolve working directory contexts.

/**
 * Convert config-relative paths to working-directory-relative paths
 * @param options - Path conversion options
 * @returns Working directory relative path
 */
function getDirectoryFromWorkingDir(options: {
  configDir: string;
  workingDir?: string;
  directory: string;
}): string;

/**
 * Ensure story paths start with './' or '../'
 * @param filename - File path to normalize
 * @returns Normalized path with proper prefix
 */
function normalizeStoryPath(filename: string): string;

Usage Examples:

import { 
  getDirectoryFromWorkingDir, 
  normalizeStoryPath 
} from "@storybook/core-common";

// Convert to working directory relative
const workingDirPath = getDirectoryFromWorkingDir({
  configDir: '.storybook',
  workingDir: '/project',
  directory: '../shared/stories'
});

// Normalize story paths
const normalized = normalizeStoryPath('src/components/Button.stories.js');
console.log(normalized); // './src/components/Button.stories.js'

Pattern Matching Utilities

Convert glob patterns to regular expressions for story matching.

/**
 * Convert glob pattern to RegExp with special handling for story patterns
 * @param glob - Glob pattern string
 * @returns Regular expression for pattern matching
 */
function globToRegexp(glob: string): RegExp;

Usage Example:

import { globToRegexp } from "@storybook/core-common";

// Convert story glob to regex
const pattern = globToRegexp('**/*.stories.@(js|jsx|ts|tsx)');
console.log(pattern.test('Button.stories.js')); // true
console.log(pattern.test('Button.test.js')); // false

// Handle specific path patterns
const srcPattern = globToRegexp('./src/**/*.stories.*');
console.log(srcPattern.test('./src/Button.stories.js')); // true

Story Entry Types

/**
 * Story entry configuration - string glob or detailed object
 */
type StoriesEntry = string | {
  /** Directory containing stories */
  directory: string;
  /** File pattern within directory */
  files: string;
  /** Optional prefix for story titles */
  titlePrefix?: string;
};

/**
 * Normalized story entry with computed properties
 */
interface NormalizedStoriesEntry {
  /** Base directory for stories */
  directory: string;
  /** File pattern for matching stories */
  files: string;
  /** RegExp for matching import paths */
  importPathMatcher: RegExp;
  /** Normalized directory path */
  normalizedPath: string;
  /** Title prefix for story organization */
  titlePrefix?: string;
}

Advanced Story Processing

Custom Story Indexing

import { normalizeStories, getStoryId } from "@storybook/core-common";

async function buildCustomStoryIndex(mainConfig: any) {
  // Normalize all story entries
  const normalizedEntries = normalizeStories(mainConfig.stories, {
    configDir: '.storybook'
  });

  const storyIndex = {};

  for (const entry of normalizedEntries) {
    // Find all story files matching this entry
    const storyFiles = await glob(entry.files, {
      cwd: entry.directory
    });

    for (const file of storyFiles) {
      // Extract stories from file
      const stories = await extractStoriesFromFile(file);
      
      for (const story of stories) {
        const storyId = getStoryId(
          { title: story.title, name: story.name },
          {
            directory: entry.directory,
            importPath: file,
            normalizedPath: entry.normalizedPath,
            titlePrefix: entry.titlePrefix
          }
        );
        
        storyIndex[storyId] = {
          id: storyId,
          title: story.title,
          name: story.name,
          importPath: file
        };
      }
    }
  }

  return storyIndex;
}

Story Validation

import { normalizeStories } from "@storybook/core-common";

function validateStoryConfiguration(stories: StoriesEntry[], configDir: string) {
  try {
    const normalized = normalizeStories(stories, { configDir });
    
    // Check for valid patterns
    for (const entry of normalized) {
      if (!entry.files || !entry.directory) {
        throw new Error(`Invalid story entry: ${JSON.stringify(entry)}`);
      }
      
      // Validate glob patterns
      if (!entry.importPathMatcher) {
        throw new Error(`Unable to create matcher for entry: ${entry.files}`);
      }
    }
    
    return { valid: true, entries: normalized };
  } catch (error) {
    return { valid: false, error: error.message };
  }
}

Story Path Resolution

import { normalizeStoryPath, getDirectoryFromWorkingDir } from "@storybook/core-common";

function resolveStoryPaths(configDir: string, stories: string[]) {
  return stories.map(story => {
    // Normalize the path format
    const normalizedPath = normalizeStoryPath(story);
    
    // Convert to working directory relative if needed
    return getDirectoryFromWorkingDir({
      configDir,
      workingDir: process.cwd(),
      directory: normalizedPath
    });
  });
}

// Usage
const resolvedPaths = resolveStoryPaths('.storybook', [
  'src/**/*.stories.js',
  '../shared/components/**/*.stories.tsx'
]);

Install with Tessl CLI

npx tessl i tessl/npm-storybook--core-common

docs

caching.md

configuration.md

environment-cli.md

index.md

package-management.md

presets.md

story-processing.md

text-processing.md

tile.json