Files
api/web/eslint.config.mjs
Pujit Mehrotra 11d2de5d08 chore(web): reduce lint duration by 90% (#1766)
Replace the eslint prettier plugin (which profiling revealed to be the
bottleneck) with separate `prettier` invocations. This yielded a 73 second reduction (89%) in the environment described below.

Before:
```
pnpm --filter web lint:fix  81.79s user 1.85s system 110% cpu 1:15.81 total
```
After: 
```
pnpm --filter web lint:fix  8.83s user 0.93s system 170% cpu 5.737 total
```
System specs (Nov 5 2025):
```
OS: macOS Sequoia 15.6.1 (24G90) arm64
Host: MacBook Air (15-inch, M2, 2023)
Kernel: Darwin 24.6.0
Uptime: 44 days, 5 hours, 22 mins
Packages: 52 (nix-default), 195 (brew), 4 (brew-cask)
Shell: zsh 5.9
CPU: Apple M2 (8) @ 3.50 GHz
GPU: Apple M2 (10) @ 1.40 GHz [Integrated]
Memory: 19.51 GiB / 24.00 GiB (81%)
Swap: 4.83 GiB / 6.00 GiB (80%)
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Separated code formatting and linting tools into independent workflows
for improved developer efficiency
* Updated development tool configuration to streamline the linting and
formatting process

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-11-06 09:22:45 -05:00

203 lines
5.0 KiB
JavaScript

import eslint from '@eslint/js';
import importPlugin from 'eslint-plugin-import';
import noRelativeImportPaths from 'eslint-plugin-no-relative-import-paths';
import vuePlugin from 'eslint-plugin-vue';
import globals from 'globals';
import tseslint from 'typescript-eslint';
// Import vue-eslint-parser as an ESM import
import vueEslintParser from 'vue-eslint-parser';
// Common rules shared across file types
const commonRules = {
'@typescript-eslint/consistent-type-imports': [
'error',
{
prefer: 'type-imports',
disallowTypeAnnotations: false, // Allow type annotations in import expressions
},
],
'@typescript-eslint/no-unused-vars': ['off'],
'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 1 }],
'no-relative-import-paths/no-relative-import-paths': [
'error',
{ allowSameFolder: false, rootDir: 'src', prefix: '@' },
],
'no-restricted-globals': [
'error',
{
name: '__dirname',
message: 'Use import.meta.url instead of __dirname in ESM',
},
{
name: '__filename',
message: 'Use import.meta.url instead of __filename in ESM',
},
],
'eol-last': ['error', 'always'],
'@typescript-eslint/no-explicit-any': [
'error',
{
ignoreRestArgs: true,
fixToUnknown: false,
},
],
};
// Vue-specific rules
const vueRules = {
'vue/multi-word-component-names': 'off',
// Nuxt UI components are auto-imported by the @nuxt/ui vite plugin
'vue/no-undef-components': [
'error',
{
ignorePatterns: [
'^U[A-Z].*', // All Nuxt UI components (UButton, UCard, etc.)
'client-only', // Vue/Nuxt built-in
],
},
],
'vue/html-self-closing': [
'error',
{
html: {
void: 'always',
normal: 'always',
component: 'always',
},
},
],
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
'vue/component-definition-name-casing': ['error', 'PascalCase'],
'vue/no-unsupported-features': [
'error',
{
version: '^3.3.0',
},
],
'vue/no-unused-properties': [
'error',
{
groups: ['props'],
deepData: false,
},
],
};
// Common language options
const commonLanguageOptions = {
ecmaVersion: 'latest',
sourceType: 'module',
};
// No need to manually define globals - using globals package
export default [
// Base config from recommended configs
eslint.configs.recommended,
...tseslint.configs.recommended, // TypeScript Files (.ts)
{
files: ['**/*.ts'],
languageOptions: {
parser: tseslint.parser,
parserOptions: {
...commonLanguageOptions,
tsconfigRootDir: import.meta.dirname,
ecmaFeatures: {
jsx: true,
},
},
globals: {
...globals.browser,
...globals.node,
},
},
plugins: {
'no-relative-import-paths': noRelativeImportPaths,
import: importPlugin,
},
rules: {
...commonRules,
},
}, // Vue Files (.vue)
{
files: ['**/*.vue'],
languageOptions: {
parser: vueEslintParser,
parserOptions: {
...commonLanguageOptions,
parser: tseslint.parser,
tsconfigRootDir: import.meta.dirname,
ecmaFeatures: {
jsx: true,
},
},
globals: {
...globals.browser,
...globals.node,
},
},
plugins: {
'no-relative-import-paths': noRelativeImportPaths,
import: importPlugin,
vue: vuePlugin,
},
rules: {
...commonRules,
...vueRules,
},
}, // Ignores
{
ignores: [
'src/graphql/generated/client/**/*',
'src/global.d.ts',
'eslint.config.ts',
'.output/**/*',
'dist/**/*',
'.nuxt/**/*',
'node_modules/**/*',
'coverage/**/*',
],
},
// JavaScript files
{
files: ['**/*.js', '**/*.mjs'],
languageOptions: {
...commonLanguageOptions,
globals: {
...globals.browser,
...globals.node,
},
},
plugins: {
'no-relative-import-paths': noRelativeImportPaths,
},
rules: {
...commonRules,
'@typescript-eslint/no-unused-vars': 'off', // Use regular no-unused-vars for JS
'no-unused-vars': ['error'],
'@typescript-eslint/consistent-type-imports': 'off', // Not applicable to JS
'@typescript-eslint/no-explicit-any': 'off', // Not applicable to JS
},
},
// Node.js files (config files, scripts)
{
files: ['**/*.config.ts', '**/*.config.js', '**/*.config.mjs', 'scripts/**/*', 'vite-plugin-*.ts'],
languageOptions: {
globals: {
...globals.node,
},
},
rules: {
'no-restricted-globals': 'off', // Allow __dirname in config files
// Keep no-require-imports enabled to enforce pure ESM
},
},
// Disable no-relative-import-paths specifically for vite.config.ts
{
files: ['vite.config.ts'],
rules: {
'no-relative-import-paths/no-relative-import-paths': 'off', // Allow relative imports in vite.config.ts for local plugins
},
},
];