runtime/entrypoints/validation.entrypoint.ts
runtime/entrypoints/validation.entrypoint.ts is a file in Bane's Lab Social Share. 112 lines of code and 22 definitions.
import {
CARDS_VALID,
HEALING,
MALFORMED_SHARE_MAP,
MISSING_IMAGE,
NO_CARDS,
ORPHAN_IMAGE,
PRUNED_PREFIX,
RENDERED_PREFIX,
STALE_IMAGE,
STALE_MAP,
SUBJECT_SEPARATOR,
VALIDATION_SUMMARY,
} from "#configuration/strings/card.strings";
import { conclude, say } from "#core/reporters/card.reporter";
import {
missingImages,
orphanImages,
readLedger,
shareEntriesOf,
staleEntries,
} from "#core/persistence/image.persistence";
import { strayShares, unpublishedShares } from "#core/persistence/export.persistence";
import type { CardFinding } from "#types/card.types";
import { PROFILES } from "#configuration/configs/card.config";
import type { ShareImage } from "@banes-lab/web/types/card.types.ts";
import { VALIDATION_COMMAND } from "#configuration/constants/card.constants";
import { absolutePath } from "@ssot/paths";
import { animationFindings } from "#core/probes/image.probe";
import { defineCheck } from "@govlab/context/check";
import { exportCards } from "#core/coordinators/export.coordinator";
import { openStage } from "#core/adapters/stage.adapter";
import { pathToFileURL } from "node:url";
import { resolveArgv } from "@govlab/argv";
import { validateCards } from "#core/validators/card.validator";
defineCheck({ detects: [], enforces: ["architecture:reproducibility"] });
interface ShareMapModule {
readonly SHARE_IMAGES: ReadonlyMap<string, ShareImage>;
}
resolveArgv({ command: VALIDATION_COMMAND, flags: [], summary: VALIDATION_SUMMARY });
const RENDERS = absolutePath("app.cardRenders");
const SHARES = absolutePath("app.shares");
const FRESH_QUERY = "?read=";
const SHARE_EXPORT = "SHARE_IMAGES";
const loader = await openStage(false);
const loaded = await loader.cards();
await loader.close();
const specs = loaded.cards.map((card) => card.spec);
const specFindings: readonly CardFinding[] = [
...(loaded.cards.length === 0 ? [{ card: VALIDATION_COMMAND, message: NO_CARDS }] : []),
...validateCards(loaded.cards, loaded.plugins, {
brand: loaded.brand,
pages: loaded.pages,
profiles: PROFILES,
repeated: loaded.repeated,
}),
...(await animationFindings(specs, absolutePath("app.public"))),
];
const isShareMapModule = function isShareMapModule(value: unknown): value is ShareMapModule {
return typeof value === "object" && value !== null && Reflect.get(value, SHARE_EXPORT) instanceof Map;
};
const shareMap = async function shareMap(): Promise<ReadonlyMap<string, ShareImage>> {
const location = pathToFileURL(absolutePath("app.shareMap")).href + FRESH_QUERY + String(Date.now());
const module: unknown = await import(location);
if (!isShareMapModule(module)) {
throw new TypeError(MALFORMED_SHARE_MAP + SUBJECT_SEPARATOR + location);
}
return module.SHARE_IMAGES;
};
const mapFindings = async function mapFindings(): Promise<readonly CardFinding[]> {
const expected = shareEntriesOf(specs, RENDERS);
const held = await shareMap();
const mapCurrent =
expected.length === held.size &&
expected.every(({ page, ...share }) => JSON.stringify(held.get(page)) === JSON.stringify(share));
return [
...(mapCurrent ? [] : [{ card: VALIDATION_COMMAND, message: STALE_MAP }]),
...unpublishedShares(expected, SHARES).map((file) => ({ card: file, message: MISSING_IMAGE })),
...strayShares(expected, SHARES).map((file) => ({ card: file, message: ORPHAN_IMAGE })),
];
};
const outputFindings = async function outputFindings(): Promise<readonly CardFinding[]> {
const missing = missingImages(specs, RENDERS).map((file) => ({ card: file, message: MISSING_IMAGE }));
return [
...missing,
...orphanImages(specs, RENDERS).map((file) => ({ card: file, message: ORPHAN_IMAGE })),
...staleEntries(specs, readLedger(absolutePath("app.shareLedger"))).map((entry) => ({
card: entry,
message: STALE_IMAGE,
})),
...(missing.length === 0 ? await mapFindings() : []),
];
};
const heal = async function heal(): Promise<void> {
say(HEALING);
const capture = await openStage(true);
try {
const result = await exportCards({ force: false, gpu: false, only: null, url: capture.url }, specs);
for (const key of result.rendered) {
say(RENDERED_PREFIX + key);
}
for (const file of result.pruned) {
say(PRUNED_PREFIX + file);
}
} finally {
await capture.close();
}
};
if (specFindings.length === 0 && (await outputFindings()).length > 0) {
await heal();
}
conclude([...specFindings, ...(specFindings.length === 0 ? await outputFindings() : [])], CARDS_VALID);