3 Commits

Author SHA1 Message Date
Guz
88e90e3533 Merge pull request #11 from LoredDev/changeset-release/main
🦋 Release branch
2023-08-23 11:13:48 -03:00
Guz
db8bcda886 Merge pull request #9 from LoredDev/changeset-release/main
🦋 Release branch
2023-08-23 11:09:20 -03:00
github-actions[bot]
75f08247b2 ci: 👷🦋 version packages 2023-08-23 14:07:04 +00:00
100 changed files with 964 additions and 3298 deletions

View File

@@ -1,12 +0,0 @@
---
"@eslegant/js": minor
---
Added rules for NodeJS environments, using the eslint-plugin-n and eslint-plugin-security.
The added configs in the `recommended` object helps preventing issues
such as using deprecated or unsupported APIs and warns about security issues.
Building on top of the recommended configs of the plugins.
In the `strict` object they helps making the code more node-explicit, such as importing
global variables (e.g. `process` needs to be imported from `node:process`).

View File

@@ -1,5 +0,0 @@
---
"@eslegant/js": minor
---
Added new ESLint rules inspired by StandardJS.

View File

@@ -1,12 +0,0 @@
---
"@eslegant/js": minor
---
New rules structure.
Now all configs have at least `recommended` and `strict` variants, each having `error`, `warn` and `disabled`/`off` rule levels.
They are exported under the `configs` object, and are separated by purpose.
Presets are now exported under the `presets` object, being a easier way of enabling multiple configs at once.
The package has a more defined purpose, and will be used just for rules/configs related to
JavaScript and TypeScript.

View File

@@ -1,6 +0,0 @@
---
"@eslegant/cli": minor
---
Now the cli exports a API that runs the application and the configs object needs to be passed to the Cli class, this way any other package can run and have their configs array.
With this, the new command line interface that handles the actual configs of this repo is the "eslegant" package.

View File

@@ -1,6 +0,0 @@
---
"@eslegant/js": patch
"@eslegant/cli": patch
---
Updated dependencies

View File

@@ -1,5 +0,0 @@
---
"eslegant": patch
---
Created the ESLegant package, being now the actual command that runs the CLI with the ESLegant's configs

View File

@@ -1,5 +0,0 @@
---
"@eslegant/js": minor
---
Configs now export a `default` variation, where rule leves aren't overriden.

View File

@@ -1,5 +0,0 @@
---
"@eslegant/cli": patch
---
Fixed some small errors that could be thrown when prompts are canceled. Also fixed --merge-to-root cli argument not working and added list of packages that are installed on confirmation prompt.

View File

@@ -1,5 +0,0 @@
---
"create-eslegant": patch
---
Created the "create-eslegant" package, as a _alias_ to the eslegant package, so it is compatible with `npm init` or `npm create` commands

View File

@@ -1,6 +0,0 @@
---
"@eslegant/js": minor
---
New rules related to possible security vulnerabilities in JavaScript.
Provided by `eslint-plugin-security` and `eslint-plugin-no-secrets`

View File

@@ -1,8 +0,0 @@
---
"create-eslegant": minor
"eslegant": minor
"@eslegant/js": minor
"@eslegant/cli": minor
---
Renamed all packages from "eslit" to "eslegant"

View File

@@ -1,5 +0,0 @@
---
"@eslegant/js": patch
---
Renamed @eslegant/config to @eslegant/js

View File

@@ -2,7 +2,7 @@ root = true
[*]
indent_style = tab
indent_size = 4
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true

View File

@@ -13,10 +13,6 @@ inputs:
required: false
type: boolean
default: true
scope:
required: false
type: string
default: '@eslegant'
runs:
using: composite
@@ -25,8 +21,6 @@ runs:
uses: actions/setup-node@v3
with:
node-version: ${{ inputs.node-version }}
registry-url: 'https://registry.npmjs.org'
scope: ${{ inputs.scope }}
- name: Install PNPM
uses: pnpm/action-setup@v2

View File

@@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 2
@@ -40,7 +40,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 2

View File

@@ -8,8 +8,8 @@ on:
jobs:
mirror:
if: github.repository == 'loreddev/eslegant'
if: github.repository == 'loreddev/eslit'
uses: loreddev/.github/.github/workflows/mirrors.yml@main
secrets: inherit
with:
codeberg-repo: https://codeberg.org/LoredDev/ESLegant
codeberg-repo: https://codeberg.org/LoredDev/ESLit

View File

@@ -10,7 +10,7 @@ concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs:
update-release:
if: ${{ github.repository == 'loreddev/eslegant' }}
if: ${{ github.repository == 'loreddev/eslit' }}
runs-on: ubuntu-latest
permissions:
contents: write
@@ -20,7 +20,7 @@ jobs:
HUSKY: 0
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 0

View File

@@ -11,14 +11,14 @@ on:
jobs:
release:
if: ${{ github.event.workflow_run.conclusion == 'success' && github.repository == 'loreddev/eslegant' }}
if: ${{ github.event.workflow_run.conclusion == 'success' && github.repository == 'loreddev/eslit' }}
name: Release preview
env:
HUSKY: 0
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
@@ -27,10 +27,8 @@ jobs:
- name: Update versions
run: pnpm changeset version --snapshot next
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Release packages
run: pnpm run release --tag next
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@@ -10,10 +10,10 @@ on:
jobs:
generate-changeset:
runs-on: ubuntu-latest
if: github.actor == 'renovate[bot]' && github.repository == 'loreddev/eslegant'
if: github.actor == 'renovate[bot]' && github.repository == 'loreddev/eslit'
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Configure Git

View File

@@ -1,53 +0,0 @@
{
"folders": [
{
"name": "configs/js",
"path": "../configs/js"
},
{
"name": "packages/cli",
"path": "../packages/cli"
},
{
"name": "packages/create-eslegant",
"path": "../packages/create-eslegant"
},
{
"name": "packages/eslegant",
"path": "../packages/eslegant"
},
{
"name": "ROOT",
"path": "../"
}
],
"settings": {
"eslint.workingDirectories": ["./"],
"eslint.experimental.useFlatConfig": true,
"prettier.enable": false,
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.organizeImports": false,
},
// The following is optional.
// It's better to put under project setting `.vscode/settings.json`
// to avoid conflicts with working with different eslint configs
// that does not support all formats.
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"html",
"markdown",
"json",
"jsonc",
"yaml"
],
"cSpell.words": [
"eslegant"
]
}
}

View File

@@ -23,6 +23,6 @@
"yaml"
],
"cSpell.words": [
"eslegant"
"ESLIT"
]
}

View File

@@ -1,48 +0,0 @@
# Duplicated rules
This is a list of rules that implements the same features and/or end
up fixing the same errors.
- **[`@typescript/member-ordering`][ts/member-ordering], [`@typescript/sort-type-constituents`][ts/sort-type-constituents], [`import/order`][im/order]**:
implements the same functions from [`eslint-plugin-perfectionist`][plugin-perfectionist]
- **[`unicorn/no-for-loop`][un/no-for-loop] and [`@typescript/prefer-for-of`][ts/prefer-for-of]**:
`unicorn/no-for-loop` was used as it also reports when `i`/`index` is used.
- **[`unicorn/prefer-includes`][un/prefer-includes] and [`@typescript/prefer-includes`][ts/prefer-includes]**:
`unicorn/prefer-includes` was used as it not needs type information to run.
- **[`@typescript/prefer-regexp-exec`][ts/prefer-regexp-exec] and [`unicorn/prefer-regexp-test`][un/prefer-regexp-test]**:
`unicorn/prefer-regexp-exec` was used, because it reports on `RegExp#exec()` and `String#match()`
- **[`import/extensions`][im/extensions] and [`n/file-extension-in-import`][n/file-extension-in-import]**:
`import/extensions` was used, as it is not a node-specific issue.
- **[`import/no-extraneous-dependencies`][im/no-extraneous-dependencies], [`n/no-extraneous-require`][n/no-extraneous-require] and [`n/no-extraneous-import`][n/no-extraneous-import]**:
`import/no-extraneous-dependencies` was used, as it is not a node-specific issue.
- **[`import/no-unresolved`][im/no-unresolved], [`n/no-missing-require`][n/no-missing-require] and [`n/no-missing-import`][n/no-missing-import]**:
`import/no-unresolved` was used, as it is not a node-specific issue.
[ts/member-ordering]: <https://typescript-eslint.io/rules/member-ordering>
[ts/prefer-for-of]: <https://typescript-eslint.io/rules/prefer-for-of>
[ts/prefer-includes]: <https://typescript-eslint.io/rules/prefer-includes>
[ts/prefer-regexp-exec]: <https://typescript-eslint.io/rules/prefer-regexp-exec>
[ts/sort-type-constituents]: <https://typescript-eslint.io/rules/sort-type-constituents>
[un/no-for-loop]: <https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-for-loop.md>
[un/prefer-includes]: <https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-includes.md>
[un/prefer-regexp-test]: <https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-regexp-test.md>
[im/order]: <https://github.com/import-js/eslint-plugin-import/blob/maib/docs/rules/order.md>
[im/extensions]: <https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/extensions.md>
[im/no-extraneous-dependencies]: <https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md>
[im/no-unresolved]: <https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unresolved.md>
[n/file-extension-in-import]: <https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/file-extension-in-import.md>
[n/no-extraneous-import]: <https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/no-extraneous-import.md>
[n/no-extraneous-require]: <https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/no-extraneous-require.md>
[n/no-missing-import]: <https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/no-missing-import.md>
[n/no-missing-require]: <https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/no-missing-require.md>
[plugin-perfectionist]: <https://eslint-plugin-perfectionist.azat.io/>

View File

@@ -1,5 +0,0 @@
{
"extends": "../../tsconfig.json",
"exclude": ["./node_modules/**", "./dist/**"],
"include": ["src/index.d.ts", "./src/**/*.ts", "./src/**/*.js", "src/index.js"],
}

View File

@@ -1,35 +0,0 @@
/**
* @file
* Type declaration for the `eslint-plugin-i` package in a attempt to make it
* compatible with the new flat config.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
// eslint-disable-next-line unicorn/prevent-abbreviations
import type { ESLint, Linter } from 'eslint';
/**
* @summary ESLint plugin with rules that help validate proper imports.
*
* ---
* **Note:** Types in this project where overridden to be compatible with
* ESLint new flat config types. ESlint already has backwards compatibility
* for plugins not created in the new flat config.
* @see {@link https://www.npmjs.com/package/eslint-plugin-import npm package}
*/
declare module 'eslint-plugin-i' {
interface importEslintPlugin extends ESLint.Plugin {
configs: {
recommended: {
rules: Linter.RulesRecord,
},
typescript: {
rules: Linter.RulesRecord,
},
},
}
declare const plugin: importEslintPlugin;
export default plugin;
}

View File

@@ -1,34 +0,0 @@
/**
* @file
* Type declaration for the `eslint-plugin-jsdoc` package in a attempt to make it
* compatible with the new flat config.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import type { ESLint } from 'eslint';
/**
* @summary JSDoc specific linting rules for ESLint.
*
* ---
* **Note:** Types in this project where overridden to be compatible with
* ESLint new flat config types. ESlint already has backwards compatibility
* for plugins not created in the new flat config.
* @see {@link https://www.npmjs.org/package/eslint-plugin-jsdoc npm package}
*/
declare module 'eslint-plugin-jsdoc' {
// eslint-disable-next-line unicorn/prevent-abbreviations
interface jsDocESlintPlugin extends ESLint.Plugin {
configs: ESLint.Plugin['configs'] & {
recommended: ESLint.ConfigData,
'recommended-error': ESLint.ConfigData,
'recommended-typescript': ESLint.ConfigData,
'recommended-typescript-error': ESLint.ConfigData,
'recommended-typescript-flavor': ESLint.ConfigData,
'recommended-typescript-flavor-error': ESLint.ConfigData,
},
}
declare const plugin: jsDocESlintPlugin;
export default plugin;
}

View File

@@ -1,24 +0,0 @@
/**
* @file
* Type declaration for the `eslint-plugin-n` package in a attempt to make it
* compatible with the new flat config.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import type { ESLint } from 'eslint';
/**
* @summary Additional ESLint's rules for Node.js.
*
* ---
* **Note:** Types in this project where overridden to be compatible with
* ESLint new flat config types. ESlint already has backwards compatibility
* for plugins not created in the new flat config.
* @see {@link https://www.npmjs.com/package/eslint-plugin-n npm package}
*/
declare module 'eslint-plugin-n' {
declare const plugin: ESLint.Plugin;
export default plugin;
}

View File

@@ -1,24 +0,0 @@
/**
* @file
* Type declaration for the `eslint-plugin-no-secrets` package in a attempt to make it
* compatible with the new flat config.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import type { ESLint } from 'eslint';
/**
* @summary An eslint plugin to find strings that might be secrets/credentials.
*
* ---
* **Note:** Types in this project where overridden to be compatible with
* ESLint new flat config types. ESlint already has backwards compatibility
* for plugins not created in the new flat config.
* @see {@link https://www.npmjs.com/package/eslint-plugin-no-secrets npm package}
*/
declare module 'eslint-plugin-no-secrets' {
declare const plugin: ESLint.Plugin;
export default plugin;
}

View File

