@qstanay/eslint-config 1.0.0
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 +155 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +55 -0
- package/dist/index.mjs.map +1 -0
- package/dist/nuxt-CehpYBa3.d.mts +43 -0
- package/dist/nuxt-CehpYBa3.d.mts.map +1 -0
- package/dist/nuxt-Cz6LtoZ_.mjs +178 -0
- package/dist/nuxt-Cz6LtoZ_.mjs.map +1 -0
- package/dist/nuxt.d.mts +2 -0
- package/dist/nuxt.mjs +2 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# @qstanay/eslint-config
|
|
2
|
+
|
|
3
|
+
Opinionated ESLint **flat config** for:
|
|
4
|
+
|
|
5
|
+
- Nuxt applications
|
|
6
|
+
- Vue applications
|
|
7
|
+
- TypeScript packages
|
|
8
|
+
|
|
9
|
+
This preset uses **@stylistic** for formatting through ESLint (single toolchain: `eslint --fix`).
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
- Node.js 18+ recommended
|
|
14
|
+
- ESLint `^9 || ^10`
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm i -D eslint @qstanay/eslint-config
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### Nuxt (recommended)
|
|
25
|
+
|
|
26
|
+
In a Nuxt app, use `@nuxt/eslint` module and layer this preset on top of Nuxt generated config.
|
|
27
|
+
|
|
28
|
+
1) Ensure Nuxt ESLint module is enabled in `nuxt.config.ts`:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
export default defineNuxtConfig({
|
|
32
|
+
modules: ['@nuxt/eslint'],
|
|
33
|
+
})
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
2) Create `eslint.config.mjs`:
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
import withNuxt from './.nuxt/eslint.config.mjs'
|
|
40
|
+
import { nuxt } from '@qstanay/eslint-config/nuxt'
|
|
41
|
+
|
|
42
|
+
export default withNuxt(
|
|
43
|
+
...nuxt({
|
|
44
|
+
stylistic: {
|
|
45
|
+
semi: true,
|
|
46
|
+
quotes: 'single',
|
|
47
|
+
indent: 2,
|
|
48
|
+
maxLen: 100,
|
|
49
|
+
},
|
|
50
|
+
}),
|
|
51
|
+
)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Vue (Vite) app
|
|
55
|
+
|
|
56
|
+
Create `eslint.config.mjs`:
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
import { defineConfig } from '@qstanay/eslint-config'
|
|
60
|
+
|
|
61
|
+
export default defineConfig({
|
|
62
|
+
vue: true,
|
|
63
|
+
typescript: true,
|
|
64
|
+
})
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### TypeScript package
|
|
68
|
+
|
|
69
|
+
Create `eslint.config.mjs`:
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
import { defineConfig } from '@qstanay/eslint-config'
|
|
73
|
+
|
|
74
|
+
export default defineConfig({
|
|
75
|
+
vue: false,
|
|
76
|
+
nuxt: false,
|
|
77
|
+
typescript: true,
|
|
78
|
+
})
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Options
|
|
82
|
+
|
|
83
|
+
### `stylistic`
|
|
84
|
+
|
|
85
|
+
Enable/disable formatting rules (enabled by default).
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
defineConfig({
|
|
89
|
+
stylistic: {
|
|
90
|
+
semi: true,
|
|
91
|
+
quotes: 'single',
|
|
92
|
+
indent: 2,
|
|
93
|
+
maxLen: 100,
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Set `stylistic: false` to disable all stylistic rules.
|
|
99
|
+
|
|
100
|
+
### `overrides`
|
|
101
|
+
|
|
102
|
+
Merge custom rules last.
|
|
103
|
+
|
|
104
|
+
```js
|
|
105
|
+
defineConfig({
|
|
106
|
+
overrides: {
|
|
107
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
108
|
+
},
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `ignores`
|
|
113
|
+
|
|
114
|
+
Add extra ignore globs.
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
defineConfig({
|
|
118
|
+
ignores: ['**/coverage/**'],
|
|
119
|
+
})
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Scripts
|
|
123
|
+
|
|
124
|
+
Suggested `package.json` scripts:
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"scripts": {
|
|
129
|
+
"lint": "eslint .",
|
|
130
|
+
"lint:fix": "eslint . --fix"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## VS Code setup
|
|
136
|
+
|
|
137
|
+
Use ESLint as the formatter and apply fixes on save.
|
|
138
|
+
|
|
139
|
+
`.vscode/settings.json`:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
|
|
144
|
+
"editor.formatOnSave": true,
|
|
145
|
+
"editor.codeActionsOnSave": {
|
|
146
|
+
"source.fixAll.eslint": "explicit"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Notes
|
|
152
|
+
|
|
153
|
+
- For Nuxt projects, this package intentionally does **not** replace `@nuxt/eslint` project-aware config. It extends it.
|
|
154
|
+
- This package focuses on Nuxt/Vue/TypeScript. JSON/YAML/Markdown/CSS formatting can be added later if needed.
|
|
155
|
+
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { a as StylisticOptions, i as OptionsConfig, n as nuxt, o as TypedFlatConfigItem, r as Awaitable } from "./nuxt-CehpYBa3.mjs";
|
|
2
|
+
import { FlatConfigComposer } from "eslint-flat-config-utils";
|
|
3
|
+
//#region src/index.d.ts
|
|
4
|
+
declare function defineConfig(options?: OptionsConfig, ...userConfigs: (Awaitable<TypedFlatConfigItem | TypedFlatConfigItem[]>)[]): FlatConfigComposer<TypedFlatConfigItem, never>;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { Awaitable, OptionsConfig, StylisticOptions, TypedFlatConfigItem, defineConfig, nuxt };
|
|
7
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;iBAegB,aACd,UAAS,kBACN,cAAc,UAAU,sBAAsB,4BAAyB,mBAAA"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { a as nuxt$1, i as stylistic, n as vue, o as imports, r as typescript, s as sharedRules, t as nuxt } from "./nuxt-Cz6LtoZ_.mjs";
|
|
2
|
+
import { FlatConfigComposer } from "eslint-flat-config-utils";
|
|
3
|
+
import { isPackageExists } from "local-pkg";
|
|
4
|
+
//#region src/utils.ts
|
|
5
|
+
function resolveEnabled(explicit, detected) {
|
|
6
|
+
return explicit ?? detected;
|
|
7
|
+
}
|
|
8
|
+
function has(pkg) {
|
|
9
|
+
return isPackageExists(pkg);
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/configs/ignores.ts
|
|
13
|
+
function ignores(extraIgnores = []) {
|
|
14
|
+
return [{
|
|
15
|
+
name: "qstanay/ignores",
|
|
16
|
+
ignores: [
|
|
17
|
+
"**/node_modules/**",
|
|
18
|
+
"**/dist/**",
|
|
19
|
+
"**/.output/**",
|
|
20
|
+
"**/.nuxt/**",
|
|
21
|
+
"**/.nitro/**",
|
|
22
|
+
...extraIgnores
|
|
23
|
+
]
|
|
24
|
+
}];
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/index.ts
|
|
28
|
+
function defineConfig(options = {}, ...userConfigs) {
|
|
29
|
+
const enableTs = resolveEnabled(options.typescript, has("typescript"));
|
|
30
|
+
const enableVue = resolveEnabled(options.vue, has("vue") || has("nuxt"));
|
|
31
|
+
const enableNuxt = resolveEnabled(options.nuxt, has("nuxt"));
|
|
32
|
+
const stylisticOptions = options.stylistic === false ? false : typeof options.stylistic === "object" ? options.stylistic : {};
|
|
33
|
+
const configs = [];
|
|
34
|
+
configs.push(Promise.resolve(ignores(options.ignores)));
|
|
35
|
+
if (enableTs) configs.push(typescript());
|
|
36
|
+
configs.push(imports());
|
|
37
|
+
if (stylisticOptions) configs.push(stylistic(stylisticOptions));
|
|
38
|
+
if (enableVue) configs.push(vue());
|
|
39
|
+
if (enableNuxt) configs.push(nuxt$1());
|
|
40
|
+
configs.push(Promise.resolve([{
|
|
41
|
+
name: "qstanay/shared-rules",
|
|
42
|
+
rules: {
|
|
43
|
+
...sharedRules(),
|
|
44
|
+
...options.overrides ?? {}
|
|
45
|
+
},
|
|
46
|
+
files: ["**/*.{js,jsx,ts,tsx,cts,mts,vue}"]
|
|
47
|
+
}]));
|
|
48
|
+
const composer = new FlatConfigComposer();
|
|
49
|
+
composer.append(...configs, ...userConfigs);
|
|
50
|
+
return composer;
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { defineConfig, nuxt };
|
|
54
|
+
|
|
55
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["typescriptConfig","stylisticConfig","vueConfig","nuxtConfig"],"sources":["../src/utils.ts","../src/configs/ignores.ts","../src/index.ts"],"sourcesContent":["import { isPackageExists } from 'local-pkg';\n\nexport function resolveEnabled(explicit: boolean | undefined, detected: boolean) {\n return explicit ?? detected;\n}\n\nexport function has(pkg: string) {\n return isPackageExists(pkg);\n}\n","import type { TypedFlatConfigItem } from '../types';\n\nexport function ignores(extraIgnores: string[] = []): TypedFlatConfigItem[] {\n return [\n {\n name: 'qstanay/ignores',\n ignores: [\n '**/node_modules/**',\n '**/dist/**',\n '**/.output/**',\n '**/.nuxt/**',\n '**/.nitro/**',\n ...extraIgnores,\n ],\n },\n ];\n}\n","import type { Awaitable, OptionsConfig, TypedFlatConfigItem } from './types';\n\nimport { FlatConfigComposer } from 'eslint-flat-config-utils';\nimport { has, resolveEnabled } from './utils';\nimport { ignores } from './configs/ignores';\nimport { sharedRules } from './configs/shared-rules';\nimport { imports } from './configs/imports';\nimport { nuxt as nuxtConfig } from './configs/nuxt';\nimport { stylistic as stylisticConfig } from './configs/stylistic';\nimport { typescript as typescriptConfig } from './configs/typescript';\nimport { vue as vueConfig } from './configs/vue';\n\nexport { nuxt } from './nuxt';\nexport * from './types';\n\nexport function defineConfig(\n options: OptionsConfig = {},\n ...userConfigs: (Awaitable<TypedFlatConfigItem | TypedFlatConfigItem[]>)[]\n) {\n const enableTs = resolveEnabled(options.typescript, has('typescript'));\n const enableVue = resolveEnabled(options.vue, has('vue') || has('nuxt'));\n const enableNuxt = resolveEnabled(options.nuxt, has('nuxt'));\n\n const stylisticOptions = options.stylistic === false\n ? false\n : typeof options.stylistic === 'object'\n ? options.stylistic\n : {};\n\n const configs: (Awaitable<TypedFlatConfigItem[]>)[] = [];\n\n configs.push(Promise.resolve(ignores(options.ignores)));\n\n if (enableTs) {\n configs.push(typescriptConfig());\n }\n\n configs.push(imports());\n\n if (stylisticOptions) {\n configs.push(stylisticConfig(stylisticOptions));\n }\n\n if (enableVue) {\n configs.push(vueConfig());\n }\n\n if (enableNuxt) {\n configs.push(nuxtConfig());\n }\n\n configs.push(Promise.resolve([\n {\n name: 'qstanay/shared-rules',\n rules: {\n ...sharedRules(),\n ...(options.overrides ?? {}),\n },\n files: ['**/*.{js,jsx,ts,tsx,cts,mts,vue}'],\n },\n ]));\n\n const composer = new FlatConfigComposer<TypedFlatConfigItem>();\n composer.append(...configs, ...userConfigs as any);\n return composer;\n}\n"],"mappings":";;;;AAEA,SAAgB,eAAe,UAA+B,UAAmB;CAC/E,OAAO,YAAY;AACrB;AAEA,SAAgB,IAAI,KAAa;CAC/B,OAAO,gBAAgB,GAAG;AAC5B;;;ACNA,SAAgB,QAAQ,eAAyB,CAAC,GAA0B;CAC1E,OAAO,CACL;EACE,MAAM;EACN,SAAS;GACP;GACA;GACA;GACA;GACA;GACA,GAAG;EACL;CACF,CACF;AACF;;;ACDA,SAAgB,aACd,UAAyB,CAAC,GAC1B,GAAG,aACH;CACA,MAAM,WAAW,eAAe,QAAQ,YAAY,IAAI,YAAY,CAAC;CACrE,MAAM,YAAY,eAAe,QAAQ,KAAK,IAAI,KAAK,KAAK,IAAI,MAAM,CAAC;CACvE,MAAM,aAAa,eAAe,QAAQ,MAAM,IAAI,MAAM,CAAC;CAE3D,MAAM,mBAAmB,QAAQ,cAAc,QAC3C,QACA,OAAO,QAAQ,cAAc,WAC3B,QAAQ,YACR,CAAC;CAEP,MAAM,UAAgD,CAAC;CAEvD,QAAQ,KAAK,QAAQ,QAAQ,QAAQ,QAAQ,OAAO,CAAC,CAAC;CAEtD,IAAI,UACF,QAAQ,KAAKA,WAAiB,CAAC;CAGjC,QAAQ,KAAK,QAAQ,CAAC;CAEtB,IAAI,kBACF,QAAQ,KAAKC,UAAgB,gBAAgB,CAAC;CAGhD,IAAI,WACF,QAAQ,KAAKC,IAAU,CAAC;CAG1B,IAAI,YACF,QAAQ,KAAKC,OAAW,CAAC;CAG3B,QAAQ,KAAK,QAAQ,QAAQ,CAC3B;EACE,MAAM;EACN,OAAO;GACL,GAAG,YAAY;GACf,GAAI,QAAQ,aAAa,CAAC;EAC5B;EACA,OAAO,CAAC,kCAAkC;CAC5C,CACF,CAAC,CAAC;CAEF,MAAM,WAAW,IAAI,mBAAwC;CAC7D,SAAS,OAAO,GAAG,SAAS,GAAG,WAAkB;CACjD,OAAO;AACT"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Linter } from "eslint";
|
|
2
|
+
//#region src/types.d.ts
|
|
3
|
+
type Awaitable<T> = T | Promise<T>;
|
|
4
|
+
type TypedFlatConfigItem = Linter.FlatConfig;
|
|
5
|
+
interface StylisticOptions {
|
|
6
|
+
indent?: 2 | 4;
|
|
7
|
+
quotes?: 'single' | 'double';
|
|
8
|
+
semi?: boolean;
|
|
9
|
+
maxLen?: number;
|
|
10
|
+
}
|
|
11
|
+
interface OptionsConfig {
|
|
12
|
+
/**
|
|
13
|
+
* Enable Vue rules when the project depends on Vue/Nuxt unless explicitly set.
|
|
14
|
+
*/
|
|
15
|
+
vue?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Enable Nuxt-specific rules when `nuxt` is installed unless explicitly set.
|
|
18
|
+
*/
|
|
19
|
+
nuxt?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Enable TypeScript rules when `typescript` is installed unless explicitly set.
|
|
22
|
+
*/
|
|
23
|
+
typescript?: boolean;
|
|
24
|
+
stylistic?: boolean | StylisticOptions;
|
|
25
|
+
/**
|
|
26
|
+
* Extra ignores appended to defaults.
|
|
27
|
+
*/
|
|
28
|
+
ignores?: string[];
|
|
29
|
+
/**
|
|
30
|
+
* Pass-through overrides merged last.
|
|
31
|
+
*/
|
|
32
|
+
overrides?: Linter.RulesRecord;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/nuxt.d.ts
|
|
36
|
+
interface NuxtPresetOptions {
|
|
37
|
+
stylistic?: boolean | StylisticOptions;
|
|
38
|
+
overrides?: Record<string, unknown>;
|
|
39
|
+
}
|
|
40
|
+
declare function nuxt(options?: NuxtPresetOptions): Promise<TypedFlatConfigItem[]>[];
|
|
41
|
+
//#endregion
|
|
42
|
+
export { StylisticOptions as a, OptionsConfig as i, nuxt as n, TypedFlatConfigItem as o, Awaitable as r, NuxtPresetOptions as t };
|
|
43
|
+
//# sourceMappingURL=nuxt-CehpYBa3.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nuxt-CehpYBa3.d.mts","names":[],"sources":["../src/types.ts","../src/nuxt.ts"],"mappings":";;KAEY,UAAU,KAAK,IAAI,QAAQ;KAE3B,sBAAsB,OAAO;UAExB;EACf;EACA;EACA;EACA;;UAGe;;;;EAIf;;;;EAIA;;;;EAIA;EACA,sBAAsB;;;;EAItB;;;;EAIA,YAAY,OAAO;;;;UCzBJ;EACf,sBAAsB;EACtB,YAAY;;iBAGE,KAAK,UAAS,oBAAsB,QAAA"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
//#region src/configs/shared-rules.ts
|
|
2
|
+
function sharedRules() {
|
|
3
|
+
return {
|
|
4
|
+
"no-console": ["error", { allow: ["warn", "error"] }],
|
|
5
|
+
"no-debugger": "error",
|
|
6
|
+
"eqeqeq": ["error", "always"],
|
|
7
|
+
"object-shorthand": ["error", "always"],
|
|
8
|
+
"prefer-template": "error",
|
|
9
|
+
"curly": ["error", "all"],
|
|
10
|
+
"arrow-body-style": ["error", "as-needed"],
|
|
11
|
+
"@typescript-eslint/no-unused-vars": ["error", {
|
|
12
|
+
argsIgnorePattern: "^_",
|
|
13
|
+
varsIgnorePattern: "^_",
|
|
14
|
+
caughtErrorsIgnorePattern: "^_",
|
|
15
|
+
destructuredArrayIgnorePattern: "^_"
|
|
16
|
+
}],
|
|
17
|
+
"@typescript-eslint/consistent-type-imports": ["error", {
|
|
18
|
+
prefer: "type-imports",
|
|
19
|
+
disallowTypeAnnotations: false
|
|
20
|
+
}],
|
|
21
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
22
|
+
"@typescript-eslint/no-non-null-assertion": "error",
|
|
23
|
+
"@typescript-eslint/no-empty-function": ["error", { allow: ["arrowFunctions"] }],
|
|
24
|
+
"@typescript-eslint/no-magic-numbers": ["warn", {
|
|
25
|
+
ignore: [
|
|
26
|
+
-1,
|
|
27
|
+
0,
|
|
28
|
+
1,
|
|
29
|
+
2,
|
|
30
|
+
1e3
|
|
31
|
+
],
|
|
32
|
+
ignoreEnums: true,
|
|
33
|
+
ignoreArrayIndexes: true,
|
|
34
|
+
ignoreDefaultValues: true,
|
|
35
|
+
ignoreClassFieldInitialValues: true,
|
|
36
|
+
ignoreReadonlyClassProperties: true
|
|
37
|
+
}]
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/configs/imports.ts
|
|
42
|
+
async function imports() {
|
|
43
|
+
const mod = await import("eslint-plugin-import-x");
|
|
44
|
+
return [{
|
|
45
|
+
name: "qstanay/imports",
|
|
46
|
+
plugins: { import: mod.default ?? mod },
|
|
47
|
+
rules: {
|
|
48
|
+
"import/first": "error",
|
|
49
|
+
"import/no-duplicates": "error",
|
|
50
|
+
"import/no-mutable-exports": "error",
|
|
51
|
+
"import/no-named-default": "error"
|
|
52
|
+
}
|
|
53
|
+
}];
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/configs/nuxt.ts
|
|
57
|
+
async function nuxt$1() {
|
|
58
|
+
const mod = await import("@nuxt/eslint-plugin");
|
|
59
|
+
return [{
|
|
60
|
+
name: "qstanay/nuxt",
|
|
61
|
+
plugins: { nuxt: mod.default ?? mod },
|
|
62
|
+
rules: { "nuxt/prefer-import-meta": "error" }
|
|
63
|
+
}];
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region src/configs/stylistic.ts
|
|
67
|
+
async function loadStylistic() {
|
|
68
|
+
const mod = await import("@stylistic/eslint-plugin");
|
|
69
|
+
return mod.default ?? mod;
|
|
70
|
+
}
|
|
71
|
+
async function stylistic(options = {}) {
|
|
72
|
+
const { indent = 2, quotes = "single", semi = true, maxLen = 100 } = options;
|
|
73
|
+
const plugin = await loadStylistic();
|
|
74
|
+
const config = plugin.configs.customize({
|
|
75
|
+
indent,
|
|
76
|
+
quotes,
|
|
77
|
+
semi,
|
|
78
|
+
jsx: false,
|
|
79
|
+
pluginName: "style"
|
|
80
|
+
});
|
|
81
|
+
return [{
|
|
82
|
+
name: "qstanay/stylistic",
|
|
83
|
+
plugins: { style: plugin },
|
|
84
|
+
rules: {
|
|
85
|
+
...config.rules ?? {},
|
|
86
|
+
"style/max-len": ["warn", {
|
|
87
|
+
code: maxLen,
|
|
88
|
+
ignoreUrls: true,
|
|
89
|
+
ignoreStrings: true,
|
|
90
|
+
ignoreTemplateLiterals: true,
|
|
91
|
+
ignoreComments: true,
|
|
92
|
+
ignoreTrailingComments: true,
|
|
93
|
+
ignoreRegExpLiterals: true
|
|
94
|
+
}]
|
|
95
|
+
}
|
|
96
|
+
}];
|
|
97
|
+
}
|
|
98
|
+
//#endregion
|
|
99
|
+
//#region src/configs/typescript.ts
|
|
100
|
+
async function typescript() {
|
|
101
|
+
const parserMod = await import("@typescript-eslint/parser");
|
|
102
|
+
const pluginMod = await import("@typescript-eslint/eslint-plugin");
|
|
103
|
+
const parser = parserMod.default ?? parserMod;
|
|
104
|
+
const plugin = pluginMod.default ?? pluginMod;
|
|
105
|
+
return [{
|
|
106
|
+
name: "qstanay/typescript",
|
|
107
|
+
files: ["**/*.{ts,tsx,cts,mts,vue}"],
|
|
108
|
+
languageOptions: {
|
|
109
|
+
parser,
|
|
110
|
+
parserOptions: {
|
|
111
|
+
sourceType: "module",
|
|
112
|
+
ecmaVersion: "latest"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
plugins: { "@typescript-eslint": plugin },
|
|
116
|
+
rules: { ...plugin.configs?.recommended?.rules ?? {} }
|
|
117
|
+
}];
|
|
118
|
+
}
|
|
119
|
+
//#endregion
|
|
120
|
+
//#region src/configs/vue.ts
|
|
121
|
+
async function vue() {
|
|
122
|
+
const vuePluginMod = await import("eslint-plugin-vue");
|
|
123
|
+
const vueParserMod = await import("vue-eslint-parser");
|
|
124
|
+
const vuePlugin = vuePluginMod.default ?? vuePluginMod;
|
|
125
|
+
return [{
|
|
126
|
+
name: "qstanay/vue",
|
|
127
|
+
files: ["**/*.vue"],
|
|
128
|
+
languageOptions: {
|
|
129
|
+
parser: vueParserMod.default ?? vueParserMod,
|
|
130
|
+
parserOptions: {
|
|
131
|
+
parser: {
|
|
132
|
+
ts: "@typescript-eslint/parser",
|
|
133
|
+
js: "espree"
|
|
134
|
+
},
|
|
135
|
+
ecmaVersion: "latest",
|
|
136
|
+
sourceType: "module",
|
|
137
|
+
extraFileExtensions: [".vue"]
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
plugins: { vue: vuePlugin },
|
|
141
|
+
rules: {
|
|
142
|
+
...vuePlugin.configs?.["flat/recommended"]?.[0]?.rules ?? {},
|
|
143
|
+
"vue/html-self-closing": ["error", {
|
|
144
|
+
html: {
|
|
145
|
+
void: "always",
|
|
146
|
+
normal: "always",
|
|
147
|
+
component: "always"
|
|
148
|
+
},
|
|
149
|
+
svg: "always",
|
|
150
|
+
math: "always"
|
|
151
|
+
}],
|
|
152
|
+
"vue/attributes-order": "error",
|
|
153
|
+
"vue/padding-line-between-tags": "error"
|
|
154
|
+
}
|
|
155
|
+
}];
|
|
156
|
+
}
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/nuxt.ts
|
|
159
|
+
function nuxt(options = {}) {
|
|
160
|
+
const stylisticOptions = options.stylistic === false ? false : typeof options.stylistic === "object" ? options.stylistic : {};
|
|
161
|
+
const configs = [
|
|
162
|
+
typescript(),
|
|
163
|
+
imports(),
|
|
164
|
+
vue(),
|
|
165
|
+
nuxt$1(),
|
|
166
|
+
Promise.resolve([{
|
|
167
|
+
name: "qstanay/nuxt/shared-rules",
|
|
168
|
+
files: ["**/*.{js,jsx,ts,tsx,cts,mts,vue}"],
|
|
169
|
+
rules: { ...sharedRules() }
|
|
170
|
+
}])
|
|
171
|
+
];
|
|
172
|
+
if (stylisticOptions) configs.unshift(stylistic(stylisticOptions));
|
|
173
|
+
return configs;
|
|
174
|
+
}
|
|
175
|
+
//#endregion
|
|
176
|
+
export { nuxt$1 as a, stylistic as i, vue as n, imports as o, typescript as r, sharedRules as s, nuxt as t };
|
|
177
|
+
|
|
178
|
+
//# sourceMappingURL=nuxt-Cz6LtoZ_.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nuxt-Cz6LtoZ_.mjs","names":["nuxt","typescriptConfig","vueConfig","nuxtConfig","stylisticConfig"],"sources":["../src/configs/shared-rules.ts","../src/configs/imports.ts","../src/configs/nuxt.ts","../src/configs/stylistic.ts","../src/configs/typescript.ts","../src/configs/vue.ts","../src/nuxt.ts"],"sourcesContent":["import type { Linter } from 'eslint';\n\nexport function sharedRules(): Linter.RulesRecord {\n return {\n // JavaScript logic\n 'no-console': ['error', { allow: ['warn', 'error'] }],\n 'no-debugger': 'error',\n 'eqeqeq': ['error', 'always'],\n 'object-shorthand': ['error', 'always'],\n 'prefer-template': 'error',\n 'curly': ['error', 'all'],\n 'arrow-body-style': ['error', 'as-needed'],\n\n // TypeScript logic\n '@typescript-eslint/no-unused-vars': [\n 'error',\n {\n argsIgnorePattern: '^_',\n varsIgnorePattern: '^_',\n caughtErrorsIgnorePattern: '^_',\n destructuredArrayIgnorePattern: '^_',\n },\n ],\n '@typescript-eslint/consistent-type-imports': [\n 'error',\n { prefer: 'type-imports', disallowTypeAnnotations: false },\n ],\n '@typescript-eslint/no-explicit-any': 'warn',\n '@typescript-eslint/no-non-null-assertion': 'error',\n '@typescript-eslint/no-empty-function': ['error', { allow: ['arrowFunctions'] }],\n '@typescript-eslint/no-magic-numbers': [\n 'warn',\n {\n ignore: [-1, 0, 1, 2, 1000],\n ignoreEnums: true,\n ignoreArrayIndexes: true,\n ignoreDefaultValues: true,\n ignoreClassFieldInitialValues: true,\n ignoreReadonlyClassProperties: true,\n },\n ],\n };\n}\n","import type { TypedFlatConfigItem } from '../types';\n\nexport async function imports(): Promise<TypedFlatConfigItem[]> {\n const mod = await import('eslint-plugin-import-x');\n const plugin = (mod as any).default ?? mod;\n\n return [\n {\n name: 'qstanay/imports',\n plugins: {\n import: plugin,\n },\n rules: {\n 'import/first': 'error',\n 'import/no-duplicates': 'error',\n 'import/no-mutable-exports': 'error',\n 'import/no-named-default': 'error',\n },\n },\n ];\n}\n","import type { TypedFlatConfigItem } from '../types';\n\nexport async function nuxt(): Promise<TypedFlatConfigItem[]> {\n const mod = await import('@nuxt/eslint-plugin');\n const plugin = (mod as any).default ?? mod;\n\n return [\n {\n name: 'qstanay/nuxt',\n plugins: {\n nuxt: plugin,\n },\n rules: {\n // keep this minimal; Nuxt base config already provides most of it\n 'nuxt/prefer-import-meta': 'error',\n },\n },\n ];\n}\n","import type { TypedFlatConfigItem, StylisticOptions } from '../types';\n\nasync function loadStylistic() {\n const mod = await import('@stylistic/eslint-plugin');\n return mod.default ?? mod;\n}\n\nexport async function stylistic(\n options: StylisticOptions = {},\n): Promise<TypedFlatConfigItem[]> {\n const {\n indent = 2,\n quotes = 'single',\n semi = true,\n maxLen = 100,\n } = options;\n\n const plugin = await loadStylistic();\n\n // `customize()` gives us a coherent bundle of stylistic rules.\n // Plugin name is fixed to `style` for stable rule IDs.\n const config = plugin.configs.customize({\n indent,\n quotes,\n semi,\n jsx: false,\n pluginName: 'style',\n }) as TypedFlatConfigItem;\n\n return [\n {\n name: 'qstanay/stylistic',\n plugins: {\n style: plugin,\n },\n rules: {\n ...(config.rules ?? {}),\n // Keep max line length aligned across all projects.\n 'style/max-len': [\n 'warn',\n {\n code: maxLen,\n ignoreUrls: true,\n ignoreStrings: true,\n ignoreTemplateLiterals: true,\n ignoreComments: true,\n ignoreTrailingComments: true,\n ignoreRegExpLiterals: true,\n },\n ],\n },\n },\n ];\n}\n","import type { TypedFlatConfigItem } from '../types';\n\nexport async function typescript(): Promise<TypedFlatConfigItem[]> {\n const parserMod = await import('@typescript-eslint/parser');\n const pluginMod = await import('@typescript-eslint/eslint-plugin');\n\n const parser = (parserMod as any).default ?? parserMod;\n const plugin = (pluginMod as any).default ?? pluginMod;\n\n return [\n {\n name: 'qstanay/typescript',\n files: ['**/*.{ts,tsx,cts,mts,vue}'],\n languageOptions: {\n parser,\n parserOptions: {\n sourceType: 'module',\n ecmaVersion: 'latest',\n },\n },\n plugins: {\n '@typescript-eslint': plugin,\n },\n rules: {\n ...(plugin.configs?.recommended?.rules ?? {}),\n },\n },\n ];\n}\n","import type { TypedFlatConfigItem } from '../types';\n\nexport async function vue(): Promise<TypedFlatConfigItem[]> {\n const vuePluginMod = await import('eslint-plugin-vue');\n const vueParserMod = await import('vue-eslint-parser');\n\n const vuePlugin = (vuePluginMod as any).default ?? vuePluginMod;\n const vueParser = (vueParserMod as any).default ?? vueParserMod;\n\n return [\n {\n name: 'qstanay/vue',\n files: ['**/*.vue'],\n languageOptions: {\n parser: vueParser,\n parserOptions: {\n parser: {\n ts: '@typescript-eslint/parser',\n js: 'espree',\n },\n ecmaVersion: 'latest',\n sourceType: 'module',\n extraFileExtensions: ['.vue'],\n },\n },\n plugins: {\n vue: vuePlugin,\n },\n rules: {\n ...(vuePlugin.configs?.['flat/recommended']?.[0]?.rules ?? {}),\n 'vue/html-self-closing': [\n 'error',\n {\n html: {\n void: 'always',\n normal: 'always',\n component: 'always',\n },\n svg: 'always',\n math: 'always',\n },\n ],\n 'vue/attributes-order': 'error',\n 'vue/padding-line-between-tags': 'error',\n },\n },\n ];\n}\n","import type { StylisticOptions, TypedFlatConfigItem } from './types';\n\nimport { sharedRules } from './configs/shared-rules';\nimport { imports } from './configs/imports';\nimport { nuxt as nuxtConfig } from './configs/nuxt';\nimport { stylistic as stylisticConfig } from './configs/stylistic';\nimport { typescript as typescriptConfig } from './configs/typescript';\nimport { vue as vueConfig } from './configs/vue';\n\nexport interface NuxtPresetOptions {\n stylistic?: boolean | StylisticOptions;\n overrides?: Record<string, unknown>;\n}\n\nexport function nuxt(options: NuxtPresetOptions = {}) {\n const stylisticOptions = options.stylistic === false\n ? false\n : typeof options.stylistic === 'object'\n ? options.stylistic\n : {};\n\n const configs: Promise<TypedFlatConfigItem[]>[] = [\n typescriptConfig(),\n imports(),\n vueConfig(),\n nuxtConfig(),\n Promise.resolve([\n {\n name: 'qstanay/nuxt/shared-rules',\n files: ['**/*.{js,jsx,ts,tsx,cts,mts,vue}'],\n rules: {\n ...sharedRules(),\n },\n },\n ]),\n ];\n\n if (stylisticOptions) {\n configs.unshift(stylisticConfig(stylisticOptions));\n }\n\n return configs;\n}\n"],"mappings":"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"}
|
package/dist/nuxt.d.mts
ADDED
package/dist/nuxt.mjs
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@qstanay/eslint-config",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Opinionated ESLint flat config for Nuxt, Vue and TypeScript",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./dist/index.mjs",
|
|
8
|
+
"./nuxt": "./dist/nuxt.mjs",
|
|
9
|
+
"./package.json": "./package.json"
|
|
10
|
+
},
|
|
11
|
+
"types": "./dist/index.d.mts",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsdown --clean --dts",
|
|
14
|
+
"dev": "tsdown --watch",
|
|
15
|
+
"lint": "eslint .",
|
|
16
|
+
"lint:fix": "eslint . --fix",
|
|
17
|
+
"test": "vitest",
|
|
18
|
+
"typecheck": "tsc --noEmit"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/qstanay/eslint-config.git"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [],
|
|
25
|
+
"author": "",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/qstanay/eslint-config/issues"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/qstanay/eslint-config#readme",
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"eslint": "^9.0.0 || ^10.0.0"
|
|
36
|
+
},
|
|
37
|
+
"peerDependenciesMeta": {
|
|
38
|
+
"typescript": {
|
|
39
|
+
"optional": true
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@nuxt/eslint-plugin": "^1.16.0",
|
|
44
|
+
"@stylistic/eslint-plugin": "^5.10.0",
|
|
45
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
46
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
47
|
+
"eslint-config-flat-gitignore": "^2.3.0",
|
|
48
|
+
"eslint-flat-config-utils": "^3.2.0",
|
|
49
|
+
"eslint-plugin-import-x": "^4.0.0",
|
|
50
|
+
"eslint-plugin-vue": "^10.0.0",
|
|
51
|
+
"eslint-processor-vue-blocks": "^2.0.0",
|
|
52
|
+
"globals": "^17.0.0",
|
|
53
|
+
"local-pkg": "^1.2.0",
|
|
54
|
+
"vue-eslint-parser": "^10.0.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/node": "^26.1.1",
|
|
58
|
+
"eslint": "^10.7.0",
|
|
59
|
+
"jiti": "^2.5.1",
|
|
60
|
+
"tsdown": "^0.22.7",
|
|
61
|
+
"typescript": "^6.0.3",
|
|
62
|
+
"vitest": "^4.1.10"
|
|
63
|
+
}
|
|
64
|
+
}
|