@robertying/thu-learn-lib 5.0.0 → 6.0.0

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 (84) hide show
  1. package/README.md +94 -227
  2. package/lib/auth.d.ts +15 -4
  3. package/lib/auth.d.ts.map +1 -1
  4. package/lib/auth.js +65 -55
  5. package/lib/auth.js.map +1 -1
  6. package/lib/calendar.d.ts +12 -5
  7. package/lib/calendar.d.ts.map +1 -1
  8. package/lib/calendar.js +118 -20
  9. package/lib/calendar.js.map +1 -1
  10. package/lib/contents.d.ts.map +1 -1
  11. package/lib/contents.js +10 -6
  12. package/lib/contents.js.map +1 -1
  13. package/lib/courses.d.ts.map +1 -1
  14. package/lib/courses.js +15 -29
  15. package/lib/courses.js.map +1 -1
  16. package/lib/discussions.d.ts.map +1 -1
  17. package/lib/discussions.js +8 -19
  18. package/lib/discussions.js.map +1 -1
  19. package/lib/favorites.d.ts +1 -0
  20. package/lib/favorites.d.ts.map +1 -1
  21. package/lib/favorites.js +25 -60
  22. package/lib/favorites.js.map +1 -1
  23. package/lib/files.d.ts +4 -4
  24. package/lib/files.d.ts.map +1 -1
  25. package/lib/files.js +112 -134
  26. package/lib/files.js.map +1 -1
  27. package/lib/homework.d.ts +35 -5
  28. package/lib/homework.d.ts.map +1 -1
  29. package/lib/homework.js +150 -92
  30. package/lib/homework.js.map +1 -1
  31. package/lib/index.d.ts +45 -20
  32. package/lib/index.d.ts.map +1 -1
  33. package/lib/index.js +52 -17
  34. package/lib/index.js.map +1 -1
  35. package/lib/notices.d.ts +4 -4
  36. package/lib/notices.d.ts.map +1 -1
  37. package/lib/notices.js +13 -33
  38. package/lib/notices.js.map +1 -1
  39. package/lib/questionnaires.d.ts +6 -3
  40. package/lib/questionnaires.d.ts.map +1 -1
  41. package/lib/questionnaires.js +26 -24
  42. package/lib/questionnaires.js.map +1 -1
  43. package/lib/request.d.ts +64 -20
  44. package/lib/request.d.ts.map +1 -1
  45. package/lib/request.js +174 -64
  46. package/lib/request.js.map +1 -1
  47. package/lib/timetable.d.ts +26 -0
  48. package/lib/timetable.d.ts.map +1 -0
  49. package/lib/timetable.js +110 -0
  50. package/lib/timetable.js.map +1 -0
  51. package/lib/types.d.ts +117 -76
  52. package/lib/types.d.ts.map +1 -1
  53. package/lib/types.js +3 -0
  54. package/lib/types.js.map +1 -1
  55. package/lib/urls.d.ts +10 -20
  56. package/lib/urls.d.ts.map +1 -1
  57. package/lib/urls.js +11 -56
  58. package/lib/urls.js.map +1 -1
  59. package/lib/user.d.ts +7 -2
  60. package/lib/user.d.ts.map +1 -1
  61. package/lib/user.js +20 -6
  62. package/lib/user.js.map +1 -1
  63. package/lib/utils.d.ts +42 -4
  64. package/lib/utils.d.ts.map +1 -1
  65. package/lib/utils.js +80 -29
  66. package/lib/utils.js.map +1 -1
  67. package/package.json +9 -8
  68. package/src/auth.ts +72 -70
  69. package/src/calendar.ts +136 -24
  70. package/src/contents.ts +13 -6
  71. package/src/courses.ts +21 -37
  72. package/src/discussions.ts +10 -21
  73. package/src/favorites.ts +44 -80
  74. package/src/files.ts +124 -142
  75. package/src/homework.ts +207 -135
  76. package/src/index.ts +79 -48
  77. package/src/notices.ts +29 -42
  78. package/src/questionnaires.ts +62 -45
  79. package/src/request.ts +192 -69
  80. package/src/timetable.ts +121 -0
  81. package/src/types.ts +123 -87
  82. package/src/urls.ts +13 -64
  83. package/src/user.ts +22 -7
  84. package/src/utils.ts +97 -29
