Deprecated compatibility shim for Storybook's framework-agnostic API utilities
—
Template interpolation, code formatting, and logging utilities for development tools and code generation. These utilities provide consistent text processing capabilities across Storybook tooling.
String template interpolation with variable substitution using {{key}} syntax.
/**
* Template string interpolation with variable substitution
* @param template - Template string with {{key}} placeholders
* @param bindings - Object with key-value pairs for substitution
* @returns Interpolated string with variables replaced
*/
function interpolate(template: string, bindings: Record<string, any>): string;Usage Examples:
import { interpolate } from "@storybook/core-common";
// Basic interpolation
const template = 'Hello {{name}}, welcome to {{app}}!';
const result = interpolate(template, {
name: 'Alice',
app: 'Storybook'
});
console.log(result); // 'Hello Alice, welcome to Storybook!'
// HTML template interpolation
const htmlTemplate = `
<div class="{{className}}">
<h1>{{title}}</h1>
<p>Version: {{version}}</p>
</div>
`;
const html = interpolate(htmlTemplate, {
className: 'story-container',
title: 'My Component',
version: '1.2.0'
});Format code content using Prettier with intelligent fallbacks and error handling.
/**
* Format code using Prettier with fallbacks for different file types
* @param filePath - File path for parser detection
* @param content - Code content to format
* @returns Promise resolving to formatted code content
*/
function formatFileContent(filePath: string, content: string): Promise<string>;Usage Examples:
import { formatFileContent } from "@storybook/core-common";
// Format JavaScript code
const jsCode = `
const component={props}=><div className="test">{props.children}</div>;
export default component;
`;
const formattedJs = await formatFileContent('Component.js', jsCode);
console.log(formattedJs);
// const component = ({ props }) => (
// <div className="test">{props.children}</div>
// );
// export default component;
// Format TypeScript
const tsCode = `interface Props{title:string;onClick:()=>void;}`;
const formattedTs = await formatFileContent('types.ts', tsCode);
// Format JSON
const jsonCode = `{"name":"my-app","version":"1.0.0"}`;
const formattedJson = await formatFileContent('package.json', jsonCode);Styled logging functions for command-line interfaces and development tools.
/**
* Styled command logging with success/error callbacks
* @param message - Base log message
* @returns Object with success and error logging methods
*/
function commandLog(message: string): {
success: (message: string) => void;
error: (message: string) => void;
};
/**
* Indented logging with consistent padding
* @param message - Message to log with padding
*/
function paddedLog(message: string): void;
/**
* Format code blocks for display with syntax highlighting hints
* @param codeLines - Array of code lines or single code string
* @param leftPadAmount - Left padding amount in spaces
*/
function codeLog(codeLines: string[] | string, leftPadAmount?: number): void;
/**
* Generate repeated character strings for formatting
* @param char - Character to repeat
* @param amount - Number of repetitions
* @returns String with repeated characters
*/
function getChars(char: string, amount: number): string;Usage Examples:
import {
commandLog,
paddedLog,
codeLog,
getChars
} from "@storybook/core-common";
// Command logging with status
const buildLog = commandLog('Building Storybook');
buildLog.success('Build completed successfully!');
buildLog.error('Build failed with errors');
// Padded logging for hierarchical output
console.log('Starting process...');
paddedLog('Loading configuration');
paddedLog('Processing stories');
paddedLog('Generating output');
// Code block logging
codeLog([
'import { Meta, StoryObj } from "@storybook/react";',
'import { Button } from "./Button";',
'',
'const meta: Meta<typeof Button> = {',
' title: "Example/Button",',
' component: Button,',
'};'
], 2);
// Character repetition for separators
const separator = getChars('=', 50);
console.log(separator);
console.log('Section Title');
console.log(separator);Generate HTML templates for Storybook preview with variable interpolation.
/**
* Generate preview body HTML template with interpolations
* @param configDir - Storybook configuration directory
* @param interpolations - Variables for template interpolation
* @returns Generated HTML body content
*/
function getPreviewBodyTemplate(
configDir: string,
interpolations?: Record<string, any>
): Promise<string>;
/**
* Generate preview head HTML template with interpolations
* @param configDir - Storybook configuration directory
* @param interpolations - Variables for template interpolation
* @returns Generated HTML head content
*/
function getPreviewHeadTemplate(
configDir: string,
interpolations?: Record<string, any>
): Promise<string>;Usage Examples:
import {
getPreviewBodyTemplate,
getPreviewHeadTemplate
} from "@storybook/core-common";
// Generate preview templates
const bodyHtml = await getPreviewBodyTemplate('.storybook', {
theme: 'dark',
customStyles: '/assets/custom.css'
});
const headHtml = await getPreviewHeadTemplate('.storybook', {
title: 'My Storybook',
favicon: '/assets/favicon.ico'
});
// Use in HTML generation
const fullHtml = `
<!DOCTYPE html>
<html>
<head>
${headHtml}
</head>
<body>
${bodyHtml}
</body>
</html>
`;Read template files with fallback handling and error recovery.
/**
* Read template file with fallbacks and error handling
* @param filePath - Path to template file
* @returns Promise resolving to template content
*/
function readTemplate(filePath: string): Promise<string>;Usage Example:
import { readTemplate, interpolate } from "@storybook/core-common";
// Read and process template
const templateContent = await readTemplate('./templates/component.template');
const processedTemplate = interpolate(templateContent, {
componentName: 'MyButton',
props: 'title: string; onClick: () => void'
});
console.log(processedTemplate);import { interpolate, formatFileContent } from "@storybook/core-common";
async function generateComponentCode(config: {
name: string;
props: Record<string, string>;
framework: 'react' | 'vue' | 'angular';
}) {
// Load framework-specific template
const templateMap = {
react: 'export interface {{name}}Props {\n{{propTypes}}\n}\n\nexport const {{name}} = (props: {{name}}Props) => {\n return <div>{{name}}</div>;\n};',
vue: '<template>\n <div>{{name}}</div>\n</template>\n\n<script>\nexport default {\n name: "{{name}}",\n props: {\n{{propTypes}}\n }\n};\n</script>',
angular: '@Component({\n selector: "app-{{kebabName}}",\n template: "<div>{{name}}</div>"\n})\nexport class {{name}}Component {\n{{propTypes}}\n}'
};
// Process prop types
const propTypes = Object.entries(config.props)
.map(([key, type]) => ` ${key}: ${type};`)
.join('\n');
// Interpolate template
const code = interpolate(templateMap[config.framework], {
name: config.name,
kebabName: config.name.replace(/([A-Z])/g, '-$1').toLowerCase(),
propTypes
});
// Format the generated code
const extension = config.framework === 'react' ? '.tsx' :
config.framework === 'vue' ? '.vue' : '.ts';
return await formatFileContent(`${config.name}${extension}`, code);
}import { commandLog, paddedLog, codeLog } from "@storybook/core-common";
class StorybookLogger {
private level: number = 0;
startSection(title: string) {
const log = commandLog(title);
this.level++;
return {
info: (msg: string) => paddedLog(`${' '.repeat(this.level)}${msg}`),
success: (msg: string) => {
log.success(msg);
this.level--;
},
error: (msg: string) => {
log.error(msg);
this.level--;
},
code: (code: string[] | string) => codeLog(code, this.level * 2)
};
}
}
// Usage
const logger = new StorybookLogger();
const buildSection = logger.startSection('Building Storybook');
buildSection.info('Loading configuration...');
buildSection.info('Processing stories...');
buildSection.code([
'Found 25 stories in:',
' - src/components/*.stories.tsx',
' - src/pages/*.stories.tsx'
]);
buildSection.success('Build completed successfully!');import { readTemplate, interpolate, cache } from "@storybook/core-common";
class TemplateCache {
private templateCache = new Map<string, string>();
async getTemplate(templatePath: string): Promise<string> {
// Check memory cache first
if (this.templateCache.has(templatePath)) {
return this.templateCache.get(templatePath)!;
}
// Check file system cache
const cacheKey = `template-${templatePath}`;
let template = await cache.get<string>(cacheKey);
if (!template) {
// Read from disk and cache
template = await readTemplate(templatePath);
await cache.set(cacheKey, template);
}
// Store in memory for immediate reuse
this.templateCache.set(templatePath, template);
return template;
}
async processTemplate(
templatePath: string,
bindings: Record<string, any>
): Promise<string> {
const template = await this.getTemplate(templatePath);
return interpolate(template, bindings);
}
}
// Usage
const templates = new TemplateCache();
const processed = await templates.processTemplate('./templates/story.template', {
componentName: 'Button',
storyName: 'Primary'
});interface InterpolationBindings {
[key: string]: string | number | boolean | null | undefined;
}
interface LogMethods {
success: (message: string) => void;
error: (message: string) => void;
}
interface TemplateOptions {
configDir: string;
interpolations?: Record<string, any>;
}Install with Tessl CLI
npx tessl i tessl/npm-storybook--core-common