@tmlmt/cooklang-parser 3.0.0-alpha.13 → 3.0.0-alpha.14

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/dist/index.d.cts CHANGED
@@ -657,6 +657,11 @@ interface Timer {
657
657
  /** The unit of the timer. */
658
658
  unit: string;
659
659
  }
660
+ /**
661
+ * Represents a formatting attribute for a {@link TextItem}.
662
+ * @category Types
663
+ */
664
+ type TextAttribute = "bold" | "italic" | "bold+italic" | "link" | "code";
660
665
  /**
661
666
  * Represents a text item in a recipe step.
662
667
  * @category Types
@@ -666,6 +671,10 @@ interface TextItem {
666
671
  type: "text";
667
672
  /** The content of the text item. */
668
673
  value: string;
674
+ /** The formatting attribute of the text item, if any. */
675
+ attribute?: TextAttribute;
676
+ /** The URL target, only present when attribute is "link". */
677
+ href?: string;
669
678
  }
670
679
  /**
671
680
  * Represents an arbitrary scalable quantity in a recipe.
@@ -1653,5 +1662,11 @@ declare class NoProductCatalogForCartError extends Error {
1653
1662
  declare class NoShoppingListForCartError extends Error {
1654
1663
  constructor();
1655
1664
  }
1665
+ declare class NoTabAsIndentError extends Error {
1666
+ constructor();
1667
+ }
1668
+ declare class BadIndentationError extends Error {
1669
+ constructor();
1670
+ }
1656
1671
 
1657
- export { type AddedIngredient, type AddedRecipe, type AddedRecipeOptions, type AlternativeIngredientRef, type AndGroup, type ArbitraryScalable, type ArbitraryScalableItem, type CartContent, type CartMatch, type CartMisMatch, type CategorizedIngredients, type Category, CategoryConfig, type CategoryIngredient, type Cookware, type CookwareFlag, type CookwareItem, type DecimalValue, type FixedNumericValue, type FixedValue, type FlatAndGroup, type FlatGroup, type FlatOrGroup, type FractionValue, type GetIngredientQuantitiesOptions, type Group, type Ingredient, type IngredientAlternative, type IngredientExtras, type IngredientFlag, type IngredientItem, type IngredientQuantityAndGroup, type IngredientQuantityGroup, type MaybeNestedAndGroup, type MaybeNestedGroup, type MaybeNestedOrGroup, type MaybeScalableQuantity, type Metadata, type MetadataObject, type MetadataSource, type MetadataTime, type MetadataValue, NoProductCatalogForCartError, type NoProductMatchErrorCode, NoShoppingListForCartError, type Note, type NoteItem, type OrGroup, ProductCatalog, type ProductMatch, type ProductMisMatch, type ProductOption, type ProductOptionBase, type ProductOptionCore, type ProductSelection, type ProductSize, type QuantityBase, type QuantityWithExtendedUnit, type QuantityWithPlainUnit, type QuantityWithUnitDef, type QuantityWithUnitLike, type Range, Recipe, type RecipeAlternatives, type RecipeChoices, type RecipeWithFactor, type RecipeWithServings, Section, ShoppingCart, type ShoppingCartOptions, type ShoppingCartSummary, ShoppingList, type SpecificUnitSystem, type Step, type StepItem, type TextItem, type TextValue, type Timer, type TimerItem, type ToBaseBySystem, type Unit, type UnitDefinition, type UnitDefinitionLike, type UnitSystem, type UnitType, convertQuantityToSystem, formatExtendedQuantity, formatItemQuantity, formatNumericValue, formatQuantity, formatQuantityWithUnit, formatSingleValue, formatUnit, hasAlternatives, isAlternativeSelected, isAndGroup, isGroupedItem, isSimpleGroup, renderFractionAsVulgar };
1672
+ export { type AddedIngredient, type AddedRecipe, type AddedRecipeOptions, type AlternativeIngredientRef, type AndGroup, type ArbitraryScalable, type ArbitraryScalableItem, BadIndentationError, type CartContent, type CartMatch, type CartMisMatch, type CategorizedIngredients, type Category, CategoryConfig, type CategoryIngredient, type Cookware, type CookwareFlag, type CookwareItem, type DecimalValue, type FixedNumericValue, type FixedValue, type FlatAndGroup, type FlatGroup, type FlatOrGroup, type FractionValue, type GetIngredientQuantitiesOptions, type Group, type Ingredient, type IngredientAlternative, type IngredientAlternativeBase, type IngredientExtras, type IngredientFlag, type IngredientItem, type IngredientQuantityAndGroup, type IngredientQuantityGroup, type MaybeNestedAndGroup, type MaybeNestedGroup, type MaybeNestedOrGroup, type MaybeScalableQuantity, type Metadata, type MetadataObject, type MetadataSource, type MetadataTime, type MetadataValue, NoProductCatalogForCartError, type NoProductMatchErrorCode, NoShoppingListForCartError, NoTabAsIndentError, type Note, type NoteItem, type OrGroup, ProductCatalog, type ProductMatch, type ProductMisMatch, type ProductOption, type ProductOptionBase, type ProductOptionCore, type ProductSelection, type ProductSize, type QuantityBase, type QuantityWithExtendedUnit, type QuantityWithPlainUnit, type QuantityWithUnitDef, type QuantityWithUnitLike, type Range, Recipe, type RecipeAlternatives, type RecipeChoices, type RecipeWithFactor, type RecipeWithServings, Section, ShoppingCart, type ShoppingCartOptions, type ShoppingCartSummary, ShoppingList, type SpecificUnitSystem, type Step, type StepItem, type TextAttribute, type TextItem, type TextValue, type Timer, type TimerItem, type ToBaseBySystem, type Unit, type UnitDefinition, type UnitDefinitionLike, type UnitFractionConfig, type UnitSystem, type UnitType, type WithOptionalQuantity, convertQuantityToSystem, formatExtendedQuantity, formatItemQuantity, formatNumericValue, formatQuantity, formatQuantityWithUnit, formatSingleValue, formatUnit, hasAlternatives, isAlternativeSelected, isAndGroup, isGroupedItem, isSimpleGroup, renderFractionAsVulgar };
package/dist/index.d.ts CHANGED
@@ -657,6 +657,11 @@ interface Timer {
657
657
  /** The unit of the timer. */
