0
# Text Processing & Formatting
1
2
Template interpolation, code formatting, and logging utilities for development tools and code generation. These utilities provide consistent text processing capabilities across Storybook tooling.
3
4
## Capabilities
5
6
### Template Interpolation
7
8
String template interpolation with variable substitution using `{{key}}` syntax.
9
10
```typescript { .api }
11
/**
12
* Template string interpolation with variable substitution
13
* @param template - Template string with {{key}} placeholders
14
* @param bindings - Object with key-value pairs for substitution
15
* @returns Interpolated string with variables replaced
16
*/
17
function interpolate(template: string, bindings: Record<string, any>): string;
18
```
19
20
**Usage Examples:**
21
22
```typescript
23
import { interpolate } from "@storybook/core-common";
24
25
// Basic interpolation
26
const template = 'Hello {{name}}, welcome to {{app}}!';
27
const result = interpolate(template, {
28
name: 'Alice',
29
app: 'Storybook'
30
});
31
console.log(result); // 'Hello Alice, welcome to Storybook!'
32
33
// HTML template interpolation
34
const htmlTemplate = `
35
<div class="{{className}}">
36
<h1>{{title}}</h1>
37
<p>Version: {{version}}</p>
38
</div>
39
`;
40
41
const html = interpolate(htmlTemplate, {
42
className: 'story-container',
43
title: 'My Component',
44
version: '1.2.0'
45
});
46
```
47
48
### Code Formatting
49
50
Format code content using Prettier with intelligent fallbacks and error handling.
51
52
```typescript { .api }
53
/**
54
* Format code using Prettier with fallbacks for different file types
55
* @param filePath - File path for parser detection
56
* @param content - Code content to format
57
* @returns Promise resolving to formatted code content
58
*/
59
function formatFileContent(filePath: string, content: string): Promise<string>;
60
```
61
62
**Usage Examples:**
63
64
```typescript
65
import { formatFileContent } from "@storybook/core-common";
66
67
// Format JavaScript code
68
const jsCode = `
69
const component={props}=><div className="test">{props.children}</div>;
70
export default component;
71
`;
72
73
const formattedJs = await formatFileContent('Component.js', jsCode);
74
console.log(formattedJs);
75
// const component = ({ props }) => (
76
// <div className="test">{props.children}</div>
77
// );
78
// export default component;
79
80
// Format TypeScript
81
const tsCode = `interface Props{title:string;onClick:()=>void;}`;
82
const formattedTs = await formatFileContent('types.ts', tsCode);
83
84
// Format JSON
85
const jsonCode = `{"name":"my-app","version":"1.0.0"}`;
86
const formattedJson = await formatFileContent('package.json', jsonCode);
87
```
88
89
### Logging Utilities
90
91
Styled logging functions for command-line interfaces and development tools.
92
93
```typescript { .api }
94
/**
95
* Styled command logging with success/error callbacks
96
* @param message - Base log message
97
* @returns Object with success and error logging methods
98
*/
99
function commandLog(message: string): {
100
success: (message: string) => void;
101
error: (message: string) => void;
102
};
103
104
/**
105
* Indented logging with consistent padding
106
* @param message - Message to log with padding
107
*/
108
function paddedLog(message: string): void;
109
110
/**
111
* Format code blocks for display with syntax highlighting hints
112
* @param codeLines - Array of code lines or single code string
113
* @param leftPadAmount - Left padding amount in spaces
114
*/
115
function codeLog(codeLines: string[] | string, leftPadAmount?: number): void;
116
117
/**
118
* Generate repeated character strings for formatting
119
* @param char - Character to repeat
120
* @param amount - Number of repetitions
121
* @returns String with repeated characters
122
*/
123
function getChars(char: string, amount: number): string;
124
```
125
126
**Usage Examples:**
127
128
```typescript
129
import {
130
commandLog,
131
paddedLog,
132
codeLog,
133
getChars
134
} from "@storybook/core-common";
135
136
// Command logging with status
137
const buildLog = commandLog('Building Storybook');
138
buildLog.success('Build completed successfully!');
139
buildLog.error('Build failed with errors');
140
141
// Padded logging for hierarchical output
142
console.log('Starting process...');
143
paddedLog('Loading configuration');
144
paddedLog('Processing stories');
145
paddedLog('Generating output');
146
147
// Code block logging
148
codeLog([
149
'import { Meta, StoryObj } from "@storybook/react";',
150
'import { Button } from "./Button";',
151
'',
152
'const meta: Meta<typeof Button> = {',
153
' title: "Example/Button",',
154
' component: Button,',
155
'};'
156
], 2);
157
158
// Character repetition for separators
159
const separator = getChars('=', 50);
160
console.log(separator);
161
console.log('Section Title');
162
console.log(separator);
163
```
164
165
### Template Generation
166
167
Generate HTML templates for Storybook preview with variable interpolation.
168
169
```typescript { .api }
170
/**
171
* Generate preview body HTML template with interpolations
172
* @param configDir - Storybook configuration directory
173
* @param interpolations - Variables for template interpolation
174
* @returns Generated HTML body content
175
*/
176
function getPreviewBodyTemplate(
177
configDir: string,
178
interpolations?: Record<string, any>
179
): Promise<string>;
180
181
/**
182
* Generate preview head HTML template with interpolations
183
* @param configDir - Storybook configuration directory
184
* @param interpolations - Variables for template interpolation
185
* @returns Generated HTML head content
186
*/
187
function getPreviewHeadTemplate(
188
configDir: string,
189
interpolations?: Record<string, any>
190
): Promise<string>;
191
```
192
193
**Usage Examples:**
194
195
```typescript
196
import {
197
getPreviewBodyTemplate,
198
getPreviewHeadTemplate
199
} from "@storybook/core-common";
200
201
// Generate preview templates
202
const bodyHtml = await getPreviewBodyTemplate('.storybook', {
203
theme: 'dark',
204
customStyles: '/assets/custom.css'
205
});
206
207
const headHtml = await getPreviewHeadTemplate('.storybook', {
208
title: 'My Storybook',
209
favicon: '/assets/favicon.ico'
210
});
211
212
// Use in HTML generation
213
const fullHtml = `
214
<!DOCTYPE html>
215
<html>
216
<head>
217
${headHtml}
218
</head>
219
<body>
220
${bodyHtml}
221
</body>
222
</html>
223
`;
224
```
225
226
### File Template Reading
227
228
Read template files with fallback handling and error recovery.
229
230
```typescript { .api }
231
/**
232
* Read template file with fallbacks and error handling
233
* @param filePath - Path to template file
234
* @returns Promise resolving to template content
235
*/
236
function readTemplate(filePath: string): Promise<string>;
237
```
238
239
**Usage Example:**
240
241
```typescript
242
import { readTemplate, interpolate } from "@storybook/core-common";
243
244
// Read and process template
245
const templateContent = await readTemplate('./templates/component.template');
246
const processedTemplate = interpolate(templateContent, {
247
componentName: 'MyButton',
248
props: 'title: string; onClick: () => void'
249
});
250
251
console.log(processedTemplate);
252
```
253
254
## Advanced Text Processing Patterns
255
256
### Dynamic Template Processing
257
258
```typescript
259
import { interpolate, formatFileContent } from "@storybook/core-common";
260
261
async function generateComponentCode(config: {
262
name: string;
263
props: Record<string, string>;
264
framework: 'react' | 'vue' | 'angular';
265
}) {
266
// Load framework-specific template
267
const templateMap = {
268
react: 'export interface {{name}}Props {\n{{propTypes}}\n}\n\nexport const {{name}} = (props: {{name}}Props) => {\n return <div>{{name}}</div>;\n};',
269
vue: '<template>\n <div>{{name}}</div>\n</template>\n\n<script>\nexport default {\n name: "{{name}}",\n props: {\n{{propTypes}}\n }\n};\n</script>',
270
angular: '@Component({\n selector: "app-{{kebabName}}",\n template: "<div>{{name}}</div>"\n})\nexport class {{name}}Component {\n{{propTypes}}\n}'
271
};
272
273
// Process prop types
274
const propTypes = Object.entries(config.props)
275
.map(([key, type]) => ` ${key}: ${type};`)
276
.join('\n');
277
278
// Interpolate template
279
const code = interpolate(templateMap[config.framework], {
280
name: config.name,
281
kebabName: config.name.replace(/([A-Z])/g, '-$1').toLowerCase(),
282
propTypes
283
});
284
285
// Format the generated code
286
const extension = config.framework === 'react' ? '.tsx' :
287
config.framework === 'vue' ? '.vue' : '.ts';
288
289
return await formatFileContent(`${config.name}${extension}`, code);
290
}
291
```
292
293
### Structured Logging System
294
295
```typescript
296
import { commandLog, paddedLog, codeLog } from "@storybook/core-common";
297
298
class StorybookLogger {
299
private level: number = 0;
300
301
startSection(title: string) {
302
const log = commandLog(title);
303
this.level++;
304
return {
305
info: (msg: string) => paddedLog(`${' '.repeat(this.level)}${msg}`),
306
success: (msg: string) => {
307
log.success(msg);
308
this.level--;
309
},
310
error: (msg: string) => {
311
log.error(msg);
312
this.level--;
313
},
314
code: (code: string[] | string) => codeLog(code, this.level * 2)
315
};
316
}
317
}
318
319
// Usage
320
const logger = new StorybookLogger();
321
322
const buildSection = logger.startSection('Building Storybook');
323
buildSection.info('Loading configuration...');
324
buildSection.info('Processing stories...');
325
buildSection.code([
326
'Found 25 stories in:',
327
' - src/components/*.stories.tsx',
328
' - src/pages/*.stories.tsx'
329
]);
330
buildSection.success('Build completed successfully!');
331
```
332
333
### Template Caching System
334
335
```typescript
336
import { readTemplate, interpolate, cache } from "@storybook/core-common";
337
338
class TemplateCache {
339
private templateCache = new Map<string, string>();
340
341
async getTemplate(templatePath: string): Promise<string> {
342
// Check memory cache first
343
if (this.templateCache.has(templatePath)) {
344
return this.templateCache.get(templatePath)!;
345
}
346
347
// Check file system cache
348
const cacheKey = `template-${templatePath}`;
349
let template = await cache.get<string>(cacheKey);
350
351
if (!template) {
352
// Read from disk and cache
353
template = await readTemplate(templatePath);
354
await cache.set(cacheKey, template);
355
}
356
357
// Store in memory for immediate reuse
358
this.templateCache.set(templatePath, template);
359
return template;
360
}
361
362
async processTemplate(
363
templatePath: string,
364
bindings: Record<string, any>
365
): Promise<string> {
366
const template = await this.getTemplate(templatePath);
367
return interpolate(template, bindings);
368
}
369
}
370
371
// Usage
372
const templates = new TemplateCache();
373
const processed = await templates.processTemplate('./templates/story.template', {
374
componentName: 'Button',
375
storyName: 'Primary'
376
});
377
```
378
379
## Supporting Types
380
381
```typescript { .api }
382
interface InterpolationBindings {
383
[key: string]: string | number | boolean | null | undefined;
384
}
385
386
interface LogMethods {
387
success: (message: string) => void;
388
error: (message: string) => void;
389
}
390
391
interface TemplateOptions {
392
configDir: string;
393
interpolations?: Record<string, any>;
394
}
395
```