-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add validators for LocalBusiness, Article, Event, FAQPage, HowT… #58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
fe0f86b
9bb305c
a82c7af
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "Article", | ||
| "author": { | ||
| "@type": "Person", | ||
| "name": "Jane Doe" | ||
| }, | ||
| "datePublished": "2025-01-07" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "Article", | ||
| "headline": "How to Write Great Headlines", | ||
| "author": { | ||
| "@type": "Person", | ||
| "name": "Jane Doe" | ||
| }, | ||
| "publisher": { | ||
| "@type": "Organization", | ||
| "name": "Example News", | ||
| "logo": { | ||
| "@type": "ImageObject", | ||
| "url": "https://example.com/logo.png" | ||
| } | ||
| }, | ||
| "datePublished": "2025-01-07", | ||
| "dateModified": "2025-01-07", | ||
| "image": "https://example.com/article-image.jpg" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "Event", | ||
| "name": "The Adventures of Kira and Morrison", | ||
| "startDate": "2025-07-21T19:00-05:00" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "Event", | ||
| "startDate": "2025-07-21T19:00-05:00", | ||
| "location": { | ||
| "@type": "Place", | ||
| "name": "Snickerpark Stadium" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "Event", | ||
| "name": "The Adventures of Kira and Morrison", | ||
| "startDate": "2025-07-21T19:00-05:00", | ||
| "endDate": "2025-07-21T23:00-05:00", | ||
| "location": { | ||
| "@type": "Place", | ||
| "name": "Snickerpark Stadium", | ||
| "address": { | ||
| "@type": "PostalAddress", | ||
| "streetAddress": "100 West Snickerpark Dr", | ||
| "addressLocality": "Snickertown", | ||
| "postalCode": "19019", | ||
| "addressRegion": "PA", | ||
| "addressCountry": "US" | ||
| } | ||
| }, | ||
| "image": "https://example.com/event-image.jpg", | ||
| "description": "An amazing concert event", | ||
| "offers": { | ||
| "@type": "Offer", | ||
| "url": "https://example.com/tickets", | ||
| "price": "30", | ||
| "priceCurrency": "USD", | ||
| "availability": "https://schema.org/InStock" | ||
| }, | ||
| "performer": { | ||
| "@type": "Person", | ||
| "name": "Kira Morrison" | ||
| }, | ||
| "organizer": { | ||
| "@type": "Organization", | ||
| "name": "Concert Events Inc" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "Event", | ||
| "name": "Online Webinar: Introduction to Schema.org", | ||
| "startDate": "2025-07-21T19:00-05:00", | ||
| "eventAttendanceMode": "https://schema.org/OnlineEventAttendanceMode", | ||
| "eventStatus": "https://schema.org/EventScheduled", | ||
| "description": "Learn about structured data" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "FAQPage", | ||
| "name": "Frequently Asked Questions" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "FAQPage", | ||
| "mainEntity": [ | ||
| { | ||
| "@type": "Question", | ||
| "name": "What is structured data?", | ||
| "acceptedAnswer": { | ||
| "@type": "Answer", | ||
| "text": "Structured data is a standardized format for providing information about a page and classifying the page content." | ||
| } | ||
| }, | ||
| { | ||
| "@type": "Question", | ||
| "name": "Why is structured data important?", | ||
| "acceptedAnswer": { | ||
| "@type": "Answer", | ||
| "text": "Structured data helps search engines understand your content better and can enable rich results in search." | ||
| } | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "HowTo", | ||
| "step": [ | ||
| { | ||
| "@type": "HowToStep", | ||
| "text": "Do something" | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "HowTo", | ||
| "name": "How to Do Something" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "HowTo", | ||
| "name": "How to Change a Tire", | ||
| "description": "A step-by-step guide to changing a flat tire.", | ||
| "totalTime": "PT30M", | ||
| "estimatedCost": { | ||
| "@type": "MonetaryAmount", | ||
| "currency": "USD", | ||
| "value": "0" | ||
| }, | ||
| "supply": [ | ||
| { | ||
| "@type": "HowToSupply", | ||
| "name": "Spare tire" | ||
| }, | ||
| { | ||
| "@type": "HowToSupply", | ||
| "name": "Lug wrench" | ||
| } | ||
| ], | ||
| "tool": [ | ||
| { | ||
| "@type": "HowToTool", | ||
| "name": "Jack" | ||
| } | ||
| ], | ||
| "step": [ | ||
| { | ||
| "@type": "HowToStep", | ||
| "name": "Loosen the lug nuts", | ||
| "text": "Use the lug wrench to loosen the lug nuts on the flat tire." | ||
| }, | ||
| { | ||
| "@type": "HowToStep", | ||
| "name": "Jack up the car", | ||
| "text": "Place the jack under the car frame and raise the car." | ||
| }, | ||
| { | ||
| "@type": "HowToStep", | ||
| "name": "Remove the flat tire", | ||
| "text": "Remove the lug nuts and pull off the flat tire." | ||
| } | ||
| ], | ||
| "image": "https://example.com/tire-change.jpg" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "LocalBusiness", | ||
| "name": "Dave's Steak House" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "LocalBusiness", | ||
| "address": { | ||
| "@type": "PostalAddress", | ||
| "streetAddress": "123 Main St", | ||
| "addressLocality": "New York", | ||
| "addressRegion": "NY", | ||
| "postalCode": "10001", | ||
| "addressCountry": "US" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "LocalBusiness", | ||
| "name": "Dave's Steak House", | ||
| "address": { | ||
| "@type": "PostalAddress", | ||
| "streetAddress": "123 Main St", | ||
| "addressLocality": "New York", | ||
| "addressRegion": "NY", | ||
| "postalCode": "10001", | ||
| "addressCountry": "US" | ||
| }, | ||
| "telephone": "+1-212-555-1234", | ||
| "url": "https://www.davessteakhouse.example.com", | ||
| "image": "https://www.davessteakhouse.example.com/image.jpg", | ||
| "priceRange": "$$", | ||
| "geo": { | ||
| "@type": "GeoCoordinates", | ||
| "latitude": "40.7128", | ||
| "longitude": "-74.0060" | ||
| }, | ||
| "openingHoursSpecification": [ | ||
| { | ||
| "@type": "OpeningHoursSpecification", | ||
| "dayOfWeek": [ | ||
| "Monday", | ||
| "Tuesday", | ||
| "Wednesday", | ||
| "Thursday", | ||
| "Friday" | ||
| ], | ||
| "opens": "11:00", | ||
| "closes": "22:00" | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "WebSite", | ||
| "url": "https://www.example.com" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "WebSite", | ||
| "name": "Example Website" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| { | ||
| "@context": "https://schema.org", | ||
| "@type": "WebSite", | ||
| "name": "Example Website", | ||
| "url": "https://www.example.com", | ||
| "potentialAction": { | ||
| "@type": "SearchAction", | ||
| "target": { | ||
| "@type": "EntryPoint", | ||
| "urlTemplate": "https://www.example.com/search?q={search_term_string}" | ||
| }, | ||
| "query-input": "required name=search_term_string" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| /** | ||
| * Copyright 2025 Adobe. All rights reserved. | ||
| * This file is licensed to you under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. You may obtain a copy | ||
| * of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software distributed under | ||
| * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS | ||
| * OF ANY KIND, either express or implied. See the License for the specific language | ||
| * governing permissions and limitations under the License. | ||
| */ | ||
| import BaseValidator from './base.js'; | ||
|
|
||
| export default class AnswerValidator extends BaseValidator { | ||
| getConditions() { | ||
| return [this.required('text')].map((c) => c.bind(this)); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| /** | ||
| * Copyright 2025 Adobe. All rights reserved. | ||
| * This file is licensed to you under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. You may obtain a copy | ||
| * of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software distributed under | ||
| * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS | ||
| * OF ANY KIND, either express or implied. See the License for the specific language | ||
| * governing permissions and limitations under the License. | ||
| */ | ||
| import BaseValidator from './base.js'; | ||
|
|
||
| export default class ArticleValidator extends BaseValidator { | ||
| getConditions() { | ||
| return [ | ||
| this.required('headline'), | ||
|
|
||
| this.recommended('author', 'arrayOrObject'), | ||
| this.recommended('dateModified', 'date'), | ||
| this.recommended('datePublished', 'date'), | ||
| this.recommended('image', 'arrayOrObject'), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can be an URL as string as well. |
||
| this.recommended('publisher', 'object'), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This attribute is optional according to the documentation. Basically recommending that the publisher of an article should not be listed as part of the https://developers.google.com/search/docs/appearance/structured-data/article |
||
| ].map((c) => c.bind(this)); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| /** | ||
| * Copyright 2025 Adobe. All rights reserved. | ||
| * This file is licensed to you under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. You may obtain a copy | ||
| * of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software distributed under | ||
| * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS | ||
| * OF ANY KIND, either express or implied. See the License for the specific language | ||
| * governing permissions and limitations under the License. | ||
| */ | ||
| import BaseValidator from './base.js'; | ||
|
|
||
| export default class EventValidator extends BaseValidator { | ||
| getConditions() { | ||
| return [ | ||
| this.required('name'), | ||
| this.required('startDate', 'date'), | ||
| this.locationOrAttendanceMode, | ||
|
|
||
| this.recommended('description'), | ||
| this.recommended('endDate', 'date'), | ||
| this.recommended('eventAttendanceMode'), | ||
| this.recommended('eventStatus'), | ||
| this.recommended('image', 'arrayOrObject'), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could also be an URL as string. |
||
| this.recommended('offers', 'arrayOrObject'), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please adjust the |
||
| this.recommended('organizer', 'object'), | ||
| this.recommended('performer', 'arrayOrObject'), | ||
| ].map((c) => c.bind(this)); | ||
| } | ||
|
|
||
| locationOrAttendanceMode(data) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should probably also check for |
||
| const hasLocation = data.location !== undefined && data.location !== null; | ||
| const hasOnlineAttendanceMode = | ||
| data.eventAttendanceMode && | ||
| (data.eventAttendanceMode.includes('OnlineEventAttendanceMode') || | ||
| data.eventAttendanceMode.includes('MixedEventAttendanceMode')); | ||
|
|
||
| if (!hasLocation && !hasOnlineAttendanceMode) { | ||
| return { | ||
| issueMessage: | ||
| 'Either "location" or online "eventAttendanceMode" is required', | ||
| severity: 'ERROR', | ||
| path: this.path, | ||
| fieldName: 'location', | ||
| fieldNames: ['location', 'eventAttendanceMode'], | ||
| }; | ||
| } | ||
| return null; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| /** | ||
| * Copyright 2025 Adobe. All rights reserved. | ||
| * This file is licensed to you under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. You may obtain a copy | ||
| * of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software distributed under | ||
| * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS | ||
| * OF ANY KIND, either express or implied. See the License for the specific language | ||
| * governing permissions and limitations under the License. | ||
| */ | ||
| import BaseValidator from './base.js'; | ||
|
|
||
| export default class FAQPageValidator extends BaseValidator { | ||
| getConditions() { | ||
| return [this.required('mainEntity', 'arrayOrObject')].map((c) => c.bind(this)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please additionally check that https://developers.google.com/search/docs/appearance/structured-data/faqpage#faq-page |
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the documentation,
headlineis only a recommended property.https://developers.google.com/search/docs/appearance/structured-data/article