# eslint-config-sensible-prettier-typescript

Sensible default ESLint rules and Prettier rules for TypeScript projects with ESLint 9 flat config support

## Install

```sh
npm i -D eslint-config-sensible-prettier-typescript
```

Or you can get it installed through [handy-common-utils/dev-dependencies](https://github.com/handy-common-utils/dev-dependencies):

```sh
npm i -D @handy-common-utils/dev-dependencies-mocha
```

```sh
npm i -D @handy-common-utils/dev-dependencies-jest
```

## Usage

This package provides **configuration builder functions** that return ESLint 9 flat config objects and Prettier configurations. These can be imported and customized as needed.

### ESLint Configuration

#### CommonJS

Create an `eslint.config.js` file:

```javascript
const { eslintConfig } = require('eslint-config-sensible-prettier-typescript');
const { defineConfig } = require('eslint/config');

module.exports = defineConfig([
  ...eslintConfig(),
  // Add your customizations here
  {
    rules: {
      'no-console': 'warn',
      // Your custom rules...
    },
  },
]);
```

#### ES Modules

Create an `eslint.config.js` file:

```javascript
import { eslintConfig } from 'eslint-config-sensible-prettier-typescript';
import { defineConfig } from 'eslint/config';

export default defineConfig([
  ...eslintConfig(),
  // Add your customizations here
  {
    rules: {
      'no-console': 'warn',
      // Your custom rules...
    },
  },
]);
```

### Prettier Configuration

#### CommonJS

```javascript
// prettier.config.js
const { prettierConfig } = require('eslint-config-sensible-prettier-typescript');

module.exports = {
  ...prettierConfig(),
  // Override or extend the default config
  printWidth: 120,
  tabWidth: 4,
};
```

#### ES Modules

```javascript
// prettier.config.js
import { prettierConfig } from 'eslint-config-sensible-prettier-typescript';

export default {
  ...prettierConfig(),
  // Override or extend the default config
  printWidth: 120,
  tabWidth: 4,
};
```

# Customizing ESLint Configurations

## `customiseESLintConfig`

The `customiseESLintConfig` function allows you to programmatically modify specific configuration objects within an ESLint flat config array. This is useful for applying project-specific customizations to certain file types or rule sets.

### Parameters

- **configArray**: The ESLint configuration array to modify.
- **selector**: A function that receives each config object and returns `true` for configs you want to modify.
- **modifier**: A function that receives each selected config object and applies your changes.

### Example: 'module' as default but override to 'commonjs' for .ts files

```javascript
const { buildESLintConfig, customiseESLintConfig } = require('./src/eslint.config.cjs');

const configArray = buildESLintConfig({ defaultSourceType: 'module' });

// Example: Change all TypeScript configs to use 'commonjs' sourceType
customiseESLintConfig(
  configArray,
  (cfg) => Array.isArray(cfg.files) && cfg.files.some((f) => typeof f === 'string' && f.endsWith('*.ts')),
  (cfg) => {
    cfg.languageOptions.parserOptions.sourceType = 'commonjs';
  },
);

// Export the customized config
module.exports = configArray;
```

### Example: Specify "globals" for .ts files, add ignores, and override rules

```javascript
const { buildESLintConfig, customiseESLintConfig } = require('eslint-config-sensible-prettier-typescript');
const { defineConfig } = require('eslint/config');
const globals = require('globals');

// Modify all TypeScript configurations for applying desired globals
const config = buildESLintConfig({ defaultSourceType: 'module' });
customiseESLintConfig(
  config,
  (cfg) => [cfg.files].flat().some((f) => typeof f === 'string' && f.endsWith('*.ts')),
  (cfg) => {
    cfg.languageOptions.globals = {
      ...globals.node,
      ...globals.browser,
      ...globals.jquery,
    };
  },
);

// More overriding
module.exports = defineConfig([
  {
    ignores: ['dist', 'coverage', 'report', 'node_modules'],
  },
  ...config,
  {
    rules: {
      'unicorn/filename-case': 'off',
    },
  },
]);
```

### Example: Disable a rule for all `.tsx` files

```javascript
customiseESLintConfig(
  configArray,
  (cfg) => Array.isArray(cfg.files) && cfg.files.some((f) => typeof f === 'string' && f.endsWith('*.tsx')),
  (cfg) => {
    cfg.rules['no-console'] = 'off';
  },
);
```

### Example: Apply plugin `eslint-plugin-chai-friendly`

```javascript
customiseESLintConfig(
  config,
  (cfg) => [cfg.files].flat().some((f) => typeof f === 'string' && f.endsWith('*.ts')),
  (cfg) => {
    cfg.languageOptions.globals = { ...globals.node, ...globals.mocha };
    cfg.plugins = { ...cfg.plugins, 'chai-friendly': pluginChaiFriendly };
    cfg.rules = {
      ...cfg.rules,
      'no-unused-expressions': 'off', // disable original rule
      '@typescript-eslint/no-unused-expressions': 'off', // disable TypeScript ESLint version
      'chai-friendly/no-unused-expressions': 'warn',
    };
  },
);
```

### When to use

- To override rules for specific file types.
- To change parser options for certain configs.
- To apply project-specific tweaks without
