From a57d7ac44ce00c7dba0c476dd096d1c4d8af0d99 Mon Sep 17 00:00:00 2001 From: Adrian Bonpin Date: Tue, 18 Aug 2026 15:26:13 +0800 Subject: [PATCH] feat: parse study load table --- parsers.js | 50 ++++++++++++++++++++++++++++++++++++++++++++ test/parsers.test.js | 28 +++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 parsers.js create mode 100644 test/parsers.test.js diff --git a/parsers.js b/parsers.js new file mode 100644 index 0000000..756b14d --- /dev/null +++ b/parsers.js @@ -0,0 +1,50 @@ +(function (root, factory) { + if (typeof module === 'object' && module.exports) { + module.exports = factory(); + } else { + root.ISMIStools = Object.assign(root.ISMIStools || {}, factory()); + } +})(typeof self !== 'undefined' ? self : this, function () { + 'use strict'; + + function cleanText(s) { + return String(s == null ? '' : s) + .replace(/<[^>]+>/g, ' ') + .replace(/ /gi, ' ') + .replace(/\s+/g, ' ') + .trim(); + } + + function extractRows(html) { + const rows = []; + const trRe = /]*>([\s\S]*?)<\/tr>/gi; + let trMatch; + while ((trMatch = trRe.exec(html)) !== null) { + const rowHtml = trMatch[1]; + if (/]*>([\s\S]*?)<\/td>/gi; + let tdMatch; + while ((tdMatch = tdRe.exec(rowHtml)) !== null) { + tds.push(cleanText(tdMatch[1])); + } + rows.push(tds); + } + return rows; + } + + function parseStudyLoadTable(html) { + return extractRows(html) + .filter((tds) => tds.length >= 6) + .map((tds) => ({ + group: tds[0], + courseCode: tds[1], + schedule: tds[2], + faculty: tds[3], + units: tds[4], + status: tds[5] + })); + } + + return { parseStudyLoadTable }; +}); diff --git a/test/parsers.test.js b/test/parsers.test.js new file mode 100644 index 0000000..fbb9f21 --- /dev/null +++ b/test/parsers.test.js @@ -0,0 +1,28 @@ +const { test } = require('node:test'); +const assert = require('node:assert'); +const fs = require('node:fs'); +const path = require('node:path'); +const { parseStudyLoadTable } = require('../parsers.js'); + +const fixture = fs.readFileSync(path.join(__dirname, 'fixtures', 'study-load-table.html'), 'utf8'); + +test('parseStudyLoadTable extracts all course rows', () => { + const rows = parseStudyLoadTable(fixture); + assert.strictEqual(rows.length, 5); +}); + +test('parseStudyLoadTable maps columns correctly', () => { + const rows = parseStudyLoadTable(fixture); + const first = rows[0]; + assert.strictEqual(first.group, '1'); + assert.strictEqual(first.courseCode, 'CS 5105'); + assert.strictEqual(first.units, '3.00'); + assert.strictEqual(first.status, 'DISSOLVED'); + assert.ok(first.schedule.includes('F 01:30 PM')); +}); + +test('parseStudyLoadTable handles empty faculty', () => { + const rows = parseStudyLoadTable(fixture); + const it4102 = rows.find(r => r.courseCode === 'IT 4102N'); + assert.strictEqual(it4102.faculty, ''); +});