diff --git a/NodeApp/.eslintignore b/NodeApp/.eslintignore deleted file mode 100644 index ecded56c0bd829718e46ffea13b1e3b6791c794e..0000000000000000000000000000000000000000 --- a/NodeApp/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -dist -node_modules -.gitlab-ci \ No newline at end of file diff --git a/NodeApp/.eslintrc.json b/NodeApp/.eslintrc.json deleted file mode 100644 index be8c02d07111eec0c73437a65326e56150fda24d..0000000000000000000000000000000000000000 --- a/NodeApp/.eslintrc.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "root" : true, - "parser" : "@typescript-eslint/parser", - "plugins": [ - "@typescript-eslint" - ], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended" - ] -} \ No newline at end of file diff --git a/NodeApp/.idea/jsLinters/eslint.xml b/NodeApp/.idea/jsLinters/eslint.xml index 541945bb0819b8ff4a3dae9431632ebd10e6f98b..8f07b941341104616456519be3dc0a7cd019c07d 100644 --- a/NodeApp/.idea/jsLinters/eslint.xml +++ b/NodeApp/.idea/jsLinters/eslint.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="EslintConfiguration"> + <custom-configuration-file used="false" path="./eslint.config.js" /> <option name="fix-on-save" value="true" /> </component> </project> \ No newline at end of file diff --git a/NodeApp/eslint.config.js b/NodeApp/eslint.config.js new file mode 100644 index 0000000000000000000000000000000000000000..961e9fb812497cdf22daeacb74a45c68d849c360 --- /dev/null +++ b/NodeApp/eslint.config.js @@ -0,0 +1,25 @@ +// @ts-check +// @formatter:off + +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; + + +export default tseslint.config({ + ignores: [ 'dist/*', 'node_modules/*', '.gitlab-ci.yml', 'eslint.config.js' ] + }, eslint.configs.recommended, ...tseslint.configs.recommendedTypeChecked, { + languageOptions: { + parserOptions: { + project: true, tsconfigRootDir: import.meta.dirname + } + } + }, { + plugins: { + '@typescript-eslint': tseslint.plugin + }, rules: { + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/require-await': 'off', + '@typescript-eslint/restrict-template-expressions': 'off', + } + }); \ No newline at end of file diff --git a/NodeApp/package-lock.json b/NodeApp/package-lock.json index a5b74384cb878dde7b4ebb2ef70420203e916a06..3db06b9d633bf22dc2237022e13343d744bdc5b4 100644 --- a/NodeApp/package-lock.json +++ b/NodeApp/package-lock.json @@ -51,7 +51,7 @@ "pkg": "^5.8.1", "tiny-typed-emitter": "^2.1.0", "tsx": "^4.7.1", - "typescript": "^5.4.2", + "typescript": "^5.4.3", "typescript-eslint": "^7.4.0" } }, diff --git a/NodeApp/package.json b/NodeApp/package.json index 922ec57c97bb69440511247d2ba5291cbae3646b..8356bf0242d6c644dbe01516327c73980bf72500 100644 --- a/NodeApp/package.json +++ b/NodeApp/package.json @@ -34,14 +34,14 @@ "test" : "echo \"Error: no test specified\" && exit 1" }, "dependencies" : { - "@gitbeaker/rest" : "^40.0.1", - "@gitbeaker/core" : "^40.0.1", - "@gitbeaker/requester-utils": "^40.0.1", + "@gitbeaker/rest" : "^40.0.2", + "@gitbeaker/core" : "^40.0.2", + "@gitbeaker/requester-utils": "^40.0.2", "appdata-path" : "^1.0.0", - "axios" : "^1.6.5", + "axios" : "^1.6.8", "boxen" : "^5.1.2", "chalk" : "^4.1.2", - "commander" : "^11.1.0", + "commander" : "^12.0.0", "dotenv" : "^16.3.1", "dotenv-expand" : "^10.0.0", "form-data" : "^4.0.0", @@ -52,28 +52,28 @@ "jsonwebtoken" : "^8.5.1", "open" : "^8.4.2", "ora" : "^5.4.1", - "semver" : "^7.5.4", - "tar-stream" : "^3.1.6", - "winston" : "^3.11.0", + "semver" : "^7.6.0", + "tar-stream" : "^3.1.7", + "winston" : "^3.13.0", "winston-transport" : "^4.7.0", - "yaml" : "^2.3.4", + "yaml" : "^2.4.1", "zod" : "^3.22.4", - "zod-validation-error" : "^3.0.0" + "zod-validation-error" : "^3.0.3" }, "devDependencies": { - "@types/fs-extra" : "^11.0.4", - "@types/inquirer" : "^8.2.10", - "@types/jsonwebtoken" : "^8.5.9", - "@types/node" : "^18.19.2", - "@types/semver" : "^7.5.6", - "@types/tar-stream" : "^3.1.3", - "@typescript-eslint/eslint-plugin": "^6.18.1", - "@typescript-eslint/parser" : "^6.18.1", - "dotenv-vault" : "^1.25.0", - "genversion" : "^3.2.0", - "pkg" : "^5.8.1", + "@types/fs-extra" : "^11.0.4", + "@types/inquirer" : "^8.2.10", + "@types/jsonwebtoken": "^8.5.9", + "@types/node" : "^18.19.26", + "@types/semver" : "^7.5.8", + "@types/tar-stream" : "^3.1.3", + "dotenv-vault" : "^1.25.0", + "eslint" : "^8.57.0", + "genversion" : "^3.2.0", + "pkg" : "^5.8.1", + "tiny-typed-emitter" : "^2.1.0", "tsx" : "^4.7.1", - "typescript" : "^5.4.2", - "typescript" : "^5.3.3" + "typescript" : "^5.4.3", + "typescript-eslint" : "^7.4.0" } } diff --git a/NodeApp/src/commander/CommanderApp.ts b/NodeApp/src/commander/CommanderApp.ts index c2d236f8e6520209255fe264e359a9b248bc76f7..7cb5952408f98e02b73517ca53746c41dc13c3ab 100644 --- a/NodeApp/src/commander/CommanderApp.ts +++ b/NodeApp/src/commander/CommanderApp.ts @@ -96,7 +96,7 @@ ${ TextStyle.CODE(' dojo upgrade ') }`, { if ( SharedConfig.production ) { const latestDojoCliVersion = stateConfigFile.getParam('latestDojoCliVersion') as string | null || '0.0.0'; const latestDojoCliVersionNotification = stateConfigFile.getParam('latestDojoCliVersionNotification') as number | null || 0; - if ( semver.lt(version, latestDojoCliVersion) && (new Date()).getTime() - latestDojoCliVersionNotification >= Config.versionUpdateInformationPeriodHours * 60 * 60 * 1000 ) { + if ( semver.lt(version as string, latestDojoCliVersion) && (new Date()).getTime() - latestDojoCliVersionNotification >= Config.versionUpdateInformationPeriodHours * 60 * 60 * 1000 ) { console.log(boxen(`The ${ latestDojoCliVersion } version of the DojoCLI is available. You can upgrade the DojoCLI by executing this command: ${ TextStyle.CODE(' dojo upgrade ') }`, { diff --git a/NodeApp/src/commander/exercise/subcommands/ExerciseCorrectionCommand.ts b/NodeApp/src/commander/exercise/subcommands/ExerciseCorrectionCommand.ts index 146829dcc1bf320eb4c4daa5c6652b53eea3e6b9..6dfddd1a4eed2f39a8ae2def689536d4b9275bdf 100644 --- a/NodeApp/src/commander/exercise/subcommands/ExerciseCorrectionCommand.ts +++ b/NodeApp/src/commander/exercise/subcommands/ExerciseCorrectionCommand.ts @@ -68,7 +68,7 @@ class ExerciseCorrectionCommand extends CommanderCommand { console.log(TextStyle.URL(correctionUrl)); - open(correctionUrl).then(); + await open(correctionUrl); } } diff --git a/NodeApp/src/config/LocalConfigFile.ts b/NodeApp/src/config/LocalConfigFile.ts index a292b4ec9cba0ea8755da098fabcf9aadd607a3d..29f62a6343defe952125d6e52b546fbd7f5e7057 100644 --- a/NodeApp/src/config/LocalConfigFile.ts +++ b/NodeApp/src/config/LocalConfigFile.ts @@ -8,7 +8,7 @@ class LocalConfigFile { constructor(filename: string) { this.filename = filename; - + this.loadConfig(); } @@ -32,7 +32,7 @@ class LocalConfigFile { } } - getParam(key: string): unknown | null { + getParam(key: string): unknown { const value = key in this._config ? this._config[key] : null; if ( value === null ) { return null; diff --git a/NodeApp/src/helpers/AutoCompletionHelper.ts b/NodeApp/src/helpers/AutoCompletionHelper.ts index 28dea1d9ebe8c2dfc104ba8952a5d97fd43d8dca..122be3bc783ed231386135b1a747cc45a67dc3d8 100644 --- a/NodeApp/src/helpers/AutoCompletionHelper.ts +++ b/NodeApp/src/helpers/AutoCompletionHelper.ts @@ -27,7 +27,7 @@ async function askConfirmation(msg: string): Promise<boolean> { message: msg, type : 'confirm', default: false - })).confirm; + })).confirm as boolean; } // Returns false, when the renaming is interrupted diff --git a/NodeApp/src/helpers/Dojo/ExerciseRunHelper.ts b/NodeApp/src/helpers/Dojo/ExerciseRunHelper.ts index aaf189a9090e7940ad6604d6b7c8cf2763f997d7..266d1426a88a1be82ef5630e163fa780c04aaaed 100644 --- a/NodeApp/src/helpers/Dojo/ExerciseRunHelper.ts +++ b/NodeApp/src/helpers/Dojo/ExerciseRunHelper.ts @@ -256,7 +256,7 @@ class ExerciseRunHelper { }); this.exerciseResultsValidation.events.on('finished', (success: boolean, exitCode: number) => { - success || exitCode === ExerciseCheckerError.EXERCISE_RESULTS_FOLDER_TOO_BIG ? resolve() : reject(); + success || exitCode === ExerciseCheckerError.EXERCISE_RESULTS_FOLDER_TOO_BIG.valueOf() ? resolve() : reject(); }); this.exerciseResultsValidation.run(); @@ -271,7 +271,7 @@ class ExerciseRunHelper { * Step 4: Display results + Volume location * @private */ - private async displayResults() { + private displayResults() { const info = chalk.magenta.bold.italic; ClientsSharedExerciseHelper.displayExecutionResults(this.exerciseResultsValidation.exerciseResults, this.exerciseDockerCompose.exitCode, { INFO : info, @@ -285,7 +285,7 @@ class ExerciseRunHelper { await this.checkRequirements(); await this.runDockerCompose(); await this.getResults(); - await this.displayResults(); + this.displayResults(); } catch ( error ) { return; } diff --git a/NodeApp/src/managers/DojoBackendManager.ts b/NodeApp/src/managers/DojoBackendManager.ts index ff4e83e231ccc7d7a63f074be9b949dec888b5db..c16b7388e4fede536e61f97fe0e2ba57e410e02b 100644 --- a/NodeApp/src/managers/DojoBackendManager.ts +++ b/NodeApp/src/managers/DojoBackendManager.ts @@ -25,7 +25,7 @@ class DojoBackendManager { spinner.fail(`No pipeline found for this assignment.`); break; case DojoStatusCode.ASSIGNMENT_PUBLISH_PIPELINE_FAILED: - spinner.fail(error.response?.data?.message ?? `Last pipeline status is not "${ GitlabPipelineStatus.SUCCESS }".`); + spinner.fail((error.response?.data?.message as string | undefined) ?? `Last pipeline status is not "${ GitlabPipelineStatus.SUCCESS }".`); break; case DojoStatusCode.EXERCISE_CORRECTION_ALREADY_EXIST: spinner.fail(`This exercise is already labelled as a correction. If you want to update it, please use the update command.`); @@ -199,7 +199,7 @@ class DojoBackendManager { } try { - const axiosFunction = isUpdate ? axios.patch : axios.post; + const axiosFunction = isUpdate ? axios.patch.bind(axios) : axios.post.bind(axios); const route = isUpdate ? ApiRoute.ASSIGNMENT_CORRECTION_UPDATE : ApiRoute.ASSIGNMENT_CORRECTION_LINK; await axiosFunction(DojoBackendHelper.getApiUrl(route, { diff --git a/NodeApp/src/managers/HttpManager.ts b/NodeApp/src/managers/HttpManager.ts index e854c4b79d50779d7376bfe9e5fc588374335306..760f19c1f1f0b4d12089bd6f9badd84e68eb424d 100644 --- a/NodeApp/src/managers/HttpManager.ts +++ b/NodeApp/src/managers/HttpManager.ts @@ -26,9 +26,11 @@ class HttpManager { } if ( config.url && (config.url.indexOf(ClientsSharedConfig.apiURL) !== -1) ) { + + config.headers['Accept-Encoding'] = 'gzip'; - if ( config.data && Object.keys(config.data).length > 0 ) { + if ( config.data && Object.keys(config.data as { [key: string]: unknown }).length > 0 ) { config.headers['Content-Type'] = 'multipart/form-data'; } @@ -62,10 +64,10 @@ class HttpManager { const data: DojoBackendResponse<void> = error.response.data as DojoBackendResponse<void>; switch ( data.code ) { - case DojoStatusCode.CLIENT_NOT_SUPPORTED: + case DojoStatusCode.CLIENT_NOT_SUPPORTED.valueOf(): this.requestError('Client not recognized by the server. Please contact the administrator.'); break; - case DojoStatusCode.CLIENT_VERSION_NOT_SUPPORTED: + case DojoStatusCode.CLIENT_VERSION_NOT_SUPPORTED.valueOf(): this.requestError(`CLI version not anymore supported by the server. Please update the CLI by executing this command:\n${ TextStyle.CODE(' dojo upgrade ') }`); break; default: @@ -77,13 +79,13 @@ class HttpManager { private apiAuthorizationError(error: AxiosError, isFromApi: boolean) { if ( this.handleAuthorizationCommandErrors && isFromApi && error.response ) { const errorCustomCode = (error.response.data as DojoBackendResponse<unknown> | undefined)?.code ?? error.response.status; - + if ( errorCustomCode === error.response.status ) { switch ( error.response.status ) { - case StatusCodes.UNAUTHORIZED: + case StatusCodes.UNAUTHORIZED.valueOf(): this.requestError('Session expired or does not exist. Please login again.'); break; - case StatusCodes.FORBIDDEN: + case StatusCodes.FORBIDDEN.valueOf(): this.requestError('Forbidden access.'); break; default: @@ -114,8 +116,8 @@ class HttpManager { return response; }, async error => { - if ( error.response ) { - const isFromApi = error.response.config.url && error.response.config.url.indexOf(ClientsSharedConfig.apiURL) !== -1; + if ( error instanceof AxiosError && error.response ) { + const isFromApi = error.response.config.url !== undefined && error.response.config.url.indexOf(ClientsSharedConfig.apiURL) !== -1; this.apiMethodNotAllowed(error, isFromApi); this.apiAuthorizationError(error, isFromApi); diff --git a/NodeApp/src/managers/SessionManager.ts b/NodeApp/src/managers/SessionManager.ts index e3f6b2f52f6bd3678a3ed1c5182020f9208282a8..2b4a3da164b0419c08adac66ae5fe61a8b587f44 100644 --- a/NodeApp/src/managers/SessionManager.ts +++ b/NodeApp/src/managers/SessionManager.ts @@ -134,7 +134,7 @@ class SessionManager { message: `${ chalk.green('?') } Please paste the Gitlab code here`, mask : '*', prefix : ' ' - })).code; + })).code as string; } private getGitlabCodeFromGraphicEnvironment(): Promise<string> { @@ -156,7 +156,7 @@ class SessionManager { text : `Waiting for user to authorize the application in his web browser. If the browser does not open automatically, please go to : ${ Config.login.gitlab.url.code }`, indent: 4 }).start(); - open(Config.login.gitlab.url.code).then(); + void open(Config.login.gitlab.url.code).then(); }); loginServer.events.on('error', (error: string) => { currentSpinner.fail(`Login server error: ${ error }`); diff --git a/NodeApp/src/shared b/NodeApp/src/shared index 77badeab872fc6ce5873c1182b428e9410525f95..021300d29473dee2ad229384d22a521c0e5c14aa 160000 --- a/NodeApp/src/shared +++ b/NodeApp/src/shared @@ -1 +1 @@ -Subproject commit 77badeab872fc6ce5873c1182b428e9410525f95 +Subproject commit 021300d29473dee2ad229384d22a521c0e5c14aa diff --git a/NodeApp/src/sharedByClients b/NodeApp/src/sharedByClients index acba6304b6fea92d473ceba1a66adacd06ca00c5..8514d5ef589a8aa34e4d2260c618781d81368c22 160000 --- a/NodeApp/src/sharedByClients +++ b/NodeApp/src/sharedByClients @@ -1 +1 @@ -Subproject commit acba6304b6fea92d473ceba1a66adacd06ca00c5 +Subproject commit 8514d5ef589a8aa34e4d2260c618781d81368c22