# presentation/renderers/schema.renderer.ts

> 119 lines of code and 23 definitions.

Tree: Site tree
Language: typescript
Layer: product
Canonical: https://banes-lab.com/anatomy/tree#file-presentation-renderers-schema-renderer-ts
Source text: https://banes-lab.com/assets/sources/source.13f0b7942e0253ccf6e0a3f0e9cc95dcc68bd8dcfc85043796e41c2ff2cc2d65.generated.txt

## Definitions

- `schemaOf` (lexical_declaration, line 128, exported)
- `webPage` (lexical_declaration, line 105)
- `crumbsOf` (lexical_declaration, line 69)
- `breadcrumb` (lexical_declaration, line 78)
- `sectionsOf` (lexical_declaration, line 90)
- `partsOf` (lexical_declaration, line 98)
- `CONTEXT` (lexical_declaration, line 19)
- `LANGUAGE` (lexical_declaration, line 20)
- `ORGANIZATION_ID` (lexical_declaration, line 21)
- `PERSON_ID` (lexical_declaration, line 22)
- `WEBSITE_ID` (lexical_declaration, line 23)
- `NUMBER_SEPARATOR` (lexical_declaration, line 25)
- `VAT_ID` (lexical_declaration, line 26)
- `ORGANIZATION` (lexical_declaration, line 28)
- `PERSON` (lexical_declaration, line 44)
- `WEBSITE` (lexical_declaration, line 54)
- `Crumb` (interface_declaration, line 64)
- `home` (lexical_declaration, line 70)
- `content` (lexical_declaration, line 91)
- `url` (lexical_declaration, line 100)
- `page` (lexical_declaration, line 106)
- `parts` (lexical_declaration, line 120)
- `entities` (lexical_declaration, line 129, exported)

## Used by

- [presentation/renderers/page.renderer.ts](https://banes-lab.com/source/tree/presentation/renderers/page.renderer.ts.md)

## Source

```typescript
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 type { Section, Tab } from "#types/document.types";
import { ANCHOR_PREFIX } from "#configuration/constants/document.constants";
import { BADGE_LOGO } from "#assets/image.assets";
import { HOME_PAGE } from "#core/ids/page.ids";

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 sectionsOf = function sectionsOf(subject: SchemaSubject): readonly Section[] {
    const content = subject.definition?.content;
    if (content?.kind === "document") {
        return content.sections;
    }
    return content?.kind === "tabbed" ? ((subject.tab ?? content.tabs[0])?.sections ?? []) : [];
};

const partsOf = function partsOf(subject: SchemaSubject): readonly SchemaEntity[] {
    return sectionsOf(subject).map((section) => {
        const url = SITE_URL + subject.path + ANCHOR_PREFIX + section.id;
        return { "@id": url, "@type": "WebPageElement", name: section.title, url };
    });
};

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;
    }
    const parts = partsOf(subject);
    return {
        ...page,
        breadcrumb: breadcrumb(crumbsOf(subject.definition, subject.tab, subject.path)),
        ...(parts.length === 0 ? {} : { hasPart: parts }),
    };
};

export const schemaOf = function schemaOf(subject: SchemaSubject): SchemaGraph {
    const entities = subject.definition?.entities ?? [];
    return { "@context": CONTEXT, "@graph": [ORGANIZATION, PERSON, WEBSITE, webPage(subject), ...entities] };
};
```