@@ -1,24 +0,0 @@
/**
* @file
* Type declaration for the `eslint-plugin-security` package in a attempt to make it
* compatible with the new flat config.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import type { ESLint } from 'eslint';
/**
* @summary ESLint rules for Node Security.
*
* ---
* **Note:** Types in this project where overridden to be compatible with
* ESLint new flat config types. ESlint already has backwards compatibility
* for plugins not created in the new flat config.
* @see {@link https://www.npmjs.com/package/eslint-plugin-security npm package}
*/
declare module 'eslint-plugin-security' {
declare const plugin: ESLint.Plugin;
export default plugin;
}

View File

@@ -1,18 +0,0 @@
/**
* @file
* Type declaration for the `globals` package in a attempt to make it
* compatible with the new flat config.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
declare module 'globals' {
const globals: {
browser: { [rule: string]: boolean, },
builtin: { [rule: string]: boolean, },
commonjs: { [rule: string]: boolean, },
node: { [rule: string]: boolean, },
nodeBuiltin: { [rule: string]: boolean, },
};
export default globals;
}

View File

@@ -1,64 +0,0 @@
/**
* @file
* Configuration object that adds necessary plugins for the other objects.
* See more info on the configs type declaration file.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import process from 'node:process';
import tsESLint from '@typescript-eslint/eslint-plugin';
import securityPlugin from 'eslint-plugin-security';
import unicornPlugin from 'eslint-plugin-unicorn';
// @ts-expect-error because the package doesn't export correct types
import tsParser from '@typescript-eslint/parser';
import jsdocPlugin from 'eslint-plugin-jsdoc';
import importPlugin from 'eslint-plugin-i';
import globals from 'globals';
// eslint-disable-next-line import/no-relative-parent-imports
import { jsFiles, tsFiles } from '../constants.js';
/** @type {import('eslint').Linter.FlatConfig} */
const config = {
files: [...tsFiles, ...jsFiles],
languageOptions: {
globals: {
...globals.builtin,
},
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
parser: tsParser,
parserOptions: {
project: process.env.ESLEGANT_TSCONFIG ?? [
'./{ts,js}config{.eslint,}.json',
'./*/{ts,js}config{.eslint,}.json',
'./*/*/{ts,js}config{.eslint,}.json',
],
tsconfigRootDir: process.env.ESLEGANT_ROOT ?? process.cwd(),
},
},
plugins: {
'@typescript-eslint': tsESLint,
'import': importPlugin,
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
'jsdoc': jsdocPlugin,
// @ts-expect-error because eslint-plugin-security doesn't export correct types
'security': securityPlugin,
// @ts-expect-error because eslint-plugin-unicorn doesn't export correct types
'unicorn': unicornPlugin,
},
settings: {
'import/extensions': [...tsFiles, ...jsFiles],
'import/parsers': {
'@typescript-eslint/parser': [...tsFiles, ...jsFiles ],
},
'import/resolver': {
node: true,
typescript: true,
},
'jsdoc/mode': 'typescript',
},
};
export default config;

View File

