@bastidood/eslint-config 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +44 -2
- package/dist/compose/index.d.mts +52 -0
- package/dist/compose/index.mjs +106 -0
- package/dist/convert-B62YDKje.mjs +1561 -0
- package/dist/core.d.mts +6 -0
- package/dist/core.mjs +61 -0
- package/dist/jsdoc.d.mts +3 -0
- package/dist/jsdoc.mjs +42 -0
- package/dist/node.d.mts +3 -0
- package/dist/node.mjs +25 -0
- package/dist/promise.d.mts +3 -0
- package/dist/promise.mjs +30 -0
- package/dist/unicorn.d.mts +3 -0
- package/dist/unicorn.mjs +146 -0
- package/dist/vitest.d.mts +3 -0
- package/dist/vitest.mjs +100 -0
- package/package.json +50 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Basti Ortiz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,45 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@bastidood/eslint-config`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
ESLint port of `@bastidood/oxlint-config` for projects that Oxlint cannot lint, such as Svelte and Astro.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pnpm add --save-dev @bastidood/eslint-config eslint typescript
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// eslint.config.ts
|
|
15
|
+
import { compose } from '@bastidood/eslint-config';
|
|
16
|
+
import { CORE } from '@bastidood/eslint-config/core';
|
|
17
|
+
import { PROMISE } from '@bastidood/eslint-config/promise';
|
|
18
|
+
import { UNICORN } from '@bastidood/eslint-config/unicorn';
|
|
19
|
+
import { defineConfig } from 'eslint/config';
|
|
20
|
+
|
|
21
|
+
export default defineConfig({ files: ['**/*.ts'] }, compose(CORE, UNICORN, PROMISE));
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
List `CORE` first.
|
|
25
|
+
|
|
26
|
+
## Entry Points
|
|
27
|
+
|
|
28
|
+
| Entry point | Contents |
|
|
29
|
+
| ---------------------------------- | ------------------------------------------------------------ |
|
|
30
|
+
| `@bastidood/eslint-config` | `compose` |
|
|
31
|
+
| `@bastidood/eslint-config/core` | ESLint core, `import`, and `@typescript-eslint` rules |
|
|
32
|
+
| `@bastidood/eslint-config/unicorn` | `unicorn` rules |
|
|
33
|
+
| `@bastidood/eslint-config/promise` | `promise` rules |
|
|
34
|
+
| `@bastidood/eslint-config/node` | Node.js rules |
|
|
35
|
+
| `@bastidood/eslint-config/vitest` | Vitest rules |
|
|
36
|
+
| `@bastidood/eslint-config/jsdoc` | JSDoc rules for documentation that TypeScript does not cover |
|
|
37
|
+
|
|
38
|
+
## Limitations
|
|
39
|
+
|
|
40
|
+
- Prefer `@bastidood/oxlint-config` wherever Oxlint can run.
|
|
41
|
+
- Rules are not configurable. Supply only project-specific settings, such as `files` and globals.
|
|
42
|
+
- No `files` are set. ESLint lints only JavaScript files unless you list others.
|
|
43
|
+
- `typescript-eslint` supports TypeScript up to 6.0. On TypeScript 7, alias `typescript` to `@typescript/typescript6`.
|
|
44
|
+
- Requires ESLint 10.
|
|
45
|
+
- Run ESLint from the directory that contains `tsconfig.json` or a parent directory. Type-aware rules search for `tsconfig.json` only up to the working directory.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Linter } from "eslint";
|
|
2
|
+
export interface RestrictedImportPath {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly importNames?: string[];
|
|
5
|
+
readonly message: string;
|
|
6
|
+
}
|
|
7
|
+
export interface RestrictedImportPattern {
|
|
8
|
+
readonly regex: string;
|
|
9
|
+
readonly message: string;
|
|
10
|
+
}
|
|
11
|
+
export interface RestrictedGlobal {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly message: string;
|
|
14
|
+
}
|
|
15
|
+
export interface RestrictedProperty {
|
|
16
|
+
readonly object: string;
|
|
17
|
+
readonly property: string;
|
|
18
|
+
readonly message: string;
|
|
19
|
+
}
|
|
20
|
+
export interface RestrictedSyntax {
|
|
21
|
+
readonly selector: string;
|
|
22
|
+
readonly message: string;
|
|
23
|
+
}
|
|
24
|
+
/** The same restriction lists as `@bastidood/oxlint-config/restrictions`. */
|
|
25
|
+
export interface Restrictions {
|
|
26
|
+
readonly importPaths?: RestrictedImportPath[];
|
|
27
|
+
readonly importPatterns?: RestrictedImportPattern[];
|
|
28
|
+
readonly globals?: RestrictedGlobal[];
|
|
29
|
+
readonly properties?: RestrictedProperty[];
|
|
30
|
+
readonly syntax?: RestrictedSyntax[];
|
|
31
|
+
}
|
|
32
|
+
export interface ScopedRestrictions {
|
|
33
|
+
readonly files: string[];
|
|
34
|
+
readonly restrictions: Restrictions;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* An entry point: ESLint configuration objects plus the lists that `compose` concatenates, namely the
|
|
38
|
+
* restriction lists and the non-standard file extensions that the TypeScript project service must resolve.
|
|
39
|
+
* `configs` may nest a configuration list one level deep, such as a plugin's `recommended` list.
|
|
40
|
+
*/
|
|
41
|
+
export interface Entry {
|
|
42
|
+
readonly configs?: (Linter.Config | Linter.Config[])[];
|
|
43
|
+
readonly extraFileExtensions?: string[];
|
|
44
|
+
readonly restrictions?: Restrictions;
|
|
45
|
+
readonly scopedRestrictions?: ScopedRestrictions[];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Compose entry points into one ESLint flat configuration for `extends`. Restriction lists are concatenated
|
|
49
|
+
* instead of replaced, and every scoped configuration repeats the top-level restrictions so that it cannot
|
|
50
|
+
* drop them.
|
|
51
|
+
*/
|
|
52
|
+
export declare function compose(...entries: Entry[]): Linter.Config[];
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// ../oxlint/src/restrictions/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Restriction lists accumulated across entry points for the list-valued `no-restricted-*` rules, which Oxlint and
|
|
4
|
+
* ESLint replace instead of merge. Each list is stored as the final rule entry with its severity in front, so
|
|
5
|
+
* emitting a rule never copies the list.
|
|
6
|
+
*/
|
|
7
|
+
var RestrictionLists = class RestrictionLists {
|
|
8
|
+
#imports = {
|
|
9
|
+
paths: [],
|
|
10
|
+
patterns: []
|
|
11
|
+
};
|
|
12
|
+
#globals = ["error"];
|
|
13
|
+
#properties = ["error"];
|
|
14
|
+
#syntax = ["error"];
|
|
15
|
+
/** Append every list of an entry point's restrictions. */
|
|
16
|
+
append(restrictions) {
|
|
17
|
+
appendAll(this.#imports.paths, restrictions.importPaths);
|
|
18
|
+
appendAll(this.#imports.patterns, restrictions.importPatterns);
|
|
19
|
+
appendAll(this.#globals, restrictions.globals);
|
|
20
|
+
appendAll(this.#properties, restrictions.properties);
|
|
21
|
+
appendAll(this.#syntax, restrictions.syntax);
|
|
22
|
+
}
|
|
23
|
+
/** Copy these lists so that a scoped override can extend them without changing the top-level rules. */
|
|
24
|
+
copy() {
|
|
25
|
+
const copy = new RestrictionLists();
|
|
26
|
+
appendAll(copy.#imports.paths, this.#imports.paths);
|
|
27
|
+
appendAll(copy.#imports.patterns, this.#imports.patterns);
|
|
28
|
+
appendAll(copy.#globals, this.#globals.values().drop(1));
|
|
29
|
+
appendAll(copy.#properties, this.#properties.values().drop(1));
|
|
30
|
+
appendAll(copy.#syntax, this.#syntax.values().drop(1));
|
|
31
|
+
return copy;
|
|
32
|
+
}
|
|
33
|
+
importsRule() {
|
|
34
|
+
const { paths, patterns } = this.#imports;
|
|
35
|
+
return paths.length === 0 && patterns.length === 0 ? null : ["error", this.#imports];
|
|
36
|
+
}
|
|
37
|
+
globalsRule() {
|
|
38
|
+
return this.#globals.length === 1 ? null : this.#globals;
|
|
39
|
+
}
|
|
40
|
+
propertiesRule() {
|
|
41
|
+
return this.#properties.length === 1 ? null : this.#properties;
|
|
42
|
+
}
|
|
43
|
+
syntaxRule() {
|
|
44
|
+
return this.#syntax.length === 1 ? null : this.#syntax;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
function appendAll(target, items) {
|
|
48
|
+
if (typeof items === "undefined") return;
|
|
49
|
+
for (const item of items) target.push(item);
|
|
50
|
+
}
|
|
51
|
+
// src/compose/index.ts
|
|
52
|
+
/**
|
|
53
|
+
* Compose entry points into one ESLint flat configuration for `extends`. Restriction lists are concatenated
|
|
54
|
+
* instead of replaced, and every scoped configuration repeats the top-level restrictions so that it cannot
|
|
55
|
+
* drop them.
|
|
56
|
+
*/
|
|
57
|
+
function compose(...entries) {
|
|
58
|
+
const configs = [];
|
|
59
|
+
const extraFileExtensions = [];
|
|
60
|
+
const restrictions = new RestrictionLists();
|
|
61
|
+
for (const { configs: entryConfigs, extraFileExtensions: entryExtensions, restrictions: entryRestrictions } of entries) {
|
|
62
|
+
appendConfigs(configs, entryConfigs);
|
|
63
|
+
if (typeof entryExtensions !== "undefined") for (const extension of entryExtensions) extraFileExtensions.push(extension);
|
|
64
|
+
if (typeof entryRestrictions !== "undefined") restrictions.append(entryRestrictions);
|
|
65
|
+
}
|
|
66
|
+
configs.push({
|
|
67
|
+
name: "@bastidood/eslint-config/restrictions",
|
|
68
|
+
rules: restrictionRules(restrictions)
|
|
69
|
+
});
|
|
70
|
+
for (const { scopedRestrictions } of entries) {
|
|
71
|
+
if (typeof scopedRestrictions === "undefined") continue;
|
|
72
|
+
for (const { files, restrictions: scoped } of scopedRestrictions) {
|
|
73
|
+
const lists = restrictions.copy();
|
|
74
|
+
lists.append(scoped);
|
|
75
|
+
configs.push({
|
|
76
|
+
name: "@bastidood/eslint-config/scoped-restrictions",
|
|
77
|
+
files,
|
|
78
|
+
rules: restrictionRules(lists)
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (extraFileExtensions.length > 0) configs.push({
|
|
83
|
+
name: "@bastidood/eslint-config/project-service",
|
|
84
|
+
languageOptions: { parserOptions: { extraFileExtensions } }
|
|
85
|
+
});
|
|
86
|
+
return configs;
|
|
87
|
+
}
|
|
88
|
+
/** Append an entry point's configurations, flattening nested configuration lists one level. */
|
|
89
|
+
function appendConfigs(target, configs) {
|
|
90
|
+
if (typeof configs === "undefined") return;
|
|
91
|
+
for (const config of configs) if (Array.isArray(config)) for (const nested of config) target.push(nested);
|
|
92
|
+
else target.push(config);
|
|
93
|
+
}
|
|
94
|
+
function restrictionRules(lists) {
|
|
95
|
+
const rules = {};
|
|
96
|
+
const imports = lists.importsRule();
|
|
97
|
+
if (imports !== null) rules["no-restricted-imports"] = imports;
|
|
98
|
+
const globals = lists.globalsRule();
|
|
99
|
+
if (globals !== null) rules["no-restricted-globals"] = globals;
|
|
100
|
+
const properties = lists.propertiesRule();
|
|
101
|
+
if (properties !== null) rules["no-restricted-properties"] = properties;
|
|
102
|
+
const syntax = lists.syntaxRule();
|
|
103
|
+
if (syntax !== null) rules["no-restricted-syntax"] = syntax;
|
|
104
|
+
return rules;
|
|
105
|
+
}
|
|
106
|
+
export { compose };
|