chore: merge pull request #8 from LoredDev/3-eslint-flat-config-by-default
refactor/feat: use a more standard ESLint flat configuration object
This commit is contained in:
6
.changeset/small-ties-dream.md
Normal file
6
.changeset/small-ties-dream.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@eslit/config": minor
|
||||
---
|
||||
|
||||
Rewritten most of the package logic, so now it uses a more standard ESLint configuration object structure. All configurations now are separated in scope and presets are created for better convenience when configuring ESLint.
|
||||
Fixing ESLint flat-config by default [#3](https://github.com/LoredDev/ESLit/issues/3).
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -21,5 +21,8 @@
|
||||
"json",
|
||||
"jsonc",
|
||||
"yaml"
|
||||
],
|
||||
"cSpell.words": [
|
||||
"ESLIT"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { defineConfig } from '@eslit/core';
|
||||
import { configs, defineConfig, presets } from '@eslit/config';
|
||||
|
||||
export default defineConfig({
|
||||
environment: {
|
||||
node: true,
|
||||
},
|
||||
});
|
||||
export default defineConfig([
|
||||
...presets.default,
|
||||
configs.environments.node,
|
||||
]);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@eslit/core": "workspace:*"
|
||||
"@eslit/config": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.26.2",
|
||||
|
||||
56
packages/config/index.d.ts
vendored
Normal file
56
packages/config/index.d.ts
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
import type { Config, EnvOptions } from './src/types';
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
/**
|
||||
* Helper functions for creating/configuring ESLint.
|
||||
*
|
||||
* @param config - Array or function returning an array of ESLint's configuration objects array to be used.
|
||||
* @param environment - An object with environment variables to be declared and used by the configuration.
|
||||
* @returns The array of ESLint's configuration objects.
|
||||
*/
|
||||
export async function defineConfig(config: Config, environment?: EnvOptions): Promise<Linter.FlatConfig[]>;
|
||||
|
||||
export const configs: Readonly<{
|
||||
/**
|
||||
* **This configuration is necessary to be used before any other one**.
|
||||
* Common configuration for using ESLit rules overrides.
|
||||
*/
|
||||
common: Linter.FlatConfig
|
||||
/**
|
||||
* Recommended configuration overrides of ESLit
|
||||
*/
|
||||
recommended: Linter.FlatConfig
|
||||
/**
|
||||
* Formatting rules/configuration overrides for Javascript and Typescript
|
||||
*/
|
||||
formatting: Linter.FlatConfig
|
||||
/**
|
||||
* Typescript specific configuration overrides
|
||||
*/
|
||||
typescript: Linter.FlatConfig
|
||||
/**
|
||||
* Configuration objects for different development environments.
|
||||
*/
|
||||
environments: {
|
||||
/**
|
||||
* Configuration for Node development environment
|
||||
*/
|
||||
node: Linter.FlatConfig
|
||||
/**
|
||||
* Configuration for Deno development environment
|
||||
*/
|
||||
deno: Linter.FlatConfig
|
||||
/**
|
||||
* Configuration for browser development environment
|
||||
*/
|
||||
browser: Linter.FlatConfig
|
||||
}
|
||||
/**
|
||||
* JSDoc rules overrides
|
||||
*/
|
||||
jsdoc: Linter.FlatConfig
|
||||
}>;
|
||||
|
||||
export const presets: Readonly<{
|
||||
default: Linter.FlatConfig[]
|
||||
}>;
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@eslit/core",
|
||||
"name": "@eslit/config",
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
@@ -22,7 +22,7 @@
|
||||
"lint": "eslint ."
|
||||
},
|
||||
"repository": {
|
||||
"directory": "packages/core",
|
||||
"directory": "packages/config",
|
||||
"type": "git",
|
||||
"url": "https://github.com/LoredDev/ESLit"
|
||||
},
|
||||
36
packages/config/src/configs/common.js
Normal file
36
packages/config/src/configs/common.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import tsESLint from '@typescript-eslint/eslint-plugin';
|
||||
import tsParser from '@typescript-eslint/parser';
|
||||
import jsdoc from 'eslint-plugin-jsdoc';
|
||||
|
||||
/**
|
||||
* **This configuration is necessary to be used before any other one**.
|
||||
* Common configuration for using ESLit rules overrides.
|
||||
*
|
||||
* @type {Readonly<import('eslint').Linter.FlatConfig>}
|
||||
*/
|
||||
const config = {
|
||||
files: ['**/*.js', '**/*.cjs', '**/*.mjs', '**/*.ts', '**/*.cts', '**/*.mts'],
|
||||
plugins: {
|
||||
'@typescript-eslint': tsESLint,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
'jsdoc': jsdoc,
|
||||
},
|
||||
languageOptions: {
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
project: process.env.ESLIT_TSCONFIG ?? [
|
||||
'./{ts,js}config{.eslint,}.json',
|
||||
'./packages/*/{ts,js}config{.eslint,}.json',
|
||||
'./apps/*/{ts,js}config{.eslint,}.json',
|
||||
],
|
||||
tsconfigRootDir: process.env.ESLIT_ROOT ?? process.cwd(),
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
ecmaVersion: (
|
||||
/** @type {import('eslint').Linter.ParserOptions['ecmaVersion']} */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
() => {return JSON.parse(process.env.ESLIT_ECMASCRIPT ?? '"latest"');}
|
||||
)(),
|
||||
},
|
||||
};
|
||||
export default config;
|
||||
47
packages/config/src/configs/environments.js
Normal file
47
packages/config/src/configs/environments.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import globals from 'globals';
|
||||
|
||||
/**
|
||||
* Configuration for Node development environment
|
||||
*
|
||||
* @type {import('eslint').Linter.FlatConfig}
|
||||
*/
|
||||
const node = {
|
||||
files: ['**/*.js', '**/*.cjs', '**/*.mjs', '**/*.ts', '**/*.cts', '**/*.mts'],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.nodeBuiltin,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration for Deno development environment
|
||||
*
|
||||
* @type {import('eslint').Linter.FlatConfig}
|
||||
*/
|
||||
const deno = {
|
||||
files: ['**/*.js', '**/*.ts'],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
Deno: true,
|
||||
...globals.browser,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration for browser development environment
|
||||
*
|
||||
* @type {import('eslint').Linter.FlatConfig}
|
||||
*/
|
||||
const browser = {
|
||||
files: ['**/*.js', '**/*.ts'],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
Deno: true,
|
||||
...globals.browser,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default { node, deno, browser };
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Formatting rules/configuration for Javascript and Typescript
|
||||
* Formatting rules/configuration overrides for Javascript and Typescript
|
||||
*
|
||||
* @type {import('../types').ESConfig}
|
||||
* @type {Readonly<import('eslint').Linter.FlatConfig>}
|
||||
*/
|
||||
const config = {
|
||||
files: ['**/*.js', '**/*.cjs', '**/*.mjs', '**/*.ts', '**/*.cts', '**/*.mts'],
|
||||
@@ -15,7 +15,14 @@ const config = {
|
||||
'@typescript-eslint/comma-dangle': ['error', 'always-multiline'],
|
||||
|
||||
'indent': 'off',
|
||||
'@typescript-eslint/indent': ['error', process.env.READABLE_ESLINT_OPTIONS?.indent === 'space' ? 2 : 'tab', {
|
||||
'@typescript-eslint/indent': ['error', (() => {
|
||||
/** @type {import('../types').EnvOptions['ESLIT_INDENT']} */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const indent = JSON.parse(process.env.ESLINT_INDENT ?? '"tab"');
|
||||
|
||||
if (indent === 'space') return 2;
|
||||
else return indent;
|
||||
})(), {
|
||||
SwitchCase: 1,
|
||||
VariableDeclarator: 1,
|
||||
outerIIFEBody: 1,
|
||||
@@ -67,13 +74,13 @@ const config = {
|
||||
'@typescript-eslint/object-curly-spacing': ['error', 'always'],
|
||||
|
||||
'quotes': 'off',
|
||||
'@typescript-eslint/quotes': ['error', process.env.READABLE_ESLINT_OPTIONS?.quotes ?? 'single'],
|
||||
'@typescript-eslint/quotes': ['error', process.env.ESLINT_QUOTES ?? 'single'],
|
||||
|
||||
'semi': 'off',
|
||||
'@typescript-eslint/semi': ['error', 'always'],
|
||||
|
||||
'space-before-blocks': 'off',
|
||||
'@typescript-eslint/space-before-blocks': ['error', process.env.READABLE_ESLINT_OPTIONS?.semi ?? 'always'],
|
||||
'@typescript-eslint/space-before-blocks': ['error', process.env.ESLIT_SEMI ?? 'always'],
|
||||
|
||||
'space-before-function-paren': 'off',
|
||||
'@typescript-eslint/space-before-function-paren': ['error', {
|
||||
8
packages/config/src/configs/index.js
Normal file
8
packages/config/src/configs/index.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import formatting from './formatting.js';
|
||||
import jsdoc from './jsdoc.js';
|
||||
import typescript from './typescript.js';
|
||||
import recommended from './recommended.js';
|
||||
import environments from './environments.js';
|
||||
import common from './common.js';
|
||||
|
||||
export default { formatting, jsdoc, typescript, recommended, environments, common };
|
||||
@@ -1,11 +1,17 @@
|
||||
import jsdoc from 'eslint-plugin-jsdoc';
|
||||
|
||||
/**
|
||||
* JSDoc rules overrides
|
||||
*
|
||||
* @type {import('../types').ESConfig}
|
||||
* @type {Readonly<import('eslint').Linter.FlatConfig>}
|
||||
*/
|
||||
const config = {
|
||||
files: ['**/*.js', '**/*.cjs', '**/*.mjs', '**/*.ts', '**/*.cts', '**/*.mts'],
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
rules: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
...jsdoc.configs['recommended-typescript-flavor-error'].rules,
|
||||
|
||||
'jsdoc/tag-lines': ['error', 'always', {
|
||||
count: 1,
|
||||
applyToEndTag: false,
|
||||
@@ -1,12 +1,19 @@
|
||||
import tsESlint from '@typescript-eslint/eslint-plugin';
|
||||
import js from '@eslint/js';
|
||||
|
||||
/**
|
||||
* Common configuration related to language features of Javascript and Typescript
|
||||
* Recommended configuration overrides of ESLit
|
||||
*
|
||||
* @type {import('../types').ESConfig}
|
||||
* @type {Readonly<import('eslint').Linter.FlatConfig>}
|
||||
*/
|
||||
const config = {
|
||||
files: ['**/*.js', '**/*.cjs', '**/*.mjs', '**/*.ts', '**/*.cts', '**/*.mts'],
|
||||
rules: {
|
||||
...js.configs.recommended.rules,
|
||||
...tsESlint.configs.recommended.rules,
|
||||
...tsESlint.configs['recommended-requiring-type-checking'].rules,
|
||||
...tsESlint.configs['eslint-recommended'].rules,
|
||||
...tsESlint.configs.strict.rules,
|
||||
|
||||
'@typescript-eslint/ban-ts-comment': ['error', {
|
||||
'ts-ignore': 'allow-with-description',
|
||||
}],
|
||||
@@ -1,9 +1,9 @@
|
||||
import jsdoc from 'eslint-plugin-jsdoc';
|
||||
|
||||
/**
|
||||
* Typescript specific configuration
|
||||
* Typescript specific configuration overrides
|
||||
*
|
||||
* @type {import('../types').ESConfig}
|
||||
* @type {Readonly<import('eslint').Linter.FlatConfig>}
|
||||
*/
|
||||
const config = {
|
||||
files: ['**/*.ts', '**/*.cts', '**/*.mts'],
|
||||
@@ -35,7 +35,9 @@ const config = {
|
||||
...(
|
||||
/** @type {() => import('eslint').Linter.RulesRecord} */
|
||||
() => {
|
||||
const inferrableTypes = process.env.READABLE_ESLINT_OPTIONS?.inferrableTypes ?? 'never';
|
||||
/** @type {import('../types').inferrableTypesOptions} */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const inferrableTypes = JSON.parse(process.env.ESLIT_INFER_TYPES ?? '"never"');
|
||||
|
||||
if (typeof inferrableTypes === 'string') {
|
||||
return {
|
||||
22
packages/config/src/index.js
Normal file
22
packages/config/src/index.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { eslintrc } from './eslintrc-compact.js';
|
||||
|
||||
/**
|
||||
* @param {import('./types').Config} config
|
||||
* Array or function returning an array of ESLint's configuration objects array to be used.
|
||||
*
|
||||
* @param {import('./types').EnvOptions | undefined} environment
|
||||
* An object with environment variables to be declared and used by the configuration.
|
||||
*
|
||||
* @returns {Promise<import('eslint').Linter.FlatConfig[]>}
|
||||
* The array of ESLint's configuration objects.
|
||||
*/
|
||||
export async function defineConfig(config, environment = {}) {
|
||||
for (const [key, value] of Object.entries(environment)) {
|
||||
process.env[key] = JSON.stringify(value);
|
||||
}
|
||||
return typeof config === 'function' ? await config(eslintrc) : config;
|
||||
}
|
||||
|
||||
export { default as configs } from './configs/index.js';
|
||||
export { default as presets } from './presets/index.js';
|
||||
|
||||
23
packages/config/src/presets/default.js
Normal file
23
packages/config/src/presets/default.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import configs from '../configs/index.js';
|
||||
|
||||
/**
|
||||
* @type {Readonly<import('eslint').Linter.FlatConfig[]>}
|
||||
*/
|
||||
const preset = [
|
||||
{
|
||||
ignores: [
|
||||
'**/node_modules',
|
||||
'**/dist',
|
||||
'**/fixtures',
|
||||
'**/pnpm-lock.yaml',
|
||||
'**/yarn.lock',
|
||||
'**/package-lock.json',
|
||||
],
|
||||
},
|
||||
configs.common,
|
||||
configs.recommended,
|
||||
configs.formatting,
|
||||
configs.jsdoc,
|
||||
configs.typescript,
|
||||
];
|
||||
export default preset;
|
||||
4
packages/config/src/presets/index.js
Normal file
4
packages/config/src/presets/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
import defaultPreset from './default.js';
|
||||
|
||||
export default { default: defaultPreset };
|
||||
56
packages/config/src/types.d.ts
vendored
Normal file
56
packages/config/src/types.d.ts
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
import type { FlatCompat } from '@eslint/eslintrc';
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
type MaybePromise<T> = Promise<T> | T;
|
||||
export type Config = Linter.FlatConfig[] | ((eslintrc: FlatCompat) => MaybePromise<Linter.FlatConfig[]>);
|
||||
|
||||
export interface EnvOptions {
|
||||
ESLIT_TSCONFIG?: string | string[] | true
|
||||
ESLIT_ROOT?: string
|
||||
ESLIT_INDENT?: 'tab' | 'space' | number
|
||||
ESLIT_ECMASCRIPT?: Linter.ParserOptions['ecmaVersion']
|
||||
ESLIT_QUOTES?: 'single' | 'double'
|
||||
ESLIT_SEMI?: 'never' | 'always'
|
||||
/**
|
||||
* Typescript's type-checking is able to infer types from parameters.
|
||||
* So using an explicit `:` type annotation isn't obligatory.
|
||||
*
|
||||
* But, **by default in strict mode**, type annotations are always mandated to make
|
||||
* the code more readable, explicit and robust to changes.
|
||||
*
|
||||
* See {@link https://typescript-eslint.io/rules/no-inferrable-types typescript-eslint documentation }
|
||||
* for more info.
|
||||
* ---
|
||||
* **Option: `never`** (default)
|
||||
* Types are always explicit in Typescript
|
||||
*
|
||||
* @example ```ts
|
||||
// Typescript
|
||||
const id: number = 10;
|
||||
const name: string = 'foo';
|
||||
```
|
||||
* ---
|
||||
* **Option: `always`**
|
||||
* Types are always inferred in Typescript
|
||||
*
|
||||
* @example ```ts
|
||||
// Typescript
|
||||
const id = 10;
|
||||
const name = 'foo';
|
||||
```
|
||||
*/
|
||||
ESLIT_INFER_TYPES?: inferrableTypesOptions
|
||||
[ENV: string]: unknown
|
||||
}
|
||||
|
||||
export type inferrableTypesOptions = [
|
||||
'never' | 'always',
|
||||
{
|
||||
/** @see {@link https://typescript-eslint.io/rules/no-inferrable-types#ignoreparameters} */
|
||||
parameters?: boolean
|
||||
/** @see {@link https://typescript-eslint.io/rules/no-inferrable-types#ignoreproperties} */
|
||||
properties?: boolean
|
||||
/** @see {@link https://typescript-eslint.io/rules/explicit-function-return-type} */
|
||||
returnValues?: boolean
|
||||
},
|
||||
] | 'never' | 'always';
|
||||
3
packages/core/index.d.ts
vendored
3
packages/core/index.d.ts
vendored
@@ -1,3 +0,0 @@
|
||||
import type { Config, ESConfig } from './src/types';
|
||||
|
||||
export async function defineConfig(config: Config): Promise<ESConfig[]>;
|
||||
@@ -1,58 +0,0 @@
|
||||
import globals from 'globals';
|
||||
|
||||
/**
|
||||
* @param {import('../types').Config['environment']} environment
|
||||
* Manual configuration of environments, if undefined,
|
||||
* the function tries to detect the environment automatically
|
||||
* @returns {import('../types').ESConfig[]}
|
||||
* ESLint configuration with global variables and environment
|
||||
*/
|
||||
export function environments(environment) {
|
||||
|
||||
environment ||= {
|
||||
node:
|
||||
typeof window === 'undefined' &&
|
||||
typeof process !== 'undefined' &&
|
||||
typeof require !== 'function',
|
||||
deno:
|
||||
typeof window !== 'undefined' &&
|
||||
// @ts-expect-error because this package is develop in node
|
||||
typeof Deno !== 'undefined',
|
||||
browser:
|
||||
typeof window !== 'undefined',
|
||||
};
|
||||
|
||||
return [
|
||||
{
|
||||
files: ['**/*.js', '**/*.cjs', '**/*.mjs', '**/*.ts', '**/*.cts', '**/*.mts'],
|
||||
languageOptions: {
|
||||
ecmaVersion: environment.ecmaVersion ?? 'latest',
|
||||
globals: {
|
||||
...globals.builtin,
|
||||
...environment.customGlobals,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.cjs', '**/*.cts'],
|
||||
languageOptions: {
|
||||
sourceType: 'commonjs',
|
||||
globals: {
|
||||
...globals.node,
|
||||
...globals.commonjs,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.js', '**/*.mjs', '**/*.ts', '**/*.mts'],
|
||||
languageOptions: {
|
||||
sourceType: 'module',
|
||||
globals: {
|
||||
...(environment.node ? globals.nodeBuiltin : {}),
|
||||
...(environment.browser || environment.deno ? globals.browser : {}),
|
||||
...(environment.deno ? { Deno: true } : {}),
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
export { default as common } from './common.js';
|
||||
export { default as formatting } from './formatting.js';
|
||||
export { default as jsdoc } from './jsdoc.js';
|
||||
export { default as typescript } from './typescript.js';
|
||||
export * from './environments.js';
|
||||
12
packages/core/src/env.d.ts
vendored
12
packages/core/src/env.d.ts
vendored
@@ -1,12 +0,0 @@
|
||||
import type { Config } from './types';
|
||||
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
READABLE_ESLINT_STRICT: Config['strict']
|
||||
READABLE_ESLINT_OPTIONS: Config['options']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
@@ -1,83 +0,0 @@
|
||||
import { eslintrc } from './eslintrc-compact.js';
|
||||
import tsESlint from '@typescript-eslint/eslint-plugin';
|
||||
import tsParser from '@typescript-eslint/parser';
|
||||
import jsdoc from 'eslint-plugin-jsdoc';
|
||||
import js from '@eslint/js';
|
||||
import * as configs from './configs/index.js';
|
||||
import { getTsConfigs } from './tsconfigs.js';
|
||||
|
||||
/**
|
||||
* @param {import('./types').Config} userConfig
|
||||
* User configuration
|
||||
* @returns {Promise<import('./types').ESConfig[]>}
|
||||
* The complete list of configs for ESLint
|
||||
*/
|
||||
export async function defineConfig(userConfig) {
|
||||
|
||||
userConfig.strict ??= true;
|
||||
userConfig.rootDir ??= process.cwd();
|
||||
userConfig.tsconfig ??= await getTsConfigs(userConfig.rootDir);
|
||||
|
||||
process.env.READABLE_ESLINT_STRICT = userConfig.strict;
|
||||
process.env.READABLE_ESLINT_OPTIONS = {
|
||||
inferrableTypes: userConfig.strict ? 'always' : 'never',
|
||||
...userConfig.options,
|
||||
};
|
||||
|
||||
const userOverrides = (typeof userConfig.overrides !== 'function'
|
||||
? userConfig.overrides
|
||||
: await userConfig.overrides(eslintrc)) ?? [];
|
||||
|
||||
return [
|
||||
{
|
||||
ignores: [
|
||||
'**/node_modules',
|
||||
'**/dist',
|
||||
'**/fixtures',
|
||||
'**/pnpm-lock.yaml',
|
||||
'**/yarn.lock',
|
||||
'**/package-lock.json',
|
||||
],
|
||||
},
|
||||
js.configs.recommended,
|
||||
{
|
||||
files: ['**/*.js', '**/*.cjs', '**/*.mjs', '**/*.ts', '**/*.cts', '**/*.mts'],
|
||||
plugins: {
|
||||
'@typescript-eslint': tsESlint,
|
||||
/**
|
||||
* @todo
|
||||
* Fix eslint-plugin-jsdoc type definitions.
|
||||
* _Typescript should have detected [eslint-plugin-jsdoc.d.ts](./@types/eslint-plugin-jsdoc.d.ts)._
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
'jsdoc': jsdoc,
|
||||
},
|
||||
languageOptions: {
|
||||
sourceType: 'module',
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
project: userConfig.tsconfig,
|
||||
tsconfigRootDir: userConfig.rootDir,
|
||||
},
|
||||
},
|
||||
// See plugins['jsdoc'] for more info on this error
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
rules: {
|
||||
...tsESlint.configs.recommended.rules,
|
||||
...tsESlint.configs['recommended-requiring-type-checking'].rules,
|
||||
...tsESlint.configs['eslint-recommended'].rules,
|
||||
...(userConfig.strict ? tsESlint.configs.strict.rules : null),
|
||||
// See plugins['jsdoc'] for more info on this error
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
...jsdoc.configs['recommended-typescript-flavor-error'].rules,
|
||||
},
|
||||
},
|
||||
configs.common,
|
||||
configs.formatting,
|
||||
configs.jsdoc,
|
||||
configs.typescript,
|
||||
...configs.environments(userConfig.environment),
|
||||
...userOverrides,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import { existsSync } from 'node:fs';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { join, normalize } from 'node:path';
|
||||
|
||||
/** @type {(...path: string[]) => string} */
|
||||
function toPath(...path) {
|
||||
return normalize(join(...path));
|
||||
}
|
||||
|
||||
/** @type {(...path: string[]) => boolean} */
|
||||
function exists(...path) {
|
||||
return existsSync(toPath(...path));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} directory what the root directory to detect an workspace/monorepo configuration file
|
||||
* @returns {Promise<string[]>} list of possible paths of packages' tsconfig.json and jsconfig.json files
|
||||
*/
|
||||
async function getMonorepoConfigs(directory) {
|
||||
|
||||
/** @type {string[]} */
|
||||
const paths = [];
|
||||
|
||||
if (exists(directory, 'pnpm-workspace.yaml') || exists(directory, 'pnpm-workspace.yml')) {
|
||||
|
||||
const YAML = await import('yaml');
|
||||
|
||||
const yamlFilePath = exists(directory, 'pnpm-workspace.yaml')
|
||||
? join(directory, 'pnpm-workspace.yaml')
|
||||
: join(directory, 'pnpm-workspace.yml');
|
||||
|
||||
/** @type {{packages?: string[], [properties: string]: unknown}} */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const pnpmWorkspaces = YAML.parse(await readFile(yamlFilePath, 'utf-8'));
|
||||
|
||||
const files = pnpmWorkspaces.packages?.map(w => [
|
||||
toPath(directory, w, 'tsconfig.json'),
|
||||
toPath(directory, w, 'jsconfig.json'),
|
||||
]).flat() ?? [];
|
||||
|
||||
paths.push(...files);
|
||||
|
||||
}
|
||||
else if (exists(directory, 'package.json')) {
|
||||
/** @type {{workspaces?: string[], [properties: string]: unknown}} */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const packageJson = JSON.parse(await readFile(join(directory, 'package.json'), 'utf-8'));
|
||||
|
||||
const files = packageJson.workspaces?.map(w => [
|
||||
toPath(directory, w, 'tsconfig.json'),
|
||||
toPath(directory, w, 'jsconfig.json'),
|
||||
]).flat() ?? [];
|
||||
|
||||
paths.push(...files);
|
||||
|
||||
}
|
||||
|
||||
return paths;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} directory what the root directory to work on
|
||||
* @returns {Promise<string[]>} list of tsconfig.json and jsconfig.json file paths
|
||||
*/
|
||||
export async function getTsConfigs(directory) {
|
||||
|
||||
const rootTSConfig = exists(directory, 'tsconfig.eslint.json')
|
||||
? toPath(directory, 'tsconfig.eslint.json')
|
||||
: exists(directory, 'tsconfig.json')
|
||||
? toPath(directory, 'tsconfig.json')
|
||||
: undefined;
|
||||
|
||||
const rootJSConfig = exists(directory, 'jsconfig.eslint.json')
|
||||
? toPath(directory, 'jsconfig.eslint.json')
|
||||
: exists(directory, 'jsconfig.json')
|
||||
? toPath(directory, 'jsconfig.json')
|
||||
: undefined;
|
||||
|
||||
const monorepoConfigs = await getMonorepoConfigs(directory);
|
||||
|
||||
const paths = /** @type {string[]} */
|
||||
([rootTSConfig, rootJSConfig, ...monorepoConfigs]).filter(p => p);
|
||||
|
||||
return paths;
|
||||
|
||||
}
|
||||
112
packages/core/src/types.d.ts
vendored
112
packages/core/src/types.d.ts
vendored
@@ -1,112 +0,0 @@
|
||||
import type { FlatCompat } from '@eslint/eslintrc';
|
||||
import type { Linter } from 'eslint';
|
||||
|
||||
export type ESConfig = Readonly<Linter.FlatConfig>;
|
||||
|
||||
export interface Config {
|
||||
tsconfig?: string | string[] | true
|
||||
strict?: boolean
|
||||
rootDir?: string
|
||||
/**
|
||||
* @summary
|
||||
* Environment and language settings
|
||||
*
|
||||
* If no globals/environments are defined, the configuration tries to detect the
|
||||
* environment using `typeof`. See each option for more explanation
|
||||
*/
|
||||
environment?: {
|
||||
/**
|
||||
* @summary
|
||||
* Enables NodeJS environment globals.
|
||||
*
|
||||
* **Note:** this does not enables CommonJS globals, if you are using
|
||||
* CommonJS, use a file ending in `.cjs` or `.cts`
|
||||
*
|
||||
* @example // Detects if
|
||||
* typeof window === 'undefined' &&
|
||||
* typeof process !== 'undefined' &&
|
||||
* typeof require !== 'undefined'
|
||||
*/
|
||||
node?: boolean
|
||||
/**
|
||||
* @summary
|
||||
* Enables the global `Deno` namespace and browser/web standards globals
|
||||
*
|
||||
* @example // Detects if
|
||||
* typeof window !== 'undefined' &&
|
||||
* typeof Deno !== 'undefined'
|
||||
*/
|
||||
deno?: boolean
|
||||
/**
|
||||
* @summary
|
||||
* Enables browser/web standards globals
|
||||
*
|
||||
* @example // Detects if
|
||||
* typeof window !== 'undefined'
|
||||
*/
|
||||
browser?: boolean
|
||||
/**
|
||||
* @summary
|
||||
* What JavaScript (ECMAScript) that will be evaluated
|
||||
*
|
||||
* **Defaults to `latest`**
|
||||
*/
|
||||
ecmaVersion?: Linter.ParserOptions['ecmaVersion']
|
||||
/**
|
||||
* @summary
|
||||
* User defined globals for edge-cases or if available aren't enough
|
||||
*
|
||||
* **Does not overrides previous enabled ones**
|
||||
*/
|
||||
customGlobals?: Record<string, boolean>
|
||||
}
|
||||
options?: {
|
||||
indent?: 'tab' | 'space'
|
||||
quotes?: 'single' | 'double'
|
||||
semi?: 'never' | 'always'
|
||||
/**
|
||||
* Typescript's type-checking is able to infer types from parameters.
|
||||
* So using an explicit `:` type annotation isn't obligatory.
|
||||
*
|
||||
* But, **by default in strict mode**, type annotations are always mandated to make
|
||||
* the code more readable, explicit and robust to changes.
|
||||
*
|
||||
* See {@link https://typescript-eslint.io/rules/no-inferrable-types typescript-eslint documentation }
|
||||
* for more info.
|
||||
* ---
|
||||
* **Option: `never`** (default)
|
||||
* Types are always explicit in Typescript
|
||||
*
|
||||
* @example ```ts
|
||||
// Typescript
|
||||
const id: number = 10;
|
||||
const name: string = 'foo';
|
||||
```
|
||||
* ---
|
||||
* **Option: `always`**
|
||||
* Types are always inferred in Typescript
|
||||
*
|
||||
* @example ```ts
|
||||
// Typescript
|
||||
const id = 10;
|
||||
const name = 'foo';
|
||||
```
|
||||
*/
|
||||
inferrableTypes?: inferrableTypesOptions
|
||||
}
|
||||
overrides?:
|
||||
| Linter.FlatConfig[]
|
||||
| ((eslintrc: FlatCompat) => Linter.FlatConfig[] | Promise<Linter.FlatConfig[]>)
|
||||
}
|
||||
|
||||
export type inferrableTypesOptions = [
|
||||
'never' | 'always',
|
||||
{
|
||||
/** @see {@link https://typescript-eslint.io/rules/no-inferrable-types#ignoreparameters} */
|
||||
parameters?: boolean
|
||||
/** @see {@link https://typescript-eslint.io/rules/no-inferrable-types#ignoreproperties} */
|
||||
properties?: boolean
|
||||
/** @see {@link https://typescript-eslint.io/rules/explicit-function-return-type} */
|
||||
returnValues?: boolean
|
||||
},
|
||||
] | 'never' | 'always';
|
||||
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
@@ -8,9 +8,9 @@ importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@eslit/core':
|
||||
'@eslit/config':
|
||||
specifier: workspace:*
|
||||
version: link:packages/core
|
||||
version: link:packages/config
|
||||
devDependencies:
|
||||
'@changesets/cli':
|
||||
specifier: ^2.26.2
|
||||
@@ -76,7 +76,7 @@ importers:
|
||||
specifier: ^4.4.2
|
||||
version: 4.4.2
|
||||
|
||||
packages/core:
|
||||
packages/config:
|
||||
dependencies:
|
||||
'@eslint/eslintrc':
|
||||
specifier: ^2.1.0
|
||||
|
||||
Reference in New Issue
Block a user