UNPKG

next-seo

Version:

SEO plugin for Next.js projects

1,744 lines (1,735 loc) 105 kB
var __defProp = Object.defineProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; // src/utils/stringify.ts var safeJsonLdReplacer = /* @__PURE__ */ (() => { return (_, value) => { switch (typeof value) { case "object": if (value === null) { return void 0; } return value; // JSON.stringify will recursively call replacer. case "number": case "boolean": case "bigint": case "string": return value; // Return all primitive values as-is default: { isNever(value); return void 0; } } }; })(); function isNever(_) { } var stringify = (data) => { const jsonString = JSON.stringify(data, safeJsonLdReplacer); return jsonString.replace(/<\/script>/gi, "\\u003C/script>").replace(/<!--/g, "\\u003C!--").replace(/-->/g, "--\\u003E"); }; // src/core/JsonLdScript.tsx import { jsx } from "react/jsx-runtime"; function JsonLdScript({ data, id, scriptKey }) { if (data === null || data === void 0) { return null; } const jsonString = stringify(data); return /* @__PURE__ */ jsx( "script", { type: "application/ld+json", id: id || scriptKey, "data-testid": id, dangerouslySetInnerHTML: { __html: jsonString } }, scriptKey ); } // src/utils/processors.export.ts var processors_export_exports = {}; __export(processors_export_exports, { processAccommodation: () => processAccommodation, processAddress: () => processAddress, processAggregateOffer: () => processAggregateOffer, processAggregateRating: () => processAggregateRating, processAppearance: () => processAppearance, processApplicantLocationRequirements: () => processApplicantLocationRequirements, processAuthor: () => processAuthor, processBedDetails: () => processBedDetails, processBrand: () => processBrand, processBreadcrumbItem: () => processBreadcrumbItem, processBroadcastEvent: () => processBroadcastEvent, processCertification: () => processCertification, processClaim: () => processClaim, processClaimReviewRating: () => processClaimReviewRating, processClip: () => processClip, processComment: () => processComment, processContactPoint: () => processContactPoint, processCreator: () => processCreator, processDataCatalog: () => processDataCatalog, processDataDownload: () => processDataDownload, processDefinedRegion: () => processDefinedRegion, processDirector: () => processDirector, processEducationRequirements: () => processEducationRequirements, processEstimatedCost: () => processEstimatedCost, processExperienceRequirements: () => processExperienceRequirements, processFeatureList: () => processFeatureList, processFunder: () => processFunder, processGeo: () => processGeo, processHiringOrganization: () => processHiringOrganization, processHowToDirection: () => processHowToDirection, processHowToSection: () => processHowToSection, processHowToStep: () => processHowToStep, processHowToSupply: () => processHowToSupply, processHowToTip: () => processHowToTip, processHowToTool: () => processHowToTool, processHowToYield: () => processHowToYield, processIdentifier: () => processIdentifier, processImage: () => processImage, processInstruction: () => processInstruction, processInteractionStatistic: () => processInteractionStatistic, processIsPartOf: () => processIsPartOf, processItemReviewed: () => processItemReviewed, processJobLocation: () => processJobLocation, processJobPropertyValue: () => processJobPropertyValue, processLicense: () => processLicense, processLocationFeatureSpecification: () => processLocationFeatureSpecification, processLogo: () => processLogo, processMainEntityOfPage: () => processMainEntityOfPage, processMemberProgram: () => processMemberProgram, processMemberProgramTier: () => processMemberProgramTier, processMembershipPointsEarned: () => processMembershipPointsEarned, processMerchantReturnPolicy: () => processMerchantReturnPolicy, processMonetaryAmount: () => processMonetaryAmount, processNumberOfEmployees: () => processNumberOfEmployees, processNutrition: () => processNutrition, processOffer: () => processOffer, processOfferShippingDetails: () => processOfferShippingDetails, processOpeningHours: () => processOpeningHours, processOrganization: () => processOrganization, processOrganizer: () => processOrganizer, processPeopleAudience: () => processPeopleAudience, processPerformer: () => processPerformer, processPlace: () => processPlace, processPriceSpecification: () => processPriceSpecification, processProductItemList: () => processProductItemList, processProductOffer: () => processProductOffer, processProductReview: () => processProductReview, processProductVariant: () => processProductVariant, processProvider: () => processProvider, processPublisher: () => processPublisher, processQuantitativeValue: () => processQuantitativeValue, processRating: () => processRating, processReturnPolicySeasonalOverride: () => processReturnPolicySeasonalOverride, processReview: () => processReview, processSchemaType: () => processSchemaType, processScreenshot: () => processScreenshot, processSeekToAction: () => processSeekToAction, processSharedContent: () => processSharedContent, processShippingDeliveryTime: () => processShippingDeliveryTime, processSimpleMonetaryAmount: () => processSimpleMonetaryAmount, processSizeSpecification: () => processSizeSpecification, processSpatialCoverage: () => processSpatialCoverage, processStep: () => processStep, processThreeDModel: () => processThreeDModel, processTierBenefit: () => processTierBenefit, processTierRequirement: () => processTierRequirement, processUnitPriceSpecification: () => processUnitPriceSpecification, processVariesBy: () => processVariesBy, processVideo: () => processVideo, processWebPageElement: () => processWebPageElement }); // src/utils/processors.ts var SCHEMA_TYPES = { PERSON: "Person", ORGANIZATION: "Organization", IMAGE_OBJECT: "ImageObject", POSTAL_ADDRESS: "PostalAddress", CONTACT_POINT: "ContactPoint", QUANTITATIVE_VALUE: "QuantitativeValue", GEO_COORDINATES: "GeoCoordinates", GEO_SHAPE: "GeoShape", OPENING_HOURS: "OpeningHoursSpecification", REVIEW: "Review", RATING: "Rating", AGGREGATE_RATING: "AggregateRating", MERCHANT_RETURN_POLICY: "MerchantReturnPolicy", MERCHANT_RETURN_POLICY_SEASONAL_OVERRIDE: "MerchantReturnPolicySeasonalOverride", MONETARY_AMOUNT: "MonetaryAmount", VIDEO_OBJECT: "VideoObject", INTERACTION_COUNTER: "InteractionCounter", BRAND: "Brand", CREDIT_CARD: "CreditCard", UNIT_PRICE_SPECIFICATION: "UnitPriceSpecification", MEMBER_PROGRAM: "MemberProgram", MEMBER_PROGRAM_TIER: "MemberProgramTier", BED_DETAILS: "BedDetails", LOCATION_FEATURE: "LocationFeatureSpecification", ACCOMMODATION: "Accommodation", PLACE: "Place", PERFORMING_GROUP: "PerformingGroup", OFFER: "Offer", AGGREGATE_OFFER: "AggregateOffer", PRICE_SPECIFICATION: "PriceSpecification", ITEM_LIST: "ItemList", LIST_ITEM: "ListItem", PRODUCT: "Product", PRODUCT_GROUP: "ProductGroup", NUTRITION_INFORMATION: "NutritionInformation", HOW_TO_STEP: "HowToStep", HOW_TO_SECTION: "HowToSection", HOW_TO_SUPPLY: "HowToSupply", HOW_TO_TOOL: "HowToTool", HOW_TO_DIRECTION: "HowToDirection", HOW_TO_TIP: "HowToTip", PROPERTY_VALUE: "PropertyValue", CREATIVE_WORK: "CreativeWork", DATA_DOWNLOAD: "DataDownload", DATA_CATALOG: "DataCatalog", COUNTRY: "Country", STATE: "State", EDUCATIONAL_CREDENTIAL: "EducationalOccupationalCredential", OCCUPATIONAL_EXPERIENCE: "OccupationalExperienceRequirements", COMMENT: "Comment", WEB_PAGE: "WebPage", WEB_PAGE_ELEMENT: "WebPageElement", CLAIM: "Claim", CERTIFICATION: "Certification", PEOPLE_AUDIENCE: "PeopleAudience", SIZE_SPECIFICATION: "SizeSpecification", THREE_D_MODEL: "3DModel", DEFINED_REGION: "DefinedRegion", SHIPPING_DELIVERY_TIME: "ShippingDeliveryTime", OFFER_SHIPPING_DETAILS: "OfferShippingDetails" }; function hasType(obj) { return obj !== null && typeof obj === "object" && "@type" in obj; } function isString(value) { return typeof value === "string"; } function processSchemaType(value, schemaType, stringHandler, numberHandler) { if (isString(value) && stringHandler) { return { "@type": schemaType, ...stringHandler(value) }; } if (typeof value === "number" && numberHandler) { return { "@type": schemaType, ...numberHandler(value) }; } if (hasType(value)) { return value; } if (typeof value === "object" && value !== null) { return { "@type": schemaType, ...value }; } return { "@type": schemaType }; } function processOrganizationFields(org) { if (org.logo && !isString(org.logo)) { org.logo = processLogo(org.logo); } if (org.address && !isString(org.address)) { if (Array.isArray(org.address)) { org.address = org.address.map( (addr) => isString(addr) ? addr : processAddress(addr) ); } else { org.address = processAddress(org.address); } } if (org.contactPoint) { if (Array.isArray(org.contactPoint)) { org.contactPoint = org.contactPoint.map(processContactPoint); } else { org.contactPoint = processContactPoint(org.contactPoint); } } } function processAuthor(author) { if (isString(author)) { const orgIndicators = [ "magazine", "publication", "company", "corporation", "corp", "inc", "llc", "ltd", "limited", "group", "foundation", "institute", "association", "society", "union", "times", "news", "press", "media", "network", "agency", "studio" ]; const lowerName = author.toLowerCase(); const isLikelyOrg = orgIndicators.some( (indicator) => lowerName.includes(indicator) ); if (isLikelyOrg) { return { "@type": SCHEMA_TYPES.ORGANIZATION, name: author }; } return { "@type": SCHEMA_TYPES.PERSON, name: author }; } if (hasType(author)) { return author; } const hasOrgProperties = "logo" in author || "address" in author || "contactPoint" in author; if (hasOrgProperties) { const org = { "@type": SCHEMA_TYPES.ORGANIZATION, ...author }; processOrganizationFields(org); return org; } return { "@type": SCHEMA_TYPES.PERSON, ...author }; } function processImage(image) { if (isString(image)) { return image; } return processSchemaType(image, SCHEMA_TYPES.IMAGE_OBJECT); } function processAddress(address) { return processSchemaType( address, SCHEMA_TYPES.POSTAL_ADDRESS, (str) => ({ streetAddress: str }), void 0 ); } function processContactPoint(contactPoint) { return processSchemaType( contactPoint, SCHEMA_TYPES.CONTACT_POINT ); } function processLogo(logo) { return processImage(logo); } function processNumberOfEmployees(numberOfEmployees) { return processSchemaType( numberOfEmployees, SCHEMA_TYPES.QUANTITATIVE_VALUE, void 0, (num) => ({ value: num }) ); } function processGeo(geo) { return processSchemaType(geo, SCHEMA_TYPES.GEO_COORDINATES); } function processOpeningHours(hours) { return processSchemaType( hours, SCHEMA_TYPES.OPENING_HOURS ); } function processReview(review) { const processed = processSchemaType( review, SCHEMA_TYPES.REVIEW ); if (review.reviewRating) { processed.reviewRating = processSchemaType( review.reviewRating, SCHEMA_TYPES.RATING ); } if (review.author) { processed.author = processAuthor(review.author); } return processed; } function processBreadcrumbItem(item, position) { return { "@type": SCHEMA_TYPES.LIST_ITEM, position, ...item.name && { name: item.name }, ...item.item && { item: item.item } }; } function processPlace(location) { return processSchemaType( location, SCHEMA_TYPES.PLACE, (str) => ({ name: str, address: { "@type": SCHEMA_TYPES.POSTAL_ADDRESS, streetAddress: str } }), void 0 ); } function processPerformer(performer) { if (isString(performer)) { return { "@type": SCHEMA_TYPES.PERFORMING_GROUP, name: performer }; } if (hasType(performer)) { return performer; } const hasPersonProperties = "familyName" in performer || "givenName" in performer || "additionalName" in performer; return hasPersonProperties ? { "@type": SCHEMA_TYPES.PERSON, ...performer } : { "@type": SCHEMA_TYPES.PERFORMING_GROUP, ...performer }; } function processOrganizer(organizer) { if (isString(organizer)) { return { "@type": SCHEMA_TYPES.ORGANIZATION, name: organizer }; } if (hasType(organizer)) { return organizer; } const hasPersonProperties = "familyName" in organizer || "givenName" in organizer || "additionalName" in organizer; return hasPersonProperties ? { "@type": SCHEMA_TYPES.PERSON, ...organizer } : { "@type": SCHEMA_TYPES.ORGANIZATION, ...organizer }; } function processOrganization(org) { if (isString(org)) { return { "@type": SCHEMA_TYPES.ORGANIZATION, name: org }; } const processed = processSchemaType( org, SCHEMA_TYPES.ORGANIZATION ); processOrganizationFields(processed); return processed; } function processOffer(offer) { return processSchemaType(offer, SCHEMA_TYPES.OFFER); } function processPublisher(publisher) { if (isString(publisher)) { return { "@type": SCHEMA_TYPES.ORGANIZATION, name: publisher }; } if (hasType(publisher) && publisher["@type"] === SCHEMA_TYPES.ORGANIZATION) { const org2 = { ...publisher }; processOrganizationFields(org2); return org2; } if (hasType(publisher)) { return publisher; } const org = { "@type": SCHEMA_TYPES.ORGANIZATION, ...publisher }; processOrganizationFields(org); return org; } function processNutrition(nutrition) { return { "@type": SCHEMA_TYPES.NUTRITION_INFORMATION, ...nutrition }; } function processAggregateRating(rating) { return processSchemaType( rating, SCHEMA_TYPES.AGGREGATE_RATING ); } function processMainEntityOfPage(mainEntityOfPage) { if (isString(mainEntityOfPage)) { return mainEntityOfPage; } return processSchemaType(mainEntityOfPage, SCHEMA_TYPES.WEB_PAGE); } function processSimpleMonetaryAmount(amount) { if (!amount) return void 0; if (typeof amount === "number") { return { "@type": SCHEMA_TYPES.MONETARY_AMOUNT, value: amount, currency: "USD" // Default currency, should be overridden in component }; } return processSchemaType( amount, SCHEMA_TYPES.MONETARY_AMOUNT ); } function processReturnPolicySeasonalOverride(override) { return processSchemaType( override, SCHEMA_TYPES.MERCHANT_RETURN_POLICY_SEASONAL_OVERRIDE ); } function processMerchantReturnPolicy(policy) { if (!policy) return policy; const processed = processSchemaType( policy, SCHEMA_TYPES.MERCHANT_RETURN_POLICY ); if (processed.applicableCountry && !Array.isArray(processed.applicableCountry)) { processed.applicableCountry = [processed.applicableCountry]; } if (processed.returnPolicyCountry && !Array.isArray(processed.returnPolicyCountry)) { processed.returnPolicyCountry = [processed.returnPolicyCountry]; } if (processed.returnMethod && !Array.isArray(processed.returnMethod)) { processed.returnMethod = [processed.returnMethod]; } if (processed.refundType && !Array.isArray(processed.refundType)) { processed.refundType = [processed.refundType]; } if (processed.itemCondition && !Array.isArray(processed.itemCondition)) { processed.itemCondition = [processed.itemCondition]; } if (processed.returnShippingFeesAmount) { processed.returnShippingFeesAmount = processSimpleMonetaryAmount( processed.returnShippingFeesAmount ); } if (processed.customerRemorseReturnShippingFeesAmount) { processed.customerRemorseReturnShippingFeesAmount = processSimpleMonetaryAmount( processed.customerRemorseReturnShippingFeesAmount ); } if (processed.itemDefectReturnShippingFeesAmount) { processed.itemDefectReturnShippingFeesAmount = processSimpleMonetaryAmount( processed.itemDefectReturnShippingFeesAmount ); } if (processed.restockingFee && typeof processed.restockingFee === "object") { processed.restockingFee = processSimpleMonetaryAmount( processed.restockingFee ); } if (processed.returnPolicySeasonalOverride) { if (Array.isArray(processed.returnPolicySeasonalOverride)) { processed.returnPolicySeasonalOverride = processed.returnPolicySeasonalOverride.map( processReturnPolicySeasonalOverride ); } else { processed.returnPolicySeasonalOverride = processReturnPolicySeasonalOverride( processed.returnPolicySeasonalOverride ); } } return processed; } function processTierRequirement(requirement) { if (!requirement) return requirement; if (isString(requirement)) { return requirement; } if (hasType(requirement)) { return requirement; } if ("priceCurrency" in requirement && "price" in requirement) { if ("billingDuration" in requirement || "billingIncrement" in requirement || "unitCode" in requirement) { return { "@type": SCHEMA_TYPES.UNIT_PRICE_SPECIFICATION, ...requirement }; } } if ("value" in requirement && "currency" in requirement) { return { "@type": SCHEMA_TYPES.MONETARY_AMOUNT, ...requirement }; } if ("name" in requirement) { return { "@type": SCHEMA_TYPES.CREDIT_CARD, ...requirement }; } return requirement; } function processTierBenefit(benefit) { const normalizeBenefit = (b) => { if (b.startsWith("https://schema.org/")) { return b; } if (b === "TierBenefitLoyaltyPoints") { return "https://schema.org/TierBenefitLoyaltyPoints"; } if (b === "TierBenefitLoyaltyPrice") { return "https://schema.org/TierBenefitLoyaltyPrice"; } return b; }; if (Array.isArray(benefit)) { return benefit.map(normalizeBenefit); } return normalizeBenefit(benefit); } function processMembershipPointsEarned(points) { if (typeof points === "number") { return { "@type": SCHEMA_TYPES.QUANTITATIVE_VALUE, value: points }; } return processSchemaType( points, SCHEMA_TYPES.QUANTITATIVE_VALUE ); } function processMemberProgramTier(tier) { const processed = processSchemaType( tier, SCHEMA_TYPES.MEMBER_PROGRAM_TIER ); if (processed.hasTierBenefit) { processed.hasTierBenefit = processTierBenefit(processed.hasTierBenefit); } if (processed.hasTierRequirement) { processed.hasTierRequirement = processTierRequirement( processed.hasTierRequirement ); } if (processed.membershipPointsEarned !== void 0) { processed.membershipPointsEarned = processMembershipPointsEarned( processed.membershipPointsEarned ); } return processed; } function processMemberProgram(program) { const processed = processSchemaType( program, SCHEMA_TYPES.MEMBER_PROGRAM ); if (processed.hasTiers) { if (Array.isArray(processed.hasTiers)) { processed.hasTiers = processed.hasTiers.map(processMemberProgramTier); } else { processed.hasTiers = processMemberProgramTier(processed.hasTiers); } } return processed; } function processVideo(video) { return processSchemaType(video, SCHEMA_TYPES.VIDEO_OBJECT); } function processBroadcastEvent(broadcast) { if (!broadcast) return broadcast; if (typeof broadcast === "object" && !("@type" in broadcast)) { return { "@type": "BroadcastEvent", ...broadcast }; } return broadcast; } function processClip(clip) { if (!clip) return clip; if (typeof clip === "object" && !("@type" in clip)) { return { "@type": "Clip", ...clip }; } return clip; } function processSeekToAction(action) { if (!action) return action; if (typeof action === "object" && !("@type" in action)) { return { "@type": "SeekToAction", ...action }; } return action; } function processInstruction(instruction) { if (isString(instruction)) { return instruction; } if (hasType(instruction)) { if (instruction["@type"] === SCHEMA_TYPES.HOW_TO_SECTION && "itemListElement" in instruction) { return { ...instruction, itemListElement: instruction.itemListElement.map( (item) => processInstruction(item) ) }; } return instruction; } if ("itemListElement" in instruction) { return { "@type": SCHEMA_TYPES.HOW_TO_SECTION, ...instruction, itemListElement: instruction.itemListElement.map( (item) => processInstruction(item) ) }; } return { "@type": SCHEMA_TYPES.HOW_TO_STEP, ...instruction }; } function processDirector(director) { return processSchemaType( director, SCHEMA_TYPES.PERSON, (str) => ({ name: str }), void 0 ); } function processCreator(creator) { return Array.isArray(creator) ? creator.map(processAuthor) : processAuthor(creator); } function processIdentifier(identifier) { if (isString(identifier)) { return identifier; } return processSchemaType( identifier, SCHEMA_TYPES.PROPERTY_VALUE ); } function processSpatialCoverage(spatial) { if (isString(spatial)) { return spatial; } const processed = processSchemaType( spatial, SCHEMA_TYPES.PLACE ); if (spatial.geo && typeof spatial.geo === "object" && !hasType(spatial.geo)) { if ("latitude" in spatial.geo && "longitude" in spatial.geo) { processed.geo = processSchemaType( spatial.geo, SCHEMA_TYPES.GEO_COORDINATES ); } else if ("box" in spatial.geo || "circle" in spatial.geo || "line" in spatial.geo || "polygon" in spatial.geo) { processed.geo = processSchemaType( spatial.geo, SCHEMA_TYPES.GEO_SHAPE ); } } return processed; } function processDataDownload(download) { return processSchemaType(download, SCHEMA_TYPES.DATA_DOWNLOAD); } function processLicense(license) { if (isString(license)) { return license; } return processSchemaType(license, SCHEMA_TYPES.CREATIVE_WORK); } function processDataCatalog(catalog) { return processSchemaType(catalog, SCHEMA_TYPES.DATA_CATALOG); } function processHiringOrganization(org) { if (isString(org)) { return { "@type": SCHEMA_TYPES.ORGANIZATION, name: org }; } const processed = processSchemaType( org, SCHEMA_TYPES.ORGANIZATION ); if (processed.logo && !isString(processed.logo)) { processed.logo = processImage(processed.logo); } return processed; } function processJobLocation(location) { if (isString(location)) { return { "@type": SCHEMA_TYPES.PLACE, address: { "@type": SCHEMA_TYPES.POSTAL_ADDRESS, streetAddress: location } }; } const processed = processSchemaType(location, SCHEMA_TYPES.PLACE); if (processed.address && !isString(processed.address)) { processed.address = processAddress(processed.address); } return processed; } function processMonetaryAmount(amount) { const processed = processSchemaType(amount, "MonetaryAmount"); processed.value = processSchemaType( amount.value, SCHEMA_TYPES.QUANTITATIVE_VALUE ); return processed; } function processRating(rating) { return processSchemaType(rating, SCHEMA_TYPES.RATING); } function processJobPropertyValue(identifier) { return processSchemaType( identifier, SCHEMA_TYPES.PROPERTY_VALUE, (str) => ({ value: str }), void 0 ); } function processApplicantLocationRequirements(location) { if (hasType(location)) { return location; } const name = location.name; const statePatterns = [ /\b[A-Z]{2}\b/, // Two-letter state codes /\bstate\b/i, // Contains "state" /,/, // Contains comma (often "City, State") /\b(AL|AK|AZ|AR|CA|CO|CT|DE|FL|GA|HI|ID|IL|IN|IA|KS|KY|LA|ME|MD|MA|MI|MN|MS|MO|MT|NE|NV|NH|NJ|NM|NY|NC|ND|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VT|VA|WA|WV|WI|WY)\b/ // US state codes ]; const isState = statePatterns.some((pattern) => pattern.test(name)); return { "@type": isState ? SCHEMA_TYPES.STATE : SCHEMA_TYPES.COUNTRY, ...location }; } function processEducationRequirements(education) { if (isString(education)) { return education; } return processSchemaType( education, SCHEMA_TYPES.EDUCATIONAL_CREDENTIAL ); } function processExperienceRequirements(experience) { if (isString(experience)) { return experience; } return processSchemaType( experience, SCHEMA_TYPES.OCCUPATIONAL_EXPERIENCE ); } function processInteractionStatistic(statistic) { return processSchemaType( statistic, SCHEMA_TYPES.INTERACTION_COUNTER ); } function processSharedContent(content) { if (isString(content)) { return { "@type": SCHEMA_TYPES.WEB_PAGE, url: content }; } if (hasType(content)) { return content; } const hasVideoProperties = "uploadDate" in content && "thumbnailUrl" in content; const hasImageProperties = "url" in content && ("width" in content || "height" in content); if (hasVideoProperties) { return processSchemaType(content, SCHEMA_TYPES.VIDEO_OBJECT); } if (hasImageProperties) { return processSchemaType(content, SCHEMA_TYPES.IMAGE_OBJECT); } return processSchemaType(content, SCHEMA_TYPES.WEB_PAGE); } function processComment(comment) { const processed = processSchemaType( comment, SCHEMA_TYPES.COMMENT ); if (comment.author) { processed.author = processAuthor(comment.author); } if (comment.image && !isString(comment.image)) { processed.image = processImage(comment.image); } if (comment.video) { processed.video = processVideo(comment.video); } if (comment.interactionStatistic) { processed.interactionStatistic = Array.isArray(comment.interactionStatistic) ? comment.interactionStatistic.map(processInteractionStatistic) : processInteractionStatistic(comment.interactionStatistic); } if (comment.sharedContent) { processed.sharedContent = processSharedContent(comment.sharedContent); } if (comment.comment) { processed.comment = comment.comment.map(processComment); } return processed; } function processIsPartOf(isPartOf) { if (isString(isPartOf)) { return isPartOf; } return processSchemaType( isPartOf, SCHEMA_TYPES.CREATIVE_WORK ); } function processBrand(brand) { if ("@type" in brand) { return brand; } if ("logo" in brand || "address" in brand || "contactPoint" in brand) { const org = { "@type": SCHEMA_TYPES.ORGANIZATION, ...brand }; processOrganizationFields(org); return org; } return processSchemaType(brand, SCHEMA_TYPES.BRAND); } function processBedDetails(bed) { return processSchemaType(bed, SCHEMA_TYPES.BED_DETAILS); } function processLocationFeatureSpecification(feature) { return processSchemaType( feature, SCHEMA_TYPES.LOCATION_FEATURE ); } function processAccommodation(accommodation) { const processed = processSchemaType( accommodation, SCHEMA_TYPES.ACCOMMODATION ); if (accommodation.bed) { processed.bed = Array.isArray(accommodation.bed) ? accommodation.bed.map(processBedDetails) : processBedDetails(accommodation.bed); } if (accommodation.occupancy) { processed.occupancy = processNumberOfEmployees( accommodation.occupancy ); } if (accommodation.amenityFeature) { processed.amenityFeature = Array.isArray(accommodation.amenityFeature) ? accommodation.amenityFeature.map(processLocationFeatureSpecification) : processLocationFeatureSpecification(accommodation.amenityFeature); } if (accommodation.floorSize) { processed.floorSize = processNumberOfEmployees( accommodation.floorSize ); } return processed; } function processProvider(provider) { return processSchemaType( provider, SCHEMA_TYPES.ORGANIZATION, (str) => ({ name: str }), void 0 ); } function processFunder(funder) { if (Array.isArray(funder)) { return funder.map(processFunderSingle); } return processFunderSingle(funder); } function processFunderSingle(funder) { if (isString(funder)) { return { "@type": SCHEMA_TYPES.ORGANIZATION, name: funder }; } if (hasType(funder)) { return funder; } return { "@type": SCHEMA_TYPES.ORGANIZATION, ...funder }; } function processScreenshot(screenshot) { return processImage(screenshot); } function processFeatureList(features) { return features; } function processClaimReviewRating(rating) { return processSchemaType(rating, SCHEMA_TYPES.RATING); } function processClaim(claim) { const processed = processSchemaType(claim, SCHEMA_TYPES.CLAIM); if (claim.author) { processed.author = processAuthor(claim.author); } if (claim.appearance) { if (Array.isArray(claim.appearance)) { processed.appearance = claim.appearance.map(processAppearance); } else { processed.appearance = processAppearance(claim.appearance); } } if (claim.firstAppearance) { processed.firstAppearance = processAppearance(claim.firstAppearance); } return processed; } function processAppearance(appearance) { if (isString(appearance)) { return appearance; } const processed = processSchemaType( appearance, SCHEMA_TYPES.CREATIVE_WORK ); if (appearance.author) { processed.author = processAuthor(appearance.author); } if (appearance.publisher && !isString(appearance.publisher)) { processed.publisher = processPublisher(appearance.publisher); } return processed; } function processWebPageElement(element) { return processSchemaType( element, SCHEMA_TYPES.WEB_PAGE_ELEMENT ); } function processProductOffer(offer) { const processed = processSchemaType( offer, SCHEMA_TYPES.OFFER ); if (offer.seller) { processed.seller = processAuthor(offer.seller); } if (offer.priceSpecification) { if (Array.isArray(offer.priceSpecification)) { processed.priceSpecification = offer.priceSpecification.map( processPriceSpecification ); } else { processed.priceSpecification = processPriceSpecification( offer.priceSpecification ); } } if (offer.hasMerchantReturnPolicy) { if (Array.isArray(offer.hasMerchantReturnPolicy)) { processed.hasMerchantReturnPolicy = offer.hasMerchantReturnPolicy.map( processMerchantReturnPolicy ); } else { processed.hasMerchantReturnPolicy = processMerchantReturnPolicy( offer.hasMerchantReturnPolicy ); } } if (offer.shippingDetails) { if (Array.isArray(offer.shippingDetails)) { processed.shippingDetails = offer.shippingDetails.map( processOfferShippingDetails ); } else { processed.shippingDetails = processOfferShippingDetails( offer.shippingDetails ); } } return processed; } function processAggregateOffer(offer) { const processed = processSchemaType( offer, SCHEMA_TYPES.AGGREGATE_OFFER ); if (offer.offers) { processed.offers = offer.offers.map(processProductOffer); } return processed; } function processPriceSpecification(spec) { if ("priceType" in spec || "validForMemberTier" in spec || "membershipPointsEarned" in spec || "referenceQuantity" in spec) { return processUnitPriceSpecification( spec ); } return processSchemaType( spec, SCHEMA_TYPES.PRICE_SPECIFICATION ); } function processUnitPriceSpecification(spec) { const processed = processSchemaType( spec, SCHEMA_TYPES.UNIT_PRICE_SPECIFICATION ); if (spec.validForMemberTier) { if (Array.isArray(spec.validForMemberTier)) { processed.validForMemberTier = spec.validForMemberTier.map( processMemberProgramTier ); } else { processed.validForMemberTier = processMemberProgramTier( spec.validForMemberTier ); } } if (spec.referenceQuantity) { processed.referenceQuantity = processQuantitativeValue( spec.referenceQuantity ); } return processed; } function processQuantitativeValue(value) { const processed = processSchemaType( value, SCHEMA_TYPES.QUANTITATIVE_VALUE ); if (value.valueReference) { processed.valueReference = processQuantitativeValue(value.valueReference); } return processed; } function processProductItemList(list) { const processed = processSchemaType( list, SCHEMA_TYPES.ITEM_LIST ); if (list.itemListElement) { processed.itemListElement = list.itemListElement.map((item, index) => { const processedItem = processSchemaType( item, SCHEMA_TYPES.LIST_ITEM ); if (!processedItem.position) { processedItem.position = index + 1; } return processedItem; }); } return processed; } function processProductReview(review) { const processed = processSchemaType( review, SCHEMA_TYPES.REVIEW ); if (review.reviewRating) { processed.reviewRating = processSchemaType( review.reviewRating, SCHEMA_TYPES.RATING ); } if (review.author) { processed.author = processAuthor(review.author); } if (review.positiveNotes) { processed.positiveNotes = processProductItemList(review.positiveNotes); } if (review.negativeNotes) { processed.negativeNotes = processProductItemList(review.negativeNotes); } return processed; } function processVariesBy(variesBy) { const processOne = (value) => { if (value.startsWith("https://schema.org/")) { return value; } return `https://schema.org/${value}`; }; if (Array.isArray(variesBy)) { return variesBy.map(processOne); } return processOne(variesBy); } function processProductVariant(variant) { if ("url" in variant && Object.keys(variant).length <= 2) { return variant; } const product = variant; if ("@type" in product) { return product; } const processed = { "@type": SCHEMA_TYPES.PRODUCT, ...product }; if (product.image) { processed.image = Array.isArray(product.image) ? product.image.map(processImage) : processImage(product.image); } if (product.brand) { if (typeof product.brand === "string") { processed.brand = { "@type": SCHEMA_TYPES.BRAND, name: product.brand }; } else { processed.brand = processBrand(product.brand); } } if (product.offers) { if (Array.isArray(product.offers)) { processed.offers = product.offers.map((offer) => { if ("lowPrice" in offer && "priceCurrency" in offer) { return processAggregateOffer( offer ); } return processProductOffer( offer ); }); } else if ("lowPrice" in product.offers && "priceCurrency" in product.offers) { processed.offers = processAggregateOffer( product.offers ); } else { processed.offers = processProductOffer( product.offers ); } } if (product.review) { processed.review = Array.isArray(product.review) ? product.review.map(processProductReview) : processProductReview(product.review); } if (product.aggregateRating) { processed.aggregateRating = processAggregateRating(product.aggregateRating); } if (product.manufacturer) { processed.manufacturer = processAuthor(product.manufacturer); } if (product.weight && typeof product.weight === "object" && !("@type" in product.weight)) { processed.weight = { "@type": "QuantitativeValue", ...product.weight }; } if (product.width && typeof product.width === "object" && !("@type" in product.width)) { processed.width = { "@type": "QuantitativeValue", ...product.width }; } if (product.height && typeof product.height === "object" && !("@type" in product.height)) { processed.height = { "@type": "QuantitativeValue", ...product.height }; } if (product.depth && typeof product.depth === "object" && !("@type" in product.depth)) { processed.depth = { "@type": "QuantitativeValue", ...product.depth }; } return processed; } function processCertification(cert) { const processed = processSchemaType( cert, SCHEMA_TYPES.CERTIFICATION ); if (cert.issuedBy) { if (typeof cert.issuedBy === "object" && !("@type" in cert.issuedBy)) { processed.issuedBy = { "@type": SCHEMA_TYPES.ORGANIZATION, ...cert.issuedBy }; } else { processed.issuedBy = cert.issuedBy; } } if (cert.certificationRating) { processed.certificationRating = processRating(cert.certificationRating); } return processed; } function processPeopleAudience(audience) { const processed = processSchemaType( audience, SCHEMA_TYPES.PEOPLE_AUDIENCE ); if (audience.suggestedAge) { processed.suggestedAge = processQuantitativeValue(audience.suggestedAge); } return processed; } function processSizeSpecification(size) { if (typeof size === "string") { return size; } return processSchemaType( size, SCHEMA_TYPES.SIZE_SPECIFICATION ); } function processThreeDModel(model) { const processed = processSchemaType( model, SCHEMA_TYPES.THREE_D_MODEL ); if (model.encoding && !("@type" in model.encoding)) { processed.encoding = { "@type": "MediaObject", ...model.encoding }; } return processed; } function processDefinedRegion(region) { return processSchemaType(region, SCHEMA_TYPES.DEFINED_REGION); } function processShippingDeliveryTime(time) { const processed = processSchemaType( time, SCHEMA_TYPES.SHIPPING_DELIVERY_TIME ); if (time.handlingTime) { processed.handlingTime = processQuantitativeValue(time.handlingTime); } if (time.transitTime) { processed.transitTime = processQuantitativeValue(time.transitTime); } return processed; } function processOfferShippingDetails(details) { const processed = processSchemaType( details, SCHEMA_TYPES.OFFER_SHIPPING_DETAILS ); if (details.shippingRate) { processed.shippingRate = processSimpleMonetaryAmount(details.shippingRate); } if (details.shippingDestination) { if (Array.isArray(details.shippingDestination)) { processed.shippingDestination = details.shippingDestination.map(processDefinedRegion); } else { processed.shippingDestination = processDefinedRegion( details.shippingDestination ); } } if (details.deliveryTime) { processed.deliveryTime = processShippingDeliveryTime(details.deliveryTime); } return processed; } function processItemReviewed(itemReviewed, defaultType) { if (isString(itemReviewed)) { return { "@type": defaultType || "Thing", name: itemReviewed }; } if (typeof itemReviewed === "object" && itemReviewed !== null && "@type" in itemReviewed) { return itemReviewed; } const candidate = { ...itemReviewed }; const inferType = () => { if (defaultType) return defaultType; if ("brand" in candidate || "sku" in candidate) return "Product"; if ("recipeIngredient" in candidate || "recipeInstructions" in candidate) return "Recipe"; if ("servesCuisine" in candidate || "address" in candidate) return "LocalBusiness"; if ("applicationCategory" in candidate || "operatingSystem" in candidate) return "SoftwareApplication"; if ("director" in candidate || "actor" in candidate) return "Movie"; if ("provider" in candidate) return "Course"; return "Thing"; }; return { "@type": inferType(), ...candidate }; } function processHowToDirection(direction) { const processed = processSchemaType( direction, SCHEMA_TYPES.HOW_TO_DIRECTION ); if (direction.beforeMedia && !isString(direction.beforeMedia)) { processed.beforeMedia = processImage(direction.beforeMedia); } if (direction.afterMedia && !isString(direction.afterMedia)) { processed.afterMedia = processImage(direction.afterMedia); } if (direction.duringMedia && !isString(direction.duringMedia)) { processed.duringMedia = processImage(direction.duringMedia); } return processed; } function processHowToTip(tip) { return processSchemaType(tip, SCHEMA_TYPES.HOW_TO_TIP); } function processHowToStepItem(item) { if (hasType(item)) { if (item["@type"] === SCHEMA_TYPES.HOW_TO_DIRECTION) { return processHowToDirection(item); } return processHowToTip(item); } if ("beforeMedia" in item || "afterMedia" in item || "duringMedia" in item) { return processHowToDirection(item); } return processHowToDirection(item); } function processHowToStep(step) { if (isString(step)) { return step; } const processed = processSchemaType( step, SCHEMA_TYPES.HOW_TO_STEP ); if (step.image && !isString(step.image)) { processed.image = processImage(step.image); } if (step.itemListElement) { processed.itemListElement = step.itemListElement.map(processHowToStepItem); } return processed; } function processHowToSection(section) { const processed = processSchemaType( section, SCHEMA_TYPES.HOW_TO_SECTION ); if (section.itemListElement) { processed.itemListElement = section.itemListElement.map((item) => { const result = processHowToStep(item); return typeof result === "string" ? { "@type": "HowToStep", text: result } : result; }); } return processed; } function processStep(step) { if (isString(step)) { return step; } if (hasType(step)) { if (step["@type"] === SCHEMA_TYPES.HOW_TO_SECTION) { return processHowToSection(step); } const result2 = processHowToStep(step); return typeof result2 === "string" ? { "@type": "HowToStep", text: result2 } : result2; } if ("itemListElement" in step && "name" in step) { return processHowToSection(step); } const result = processHowToStep(step); return typeof result === "string" ? { "@type": "HowToStep", text: result } : result; } function processHowToSupply(supply) { if (isString(supply)) { return { "@type": SCHEMA_TYPES.HOW_TO_SUPPLY, name: supply }; } const processed = processSchemaType( supply, SCHEMA_TYPES.HOW_TO_SUPPLY ); if (supply.image && !isString(supply.image)) { processed.image = processImage(supply.image); } if (supply.estimatedCost && !isString(supply.estimatedCost)) { processed.estimatedCost = processSimpleMonetaryAmount(supply.estimatedCost); } if (supply.requiredQuantity && typeof supply.requiredQuantity === "object") { processed.requiredQuantity = processQuantitativeValue( supply.requiredQuantity ); } return processed; } function processHowToTool(tool) { if (isString(tool)) { return { "@type": SCHEMA_TYPES.HOW_TO_TOOL, name: tool }; } const processed = processSchemaType( tool, SCHEMA_TYPES.HOW_TO_TOOL ); if (tool.image && !isString(tool.image)) { processed.image = processImage(tool.image); } if (tool.requiredQuantity && typeof tool.requiredQuantity === "object") { processed.requiredQuantity = processQuantitativeValue( tool.requiredQuantity ); } return processed; } function processEstimatedCost(cost) { if (isString(cost)) { return cost; } return processSimpleMonetaryAmount(cost); } function processHowToYield(yieldValue) { if (isString(yieldValue)) { return yieldValue; } return processQuantitativeValue(yieldValue); } // src/components/ArticleJsonLd.tsx import { jsx as jsx2 } from "react/jsx-runtime"; function ArticleJsonLd({ type = "Article", scriptId, scriptKey, headline, url, author, datePublished, dateModified, image, publisher, description, isAccessibleForFree, mainEntityOfPage }) { const data = { "@context": "https://schema.org", "@type": type, headline, ...url && { url }, ...author && { author: Array.isArray(author) ? author.map(processAuthor) : processAuthor(author) }, ...datePublished && { datePublished }, ...dateModified && { dateModified }, // If dateModified is not provided but datePublished is, use datePublished ...!dateModified && datePublished && { dateModified: datePublished }, ...image && { image: Array.isArray(image) ? image.map(processImage) : processImage(image) }, ...publisher && { publisher: processPublisher(publisher) }, ...description && { description }, ...isAccessibleForFree !== void 0 && { isAccessibleForFree }, ...mainEntityOfPage && { mainEntityOfPage: processMainEntityOfPage(mainEntityOfPage) } }; return /* @__PURE__ */ jsx2( JsonLdScript, { data, id: scriptId, scriptKey: scriptKey || `article-jsonld-${type}` } ); } // src/components/ClaimReviewJsonLd.tsx import { jsx as jsx3 } from "react/jsx-runtime"; function ClaimReviewJsonLd({ scriptId, scriptKey, claimReviewed, reviewRating, url, author, itemReviewed }) { const data = { "@context": "https://schema.org", "@type": "ClaimReview", claimReviewed, reviewRating: processClaimReviewRating(reviewRating), url, ...author && { author: processAuthor(author) }, ...itemReviewed && { itemReviewed: processClaim(itemReviewed) } }; return /* @__PURE__ */ jsx3( JsonLdScript, { data, id: scriptId, scriptKey: scriptKey || "claimreview-jsonld" } ); } // src/components/CreativeWorkJsonLd.tsx import { jsx as jsx4 } from "react/jsx-runtime"; function CreativeWorkJsonLd({ type = "CreativeWork", scriptId, scriptKey, headline, name, url, author, datePublished, dateModified, image, publisher, description, isAccessibleForFree, hasPart, mainEntityOfPage, // Additional properties for specific types text, // For Comment provider, // For Course itemReviewed, // For Review reviewRating // For Review }) { const data = { "@context": "https://schema.org", "@type": type, // Use headline if provided, otherwise use name ...headline && { headline }, ...name && !headline && { name }, ...url && { url }, ...author && { author: Array.isArray(author) ? author.map(processAuthor) : processAuthor(author) }, ...datePublished && { datePublished }, ...dateModified && { dateModified }, // If dateModified is not provided but datePublished is, use datePublished for certain types ...!dateModified && datePublished && ["Article", "NewsArticle", "BlogPosting"].includes(type) && { dateModified: datePublished }, ...image && { image: Array.isArray(image) ? image.map(processImage) : processImage(image) }, ...publisher && { publisher: processPublisher(publisher) }, ...description && { description }, ...isAccessibleForFree !== void 0 && { isAccessibleForFree }, ...hasPart && { hasPart: Array.isArray(hasPart) ? hasPart.map(processWebPageElement) : processWebPageElement(hasPart) }, ...mainEntityOfPage && { mainEntityOfPage: processMainEntityOfPage(mainEntityOfPage) }, // Type-specific properties ...text && type === "Comment" && { text }, ...provider && type === "Course" && { provider: processPublisher(provider) }, ...itemReviewed && type === "Review" && { itemReviewed }, ...reviewRating && type === "Review" && { reviewRating } }; return /* @__PURE__ */ jsx4( JsonLdScript, { data, id: scriptId, scriptKey: scriptKey || `creativework-jsonld-${type.toLowerCase()}` } ); } // src/components/RecipeJsonLd.tsx import { jsx as jsx5 } from "react/jsx-runtime"; function RecipeJsonLd({ scriptId, scriptKey, name, image, description, author, datePublished, prepTime, cookTime, totalTime, recipeYield, recipeCategory, recipeCuisine, nutrition, recipeIngredient, recipeInstructions, aggregateRating, video, keywords, url }) { const data = { "@context": "https://schema.org", "@type": "Recipe", name, image: Array.isArray(image) ? image.map(processImage) : processImage(image), ...description && { description }, ...author && { author: processAuthor(author) }, ...datePublished && { datePublished }, ...prepTime && { prepTime }, ...cookTime && { cookTime }, ...totalTime && { totalTime }, ...recipeYield !== void 0 && { recipeYield }, ...recipeCategory && { recipeCategory }, ...recipeCuisine && { recipeCuisine }, ...nutrition && { nutrition: processNutrition(nutrition) }, ...recipeIngredient && { recipeIngredient }, ...recipeInstructions && { recipeInstructions: Array.isArray(recipeInstructions) ? recipeInstructions.map(processInstruction) : processInstruction(recipeInstructions) }, ...aggregateRating && { aggregateRating: processAggregateRating(aggregateRating) }, ...video && { video: processVideo(video) }, ...keywords && { keywords }, ...url && { url } }; return /* @__PURE__ */ jsx5( JsonLdScript, { data, id: scriptId, scriptKey: scriptKey || "recipe-jsonld" } ); } // src/components/HowToJsonLd.tsx import { jsx as jsx6 } from "react/jsx-runtime"; function HowToJsonLd({ scriptId, scriptKey, name, description, image, estimatedCost, performTime, prepTime, totalTime, step, supply, tool, yield: yieldValue, video }) { const data = { "@context": "https://schema.org", "@type": "HowTo", name, ...description && { descript