diff --git a/.gitignore b/.gitignore index 19e2cdb0..a2b82631 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ project/src/__coverage__/ ## visual studio .vs .idea +.vscode slnx.sqlite slnx-journal.sqlite diff --git a/README.md b/README.md index b1cebba3..35ac59f3 100644 --- a/README.md +++ b/README.md @@ -6,16 +6,16 @@ This is the Server project for the Single Player Tarkov mod for Escape From Tark - [Features](#features) - [Installation](#installation) - - [Requirements](#requirements) - - [Initial Setup](#initial-setup) + - [Requirements](#requirements) + - [Initial Setup](#initial-setup) - [Development](#development) - - [Commands](#commands) - - [Debugging](#debugging) - - [Mod Debugging](#mod-debugging) + - [Commands](#commands) + - [Debugging](#debugging) + - [Mod Debugging](#mod-debugging) - [Contributing](#contributing) - - [Branches](#branchs) - - [Pull Request Guidelines](#pull-request-guidelines) - - [Tests](#tests) + - [Branches](#branchs) + - [Pull Request Guidelines](#pull-request-guidelines) + - [Tests](#tests) - [License](#license) ## Features @@ -31,10 +31,11 @@ This project has been built in [Visual Studio Code](https://code.visualstudio.co There are a number of VSC extensions that we recommended for this project. VSC will prompt you to install these when you open the workspace file. If you do not see the prompt, you can install them manually: - [EditorConfig](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) - Editor Settings Synchronization -- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - Linting for Coding Issues & Naming Conventions - [Vitest](https://marketplace.visualstudio.com/items?itemName=vitest.explorer) - Debugging Tests - [SPT ID Highlighter](https://marketplace.visualstudio.com/items?itemName=refringe.spt-id-highlighter) - Converts IDs to Names - +- [Format Code Action](https://marketplace.visualstudio.com/items?itemName=rohit-gohri.format-code-action) - Custom Format-on-save Actions +- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - Code Formatting +- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - Linting for Coding Issues & Naming Conventions ### Initial Setup @@ -42,9 +43,9 @@ To prepare the project for development you will need to: 1. Run `git clone https://dev.sp-tarkov.com/SPT-AKI/Server.git server` to clone the repository. 2. Run `git lfs pull` to download LFS files locally. -2. Open the `project/mod.code-workspace` file in Visual Studio Code (VSC). -3. Run `nvm use 20.11.1` in the VSC terminal. -4. Run `npm install` in the VSC terminal. +3. Open the `project/mod.code-workspace` file in Visual Studio Code (VSC). +4. Run `nvm use 20.11.1` in the VSC terminal. +5. Run `npm install` in the VSC terminal. ## Development @@ -52,24 +53,27 @@ To prepare the project for development you will need to: The following commands are available after the initial setup. Run them with `npm run `. -| Command | Description | -|--------------------------|-----------------------------------------------------------------------| -| `check:circular` | Check for circular dependencies in the project. | -| `lint` | Check the project for coding standards and style/formatting issues. | -| `lint:fix` | Automatically fix coding standard issues and style/formatting issues. | -| `test` | Run all tests. | -| `test:watch` | Run tests in watch mode. Tests will re-run when files are changed. | -| `test:coverage` | Run tests and generate a coverage report. | -| `test:ui` | Run tests in UI mode. This will open a browser window to view tests. | -| `build:release` | Build the project for release. | -| `build:debug` | Build the project for debugging. | -| `build:bleeding` | Build the project on the bleeding edge. | -| `build:bleedingmods` | Build the project on the bleeding edge with mods. | -| `run:build` | Run the project in build mode. | -| `run:debug` | Run the project in debug mode. | -| `run:profiler` | Run the project in profiler mode. | -| `gen:types` | Generate types for the project. | -| `gen:docs` | Generate documentation for the project. | +| Command | Description | +| -------------------- | ----------------------------------------------------------------------------- | +| `check:circular` | Check for circular dependencies in the project. | +| `lint` | Check the project for coding standards and post-Prettier formatting issues. | +| `lint:fix` | Automatically fix coding standard issues and post-Prettier formatting issues. | +| `style` | Check the project for coding standards and post-Prettier formatting issues. | +| `style:fix` | Automatically fix coding standard issues and post-Prettier formatting issues. | +| `format` | Run Prettier and then ESLint Stylistic to fix code formatting. | +| `test` | Run all tests. | +| `test:watch` | Run tests in watch mode. Tests will re-run when files are changed. | +| `test:coverage` | Run tests and generate a coverage report. | +| `test:ui` | Run tests in UI mode. This will open a browser window to view tests. | +| `build:release` | Build the project for release. | +| `build:debug` | Build the project for debugging. | +| `build:bleeding` | Build the project on the bleeding edge. | +| `build:bleedingmods` | Build the project on the bleeding edge with mods. | +| `run:build` | Run the project in build mode. | +| `run:debug` | Run the project in debug mode. | +| `run:profiler` | Run the project in profiler mode. | +| `gen:types` | Generate types for the project. | +| `gen:docs` | Generate documentation for the project. | ### Debugging @@ -85,29 +89,29 @@ We're really excited that you're interested in contributing! Before submitting y ### Branchs -- __master__ +- **master** The default branch used for the latest stable release. This branch is protected and typically is only merges with release branches. -- __3.9.0-DEV__ +- **3.9.0-DEV** Development for the next minor release of SPT. Minor releases target the latest version of EFT. Late in the minor release cycle the EFT version is frozen for stability to prepare for release. Larger changes to the project structure may be included in minor releases. -- __3.8.1-DEV__ +- **3.8.4-DEV** Development for the next hotfix release of SPT. Hotfix releases include bug fixes and minor features that do not effect the coding structure of the project. Special care is taken to not break server mod stability. These always target the same version of EFT as the last minor release. ### Pull Request Guidelines -- __Keep Them Small__ +- **Keep Them Small** If you're fixing a bug, try to keep the changes to the bug fix only. If you're adding a feature, try to keep the changes to the feature only. This will make it easier to review and merge your changes. -- __Perform a Self-Review__ +- **Perform a Self-Review** Before submitting your changes, review your own code. This will help you catch any mistakes you may have made. -- __Remove Noise__ +- **Remove Noise** Remove any unnecessary changes to white space, code style formatting, or some text change that has no impact related to the intention of the PR. -- __Create a Meaningful Title__ +- **Create a Meaningful Title** When creating a PR, make sure the title is meaningful and describes the changes you've made. -- __Write Detailed Commit Messages__ +- **Write Detailed Commit Messages** Bring out your table manners, speak the Queen's English and be on your best behaviour. ### Style Guide -We use ESLint Stylistic to enforce a consistent code style. Please run `npm run lint` and/or `npm run lint:fix` before submitting your changes. This is made easier by using the recommended VSC extensions to automatically format your code whenever you save a file. +We use a combination of Prettier and ESLint Stylistic to enforce a consistent code style. Please run `npm run format` before submitting your changes. This is made easier by using the recommended VSC extensions to automatically format your code whenever you save a file. ### Tests diff --git a/project/.eslintrc.json b/project/.eslintrc.json index 49d679c8..f69b3c19 100644 --- a/project/.eslintrc.json +++ b/project/.eslintrc.json @@ -3,13 +3,10 @@ "plugin:@typescript-eslint/recommended", "plugin:@stylistic/recommended-extends", "plugin:import/recommended", - "plugin:import/typescript" - ], - "plugins": [ - "@typescript-eslint", - "@stylistic", - "import" + "plugin:import/typescript", + "prettier" ], + "plugins": ["@typescript-eslint", "@stylistic", "import", "unused-imports", "switch-allman"], "settings": { "import/resolver": { "typescript": { @@ -26,81 +23,83 @@ "@typescript-eslint/no-unused-vars": "off", "@typescript-eslint/no-empty-interface": "off", "@typescript-eslint/no-var-requires": "error", - "@typescript-eslint/explicit-module-boundary-types": ["error", { - "allowArgumentsExplicitlyTypedAsAny": true - }], - "@typescript-eslint/naming-convention": ["error", { - "selector": "default", - "format": ["camelCase"], - "leadingUnderscore": "allow" - }, { - "selector": "typeLike", - "format": ["PascalCase"] - }, { - "selector": "objectLiteralProperty", - "format": ["PascalCase", "camelCase", "snake_case"], - "leadingUnderscore": "allow" - }, { - "selector": "typeProperty", - "format": ["PascalCase", "camelCase"], - "leadingUnderscore": "allow" - }, { - "selector": "enumMember", - "format": ["UPPER_CASE"] - }, { - "selector": "property", - "modifiers": ["readonly", "static"], - "format": ["UPPER_CASE"] - }], + "@typescript-eslint/explicit-module-boundary-types": [ + "error", + { + "allowArgumentsExplicitlyTypedAsAny": true + } + ], + "@typescript-eslint/naming-convention": [ + "error", + { + "selector": "default", + "format": ["camelCase"], + "leadingUnderscore": "allow" + }, + { + "selector": "typeLike", + "format": ["PascalCase"] + }, + { + "selector": "objectLiteralProperty", + "format": ["PascalCase", "camelCase", "snake_case"], + "leadingUnderscore": "allow" + }, + { + "selector": "typeProperty", + "format": ["PascalCase", "camelCase"], + "leadingUnderscore": "allow" + }, + { + "selector": "enumMember", + "format": ["UPPER_CASE"] + }, + { + "selector": "property", + "modifiers": ["readonly", "static"], + "format": ["UPPER_CASE"] + } + ], "@stylistic/indent": ["error", 4, { "MemberExpression": 1, "SwitchCase": 1 }], "@stylistic/brace-style": ["error", "allman", { "allowSingleLine": false }], "@stylistic/semi": ["error", "always"], "@stylistic/quotes": ["error", "double", { "avoidEscape": true }], - "@stylistic/linebreak-style": ["error", "unix"], - "@stylistic/max-len": ["error", { - "code": 120, - "tabWidth": 4, - "ignoreComments": true, - "ignoreTrailingComments": true, - "ignoreUrls": true, - "ignoreStrings": true, - "ignoreTemplateLiterals": true, - "ignoreRegExpLiterals": true - }], - "@stylistic/multiline-ternary": ["error", "always-multiline"], - "@stylistic/no-confusing-arrow": ["error", {"allowParens": true}], - "@stylistic/no-extra-parens": ["error", "all", { - "returnAssign": false, - "nestedBinaryExpressions": false, - "ternaryOperandBinaryExpressions": false, - "enforceForArrowConditionals": false - }], - "@stylistic/new-parens": "error", - "@stylistic/newline-per-chained-call": ["error", { "ignoreChainWithDepth": 3 }], - "@stylistic/no-extra-semi": "error", - "@stylistic/no-floating-decimal": "error", - "@stylistic/no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1 }], - "@stylistic/switch-colon-spacing": "error", - "@stylistic/type-annotation-spacing": "error", - "@stylistic/type-generic-spacing": ["error"], - "@stylistic/type-named-tuple-spacing": ["error"], - "@stylistic/wrap-regex": "error", - "@stylistic/yield-star-spacing": ["error", "both"], - "import/order": ["error", { - "groups": ["builtin", "external", "internal", "parent", "sibling", "index"], - "pathGroups": [ - { - "pattern": "tsyringe", - "group": "builtin", - "position": "before" - } - ], - "newlines-between": "never", - "alphabetize": { - "order": "asc", - "caseInsensitive": true + "@stylistic/operator-linebreak": ["error", "before"], + "@stylistic/arrow-parens": ["error", "always"], + "@stylistic/max-len": [ + "warn", + { + "code": 121, // +1 to prevent conflicts with Prettier rule. + "tabWidth": 4, + "ignoreComments": true, + "ignoreTrailingComments": true, + "ignoreUrls": true, + "ignoreStrings": true, + "ignoreTemplateLiterals": true, + "ignoreRegExpLiterals": true } - }] + ], + "@stylistic/multiline-ternary": ["error", "always-multiline"], + "import/order": [ + "error", + { + "groups": ["builtin", "external", "internal", "parent", "sibling", "index"], + "pathGroups": [ + { + "pattern": "tsyringe", + "group": "builtin", + "position": "before" + } + ], + "newlines-between": "never", + "alphabetize": { + "order": "asc", + "caseInsensitive": true + } + } + ], + "unused-imports/no-unused-imports-ts": "error", + "switch-allman/case-allman": "error" }, "overrides": [ { diff --git a/project/.prettierignore b/project/.prettierignore new file mode 100644 index 00000000..7b79a188 --- /dev/null +++ b/project/.prettierignore @@ -0,0 +1,10 @@ +**/.git +**/.pkg-cache +**/.vscode +**/build +**/node_modules +**/types +**/tests/__cache__ +**/tests/__coverage__ +.editorconfig +src/services/ModCompilerService.ts diff --git a/project/.prettierrc b/project/.prettierrc new file mode 100644 index 00000000..04ff7639 --- /dev/null +++ b/project/.prettierrc @@ -0,0 +1,3 @@ +{ + "quoteProps": "consistent" +} diff --git a/project/.vscode/extensions.json b/project/.vscode/extensions.json deleted file mode 100644 index 547ba280..00000000 --- a/project/.vscode/extensions.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "recommendations": [ - "EditorConfig.EditorConfig", - "vitest.explorer", - "refringe.spt-id-highlighter", - "dbaeumer.vscode-eslint" - ] -} diff --git a/project/.vscode/launch.json b/project/.vscode/launch.json deleted file mode 100644 index 5bb44a65..00000000 --- a/project/.vscode/launch.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Debug", - "type": "node", - "runtimeVersion": "20.11.1", - "runtimeExecutable": "npm", - "request": "launch", - "sourceMaps": true, - "runtimeArgs": [ - "run", - "run:debug" - ], - "outFiles": [ - "!**/node_modules/**" - ], - "cwd": "${workspaceFolder}", - "outputCapture": "std" - }, - { - "name": "Run Vitest Tests", - "type": "node", - "runtimeVersion": "20.11.1", - "runtimeExecutable": "npm", - "request": "launch", - "runtimeArgs": [ - "run", - "test" - ], - "console": "integratedTerminal", - "internalConsoleOptions": "neverOpen" - } - ] -} diff --git a/project/Server.code-workspace b/project/Server.code-workspace index a47cd254..ad4e8f48 100644 --- a/project/Server.code-workspace +++ b/project/Server.code-workspace @@ -1,17 +1,52 @@ { "folders": [ { - "path": "." - } + "path": ".", + }, ], "settings": { "window.title": "SPT-AKI Server", - "editor.formatOnSave": true, - "editor.defaultFormatter": "dbaeumer.vscode-eslint", - "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit" - }, - "eslint.debug": true, - "eslint.experimental.useFlatConfig": false - } + "editor.formatOnSave": false, // We use an extension to format on save. + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.codeActionsOnSave": ["source.formatDocument", "source.fixAll.eslint"], + "eslint.debug": false, + "eslint.experimental.useFlatConfig": false, + }, + "extensions": { + "recommendations": [ + "EditorConfig.EditorConfig", // EditorConfig file format support. + "vitest.explorer", // ViTest test runner. + "refringe.spt-id-highlighter", // Highly SPT IDs. + "rohit-gohri.format-code-action", // Custom format on save actions. + "esbenp.prettier-vscode", // Prettier code formatter. + "dbaeumer.vscode-eslint", // ESLint code linter and formatter. + ], + }, + "launch": { + "version": "0.2.0", + "configurations": [ + { + "name": "Debug", + "type": "node", + "runtimeVersion": "20.11.1", + "runtimeExecutable": "npm", + "request": "launch", + "sourceMaps": true, + "runtimeArgs": ["run", "run:debug"], + "outFiles": ["!**/node_modules/**"], + "cwd": "${workspaceFolder}", + "outputCapture": "std", + }, + { + "name": "Run Vitest Tests", + "type": "node", + "runtimeVersion": "20.11.1", + "runtimeExecutable": "npm", + "request": "launch", + "runtimeArgs": ["run", "test"], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + }, + ], + }, } diff --git a/project/package.json b/project/package.json index 9c7493c5..5f834739 100644 --- a/project/package.json +++ b/project/package.json @@ -14,6 +14,9 @@ "check:circular": "madge --circular --ts-config tsconfig.json --extensions ts ./src/", "lint": "eslint src", "lint:fix": "eslint src --fix", + "style": "prettier src --check", + "style:fix": "prettier src --write", + "format": "npm run style:fix && npm run lint:fix", "test": "vitest run", "test:watch": "vitest", "test:coverage": "vitest run --coverage", @@ -67,8 +70,12 @@ "@yao-pkg/pkg-fetch": "3.5.9", "cross-env": "~7.0", "eslint": "~8.57", + "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-typescript": "~3.6", "eslint-plugin-import": "~2.29", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-switch-allman": "^1.0.2", + "eslint-plugin-unused-imports": "^3.2.0", "fs-extra": "~11.2", "gulp": "~4.0", "gulp-decompress": "~3.0", @@ -77,9 +84,11 @@ "gulp-rename": "~2.0", "madge": "~6.1", "minimist": "~1.2", + "prettier": "^3.2.5", "resedit": "~2.0", "ts-node-dev": "~2.0", "tsconfig-paths": "~4.2", + "tslint-config-prettier": "^1.18.0", "typedoc": "~0.25", "typemoq": "~2.1", "typescript-eslint": "~7.8", diff --git a/project/src/services/ModCompilerService.ts b/project/src/services/ModCompilerService.ts index 99cf9a53..f56ea4e8 100644 --- a/project/src/services/ModCompilerService.ts +++ b/project/src/services/ModCompilerService.ts @@ -85,8 +85,7 @@ export class ModCompilerService protected async compile(fileNames: string[], options: ts.CompilerOptions): Promise { // C:/snapshot/project || /snapshot/project - const baseDir: string = __dirname.replace(/\\/g, "/").split("/").slice(0, 3) - .join("/"); + const baseDir: string = __dirname.replace(/\\/g, "/").split("/").slice(0, 3).join("/"); for (const filePath of fileNames) { @@ -140,7 +139,7 @@ export class ModCompilerService */ protected areFilesReady(fileNames: string[]): boolean { - return fileNames.filter(x => !this.vfs.exists(x.replace(".ts", ".js"))).length === 0; + return fileNames.filter((x) => !this.vfs.exists(x.replace(".ts", ".js"))).length === 0; } /** @@ -150,6 +149,6 @@ export class ModCompilerService */ protected delay(ms: number): Promise { - return new Promise(resolve => setTimeout(resolve, ms)); + return new Promise((resolve) => setTimeout(resolve, ms)); } }