Skip to content

Instantly share code, notes, and snippets.

@agneym
Created May 9, 2025 15:20
Show Gist options
  • Save agneym/143212017bbcc3e44e1dd732bfc463c0 to your computer and use it in GitHub Desktop.
Save agneym/143212017bbcc3e44e1dd732bfc463c0 to your computer and use it in GitHub Desktop.
Add a title for all stories
// storybook-title.js
let titleCounter = 0;
function getNextSequentialTitle() {
titleCounter++;
return String(titleCounter);
}
export default function transformer(fileInfo, api) {
// Add this check to ensure only relevant story files are processed
if (!/\.stories\.(jsx|tsx)$/.test(fileInfo.path)) {
return null; // Skip files not matching the *.stories.(jsx|tsx) pattern
}
const j = api.jscodeshift;
const root = j(fileInfo.source);
let changed = false;
// Helper function to add title if missing from an ObjectExpression
const addTitleToObjectIfMissing = (objectExpression) => {
if (!objectExpression || objectExpression.type !== 'ObjectExpression') {
return;
}
const properties = objectExpression.properties;
const hasTitle = properties.some(prop =>
prop.type === 'Property' &&
prop.key && prop.key.type === 'Identifier' &&
prop.key.name === 'title'
);
if (!hasTitle) {
const newTitleProperty = j.property(
'init',
j.identifier('title'),
j.literal(getNextSequentialTitle())
);
properties.unshift(newTitleProperty);
changed = true;
}
};
// Case 1: export default { ... }
root.find(j.ExportDefaultDeclaration)
.filter(path => path.node.declaration.type === 'ObjectExpression')
.forEach(path => {
addTitleToObjectIfMissing(path.node.declaration);
});
// Case 2: const meta = { ... }; export default meta;
root.find(j.ExportDefaultDeclaration)
.filter(path => path.node.declaration.type === 'Identifier')
.forEach(path => {
const varName = path.node.declaration.name;
root.findVariableDeclarators(varName)
.filter(declPath => declPath.node.init && declPath.node.init.type === 'ObjectExpression')
.forEach(declPath => {
addTitleToObjectIfMissing(declPath.node.init);
});
});
// Case 3: export const meta = { ... };
root.find(j.ExportNamedDeclaration)
.forEach(path => {
const declaration = path.node.declaration;
if (declaration && declaration.type === 'VariableDeclaration') {
declaration.declarations.forEach(declarator => {
if (declarator.id.type === 'Identifier' &&
declarator.id.name === 'meta' &&
declarator.init && declarator.init.type === 'ObjectExpression') {
addTitleToObjectIfMissing(declarator.init);
}
});
}
});
return changed ? root.toSource({ quote: 'single', trailingComma: true }) : null;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment