How the Star Rating System Works in HowToCook: A Complete Technical Guide
The HowToCook star rating system automatically categorizes recipes by difficulty using Unicode star characters (★) embedded in markdown files, then generates indexed navigation pages through the countStars() function in .github/readme-generate.js.
The Anduin2017/HowToCook repository implements a data-driven star rating system to help cooks find recipes matching their skill level. This automated pipeline parses difficulty ratings from individual recipe files and generates organized index pages without requiring manual maintenance.
How the Star Rating System Parses Recipe Difficulty
The Star Syntax in Recipe Markdown Files
Every recipe in the repository includes a difficulty declaration using Unicode star characters. The line appears as:
预估烹饪难度:★
The number of ★ symbols ranges from 1 to 5, representing increasing complexity. For example, the 鸡蛋花 recipe contains a single star, indicating beginner-friendly difficulty, located at line 5 in dishes/vegetable_dish/鸡蛋花/鸡蛋花.md.
Counting Stars with the countStars() Function
The core parsing logic resides in .github/readme-generate.js at lines 65-73. The countStars() function reads markdown files and tallies star 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;
}
This implementation uses a regular expression to match all ★ characters across the entire file, ensuring accurate difficulty calculation even if formatting varies.
Generating the Star System Index Pages
Organizing Recipes by Difficulty
The organizeByStars() function (lines 75-90 in .github/readme-generate.js) orchestrates the categorization process. It traverses the dishes/ directory, invokes countStars() for every .md file, and constructs a mapping of file paths to their respective star counts.
Creating Star-Specific Markdown Files
After collecting the difficulty data, the generator creates individual index pages within the starsystem/ directory. Files follow the naming convention {N}Star.md, ranging from 0Star.md to 5Star.md.
Each generated file contains a header and bulleted list of recipes with relative links:
# 1 星难度菜品
* [鸡蛋花](../dishes/vegetable_dish/鸡蛋花/鸡蛋花.md)
This structure enables direct navigation to recipes matching specific skill levels.
Integrating Star Ratings into the Main README
The automation extends to the repository's main entry point. The script constructs a navigation block:
### 按难度索引
- [0 星难度](starsystem/0Star.md)
- [1 星难度](starsystem/1Star.md)
This block replaces the {{index_stars}} placeholder in README_template.md, resulting in the live "按难度索引" section visible in README.md (lines 55-59). The process ensures the difficulty navigation stays synchronized with the actual recipe collection without manual updates.
Practical Code Examples
Checking a Specific Recipe's Rating
Use the countStars function directly to verify a dish's difficulty:
const { countStars } = require('./.github/readme-generate.js');
(async () => {
const stars = await countStars('dishes/vegetable_dish/鸡蛋花/鸡蛋花.md');
console.log(`鸡蛋花 rating: ${stars} ★`);
})();
Regenerating the Entire Star System
Execute the full pipeline from the repository root:
node .github/readme-generate.js
This command rescans all dishes, rebuilds the starsystem/ index pages, and updates README.md with current navigation links.
Reading Generated Star Indexes Programmatically
Access the pre-built difficulty lists for external applications:
const fs = require('fs').promises;
async function listStars(star) {
const file = `starsystem/${star}Star.md`;
const content = await fs.readFile(file, 'utf-8');
console.log(`Recipes with ${star} star(s):\n${content}`);
}
listStars(3); // prints all 3‑star recipes
Summary
- The star rating system in HowToCook uses Unicode ★ characters embedded in recipe markdown to indicate cooking difficulty from 1 to 5 stars.
- The
countStars()function in.github/readme-generate.jsparses these characters using regex matching to calculate difficulty scores. - The
organizeByStars()function automatically categorizes recipes and generates dedicated index pages (0Star.mdthrough5Star.md) in thestarsystem/directory. - The README navigation updates automatically via template replacement of the
{{index_stars}}placeholder, ensuring the difficulty index remains synchronized with the recipe collection.
Frequently Asked Questions
How is the cooking difficulty determined for each recipe?
Recipe authors manually specify difficulty by including a line such as 预估烹饪难度:★★★ in the markdown file. The number of ★ symbols (1 to 5) represents the estimated complexity, preparation time, and technique required. The generator script does not assign ratings automatically; it only reads the existing markers.
Can I filter recipes by star rating on the GitHub website?
Yes. The repository generates static markdown index pages in the starsystem/ folder (e.g., 1Star.md, 2Star.md). You can navigate to these files directly in the GitHub file browser or through the "按难度索引" (Index by Difficulty) section in the main README, which links to each star category.
What happens if a recipe has no star rating or an invalid number of stars?
If a recipe contains no ★ characters, the countStars() function returns 0, and the recipe is categorized under 0Star.md. The current implementation does not enforce a maximum limit during counting, but the convention limits ratings to 5 stars. Recipes with more than 5 stars would still be counted accurately but would generate index files like 6Star.md if they existed.
How do I update the star rating for an existing recipe?
Edit the specific recipe markdown file in the dishes/ directory and modify the line containing 预估烹饪难度:. Change the number of ★ symbols to reflect the new difficulty level. After committing the change, run node .github/readme-generate.js to regenerate the star system indexes and update the README navigation automatically.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →