@heyq02/rslint-config 0.0.2 → 0.0.3-beta.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/README.md +90 -30
- package/dist/configs/de-morgan.d.ts +5 -0
- package/dist/configs/eslint-comments.d.ts +5 -0
- package/dist/configs/imports.d.ts +9 -3
- package/dist/configs/index.d.ts +5 -0
- package/dist/configs/regexp.d.ts +5 -0
- package/dist/configs/sort-imports.d.ts +42 -0
- package/dist/configs/unused-imports.d.ts +5 -0
- package/dist/index.js +228 -28
- package/dist/plugin-utils.d.ts +3 -0
- package/dist/types.d.ts +112 -0
- package/package.json +27 -11
package/README.md
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# @heyq02/rslint-config
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[](https://npmjs.com/package/@heyq02/rslint-config)
|
|
6
|
+
[](https://npm.chart.dev/@heyq02/rslint-config)
|
|
7
|
+
[](https://github.com/heyq02/rslint-config/blob/main/LICENSE)
|
|
8
|
+
|
|
9
|
+
<!-- /automd -->
|
|
6
10
|
|
|
7
11
|
Opinionated [Rslint](https://rslint.rs/) flat-config preset, structured like [`@sxzz/eslint-config`](https://github.com/sxzz/eslint-config) and built on `@rslint/core` native presets.
|
|
8
12
|
|
|
@@ -11,6 +15,8 @@ Opinionated [Rslint](https://rslint.rs/) flat-config preset, structured like [`@
|
|
|
11
15
|
- One-line config via `heyq02()`
|
|
12
16
|
- JavaScript + TypeScript presets (`recommended` / `strict` / type-checked / stylistic)
|
|
13
17
|
- Built-in Unicorn, import, Node, and Promise rules
|
|
18
|
+
- Import sorting via `import/order` with an [Oxfmt `sortImports`](https://oxc.rs/docs/guide/usage/formatter/sorting.html)-shaped API
|
|
19
|
+
- Community plugins (Rslint-compatible): unused-imports, regexp, de-morgan, eslint-comments
|
|
14
20
|
- Optional React, React Hooks, JSX a11y, Jest, and Rstest (auto-detected)
|
|
15
21
|
- Ignores common build artifacts (`dist`, `coverage`, lockfiles, …)
|
|
16
22
|
- Special-case overrides for CLIs, tests, config files, and components
|
|
@@ -52,28 +58,72 @@ export default heyq02(
|
|
|
52
58
|
|
|
53
59
|
### Options
|
|
54
60
|
|
|
55
|
-
| Option
|
|
56
|
-
|
|
|
57
|
-
| `typescript`
|
|
58
|
-
| `javascript`
|
|
59
|
-
| `unicorn`
|
|
60
|
-
| `imports`
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
61
|
+
| Option | Default | Description |
|
|
62
|
+
| ---------------- | ------------------- | --------------------------------------------------------------------------------------------- |
|
|
63
|
+
| `typescript` | auto (`typescript`) | `true` / `false` / `{ typeChecked, strict, stylistic, projectService }` |
|
|
64
|
+
| `javascript` | `true` | JavaScript recommended + opinionated rules |
|
|
65
|
+
| `unicorn` | `true` | Unicorn recommended + overrides |
|
|
66
|
+
| `imports` | `true` | Import recommended + no-default-export, etc. |
|
|
67
|
+
| `sortImports` | `true` | `true` / `false` / Oxfmt-like `{ groups, newlinesBetween, customGroups, … }` → `import/order` |
|
|
68
|
+
| `node` | `true` (`module`) | `true` / `'module'` / `'script'` / `'mixed'` |
|
|
69
|
+
| `promise` | `true` | Promise recommended (relaxed for async/await) |
|
|
70
|
+
| `react` | auto (`react`) | React + React Hooks (+ jsx-a11y) |
|
|
71
|
+
| `jsxA11y` | with react | JSX accessibility rules |
|
|
72
|
+
| `jest` | auto (`jest`) | Jest recommended + style |
|
|
73
|
+
| `rstest` | auto (`rstest`) | Rstest recommended |
|
|
74
|
+
| `unusedImports` | `true` | `eslint-plugin-unused-imports` (autofix unused imports) |
|
|
75
|
+
| `regexp` | `true` | `eslint-plugin-regexp` |
|
|
76
|
+
| `deMorgan` | `true` | `eslint-plugin-de-morgan` |
|
|
77
|
+
| `eslintComments` | `true` | `@eslint-community/eslint-plugin-eslint-comments` |
|
|
78
|
+
| `ignores` | `[]` | Extra global ignore patterns |
|
|
79
|
+
|
|
80
|
+
### Sort imports
|
|
81
|
+
|
|
82
|
+
Enabled by default (when `imports` is on). Options mirror Oxfmt [`sortImports`](https://oxc.rs/docs/guide/usage/formatter/sorting.html) where Rslint can enforce them via [`import/order`](https://rslint.rs/rules/import/order):
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
export default heyq02({
|
|
86
|
+
sortImports: {
|
|
87
|
+
groups: [
|
|
88
|
+
'type',
|
|
89
|
+
['builtin', 'external'],
|
|
90
|
+
'internal',
|
|
91
|
+
['parent', 'sibling', 'index'],
|
|
92
|
+
'unknown',
|
|
93
|
+
],
|
|
94
|
+
newlinesBetween: true,
|
|
95
|
+
internalPattern: ['~/', '@/', '#'],
|
|
96
|
+
customGroups: [
|
|
97
|
+
{
|
|
98
|
+
groupName: 'react-libs',
|
|
99
|
+
elementNamePattern: ['react', 'react-**'],
|
|
100
|
+
group: 'external',
|
|
101
|
+
position: 'before',
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
order: 'asc',
|
|
105
|
+
ignoreCase: true,
|
|
106
|
+
named: true,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
| Oxfmt option | This package | Notes |
|
|
112
|
+
| ------------------------------------------- | ----------------- | --------------------------------------------------------------------------------------------------- |
|
|
113
|
+
| `groups` | `groups` | Uses `import/order` names (`builtin`, `type`, …), not perfectionist selectors (`value-builtin`) |
|
|
114
|
+
| `newlinesBetween` | `newlinesBetween` | `boolean` → `always` / `never`; per-group `{ newlinesBetween }` markers unsupported |
|
|
115
|
+
| `customGroups` | `customGroups` | Mapped to `pathGroups` (`group` + `position` required conceptually; defaults `external` / `before`) |
|
|
116
|
+
| `internalPattern` | `internalPattern` | Glob-like prefixes → `import/internal-regex` |
|
|
117
|
+
| `order` / `ignoreCase` | same | → `alphabetize` |
|
|
118
|
+
| `sortSideEffects` | `sortSideEffects` | → `warnOnUnassignedImports` |
|
|
119
|
+
| `partitionByComment` / `partitionByNewline` | — | Not supported by `import/order` |
|
|
120
|
+
|
|
121
|
+
If Oxfmt already sorts imports, set `sortImports: false` to avoid fighting the formatter.
|
|
68
122
|
|
|
69
123
|
### Presets
|
|
70
124
|
|
|
71
125
|
```ts
|
|
72
|
-
import {
|
|
73
|
-
presetJavaScript,
|
|
74
|
-
presetBasic,
|
|
75
|
-
presetAll,
|
|
76
|
-
} from '@heyq02/rslint-config';
|
|
126
|
+
import { presetJavaScript, presetBasic, presetAll } from '@heyq02/rslint-config';
|
|
77
127
|
|
|
78
128
|
export default presetBasic();
|
|
79
129
|
```
|
|
@@ -85,18 +135,28 @@ pnpm install
|
|
|
85
135
|
pnpm run build
|
|
86
136
|
pnpm run lint
|
|
87
137
|
pnpm run typecheck
|
|
88
|
-
pnpm
|
|
138
|
+
pnpm run format # automd + vp fmt (Oxfmt via Vite+)
|
|
139
|
+
pnpm run check # format:check + rslint + tsc
|
|
140
|
+
pnpm release # bumpp → tag v* → GitHub Release + npm publish
|
|
89
141
|
```
|
|
90
142
|
|
|
91
143
|
## License
|
|
92
144
|
|
|
93
|
-
|
|
145
|
+
<!-- automd:contributors license=MIT author="heyq02" -->
|
|
146
|
+
|
|
147
|
+
Published under the [MIT](https://github.com/heyq02/rslint-config/blob/main/LICENSE) license.
|
|
148
|
+
Made by [@heyq02](https://github.com/heyq02) and [community](https://github.com/heyq02/rslint-config/graphs/contributors) 💛
|
|
149
|
+
<br><br>
|
|
150
|
+
<a href="https://github.com/heyq02/rslint-config/graphs/contributors">
|
|
151
|
+
<img src="https://contrib.rocks/image?repo=heyq02/rslint-config" />
|
|
152
|
+
</a>
|
|
153
|
+
|
|
154
|
+
<!-- /automd -->
|
|
155
|
+
|
|
156
|
+
<!-- automd:with-automd -->
|
|
157
|
+
|
|
158
|
+
---
|
|
94
159
|
|
|
95
|
-
|
|
160
|
+
_🤖 auto updated with [automd](https://automd.unjs.io)_
|
|
96
161
|
|
|
97
|
-
|
|
98
|
-
[npm-version-href]: https://npmjs.com/package/@heyq02/rslint-config
|
|
99
|
-
[npm-downloads-src]: https://img.shields.io/npm/dm/@heyq02/rslint-config
|
|
100
|
-
[npm-downloads-href]: https://www.npmcharts.com/compare/@heyq02/rslint-config?interval=30
|
|
101
|
-
[unit-test-src]: https://github.com/heyq02/rslint-config/actions/workflows/unit-test.yml/badge.svg
|
|
102
|
-
[unit-test-href]: https://github.com/heyq02/rslint-config/actions/workflows/unit-test.yml
|
|
162
|
+
<!-- /automd -->
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import type { TypedFlatConfig } from '../types.js';
|
|
2
|
-
export
|
|
1
|
+
import type { SortImportsOptions, TypedFlatConfig } from '../types.js';
|
|
2
|
+
export interface ImportsOptions {
|
|
3
3
|
typescript?: boolean;
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Enable Oxfmt-shaped import sorting via `import/order`.
|
|
6
|
+
* @default true
|
|
7
|
+
*/
|
|
8
|
+
sortImports?: boolean | SortImportsOptions;
|
|
9
|
+
}
|
|
10
|
+
export declare const imports: (options?: ImportsOptions) => TypedFlatConfig[];
|
package/dist/configs/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export * from './de-morgan.js';
|
|
2
|
+
export * from './eslint-comments.js';
|
|
1
3
|
export * from './ignores.js';
|
|
2
4
|
export * from './imports.js';
|
|
3
5
|
export * from './javascript.js';
|
|
@@ -5,7 +7,10 @@ export * from './jest.js';
|
|
|
5
7
|
export * from './node.js';
|
|
6
8
|
export * from './promise.js';
|
|
7
9
|
export * from './react.js';
|
|
10
|
+
export * from './regexp.js';
|
|
8
11
|
export * from './rstest.js';
|
|
12
|
+
export * from './sort-imports.js';
|
|
9
13
|
export * from './special-cases.js';
|
|
10
14
|
export * from './typescript.js';
|
|
11
15
|
export * from './unicorn.js';
|
|
16
|
+
export * from './unused-imports.js';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ImportOrderOptions } from '@rslint/core';
|
|
2
|
+
import type { SortImportsCustomGroup, SortImportsOptions } from '../types.js';
|
|
3
|
+
/** eslint-plugin-import / Rslint `import/order` group names. */
|
|
4
|
+
export type ImportOrderGroup = 'builtin' | 'external' | 'internal' | 'unknown' | 'parent' | 'sibling' | 'index' | 'object' | 'type';
|
|
5
|
+
type ImportOrderConfig = NonNullable<ImportOrderOptions[0]>;
|
|
6
|
+
/**
|
|
7
|
+
* Default group order inspired by Oxfmt / perfectionist `sort-imports`
|
|
8
|
+
* (type-first, then builtin+external, internal, relative, unknown).
|
|
9
|
+
*
|
|
10
|
+
* Mapped onto `import/order` groups — modifier-selectors like
|
|
11
|
+
* `value-builtin` / `type-internal` are not expressible 1:1, so types are
|
|
12
|
+
* collected via the dedicated `type` group.
|
|
13
|
+
*
|
|
14
|
+
* @see https://oxc.rs/docs/guide/usage/formatter/sorting.html
|
|
15
|
+
*/
|
|
16
|
+
export declare const DEFAULT_SORT_IMPORT_GROUPS: (ImportOrderGroup | ImportOrderGroup[])[];
|
|
17
|
+
/** Oxfmt default prefixes for internal modules. */
|
|
18
|
+
export declare const DEFAULT_INTERNAL_PATTERN: string[];
|
|
19
|
+
/**
|
|
20
|
+
* Convert Oxfmt-style glob prefixes (`~/`, `@/`, `#`) into a single
|
|
21
|
+
* `import/internal-regex` source string.
|
|
22
|
+
*/
|
|
23
|
+
export declare function internalPatternToRegex(patterns: string[]): string;
|
|
24
|
+
/**
|
|
25
|
+
* Map Oxfmt-like `customGroups` onto `import/order` `pathGroups`.
|
|
26
|
+
*
|
|
27
|
+
* Custom group names are not first-class in `import/order`; each entry must
|
|
28
|
+
* attach to a real group via `group` / `position` (defaults: `external` /
|
|
29
|
+
* `before`), matching the common “react before other externals” pattern.
|
|
30
|
+
*/
|
|
31
|
+
export declare function customGroupsToPathGroups(customGroups: SortImportsCustomGroup[]): Exclude<ImportOrderConfig['pathGroups'], undefined>;
|
|
32
|
+
/**
|
|
33
|
+
* Translate Oxfmt-shaped `sortImports` options into `import/order` options +
|
|
34
|
+
* settings. Options that cannot be honored (per-group `newlinesBetween`
|
|
35
|
+
* markers, `partitionByComment`, perfectionist modifier-selectors, etc.) are
|
|
36
|
+
* intentionally omitted — see README.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveSortImports(options?: true | SortImportsOptions): {
|
|
39
|
+
rule: ImportOrderConfig;
|
|
40
|
+
settings: Record<string, unknown>;
|
|
41
|
+
};
|
|
42
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import eslint_plugin_de_morgan from "eslint-plugin-de-morgan";
|
|
2
|
+
import eslint_plugin_eslint_comments from "@eslint-community/eslint-plugin-eslint-comments";
|
|
1
3
|
import { globalIgnores, globals, importPlugin, jestPlugin, js, jsxA11yPlugin, nodePlugin, promisePlugin, reactHooksPlugin, reactPlugin, rstestPlugin, ts, unicornPlugin } from "@rslint/core";
|
|
2
|
-
import
|
|
4
|
+
import eslint_plugin_regexp from "eslint-plugin-regexp";
|
|
5
|
+
import eslint_plugin_unused_imports from "eslint-plugin-unused-imports";
|
|
6
|
+
import { isPackageExists } from "local-pkg";
|
|
3
7
|
import node_process from "node:process";
|
|
4
8
|
const GLOB_SRC_EXT = '?([cm])[jt]s?(x)';
|
|
5
9
|
const GLOB_SRC = `**/*.${GLOB_SRC_EXT}`;
|
|
@@ -49,6 +53,47 @@ const GLOB_EXCLUDE = [
|
|
|
49
53
|
'**/auto-import?(s).d.ts',
|
|
50
54
|
'**/components.d.ts'
|
|
51
55
|
];
|
|
56
|
+
function asESLintPlugin(plugin) {
|
|
57
|
+
return plugin;
|
|
58
|
+
}
|
|
59
|
+
const deMorgan = ()=>[
|
|
60
|
+
{
|
|
61
|
+
files: [
|
|
62
|
+
GLOB_SRC
|
|
63
|
+
],
|
|
64
|
+
name: 'heyq02/de-morgan',
|
|
65
|
+
plugins: {
|
|
66
|
+
'de-morgan': asESLintPlugin(eslint_plugin_de_morgan)
|
|
67
|
+
},
|
|
68
|
+
rules: {
|
|
69
|
+
'de-morgan/no-negated-conjunction': 'error',
|
|
70
|
+
'de-morgan/no-negated-disjunction': 'error'
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
];
|
|
74
|
+
const eslintComments = ()=>[
|
|
75
|
+
{
|
|
76
|
+
files: [
|
|
77
|
+
GLOB_SRC
|
|
78
|
+
],
|
|
79
|
+
name: 'heyq02/eslint-comments',
|
|
80
|
+
plugins: {
|
|
81
|
+
'@eslint-community/eslint-comments': asESLintPlugin(eslint_plugin_eslint_comments)
|
|
82
|
+
},
|
|
83
|
+
rules: {
|
|
84
|
+
'@eslint-community/eslint-comments/disable-enable-pair': [
|
|
85
|
+
'error',
|
|
86
|
+
{
|
|
87
|
+
allowWholeFile: true
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
'@eslint-community/eslint-comments/no-aggregating-enable': 'error',
|
|
91
|
+
'@eslint-community/eslint-comments/no-duplicate-disable': 'error',
|
|
92
|
+
'@eslint-community/eslint-comments/no-unlimited-disable': 'error',
|
|
93
|
+
'@eslint-community/eslint-comments/no-unused-enable': 'error'
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
];
|
|
52
97
|
const ignores = (extra = [])=>[
|
|
53
98
|
{
|
|
54
99
|
...globalIgnores([
|
|
@@ -58,7 +103,96 @@ const ignores = (extra = [])=>[
|
|
|
58
103
|
name: 'heyq02/global-ignores'
|
|
59
104
|
}
|
|
60
105
|
];
|
|
61
|
-
const
|
|
106
|
+
const DEFAULT_SORT_IMPORT_GROUPS = [
|
|
107
|
+
'type',
|
|
108
|
+
[
|
|
109
|
+
'builtin',
|
|
110
|
+
'external'
|
|
111
|
+
],
|
|
112
|
+
'internal',
|
|
113
|
+
[
|
|
114
|
+
'parent',
|
|
115
|
+
'sibling',
|
|
116
|
+
'index'
|
|
117
|
+
],
|
|
118
|
+
'unknown'
|
|
119
|
+
];
|
|
120
|
+
const DEFAULT_INTERNAL_PATTERN = [
|
|
121
|
+
'~/',
|
|
122
|
+
'@/',
|
|
123
|
+
'#'
|
|
124
|
+
];
|
|
125
|
+
const PREDEFINED_GROUPS = new Set([
|
|
126
|
+
'builtin',
|
|
127
|
+
'external',
|
|
128
|
+
'internal',
|
|
129
|
+
'unknown',
|
|
130
|
+
'parent',
|
|
131
|
+
'sibling',
|
|
132
|
+
'index',
|
|
133
|
+
'object',
|
|
134
|
+
'type'
|
|
135
|
+
]);
|
|
136
|
+
function internalPatternToRegex(patterns) {
|
|
137
|
+
const escaped = patterns.map((pattern)=>pattern.replaceAll(/[.*+?^${}()|[\]\\]/g, '\\$&')).filter(Boolean);
|
|
138
|
+
if (0 === escaped.length) return '';
|
|
139
|
+
return `^(?:${escaped.join('|')})`;
|
|
140
|
+
}
|
|
141
|
+
function toPatterns(value) {
|
|
142
|
+
return Array.isArray(value) ? value : [
|
|
143
|
+
value
|
|
144
|
+
];
|
|
145
|
+
}
|
|
146
|
+
function customGroupsToPathGroups(customGroups) {
|
|
147
|
+
return customGroups.flatMap((entry)=>{
|
|
148
|
+
const group = entry.group ?? 'external';
|
|
149
|
+
const position = entry.position ?? 'before';
|
|
150
|
+
return toPatterns(entry.elementNamePattern).map((pattern)=>({
|
|
151
|
+
pattern,
|
|
152
|
+
group,
|
|
153
|
+
position
|
|
154
|
+
}));
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
function resolveSortImports(options = true) {
|
|
158
|
+
const opts = true === options ? {} : options;
|
|
159
|
+
const { groups = DEFAULT_SORT_IMPORT_GROUPS, newlinesBetween = true, customGroups = [], internalPattern = DEFAULT_INTERNAL_PATTERN, order = 'asc', ignoreCase = true, named = true, sortSideEffects = false } = opts;
|
|
160
|
+
const pathGroups = customGroupsToPathGroups(customGroups);
|
|
161
|
+
const normalizedGroups = groups.map((item)=>{
|
|
162
|
+
if (Array.isArray(item)) {
|
|
163
|
+
const filtered = item.filter((g)=>PREDEFINED_GROUPS.has(g));
|
|
164
|
+
return filtered.length > 0 ? filtered : null;
|
|
165
|
+
}
|
|
166
|
+
return PREDEFINED_GROUPS.has(item) ? item : null;
|
|
167
|
+
}).filter((item)=>Boolean(item));
|
|
168
|
+
const rule = {
|
|
169
|
+
groups: normalizedGroups.length > 0 ? normalizedGroups : DEFAULT_SORT_IMPORT_GROUPS,
|
|
170
|
+
'newlines-between': newlinesBetween ? 'always' : 'never',
|
|
171
|
+
alphabetize: {
|
|
172
|
+
order,
|
|
173
|
+
caseInsensitive: ignoreCase
|
|
174
|
+
},
|
|
175
|
+
named,
|
|
176
|
+
warnOnUnassignedImports: sortSideEffects,
|
|
177
|
+
...pathGroups.length > 0 ? {
|
|
178
|
+
pathGroups,
|
|
179
|
+
pathGroupsExcludedImportTypes: [
|
|
180
|
+
'builtin',
|
|
181
|
+
'object'
|
|
182
|
+
]
|
|
183
|
+
} : {}
|
|
184
|
+
};
|
|
185
|
+
const settings = {};
|
|
186
|
+
const internalRegex = internalPatternToRegex(internalPattern);
|
|
187
|
+
if (internalRegex) settings['import/internal-regex'] = internalRegex;
|
|
188
|
+
return {
|
|
189
|
+
rule,
|
|
190
|
+
settings
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
const imports = (options = {})=>{
|
|
194
|
+
const { typescript = false, sortImports: sortImportsOption = true } = options;
|
|
195
|
+
const configs = [
|
|
62
196
|
{
|
|
63
197
|
...importPlugin.configs.recommended,
|
|
64
198
|
files: [
|
|
@@ -82,7 +216,7 @@ const imports = (options = {})=>[
|
|
|
82
216
|
],
|
|
83
217
|
'import/no-mutable-exports': 'error',
|
|
84
218
|
'import/no-named-default': 'error',
|
|
85
|
-
...
|
|
219
|
+
...typescript ? {
|
|
86
220
|
'import/default': 'off',
|
|
87
221
|
'import/named': 'off',
|
|
88
222
|
'import/namespace': 'off',
|
|
@@ -91,6 +225,26 @@ const imports = (options = {})=>[
|
|
|
91
225
|
}
|
|
92
226
|
}
|
|
93
227
|
];
|
|
228
|
+
if (sortImportsOption) {
|
|
229
|
+
const { rule, settings } = resolveSortImports(sortImportsOption);
|
|
230
|
+
configs.push({
|
|
231
|
+
files: [
|
|
232
|
+
GLOB_SRC
|
|
233
|
+
],
|
|
234
|
+
name: 'heyq02/imports/sort',
|
|
235
|
+
...Object.keys(settings).length > 0 ? {
|
|
236
|
+
settings
|
|
237
|
+
} : {},
|
|
238
|
+
rules: {
|
|
239
|
+
'import/order': [
|
|
240
|
+
'error',
|
|
241
|
+
rule
|
|
242
|
+
]
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
return configs;
|
|
247
|
+
};
|
|
94
248
|
const restrictedSyntaxJs = [
|
|
95
249
|
'ForInStatement',
|
|
96
250
|
'LabeledStatement'
|
|
@@ -354,6 +508,21 @@ const react = (options = {})=>{
|
|
|
354
508
|
if (false !== options.jsxA11y) configs.push(...jsxA11y());
|
|
355
509
|
return configs;
|
|
356
510
|
};
|
|
511
|
+
const regexp = ()=>{
|
|
512
|
+
const recommended = eslint_plugin_regexp.configs["flat/recommended"];
|
|
513
|
+
return [
|
|
514
|
+
{
|
|
515
|
+
files: [
|
|
516
|
+
GLOB_SRC
|
|
517
|
+
],
|
|
518
|
+
name: 'heyq02/regexp',
|
|
519
|
+
plugins: {
|
|
520
|
+
regexp: asESLintPlugin(eslint_plugin_regexp)
|
|
521
|
+
},
|
|
522
|
+
rules: recommended.rules
|
|
523
|
+
}
|
|
524
|
+
];
|
|
525
|
+
};
|
|
357
526
|
const rstest = ()=>[
|
|
358
527
|
{
|
|
359
528
|
...rstestPlugin.configs.recommended,
|
|
@@ -391,7 +560,9 @@ const specialCases = ()=>[
|
|
|
391
560
|
`**/{views,pages,routes,middleware,plugins,api,modules}/${GLOB_SRC}`,
|
|
392
561
|
`**/{index,vite,esbuild,rollup,rolldown,webpack,rspack,farm,unloader,nuxt,rslint}.${GLOB_SRC_EXT}`,
|
|
393
562
|
'**/*.d.ts',
|
|
394
|
-
'**/.prettierrc*'
|
|
563
|
+
'**/.prettierrc*',
|
|
564
|
+
'**/.oxfmtrc*',
|
|
565
|
+
'**/oxfmt.config.*'
|
|
395
566
|
],
|
|
396
567
|
name: 'heyq02/special/allow-default-export',
|
|
397
568
|
rules: {
|
|
@@ -432,7 +603,7 @@ function resolveTypeScriptOptions(options) {
|
|
|
432
603
|
projectService: options.projectService
|
|
433
604
|
};
|
|
434
605
|
}
|
|
435
|
-
const
|
|
606
|
+
const typescript_typescript = (options = true)=>{
|
|
436
607
|
const opts = resolveTypeScriptOptions(options);
|
|
437
608
|
const baseline = opts.strict && opts.typeChecked ? ts.configs.strictTypeChecked : opts.strict ? ts.configs.strict : opts.typeChecked ? ts.configs.recommendedTypeChecked : ts.configs.recommended;
|
|
438
609
|
const stylistic = opts.stylistic ? opts.typeChecked ? ts.configs.stylisticTypeChecked : ts.configs.stylistic : [];
|
|
@@ -568,20 +739,34 @@ const unicorn = ()=>[
|
|
|
568
739
|
}
|
|
569
740
|
}
|
|
570
741
|
];
|
|
571
|
-
const
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
742
|
+
const unusedVarsOptions = {
|
|
743
|
+
args: 'after-used',
|
|
744
|
+
argsIgnorePattern: '^_',
|
|
745
|
+
ignoreRestSiblings: true,
|
|
746
|
+
varsIgnorePattern: '^_'
|
|
747
|
+
};
|
|
748
|
+
const unusedImports = ()=>[
|
|
749
|
+
{
|
|
750
|
+
files: [
|
|
751
|
+
GLOB_SRC
|
|
752
|
+
],
|
|
753
|
+
name: 'heyq02/unused-imports',
|
|
754
|
+
plugins: {
|
|
755
|
+
'unused-imports': asESLintPlugin(eslint_plugin_unused_imports)
|
|
756
|
+
},
|
|
757
|
+
rules: {
|
|
758
|
+
'no-unused-vars': 'off',
|
|
759
|
+
"@typescript-eslint/no-unused-vars": 'off',
|
|
760
|
+
'unused-imports/no-unused-imports': 'error',
|
|
761
|
+
'unused-imports/no-unused-vars': [
|
|
762
|
+
'error',
|
|
763
|
+
{
|
|
764
|
+
...unusedVarsOptions
|
|
765
|
+
}
|
|
766
|
+
]
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
];
|
|
585
770
|
const hasTypeScript = ()=>isPackageExists("typescript");
|
|
586
771
|
const hasReact = ()=>isPackageExists('react') || isPackageExists('react-dom') || isPackageExists('next') || isPackageExists('preact') || isPackageExists('@remix-run/react');
|
|
587
772
|
const hasJest = ()=>isPackageExists('jest') || isPackageExists('@jest/globals');
|
|
@@ -614,22 +799,32 @@ const presetJavaScript = ()=>[
|
|
|
614
799
|
...ignores(),
|
|
615
800
|
...javascript(),
|
|
616
801
|
...imports({
|
|
617
|
-
typescript: false
|
|
802
|
+
typescript: false,
|
|
803
|
+
sortImports: true
|
|
618
804
|
}),
|
|
619
805
|
...unicorn(),
|
|
620
806
|
...node(),
|
|
621
|
-
...promise()
|
|
807
|
+
...promise(),
|
|
808
|
+
...unusedImports(),
|
|
809
|
+
...regexp(),
|
|
810
|
+
...deMorgan(),
|
|
811
|
+
...eslintComments()
|
|
622
812
|
];
|
|
623
813
|
const presetBasic = (typescriptOptions = true)=>[
|
|
624
814
|
...ignores(),
|
|
625
815
|
...javascript(),
|
|
626
|
-
...
|
|
816
|
+
...typescript_typescript(typescriptOptions),
|
|
627
817
|
...imports({
|
|
628
|
-
typescript: true
|
|
818
|
+
typescript: true,
|
|
819
|
+
sortImports: true
|
|
629
820
|
}),
|
|
630
821
|
...unicorn(),
|
|
631
822
|
...node(),
|
|
632
|
-
...promise()
|
|
823
|
+
...promise(),
|
|
824
|
+
...unusedImports(),
|
|
825
|
+
...regexp(),
|
|
826
|
+
...deMorgan(),
|
|
827
|
+
...eslintComments()
|
|
633
828
|
];
|
|
634
829
|
const presetAll = ()=>heyq02({
|
|
635
830
|
typescript: true,
|
|
@@ -639,14 +834,15 @@ const presetAll = ()=>heyq02({
|
|
|
639
834
|
jsxA11y: true
|
|
640
835
|
});
|
|
641
836
|
function heyq02(options = {}, ...userConfigs) {
|
|
642
|
-
const { ignores: extraIgnores = [], javascript: enableJavaScript = true, typescript: enableTypeScript = hasTypeScript(), unicorn: enableUnicorn = true, imports: enableImports = true, node: enableNode = true, promise: enablePromise = true, react: enableReact = hasReact(), jsxA11y: enableJsxA11y, jest: enableJest = hasJest(), rstest: enableRstest = hasRstest() } = options;
|
|
837
|
+
const { ignores: extraIgnores = [], javascript: enableJavaScript = true, typescript: enableTypeScript = hasTypeScript(), unicorn: enableUnicorn = true, imports: enableImports = true, sortImports: sortImportsOption = true, node: enableNode = true, promise: enablePromise = true, react: enableReact = hasReact(), jsxA11y: enableJsxA11y, jest: enableJest = hasJest(), rstest: enableRstest = hasRstest(), unusedImports: enableUnusedImports = true, regexp: enableRegexp = true, deMorgan: enableDeMorgan = true, eslintComments: enableEslintComments = true } = options;
|
|
643
838
|
const configs = [
|
|
644
839
|
...ignores(extraIgnores)
|
|
645
840
|
];
|
|
646
841
|
if (enableJavaScript) configs.push(...javascript());
|
|
647
|
-
if (enableTypeScript) configs.push(...
|
|
842
|
+
if (enableTypeScript) configs.push(...typescript_typescript(true === enableTypeScript ? true : enableTypeScript));
|
|
648
843
|
if (enableImports) configs.push(...imports({
|
|
649
|
-
typescript: Boolean(enableTypeScript)
|
|
844
|
+
typescript: Boolean(enableTypeScript),
|
|
845
|
+
sortImports: sortImportsOption
|
|
650
846
|
}));
|
|
651
847
|
if (enableUnicorn) configs.push(...unicorn());
|
|
652
848
|
if (enableNode) configs.push(...node(true === enableNode ? 'module' : enableNode));
|
|
@@ -657,9 +853,13 @@ function heyq02(options = {}, ...userConfigs) {
|
|
|
657
853
|
else if (enableJsxA11y) configs.push(...jsxA11y());
|
|
658
854
|
if (enableJest) configs.push(...jest());
|
|
659
855
|
if (enableRstest) configs.push(...rstest());
|
|
856
|
+
if (enableUnusedImports) configs.push(...unusedImports());
|
|
857
|
+
if (enableRegexp) configs.push(...regexp());
|
|
858
|
+
if (enableDeMorgan) configs.push(...deMorgan());
|
|
859
|
+
if (enableEslintComments) configs.push(...eslintComments());
|
|
660
860
|
configs.push(...specialCases());
|
|
661
861
|
configs.push(...flattenConfigs(...userConfigs));
|
|
662
862
|
return configs;
|
|
663
863
|
}
|
|
664
864
|
const rslintConfig = heyq02;
|
|
665
|
-
export { GLOB_DIST, GLOB_EXCLUDE, GLOB_JS, GLOB_JSX, GLOB_LOCKFILE, GLOB_NODE_MODULES, GLOB_SRC, GLOB_SRC_EXT, GLOB_TESTS, GLOB_TS, GLOB_TSX, flattenConfigs, hasJest, hasReact, hasRstest, hasTypeScript, heyq02, ignores, imports, isInEditorEnv, isInGitHooksOrLintStaged, javascript, jest, jsxA11y, node, presetAll, presetBasic, presetJavaScript, promise, react, restrictedSyntaxJs, rslintConfig, rstest, specialCases, toArray, typescript, unicorn };
|
|
865
|
+
export { DEFAULT_INTERNAL_PATTERN, DEFAULT_SORT_IMPORT_GROUPS, GLOB_DIST, GLOB_EXCLUDE, GLOB_JS, GLOB_JSX, GLOB_LOCKFILE, GLOB_NODE_MODULES, GLOB_SRC, GLOB_SRC_EXT, GLOB_TESTS, GLOB_TS, GLOB_TSX, customGroupsToPathGroups, deMorgan, eslintComments, flattenConfigs, hasJest, hasReact, hasRstest, hasTypeScript, heyq02, ignores, imports, internalPatternToRegex, isInEditorEnv, isInGitHooksOrLintStaged, javascript, jest, jsxA11y, node, presetAll, presetBasic, presetJavaScript, promise, react, regexp, resolveSortImports, restrictedSyntaxJs, rslintConfig, rstest, specialCases, toArray, typescript_typescript as typescript, unicorn, unusedImports };
|
package/dist/types.d.ts
CHANGED
|
@@ -27,6 +27,91 @@ export interface TypeScriptOptions {
|
|
|
27
27
|
projectService?: boolean;
|
|
28
28
|
}
|
|
29
29
|
export type NodePreset = boolean | 'module' | 'script' | 'mixed';
|
|
30
|
+
/**
|
|
31
|
+
* `import/order` group names (Rslint / eslint-plugin-import).
|
|
32
|
+
* Closest enforceable equivalent of Oxfmt perfectionist selectors.
|
|
33
|
+
*/
|
|
34
|
+
export type SortImportsGroup = 'builtin' | 'external' | 'internal' | 'unknown' | 'parent' | 'sibling' | 'index' | 'object' | 'type';
|
|
35
|
+
/**
|
|
36
|
+
* Oxfmt-like custom group → mapped to `import/order` `pathGroups`.
|
|
37
|
+
*
|
|
38
|
+
* @see https://oxc.rs/docs/guide/usage/formatter/sorting.html
|
|
39
|
+
*/
|
|
40
|
+
export interface SortImportsCustomGroup {
|
|
41
|
+
/**
|
|
42
|
+
* Display / documentation name (Oxfmt `groupName`).
|
|
43
|
+
* Not a first-class `import/order` group — attach via {@link group}.
|
|
44
|
+
*/
|
|
45
|
+
groupName?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Glob patterns matched against the import source (Oxfmt `elementNamePattern`).
|
|
48
|
+
*/
|
|
49
|
+
elementNamePattern: string | string[];
|
|
50
|
+
/**
|
|
51
|
+
* Target `import/order` group to attach to.
|
|
52
|
+
* @default 'external'
|
|
53
|
+
*/
|
|
54
|
+
group?: SortImportsGroup;
|
|
55
|
+
/**
|
|
56
|
+
* Position relative to {@link group}.
|
|
57
|
+
* @default 'before'
|
|
58
|
+
*/
|
|
59
|
+
position?: 'before' | 'after';
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Import sorting options, shaped like Oxfmt `sortImports` and implemented via
|
|
63
|
+
* Rslint `import/order`.
|
|
64
|
+
*
|
|
65
|
+
* Unsupported Oxfmt knobs (no-op / not exposed): per-group `{ newlinesBetween }`,
|
|
66
|
+
* `partitionByComment`, `partitionByNewline`, perfectionist modifier-selectors
|
|
67
|
+
* (`value-builtin`, `type-import`, …).
|
|
68
|
+
*
|
|
69
|
+
* @see https://oxc.rs/docs/guide/usage/formatter/sorting.html
|
|
70
|
+
*/
|
|
71
|
+
export interface SortImportsOptions {
|
|
72
|
+
/**
|
|
73
|
+
* Relative order of import groups.
|
|
74
|
+
* @default `['type', ['builtin', 'external'], 'internal', ['parent', 'sibling', 'index'], 'unknown']`
|
|
75
|
+
*/
|
|
76
|
+
groups?: (SortImportsGroup | SortImportsGroup[])[];
|
|
77
|
+
/**
|
|
78
|
+
* Insert a blank line between groups.
|
|
79
|
+
* Maps to `newlines-between: 'always' | 'never'`.
|
|
80
|
+
* @default true
|
|
81
|
+
*/
|
|
82
|
+
newlinesBetween?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Custom path-based groups (Oxfmt `customGroups` → `pathGroups`).
|
|
85
|
+
*/
|
|
86
|
+
customGroups?: SortImportsCustomGroup[];
|
|
87
|
+
/**
|
|
88
|
+
* Prefixes treated as internal imports (Oxfmt `internalPattern`).
|
|
89
|
+
* Converted to `settings['import/internal-regex']`.
|
|
90
|
+
* @default `['~/', '@/', '#']`
|
|
91
|
+
*/
|
|
92
|
+
internalPattern?: string[];
|
|
93
|
+
/**
|
|
94
|
+
* Alphabetical order within each group.
|
|
95
|
+
* @default 'asc'
|
|
96
|
+
*/
|
|
97
|
+
order?: 'asc' | 'desc';
|
|
98
|
+
/**
|
|
99
|
+
* Case-insensitive alphabetical sort.
|
|
100
|
+
* @default true
|
|
101
|
+
*/
|
|
102
|
+
ignoreCase?: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Sort named import / export members.
|
|
105
|
+
* @default true
|
|
106
|
+
*/
|
|
107
|
+
named?: boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Whether side-effect imports participate in ordering
|
|
110
|
+
* (`warnOnUnassignedImports`).
|
|
111
|
+
* @default false
|
|
112
|
+
*/
|
|
113
|
+
sortSideEffects?: boolean;
|
|
114
|
+
}
|
|
30
115
|
export interface Options {
|
|
31
116
|
/**
|
|
32
117
|
* Global ignore patterns. Merged with the built-in excludes.
|
|
@@ -50,6 +135,13 @@ export interface Options {
|
|
|
50
135
|
* Import rules. @default true
|
|
51
136
|
*/
|
|
52
137
|
imports?: boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Sort imports via `import/order`, with an Oxfmt-like options surface.
|
|
140
|
+
* Enabled by default when {@link imports} is on.
|
|
141
|
+
* Set `false` if Oxfmt `sortImports` already owns ordering.
|
|
142
|
+
* @default true
|
|
143
|
+
*/
|
|
144
|
+
sortImports?: boolean | SortImportsOptions;
|
|
53
145
|
/**
|
|
54
146
|
* Node.js rules.
|
|
55
147
|
* - `true` / `'module'` — ESM-oriented Node rules (default)
|
|
@@ -82,4 +174,24 @@ export interface Options {
|
|
|
82
174
|
* @default auto
|
|
83
175
|
*/
|
|
84
176
|
rstest?: boolean;
|
|
177
|
+
/**
|
|
178
|
+
* Autofix unused imports (`eslint-plugin-unused-imports`).
|
|
179
|
+
* @default true
|
|
180
|
+
*/
|
|
181
|
+
unusedImports?: boolean;
|
|
182
|
+
/**
|
|
183
|
+
* RegExp rules (`eslint-plugin-regexp`).
|
|
184
|
+
* @default true
|
|
185
|
+
*/
|
|
186
|
+
regexp?: boolean;
|
|
187
|
+
/**
|
|
188
|
+
* De Morgan rewrites (`eslint-plugin-de-morgan`).
|
|
189
|
+
* @default true
|
|
190
|
+
*/
|
|
191
|
+
deMorgan?: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* `eslint-disable` hygiene (`@eslint-community/eslint-plugin-eslint-comments`).
|
|
194
|
+
* @default true
|
|
195
|
+
*/
|
|
196
|
+
eslintComments?: boolean;
|
|
85
197
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heyq02/rslint-config",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3-beta.1",
|
|
4
4
|
"description": "Opinionated Rslint flat-config preset.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"flat-config",
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
"dist"
|
|
24
24
|
],
|
|
25
25
|
"type": "module",
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
26
28
|
"exports": {
|
|
27
29
|
".": {
|
|
28
30
|
"types": "./dist/index.d.ts",
|
|
@@ -30,25 +32,30 @@
|
|
|
30
32
|
},
|
|
31
33
|
"./package.json": "./package.json"
|
|
32
34
|
},
|
|
33
|
-
"types": "./dist/index.d.ts",
|
|
34
|
-
"sideEffects": false,
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
|
-
"
|
|
39
|
-
"@
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@eslint-community/eslint-plugin-eslint-comments": "^4.8.1",
|
|
40
|
+
"eslint-plugin-de-morgan": "^2.2.0",
|
|
41
|
+
"eslint-plugin-regexp": "^3.3.1",
|
|
42
|
+
"eslint-plugin-unused-imports": "^4.4.1",
|
|
43
|
+
"local-pkg": "^1.2.1"
|
|
40
44
|
},
|
|
41
45
|
"devDependencies": {
|
|
46
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
42
47
|
"@heyq02/rslib-config": "^1.0.1",
|
|
43
48
|
"@rslib/core": "^1.0.3",
|
|
44
49
|
"@rslint/core": "^0.9.4",
|
|
45
50
|
"@types/node": "^26.1.1",
|
|
51
|
+
"automd": "^0.4.3",
|
|
46
52
|
"bumpp": "^11.1.0",
|
|
47
|
-
"
|
|
48
|
-
"typescript": "^7.0.2"
|
|
53
|
+
"publint": "^0.3.25",
|
|
54
|
+
"typescript": "^7.0.2",
|
|
55
|
+
"vite-plus": "^1.1.0"
|
|
49
56
|
},
|
|
50
|
-
"
|
|
51
|
-
"
|
|
57
|
+
"peerDependencies": {
|
|
58
|
+
"@rslint/core": "^0.9.0"
|
|
52
59
|
},
|
|
53
60
|
"devEngines": {
|
|
54
61
|
"packageManager": {
|
|
@@ -57,14 +64,23 @@
|
|
|
57
64
|
"onFail": "download"
|
|
58
65
|
}
|
|
59
66
|
},
|
|
67
|
+
"engines": {
|
|
68
|
+
"node": "^20.19.0 || >=22.12.0"
|
|
69
|
+
},
|
|
60
70
|
"scripts": {
|
|
61
71
|
"build": "rslib",
|
|
62
72
|
"dev": "rslib --watch",
|
|
63
|
-
"test": "
|
|
73
|
+
"test": "vp test",
|
|
64
74
|
"lint": "rslint .",
|
|
65
75
|
"lint:fix": "rslint --fix .",
|
|
66
|
-
"
|
|
76
|
+
"automd": "automd",
|
|
77
|
+
"format": "pnpm automd && vp fmt",
|
|
78
|
+
"format:check": "vp fmt --check",
|
|
67
79
|
"typecheck": "tsc --noEmit",
|
|
80
|
+
"check": "pnpm run format:check && pnpm run lint && pnpm run typecheck",
|
|
81
|
+
"publint": "publint",
|
|
82
|
+
"attw": "pnpm pack && attw heyq02-rslint-config-*.tgz --profile esm-only && rm -f heyq02-rslint-config-*.tgz",
|
|
83
|
+
"check:package": "pnpm run build && pnpm run publint && pnpm run attw",
|
|
68
84
|
"release": "bumpp"
|
|
69
85
|
}
|
|
70
86
|
}
|