Files
PolyMPR/logic/maquette.ts
djalim 951c9c1fea
Check Deno code / Check Deno code (pull_request) Has been cancelled
Tests / Unit tests (pull_request) Has been cancelled
Tests / Integration tests (pull_request) Has been cancelled
Check Deno code / Check Deno code (push) Has been cancelled
Tests / Unit tests (push) Has been cancelled
Tests / Integration tests (push) Has been cancelled
test : changed test format + added playwright support
2026-05-03 21:52:02 +02:00

91 lines
2.7 KiB
TypeScript

// @deno-types="https://cdn.sheetjs.com/xlsx-0.20.3/package/types/index.d.ts"
import * as XLSX from "https://cdn.sheetjs.com/xlsx-0.20.3/package/xlsx.mjs";
export type ParsedUE = {
code: string | null;
name: string;
ects: number | null;
modules: ParsedModule[];
};
export type ParsedModule = {
code: string;
name: string;
coeff: number;
};
export type ParsedYear = {
label: string;
ues: ParsedUE[];
};
/**
* Analyse un classeur Excel pour en extraire la maquette pédagogique.
*/
export function parseMaquette(workbook: XLSX.WorkBook): ParsedYear[] {
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const rows = XLSX.utils.sheet_to_json<(string | number | null)[]>(sheet, {
header: 1,
});
const years: ParsedYear[] = [];
let currentYear: ParsedYear | null = null;
let currentUE: ParsedUE | null = null;
let moduleIndex = 0;
for (const row of rows) {
if (!row || row.length === 0) continue;
const col0 = row[0] != null ? String(row[0]).trim() : "";
// Detect year row: INFO3A, INFO4A, INFO5A, INFOAPP3A, INFOAPP4A, etc.
if (/^(INFO|INFOAPP)\s*\d+A$/i.test(col0)) {
currentYear = { label: col0, ues: [] };
years.push(currentYear);
currentUE = null;
continue;
}
// Detect UE row: col[0] === "UE" or starts with "UE" (e.g., "UE51")
if (col0 === "UE" || (col0.startsWith("UE") && /^UE\d/.test(col0))) {
const ueCode = row[1] != null ? String(row[1]).trim() : null;
const ueName = row[2] != null ? String(row[2]).trim() : "UE sans nom";
const ects = typeof row[4] === "number" ? row[4] : null;
currentUE = { code: ueCode, name: ueName, ects, modules: [] };
if (currentYear) {
currentYear.ues.push(currentUE);
} else {
// No year detected yet — create a default one
currentYear = { label: "Maquette", ues: [currentUE] };
years.push(currentYear);
}
moduleIndex = 0;
continue;
}
// Detect semester header rows — just skip, don't reset UE
if (/^SEM\s*\d/i.test(col0)) {
currentUE = null;
continue;
}
// Detect module row: inside a UE, col[3] has a name, col[5] is a number (coeff)
if (currentUE && row[3] != null && typeof row[5] === "number") {
const modName = String(row[3]).trim();
if (!modName) continue;
let modCode = row[1] != null ? String(row[1]).trim() : "";
if (!modCode) {
const uePrefix = (currentUE.code || "MOD").replace(/[^A-Z0-9]/gi, "");
modCode = `${uePrefix}_${String(moduleIndex).padStart(2, "0")}`;
}
currentUE.modules.push({ code: modCode, name: modName, coeff: row[5] });
moduleIndex++;
}
}
return years;
}