658
658
  unit: string;
659
659
  }
660
+ /**
661
+ * Represents a formatting attribute for a {@link TextItem}.
662
+ * @category Types
663
+ */
664
+ type TextAttribute = "bold" | "italic" | "bold+italic" | "link" | "code";
660
665
  /**
661
666
  * Represents a text item in a recipe step.
662
667
  * @category Types
@@ -666,6 +671,10 @@ interface TextItem {
666
671
  type: "text";
667
672
  /** The content of the text item. */
668
673
  value: string;
674
+ /** The formatting attribute of the text item, if any. */
675
+ attribute?: TextAttribute;
676
+ /** The URL target, only present when attribute is "link". */
677
+ href?: string;
669
678
  }
670
679
  /**
671
680
  * Represents an arbitrary scalable quantity in a recipe.
@@ -1653,5 +1662,11 @@ declare class NoProductCatalogForCartError extends Error {
1653
1662
  declare class NoShoppingListForCartError extends Error {
1654
1663
  constructor();
1655
1664
  }
1665
+ declare class NoTabAsIndentError extends Error {
1666
+ constructor();
1667
+ }
1668
+ declare class BadIndentationError extends Error {
1669
+ constructor();
1670
+ }
1656
1671
 
1657
- export { type AddedIngredient, type AddedRecipe, type AddedRecipeOptions, type AlternativeIngredientRef, type AndGroup, type ArbitraryScalable, type ArbitraryScalableItem, type CartContent, type CartMatch, type CartMisMatch, type CategorizedIngredients, type Category, CategoryConfig, type CategoryIngredient, type Cookware, type CookwareFlag, type CookwareItem, type DecimalValue, type FixedNumericValue, type FixedValue, type FlatAndGroup, type FlatGroup, type FlatOrGroup, type FractionValue, type GetIngredientQuantitiesOptions, type Group, type Ingredient, type IngredientAlternative, type IngredientExtras, type IngredientFlag, type IngredientItem, type IngredientQuantityAndGroup, type IngredientQuantityGroup, type MaybeNestedAndGroup, type MaybeNestedGroup, type MaybeNestedOrGroup, type MaybeScalableQuantity, type Metadata, type MetadataObject, type MetadataSource, type MetadataTime, type MetadataValue, NoProductCatalogForCartError, type NoProductMatchErrorCode, NoShoppingListForCartError, type Note, type NoteItem, type OrGroup, ProductCatalog, type ProductMatch, type ProductMisMatch, type ProductOption, type ProductOptionBase, type ProductOptionCore, type ProductSelection, type ProductSize, type QuantityBase, type QuantityWithExtendedUnit, type QuantityWithPlainUnit, type QuantityWithUnitDef, type QuantityWithUnitLike, type Range, Recipe, type RecipeAlternatives, type RecipeChoices, type RecipeWithFactor, type RecipeWithServings, Section, ShoppingCart, type ShoppingCartOptions, type ShoppingCartSummary, ShoppingList, type SpecificUnitSystem, type Step, type StepItem, type TextItem, type TextValue, type Timer, type TimerItem, type ToBaseBySystem, type Unit, type UnitDefinition, type UnitDefinitionLike, type UnitSystem, type UnitType, convertQuantityToSystem, formatExtendedQuantity, formatItemQuantity, formatNumericValue, formatQuantity, formatQuantityWithUnit, formatSingleValue, formatUnit, hasAlternatives, isAlternativeSelected, isAndGroup, isGroupedItem, isSimpleGroup, renderFractionAsVulgar };
1672
+ export { type AddedIngredient, type AddedRecipe, type AddedRecipeOptions, type AlternativeIngredientRef, type AndGroup, type ArbitraryScalable, type ArbitraryScalableItem, BadIndentationError, type CartContent, type CartMatch, type CartMisMatch, type CategorizedIngredients, type Category, CategoryConfig, type CategoryIngredient, type Cookware, type CookwareFlag, type CookwareItem, type DecimalValue, type FixedNumericValue, type FixedValue, type FlatAndGroup, type FlatGroup, type FlatOrGroup, type FractionValue, type GetIngredientQuantitiesOptions, type Group, type Ingredient, type IngredientAlternative, type IngredientAlternativeBase, type IngredientExtras, type IngredientFlag, type IngredientItem, type IngredientQuantityAndGroup, type IngredientQuantityGroup, type MaybeNestedAndGroup, type MaybeNestedGroup, type MaybeNestedOrGroup, type MaybeScalableQuantity, type Metadata, type MetadataObject, type MetadataSource, type MetadataTime, type MetadataValue, NoProductCatalogForCartError, type NoProductMatchErrorCode, NoShoppingListForCartError, NoTabAsIndentError, type Note, type NoteItem, type OrGroup, ProductCatalog, type ProductMatch, type ProductMisMatch, type ProductOption, type ProductOptionBase, type ProductOptionCore, type ProductSelection, type ProductSize, type QuantityBase, type QuantityWithExtendedUnit, type QuantityWithPlainUnit, type QuantityWithUnitDef, type QuantityWithUnitLike, type Range, Recipe, type RecipeAlternatives, type RecipeChoices, type RecipeWithFactor, type RecipeWithServings, Section, ShoppingCart, type ShoppingCartOptions, type ShoppingCartSummary, ShoppingList, type SpecificUnitSystem, type Step, type StepItem, type TextAttribute, type TextItem, type TextValue, type Timer, type TimerItem, type ToBaseBySystem, type Unit, type UnitDefinition, type UnitDefinitionLike, type UnitFractionConfig, type UnitSystem, type UnitType, type WithOptionalQuantity, convertQuantityToSystem, formatExtendedQuantity, formatItemQuantity, formatNumericValue, formatQuantity, formatQuantityWithUnit, formatSingleValue, formatUnit, hasAlternatives, isAlternativeSelected, isAndGroup, isGroupedItem, isSimpleGroup, renderFractionAsVulgar };
package/dist/index.js CHANGED
@@ -299,6 +299,37 @@ var shoppingListRegex = d().literal("[").startNamedGroup("name").anyCharacter().
299
299
  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();
300
300
  var numberLikeRegex = d().startAnchor().digit().oneOrMore().startGroup().anyOf(".,/").exactly(1).digit().oneOrMore().endGroup().optional().endAnchor().toRegExp();
301
301
  var floatRegex = d().startAnchor().digit().oneOrMore().startGroup().anyOf(".").exactly(1).digit().oneOrMore().endGroup().optional().endAnchor().toRegExp();
302
+ var mdEscaped = d().literal("\\").startCaptureGroup().anyOf("*_`").endGroup();
303
+ var mdInlineCode = d().literal("`").startCaptureGroup().notAnyOf("`").oneOrMore().lazy().endGroup().literal("`");
304
+ var mdLink = d().literal("[").startCaptureGroup().notAnyOf("\\]").oneOrMore().lazy().endGroup().literal("](").startCaptureGroup().notAnyOf(")").oneOrMore().lazy().endGroup().literal(")");
305
+ var mdTripleAsterisk = d().literal("***").startCaptureGroup().anyCharacter().oneOrMore().lazy().endGroup().literal("***");
306
+ var mdTripleUnderscore = d().literal("___").startCaptureGroup().anyCharacter().oneOrMore().lazy().endGroup().literal("___");
307
+ var mdBoldAstItalicUnd = d().literal("**_").startCaptureGroup().anyCharacter().oneOrMore().lazy().endGroup().literal("_**");
308
+ var mdBoldUndItalicAst = d().literal("__*").startCaptureGroup().anyCharacter().oneOrMore().lazy().endGroup().literal("*__");
309
+ var mdItalicAstBoldUnd = d().literal("*__").startCaptureGroup().anyCharacter().oneOrMore().lazy().endGroup().literal("__*");
310
+ var mdItalicUndBoldAst = d().literal("_**").startCaptureGroup().anyCharacter().oneOrMore().lazy().endGroup().literal("**_");
311
+ var mdBoldAsterisk = d().literal("**").startCaptureGroup().anyCharacter().oneOrMore().lazy().endGroup().literal("**");
312
+ var mdBoldUnderscore = d().wordBoundary().literal("__").startCaptureGroup().anyCharacter().oneOrMore().lazy().endGroup().literal("__").wordBoundary();
313
+ var mdItalicAsterisk = d().literal("*").startCaptureGroup().anyCharacter().oneOrMore().lazy().endGroup().literal("*");
314
+ var mdItalicUnderscore = d().wordBoundary().literal("_").startCaptureGroup().anyCharacter().oneOrMore().lazy().endGroup().literal("_").wordBoundary();
315
+ var markdownRegex = new RegExp(
316
+ [
317
+ mdEscaped,
318
+ mdInlineCode,
319
+ mdLink,
320
+ mdTripleAsterisk,
321
+ mdTripleUnderscore,
322
+ mdBoldAstItalicUnd,
323
+ mdBoldUndItalicAst,
324
+ mdItalicAstBoldUnd,
325
+ mdItalicUndBoldAst,
326
+ mdBoldAsterisk,
327
+ mdBoldUnderscore,
328
+ mdItalicAsterisk,
329
+ mdItalicUnderscore
330
+ ].map((r2) => r2.toRegExp().source).join("|"),
331
+ "g"
332
+ );
302
333
 
303
334
  // src/units/definitions.ts
304
335
  var units = [
@@ -1425,12 +1456,106 @@ function parseQuantityInput(input_str) {
1425
1456
  }
1426
1457
  return { type: "fixed", value: parseFixedValue(clean_str) };
1427
1458
  }
1459
+ function parseMarkdownSegments(text) {
1460
+ const items = [];
1461
+ let cursor = 0;
1462
+ for (const match of text.matchAll(markdownRegex)) {
1463
+ const idx = match.index;
1464
+ if (idx > cursor) {
1465
+ items.push({ type: "text", value: text.slice(cursor, idx) });
1466
+ }
1467
+ const [
1468
+ ,
1469
+ escaped,
1470
+ // group 1: escaped character
1471
+ code,
1472
+ // group 2: inline code
1473
+ linkText,
1474
+ // group 3: link text
1475
+ linkUrl,
1476
+ // group 4: link url
1477
+ tripleAst,
1478
+ // group 5: ***bold+italic***
1479
+ tripleUnd,
1480
+ // group 6: ___bold+italic___
1481
+ astUnd,
1482
+ // group 7: **_bold+italic_**
1483
+ undAst,
1484
+ // group 8: __*bold+italic*__
1485
+ astUndUnd,
1486
+ // group 9: *__bold+italic__*
1487
+ undAstAst,
1488
+ // group 10: _**bold+italic**_
1489
+ boldAst,
1490
+ // group 11: **bold**
1491
+ boldUnd,
1492
+ // group 12: __bold__
1493
+ italicAst,
1494
+ // group 13: *italic*
1495
+ italicUnd
1496
+ // group 14: _italic_
1497
+ ] = match;
1498
+ let value;
1499
+ let attribute;
1500
+ let href;
1501
+ if (escaped !== void 0) {
1502
+ items.push({ type: "text", value: escaped });
1503
+ cursor = idx + match[0].length;
1504
+ continue;
1505
+ } else if (code !== void 0) {
1506
+ value = code;
1507
+ attribute = "code";
1508
+ } else if (linkText !== void 0) {
1509
+ value = linkText;
1510
+ attribute = "link";
1511
+ href = linkUrl;
1512
+ } else if (tripleAst !== void 0 || tripleUnd !== void 0 || astUnd !== void 0 || undAst !== void 0 || astUndUnd !== void 0 || undAstAst !== void 0) {
1513
+ value = tripleAst ?? tripleUnd ?? astUnd ?? undAst ?? astUndUnd ?? undAstAst;
1514
+ attribute = "bold+italic";
1515
+ } else if (boldAst !== void 0 || boldUnd !== void 0) {
1516
+ value = boldAst ?? boldUnd;
1517
+ attribute = "bold";
1518
+ } else {
1519
+ value = italicAst ?? italicUnd;
1520
+ attribute = "italic";
1521
+ }
1522
+ const item = { type: "text", value };
1523
+ if (attribute) item.attribute = attribute;
1524
+ if (href) item.href = href;
1525
+ items.push(item);
1526
+ cursor = idx + match[0].length;
1527
+ }
1528
+ if (cursor < text.length) {
1529
+ items.push({ type: "text", value: text.slice(cursor) });
1530
+ }
1531
+ return items;
1532
+ }
1428
1533
  function parseSimpleMetaVar(content, varName) {
1429
1534
  const varMatch = content.match(
1430
1535
  new RegExp(`^${varName}:\\s*(.*(?:\\r?\\n\\s+.*)*)+`, "m")
1431
1536
  );
1432
1537
  return varMatch ? varMatch[1]?.trim().replace(/\s*\r?\n\s+/g, " ") : void 0;
1433
1538
  }
1539
+ function parseBlockScalarMetaVar(content, varName) {
1540
+ const match = content.match(
1541
+ new RegExp(
1542
+ `^${varName}:\\s*([|>])\\s*\\r?\\n((?:(?:[ ]+.*|\\s*)(?:\\r?\\n|$))+)`,
1543
+ "m"
1544
+ )
1545
+ );
1546
+ if (!match) return void 0;
1547
+ const style = match[1];
1548
+ const rawBlock = match[2];
1549
+ const lines = rawBlock.split(/\r?\n/);
1550
+ const firstNonEmpty = lines.find((l) => l.trim() !== "");
1551
+ if (!firstNonEmpty) return void 0;
1552
+ const baseIndent = firstNonEmpty.match(/^([ ]*)/)[1].length;
1553
+ const stripped = lines.map((line) => line.trim() === "" ? "" : line.slice(baseIndent)).join("\n").replace(/\n+$/, "");
1554
+ if (style === "|") {
1555
+ return stripped;
1556
+ }
1557
+ return stripped.replace(/\n\n/g, "\0").replace(/\n/g, " ").replace(/\0/g, "\n");
1558
+ }
1434
1559
  function parseScalingMetaVar(content, varName) {
1435
1560
  const varMatch = content.match(scalingMetaValueRegex(varName));
1436
1561
  if (!varMatch) return void 0;
@@ -1613,6 +1738,13 @@ function extractMetadata(content) {
1613
1738
  "cuisine",
1614
1739
  "difficulty"
1615
1740
  ]) {
1741
+ if (metaVar === "description" || metaVar === "introduction") {
1742
+ const blockValue = parseBlockScalarMetaVar(metadataContent, metaVar);
1743
+ if (blockValue) {
1744
+ metadata[metaVar] = blockValue;
1745
+ continue;
1746
+ }
1747
+ }
1616
1748
  const stringMetaValue = parseSimpleMetaVar(metadataContent, metaVar);
1617
1749
  if (stringMetaValue) metadata[metaVar] = stringMetaValue;
1618
1750
  }
@@ -2316,13 +2448,13 @@ var _Recipe = class _Recipe {
2316
2448
  for (const match of text.matchAll(globalRegex)) {
2317
2449
  const idx = match.index;
2318
2450
  if (idx > cursor) {
2319
- noteItems.push({ type: "text", value: text.slice(cursor, idx) });
2451
+ noteItems.push(...parseMarkdownSegments(text.slice(cursor, idx)));
2320
2452
  }
2321
2453
  this._parseArbitraryScalable(match.groups, noteItems);
2322
2454
  cursor = idx + match[0].length;
2323
2455
  }
2324
2456
  if (cursor < text.length) {
2325
- noteItems.push({ type: "text", value: text.slice(cursor) });
2457
+ noteItems.push(...parseMarkdownSegments(text.slice(cursor)));
2326
2458
  }
2327
2459
  return noteItems;
2328
2460
  }
@@ -2876,7 +3008,7 @@ var _Recipe = class _Recipe {
2876
3008
  for (const match of line.matchAll(tokensRegex)) {
2877
3009
  const idx = match.index;
2878
3010
  if (idx > cursor) {
2879
- items.push({ type: "text", value: line.slice(cursor, idx) });
3011
+ items.push(...parseMarkdownSegments(line.slice(cursor, idx)));
2880
3012
  }
2881
3013
  const groups = match.groups;
2882
3014
  if (groups.mIngredientName || groups.sIngredientName) {
@@ -2938,7 +3070,7 @@ var _Recipe = class _Recipe {
2938
3070
  cursor = idx + match[0].length;
2939
3071
  }
2940
3072
  if (cursor < line.length) {
2941
- items.push({ type: "text", value: line.slice(cursor) });
3073
+ items.push(...parseMarkdownSegments(line.slice(cursor)));
2942
3074
  }
2943
3075
  blankLineBefore = false;
2944
3076
  }
@@ -3867,9 +3999,11 @@ function isAlternativeSelected(recipe, choices, item, alternativeIndex) {
3867
3999
  return alternativeIndex === selectedIndex;
3868
4000
  }
3869
4001
  export {
4002
+ BadIndentationError,
3870
4003
  CategoryConfig,
3871
4004
  NoProductCatalogForCartError,
3872
4005
  NoShoppingListForCartError,
4006
+ NoTabAsIndentError,
3873
4007
  ProductCatalog,
3874
4008
  Recipe,
3875
4009
  Section,