Skip to content

Commit

Permalink
add additional validation
Browse files Browse the repository at this point in the history
  • Loading branch information
benlife5 committed Jan 6, 2025
1 parent 0c6a5db commit 2bf105b
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,31 @@ type RTF2 = {
json?: Record<string, any>;
};

type FAQ =
| {
question: string;
answer: string;
}
| {
question: string;
answerV2: RTF2;
};
type FAQ = PlainTextFAQ | RichTextFAQ;

type PlainTextFAQ = {
question: string;
answer: string;
};

type RichTextFAQ = {
question: string;
answerV2: RTF2;
};

const validatePlainTextFAQ = (faq: any): faq is PlainTextFAQ => {
if (typeof faq !== "object") {
return false;
}
return "question" in faq && "answer" in faq;
};

const validateRichTextFAQ = (faq: any): faq is RichTextFAQ => {
if (typeof faq === "object" && "question" in faq && "answerV2" in faq) {
return "json" in faq.answerV2 && typeof faq.answerV2.json === "object";
}
return false;
};

function getTextNodesFromJson(
rtfObject: Record<string, any>,
Expand Down Expand Up @@ -51,7 +67,7 @@ const FAQPage = (data: FAQ[]) => {
"@context": "http://www.schema.org",
"@type": "FAQPage",
mainEntity: data.map((faq) => {
if (typeof faq !== "object") {
if (!(validatePlainTextFAQ(faq) || validateRichTextFAQ(faq))) {
return undefined;
}
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,29 @@ export type Location = {
address?: AddressType;
};

const validateLocation = (location: any): location is Location => {
if (typeof location !== "object") {
return false;
}
return "name" in location || "address" in location;
};

const validateAddress = (address: any): address is AddressType => {
if (typeof address !== "object") {
return false;
}
return (
"line1" in address ||
"city" in address ||
"region" in address ||
"postalCode" in address ||
"countryCode" in address
);
};

export const AddressSchema = (address?: AddressType) => {
return (
address && {
validateAddress(address) && {
address: {
"@type": "PostalAddress",
streetAddress: address.line1,
Expand All @@ -22,7 +42,7 @@ export const AddressSchema = (address?: AddressType) => {

export const LocationSchema = (location?: Location) => {
return (
location && {
validateLocation(location) && {
"@type": "Place",
name: location.name,
...AddressSchema(location.address),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,42 @@
import { HoursType, DayType } from "../../hours/types.js";

const validateHoursType = (hours: any): hours is HoursType => {
if (typeof hours !== "object") {
return false;
}
return (
"monday" in hours ||
"tuesday" in hours ||
"wednesday" in hours ||
"thursday" in hours ||
"friday" in hours ||
"saturday" in hours ||
"sunday" in hours
);
};

const validateDayType = (hours: any): hours is DayType => {
if (
typeof hours === "object" &&
"isClosed" in hours &&
Array.isArray(hours.openIntervals)
) {
if (hours.openIntervals.length === 0) {
return true;
}
let result = true
hours.openIntervals.forEach((interval : any) => {
result = result && typeof interval === "object" && "start" in interval && "end" in interval
})
return result
}
return false;
};

// example output: ["Mo-Fr 10:00-19:00", "Sa 10:00-22:00", "Su 10:00-21:00"]
// weekdays are indicated as Mo, Tu, We, Th, Fr, Sa, Su
export const OpeningHoursSchema = (hours?: HoursType) => {
if (!hours?.monday) {
if (!validateHoursType(hours)) {
return {};
}

Expand Down Expand Up @@ -34,7 +67,7 @@ const getHoursByDay = (
hoursMap: Map<string, Array<string>>,
day: string
) => {
if (!hours || hours.isClosed) {
if (!validateDayType(hours) || hours.isClosed) {
const interval = "00:00-00:00";
const days = hoursMap.get(interval) ?? [];
days.push(day);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,23 @@ export type Offer = {
availability?: string;
};

const validateOffer = (offer: any): offer is Offer => {
if (typeof offer !== "object") {
return false;
}
return (
"url" in offer ||
"priceCurrency" in offer ||
"price" in offer ||
"priceValidUntil" in offer ||
"itemCondition" in offer ||
"availability" in offer
);
};

export const OfferSchema = (offer?: Offer) => {
return (
offer && {
validateOffer(offer) && {
offers: {
"@type": "Offer",
url: offer.url,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,20 @@ export type Organization = {
url?: string;
};

const validateOrganization = (org: any): org is Organization => {
if (typeof org !== "object") {
return false;
}
return "url" in org || "name" in org;
};

const validatePerformers = (performers: any): performers is any[] => {
return Array.isArray(performers);
};

export const PerformerSchema = (performers?: string[]) => {
return (
performers && {
validatePerformers(performers) && {
performer: {
"@type": "PerformingGroup",
name: performers.join(" and "),
Expand All @@ -16,7 +27,7 @@ export const PerformerSchema = (performers?: string[]) => {

export const OrganizationSchema = (org?: Organization) => {
return (
org && {
validateOrganization(org) && {
organizer: {
"@type": "Organization",
name: org.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ type Photo = {
image: ImageType;
};

const validatePhoto = (photo: any): photo is Photo => {
if (typeof photo !== "object" || !("image" in photo)) {
return false;
}
return "url" in photo.image;
};

// takes in a list of Yext images and return a list of image urls
export const PhotoGallerySchema = (gallery?: PhotoGallery) => {
if (!gallery) {
Expand All @@ -15,7 +22,9 @@ export const PhotoGallerySchema = (gallery?: PhotoGallery) => {
const imageArray = new Array<string>();

for (const photo of gallery) {
imageArray.push(photo.image.url);
if (validatePhoto(photo)) {
imageArray.push(photo.image.url);
}
}

return {
Expand All @@ -26,7 +35,7 @@ export const PhotoGallerySchema = (gallery?: PhotoGallery) => {
// takes in a single Yext image
export const PhotoSchema = (photo?: Photo) => {
return (
photo && {
validatePhoto(photo) && {
image: photo.image.url,
}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,30 @@ export type Review = {
author?: string;
};

const validateReview = (review: any): review is Review => {
if (typeof review !== "object") {
return false;
}
return "ratingValue" in review || "bestRating" in review || "author" in review;
};

export type AggregateRating = {
ratingValue?: string;
reviewCount?: string;
};

const validateAggregateRating = (
aggregateRating: any
): aggregateRating is AggregateRating => {
if (typeof aggregateRating !== "object") {
return false;
}
return "ratingValue" in aggregateRating || "reviewCount" in aggregateRating;
};

export const ReviewSchema = (review?: Review) => {
return (
review && {
validateReview(review) && {
review: {
"@type": "Review",
reviewRating: {
Expand All @@ -29,13 +45,13 @@ export const ReviewSchema = (review?: Review) => {
};

export const AggregateRatingSchema = (rating?: AggregateRating) => {
return (
rating && {
aggregateRating: {
"@type": "AggregateRating",
ratingValue: rating.ratingValue,
reviewCount: rating.reviewCount,
},
}
);
return validateAggregateRating(rating)
? {
aggregateRating: {
"@type": "AggregateRating",
ratingValue: rating.ratingValue,
reviewCount: rating.reviewCount,
},
}
: undefined;
};

0 comments on commit 2bf105b

Please sign in to comment.