docs: sync core-parser spec and add unit normalisation
Bring core-parser.md in line with the resolved design in CONTEXT.md and ADRs 0004/0005, and promote a new decision to normalise ingredient/cookware units. - Full sync of the core-parser spec: diagnostics/total-function channel, container blocks (ListItemBlock, BlockquoteBlock), RawInline alongside RawBlock via position-slicing, the unified WikilinkNode/TransclusionNode shape as two typed nodes, and the minimal remark plugin set. - New ADR 0006: normalise ingredient/cookware units via a known-alias table with passthrough, case-insensitive, canonical-only; align Timer matching to case-insensitive too. - SPEC.md: units are normalised (new Units section, alias table); Timer table marked case-insensitive. - CONTEXT.md: add Unit Normalisation entry, resolve the open item. - fixtures/basic.md: add a blockquote (callout) carrying an annotation and a non-canonical unit so the integration test exercises containers and normalisation. - Expand the core test.todo checklists to cover the new behaviour (containers, raw fallbacks, diagnostics, unit normalisation, wikilink/transclusion variants); still pending, suite stays green.
This commit is contained in:
38
SPEC.md
38
SPEC.md
@@ -56,12 +56,14 @@ Multi-word names work naturally: `@unsalted butter{30 g}`.
|
||||
- Simple fraction: `1/2`
|
||||
- Mixed number: `1 1/2`
|
||||
|
||||
**Unit**: optional, free-form string.
|
||||
**Unit**: optional.
|
||||
The quantity/unit split is **grammar-driven**: the parser matches the quantity greedily against the quantity grammar (mixed number → fraction → decimal → integer) anchored at the start of the braces, and any non-empty remainder after the delimiting space is the unit.
|
||||
`@butter{1 1/2 tbsp}` → quantity `1 1/2`, unit `tbsp`.
|
||||
`@butter{1 1/2}` → quantity `1 1/2`, no unit.
|
||||
A plain "last space" rule cannot express this, because a mixed-number quantity itself contains a space; the grammar is authoritative.
|
||||
If the brace content does not begin with a grammar-valid quantity (e.g. `@stock{a splash}`), the entire content is preserved as the quantity string and the unit is left empty, so no annotation is dropped.
|
||||
The unit is **normalised**: a unit matching a known alias is rewritten to its canonical abbreviation (case-insensitive), and any unit not in the table is passed through verbatim.
|
||||
See the [Units](#units) section for the alias table.
|
||||
|
||||
**Examples**:
|
||||
```
|
||||
@@ -90,7 +92,7 @@ $name{quantity unit}
|
||||
|
||||
**Quantity**: optional. Follows the same format rules as Ingredient quantity (integer, decimal, fraction, mixed number).
|
||||
|
||||
**Unit**: optional, free-form. Same grammar-driven quantity/unit split as Ingredient.
|
||||
**Unit**: optional. Same grammar-driven quantity/unit split and canonical [unit normalisation](#units) as Ingredient.
|
||||
|
||||
**Examples**:
|
||||
```
|
||||
@@ -116,7 +118,7 @@ $cupcake liner{12 large}
|
||||
**Range**: two quantities separated by `-`. Since negative quantities do not exist, the `-` is unambiguous.
|
||||
`~1/2-1 hr` → range of 1/2 hr to 1 hr.
|
||||
|
||||
**Unit**: one word from the known set, normalised to its canonical abbreviation:
|
||||
**Unit**: one word from the known set, matched **case-insensitively** and normalised to its canonical abbreviation:
|
||||
|
||||
| Written | Canonical |
|
||||
|---------|-----------|
|
||||
@@ -139,6 +141,36 @@ A `~` followed by a number but not a known unit word is not a valid annotation a
|
||||
|
||||
---
|
||||
|
||||
## Units
|
||||
|
||||
Ingredient and Cookware units are normalised: a unit matching a known alias is rewritten to its canonical abbreviation, and any unit not in the table is passed through verbatim (its original casing and spacing preserved).
|
||||
Lookup is **case-insensitive**, and multi-word aliases (`fluid ounce`) match on the whole unit string.
|
||||
Only the canonical unit is retained; the author's original spelling is not kept.
|
||||
|
||||
| Canonical | Aliases |
|
||||
|-----------|---------|
|
||||
| `g` | g, gram, grams |
|
||||
| `kg` | kg, kilogram, kilograms, kilo, kilos |
|
||||
| `mg` | mg, milligram, milligrams |
|
||||
| `oz` | oz, ounce, ounces |
|
||||
| `lb` | lb, lbs, pound, pounds |
|
||||
| `ml` | ml, milliliter, millilitre, milliliters, millilitres |
|
||||
| `l` | l, liter, litre, liters, litres |
|
||||
| `tsp` | tsp, teaspoon, teaspoons |
|
||||
| `tbsp` | tbsp, tablespoon, tablespoons |
|
||||
| `cup` | cup, cups |
|
||||
| `fl oz` | fl oz, fluid ounce, fluid ounces |
|
||||
| `pt` | pt, pint, pints |
|
||||
| `qt` | qt, quart, quarts |
|
||||
| `gal` | gal, gallon, gallons |
|
||||
|
||||
Single-letter cooking abbreviations (`t`, `T`, `c`) are intentionally excluded as ambiguous.
|
||||
Count and descriptive units (`clove`, `pinch`, `dash`, `can`, `large`, `to taste`) have no canonical form and pass through unchanged.
|
||||
|
||||
Timer units are normalised from their own known set (see [Timer](#timer)), also case-insensitively.
|
||||
|
||||
---
|
||||
|
||||
## Recipe structure
|
||||
|
||||
A KitchenMD file is prose instructions only.
|
||||
|
||||
Reference in New Issue
Block a user