@@ -1,56 +0,0 @@
/* eslint-disable import/no-relative-parent-imports */
/* eslint-disable unicorn/no-useless-spread */
/**
* @file
* Configuration objects that helps document your code.
* See more info on the configs type declaration file.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import { createVariations } from '../lib/rule-variations.js';
import { jsFiles, tsFiles } from '../constants.js';
const recommended = createVariations({
files: [...tsFiles, ...jsFiles],
rules: {
...{}, // Plugin: eslint-plugin-jsdoc
'jsdoc/match-description': 'error',
'jsdoc/require-description-complete-sentence': 'error',
'jsdoc/require-hyphen-before-param-description': ['error', 'always'],
'jsdoc/require-param-description': 'error',
'jsdoc/require-property-description': 'error',
'jsdoc/require-returns-check': 'error',
},
});
const strict = createVariations({
...recommended.error,
rules: {
...recommended.error.rules,
...{}, // Plugin: eslint-plugin-jsdoc
'jsdoc/require-description': 'error',
'jsdoc/require-file-overview': ['error', { tags: {
author: {
mustExist: true,
},
copyright: {
initialCommentsOnly: true,
},
file: {
initialCommentsOnly: true,
mustExist: true,
preventDuplicates: true,
},
license: {
initialCommentsOnly: true,
mustExist: true,
preventDuplicates: true,
},
} }],
},
});
const documentation = { recommended, strict };
export default documentation;

View File

@@ -1,37 +0,0 @@
/* eslint-disable import/no-relative-parent-imports */
/* eslint-disable unicorn/no-useless-spread */
/**
* @file
* Configuration objects for the browser environment.
* See more info on the configs type declaration file.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import { createVariations } from '../../lib/rule-variations.js';
import { jsFiles, tsFiles } from '../../constants.js';
const recommended = createVariations({
files: [...tsFiles, ...jsFiles],
rules: {
...{}, // Plugin: eslint-plugin-unicorn
'unicorn/prefer-add-event-listener': 'error',
'unicorn/prefer-dom-node-append': 'error',
'unicorn/prefer-dom-node-dataset': 'error',
'unicorn/prefer-dom-node-remove': 'error',
'unicorn/prefer-dom-node-text-content': 'error',
'unicorn/prefer-keyboard-event-key': 'error',
'unicorn/prefer-modern-dom-apis': 'error',
'unicorn/prefer-query-selector': 'error',
},
});
const strict = createVariations({
...recommended.error,
rules: {
...recommended.error.rules,
},
});
const node = { recommended, strict };
export default node;

View File

@@ -1,12 +0,0 @@
/**
* @file
* Configuration object for the all the environment.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import browser from './browser.js';
import node from './node.js';
const environments = { browser, node };
export default environments;

View File

@@ -1,116 +0,0 @@
/* eslint-disable import/no-relative-parent-imports */
/* eslint-disable unicorn/no-useless-spread */
/**
* @file
* Configuration objects for the NodeJS environment.
* See more info on the configs type declaration file.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import nodePlugin from 'eslint-plugin-n';
import globals from 'globals';
import { createVariations } from '../../lib/rule-variations.js';
import { jsFiles, tsFiles } from '../../constants.js';
const commonjs = createVariations({
files: ['**/*.cts', '**/*.cjs'],
languageOptions: {
globals: {
...globals.nodeBuiltin,
...globals.commonjs,
},
},
plugins: {
// @ts-expect-error because types are not defined in 'eslint-plugin-n'
n: nodePlugin,
},
rules: {
...{}, // Plugin: @typescript-eslint/eslint-plugin
'@typescript-eslint/no-require-imports': 'off',
'@typescript-eslint/no-var-requires': 'off',
...{}, // Plugin: eslint-plugin-unicorn
'unicorn/prefer-module': 'off',
...{}, // Plugin: eslint-plugin-import
'import/no-commonjs': 'off',
...{}, // Plugin: eslint-plugin-n
'n/global-require': 'error',
'n/no-exports-assign': 'error',
...{}, // Plugin: eslint-plugin-security
'security/detect-non-literal-require': 'error',
},
});
const recommended = createVariations({
files: [...tsFiles, ...jsFiles],
languageOptions: {
globals: {
...globals.nodeBuiltin,
},
},
plugins: {
// @ts-expect-error because types are not defined in 'eslint-plugin-n'
n: nodePlugin,
},
rules: {
...{}, // Plugin: eslint-plugin-unicorn
'unicorn/prefer-node-protocol': 'error',
...{}, // Plugin: eslint-plugin-import
'import/no-dynamic-require': 'error',
...{}, // Plugin: eslint-plugin-n
'n/no-deprecated-api': 'error',
'n/no-process-exit': 'error',
'n/no-unpublished-bin': 'error',
'n/no-unpublished-import': 'error',
'n/no-unpublished-require': 'error',
'n/no-unsupported-features/es-builtins': 'error',
'n/no-unsupported-features/es-syntax': 'error',
'n/no-unsupported-features/node-builtins': 'error',
'n/process-exit-as-throw': 'error',
'n/shebang': 'error',
...{}, // Plugin: eslint-plugin-security
'security/detect-buffer-noassert': 'warn',
'security/detect-child-process': 'warn',
'security/detect-new-buffer': 'warn',
'security/detect-no-csrf-before-method-override': 'warn',
'security/detect-non-literal-fs-filename': 'warn',
},
});
const strict = createVariations({
...recommended.error,
rules: {
...recommended.error.rules,
...{}, // Plugin: eslint-plugin-n
'n/no-new-require': 'error',
'n/no-path-concat': 'error',
'n/prefer-global/buffer': ['error', 'never'],
'n/prefer-global/console': ['error', 'always'],
'n/prefer-global/process': ['error', 'never'],
'n/prefer-global/text-decoder': ['error', 'always'],
'n/prefer-global/text-encoder': ['error', 'always'],
'n/prefer-global/url': ['error', 'always'],
'n/prefer-global/url-search-params': ['error', 'always'],
'n/prefer-promises/dns': 'error',
'n/prefer-promises/fs': 'error',
...{}, // Plugin: eslint-plugin-security
'security/detect-buffer-noassert': 'error',
'security/detect-child-process': 'error',
'security/detect-new-buffer': 'error',
'security/detect-no-csrf-before-method-override': 'error',
'security/detect-non-literal-fs-filename': 'warn',
},
});
const node = { commonjs, recommended, strict };
export default node;

View File

@@ -1,192 +0,0 @@
/* eslint-disable import/no-relative-parent-imports */
/* eslint-disable unicorn/no-useless-spread */
/**
* @file
* Configuration objects for code formatting and style in JavaScript and TypeScript.
* See more info on the configs type declaration file.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import perfectionistPlugin from 'eslint-plugin-perfectionist';
import { createVariations } from '../lib/rule-variations.js';
import { jsFiles, tsFiles } from '../constants.js';
const recommended = createVariations({
files: [...tsFiles, ...jsFiles],
plugins: {
// @ts-expect-error because plugin doesn't export correct type
perfectionist: perfectionistPlugin,
},
rules: {
...{}, // ESLint rules
'arrow-parens': ['error', 'as-needed', { requireForBlockBody: true }],
'comma-style': 'error',
'curly': ['error', 'multi-or-nest', 'consistent'],
'dot-location': 'error',
'eol-last': 'error',
'generator-star-spacing': ['error', 'before'],
'no-mixed-spaces-and-tabs': 'error',
'no-multi-spaces': 'error',
'no-whitespace-before-property': 'error',
'padded-blocks': 'error',
'rest-spread-spacing': 'error',
'semi-spacing': 'error',
'space-in-parens': 'error',
'space-unary-ops': 'error',
'spaced-comment': ['error', 'always', {
block: {
balanced: true,
exceptions: ['*'],
markers: ['!'],
},
line: {
exceptions: ['/', '#'],
markers: ['/'],
},
}],
'template-curly-spacing': ['error', 'never'],
...{}, // Plugin: @typescript-eslint/eslint-plugin
'@typescript-eslint/block-spacing': ['error', 'always'],
'@typescript-eslint/brace-style': ['error', 'stroustrup', {
allowSingleLine: true,
}],
'@typescript-eslint/comma-dangle': ['error', 'always-multiline'],
'@typescript-eslint/comma-spacing': 'error',
'@typescript-eslint/dot-notation': 'error',
'@typescript-eslint/func-call-spacing': 'error',
'@typescript-eslint/indent': ['error', 'tab', { ArrayExpression: 1,
CallExpression: { arguments: 1 },
FunctionDeclaration: { body: 1,
parameters: 1 },
FunctionExpression: { body: 1,
parameters: 1 },
ImportDeclaration: 1,
MemberExpression: 1,
ObjectExpression: 1,
SwitchCase: 1,
VariableDeclarator: 1,
flatTernaryExpressions: false,
ignoreComments: false, ignoredNodes: [
'TemplateLiteral *',
'JSXElement',
'JSXElement > *',
'JSXAttribute',
'JSXIdentifier',
'JSXNamespacedName',
'JSXMemberExpression',
'JSXSpreadAttribute',
'JSXExpressionContainer',
'JSXOpeningElement',
'Element',
'JSXFragment',
'JSXOpeningFragment',
'JSXClosingFragment',
'JSXText',
'JSXEmptyExpression',
'JSXSpreadChild',
'TSTypeParameterInstantiation',
'FunctionExpression > .params[decorators.length > 0]',
// eslint-disable-next-line max-len
'FunctionExpression > .params > :matches(Decorator, :not(:first-child))',
// eslint-disable-next-line max-len
'ClassBody.body > PropertyDefinition[decorators.length > 0] > .key',
], offsetTernaryExpressions: true, outerIIFEBody: 1,
}],
'@typescript-eslint/key-spacing': ['error', {
afterColon: true,
beforeColon: false,
}],
'@typescript-eslint/keyword-spacing': ['error', {
after: true,
before: true,
}],
'@typescript-eslint/lines-between-class-members': ['error'],
'@typescript-eslint/member-delimiter-style': ['error', {
multiline: { delimiter: 'comma', requireLast: true },
singleline: { delimiter: 'comma', requireLast: true },
}],
'@typescript-eslint/no-extra-parens': ['error', 'functions'],
'@typescript-eslint/object-curly-spacing': ['error', 'always'],
'@typescript-eslint/quotes': ['error', 'single'],
'@typescript-eslint/semi': ['error', 'always'],
'@typescript-eslint/space-before-blocks': ['error', 'always'],
'@typescript-eslint/space-before-function-paren': ['error', {
anonymous: 'always',
asyncArrow: 'always',
named: 'never',
}],
'@typescript-eslint/space-infix-ops': 'error',
'@typescript-eslint/type-annotation-spacing': ['error', {
after: true,
before: false,
overrides: {
arrow: { after: true, before: true },
},
}],
'block-spacing': 'off',
'brace-style': 'off',
'comma-dangle': 'off',
'comma-spacing': 'off',
'dot-notation': 'off',
'func-call-spacing': 'off',
'indent': 'off',
'key-spacing': 'off',
'keyword-spacing': 'off',
'lines-between-class-members': 'off',
'object-curly-spacing': 'off',
'quotes': 'off',
'semi': 'off',
'space-before-blocks': 'off',
'space-before-function-paren': 'off',
'space-infix-ops': 'off',
...{}, // Plugin: eslint-plugin-import
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
'import/exports-last': 'error',
'import/first': 'error',
'import/group-exports': 'error',
...{}, // Plugin: eslint-plugin-perfectionist
'perfectionist/sort-array-includes': ['error', { type: 'natural' }],
'perfectionist/sort-classes': ['error', { type: 'natural' }],
'perfectionist/sort-enums': ['error', { type: 'natural' }],
'perfectionist/sort-exports': ['error', { type: 'line-length' }],
'perfectionist/sort-imports': ['error', {
groups: [
'type',
'builtin',
'external',
'internal-type',
'internal',
['parent-type', 'sibling-type', 'index-type'],
['parent', 'sibling', 'index'],
'object',
'unknown',
],
order: 'desc',
type: 'line-length',
}],
'perfectionist/sort-interfaces': ['error', { type: 'natural' }],
'perfectionist/sort-jsx-props': ['error', { type: 'natural' }],
'perfectionist/sort-map-elements': ['error', { type: 'natural' }],
'perfectionist/sort-named-exports': ['error', { type: 'natural' }],
'perfectionist/sort-named-imports': ['error', { type: 'natural' }],
'perfectionist/sort-object-types': ['error', { type: 'natural' }],
'perfectionist/sort-objects': ['error', { type: 'natural' }],
'perfectionist/sort-union-types': ['error', { type: 'natural' }],
},
});
const strict = createVariations({
...recommended.error,
rules: {
...recommended.error.rules,
},
});
const formatting = { recommended, strict };
export default formatting;

View File

@@ -1,318 +0,0 @@
/**
* @file
* Type declarations and documentations for all configs objects.
* All these types are public to the user.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import type { Linter } from 'eslint';
interface ConfigVariations {
/**
* @summary
* Enable rules with the predefined levels of the package.
* @description
* Most of the rules in ESLegant are on `error` level. This
* was preferred so it is harder to ignore them. But it has
* some small exceptions where rules will be at `warn` level,
* being more as a "reminder" than a actual rule.
*
* If you want to **every** rule in the config to have an
* `error` or `warn` level, you can use the other variants.
*/
default: Linter.FlatConfig,
/**
* @description
* Enable all rules with `error` level.
*/
error: Linter.FlatConfig,
/**
* @description
* Disable all rules in this config.
*/
off: Linter.FlatConfig,
/**
* @description
* Enable all rules with `warn` level.
*/
warn: Linter.FlatConfig,
}
const configs: Readonly<{
/**
* @summary
* **Add this configuration at the start of your array**.
* @description
* This config adds necessary plugins and configuration for ESLint
* to use in the other configs **This should always be in the top
* of the configuration array**.
*/
core: Linter.FlatConfig,
/**
* @description
* This configuration helps you document your code with JSDoc.
*/
documentation: {
/**
* @summary
* Recommended rules from the original plugins.
* @description
* Less strict rules, that nots enforces documentation on
* every aspect/function of your code. Recommended rules for
* projects in prototyping or starting phases, or apps that
* doesn't needs massive documentations.
*/
recommended: ConfigVariations,
/**
* @summary
* More opinionated configuration, created for ESLegant and Lored's projects.
* @borrows Builds on top of the recommended configuration
* @description
* Enforces some documentation of every function and file.
* Better for libraries (in more production-ready phases),
* large codebase's and/or projects with multiple teams/people.
*/
strict: ConfigVariations,
},
/**
* @summary
* Configurations related to specific JavaScript/TypeScript environments,
* such as Node, Deno and the Browser.
* @description
* Adds global variables and rules related to code on said environments.
* **They can and should be combined** depending on the codebase you're
* working with.
*/
environments: {
/**
* @description
* Browser environment configuration, use this if you are working
* on a pure client-side or mixed codebase environment.
*/
browser: {
/**
* @description
* Recommends end enforces the use of newer web APIs
* on your codebase.
*/
recommended: ConfigVariations,
/**
* @borrows Builds on top of the recommended configuration
* @todo
* For now, the strict rules is a alias of the recommended,
* as it not currently adds any new rules.
*/
strict: ConfigVariations,
},
node: {
/**
* @summary
* Configuration overrides for CommonJS files.
* @description
* ESLegant recommends the use of ESModules and newer syntax
* for javascript files. This configuration should mostly be
* used for exceptions, like config files that don't support
* ESM.
*
* This configuration just affects files ending in `*.cjs`
* and `*.cts` extensions. If you want to use in other files
* consider creating a config object.
* @example <caption>Example of using the config for specific CommonJS files</caption>
* import { configs } from '@eslegant/js';
*
* export default [
* {
* ...configs.environments.node.commonjs.error
* files: ['*.config.js'],
* }
* ]
*/
commonjs: ConfigVariations,
/**
* @description
* Recommends newer and best practices on NodeJS projects.
*/
recommended: ConfigVariations,
/**
* @borrows Builds on top of the recommended configuration
* @todo
* For now, the strict rules is a alias of the recommended,
* as it not currently adds any new rules.
*/
strict: ConfigVariations,
},
},
/**
* @summary
* This config relates to code formatting and style in JavaScript and TypeScript.
* @description
* This configuration enforces a specific code formatting and style in JavaScript
* and TypeScript. The purpose of it can sometimes overlap with the `suggestions`
* config, so to separate better, this tries to mostly enforces just rules for
* how the code looks and is organized than coding style/way of handling something.
*/
formatting: {
/**
* @summary
* ESLegant / Lored's code style configuration.
* @description
* This configuration recommends a opinionated code and formatting style, which
* is mostly similar to other styles in the JavaScript environment.
* It is based on the work and config of Anthony's ESLint config (`antfu/eslint-config`),
* with the most notable changes being the use of `tabs` instead of 2 space indentation
* and the use of semicolons.
* @see {@link https://github.com/antfu/eslint-config Anthony's config}
*/
recommended: ConfigVariations,
/**
* @borrows Builds on top of the recommended configuration
* @todo
* For now, the strict rules is a alias of the recommended,
* as it not currently adds any new rules.
*/
strict: ConfigVariations,
},
/**
* @description
* This configuration enforces a specific naming convention for the codebase.
* With the object of making the code more readable and understandable.
*/
naming: {
/**
* @summary
* Prevents bad naming conventions and behavior.
* @description
* This configuration prevents bad names and behaviors such as abbreviations.
* It does not enforces specific names or naming structure/strategies.
* **With the exception of** file names being enforces to be `kebab-case`.
*/
recommended: ConfigVariations,
/**
* @summary
* Enforces specific naming structure/strategies.
* @borrows Builds on top of the recommended configuration
* @description
* This configuration enforces specific names or naming structure/strategies for your
* code. Enforcing things such using verbs and nouns in specif orders and
* when abbreviations are accepted or not.
*/
strict: ConfigVariations,
},
overrides: {
'inferrable-types': ConfigVariations,
performance: ConfigVariations,
},
/**
* @summary
* Prevents possible syntax errors in your code.
* @description
* This configuration object prevents possible syntax and code logic
* errors on your file. Mostly not opinionated.
*/
problems: {
/**
* @description
* Rules which prevents most errors in your code. Based
* mostly on ESLint's recommended configuration.
*/
recommended: ConfigVariations,
/**
* @borrows Builds on top of the recommended configuration
* @description
* Extra-safety rules, reporting possible forgettable errors
* or errors in typing.
*/
strict: ConfigVariations,
},
/**
* @summary
* Prevents possible vulnerabilities.
* @description
* This configuration tries to prevent possible vulnerabilities
* in you code, such as hard-coded secrets, personal information in comments,
* XSS attacks, etc.
*/
security: {
/**
* @description
* Rules which warns you about possible security vulnerabilities.
*/
recommended: ConfigVariations,
/**
* @borrows Builds on top of the recommended configuration
* @description
* Similar to recommended config, but with rules in error-level
* to make possible vulnerabilities harder to ignore.
*/
strict: ConfigVariations,
},
/**
* @summary
* Enforces different ways of coding in JavaScript and TypeScript.
* @description
* This configuration enforces different ways doing things, coding style and/or
* code logic patterns. Preferring over explicit and declarative code than
* implicit.
*/
suggestions: {
/**
* @summary
* Recommended for projects in prototyping/starting phases.
* @description
* This configuration enforces mostly best practices,
* based on the `recommended` options of the plugins.
*/
recommended: ConfigVariations,
/**
* @summary
* Strict rules that takes "guarding rails" for your code.
* @borrows Builds on top of the recommended configuration
* @description
* **This will get in the way of your programming**. This configuration
* tries prevent possible bad code smells and practices that could built
* up when your project grows. Enforcing you to refactor more the code
* and separating and or reorganizing functions and code logic.
* @see {@link https://youtu.be/CFRhGnuXG-4 Example: Why You Shouldn't Nest Your Code - by: CodeAesthetic}
* - The maximum depth allowed is 4. (`max-depth: [error, 4]`)
* @see {@link https://youtu.be/J1f5b4vcxCQ Example: Dependency Injection, The Best Pattern - by: CodeAesthetic}
* - Files should be organized in a tree-like structure, and shouldn't import modules
* in parent directories. This helps you organize your code and suggests using
* dependency injection more.
*/
strict: ConfigVariations,
},
/**
* @summary
* Rules for TypeScript files specifically. **Use this if
* you have Typescript files in your project**.
* Affects `*.ts`, `*.tsx`, `*.mts` and `*.cts` files.
* @description
* Most of TypeScript rules can be applied to type-checked JavaScript
* files also. But some can just be fixed in TypeScript syntax, so they
* where disabled and moved to this specific configuration.
*
* It also disable things that aren't useful when using TypeScript, such
* as types in JSDoc comments.
*
* **This should be placed after the `suggestion` config.**.
*
*/
'suggestions-typescript': {
/**
* @summary
* Rules similar to {@link configs.suggestions.recommended `suggestions#recommended`},
* but for TypeScript.
*/
recommended: ConfigVariations,
/**
* @summary
* Rules similar to {@link configs.suggestions.strict `suggestions#strict`},
* but for TypeScript.
*/
strict: ConfigVariations,
},
}>;
export default configs;
export type { ConfigVariations };

View File

@@ -1,31 +0,0 @@
/**
* @file
* Main export files for all the configs objects, merging then in one `configs` object.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import typescript from './suggestions-typescript.js';
import environments from './environments/index.js';
import documentation from './documentation.js';
import suggestions from './suggestions.js';
import formatting from './formatting.js';
import overrides from './overrides.js';
import security from './security.js';
import problems from './problems.js';
import naming from './naming.js';
import core from './core.js';
const configs = {
core,
documentation,
environments,
formatting,
naming,
overrides,
problems,
security,
suggestions,
'suggestions-typescript': typescript,
};
export default configs;

View File

@@ -1,37 +0,0 @@
/* eslint-disable import/no-relative-parent-imports */
/* eslint-disable unicorn/no-useless-spread */
/**
* @file
* Configuration objects which enforces a specific naming convention for the codebase.
* See more info on the configs type declaration file.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import { createVariations } from '../lib/rule-variations.js';
import { jsFiles, tsFiles } from '../constants.js';
const recommended = createVariations({
files: [...tsFiles, ...jsFiles],
rules: {
...{}, // Plugin: eslint-plugin-unicorn
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
'unicorn/prevent-abbreviations': 'error',
},
});
const strict = createVariations({
...recommended.error,
rules: {
...recommended.error.rules,
...{}, // Plugin: @typescript-eslint/eslint-plugin
// '@typescript-eslint/naming-convention': 'error',
...{}, // Plugin: eslint-plugin-unicorn
'unicorn/no-keyword-prefix': 'error',
},
});
const suggestions = { recommended, strict };
export default suggestions;

View File

@@ -1,35 +0,0 @@
/* eslint-disable import/no-relative-parent-imports */
/* eslint-disable unicorn/no-useless-spread */
/**
* @file
* Overrides for specific scenarios or preferences of users. The objects
* are supposed to be placed on the end of the arrays and can
* change configs of multiple other categories.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
* @todo This file is not completed fully.
*/
import { createVariations } from '../lib/rule-variations.js';
import { jsFiles, tsFiles } from '../constants.js';
// TODO [>=1.0.0]: Create a separate config for performance related practices
const performance = createVariations({
files: [...tsFiles, ...jsFiles],
rules: {
'prefer-object-spread': 'off',
'prefer-spread': 'off',
},
});
const inferrableTypes = createVariations({
files: [...tsFiles],
rules: {
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-inferrable-types': 'error',
'@typescript-eslint/typedef': 'off',
},
});
const overrides = { 'inferrable-types': inferrableTypes, performance };
export default overrides;

