-
-
Notifications
You must be signed in to change notification settings - Fork 10k
Duplicate Code: previewAnnotations Pattern Repeated Across 5 Renderer Presets #34389
Description
Analysis of commit 0efef13
Assignee: @copilot
Summary
The previewAnnotations export function is nearly identical across 5 renderer preset files, differing only in the package name string. This is a clear copy-paste duplication that impacts maintainability and increases the risk of inconsistencies when the pattern needs to change.
Duplication Details
Pattern: Identical previewAnnotations factory logic across renderer presets
-
Severity: Medium
-
Occurrences: 5 instances
-
Locations:
code/renderers/html/src/preset.ts(lines 5–17)code/renderers/preact/src/preset.ts(lines 5–19)code/renderers/svelte/src/preset.ts(lines 5–19)code/renderers/vue3/src/preset.ts(lines 5–17)code/renderers/web-components/src/preset.ts(lines 5–22)
-
Code Sample (html renderer, representative of all 5):
export const previewAnnotations: PresetProperty<'previewAnnotations'> = async ( input = [], options ) => { const docsEnabled = Object.keys(await options.presets.apply('docs', {}, options)).length > 0; const result: string[] = []; return result .concat(input) .concat([fileURLToPath(import.meta.resolve('`@storybook/html`/entry-preview'))]) .concat( docsEnabled ? [fileURLToPath(import.meta.resolve('`@storybook/html`/entry-preview-docs'))] : [] ); };
The only difference across all 5 files is the package name (
@storybook/html,@storybook/preact,@storybook/svelte,@storybook/vue3,@storybook/web-components). ThedocsEnabledcheck, result-building logic, and function signature are identical.
Impact Analysis
- Maintainability: Any change to the
docsEnabledcheck logic (e.g., adding another condition, changing how docs is detected) must be made in 5 separate files manually. - Bug Risk: A bug in one file may not be fixed in the others if developers don't know about the duplication.
- Code Bloat: ~60 lines of functionally identical code spread across 5 packages.
Refactoring Recommendations
-
Extract a shared factory helper
- Create a utility in
code/core/src/common/utils/(e.g.,createPreviewAnnotations.ts) or in a shared renderer utility:export function createPreviewAnnotations(packageName: string, extraEntries: string[] = []) { return async (input = [], options) => { const docsEnabled = Object.keys(await options.presets.apply('docs', {}, options)).length > 0; return ([] as string[]) .concat(input) .concat(extraEntries.map(e => fileURLToPath(import.meta.resolve(e)))) .concat([fileURLToPath(import.meta.resolve(`\$\{packageName}/entry-preview`))]) .concat(docsEnabled ? [fileURLToPath(import.meta.resolve(`\$\{packageName}/entry-preview-docs`))] : []); }; }
- Each renderer then becomes a one-liner:
export const previewAnnotations = createPreviewAnnotations('`@storybook/html`');
- Estimated effort: 2–3 hours
- Benefits: Single place to update the docs detection logic; consistent behavior across renderers
- Create a utility in
-
Keep renderer-specific overrides (e.g.,
web-componentsaddsentry-preview-argtypes,reacthas additional conditions) handled via theextraEntriesparameter or a callback.
Implementation Checklist
- Review duplication findings
- Create shared
createPreviewAnnotationsfactory - Update
html,preact,svelte,vue3,web-componentspresets to use it - Confirm
reactpreset (which has additional logic) either uses the factory with extensions or stays separate - Update tests if any exist for these presets
- Verify no functionality broken
Analysis Metadata
- Analyzed Files: 5 renderer preset files
- Detection Method: Semantic code analysis + direct file comparison
- Commit: 0efef13
- Analysis Date: 2026-03-29
Generated by Duplicate Code Detector · ◷
To install this agentic workflow, run
gh aw add github/gh-aw/.github/workflows/duplicate-code-detector.md@852cb06ad52958b402ed982b69957ffc57ca0619