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.
@@ -0,0 +1,3 @@
1
+ import type { CooklangRecipe, ParseCooklangOptions } from "./types";
2
+ export declare function parseCooklang(source: string, options?: ParseCooklangOptions): CooklangRecipe;
3
+ //# sourceMappingURL=parse-cooklang.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-cooklang.d.ts","sourceRoot":"","sources":["../src/parse-cooklang.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EACV,cAAc,EACd,oBAAoB,EAQrB,MAAM,SAAS,CAAA;AAehB,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,cAAc,CAkRhG"}
@@ -0,0 +1,10 @@
1
+ import type { RecipeCookware, RecipeIngredient } from "../types";
2
+ /** Build an ingredient from structured grammar data. */
3
+ export declare function buildIngredient(mods: string, rawName: string, amount: {
4
+ quantity: string | number;
5
+ units: string;
6
+ fixed: boolean;
7
+ }, note: string | undefined): RecipeIngredient;
8
+ /** Build a cookware item from structured grammar data. */
9
+ export declare function buildCookware(mods: string, rawName: string, quantity: string | number, note: string | undefined): RecipeCookware;
10
+ //# sourceMappingURL=component-builders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-builders.d.ts","sourceRoot":"","sources":["../../src/parser/component-builders.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,cAAc,EACd,gBAAgB,EAEjB,MAAM,UAAU,CAAA;AAoBjB,wDAAwD;AACxD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,EACpE,IAAI,EAAE,MAAM,GAAG,SAAS,GACvB,gBAAgB,CAWlB;AAED,0DAA0D;AAC1D,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GAAG,MAAM,EACzB,IAAI,EAAE,MAAM,GAAG,SAAS,GACvB,cAAc,CAkBhB"}
@@ -0,0 +1,5 @@
1
+ import type { ParseCooklangOptions } from "../types";
2
+ import type { ExtensionState } from "./internal-types";
3
+ export declare function resolveExtensions(options?: ParseCooklangOptions): ExtensionState;
4
+ export declare function hasAllExtensions(options?: ParseCooklangOptions): boolean;
5
+ //# sourceMappingURL=extensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extensions.d.ts","sourceRoot":"","sources":["../../src/parser/extensions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEtD,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,cAAc,CAKhF;AAED,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAExE"}
@@ -0,0 +1,9 @@
1
+ import type { SourcePosition } from "../types";
2
+ interface YamlParseResult {
3
+ data: Record<string, unknown>;
4
+ warning?: string;
5
+ position?: SourcePosition;
6
+ }
7
+ export declare function parseYamlFrontmatter(content: string, yamlStartOffset: number): YamlParseResult;
8
+ export {};
9
+ //# sourceMappingURL=frontmatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/parser/frontmatter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAE9C,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,cAAc,CAAA;CAC1B;AAyBD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,eAAe,CAoC9F"}
@@ -0,0 +1,31 @@
1
+ import type { RecipeStepItem, SourcePosition } from "../types";
2
+ export interface ExtensionState {
3
+ modes: boolean;
4
+ inlineQuantities: boolean;
5
+ }
6
+ export type DefineMode = "all" | "components" | "steps" | "text";
7
+ export interface DirectiveNode {
8
+ type: "directive";
9
+ key: string;
10
+ rawValue: string;
11
+ rawLine: string;
12
+ position: SourcePosition;
13
+ }
14
+ export type SemanticItem = {
15
+ kind: "step";
16
+ items: RecipeStepItem[];
17
+ } | {
18
+ kind: "section";
19
+ name: string;
20
+ } | {
21
+ kind: "note";
22
+ text: string;
23
+ } | {
24
+ kind: "directive";
25
+ directive: DirectiveNode;
26
+ };
27
+ export interface SemanticResult {
28
+ frontmatter: string | null;
29
+ items: SemanticItem[];
30
+ }
31
+ //# sourceMappingURL=internal-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal-types.d.ts","sourceRoot":"","sources":["../../src/parser/internal-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAE9D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,OAAO,CAAA;IACd,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,YAAY,GAAG,OAAO,GAAG,MAAM,CAAA;AAEhE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,cAAc,CAAA;CACzB;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,cAAc,EAAE,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,aAAa,CAAA;CAAE,CAAA;AAEnD,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,KAAK,EAAE,YAAY,EAAE,CAAA;CACtB"}
@@ -0,0 +1,8 @@
1
+ import type { ParseError } from "../types";
2
+ import type { DefineMode, DirectiveNode } from "./internal-types";
3
+ /** Validate standard metadata entries and push type-mismatch warnings. */
4
+ export declare function checkStandardMetadata(metadata: Record<string, unknown>, warnings: ParseError[], directives: DirectiveNode[]): void;
5
+ export declare function isSpecialDirectiveKey(key: string): boolean;
6
+ export declare function applyDirectiveMode(current: DefineMode, key: string, rawValue: string): DefineMode;
7
+ export declare function createDeprecatedMetadataWarning(directives: DirectiveNode[]): ParseError | null;
8
+ //# sourceMappingURL=metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/parser/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,UAAU,CAAA;AAE1D,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AA4GjE,0EAA0E;AAC1E,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,QAAQ,EAAE,UAAU,EAAE,EACtB,UAAU,EAAE,aAAa,EAAE,GAC1B,IAAI,CAuBN;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAG1D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAYjG;AAED,wBAAgB,+BAA+B,CAAC,UAAU,EAAE,aAAa,EAAE,GAAG,UAAU,GAAG,IAAI,CAwB9F"}
@@ -0,0 +1,14 @@
1
+ import * as Ohm from "ohm-js";
2
+ import type { ParseError } from "../types";
3
+ import type { SemanticResult } from "./internal-types";
4
+ declare const grammar: Ohm.Grammar;
5
+ type ParseWithOhmResult = {
6
+ ok: true;
7
+ value: SemanticResult;
8
+ } | {
9
+ ok: false;
10
+ error: ParseError;
11
+ };
12
+ export declare function parseWithOhm(source: string): ParseWithOhmResult;
13
+ export { grammar };
14
+ //# sourceMappingURL=ohm-ast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ohm-ast.d.ts","sourceRoot":"","sources":["../../src/parser/ohm-ast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,QAAQ,CAAA;AAE7B,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,UAAU,CAAA;AAG1D,OAAO,KAAK,EAA+B,cAAc,EAAE,MAAM,kBAAkB,CAAA;AASnF,QAAA,MAAM,OAAO,aAA6B,CAAA;AAwN1C,KAAK,kBAAkB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAA;AAEhG,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAsB/D;AAED,OAAO,EAAE,OAAO,EAAE,CAAA"}
@@ -0,0 +1,10 @@
1
+ /** Strip block comments [- ... -] from source, preserving only newlines. */
2
+ export declare function stripBlockComments(source: string): string;
3
+ /**
4
+ * Normalize marker spacing variants accepted by cooklang-rs parser:
5
+ * - `@ example{}` -> `@example{}`
6
+ * - `# 10{}` -> `#10{}`
7
+ * - `~ {5}` -> `~{5}`
8
+ */
9
+ export declare function normalizeMarkerSpacing(source: string): string;
10
+ //# sourceMappingURL=preprocess.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preprocess.d.ts","sourceRoot":"","sources":["../../src/parser/preprocess.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIzD;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAK7D"}
@@ -0,0 +1,3 @@
1
+ /** Parse a quantity string into a number (including fractions) or keep as string. */
2
+ export declare function parseQuantity(raw: string): string | number;
3
+ //# sourceMappingURL=quantity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quantity.d.ts","sourceRoot":"","sources":["../../src/parser/quantity.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAyB1D"}
@@ -0,0 +1,4 @@
1
+ import type { RecipeStepItem } from "../types";
2
+ export declare function attachRaw<T extends RecipeStepItem>(item: T, raw: string): T;
3
+ export declare function serializeStepItemRaw(item: RecipeStepItem): string;
4
+ //# sourceMappingURL=raw-step-items.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raw-step-items.d.ts","sourceRoot":"","sources":["../../src/parser/raw-step-items.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAI9C,wBAAgB,SAAS,CAAC,CAAC,SAAS,cAAc,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,CAG3E;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAuCjE"}
@@ -0,0 +1,14 @@
1
+ import type { ParseError, RecipeInlineQuantity, RecipeStepItem } from "../types";
2
+ import type { DefineMode } from "./internal-types";
3
+ /** Merge adjacent text items into single items (e.g. across soft line breaks). */
4
+ export declare function mergeConsecutiveTexts(items: RecipeStepItem[]): RecipeStepItem[];
5
+ /** Collect unique items of a given type across parsed step items. */
6
+ export declare function collectUniqueFromSteps<T extends RecipeStepItem>(allSteps: RecipeStepItem[][], type: RecipeStepItem["type"], key: (item: T) => string): T[];
7
+ export declare function applyInlineQuantityExtraction(stepItems: RecipeStepItem[], inlineQuantities: RecipeInlineQuantity[], enabled: boolean): RecipeStepItem[];
8
+ export declare function applyAdvancedUnits(stepItems: RecipeStepItem[], enabled: boolean): RecipeStepItem[];
9
+ export declare function applyAliasMode(stepItems: RecipeStepItem[], aliasEnabled: boolean): RecipeStepItem[];
10
+ export declare function splitInvalidMarkerTextItems(stepItems: RecipeStepItem[]): RecipeStepItem[];
11
+ export declare function warnTimerMissingUnit(stepItems: RecipeStepItem[], warnings: ParseError[]): void;
12
+ export declare function warnUnnecessaryScalingLock(stepItems: RecipeStepItem[], warnings: ParseError[]): void;
13
+ export declare function checkStepsModeReferences(stepItems: RecipeStepItem[], defineMode: DefineMode, knownIngredients: Set<string>, knownCookware: Set<string>, errors: ParseError[]): void;
14
+ //# sourceMappingURL=step-processing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-processing.d.ts","sourceRoot":"","sources":["../../src/parser/step-processing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAChF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAGlD,kFAAkF;AAClF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE,CAW/E;AAED,qEAAqE;AACrE,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,cAAc,EAC7D,QAAQ,EAAE,cAAc,EAAE,EAAE,EAC5B,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,EAC5B,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GACvB,CAAC,EAAE,CAcL;AAkGD,wBAAgB,6BAA6B,CAC3C,SAAS,EAAE,cAAc,EAAE,EAC3B,gBAAgB,EAAE,oBAAoB,EAAE,EACxC,OAAO,EAAE,OAAO,GACf,cAAc,EAAE,CAWlB;AA0BD,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,cAAc,EAAE,EAC3B,OAAO,EAAE,OAAO,GACf,cAAc,EAAE,CAgBlB;AAED,wBAAgB,cAAc,CAC5B,SAAS,EAAE,cAAc,EAAE,EAC3B,YAAY,EAAE,OAAO,GACpB,cAAc,EAAE,CAmBlB;AAED,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE,CAyDzF;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,cAAc,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI,CAW9F;AAED,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,cAAc,EAAE,EAC3B,QAAQ,EAAE,UAAU,EAAE,GACrB,IAAI,CASN;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,cAAc,EAAE,EAC3B,UAAU,EAAE,UAAU,EACtB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,EAC7B,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,EAC1B,MAAM,EAAE,UAAU,EAAE,GACnB,IAAI,CA0BN"}
@@ -1,6 +1,3 @@
1
- import * as Ohm from "ohm-js";
2
- import type { CooklangRecipe } from "./types";
3
- declare const grammar: Ohm.Grammar;
4
- export declare function parseCooklang(source: string): CooklangRecipe;
5
- export { grammar };
1
+ export { parseCooklang } from "./parse-cooklang";
2
+ export { grammar } from "./parser/ohm-ast";
6
3
  //# sourceMappingURL=semantics.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"semantics.d.ts","sourceRoot":"","sources":["../src/semantics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,QAAQ,CAAA;AAG7B,OAAO,KAAK,EACV,cAAc,EAOf,MAAM,SAAS,CAAA;AAEhB,QAAA,MAAM,OAAO,aAA6B,CAAA;AAuS1C,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CA0D5D;AAED,OAAO,EAAE,OAAO,EAAE,CAAA"}
