diff --git a/.env-example b/.env-example
index 3874f4c35..b5cc7846b 100644
--- a/.env-example
+++ b/.env-example
@@ -1 +1,5 @@
-HYF_SECRET=
\ No newline at end of file
+# Development
+ASSIGNMENT_FOLDER=assignment
+BRANCH_CHECKS=0
+ENABLE_CLEAN=1
+# HUSKY=0
\ No newline at end of file
diff --git a/.eslintrc.js b/.eslintrc.js
index 62e7dc28e..b475e0ef2 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -6,14 +6,11 @@ module.exports = {
node: true,
jest: true,
},
- plugins: ['hyf', 'no-autofix'],
+ plugins: ['no-autofix'],
extends: ['eslint:recommended'],
parserOptions: {
ecmaVersion: 2020,
},
- globals: {
- axios: 'readonly',
- },
rules: {
'no-console': 'off',
'no-var': 'error',
@@ -44,8 +41,8 @@ module.exports = {
message: 'Avoid `for in` loops. Prefer `Object.keys()` instead.',
},
],
- 'hyf/use-map-result': 'error',
- 'hyf/camelcase': 'warn',
- 'hyf/no-commented-out-code': 'warn',
+ // 'hyf/use-map-result': 'error',
+ // 'hyf/camelcase': 'warn',
+ // 'hyf/no-commented-out-code': 'warn',
},
};
diff --git a/.github-later/workflows/ci.yml b/.github-later/workflows/ci.yml
new file mode 100644
index 000000000..e01c6c5c4
--- /dev/null
+++ b/.github-later/workflows/ci.yml
@@ -0,0 +1,24 @@
+name: 'CI'
+on:
+ pull_request:
+jobs:
+ build-test:
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ node-version: [20.x]
+
+ steps:
+ - uses: actions/checkout@v4 # checkout the repo
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ matrix.node-version }}
+ - run: npm ci # install packages
+ - run: ./module-week.sh # run tests (configured to use jest-junit reporter)
+ - uses: actions/upload-artifact@v4 # upload test results
+ if: success() || failure() # run this step even if previous step failed
+ with:
+ name: test-results
+ path: junit.xml
diff --git a/.github-later/workflows/test-report.yml b/.github-later/workflows/test-report.yml
new file mode 100644
index 000000000..45451b7da
--- /dev/null
+++ b/.github-later/workflows/test-report.yml
@@ -0,0 +1,20 @@
+name: 'Test Report'
+on:
+ workflow_run:
+ workflows: ['CI'] # runs after CI workflow
+ types:
+ - completed
+permissions:
+ contents: read
+ actions: read
+ checks: write
+jobs:
+ report:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: dorny/test-reporter@v1
+ with:
+ artifact: test-results # artifact name
+ name: JEST Tests # Name of the check run which will be created
+ path: '*.xml' # Path to test results (inside artifact .zip)
+ reporter: jest-junit # Format of test results
diff --git a/.gitignore b/.gitignore
index 4b72510b7..c62043e2d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -122,3 +122,4 @@ dist
.recent.json
.disclaimer
@assignment*
+.dist/
diff --git a/.hashes.json b/.hashes.json
index cbd6b59f0..c6dc8be95 100644
--- a/.hashes.json
+++ b/.hashes.json
@@ -1,31 +1,47 @@
{
- "ex1-giveCompliment": "60df6f8686e387e8c2fb72789b35af2c66a27b224112dcf5b0c0eeb7ab694852",
- "ex2-dogYears": "98e25ac9c737f580a1736eee1dcea2cb39a9739429c84aa182aaa4a13437e646",
- "ex3-tellFortune": "684d840ab303b2bfbcc0aee3e4bcf94478b63f4dbe3a603ccba489bd922442a5",
- "ex4-shoppingCart": "1ce7c5ff829999bccc0234f10d5304c80b8421ce4dc9dbae81cf0888c977b5fe",
- "ex5-shoppingCartPure": "9fde65b469f4a86031503c6700845db4e832c76fd4322de4009be67a12c2dd6b",
- "ex6-totalCost": "c52ceb8ee35009539c45ce3fb74b4cc00e2895a7e214419f313b7e61f6679376",
- "ex7-mindPrivacy": "47ce19447d1c3e32a702dd708ed06091e9ea9996e01725b8f8b219f4524782af",
- "ex1-doubleEvenNumbers.test": "fca4268f9c4ea8ba7a19d564a7150b3f7f1e2f3fb254d2a0902a0838d067a1dc",
- "ex2-mondaysWorth.test": "3205b7ea8a12a08e200fca68febb9d373cfe8b8c005b32c990dbd91d0519c0e6",
- "ex3-lemonAllergy.test": "58055218f88d00d396ab254800218a50fcfab10ed0548602aece6040a799c4a8",
- "ex4-observable": "7c28d25384d6ef4e06a59ec651a053a2f5781fc555f9df4f2f2aeb7d07507354",
- "ex5-wallet": "b2664b9411474a468f999c8c3bb7590046dd3dd3c883795d9ebffbee1140dea4",
- "ex1-bookList": "889909bb59ecd158fe43a0bf36bcc4708bbb941e4566bcaf080481bedef7b0f0",
- "ex2-aboutMe": "759d12d04b4c42592089e4ad77b0cc9fe440f543220f09eb2bbdccedacbc503f",
- "ex3-hijackLogo": "86782e88e1dbb6571bb3576983e37e0293935531932621c13728924f24587aaf",
- "ex4-whatsTheTime": "8106f06feb81e186a44a7c8bf57339187717c896f4c726008b85030fb868a391",
- "ex5-catWalk": "748e45f93e283bf8972bc64a01f393fb28cb8d50efcfc6a664cf664b7c998508",
- "ex6-gameOfLife": "0c29b5725dd8c3cba7e9bb6785ea1729f9229561642b65cff14ee379f9553efb",
- "ex1-johnWho": "00f3567ed9d194394b7a5bfe66ff9442bdadf715dd0700be1a9f43667d2fae2a",
- "ex2-checkDoubleDigits": "185367ae2f185e90ec03cc220029607981514d909f1b9ecc3a4f01607e14c88c",
- "ex3-rollDie": "9ad20d60390ddf6029db0a87007100de4271f9c2056f9b4578bff6013338cb3c",
- "ex4-pokerDiceAll": "f9eacfcbbd34dc82b5d1a66810b130929287aada2e0b84ea9bd95d6582f5150d",
- "ex5-pokerDiceChain": "23651f5d5cbc70b78728c07290beb9700f7bae71edff6f7bd6bc478f168be1d6",
- "ex1-programmerFun": "5f7ecc0ba804c290534a4ec32bb1d940e9783a105581f8c6fd06015a538b5c1c",
- "ex2-pokemonApp": "47a8794931e8aaa2c0b24212334cb5a82b25ae09e857806f1debe5b83207f081",
- "ex3-rollAnAce": "7d8d1a5bb999d4f3ff74675f57fb9cf2e02d9486c5c0308b2a3d545c59c5adf5",
- "ex4-diceRace": "70eb2aa459da54f85959fd1a19d34e0287ea2c1f6f99bcb34686c16f175196c1",
- "ex5-vscDebug": "b8f99814051d491d0aebe495dcab79d86ac4c98cecc063cf1604451e9a7a1090",
- "ex6-browserDebug": "41899e54aeed71c8f8c2b4b02b264fea8952171b0074351964a28856b9b6e45b"
+ "1-JavaScript": {
+ "Week2": {
+ "ex1-giveCompliment": "c2c8b6253ad706989b9120f00d80e8453b5be70f34c35fcd7567dcf5550ba897",
+ "ex2-dogYears": "83cde87e41e27739a745da5038550cdb2470ce917b8b6f3b5b5d92d9576c6b8e",
+ "ex3-tellFortune": "8b2f61a4b1fc2603bac8d09a497fce6febcc94103f4a8eef05562f31410c04e0",
+ "ex4-shoppingCart": "faa80df26c206721a4126e3e11f2d8601e7a74b5f480b5c2b895cd21573389db",
+ "ex5-shoppingCartPure": "3476061983b7ffbd6550e5e57fd7499bd2808d31ee2d4bc61cb97404d9f38d44",
+ "ex6-totalCost": "5b1d0494344f16ac5b707ba868879c799b503b60595afa6684698ea4bf7aa351",
+ "ex7-mindPrivacy": "f809108686ee3c05c2b7dc39de4ec6259ae48b7940f4cf56f34293302e256380"
+ },
+ "Week3": {
+ "ex1-doubleEvenNumbers.test": "99e7d34f1878d376c2c14367a5de445a3bf00abee43ff86996f1d2a1bb1bc683",
+ "ex2-mondaysWorth.test": "25e38c63390f21cac3f8cf83f683f79cb516b94c693c8679f6ddcba341859620",
+ "ex3-lemonAllergy.test": "a3438041779e7419eac19d7112feff3cf91aec0055810ad9b721683cbf83312e",
+ "ex4-observable": "4085411da456ca5f34e7bd7c8607e1e1ff6d82c7acec2f823791e4c422961d72",
+ "ex5-wallet": "2c8d09de71b9044b8107b2e86d7b66a3b82eebea17c17d7153bfc68fdf20da5e"
+ }
+ },
+ "2-Browsers": {
+ "Week1": {
+ "ex1-bookList": "8ac2dee143392160c9d60b181eb3f43b7b1318ea2addfe490c9c1cff048d5d9b",
+ "ex2-aboutMe": "3fc6e8adc0af28648d048c388dd087a8bbc1d22d8b2aebe7b3329c8423d26810",
+ "ex3-hijackLogo": "9d5ad72401c231c92e03df70946d9ba40759c780b7c39756d8b17cd15945d241",
+ "ex4-whatsTheTime": "80ebbed95a4c838d067d9a4eab32bc002101ab60847a2e0bc4ff463e97c354fd",
+ "ex5-catWalk": "4d75417fd3a7792b084fa234753d4cdd652d40d3990bad13aa7eec11a5db648a",
+ "ex6-gameOfLife": "10ccd24d0b46559e7c3b778ef9d1659995064f36fb329b7aba2261b65e9f0355"
+ }
+ },
+ "3-UsingAPIs": {
+ "Week1": {
+ "ex1-johnWho": "3a45143e7c62f304fd5bd5eb706cea077912373fa521c80934adac49ec9436ef",
+ "ex2-checkDoubleDigits": "05d6893c90f828e26c4471b69054252a7c094a8a1ea02e28fb72716230cfbbc8",
+ "ex3-rollDie": "a3001b96605ee20f187421d3323635c1556cc77c06346ff25d79302a2b798c55",
+ "ex4-pokerDiceAll": "c03cf0564e4702c69bc4224ceba797efbf69420ed87979cb823c920567866923",
+ "ex5-pokerDiceChain": "e0b3668e27909a717506dd028b67b7c3b53f8ba1e5b643c39dfb2a40c44d89f4"
+ },
+ "Week2": {
+ "ex1-programmerFun": "e6cbf8715cf9b840b26fc8d8553dd235ed52b456fa6b37d639f6d54625e58797",
+ "ex2-pokemonApp": "b9ec9888524d269f507943086df9ccba3ae32c76b1d39ac6565f6f8371c04631",
+ "ex3-rollAnAce": "8c840efffc0734a9b226588289a44df893955da251120e21ef1a1afa10a5e181",
+ "ex4-diceRace": "d21ce44070d9ff596b941d138ca1a701fbfc1292afdd412cc8b8951ef512d413",
+ "ex5-vscDebug": "6242bc8861bdb0abea48d00fa6f2cd9bf3a6f93fdd9b708ad130c8b64c6c75eb",
+ "ex6-browserDebug": "1787583932555b23bcb625030cfcad2094bc222824dcba2d79db4bc01e6b9142"
+ }
+ }
}
\ No newline at end of file
diff --git a/.husky/pre-commit b/.husky/pre-commit
new file mode 100644
index 000000000..33d42f29c
--- /dev/null
+++ b/.husky/pre-commit
@@ -0,0 +1,3 @@
+#!/bin/bash
+echo "Branch name: $(git rev-parse --abbrev-ref HEAD)"
+npm run pre-commit
\ No newline at end of file
diff --git a/.husky/pre-push b/.husky/pre-push
new file mode 100644
index 000000000..1860e5563
--- /dev/null
+++ b/.husky/pre-push
@@ -0,0 +1,3 @@
+#!/bin/bash
+echo "Branch name: $(git rev-parse --abbrev-ref HEAD)"
+npm run pre-push
\ No newline at end of file
diff --git a/.markdownlint.json b/.markdownlint.json
index eef34aa53..e532ef2b8 100644
--- a/.markdownlint.json
+++ b/.markdownlint.json
@@ -2,5 +2,6 @@
"default": true,
"line-length": false,
"no-inline-html": false,
- "no-duplicate-header": false
+ "no-duplicate-header": false,
+ "table-pipe-style": false
}
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 000000000..f1239caa5
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,2 @@
+# Ignore JSON files
+*.json
\ No newline at end of file
diff --git a/.tours/test-runner.tour b/.tours/test-runner.tour
deleted file mode 100644
index 8036f7fb1..000000000
--- a/.tours/test-runner.tour
+++ /dev/null
@@ -1,147 +0,0 @@
-{
- "$schema": "https://aka.ms/codetour-schema",
- "title": "1. test-runner",
- "steps": [
- {
- "file": "test-runner/index.js",
- "description": "The test runner starts by calling function `main()`.",
- "line": 231,
- "title": "entry point"
- },
- {
- "file": "test-runner/index.js",
- "description": "The function `compileMenuData()` is called to compile menu data by scanning the repo's directory tree, looking for exercise files and directories that match a prescribed naming convention. The returned menu data (a JavaScript object) is used to drive the menu dialog.",
- "line": 175,
- "title": "get menu data"
- },
- {
- "file": "test-runner/test-runner-helpers.js",
- "description": "Exercise files and folders must reside in a folder named **assignment** and match a pattern that starts with the letters **ex** followed by a number and a dash. Each **assignment** folder is a subfolder of a **Week𝑛** folder, which itself is a subfolder of a module specific top-level folder. For instance:\n\n```console\n1-JavaScript/\n Week3/\n assignment/\n ex1-giveCompliment.js\n ...\n```\n\nNote that Windows paths contain back slashes that must be replaced with forward slashes as required by `fast-glob`.",
- "line": 26,
- "selection": {
- "start": {
- "line": 20,
- "character": 3
- },
- "end": {
- "line": 27,
- "character": 1
- }
- },
- "title": "compile menu data"
- },
- {
- "file": "test-runner/test-runner-helpers.js",
- "description": "We use a regular expression to extract the **module**, **week** and *exercise* name from each file path. If the exercise is a (JavaScript) file, we strip off the `.js` file extension.",
- "line": 43,
- "selection": {
- "start": {
- "line": 28,
- "character": 1
- },
- "end": {
- "line": 44,
- "character": 1
- }
- },
- "title": "build menu data object"
- },
- {
- "file": "test-runner/index.js",
- "description": "As a time-saver, a user is given the option to re-run the last test (if there is one). This information is kept in the file `.recent.json`.",
- "line": 183,
- "selection": {
- "start": {
- "line": 179,
- "character": 1
- },
- "end": {
- "line": 184,
- "character": 1
- }
- },
- "title": "recent selection"
- },
- {
- "file": "test-runner/index.js",
- "description": "If the user wishes to select a different exercise to test (or if there was no previous to re-run) a series of menu prompts allows the user to select a **module**, **week** and **exercise** to test.",
- "line": 190,
- "title": "selection menu",
- "selection": {
- "start": {
- "line": 185,
- "character": 1
- },
- "end": {
- "line": 191,
- "character": 1
- }
- }
- },
- {
- "file": "test-runner/index.js",
- "description": "The students' exercises are in subfolders of the **assignment** folder. For testing the \"happy path\" of the unit tests completed exercises can be placed in an alternate folder, the name of whhich can be defined through the `ASSIGNMENT_FOLDER` environment variable. The recommended folder for this purpose is **@assignment** (git-ignored). The npm script **npm run testalt** sets the `ASSIGNMENT_FOLDER` environment variable to **@assignment** before running the test.",
- "line": 198
- },
- {
- "file": "test-runner/index.js",
- "description": "A hash is computed over each exercise as part of the **posinstall** npm script. These hashes are stored in the file `.hashes.json` (git-ignored). When the use runs a test the hash is recomputed and compare with the stored hash. If the hash values are the same then obviously the exercise has not been touched.",
- "line": 201,
- "title": "recompute hash",
- "selection": {
- "start": {
- "line": 203,
- "character": 1
- },
- "end": {
- "line": 207,
- "character": 6
- }
- }
- },
- {
- "file": "test-runner/index.js",
- "description": "If the exercise is untouched, we log a message to the console and to log file.",
- "line": 207,
- "selection": {
- "start": {
- "line": 203,
- "character": 1
- },
- "end": {
- "line": 208,
- "character": 1
- }
- },
- "title": "compare hashes"
- },
- {
- "file": "test-runner/index.js",
- "description": "Running a test comprises three steps:\n\n1. Unit test with Jest\n2. ESLint check\n3. Spelling check\n\nEach of these steps returns a (potentially multiline) string with error information or just an empty string if there were no errors. These strings are concatenated to form an error report.",
- "line": 213,
- "selection": {
- "start": {
- "line": 210,
- "character": 1
- },
- "end": {
- "line": 214,
- "character": 1
- }
- },
- "title": "run test steps"
- },
- {
- "file": "test-runner/index.js",
- "description": "An error report is written to the `test-reports` folder, but only if the student did some work on the exercise.",
- "line": 216,
- "title": "write report"
- },
- {
- "file": "test-runner/index.js",
- "description": "A textual disclaimer is shown at the end of the test that can be silenced for subsequent tests.",
- "line": 220,
- "title": "show disclaimer"
- }
- ]
-}
\ No newline at end of file
diff --git a/.tours/unit-test-browser.tour b/.tours/unit-test-browser.tour
deleted file mode 100644
index 7354e8694..000000000
--- a/.tours/unit-test-browser.tour
+++ /dev/null
@@ -1,88 +0,0 @@
-{
- "$schema": "https://aka.ms/codetour-schema",
- "title": "4. unit test browser",
- "steps": [
- {
- "file": "2-Browsers/Week1/unit-tests/ex4-whatsTheTime.test.js",
- "description": "For browser-based exercises we make use of `jsdom` through the helper function `prepare()`.",
- "line": 11,
- "title": "beforeAll prepare"
- },
- {
- "file": "test-runner/jsdom-helpers.js",
- "description": "We use the JSDOM convenience function `JSDOM.fromFile()` to load `index.html` into jsdom. We add some sleep time to allow JavaScript file used in `
+