@unhead/schema-org 2.0.19 → 2.1.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.
Files changed (69) hide show
  1. package/dist/chunks/index.mjs +23 -0
  2. package/dist/chunks/index10.mjs +63 -0
  3. package/dist/chunks/index11.mjs +35 -0
  4. package/dist/chunks/index12.mjs +48 -0
  5. package/dist/chunks/index13.mjs +36 -0
  6. package/dist/chunks/index14.mjs +25 -0
  7. package/dist/chunks/index15.mjs +37 -0
  8. package/dist/chunks/index16.mjs +27 -0
  9. package/dist/chunks/index17.mjs +34 -0
  10. package/dist/chunks/index18.mjs +32 -0
  11. package/dist/chunks/index19.mjs +31 -0
  12. package/dist/chunks/index2.mjs +12 -0
  13. package/dist/chunks/index20.mjs +31 -0
  14. package/dist/chunks/index21.mjs +30 -0
  15. package/dist/chunks/index22.mjs +30 -0
  16. package/dist/chunks/index23.mjs +82 -0
  17. package/dist/chunks/index24.mjs +14 -0
  18. package/dist/chunks/index25.mjs +33 -0
  19. package/dist/chunks/index26.mjs +31 -0
  20. package/dist/chunks/index27.mjs +29 -0
  21. package/dist/chunks/index28.mjs +12 -0
  22. package/dist/chunks/index29.mjs +46 -0
  23. package/dist/chunks/index3.mjs +317 -0
  24. package/dist/chunks/index30.mjs +53 -0
  25. package/dist/chunks/index31.mjs +41 -0
  26. package/dist/chunks/index32.mjs +26 -0
  27. package/dist/chunks/index33.mjs +47 -0
  28. package/dist/chunks/index34.mjs +29 -0
  29. package/dist/chunks/index35.mjs +34 -0
  30. package/dist/chunks/index36.mjs +33 -0
  31. package/dist/chunks/index37.mjs +34 -0
  32. package/dist/chunks/index38.mjs +51 -0
  33. package/dist/chunks/index39.mjs +17 -0
  34. package/dist/chunks/index4.mjs +54 -0
  35. package/dist/chunks/index40.mjs +29 -0
  36. package/dist/chunks/index5.mjs +31 -0
  37. package/dist/chunks/index6.mjs +29 -0
  38. package/dist/chunks/index7.mjs +35 -0
  39. package/dist/chunks/index8.mjs +18 -0
  40. package/dist/chunks/index9.mjs +20 -0
  41. package/dist/index.d.mts +6 -11
  42. package/dist/index.d.ts +6 -11
  43. package/dist/index.mjs +43 -3
  44. package/dist/react.d.mts +3 -3
  45. package/dist/react.d.ts +3 -3
  46. package/dist/react.mjs +3 -5
  47. package/dist/shared/schema-org.40UJYB57.mjs +19 -0
  48. package/dist/shared/{schema-org.B3f2mYF6.d.ts → schema-org.BR4WcSqZ.d.ts} +3 -3
  49. package/dist/shared/schema-org.CAKsqzbX.d.ts +1022 -0
  50. package/dist/shared/{schema-org.D5CDiwX5.d.ts → schema-org.CFcsqFfN.d.mts} +215 -15
  51. package/dist/shared/{schema-org.D5CDiwX5.d.mts → schema-org.CFcsqFfN.d.ts} +215 -15
  52. package/dist/shared/{schema-org.q010LqYD.mjs → schema-org.CHbRCiep.mjs} +12 -0
  53. package/dist/shared/schema-org.Cp6bpwL2.mjs +875 -0
  54. package/dist/shared/schema-org.Dg61qWpa.mjs +27 -0
  55. package/dist/shared/schema-org.UT1u1UYq.d.mts +1022 -0
  56. package/dist/shared/{schema-org.jGJJYnRv.d.mts → schema-org.oFHFm6my.d.mts} +3 -3
  57. package/dist/solid-js.d.mts +3 -3
  58. package/dist/solid-js.d.ts +3 -3
  59. package/dist/solid-js.mjs +3 -5
  60. package/dist/svelte.d.mts +3 -3
  61. package/dist/svelte.d.ts +3 -3
  62. package/dist/svelte.mjs +3 -5
  63. package/dist/vue.d.mts +3 -3
  64. package/dist/vue.d.ts +3 -3
  65. package/dist/vue.mjs +6 -7
  66. package/package.json +12 -14
  67. package/dist/shared/schema-org.B8mOT8YC.d.ts +0 -44
  68. package/dist/shared/schema-org.CWjoIjIr.d.mts +0 -44
  69. package/dist/shared/schema-org.DoKdjnca.mjs +0 -1690