1
+ {"version":3,"file":"semantics.d.ts","sourceRoot":"","sources":["../src/semantics.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA"}
package/dist/types.d.ts CHANGED
@@ -8,35 +8,88 @@ export interface ParseError {
8
8
  shortMessage?: string;
9
9
  position: SourcePosition;
10
10
  severity: "error" | "warning";
11
+ help?: string;
12
+ }
13
+ export interface ParseCooklangOptions {
14
+ /**
15
+ * Parser behavior preset:
16
+ * - "canonical": canonical/spec-oriented behavior (extensions off)
17
+ * - "all": cooklang-rs default behavior (extensions on)
18
+ */
19
+ extensions?: "canonical" | "all";
20
+ }
21
+ export type SectionContent = {
22
+ type: "step";
23
+ items: RecipeStepItem[];
24
+ number?: number;
25
+ } | {
26
+ type: "text";
27
+ value: string;
28
+ };
29
+ export interface RecipeSection {
30
+ name: string | null;
31
+ content: SectionContent[];
11
32
  }
12
33
  export interface CooklangRecipe {
13
34
  metadata: Record<string, unknown>;
14
- steps: RecipeStepItem[][];
35
+ sections: RecipeSection[];
15
36
  ingredients: RecipeIngredient[];
16
37
  cookware: RecipeCookware[];
17
38
  timers: RecipeTimer[];
18
- sections: string[];
19
- notes: string[];
39
+ inlineQuantities: RecipeInlineQuantity[];
20
40
  errors: ParseError[];
21
41
  warnings: ParseError[];
22
42
  }
23
43
  export type RecipeStepItem = {
24
44
  type: "text";
25
45
  value: string;
26
- } | RecipeIngredient | RecipeCookware | RecipeTimer;
46
+ } | RecipeIngredient | RecipeCookware | RecipeTimer | {
47
+ type: "inline_quantity";
48
+ index: number;
49
+ };
50
+ export type ComponentRelation = {
51
+ type: "definition";
52
+ referencedFrom: number[];
53
+ definedInStep: boolean;
54
+ } | {
55
+ type: "reference";
56
+ referencesTo: number;
57
+ };
58
+ export type IngredientReferenceTarget = "ingredient" | "step" | "section";
59
+ export interface IngredientRelation {
60
+ type: "definition" | "reference";
61
+ referencedFrom?: number[];
62
+ definedInStep?: boolean;
63
+ referencesTo?: number;
64
+ referenceTarget?: IngredientReferenceTarget;
65
+ }
66
+ export interface RecipeModifiers {
67
+ recipe?: boolean;
68
+ reference?: boolean;
69
+ hidden?: boolean;
70
+ optional?: boolean;
71
+ new?: boolean;
72
+ }
27
73
  export interface RecipeIngredient {
28
74
  type: "ingredient";
29
75
  name: string;
76
+ alias?: string;
30
77
  quantity: number | string;
31
78
  units: string;
32
79
  fixed: boolean;
33
- preparation?: string;
80
+ note?: string;
81
+ modifiers: RecipeModifiers;
82
+ relation: IngredientRelation;
34
83
  }
