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

> Discover how the npm build script in HowToCook generates your README and mkdocs.yml by scanning recipe files and organizing them by difficulty.

- Repository: [Anduin Xue/HowToCook](https://github.com/Anduin2017/HowToCook)
- Tags: deep-dive
- Published: 2026-02-27

---

**The npm build script runs a Node.js generator at [`.github/readme-generate.js`](https://github.com/Anduin2017/HowToCook/blob/main/.github/readme-generate.js) that scans Markdown recipe files, categorizes them by difficulty using star ratings, and outputs both [`README.md`](https://github.com/Anduin2017/HowToCook/blob/main/README.md) and [`mkdocs.yml`](https://github.com/Anduin2017/HowToCook/blob/main/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`](https://github.com/Anduin2017/HowToCook/blob/main/package.json) as a single Node execution:

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

```

When you execute `npm run build`, Node.js immediately invokes [`.github/readme-generate.js`](https://github.com/Anduin2017/HowToCook/blob/main/.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`](https://github.com/Anduin2017/HowToCook/blob/main/.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`](https://github.com/Anduin2017/HowToCook/blob/main/.github/templates/readme_template.md) or [`.github/templates/mkdocs_template.yml`](https://github.com/Anduin2017/HowToCook/blob/main/.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`](https://github.com/Anduin2017/HowToCook/blob/main/.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`](https://github.com/Anduin2017/HowToCook/blob/main/5Star.md), [`6Star.md`](https://github.com/Anduin2017/HowToCook/blob/main/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`](https://github.com/Anduin2017/HowToCook/blob/main/README.md) – The repository's main documentation.
- [`mkdocs.yml`](https://github.com/Anduin2017/HowToCook/blob/main/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`](https://github.com/Anduin2017/HowToCook/blob/main/.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:

```javascript
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`](https://github.com/Anduin2017/HowToCook/blob/main/.github/readme-generate.js).

This function powers the `organizeByStars` logic, enabling the build script to generate difficulty-based indexes like [`5Star.md`](https://github.com/Anduin2017/HowToCook/blob/main/5Star.md) for five-star recipes.

## Key Files in the Build System

| File | Role | Source |
|------|------|--------|
| [`package.json`](https://github.com/Anduin2017/HowToCook/blob/main/package.json) | Declares the `build` command that triggers the generator. | [package.json](https://github.com/Anduin2017/HowToCook/blob/master/package.json) |
| [`.github/readme-generate.js`](https://github.com/Anduin2017/HowToCook/blob/main/.github/readme-generate.js) | Core generator: discovers Markdown, groups by category/stars, writes outputs. | [.github/readme‑generate.js](https://github.com/Anduin2017/HowToCook/blob/master/.github/readme-generate.js) |
| [`.github/templates/readme_template.md`](https://github.com/Anduin2017/HowToCook/blob/main/.github/templates/readme_template.md) | Optional template for README structure with placeholders. | [readme_template.md](https://github.com/Anduin2017/HowToCook/blob/master/.github/templates/readme_template.md) |
| [`.github/templates/mkdocs_template.yml`](https://github.com/Anduin2017/HowToCook/blob/main/.github/templates/mkdocs_template.yml) | Optional MkDocs configuration template. | [mkdocs_template.yml](https://github.com/Anduin2017/HowToCook/blob/master/.github/templates/mkdocs_template.yml) |
| [`README.md`](https://github.com/Anduin2017/HowToCook/blob/main/README.md) | Generated output displayed on GitHub. | [README.md](https://github.com/Anduin2017/HowToCook/blob/master/README.md) |
| [`mkdocs.yml`](https://github.com/Anduin2017/HowToCook/blob/main/mkdocs.yml) | Generated MkDocs site configuration. | [mkdocs.yml](https://github.com/Anduin2017/HowToCook/blob/master/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`](https://github.com/Anduin2017/HowToCook/blob/main/README.md) and [`mkdocs.yml`](https://github.com/Anduin2017/HowToCook/blob/main/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`](https://github.com/Anduin2017/HowToCook/blob/main/.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`](https://github.com/Anduin2017/HowToCook/blob/main/package.json). This command invokes Node.js to run [`.github/readme-generate.js`](https://github.com/Anduin2017/HowToCook/blob/main/.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`](https://github.com/Anduin2017/HowToCook/blob/main/5Star.md) or [`3Star.md`](https://github.com/Anduin2017/HowToCook/blob/main/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`](https://github.com/Anduin2017/HowToCook/blob/main/.github/templates/readme_template.md) and [`.github/templates/mkdocs_template.yml`](https://github.com/Anduin2017/HowToCook/blob/main/.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`](https://github.com/Anduin2017/HowToCook/blob/main/README.md) for the GitHub repository homepage, and [`mkdocs.yml`](https://github.com/Anduin2017/HowToCook/blob/main/mkdocs.yml) for the MkDocs static site generator. It also creates intermediate star-rating index files in the `starsystem/` directory (e.g., [`5Star.md`](https://github.com/Anduin2017/HowToCook/blob/main/5Star.md)) that are linked within the main README.