Linting Updates (!336)

This update now runs Prettier before ESLint (with the Stylistic plugin) for code formatting. This takes care of a lot of the edge cases that ESLint doesn't touch by itself. Also adds the `eslint-plugin-unused-imports` ESLint plugin to remove unused imports and the `eslint-plugin-switch-allman` ESLint plugin to enforce Allman braces on case declarations.

The VSCode format-on-save function now requires two additional extentions to be installed: Prettier and Format Code Action. Links can be found in the README and in the recommended extentions section of VSCode when the workspace is open.

Co-authored-by: chomp <chomp@noreply.dev.sp-tarkov.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/336
Co-authored-by: Refringe <me@refringe.com>
Co-committed-by: Refringe <me@refringe.com>
This commit is contained in:
Refringe 2024-05-16 08:41:05 +00:00 committed by chomp
parent f147bb64eb
commit 79781ab8bb
10 changed files with 190 additions and 173 deletions

1
.gitignore vendored
View File

@ -18,6 +18,7 @@ project/src/__coverage__/
## visual studio
.vs
.idea
.vscode
slnx.sqlite
slnx-journal.sqlite

View File

@ -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>`.
| 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

View File

@ -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": [
{

10
project/.prettierignore Normal file
View File

@ -0,0 +1,10 @@
**/.git
**/.pkg-cache
**/.vscode
**/build
**/node_modules
**/types
**/tests/__cache__
**/tests/__coverage__
.editorconfig
src/services/ModCompilerService.ts

3
project/.prettierrc Normal file
View File

@ -0,0 +1,3 @@
{
"quoteProps": "consistent"
}

View File

@ -1,8 +0,0 @@
{
"recommendations": [
"EditorConfig.EditorConfig",
"vitest.explorer",
"refringe.spt-id-highlighter",
"dbaeumer.vscode-eslint"
]
}

View File

@ -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"
}
]
}

View File

@ -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",
},
],
},
}

View File

@ -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",

View File

@ -85,8 +85,7 @@ export class ModCompilerService
protected async compile(fileNames: string[], options: ts.CompilerOptions): Promise<void>
{
// 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<unknown>
{
return new Promise(resolve => setTimeout(resolve, ms));
return new Promise((resolve) => setTimeout(resolve, ms));
}
}