Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 145 additions & 0 deletions eslint-config/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# @synergitech/eslint-config

SynergiTech's shareable ESLint configuration with support for TypeScript, Vue, and Vitest.

## Installation

```bash
npm i -D @synergitech/eslint-config
```

You'll also need to install the peer dependencies based on which features you want to use:

### For the complete configuration (recommended):

```bash
npm i -D @eslint/js eslint-config-prettier eslint-plugin-import-x eslint-plugin-no-relative-import-paths eslint-plugin-unused-imports eslint-plugin-vitest eslint-plugin-vue globals typescript-eslint
```

### For base configuration only (no Vue, no Vitest):

```bash
npm i -D @eslint/js eslint-config-prettier eslint-plugin-import-x eslint-plugin-no-relative-import-paths eslint-plugin-unused-imports globals typescript-eslint
```

## Usage

### Complete Configuration (Vue + TypeScript + Vitest)

For the full configuration with Vue and Vitest support (equivalent to the original configuration):

```javascript
// eslint.config.js
import config from "@synergitech/eslint-config";

export default config;
```

### Base Configuration Only (TypeScript without Vue/Vitest)

For projects that only need TypeScript support without Vue or Vitest:

```javascript
// eslint.config.js
import tseslint from "typescript-eslint";
import prettierConfig from "eslint-config-prettier";
import baseConfig from "@synergitech/eslint-config/base";

export default tseslint.config(
{
ignores: ["node_modules", "dist", "build"],
},
...baseConfig,
prettierConfig
);
```

### Vue Configuration without Vitest

For Vue projects that don't use Vitest for testing:

```javascript
// eslint.config.js
import tseslint from "typescript-eslint";
import prettierConfig from "eslint-config-prettier";
import vueConfig from "@synergitech/eslint-config/vue";

export default tseslint.config(
{
ignores: ["node_modules", "dist", "build"],
},
...vueConfig,
prettierConfig
);
```

### TypeScript + Vitest without Vue

For TypeScript projects using Vitest but not Vue:

```javascript
// eslint.config.js
import tseslint from "typescript-eslint";
import prettierConfig from "eslint-config-prettier";
import baseConfig from "@synergitech/eslint-config/base";
import vitestConfig from "@synergitech/eslint-config/vitest";

export default tseslint.config(
{
ignores: ["node_modules", "dist", "build"],
},
...baseConfig,
...vitestConfig,
prettierConfig
);
```

### Custom Configuration

You can also extend any of the configurations with your own rules:

```javascript
// eslint.config.js
import tseslint from "typescript-eslint";
import config from "@synergitech/eslint-config";

export default tseslint.config(...config, {
rules: {
// Your custom rules here
"no-console": "warn", // Override the default "error"
},
});
```

## What's Included

### Base Configuration

- ESLint recommended rules
- TypeScript ESLint recommended rules
- Import/export rules (import-x plugin)
- Unused imports cleanup
- No relative import paths enforcement
- Comprehensive JavaScript/TypeScript best practices

### Vue Configuration

- All base configuration rules
- Vue ESLint recommended rules
- Vue 3 Composition API best practices
- Custom Vue-specific rules for better code quality

### Vitest Configuration

- Vitest ESLint recommended rules
- Applied only to test files (`**/*.spec.{js,ts}`, `**/*.test.{js,ts}`)

## Rules Philosophy

This configuration follows these principles:

- **Strict but practical**: Enforces best practices while avoiding overly pedantic rules
- **Modern JavaScript/TypeScript**: Targets ES2021+ with modern syntax preferences
- **Import hygiene**: Maintains clean import/export statements
- **Vue best practices**: Follows Vue 3 Composition API recommendations
- **Test-friendly**: Provides appropriate rules for test files
55 changes: 55 additions & 0 deletions eslint-config/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"name": "@synergitech/eslint-config",
"version": "1.0.0",
"license": "MIT",
"private": false,
"type": "module",
"exports": {
".": "./src/index.js",
"./base": "./src/base.js",
"./vue": "./src/vue.js",
"./vitest": "./src/vitest.js"
},
"files": [
"src/"
],
"description": "SynergiTech's shareable ESLint configuration",
"keywords": [
"eslint",
"eslintconfig",
"typescript",
"vue",
"vitest"
],
"homepage": "https://github.com/SynergiTech/laravel-coding-standards",
"repository": {
"type": "git",
"url": "git+https://github.com/SynergiTech/laravel-coding-standards.git"
},
"bugs": {
"url": "https://github.com/SynergiTech/laravel-coding-standards/issues"
},
"author": {
"name": "synergitech",
"url": "https://www.npmjs.com/~synergitech"
},
"peerDependencies": {
"@eslint/js": "^9.33.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import-x": "^4.16.1",
"eslint-plugin-no-relative-import-paths": "^1.6.1",
"eslint-plugin-unused-imports": "^4.2.0",
"eslint-plugin-vitest": "^0.5.4",
"eslint-plugin-vue": "^10.4.0",
"globals": "^16.3.0",
"typescript-eslint": "^8.39.0"
},
"peerDependenciesMeta": {
"eslint-plugin-vue": {
"optional": true
},
"eslint-plugin-vitest": {
"optional": true
}
}
}
121 changes: 121 additions & 0 deletions eslint-config/src/base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import pluginNoRelativeImportPaths from "eslint-plugin-no-relative-import-paths";
import pluginUnusedImports from "eslint-plugin-unused-imports";
import pluginImportX from "eslint-plugin-import-x";
import globals from "globals";