@@ -1,1690 +0,0 @@
1
- import { createDefu, defu } from 'defu';
2
- import { defineHeadPlugin, TemplateParamsPlugin } from 'unhead/plugins';
3
- import { processTemplateParams } from 'unhead/utils';
4
- import { hasProtocol, withBase, withoutTrailingSlash, hasTrailingSlash, withTrailingSlash, joinURL } from 'ufo';
5
- import { hash } from 'ohash';
6
-
7
- function defineSchemaOrgResolver(schema) {
8
- return schema;
9
- }
10
-
11
- function idReference(node) {
12
- return {
13
- "@id": typeof node !== "string" ? node["@id"] : node
14
- };
15
- }
16
- function resolvableDateToDate(val) {
17
- try {
18
- const date = val instanceof Date ? val : new Date(Date.parse(val));
19
- return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
20
- } catch {
21
- }
22
- return typeof val === "string" ? val : val.toString();
23
- }
24
- const IS_VALID_W3C_DATE = [
25
- /(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/,
26
- /^\d{4}-[01]\d-[0-3]\d$/,
27
- /^\d{4}-[01]\d$/,
28
- /^\d{4}$/
29
- ];
30
- function isValidW3CDate(d) {
31
- return IS_VALID_W3C_DATE.some((r) => r.test(d));
32
- }
33
- function resolvableDateToIso(val) {
34
- if (!val)
35
- return val;
36
- try {
37
- if (val instanceof Date)
38
- return val.toISOString();
39
- else if (isValidW3CDate(val))
40
- return val;
41
- else
42
- return new Date(Date.parse(val)).toISOString();
43
- } catch {
44
- }
45
- return typeof val === "string" ? val : val.toString();
46
- }
47
- const IdentityId = "#identity";
48
- function setIfEmpty(node, field, value) {
49
- if (!node?.[field] && value)
50
- node[field] = value;
51
- }
52
- function asArray(input) {
53
- return Array.isArray(input) ? input : [input];
54
- }
55
- function dedupeMerge(node, field, value) {
56
- const data = new Set(asArray(node[field]));
57
- data.add(value);
58
- node[field] = [...data].filter(Boolean);
59
- }
60
- function prefixId(url, id) {
61
- if (hasProtocol(id))
62
- return id;
63
- if (!id.includes("#"))
64
- id = `#${id}`;
65
- return `${url || ""}${id}`;
66
- }
67
- function trimLength(val, length) {
68
- if (!val)
69
- return val;
70
- if (val.length > length) {
71
- const trimmedString = val.substring(0, length);
72
- return trimmedString.substring(0, Math.min(trimmedString.length, trimmedString.lastIndexOf(" ")));
73
- }
74
- return val;
75
- }
76
- function resolveDefaultType(node, defaultType) {
77
- const val = node["@type"];
78
- if (val === defaultType)
79
- return;
80
- const types = /* @__PURE__ */ new Set([
81
- ...asArray(defaultType),
82
- ...asArray(val)
83
- ]);
84
- node["@type"] = types.size === 1 ? val : [...types.values()];
85
- }
86
- function resolveWithBase(base, urlOrPath) {
87
- if (!urlOrPath || hasProtocol(urlOrPath) || urlOrPath[0] !== "/" && urlOrPath[0] !== "#")
88
- return urlOrPath;
89
- return withBase(urlOrPath, base);
90
- }
91
- function resolveAsGraphKey(key) {
92
- if (!key)
93
- return key;
94
- return key.substring(key.lastIndexOf("#"));
95
- }
96
- function stripEmptyProperties(obj) {
97
- for (const k in obj) {
98
- if (!Object.prototype.hasOwnProperty.call(obj, k)) {
99
- continue;
100
- }
101
- if (obj[k] && typeof obj[k] === "object") {
102
- if (obj[k].__v_isReadonly || obj[k].__v_isRef)
103
- return;
104
- stripEmptyProperties(obj[k]);
105
- return;
106
- }
107
- if (obj[k] === "" || obj[k] === null || obj[k] === void 0)
108
- delete obj[k];
109
- }
110
- return obj;
111
- }
112
- function hashCode(s) {
113
- let h = 9;
114
- for (let i = 0; i < s.length; )
115
- h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9);
116
- return ((h ^ h >>> 9) + 65536).toString(16).substring(1, 8).toLowerCase();
117
- }
118
-
119
- const quantitativeValueResolver = defineSchemaOrgResolver({
120
- cast(node) {
121
- if (typeof node === "number") {
122
- return {
123
- value: node
124
- };
125
- }
126
- return node;
127
- },
128
- defaults: {
129
- "@type": "QuantitativeValue"
130
- }
131
- });
132
- const monetaryAmountResolver = defineSchemaOrgResolver({
133
- defaults: {
134
- "@type": "MonetaryAmount"
135
- },
136
- resolve(node, ctx) {
137
- if (typeof node.value !== "number")
138
- node.value = resolveRelation(node.value, ctx, quantitativeValueResolver);
139
- return node;
140
- }
141
- });
142
-
143
- const merchantReturnPolicyResolver = defineSchemaOrgResolver({
144
- defaults: {
145
- "@type": "MerchantReturnPolicy"
146
- },
147
- resolve(node, ctx) {
148
- if (node.returnPolicyCategory)
149
- node.returnPolicyCategory = withBase(node.returnPolicyCategory, "https://schema.org/");
150
- if (node.returnFees)
151
- node.returnFees = withBase(node.returnFees, "https://schema.org/");
152
- if (node.returnMethod)
153
- node.returnMethod = withBase(node.returnMethod, "https://schema.org/");
154
- node.returnShippingFeesAmount = resolveRelation(node.returnShippingFeesAmount, ctx, monetaryAmountResolver);
155
- return node;
156
- }
157
- });
158
-
159
- const definedRegionResolver = defineSchemaOrgResolver({
160
- defaults: {
161
- "@type": "DefinedRegion"
162
- }
163
- });
164
-
165
- const shippingDeliveryTimeResolver = defineSchemaOrgResolver({
166
- defaults: {
167
- "@type": "ShippingDeliveryTime"
168
- },
169
- resolve(node, ctx) {
170
- node.handlingTime = resolveRelation(node.handlingTime, ctx, quantitativeValueResolver);
171
- node.transitTime = resolveRelation(node.transitTime, ctx, quantitativeValueResolver);
172
- return node;
173
- }
174
- });
175
-
176
- const offerShippingDetailsResolver = defineSchemaOrgResolver({
177
- defaults: {
178
- "@type": "OfferShippingDetails"
179
- },
180
- resolve(node, ctx) {
181
- node.deliveryTime = resolveRelation(node.deliveryTime, ctx, shippingDeliveryTimeResolver);
182
- node.shippingDestination = resolveRelation(node.shippingDestination, ctx, definedRegionResolver);
183
- node.shippingRate = resolveRelation(node.shippingRate, ctx, monetaryAmountResolver);
184
- return node;
185
- }
186
- });
187
-
188
- const offerResolver = defineSchemaOrgResolver({
189
- cast(node) {
190
- if (typeof node === "number" || typeof node === "string") {
191
- return {
192
- price: node
193
- };
194
- }
195
- return node;
196
- },
197
- defaults: {
198
- "@type": "Offer",
199
- "availability": "InStock"
200
- },
201
- resolve(node, ctx) {
202
- setIfEmpty(node, "priceCurrency", ctx.meta.currency);
203
- setIfEmpty(node, "priceValidUntil", new Date(Date.UTC((/* @__PURE__ */ new Date()).getFullYear() + 1, 12, -1, 0, 0, 0)));
204
- if (node.url)
205
- resolveWithBase(ctx.meta.host, node.url);
206
- if (node.availability)
207
- node.availability = withBase(node.availability, "https://schema.org/");
208
- if (node.itemCondition)
209
- node.itemCondition = withBase(node.itemCondition, "https://schema.org/");
210
- if (node.priceValidUntil)
211
- node.priceValidUntil = resolvableDateToIso(node.priceValidUntil);
212
- node.hasMerchantReturnPolicy = resolveRelation(node.hasMerchantReturnPolicy, ctx, merchantReturnPolicyResolver);
213
- node.shippingDetails = resolveRelation(node.shippingDetails, ctx, offerShippingDetailsResolver);
214
- return node;
215
- }
216
- });
217
-
218
- const aggregateOfferResolver = defineSchemaOrgResolver({
219
- defaults: {
220
- "@type": "AggregateOffer"
221
- },
222
- inheritMeta: [
223
- { meta: "currency", key: "priceCurrency" }
224
- ],
225
- resolve(node, ctx) {
226
- node.offers = resolveRelation(node.offers, ctx, offerResolver);
227
- if (node.offers)
228
- setIfEmpty(node, "offerCount", asArray(node.offers).length);
229
- return node;
230
- }
231
- });
232
-
233
- const aggregateRatingResolver = defineSchemaOrgResolver({
234
- defaults: {
235
- "@type": "AggregateRating"
236
- }
237
- });
238
-
239
- const listItemResolver = defineSchemaOrgResolver({
240
- cast(node) {
241
- if (typeof node === "string") {
242
- node = {
243
- name: node
244
- };
245
- }
246
- return node;
247
- },
248
- defaults: {
249
- "@type": "ListItem"
250
- },
251
- resolve(node, ctx) {
252
- if (typeof node.item === "string")
253
- node.item = resolveWithBase(ctx.meta.host, node.item);
254
- else if (typeof node.item === "object")
255
- node.item = resolveRelation(node.item, ctx);
256
- return node;
257
- }
258
- });
259
-
260
- const PrimaryBreadcrumbId = "#breadcrumb";
261
- const breadcrumbResolver = defineSchemaOrgResolver({
262
- defaults: {
263
- "@type": "BreadcrumbList"
264
- },
265
- idPrefix: ["url", PrimaryBreadcrumbId],
266
- resolve(breadcrumb, ctx) {
267
- if (breadcrumb.itemListElement) {
268
- let index = 1;
269
- breadcrumb.itemListElement = resolveRelation(breadcrumb.itemListElement, ctx, listItemResolver, {
270
- array: true,
271
- afterResolve(node) {
272
- setIfEmpty(node, "position", index++);
273
- }
274
- });
275
- }
276
- return breadcrumb;
277
- },
278
- resolveRootNode(node, { find }) {
279
- const webPage = find(PrimaryWebPageId);
280
- if (webPage)
281
- setIfEmpty(webPage, "breadcrumb", idReference(node));
282
- }
283
- });
284
-
285
- const imageResolver = defineSchemaOrgResolver({
286
- alias: "image",
287
- cast(input) {
288
- if (typeof input === "string") {
289
- input = {
290
- url: input
291
- };
292
- }
293
- return input;
294
- },
295
- defaults: {
296
- "@type": "ImageObject"
297
- },
298
- inheritMeta: [
299
- // @todo possibly only do if there's a caption
300
- "inLanguage"
301
- ],
302
- idPrefix: "host",
303
- resolve(image, { meta }) {
304
- image.url = resolveWithBase(meta.host, image.url);
305
- setIfEmpty(image, "contentUrl", image.url);
306
- if (image.height && !image.width)
307
- delete image.height;
308
- if (image.width && !image.height)
309
- delete image.width;
310
- return image;
311
- }
312
- });
313
-
314
- const addressResolver = defineSchemaOrgResolver({
315
- defaults: {
316
- "@type": "PostalAddress"
317
- }
318
- });
319
-
320
- const searchActionResolver = defineSchemaOrgResolver({
321
- defaults: {
322
- "@type": "SearchAction",
323
- "target": {
324
- "@type": "EntryPoint"
325
- },
326
- "query-input": {
327
- "@type": "PropertyValueSpecification",
328
- "valueRequired": true,
329
- "valueName": "search_term_string"
330
- }
331
- },
332
- resolve(node, ctx) {
333
- if (typeof node.target === "string") {
334
- node.target = {
335
- "@type": "EntryPoint",
336
- "urlTemplate": resolveWithBase(ctx.meta.host, node.target)
337
- };
338
- }
339
- return node;
340
- }
341
- });
342
-
343
- const PrimaryWebSiteId = "#website";
344
- const webSiteResolver = defineSchemaOrgResolver({
345
- defaults: {
346
- "@type": "WebSite"
347
- },
348
- inheritMeta: [
349
- "inLanguage",
350
- { meta: "host", key: "url" }
351
- ],
352
- idPrefix: ["host", PrimaryWebSiteId],
353
- resolve(node, ctx) {
354
- node.potentialAction = resolveRelation(node.potentialAction, ctx, searchActionResolver, {
355
- array: true
356
- });
357
- node.publisher = resolveRelation(node.publisher, ctx);
358
- return node;
359
- },
360
- resolveRootNode(node, { find }) {
361
- if (resolveAsGraphKey(node["@id"]) === PrimaryWebSiteId) {
362
- const identity = find(IdentityId);
363
- if (identity)
364
- setIfEmpty(node, "publisher", idReference(identity));
365
- const webPage = find(PrimaryWebPageId);
366
- if (webPage)
367
- setIfEmpty(webPage, "isPartOf", idReference(node));
368
- }
369
- return node;
370
- }
371
- });
372
-
373
- const organizationResolver = defineSchemaOrgResolver({
374
- defaults: {
375
- "@type": "Organization"
376
- },
377
- idPrefix: ["host", IdentityId],
378
- inheritMeta: [
379
- { meta: "host", key: "url" }
380
- ],
381
- resolve(node, ctx) {
382
- resolveDefaultType(node, "Organization");
383
- node.address = resolveRelation(node.address, ctx, addressResolver);
384
- return node;
385
- },
386
- resolveRootNode(node, ctx) {
387
- const isIdentity = resolveAsGraphKey(node["@id"]) === IdentityId;
388
- const webPage = ctx.find(PrimaryWebPageId);
389
- if (node.logo && isIdentity) {
390
- if (!ctx.find("#organization")) {
391
- const logoNode = resolveRelation(node.logo, ctx, imageResolver, {
392
- root: true,
393
- afterResolve(logo) {
394
- logo["@id"] = prefixId(ctx.meta.host, "#logo");
395
- setIfEmpty(logo, "caption", node.name);
396
- }
397
- });
398
- if (webPage && logoNode)
399
- setIfEmpty(webPage, "primaryImageOfPage", idReference(logoNode));
400
- ctx.nodes.push({
401
- // we want to make a simple node that has the essentials, this will allow parent nodes to inject
402
- // as well without inserting invalid data (i.e LocalBusiness operatingHours)
403
- "@type": "Organization",
404
- "name": node.name,
405
- "url": node.url,
406
- "sameAs": node.sameAs,
407
- // 'image': idReference(logoNode),
408
- "address": node.address,
409
- // needs to be a URL
410
- "logo": resolveRelation(node.logo, ctx, imageResolver, { root: false }).url,
411
- "_priority": -1,
412
- "@id": prefixId(ctx.meta.host, "#organization")
413
- // avoid the id so nothing can link to it
414
- });
415
- }
416
- delete node.logo;
417
- }
418
- if (isIdentity && webPage)
419
- setIfEmpty(webPage, "about", idReference(node));
420
- const webSite = ctx.find(PrimaryWebSiteId);
421
- if (webSite)
422
- setIfEmpty(webSite, "publisher", idReference(node));
423
- }
424
- });
425
-
426
- const readActionResolver = defineSchemaOrgResolver({
427
- defaults: {
428
- "@type": "ReadAction"
429
- },
430
- resolve(node, ctx) {
431
- if (!node.target.includes(ctx.meta.url))
432
- node.target.unshift(ctx.meta.url);
433
- return node;
434
- }
435
- });
436
-
437
- const PrimaryWebPageId = "#webpage";
438
- const webPageResolver = defineSchemaOrgResolver({
439
- defaults({ meta }) {
440
- const endPath = withoutTrailingSlash(meta.url.substring(meta.url.lastIndexOf("/") + 1));
441
- let type = "WebPage";
442
- switch (endPath) {
443
- case "about":
444
- case "about-us":
445
- type = "AboutPage";
446
- break;
447
- case "search":
448
- type = "SearchResultsPage";
449
- break;
450
- case "checkout":
451
- type = "CheckoutPage";
452
- break;
453
- case "contact":
454
- case "get-in-touch":
455
- case "contact-us":
456
- type = "ContactPage";
457
- break;
458
- case "faq":
459
- type = "FAQPage";
460
- break;
461
- }
462
- const defaults = {
463
- "@type": type
464
- };
465
- return defaults;
466
- },
467
- idPrefix: ["url", PrimaryWebPageId],
468
- inheritMeta: [
469
- { meta: "title", key: "name" },
470
- "description",
471
- "datePublished",
472
- "dateModified",
473
- "url"
474
- ],
475
- resolve(node, ctx) {
476
- node.dateModified = resolvableDateToIso(node.dateModified);
477
- node.datePublished = resolvableDateToIso(node.datePublished);
478
- resolveDefaultType(node, "WebPage");
479
- node.about = resolveRelation(node.about, ctx, organizationResolver);
480
- node.breadcrumb = resolveRelation(node.breadcrumb, ctx, breadcrumbResolver);
481
- node.author = resolveRelation(node.author, ctx, personResolver);
482
- node.primaryImageOfPage = resolveRelation(node.primaryImageOfPage, ctx, imageResolver);
483
- node.potentialAction = resolveRelation(node.potentialAction, ctx, readActionResolver);
484
- if (node["@type"] === "WebPage" && ctx.meta.url) {
485
- setIfEmpty(node, "potentialAction", [
486
- {
487
- "@type": "ReadAction",
488
- "target": [ctx.meta.url]
489
- }
490
- ]);
491
- }
492
- return node;
493
- },
494
- resolveRootNode(webPage, { find, meta }) {
495
- const identity = find(IdentityId);
496
- const webSite = find(PrimaryWebSiteId);
497
- const logo = find("#logo");
498
- if (identity && meta.url === meta.host)
499
- setIfEmpty(webPage, "about", idReference(identity));
500
- if (logo)
501
- setIfEmpty(webPage, "primaryImageOfPage", idReference(logo));
502
- if (webSite)
503
- setIfEmpty(webPage, "isPartOf", idReference(webSite));
504
- const breadcrumb = find(PrimaryBreadcrumbId);
505
- if (breadcrumb)
506
- setIfEmpty(webPage, "breadcrumb", idReference(breadcrumb));
507
- return webPage;
508
- }
509
- });
510
-
511
- const personResolver = defineSchemaOrgResolver({
512
- cast(node) {
513
- if (typeof node === "string") {
514
- return {
515
- name: node
516
- };
517
- }
518
- return node;
519
- },
520
- defaults: {
521
- "@type": "Person"
522
- },
523
- idPrefix: ["host", IdentityId],
524
- resolve(node, ctx) {
525
- if (node.url)
526
- node.url = resolveWithBase(ctx.meta.host, node.url);
527
- return node;
528
- },
529
- resolveRootNode(node, { find, meta }) {
530
- if (resolveAsGraphKey(node["@id"]) === IdentityId) {
531
- setIfEmpty(node, "url", meta.host);
532
- const webPage = find(PrimaryWebPageId);
533
- if (webPage)
534
- setIfEmpty(webPage, "about", idReference(node));
535
- const webSite = find(PrimaryWebSiteId);
536
- if (webSite)
537
- setIfEmpty(webSite, "publisher", idReference(node));
538
- }
539
- const article = find(PrimaryArticleId);
540
- if (article)
541
- setIfEmpty(article, "author", idReference(node));
542
- }
543
- });
544
-
545
- const PrimaryArticleId = "#article";
546
- const articleResolver = defineSchemaOrgResolver({
547
- defaults: {
548
- "@type": "Article"
549
- },
550
- inheritMeta: [
551
- "inLanguage",
552
- "description",
553
- "image",
554
- "dateModified",
555
- "datePublished",
556
- { meta: "title", key: "headline" }
557
- ],
558
- idPrefix: ["url", PrimaryArticleId],
559
- resolve(node, ctx) {
560
- node.author = resolveRelation(node.author, ctx, personResolver, {
561
- root: true
562
- });
563
- node.publisher = resolveRelation(node.publisher, ctx);
564
- node.dateModified = resolvableDateToIso(node.dateModified);
565
- node.datePublished = resolvableDateToIso(node.datePublished);
566
- resolveDefaultType(node, "Article");
567
- node.headline = trimLength(node.headline, 110);
568
- return node;
569
- },
570
- resolveRootNode(node, { find, meta }) {
571
- const webPage = find(PrimaryWebPageId);
572
- const identity = find(IdentityId);
573
- if (node.image && !node.thumbnailUrl) {
574
- const firstImage = asArray(node.image)[0];
575
- if (typeof firstImage === "string")
576
- setIfEmpty(node, "thumbnailUrl", resolveWithBase(meta.host, firstImage));
577
- else if (firstImage?.["@id"])
578
- setIfEmpty(node, "thumbnailUrl", find(firstImage["@id"])?.url);
579
- }
580
- if (identity) {
581
- setIfEmpty(node, "publisher", idReference(identity));
582
- setIfEmpty(node, "author", idReference(identity));
583
- }
584
- if (webPage) {
585
- setIfEmpty(node, "isPartOf", idReference(webPage));
586
- setIfEmpty(node, "mainEntityOfPage", idReference(webPage));
587
- setIfEmpty(webPage, "potentialAction", [
588
- {
589
- "@type": "ReadAction",
590
- "target": [meta.url]
591
- }
592
- ]);
593
- setIfEmpty(webPage, "dateModified", node.dateModified);
594
- setIfEmpty(webPage, "datePublished", node.datePublished);
595
- }
596
- return node;
597
- }
598
- });
599
-
600
- const bookEditionResolver = defineSchemaOrgResolver({
601
- defaults: {
602
- "@type": "Book"
603
- },
604
- inheritMeta: [
605
- "inLanguage"
606
- ],
607
- resolve(node, ctx) {
608
- if (node.bookFormat)
609
- node.bookFormat = withBase(node.bookFormat, "https://schema.org/");
610
- if (node.datePublished)
611
- node.datePublished = resolvableDateToDate(node.datePublished);
612
- node.author = resolveRelation(node.author, ctx);
613
- return node;
614
- },
615
- resolveRootNode(node, { find }) {
616
- const identity = find(IdentityId);
617
- if (identity)
618
- setIfEmpty(node, "provider", idReference(identity));
619
- return node;
620
- }
621
- });
622
- const PrimaryBookId = "#book";
623
- const bookResolver = defineSchemaOrgResolver({
624
- defaults: {
625
- "@type": "Book"
626
- },
627
- inheritMeta: [
628
- "description",
629
- "url",
630
- { meta: "title", key: "name" }
631
- ],
632
- idPrefix: ["url", PrimaryBookId],
633
- resolve(node, ctx) {
634
- node.workExample = resolveRelation(node.workExample, ctx, bookEditionResolver);
635
- node.author = resolveRelation(node.author, ctx);
636
- if (node.url)
637
- withBase(node.url, ctx.meta.host);
638
- return node;
639
- },
640
- resolveRootNode(node, { find }) {
641
- const identity = find(IdentityId);
642
- if (identity)
643
- setIfEmpty(node, "author", idReference(identity));
644
- return node;
645
- }
646
- });
647
-
648
- const commentResolver = defineSchemaOrgResolver({
649
- defaults: {
650
- "@type": "Comment"
651
- },
652
- idPrefix: "url",
653
- resolve(node, ctx) {
654
- node.author = resolveRelation(node.author, ctx, personResolver, {
655
- root: true
656
- });
657
- return node;
658
- },
659
- resolveRootNode(node, { find }) {
660
- const article = find(PrimaryArticleId);
661
- if (article)
662
- setIfEmpty(node, "about", idReference(article));
663
- }
664
- });
665
-
666
- const courseResolver = defineSchemaOrgResolver({
667
- defaults: {
668
- "@type": "Course"
669
- },
670
- resolve(node, ctx) {
671
- node.provider = resolveRelation(node.provider, ctx, organizationResolver, {
672
- root: true
673
- });
674
- return node;
675
- },
676
- resolveRootNode(node, { find }) {
677
- const identity = find(IdentityId);
678
- if (identity)
679
- setIfEmpty(node, "provider", idReference(identity));
680
- return node;
681
- }
682
- });
683
-
684
- const placeResolver = defineSchemaOrgResolver({
685
- defaults: {
686
- "@type": "Place"
687
- },
688
- resolve(node, ctx) {
689
- if (typeof node.address !== "string")
690
- node.address = resolveRelation(node.address, ctx, addressResolver);
691
- return node;
692
- }
693
- });
694
-
695
- const virtualLocationResolver = defineSchemaOrgResolver({
696
- cast(node) {
697
- if (typeof node === "string") {
698
- return {
699
- url: node
700
- };
701
- }
702
- return node;
703
- },
704
- defaults: {
705
- "@type": "VirtualLocation"
706
- }
707
- });
708
-
709
- const PrimaryEventId = "#event";
710
- const eventResolver = defineSchemaOrgResolver({
711
- defaults: {
712
- "@type": "Event"
713
- },
714
- inheritMeta: [
715
- "inLanguage",
716
- "description",
717
- "image",
718
- { meta: "title", key: "name" }
719
- ],
720
- idPrefix: ["url", PrimaryEventId],
721
- resolve(node, ctx) {
722
- if (node.location) {
723
- const isVirtual = node.location === "string" || node.location?.url !== "undefined";
724
- node.location = resolveRelation(node.location, ctx, isVirtual ? virtualLocationResolver : placeResolver);
725
- }
726
- node.performer = resolveRelation(node.performer, ctx, personResolver, {
727
- root: true
728
- });
729
- node.organizer = resolveRelation(node.organizer, ctx, organizationResolver, {
730
- root: true
731
- });
732
- node.offers = resolveRelation(node.offers, ctx, offerResolver);
733
- if (node.eventAttendanceMode)
734
- node.eventAttendanceMode = withBase(node.eventAttendanceMode, "https://schema.org/");
735
- if (node.eventStatus)
736
- node.eventStatus = withBase(node.eventStatus, "https://schema.org/");
737
- const isOnline = node.eventStatus === "https://schema.org/EventMovedOnline";
738
- const dates = ["startDate", "previousStartDate", "endDate"];
739
- dates.forEach((date) => {
740
- if (!isOnline) {
741
- if (node[date] instanceof Date && node[date].getHours() === 0 && node[date].getMinutes() === 0)
742
- node[date] = resolvableDateToDate(node[date]);
743
- } else {
744
- node[date] = resolvableDateToIso(node[date]);
745
- }
746
- });
747
- setIfEmpty(node, "endDate", node.startDate);
748
- return node;
749
- },
750
- resolveRootNode(node, { find }) {
751
- const identity = find(IdentityId);
752
- if (identity)
753
- setIfEmpty(node, "organizer", idReference(identity));
754
- }
755
- });
756
-
757
- const openingHoursResolver = defineSchemaOrgResolver({
758
- defaults: {
759
- "@type": "OpeningHoursSpecification",
760
- "opens": "00:00",
761
- "closes": "23:59"
762
- }
763
- });
764
-
765
- const localBusinessResolver = defineSchemaOrgResolver({
766
- defaults: {
767
- "@type": ["Organization", "LocalBusiness"]
768
- },
769
- inheritMeta: [
770
- { key: "url", meta: "host" },
771
- { key: "currenciesAccepted", meta: "currency" }
772
- ],
773
- idPrefix: ["host", IdentityId],
774
- resolve(node, ctx) {
775
- resolveDefaultType(node, ["Organization", "LocalBusiness"]);
776
- node.address = resolveRelation(node.address, ctx, addressResolver);
777
- node.openingHoursSpecification = resolveRelation(node.openingHoursSpecification, ctx, openingHoursResolver);
778
- node = resolveNode({ ...node }, ctx, organizationResolver);
779
- return node;
780
- },
781
- resolveRootNode(node, ctx) {
782
- organizationResolver.resolveRootNode(node, ctx);
783
- return node;
784
- }
785
- });
786
-
787
- const ratingResolver = defineSchemaOrgResolver({
788
- cast(node) {
789
- if (node === "number") {
790
- return {
791
- ratingValue: node
792
- };
793
- }
794
- return node;
795
- },
796
- defaults: {
797
- "@type": "Rating",
798
- "bestRating": 5,
799
- "worstRating": 1
800
- }
801
- });
802
-
803
- const foodEstablishmentResolver = defineSchemaOrgResolver({
804
- defaults: {
805
- "@type": ["Organization", "LocalBusiness", "FoodEstablishment"]
806
- },
807
- inheritMeta: [
808
- { key: "url", meta: "host" },
809
- { key: "currenciesAccepted", meta: "currency" }
810
- ],
811
- idPrefix: ["host", IdentityId],
812
- resolve(node, ctx) {
813
- resolveDefaultType(node, ["Organization", "LocalBusiness", "FoodEstablishment"]);
814
- node.starRating = resolveRelation(node.starRating, ctx, ratingResolver);
815
- node = resolveNode(node, ctx, localBusinessResolver);
816
- return node;
817
- },
818
- resolveRootNode(node, ctx) {
819
- localBusinessResolver.resolveRootNode(node, ctx);
820
- return node;
821
- }
822
- });
823
-
824
- const howToStepDirectionResolver = defineSchemaOrgResolver({
825
- cast(node) {
826
- if (typeof node === "string") {
827
- return {
828
- text: node
829
- };
830
- }
831
- return node;
832
- },
833
- defaults: {
834
- "@type": "HowToDirection"
835
- }
836
- });
837
-
838
- const howToStepResolver = defineSchemaOrgResolver({
839
- cast(node) {
840
- if (typeof node === "string") {
841
- return {
842
- text: node
843
- };
844
- }
845
- return node;
846
- },
847
- defaults: {
848
- "@type": "HowToStep"
849
- },
850
- resolve(step, ctx) {
851
- if (step.url)
852
- step.url = resolveWithBase(ctx.meta.url, step.url);
853
- if (step.image) {
854
- step.image = resolveRelation(step.image, ctx, imageResolver, {
855
- root: true
856
- });
857
- }
858
- if (step.itemListElement)
859
- step.itemListElement = resolveRelation(step.itemListElement, ctx, howToStepDirectionResolver);
860
- return step;
861
- }
862
- });
863
-
864
- const HowToId = "#howto";
865
- const howToResolver = defineSchemaOrgResolver({
866
- defaults: {
867
- "@type": "HowTo"
868
- },
869
- inheritMeta: [
870
- "description",
871
- "image",
872
- "inLanguage",
873
- { meta: "title", key: "name" }
874
- ],
875
- idPrefix: ["url", HowToId],
876
- resolve(node, ctx) {
877
- node.step = resolveRelation(node.step, ctx, howToStepResolver);
878
- return node;
879
- },
880
- resolveRootNode(node, { find }) {
881
- const webPage = find(PrimaryWebPageId);
882
- if (webPage)
883
- setIfEmpty(node, "mainEntityOfPage", idReference(webPage));
884
- }
885
- });
886
-
887
- const itemListResolver = defineSchemaOrgResolver({
888
- defaults: {
889
- "@type": "ItemList"
890
- },
891
- resolve(node, ctx) {
892
- if (node.itemListElement) {
893
- let index = 1;
894
- node.itemListElement = resolveRelation(node.itemListElement, ctx, listItemResolver, {
895
- array: true,
896
- afterResolve(node2) {
897
- setIfEmpty(node2, "position", index++);
898
- }
899
- });
900
- }
901
- return node;
902
- }
903
- });
904
-
905
- const jobPostingResolver = defineSchemaOrgResolver({
906
- defaults: {
907
- "@type": "JobPosting"
908
- },
909
- idPrefix: ["url", "#job-posting"],
910
- resolve(node, ctx) {
911
- node.datePosted = resolvableDateToIso(node.datePosted);
912
- node.hiringOrganization = resolveRelation(node.hiringOrganization, ctx, organizationResolver);
913
- node.jobLocation = resolveRelation(node.jobLocation, ctx, placeResolver);
914
- node.baseSalary = resolveRelation(node.baseSalary, ctx, monetaryAmountResolver);
915
- node.validThrough = resolvableDateToIso(node.validThrough);
916
- return node;
917
- },
918
- resolveRootNode(jobPosting, { find }) {
919
- const webPage = find(PrimaryWebPageId);
920
- const identity = find(IdentityId);
921
- if (identity)
922
- setIfEmpty(jobPosting, "hiringOrganization", idReference(identity));
923
- if (webPage)
924
- setIfEmpty(jobPosting, "mainEntityOfPage", idReference(webPage));
925
- return jobPosting;
926
- }
927
- });
928
-
929
- const reviewResolver = defineSchemaOrgResolver({
930
- defaults: {
931
- "@type": "Review"
932
- },
933
- inheritMeta: [
934
- "inLanguage"
935
- ],
936
- resolve(review, ctx) {
937
- review.reviewRating = resolveRelation(review.reviewRating, ctx, ratingResolver);
938
- review.author = resolveRelation(review.author, ctx, personResolver);
939
- return review;
940
- }
941
- });
942
-
943
- const videoResolver = defineSchemaOrgResolver({
944
- cast(input) {
945
- if (typeof input === "string") {
946
- input = {
947
- url: input
948
- };
949
- }
950
- return input;
951
- },
952
- alias: "video",
953
- defaults: {
954
- "@type": "VideoObject"
955
- },
956
- inheritMeta: [
957
- { meta: "title", key: "name" },
958
- "description",
959
- "image",
960
- "inLanguage",
961
- { meta: "datePublished", key: "uploadDate" }
962
- ],
963
- idPrefix: "host",
964
- resolve(video, ctx) {
965
- if (video.uploadDate)
966
- video.uploadDate = resolvableDateToIso(video.uploadDate);
967
- video.url = resolveWithBase(ctx.meta.host, video.url);
968
- if (video.caption && !video.description)
969
- video.description = video.caption;
970
- if (!video.description)
971
- video.description = "No description";
972
- if (video.thumbnailUrl && (typeof video.thumbnailUrl === "string" || Array.isArray(video.thumbnailUrl))) {
973
- const images = asArray(video.thumbnailUrl).map((image) => resolveWithBase(ctx.meta.host, image));
974
- video.thumbnailUrl = images.length > 1 ? images : images[0];
975
- }
976
- if (video.thumbnail)
977
- video.thumbnail = resolveRelation(video.thumbnailUrl, ctx, imageResolver);
978
- return video;
979
- },
980
- resolveRootNode(video, { find }) {
981
- if (video.image && !video.thumbnail) {
982
- const firstImage = asArray(video.image)[0];
983
- setIfEmpty(video, "thumbnail", find(firstImage["@id"])?.url);
984
- }
985
- }
986
- });
987
-
988
- const movieResolver = defineSchemaOrgResolver({
989
- defaults: {
990
- "@type": "Movie"
991
- },
992
- resolve(node, ctx) {
993
- node.aggregateRating = resolveRelation(node.aggregateRating, ctx, aggregateRatingResolver);
994
- node.review = resolveRelation(node.review, ctx, reviewResolver);
995
- node.director = resolveRelation(node.director, ctx, personResolver);
996
- node.actor = resolveRelation(node.actor, ctx, personResolver);
997
- node.trailer = resolveRelation(node.trailer, ctx, videoResolver);
998
- if (node.dateCreated)
999
- node.dateCreated = resolvableDateToDate(node.dateCreated);
1000
- return node;
1001
- }
1002
- });
1003
-
1004
- const ProductId = "#product";
1005
- const productResolver = defineSchemaOrgResolver({
1006
- defaults: {
1007
- "@type": "Product"
1008
- },
1009
- inheritMeta: [
1010
- "description",
1011
- "image",
1012
- { meta: "title", key: "name" }
1013
- ],
1014
- idPrefix: ["url", ProductId],
1015
- resolve(node, ctx) {
1016
- setIfEmpty(node, "sku", hashCode(node.name));
1017
- node.aggregateOffer = resolveRelation(node.aggregateOffer, ctx, aggregateOfferResolver);
1018
- node.aggregateRating = resolveRelation(node.aggregateRating, ctx, aggregateRatingResolver);
1019
- node.offers = resolveRelation(node.offers, ctx, offerResolver);
1020
- node.review = resolveRelation(node.review, ctx, reviewResolver);
1021
- return node;
1022
- },
1023
- resolveRootNode(product, { find }) {
1024
- const webPage = find(PrimaryWebPageId);
1025
- const identity = find(IdentityId);
1026
- if (identity)
1027
- setIfEmpty(product, "brand", idReference(identity));
1028
- if (webPage)
1029
- setIfEmpty(product, "mainEntityOfPage", idReference(webPage));
1030
- return product;
1031
- }
1032
- });
1033
-
1034
- const answerResolver = defineSchemaOrgResolver({
1035
- cast(node) {
1036
- if (typeof node === "string") {
1037
- return {
1038
- text: node
1039
- };
1040
- }
1041
- return node;
1042
- },
1043
- defaults: {
1044
- "@type": "Answer"
1045
- }
1046
- });
1047
-
1048
- const questionResolver = defineSchemaOrgResolver({
1049
- defaults: {
1050
- "@type": "Question"
1051
- },
1052
- inheritMeta: [
1053
- "inLanguage"
1054
- ],
1055
- idPrefix: "url",
1056
- resolve(question, ctx) {
1057
- if (question.question) {
1058
- question.name = question.question;
1059
- delete question.question;
1060
- }
1061
- if (question.answer) {
1062
- question.acceptedAnswer = question.answer;
1063
- delete question.answer;
1064
- }
1065
- question.acceptedAnswer = resolveRelation(question.acceptedAnswer, ctx, answerResolver);
1066
- return question;
1067
- },
1068
- resolveRootNode(question, { find }) {
1069
- const webPage = find(PrimaryWebPageId);
1070
- if (webPage && asArray(webPage["@type"]).includes("FAQPage"))
1071
- dedupeMerge(webPage, "mainEntity", idReference(question));
1072
- }
1073
- });
1074
-
1075
- const RecipeId = "#recipe";
1076
- const recipeResolver = defineSchemaOrgResolver({
1077
- defaults: {
1078
- "@type": "Recipe"
1079
- },
1080
- inheritMeta: [
1081
- { meta: "title", key: "name" },
1082
- "description",
1083
- "image",
1084
- "datePublished"
1085
- ],
1086
- idPrefix: ["url", RecipeId],
1087
- resolve(node, ctx) {
1088
- node.recipeInstructions = resolveRelation(node.recipeInstructions, ctx, howToStepResolver);
1089
- return node;
1090
- },
1091
- resolveRootNode(node, { find }) {
1092
- const article = find(PrimaryArticleId);
1093
- const webPage = find(PrimaryWebPageId);
1094
- if (article)
1095
- setIfEmpty(node, "mainEntityOfPage", idReference(article));
1096
- else if (webPage)
1097
- setIfEmpty(node, "mainEntityOfPage", idReference(webPage));
1098
- if (article?.author)
1099
- setIfEmpty(node, "author", article.author);
1100
- return node;
1101
- }
1102
- });
1103
-
1104
- const softwareAppResolver = defineSchemaOrgResolver({
1105
- defaults: {
1106
- "@type": "SoftwareApplication"
1107
- },
1108
- resolve(node, ctx) {
1109
- resolveDefaultType(node, "SoftwareApplication");
1110
- node.offers = resolveRelation(node.offers, ctx, offerResolver);
1111
- node.aggregateRating = resolveRelation(node.aggregateRating, ctx, aggregateRatingResolver);
1112
- node.review = resolveRelation(node.review, ctx, reviewResolver);
1113
- return node;
1114
- }
1115
- });
1116
-
1117
- function loadResolver(resolver) {
1118
- switch (resolver) {
1119
- case "address":
1120
- return addressResolver;
1121
- case "aggregateOffer":
1122
- return aggregateOfferResolver;
1123
- case "aggregateRating":
1124
- return aggregateRatingResolver;
1125
- case "article":
1126
- return articleResolver;
1127
- case "breadcrumb":
1128
- return breadcrumbResolver;
1129
- case "comment":
1130
- return commentResolver;
1131
- case "event":
1132
- return eventResolver;
1133
- case "foodEstablishment":
1134
- return foodEstablishmentResolver;
1135
- case "virtualLocation":
1136
- return virtualLocationResolver;
1137
- case "place":
1138
- return placeResolver;
1139
- case "howTo":
1140
- return howToResolver;
1141
- case "howToStep":
1142
- return howToStepResolver;
1143
- case "image":
1144
- return imageResolver;
1145
- case "localBusiness":
1146
- return localBusinessResolver;
1147
- case "offer":
1148
- return offerResolver;
1149
- case "openingHours":
1150
- return openingHoursResolver;
1151
- case "organization":
1152
- return organizationResolver;
1153
- case "person":
1154
- return personResolver;
1155
- case "product":
1156
- return productResolver;
1157
- case "question":
1158
- return questionResolver;
1159
- case "recipe":
1160
- return recipeResolver;
1161
- case "review":
1162
- return reviewResolver;
1163
- case "video":
1164
- return videoResolver;
1165
- case "webPage":
1166
- return webPageResolver;
1167
- case "webSite":
1168
- return webSiteResolver;
1169
- case "book":
1170
- return bookResolver;
1171
- case "course":
1172
- return courseResolver;
1173
- case "itemList":
1174
- return itemListResolver;
1175
- case "jobPosting":
1176
- return jobPostingResolver;
1177
- case "listItem":
1178
- return listItemResolver;
1179
- case "movie":
1180
- return movieResolver;
1181
- case "searchAction":
1182
- return searchActionResolver;
1183
- case "readAction":
1184
- return readActionResolver;
1185
- case "softwareApp":
1186
- return softwareAppResolver;
1187
- case "bookEdition":
1188
- return bookEditionResolver;
1189
- }
1190
- return null;
1191
- }
1192
-
1193
- function resolveMeta(meta) {
1194
- if (!meta.host && meta.canonicalHost)
1195
- meta.host = meta.canonicalHost;
1196
- if (!meta.tagPosition && meta.position)
1197
- meta.tagPosition = meta.position;
1198
- if (!meta.currency && meta.defaultCurrency)
1199
- meta.currency = meta.defaultCurrency;
1200
- if (!meta.inLanguage && meta.defaultLanguage)
1201
- meta.inLanguage = meta.defaultLanguage;
1202
- if (!meta.path)
1203
- meta.path = "/";
1204
- if (!meta.host && typeof document !== "undefined")
1205
- meta.host = document.location.host;
1206
- if (!meta.url && meta.canonicalUrl)
1207
- meta.url = meta.canonicalUrl;
1208
- if (meta.path !== "/") {
1209
- if (meta.trailingSlash && !hasTrailingSlash(meta.path))
1210
- meta.path = withTrailingSlash(meta.path);
1211
- else if (!meta.trailingSlash && hasTrailingSlash(meta.path))
1212
- meta.path = withoutTrailingSlash(meta.path);
1213
- }
1214
- meta.url = joinURL(meta.host || "", meta.path);
1215
- return {
1216
- ...meta,
1217
- host: meta.host,
1218
- url: meta.url,
1219
- currency: meta.currency,
1220
- image: meta.image,
1221
- inLanguage: meta.inLanguage,
1222
- title: meta.title,
1223
- description: meta.description,
1224
- datePublished: meta.datePublished,
1225
- dateModified: meta.dateModified
1226
- };
1227
- }
1228
- function resolveNode(node, ctx, resolver) {
1229
- if (resolver?.cast)
1230
- node = resolver.cast(node, ctx);
1231
- if (resolver?.defaults) {
1232
- let defaults = resolver.defaults || {};
1233
- if (typeof defaults === "function")
1234
- defaults = defaults(ctx);
1235
- node = {
1236
- ...defaults,
1237
- ...node
1238
- };
1239
- }
1240
- resolver?.inheritMeta?.forEach((entry) => {
1241
- if (typeof entry === "string")
1242
- setIfEmpty(node, entry, ctx.meta[entry]);
1243
- else
1244
- setIfEmpty(node, entry.key, ctx.meta[entry.meta]);
1245
- });
1246
- if (resolver?.resolve)
1247
- node = resolver.resolve(node, ctx);
1248
- for (const k in node) {
1249
- const v = node[k];
1250
- if (Array.isArray(v)) {
1251
- v.forEach((v2, k2) => {
1252
- if (typeof v2 === "object" && v2?._resolver) {
1253
- node[k][k2] = resolveRelation(v2, ctx, v2._resolver);
1254
- }
1255
- });
1256
- }
1257
- if (typeof v === "object" && v?._resolver)
1258
- node[k] = resolveRelation(v, ctx, v._resolver);
1259
- }
1260
- stripEmptyProperties(node);
1261
- return node;
1262
- }
1263
- function resolveNodeId(node, ctx, resolver, resolveAsRoot = false) {
1264
- if (node["@id"] && node["@id"].startsWith("http"))
1265
- return node;
1266
- const prefix = resolver ? (Array.isArray(resolver.idPrefix) ? resolver.idPrefix[0] : resolver.idPrefix) || "url" : "url";
1267
- const rootId = node["@id"] || (resolver ? Array.isArray(resolver.idPrefix) ? resolver.idPrefix?.[1] : void 0 : "");
1268
- if (!node["@id"] && resolveAsRoot && rootId) {
1269
- node["@id"] = prefixId(ctx.meta[prefix], rootId);
1270
- return node;
1271
- }
1272
- if (node["@id"]?.startsWith("#/schema/") || node["@id"]?.startsWith("/")) {
1273
- node["@id"] = prefixId(ctx.meta[prefix], node["@id"]);
1274
- return node;
1275
- }
1276
- let alias = resolver?.alias;
1277
- if (!alias) {
1278
- const type = asArray(node["@type"])?.[0] || "";
1279
- alias = type.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
1280
- }
1281
- const hashNodeData = {};
1282
- for (const key in node) {
1283
- if (key[0] === "_") {
1284
- continue;
1285
- }
1286
- if (!Object.prototype.hasOwnProperty.call(node, key)) {
1287
- continue;
1288
- }
1289
- hashNodeData[key] = node[key];
1290
- }
1291
- node["@id"] = prefixId(ctx.meta[prefix], `#/schema/${alias}/${node["@id"] || hashCode(JSON.stringify(hashNodeData))}`);
1292
- return node;
1293
- }
1294
- function resolveRelation(input, ctx, fallbackResolver, options = {}) {
1295
- if (!input)
1296
- return input;
1297
- const ids = asArray(input).map((a) => {
1298
- const keys = Object.keys(a).length;
1299
- if (keys === 1 && a["@id"] || keys === 2 && a["@id"] && a["@type"]) {
1300
- return resolveNodeId({
1301
- // we drop @type
1302
- "@id": ctx.find(a["@id"])?.["@id"] || a["@id"]
1303
- }, ctx);
1304
- }
1305
- let resolver = fallbackResolver;
1306
- if (a._resolver) {
1307
- resolver = a._resolver;
1308
- if (typeof resolver === "string")
1309
- resolver = loadResolver(resolver);
1310
- delete a._resolver;
1311
- }
1312
- if (!resolver)
1313
- return a;
1314
- let node = resolveNode(a, ctx, resolver);
1315
- if (options.afterResolve)
1316
- options.afterResolve(node);
1317
- if (options.generateId || options.root)
1318
- node = resolveNodeId(node, ctx, resolver, false);
1319
- if (options.root) {
1320
- if (resolver.resolveRootNode)
1321
- resolver.resolveRootNode(node, ctx);
1322
- ctx.push(node);
1323
- return idReference(node["@id"]);
1324
- }
1325
- return node;
1326
- });
1327
- if (!options.array && ids.length === 1)
1328
- return ids[0];
1329
- return ids;
1330
- }
1331
-
1332
- function groupBy(array, predicate) {
1333
- return array.reduce((acc, value, index, array2) => {
1334
- const key = predicate(value, index, array2);
1335
- if (!acc[key])
1336
- acc[key] = [];
1337
- acc[key].push(value);
1338
- return acc;
1339
- }, {});
1340
- }
1341
- function uniqueBy(array, predicate) {
1342
- return Object.values(groupBy(array, predicate)).map((a) => a[a.length - 1]);
1343
- }
1344
- const merge = createDefu((object, key, value) => {
1345
- if (Array.isArray(object[key])) {
1346
- if (Array.isArray(value)) {
1347
- const map = {};
1348
- for (const item of [...object[key], ...value])
1349
- map[hash(item)] = item;
1350
- object[key] = Object.values(map);
1351
- if (key === "itemListElement") {
1352
- object[key] = [...uniqueBy(object[key], (item) => item.position)];
1353
- }
1354
- return true;
1355
- }
1356
- object[key] = merge(object[key], Array.isArray(value) ? value : [value]);
1357
- return true;
1358
- }
1359
- });
1360
- function dedupeNodes(nodes) {
1361
- const dedupedNodes = {};
1362
- for (const key of nodes.keys()) {
1363
- const n = nodes[key];
1364
- const nodeKey = resolveAsGraphKey(n["@id"] || hash(n));
1365
- if (dedupedNodes[nodeKey] && n._dedupeStrategy !== "replace")
1366
- dedupedNodes[nodeKey] = merge(nodes[key], dedupedNodes[nodeKey]);
1367
- else
1368
- dedupedNodes[nodeKey] = nodes[key];
1369
- }
1370
- return Object.values(dedupedNodes);
1371
- }
1372
- function normaliseNodes(nodes) {
1373
- const sortedNodeKeys = nodes.keys();
1374
- const dedupedNodes = {};
1375
- for (const key of sortedNodeKeys) {
1376
- const n = nodes[key];
1377
- const nodeKey = resolveAsGraphKey(n["@id"] || hash(n));
1378
- const groupedKeys = groupBy(Object.keys(n), (key2) => {
1379
- const val = n[key2];
1380
- if (key2[0] === "_")
1381
- return "ignored";
1382
- if (Array.isArray(val) || typeof val === "object")
1383
- return "relations";
1384
- return "primitives";
1385
- });
1386
- const keys = [
1387
- ...(groupedKeys.primitives || []).sort(),
1388
- ...(groupedKeys.relations || []).sort()
1389
- ];
1390
- let newNode = {};
1391
- for (const key2 of keys)
1392
- newNode[key2] = n[key2];
1393
- if (dedupedNodes[nodeKey])
1394
- newNode = merge(newNode, dedupedNodes[nodeKey]);
1395
- dedupedNodes[nodeKey] = newNode;
1396
- }
1397
- return Object.values(dedupedNodes);
1398
- }
1399
-
1400
- const baseRelationNodes = [
1401
- "translationOfWork",
1402
- "workTranslation"
1403
- ];
1404
- function createSchemaOrgGraph() {
1405
- const ctx = {
1406
- find(id) {
1407
- let resolver = (s) => s;
1408
- if (id[0] === "#") {
1409
- resolver = resolveAsGraphKey;
1410
- } else if (id[0] === "/") {
1411
- resolver = (s) => s.replace(/(https?:)?\/\//, "").split("/")[0];
1412
- }
1413
- const key = resolver(id);
1414
- return ctx.nodes.filter((n) => !!n["@id"]).find((n) => resolver(n["@id"]) === key);
1415
- },
1416
- push(input) {
1417
- asArray(input).forEach((node) => {
1418
- const registeredNode = node;
1419
- ctx.nodes.push(registeredNode);
1420
- });
1421
- },
1422
- resolveGraph(meta) {
1423
- ctx.meta = resolveMeta({ ...meta });
1424
- ctx.nodes.forEach((node, key) => {
1425
- const resolver = node._resolver;
1426
- node = resolveNode(node, ctx, resolver);
1427
- node = resolveNodeId(node, ctx, resolver, true);
1428
- ctx.nodes[key] = node;
1429
- });
1430
- ctx.nodes = dedupeNodes(ctx.nodes);
1431
- ctx.nodes.forEach((node) => {
1432
- if (node.image && typeof node.image === "string") {
1433
- node.image = resolveRelation(node.image, ctx, imageResolver, {
1434
- root: true
1435
- });
1436
- }
1437
- baseRelationNodes.forEach((k) => {
1438
- node[k] = resolveRelation(node[k], ctx);
1439
- });
1440
- if (node._resolver?.resolveRootNode)
1441
- node._resolver.resolveRootNode(node, ctx);
1442
- delete node._resolver;
1443
- });
1444
- return normaliseNodes(ctx.nodes);
1445
- },
1446
- nodes: [],
1447
- meta: {}
1448
- };
1449
- return ctx;
1450
- }
1451
-
1452
- function UnheadSchemaOrg(options) {
1453
- return SchemaOrgUnheadPlugin({}, () => ({}), options);
1454
- }
1455
- function PluginSchemaOrg(options) {
1456
- const fallback = () => ({});
1457
- return SchemaOrgUnheadPlugin({}, options?.resolveMeta || fallback, options);
1458
- }
1459
- function SchemaOrgUnheadPlugin(config, meta, options) {
1460
- config = resolveMeta({ ...config });
1461
- let graph;
1462
- let resolvedMeta = {};
1463
- return defineHeadPlugin((head) => {
1464
- head.use(TemplateParamsPlugin);
1465
- return {
1466
- key: "schema-org",
1467
- hooks: {
1468
- "entries:normalize": async ({ tags }) => {
1469
- graph = graph || createSchemaOrgGraph();
1470
- for (const tag of tags) {
1471
- if (tag.tag === "script" && tag.props.type === "application/ld+json" && tag.props.nodes) {
1472
- const nodes = await tag.props.nodes;
1473
- for (const node of Array.isArray(nodes) ? nodes : [nodes]) {
1474
- if (typeof node !== "object" || Object.keys(node).length === 0) {
1475
- continue;
1476
- }
1477
- const newNode = {
1478
- ...node,
1479
- _dedupeStrategy: tag.tagDuplicateStrategy,
1480
- _resolver: loadResolver(await node._resolver)
1481
- };
1482
- graph.push(newNode);
1483
- }
1484
- tag.tagPosition = tag.tagPosition || config.tagPosition === "head" ? "head" : "bodyClose";
1485
- }
1486
- if (tag.tag === "htmlAttrs" && tag.props.lang) {
1487
- resolvedMeta.inLanguage = tag.props.lang;
1488
- } else if (tag.tag === "title") {
1489
- resolvedMeta.title = tag.textContent;
1490
- } else if (tag.tag === "meta" && tag.props.name === "description") {
1491
- resolvedMeta.description = tag.props.content;
1492
- } else if (tag.tag === "link" && tag.props.rel === "canonical") {
1493
- resolvedMeta.url = tag.props.href;
1494
- if (resolvedMeta.url && !resolvedMeta.host) {
1495
- try {
1496
- resolvedMeta.host = new URL(resolvedMeta.url).origin;
1497
- } catch {
1498
- }
1499
- }
1500
- } else if (tag.tag === "meta" && tag.props.property === "og:image") {
1501
- resolvedMeta.image = tag.props.content;
1502
- } else if (tag.tag === "templateParams" && tag.props.schemaOrg) {
1503
- resolvedMeta = {
1504
- ...resolvedMeta,
1505
- // @ts-expect-error untyped
1506
- ...tag.props.schemaOrg
1507
- };
1508
- delete tag.props.schemaOrg;
1509
- }
1510
- }
1511
- },
1512
- "tags:resolve": async (ctx) => {
1513
- for (const k in ctx.tags) {
1514
- const tag = ctx.tags[k];
1515
- if (tag.tag === "script" && tag.props.type === "application/ld+json" && tag.props.nodes) {
1516
- delete tag.props.nodes;
1517
- const resolvedGraph = graph.resolveGraph({ ...await meta?.() || {}, ...config, ...resolvedMeta });
1518
- if (!resolvedGraph.length) {
1519
- tag.props = {};
1520
- return;
1521
- }
1522
- const minify = options?.minify || process.env.NODE_ENV === "production";
1523
- tag.innerHTML = JSON.stringify({
1524
- "@context": "https://schema.org",
1525
- "@graph": resolvedGraph
1526
- }, (_, value) => {
1527
- if (typeof value !== "object")
1528
- return processTemplateParams(value, head._templateParams, head._separator);
1529
- return value;
1530
- }, minify ? 0 : 2);
1531
- return;
1532
- }
1533
- }
1534
- },
1535
- "tags:afterResolve": (ctx) => {
1536
- let firstNodeKey;
1537
- for (const k in ctx.tags) {
1538
- const tag = ctx.tags[k];
1539
- if (tag.props.type === "application/ld+json" && tag.props.nodes || tag.key === "schema-org-graph") {
1540
- delete tag.props.nodes;
1541
- if (typeof firstNodeKey === "undefined") {
1542
- firstNodeKey = k;
1543
- continue;
1544
- }
1545
- ctx.tags[firstNodeKey].props = defu(ctx.tags[firstNodeKey].props, tag.props);
1546
- delete ctx.tags[firstNodeKey].props.nodes;
1547
- ctx.tags[k] = false;
1548
- }
1549
- }
1550
- ctx.tags = ctx.tags.filter(Boolean);
1551
- }
1552
- }
1553
- };
1554
- });
1555
- }
1556
-
1557
- function provideResolver(input, resolver) {
1558
- if (!input)
1559
- input = {};
1560
- input._resolver = resolver;
1561
- return input;
1562
- }
1563
- function defineAddress(input) {
1564
- return provideResolver(input, "address");
1565
- }
1566
- function defineAggregateOffer(input) {
1567
- return provideResolver(input, "aggregateOffer");
1568
- }
1569
- function defineAggregateRating(input) {
1570
- return provideResolver(input, "aggregateRating");
1571
- }
1572
- function defineArticle(input) {
1573
- return provideResolver(input, "article");
1574
- }
1575
- function defineBreadcrumb(input) {
1576
- return provideResolver(input, "breadcrumb");
1577
- }
1578
- function defineComment(input) {
1579
- return provideResolver(input, "comment");
1580
- }
1581
- function defineEvent(input) {
1582
- return provideResolver(input, "event");
1583
- }
1584
- function defineFoodEstablishment(input) {
1585
- return provideResolver(input, "foodEstablishment");
1586
- }
1587
- function defineVirtualLocation(input) {
1588
- return provideResolver(input, "virtualLocation");
1589
- }
1590
- function definePlace(input) {
1591
- return provideResolver(input, "place");
1592
- }
1593
- function defineHowTo(input) {
1594
- return provideResolver(input, "howTo");
1595
- }
1596
- function defineHowToStep(input) {
1597
- return provideResolver(input, "howToStep");
1598
- }
1599
- function defineImage(input) {
1600
- return provideResolver(input, "image");
1601
- }
1602
- function defineJobPosting(input) {
1603
- return provideResolver(input, "jobPosting");
1604
- }
1605
- function defineLocalBusiness(input) {
1606
- return provideResolver(input, "localBusiness");
1607
- }
1608
- function defineOffer(input) {
1609
- return provideResolver(input, "offer");
1610
- }
1611
- function defineOpeningHours(input) {
1612
- return provideResolver(input, "openingHours");
1613
- }
1614
- function defineOrganization(input) {
1615
- return provideResolver(input, "organization");
1616
- }
1617
- function definePerson(input) {
1618
- return provideResolver(input, "person");
1619
- }
1620
- function defineProduct(input) {
1621
- return provideResolver(input, "product");
1622
- }
1623
- function defineQuestion(input) {
1624
- return provideResolver(input, "question");
1625
- }
1626
- function defineRecipe(input) {
1627
- return provideResolver(input, "recipe");
1628
- }
1629
- function defineReview(input) {
1630
- return provideResolver(input, "review");
1631
- }
1632
- function defineVideo(input) {
1633
- return provideResolver(input, "video");
1634
- }
1635
- function defineWebPage(input) {
1636
- return provideResolver(input, "webPage");
1637
- }
1638
- function defineWebSite(input) {
1639
- return provideResolver(input, "webSite");
1640
- }
1641
- function defineBook(input) {
1642
- return provideResolver(input, "book");
1643
- }
1644
- function defineCourse(input) {
1645
- return provideResolver(input, "course");
1646
- }
1647
- function defineItemList(input) {
1648
- return provideResolver(input, "itemList");
1649
- }
1650
- function defineListItem(input) {
1651
- return provideResolver(input, "listItem");
1652
- }
1653
- function defineMovie(input) {
1654
- return provideResolver(input, "movie");
1655
- }
1656
- function defineSearchAction(input) {
1657
- return provideResolver(input, "searchAction");
1658
- }
1659
- function defineReadAction(input) {
1660
- return provideResolver(input, "readAction");
1661
- }
1662
- function defineSoftwareApp(input) {
1663
- return provideResolver(input, "softwareApp");
1664
- }
1665
- function defineBookEdition(input) {
1666
- return provideResolver(input, "bookEdition");
1667
- }
1668
- function normalizeSchemaOrgInput(input) {
1669
- if (input.script) {
1670
- return input;
1671
- }
1672
- return {
1673
- script: [
1674
- {
1675
- type: "application/ld+json",
1676
- key: "schema-org-graph",
1677
- nodes: input
1678
- }
1679
- ]
1680
- };
1681
- }
1682
- function useSchemaOrg(unhead, input = [], options = {}) {
1683
- unhead.use(UnheadSchemaOrg());
1684
- const entry = unhead.push(normalizeSchemaOrgInput(input), options);
1685
- const corePatch = entry.patch;
1686
- entry.patch = (input2) => corePatch(normalizeSchemaOrgInput(input2));
1687
- return entry;
1688
- }
1689
-
1690
- export { searchActionResolver as $, imageResolver as A, itemListResolver as B, jobPostingResolver as C, listItemResolver as D, localBusinessResolver as E, movieResolver as F, offerResolver as G, HowToId as H, openingHoursResolver as I, organizationResolver as J, personResolver as K, addressResolver as L, ProductId as M, productResolver as N, questionResolver as O, PrimaryArticleId as P, ratingResolver as Q, RecipeId as R, recipeResolver as S, reviewResolver as T, softwareAppResolver as U, videoResolver as V, PrimaryWebPageId as W, webPageResolver as X, readActionResolver as Y, PrimaryWebSiteId as Z, webSiteResolver as _, resolveNode as a, UnheadSchemaOrg as a0, PluginSchemaOrg as a1, SchemaOrgUnheadPlugin as a2, defineAddress as a3, defineAggregateOffer as a4, defineAggregateRating as a5, defineArticle as a6, defineBreadcrumb as a7, defineComment as a8, defineEvent as a9, defineSoftwareApp as aA, defineBookEdition as aB, normalizeSchemaOrgInput as aC, useSchemaOrg as aD, defineFoodEstablishment as aa, defineVirtualLocation as ab, definePlace as ac, defineHowTo as ad, defineHowToStep as ae, defineImage as af, defineJobPosting as ag, defineLocalBusiness as ah, defineOffer as ai, defineOpeningHours as aj, defineOrganization as ak, definePerson as al, defineProduct as am, defineQuestion as an, defineRecipe as ao, defineReview as ap, defineVideo as aq, defineWebPage as ar, defineWebSite as as, defineBook as at, defineCourse as au, defineItemList as av, defineListItem as aw, defineMovie as ax, defineSearchAction as ay, defineReadAction as az, resolveNodeId as b, createSchemaOrgGraph as c, defineSchemaOrgResolver as d, resolveRelation as e, dedupeNodes as f, aggregateOfferResolver as g, aggregateRatingResolver as h, articleResolver as i, bookEditionResolver as j, PrimaryBookId as k, bookResolver as l, PrimaryBreadcrumbId as m, normaliseNodes as n, breadcrumbResolver as o, commentResolver as p, courseResolver as q, resolveMeta as r, PrimaryEventId as s, eventResolver as t, placeResolver as u, virtualLocationResolver as v, foodEstablishmentResolver as w, howToResolver as x, howToStepResolver as y, howToStepDirectionResolver as z };