Skip to content

Duplicate Code: Shared Logic in New Story File Template Generators #34456

@github-actions

Description

@github-actions

Analysis of commit ce8c743

Assignee: @copilot

Summary

The three new story file template generator functions in code/core/src/core-server/utils/new-story-templates/ contain near-identical import resolution and args serialization logic that is duplicated across all template variants. This is copy-paste duplication introduced as part of the recent PR adding new-story template helpers.

Duplication Details

Pattern: Component Import Resolution Logic

  • Severity: Medium
  • Occurrences: 3 identical or near-identical blocks
  • Locations:
    • code/core/src/core-server/utils/new-story-templates/javascript.ts (lines 17–22)
    • code/core/src/core-server/utils/new-story-templates/typescript.ts (lines 19–24)
    • code/core/src/core-server/utils/new-story-templates/csf-factory-template.ts (lines 19–24)
  • Code Sample:
    const importName = data.componentIsDefaultExport
      ? await getComponentVariableName(data.basenameWithoutExtension)
      : data.componentExportName;
    const importStatement = data.componentIsDefaultExport
      ? `import \$\{importName} from './\$\{data.basenameWithoutExtension}';`
      : `import { \$\{importName} } from './\$\{data.basenameWithoutExtension}';`;

Pattern: hasArgs / argsString Serialization Logic

  • Severity: Low–Medium
  • Occurrences: 2 identical blocks
  • Locations:
    • code/core/src/core-server/utils/new-story-templates/javascript.ts (lines 24–25)
    • code/core/src/core-server/utils/new-story-templates/typescript.ts (lines 26–27)
  • Code Sample:
    const hasArgs = Boolean(data.args && Object.keys(data.args).length > 0);
    const argsString = hasArgs ? `args: \$\{JSON.stringify(data.args, null, 2)},` : '';

Pattern: Shared Interface Fields

All three template data interfaces (JavaScriptTemplateData, TypeScriptTemplateData, CsfFactoryTemplateData) declare the same five fields:

basenameWithoutExtension: string;
componentExportName: string;
componentIsDefaultExport: boolean;
exportedStoryName: string;
args?: Record(string, any);

Impact Analysis

  • Maintainability: Any change to import generation logic (e.g., supporting import type, ESM extensions, or path aliases) must be applied in three separate files. This has already caused a subtle inconsistency: the TypeScript template omits the trailing semicolon on the import statement (line 23 of typescript.ts) while the other two templates include it.
  • Bug Risk: High — a fix to one template (e.g., correcting the argsString format or escaping) will silently miss the other two if not applied consistently.
  • Code Bloat: ~18 lines of duplicated import-resolution code across the three template files.

Refactoring Recommendations

  1. Extract resolveComponentImport() helper

    • Create: code/core/src/core-server/utils/new-story-templates/helpers.ts
    • Signature:
      export async function resolveComponentImport(
        data: Pick(BaseTemplateData, 'componentIsDefaultExport' | 'componentExportName' | 'basenameWithoutExtension'),
        trailingSemicolon = true
      ): Promise<{ importName: string; importStatement: string }>;
    • Estimated effort: ~1 hour
    • Benefits: Single place to update import logic; fixes existing inconsistency around trailing semicolons
  2. Extract BaseTemplateData interface

    • Define the five shared fields in a BaseTemplateData interface in helpers.ts and have each template interface extend it:
      export interface BaseTemplateData {
        basenameWithoutExtension: string;
        componentExportName: string;
        componentIsDefaultExport: boolean;
        exportedStoryName: string;
        args?: Record(string, any);
      }
    • Estimated effort: ~30 minutes
    • Benefits: Single source of truth for shared template input shape
  3. Extract serializeArgs() helper (optional)

    • Consolidate the hasArgs/argsString pattern used in JS and TS templates
    • Estimated effort: ~30 minutes

Implementation Checklist

  • Review duplication findings
  • Create code/core/src/core-server/utils/new-story-templates/helpers.ts with BaseTemplateData and resolveComponentImport()
  • Refactor javascript.ts, typescript.ts, and csf-factory-template.ts to use shared helpers
  • Align trailing semicolon behaviour across all three templates
  • Update tests in *.test.ts files alongside each template
  • Verify no functionality broken

Analysis Metadata

  • Analyzed Files: 3 (javascript.ts, typescript.ts, csf-factory-template.ts)
  • Detection Method: Serena semantic code analysis + pattern search
  • Commit: ce8c743
  • Analysis Date: 2026-04-03

Generated by Duplicate Code Detector ·

To install this agentic workflow, run

gh aw add github/gh-aw/.github/workflows/duplicate-code-detector.md@852cb06ad52958b402ed982b69957ffc57ca0619

Metadata

Metadata

Assignees

No one assigned

    Labels

    cleanupMinor cleanup style change that won't show up in release changelogtech debt

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions