@chukyo-umebo/web_parser 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +56 -0
  2. package/dist/cjs/albo/index.js +5 -0
  3. package/dist/cjs/albo/parser/albo.js +52 -0
  4. package/dist/cjs/albo/types/albo.js +19 -0
  5. package/dist/cjs/common/dom.js +116 -0
  6. package/dist/cjs/common/utils.js +13 -0
  7. package/dist/cjs/cubics/index.js +5 -0
  8. package/dist/cjs/cubics/parser/cubics.js +94 -0
  9. package/dist/cjs/cubics/types/cubics.js +38 -0
  10. package/dist/cjs/index.js +19 -0
  11. package/dist/cjs/manabo/index.js +23 -0
  12. package/dist/cjs/manabo/parser/manaboClass.js +428 -0
  13. package/dist/cjs/manabo/parser/manaboEntry.js +35 -0
  14. package/dist/cjs/manabo/parser/manaboMail.js +169 -0
  15. package/dist/cjs/manabo/parser/manaboNews.js +29 -0
  16. package/dist/cjs/manabo/parser/manaboTimetable.js +75 -0
  17. package/dist/cjs/manabo/types/manaboClass.js +126 -0
  18. package/dist/cjs/manabo/types/manaboEntry.js +21 -0
  19. package/dist/cjs/manabo/types/manaboMail.js +66 -0
  20. package/dist/cjs/manabo/types/manaboNews.js +11 -0
  21. package/dist/cjs/manabo/types/manaboTimetable.js +32 -0
  22. package/dist/esm/albo/index.d.ts +3 -0
  23. package/dist/esm/albo/index.d.ts.map +1 -0
  24. package/dist/esm/albo/index.js +1 -0
  25. package/dist/esm/albo/parser/albo.d.ts +4 -0
  26. package/dist/esm/albo/parser/albo.d.ts.map +1 -0
  27. package/dist/esm/albo/parser/albo.js +48 -0
  28. package/dist/esm/albo/types/albo.d.ts +34 -0
  29. package/dist/esm/albo/types/albo.d.ts.map +1 -0
  30. package/dist/esm/albo/types/albo.js +16 -0
  31. package/dist/esm/common/dom.d.ts +18 -0
  32. package/dist/esm/common/dom.d.ts.map +1 -0
  33. package/dist/esm/common/dom.js +99 -0
  34. package/dist/esm/common/utils.d.ts +3 -0
  35. package/dist/esm/common/utils.d.ts.map +1 -0
  36. package/dist/esm/common/utils.js +8 -0
  37. package/dist/esm/cubics/index.d.ts +3 -0
  38. package/dist/esm/cubics/index.d.ts.map +1 -0
  39. package/dist/esm/cubics/index.js +1 -0
  40. package/dist/esm/cubics/parser/cubics.d.ts +4 -0
  41. package/dist/esm/cubics/parser/cubics.d.ts.map +1 -0
  42. package/dist/esm/cubics/parser/cubics.js +90 -0
  43. package/dist/esm/cubics/types/cubics.d.ts +60 -0
  44. package/dist/esm/cubics/types/cubics.d.ts.map +1 -0
  45. package/dist/esm/cubics/types/cubics.js +35 -0
  46. package/dist/esm/index.d.ts +4 -0
  47. package/dist/esm/index.d.ts.map +1 -0
  48. package/dist/esm/index.js +3 -0
  49. package/dist/esm/manabo/index.d.ts +11 -0
  50. package/dist/esm/manabo/index.d.ts.map +1 -0
  51. package/dist/esm/manabo/index.js +5 -0
  52. package/dist/esm/manabo/parser/manaboClass.d.ts +9 -0
  53. package/dist/esm/manabo/parser/manaboClass.d.ts.map +1 -0
  54. package/dist/esm/manabo/parser/manaboClass.js +419 -0
  55. package/dist/esm/manabo/parser/manaboEntry.d.ts +5 -0
  56. package/dist/esm/manabo/parser/manaboEntry.d.ts.map +1 -0
  57. package/dist/esm/manabo/parser/manaboEntry.js +30 -0
  58. package/dist/esm/manabo/parser/manaboMail.d.ts +8 -0
  59. package/dist/esm/manabo/parser/manaboMail.d.ts.map +1 -0
  60. package/dist/esm/manabo/parser/manaboMail.js +161 -0
  61. package/dist/esm/manabo/parser/manaboNews.d.ts +4 -0
  62. package/dist/esm/manabo/parser/manaboNews.d.ts.map +1 -0
  63. package/dist/esm/manabo/parser/manaboNews.js +25 -0
  64. package/dist/esm/manabo/parser/manaboTimetable.d.ts +4 -0
  65. package/dist/esm/manabo/parser/manaboTimetable.d.ts.map +1 -0
  66. package/dist/esm/manabo/parser/manaboTimetable.js +71 -0
  67. package/dist/esm/manabo/types/manaboClass.d.ts +268 -0
  68. package/dist/esm/manabo/types/manaboClass.d.ts.map +1 -0
  69. package/dist/esm/manabo/types/manaboClass.js +123 -0
  70. package/dist/esm/manabo/types/manaboEntry.d.ts +21 -0
  71. package/dist/esm/manabo/types/manaboEntry.d.ts.map +1 -0
  72. package/dist/esm/manabo/types/manaboEntry.js +18 -0
  73. package/dist/esm/manabo/types/manaboMail.d.ts +95 -0
  74. package/dist/esm/manabo/types/manaboMail.d.ts.map +1 -0
  75. package/dist/esm/manabo/types/manaboMail.js +63 -0
  76. package/dist/esm/manabo/types/manaboNews.d.ts +13 -0
  77. package/dist/esm/manabo/types/manaboNews.d.ts.map +1 -0
  78. package/dist/esm/manabo/types/manaboNews.js +8 -0
  79. package/dist/esm/manabo/types/manaboTimetable.d.ts +57 -0
  80. package/dist/esm/manabo/types/manaboTimetable.d.ts.map +1 -0
  81. package/dist/esm/manabo/types/manaboTimetable.js +29 -0
  82. package/package.json +37 -0