35
84
  export interface RecipeCookware {
36
85
  type: "cookware";
37
86
  name: string;
87
+ alias?: string;
38
88
  quantity: number | string;
39
89
  units: string;
90
+ note?: string;
91
+ modifiers: RecipeModifiers;
92
+ relation: ComponentRelation;
40
93
  }
41
94
  export interface RecipeTimer {
42
95
  type: "timer";
@@ -44,4 +97,8 @@ export interface RecipeTimer {
44
97
  quantity: number | string;
45
98
  units: string;
46
99
  }
100
+ export interface RecipeInlineQuantity {
101
+ quantity: number | string;
102
+ units: string;
103
+ }
47
104
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,cAAc,CAAA;IACxB,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAA;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,KAAK,EAAE,cAAc,EAAE,EAAE,CAAA;IACzB,WAAW,EAAE,gBAAgB,EAAE,CAAA;IAC/B,QAAQ,EAAE,cAAc,EAAE,CAAA;IAC1B,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,QAAQ,EAAE,UAAU,EAAE,CAAA;CACvB;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/B,gBAAgB,GAChB,cAAc,GACd,WAAW,CAAA;AAEf,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,YAAY,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,OAAO,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB,KAAK,EAAE,MAAM,CAAA;CACd"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function isRecord(v: unknown): v is Record<string, unknown>;
2
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEjE"}
@@ -6,11 +6,11 @@
6
6
  Cooklang {
7
7
  // Main recipe structure
8
8
  Recipe
9
- = Metadata? RecipeItem*
9
+ = (MetadataDirective | blankLine)* Metadata? RecipeItem*
10
10
 
11
11
  // Recipe items can be interleaved
12
12
  RecipeItem
13
- = Section | Note | BlockComment | CommentLine | blankLine | spaceOnly | Step
13
+ = Section | MetadataDirective | Note | CommentLine | blankLine | spaceOnly | Step
14
14
 
15
15
  // YAML front matter metadata
16
16
  Metadata
@@ -32,7 +32,7 @@ Cooklang {
32
32
  = StepLine+
33
33
 
34
34
  StepLine
35
- = ~(hspace* "-- ") ~(hspace* newline) ~sectionStart StepItem+ InlineComment? "\n"?
35
+ = ~(hspace* "-- ") ~(hspace* newline) ~sectionStart ~MetadataDirective StepItem+ InlineComment? "\n"?
36
36
 
37
37
  sectionStart
38
38
  = "==" | "=" ~"=" ~"@"
@@ -43,7 +43,7 @@ Cooklang {
43
43
 
44
44
  // Text without special Cooklang syntax
45
45
  Text
46
- = (~("\n" | "\r\n" | "\r" | "=" &"@" | "@" &ingredientStartChar | "#" &cookwareStartChar | "~" &wordChar | "~" &"{" | "-- " | "[-") any)+
46
+ = (~("\n" | "\r\n" | "\r" | "@" &ingredientStartChar | "#" &cookwareStartChar | "~" &wordChar | "~" &"{" | "-- ") any)+
47
47
 
48
48
  ingredientStartChar
49
49
  = wordChar | "@" | "&" | "?" | "+" | "-"
@@ -52,12 +52,11 @@ Cooklang {
52
52
  = wordChar | "&" | "?" | "+" | "-"
53
53
 
54
54
  // Ingredient: @name{quantity%unit} or @multi word name{}
55
- // Fixed quantity: =@name{quantity%unit}
56
55
  Ingredient
57
- = FixedIndicator? "@" ingredientModifiers ingredientWord (hspace+ ingredientWord)+ ingredientAmount ingredientPreparation? -- multi
58
- | FixedIndicator? "@" ingredientModifiers ingredientWord ingredientAmount? ingredientPreparation? -- single
56
+ = "@" ingredientModifiers ingredientWord (hspace+ ingredientWord)+ ingredientAmount ingredientNote? -- multi
57
+ | "@" ingredientModifiers ingredientWord ingredientAmount? ingredientNote? -- single
59
58
 
60
- ingredientPreparation
59
+ ingredientNote
61
60
  = "(" (~")" ~newline any)* ")"
62
61
 
63
62
  ingredientModifiers
@@ -67,15 +66,17 @@ Cooklang {
67
66
  = componentWordChar+
68
67
 
69
68
  ingredientAmount
70
- = "{" (~"}" any)* "}"
71
-
72
- FixedIndicator
73
- = "="
69
+ = "{" amountFixed? amountQuantity "%" amountUnit "}" -- withUnit
70
+ | "{" hspace* amountFixed? hspace* "}" -- empty
71
+ | "{" amountFixed? amountQuantity "}" -- quantityOnly
74
72
 
75
73
  // Cookware: #name or #multi word{}
76
74
  Cookware
77
- = "#" cookwareModifiers cookwareWord (hspace+ cookwareWord)+ cookwareAmount -- multi
78
- | "#" cookwareModifiers cookwareWord cookwareAmount? -- single
75
+ = "#" cookwareModifiers cookwareWord (hspace+ cookwareWord)+ cookwareAmount cookwareNote? -- multi
76
+ | "#" cookwareModifiers cookwareWord cookwareAmount? cookwareNote? -- single
77
+
78
+ cookwareNote
79
+ = "(" (~")" ~newline any)* ")"
79
80
 
80
81
  cookwareModifiers
81
82
  = ("&" | "?" | "+" | "-")*
@@ -84,21 +85,30 @@ Cooklang {
84
85
  = componentWordChar+
85
86
 
86
87
  cookwareAmount
87
- = "{" (~"}" any)* "}"
88
+ = "{" hspace* "}" -- empty
89
+ | "{" cookwareQuantity "}" -- withQuantity
90
+
91
+ cookwareQuantity
92
+ = (~"}" any)+
88
93
 
89
94
  // Timer: ~{quantity%unit} or ~name{quantity%unit}
90
95
  Timer
91
- = "~" timerName? "{" timerQuantity timerUnit? "}" -- withAmount
92
- | "~" timerName -- word
96
+ = "~" timerName? "{" amountQuantity "%" amountUnit "}" -- withUnit
97
+ | "~" timerName? "{" amountQuantity "}" -- quantityOnly
98
+ | "~" timerName -- word
93
99
 
94
100
  timerName
95
101
  = word+
96
102
 
97
- timerQuantity
103
+ // Shared amount sub-rules for ingredients and timers
104
+ amountFixed
105
+ = hspace* "=" hspace*
106
+
107
+ amountQuantity
98
108
  = (~"%" ~"}" any)+
99
109
 
100
- timerUnit
101
- = "%" (~"}" any)+
110
+ amountUnit
111
+ = (~"}" any)+
102
112
 
103
113
  // Note lines (start with >)
104
114
  Note
@@ -107,6 +117,19 @@ Cooklang {
107
117
  noteText
108
118
  = (~"\n" ~"\r" ~">" any)+
109
119
 
120
+ // Metadata directive: >> key: value
121
+ MetadataDirective
122
+ = hspace* ">>" directiveBody Newline?
123
+
124
+ directiveBody
125
+ = hspace* directiveKey hspace* ":" directiveValue
126
+
127
+ directiveKey
128
+ = (~":" ~newline any)+
129
+
130
+ directiveValue
131
+ = (~newline any)*
132
+
110
133
  // Inline comment: -- comment
111
134
  InlineComment
112
135
  = "-- " (~Newline any)*
@@ -115,10 +138,6 @@ Cooklang {
115
138
  CommentLine
116
139
  = hspace* InlineComment Newline?
117
140
 
118
- // Block comment: [- comment -]
119
- BlockComment
120
- = "[-" (~"-]" any)+ "-]"
121
-
122
141
  // Component name word char - wordChar plus | for alias syntax
123
142
  componentWordChar
124
143
  = wordChar | "|"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cooklang-parse",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "A simple, type-safe Cooklang parser built with Ohm.js",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -45,7 +45,8 @@
45
45
  },
46
46
  "devDependencies": {
47
47
  "@biomejs/biome": "^2.3.11",
48
- "@types/bun": "latest"
48
+ "@types/bun": "latest",
49
+ "lefthook": "^2.1.0"
49
50
  },
50
51
  "peerDependencies": {
51
52
  "typescript": "^5"