import { AUTHOR_GITHUB, AUTHOR_PROFILE, SITE_URL, pagePath } from "#assets/link.assets"; import { COMPANY_CITY, COMPANY_COUNTRY, COMPANY_EMAIL, COMPANY_FOUNDED, COMPANY_NAME, COMPANY_NUMBER, COMPANY_OWNER, } from "#configuration/strings/company.strings"; import { HOME_DESCRIPTION, HOME_TITLE, SITE_NAME } from "#configuration/strings/page.strings"; import type { PageDefinition, SchemaSubject } from "#types/page.types"; import type { SchemaEntity, SchemaGraph } from "#types/schema.types"; import { BADGE_LOGO } from "#assets/image.assets"; import { HOME_PAGE } from "#core/ids/page.ids"; import type { Tab } from "#types/document.types"; const CONTEXT = "https://schema.org"; const LANGUAGE = "en"; const ORGANIZATION_ID = `${SITE_URL}/#organization`; const PERSON_ID = `${SITE_URL}/#person`; const WEBSITE_ID = `${SITE_URL}/#website`; const NUMBER_SEPARATOR = "."; const VAT_ID = COMPANY_COUNTRY + COMPANY_NUMBER.split(NUMBER_SEPARATOR).join(""); const ORGANIZATION: SchemaEntity = { "@id": ORGANIZATION_ID, "@type": "Organization", address: { "@type": "PostalAddress", addressCountry: COMPANY_COUNTRY, addressLocality: COMPANY_CITY }, contactPoint: { "@type": "ContactPoint", email: COMPANY_EMAIL, url: SITE_URL + pagePath(HOME_PAGE) }, email: COMPANY_EMAIL, founder: { "@id": PERSON_ID }, foundingDate: COMPANY_FOUNDED, logo: SITE_URL + BADGE_LOGO, name: COMPANY_NAME, sameAs: [AUTHOR_GITHUB, AUTHOR_PROFILE], taxID: VAT_ID, url: SITE_URL + pagePath(HOME_PAGE), vatID: VAT_ID, }; const PERSON: SchemaEntity = { "@id": PERSON_ID, "@type": "Person", email: COMPANY_EMAIL, name: COMPANY_OWNER, sameAs: [AUTHOR_PROFILE, AUTHOR_GITHUB], url: AUTHOR_PROFILE, worksFor: { "@id": ORGANIZATION_ID }, }; const WEBSITE: SchemaEntity = { "@id": WEBSITE_ID, "@type": "WebSite", description: HOME_DESCRIPTION, inLanguage: LANGUAGE, name: SITE_NAME, publisher: { "@id": ORGANIZATION_ID }, url: SITE_URL + pagePath(HOME_PAGE), }; interface Crumb { readonly name: string; readonly path: string; } const crumbsOf = function crumbsOf(definition: PageDefinition, tab: Tab | undefined, path: string): Crumb[] { const home: Crumb = { name: HOME_TITLE, path: pagePath(HOME_PAGE) }; if (definition.id === HOME_PAGE) { return [home]; } const page: Crumb = { name: definition.title, path: pagePath(definition.id) }; return tab === undefined ? [home, page] : [home, page, { name: tab.label, path }]; }; const breadcrumb = function breadcrumb(crumbs: readonly Crumb[]): SchemaEntity { return { "@type": "BreadcrumbList", itemListElement: crumbs.map((crumb, index) => ({ "@type": "ListItem", item: SITE_URL + crumb.path, name: crumb.name, position: index + 1, })), }; }; const webPage = function webPage(subject: SchemaSubject): SchemaEntity { const page: SchemaEntity = { "@id": SITE_URL + subject.path, "@type": "WebPage", author: { "@id": PERSON_ID }, description: subject.description, inLanguage: LANGUAGE, isPartOf: { "@id": WEBSITE_ID }, name: subject.title, publisher: { "@id": ORGANIZATION_ID }, url: SITE_URL + subject.path, }; if (subject.definition === undefined) { return page; } return { ...page, breadcrumb: breadcrumb(crumbsOf(subject.definition, subject.tab, subject.path)) }; }; export const schemaOf = function schemaOf(subject: SchemaSubject): SchemaGraph { const entities = subject.definition?.entities ?? []; return { "@context": CONTEXT, "@graph": [ORGANIZATION, PERSON, WEBSITE, webPage(subject), ...entities] }; };