| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- import assert from 'node:assert/strict';
- import { readFile } from 'node:fs/promises';
- import { fileURLToPath } from 'node:url';
- import path from 'node:path';
- import {
- teachingDiagrams,
- getModuleDiagrams,
- hasLessonDiagrams,
- } from '../app/diagram-catalog.ts';
- const root = fileURLToPath(new URL('../', import.meta.url));
- const modules = [
- 'api',
- 'database',
- 'api-database',
- 'tasks',
- 'redis',
- 'docker',
- 'linux',
- 'troubleshooting',
- 'distributed',
- ];
- const lessons = new Map();
- for (const moduleSlug of modules) {
- const file =
- moduleSlug === 'api'
- ? 'app/lessons.json'
- : `public/content/${moduleSlug}.json`;
- const content = JSON.parse(await readFile(path.join(root, file), 'utf8'));
- lessons.set(moduleSlug, new Set(content.map((lesson) => lesson.id)));
- }
- const diagramIds = new Set();
- for (const diagram of teachingDiagrams) {
- assert(!diagramIds.has(diagram.id), `Duplicate diagram: ${diagram.id}`);
- diagramIds.add(diagram.id);
- assert(
- lessons.has(diagram.module),
- `${diagram.id}: unknown module ${diagram.module}`,
- );
- assert(diagram.lessons.length > 0, `${diagram.id}: missing lesson mapping`);
- assert.equal(
- new Set(diagram.lessons).size,
- diagram.lessons.length,
- `${diagram.id}: duplicate lesson mapping`,
- );
- for (const lesson of diagram.lessons) {
- assert(
- lessons.get(diagram.module).has(lesson),
- `${diagram.id}: unknown lesson ${diagram.module}/${lesson}`,
- );
- }
- const nodeIds = new Set(diagram.nodes.map((node) => node.id));
- assert.equal(
- nodeIds.size,
- diagram.nodes.length,
- `${diagram.id}: duplicate node ID`,
- );
- assert(
- diagram.steps.length >= 3 && diagram.misconception.length > 0,
- `${diagram.id}: missing text explanation`,
- );
- for (const node of diagram.nodes) {
- assert(
- node.x >= 0 && node.x + 210 <= 900,
- `${diagram.id}/${node.id}: node outside SVG width`,
- );
- assert(
- node.y >= 0 && node.y + 104 <= diagram.rows.length * 185 + 60,
- `${diagram.id}/${node.id}: node outside SVG height`,
- );
- const lineCount = (text, maxUnits) => {
- let lines = 1;
- let units = 0;
- for (const character of text) {
- const width = /[\u0020-\u007e]/.test(character) ? 1 : 2;
- if (units + width > maxUnits) {
- lines++;
- units = 0;
- }
- units += width;
- }
- return lines;
- };
- const bottomBaseline =
- 26 +
- lineCount(node.title, 24) * 19 +
- 5 +
- (lineCount(node.detail, 29) - 1) * 16;
- assert(
- bottomBaseline <= 98,
- `${diagram.id}/${node.id}: text exceeds node height`,
- );
- }
- for (const edge of diagram.edges) {
- assert(
- nodeIds.has(edge.from) && nodeIds.has(edge.to),
- `${diagram.id}: dangling edge ${edge.from} -> ${edge.to}`,
- );
- for (const [x, y] of [
- ...(edge.via ?? []),
- ...(edge.labelAt ? [edge.labelAt] : []),
- ]) {
- assert(
- x >= 0 && x <= 900 && y >= 0 && y <= diagram.rows.length * 185 + 60,
- `${diagram.id}: edge outside viewBox`,
- );
- }
- }
- }
- for (const moduleSlug of modules) {
- assert(
- getModuleDiagrams(moduleSlug).length >= 1,
- `${moduleSlug}: missing overview diagram`,
- );
- }
- for (const lesson of lessons.get('distributed')) {
- assert(
- hasLessonDiagrams('distributed', lesson),
- `distributed/${lesson}: missing diagram`,
- );
- }
- console.log(
- `Validated ${teachingDiagrams.length} diagrams: unique IDs, valid edges, text bounds, lesson mappings, 9 module overviews, and all distributed lessons.`,
- );
- for (const moduleSlug of modules) {
- const covered = [...lessons.get(moduleSlug)].filter((lesson) =>
- hasLessonDiagrams(moduleSlug, lesson),
- ).length;
- console.log(
- `${moduleSlug}: ${teachingDiagrams.filter((diagram) => diagram.module === moduleSlug).length} diagrams, ${covered}/${lessons.get(moduleSlug).size} lessons illustrated`,
- );
- }
|