View File

@@ -1,109 +0,0 @@
/* eslint-disable import/no-relative-parent-imports */
/* eslint-disable unicorn/no-useless-spread */
/**
* @file
* Configuration objects for preventing possible syntax errors.
* See more info on the configs type declaration file.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import { createVariations } from '../lib/rule-variations.js';
import { jsFiles, tsFiles } from '../constants.js';
const recommended = createVariations({
files: [...tsFiles, ...jsFiles],
rules: {
...{}, // ESLint rules
'constructor-super': 'error',
'for-direction': 'error',
'getter-return': 'error',
'no-async-promise-executor': 'error',
'no-class-assign': 'error',
'no-compare-neg-zero': 'error',
'no-cond-assign': 'error',
'no-const-assign': 'error',
'no-constant-condition': 'error',
'no-control-regex': 'error',
'no-debugger': 'error',
'no-delete-var': 'error',
'no-dupe-args': 'error',
'no-dupe-class-members': 'error',
'no-dupe-else-if': 'error',
'no-dupe-keys': 'error',
'no-duplicate-case': 'error',
'no-empty-character-class': 'error',
'no-empty-pattern': 'error',
'no-ex-assign': 'error',
'no-fallthrough': 'error',
'no-func-assign': 'error',
'no-global-assign': 'error',
'no-import-assign': 'error',
'no-inner-declarations': 'error',
'no-invalid-regexp': 'error',
'no-irregular-whitespace': 'error',
'no-misleading-character-class': 'error',
'no-nonoctal-decimal-escape': 'error',
'no-obj-calls': 'error',
'no-octal': 'error',
'no-octal-escape': 'error',
'no-prototype-builtins': 'error',
'no-regex-spaces': 'error',
'no-self-assign': 'error',
'no-setter-return': 'error',
'no-shadow-restricted-names': 'error',
'no-sparse-arrays': 'error',
'no-this-before-super': 'error',
'no-undef': 'error',
'no-unexpected-multiline': 'error',
'no-unreachable': 'error',
'no-unsafe-finally': 'error',
'no-unsafe-negation': 'error',
'no-unsafe-optional-chaining': 'error',
'no-unused-labels': 'error',
'no-useless-backreference': 'error',
'use-isnan': 'error',
'valid-typeof': 'error',
...{}, // Plugin: @typescript-eslint/eslint-plugin
'@typescript-eslint/no-loss-of-precision': 'error',
'@typescript-eslint/no-redeclare': 'error',
'@typescript-eslint/no-unused-vars': 'error',
'no-loss-of-precision': 'off',
'no-redeclare': 'off',
'no-unused-vars': 'off',
...{}, // Plugin: eslint-plugin-import
'import/default': 'error',
'import/export': 'error',
'import/named': 'error',
'import/namespace': 'error',
'import/no-unresolved': 'error',
},
});
const strict = createVariations({
...recommended.error,
rules: {
...recommended.error.rules,
...{}, // ESLint rules
'no-constant-binary-expression': 'error',
'no-duplicate-imports': 'error',
'no-new-native-nonconstructor': 'error',
'no-promise-executor-return': 'error',
'no-self-compare': 'error',
'no-sequences': 'error',
'no-template-curly-in-string': 'error',
'no-unmodified-loop-condition': 'error',
'no-unreachable-loop': 'error',
'no-unused-private-class-members': 'error',
'require-atomic-updates': 'error',
...{}, // Plugin: eslint-plugin-import
'import/no-extraneous-dependencies': 'error',
},
});
const problems = { recommended, strict };
export default problems;

View File

@@ -1,61 +0,0 @@
/* eslint-disable import/no-relative-parent-imports */
/* eslint-disable unicorn/no-useless-spread */
/**
* @file
* Configuration objects for preventing possible security vulnerabilities.
* See more info on the configs type declaration file.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import noSecretsPluginRegexes from 'eslint-plugin-no-secrets/regexes.js';
import noSecretsPlugin from 'eslint-plugin-no-secrets';
import { createVariations } from '../lib/rule-variations.js';
import { jsFiles, tsFiles } from '../constants.js';
const recommended = createVariations({
files: [...tsFiles, ...jsFiles],
plugins: {
'no-secrets': noSecretsPlugin,
},
rules: {
...{}, // Plugin: eslint-plugin-security
'security/detect-bidi-characters': 'warn',
'security/detect-disable-mustache-escape': 'warn',
'security/detect-eval-with-expression': 'warn',
'security/detect-non-literal-regexp': 'warn',
'security/detect-object-injection': 'warn',
'security/detect-possible-timing-attacks': 'warn',
'security/detect-pseudoRandomBytes': 'warn',
'security/detect-unsafe-regex': 'warn',
...{}, // Plugin: eslint-plugin-no-secrets
'no-secrets/no-secrets': 'warn',
},
});
const strict = createVariations({
...recommended.error,
rules: {
...recommended.error.rules,
...{}, // Plugin: eslint-plugin-security
'security/detect-bidi-characters': 'error',
'security/detect-disable-mustache-escape': 'error',
'security/detect-eval-with-expression': 'error',
'security/detect-non-literal-regexp': 'error',
'security/detect-object-injection': 'warn',
'security/detect-possible-timing-attacks': 'warn',
'security/detect-pseudoRandomBytes': 'error',
'security/detect-unsafe-regex': 'error',
...{}, // Plugin: eslint-plugin-no-secrets
'no-secrets/no-secrets': ['error', {
additionalRegexes: noSecretsPluginRegexes,
}],
},
});
const security = { recommended, strict };
export default security;

View File

@@ -1,40 +0,0 @@
/* eslint-disable import/no-relative-parent-imports */
/* eslint-disable unicorn/no-useless-spread */
/**
* @file
* Configuration objects that enforces different ways of coding in TypeScript specifically.
* See more info on the configs type declaration file.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import { createVariations } from '../lib/rule-variations.js';
import { tsFiles } from '../constants.js';
const recommended = createVariations({
files: [...tsFiles],
rules: {
...{}, // Plugin: @typescript-eslint/eslint-plugin
'@typescript-eslint/explicit-function-return-type': 'error',
...{}, // Plugin: eslint-plugin-jsdoc
'jsdoc/check-tag-names': ['error', { typed: true }],
'jsdoc/no-types': 'error',
'jsdoc/require-param-type': 'off',
'jsdoc/require-property-type': 'off',
'jsdoc/require-returns-type': 'off',
},
});
const strict = createVariations({
...recommended.error,
rules: {
...recommended.error.rules,
...{}, // Plugin: @typescript-eslint/eslint-plugin
'@typescript-eslint/explicit-member-accessibility': 'error',
'@typescript-eslint/explicit-module-boundary-types': 'error',
},
});
const typescript = { recommended, strict };
export default typescript;

View File

@@ -1,451 +0,0 @@
/* eslint-disable import/no-relative-parent-imports */
/* eslint-disable unicorn/no-useless-spread */
/**
* @file
* Configuration objects that enforces different ways of coding in JavaScript and TypeScript..
* See more info on the configs type declaration file.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import { createVariations } from '../lib/rule-variations.js';
import { jsFiles, tsFiles } from '../constants.js';
const recommended = createVariations({
files: [...tsFiles, ...jsFiles],
rules: {
'camelcase': 'error',
'max-len': ['error', { code: 80, comments: 100, ignoreUrls: true }],
'no-case-declarations': 'error',
'no-confusing-arrow': 'error',
'no-console': 'error',
'no-constant-condition': 'error',
'no-delete-var': 'error',
'no-empty': 'error',
'no-lonely-if': 'error',
'no-new-symbol': 'error',
'no-redeclare': 'error',
'no-useless-catch': 'error',
'no-useless-escape': 'error',
'no-var': 'error',
'no-with': 'error',
'object-shorthand': ['error', 'always', {
avoidQuotes: true,
ignoreConstructors: false,
}],
'prefer-exponentiation-operator': 'error',
'prefer-rest-params': 'error',
'prefer-spread': 'error',
'prefer-template': 'error',
'quote-props': ['error', 'consistent-as-needed'],
'require-yield': 'error',
...{}, // Plugin: @typescript-eslint/eslint-plugin
/*
* '@typescript-eslint/adjacent-overload-signatures': 'error',
* Incompatible with perfectionist/sort-interfaces and
* perfectionist/sort-object-types.
*/
'@typescript-eslint/array-type': 'error',
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/ban-ts-comment': 'error',
'@typescript-eslint/ban-tslint-comment': 'error',
'@typescript-eslint/ban-types': 'error',
'@typescript-eslint/class-literal-property-style': 'error',
'@typescript-eslint/consistent-generic-constructors': 'error',
// eslint-disable-next-line max-len
'@typescript-eslint/consistent-indexed-object-style': ['error', 'index-signature'],
'@typescript-eslint/consistent-type-assertions': 'error',
'@typescript-eslint/consistent-type-definitions': 'error',
'@typescript-eslint/no-base-to-string': 'error',
'@typescript-eslint/no-confusing-non-null-assertion': 'error',
'@typescript-eslint/no-confusing-void-expression': 'error',
'@typescript-eslint/no-duplicate-enum-values': 'error',
'@typescript-eslint/no-duplicate-type-constituents': 'error',
'@typescript-eslint/no-dynamic-delete': 'error',
'@typescript-eslint/no-empty-interface': 'error',
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-extra-non-null-assertion': 'error',
'@typescript-eslint/no-extraneous-class': 'error',
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-for-in-array': 'error',
'@typescript-eslint/no-import-type-side-effects': 'error',
'@typescript-eslint/no-invalid-void-type': 'error',
'@typescript-eslint/no-meaningless-void-operator': 'error',
'@typescript-eslint/no-misused-new': 'error',
'@typescript-eslint/no-misused-promises': 'error',
'@typescript-eslint/no-mixed-enums': 'error',
'@typescript-eslint/no-namespace': 'error',
'@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
'@typescript-eslint/no-non-null-assertion': 'error',
'@typescript-eslint/no-redundant-type-constituents': 'error',
'@typescript-eslint/no-require-imports': 'error',
'@typescript-eslint/no-this-alias': 'error',
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error',
'@typescript-eslint/no-unnecessary-condition': 'error',
'@typescript-eslint/no-unnecessary-type-arguments': 'error',
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
'@typescript-eslint/no-unnecessary-type-constraint': 'error',
'@typescript-eslint/no-unsafe-argument': 'error',
'@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unsafe-declaration-merging': 'error',
'@typescript-eslint/no-unsafe-enum-comparison': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
'@typescript-eslint/no-var-requires': 'error',
'@typescript-eslint/non-nullable-type-assertion-style': 'error',
'@typescript-eslint/prefer-as-const': 'error',
'@typescript-eslint/prefer-function-type': 'error',
'@typescript-eslint/prefer-literal-enum-member': 'error',
'@typescript-eslint/prefer-namespace-keyword': 'error',
'@typescript-eslint/prefer-nullish-coalescing': 'error',
'@typescript-eslint/prefer-optional-chain': 'error',
'@typescript-eslint/prefer-reduce-type-parameter': 'error',
'@typescript-eslint/prefer-return-this-type': 'error',
'@typescript-eslint/prefer-string-starts-ends-with': 'error',
'@typescript-eslint/prefer-ts-expect-error': 'error',
'@typescript-eslint/restrict-plus-operands': 'error',
'@typescript-eslint/restrict-template-expressions': 'error',
'@typescript-eslint/triple-slash-reference': 'error',
'@typescript-eslint/unbound-method': 'error',
'@typescript-eslint/unified-signatures': 'error',
...{}, // Plugin: eslint-plugin-unicorn
'unicorn/better-regex': 'error',
'unicorn/catch-error-name': 'error',
'unicorn/consistent-destructuring': 'error',
'unicorn/consistent-function-scoping': 'error',
'unicorn/empty-brace-spaces': 'error',
'unicorn/error-message': 'error',
'unicorn/escape-case': 'error',
'unicorn/expiring-todo-comments': ['error', {
allowWarningComments: false,
}],
'unicorn/explicit-length-check': 'error',
'unicorn/new-for-builtins': 'error',
'unicorn/no-abusive-eslint-disable': 'error',
'unicorn/no-array-callback-reference': 'error',
'unicorn/no-array-for-each': 'error',
'unicorn/no-array-method-this-argument': 'error',
'unicorn/no-array-push-push': 'error',
'unicorn/no-array-reduce': 'error',
'unicorn/no-await-expression-member': 'error',
'unicorn/no-console-spaces': 'error',
'unicorn/no-document-cookie': 'error',
'unicorn/no-empty-file': 'error',
'unicorn/no-for-loop': 'error',
'unicorn/no-hex-escape': 'error',
'unicorn/no-instanceof-array': 'error',
'unicorn/no-invalid-remove-event-listener': 'error',
'unicorn/no-lonely-if': 'error',
'unicorn/no-new-array': 'error',
'unicorn/no-new-buffer': 'error',
'unicorn/no-object-as-default-parameter': 'error',
'unicorn/no-process-exit': 'error',
'unicorn/no-static-only-class': 'error',
'unicorn/no-thenable': 'error',
'unicorn/no-this-assignment': 'error',
'unicorn/no-typeof-undefined': 'error',
'unicorn/no-unnecessary-await': 'error',
'unicorn/no-unreadable-array-destructuring': 'error',
'unicorn/no-unreadable-iife': 'error',
'unicorn/no-useless-fallback-in-spread': 'error',
'unicorn/no-useless-length-check': 'error',
'unicorn/no-useless-promise-resolve-reject': 'error',
'unicorn/no-useless-spread': 'error',
'unicorn/no-useless-switch-case': 'error',
/*
* TODO (@guz013) [>=1.0.0]: 'unicorn/no-useless-undefined' rule
* It could be better to use a invert to this rule instead, as
* explicity code could be better then implicitly.
*/
'unicorn/no-zero-fractions': 'error',
'unicorn/number-literal-case': 'error',
'unicorn/numeric-separators-style': 'error',
'unicorn/prefer-array-find': ['error', { checkFromLast: true }],
'unicorn/prefer-array-flat': 'error',
'unicorn/prefer-array-flat-map': 'error',
'unicorn/prefer-array-index-of': 'error',
'unicorn/prefer-array-some': 'error',
'unicorn/prefer-at': 'error',
'unicorn/prefer-blob-reading-methods': 'error',
'unicorn/prefer-code-point': 'error',
'unicorn/prefer-date-now': 'error',
'unicorn/prefer-default-parameters': 'error',
'unicorn/prefer-event-target': 'error',
'unicorn/prefer-export-from': 'error',
'unicorn/prefer-includes': 'error',
'unicorn/prefer-logical-operator-over-ternary': 'error',
'unicorn/prefer-math-trunc': 'error',
'unicorn/prefer-modern-math-apis': 'error',
'unicorn/prefer-module': 'error',
'unicorn/prefer-native-coercion-functions': 'error',
'unicorn/prefer-negative-index': 'error',
'unicorn/prefer-number-properties': 'error',
'unicorn/prefer-optional-catch-binding': 'error',
'unicorn/prefer-prototype-methods': 'error',
'unicorn/prefer-reflect-apply': 'error',
'unicorn/prefer-regexp-test': 'error',
'unicorn/prefer-set-has': 'error',
// TODO [>=1.0.0]: Should this be on a "performance" preset?
'unicorn/prefer-set-size': 'error',
// TODO [>=1.0.0]: Should this be disabled on a "performance" preset?
'unicorn/prefer-spread': 'error',
'unicorn/prefer-string-replace-all': 'error',
'unicorn/prefer-string-slice': 'error',
'unicorn/prefer-string-starts-ends-with': 'error',
'unicorn/prefer-string-trim-start-end': 'error',
'unicorn/prefer-switch': ['error', {
emptyDefaultCase: 'do-nothing-comment',
}],
'unicorn/prefer-ternary': 'error',
'unicorn/prefer-top-level-await': 'error',
'unicorn/prefer-type-error': 'error',
'unicorn/relative-url-style': 'error',
'unicorn/require-array-join-separator': 'error',
'unicorn/require-number-to-fixed-digits-argument': 'error',
'unicorn/switch-case-braces': 'error',
'unicorn/text-encoding-identifier-case': 'error',
'unicorn/throw-new-error': 'error',
...{}, // Plugin: eslint-plugin-import
'import/no-amd': 'error',
'import/no-commonjs': 'error',
'import/no-deprecated': 'error',
'import/no-duplicates': 'error',
'import/no-empty-named-blocks': 'error',
'import/no-named-as-default': 'error',
'import/no-named-as-default-member': 'error',
'import/no-self-import': 'error',
'import/no-useless-path-segments': 'error',
...{}, // Plugin: eslint-plugin-jsdoc
'jsdoc/check-alignment': 'error',
'jsdoc/check-param-names': 'error',
'jsdoc/check-property-names': 'error',
'jsdoc/check-syntax': 'error',
'jsdoc/check-tag-names': 'error',
'jsdoc/check-types': 'error',
'jsdoc/check-values': 'error',
'jsdoc/empty-tags': 'error',
'jsdoc/implements-on-classes': 'error',
'jsdoc/multiline-blocks': 'error',
'jsdoc/no-multi-asterisks': ['error', { allowWhitespace: true }],
'jsdoc/require-asterisk-prefix': ['error', 'always'],
'jsdoc/require-jsdoc': 'error',
'jsdoc/require-param': 'error',
'jsdoc/require-param-name': 'error',
'jsdoc/require-param-type': 'error',
'jsdoc/require-property': 'error',
'jsdoc/require-property-name': 'error',
'jsdoc/require-property-type': 'error',
'jsdoc/require-returns': 'error',
'jsdoc/require-returns-check': 'error',
'jsdoc/require-returns-type': 'error',
'jsdoc/require-throws': 'error',
'jsdoc/require-yields': 'error',
'jsdoc/require-yields-check': 'error',
'jsdoc/sort-tags': 'error',
// 'jsdoc/valid-types': 'error', This is already handled by Typescript type checking mostly
},
});
const strict = createVariations({
...recommended.error,
rules: {
...recommended.error.rules,
...{}, // ESLint rules
'accessor-pairs': 'error',
'arrow-body-style': ['error', 'as-needed'],
'block-scoped-var': 'error',
'capitalized-comments': 'error',
'complexity': ['error', 10],
'consistent-return': 'error',
'consistent-this': 'error',
'default-case': 'error',
'default-case-last': 'error',
'eqeqeq': 'error',
'func-name-matching': 'error',
'func-names': ['error', 'as-needed'],
'func-style': ['error', 'declaration'],
'grouped-accessor-pairs': ['error', 'setBeforeGet'],
'handle-callback-err': 'error',
'logical-assignment-operators': ['error', 'always', {
enforceForIfStatements: true,
}],
'max-classes-per-file': ['error', 1],
'max-depth': ['error', 4],
'max-lines': ['error', 500],
'max-lines-per-function': ['error', {
max: 60,
skipBlankLines: true,
skipComments: true,
}],
'max-nested-callbacks': ['error', 10],
'max-params': ['error', 4],
'max-statements': ['error', 10],
'multiline-comment-style': ['error', 'starred-block'],
'new-cap': 'error',
'new-parens': 'error',
'no-alert': 'error',
'no-await-in-loop': 'error',
'no-bitwise': 'error',
'no-caller': 'error',
'no-continue': 'error',
'no-div-regex': 'error',
'no-else-return': 'error',
'no-empty-static-block': 'error',
'no-eval': 'error',
'no-extend-native': 'error',
'no-extra-bind': 'error',
'no-extra-boolean-cast': 'error',
'no-extra-parens': ['error', 'all', {
enforceForArrowConditionals: false,
nestedBinaryExpressions: false,
ternaryOperandBinaryExpressions: false,
}],
'no-floating-decimal': 'error',
'no-implicit-coercion': 'error',
'no-implied-eval': 'error',
'no-iterator': 'error',
'no-labels': 'error',
'no-lone-blocks': 'error',
'no-mixed-operators': 'error',
'no-multi-assign': 'error',
'no-multi-str': 'error',
'no-multiple-empty-lines': 'error',
'no-negated-condition': 'error',
'no-new': 'error',
'no-new-func': 'error',
'no-new-object': 'error',
'no-new-wrappers': 'error',
'no-path-concat': 'error',
'no-proto': 'error',
'no-return-assign': 'error',
'no-script-url': 'error',
'no-sequences': 'error',
'no-undef-init': 'error',
'no-underscore-dangle': 'error',
'no-unneeded-ternary': 'error',
'no-unused-expressions': 'error',
'no-use-before-define': 'error',
'no-useless-call': 'error',
'no-useless-computed-key': 'error',
'no-useless-rename': 'error',
'no-useless-return': 'error',
'one-var': ['error', 'never'],
'operator-assignment': ['error', 'always'],
'operator-linebreak': 'error',
'prefer-arrow-callback': 'error',
'prefer-const': 'error',
'prefer-named-capture-group': 'error',
'prefer-numeric-literals': 'error',
'prefer-object-has-own': 'error',
'prefer-object-spread': 'error',
'prefer-promise-reject-errors': 'error',
'prefer-regex-literals': 'error',
'radix': ['error', 'always'],
'require-unicode-regexp': 'error',
'symbol-description': 'error',
'wrap-iife': 'error',
'yoda': ['error', 'never'],
...{}, // Plugin: @typescript-eslint/eslint-plugin
'@typescript-eslint/class-methods-use-this': 'error',
'@typescript-eslint/consistent-type-exports': ['error', {
fixMixedExportsWithInlineTypeSpecifier: false,
}],
'@typescript-eslint/consistent-type-imports': ['error', {
disallowTypeAnnotations: true,
fixStyle: 'separate-type-imports',
prefer: 'type-imports',
}],
'@typescript-eslint/default-param-last': 'error',
'@typescript-eslint/dot-notation': 'error',
'@typescript-eslint/method-signature-style': ['error', 'method'],
'@typescript-eslint/no-array-constructor': 'error',
'@typescript-eslint/no-empty-function': 'error',
'@typescript-eslint/no-extra-semi': 'error',
'@typescript-eslint/no-invalid-this': 'error',
'@typescript-eslint/no-loop-func': 'error',
'@typescript-eslint/no-shadow': 'error',
'@typescript-eslint/no-throw-literal': 'error',
'@typescript-eslint/no-unnecessary-qualifier': 'error',
'@typescript-eslint/no-use-before-define': 'error',
'@typescript-eslint/no-useless-constructor': 'error',
'@typescript-eslint/no-useless-empty-export': 'error',
'@typescript-eslint/parameter-properties': 'error',
'@typescript-eslint/prefer-enum-initializers': 'error',
'@typescript-eslint/prefer-readonly': 'error',
'@typescript-eslint/promise-function-async': 'error',
'@typescript-eslint/require-array-sort-compare': 'error',
'@typescript-eslint/require-await': 'error',
'@typescript-eslint/switch-exhaustiveness-check': 'error',
'@typescript-eslint/typedef': 'error',
// '@typescript-eslint/no-magic-numbers': ['error'],
'class-methods-use-this': 'off',
'default-param-last': 'off',
'no-array-constructor': 'off',
'no-empty-function': 'off',
'no-extra-semi': 'off',
'no-invalid-this': 'off',
'no-loop-func': 'off',
'no-shadow': 'off',
'no-throw-literal': 'off',
'no-use-before-defined': 'off',
'no-useless-constructor': 'off',
'require-await': 'off',
// 'no-magic-numbers': 'off',
...{}, // Plugin: eslint-plugin-unicorn
'no-nested-ternary': 'off',
'unicorn/custom-error-definition': 'error',
'unicorn/no-negated-condition': 'error',
'unicorn/no-nested-ternary': 'error',
/*
* TODO (@guz013) [>=1.0.0]: 'unicorn/no-null' rule
* It could be better to use a invert to this rule instead,
* because the null type could be a better representation to
* "no value" then undefined.
*/
'unicorn/no-unsafe-regex': 'error',
'unicorn/no-unused-properties': 'error',
...{}, // Plugin: eslint-plugin-import
'import/extensions': ['error', 'always', { ignorePackages: true }],
'import/max-dependencies': ['error', {
ignoreTypeImports: true,
max: 10,
}],
'import/no-absolute-path': 'error',
'import/no-anonymous-default-export': 'error',
'import/no-cycle': 'error',
'import/no-import-module-exports': 'error',
'import/no-mutable-exports': 'error',
'import/no-named-default': 'error',
'import/no-relative-packages': 'error',
'import/no-relative-parent-imports': 'error',
'import/no-unassigned-import': ['error', {
allow: ['**/*.css', '**/*.scss', '**/*.less'],
}],
'import/prefer-default-export': 'error',
'import/unambiguous': 'error',
...{}, // Plugin: eslint-plugin-jsdoc
'jsdoc/check-access': 'error',
'jsdoc/check-indentation': 'error',
'jsdoc/informative-docs': 'error',
'jsdoc/multiline-blocks': ['error', { noSingleLineBlocks: true }],
'jsdoc/no-bad-blocks': 'error',
'jsdoc/no-blank-block-descriptions': 'error',
'jsdoc/no-blank-blocks': 'error',
},
});
const suggestions = { recommended, strict };
export default suggestions;

