@recipe-book/core 0.1.0 → 0.1.2
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/CHANGELOG.md +138 -0
- package/README.md +1 -1
- package/dist/{chunk-VWVIBCTG.cjs → chunk-ISRDJR2O.cjs} +227 -179
- package/dist/chunk-ISRDJR2O.cjs.map +1 -0
- package/dist/errors.js +29 -1
- package/dist/errors.js.map +1 -1
- package/dist/format/duration.js.map +1 -1
- package/dist/format/ingredient.js.map +1 -1
- package/dist/format/number.js +1 -1
- package/dist/format/number.js.map +1 -1
- package/dist/format/options.js.map +1 -1
- package/dist/format/quantity.js.map +1 -1
- package/dist/format/servings.js.map +1 -1
- package/dist/format/temperature.js.map +1 -1
- package/dist/index.cjs +87 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +71 -28
- package/dist/index.d.ts +71 -28
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/ingredient/parse.js +27 -22
- package/dist/ingredient/parse.js.map +1 -1
- package/dist/issues.js.map +1 -1
- package/dist/quantity/amount.js +11 -0
- package/dist/quantity/amount.js.map +1 -1
- package/dist/quantity/parse.js +58 -81
- package/dist/quantity/parse.js.map +1 -1
- package/dist/quantity/scale.js +5 -2
- package/dist/quantity/scale.js.map +1 -1
- package/dist/recipe/ids.js.map +1 -1
- package/dist/recipe/parse.js +80 -60
- package/dist/recipe/parse.js.map +1 -1
- package/dist/recipe/schema.js +8 -6
- package/dist/recipe/schema.js.map +1 -1
- package/dist/resolve.js +6 -1
- package/dist/resolve.js.map +1 -1
- package/dist/schema-org/find.js +46 -13
- package/dist/schema-org/find.js.map +1 -1
- package/dist/schema-org/from-json-ld.js +134 -71
- package/dist/schema-org/from-json-ld.js.map +1 -1
- package/dist/schema-org/text.js.map +1 -1
- package/dist/schema-org/to-json-ld.js +12 -15
- package/dist/schema-org/to-json-ld.js.map +1 -1
- package/dist/schema-org.cjs +239 -147
- package/dist/schema-org.cjs.map +1 -1
- package/dist/schema-org.d.cts +35 -21
- package/dist/schema-org.d.ts +35 -21
- package/dist/steps/segment.js.map +1 -1
- package/dist/steps/temperature.js +13 -13
- package/dist/steps/temperature.js.map +1 -1
- package/dist/{types-DSMf45H5.d.cts → types-CKIoWsz8.d.cts} +25 -7
- package/dist/{types-DSMf45H5.d.ts → types-CKIoWsz8.d.ts} +25 -7
- package/dist/units/convert.js +16 -8
- package/dist/units/convert.js.map +1 -1
- package/dist/units/temperature.js +7 -1
- package/dist/units/temperature.js.map +1 -1
- package/dist/validation.js +1 -1
- package/dist/validation.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-VWVIBCTG.cjs.map +0 -1
package/dist/schema-org.cjs
CHANGED
|
@@ -1,32 +1,39 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkISRDJR2O_cjs = require('./chunk-ISRDJR2O.cjs');
|
|
4
4
|
|
|
5
5
|
// src/schema-org/find.ts
|
|
6
6
|
var MAX_DEPTH = 32;
|
|
7
7
|
function locate(documents) {
|
|
8
|
+
const direct = scan(documents, false);
|
|
9
|
+
return direct.recipes.length > 0 ? direct : scan(documents, true);
|
|
10
|
+
}
|
|
11
|
+
function scan(documents, lists) {
|
|
8
12
|
const recipes = [];
|
|
9
13
|
const ids = /* @__PURE__ */ new Map();
|
|
10
14
|
const recipeIds = /* @__PURE__ */ new Map();
|
|
11
|
-
const visit = (value, path,
|
|
15
|
+
const visit = (value, path, reach = "any") => {
|
|
12
16
|
if (path.length > MAX_DEPTH) {
|
|
13
17
|
return;
|
|
14
18
|
}
|
|
15
19
|
if (Array.isArray(value)) {
|
|
16
|
-
value
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
for (const [entry, entryPath] of entriesOf(value, path)) {
|
|
21
|
+
visit(entry, entryPath, reach);
|
|
22
|
+
}
|
|
19
23
|
return;
|
|
20
24
|
}
|
|
21
|
-
const fields =
|
|
25
|
+
const fields = chunkISRDJR2O_cjs.asRecord(value);
|
|
22
26
|
if (!fields) {
|
|
23
27
|
return;
|
|
24
28
|
}
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
const isRecipe = hasType(fields, "Recipe");
|
|
30
|
+
const isList = lists && hasType(fields, "ItemList");
|
|
31
|
+
if (reach !== "any" && !isRecipe) {
|
|
32
|
+
if (isList && reach === "mainEntity") {
|
|
33
|
+
visit(fields.itemListElement, [...path, "itemListElement"], "entry");
|
|
34
|
+
} else if (lists && reach === "entry" && hasType(fields, "ListItem")) {
|
|
35
|
+
visit(fields.item, [...path, "item"], "item");
|
|
36
|
+
}
|
|
30
37
|
return;
|
|
31
38
|
}
|
|
32
39
|
const located = { node: value, path };
|
|
@@ -47,7 +54,10 @@ function locate(documents) {
|
|
|
47
54
|
}
|
|
48
55
|
} else {
|
|
49
56
|
visit(fields["@graph"], [...path, "@graph"]);
|
|
50
|
-
visit(fields.mainEntity, [...path, "mainEntity"],
|
|
57
|
+
visit(fields.mainEntity, [...path, "mainEntity"], "mainEntity");
|
|
58
|
+
if (isList) {
|
|
59
|
+
visit(fields.itemListElement, [...path, "itemListElement"], "entry");
|
|
60
|
+
}
|
|
51
61
|
}
|
|
52
62
|
};
|
|
53
63
|
for (const document of documents) {
|
|
@@ -55,14 +65,36 @@ function locate(documents) {
|
|
|
55
65
|
}
|
|
56
66
|
return { recipes, ids };
|
|
57
67
|
}
|
|
68
|
+
var TYPES = {
|
|
69
|
+
Recipe: /(?:^|[/:#])Recipe$/,
|
|
70
|
+
ItemList: /(?:^|[/:#])ItemList$/,
|
|
71
|
+
ListItem: /(?:^|[/:#])ListItem$/
|
|
72
|
+
};
|
|
73
|
+
function hasType(node, name) {
|
|
74
|
+
return entriesOf(node["@type"], []).some(
|
|
75
|
+
([type]) => typeof type === "string" && TYPES[name].test(type)
|
|
76
|
+
);
|
|
77
|
+
}
|
|
58
78
|
function hasContent(node) {
|
|
59
|
-
return Object.keys(node).some((key) => key
|
|
79
|
+
return Object.keys(node).some((key) => !key.startsWith("@"));
|
|
80
|
+
}
|
|
81
|
+
function entriesOf(value, path) {
|
|
82
|
+
if (!Array.isArray(value)) {
|
|
83
|
+
return [[value, path]];
|
|
84
|
+
}
|
|
85
|
+
const entries = [];
|
|
86
|
+
for (let i = 0; i < value.length; i++) {
|
|
87
|
+
if (chunkISRDJR2O_cjs.hasOwn(value, i)) {
|
|
88
|
+
entries.push([value[i], [...path, i]]);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return entries;
|
|
60
92
|
}
|
|
61
93
|
function findRecipeJsonLd(html) {
|
|
62
94
|
if (typeof html !== "string") {
|
|
63
|
-
throw new
|
|
95
|
+
throw new chunkISRDJR2O_cjs.RecipeBookError(
|
|
64
96
|
"invalid_argument",
|
|
65
|
-
`findRecipeJsonLd: html must be a string, such as await response.text(), received ${
|
|
97
|
+
`findRecipeJsonLd: html must be a string, such as await response.text(), received ${chunkISRDJR2O_cjs.describeValue(html)}.`
|
|
66
98
|
);
|
|
67
99
|
}
|
|
68
100
|
const documents = [];
|
|
@@ -85,7 +117,7 @@ function findRecipeJsonLd(html) {
|
|
|
85
117
|
}
|
|
86
118
|
function withImages(node, ids) {
|
|
87
119
|
const follow = (value) => {
|
|
88
|
-
const id =
|
|
120
|
+
const id = chunkISRDJR2O_cjs.isRecord(value) && Object.keys(value).join() === "@id" && value["@id"];
|
|
89
121
|
const target = typeof id === "string" && ids.get(id)?.node;
|
|
90
122
|
return target && target !== node ? target : value;
|
|
91
123
|
};
|
|
@@ -97,7 +129,7 @@ function withImages(node, ids) {
|
|
|
97
129
|
if (Array.isArray(value)) {
|
|
98
130
|
return value.map((entry) => copy(entry, depth + 1, keys));
|
|
99
131
|
}
|
|
100
|
-
const fields =
|
|
132
|
+
const fields = chunkISRDJR2O_cjs.asRecord(value);
|
|
101
133
|
if (!fields) {
|
|
102
134
|
return value;
|
|
103
135
|
}
|
|
@@ -231,11 +263,11 @@ function cleanLines(text2) {
|
|
|
231
263
|
const code = decimal === void 0 ? parseInt(hex, 16) : +decimal;
|
|
232
264
|
return code > 0 && code <= 1114111 && (code < 55296 || code > 57343) ? String.fromCodePoint(code) : entity;
|
|
233
265
|
}
|
|
234
|
-
if (
|
|
266
|
+
if (chunkISRDJR2O_cjs.hasOwn(NAMED_ENTITIES, name)) {
|
|
235
267
|
return NAMED_ENTITIES[name];
|
|
236
268
|
}
|
|
237
269
|
const accent = /^([aceinouyACEINOUY])([a-z]+)$/.exec(name);
|
|
238
|
-
return accent &&
|
|
270
|
+
return accent && chunkISRDJR2O_cjs.hasOwn(MARKS, accent[2]) ? `${accent[1]}${MARKS[accent[2]]}`.normalize("NFC") : entity;
|
|
239
271
|
}
|
|
240
272
|
).split(/[\n\r\u2028\u2029]/).map((line) => line.replace(/\s+/g, " ").trim()).filter(Boolean);
|
|
241
273
|
}
|
|
@@ -271,55 +303,54 @@ var READ_FIELDS = [
|
|
|
271
303
|
"tool",
|
|
272
304
|
"nutrition"
|
|
273
305
|
];
|
|
274
|
-
var
|
|
275
|
-
["prep", "prepTime"],
|
|
276
|
-
["cook", "cookTime"],
|
|
277
|
-
["total", "totalTime"]
|
|
278
|
-
];
|
|
306
|
+
var MAX_URL_LENGTH = 4096;
|
|
279
307
|
var SERVINGS_WORD = /^(?:servings?|portions?|(?:serving|portion)\(s\)|people|persons?)\.?$/i;
|
|
280
308
|
function fromJsonLd(input) {
|
|
281
309
|
const { recipes, ids } = locate([input]);
|
|
282
310
|
const [found] = recipes;
|
|
283
311
|
if (!found) {
|
|
284
312
|
return {
|
|
285
|
-
...
|
|
286
|
-
|
|
313
|
+
...chunkISRDJR2O_cjs.toResult("invalid_recipe", void 0, [
|
|
314
|
+
chunkISRDJR2O_cjs.issue(
|
|
287
315
|
"error",
|
|
288
316
|
"invalid_type",
|
|
289
317
|
[],
|
|
290
|
-
`Expected a schema.org Recipe, or an array, @graph, or
|
|
318
|
+
`Expected a schema.org Recipe, or an array, @graph, mainEntity, or ItemList that holds one, received ${chunkISRDJR2O_cjs.describeValue(input)}.`
|
|
291
319
|
)
|
|
292
320
|
]),
|
|
293
321
|
extra: {}
|
|
294
322
|
};
|
|
295
323
|
}
|
|
296
|
-
const node =
|
|
324
|
+
const node = chunkISRDJR2O_cjs.asRecord(found.node);
|
|
297
325
|
const reader = {
|
|
298
326
|
recipe: found.node,
|
|
299
327
|
ids,
|
|
300
328
|
warnings: [],
|
|
301
329
|
sources: /* @__PURE__ */ new Map(),
|
|
302
330
|
droppable: /* @__PURE__ */ new Set(),
|
|
303
|
-
images: /* @__PURE__ */ new Map()
|
|
331
|
+
images: [/* @__PURE__ */ new Map(), /* @__PURE__ */ new Map()],
|
|
332
|
+
repeated: 0,
|
|
333
|
+
deepest: 0
|
|
304
334
|
};
|
|
305
335
|
const name = text(node.name);
|
|
306
336
|
if (recipes.length > 1) {
|
|
307
|
-
|
|
337
|
+
chunkISRDJR2O_cjs.warning(
|
|
308
338
|
reader.warnings,
|
|
309
339
|
"ignored_value",
|
|
310
340
|
[],
|
|
311
|
-
`Found ${recipes.length} recipes. Only the first${typeof name === "string" ? `, ${
|
|
341
|
+
`Found ${recipes.length} recipes. Only the first${typeof name === "string" ? `, ${chunkISRDJR2O_cjs.quote(name)},` : ""} is read.`
|
|
312
342
|
);
|
|
313
343
|
}
|
|
314
344
|
const model = readRecipe(reader, node, found.path);
|
|
315
|
-
const parse = () =>
|
|
345
|
+
const parse = () => chunkISRDJR2O_cjs.parseRecipeWith(model, chunkISRDJR2O_cjs.parseIngredientLine);
|
|
316
346
|
let result = parse();
|
|
317
347
|
const dropped = [];
|
|
318
348
|
if (!result.success) {
|
|
349
|
+
const targets = [];
|
|
319
350
|
for (const error of result.error.issues) {
|
|
320
351
|
const target = error.severity === "error" ? droppableAt(reader, error.path) : void 0;
|
|
321
352
|
if (target) {
|
|
322
|
-
|
|
353
|
+
targets.push(target);
|
|
323
354
|
dropped.push({
|
|
324
355
|
...error,
|
|
325
356
|
severity: "warning",
|
|
@@ -327,12 +358,13 @@ function fromJsonLd(input) {
|
|
|
327
358
|
});
|
|
328
359
|
}
|
|
329
360
|
}
|
|
361
|
+
targets.sort((a, b) => b.length - a.length).forEach((target) => remove(model, target));
|
|
330
362
|
if (dropped.length > 0) {
|
|
331
363
|
result = parse();
|
|
332
364
|
}
|
|
333
365
|
}
|
|
334
366
|
const order = ({ code, path }) => [
|
|
335
|
-
READ_FIELDS.indexOf(String(path[found.path.length])),
|
|
367
|
+
path.length > found.path.length ? READ_FIELDS.indexOf(String(path[found.path.length])) : -1,
|
|
336
368
|
...path.slice(found.path.length + 1).filter((key) => typeof key === "number"),
|
|
337
369
|
...code === "unknown_field" ? [Infinity] : []
|
|
338
370
|
];
|
|
@@ -343,18 +375,50 @@ function fromJsonLd(input) {
|
|
|
343
375
|
...result.success ? result.warnings : result.error.issues
|
|
344
376
|
].map((issue2) => ({ ...issue2, path: sourceOf(reader, issue2.path) }))
|
|
345
377
|
].sort((a, b) => compareOrder(order(a), order(b)));
|
|
378
|
+
const checked = /* @__PURE__ */ new Map();
|
|
379
|
+
const extra = Object.fromEntries(
|
|
380
|
+
Object.entries(node).filter(([key, value]) => {
|
|
381
|
+
if (READ_FIELDS.includes(key)) {
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
const path = [...found.path, key];
|
|
385
|
+
if (tooDeep(value, path.length, checked)) {
|
|
386
|
+
chunkISRDJR2O_cjs.warning(
|
|
387
|
+
issues,
|
|
388
|
+
"invalid_type",
|
|
389
|
+
path,
|
|
390
|
+
`Expected a value to keep in extra, received ${chunkISRDJR2O_cjs.describeValue(value)} nested more than ${MAX_DEPTH} levels deep. It is ignored.`
|
|
391
|
+
);
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
return true;
|
|
395
|
+
})
|
|
396
|
+
);
|
|
346
397
|
return {
|
|
347
|
-
...
|
|
398
|
+
...chunkISRDJR2O_cjs.toResult(
|
|
348
399
|
"invalid_recipe",
|
|
349
400
|
result.success ? result.data : void 0,
|
|
350
401
|
issues,
|
|
351
|
-
typeof name === "string" ?
|
|
402
|
+
typeof name === "string" ? chunkISRDJR2O_cjs.quote(name) : void 0
|
|
352
403
|
),
|
|
353
|
-
extra
|
|
354
|
-
Object.entries(node).filter(([key]) => !READ_FIELDS.includes(key))
|
|
355
|
-
)
|
|
404
|
+
extra
|
|
356
405
|
};
|
|
357
406
|
}
|
|
407
|
+
function tooDeep(value, length, checked) {
|
|
408
|
+
if (length > MAX_DEPTH) {
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
if (typeof value !== "object" || value === null || (checked.get(value) ?? 0) >= length) {
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
const deep = Object.values(value).some(
|
|
415
|
+
(child) => tooDeep(child, length + 1, checked)
|
|
416
|
+
);
|
|
417
|
+
if (!deep) {
|
|
418
|
+
checked.set(value, length);
|
|
419
|
+
}
|
|
420
|
+
return deep;
|
|
421
|
+
}
|
|
358
422
|
function readRecipe(reader, node, base) {
|
|
359
423
|
const at = (...path) => [...base, ...path];
|
|
360
424
|
const model = {
|
|
@@ -371,7 +435,8 @@ function readRecipe(reader, node, base) {
|
|
|
371
435
|
}
|
|
372
436
|
readYield(reader, model, node.recipeYield, at("recipeYield"));
|
|
373
437
|
const times = {};
|
|
374
|
-
for (const [
|
|
438
|
+
for (const key of ["prep", "cook", "total"]) {
|
|
439
|
+
const field = `${key}Time`;
|
|
375
440
|
const minutes = readTime(reader, node[field], at(field));
|
|
376
441
|
if (minutes !== void 0) {
|
|
377
442
|
times[key] = minutes;
|
|
@@ -402,104 +467,132 @@ function readImage(reader, value, source) {
|
|
|
402
467
|
if (isAbsent(value)) {
|
|
403
468
|
return void 0;
|
|
404
469
|
}
|
|
405
|
-
const warnings = reader.warnings.length;
|
|
406
|
-
reader.repeated = false;
|
|
470
|
+
const warnings = reader.warnings.length + reader.repeated;
|
|
407
471
|
const image = findImage(reader, value, source);
|
|
408
|
-
if (!image &&
|
|
472
|
+
if (!image && reader.warnings.length + reader.repeated === warnings) {
|
|
409
473
|
ignore(
|
|
410
474
|
reader,
|
|
411
475
|
"invalid_type",
|
|
412
476
|
source,
|
|
413
|
-
`Expected an image URL, an ImageObject with a url, or a list of them, received ${
|
|
477
|
+
`Expected an image URL, an ImageObject with a url, or a list of them, received ${chunkISRDJR2O_cjs.describeValue(value)}.`
|
|
414
478
|
);
|
|
415
479
|
}
|
|
416
480
|
return image;
|
|
417
481
|
}
|
|
418
482
|
function findImage(reader, value, source, referenced = false) {
|
|
483
|
+
reader.deepest = Math.max(reader.deepest, source.length);
|
|
484
|
+
if (source.length > MAX_DEPTH) {
|
|
485
|
+
if (!isAbsent(value)) {
|
|
486
|
+
ignore(
|
|
487
|
+
reader,
|
|
488
|
+
"invalid_type",
|
|
489
|
+
source,
|
|
490
|
+
`Expected an image URL, an ImageObject with a url, or a list of them, received ${chunkISRDJR2O_cjs.describeValue(value)} nested more than ${MAX_DEPTH} levels deep.`
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
return void 0;
|
|
494
|
+
}
|
|
419
495
|
if (typeof value === "string") {
|
|
420
496
|
const url = cleanText(value);
|
|
421
|
-
const scheme =
|
|
497
|
+
const scheme = chunkISRDJR2O_cjs.disallowedScheme(url);
|
|
422
498
|
if (scheme) {
|
|
423
499
|
ignore(
|
|
424
500
|
reader,
|
|
425
501
|
"invalid_url",
|
|
426
502
|
source,
|
|
427
|
-
`Expected an http or https URL, or a relative one, received ${
|
|
503
|
+
`Expected an http or https URL, or a relative one, received ${chunkISRDJR2O_cjs.quote(`${scheme}\u2026`)}.`
|
|
504
|
+
);
|
|
505
|
+
return void 0;
|
|
506
|
+
}
|
|
507
|
+
if (url.length > MAX_URL_LENGTH) {
|
|
508
|
+
ignore(
|
|
509
|
+
reader,
|
|
510
|
+
"invalid_url",
|
|
511
|
+
source,
|
|
512
|
+
`Expected a URL of at most ${MAX_URL_LENGTH} UTF-16 code units, received ${url.length}.`
|
|
428
513
|
);
|
|
429
514
|
return void 0;
|
|
430
515
|
}
|
|
431
516
|
return url ? { url, source } : void 0;
|
|
432
517
|
}
|
|
433
|
-
if (source.length > MAX_DEPTH) {
|
|
434
|
-
return void 0;
|
|
435
|
-
}
|
|
436
518
|
if (Array.isArray(value)) {
|
|
437
|
-
for (const [
|
|
438
|
-
const image2 = findImage(reader, entry,
|
|
519
|
+
for (const [entry, entrySource] of entriesOf(value, source)) {
|
|
520
|
+
const image2 = findImage(reader, entry, entrySource, referenced);
|
|
439
521
|
if (image2) {
|
|
440
522
|
return image2;
|
|
441
523
|
}
|
|
442
524
|
}
|
|
443
525
|
return void 0;
|
|
444
526
|
}
|
|
445
|
-
const
|
|
527
|
+
const images = reader.images[referenced ? 1 : 0];
|
|
528
|
+
const reads = images.get(value) ?? [];
|
|
529
|
+
const read = reads.find(
|
|
530
|
+
([, , depth, length]) => length === source.length || Math.max(length, source.length) + depth <= MAX_DEPTH
|
|
531
|
+
);
|
|
532
|
+
if (read) {
|
|
533
|
+
reader.repeated += read[1];
|
|
534
|
+
reader.deepest = Math.max(reader.deepest, source.length + read[2]);
|
|
535
|
+
return read[0];
|
|
536
|
+
}
|
|
537
|
+
const record = chunkISRDJR2O_cjs.asRecord(value);
|
|
446
538
|
if (!record) {
|
|
447
539
|
return void 0;
|
|
448
540
|
}
|
|
541
|
+
images.set(value, reads);
|
|
542
|
+
const warnings = reader.warnings.length + reader.repeated;
|
|
543
|
+
const deepest = reader.deepest;
|
|
544
|
+
reader.deepest = source.length;
|
|
449
545
|
const id = record["@id"];
|
|
450
546
|
const target = typeof id === "string" && !referenced ? reader.ids.get(id) : void 0;
|
|
451
|
-
|
|
452
|
-
if (image
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
}
|
|
464
|
-
let read = reader.images.get(target);
|
|
465
|
-
if (!read) {
|
|
466
|
-
const warnings = reader.warnings.length;
|
|
467
|
-
const found = findImage(reader, target.node, target.path, true);
|
|
468
|
-
read = [found, reader.warnings.length > warnings];
|
|
469
|
-
reader.images.set(target, read);
|
|
470
|
-
} else if (read[1]) {
|
|
471
|
-
reader.repeated = true;
|
|
547
|
+
let image = findImage(reader, record.url, [...source, "url"], referenced) ?? findImage(reader, record.contentUrl, [...source, "contentUrl"], referenced);
|
|
548
|
+
if (!image && target) {
|
|
549
|
+
if (target.node === reader.recipe) {
|
|
550
|
+
ignore(
|
|
551
|
+
reader,
|
|
552
|
+
"invalid_type",
|
|
553
|
+
source,
|
|
554
|
+
"Expected an image URL, an ImageObject with a url, or a list of them, received a reference to the recipe itself."
|
|
555
|
+
);
|
|
556
|
+
} else {
|
|
557
|
+
image = findImage(reader, target.node, target.path, true);
|
|
558
|
+
}
|
|
472
559
|
}
|
|
473
|
-
|
|
560
|
+
reads.push([
|
|
561
|
+
image,
|
|
562
|
+
reader.warnings.length + reader.repeated - warnings,
|
|
563
|
+
reader.deepest - source.length,
|
|
564
|
+
source.length
|
|
565
|
+
]);
|
|
566
|
+
reader.deepest = Math.max(reader.deepest, deepest);
|
|
567
|
+
return image;
|
|
474
568
|
}
|
|
475
569
|
function readYield(reader, model, value, source) {
|
|
476
|
-
const
|
|
477
|
-
const batches = entries.flatMap(
|
|
570
|
+
const batches = entriesOf(value, source).flatMap(
|
|
478
571
|
([entry, entrySource]) => (typeof entry === "string" ? entry.split(/,\s+/) : [entry]).map(
|
|
479
572
|
(part) => readBatch(reader, part, entrySource)
|
|
480
573
|
)
|
|
481
574
|
).filter((batch) => batch !== void 0);
|
|
482
575
|
const yields = batches.filter((batch) => batch.yield !== void 0);
|
|
483
576
|
const servings = batches.filter((batch) => batch.servings !== void 0);
|
|
484
|
-
const kept = yields.find((batch) => !batch.article) ?? yields
|
|
577
|
+
const kept = yields.find((batch) => !batch.article) ?? yields.find((batch) => batch.article);
|
|
485
578
|
const keptServings = servings.find((batch) => batch.worded) ?? servings.find((batch) => batch.amount !== kept?.amount);
|
|
486
579
|
for (const batch of servings) {
|
|
487
580
|
if (keptServings && batch.amount !== keptServings.amount && (batch.worded || batch.amount !== kept?.amount)) {
|
|
488
|
-
|
|
581
|
+
chunkISRDJR2O_cjs.warning(
|
|
489
582
|
reader.warnings,
|
|
490
583
|
"ignored_value",
|
|
491
584
|
batch.source,
|
|
492
|
-
`Only one number of servings is read, ${
|
|
585
|
+
`Only one number of servings is read, ${chunkISRDJR2O_cjs.quote(keptServings.label)}, so this one is ignored.`
|
|
493
586
|
);
|
|
494
587
|
}
|
|
495
588
|
}
|
|
496
589
|
for (const batch of yields) {
|
|
497
590
|
if (batch !== kept) {
|
|
498
|
-
|
|
591
|
+
chunkISRDJR2O_cjs.warning(
|
|
499
592
|
reader.warnings,
|
|
500
593
|
"ignored_value",
|
|
501
594
|
batch.source,
|
|
502
|
-
`Only one yield is read, ${
|
|
595
|
+
`Only one yield is read, ${chunkISRDJR2O_cjs.quote(kept.label)}, so this one is ignored.`
|
|
503
596
|
);
|
|
504
597
|
}
|
|
505
598
|
}
|
|
@@ -525,13 +618,13 @@ function readBatch(reader, value, source) {
|
|
|
525
618
|
/^(?:(?:serves|servings?|yields?|makes)\s*:?\s*)?(?:about\s+)?/i,
|
|
526
619
|
""
|
|
527
620
|
);
|
|
528
|
-
const match =
|
|
621
|
+
const match = chunkISRDJR2O_cjs.matchAmount(text2);
|
|
529
622
|
if (!match || "code" in match) {
|
|
530
623
|
ignore(
|
|
531
624
|
reader,
|
|
532
625
|
match?.code ?? "invalid_quantity",
|
|
533
626
|
source,
|
|
534
|
-
match?.message ?? `Expected a batch such as "24 cookies" or "3\u20134 loaves", received ${
|
|
627
|
+
match?.message ?? `Expected a batch such as "24 cookies" or "3\u20134 loaves", received ${chunkISRDJR2O_cjs.describeValue(label)}.`
|
|
535
628
|
);
|
|
536
629
|
return void 0;
|
|
537
630
|
}
|
|
@@ -539,7 +632,7 @@ function readBatch(reader, value, source) {
|
|
|
539
632
|
const rest = match.rest.trim();
|
|
540
633
|
return !rest || SERVINGS_WORD.test(rest) ? { source, label, amount: amount2, servings: match.amountText, worded: !!rest } : { source, label, amount: amount2, yield: text2, article: /^an?\s/i.test(text2) };
|
|
541
634
|
}
|
|
542
|
-
const record =
|
|
635
|
+
const record = chunkISRDJR2O_cjs.asRecord(value);
|
|
543
636
|
const amount = toNumber(record?.value ?? record?.minValue);
|
|
544
637
|
if (record && amount !== void 0) {
|
|
545
638
|
const max = toNumber(record.maxValue);
|
|
@@ -548,7 +641,7 @@ function readBatch(reader, value, source) {
|
|
|
548
641
|
amount,
|
|
549
642
|
...max !== void 0 && max !== amount && { max }
|
|
550
643
|
};
|
|
551
|
-
const label = `${amount}${
|
|
644
|
+
const label = `${amount}${max !== amount && max ? `\u2013${max}` : ""}${unit && ` ${unit}`}`;
|
|
552
645
|
return !unit || SERVINGS_WORD.test(unit) ? { source, label, amount, servings: range, worded: !!unit } : { source, label, amount, yield: { ...range, unit } };
|
|
553
646
|
}
|
|
554
647
|
if (!isAbsent(value)) {
|
|
@@ -556,7 +649,7 @@ function readBatch(reader, value, source) {
|
|
|
556
649
|
reader,
|
|
557
650
|
"invalid_type",
|
|
558
651
|
source,
|
|
559
|
-
`Expected a yield such as "4 servings" or "24 cookies", received ${
|
|
652
|
+
`Expected a yield such as "4 servings" or "24 cookies", received ${chunkISRDJR2O_cjs.describeValue(value)}.`
|
|
560
653
|
);
|
|
561
654
|
}
|
|
562
655
|
return void 0;
|
|
@@ -565,13 +658,13 @@ function readTime(reader, value, source) {
|
|
|
565
658
|
if (isAbsent(value)) {
|
|
566
659
|
return void 0;
|
|
567
660
|
}
|
|
568
|
-
const minutes = typeof value === "string" ?
|
|
661
|
+
const minutes = typeof value === "string" ? chunkISRDJR2O_cjs.parseIsoDuration(cleanText(value)) : void 0;
|
|
569
662
|
if (minutes === void 0 || minutes > Number.MAX_SAFE_INTEGER) {
|
|
570
663
|
ignore(
|
|
571
664
|
reader,
|
|
572
665
|
"invalid_duration",
|
|
573
666
|
source,
|
|
574
|
-
`Expected an ISO 8601 duration such as "PT30M", received ${
|
|
667
|
+
`Expected an ISO 8601 duration such as "PT30M", received ${chunkISRDJR2O_cjs.describeValue(value)}${minutes === void 0 ? "" : ", which is too long"}.`
|
|
575
668
|
);
|
|
576
669
|
return void 0;
|
|
577
670
|
}
|
|
@@ -589,24 +682,26 @@ function readList(reader, key, value, source, readItem, expected) {
|
|
|
589
682
|
reader,
|
|
590
683
|
"invalid_type",
|
|
591
684
|
entrySource,
|
|
592
|
-
`Expected ${expected}, received ${
|
|
685
|
+
`Expected ${expected}, received ${chunkISRDJR2O_cjs.describeValue(entry)} nested more than ${MAX_DEPTH} levels deep.`
|
|
593
686
|
);
|
|
594
687
|
return;
|
|
595
688
|
}
|
|
596
689
|
if (Array.isArray(entry)) {
|
|
597
|
-
const
|
|
598
|
-
|
|
690
|
+
const elements2 = entriesOf(entry, entrySource);
|
|
691
|
+
const positions = elements2.map(
|
|
692
|
+
([element]) => toNumber(chunkISRDJR2O_cjs.asRecord(element)?.position)
|
|
599
693
|
);
|
|
600
|
-
const order = [...
|
|
694
|
+
const order = [...elements2.keys()];
|
|
601
695
|
if (!positions.includes(void 0)) {
|
|
602
696
|
order.sort((a, b) => positions[a] - positions[b]);
|
|
603
697
|
}
|
|
604
698
|
for (const i of order) {
|
|
605
|
-
|
|
699
|
+
const [element, elementSource] = elements2[i];
|
|
700
|
+
add(items, path, element, elementSource, inSection);
|
|
606
701
|
}
|
|
607
702
|
return;
|
|
608
703
|
}
|
|
609
|
-
const record =
|
|
704
|
+
const record = chunkISRDJR2O_cjs.asRecord(entry);
|
|
610
705
|
const elements = [...entrySource, "itemListElement"];
|
|
611
706
|
if (record?.itemListElement !== void 0 && record.text === void 0) {
|
|
612
707
|
const title = typeof record.name === "string" ? cleanText(record.name) : "";
|
|
@@ -628,13 +723,17 @@ function readList(reader, key, value, source, readItem, expected) {
|
|
|
628
723
|
}
|
|
629
724
|
return;
|
|
630
725
|
}
|
|
726
|
+
if (record && !isAbsent(record.item)) {
|
|
727
|
+
add(items, path, record.item, [...entrySource, "item"], inSection);
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
631
730
|
const read = readItem(reader, entry, entrySource);
|
|
632
731
|
if (!read) {
|
|
633
732
|
ignore(
|
|
634
733
|
reader,
|
|
635
734
|
"invalid_type",
|
|
636
735
|
entrySource,
|
|
637
|
-
`Expected ${expected}, received ${
|
|
736
|
+
`Expected ${expected}, received ${chunkISRDJR2O_cjs.describeValue(entry)}.`
|
|
638
737
|
);
|
|
639
738
|
return;
|
|
640
739
|
}
|
|
@@ -642,7 +741,7 @@ function readList(reader, key, value, source, readItem, expected) {
|
|
|
642
741
|
const itemPath = [...path, items.length];
|
|
643
742
|
items.push(item.value);
|
|
644
743
|
link(reader, itemPath, item.source, true);
|
|
645
|
-
for (const [field, fieldSource, droppable] of item.fields
|
|
744
|
+
for (const [field, fieldSource, droppable] of item.fields) {
|
|
646
745
|
link(reader, [...itemPath, field], fieldSource, droppable);
|
|
647
746
|
}
|
|
648
747
|
}
|
|
@@ -651,27 +750,24 @@ function readList(reader, key, value, source, readItem, expected) {
|
|
|
651
750
|
return list;
|
|
652
751
|
}
|
|
653
752
|
function readLine(reader, value, source) {
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
return readLine(reader, record.item, [...source, "item"]);
|
|
660
|
-
}
|
|
661
|
-
const parts = [record?.value, record?.unitText, record?.name ?? record?.text].filter((part) => typeof part === "string" || typeof part === "number").join(" ");
|
|
662
|
-
return parts ? cleanLines(parts).map((line) => ({ value: line, source })) : void 0;
|
|
753
|
+
const record = chunkISRDJR2O_cjs.asRecord(value);
|
|
754
|
+
const parts = typeof value === "string" ? value : [record?.value, record?.unitText, record?.name ?? record?.text].filter(
|
|
755
|
+
(part) => typeof part === "string" || typeof part === "number"
|
|
756
|
+
).join(" ");
|
|
757
|
+
return parts ? cleanLines(parts).map((line) => ({ value: line, source, fields: [] })) : void 0;
|
|
663
758
|
}
|
|
664
759
|
function readStep(reader, value, source) {
|
|
665
760
|
if (typeof value === "string") {
|
|
666
|
-
return cleanLines(value).map((line) => ({
|
|
761
|
+
return cleanLines(value).map((line) => ({
|
|
762
|
+
value: line,
|
|
763
|
+
source,
|
|
764
|
+
fields: []
|
|
765
|
+
}));
|
|
667
766
|
}
|
|
668
|
-
const record =
|
|
767
|
+
const record = chunkISRDJR2O_cjs.asRecord(value);
|
|
669
768
|
if (!record) {
|
|
670
769
|
return void 0;
|
|
671
770
|
}
|
|
672
|
-
if (record.item !== void 0 && source.length < MAX_DEPTH) {
|
|
673
|
-
return readStep(reader, record.item, [...source, "item"]);
|
|
674
|
-
}
|
|
675
771
|
const name = typeof record.name === "string" ? cleanText(record.name) : "";
|
|
676
772
|
const body = text(record.text) ?? name;
|
|
677
773
|
const image = readImage(reader, record.image, [...source, "image"]);
|
|
@@ -696,16 +792,15 @@ function readStep(reader, value, source) {
|
|
|
696
792
|
];
|
|
697
793
|
}
|
|
698
794
|
function readTools(reader, value, source) {
|
|
699
|
-
const entries = Array.isArray(value) ? value.map((entry, i) => [entry, [...source, i]]) : [[value, source]];
|
|
700
795
|
const equipment = [];
|
|
701
796
|
link(reader, ["equipment"], source);
|
|
702
|
-
for (const [entry, entrySource] of
|
|
703
|
-
const record =
|
|
797
|
+
for (const [entry, entrySource] of entriesOf(value, source)) {
|
|
798
|
+
const record = chunkISRDJR2O_cjs.asRecord(entry);
|
|
704
799
|
const item = record ? {
|
|
705
800
|
name: text(record.name),
|
|
706
801
|
...record.requiredQuantity !== void 0 && {
|
|
707
802
|
quantity: toNumber(
|
|
708
|
-
|
|
803
|
+
chunkISRDJR2O_cjs.asRecord(record.requiredQuantity)?.value ?? record.requiredQuantity
|
|
709
804
|
) ?? record.requiredQuantity
|
|
710
805
|
},
|
|
711
806
|
...record.url !== void 0 && { url: text(record.url) }
|
|
@@ -732,13 +827,13 @@ function readNutrition(reader, value, source) {
|
|
|
732
827
|
if (isAbsent(value)) {
|
|
733
828
|
return void 0;
|
|
734
829
|
}
|
|
735
|
-
const record =
|
|
830
|
+
const record = chunkISRDJR2O_cjs.asRecord(value);
|
|
736
831
|
if (!record) {
|
|
737
832
|
ignore(
|
|
738
833
|
reader,
|
|
739
834
|
"invalid_type",
|
|
740
835
|
source,
|
|
741
|
-
`Expected NutritionInformation, such as { "calories": "250 kcal" }, received ${
|
|
836
|
+
`Expected NutritionInformation, such as { "calories": "250 kcal" }, received ${chunkISRDJR2O_cjs.describeValue(value)}.`
|
|
742
837
|
);
|
|
743
838
|
return void 0;
|
|
744
839
|
}
|
|
@@ -766,7 +861,7 @@ function isAbsent(value) {
|
|
|
766
861
|
return value === void 0 || value === null || typeof value === "string" && !value.trim();
|
|
767
862
|
}
|
|
768
863
|
function ignore(reader, code, path, message) {
|
|
769
|
-
|
|
864
|
+
chunkISRDJR2O_cjs.warning(reader.warnings, code, path, `${message} It is ignored.`);
|
|
770
865
|
}
|
|
771
866
|
function link(reader, path, source, droppable = false) {
|
|
772
867
|
const key = JSON.stringify(path);
|
|
@@ -786,10 +881,10 @@ function sourceOf(reader, path) {
|
|
|
786
881
|
}
|
|
787
882
|
function compareOrder(a, b) {
|
|
788
883
|
for (const [i, n] of a.entries()) {
|
|
789
|
-
|
|
790
|
-
if (m === void 0) {
|
|
884
|
+
if (i === b.length) {
|
|
791
885
|
return 1;
|
|
792
886
|
}
|
|
887
|
+
const m = b[i];
|
|
793
888
|
if (n !== m) {
|
|
794
889
|
return n - m;
|
|
795
890
|
}
|
|
@@ -818,18 +913,28 @@ function remove(model, path) {
|
|
|
818
913
|
// src/schema-org/to-json-ld.ts
|
|
819
914
|
function toJsonLd(recipe, options) {
|
|
820
915
|
const { servings, system, url, extra } = options ?? {};
|
|
821
|
-
const resolved =
|
|
822
|
-
const page = typeof url === "string" ?
|
|
916
|
+
const resolved = chunkISRDJR2O_cjs.resolveRecipe(recipe, { servings, system });
|
|
917
|
+
const page = typeof url === "string" ? url.replace(/#.*/s, "") : void 0;
|
|
823
918
|
const yields = [
|
|
824
919
|
...resolved.servings ? servingsText(resolved.servings) : [],
|
|
825
|
-
...resolved.yield ? [
|
|
920
|
+
...resolved.yield ? [chunkISRDJR2O_cjs.formatYield(resolved.yield, { fractions: false })] : []
|
|
826
921
|
];
|
|
827
922
|
const ingredients = resolved.ingredients.flatMap(
|
|
828
923
|
({ items }) => items.map((item) => ingredientLine(item, resolved.scale, resolved.system))
|
|
829
924
|
);
|
|
830
925
|
const steps = resolved.steps.flatMap(
|
|
831
926
|
({ title, items }) => {
|
|
832
|
-
const howToSteps = items.map((step) =>
|
|
927
|
+
const howToSteps = items.map((step) => ({
|
|
928
|
+
"@type": "HowToStep",
|
|
929
|
+
...step.name !== void 0 && { name: step.name },
|
|
930
|
+
text: step.text,
|
|
931
|
+
...step.image !== void 0 && { image: step.image },
|
|
932
|
+
...page !== void 0 && {
|
|
933
|
+
// encodeURIComponent throws on a lone surrogate. With the u flag,
|
|
934
|
+
// \p{Cs} matches only those, as a pair reads as one code point.
|
|
935
|
+
url: `${page}#${encodeURIComponent(step.id.replace(/\p{Cs}/gu, "\uFFFD"))}`
|
|
936
|
+
}
|
|
937
|
+
}));
|
|
833
938
|
return title === void 0 || howToSteps.length === 0 ? howToSteps : [
|
|
834
939
|
{
|
|
835
940
|
"@type": "HowToSection",
|
|
@@ -861,13 +966,13 @@ function toJsonLd(recipe, options) {
|
|
|
861
966
|
const data = {
|
|
862
967
|
...written,
|
|
863
968
|
...Object.fromEntries(
|
|
864
|
-
Object.entries(
|
|
865
|
-
([field, value]) => value !== void 0 && !
|
|
969
|
+
Object.entries(chunkISRDJR2O_cjs.isRecord(extra) ? extra : {}).filter(
|
|
970
|
+
([field, value]) => value !== void 0 && !chunkISRDJR2O_cjs.hasOwn(written, field)
|
|
866
971
|
)
|
|
867
972
|
)
|
|
868
973
|
};
|
|
869
974
|
if (data.image === void 0) {
|
|
870
|
-
|
|
975
|
+
chunkISRDJR2O_cjs.warning(
|
|
871
976
|
warnings,
|
|
872
977
|
"missing_field",
|
|
873
978
|
["image"],
|
|
@@ -875,7 +980,7 @@ function toJsonLd(recipe, options) {
|
|
|
875
980
|
);
|
|
876
981
|
}
|
|
877
982
|
if (data.nutrition !== void 0 && data.recipeYield === void 0) {
|
|
878
|
-
|
|
983
|
+
chunkISRDJR2O_cjs.warning(
|
|
879
984
|
warnings,
|
|
880
985
|
"missing_field",
|
|
881
986
|
["recipeYield"],
|
|
@@ -885,45 +990,32 @@ function toJsonLd(recipe, options) {
|
|
|
885
990
|
return { data, warnings };
|
|
886
991
|
}
|
|
887
992
|
function servingsText(servings) {
|
|
888
|
-
const amount =
|
|
993
|
+
const amount = chunkISRDJR2O_cjs.formatServings(servings, { fractions: false });
|
|
889
994
|
const word = servings.amount === 1 && servings.max === void 0 ? "serving" : "servings";
|
|
890
995
|
return [amount, `${amount} ${word}`];
|
|
891
996
|
}
|
|
892
997
|
function ingredientLine(item, scale, system) {
|
|
893
998
|
const { ingredient, origin } = item;
|
|
894
|
-
const { quantity, name, note } =
|
|
999
|
+
const { quantity, name, note } = chunkISRDJR2O_cjs.formatIngredient(item);
|
|
895
1000
|
const authored = ingredient.quantity ? [ingredient.quantity, ...ingredient.equivalents] : [];
|
|
896
|
-
const shown = origin === "authored" ? 0 : origin === "equivalent" ? 1 + ingredient.equivalents.findIndex((q) =>
|
|
897
|
-
const alternatives = authored.filter((_, i) => i !== shown).map((q) =>
|
|
1001
|
+
const shown = origin === "authored" ? 0 : origin === "equivalent" ? 1 + ingredient.equivalents.findIndex((q) => chunkISRDJR2O_cjs.isNative(q, system)) : -1;
|
|
1002
|
+
const alternatives = authored.filter((_, i) => i !== shown).map((q) => chunkISRDJR2O_cjs.formatQuantity(scale === 1 ? q : chunkISRDJR2O_cjs.multiply(q, scale))).join("; ");
|
|
898
1003
|
const inParentheses = alternatives && ` (${alternatives})`;
|
|
899
1004
|
const head = quantity === void 0 ? name : item.quantity?.unit === void 0 ? `${quantity} ${name}${inParentheses}` : `${quantity}${inParentheses} ${name}`;
|
|
900
1005
|
return plainSpaces(
|
|
901
1006
|
`${head}${note ? `, ${note}` : ""}${ingredient.optional ? " (optional)" : ""}`
|
|
902
1007
|
);
|
|
903
1008
|
}
|
|
904
|
-
function howToStep(step, page) {
|
|
905
|
-
return {
|
|
906
|
-
"@type": "HowToStep",
|
|
907
|
-
...step.name !== void 0 && { name: step.name },
|
|
908
|
-
text: step.text,
|
|
909
|
-
...step.image !== void 0 && { image: step.image },
|
|
910
|
-
...page !== void 0 && {
|
|
911
|
-
// encodeURIComponent throws on a lone surrogate. With the u flag,
|
|
912
|
-
// \p{Cs} matches only those, as a pair reads as one code point.
|
|
913
|
-
url: `${page}#${encodeURIComponent(step.id.replace(/\p{Cs}/gu, "\uFFFD"))}`
|
|
914
|
-
}
|
|
915
|
-
};
|
|
916
|
-
}
|
|
917
1009
|
function duration(warnings, key, minutes) {
|
|
918
1010
|
if (minutes === void 0) {
|
|
919
1011
|
return {};
|
|
920
1012
|
}
|
|
921
1013
|
if (Number.isNaN(minutes) || minutes > Number.MAX_SAFE_INTEGER) {
|
|
922
|
-
|
|
1014
|
+
chunkISRDJR2O_cjs.warning(
|
|
923
1015
|
warnings,
|
|
924
1016
|
"invalid_duration",
|
|
925
1017
|
["times", key],
|
|
926
|
-
`Expected minutes such as 30, received ${
|
|
1018
|
+
`Expected minutes such as 30, received ${chunkISRDJR2O_cjs.describeValue(minutes)}${Number.isNaN(minutes) ? "" : ", which is too long"}. It is ignored.`
|
|
927
1019
|
);
|
|
928
1020
|
return {};
|
|
929
1021
|
}
|
|
@@ -947,7 +1039,7 @@ function nutritionInformation(nutrition) {
|
|
|
947
1039
|
for (const key of Object.keys(NUTRIENTS)) {
|
|
948
1040
|
const value = nutrition[key];
|
|
949
1041
|
if (value !== void 0) {
|
|
950
|
-
information[NUTRIENTS[key]] = typeof value === "string" ? value : `${
|
|
1042
|
+
information[NUTRIENTS[key]] = typeof value === "string" ? value : `${chunkISRDJR2O_cjs.round(value, 3)} ${chunkISRDJR2O_cjs.NUTRIENT_UNITS[key]}`;
|
|
951
1043
|
}
|
|
952
1044
|
}
|
|
953
1045
|
return information;
|