/**
* Base ESLint configuration with TypeScript support
* Includes core JS/TS rules without Vue or Vitest
*/
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
{
languageOptions: {
ecmaVersion: 13,
sourceType: "module",
globals: {
...globals.browser,
es2021: true,
App: "writable",
},
parserOptions: {
parser: tseslint.parser,
sourceType: "module",
},
},
plugins: {
"import-x": pluginImportX,
"unused-imports": pluginUnusedImports,
"no-relative-import-paths": pluginNoRelativeImportPaths,
},
rules: {
"no-console": "error",
"no-var": "error",
// Disable the base rule as it can report incorrect errors
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
caughtErrors: "none",
args: "none",
varsIgnorePattern: "^_",
argsIgnorePattern: "^_",
},
],
// Allow unused expressions for callback patterns
"@typescript-eslint/no-unused-expressions": "off",
"unused-imports/no-unused-imports": "error",
"no-relative-import-paths/no-relative-import-paths": "error",
"import-x/extensions": ["error", "ignorePackages"],
"import-x/no-useless-path-segments": "error",
"import-x/first": "error",
"import-x/newline-after-import": "error",
"import-x/order": "error",
"array-callback-return": "error",
"no-constructor-return": "error",
"no-duplicate-imports": "error",
"no-inner-declarations": "error",
"no-promise-executor-return": "error",
"no-self-compare": "error",
"no-template-curly-in-string": "error",
"no-unreachable-loop": "error",
// Would be nice, but tends to be a little chaotic.
// "no-use-before-define": "error",
// Not working
// "no-useless-assignment": "error",
"require-atomic-updates": "error",
"default-case-last": "error",
"default-param-last": "error",
"dot-notation": "error",
eqeqeq: "error",
"grouped-accessor-pairs": "error",
"no-array-constructor": "error",
"no-caller": "error",
"no-else-return": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-lone-blocks": "error",
"no-lonely-if": "error",
"no-multi-assign": "error",
"no-nested-ternary": "error",
"no-new-func": "error",
"no-new-wrappers": "error",
"no-object-constructor": "error",
// Maybe?
// "no-param-reassign": "error",
"no-return-assign": "error",
"no-sequences": "error",
"no-throw-literal": "error",
"no-undef-init": "error",
"no-unneeded-ternary": "error",
"no-unused-expressions": "error",
"no-useless-call": "error",
"no-useless-computed-key": "error",
"no-useless-return": "error",
// Controversial...
"object-shorthand": "error",
"one-var": ["error", "never"],
// Might annoy some people.
// "operator-assignment": "error",
"prefer-const": "error",
"prefer-exponentiation-operator": "error",
"prefer-object-has-own": "error",
"prefer-promise-reject-errors": "error",
"prefer-rest-params": "error",
"prefer-template": "error",
"require-await": "error",
yoda: "error",
},
},
// Typescript generation (rightly) generates any types for many scenarios.
// It's not ideal, but there's not too much we can do.
{
files: ["**/types/generated.d.ts"],
rules: {
"@typescript-eslint/no-explicit-any": "off",
},
}
);
42 changes: 42 additions & 0 deletions eslint-config/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import tseslint from "typescript-eslint";
import prettierConfig from "eslint-config-prettier";
import vueConfig from "./vue.js";
import vitestConfig from "./vitest.js";

/**
* Complete ESLint configuration including Vue and Vitest support
* This is the default export that provides the full configuration
* equivalent to the original eslint.config.js
*/
export default tseslint.config(
{
ignores: [
".docker",
".docker-contents",
".github",
"app",
"bootstrap",
"build",
"config",
"database",
"lang",
"node_modules",
"public",
"resources/css",
"resources/certificates",
"resources/js/routes",
"resources/js/actions",
"resources/js/wayfinder",
"resources/views",
"routes",
"settings",
"storage",
"tests/Feature",
"tests/Unit",
"vendor",
],
},
...vueConfig,
...vitestConfig,
prettierConfig
);
16 changes: 16 additions & 0 deletions eslint-config/src/vitest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import tseslint from "typescript-eslint";
import pluginVitest from "eslint-plugin-vitest";

/**
* Vitest ESLint configuration for test files
* Can be combined with base or vue configs
*/
export default tseslint.config({
files: ["**/*.spec.{js,ts}", "**/*.test.{js,ts}"],
plugins: {
vitest: pluginVitest,
},
rules: {
...pluginVitest.configs.recommended.rules,
},
});
Loading