View File

@@ -1,11 +0,0 @@
/**
* @file
* Constant values used around the package.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
const jsFiles = ['**/*.js', '**/*.mjs', '**/*.cjs', '**/*.jsx'];
const tsFiles = ['**/*.ts', '**/*.mts', '**/*.cts', '**/*.tsx'];
export { jsFiles, tsFiles };

View File

@@ -1,22 +0,0 @@
/**
* @file
* Types entrypoint of the package.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import type { Linter } from 'eslint';
export { default as presets } from './presets/index.d.ts';
export { default as configs } from './configs/index.d.ts';
/**
* Helper function to provide type-checking when defining
* ESLint's configuration.
*
* @param config - The configuration array to be returned.
* @returns The configuration array passed on the first parameter.
*/
export function defineConfig(
config: Linter.FlatConfig[],
): Linter.FlatConfig[];

View File

@@ -1,27 +0,0 @@
/**
* @file
* Main file entrypoint of the package.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import presets from './presets/index.js';
import configs from './configs/index.js';
/**
* Helper function to provide type-checking when defining
* ESLint's configuration.
*
* @param {import('eslint').Linter.FlatConfig[]} config
* - The configuration array to be returned.
* @returns {import('eslint').Linter.FlatConfig[]}
*/
function defineConfig(config) {
return config;
}
const eslegant = { configs, presets };
export { defineConfig, eslegant as default };
export { default as configs } from './configs/index.js';
export { default as presets } from './presets/index.js';

