How the npm Build Script Works in HowToCook: A Deep Dive into the Documentation Generator

The npm build script runs a Node.js generator at .github/readme-generate.js that scans Markdown recipe files, categorizes them by difficulty using star ratings, and outputs both README.md and mkdocs.yml for GitHub and the documentation site.

The Anduin2017/HowToCook repository uses an automated build pipeline to maintain its documentation. When contributors add new recipes or modify existing ones, the npm build script orchestrates the regeneration of the project's README and MkDocs configuration. This ensures the documentation stays synchronized with the actual recipe files stored in the repository.

What the npm Build Script Does

The build command is defined in package.json as a single Node execution:

"build": "node ./.github/readme-generate.js"

When you execute npm run build, Node.js immediately invokes .github/readme-generate.js. This script performs a multi-stage pipeline that discovers all Markdown content, groups recipes by category and difficulty, and writes the final output files.

The Build Pipeline: Step-by-Step Execution

The main() function in .github/readme-generate.js orchestrates seven distinct stages:

1. Template Loading

The script first attempts to load optional template files. If .github/templates/readme_template.md or .github/templates/mkdocs_template.yml exist, they are read into memory. If missing, the script falls back to default template strings stored in the README_TEMPLATE and MKDOCS_TEMPLATE constants.

Source reference: Lines 67-80 in .github/readme-generate.js.

2. Markdown Discovery

The getAllMarkdown('.') function recursively walks the repository root, skipping ignored paths like node_modules and .git. It returns an array of objects containing the file path and content for every .md file found.

Source reference: Function getAllMarkdown at lines 110-126.

3. Content Classification

The script iterates over each Markdown entry and distributes files into three buckets:

  • Tips: Files in tips/ and tips/advanced/ are appended to README_BEFORE or README_AFTER sections.
  • Dish categories: Files in folders like vegetable_dish, meat_dish, or breakfast are grouped into category objects containing both README and MkDocs content.
  • Other content: Auxiliary files are handled according to their directory structure.

Classification occurs by matching file paths against known category keys in the main processing loop.

Source reference: Loop over markdownObj in main() at lines 33-57.

4. Category Assembly

For each category object, the script builds formatted sections using categoryReadmeTemplate and categoryMkdocsTemplate. These templates generate the navigation structure for the README table of contents and the MkDocs site hierarchy.

Source reference: Template definitions at lines 33-44.

5. Star Rating Index Generation

The organizeByStars(dishesFolder, starsystemFolder) function scans every dish Markdown file and counts the number of ★ characters (representing difficulty). It creates individual markdown files for each rating level (e.g., 5Star.md, 6Star.md) and returns navigation links to be inserted into the README.

Source reference: Function organizeByStars at lines 75-122.

6. Final File Generation

The script replaces placeholders in the loaded templates ({{before}}, {{main}}, {{after}}, {{index_stars}}) with the assembled content strings. It then writes the final output to:

  • README.md – The repository's main documentation.
  • mkdocs.yml – Configuration for the MkDocs static site generator.

Source reference: writeFile calls at lines 86-101.

7. Execution Entry Point

The main() function is invoked immediately at the bottom of the script file, starting the entire pipeline when npm run build executes.

Source reference: Line 245 in .github/readme-generate.js.

How the Star Rating System Works

The difficulty rating system relies on Unicode star characters (★) embedded in recipe files. The countStars function reads each file and tallies the occurrences:

async function countStars(filename) {
  const data = await fs.readFile(filename, 'utf-8');
  let stars = 0;
  const lines = data.split('\n');
  lines.forEach(line => {
    stars += (line.match(//g) || []).length;
  });
  return stars;
}

Source reference: Lines 66-71 in .github/readme-generate.js.

This function powers the organizeByStars logic, enabling the build script to generate difficulty-based indexes like 5Star.md for five-star recipes.

Key Files in the Build System

File Role Source
package.json Declares the build command that triggers the generator. package.json
.github/readme-generate.js Core generator: discovers Markdown, groups by category/stars, writes outputs. .github/readme‑generate.js
.github/templates/readme_template.md Optional template for README structure with placeholders. readme_template.md
.github/templates/mkdocs_template.yml Optional MkDocs configuration template. mkdocs_template.yml
README.md Generated output displayed on GitHub. README.md
mkdocs.yml Generated MkDocs site configuration. mkdocs.yml

Summary

  • The npm build script executes node ./.github/readme-generate.js to regenerate documentation.
  • The pipeline loads templates, discovers all Markdown files, classifies them by category and difficulty, and assembles navigation structures.
  • Star ratings (★) are counted via regex in each recipe file to generate difficulty-based indexes.
  • Output files README.md and mkdocs.yml are generated from templates using placeholder substitution ({{before}}, {{main}}, {{after}}, {{index_stars}}).
  • The entire process is orchestrated by the main() function in .github/readme-generate.js.

Frequently Asked Questions

What command triggers the documentation build?

Running npm run build in the repository root executes the build script defined in package.json. This command invokes Node.js to run .github/readme-generate.js, which regenerates both the README and MkDocs configuration files.

How does the script determine recipe difficulty?

The script analyzes each Markdown file for Unicode star characters (★) using the countStars function. It reads the file content, splits it by lines, and counts star occurrences with a regular expression. Recipes are then grouped into files like 5Star.md or 3Star.md based on these counts.

Can I customize the output format?

Yes. The script looks for template files at .github/templates/readme_template.md and .github/templates/mkdocs_template.yml. If present, it uses these templates and replaces placeholders like {{main}} and {{index_stars}} with generated content. If templates are missing, the script falls back to default internal strings.

What files does the build script generate?

The script produces two primary outputs: README.md for the GitHub repository homepage, and mkdocs.yml for the MkDocs static site generator. It also creates intermediate star-rating index files in the starsystem/ directory (e.g., 5Star.md) that are linked within the main README.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →