DEV Community

Steven Hur
Steven Hur

Posted on

A Deep Dive into Repomix: How a Simple `--style` Flag Powers Multiple Output Formats

For my OSD600 Lab 6, I had to explore Repomix, an open-source tool, to get inspiration for my own project. Repomix is AI-friendly file that packs a codebase into a single file. The feature that caught my eye was its ability to generate different output formats—XML, Markdown, JSON, and plain text all controlled by a simple --style flag.

Where are you???
Initially, I tried using GitHub's web interface to search for keywords like --style and markdown. It was useful searching for file names but it had limitations for searching the content inside the files. So I decided to fork/clone the repository and use VScode search feature to find the exact function or methods. Using search feature, I looked for my key clues: style, markdown, and output. This was a correct decision to make because it lead me to the markdownStyle.ts and outputGenerate.ts file.

While reading and analyzing the two source code files, I was able to notice the clean and effective software design structure. The logic is split into two main parts:

  1. The Blueprint (Template): A file that defines the structure of the output. (markdownStyle.ts)
  2. The Command Center(Generator): A file that gathers the data, selects the correct blueprint, and builds the final product. (outputGenerate.ts)

File 1: The Blueprint - markdownStyle.ts
This file acts as a template for the Markdown output. Instead of building the string piece by piece using concat, Repomix uses the Handlebars. This is a fill-in-the-blanks approach.
The getMarkdownTemplate returns a single template string that lays out the entire structure of the final .md file.

export const getMarkdownTemplate = () => {
  return /* md */ `
{{#if directoryStructureEnabled}}
# Directory Structure
\`\`\`
{{{treeString}}}
\`\`\`

{{/if}}
{{#if filesEnabled}}
# Files

{{#each processedFiles}}
## File: {{{this.path}}}
{{{../markdownCodeBlockDelimiter}}}{{{getFileExtension this.path}}}
{{{this.content}}}
{{{../markdownCodeBlockDelimiter}}}

{{/each}}
{{/if}}
`;
};
Enter fullscreen mode Exit fullscreen mode

This block of code shows how Handlebars placeholders like {{{treeString}}} and loops like {{#each processedFiles}} are used.

File 2: The Command Center - outputGenerate.ts
This file is the main control center. It brings together the data and the templates to generate the final output.
It has three purposes:

  1. Gathering Data: It collects all the necessary information- the directory tree, file contents, git logs, etc. and put it into a single object called RenderContext.

  2. Selecting the Blueprint: It uses the user's config.output.style choice to select the required template.

  3. Building the Output: It passes the RenderContext data object to the correct template for rendering.

The core of this logic resides in the generateOutput and generateHandlebarOutput functions.
The generateOutput function acts as the main router, deciding which generation method to use based on the style.

// src/core/output/outputGenerate.ts

export const generateOutput = async (...) => {
  // ... data preparation logic ...
  const renderContext = createRenderContext(outputGeneratorContext);

  switch (config.output.style) {
    case 'xml':
      // ... uses a dedicated XML builder
    case 'json':
      // ... uses a dedicated JSON builder
    case 'markdown':
    case 'plain':
      return deps.generateHandlebarOutput(config, renderContext, sortedProcessedFiles);
    default:
      throw new RepomixError(`Unsupported output style: ${config.output.style}`);
  }
};
Enter fullscreen mode Exit fullscreen mode

For Markdown and plain text, it calls generateHandlebarOutput, which in turn selects the specific template file.

// src/core/output/outputGenerate.ts

const generateHandlebarOutput = async (...) => {
  let template: string;
  switch (config.output.style) {
    case 'xml':
      template = getXmlTemplate();
      break;
    case 'markdown':
      template = getMarkdownTemplate(); // Our blueprint is chosen here!
      break;
    case 'plain':
      template = getPlainTemplate();
      break;
    // ...
  }
  // ... Handlebars compiles the template and data ...
};
Enter fullscreen mode Exit fullscreen mode

Conclusion
Analyzing Repomix was a good chance to learn system architecture technique. The key takeaway for me is the power of separating data from the presentation. By providing templates, the code is cleaner to maintain and easily extensible. This is an architectural pattern I will definitely be utilizing for my own Repo_Code_Packager project as I add the same multi-format output feature.

Top comments (0)