View File

@@ -1,104 +0,0 @@
/**
* @file Utility functions used in the package to manipulate rules records.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
/**
* @typedef {import('../configs/index').ConfigVariations} ConfigVariations
* @typedef {import('eslint').Linter.RuleEntry} RuleEntry
* @typedef {import('eslint').Linter.RuleLevel} RuleLevel
* @typedef {import('eslint').Linter.FlatConfig} FlatConfig
*/
/**
* Changes the level of a rule entry. Checking if it
* is a Array or a simple RuleLevel entry.
*
* Useful in conjunction with {@link iterateRules `iterateRules()`} function.
*
* @param {Readonly<RuleEntry>} ruleEntry
* - The rule entry to be modified.
* @param {RuleLevel} level
* - The new level to be passed to the rule.
* @returns {RuleEntry}
*/
function changeLevel(ruleEntry, level) {
if (typeof level === 'number') {
/** @type {RuleLevel[]} */
const levels = ['error', 'off', 'warn'];
level = levels[level];
}
if (Array.isArray(ruleEntry))
return [level, ruleEntry[1]];
return level;
}
/**
* Iterates through a rule entry record, using the handler
* on each entry and returns the resulting object.
*
* Useful for applying plugin prefixes or changing the rule
* level of the entries.
*
* @param {Readonly<{[name: string]: RuleEntry}>} rules
* - The object to be iterated through.
* @param {([name, entry]: [string, RuleEntry]) => [string, RuleEntry]} handler
* - Function to run on every rule entry.
* @returns {{[name: string]: RuleEntry}} - The resulting object.
*/
function iterateRules(rules, handler) {
const entries = Object.entries(rules);
entries.map(entry => handler(entry));
return Object.fromEntries(entries);
}
/**
* Creates {@link ConfigVariations variations} for the given configuration object.
* With `error`, `warn` and `off` rule levels.
*
* Used in the configuration objects of this package.
*
* @param {Readonly<FlatConfig>} config
* - The configuration object to create `error`, `warn`, and `off` variations.
* @returns {ConfigVariations}
*/
function createVariations(config) {
const configError = {
...config,
rules: iterateRules(config.rules ?? {}, ([key, entry]) =>
(entry === 'off' || (Array.isArray(entry) && entry[0] === 'off')
? [key, entry]
: [key, changeLevel(entry, 'error')]),
),
};
const configWarning = {
...config,
rules: iterateRules(config.rules ?? {}, ([key, entry]) =>
(entry === 'off' || (Array.isArray(entry) && entry[0] === 'off')
? [key, entry]
: [key, changeLevel(entry, 'warn')]),
),
};
const configDisabled = {
...config,
rules: iterateRules(
config.rules ?? {},
([key, entry]) => [key, changeLevel(entry, 'off')],
),
};
return {
default: config,
error: configError,
off: configDisabled,
warn: configWarning,
};
}
export { createVariations, iterateRules };

View File

@@ -1,51 +0,0 @@
/**
* @file
* Types declarations and documentation for the presets object.
* All these types are public to the user.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import type { Linter } from 'eslint';
const presets: Readonly<{
/**
* @summary
* Preset recommended for projects in a prototyping or starting phase.
* @description
* This preset is mostly recommended for projects in the start of
* their development, being more flexible and less opinionated.
* Useful for preventing errors.
*
* Configs used:
* - `problems#recommended`;
* - `suggestions#recommended`;
* - `suggestions-typescript#recommended`;
* - `formatting#recommended`;
* - `naming#recommended`;
* - `documentation#recommended`;
*
* All configs are set on level `error`.
*/
recommended: Linter.FlatConfig[],
/**
* @summary
* Preset recommended for projects in a production or large scale.
* @description
* This preset is more strict and opinionated, focusing on making
* your code follow a specific structure and pattern.
*
* Configs used:
* - `problems#strict`;
* - `suggestions#strict`;
* - `suggestions-typescript#strict`;
* - `formatting#strict`;
* - `naming#strict`;
* - `documentation#recommended`;
*
* All configs are set on level `error`.
*/
strict: Linter.FlatConfig[],
}>;
export default presets;

View File

@@ -1,12 +0,0 @@
/**
* @file
* Presets object export.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import recommended from './recommended.js';
import strict from './strict.js';
const presets = { recommended, strict };
export default presets;

View File

@@ -1,23 +0,0 @@
/**
* @file
* Recommended preset object. More info and docs on the type
* declaration file.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
// eslint-disable-next-line import/no-relative-parent-imports
import configs from '../configs/index.js';
/** @type {import('eslint').Linter.FlatConfig[]} */
const recommended = [
configs.core,
configs.problems.recommended.default,
configs.suggestions.recommended.default,
configs['suggestions-typescript'].recommended.default,
configs.formatting.recommended.default,
configs.naming.recommended.default,
configs.documentation.recommended.default,
configs.security.recommended.default,
];
export default recommended;

View File

@@ -1,23 +0,0 @@
/**
* @file
* Strict preset object. More info and docs on the type
* declaration file.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
// eslint-disable-next-line import/no-relative-parent-imports
import configs from '../configs/index.js';
/** @type {import('eslint').Linter.FlatConfig[]} */
const strict = [
configs.core,
configs.problems.strict.default,
configs.suggestions.strict.default,
configs['suggestions-typescript'].strict.default,
configs.formatting.strict.default,
configs.naming.strict.default,
configs.documentation.recommended.default,
configs.security.strict.default,
];
export default strict;

View File

@@ -1,16 +1,6 @@
import { configs, defineConfig, presets } from '@eslegant/js';
import { configs, defineConfig, presets } from '@eslit/config';
export default defineConfig([
...presets.strict,
configs.environments.node.strict.error,
{
...configs.documentation.strict.error,
files: ['configs/**/*.js', 'configs/**/*.ts'],
},
{
files: ['**/*.{js,ts,cjs,tjs,mjs,mts,jsx,tsx}'],
rules: {
'jsdoc/check-values': ['error', { allowedLicenses: ['MIT'] }],
},
},
...presets.default,
configs.environments.node,
]);

View File

@@ -1,5 +1,5 @@
{
"name": "fixtures/library",
"name": "@eslit-fixtures/library",
"version": "1.0.1",
"description": "",
"main": "index.js",
@@ -8,7 +8,7 @@
"test": "pnpm cli"
},
"dependencies": {
"@eslegant/cli": "workspace:*"
"@eslit/cli": "workspace:*"
},
"keywords": [],
"author": "",

View File

