@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 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
+
@@ -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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"}
@@ -0,0 +1,2 @@
1
+ import { n as nuxt, t as NuxtPresetOptions } from "./nuxt-CehpYBa3.mjs";
2
+ export { NuxtPresetOptions, nuxt };
package/dist/nuxt.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { t as nuxt } from "./nuxt-Cz6LtoZ_.mjs";
2
+ export { nuxt };
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
+ }