@schemasentry/core 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +95 -1
- package/dist/index.d.cts +40 -3
- package/dist/index.d.ts +40 -3
- package/dist/index.js +92 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -23,12 +23,15 @@ __export(index_exports, {
|
|
|
23
23
|
Article: () => Article,
|
|
24
24
|
BlogPosting: () => BlogPosting,
|
|
25
25
|
BreadcrumbList: () => BreadcrumbList,
|
|
26
|
+
Event: () => Event,
|
|
26
27
|
FAQPage: () => FAQPage,
|
|
27
28
|
HowTo: () => HowTo,
|
|
29
|
+
LocalBusiness: () => LocalBusiness,
|
|
28
30
|
Location: () => Location,
|
|
29
31
|
Organization: () => Organization,
|
|
30
32
|
Person: () => Person,
|
|
31
33
|
Product: () => Product,
|
|
34
|
+
Review: () => Review,
|
|
32
35
|
SCHEMA_CONTEXT: () => SCHEMA_CONTEXT,
|
|
33
36
|
WebPage: () => WebPage,
|
|
34
37
|
WebSite: () => WebSite,
|
|
@@ -53,6 +56,7 @@ var withBase = (type, input) => {
|
|
|
53
56
|
var Organization = (input) => withBase("Organization", input);
|
|
54
57
|
var Person = (input) => withBase("Person", input);
|
|
55
58
|
var Location = (input) => withBase("Place", input);
|
|
59
|
+
var LocalBusiness = (input) => withBase("LocalBusiness", input);
|
|
56
60
|
var WebSite = (input) => withBase("WebSite", input);
|
|
57
61
|
var WebPage = (input) => withBase("WebPage", input);
|
|
58
62
|
var Article = (input) => {
|
|
@@ -87,6 +91,59 @@ var Product = (input) => {
|
|
|
87
91
|
} : {}
|
|
88
92
|
});
|
|
89
93
|
};
|
|
94
|
+
var Event = (input) => {
|
|
95
|
+
const {
|
|
96
|
+
locationName,
|
|
97
|
+
locationAddress,
|
|
98
|
+
locationUrl,
|
|
99
|
+
organizerName,
|
|
100
|
+
...rest
|
|
101
|
+
} = input;
|
|
102
|
+
return withBase("Event", {
|
|
103
|
+
...rest,
|
|
104
|
+
...locationName || locationAddress || locationUrl ? {
|
|
105
|
+
location: {
|
|
106
|
+
"@type": "Place",
|
|
107
|
+
...locationName ? { name: locationName } : {},
|
|
108
|
+
...locationAddress ? { address: locationAddress } : {},
|
|
109
|
+
...locationUrl ? { url: locationUrl } : {}
|
|
110
|
+
}
|
|
111
|
+
} : {},
|
|
112
|
+
...organizerName ? {
|
|
113
|
+
organizer: {
|
|
114
|
+
"@type": "Organization",
|
|
115
|
+
name: organizerName
|
|
116
|
+
}
|
|
117
|
+
} : {}
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
var Review = (input) => {
|
|
121
|
+
const {
|
|
122
|
+
itemName,
|
|
123
|
+
authorName,
|
|
124
|
+
ratingValue,
|
|
125
|
+
bestRating,
|
|
126
|
+
worstRating,
|
|
127
|
+
...rest
|
|
128
|
+
} = input;
|
|
129
|
+
return withBase("Review", {
|
|
130
|
+
...rest,
|
|
131
|
+
itemReviewed: {
|
|
132
|
+
"@type": "Thing",
|
|
133
|
+
name: itemName
|
|
134
|
+
},
|
|
135
|
+
author: {
|
|
136
|
+
"@type": "Person",
|
|
137
|
+
name: authorName
|
|
138
|
+
},
|
|
139
|
+
reviewRating: {
|
|
140
|
+
"@type": "Rating",
|
|
141
|
+
ratingValue,
|
|
142
|
+
...bestRating !== void 0 ? { bestRating } : {},
|
|
143
|
+
...worstRating !== void 0 ? { worstRating } : {}
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
};
|
|
90
147
|
var FAQPage = (input) => withBase("FAQPage", {
|
|
91
148
|
mainEntity: input.questions.map((item) => ({
|
|
92
149
|
"@type": "Question",
|
|
@@ -113,8 +170,9 @@ var BreadcrumbList = (input) => withBase("BreadcrumbList", {
|
|
|
113
170
|
item: item.useItemObject ? { "@id": item.url, name: item.name } : item.url
|
|
114
171
|
}))
|
|
115
172
|
});
|
|
116
|
-
var validateSchema = (nodes) => {
|
|
173
|
+
var validateSchema = (nodes, options = {}) => {
|
|
117
174
|
const issues = [];
|
|
175
|
+
const { recommended = true } = options;
|
|
118
176
|
if (!nodes.length) {
|
|
119
177
|
issues.push({
|
|
120
178
|
path: "root",
|
|
@@ -205,6 +263,20 @@ var validateSchema = (nodes) => {
|
|
|
205
263
|
});
|
|
206
264
|
}
|
|
207
265
|
}
|
|
266
|
+
if (recommended) {
|
|
267
|
+
const recommendedFields = RECOMMENDED_FIELDS[type] ?? [];
|
|
268
|
+
for (const field of recommendedFields) {
|
|
269
|
+
const value = node[field];
|
|
270
|
+
if (isEmpty(value)) {
|
|
271
|
+
issues.push({
|
|
272
|
+
path: `${pathPrefix}.${field}`,
|
|
273
|
+
message: `Recommended field '${field}' is missing`,
|
|
274
|
+
severity: "warn",
|
|
275
|
+
ruleId: `schema.recommended.${field}`
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
208
280
|
if (type === "BreadcrumbList") {
|
|
209
281
|
validateBreadcrumbList(node, pathPrefix, issues);
|
|
210
282
|
}
|
|
@@ -222,15 +294,34 @@ var REQUIRED_FIELDS = {
|
|
|
222
294
|
Organization: ["name"],
|
|
223
295
|
Person: ["name"],
|
|
224
296
|
Place: ["name"],
|
|
297
|
+
LocalBusiness: ["name"],
|
|
225
298
|
WebSite: ["name", "url"],
|
|
226
299
|
WebPage: ["name", "url"],
|
|
227
300
|
Article: ["headline", "author", "datePublished", "url"],
|
|
228
301
|
BlogPosting: ["headline", "author", "datePublished", "url"],
|
|
229
302
|
Product: ["name", "description", "url"],
|
|
303
|
+
Event: ["name", "startDate"],
|
|
304
|
+
Review: ["itemReviewed", "reviewRating", "author"],
|
|
230
305
|
FAQPage: ["mainEntity"],
|
|
231
306
|
HowTo: ["name", "step"],
|
|
232
307
|
BreadcrumbList: ["itemListElement"]
|
|
233
308
|
};
|
|
309
|
+
var RECOMMENDED_FIELDS = {
|
|
310
|
+
Organization: ["url", "logo", "sameAs"],
|
|
311
|
+
Person: ["url", "sameAs", "jobTitle"],
|
|
312
|
+
Place: ["address", "url"],
|
|
313
|
+
LocalBusiness: ["address", "telephone", "url"],
|
|
314
|
+
WebSite: ["description"],
|
|
315
|
+
WebPage: ["description", "isPartOf"],
|
|
316
|
+
Article: ["description", "image", "dateModified"],
|
|
317
|
+
BlogPosting: ["description", "image", "dateModified"],
|
|
318
|
+
Product: ["image", "brand", "sku"],
|
|
319
|
+
Event: ["description", "location", "organizer", "url"],
|
|
320
|
+
Review: ["reviewBody", "datePublished", "url"],
|
|
321
|
+
FAQPage: [],
|
|
322
|
+
HowTo: [],
|
|
323
|
+
BreadcrumbList: []
|
|
324
|
+
};
|
|
234
325
|
var isSchemaType = (value) => typeof value === "string" && value in REQUIRED_FIELDS;
|
|
235
326
|
var isEmpty = (value) => {
|
|
236
327
|
if (value === null || value === void 0) {
|
|
@@ -344,12 +435,15 @@ var stableStringify = (value) => JSON.stringify(sortKeys(value));
|
|
|
344
435
|
Article,
|
|
345
436
|
BlogPosting,
|
|
346
437
|
BreadcrumbList,
|
|
438
|
+
Event,
|
|
347
439
|
FAQPage,
|
|
348
440
|
HowTo,
|
|
441
|
+
LocalBusiness,
|
|
349
442
|
Location,
|
|
350
443
|
Organization,
|
|
351
444
|
Person,
|
|
352
445
|
Product,
|
|
446
|
+
Review,
|
|
353
447
|
SCHEMA_CONTEXT,
|
|
354
448
|
WebPage,
|
|
355
449
|
WebSite,
|
package/dist/index.d.cts
CHANGED
|
@@ -3,7 +3,7 @@ type JsonLdValue = string | number | boolean | null | JsonLdObject | JsonLdValue
|
|
|
3
3
|
type JsonLdObject = {
|
|
4
4
|
[key: string]: JsonLdValue;
|
|
5
5
|
};
|
|
6
|
-
type SchemaTypeName = "Organization" | "Person" | "Place" | "WebSite" | "WebPage" | "Article" | "BlogPosting" | "Product" | "FAQPage" | "HowTo" | "BreadcrumbList";
|
|
6
|
+
type SchemaTypeName = "Organization" | "Person" | "Place" | "LocalBusiness" | "WebSite" | "WebPage" | "Article" | "BlogPosting" | "Product" | "Event" | "Review" | "FAQPage" | "HowTo" | "BreadcrumbList";
|
|
7
7
|
type SchemaNode = JsonLdObject & {
|
|
8
8
|
"@context": typeof SCHEMA_CONTEXT;
|
|
9
9
|
"@type": SchemaTypeName;
|
|
@@ -33,6 +33,17 @@ type LocationInput = BaseInput & {
|
|
|
33
33
|
url?: string;
|
|
34
34
|
};
|
|
35
35
|
declare const Location: (input: LocationInput) => SchemaNode;
|
|
36
|
+
type LocalBusinessInput = BaseInput & {
|
|
37
|
+
name: string;
|
|
38
|
+
address?: string;
|
|
39
|
+
url?: string;
|
|
40
|
+
telephone?: string;
|
|
41
|
+
image?: string;
|
|
42
|
+
priceRange?: string;
|
|
43
|
+
sameAs?: string[];
|
|
44
|
+
description?: string;
|
|
45
|
+
};
|
|
46
|
+
declare const LocalBusiness: (input: LocalBusinessInput) => SchemaNode;
|
|
36
47
|
type WebSiteInput = BaseInput & {
|
|
37
48
|
name: string;
|
|
38
49
|
url: string;
|
|
@@ -67,6 +78,29 @@ type ProductInput = BaseInput & {
|
|
|
67
78
|
sku?: string;
|
|
68
79
|
};
|
|
69
80
|
declare const Product: (input: ProductInput) => SchemaNode;
|
|
81
|
+
type EventInput = BaseInput & {
|
|
82
|
+
name: string;
|
|
83
|
+
startDate: string;
|
|
84
|
+
endDate?: string;
|
|
85
|
+
url?: string;
|
|
86
|
+
description?: string;
|
|
87
|
+
locationName?: string;
|
|
88
|
+
locationAddress?: string;
|
|
89
|
+
locationUrl?: string;
|
|
90
|
+
organizerName?: string;
|
|
91
|
+
};
|
|
92
|
+
declare const Event: (input: EventInput) => SchemaNode;
|
|
93
|
+
type ReviewInput = BaseInput & {
|
|
94
|
+
itemName: string;
|
|
95
|
+
authorName: string;
|
|
96
|
+
ratingValue: number;
|
|
97
|
+
bestRating?: number;
|
|
98
|
+
worstRating?: number;
|
|
99
|
+
reviewBody?: string;
|
|
100
|
+
datePublished?: string;
|
|
101
|
+
url?: string;
|
|
102
|
+
};
|
|
103
|
+
declare const Review: (input: ReviewInput) => SchemaNode;
|
|
70
104
|
type FAQItem = {
|
|
71
105
|
question: string;
|
|
72
106
|
answer: string;
|
|
@@ -103,12 +137,15 @@ type ValidationIssue = {
|
|
|
103
137
|
severity: ValidationSeverity;
|
|
104
138
|
ruleId: string;
|
|
105
139
|
};
|
|
140
|
+
type ValidationOptions = {
|
|
141
|
+
recommended?: boolean;
|
|
142
|
+
};
|
|
106
143
|
type ValidationResult = {
|
|
107
144
|
ok: boolean;
|
|
108
145
|
score: number;
|
|
109
146
|
issues: ValidationIssue[];
|
|
110
147
|
};
|
|
111
|
-
declare const validateSchema: (nodes: SchemaNode[]) => ValidationResult;
|
|
148
|
+
declare const validateSchema: (nodes: SchemaNode[], options?: ValidationOptions) => ValidationResult;
|
|
112
149
|
declare const stableStringify: (value: JsonLdValue) => string;
|
|
113
150
|
|
|
114
|
-
export { Article, type ArticleInput, BlogPosting, type BlogPostingInput, type BreadcrumbItem, BreadcrumbList, type BreadcrumbListInput, type FAQItem, FAQPage, type FAQPageInput, HowTo, type HowToInput, type HowToStep, type JsonLdObject, type JsonLdValue, Location, type LocationInput, type Manifest, Organization, type OrganizationInput, Person, type PersonInput, Product, type ProductInput, SCHEMA_CONTEXT, type SchemaNode, type SchemaTypeName, type ValidationIssue, type ValidationResult, type ValidationSeverity, WebPage, type WebPageInput, WebSite, type WebSiteInput, stableStringify, validateSchema };
|
|
151
|
+
export { Article, type ArticleInput, BlogPosting, type BlogPostingInput, type BreadcrumbItem, BreadcrumbList, type BreadcrumbListInput, Event, type EventInput, type FAQItem, FAQPage, type FAQPageInput, HowTo, type HowToInput, type HowToStep, type JsonLdObject, type JsonLdValue, LocalBusiness, type LocalBusinessInput, Location, type LocationInput, type Manifest, Organization, type OrganizationInput, Person, type PersonInput, Product, type ProductInput, Review, type ReviewInput, SCHEMA_CONTEXT, type SchemaNode, type SchemaTypeName, type ValidationIssue, type ValidationOptions, type ValidationResult, type ValidationSeverity, WebPage, type WebPageInput, WebSite, type WebSiteInput, stableStringify, validateSchema };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ type JsonLdValue = string | number | boolean | null | JsonLdObject | JsonLdValue
|
|
|
3
3
|
type JsonLdObject = {
|
|
4
4
|
[key: string]: JsonLdValue;
|
|
5
5
|
};
|
|
6
|
-
type SchemaTypeName = "Organization" | "Person" | "Place" | "WebSite" | "WebPage" | "Article" | "BlogPosting" | "Product" | "FAQPage" | "HowTo" | "BreadcrumbList";
|
|
6
|
+
type SchemaTypeName = "Organization" | "Person" | "Place" | "LocalBusiness" | "WebSite" | "WebPage" | "Article" | "BlogPosting" | "Product" | "Event" | "Review" | "FAQPage" | "HowTo" | "BreadcrumbList";
|
|
7
7
|
type SchemaNode = JsonLdObject & {
|
|
8
8
|
"@context": typeof SCHEMA_CONTEXT;
|
|
9
9
|
"@type": SchemaTypeName;
|
|
@@ -33,6 +33,17 @@ type LocationInput = BaseInput & {
|
|
|
33
33
|
url?: string;
|
|
34
34
|
};
|
|
35
35
|
declare const Location: (input: LocationInput) => SchemaNode;
|
|
36
|
+
type LocalBusinessInput = BaseInput & {
|
|
37
|
+
name: string;
|
|
38
|
+
address?: string;
|
|
39
|
+
url?: string;
|
|
40
|
+
telephone?: string;
|
|
41
|
+
image?: string;
|
|
42
|
+
priceRange?: string;
|
|
43
|
+
sameAs?: string[];
|
|
44
|
+
description?: string;
|
|
45
|
+
};
|
|
46
|
+
declare const LocalBusiness: (input: LocalBusinessInput) => SchemaNode;
|
|
36
47
|
type WebSiteInput = BaseInput & {
|
|
37
48
|
name: string;
|
|
38
49
|
url: string;
|
|
@@ -67,6 +78,29 @@ type ProductInput = BaseInput & {
|
|
|
67
78
|
sku?: string;
|
|
68
79
|
};
|
|
69
80
|
declare const Product: (input: ProductInput) => SchemaNode;
|
|
81
|
+
type EventInput = BaseInput & {
|
|
82
|
+
name: string;
|
|
83
|
+
startDate: string;
|
|
84
|
+
endDate?: string;
|
|
85
|
+
url?: string;
|
|
86
|
+
description?: string;
|
|
87
|
+
locationName?: string;
|
|
88
|
+
locationAddress?: string;
|
|
89
|
+
locationUrl?: string;
|
|
90
|
+
organizerName?: string;
|
|
91
|
+
};
|
|
92
|
+
declare const Event: (input: EventInput) => SchemaNode;
|
|
93
|
+
type ReviewInput = BaseInput & {
|
|
94
|
+
itemName: string;
|
|
95
|
+
authorName: string;
|
|
96
|
+
ratingValue: number;
|
|
97
|
+
bestRating?: number;
|
|
98
|
+
worstRating?: number;
|
|
99
|
+
reviewBody?: string;
|
|
100
|
+
datePublished?: string;
|
|
101
|
+
url?: string;
|
|
102
|
+
};
|
|
103
|
+
declare const Review: (input: ReviewInput) => SchemaNode;
|
|
70
104
|
type FAQItem = {
|
|
71
105
|
question: string;
|
|
72
106
|
answer: string;
|
|
@@ -103,12 +137,15 @@ type ValidationIssue = {
|
|
|
103
137
|
severity: ValidationSeverity;
|
|
104
138
|
ruleId: string;
|
|
105
139
|
};
|
|
140
|
+
type ValidationOptions = {
|
|
141
|
+
recommended?: boolean;
|
|
142
|
+
};
|
|
106
143
|
type ValidationResult = {
|
|
107
144
|
ok: boolean;
|
|
108
145
|
score: number;
|
|
109
146
|
issues: ValidationIssue[];
|
|
110
147
|
};
|
|
111
|
-
declare const validateSchema: (nodes: SchemaNode[]) => ValidationResult;
|
|
148
|
+
declare const validateSchema: (nodes: SchemaNode[], options?: ValidationOptions) => ValidationResult;
|
|
112
149
|
declare const stableStringify: (value: JsonLdValue) => string;
|
|
113
150
|
|
|
114
|
-
export { Article, type ArticleInput, BlogPosting, type BlogPostingInput, type BreadcrumbItem, BreadcrumbList, type BreadcrumbListInput, type FAQItem, FAQPage, type FAQPageInput, HowTo, type HowToInput, type HowToStep, type JsonLdObject, type JsonLdValue, Location, type LocationInput, type Manifest, Organization, type OrganizationInput, Person, type PersonInput, Product, type ProductInput, SCHEMA_CONTEXT, type SchemaNode, type SchemaTypeName, type ValidationIssue, type ValidationResult, type ValidationSeverity, WebPage, type WebPageInput, WebSite, type WebSiteInput, stableStringify, validateSchema };
|
|
151
|
+
export { Article, type ArticleInput, BlogPosting, type BlogPostingInput, type BreadcrumbItem, BreadcrumbList, type BreadcrumbListInput, Event, type EventInput, type FAQItem, FAQPage, type FAQPageInput, HowTo, type HowToInput, type HowToStep, type JsonLdObject, type JsonLdValue, LocalBusiness, type LocalBusinessInput, Location, type LocationInput, type Manifest, Organization, type OrganizationInput, Person, type PersonInput, Product, type ProductInput, Review, type ReviewInput, SCHEMA_CONTEXT, type SchemaNode, type SchemaTypeName, type ValidationIssue, type ValidationOptions, type ValidationResult, type ValidationSeverity, WebPage, type WebPageInput, WebSite, type WebSiteInput, stableStringify, validateSchema };
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ var withBase = (type, input) => {
|
|
|
16
16
|
var Organization = (input) => withBase("Organization", input);
|
|
17
17
|
var Person = (input) => withBase("Person", input);
|
|
18
18
|
var Location = (input) => withBase("Place", input);
|
|
19
|
+
var LocalBusiness = (input) => withBase("LocalBusiness", input);
|
|
19
20
|
var WebSite = (input) => withBase("WebSite", input);
|
|
20
21
|
var WebPage = (input) => withBase("WebPage", input);
|
|
21
22
|
var Article = (input) => {
|
|
@@ -50,6 +51,59 @@ var Product = (input) => {
|
|
|
50
51
|
} : {}
|
|
51
52
|
});
|
|
52
53
|
};
|
|
54
|
+
var Event = (input) => {
|
|
55
|
+
const {
|
|
56
|
+
locationName,
|
|
57
|
+
locationAddress,
|
|
58
|
+
locationUrl,
|
|
59
|
+
organizerName,
|
|
60
|
+
...rest
|
|
61
|
+
} = input;
|
|
62
|
+
return withBase("Event", {
|
|
63
|
+
...rest,
|
|
64
|
+
...locationName || locationAddress || locationUrl ? {
|
|
65
|
+
location: {
|
|
66
|
+
"@type": "Place",
|
|
67
|
+
...locationName ? { name: locationName } : {},
|
|
68
|
+
...locationAddress ? { address: locationAddress } : {},
|
|
69
|
+
...locationUrl ? { url: locationUrl } : {}
|
|
70
|
+
}
|
|
71
|
+
} : {},
|
|
72
|
+
...organizerName ? {
|
|
73
|
+
organizer: {
|
|
74
|
+
"@type": "Organization",
|
|
75
|
+
name: organizerName
|
|
76
|
+
}
|
|
77
|
+
} : {}
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
var Review = (input) => {
|
|
81
|
+
const {
|
|
82
|
+
itemName,
|
|
83
|
+
authorName,
|
|
84
|
+
ratingValue,
|
|
85
|
+
bestRating,
|
|
86
|
+
worstRating,
|
|
87
|
+
...rest
|
|
88
|
+
} = input;
|
|
89
|
+
return withBase("Review", {
|
|
90
|
+
...rest,
|
|
91
|
+
itemReviewed: {
|
|
92
|
+
"@type": "Thing",
|
|
93
|
+
name: itemName
|
|
94
|
+
},
|
|
95
|
+
author: {
|
|
96
|
+
"@type": "Person",
|
|
97
|
+
name: authorName
|
|
98
|
+
},
|
|
99
|
+
reviewRating: {
|
|
100
|
+
"@type": "Rating",
|
|
101
|
+
ratingValue,
|
|
102
|
+
...bestRating !== void 0 ? { bestRating } : {},
|
|
103
|
+
...worstRating !== void 0 ? { worstRating } : {}
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
};
|
|
53
107
|
var FAQPage = (input) => withBase("FAQPage", {
|
|
54
108
|
mainEntity: input.questions.map((item) => ({
|
|
55
109
|
"@type": "Question",
|
|
@@ -76,8 +130,9 @@ var BreadcrumbList = (input) => withBase("BreadcrumbList", {
|
|
|
76
130
|
item: item.useItemObject ? { "@id": item.url, name: item.name } : item.url
|
|
77
131
|
}))
|
|
78
132
|
});
|
|
79
|
-
var validateSchema = (nodes) => {
|
|
133
|
+
var validateSchema = (nodes, options = {}) => {
|
|
80
134
|
const issues = [];
|
|
135
|
+
const { recommended = true } = options;
|
|
81
136
|
if (!nodes.length) {
|
|
82
137
|
issues.push({
|
|
83
138
|
path: "root",
|
|
@@ -168,6 +223,20 @@ var validateSchema = (nodes) => {
|
|
|
168
223
|
});
|
|
169
224
|
}
|
|
170
225
|
}
|
|
226
|
+
if (recommended) {
|
|
227
|
+
const recommendedFields = RECOMMENDED_FIELDS[type] ?? [];
|
|
228
|
+
for (const field of recommendedFields) {
|
|
229
|
+
const value = node[field];
|
|
230
|
+
if (isEmpty(value)) {
|
|
231
|
+
issues.push({
|
|
232
|
+
path: `${pathPrefix}.${field}`,
|
|
233
|
+
message: `Recommended field '${field}' is missing`,
|
|
234
|
+
severity: "warn",
|
|
235
|
+
ruleId: `schema.recommended.${field}`
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
171
240
|
if (type === "BreadcrumbList") {
|
|
172
241
|
validateBreadcrumbList(node, pathPrefix, issues);
|
|
173
242
|
}
|
|
@@ -185,15 +254,34 @@ var REQUIRED_FIELDS = {
|
|
|
185
254
|
Organization: ["name"],
|
|
186
255
|
Person: ["name"],
|
|
187
256
|
Place: ["name"],
|
|
257
|
+
LocalBusiness: ["name"],
|
|
188
258
|
WebSite: ["name", "url"],
|
|
189
259
|
WebPage: ["name", "url"],
|
|
190
260
|
Article: ["headline", "author", "datePublished", "url"],
|
|
191
261
|
BlogPosting: ["headline", "author", "datePublished", "url"],
|
|
192
262
|
Product: ["name", "description", "url"],
|
|
263
|
+
Event: ["name", "startDate"],
|
|
264
|
+
Review: ["itemReviewed", "reviewRating", "author"],
|
|
193
265
|
FAQPage: ["mainEntity"],
|
|
194
266
|
HowTo: ["name", "step"],
|
|
195
267
|
BreadcrumbList: ["itemListElement"]
|
|
196
268
|
};
|
|
269
|
+
var RECOMMENDED_FIELDS = {
|
|
270
|
+
Organization: ["url", "logo", "sameAs"],
|
|
271
|
+
Person: ["url", "sameAs", "jobTitle"],
|
|
272
|
+
Place: ["address", "url"],
|
|
273
|
+
LocalBusiness: ["address", "telephone", "url"],
|
|
274
|
+
WebSite: ["description"],
|
|
275
|
+
WebPage: ["description", "isPartOf"],
|
|
276
|
+
Article: ["description", "image", "dateModified"],
|
|
277
|
+
BlogPosting: ["description", "image", "dateModified"],
|
|
278
|
+
Product: ["image", "brand", "sku"],
|
|
279
|
+
Event: ["description", "location", "organizer", "url"],
|
|
280
|
+
Review: ["reviewBody", "datePublished", "url"],
|
|
281
|
+
FAQPage: [],
|
|
282
|
+
HowTo: [],
|
|
283
|
+
BreadcrumbList: []
|
|
284
|
+
};
|
|
197
285
|
var isSchemaType = (value) => typeof value === "string" && value in REQUIRED_FIELDS;
|
|
198
286
|
var isEmpty = (value) => {
|
|
199
287
|
if (value === null || value === void 0) {
|
|
@@ -306,12 +394,15 @@ export {
|
|
|
306
394
|
Article,
|
|
307
395
|
BlogPosting,
|
|
308
396
|
BreadcrumbList,
|
|
397
|
+
Event,
|
|
309
398
|
FAQPage,
|
|
310
399
|
HowTo,
|
|
400
|
+
LocalBusiness,
|
|
311
401
|
Location,
|
|
312
402
|
Organization,
|
|
313
403
|
Person,
|
|
314
404
|
Product,
|
|
405
|
+
Review,
|
|
315
406
|
SCHEMA_CONTEXT,
|
|
316
407
|
WebPage,
|
|
317
408
|
WebSite,
|