presentation/renderers/schema.renderer.ts

presentation/renderers/schema.renderer.ts is a file in Bane's Lab Site. 169 lines of code and 26 definitions.

import type { Crumb, SchemaEntity, SchemaGraph } from "#types/schema.types";
import {
    DATASET_TYPE,
    ORGANIZATION,
    ORGANIZATION_ID,
    PERSON,
    PERSON_ID,
    PROFILE_PAGE_TYPE,
    SCHEMA_CONTEXT,
    SCHEMA_LANGUAGE,
    WEBSITE,
} from "#configuration/constants/schema.constants";
import { HOME_TITLE, TITLE_SEPARATOR } from "#configuration/strings/page.strings";
import type {
    PageDefinition,
    RecordSubject,
    SchemaSubject,
    SectionSubject,
    ServedSubject,
    SourceSubject,
} from "#types/page.types";
import {
    SITE_URL,
    markdownTwinPath,
    pageIndexPath,
    pagePath,
    payloadTwinPath,
    sectionLeafPath,
    sectionMarkdownPath,
} from "#core/assets/link.assets";
import type { Section, Tab } from "#types/document.types";
import { basePage, breadcrumb, datesOf, encoding, instantOf } from "#core/factories/schema.factory";
import { ANCHOR_PREFIX } from "#configuration/constants/document.constants";
import { HOME_PAGE } from "#core/ids/page.ids";
import { JSON_FORMAT } from "#configuration/constants/code.constants";
import { hasOwnSections } from "#presentation/renderers/tab.renderer";

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

const tabIdOf = function tabIdOf(subject: SchemaSubject): string | null {
    const content = subject.definition?.content;
    return content?.kind === "tabbed" ? ((subject.tab ?? content.tabs[0])?.id ?? null) : null;
};

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

const articleOf = function articleOf(subject: SchemaSubject, definition: PageDefinition): SchemaEntity | null {
    if (definition.article !== true || subject.banner === undefined) {
        return null;
    }
    return {
        "@type": "TechArticle",
        author: { "@id": PERSON_ID },
        ...datesOf(subject.dates),
        headline:
            subject.tab === undefined ? definition.title : subject.tab.label + TITLE_SEPARATOR + definition.title,
        image: subject.banner.stills.map((still) => SITE_URL + still),
        inLanguage: SCHEMA_LANGUAGE,
        publisher: { "@id": ORGANIZATION_ID },
    };
};

const webPage = function webPage(subject: SchemaSubject): SchemaEntity {
    const page = basePage(subject);
    if (subject.definition === undefined) {
        return page;
    }
    const parts = partsOf(subject);
    const index = pageIndexPath(subject.definition.id);
    const profile = subject.definition.profile === true;
    const main = profile ? { "@id": PERSON_ID } : articleOf(subject, subject.definition);
    return {
        ...page,
        ...(profile ? { "@type": PROFILE_PAGE_TYPE } : {}),
        breadcrumb: breadcrumb(crumbsOf(subject.definition, subject.tab, subject.path)),
        encoding: [
            ...encoding(payloadTwinPath(subject.path), markdownTwinPath(subject.path)),
            { "@type": "MediaObject", contentUrl: SITE_URL + index, encodingFormat: JSON_FORMAT },
        ],
        ...(parts.length === 0 ? {} : { hasPart: parts }),
        ...(main === null ? {} : { mainEntity: main }),
    };
};

const sourceCode = function sourceCode(subject: SourceSubject): SchemaEntity {
    return {
        "@type": "SoftwareSourceCode",
        isPartOf: { "@id": SITE_URL + subject.tabPath },
        name: subject.name,
        ...(subject.language === null ? {} : { programmingLanguage: subject.language }),
        ...(subject.repository === null ? {} : { codeRepository: subject.repository }),
        ...(subject.license === null ? {} : { license: subject.license }),
    };
};

const servedPage = function servedPage(
    subject: ServedSubject,
    parents: readonly Crumb[],
    mainEntity: SchemaEntity,
): SchemaGraph {
    const page: SchemaEntity = {
        ...basePage(subject),
        breadcrumb: breadcrumb([
            { name: HOME_TITLE, path: pagePath(HOME_PAGE) },
            ...parents,
            { name: subject.name, path: subject.path },
        ]),
        encoding: encoding(subject.alternates.json, subject.alternates.markdown),
        mainEntity,
    };
    return { "@context": SCHEMA_CONTEXT, "@graph": [ORGANIZATION, PERSON, WEBSITE, page] };
};

export const sourceSchemaOf = function sourceSchemaOf(subject: SourceSubject): SchemaGraph {
    const parents = subject.trail.map((link) => ({ name: link.label, path: link.path }));
    return servedPage(subject, parents, sourceCode(subject));
};

export const recordSchemaOf = function recordSchemaOf(subject: RecordSubject): SchemaGraph {
    const { collection } = subject;
    return servedPage(
        subject,
        [{ name: collection.label, path: collection.path }],
        {
            "@type": "DefinedTerm",
            ...(subject.code === null ? {} : { termCode: subject.code }),
            ...(subject.summary === null ? {} : { description: subject.summary }),
            inDefinedTermSet: { "@type": "DefinedTermSet", name: collection.label, url: SITE_URL + collection.path },
            name: subject.name,
            url: SITE_URL + subject.path,
        },
    );
};

export const sectionSchemaOf = function sectionSchemaOf(subject: SectionSubject): SchemaGraph {
    const { seed } = subject;
    return servedPage(
        subject,
        [{ name: seed.tabTitle, path: seed.tabPath }],
        { "@type": "ItemList", name: subject.name, numberOfItems: seed.records },
    );
};

export const schemaOf = function schemaOf(subject: SchemaSubject): SchemaGraph {
    const { dates } = subject;
    const entities = (subject.definition?.entities ?? []).map((entity) =>
        dates === undefined || entity["@type"] !== DATASET_TYPE
            ? entity
            : { ...entity, dateModified: instantOf(dates.modified) },
    );
    return { "@context": SCHEMA_CONTEXT, "@graph": [ORGANIZATION, PERSON, WEBSITE, webPage(subject), ...entities] };
};