import { readdir, readFile } from "fs/promises"; import { join } from "path"; import * as yaml from "js-yaml"; import { plainToClass } from "class-transformer"; import { validate } from "class-validator"; import { init, Page, Exercise, Grader } from "./db"; import { Page as PageConfig, Exercise as ExerciseConfig, Grader as GraderConfig } from "./page"; // TODO: configure this thru cmdline or something later let materials_dir = "../material"; let db_file = "test.db"; let db; let SLUG_RE = /([A-Za-z\-\_]+)/; async function loadPageIntoDb(name: string): Promise { let slug_match = name.match(SLUG_RE); let slug = slug_match[0]; // if this slug has already been loaded into the database, don't do anything let hasPage = await Page.count({ where: { slug }}) > 0; if (hasPage) { return; } let path = join(materials_dir, name); let rawData = await readFile(path, { encoding: "utf8" }); let parsedData = yaml.load(rawData); let page_cfg = plainToClass(PageConfig, parsedData); await validate(page_cfg); // save page let page = new Page({ slug, title: page_cfg.title, type: page_cfg.type, content: page_cfg.content, }); await page.save(); // save exercises async function loadExerciseIntoDb(ex_cfg: ExerciseConfig): Promise { let exercise = new Exercise({ page_slug: slug, name: ex_cfg.name, style: ex_cfg.style, props: ex_cfg.props, description: ex_cfg.description, }); await exercise.save(); async function loadConceptsIntoDb(concept: string): Promise { }; async function loadGraderIntoDb([language, grader_cfg]: [string, GraderConfig]): Promise { let grader = new Grader({ page_slug: slug, exercise_name: ex_cfg.name, language, style: grader_cfg.style, props: grader_cfg.props, }); await grader.save(); } let graders = ex_cfg.graders; if (graders != null) { await Promise.all(Object.entries(graders).map(loadGraderIntoDb)); } } let exercises = page_cfg.exercises; if (exercises != null) { await Promise.all(exercises.map(loadExerciseIntoDb)); } } async function main() { db = await init(db_file); // TODO: streaming version of readdir when the folder gets big let names = await readdir(materials_dir); await Promise.all(names .filter(name => name.toLowerCase().endsWith(".yml")) .map(loadPageIntoDb) ); } main();