cooklang-parse 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -30
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10698 -9909
- package/dist/parse-cooklang.d.ts +3 -0
- package/dist/parse-cooklang.d.ts.map +1 -0
- package/dist/parser/component-builders.d.ts +10 -0
- package/dist/parser/component-builders.d.ts.map +1 -0
- package/dist/parser/extensions.d.ts +5 -0
- package/dist/parser/extensions.d.ts.map +1 -0
- package/dist/parser/frontmatter.d.ts +9 -0
- package/dist/parser/frontmatter.d.ts.map +1 -0
- package/dist/parser/internal-types.d.ts +31 -0
- package/dist/parser/internal-types.d.ts.map +1 -0
- package/dist/parser/metadata.d.ts +8 -0
- package/dist/parser/metadata.d.ts.map +1 -0
- package/dist/parser/ohm-ast.d.ts +14 -0
- package/dist/parser/ohm-ast.d.ts.map +1 -0
- package/dist/parser/preprocess.d.ts +10 -0
- package/dist/parser/preprocess.d.ts.map +1 -0
- package/dist/parser/quantity.d.ts +3 -0
- package/dist/parser/quantity.d.ts.map +1 -0
- package/dist/parser/raw-step-items.d.ts +4 -0
- package/dist/parser/raw-step-items.d.ts.map +1 -0
- package/dist/parser/step-processing.d.ts +14 -0
- package/dist/parser/step-processing.d.ts.map +1 -0
- package/dist/semantics.d.ts +2 -5
- package/dist/semantics.d.ts.map +1 -1
- package/dist/types.d.ts +62 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -0
- package/grammars/cooklang.ohm +43 -24
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
|
|
12
12
|
- Full Cooklang spec support including ingredients, cookware, timers, metadata, sections, notes, and YAML frontmatter
|
|
13
13
|
- Written in TypeScript with exported type definitions
|
|
14
|
-
- Single function API — `parseCooklang(source)`
|
|
15
|
-
-
|
|
14
|
+
- Single function API with extension presets — `parseCooklang(source, options?)`
|
|
15
|
+
- 235 tests with parity coverage against [cooklang-rs](https://github.com/cooklang/cooklang-rs) canonical and default parser behaviors
|
|
16
16
|
- Source position tracking and parse error reporting
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
@@ -32,16 +32,31 @@ const recipe = parseCooklang(`
|
|
|
32
32
|
>> servings: 4
|
|
33
33
|
|
|
34
34
|
Preheat #oven to 180C.
|
|
35
|
+
|
|
35
36
|
Mix @flour{250%g} and @eggs{3} in a #bowl{}.
|
|
37
|
+
|
|
36
38
|
Bake for ~{20%minutes}.
|
|
37
39
|
`)
|
|
38
40
|
|
|
39
41
|
recipe.metadata // { servings: 4 }
|
|
40
|
-
recipe.ingredients // [{ type: "ingredient", name: "flour", quantity: 250, units: "g", fixed: false }, ...]
|
|
41
|
-
recipe.cookware // [{ type: "cookware", name: "oven", quantity: 1, units: "" }, ...]
|
|
42
|
+
recipe.ingredients // [{ type: "ingredient", name: "flour", quantity: 250, units: "g", fixed: false, modifiers: {...}, relation: {...} }, ...]
|
|
43
|
+
recipe.cookware // [{ type: "cookware", name: "oven", quantity: 1, units: "", modifiers: {...}, relation: {...} }, ...]
|
|
42
44
|
recipe.timers // [{ type: "timer", name: "", quantity: 20, units: "minutes" }]
|
|
43
|
-
recipe.
|
|
45
|
+
recipe.inlineQuantities // [] in canonical mode
|
|
44
46
|
recipe.errors // [] (parse errors and warnings)
|
|
47
|
+
|
|
48
|
+
// Steps are organized into sections:
|
|
49
|
+
recipe.sections[0].name // null (default unnamed section)
|
|
50
|
+
recipe.sections[0].content // array of { type: "step", items: [...] } and { type: "text", value: "..." }
|
|
51
|
+
|
|
52
|
+
// Each step contains ordered text + inline component tokens:
|
|
53
|
+
const step = recipe.sections[0].content[0] // { type: "step", items: [...] }
|
|
54
|
+
step.items
|
|
55
|
+
// [
|
|
56
|
+
// { type: "text", value: "Preheat " },
|
|
57
|
+
// { type: "cookware", name: "oven", quantity: 1, units: "", modifiers: {...}, relation: {...} },
|
|
58
|
+
// { type: "text", value: " to 180C." }
|
|
59
|
+
// ]
|
|
45
60
|
```
|
|
46
61
|
|
|
47
62
|
## Cooklang Syntax
|
|
@@ -61,31 +76,53 @@ recipe.errors // [] (parse errors and warnings)
|
|
|
61
76
|
| `== Title ==` | Section header | `== For the sauce ==` |
|
|
62
77
|
| `>> key: value` | Metadata directive | `>> servings: 4` |
|
|
63
78
|
| `---` | YAML frontmatter block | See below |
|
|
64
|
-
|
|
|
65
|
-
| `@name{
|
|
66
|
-
|
|
|
79
|
+
| `@name{=qty%unit}` | Fixed quantity (won't scale) | `@salt{=1%tsp}` |
|
|
80
|
+
| `@name{qty}(note)` | Ingredient with note | `@flour{100%g}(sifted)` |
|
|
81
|
+
| `#name(note)` | Cookware with note | `#pan(large)` |
|
|
67
82
|
| `@name\|alias{}` | Pipe alias syntax | `@ground beef\|beef{}` |
|
|
68
83
|
|
|
69
84
|
## API
|
|
70
85
|
|
|
71
|
-
### `parseCooklang(source: string): CooklangRecipe`
|
|
86
|
+
### `parseCooklang(source: string, options?: ParseCooklangOptions): CooklangRecipe`
|
|
72
87
|
|
|
73
88
|
Parses a Cooklang source string into a structured recipe object.
|
|
74
89
|
|
|
90
|
+
```typescript
|
|
91
|
+
interface ParseCooklangOptions {
|
|
92
|
+
extensions?: "canonical" | "all" // default: "canonical"
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
- `"canonical"`: canonical/spec behavior (extensions off)
|
|
97
|
+
- `"all"`: cooklang-rs default behavior (modes + inline temperature quantities)
|
|
98
|
+
|
|
75
99
|
```typescript
|
|
76
100
|
interface CooklangRecipe {
|
|
77
101
|
metadata: Record<string, unknown>
|
|
78
|
-
|
|
79
|
-
ingredients: RecipeIngredient[]
|
|
80
|
-
cookware: RecipeCookware[]
|
|
81
|
-
timers: RecipeTimer[]
|
|
82
|
-
|
|
83
|
-
notes: string[]
|
|
102
|
+
sections: RecipeSection[] // Sections with interleaved steps and notes
|
|
103
|
+
ingredients: RecipeIngredient[] // Deduplicated across all steps
|
|
104
|
+
cookware: RecipeCookware[] // Deduplicated across all steps
|
|
105
|
+
timers: RecipeTimer[] // Deduplicated across all steps
|
|
106
|
+
inlineQuantities: Array<{ quantity: number | string; units: string }>
|
|
84
107
|
errors: ParseError[]
|
|
108
|
+
warnings: ParseError[]
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface RecipeSection {
|
|
112
|
+
name: string | null // null for the default unnamed section
|
|
113
|
+
content: SectionContent[]
|
|
85
114
|
}
|
|
115
|
+
|
|
116
|
+
type SectionContent =
|
|
117
|
+
| { type: "step"; items: RecipeStepItem[]; number?: number }
|
|
118
|
+
| { type: "text"; value: string } // Notes (> lines)
|
|
86
119
|
```
|
|
87
120
|
|
|
88
|
-
**`
|
|
121
|
+
**`sections`** contains all recipe content. Each section has a `name` (null for the default section) and `content` — an interleaved array of steps and text (notes). Steps contain ordered `RecipeStepItem[]` arrays with text and typed tokens in document order.
|
|
122
|
+
|
|
123
|
+
**`ingredients`**, **`cookware`**, and **`timers`** are deduplicated across all steps.
|
|
124
|
+
|
|
125
|
+
### Types
|
|
89
126
|
|
|
90
127
|
```typescript
|
|
91
128
|
type RecipeStepItem =
|
|
@@ -93,27 +130,28 @@ type RecipeStepItem =
|
|
|
93
130
|
| RecipeIngredient
|
|
94
131
|
| RecipeCookware
|
|
95
132
|
| RecipeTimer
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
**`ingredients`**, **`cookware`**, and **`timers`** are deduplicated across all steps.
|
|
99
|
-
|
|
100
|
-
### Types
|
|
101
133
|
|
|
102
|
-
```typescript
|
|
103
134
|
interface RecipeIngredient {
|
|
104
135
|
type: "ingredient"
|
|
105
136
|
name: string
|
|
137
|
+
alias?: string // from @name|alias{} syntax
|
|
106
138
|
quantity: number | string
|
|
107
|
-
units: string
|
|
139
|
+
units: string // only % separator: @name{qty%unit}
|
|
108
140
|
fixed: boolean
|
|
109
|
-
|
|
141
|
+
note?: string // from @name{}(note) syntax
|
|
142
|
+
modifiers: RecipeModifiers
|
|
143
|
+
relation: IngredientRelation
|
|
110
144
|
}
|
|
111
145
|
|
|
112
146
|
interface RecipeCookware {
|
|
113
147
|
type: "cookware"
|
|
114
148
|
name: string
|
|
149
|
+
alias?: string
|
|
115
150
|
quantity: number | string
|
|
116
|
-
units: string
|
|
151
|
+
units: string // always ""
|
|
152
|
+
note?: string // from #name(note) syntax
|
|
153
|
+
modifiers: RecipeModifiers
|
|
154
|
+
relation: ComponentRelation
|
|
117
155
|
}
|
|
118
156
|
|
|
119
157
|
interface RecipeTimer {
|
|
@@ -148,10 +186,9 @@ const recipe = parseCooklang(`
|
|
|
148
186
|
---
|
|
149
187
|
title: Sourdough Bread
|
|
150
188
|
source: My grandmother
|
|
189
|
+
servings: 2
|
|
151
190
|
---
|
|
152
191
|
|
|
153
|
-
>> servings: 2
|
|
154
|
-
|
|
155
192
|
== Starter ==
|
|
156
193
|
Mix @starter{100%g} with @water{100%g}
|
|
157
194
|
Let ferment for ~{8%hours}
|
|
@@ -165,18 +202,20 @@ Knead in #mixing bowl{} for ~kneading{10%minutes}
|
|
|
165
202
|
recipe.metadata
|
|
166
203
|
// { title: "Sourdough Bread", source: "My grandmother", servings: 2 }
|
|
167
204
|
|
|
168
|
-
recipe.sections
|
|
169
|
-
// ["Starter", "Dough"]
|
|
205
|
+
recipe.sections.map(s => s.name)
|
|
206
|
+
// [null, "Starter", "Dough"]
|
|
170
207
|
|
|
171
208
|
recipe.ingredients.map(i => `${i.quantity} ${i.units} ${i.name}`.trim())
|
|
172
209
|
// ["100 g starter", "100 g water", "500 g flour", ...]
|
|
173
210
|
```
|
|
174
211
|
|
|
212
|
+
> **Note:** With YAML frontmatter (`---`), non-special `>> key: value` lines are treated as regular step text (matching [cooklang-rs](https://github.com/cooklang/cooklang-rs)). In `{ extensions: "all" }`, `[mode]/[define]/[duplicate]` directives still apply as configuration.
|
|
213
|
+
|
|
175
214
|
## Development
|
|
176
215
|
|
|
177
216
|
```bash
|
|
178
217
|
bun install # Install dependencies
|
|
179
|
-
bun test # Run all
|
|
218
|
+
bun test # Run all 235 tests
|
|
180
219
|
bun run build # Bundle + emit declarations
|
|
181
220
|
bun run typecheck # Type-check without emitting
|
|
182
221
|
bun run lint # Lint with Biome
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,mBAAmB,SAAS,CAAA"}
|