@@ -0,0 +1,428 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseManaboClassQuizResult = exports.parseManaboClassSyllabus = exports.parseManaboClassNews = exports.parseManaboClassEntry = exports.parseManaboClassContent = exports.parseManaboClassDirectory = void 0;
4
+ const dom_1 = require("../../common/dom");
5
+ const manaboClass_1 = require("../types/manaboClass");
6
+ const normalizeWhitespace = (value) => value.replace(/\s+/g, " ").trim();
7
+ const findNextMatchingSibling = (element, selector) => {
8
+ let next = (0, dom_1.nextSiblingElement)(element);
9
+ while (next) {
10
+ if ((0, dom_1.matches)(next, selector)) {
11
+ return next;
12
+ }
13
+ next = (0, dom_1.nextSiblingElement)(next);
14
+ }
15
+ return null;
16
+ };
17
+ const parseManaboClassDirectory = (html) => {
18
+ const document = (0, dom_1.loadDocument)(html);
19
+ const classNode = (0, dom_1.queryOne)(".class-top-directory .x-content-drop", document);
20
+ const classId = (0, dom_1.getAttribute)(classNode, "class_id") ?? "";
21
+ const className = normalizeWhitespace((0, dom_1.getTextContent)((0, dom_1.queryOne)(".class-top-directory .span-class-name", document)));
22
+ const directories = (0, dom_1.queryAll)(".div-panel-directory li[directory_id]", document)
23
+ .map((node) => {
24
+ const directoryId = (0, dom_1.getAttribute)(node, "directory_id") ?? "";
25
+ const title = normalizeWhitespace((0, dom_1.getTextContent)((0, dom_1.queryOne)(".x-directory-name", node)));
26
+ return {
27
+ directoryId,
28
+ title,
29
+ };
30
+ })
31
+ .filter((directory) => directory.directoryId.length > 0 && directory.title.length > 0);
32
+ return manaboClass_1.ManaboClassDirectorySchema.safeParse({
33
+ classId,
34
+ className,
35
+ directories,
36
+ });
37
+ };
38
+ exports.parseManaboClassDirectory = parseManaboClassDirectory;
39
+ const parseManaboClassContent = (html) => {
40
+ const document = (0, dom_1.loadDocument)(html);
41
+ const extractDurations = (context) => {
42
+ const containers = (0, dom_1.queryAll)(".div-small", context);
43
+ const durations = [];
44
+ containers.forEach((container) => {
45
+ const boldElements = (0, dom_1.queryAll)("b", container);
46
+ boldElements.forEach((bold) => {
47
+ const label = normalizeWhitespace((0, dom_1.getTextContent)(bold));
48
+ const valueFragments = [];
49
+ let current = bold.next;
50
+ while (current) {
51
+ if ((0, dom_1.isElement)(current) && current.name.toLowerCase() === "b") {
52
+ break;
53
+ }
54
+ if ((0, dom_1.isElement)(current)) {
55
+ const tagName = current.name.toLowerCase();
56
+ if (tagName === "br") {
57
+ valueFragments.push(" ");
58
+ }
59
+ else {
60
+ valueFragments.push((0, dom_1.getTextContent)(current));
61
+ }
62
+ }
63
+ else {
64
+ valueFragments.push((0, dom_1.getTextContent)(current));
65
+ }
66
+ current = current.next;
67
+ }
68
+ const value = normalizeWhitespace(valueFragments.join(" "));
69
+ if (label.length > 0 || value.length > 0) {
70
+ durations.push({
71
+ label,
72
+ value,
73
+ });
74
+ }
75
+ });
76
+ });
77
+ return durations;
78
+ };
79
+ const contents = [];
80
+ const rows = (0, dom_1.queryAll)(".table-class-content tbody tr", document);
81
+ rows.forEach((row) => {
82
+ if ((0, dom_1.matches)(row, ".toggle-area")) {
83
+ return;
84
+ }
85
+ const cells = (0, dom_1.queryAll)("td", row);
86
+ if (!cells.length) {
87
+ return;
88
+ }
89
+ const detailCell = cells[1];
90
+ const pluginIconWrapper = (0, dom_1.queryOne)(".plugin-icon-wrapper", row);
91
+ const pluginIconSrc = (0, dom_1.getAttribute)((0, dom_1.queryOne)(".plugin-icon", row), "src") ?? "";
92
+ const isIconChecked = (pluginIconWrapper?.attribs?.class ?? "")
93
+ .split(/\s+/)
94
+ .filter((value) => value.length > 0)
95
+ .includes("img-checked");
96
+ const icon = {
97
+ pluginIconSrc,
98
+ isIconChecked,
99
+ };
100
+ const isFileRow = !!detailCell?.attribs?.colspan && detailCell.attribs.colspan === "2";
101
+ if (isFileRow) {
102
+ const commentNode = (0, dom_1.queryOne)(".x-drag-title .cf", row);
103
+ const comment = commentNode ? (0, dom_1.getInnerHtml)(commentNode).trim() : "";
104
+ const files = (0, dom_1.queryAll)(".margin-top-md .display-block", row)
105
+ .map((block) => {
106
+ const link = (0, dom_1.queryOne)("a", block);
107
+ const fileName = normalizeWhitespace((0, dom_1.getTextContent)(link));
108
+ const href = (0, dom_1.getAttribute)(link, "href") ?? "";
109
+ const fileIcon = (0, dom_1.getAttribute)((0, dom_1.queryOne)("img.icon", block), "src") ?? "";
110
+ return {
111
+ fileName,
112
+ href,
113
+ icon: fileIcon,
114
+ };
115
+ })
116
+ .filter((file) => file.fileName.length > 0 || file.href.length > 0 || file.icon.length > 0);
117
+ contents.push({
118
+ type: "file",
119
+ icon,
120
+ attachedFile: {
121
+ comment,
122
+ files,
123
+ duration: extractDurations(row),
124
+ },
125
+ });
126
+ return;
127
+ }
128
+ const titleAnchor = (0, dom_1.queryOne)("a.a-content-open", row);
129
+ const titleElement = titleAnchor ?? (0, dom_1.queryOne)("b", row);
130
+ const title = titleElement ? normalizeWhitespace((0, dom_1.getTextContent)(titleElement)) : "";
131
+ const contentId = titleAnchor ? (0, dom_1.getAttribute)(titleAnchor, "content_id") ?? "" : "";
132
+ const pluginKey = titleAnchor ? (0, dom_1.getAttribute)(titleAnchor, "plugin_key") ?? "" : "";
133
+ const duration = extractDurations(row);
134
+ const toggleRow = findNextMatchingSibling(row, ".toggle-area");
135
+ const toggleContainer = toggleRow ? (0, dom_1.queryOne)(".x-content-hide", toggleRow) ?? toggleRow : null;
136
+ const descriptionNode = toggleContainer ? (0, dom_1.queryOne)(".description", toggleContainer) : null;
137
+ const description = descriptionNode ? (0, dom_1.getInnerHtml)(descriptionNode).trim() : "";
138
+ const errorNodes = toggleContainer ? (0, dom_1.queryAll)(".confirm .error", toggleContainer) : [];
139
+ const errorMessages = errorNodes.map((errorNode) => normalizeWhitespace((0, dom_1.getTextContent)(errorNode))).filter((message) => message.length > 0);
140
+ const hasNotAvailableYetError = errorMessages.some((message) => message.includes("まだ受講できません"));
141
+ const isNotAvailableYet = hasNotAvailableYetError;
142
+ // Treat "まだ受講できません" as a future availability notice, not an expiration.
143
+ const isExpired = errorNodes.length > 0 ? !hasNotAvailableYetError : false;
144
+ const actions = toggleContainer
145
+ ? (0, dom_1.queryAll)(".confirm a.btn", toggleContainer).map((actionNode) => ({
146
+ title: normalizeWhitespace((0, dom_1.getTextContent)(actionNode)),
147
+ href: (0, dom_1.getAttribute)(actionNode, "href") ?? "",
148
+ }))
149
+ : [];
150
+ contents.push({
151
+ type: "report",
152
+ icon,
153
+ content: {
154
+ title,
155
+ contentId,
156
+ pluginKey,
157
+ duration,
158
+ },
159
+ toggleArea: {
160
+ description,
161
+ isExpired,
162
+ isNotAvailableYet,
163
+ actions,
164
+ },
165
+ });
166
+ });
167
+ return manaboClass_1.ManaboClassContentSchema.safeParse({
168
+ contents,
169
+ });
170
+ };
171
+ exports.parseManaboClassContent = parseManaboClassContent;
172
+ const parseManaboClassEntry = (html) => {
173
+ const document = (0, dom_1.loadDocument)(html);
174
+ const rows = (0, dom_1.queryAll)("table.table-default tbody tr", document)
175
+ .filter((row) => {
176
+ const cells = (0, dom_1.queryAll)("td", row);
177
+ // colspan属性を持つセルがある場合(空の状態を示す行)をフィルタリング
178
+ const hasColspan = cells.some((cell) => (0, dom_1.getAttribute)(cell, "colspan") !== null);
179
+ return !hasColspan;
180
+ })
181
+ .map((row) => {
182
+ const cells = (0, dom_1.queryAll)("td", row);
183
+ const directory = normalizeWhitespace((0, dom_1.getTextContent)(cells[0] ?? null));
184
+ const lectureDateRaw = normalizeWhitespace((0, dom_1.getTextContent)(cells[1] ?? null));
185
+ const status = normalizeWhitespace((0, dom_1.getTextContent)(cells[2] ?? null));
186
+ return {
187
+ directory,
188
+ lectureDate: lectureDateRaw.length ? lectureDateRaw : null,
189
+ status,
190
+ };
191
+ });
192
+ return manaboClass_1.ManaboClassEntrySchema.safeParse({
193
+ rows,
194
+ });
195
+ };
196
+ exports.parseManaboClassEntry = parseManaboClassEntry;
197
+ const parseManaboClassNews = (html) => {
198
+ const document = (0, dom_1.loadDocument)(html);
199
+ const items = (0, dom_1.queryAll)("dl.x-openclose", document).map((dl) => {
200
+ const title = normalizeWhitespace((0, dom_1.getTextContent)((0, dom_1.queryOne)("dt b", dl)));
201
+ const bodyHtml = (0, dom_1.getInnerHtml)((0, dom_1.queryOne)("dd", dl)).trim() || "";
202
+ return {
203
+ id: (0, dom_1.getAttribute)(dl, "id"),
204
+ title,
205
+ bodyHtml,
206
+ };
207
+ });
208
+ return manaboClass_1.ManaboClassNewsSchema.safeParse({
209
+ items,
210
+ });
211
+ };
212
+ exports.parseManaboClassNews = parseManaboClassNews;
213
+ const parseManaboClassSyllabus = (html) => {
214
+ const document = (0, dom_1.loadDocument)(html);
215
+ const mainTable = (0, dom_1.queryOne)(".panel-body .table.table-default", document);
216
+ const rows = mainTable ? (0, dom_1.queryAll)("tr", mainTable).filter((row) => (0, dom_1.closest)(row, "table") === mainTable) : [];
217
+ let object = "";
218
+ let goal = [];
219
+ let method = "";
220
+ let usedMethods = [];
221
+ let evaluation = [];
222
+ const textbooks = [];
223
+ let references = [];
224
+ let officeHour = "";
225
+ let plan = [];
226
+ let comment = "";
227
+ let prePostStudy = "";
228
+ const isDataNode = (node) => !!node && typeof node.data === "string";
229
+ const collectSiblingText = (element) => {
230
+ if (!element) {
231
+ return "";
232
+ }
233
+ const fragments = [];
234
+ let current = element.next;
235
+ while (current) {
236
+ if ((0, dom_1.isElement)(current)) {
237
+ if (current.name.toLowerCase() === "br") {
238
+ break;
239
+ }
240
+ fragments.push((0, dom_1.getTextContent)(current));
241
+ }
242
+ else if (isDataNode(current)) {
243
+ fragments.push(current.data);
244
+ }
245
+ current = current.next;
246
+ }
247
+ return normalizeWhitespace(fragments.join(" "));
248
+ };
249
+ rows.forEach((row) => {
250
+ const heading = normalizeWhitespace((0, dom_1.getTextContent)((0, dom_1.queryOne)("th", row)));
251
+ const cell = (0, dom_1.queryOne)("td", row);
252
+ switch (heading) {
253
+ case "授業概要・目的": {
254
+ object = normalizeWhitespace((0, dom_1.getTextContent)(cell));
255
+ break;
256
+ }
257
+ case "学修到達目標": {
258
+ goal = (0, dom_1.queryAll)("li", cell)
259
+ .map((item) => normalizeWhitespace((0, dom_1.getTextContent)(item)))
260
+ .filter((item) => item.length > 0);
261
+ break;
262
+ }
263
+ case "授業方法": {
264
+ method = normalizeWhitespace((0, dom_1.getTextContent)(cell));
265
+ break;
266
+ }
267
+ case "活用される授業方法": {
268
+ usedMethods = (0, dom_1.queryAll)("input.usemethod[checked]", cell)
269
+ .map((input) => collectSiblingText(input))
270
+ .filter((value) => value.length > 0);
271
+ break;
272
+ }
273
+ case "成績評価方法・基準": {
274
+ evaluation = (0, dom_1.queryAll)("table tr", cell)
275
+ .map((evalRow) => {
276
+ const columns = (0, dom_1.queryAll)("td", evalRow);
277
+ const type = normalizeWhitespace((0, dom_1.getTextContent)(columns[0] ?? null));
278
+ const weight = normalizeWhitespace((0, dom_1.getTextContent)(columns[1] ?? null));
279
+ if (!type || !weight) {
280
+ return null;
281
+ }
282
+ return { type, weight };
283
+ })
284
+ .filter((item) => item !== null);
285
+ break;
286
+ }
287
+ case "教科書・教材・参考文献": {
288
+ (0, dom_1.queryAll)("table tr", cell).forEach((bookRow) => {
289
+ const cells = (0, dom_1.queryAll)("td", bookRow);
290
+ const label = normalizeWhitespace((0, dom_1.getTextContent)(cells[0] ?? null));
291
+ const valueCell = cells[1] ?? null;
292
+ if (!valueCell) {
293
+ return;
294
+ }
295
+ if (label.includes("教科書・教材")) {
296
+ const title = normalizeWhitespace((0, dom_1.getTextContent)(valueCell));
297
+ if (title) {
298
+ textbooks.push({
299
+ type: label,
300
+ title,
301
+ });
302
+ }
303
+ }
304
+ else if (label.includes("参考文献")) {
305
+ references = (0, dom_1.queryAll)("li", valueCell)
306
+ .map((item) => {
307
+ const title = normalizeWhitespace((0, dom_1.getTextContent)(item));
308
+ const code = (0, dom_1.getAttribute)(item, "data-code") ?? "";
309
+ if (!title || !code) {
310
+ return null;
311
+ }
312
+ return {
313
+ title,
314
+ code,
315
+ };
316
+ })
317
+ .filter((item) => item !== null);
318
+ }
319
+ });
320
+ break;
321
+ }
322
+ case "質問への対応(オフィスアワー等)": {
323
+ officeHour = normalizeWhitespace((0, dom_1.getTextContent)(cell));
324
+ break;
325
+ }
326
+ case "授業計画": {
327
+ const planTable = (0, dom_1.queryOne)("table", cell);
328
+ plan = (0, dom_1.queryAll)("tbody tr", planTable)
329
+ .map((planRow) => {
330
+ const cols = (0, dom_1.queryAll)("td", planRow);
331
+ const noText = normalizeWhitespace((0, dom_1.getTextContent)(cols[0] ?? null));
332
+ const item = normalizeWhitespace((0, dom_1.getTextContent)(cols[1] ?? null));
333
+ const content = normalizeWhitespace((0, dom_1.getTextContent)(cols[2] ?? null));
334
+ const no = Number.parseInt(noText, 10);
335
+ if (!Number.isFinite(no) || !item || !content) {
336
+ return null;
337
+ }
338
+ return { no, item, content };
339
+ })
340
+ .filter((entry) => entry !== null);
341
+ break;
342
+ }
343
+ case "履修者へのコメント": {
344
+ comment = normalizeWhitespace((0, dom_1.getTextContent)(cell));
345
+ break;
346
+ }
347
+ case "事前事後学習": {
348
+ prePostStudy = normalizeWhitespace((0, dom_1.getTextContent)(cell)).replace(/\s+\(/g, "(");
349
+ break;
350
+ }
351
+ default:
352
+ break;
353
+ }
354
+ });
355
+ return manaboClass_1.ManaboClassSyllabusSchema.safeParse({
356
+ object,
357
+ goal,
358
+ method,
359
+ usedMethods,
360
+ evaluation,
361
+ textbooks,
362
+ references,
363
+ officeHour,
364
+ plan,
365
+ comment,
366
+ prePostStudy,
367
+ });
368
+ };
369
+ exports.parseManaboClassSyllabus = parseManaboClassSyllabus;
370
+ const parseManaboClassQuizResult = (html) => {
371
+ const document = (0, dom_1.loadDocument)(html);
372
+ const scoreText = normalizeWhitespace((0, dom_1.getTextContent)((0, dom_1.queryOne)(".text-center .Red b", document)));
373
+ const totalTextRaw = normalizeWhitespace((0, dom_1.getTextContent)((0, dom_1.queryOne)(".text-center", document)));
374
+ const totalText = totalTextRaw.split("/")[1] ?? "0";
375
+ const obtained = Number(scoreText.replace(/[^\d]/g, "")) || 0;
376
+ const total = Number(totalText.replace(/[^\d]/g, "")) || 0;
377
+ const totalItemsText = normalizeWhitespace((0, dom_1.getTextContent)((0, dom_1.queryOne)(".row.margin-top-md .col-sm-2", document)));
378
+ let currentPage = "";
379
+ const questions = (0, dom_1.queryAll)("table.table-default-grade tbody tr", document).map((row) => {
380
+ const cells = (0, dom_1.queryAll)("td", row);
381
+ let cellIndex = 0;
382
+ const firstCell = cells[cellIndex];
383
+ if ((0, dom_1.getAttribute)(firstCell, "rowspan")) {
384
+ currentPage = normalizeWhitespace((0, dom_1.getTextContent)(firstCell));
385
+ cellIndex += 1;
386
+ }
387
+ else if (cells.length === 7) {
388
+ currentPage = normalizeWhitespace((0, dom_1.getTextContent)(firstCell));
389
+ cellIndex += 1;
390
+ }
391
+ const questionNumber = normalizeWhitespace((0, dom_1.getTextContent)(cells[cellIndex] ?? null));
392
+ cellIndex += 1;
393
+ const questionCell = cells[cellIndex] ?? null;
394
+ const instruction = (0, dom_1.queryOne)(".div-instructions", questionCell ?? null);
395
+ const questionText = normalizeWhitespace(instruction ? (0, dom_1.getTextContent)(instruction) : (0, dom_1.getTextContent)(questionCell));
396
+ cellIndex += 1;
397
+ const correctAnswer = normalizeWhitespace((0, dom_1.getTextContent)(cells[cellIndex] ?? null));
398
+ cellIndex += 1;
399
+ const studentAnswer = normalizeWhitespace((0, dom_1.getTextContent)(cells[cellIndex] ?? null));
400
+ cellIndex += 1;
401
+ const resultCell = cells[cellIndex] ?? null;
402
+ const resultIcon = (0, dom_1.queryOne)("img", resultCell ?? null);
403
+ const resultText = normalizeWhitespace((0, dom_1.getTextContent)(resultCell));
404
+ cellIndex += 1;
405
+ const teacherComment = normalizeWhitespace((0, dom_1.getTextContent)(cells[cellIndex] ?? null));
406
+ const resultAltRaw = normalizeWhitespace((0, dom_1.getAttribute)(resultIcon, "alt") ?? "");
407
+ return {
408
+ page: currentPage,
409
+ questionNumber,
410
+ questionText,
411
+ correctAnswer,
412
+ studentAnswer,
413
+ resultIconAlt: resultAltRaw.length ? resultAltRaw : null,
414
+ resultIconSrc: (0, dom_1.getAttribute)(resultIcon, "src"),
415
+ resultText: resultText.length ? resultText : null,
416
+ teacherComment: teacherComment.length ? teacherComment : null,
417
+ };
418
+ });
419
+ return manaboClass_1.ManaboClassQuizResultSchema.safeParse({
420
+ score: {
421
+ obtained,
422
+ total,
423
+ },
424
+ totalItemsText: totalItemsText.length ? totalItemsText : null,
425
+ questions,
426
+ });
427
+ };
428
+ exports.parseManaboClassQuizResult = parseManaboClassQuizResult;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseManaboEntryResponse = exports.parseManaboEntryForm = void 0;
4
+ const dom_1 = require("../../common/dom");
5
+ const manaboEntry_1 = require("../types/manaboEntry");
6
+ const normalizeWhitespace = (value) => value.replace(/\s+/g, " ").trim();
7
+ const parseManaboEntryForm = (html) => {
8
+ const document = (0, dom_1.loadDocument)(html);
9
+ const form = (0, dom_1.queryOne)("#form-entry", document);
10
+ const messages = form
11
+ ? (0, dom_1.queryAll)("p", form)
12
+ .map((element) => normalizeWhitespace((0, dom_1.getTextContent)(element)))
13
+ .filter((message) => message.length > 0)
14
+ : [];
15
+ return manaboEntry_1.ManaboEntryFormSchema.safeParse({
16
+ action: (0, dom_1.getAttribute)((0, dom_1.queryOne)('input[name="action"]', form ?? null), "value") ?? "",
17
+ classId: (0, dom_1.getAttribute)((0, dom_1.queryOne)('input[name="class_id"]', form ?? null), "value") ?? "",
18
+ directoryId: (0, dom_1.getAttribute)((0, dom_1.queryOne)('input[name="directory_id"]', form ?? null), "value") ?? "",
19
+ entryId: (0, dom_1.getAttribute)((0, dom_1.queryOne)('input[name="entry_id"]', form ?? null), "value") ?? "",
20
+ uniqid: (0, dom_1.getAttribute)((0, dom_1.queryOne)('input[name="uniqid"]', form ?? null), "value") ?? "",
21
+ messages,
22
+ });
23
+ };
24
+ exports.parseManaboEntryForm = parseManaboEntryForm;
25
+ const parseManaboEntryResponse = (json) => {
26
+ let parsed;
27
+ try {
28
+ parsed = JSON.parse(json);
29
+ }
30
+ catch {
31
+ parsed = undefined;
32
+ }
33
+ return manaboEntry_1.ManaboEntryResponseSchema.safeParse(parsed);
34
+ };
35
+ exports.parseManaboEntryResponse = parseManaboEntryResponse;
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseManaboMailMember = exports.parseManaboMailSend = exports.parseManaboMailView = exports.parseManaboSentMail = exports.parseManaboReceivedMail = void 0;
4
+ const dom_1 = require("../../common/dom");
5
+ const manaboMail_1 = require("../types/manaboMail");
6
+ const normalizeWhitespace = (value) => value.replace(/\s+/g, " ").trim();
7
+ const collectTextExcluding = (nodes, exclude) => normalizeWhitespace(nodes
8
+ .filter((node) => !exclude(node))
9
+ .map((node) => (0, dom_1.getTextContent)(node))
10
+ .join(" "));
11
+ const extractPagination = (document) => {
12
+ const summaryElement = (0, dom_1.queryOne)(".row.margin-top-md .col-sm-2", document);
13
+ const summaryText = normalizeWhitespace((0, dom_1.getTextContent)(summaryElement));
14
+ const pages = (0, dom_1.queryAll)("ul.pagination li", document)
15
+ .map((li) => {
16
+ const anchor = (0, dom_1.queryOne)("a", li);
17
+ const labelSource = anchor ?? (0, dom_1.queryOne)("span", li);
18
+ const label = normalizeWhitespace((0, dom_1.getTextContent)(labelSource));
19
+ return {
20
+ label,
21
+ page: anchor ? (0, dom_1.getAttribute)(anchor, "page") ?? label : label,
22
+ active: (anchor ? (0, dom_1.elementHasClass)(anchor, "active") : false) || (0, dom_1.elementHasClass)(li, "active"),
23
+ };
24
+ })
25
+ .filter((page) => page.label.length > 0);
26
+ return {
27
+ summary: summaryText.length ? summaryText : null,
28
+ pages,
29
+ };
30
+ };
31
+ const parseManaboReceivedMail = (html) => {
32
+ const document = (0, dom_1.loadDocument)(html);
33
+ const { summary, pages } = extractPagination(document);
34
+ const mails = (0, dom_1.queryAll)("table.table-default tbody tr", document).map((row) => {
35
+ const cells = (0, dom_1.queryAll)("td", row);
36
+ const checkbox = (0, dom_1.queryOne)('input[type="checkbox"]', row);
37
+ const mailId = (0, dom_1.getAttribute)(checkbox, "value") ?? (0, dom_1.getAttribute)(checkbox, "name") ?? "";
38
+ const titleAnchor = (0, dom_1.queryOne)("td.title a.a-mail-view", row);
39
+ const statusIcon = (0, dom_1.queryOne)("td.title img.icon", row);
40
+ const senderCell = cells[2];
41
+ const senderImage = (0, dom_1.getAttribute)((0, dom_1.queryOne)("img", senderCell ?? null), "src");
42
+ const humanSender = (0, dom_1.queryOne)("span.margin-left-sm", senderCell ?? null);
43
+ const classSender = (0, dom_1.queryOne)("a", senderCell ?? null);
44
+ const senderName = normalizeWhitespace((0, dom_1.getTextContent)(humanSender ?? classSender ?? null));
45
+ const receivedAt = normalizeWhitespace((0, dom_1.getTextContent)(cells[3] ?? null));
46
+ const statusAltRaw = normalizeWhitespace((0, dom_1.getAttribute)(statusIcon, "alt") ?? "");
47
+ return {
48
+ id: mailId,
49
+ title: normalizeWhitespace((0, dom_1.getTextContent)(titleAnchor)),
50
+ statusIconAlt: statusAltRaw.length ? statusAltRaw : null,
51
+ statusIconSrc: (0, dom_1.getAttribute)(statusIcon, "src"),
52
+ mailLink: (0, dom_1.getAttribute)(titleAnchor, "href"),
53
+ senderName: senderName.length ? senderName : null,
54
+ senderImage,
55
+ receivedAt,
56
+ };
57
+ });
58
+ return manaboMail_1.ManaboReceivedMailSchema.safeParse({
59
+ summary,
60
+ pages,
61
+ mails,
62
+ });
63
+ };
64
+ exports.parseManaboReceivedMail = parseManaboReceivedMail;
65
+ const parseManaboSentMail = (html) => {
66
+ const document = (0, dom_1.loadDocument)(html);
67
+ const summaryRaw = normalizeWhitespace((0, dom_1.getTextContent)((0, dom_1.queryOne)(".row.margin-top-md .col-sm-2", document)));
68
+ const mails = (0, dom_1.queryAll)("table.table-default tbody tr", document).map((row) => {
69
+ const cells = (0, dom_1.queryAll)("td", row);
70
+ const checkbox = (0, dom_1.queryOne)('input[type="checkbox"]', row);
71
+ const mailId = (0, dom_1.getAttribute)(checkbox, "value") ?? (0, dom_1.getAttribute)(checkbox, "name") ?? "";
72
+ const titleCell = cells[1];
73
+ const titleAnchor = (0, dom_1.queryOne)("a.a-mail-view", titleCell ?? null);
74
+ const statusIcon = (0, dom_1.queryOne)("img.icon", titleCell ?? null);
75
+ const recipientCell = cells[2];
76
+ const recipientImage = (0, dom_1.getAttribute)((0, dom_1.queryOne)("img", recipientCell ?? null), "src");
77
+ const humanSender = (0, dom_1.queryOne)("span.margin-left-sm", recipientCell ?? null);
78
+ const classSender = (0, dom_1.queryOne)("a", recipientCell ?? null);
79
+ const recipientName = normalizeWhitespace((0, dom_1.getTextContent)(humanSender ?? classSender ?? null));
80
+ const sentAt = normalizeWhitespace((0, dom_1.getTextContent)(cells[3] ?? null));
81
+ const unreadCountRaw = normalizeWhitespace((0, dom_1.getTextContent)(cells[4] ?? null));
82
+ const unreadCount = Number(unreadCountRaw.replace(/[^\d]/g, "")) || 0;
83
+ const statusAltRaw = normalizeWhitespace((0, dom_1.getAttribute)(statusIcon, "alt") ?? "");
84
+ return {
85
+ id: mailId,
86
+ title: normalizeWhitespace((0, dom_1.getTextContent)(titleAnchor)),
87
+ statusIconAlt: statusAltRaw.length ? statusAltRaw : null,
88
+ statusIconSrc: (0, dom_1.getAttribute)(statusIcon, "src"),
89
+ mailLink: (0, dom_1.getAttribute)(titleAnchor, "href"),
90
+ recipientName: recipientName.length ? recipientName : null,
91
+ recipientImage,
92
+ sentAt,
93
+ unreadCount,
94
+ };
95
+ });
96
+ return manaboMail_1.ManaboSentMailSchema.safeParse({
97
+ summary: summaryRaw.length ? summaryRaw : null,
98
+ mails,
99
+ });
100
+ };
101
+ exports.parseManaboSentMail = parseManaboSentMail;
102
+ const parseManaboMailView = (html) => {
103
+ const document = (0, dom_1.loadDocument)(html);
104
+ const title = normalizeWhitespace((0, dom_1.getTextContent)((0, dom_1.queryOne)(".modal-title", document)));
105
+ const replyButton = (0, dom_1.queryOne)(".a-reply-mail", document);
106
+ const nextButton = (0, dom_1.queryOne)(".a-reopen-mail", document);
107
+ const senderBlocks = (0, dom_1.queryAll)(".modal-body .margin-top-lg", document);
108
+ const senderBlock = senderBlocks[0];
109
+ const bodyBlock = senderBlocks[1];
110
+ const senderImage = (0, dom_1.getAttribute)((0, dom_1.queryOne)("img", senderBlock ?? null), "src");
111
+ const senderName = normalizeWhitespace((0, dom_1.getTextContent)((0, dom_1.queryOne)("b", senderBlock ?? null)));
112
+ const sentAtRaw = senderBlock
113
+ ? collectTextExcluding(senderBlock.children ?? [], (node) => {
114
+ if (!(0, dom_1.isElement)(node)) {
115
+ return false;
116
+ }
117
+ const name = node.name.toLowerCase();
118
+ return name === "a" || name === "script";
119
+ })
120
+ : "";
121
+ const sentAt = normalizeWhitespace(sentAtRaw);
122
+ const bodyHtml = bodyBlock ? (0, dom_1.getInnerHtml)(bodyBlock).trim() : "";
123
+ return manaboMail_1.ManaboMailViewSchema.safeParse({
124
+ title,
125
+ replyMailId: (0, dom_1.getAttribute)(replyButton, "reply_mail_id"),
126
+ fromMemberId: (0, dom_1.getAttribute)(replyButton, "from_member_id"),
127
+ nextMailId: (0, dom_1.getAttribute)(nextButton, "mail_id"),
128
+ senderName,
129
+ senderImage,
130
+ sentAt,
131
+ bodyHtml,
132
+ });
133
+ };
134
+ exports.parseManaboMailView = parseManaboMailView;
135
+ const parseManaboMailSend = (html) => {
136
+ const document = (0, dom_1.loadDocument)(html);
137
+ const modalTitle = normalizeWhitespace((0, dom_1.getTextContent)((0, dom_1.queryOne)(".modal-title", document)));
138
+ const form = (0, dom_1.queryOne)("#form-mail", document);
139
+ return manaboMail_1.ManaboMailSendSchema.safeParse({
140
+ modalTitle,
141
+ form: {
142
+ action: (0, dom_1.getAttribute)((0, dom_1.queryOne)('input[name="action"]', form ?? null), "value") ?? "",
143
+ replyMailId: (0, dom_1.getAttribute)((0, dom_1.queryOne)('input[name="reply_mail_id"]', form ?? null), "value"),
144
+ signature: (0, dom_1.getAttribute)((0, dom_1.queryOne)('input[name="signature"]', form ?? null), "value"),
145
+ csrfToken: (0, dom_1.getAttribute)((0, dom_1.queryOne)('input[name="csrf_token"]', form ?? null), "value") ?? "",
146
+ },
147
+ submitLabel: normalizeWhitespace((0, dom_1.getTextContent)((0, dom_1.queryOne)(".button-send-mail", document))),
148
+ });
149
+ };
150
+ exports.parseManaboMailSend = parseManaboMailSend;
151
+ const parseManaboMailMember = (html) => {
152
+ const document = (0, dom_1.loadDocument)(html);
153
+ const members = (0, dom_1.queryAll)(".div-mail-members li", document)
154
+ .map((item) => {
155
+ const anchor = (0, dom_1.queryOne)("a.a-set-mail-member", item);
156
+ const name = normalizeWhitespace((0, dom_1.getTextContent)(anchor));
157
+ const image = (0, dom_1.getAttribute)((0, dom_1.queryOne)("img", item), "src");
158
+ return {
159
+ memberId: (0, dom_1.getAttribute)(anchor, "member_id") ?? "",
160
+ name,
161
+ image,
162
+ };
163
+ })
164
+ .filter((member) => member.memberId.length > 0);
165
+ return manaboMail_1.ManaboMailMemberSchema.safeParse({
166
+ members,
167
+ });
168
+ };
169
+ exports.parseManaboMailMember = parseManaboMailMember;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseManaboNews = void 0;
4
+ const dom_1 = require("../../common/dom");
5
+ const manaboNews_1 = require("../types/manaboNews");
6
+ const normalizeWhitespace = (value) => value.replace(/\s+/g, " ").trim();
7
+ const parseManaboNews = (html) => {
8
+ const document = (0, dom_1.loadDocument)(html);
9
+ const rows = (0, dom_1.queryAll)(".table-info tbody tr", document);
10
+ const items = [];
11
+ let message = null;
12
+ rows.forEach((row) => {
13
+ const text = normalizeWhitespace((0, dom_1.getTextContent)(row));
14
+ if (!text.length) {
15
+ return;
16
+ }
17
+ if ((0, dom_1.queryOne)("a", row)) {
18
+ items.push({ text });
19
+ }
20
+ else {
21
+ message = text;
22
+ }
23
+ });
24
+ return manaboNews_1.ManaboNewsSchema.safeParse({
25
+ message,
26
+ items,
27
+ });
28
+ };
29
+ exports.parseManaboNews = parseManaboNews;