@tmlmt/cooklang-parser 1.4.4 → 2.0.1
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 +4 -1
- package/dist/index.cjs +249 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +105 -34
- package/dist/index.d.ts +105 -34
- package/dist/index.js +249 -94
- package/dist/index.js.map +1 -1
- package/package.json +14 -14
package/dist/index.js
CHANGED
|
@@ -289,13 +289,14 @@ var i = (() => {
|
|
|
289
289
|
|
|
290
290
|
// src/regex.ts
|
|
291
291
|
var metadataRegex = d().literal("---").newline().startCaptureGroup().anyCharacter().zeroOrMore().optional().endGroup().newline().literal("---").dotAll().toRegExp();
|
|
292
|
-
var
|
|
293
|
-
var
|
|
294
|
-
var
|
|
292
|
+
var scalingMetaValueRegex = (varName) => d().startAnchor().literal(varName).literal(":").anyOf("\\t ").zeroOrMore().startCaptureGroup().startCaptureGroup().notAnyOf(",\\n").oneOrMore().endGroup().startGroup().literal(",").whitespace().zeroOrMore().startCaptureGroup().anyCharacter().oneOrMore().endGroup().endGroup().optional().endGroup().endAnchor().multiline().toRegExp();
|
|
293
|
+
var nonWordChar = "\\s@#~\\[\\]{(,;:!?";
|
|
294
|
+
var multiwordIngredient = d().literal("@").startNamedGroup("mIngredientModifiers").anyOf("@\\-&?").zeroOrMore().endGroup().optional().startNamedGroup("mIngredientRecipeAnchor").literal("./").endGroup().optional().startNamedGroup("mIngredientName").notAnyOf(nonWordChar).oneOrMore().startGroup().whitespace().oneOrMore().notAnyOf(nonWordChar).oneOrMore().endGroup().oneOrMore().endGroup().positiveLookahead("\\s*(?:\\{[^\\}]*\\}|\\([^)]*\\))").startGroup().literal("{").startNamedGroup("mIngredientQuantityModifier").literal("=").exactly(1).endGroup().optional().startNamedGroup("mIngredientQuantity").notAnyOf("}%").oneOrMore().endGroup().optional().startGroup().literal("%").startNamedGroup("mIngredientUnit").notAnyOf("}").oneOrMore().lazy().endGroup().endGroup().optional().literal("}").endGroup().optional().startGroup().literal("(").startNamedGroup("mIngredientPreparation").notAnyOf(")").oneOrMore().lazy().endGroup().literal(")").endGroup().optional().toRegExp();
|
|
295
|
+
var singleWordIngredient = d().literal("@").startNamedGroup("sIngredientModifiers").anyOf("@\\-&?").zeroOrMore().endGroup().optional().startNamedGroup("sIngredientRecipeAnchor").literal("./").endGroup().optional().startNamedGroup("sIngredientName").notAnyOf(nonWordChar).oneOrMore().endGroup().startGroup().literal("{").startNamedGroup("sIngredientQuantityModifier").literal("=").exactly(1).endGroup().optional().startNamedGroup("sIngredientQuantity").notAnyOf("}%").oneOrMore().endGroup().optional().startGroup().literal("%").startNamedGroup("sIngredientUnit").notAnyOf("}").oneOrMore().lazy().endGroup().endGroup().optional().literal("}").endGroup().optional().startGroup().literal("(").startNamedGroup("sIngredientPreparation").notAnyOf(")").oneOrMore().lazy().endGroup().literal(")").endGroup().optional().toRegExp();
|
|
295
296
|
var ingredientAliasRegex = d().startAnchor().startNamedGroup("ingredientListName").notAnyOf("|").oneOrMore().endGroup().literal("|").startNamedGroup("ingredientDisplayName").notAnyOf("|").oneOrMore().endGroup().endAnchor().toRegExp();
|
|
296
|
-
var multiwordCookware = d().literal("#").startNamedGroup("
|
|
297
|
-
var singleWordCookware = d().literal("#").startNamedGroup("
|
|
298
|
-
var timer = d().literal("~").startNamedGroup("timerName").anyCharacter().zeroOrMore().lazy().endGroup().literal("{").startNamedGroup("timerQuantity").anyCharacter().oneOrMore().lazy().endGroup().startGroup().literal("%").startNamedGroup("
|
|
297
|
+
var multiwordCookware = d().literal("#").startNamedGroup("mCookwareModifiers").anyOf("\\-&?").zeroOrMore().endGroup().startNamedGroup("mCookwareName").notAnyOf(nonWordChar).oneOrMore().startGroup().whitespace().oneOrMore().notAnyOf(nonWordChar).oneOrMore().endGroup().oneOrMore().endGroup().positiveLookahead("\\s*(?:\\{[^\\}]*\\})").literal("{").startNamedGroup("mCookwareQuantity").anyCharacter().zeroOrMore().lazy().endGroup().literal("}").toRegExp();
|
|
298
|
+
var singleWordCookware = d().literal("#").startNamedGroup("sCookwareModifiers").anyOf("\\-&?").zeroOrMore().endGroup().startNamedGroup("sCookwareName").notAnyOf(nonWordChar).oneOrMore().endGroup().startGroup().literal("{").startNamedGroup("sCookwareQuantity").anyCharacter().zeroOrMore().lazy().endGroup().literal("}").endGroup().optional().toRegExp();
|
|
299
|
+
var timer = d().literal("~").startNamedGroup("timerName").anyCharacter().zeroOrMore().lazy().endGroup().literal("{").startNamedGroup("timerQuantity").anyCharacter().oneOrMore().lazy().endGroup().startGroup().literal("%").startNamedGroup("timerUnit").anyCharacter().oneOrMore().lazy().endGroup().endGroup().optional().literal("}").toRegExp();
|
|
299
300
|
var tokensRegex = new RegExp(
|
|
300
301
|
[
|
|
301
302
|
multiwordIngredient,
|
|
@@ -311,6 +312,7 @@ var blockCommentRegex = d().whitespace().zeroOrMore().literal("[-").anyCharacter
|
|
|
311
312
|
var shoppingListRegex = d().literal("[").startNamedGroup("name").anyCharacter().oneOrMore().endGroup().literal("]").newline().startNamedGroup("items").anyCharacter().zeroOrMore().lazy().endGroup().startGroup().newline().newline().or().endAnchor().endGroup().global().toRegExp();
|
|
312
313
|
var rangeRegex = d().startAnchor().digit().oneOrMore().startGroup().anyOf(".,/").exactly(1).digit().oneOrMore().endGroup().optional().literal("-").digit().oneOrMore().startGroup().anyOf(".,/").exactly(1).digit().oneOrMore().endGroup().optional().endAnchor().toRegExp();
|
|
313
314
|
var numberLikeRegex = d().startAnchor().digit().oneOrMore().startGroup().anyOf(".,/").exactly(1).digit().oneOrMore().endGroup().optional().endAnchor().toRegExp();
|
|
315
|
+
var floatRegex = d().startAnchor().digit().oneOrMore().startGroup().anyOf(".").exactly(1).digit().oneOrMore().endGroup().optional().endAnchor().toRegExp();
|
|
314
316
|
|
|
315
317
|
// src/units.ts
|
|
316
318
|
var units = [
|
|
@@ -425,7 +427,7 @@ for (const unit of units) {
|
|
|
425
427
|
unitMap.set(alias.toLowerCase(), unit);
|
|
426
428
|
}
|
|
427
429
|
}
|
|
428
|
-
function normalizeUnit(unit) {
|
|
430
|
+
function normalizeUnit(unit = "") {
|
|
429
431
|
return unitMap.get(unit.toLowerCase().trim());
|
|
430
432
|
}
|
|
431
433
|
var CannotAddTextValueError = class extends Error {
|
|
@@ -487,7 +489,10 @@ function addNumericValues(val1, val2) {
|
|
|
487
489
|
num2 = val2.num;
|
|
488
490
|
den2 = val2.den;
|
|
489
491
|
}
|
|
490
|
-
if (
|
|
492
|
+
if (num1 === 0 && num2 === 0) {
|
|
493
|
+
return { type: "decimal", value: 0 };
|
|
494
|
+
}
|
|
495
|
+
if (val1.type === "fraction" && val2.type === "fraction" || val1.type === "fraction" && val2.type === "decimal" && val2.value === 0 || val2.type === "fraction" && val1.type === "decimal" && val1.value === 0) {
|
|
491
496
|
const commonDen = den1 * den2;
|
|
492
497
|
const sumNum = num1 * den2 + num2 * den1;
|
|
493
498
|
return simplifyFraction(sumNum, commonDen);
|
|
@@ -528,6 +533,32 @@ var convertQuantityValue = (value, def, targetDef) => {
|
|
|
528
533
|
const factor = def.toBase / targetDef.toBase;
|
|
529
534
|
return multiplyQuantityValue(value, factor);
|
|
530
535
|
};
|
|
536
|
+
function getDefaultQuantityValue() {
|
|
537
|
+
return { type: "fixed", value: { type: "decimal", value: 0 } };
|
|
538
|
+
}
|
|
539
|
+
function addQuantityValues(v1, v2) {
|
|
540
|
+
if (v1.type === "fixed" && v1.value.type === "text" || v2.type === "fixed" && v2.value.type === "text") {
|
|
541
|
+
throw new CannotAddTextValueError();
|
|
542
|
+
}
|
|
543
|
+
if (v1.type === "fixed" && v2.type === "fixed") {
|
|
544
|
+
const res = addNumericValues(
|
|
545
|
+
v1.value,
|
|
546
|
+
v2.value
|
|
547
|
+
);
|
|
548
|
+
return { type: "fixed", value: res };
|
|
549
|
+
}
|
|
550
|
+
const r1 = v1.type === "range" ? v1 : { type: "range", min: v1.value, max: v1.value };
|
|
551
|
+
const r2 = v2.type === "range" ? v2 : { type: "range", min: v2.value, max: v2.value };
|
|
552
|
+
const newMin = addNumericValues(
|
|
553
|
+
r1.min,
|
|
554
|
+
r2.min
|
|
555
|
+
);
|
|
556
|
+
const newMax = addNumericValues(
|
|
557
|
+
r1.max,
|
|
558
|
+
r2.max
|
|
559
|
+
);
|
|
560
|
+
return { type: "range", min: newMin, max: newMax };
|
|
561
|
+
}
|
|
531
562
|
function addQuantities(q1, q2) {
|
|
532
563
|
const v1 = q1.value;
|
|
533
564
|
const v2 = q2.value;
|
|
@@ -536,33 +567,14 @@ function addQuantities(q1, q2) {
|
|
|
536
567
|
}
|
|
537
568
|
const unit1Def = normalizeUnit(q1.unit);
|
|
538
569
|
const unit2Def = normalizeUnit(q2.unit);
|
|
539
|
-
const addQuantityValuesAndSetUnit = (val1, val2, unit) => {
|
|
540
|
-
|
|
541
|
-
const res = addNumericValues(
|
|
542
|
-
val1.value,
|
|
543
|
-
val2.value
|
|
544
|
-
);
|
|
545
|
-
return { value: { type: "fixed", value: res }, unit };
|
|
546
|
-
}
|
|
547
|
-
const r1 = val1.type === "range" ? val1 : { type: "range", min: val1.value, max: val1.value };
|
|
548
|
-
const r2 = val2.type === "range" ? val2 : { type: "range", min: val2.value, max: val2.value };
|
|
549
|
-
const newMin = addNumericValues(
|
|
550
|
-
r1.min,
|
|
551
|
-
r2.min
|
|
552
|
-
);
|
|
553
|
-
const newMax = addNumericValues(
|
|
554
|
-
r1.max,
|
|
555
|
-
r2.max
|
|
556
|
-
);
|
|
557
|
-
return { value: { type: "range", min: newMin, max: newMax }, unit };
|
|
558
|
-
};
|
|
559
|
-
if (q1.unit === "" && unit2Def) {
|
|
570
|
+
const addQuantityValuesAndSetUnit = (val1, val2, unit) => ({ value: addQuantityValues(val1, val2), unit });
|
|
571
|
+
if ((q1.unit === "" || q1.unit === void 0) && q2.unit !== void 0) {
|
|
560
572
|
return addQuantityValuesAndSetUnit(v1, v2, q2.unit);
|
|
561
573
|
}
|
|
562
|
-
if (q2.unit === "" &&
|
|
574
|
+
if ((q2.unit === "" || q2.unit === void 0) && q1.unit !== void 0) {
|
|
563
575
|
return addQuantityValuesAndSetUnit(v1, v2, q1.unit);
|
|
564
576
|
}
|
|
565
|
-
if (q1.unit.toLowerCase() === q2.unit.toLowerCase()) {
|
|
577
|
+
if (!q1.unit && !q2.unit || q1.unit && q2.unit && q1.unit.toLowerCase() === q2.unit.toLowerCase()) {
|
|
566
578
|
return addQuantityValuesAndSetUnit(v1, v2, q1.unit);
|
|
567
579
|
}
|
|
568
580
|
if (unit1Def && unit2Def) {
|
|
@@ -592,6 +604,17 @@ function addQuantities(q1, q2) {
|
|
|
592
604
|
throw new IncompatibleUnitsError(q1.unit, q2.unit);
|
|
593
605
|
}
|
|
594
606
|
|
|
607
|
+
// src/errors.ts
|
|
608
|
+
var ReferencedItemCannotBeRedefinedError = class extends Error {
|
|
609
|
+
constructor(item_type, item_name, new_modifier) {
|
|
610
|
+
super(
|
|
611
|
+
`The referenced ${item_type} "${item_name}" cannot be redefined as ${new_modifier}.
|
|
612
|
+
You can either remove the reference to create a new ${item_type} defined as ${new_modifier} or add the ${new_modifier} flag to the original definition of the ${item_type}`
|
|
613
|
+
);
|
|
614
|
+
this.name = "ReferencedItemCannotBeRedefinedError";
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
|
|
595
618
|
// src/parser_helpers.ts
|
|
596
619
|
function flushPendingNote(section, note) {
|
|
597
620
|
if (note.length > 0) {
|
|
@@ -611,21 +634,28 @@ function flushPendingItems(section, items) {
|
|
|
611
634
|
function findAndUpsertIngredient(ingredients, newIngredient, isReference) {
|
|
612
635
|
const { name, quantity, unit } = newIngredient;
|
|
613
636
|
if (isReference) {
|
|
614
|
-
const
|
|
637
|
+
const indexFind = ingredients.findIndex(
|
|
615
638
|
(i2) => i2.name.toLowerCase() === name.toLowerCase()
|
|
616
639
|
);
|
|
617
|
-
if (
|
|
640
|
+
if (indexFind === -1) {
|
|
618
641
|
throw new Error(
|
|
619
642
|
`Referenced ingredient "${name}" not found. A referenced ingredient must be declared before being referenced with '&'.`
|
|
620
643
|
);
|
|
621
644
|
}
|
|
622
|
-
const existingIngredient = ingredients[
|
|
645
|
+
const existingIngredient = ingredients[indexFind];
|
|
646
|
+
for (const flag of newIngredient.flags) {
|
|
647
|
+
if (!existingIngredient.flags.includes(flag)) {
|
|
648
|
+
throw new ReferencedItemCannotBeRedefinedError(
|
|
649
|
+
"ingredient",
|
|
650
|
+
existingIngredient.name,
|
|
651
|
+
flag
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
let quantityPartIndex = void 0;
|
|
623
656
|
if (quantity !== void 0) {
|
|
624
657
|
const currentQuantity = {
|
|
625
|
-
value: existingIngredient.quantity ??
|
|
626
|
-
type: "fixed",
|
|
627
|
-
value: { type: "decimal", value: 0 }
|
|
628
|
-
},
|
|
658
|
+
value: existingIngredient.quantity ?? getDefaultQuantityValue(),
|
|
629
659
|
unit: existingIngredient.unit ?? ""
|
|
630
660
|
};
|
|
631
661
|
const newQuantity = { value: quantity, unit: unit ?? "" };
|
|
@@ -633,18 +663,35 @@ function findAndUpsertIngredient(ingredients, newIngredient, isReference) {
|
|
|
633
663
|
const total = addQuantities(currentQuantity, newQuantity);
|
|
634
664
|
existingIngredient.quantity = total.value;
|
|
635
665
|
existingIngredient.unit = total.unit || void 0;
|
|
666
|
+
if (existingIngredient.quantityParts) {
|
|
667
|
+
existingIngredient.quantityParts.push(
|
|
668
|
+
...newIngredient.quantityParts
|
|
669
|
+
);
|
|
670
|
+
} else {
|
|
671
|
+
existingIngredient.quantityParts = newIngredient.quantityParts;
|
|
672
|
+
}
|
|
673
|
+
quantityPartIndex = existingIngredient.quantityParts.length - 1;
|
|
636
674
|
} catch (e2) {
|
|
637
675
|
if (e2 instanceof IncompatibleUnitsError || e2 instanceof CannotAddTextValueError) {
|
|
638
|
-
return
|
|
676
|
+
return {
|
|
677
|
+
ingredientIndex: ingredients.push(newIngredient) - 1,
|
|
678
|
+
quantityPartIndex: 0
|
|
679
|
+
};
|
|
639
680
|
}
|
|
640
681
|
}
|
|
641
682
|
}
|
|
642
|
-
return
|
|
683
|
+
return {
|
|
684
|
+
ingredientIndex: indexFind,
|
|
685
|
+
quantityPartIndex
|
|
686
|
+
};
|
|
643
687
|
}
|
|
644
|
-
return
|
|
688
|
+
return {
|
|
689
|
+
ingredientIndex: ingredients.push(newIngredient) - 1,
|
|
690
|
+
quantityPartIndex: 0
|
|
691
|
+
};
|
|
645
692
|
}
|
|
646
693
|
function findAndUpsertCookware(cookware, newCookware, isReference) {
|
|
647
|
-
const { name } = newCookware;
|
|
694
|
+
const { name, quantity } = newCookware;
|
|
648
695
|
if (isReference) {
|
|
649
696
|
const index = cookware.findIndex(
|
|
650
697
|
(i2) => i2.name.toLowerCase() === name.toLowerCase()
|
|
@@ -654,9 +701,55 @@ function findAndUpsertCookware(cookware, newCookware, isReference) {
|
|
|
654
701
|
`Referenced cookware "${name}" not found. A referenced cookware must be declared before being referenced with '&'.`
|
|
655
702
|
);
|
|
656
703
|
}
|
|
657
|
-
|
|
704
|
+
const existingCookware = cookware[index];
|
|
705
|
+
for (const flag of newCookware.flags) {
|
|
706
|
+
if (!existingCookware.flags.includes(flag)) {
|
|
707
|
+
throw new ReferencedItemCannotBeRedefinedError(
|
|
708
|
+
"cookware",
|
|
709
|
+
existingCookware.name,
|
|
710
|
+
flag
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
let quantityPartIndex = void 0;
|
|
715
|
+
if (quantity !== void 0) {
|
|
716
|
+
if (!existingCookware.quantity) {
|
|
717
|
+
existingCookware.quantity = quantity;
|
|
718
|
+
existingCookware.quantityParts = newCookware.quantityParts;
|
|
719
|
+
quantityPartIndex = 0;
|
|
720
|
+
} else {
|
|
721
|
+
try {
|
|
722
|
+
existingCookware.quantity = addQuantityValues(
|
|
723
|
+
existingCookware.quantity,
|
|
724
|
+
quantity
|
|
725
|
+
);
|
|
726
|
+
if (!existingCookware.quantityParts) {
|
|
727
|
+
existingCookware.quantityParts = newCookware.quantityParts;
|
|
728
|
+
quantityPartIndex = 0;
|
|
729
|
+
} else {
|
|
730
|
+
quantityPartIndex = existingCookware.quantityParts.push(
|
|
731
|
+
...newCookware.quantityParts
|
|
732
|
+
) - 1;
|
|
733
|
+
}
|
|
734
|
+
} catch (e2) {
|
|
735
|
+
if (e2 instanceof CannotAddTextValueError) {
|
|
736
|
+
return {
|
|
737
|
+
cookwareIndex: cookware.push(newCookware) - 1,
|
|
738
|
+
quantityPartIndex: 0
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
return {
|
|
745
|
+
cookwareIndex: index,
|
|
746
|
+
quantityPartIndex
|
|
747
|
+
};
|
|
658
748
|
}
|
|
659
|
-
return
|
|
749
|
+
return {
|
|
750
|
+
cookwareIndex: cookware.push(newCookware) - 1,
|
|
751
|
+
quantityPartIndex: quantity ? 0 : void 0
|
|
752
|
+
};
|
|
660
753
|
}
|
|
661
754
|
var parseFixedValue = (input_str) => {
|
|
662
755
|
if (!numberLikeRegex.test(input_str)) {
|
|
@@ -688,9 +781,7 @@ function parseSimpleMetaVar(content, varName) {
|
|
|
688
781
|
return varMatch ? varMatch[1]?.trim().replace(/\s*\r?\n\s+/g, " ") : void 0;
|
|
689
782
|
}
|
|
690
783
|
function parseScalingMetaVar(content, varName) {
|
|
691
|
-
const varMatch = content.match(
|
|
692
|
-
new RegExp(`^${varName}:[\\t ]*(([^,\\n]*),? ?(?:.*)?)`, "m")
|
|
693
|
-
);
|
|
784
|
+
const varMatch = content.match(scalingMetaValueRegex(varName));
|
|
694
785
|
if (!varMatch) return void 0;
|
|
695
786
|
if (isNaN(Number(varMatch[2]?.trim()))) {
|
|
696
787
|
throw new Error("Scaling variables should be numbers");
|
|
@@ -746,7 +837,7 @@ function extractMetadata(content) {
|
|
|
746
837
|
const stringMetaValue = parseSimpleMetaVar(metadataContent, metaVar);
|
|
747
838
|
if (stringMetaValue) metadata[metaVar] = stringMetaValue;
|
|
748
839
|
}
|
|
749
|
-
for (const metaVar of ["
|
|
840
|
+
for (const metaVar of ["serves", "yield", "servings"]) {
|
|
750
841
|
const scalingMetaValue = parseScalingMetaVar(metadataContent, metaVar);
|
|
751
842
|
if (scalingMetaValue && scalingMetaValue[1]) {
|
|
752
843
|
metadata[metaVar] = scalingMetaValue[1];
|
|
@@ -862,15 +953,28 @@ var Recipe = class _Recipe {
|
|
|
862
953
|
}
|
|
863
954
|
const groups = match.groups;
|
|
864
955
|
if (groups.mIngredientName || groups.sIngredientName) {
|
|
865
|
-
|
|
956
|
+
let name = groups.mIngredientName || groups.sIngredientName;
|
|
957
|
+
const scalableQuantity = (groups.mIngredientQuantityModifier || groups.sIngredientQuantityModifier) !== "=";
|
|
866
958
|
const quantityRaw = groups.mIngredientQuantity || groups.sIngredientQuantity;
|
|
867
|
-
const
|
|
959
|
+
const unit = groups.mIngredientUnit || groups.sIngredientUnit;
|
|
868
960
|
const preparation = groups.mIngredientPreparation || groups.sIngredientPreparation;
|
|
869
|
-
const
|
|
870
|
-
const
|
|
871
|
-
const
|
|
872
|
-
|
|
873
|
-
|
|
961
|
+
const modifiers = groups.mIngredientModifiers || groups.sIngredientModifiers;
|
|
962
|
+
const reference = modifiers !== void 0 && modifiers.includes("&");
|
|
963
|
+
const flags = [];
|
|
964
|
+
if (modifiers !== void 0 && modifiers.includes("?")) {
|
|
965
|
+
flags.push("optional");
|
|
966
|
+
}
|
|
967
|
+
if (modifiers !== void 0 && modifiers.includes("-")) {
|
|
968
|
+
flags.push("hidden");
|
|
969
|
+
}
|
|
970
|
+
if (modifiers !== void 0 && modifiers.includes("@") || groups.mIngredientRecipeAnchor || groups.sIngredientRecipeAnchor) {
|
|
971
|
+
flags.push("recipe");
|
|
972
|
+
}
|
|
973
|
+
let extras = void 0;
|
|
974
|
+
if (flags.includes("recipe")) {
|
|
975
|
+
extras = { path: `${name}.cook` };
|
|
976
|
+
name = name.substring(name.lastIndexOf("/") + 1);
|
|
977
|
+
}
|
|
874
978
|
const quantity = quantityRaw ? parseQuantityInput(quantityRaw) : void 0;
|
|
875
979
|
const aliasMatch = name.match(ingredientAliasRegex);
|
|
876
980
|
let listName, displayName;
|
|
@@ -881,50 +985,70 @@ var Recipe = class _Recipe {
|
|
|
881
985
|
listName = name;
|
|
882
986
|
displayName = name;
|
|
883
987
|
}
|
|
884
|
-
const
|
|
988
|
+
const newIngredient = {
|
|
989
|
+
name: listName,
|
|
990
|
+
quantity,
|
|
991
|
+
quantityParts: quantity ? [
|
|
992
|
+
{
|
|
993
|
+
value: quantity,
|
|
994
|
+
unit,
|
|
995
|
+
scalable: scalableQuantity
|
|
996
|
+
}
|
|
997
|
+
] : void 0,
|
|
998
|
+
unit,
|
|
999
|
+
preparation,
|
|
1000
|
+
flags
|
|
1001
|
+
};
|
|
1002
|
+
if (extras) {
|
|
1003
|
+
newIngredient.extras = extras;
|
|
1004
|
+
}
|
|
1005
|
+
const idxsInList = findAndUpsertIngredient(
|
|
885
1006
|
this.ingredients,
|
|
886
|
-
|
|
887
|
-
name: listName,
|
|
888
|
-
quantity,
|
|
889
|
-
unit: units2,
|
|
890
|
-
optional,
|
|
891
|
-
hidden,
|
|
892
|
-
preparation,
|
|
893
|
-
isRecipe
|
|
894
|
-
},
|
|
1007
|
+
newIngredient,
|
|
895
1008
|
reference
|
|
896
1009
|
);
|
|
897
1010
|
const newItem = {
|
|
898
1011
|
type: "ingredient",
|
|
899
|
-
|
|
900
|
-
itemQuantity: quantity,
|
|
901
|
-
itemUnit: units2,
|
|
1012
|
+
index: idxsInList.ingredientIndex,
|
|
902
1013
|
displayName
|
|
903
1014
|
};
|
|
1015
|
+
if (idxsInList.quantityPartIndex !== void 0) {
|
|
1016
|
+
newItem.quantityPartIndex = idxsInList.quantityPartIndex;
|
|
1017
|
+
}
|
|
904
1018
|
items.push(newItem);
|
|
905
1019
|
} else if (groups.mCookwareName || groups.sCookwareName) {
|
|
906
1020
|
const name = groups.mCookwareName || groups.sCookwareName;
|
|
907
|
-
const
|
|
1021
|
+
const modifiers = groups.mCookwareModifiers || groups.sCookwareModifiers;
|
|
908
1022
|
const quantityRaw = groups.mCookwareQuantity || groups.sCookwareQuantity;
|
|
909
|
-
const
|
|
910
|
-
const
|
|
911
|
-
|
|
1023
|
+
const reference = modifiers !== void 0 && modifiers.includes("&");
|
|
1024
|
+
const flags = [];
|
|
1025
|
+
if (modifiers !== void 0 && modifiers.includes("?")) {
|
|
1026
|
+
flags.push("optional");
|
|
1027
|
+
}
|
|
1028
|
+
if (modifiers !== void 0 && modifiers.includes("-")) {
|
|
1029
|
+
flags.push("hidden");
|
|
1030
|
+
}
|
|
912
1031
|
const quantity = quantityRaw ? parseQuantityInput(quantityRaw) : void 0;
|
|
913
|
-
const
|
|
1032
|
+
const idxsInList = findAndUpsertCookware(
|
|
914
1033
|
this.cookware,
|
|
915
|
-
{
|
|
1034
|
+
{
|
|
1035
|
+
name,
|
|
1036
|
+
quantity,
|
|
1037
|
+
quantityParts: quantity ? [quantity] : void 0,
|
|
1038
|
+
flags
|
|
1039
|
+
},
|
|
916
1040
|
reference
|
|
917
1041
|
);
|
|
918
1042
|
items.push({
|
|
919
1043
|
type: "cookware",
|
|
920
|
-
|
|
921
|
-
|
|
1044
|
+
index: idxsInList.cookwareIndex,
|
|
1045
|
+
quantityPartIndex: idxsInList.quantityPartIndex
|
|
922
1046
|
});
|
|
923
|
-
} else
|
|
1047
|
+
} else {
|
|
924
1048
|
const durationStr = groups.timerQuantity.trim();
|
|
925
|
-
const unit = (groups.
|
|
1049
|
+
const unit = (groups.timerUnit || "").trim();
|
|
926
1050
|
if (!unit) {
|
|
927
|
-
throw new Error("Timer missing
|
|
1051
|
+
throw new Error("Timer missing unit");
|
|
928
1052
|
}
|
|
929
1053
|
const name = groups.timerName || void 0;
|
|
930
1054
|
const duration = parseQuantityInput(durationStr);
|
|
@@ -933,7 +1057,7 @@ var Recipe = class _Recipe {
|
|
|
933
1057
|
duration,
|
|
934
1058
|
unit
|
|
935
1059
|
};
|
|
936
|
-
items.push({ type: "timer",
|
|
1060
|
+
items.push({ type: "timer", index: this.timers.push(timerObj) - 1 });
|
|
937
1061
|
}
|
|
938
1062
|
cursor = idx + match[0].length;
|
|
939
1063
|
}
|
|
@@ -976,30 +1100,57 @@ var Recipe = class _Recipe {
|
|
|
976
1100
|
throw new Error("Error scaling recipe: no initial servings value set");
|
|
977
1101
|
}
|
|
978
1102
|
newRecipe.ingredients = newRecipe.ingredients.map((ingredient) => {
|
|
979
|
-
if (ingredient.
|
|
980
|
-
ingredient.
|
|
981
|
-
|
|
982
|
-
|
|
1103
|
+
if (ingredient.quantityParts) {
|
|
1104
|
+
ingredient.quantityParts = ingredient.quantityParts.map(
|
|
1105
|
+
(quantityPart) => {
|
|
1106
|
+
if (quantityPart.value.type === "fixed" && quantityPart.value.value.type === "text") {
|
|
1107
|
+
return quantityPart;
|
|
1108
|
+
}
|
|
1109
|
+
return {
|
|
1110
|
+
...quantityPart,
|
|
1111
|
+
value: multiplyQuantityValue(
|
|
1112
|
+
quantityPart.value,
|
|
1113
|
+
quantityPart.scalable ? factor : 1
|
|
1114
|
+
)
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
983
1117
|
);
|
|
1118
|
+
if (ingredient.quantityParts.length === 1) {
|
|
1119
|
+
ingredient.quantity = ingredient.quantityParts[0].value;
|
|
1120
|
+
ingredient.unit = ingredient.quantityParts[0].unit;
|
|
1121
|
+
} else {
|
|
1122
|
+
const totalQuantity = ingredient.quantityParts.reduce(
|
|
1123
|
+
(acc, val) => addQuantities(acc, { value: val.value, unit: val.unit }),
|
|
1124
|
+
{ value: getDefaultQuantityValue() }
|
|
1125
|
+
);
|
|
1126
|
+
ingredient.quantity = totalQuantity.value;
|
|
1127
|
+
ingredient.unit = totalQuantity.unit;
|
|
1128
|
+
}
|
|
984
1129
|
}
|
|
985
1130
|
return ingredient;
|
|
986
1131
|
}).filter((ingredient) => ingredient.quantity !== null);
|
|
987
1132
|
newRecipe.servings = originalServings * factor;
|
|
988
1133
|
if (newRecipe.metadata.servings && this.metadata.servings) {
|
|
989
|
-
|
|
990
|
-
|
|
1134
|
+
if (floatRegex.test(String(this.metadata.servings).replace(",", ".").trim())) {
|
|
1135
|
+
const servingsValue = parseFloat(
|
|
1136
|
+
String(this.metadata.servings).replace(",", ".")
|
|
1137
|
+
);
|
|
991
1138
|
newRecipe.metadata.servings = String(servingsValue * factor);
|
|
992
1139
|
}
|
|
993
1140
|
}
|
|
994
1141
|
if (newRecipe.metadata.yield && this.metadata.yield) {
|
|
995
|
-
|
|
996
|
-
|
|
1142
|
+
if (floatRegex.test(String(this.metadata.yield).replace(",", ".").trim())) {
|
|
1143
|
+
const yieldValue = parseFloat(
|
|
1144
|
+
String(this.metadata.yield).replace(",", ".")
|
|
1145
|
+
);
|
|
997
1146
|
newRecipe.metadata.yield = String(yieldValue * factor);
|
|
998
1147
|
}
|
|
999
1148
|
}
|
|
1000
1149
|
if (newRecipe.metadata.serves && this.metadata.serves) {
|
|
1001
|
-
|
|
1002
|
-
|
|
1150
|
+
if (floatRegex.test(String(this.metadata.serves).replace(",", ".").trim())) {
|
|
1151
|
+
const servesValue = parseFloat(
|
|
1152
|
+
String(this.metadata.serves).replace(",", ".")
|
|
1153
|
+
);
|
|
1003
1154
|
newRecipe.metadata.serves = String(servesValue * factor);
|
|
1004
1155
|
}
|
|
1005
1156
|
}
|
|
@@ -1068,7 +1219,7 @@ var ShoppingList = class {
|
|
|
1068
1219
|
for (const { recipe, factor } of this.recipes) {
|
|
1069
1220
|
const scaledRecipe = factor === 1 ? recipe : recipe.scaleBy(factor);
|
|
1070
1221
|
for (const ingredient of scaledRecipe.ingredients) {
|
|
1071
|
-
if (ingredient.hidden) {
|
|
1222
|
+
if (ingredient.flags && ingredient.flags.includes("hidden")) {
|
|
1072
1223
|
continue;
|
|
1073
1224
|
}
|
|
1074
1225
|
const existingIngredient = this.ingredients.find(
|
|
@@ -1076,8 +1227,8 @@ var ShoppingList = class {
|
|
|
1076
1227
|
);
|
|
1077
1228
|
let addSeparate = false;
|
|
1078
1229
|
try {
|
|
1079
|
-
if (existingIngredient) {
|
|
1080
|
-
if (existingIngredient.quantity
|
|
1230
|
+
if (existingIngredient && ingredient.quantity) {
|
|
1231
|
+
if (existingIngredient.quantity) {
|
|
1081
1232
|
const newQuantity = addQuantities(
|
|
1082
1233
|
{
|
|
1083
1234
|
value: existingIngredient.quantity,
|
|
@@ -1092,7 +1243,7 @@ var ShoppingList = class {
|
|
|
1092
1243
|
if (newQuantity.unit) {
|
|
1093
1244
|
existingIngredient.unit = newQuantity.unit;
|
|
1094
1245
|
}
|
|
1095
|
-
} else
|
|
1246
|
+
} else {
|
|
1096
1247
|
existingIngredient.quantity = ingredient.quantity;
|
|
1097
1248
|
if (ingredient.unit) {
|
|
1098
1249
|
existingIngredient.unit = ingredient.unit;
|
|
@@ -1191,4 +1342,8 @@ export {
|
|
|
1191
1342
|
Section,
|
|
1192
1343
|
ShoppingList
|
|
1193
1344
|
};
|
|
1345
|
+
/* v8 ignore else -- @preserve */
|
|
1346
|
+
/* v8 ignore else -- expliciting error types -- @preserve */
|
|
1347
|
+
/* v8 ignore else -- expliciting error type -- @preserve */
|
|
1348
|
+
/* v8 ignore else -- only set unit if it is given -- @preserve */
|
|
1194
1349
|
//# sourceMappingURL=index.js.map
|