package/lib/request.js CHANGED
@@ -1,14 +1,9 @@
1
- import * as cheerio from 'cheerio';
2
1
  import fetchCookie from 'fetch-cookie';
3
2
  import { fetch } from 'node-fetch-native';
4
3
  import { CookieJar } from 'tough-cookie';
5
4
  import { FailReason, Language } from './types.js';
6
- const CHEERIO_CONFIG = { xml: true };
7
- export const $ = (html) => {
8
- return cheerio.load(html, CHEERIO_CONFIG);
9
- };
5
+ import { apiError, looksLikeLoginPage, urlOf } from './utils.js';
10
6
  export const noLogin = (res) => res.url.includes('login_timeout') || res.status === 403;
11
- export const YES = '是';
12
7
  /** default for `HelperConfig.maxConcurrentRequests` */
13
8
  export const DEFAULT_MAX_CONCURRENT_REQUESTS = 6;
14
9
  /** default for `HelperConfig.requestTimeout`, in milliseconds */
@@ -22,7 +17,6 @@ export const addCSRFTokenToUrl = (url, token) => {
22
17
  function makeFetch(jar) {
23
18
  return fetchCookie(fetch, jar);
24
19
  }
25
- const urlOf = (input) => typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;
26
20
  /**
27
21
  * Let at most `max` calls of `inner` run at once; the rest wait in FIFO order. A slot is freed when the response
28
22
  * headers arrive (or the call fails), so reading a body does not hold one.
@@ -47,7 +41,7 @@ export function limitConcurrency(inner, max) {
47
41
  else
48
42
  active -= 1;
49
43
  };
50
- return async (...args) => {
44
+ return (async (...args) => {
51
45
  await acquire();
52
46
  try {
53
47
  return await inner(...args);
@@ -55,57 +49,82 @@ export function limitConcurrency(inner, max) {
55
49
  finally {
56
50
  release();
57
51
  }
58
- };
52
+ });
59
53
  }
60
54
  /**
61
- * Abort a call of `inner` that has no response headers after `ms` milliseconds and reject it with
62
- * `FailReason.REQUEST_TIMEOUT`. A caller's own `signal` still works. Uses only `AbortController` and `setTimeout`,
63
- * which React Native has (unlike `AbortSignal.timeout` / `AbortSignal.any`).
55
+ * Abort a call of `inner` that has no response headers after `ms` milliseconds (or `init.timeout`, which overrides it
56
+ * for one request) and reject it with `FailReason.REQUEST_TIMEOUT`. A caller's own `signal` still works, also while
57
+ * the body is read. Uses only `AbortController` and `setTimeout`, which React Native has (unlike
58
+ * `AbortSignal.timeout` / `AbortSignal.any`). Note that React Native's fetch resolves only after the whole body has
59
+ * arrived, so there the timeout covers the download too.
64
60
  */
65
61
  export function withTimeout(inner, ms) {
66
- if (!(ms > 0) || ms === Infinity)
67
- return inner;
68
- return async (input, init) => {
62
+ return async (input, options) => {
63
+ const { timeout = ms, ...init } = options ?? {};
64
+ if (!(timeout > 0) || timeout === Infinity)
65
+ return inner(input, init);
69
66
  const controller = new AbortController();
70
- const outer = init?.signal ?? undefined;
67
+ const outer = init.signal ?? undefined;
71
68
  const forward = () => controller.abort(outer?.reason);
72
69
  if (outer?.aborted)
73
70
  forward();
71
+ // kept after the headers arrive, so the caller can still cancel reading the body
74
72
  else
75
73
  outer?.addEventListener('abort', forward, { once: true });
76
74
  let timedOut = false;
77
75
  const timer = setTimeout(() => {
78
76
  timedOut = true;
79
77
  controller.abort();
80
- }, ms);
78
+ }, timeout);
81
79
  try {
82
80
  return await inner(input, { ...init, signal: controller.signal });
83
81
  }
84
82
  catch (err) {
83
+ outer?.removeEventListener('abort', forward);
85
84
  if (timedOut) {
86
- throw {
87
- reason: FailReason.REQUEST_TIMEOUT,
88
- extra: { url: urlOf(input), timeout: ms },
89
- };
85
+ throw apiError(FailReason.REQUEST_TIMEOUT, { url: urlOf(input), timeout });
90
86
  }
91
87
  throw err;
92
88
  }
93
89
  finally {
94
90
  clearTimeout(timer);
95
- outer?.removeEventListener('abort', forward);
96
91
  }
97
92
  };
98
93
  }