@@ -4,10 +4,10 @@
"test:cli": "pnpm cli"
},
"devDependencies": {
"@eslegant/cli": "workspace:*"
"@eslit/cli": "workspace:*"
},
"packageManager": "pnpm@8.6.10",
"name": "fixtures/monorepo",
"name": "monorepo",
"workspaces": [
"apps/*",
"packages/*"

View File

@@ -1,5 +1,5 @@
{
"name": "fixtures/svelte",
"name": "@eslit-fixtures/svelte",
"private": true,
"scripts": {
"dev": "vite dev",
@@ -11,7 +11,7 @@
"test:cli": "pnpm cli"
},
"devDependencies": {
"@eslegant/cli": "workspace:*",
"@eslit/cli": "workspace:*",
"@fontsource/fira-mono": "^4.5.10",
"@neoconfetti/svelte": "^1.0.0",
"@sveltejs/adapter-auto": "^2.0.0",

View File

@@ -1,5 +1,5 @@
{
"name": "eslegant-monorepo",
"name": "eslit-monorepo",
"private": true,
"scripts": {
"lint": "turbo run lint",
@@ -11,16 +11,16 @@
"license": "MIT",
"type": "module",
"dependencies": {
"@eslegant/js": "workspace:*"
"@eslit/config": "workspace:*"
},
"devDependencies": {
"@eslit/cli": "workspace:*",
"@changesets/cli": "^2.26.2",
"@commitlint/config-conventional": "^17.7.0",
"@commitlint/config-conventional": "^17.6.6",
"@commitlint/types": "^17.4.4",
"eslegant": "workspace:*",
"@svitejs/changesets-changelog-github-compact": "^1.1.0",
"eslint": "^8.47.0",
"husky": "^8.0.3",
"turbo": "^1.10.12"
"eslint": "^8.44.0",
"husky": "^8.0.0",
"turbo": "^1.10.9"
}
}

View File

@@ -1,17 +0,0 @@
import type { CliArgs } from './src/types';
/**
* Class that handles the creation and running the ESLegant command line interface
*/
export default class Cli {
/**
* @param args Arguments to pass to the cli when its runs
*/
constructor(args: CliArgs);
/**
* Runs the cli with the given arguments
*/
async run(): Promise<void>;
}
export type { CliArgs, Config } from './src/types.d.ts';

View File

@@ -1 +0,0 @@
export { default as default } from './src/cli.js';

View File

@@ -1,5 +1,5 @@
{
"extends": "../../tsconfig.json",
"exclude": ["./node_modules/**", "./dist/**"],
"include": ["**/*.ts", "**/*.js"],
"include": ["./index.d.ts", "./src/**/*.ts", "./src/**/*.js"],
}

View File

@@ -1,5 +1,5 @@
{
"name": "@eslegant/cli",
"name": "@eslit/cli",
"version": "0.1.0",
"description": "",
"scripts": {
@@ -16,16 +16,16 @@
"source": "./src/index.js",
"files": [
"src",
"index.js",
"index.d.ts"
],
"homepage": "https://github.com/LoredDev/ESLegant",
"homepage": "https://github.com/LoredDev/ESLit",
"type": "module",
"repository": {
"directory": "packages/config",
"type": "git",
"url": "https://github.com/LoredDev/ESLegant"
"url": "https://github.com/LoredDev/ESLit"
},
"bin": "./src/index.js",
"license": "MIT",
"dependencies": {
"cardinal": "^2.1.1",
@@ -34,13 +34,13 @@
"picocolors": "^1.0.0",
"picomatch": "^2.3.1",
"prompts": "^2.4.2",
"recast": "^0.23.4",
"recast": "^0.23.3",
"sisteransi": "^1.0.5",
"yaml": "^2.3.1"
},
"devDependencies": {
"@types/estree": "^1.0.1",
"@types/node": "^20.5.3",
"@types/node": "^20.4.2",
"@types/prompts": "^2.4.4"
},
"publishConfig": {

View File

@@ -1,5 +1,6 @@
import { Command } from 'commander';
import ConfigsProcessor from './configsProcessor.js';
import configs from './configs.js';
import Workspace from './workspace.js';
import c from 'picocolors';
import path from 'node:path';
@@ -7,8 +8,8 @@ import { createSpinner } from 'nanospinner';
import count from './lib/count.js';
import prompts from 'prompts';
import ConfigsFile from './configsFile.js';
import cardinal from 'cardinal';
import { erase } from 'sisteransi';
import * as cardinal from 'cardinal';
import ansi from 'sisteransi';
import PackageInstaller from './packageInstaller.js';
import notNull from './lib/notNull.js';
@@ -21,7 +22,6 @@ export default class Cli {
/** @type {import('./types').CliArgs} */
args = {
dir: process.cwd(),
configs: [],
};
/**
@@ -29,7 +29,6 @@ export default class Cli {
*/
constructor(args) {
this.#program
.argument('[url-to-config]')
.option('--packages <string...>')
.option('--dir <path>', undefined)
.option('--merge-to-root')
@@ -45,13 +44,13 @@ export default class Cli {
this.args.dir = !this.args.dir.startsWith('/')
? path.join(process.cwd(), this.args.dir)
: this.args.dir;
}
async run() {
process.chdir(this.args.dir);
const configs = this.args.configs;
const spinner = createSpinner('Detecting workspace configuration');
const processor = new ConfigsProcessor({ configs });
@@ -72,7 +71,7 @@ export default class Cli {
c.dim(`${count.packagesWithConfigs(packages)} configs founded\n`),
});
const merge = this.args.mergeToRoot !== undefined ? this.args.mergeToRoot : packages.length > 1 ?
const merge = this.args.mergeToRoot ?? packages.length > 1 ?
/** @type {{merge: boolean}} */
(await prompts({
name: 'merge',
@@ -110,7 +109,7 @@ export default class Cli {
initial: true,
})).write;
stdout.write(erase.lines(pkg.configFile.content.split('\n').length + 2));
stdout.write(ansi.erase.lines(pkg.configFile.content.split('\n').length + 2));
if (shouldWrite) await fileHandler.write(pkg.configFile.path, pkg.configFile.content);
@@ -125,7 +124,7 @@ export default class Cli {
(await prompts({
name: 'install',
message:
`Would you like to ESLit to install the npm packages with ${c.green(installer.packageManager.name)}?\n${c.reset(c.dim(` Packages to install: ${[...new Set([...packagesMap.values()])].join(' ')}\n`))}`,
`Would you like to ESLit to install the npm packages with ${c.green(installer.packageManager.name)}?`,
choices: [
{ title: 'Yes, install all packages', value: true, description: installer.packageManager.description },
{ title: 'No, I will install them manually', value: false },
@@ -145,9 +144,6 @@ export default class Cli {
type: 'select',
});
installer.packageManager = installer.packageManagers[prompt.manager];
if (!installer.packageManager) throw console.log(c.red('You must select a package manager'));
installPkgs = true;
}

View File

@@ -1,6 +1,6 @@
/** @type {import('@eslegant/cli').Config[]} */
const cliConfig = [
/** @type {import('./types').Config[]} */
export default [
{
name: 'framework',
type: 'multiple',
@@ -31,4 +31,3 @@ const cliConfig = [
}],
},
];
export default cliConfig;

View File

@@ -1,6 +1,6 @@
import path from 'node:path';
import notNull from './lib/notNull.js';
import { parse, prettyPrint } from 'recast';
import * as recast from 'recast';
import fs from 'node:fs/promises';
import { existsSync } from 'node:fs';
import astUtils from './lib/astUtils.js';
@@ -160,7 +160,7 @@ export default class ConfigsWriter {
/** @type {{program: Program}} */
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
const { program: exportTemplateAst } = parse([
const { program: exportTemplateAst } = recast.parse([
'/** @type {import(\'eslint\').Linter.FlatConfig[]} */',
'export default [',
'',
@@ -304,7 +304,7 @@ export default class ConfigsWriter {
/** @type {{program: Program}} */
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const { program: ast } = parse(existingConfig, { parser: (await import('recast/parsers/babel.js')) });
const { program: ast } = recast.parse(existingConfig, { parser: (await import('recast/parsers/babel.js')) });
await this.addDefaultExport(ast);
@@ -327,7 +327,7 @@ export default class ConfigsWriter {
this.addElementsToExport(ast, elements);
this.addPackageImports(ast, config.imports);
const finalCode = prettyPrint(ast, { parser: (await import('recast/parsers/babel.js')) }).code;
const finalCode = recast.prettyPrint(ast, { parser: (await import('recast/parsers/babel.js')) }).code;
return finalCode;
}

View File

@@ -3,7 +3,7 @@ import path from 'node:path';
import glob from 'picomatch';
import prompts from 'prompts';
import c from 'picocolors';
import capitalize from './lib/capitalize.js';
import str from './lib/str.js';
export default class ConfigsProcessor {
/** @type {string} */
@@ -75,13 +75,13 @@ export default class ConfigsProcessor {
for (const config of configs) {
/** @type {import('prompts').Choice[]} */
const configChoices = config.options.map(option => {return { title: `${capitalize(option.name)}`, value: option.name };});
const configChoices = config.options.map(option => {return { title: `${str.capitalize(option.name)}`, value: option.name };});
/** @type {Record<string, string[]>} */
const selectedOptions = await prompts({
name: config.name,
type: config.type === 'multiple' ? 'multiselect' : 'select',
message: capitalize(config.name),
message: str.capitalize(config.name),
choices: config.type === 'confirm' ? [
{
title: 'Yes',
@@ -96,7 +96,7 @@ export default class ConfigsProcessor {
instructions: instructions + c.dim(c.italic('\nSelect none if you don\'t want to use this configuration\n')),
});
if (!selectedOptions[config.name]) continue;
if (selectedOptions[config.name] === null) continue;
if (selectedOptions[config.name].length === 0) continue;

4
packages/cli/src/index.js Executable file
View File

@@ -0,0 +1,4 @@
import Cli from './cli.js';
const cli = new Cli();
await cli.run();

View File

@@ -1,4 +1,4 @@
import { parse, print } from 'recast';
import * as recast from 'recast';
/**
* @typedef {(
@@ -23,7 +23,7 @@ import { parse, print } from 'recast';
* @param {VariableInit} [init] Initial value of the variable
* @returns {VariableDeclaration} The variable declaration ast node object
*/
function createVariable(identifier, kind = 'const', init) {
export function createVariable(identifier, kind = 'const', init) {
return {
type: 'VariableDeclaration',
kind,
@@ -39,10 +39,10 @@ function createVariable(identifier, kind = 'const', init) {
* @param {string} string The expression in string
* @returns {ExpressionOrIdentifier | undefined} The expression or identifier node of that string (undefined if string is not a expression)
*/
function stringToExpression(string) {
export function stringToExpression(string) {
/** @type {ExpressionOrIdentifier} */
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
const e = parse(string).program.body[0].expression;
const e = recast.parse(string).program.body[0].expression;
if (['MemberExpression', 'Identifier', 'CallExpression', 'NewExpression'].includes(e.type)) return e;
else return undefined;
}
@@ -52,7 +52,7 @@ function stringToExpression(string) {
* @param {ExpressionOrIdentifier | SpreadElement} element The element to be search
* @returns {ExpressionOrIdentifier | undefined} The element of the array founded, undefined if it isn't found
*/
function findInArray(array, element) {
export function findInArray(array, element) {
/** @type {ExpressionOrIdentifier[]} */
// @ts-expect-error The array should have just tge type above
@@ -66,8 +66,8 @@ function findInArray(array, element) {
return n;
}).filter(n => n && n.type === element.type);
const toStringElements = filteredElements.map(n => print(n).code);
const toStringElement = print(element).code;
const toStringElements = filteredElements.map(n => recast.print(n).code);
const toStringElement = recast.print(element).code;
const idx = toStringElements.findIndex(e => e === toStringElement);
return filteredElements[idx];
@@ -77,7 +77,7 @@ function findInArray(array, element) {
* @param {ExpressionOrIdentifier} expression The expression to be spread
* @returns {SpreadElement} The spread element node
*/
function toSpreadElement(expression) {
export function toSpreadElement(expression) {
return {
type: 'SpreadElement',
argument: expression,
@@ -95,7 +95,7 @@ function toSpreadElement(expression) {
* @param {import('estree').ImportDeclaration} [body] The body of the import declaration to start with
* @returns {ImportDeclarationHelper} A helper object for manipulating the import declaration
*/
function createImportDeclaration(source, defaultImported, body) {
export function createImportDeclaration(source, defaultImported, body) {
const helper = {
/** @type {import('estree').ImportDeclaration} */
body: body ?? {
@@ -161,11 +161,10 @@ function createImportDeclaration(source, defaultImported, body) {
}
const astUtils = {
export default {
createVariable,
stringToExpression,
toSpreadElement,
findInArray,
createImportDeclaration,
};
export default astUtils;

View File

@@ -9,5 +9,4 @@ function packagesWithConfigs(packages) {
).reduce((partial, sum) => partial + sum, 0);
}
const count = { packagesWithConfigs };
export default count;
export default { packagesWithConfigs };

View File

@@ -3,6 +3,8 @@
* @param {string} str - The string to capitalize
* @returns {string} The capitalized string
*/
export default function capitalize(str) {
function capitalize(str) {
return str[0].toUpperCase() + str.slice(1);
}
export default { capitalize };

View File

@@ -1,10 +1,11 @@
import { existsSync, readFileSync } from 'node:fs';
import { existsSync } from 'node:fs';
import { join } from 'node:path';
import { exec } from 'node:child_process';
import { createSpinner } from 'nanospinner';
import c from 'picocolors';
import { parse, prettyPrint } from 'recast';
import * as recast from 'recast';
import { readFile, writeFile } from 'node:fs/promises';
import { readFileSync } from 'node:fs';
/**
@@ -77,7 +78,7 @@ class DenoHandler {
const configFile = await readFile(configPath, 'utf8');
/** @type {{program: import('estree').Program}}*/
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const { program: ast } = parse(configFile, { parser: (await import('recast/parsers/babel.js')) });
const { program: ast } = recast.parse(configFile, { parser: (await import('recast/parsers/babel.js')) });
ast.body.map((node) => {
if (node.type !== 'ImportDeclaration') return node;
@@ -88,7 +89,7 @@ class DenoHandler {
return node;
});
await writeFile(configPath, prettyPrint(ast).code, 'utf-8');
await writeFile(configPath, recast.prettyPrint(ast).code, 'utf-8');
console.log(c.green('Added npm: specifier to dependencies'));

View File

@@ -1,20 +1,15 @@
import type { OptionValues } from 'commander';
type PackageManagerName = 'npm' | 'pnpm' | 'yarn' | 'bun' | 'deno';
export type PackageManagerName = 'npm' | 'pnpm' | 'yarn' | 'bun' | 'deno';
type CliArgs = {
export type CliArgs = {
packages?: string[]
mergeToRoot?: boolean
installPkgs?: boolean | PackageManagerName
dir: string
configs: Config[]
} & OptionValues;
interface PackageManagerHandler {
install(path: string, packages: string[]): Promise<void> | void
}
type Config = {
export type Config = {
name: string
type: 'single' | 'multiple'
manual?: boolean
@@ -42,7 +37,7 @@ type Config = {
}]
};
interface Package {
export interface Package {
root?: boolean
name: string
path: string
@@ -52,7 +47,7 @@ interface Package {
configFile?: ConfigFile
}
interface ConfigFile {
export interface ConfigFile {
path: string
imports: Map<string, string | (string | [string, string])[]>
configs: string[]
@@ -61,4 +56,6 @@ interface ConfigFile {
content?: string
}
export type { PackageManagerName, PackageManagerHandler, CliArgs, Config, Package, ConfigFile };
export interface PackageManagerHandler {
install(path: string, packages: string[]): Promise<void> | void
}

View File

@@ -2,6 +2,7 @@ import fs from 'node:fs/promises';
import { existsSync } from 'node:fs';
import YAML from 'yaml';
import path, { join } from 'node:path';
import glob from 'picomatch';
import picomatch from 'picomatch';
@@ -84,7 +85,7 @@ export default class Workspace {
const paths = (await fs.readdir(directory))
.map((f) => path.normalize(join(directory, f)))
.filter((p) => !picomatch.isMatch(p, ignores));
.filter((p) => !glob.isMatch(p, ignores));
/** @type {string[]} */
const files = [];

56
packages/config/index.d.ts vendored Normal file
View 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[]
}>;

View File

@@ -1,5 +1,5 @@
{
"extends": "../../tsconfig.json",
"exclude": ["./node_modules/**", "./dist/**"],
"include": ["**/*.ts", "**/*.js"],
"include": ["./index.d.ts", "./src/**/*.ts", "./src/**/*.js"],
}

View File

@@ -1,5 +1,5 @@
{
"name": "@eslegant/js",
"name": "@eslit/config",
"version": "0.2.0",
"description": "",
"main": "index.js",
@@ -9,11 +9,11 @@
"src",
"index.d.ts"
],
"homepage": "https://github.com/LoredDev/ESLegant",
"homepage": "https://github.com/LoredDev/ESLit",
"exports": {
"default": "./src/index.js",
"import": "./src/index.js",
"types": "./src/index.d.ts"
"types": "./index.d.ts"
},
"type": "module",
"types": "./src/index.js",
@@ -22,9 +22,9 @@
"lint": "eslint ."
},
"repository": {
"directory": "configs/js",
"directory": "packages/config",
"type": "git",
"url": "https://github.com/LoredDev/ESLegant"
"url": "https://github.com/LoredDev/ESLit"
},
"author": {
"email": "contact.guz013@gmail.com",
@@ -34,24 +34,17 @@
"license": "MIT",
"devDependencies": {
"@types/eslint__js": "^8.42.0",
"@types/node": "^20.5.3",
"eslint": "^8.47.0",
"@types/node": "^20.4.2",
"eslint": "^8.45.0",
"typescript": "^5.1.6"
},
"dependencies": {
"@eslint/eslintrc": "^2.1.2",
"@eslint/js": "^8.47.0",
"@typescript-eslint/eslint-plugin": "^6.4.1",
"@typescript-eslint/parser": "^6.4.1",
"eslint-import-resolver-typescript": "^3.6.0",
"eslint-plugin-i": "2.28.0-2",
"eslint-plugin-jsdoc": "^46.5.0",
"eslint-plugin-n": "^16.0.2",
"eslint-plugin-no-secrets": "^0.8.9",
"eslint-plugin-perfectionist": "^2.0.0",
"eslint-plugin-security": "^1.7.1",
"eslint-plugin-unicorn": "^48.0.1",
"globals": "^13.21.0"
"@eslint/eslintrc": "^2.1.0",
"@eslint/js": "^8.45.0",
"@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^6.1.0",
"eslint-plugin-jsdoc": "^46.4.4",
"globals": "^13.20.0"
},
"peerDependencies": {
"eslint": "^8.45.0",

View File

@@ -0,0 +1,26 @@
import type { ESLint } from 'eslint';
/**
* @see {@link https://www.npmjs.org/package/eslint-plugin-jsdoc npm package}
*
* @summary JSDoc specific linting rules for ESLint.
*
* ---
* **Note:** Types in this project where overridden to be compatible with ESLint new flat
* config types. ESlint already has backwards compatibility for plugins not created in the
* new flat config.
*/
declare module 'eslint-plugin-jsdoc' {
interface jsDocESlintPlugin extends ESLint.Plugin {
configs: ESLint.Plugin['configs'] & {
recommended: ESLint.ConfigData
'recommended-error': ESLint.ConfigData
'recommended-typescript': ESLint.ConfigData
'recommended-typescript-error': ESLint.ConfigData
'recommended-typescript-flavor': ESLint.ConfigData
'recommended-typescript-flavor-error': ESLint.ConfigData
}
}
declare const plugin: jsDocESlintPlugin;
export default plugin;
}

10
packages/config/src/@types/globals.d.ts vendored Normal file
View File

@@ -0,0 +1,10 @@
declare module 'globals' {
const globals: {
builtin: Record<string, boolean>
browser: Record<string, boolean>
node: Record<string, boolean>
nodeBuiltin: Record<string, boolean>
commonjs: Record<string, boolean>
};
export default globals;
}

View File

@@ -1,53 +1,46 @@
/**
* @file
* Type declaration for the `@typescript-eslint/eslint-plugin` and
* `@typescript-eslint/parser` packages in a attempt to make it
* compatible with the new flat config.
* @license MIT
* @author Guz013 <contact.guz013@gmail.com> (https://guz.one)
*/
import type { ESLint, Linter } from 'eslint';
/**
* @see {@link https://www.npmjs.com/package/@typescript-eslint/eslint-plugin npm package}
*
* @summary An ESLint plugin which provides lint rules for TypeScript codebases.
*
* ---
* **Note:** Types in this project where overridden to be compatible with ESLint
* new flat config types. ESlint already has backwards compatibility for plugins
* not created in the new flat config.
* @see {@link https://www.npmjs.com/package/@typescript-eslint/eslint-plugin npm package}
* **Note:** Types in this project where overridden to be compatible with ESLint new flat
* config types. ESlint already has backwards compatibility for plugins not created in the
* new flat config.
*/
declare module '@typescript-eslint/eslint-plugin' {
interface typescriptEslintPlugin extends ESLint.Plugin {
configs: {
'eslint-recommended': {
rules: Linter.RulesRecord,
},
recommended: {
rules: Linter.RulesRecord,
},
rules: Linter.RulesRecord
}
'recommended-requiring-type-checking': {
rules: Linter.RulesRecord,
},
rules: Linter.RulesRecord
}
'eslint-recommended': {
rules: Linter.RulesRecord
}
strict: {
rules: Linter.RulesRecord,
},
},
rules: Linter.RulesRecord
}
}
}
declare const plugin: typescriptEslintPlugin;
export default plugin;
}
/**
* @summary An ESLint parser which leverages TypeScript ESTree to
* allow for ESLint to lint TypeScript source code.
* @see {@link https://www.npmjs.com/package/@typescript-eslint/parser npm package}
*
* @summary An ESLint parser which leverages TypeScript ESTree to allow for ESLint
* to lint TypeScript source code.
*
* ---
* **Note:** Types in this project where overridden to be compatible
* with ESLint new flat config types. ESlint already has backwards
* compatibility for parsers not created in the new flat config.
* @see {@link https://www.npmjs.com/package/@typescript-eslint/parser npm package}
* **Note:** Types in this project where overridden to be compatible with ESLint new flat
* config types. ESlint already has backwards compatibility for parsers not created in the
* new flat config.
*/
declare module '@typescript-eslint/parser' {
declare const parser: Linter.ParserModule;

View 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;

View 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 };

View File

@@ -0,0 +1,97 @@
/**
* Formatting rules/configuration overrides for Javascript and Typescript
*
* @type {Readonly<import('eslint').Linter.FlatConfig>}
*/
const config = {
files: ['**/*.js', '**/*.cjs', '**/*.mjs', '**/*.ts', '**/*.cts', '**/*.mts'],
rules: {
// Formatting rules
'brace-style': 'off',
'@typescript-eslint/brace-style': ['error', 'stroustrup', { allowSingleLine: true }],
'comma-dangle': 'off',
'@typescript-eslint/comma-dangle': ['error', 'always-multiline'],
'indent': 'off',
'@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,
MemberExpression: 1,
FunctionDeclaration: { parameters: 1, body: 1 },
FunctionExpression: { parameters: 1, body: 1 },
CallExpression: { arguments: 1 },
ArrayExpression: 1,
ObjectExpression: 1,
ImportDeclaration: 1,
flatTernaryExpressions: false,
offsetTernaryExpressions: true,
ignoreComments: false,
ignoredNodes: [
'TemplateLiteral *',
'JSXElement',
'JSXElement > *',
'JSXAttribute',
'JSXIdentifier',
'JSXNamespacedName',
'JSXMemberExpression',
'JSXSpreadAttribute',
'JSXExpressionContainer',
'JSXOpeningElement',
'JSXClosingElement',
'JSXFragment',
'JSXOpeningFragment',
'JSXClosingFragment',
'JSXText',
'JSXEmptyExpression',
'JSXSpreadChild',
'TSTypeParameterInstantiation',
'FunctionExpression > .params[decorators.length > 0]',
'FunctionExpression > .params > :matches(Decorator, :not(:first-child))',
'ClassBody.body > PropertyDefinition[decorators.length > 0] > .key',
],
}],
'keyword-spacing': 'off',
'@typescript-eslint/keyword-spacing': ['error', { before: true, after: true }],
'lines-between-class-members': 'off',
'@typescript-eslint/lines-between-class-members': ['error'],
'no-extra-parens': 'off',
'@typescript-eslint/no-extra-parens': ['error', 'functions'],
'object-curly-spacing': 'off',
'@typescript-eslint/object-curly-spacing': ['error', 'always'],
'quotes': 'off',
'@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.ESLIT_SEMI ?? 'always'],
'space-before-function-paren': 'off',
'@typescript-eslint/space-before-function-paren': ['error', {
anonymous: 'always',
named: 'never',
asyncArrow: 'always',
}],
'space-infix-ops': 'off',
'@typescript-eslint/space-infix-ops': 'error',
},
};
export default config;

View 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 };

View File

@@ -0,0 +1,15 @@
import jsdoc from 'eslint-plugin-jsdoc';
/**
* JSDoc rules overrides
* @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,
},
};
export default config;

View File

@@ -0,0 +1,42 @@
import tsESlint from '@typescript-eslint/eslint-plugin';
import js from '@eslint/js';
/**
* Recommended configuration overrides of ESLit
*
* @type {Readonly<import('eslint').Linter.FlatConfig>}
*/
const config = {
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',
}],
'@typescript-eslint/ban-tslint-comment': 'error',
'@typescript-eslint/no-require-imports': 'error',
// Extension rules
'no-dupe-class-members': 'off',
'@typescript-eslint/no-dupe-class-members': 'error',
'no-invalid-this': 'off',
'@typescript-eslint/no-invalid-this': 'error',
'no-redeclare': 'off',
'@typescript-eslint/no-redeclare': 'error',
'no-use-before-define': 'off',
'@typescript-eslint/no-use-before-define': 'error',
'no-empty-function': 'off',
'@typescript-eslint/no-empty-function': 'error',
},
};
export default config;

View File

@@ -0,0 +1,65 @@
import jsdoc from 'eslint-plugin-jsdoc';
/**
* Typescript specific configuration overrides
*
* @type {Readonly<import('eslint').Linter.FlatConfig>}
*/
const config = {
files: ['**/*.ts', '**/*.cts', '**/*.mts'],
// See plugins['jsdoc'] on index.js for more info on this error
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
rules: {
// See plugins['jsdoc'] on index.js for more info on this error
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
...jsdoc.configs['recommended-typescript-error'].rules,
'@typescript-eslint/adjacent-overload-signatures': 'error',
'@typescript-eslint/array-type': 'error',
'@typescript-eslint/class-literal-property-style': 'error',
'@typescript-eslint/consistent-generic-constructors': 'error',
'@typescript-eslint/consistent-indexed-object-style': 'error',
'@typescript-eslint/consistent-type-assertions': 'error',
'@typescript-eslint/consistent-type-definitions': 'error',
'@typescript-eslint/consistent-type-exports': ['error'],
'@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports', disallowTypeAnnotations: true }],
'@typescript-eslint/no-confusing-non-null-assertion': 'error',
'@typescript-eslint/member-delimiter-style': ['error', { multiline: { delimiter: 'none' } }],
'@typescript-eslint/type-annotation-spacing': 'error',
'@typescript-eslint/no-empty-interface': 'error',
'@typescript-eslint/prefer-for-of': 'error',
'@typescript-eslint/prefer-function-type': 'error',
'@typescript-eslint/prefer-namespace-keyword': 'error',
...(
/** @type {() => import('eslint').Linter.RulesRecord} */
() => {
/** @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 {
'@typescript-eslint/explicit-function-return-type': inferrableTypes === 'always' ? 'off' : 'error',
'@typescript-eslint/no-inferrable-types': inferrableTypes === 'always' ? 'off' : 'error',
};
}
else {
return {
'@typescript-eslint/explicit-function-return-type': inferrableTypes[1].returnValues ? 'off' : 'error',
'@typescript-eslint/no-inferrable-types': [
inferrableTypes[0] === 'always' ? 'off' : 'error',
{
ignoreParameters: inferrableTypes[1].parameters ?? false,
ignoreProperties: inferrableTypes[1].properties ?? false,
},
],
};
}
}
)(),
},
};
export default config;

View File

@@ -0,0 +1,15 @@
import { FlatCompat } from '@eslint/eslintrc';
import javascript from '@eslint/js';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
// mimic CommonJS variables
export const __filename = fileURLToPath(import.meta.url);
export const __dirname = path.dirname(__filename);
export const eslintrc = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: javascript.configs.recommended,
allConfig: javascript.configs.all,
});

View 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';

View 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;

View File

@@ -0,0 +1,4 @@
import defaultPreset from './default.js';
export default { default: defaultPreset };

56
packages/config/src/types.d.ts vendored Normal file
View 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';

View File

@@ -1,4 +0,0 @@
import Cli from '@eslegant/cli';
const cli = new Cli({ configs: (await import('./configs.js')).default, dir: process.cwd() });
await cli.run();

View File

@@ -1,33 +0,0 @@
{
"name": "create-eslegant",
"version": "0.1.0",
"description": "",
"keywords": [],
"author": {
"email": "contact.guz013@gmail.com",
"name": "Gustavo \"Guz\" L. de Mello",
"url": "https://guz.one"
},
"files": [
"./bin.js",
"./configs.js"
],
"dependencies": {
"@eslegant/cli": "workspace:*"
},
"homepage": "https://github.com/LoredDev/ESLegant",
"type": "module",
"repository": {
"directory": "packages/create-eslegant",
"type": "git",
"url": "https://github.com/LoredDev/ESLegant"
},
"bin": "./bin.js",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"devDependencies": {
"@types/node": "^20.5.3"
}
}

View File

@@ -1,4 +0,0 @@
import Cli from '@eslegant/cli';
const cli = new Cli({ configs: (await import('./configs.js')).default, dir: process.cwd() });
await cli.run();

View File

@@ -1,34 +0,0 @@
/** @type {import('@eslegant/cli').Config[]} */
const cliConfig = [
{
name: 'framework',
type: 'multiple',
description: 'The UI frameworks being used in the project',
options: [
{
name: 'svelte',
packages: { 'svelte': 'svelte' },
configs: ['svelte.recommended'],
detect: ['**/*.svelte', 'svelte.config.{js,ts,cjs,cts}'],
},
{
name: 'vue',
packages: { 'vue': ['vue', ['hello', 'world']], 'svelte': ['hello'] },
configs: ['vue.recommended'],
detect: ['nuxt.config.{js,ts,cjs,cts}', '**/*.vue'],
},
],
},
{
name: 'strict',
type: 'confirm',
manual: true,
options: [{
name: 'yes',
packages: { 'eslint': 'config', 'svelte': ['test1'] },
configs: ['config.strict'],
}],
},
];
export default cliConfig;

View File

@@ -1,5 +0,0 @@
{
"extends": "../../tsconfig.json",
"exclude": ["./node_modules/**", "./dist/**"],
"include": ["**/*.ts", "**/*.js"],
}

View File

@@ -1,33 +0,0 @@
{
"name": "eslegant",
"version": "0.1.0",
"description": "",
"keywords": [],
"author": {
"email": "contact.guz013@gmail.com",
"name": "Gustavo \"Guz\" L. de Mello",
"url": "https://guz.one"
},
"files": [
"./bin.js",
"./configs.js"
],
"dependencies": {
"@eslegant/cli": "workspace:*"
},
"homepage": "https://github.com/LoredDev/ESLegant",
"type": "module",
"repository": {
"directory": "packages/eslegant",
"type": "git",
"url": "https://github.com/LoredDev/ESLegant"
},
"bin": "./bin.js",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"devDependencies": {
"@types/node": "^20.5.3"
}
}

1151
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,3 @@
packages:
- 'packages/*'
- 'fixtures/*'
- 'configs/*'

View File

@@ -13,6 +13,6 @@
"alwaysStrict": true,
"outDir": "./dir"
},
"include": ["./eslint.config.js", "./commitlint.config.cjs"],
"include": ["eslint.config.js", "commitlint.config.cjs"],
"exclude": ["./node_modules/**", "./dist/**"]
}