Go implementation of a cooklang parser.
- ✅ Full Cooklang specification compliance
- 🖼️ Automatic image detection - Auto-discovers recipe images matching filename patterns
- 📝 Frontmatter CRUD operations - Programmatically edit recipe metadata
- 🧮 Unit conversion system with metric/imperial/US systems
- 📋 Shopping list generation from multiple recipes
- 🎨 Multiple output formats (Cooklang, Markdown, HTML, JSON)
- 🔧 Extended mode with ingredient/cookware annotations
- ⚖️ Recipe scaling and ingredient consolidation
- 🛠️ Comprehensive CLI tool
The library includes comprehensive, runnable examples demonstrating all major features. See docs/EXAMPLES.md for a complete list.
Quick example:
package main
import (
"fmt"
"log"
"github.com/hilli/cooklang"
)
func main() {
recipeText := `---
title: Pasta Aglio e Olio
servings: 2
---
Cook @pasta{400%g} in salted water for ~{10%minutes}.
Meanwhile, heat @olive oil{4%tbsp} and sauté @garlic{3%cloves}.
Toss everything together and serve.`
recipe, err := cooklang.ParseString(recipeText)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Recipe: %s (serves %.0f)\n", recipe.Title, recipe.Servings)
// Get shopping list
shoppingList, _ := recipe.GetCollectedIngredientsMap()
for ingredient, quantity := range shoppingList {
fmt.Printf("- %s: %s\n", ingredient, quantity)
}
}Projects using this library:
- cocktailti.me - Cocktail recipe sharing website
Using this library? Open a PR to add your project!
See the Cooklang specification for details.
This parser supports additional syntax extensions beyond the base Cooklang specification:
Ingredients can have annotations in parentheses to specify preparation notes or state:
@milk{1%l}(cold)The annotation (cold) is stored as the ingredient's value field.
Similarly, cookware items can have annotations for usage hints:
#pan{}(for frying)Timers can have descriptive multi-word names:
~roast time{4%hours}Comments are preserved as a distinct type in the parsed output rather than being discarded:
-- This is a commentComments are accessible with type: comment and their text in the value field.
This project uses a Taskfile for convenience. Install by running:
go install toolRun all tests with:
task testTest the specification specifically with:
task test-specLint the stuff:
task lint