Skip to content

Commit d6fafa8

Browse files
authored
fix(planner): handle prerequisite wildcards (#3737)
* Update checkPrerequisite to match wildcard prerequisites Change checking to parse for wildcards and check for matching prefixes instead of exact string matches. * Update yarn.lock * Update to fix linter errors and warnings
1 parent 1d4ec40 commit d6fafa8

File tree

4 files changed

+156
-15
lines changed

4 files changed

+156
-15
lines changed

website/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696
"icalendar": "0.7.1",
9797
"identity-obj-proxy": "3.0.0",
9898
"jest": "29.6.2",
99-
"jest-environment-jsdom": "^29.5.0",
99+
"jest-environment-jsdom": "^29.7.0",
100100
"jest-junit": "16.0.0",
101101
"mini-css-extract-plugin": "1.6.2",
102102
"nightwatch": "0.9.21",

website/src/utils/planner.test.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,17 @@ import {
1111
} from 'utils/planner';
1212

1313
describe(checkPrerequisite, () => {
14-
const moduleSet = new Set(['CS1010S', 'CS2107', 'CS2105', 'MA1101R', 'MA1521', 'MA2104']);
14+
const moduleSet = new Set([
15+
'CS1010S',
16+
'CS2107',
17+
'CS2105',
18+
'MA1101R',
19+
'MA1521',
20+
'MA2104',
21+
'NTW2006',
22+
'UTC1402',
23+
'UTC1702E',
24+
]);
1525

1626
test('should return null if single prerequisite is met', () => {
1727
expect(checkPrerequisite(moduleSet, 'CS1010S')).toBeNull();
@@ -33,8 +43,30 @@ describe(checkPrerequisite, () => {
3343
).toBeNull();
3444
});
3545

46+
test('should return null if single wildcard prerequisites is met', () => {
47+
expect(checkPrerequisite(moduleSet, 'NTW%')).toBeNull();
48+
expect(checkPrerequisite(moduleSet, 'UTC14%')).toBeNull();
49+
});
50+
51+
test('should return null if all wildcard prerequisites are met', () => {
52+
// Or operator
53+
expect(
54+
checkPrerequisite(moduleSet, {
55+
or: ['UTC11%', 'UTC14%'],
56+
}),
57+
).toBeNull();
58+
59+
// And operator
60+
expect(
61+
checkPrerequisite(moduleSet, {
62+
and: ['UTC14%', 'UTC1702%'],
63+
}),
64+
).toBeNull();
65+
});
66+
3667
test('should return module that are not fulfilled', () => {
3768
expect(checkPrerequisite(moduleSet, 'CS2030')).toEqual(['CS2030']);
69+
expect(checkPrerequisite(moduleSet, 'NTW1%')).toEqual(['NTW1%']);
3870
});
3971

4072
test('should return all modules that are not fulfilled', () => {
@@ -47,6 +79,16 @@ describe(checkPrerequisite, () => {
4779
or: ['CS2030', 'CS1020'],
4880
},
4981
]);
82+
83+
expect(
84+
checkPrerequisite(moduleSet, {
85+
or: ['CS20%', 'UTC1700%'],
86+
}),
87+
).toEqual([
88+
{
89+
or: ['CS20%', 'UTC1700%'],
90+
},
91+
]);
5092
});
5193
});
5294

website/src/utils/planner.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const PLAN_TO_TAKE_YEAR = '3000';
1515
export const PLAN_TO_TAKE_SEMESTER = -2;
1616

1717
const GRADE_REQUIREMENT_SEPARATOR = ':';
18+
const MODULE_WILD_CARD = '%';
1819

1920
// We assume iBLOCs takes place in special term 1
2021
export const IBLOCS_SEMESTER = 3;
@@ -38,11 +39,23 @@ export function getSemesterName(semester: Semester) {
3839
export function checkPrerequisite(moduleSet: Set<ModuleCode>, tree: PrereqTree) {
3940
function walkTree(fragment: PrereqTree): PrereqTree[] | null {
4041
if (typeof fragment === 'string') {
41-
if (fragment.includes(GRADE_REQUIREMENT_SEPARATOR)) {
42-
const [module] = fragment.split(GRADE_REQUIREMENT_SEPARATOR);
43-
return moduleSet.has(module) ? null : [module];
42+
const module = fragment.includes(GRADE_REQUIREMENT_SEPARATOR)
43+
? fragment.split(GRADE_REQUIREMENT_SEPARATOR)[0]
44+
: fragment;
45+
46+
if (module.includes(MODULE_WILD_CARD)) {
47+
const [prefix] = module.split(MODULE_WILD_CARD);
48+
let hasModule = false;
49+
moduleSet.forEach((moduleCode) => {
50+
hasModule = hasModule || moduleCode.startsWith(prefix);
51+
});
52+
53+
if (hasModule) {
54+
return null;
55+
}
4456
}
45-
return moduleSet.has(fragment) ? null : [fragment];
57+
58+
return moduleSet.has(module) ? null : [module];
4659
}
4760

4861
if ('or' in fragment) {

website/yarn.lock

Lines changed: 95 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1930,6 +1930,16 @@
19301930
"@types/node" "*"
19311931
jest-mock "^29.6.2"
19321932

1933+
"@jest/environment@^29.7.0":
1934+
version "29.7.0"
1935+
resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7"
1936+
integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==
1937+
dependencies:
1938+
"@jest/fake-timers" "^29.7.0"
1939+
"@jest/types" "^29.6.3"
1940+
"@types/node" "*"
1941+
jest-mock "^29.7.0"
1942+
19331943
"@jest/expect-utils@^29.5.0":
19341944
version "29.5.0"
19351945
resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.5.0.tgz#f74fad6b6e20f924582dc8ecbf2cb800fe43a036"
@@ -1964,6 +1974,18 @@
19641974
jest-mock "^29.6.2"
19651975
jest-util "^29.6.2"
19661976

1977+
"@jest/fake-timers@^29.7.0":
1978+
version "29.7.0"
1979+
resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565"
1980+
integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==
1981+
dependencies:
1982+
"@jest/types" "^29.6.3"
1983+
"@sinonjs/fake-timers" "^10.0.2"
1984+
"@types/node" "*"
1985+
jest-message-util "^29.7.0"
1986+
jest-mock "^29.7.0"
1987+
jest-util "^29.7.0"
1988+
19671989
"@jest/globals@^29.6.2":
19681990
version "29.6.2"
19691991
resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.6.2.tgz#74af81b9249122cc46f1eb25793617eec69bf21a"
@@ -2018,6 +2040,13 @@
20182040
dependencies:
20192041
"@sinclair/typebox" "^0.27.8"
20202042

2043+
"@jest/schemas@^29.6.3":
2044+
version "29.6.3"
2045+
resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03"
2046+
integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==
2047+
dependencies:
2048+
"@sinclair/typebox" "^0.27.8"
2049+
20212050
"@jest/source-map@^29.6.0":
20222051
version "29.6.0"
20232052
resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.0.tgz#bd34a05b5737cb1a99d43e1957020ac8e5b9ddb1"
@@ -2103,6 +2132,18 @@
21032132
"@types/yargs" "^17.0.8"
21042133
chalk "^4.0.0"
21052134

2135+
"@jest/types@^29.6.3":
2136+
version "29.6.3"
2137+
resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59"
2138+
integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==
2139+
dependencies:
2140+
"@jest/schemas" "^29.6.3"
2141+
"@types/istanbul-lib-coverage" "^2.0.0"
2142+
"@types/istanbul-reports" "^3.0.0"
2143+
"@types/node" "*"
2144+
"@types/yargs" "^17.0.8"
2145+
chalk "^4.0.0"
2146+
21062147
"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2":
21072148
version "0.3.3"
21082149
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098"
@@ -8324,18 +8365,18 @@ jest-each@^29.6.2:
83248365
jest-util "^29.6.2"
83258366
pretty-format "^29.6.2"
83268367

8327-
jest-environment-jsdom@^29.5.0:
8328-
version "29.6.2"
8329-
resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-29.6.2.tgz#4fc68836a7774a771819a2f980cb47af3b1629da"
8330-
integrity sha512-7oa/+266AAEgkzae8i1awNEfTfjwawWKLpiw2XesZmaoVVj9u9t8JOYx18cG29rbPNtkUlZ8V4b5Jb36y/VxoQ==
8368+
jest-environment-jsdom@^29.7.0:
8369+
version "29.7.0"
8370+
resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz#d206fa3551933c3fd519e5dfdb58a0f5139a837f"
8371+
integrity sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==
83318372
dependencies:
8332-
"@jest/environment" "^29.6.2"
8333-
"@jest/fake-timers" "^29.6.2"
8334-
"@jest/types" "^29.6.1"
8373+
"@jest/environment" "^29.7.0"
8374+
"@jest/fake-timers" "^29.7.0"
8375+
"@jest/types" "^29.6.3"
83358376
"@types/jsdom" "^20.0.0"
83368377
"@types/node" "*"
8337-
jest-mock "^29.6.2"
8338-
jest-util "^29.6.2"
8378+
jest-mock "^29.7.0"
8379+
jest-util "^29.7.0"
83398380
jsdom "^20.0.0"
83408381

83418382
jest-environment-node@^29.6.2:
@@ -8447,6 +8488,21 @@ jest-message-util@^29.6.2:
84478488
slash "^3.0.0"
84488489
stack-utils "^2.0.3"
84498490

8491+
jest-message-util@^29.7.0:
8492+
version "29.7.0"
8493+
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3"
8494+
integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==
8495+
dependencies:
8496+
"@babel/code-frame" "^7.12.13"
8497+
"@jest/types" "^29.6.3"
8498+
"@types/stack-utils" "^2.0.0"
8499+
chalk "^4.0.0"
8500+
graceful-fs "^4.2.9"
8501+
micromatch "^4.0.4"
8502+
pretty-format "^29.7.0"
8503+
slash "^3.0.0"
8504+
stack-utils "^2.0.3"
8505+
84508506
jest-mock@^29.6.2:
84518507
version "29.6.2"
84528508
resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.6.2.tgz#ef9c9b4d38c34a2ad61010a021866dad41ce5e00"
@@ -8456,6 +8512,15 @@ jest-mock@^29.6.2:
84568512
"@types/node" "*"
84578513
jest-util "^29.6.2"
84588514

8515+
jest-mock@^29.7.0:
8516+
version "29.7.0"
8517+
resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347"
8518+
integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==
8519+
dependencies:
8520+
"@jest/types" "^29.6.3"
8521+
"@types/node" "*"
8522+
jest-util "^29.7.0"
8523+
84598524
jest-pnp-resolver@^1.2.2:
84608525
version "1.2.2"
84618526
resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c"
@@ -8594,6 +8659,18 @@ jest-util@^29.6.2:
85948659
graceful-fs "^4.2.9"
85958660
picomatch "^2.2.3"
85968661

8662+
jest-util@^29.7.0:
8663+
version "29.7.0"
8664+
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc"
8665+
integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==
8666+
dependencies:
8667+
"@jest/types" "^29.6.3"
8668+
"@types/node" "*"
8669+
chalk "^4.0.0"
8670+
ci-info "^3.2.0"
8671+
graceful-fs "^4.2.9"
8672+
picomatch "^2.2.3"
8673+
85978674
jest-validate@^29.6.2:
85988675
version "29.6.2"
85998676
resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.6.2.tgz#25d972af35b2415b83b1373baf1a47bb266c1082"
@@ -10887,6 +10964,15 @@ pretty-format@^29.6.2:
1088710964
ansi-styles "^5.0.0"
1088810965
react-is "^18.0.0"
1088910966

10967+
pretty-format@^29.7.0:
10968+
version "29.7.0"
10969+
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812"
10970+
integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==
10971+
dependencies:
10972+
"@jest/schemas" "^29.6.3"
10973+
ansi-styles "^5.0.0"
10974+
react-is "^18.0.0"
10975+
1089010976
process-nextick-args@~2.0.0:
1089110977
version "2.0.1"
1089210978
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"

0 commit comments

Comments
 (0)