94
+ /**
95
+ * Reject a call of `inner` that fails without any response (the fetch implementation's own error: `TypeError: fetch
96
+ * failed` in Node, `Network request failed` in React Native) with `FailReason.NETWORK_ERROR`, keeping the error in
97
+ * `extra`. An `ApiError` (such as `REQUEST_TIMEOUT`) and the caller's own abort pass through unchanged.
98
+ */
99
+ export function withNetworkError(inner) {
100
+ return async (input, init) => {
101
+ try {
102
+ return await inner(input, init);
103
+ }
104
+ catch (err) {
105
+ if (err?.reason !== undefined || init?.signal?.aborted)
106
+ throw err;
107
+ throw apiError(FailReason.NETWORK_ERROR, err);
108
+ }
109
+ };
110
+ }
111
+ /** whether an error means the server was not reached: `NETWORK_ERROR`, or `REQUEST_TIMEOUT` (no answer in time) */
112
+ export const isConnectionError = (err) => {
113
+ const reason = err?.reason;
114
+ return reason === FailReason.NETWORK_ERROR || reason === FailReason.REQUEST_TIMEOUT;
115
+ };
99
116
  /** free the connection of a response we won't read */
100
- const discard = (res) => {
117
+ export const discard = (res) => {
101
118
  res.body?.cancel().catch(() => { });
102
119
  };
120
+ /** returned by a read step when the response turned out to be from an expired session */
121
+ const EXPIRED = Symbol('expired');
103
122
  /**
104
123
  * State shared by every request a `Learn2018Helper` makes: cookies, CSRF token, language and the fetch wrappers.
105
124
  * Internal; the helper keeps it in a private field.
106
125
  */
107
126
  export class Session {
108
- login;
127
+ loginWithProvider;
109
128
  provider;
110
129
  cookieJar;
111
130
  /** fetch with cookies, the concurrency cap and the timeout, but no login check */
@@ -114,15 +133,26 @@ export class Session {
114
133
  /** bumped whenever the session changes (login, `csrfToken` set), so late failures from an old session don't log in again */
115
134
  #generation = 0;
116
135
  #pendingLogin;
136
+ /**
137
+ * The `BAD_CREDENTIAL` of the last failed `CredentialProvider` login. Automatic logins (an expired session, no CSRF
138
+ * token yet) reject with it instead of trying the same credentials again, which could lock the account; an explicit
139
+ * `login`, or a new CSRF token, clears it.
140
+ */
141
+ #badCredential;
117
142
  lang = Language.ZH;
118
143
  previewFirstPage;
119
- /** `login` signs in through SSO with the `CredentialProvider`; the session calls it at most once at a time */
120
- constructor(config, login) {
121
- this.login = login;
144
+ /**
145
+ * The device fingerprints of the last SSO login. id.tsinghua.edu.cn asks for them again when another site (WebVPN,
146
+ * for the registrar) signs in with the same id.tsinghua.edu.cn session.
147
+ */
148
+ fingerprints;
149
+ /** `loginWithProvider` signs in through SSO with the `CredentialProvider` */
150
+ constructor(config, loginWithProvider) {
151
+ this.loginWithProvider = loginWithProvider;
122
152
  this.previewFirstPage = config?.generatePreviewUrlForFirstPage ?? true;
123
153
  this.provider = config?.provider;
124
154
  this.cookieJar = config?.cookieJar ?? new CookieJar();
125
- this.rawFetch = limitConcurrency(withTimeout(config?.fetch ?? makeFetch(this.cookieJar), config?.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT), config?.maxConcurrentRequests ?? DEFAULT_MAX_CONCURRENT_REQUESTS);
155
+ this.rawFetch = limitConcurrency(withNetworkError(withTimeout(config?.fetch ?? makeFetch(this.cookieJar), config?.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT)), config?.maxConcurrentRequests ?? DEFAULT_MAX_CONCURRENT_REQUESTS);
126
156
  }
127
157
  get csrfToken() {
128
158
  return this.#csrfToken;
@@ -130,68 +160,148 @@ export class Session {
130
160
  set csrfToken(token) {
131
161
  this.#csrfToken = token;
132
162
  this.#generation += 1;
163
+ this.#badCredential = undefined;
133
164
  }
134
165
  /**
135
- * Log in with the `CredentialProvider`. Concurrent callers share one SSO login instead of starting one each.
166
+ * Run one login (`login`) at a time. It starts after a login already in progress has settled, and requests that
167
+ * find the session expired meanwhile wait for it instead of starting their own (two SSO logins at once reset each
168
+ * other's id.tsinghua.edu.cn cookie).
136
169
  */
137
- relogin() {
138
- this.#pendingLogin ??= this.login().finally(() => {
139
- this.#pendingLogin = undefined;
170
+ runLogin(login) {
171
+ const previous = this.#pendingLogin?.catch(() => { }) ?? Promise.resolve();
172
+ const current = previous.then(login).finally(() => {
173
+ if (this.#pendingLogin === current)
174
+ this.#pendingLogin = undefined;
140
175
  });
141
- return this.#pendingLogin;
176
+ this.#pendingLogin = current;
177
+ return current;
178
+ }
179
+ /**
180
+ * Log in with the `CredentialProvider`, or wait for the login already in progress (also one with explicit
181
+ * credentials) instead of starting another. Called by `login()`, so it tries again after a `BAD_CREDENTIAL`.
182
+ */
183
+ relogin() {
184
+ this.#badCredential = undefined;
185
+ return this.autoRelogin();
142
186
  }
143
187
  /**
144
- * Send a request built by `makeUrl` (called again for the retry, so it can pick up a new CSRF token).
188
+ * `relogin` for a login nobody asked for (an expired session, no CSRF token yet, the registrar wanting a new
189
+ * id.tsinghua.edu.cn session), unless the last provider login was turned down with `BAD_CREDENTIAL`: then reject with
190
+ * that again
191
+ */
192
+ autoRelogin() {
193
+ return this.#badCredential
194
+ ? Promise.reject(this.#badCredential)
195
+ : (this.#pendingLogin ?? this.runLogin(this.#providerLogin));
196
+ }
197
+ #providerLogin = async () => {
198
+ try {
199
+ await this.loginWithProvider();
200
+ }
201
+ catch (err) {
202
+ if (err?.reason === FailReason.BAD_CREDENTIAL)
203
+ this.#badCredential = err;
204
+ throw err;
205
+ }
206
+ };
207
+ /**
208
+ * Send a request built by `makeUrl` (called again for the retry, so it can pick up a new CSRF token) and read it
209
+ * with `read`, which returns `EXPIRED` for a body that shows the session has expired.
145
210
  * When the session has expired, it rejects with `NOT_LOGGED_IN` if there is no `CredentialProvider`; otherwise it
146
211
  * logs in again (sharing a login already in progress, or skipping it if another request already renewed the
147
- * session) and retries once.
212
+ * session) and retries once. After a provider login failed with `BAD_CREDENTIAL` it rejects with that instead, until
213
+ * the next explicit `login`.
148
214
  */
149
- async #send(makeUrl, init) {
215
+ async #send(makeUrl, init, read) {
216
+ const attempt = async (retry) => {
217
+ const res = await this.rawFetch(makeUrl(), init);
218
+ if (noLogin(res)) {
219
+ discard(res);
220
+ return EXPIRED;
221
+ }
222
+ return read(res, retry);
223
+ };
150
224
  const generation = this.#generation;
151
- const res = await this.rawFetch(makeUrl(), init);
152
- if (!noLogin(res))
153
- return res;
154
- discard(res);
225
+ const first = await attempt(false);
226
+ if (first !== EXPIRED)
227
+ return first;
155
228
  if (!this.provider) {
156
- throw { reason: FailReason.NOT_LOGGED_IN };
229
+ throw apiError(FailReason.NOT_LOGGED_IN);
157
230
  }
158
231
  if (this.#generation === generation) {
159
- await this.relogin();
232
+ await this.autoRelogin();
160
233
  }
161
- const retry = await this.rawFetch(makeUrl(), init);
162
- if (noLogin(retry)) {
163
- discard(retry);
164
- throw { reason: FailReason.NOT_LOGGED_IN };
234
+ const second = await attempt(true);
235
+ if (second === EXPIRED) {
236
+ throw apiError(FailReason.NOT_LOGGED_IN);
165
237
  }
166
- if (retry.status !== 200) {
167
- discard(retry);
168
- throw {
169
- reason: FailReason.UNEXPECTED_STATUS,
170
- extra: { code: retry.status, text: retry.statusText },
171
- };
172
- }
173
- return retry;
238
+ return second;
174
239
  }
175
- /** fetch with a login check (see `#send`) */
176
- fetch = (input, init) => this.#send(() => urlOf(input), init);
177
- /** like `fetch`, but logs in first if there is no CSRF token yet and adds the current token to the URL */
178
- fetchWithToken = async (input, init) => {
240
+ /** the response, but after a re-login only one with status 200 */
241
+ static #response = async (res, retry) => {
242
+ if (retry && res.status !== 200) {
243
+ discard(res);
244
+ throw apiError(FailReason.UNEXPECTED_STATUS, { code: res.status, text: res.statusText });
245
+ }
246
+ return res;
247
+ };
248
+ /**
249
+ * The parsed JSON body (after a re-login only from a response with status 200); the login page with status 200
250
+ * instead means the session has expired.
251
+ */
252
+ static #json = async (res, retry) => {
253
+ await Session.#response(res, retry);
254
+ const text = await res.text();
255
+ try {
256
+ return JSON.parse(text);
257
+ }
258
+ catch {
259
+ if (res.status === 200 && looksLikeLoginPage(text))
260
+ return EXPIRED;
261
+ throw apiError(res.status === 200 ? FailReason.INVALID_RESPONSE : FailReason.UNEXPECTED_STATUS, {
262
+ code: res.status,
263
+ text: text.slice(0, 200),
264
+ });
265
+ }
266
+ };
267
+ /** the text body; a short login / redirect page with status 200 means the session has expired */
268
+ static #text = async (res, retry) => {
269
+ await Session.#response(res, retry);
270
+ const text = await res.text();
271
+ return res.status === 200 && looksLikeLoginPage(text) ? EXPIRED : text;
272
+ };
273
+ #withToken = async (input) => {
179
274
  if (this.#csrfToken === '') {
180
- await this.relogin();
275
+ await this.autoRelogin();
181
276
  }
182
277
  const url = urlOf(input);
183
- return this.#send(() => addCSRFTokenToUrl(url, this.#csrfToken), init);
278
+ return () => addCSRFTokenToUrl(url, this.#csrfToken);
184
279
  };
280
+ /** fetch with a login check (see `#send`); logs in first if there is no CSRF token yet and adds it to the URL */
281
+ fetchWithToken = async (input, init) => this.#send(await this.#withToken(input), init, Session.#response);
282
+ /**
283
+ * Like `fetchWithToken`, but returns the parsed JSON body. The short login page with status 200 instead of JSON
284
+ * counts as an expired session (log in again and retry once, as for a 403); any other page is `INVALID_RESPONSE`.
285
+ */
286
+ fetchJsonWithToken = async (input, init) => this.#send(await this.#withToken(input), init, Session.#json);
185
287
  /**
186
- * Make sure the session works: if there is a CSRF token, make one cheap authenticated request (`probeUrl`) and log
187
- * in only if it fails; otherwise log in.
288
+ * Like `fetchWithToken`, but returns the text body (an HTML page). A short login or redirect page with status 200
289
+ * counts as an expired session (log in again and retry once, as for a 403).
290
+ */
291
+ fetchTextWithToken = async (input, init) => this.#send(await this.#withToken(input), init, Session.#text);
292
+ /**
293
+ * Make sure the session works: if there is a CSRF token, fetch the current semester (`probeUrl`) and log in only if
294
+ * the session has expired; otherwise log in.
188
295
  */
189
296
  async ensureSession(probeUrl) {
190
297
  if (this.#csrfToken === '') {
191
- await this.relogin();
298
+ await this.autoRelogin();
192
299
  return;
193
300
  }
194
- discard(await this.fetchWithToken(probeUrl));
301
+ const json = await this.fetchJsonWithToken(probeUrl);
302
+ if (json?.message !== 'success') {
303
+ throw apiError(FailReason.INVALID_RESPONSE, json);
304
+ }
195
305
  }
196
306
  }
197
307
  //# sourceMappingURL=request.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"request.js","sourceRoot":"","sources":["../src/request.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../src/request.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { CourseMeeting } from './types.ts';
2
+ /**
3
+ * The start and end (Beijing time, HH:mm) of each class period (大节), which is what a course's time and location
4
+ * counts in.
5
+ */
6
+ export declare const CLASS_PERIOD_TIMES: Readonly<Record<number, readonly [string, string]>>;
7
+ /**
8
+ * The teaching weeks a meeting happens in, from the part of its time and location in parentheses: `全周`, `1-8周`,
9
+ * `9,11周`, `单周`, or in English `Week all`, `Week 1-8`, `Odd weeks`. `null` means every week, also for text it
10
+ * doesn't know.
11
+ */
12
+ export declare function parseWeeks(text: string): number[] | null;
13
+ /**
14
+ * Read one entry of a course's time and location (`Course.timeAndLocation`): `星期六第1节(9,11周),六教6A414`, or
15
+ * `Section 1 of Sat (Week 9,11 ), 六教6A414` when the website is in English. Entries without a day or a known period
16
+ * (`星期第0节(全周),`, `Section 0 (Week all ), `) give `null`.
17
+ */
18
+ export declare function parseCourseMeeting(text: string): CourseMeeting | null;
19
+ /**
20
+ * The teaching week `date` falls in, from 1 (0 or less before the term), for a term whose first day
21
+ * (`SemesterInfo.startDate`) is `semesterStartDate`. Both are YYYY-MM-DD Beijing dates. Week 1 starts on the Monday
22
+ * of the first day, or on the Monday after it when the first day is a weekend (fall 2026 starts on Saturday Sep 12;
23
+ * week 1 is Sep 14–20). Throws a `RangeError` for a date that isn't YYYY-MM-DD.
24
+ */
25
+ export declare function semesterWeek(semesterStartDate: string, date: string): number;
26
+ //# sourceMappingURL=timetable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timetable.d.ts","sourceRoot":"","sources":["../src/timetable.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAOlF,CAAC;AAkCF;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAgBxD;AAOD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CASrE;AAiBD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,iBAAiB,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAK5E"}
@@ -0,0 +1,110 @@
1
+ // Reading a course's time and location (`Course.timeAndLocation`) and counting teaching weeks, for working out a
2
+ // timetable without the registrar's calendar.
3
+ /**
4
+ * The start and end (Beijing time, HH:mm) of each class period (大节), which is what a course's time and location
5
+ * counts in.
6
+ */
7
+ export const CLASS_PERIOD_TIMES = {
8
+ 1: ['08:00', '09:35'],
9
+ 2: ['09:50', '12:15'],
10
+ 3: ['13:30', '15:05'],
11
+ 4: ['15:20', '16:55'],
12
+ 5: ['17:05', '18:40'],
13
+ 6: ['19:20', '21:45'],
14
+ };
15
+ /** weeks in a regular term, for "every other week", "last eight weeks" and the like */
16
+ const TERM_WEEKS = 16;
17
+ const range = (from, to, step = 1) => {
18
+ const weeks = [];
19
+ for (let w = from; w <= to; w += step)
20
+ weeks.push(w);
21
+ return weeks;
22
+ };
23
+ const WEEKDAYS = { 一: 1, 二: 2, 三: 3, 四: 4, 五: 5, 六: 6, 日: 7, 天: 7 };
24
+ /** English weekdays by their first three letters (the server writes `Mon`, `Tues`, `Thur`, …) */
25
+ const ENGLISH_WEEKDAYS = { mon: 1, tue: 2, wed: 3, thu: 4, fri: 5, sat: 6, sun: 7 };
26
+ /** week specs that aren't a list of weeks, in Chinese and in English (spaces removed, lower case) */
27
+ const NAMED_WEEKS = {
28
+ 全周: () => null,
29
+ all: () => null,
30
+ every: () => null,
31
+ full: () => null,
32
+ 前八周: () => range(1, 8),
33
+ first8: () => range(1, 8),
34
+ firsteight: () => range(1, 8),
35
+ 后八周: () => range(9, TERM_WEEKS),
36
+ last8: () => range(9, TERM_WEEKS),
37
+ lasteight: () => range(9, TERM_WEEKS),
38
+ 单周: () => range(1, TERM_WEEKS, 2),
39
+ odd: () => range(1, TERM_WEEKS, 2),
40
+ 双周: () => range(2, TERM_WEEKS, 2),
41
+ even: () => range(2, TERM_WEEKS, 2),
42
+ };
43
+ /**
44
+ * The teaching weeks a meeting happens in, from the part of its time and location in parentheses: `全周`, `1-8周`,
45
+ * `9,11周`, `单周`, or in English `Week all`, `Week 1-8`, `Odd weeks`. `null` means every week, also for text it
46
+ * doesn't know.
47
+ */
48
+ export function parseWeeks(text) {
49
+ const spec = text
50
+ .replace(/\s/g, '')
51
+ .toLowerCase()
52
+ .replace(/^(?:第|weeks?|wks?)/, '')
53
+ .replace(/(?:周|weeks?|wks?)$/, '');
54
+ const named = NAMED_WEEKS[spec] ?? NAMED_WEEKS[`${spec}周`];
55
+ if (named)
56
+ return named();
57
+ const weeks = [];
58
+ for (const part of spec.split(/[,,、;;]/)) {
59
+ const match = /^(\d+)(?:[-~~–—](\d+))?$/.exec(part);
60
+ if (!match)
61
+ return null;
62
+ const from = Number(match[1]);
63
+ weeks.push(...range(from, match[2] ? Number(match[2]) : from));
64
+ }
65
+ return weeks;
66
+ }
67
+ const toMeeting = (weekday, period, weeks, location) => weekday && CLASS_PERIOD_TIMES[period]
68
+ ? { weekday, period, weeks: parseWeeks(weeks), location: location.trim() }
69
+ : null;
70
+ /**
71
+ * Read one entry of a course's time and location (`Course.timeAndLocation`): `星期六第1节(9,11周),六教6A414`, or
72
+ * `Section 1 of Sat (Week 9,11 ), 六教6A414` when the website is in English. Entries without a day or a known period
73
+ * (`星期第0节(全周),`, `Section 0 (Week all ), `) give `null`.
74
+ */
75
+ export function parseCourseMeeting(text) {
76
+ const chinese = /星期([一二三四五六日天])第(\d+)节\s*[((]([^))]*)[))]\s*[,,]?\s*(.*)$/.exec(text);
77
+ if (chinese)
78
+ return toMeeting(WEEKDAYS[chinese[1]], Number(chinese[2]), chinese[3], chinese[4]);
79
+ const english = /section\s*(\d+)\s*(?:of\s*([a-z]+)\.?)?\s*[((]([^))]*)[))]\s*[,,]?\s*(.*)$/i.exec(text);
80
+ if (english) {
81
+ const day = english[2]?.slice(0, 3).toLowerCase();
82
+ return toMeeting(day ? ENGLISH_WEEKDAYS[day] : undefined, Number(english[1]), english[3], english[4]);
83
+ }
84
+ return null;
85
+ }
86
+ const DAY_MS = 24 * 60 * 60 * 1000;
87
+ /** a YYYY-MM-DD date (anything after it, like a time, is ignored) as days since the epoch */
88
+ const dayNumber = (date) => {
89
+ const match = /^(\d{4})-(\d{2})-(\d{2})/.exec(date);
90
+ const time = match ? Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3])) : NaN;
91
+ if (Number.isNaN(time) || new Date(time).toISOString().slice(0, 10) !== date.slice(0, 10)) {
92
+ throw new RangeError(`invalid date ${date}, expected YYYY-MM-DD`);
93
+ }
94
+ return time / DAY_MS;
95
+ };
96
+ /** days since the epoch of the Monday of the week of `day` (days since the epoch; day 0 was a Thursday) */
97
+ const mondayOf = (day) => day - ((day + 3) % 7);
98
+ /**
99
+ * The teaching week `date` falls in, from 1 (0 or less before the term), for a term whose first day
100
+ * (`SemesterInfo.startDate`) is `semesterStartDate`. Both are YYYY-MM-DD Beijing dates. Week 1 starts on the Monday
101
+ * of the first day, or on the Monday after it when the first day is a weekend (fall 2026 starts on Saturday Sep 12;
102
+ * week 1 is Sep 14–20). Throws a `RangeError` for a date that isn't YYYY-MM-DD.
103
+ */
104
+ export function semesterWeek(semesterStartDate, date) {
105
+ const start = dayNumber(semesterStartDate);
106
+ const weekday = (start + 3) % 7; // 0 Monday … 6 Sunday
107
+ const firstMonday = weekday >= 5 ? start + 7 - weekday : start - weekday;
108
+ return (mondayOf(dayNumber(date)) - firstMonday) / 7 + 1;
109
+ }
110
+ //# sourceMappingURL=timetable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timetable.js","sourceRoot":"","sources":["../src/timetable.ts"],"names":[],"mappings":"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"}