@qstanay/eslint-config 1.0.1 → 1.0.2

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/CHANGELOG.md ADDED
@@ -0,0 +1,48 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ ## [1.0.2] - 2026-07-18
6
+
7
+ ### Added
8
+
9
+ - `@eslint/js` recommended as the JavaScript baseline in `defineConfig()`
10
+ - Autofixable `import/order` (grouped + alphabetized)
11
+ - `strict` option for `defineConfig()` / `nuxt()` to opt into stricter TypeScript rules (e.g. `no-magic-numbers`)
12
+ - `ignores` option on the Nuxt preset (`nuxt({ ignores: [...] })`)
13
+ - npm `keywords` for discoverability
14
+
15
+ ### Changed
16
+
17
+ - `no-magic-numbers` is no longer enabled by default (use `strict: true`)
18
+ - When TypeScript is enabled, turn off conflicting base rules (`no-unused-vars`, `no-undef`)
19
+
20
+ ## [1.0.1] - 2026-07-18
21
+
22
+ ### Fixed
23
+
24
+ - Correctly apply the full `eslint-plugin-vue` `flat/recommended` preset (previously only `[0].rules` was used, which contained no rules)
25
+ - Include TypeScript shared rules only when TypeScript is enabled (JS-only projects no longer crash on a missing `@typescript-eslint` plugin)
26
+ - Apply `overrides` in a trailing config block so they win over shared/Vue rules in both `defineConfig()` and `nuxt()`
27
+
28
+ ### Added
29
+
30
+ - Honor project `.gitignore` in ignores and add `coverage` to default ignores
31
+ - Browser `globals` for Vue; load TypeScript rules from `flat/recommended`
32
+ - `prepublishOnly` build hook
33
+ - Expanded README for humans and agents
34
+ - Tests for JS-only setups, Vue recommended rules, and overrides behavior
35
+
36
+ ### Removed
37
+
38
+ - Unused dependency `eslint-processor-vue-blocks`
39
+
40
+ ## [1.0.0] - 2026-07-13
41
+
42
+ ### Added
43
+
44
+ - Initial release of `@qstanay/eslint-config`
45
+ - `defineConfig()` for Vue and TypeScript projects
46
+ - `@qstanay/eslint-config/nuxt` layer for use with `@nuxt/eslint` + `withNuxt()`
47
+ - Stylistic formatting via `@stylistic` (`eslint --fix`)
48
+ - Shared opinionated JS/TS rules, import hygiene, and Vue opinionated extras
package/README.md CHANGED
@@ -125,6 +125,7 @@ Main entry for Vue / TypeScript projects.
125
125
  | `vue` | `boolean` | auto (`vue` or `nuxt` installed) | Enable Vue rules |
126
126
  | `typescript` | `boolean` | auto (`typescript` installed) | Enable TypeScript rules |
127
127
  | `nuxt` | `boolean` | auto (`nuxt` installed) | Enable Nuxt plugin rule(s). Prefer `/nuxt` for Nuxt apps |
128
+ | `strict` | `boolean` | `false` | Stricter TS rules (e.g. `no-magic-numbers`) |
128
129
  | `stylistic` | `false \| object` | enabled | Formatting rules (see below) |
129
130
  | `overrides` | `Linter.RulesRecord` | `{}` | Custom rules merged last over shared rules |
130
131
  | `ignores` | `string[]` | `[]` | Extra ignore globs |
@@ -150,7 +151,9 @@ Layer for Nuxt apps used with `withNuxt(...nuxt())`.
150
151
  | Option | Type | Default | Description |
151
152
  |---|---|---|---|
152
153
  | `stylistic` | `false \| object` | enabled | Formatting rules (see below) |
154
+ | `strict` | `boolean` | `false` | Stricter TS rules (e.g. `no-magic-numbers`) |
153
155
  | `overrides` | `Linter.RulesRecord` | `{}` | Custom rules merged last over shared rules |
156
+ | `ignores` | `string[]` | `[]` | Extra ignore globs (plus defaults / `.gitignore`) |
154
157
 
155
158
  There are no `vue` / `typescript` flags here — `@nuxt/eslint` already provides that stack. This preset adds shared opinionated rules, Vue opinionated rules, and stylistic formatting.
156
159
 
@@ -205,9 +208,12 @@ Built-in ignores cover `node_modules`, `dist`, `.output`, `.nuxt`, `.nitro`, `co
205
208
  defineConfig({
206
209
  ignores: ['**/fixtures/**'],
207
210
  })
208
- ```
209
211
 
210
- `ignores` is only on `defineConfig`, not on the Nuxt preset (use Nuxt / ESLint ignore mechanisms there if needed).
212
+ // Nuxt:
213
+ nuxt({
214
+ ignores: ['**/fixtures/**'],
215
+ })
216
+ ```
211
217
 
212
218
  ## Prettier
213
219
 
@@ -263,11 +269,13 @@ Disable Prettier for the same file types (or uninstall / disable the Prettier ex
263
269
 
264
270
  ## What this preset enforces (high level)
265
271
 
266
- - Shared JS rules always; TypeScript opinionated rules only when TypeScript is enabled (so JS-only projects stay valid)
267
- - Official `eslint-plugin-vue` `flat/recommended` when Vue is enabled, plus a small opinionated Vue layer (self-closing tags, attribute order, padding between tags)
272
+ - `@eslint/js` recommended as the JS baseline in `defineConfig()`
273
+ - Shared opinionated JS rules always; TypeScript opinionated rules only when TypeScript is enabled
274
+ - Official `eslint-plugin-vue` `flat/recommended` when Vue is enabled, plus a small opinionated Vue layer
268
275
  - Stylistic formatting via `@stylistic` (rule namespace: `style/*`)
269
- - Import hygiene via `eslint-plugin-import-x` in `defineConfig` (Nuxt relies on `@nuxt/eslint` for its own import/TS/Vue stack)
276
+ - Import hygiene + autofixable `import/order` via `eslint-plugin-import-x` in `defineConfig` (Nuxt relies on `@nuxt/eslint` for its own import/TS/Vue stack)
270
277
  - `overrides` are applied in a trailing config block so they win over shared/Vue rules
278
+ - Optional `strict: true` for noisier TypeScript checks like `no-magic-numbers`
271
279
 
272
280
  ## Agent / setup checklist
273
281
 
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as StylisticOptions, i as OptionsConfig, n as nuxt, o as TypedFlatConfigItem, r as Awaitable } from "./nuxt-D-E7z44c.mjs";
1
+ import { a as StylisticOptions, i as OptionsConfig, n as nuxt, o as TypedFlatConfigItem, r as Awaitable } from "./nuxt-B4vvMBlj.mjs";
2
2
  import { FlatConfigComposer } from "eslint-flat-config-utils";
3
3
  //#region src/index.d.ts
4
4
  declare function defineConfig(options?: OptionsConfig, ...userConfigs: (Awaitable<TypedFlatConfigItem | TypedFlatConfigItem[]>)[]): FlatConfigComposer<TypedFlatConfigItem, never>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;iBAegB,aACd,UAAS,kBACN,cAAc,UAAU,sBAAsB,4BAAyB,mBAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;iBAiBgB,aACd,UAAS,kBACN,cAAc,UAAU,sBAAsB,4BAAyB,mBAAA"}
package/dist/index.mjs CHANGED
@@ -1,22 +1,5 @@
1
- import { a as SOURCE_FILES, c as has, i as sharedRules, l as resolveEnabled, n as vueRules, o as TYPESCRIPT_FILES, r as stylistic, s as VUE_FILES, t as nuxt, u as resolveStylisticOptions } from "./nuxt-HGf9trGQ.mjs";
1
+ import { a as VUE_FILES, c as resolveStylisticOptions, d as ignores, i as TYPESCRIPT_FILES, l as stylistic, n as vueRules, o as has, r as SOURCE_FILES, s as resolveEnabled, t as nuxt, u as sharedRules } from "./nuxt-B6cDasrO.mjs";
2
2
  import { FlatConfigComposer } from "eslint-flat-config-utils";
3
- import gitignore from "eslint-config-flat-gitignore";
4
- //#region src/configs/ignores.ts
5
- function ignores(extraIgnores = []) {
6
- return [gitignore({ strict: false }), {
7
- name: "qstanay/ignores",
8
- ignores: [
9
- "**/node_modules/**",
10
- "**/dist/**",
11
- "**/.output/**",
12
- "**/.nuxt/**",
13
- "**/.nitro/**",
14
- "**/coverage/**",
15
- ...extraIgnores
16
- ]
17
- }];
18
- }
19
- //#endregion
20
3
  //#region src/configs/imports.ts
21
4
  async function imports() {
22
5
  const mod = await import("eslint-plugin-import-x");
@@ -27,11 +10,42 @@ async function imports() {
27
10
  "import/first": "error",
28
11
  "import/no-duplicates": "error",
29
12
  "import/no-mutable-exports": "error",
30
- "import/no-named-default": "error"
13
+ "import/no-named-default": "error",
14
+ "import/order": ["error", {
15
+ "groups": [
16
+ "builtin",
17
+ "external",
18
+ "internal",
19
+ [
20
+ "parent",
21
+ "sibling",
22
+ "index"
23
+ ],
24
+ "object",
25
+ "type"
26
+ ],
27
+ "newlines-between": "always",
28
+ "alphabetize": {
29
+ order: "asc",
30
+ caseInsensitive: true
31
+ }
32
+ }]
31
33
  }
32
34
  }];
33
35
  }
34
36
  //#endregion
37
+ //#region src/configs/javascript.ts
38
+ /**
39
+ * Base JS quality rules from `@eslint/js` recommended.
40
+ */
41
+ async function javascript() {
42
+ const mod = await import("@eslint/js");
43
+ return [{
44
+ name: "qstanay/javascript",
45
+ rules: { ...(mod.default ?? mod).configs?.recommended?.rules ?? {} }
46
+ }];
47
+ }
48
+ //#endregion
35
49
  //#region src/configs/nuxt.ts
36
50
  async function nuxt$1() {
37
51
  const mod = await import("@nuxt/eslint-plugin");
@@ -105,6 +119,7 @@ function defineConfig(options = {}, ...userConfigs) {
105
119
  const stylisticOptions = resolveStylisticOptions(options.stylistic);
106
120
  const configs = [];
107
121
  configs.push(Promise.resolve(ignores(options.ignores)));
122
+ configs.push(javascript());
108
123
  if (enableTs) configs.push(typescript());
109
124
  configs.push(imports());
110
125
  if (stylisticOptions) configs.push(stylistic(stylisticOptions));
@@ -113,7 +128,10 @@ function defineConfig(options = {}, ...userConfigs) {
113
128
  configs.push(Promise.resolve([{
114
129
  name: "qstanay/shared-rules",
115
130
  files: [...SOURCE_FILES],
116
- rules: sharedRules({ typescript: enableTs })
131
+ rules: sharedRules({
132
+ typescript: enableTs,
133
+ strict: options.strict
134
+ })
117
135
  }]));
118
136
  if (options.overrides) configs.push(Promise.resolve([{
119
137
  name: "qstanay/overrides",
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["nuxt","typescriptConfig","stylisticConfig","vueConfig","nuxtConfig"],"sources":["../src/configs/ignores.ts","../src/configs/imports.ts","../src/configs/nuxt.ts","../src/configs/typescript.ts","../src/configs/vue.ts","../src/index.ts"],"sourcesContent":["import type { TypedFlatConfigItem } from '../types';\n\nimport gitignore from 'eslint-config-flat-gitignore';\n\nexport function ignores(extraIgnores: string[] = []): TypedFlatConfigItem[] {\n return [\n // Prefer project .gitignore when present; do not fail if missing.\n gitignore({ strict: false }),\n {\n name: 'qstanay/ignores',\n ignores: [\n '**/node_modules/**',\n '**/dist/**',\n '**/.output/**',\n '**/.nuxt/**',\n '**/.nitro/**',\n '**/coverage/**',\n ...extraIgnores,\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 { Linter } from 'eslint';\n\nimport type { TypedFlatConfigItem } from '../types';\n\nimport { TYPESCRIPT_FILES } from '../utils';\n\nfunction collectRules(configs: TypedFlatConfigItem[]): Linter.RulesRecord {\n return Object.assign(\n {},\n ...configs\n .filter(config => config.rules)\n .map(config => config.rules),\n );\n}\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 const recommended = (plugin.configs?.['flat/recommended'] ?? []) as TypedFlatConfigItem[];\n\n return [\n {\n name: 'qstanay/typescript',\n files: [...TYPESCRIPT_FILES],\n languageOptions: {\n parser,\n parserOptions: {\n sourceType: 'module',\n ecmaVersion: 'latest',\n extraFileExtensions: ['.vue'],\n },\n },\n plugins: {\n '@typescript-eslint': plugin,\n },\n rules: collectRules(recommended),\n },\n ];\n}\n","import type { TypedFlatConfigItem } from '../types';\n\nimport { VUE_FILES } from '../utils';\nimport { vueRules } from './vue-rules';\n\n/**\n * Vue layer based on the official flat recommended preset.\n * Must spread the full array — it includes setup, processor, and rule packs.\n */\nexport async function vue(): Promise<TypedFlatConfigItem[]> {\n const vuePluginMod = await import('eslint-plugin-vue');\n const globalsMod = await import('globals');\n\n const vuePlugin = (vuePluginMod as any).default ?? vuePluginMod;\n const globals = (globalsMod as any).default ?? globalsMod;\n\n const recommended = (vuePlugin.configs?.['flat/recommended'] ?? []) as TypedFlatConfigItem[];\n\n return [\n ...recommended,\n {\n name: 'qstanay/vue/rules',\n files: [...VUE_FILES],\n languageOptions: {\n globals: {\n ...globals.browser,\n },\n parserOptions: {\n // Keep vue-eslint-parser as the root parser (from recommended),\n // and parse <script lang=\"ts\"> with the TS parser.\n parser: {\n ts: '@typescript-eslint/parser',\n js: 'espree',\n },\n ecmaVersion: 'latest',\n sourceType: 'module',\n extraFileExtensions: ['.vue'],\n },\n },\n rules: {\n ...vueRules(),\n },\n },\n ];\n}\n","import type { Awaitable, OptionsConfig, TypedFlatConfigItem } from './types';\n\nimport { FlatConfigComposer } from 'eslint-flat-config-utils';\nimport { has, resolveEnabled, resolveStylisticOptions, SOURCE_FILES } 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 const stylisticOptions = resolveStylisticOptions(options.stylistic);\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 files: [...SOURCE_FILES],\n rules: sharedRules({ typescript: enableTs }),\n },\n ]));\n\n if (options.overrides) {\n // Trailing block so project overrides win over shared/vue/ts packs.\n configs.push(Promise.resolve([\n {\n name: 'qstanay/overrides',\n files: [...SOURCE_FILES],\n rules: options.overrides,\n },\n ]));\n }\n\n const composer = new FlatConfigComposer<TypedFlatConfigItem>();\n composer.append(...configs, ...userConfigs as any);\n return composer;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["nuxt","javascriptConfig","typescriptConfig","stylisticConfig","vueConfig","nuxtConfig"],"sources":["../src/configs/imports.ts","../src/configs/javascript.ts","../src/configs/nuxt.ts","../src/configs/typescript.ts","../src/configs/vue.ts","../src/index.ts"],"sourcesContent":["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 'import/order': [\n 'error',\n {\n 'groups': [\n 'builtin',\n 'external',\n 'internal',\n ['parent', 'sibling', 'index'],\n 'object',\n 'type',\n ],\n 'newlines-between': 'always',\n 'alphabetize': {\n order: 'asc',\n caseInsensitive: true,\n },\n },\n ],\n },\n },\n ];\n}\n","import type { TypedFlatConfigItem } from '../types';\n\n/**\n * Base JS quality rules from `@eslint/js` recommended.\n */\nexport async function javascript(): Promise<TypedFlatConfigItem[]> {\n const mod = await import('@eslint/js');\n const js = (mod as any).default ?? mod;\n\n return [\n {\n name: 'qstanay/javascript',\n rules: {\n ...(js.configs?.recommended?.rules ?? {}),\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 { TYPESCRIPT_FILES } from '../utils';\n\nimport type { TypedFlatConfigItem } from '../types';\nimport type { Linter } from 'eslint';\n\nfunction collectRules(configs: TypedFlatConfigItem[]): Linter.RulesRecord {\n return Object.assign(\n {},\n ...configs\n .filter(config => config.rules)\n .map(config => config.rules),\n );\n}\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 const recommended = (plugin.configs?.['flat/recommended'] ?? []) as TypedFlatConfigItem[];\n\n return [\n {\n name: 'qstanay/typescript',\n files: [...TYPESCRIPT_FILES],\n languageOptions: {\n parser,\n parserOptions: {\n sourceType: 'module',\n ecmaVersion: 'latest',\n extraFileExtensions: ['.vue'],\n },\n },\n plugins: {\n '@typescript-eslint': plugin,\n },\n rules: collectRules(recommended),\n },\n ];\n}\n","import { VUE_FILES } from '../utils';\nimport { vueRules } from './vue-rules';\n\nimport type { TypedFlatConfigItem } from '../types';\n\n/**\n * Vue layer based on the official flat recommended preset.\n * Must spread the full array — it includes setup, processor, and rule packs.\n */\nexport async function vue(): Promise<TypedFlatConfigItem[]> {\n const vuePluginMod = await import('eslint-plugin-vue');\n const globalsMod = await import('globals');\n\n const vuePlugin = (vuePluginMod as any).default ?? vuePluginMod;\n const globals = (globalsMod as any).default ?? globalsMod;\n\n const recommended = (vuePlugin.configs?.['flat/recommended'] ?? []) as TypedFlatConfigItem[];\n\n return [\n ...recommended,\n {\n name: 'qstanay/vue/rules',\n files: [...VUE_FILES],\n languageOptions: {\n globals: {\n ...globals.browser,\n },\n parserOptions: {\n // Keep vue-eslint-parser as the root parser (from recommended),\n // and parse <script lang=\"ts\"> with the TS parser.\n parser: {\n ts: '@typescript-eslint/parser',\n js: 'espree',\n },\n ecmaVersion: 'latest',\n sourceType: 'module',\n extraFileExtensions: ['.vue'],\n },\n },\n rules: {\n ...vueRules(),\n },\n },\n ];\n}\n","import { FlatConfigComposer } from 'eslint-flat-config-utils';\n\nimport { ignores } from './configs/ignores';\nimport { imports } from './configs/imports';\nimport { javascript as javascriptConfig } from './configs/javascript';\nimport { nuxt as nuxtConfig } from './configs/nuxt';\nimport { sharedRules } from './configs/shared-rules';\nimport { stylistic as stylisticConfig } from './configs/stylistic';\nimport { typescript as typescriptConfig } from './configs/typescript';\nimport { vue as vueConfig } from './configs/vue';\nimport { has, resolveEnabled, resolveStylisticOptions, SOURCE_FILES } from './utils';\n\nimport type { Awaitable, OptionsConfig, TypedFlatConfigItem } from './types';\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 const stylisticOptions = resolveStylisticOptions(options.stylistic);\n\n const configs: (Awaitable<TypedFlatConfigItem[]>)[] = [];\n\n configs.push(Promise.resolve(ignores(options.ignores)));\n configs.push(javascriptConfig());\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 files: [...SOURCE_FILES],\n rules: sharedRules({\n typescript: enableTs,\n strict: options.strict,\n }),\n },\n ]));\n\n if (options.overrides) {\n // Trailing block so project overrides win over shared/vue/ts packs.\n configs.push(Promise.resolve([\n {\n name: 'qstanay/overrides',\n files: [...SOURCE_FILES],\n rules: options.overrides,\n },\n ]));\n }\n\n const composer = new FlatConfigComposer<TypedFlatConfigItem>();\n composer.append(...configs, ...userConfigs as any);\n return composer;\n}\n"],"mappings":"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"}
@@ -21,6 +21,11 @@ interface OptionsConfig {
21
21
  * Enable TypeScript rules when `typescript` is installed unless explicitly set.
22
22
  */
23
23
  typescript?: boolean;
24
+ /**
25
+ * Enable stricter opinionated TypeScript rules (e.g. `no-magic-numbers`).
26
+ * Off by default to keep app/UI code quiet.
27
+ */
28
+ strict?: boolean;
24
29
  stylistic?: boolean | StylisticOptions;
25
30
  /**
26
31
  * Extra ignores appended to defaults.
@@ -35,7 +40,15 @@ interface OptionsConfig {
35
40
  //#region src/nuxt.d.ts
36
41
  interface NuxtPresetOptions {
37
42
  stylistic?: boolean | StylisticOptions;
43
+ /**
44
+ * Enable stricter opinionated TypeScript rules (e.g. `no-magic-numbers`).
45
+ */
46
+ strict?: boolean;
38
47
  overrides?: Linter.RulesRecord;
48
+ /**
49
+ * Extra ignores appended to defaults / `.gitignore`.
50
+ */
51
+ ignores?: string[];
39
52
  }
40
53
  /**
41
54
  * Opinionated layer for Nuxt apps.
@@ -47,4 +60,4 @@ interface NuxtPresetOptions {
47
60
  declare function nuxt(options?: NuxtPresetOptions): Promise<TypedFlatConfigItem[]>[];
48
61
  //#endregion
49
62
  export { StylisticOptions as a, OptionsConfig as i, nuxt as n, TypedFlatConfigItem as o, Awaitable as r, NuxtPresetOptions as t };
50
- //# sourceMappingURL=nuxt-D-E7z44c.d.mts.map
63
+ //# sourceMappingURL=nuxt-B4vvMBlj.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nuxt-B4vvMBlj.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;;;;;EAKA;EACA,sBAAsB;;;;EAItB;;;;EAIA,YAAY,OAAO;;;;UC9BJ;EACf,sBAAsB;;;;EAItB;EACA,YAAY,OAAO;;;;EAInB;;;;;;;;;iBAUc,KAAK,UAAS,oBAAsB,QAAA"}
@@ -1,19 +1,20 @@
1
+ import gitignore from "eslint-config-flat-gitignore";
1
2
  import { isPackageExists } from "local-pkg";
2
- //#region src/utils.ts
3
- function resolveEnabled(explicit, detected) {
4
- return explicit ?? detected;
5
- }
6
- function has(pkg) {
7
- return isPackageExists(pkg);
8
- }
9
- function resolveStylisticOptions(stylistic) {
10
- if (stylistic === false) return false;
11
- if (typeof stylistic === "object") return stylistic;
12
- return {};
3
+ //#region src/configs/ignores.ts
4
+ function ignores(extraIgnores = []) {
5
+ return [gitignore({ strict: false }), {
6
+ name: "qstanay/ignores",
7
+ ignores: [
8
+ "**/node_modules/**",
9
+ "**/dist/**",
10
+ "**/.output/**",
11
+ "**/.nuxt/**",
12
+ "**/.nitro/**",
13
+ "**/coverage/**",
14
+ ...extraIgnores
15
+ ]
16
+ }];
13
17
  }
14
- const SOURCE_FILES = ["**/*.{js,jsx,ts,tsx,cts,mts,vue}"];
15
- const TYPESCRIPT_FILES = ["**/*.{ts,tsx,cts,mts}", "**/*.vue"];
16
- const VUE_FILES = ["**/*.vue"];
17
18
  //#endregion
18
19
  //#region src/configs/shared-rules.ts
19
20
  function javascriptRules() {
@@ -27,8 +28,10 @@ function javascriptRules() {
27
28
  "arrow-body-style": ["error", "as-needed"]
28
29
  };
29
30
  }
30
- function typescriptRules() {
31
- return {
31
+ function typescriptRules(options = {}) {
32
+ const rules = {
33
+ "no-unused-vars": "off",
34
+ "no-undef": "off",
32
35
  "@typescript-eslint/no-unused-vars": ["error", {
33
36
  argsIgnorePattern: "^_",
34
37
  varsIgnorePattern: "^_",
@@ -41,22 +44,23 @@ function typescriptRules() {
41
44
  }],
42
45
  "@typescript-eslint/no-explicit-any": "warn",
43
46
  "@typescript-eslint/no-non-null-assertion": "error",
44
- "@typescript-eslint/no-empty-function": ["error", { allow: ["arrowFunctions"] }],
45
- "@typescript-eslint/no-magic-numbers": ["warn", {
46
- ignore: [
47
- -1,
48
- 0,
49
- 1,
50
- 2,
51
- 1e3
52
- ],
53
- ignoreEnums: true,
54
- ignoreArrayIndexes: true,
55
- ignoreDefaultValues: true,
56
- ignoreClassFieldInitialValues: true,
57
- ignoreReadonlyClassProperties: true
58
- }]
47
+ "@typescript-eslint/no-empty-function": ["error", { allow: ["arrowFunctions"] }]
59
48
  };
49
+ if (options.strict) rules["@typescript-eslint/no-magic-numbers"] = ["warn", {
50
+ ignore: [
51
+ -1,
52
+ 0,
53
+ 1,
54
+ 2,
55
+ 1e3
56
+ ],
57
+ ignoreEnums: true,
58
+ ignoreArrayIndexes: true,
59
+ ignoreDefaultValues: true,
60
+ ignoreClassFieldInitialValues: true,
61
+ ignoreReadonlyClassProperties: true
62
+ }];
63
+ return rules;
60
64
  }
61
65
  /**
62
66
  * Shared opinionated rules.
@@ -66,7 +70,7 @@ function typescriptRules() {
66
70
  function sharedRules(options = {}) {
67
71
  return {
68
72
  ...javascriptRules(),
69
- ...options.typescript ? typescriptRules() : {}
73
+ ...options.typescript ? typescriptRules({ strict: options.strict }) : {}
70
74
  };
71
75
  }
72
76
  //#endregion
@@ -103,6 +107,22 @@ async function stylistic(options = {}) {
103
107
  }];
104
108
  }
105
109
  //#endregion
110
+ //#region src/utils.ts
111
+ function resolveEnabled(explicit, detected) {
112
+ return explicit ?? detected;
113
+ }
114
+ function has(pkg) {
115
+ return isPackageExists(pkg);
116
+ }
117
+ function resolveStylisticOptions(stylistic) {
118
+ if (stylistic === false) return false;
119
+ if (typeof stylistic === "object") return stylistic;
120
+ return {};
121
+ }
122
+ const SOURCE_FILES = ["**/*.{js,jsx,ts,tsx,cts,mts,vue}"];
123
+ const TYPESCRIPT_FILES = ["**/*.{ts,tsx,cts,mts}", "**/*.vue"];
124
+ const VUE_FILES = ["**/*.vue"];
125
+ //#endregion
106
126
  //#region src/configs/vue-rules.ts
107
127
  function vueRules() {
108
128
  return {
@@ -130,12 +150,15 @@ function vueRules() {
130
150
  */
131
151
  function nuxt(options = {}) {
132
152
  const stylisticOptions = resolveStylisticOptions(options.stylistic);
133
- const configs = [];
153
+ const configs = [Promise.resolve(ignores(options.ignores))];
134
154
  if (stylisticOptions) configs.push(stylistic(stylisticOptions));
135
155
  configs.push(Promise.resolve([{
136
156
  name: "qstanay/nuxt/shared-rules",
137
157
  files: [...SOURCE_FILES],
138
- rules: sharedRules({ typescript: true })
158
+ rules: sharedRules({
159
+ typescript: true,
160
+ strict: options.strict
161
+ })
139
162
  }, {
140
163
  name: "qstanay/nuxt/vue-rules",
141
164
  files: [...VUE_FILES],
@@ -149,6 +172,6 @@ function nuxt(options = {}) {
149
172
  return configs;
150
173
  }
151
174
  //#endregion
152
- export { SOURCE_FILES as a, has as c, sharedRules as i, resolveEnabled as l, vueRules as n, TYPESCRIPT_FILES as o, stylistic as r, VUE_FILES as s, nuxt as t, resolveStylisticOptions as u };
175
+ export { VUE_FILES as a, resolveStylisticOptions as c, ignores as d, TYPESCRIPT_FILES as i, stylistic as l, vueRules as n, has as o, SOURCE_FILES as r, resolveEnabled as s, nuxt as t, sharedRules as u };
153
176
 
154
- //# sourceMappingURL=nuxt-HGf9trGQ.mjs.map
177
+ //# sourceMappingURL=nuxt-B6cDasrO.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nuxt-B6cDasrO.mjs","names":["stylisticConfig"],"sources":["../src/configs/ignores.ts","../src/configs/shared-rules.ts","../src/configs/stylistic.ts","../src/utils.ts","../src/configs/vue-rules.ts","../src/nuxt.ts"],"sourcesContent":["import gitignore from 'eslint-config-flat-gitignore';\n\nimport type { TypedFlatConfigItem } from '../types';\n\nexport function ignores(extraIgnores: string[] = []): TypedFlatConfigItem[] {\n return [\n // Prefer project .gitignore when present; do not fail if missing.\n gitignore({ strict: false }),\n {\n name: 'qstanay/ignores',\n ignores: [\n '**/node_modules/**',\n '**/dist/**',\n '**/.output/**',\n '**/.nuxt/**',\n '**/.nitro/**',\n '**/coverage/**',\n ...extraIgnores,\n ],\n },\n ];\n}\n","import type { Linter } from 'eslint';\n\nexport function javascriptRules(): Linter.RulesRecord {\n return {\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}\n\nexport function typescriptRules(options: { strict?: boolean } = {}): Linter.RulesRecord {\n const rules: Linter.RulesRecord = {\n // Disable base rules that conflict with TypeScript-aware variants.\n 'no-unused-vars': 'off',\n 'no-undef': 'off',\n\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 };\n\n if (options.strict) {\n rules['@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 return rules;\n}\n\n/**\n * Shared opinionated rules.\n * TypeScript rules are included only when `typescript` is true,\n * so JS-only projects do not reference a missing plugin.\n */\nexport function sharedRules(options: {\n typescript?: boolean;\n strict?: boolean;\n} = {}): Linter.RulesRecord {\n return {\n ...javascriptRules(),\n ...(options.typescript\n ? typescriptRules({ strict: options.strict })\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 { isPackageExists } from 'local-pkg';\n\nimport type { StylisticOptions } from './types';\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\nexport function resolveStylisticOptions(\n stylistic: boolean | StylisticOptions | undefined,\n): false | StylisticOptions {\n if (stylistic === false) {\n return false;\n }\n\n if (typeof stylistic === 'object') {\n return stylistic;\n }\n\n return {};\n}\n\nexport const SOURCE_FILES = ['**/*.{js,jsx,ts,tsx,cts,mts,vue}'] as const;\nexport const TYPESCRIPT_FILES = ['**/*.{ts,tsx,cts,mts}', '**/*.vue'] as const;\nexport const VUE_FILES = ['**/*.vue'] as const;\n","import type { Linter } from 'eslint';\n\nexport function vueRules(): Linter.RulesRecord {\n return {\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","import { ignores } from './configs/ignores';\nimport { sharedRules } from './configs/shared-rules';\nimport { stylistic as stylisticConfig } from './configs/stylistic';\nimport { vueRules } from './configs/vue-rules';\nimport { resolveStylisticOptions, SOURCE_FILES, VUE_FILES } from './utils';\n\nimport type { StylisticOptions, TypedFlatConfigItem } from './types';\nimport type { Linter } from 'eslint';\n\nexport interface NuxtPresetOptions {\n stylistic?: boolean | StylisticOptions;\n /**\n * Enable stricter opinionated TypeScript rules (e.g. `no-magic-numbers`).\n */\n strict?: boolean;\n overrides?: Linter.RulesRecord;\n /**\n * Extra ignores appended to defaults / `.gitignore`.\n */\n ignores?: string[];\n}\n\n/**\n * Opinionated layer for Nuxt apps.\n *\n * Intended to be used with `@nuxt/eslint` + `withNuxt()`:\n * Nuxt already provides TypeScript/Vue/import plugins, so this preset\n * only adds stylistic formatting and shared opinionated rules.\n */\nexport function nuxt(options: NuxtPresetOptions = {}) {\n const stylisticOptions = resolveStylisticOptions(options.stylistic);\n const configs: Promise<TypedFlatConfigItem[]>[] = [\n Promise.resolve(ignores(options.ignores)),\n ];\n\n if (stylisticOptions) {\n configs.push(stylisticConfig(stylisticOptions));\n }\n\n configs.push(Promise.resolve([\n {\n name: 'qstanay/nuxt/shared-rules',\n files: [...SOURCE_FILES],\n // Host (@nuxt/eslint) registers @typescript-eslint; include TS rules.\n rules: sharedRules({\n typescript: true,\n strict: options.strict,\n }),\n },\n {\n name: 'qstanay/nuxt/vue-rules',\n files: [...VUE_FILES],\n rules: {\n ...vueRules(),\n },\n },\n ]));\n\n if (options.overrides) {\n // Dedicated trailing block so overrides always win over vue/shared rules.\n configs.push(Promise.resolve([\n {\n name: 'qstanay/nuxt/overrides',\n files: [...SOURCE_FILES],\n rules: options.overrides,\n },\n ]));\n }\n\n return configs;\n}\n"],"mappings":"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"}
package/dist/nuxt.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { n as nuxt, t as NuxtPresetOptions } from "./nuxt-D-E7z44c.mjs";
1
+ import { n as nuxt, t as NuxtPresetOptions } from "./nuxt-B4vvMBlj.mjs";
2
2
  export { NuxtPresetOptions, nuxt };
package/dist/nuxt.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { t as nuxt } from "./nuxt-HGf9trGQ.mjs";
1
+ import { t as nuxt } from "./nuxt-B6cDasrO.mjs";
2
2
  export { nuxt };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qstanay/eslint-config",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Opinionated ESLint flat config for Nuxt, Vue and TypeScript",
5
5
  "type": "module",
6
6
  "exports": {
@@ -22,7 +22,16 @@
22
22
  "type": "git",
23
23
  "url": "git+https://github.com/qstanay/eslint-config.git"
24
24
  },
25
- "keywords": [],
25
+ "keywords": [
26
+ "eslint",
27
+ "eslint-config",
28
+ "eslintconfig",
29
+ "flat-config",
30
+ "nuxt",
31
+ "vue",
32
+ "typescript",
33
+ "stylistic"
34
+ ],
26
35
  "author": "",
27
36
  "license": "MIT",
28
37
  "bugs": {
@@ -30,7 +39,8 @@
30
39
  },
31
40
  "homepage": "https://github.com/qstanay/eslint-config#readme",
32
41
  "files": [
33
- "dist"
42
+ "dist",
43
+ "CHANGELOG.md"
34
44
  ],
35
45
  "peerDependencies": {
36
46
  "eslint": "^9.0.0 || ^10.0.0"
@@ -41,6 +51,7 @@
41
51
  }
42
52
  },
43
53
  "dependencies": {
54
+ "@eslint/js": "^10.0.1",
44
55
  "@nuxt/eslint-plugin": "^1.16.0",
45
56
  "@stylistic/eslint-plugin": "^5.10.0",
46
57
  "@typescript-eslint/eslint-plugin": "^8.0.0",
@@ -56,7 +67,6 @@
56
67
  "devDependencies": {
57
68
  "@types/node": "^26.1.1",
58
69
  "eslint": "^10.7.0",
59
- "jiti": "^2.5.1",
60
70
  "tsdown": "^0.22.7",
61
71
  "typescript": "^6.0.3",
62
72
  "vitest": "^4.1.10"
@@ -1 +0,0 @@
1
- {"version":3,"file":"nuxt-D-E7z44c.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,OAAO;;;;;;;;;iBAUL,KAAK,UAAS,oBAAsB,QAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"nuxt-HGf9trGQ.mjs","names":["stylisticConfig"],"sources":["../src/utils.ts","../src/configs/shared-rules.ts","../src/configs/stylistic.ts","../src/configs/vue-rules.ts","../src/nuxt.ts"],"sourcesContent":["import type { StylisticOptions } from './types';\n\nimport { 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\nexport function resolveStylisticOptions(\n stylistic: boolean | StylisticOptions | undefined,\n): false | StylisticOptions {\n if (stylistic === false) {\n return false;\n }\n\n if (typeof stylistic === 'object') {\n return stylistic;\n }\n\n return {};\n}\n\nexport const SOURCE_FILES = ['**/*.{js,jsx,ts,tsx,cts,mts,vue}'] as const;\nexport const TYPESCRIPT_FILES = ['**/*.{ts,tsx,cts,mts}', '**/*.vue'] as const;\nexport const VUE_FILES = ['**/*.vue'] as const;\n","import type { Linter } from 'eslint';\n\nexport function javascriptRules(): Linter.RulesRecord {\n return {\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}\n\nexport function typescriptRules(): Linter.RulesRecord {\n return {\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\n/**\n * Shared opinionated rules.\n * TypeScript rules are included only when `typescript` is true,\n * so JS-only projects do not reference a missing plugin.\n */\nexport function sharedRules(options: { typescript?: boolean } = {}): Linter.RulesRecord {\n return {\n ...javascriptRules(),\n ...(options.typescript ? typescriptRules() : {}),\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 { Linter } from 'eslint';\n\nexport function vueRules(): Linter.RulesRecord {\n return {\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","import type { Linter } from 'eslint';\n\nimport type { StylisticOptions, TypedFlatConfigItem } from './types';\n\nimport { sharedRules } from './configs/shared-rules';\nimport { stylistic as stylisticConfig } from './configs/stylistic';\nimport { vueRules } from './configs/vue-rules';\nimport { resolveStylisticOptions, SOURCE_FILES, VUE_FILES } from './utils';\n\nexport interface NuxtPresetOptions {\n stylistic?: boolean | StylisticOptions;\n overrides?: Linter.RulesRecord;\n}\n\n/**\n * Opinionated layer for Nuxt apps.\n *\n * Intended to be used with `@nuxt/eslint` + `withNuxt()`:\n * Nuxt already provides TypeScript/Vue/import plugins, so this preset\n * only adds stylistic formatting and shared opinionated rules.\n */\nexport function nuxt(options: NuxtPresetOptions = {}) {\n const stylisticOptions = resolveStylisticOptions(options.stylistic);\n const configs: Promise<TypedFlatConfigItem[]>[] = [];\n\n if (stylisticOptions) {\n configs.push(stylisticConfig(stylisticOptions));\n }\n\n configs.push(Promise.resolve([\n {\n name: 'qstanay/nuxt/shared-rules',\n files: [...SOURCE_FILES],\n // Host (@nuxt/eslint) registers @typescript-eslint; include TS rules.\n rules: sharedRules({ typescript: true }),\n },\n {\n name: 'qstanay/nuxt/vue-rules',\n files: [...VUE_FILES],\n rules: {\n ...vueRules(),\n },\n },\n ]));\n\n if (options.overrides) {\n // Dedicated trailing block so overrides always win over vue/shared rules.\n configs.push(Promise.resolve([\n {\n name: 'qstanay/nuxt/overrides',\n files: [...SOURCE_FILES],\n rules: options.overrides,\n },\n ]));\n }\n\n return configs;\n}\n"],"mappings":";;AAIA,SAAgB,eAAe,UAA+B,UAAmB;CAC/E,OAAO,YAAY;AACrB;AAEA,SAAgB,IAAI,KAAa;CAC/B,OAAO,gBAAgB,GAAG;AAC5B;AAEA,SAAgB,wBACd,WAC0B;CAC1B,IAAI,cAAc,OAChB,OAAO;CAGT,IAAI,OAAO,cAAc,UACvB,OAAO;CAGT,OAAO,CAAC;AACV;AAEA,MAAa,eAAe,CAAC,kCAAkC;AAC/D,MAAa,mBAAmB,CAAC,yBAAyB,UAAU;AACpE,MAAa,YAAY,CAAC,UAAU;;;AC1BpC,SAAgB,kBAAsC;CACpD,OAAO;EACL,cAAc,CAAC,SAAS,EAAE,OAAO,CAAC,QAAQ,OAAO,EAAE,CAAC;EACpD,eAAe;EACf,UAAU,CAAC,SAAS,QAAQ;EAC5B,oBAAoB,CAAC,SAAS,QAAQ;EACtC,mBAAmB;EACnB,SAAS,CAAC,SAAS,KAAK;EACxB,oBAAoB,CAAC,SAAS,WAAW;CAC3C;AACF;AAEA,SAAgB,kBAAsC;CACpD,OAAO;EACL,qCAAqC,CACnC,SACA;GACE,mBAAmB;GACnB,mBAAmB;GACnB,2BAA2B;GAC3B,gCAAgC;EAClC,CACF;EACA,8CAA8C,CAC5C,SACA;GAAE,QAAQ;GAAgB,yBAAyB;EAAM,CAC3D;EACA,sCAAsC;EACtC,4CAA4C;EAC5C,wCAAwC,CAAC,SAAS,EAAE,OAAO,CAAC,gBAAgB,EAAE,CAAC;EAC/E,uCAAuC,CACrC,QACA;GACE,QAAQ;IAAC;IAAI;IAAG;IAAG;IAAG;GAAI;GAC1B,aAAa;GACb,oBAAoB;GACpB,qBAAqB;GACrB,+BAA+B;GAC/B,+BAA+B;EACjC,CACF;CACF;AACF;;;;;;AAOA,SAAgB,YAAY,UAAoC,CAAC,GAAuB;CACtF,OAAO;EACL,GAAG,gBAAgB;EACnB,GAAI,QAAQ,aAAa,gBAAgB,IAAI,CAAC;CAChD;AACF;;;ACtDA,eAAe,gBAAgB;CAC7B,MAAM,MAAM,MAAM,OAAO;CACzB,OAAO,IAAI,WAAW;AACxB;AAEA,eAAsB,UACpB,UAA4B,CAAC,GACG;CAChC,MAAM,EACJ,SAAS,GACT,SAAS,UACT,OAAO,MACP,SAAS,QACP;CAEJ,MAAM,SAAS,MAAM,cAAc;CAInC,MAAM,SAAS,OAAO,QAAQ,UAAU;EACtC;EACA;EACA;EACA,KAAK;EACL,YAAY;CACd,CAAC;CAED,OAAO,CACL;EACE,MAAM;EACN,SAAS,EACP,OAAO,OACT;EACA,OAAO;GACL,GAAI,OAAO,SAAS,CAAC;GAErB,iBAAiB,CACf,QACA;IACE,MAAM;IACN,YAAY;IACZ,eAAe;IACf,wBAAwB;IACxB,gBAAgB;IAChB,wBAAwB;IACxB,sBAAsB;GACxB,CACF;EACF;CACF,CACF;AACF;;;ACnDA,SAAgB,WAA+B;CAC7C,OAAO;EACL,yBAAyB,CACvB,SACA;GACE,MAAM;IACJ,MAAM;IACN,QAAQ;IACR,WAAW;GACb;GACA,KAAK;GACL,MAAM;EACR,CACF;EACA,wBAAwB;EACxB,iCAAiC;CACnC;AACF;;;;;;;;;;ACEA,SAAgB,KAAK,UAA6B,CAAC,GAAG;CACpD,MAAM,mBAAmB,wBAAwB,QAAQ,SAAS;CAClE,MAAM,UAA4C,CAAC;CAEnD,IAAI,kBACF,QAAQ,KAAKA,UAAgB,gBAAgB,CAAC;CAGhD,QAAQ,KAAK,QAAQ,QAAQ,CAC3B;EACE,MAAM;EACN,OAAO,CAAC,GAAG,YAAY;EAEvB,OAAO,YAAY,EAAE,YAAY,KAAK,CAAC;CACzC,GACA;EACE,MAAM;EACN,OAAO,CAAC,GAAG,SAAS;EACpB,OAAO,EACL,GAAG,SAAS,EACd;CACF,CACF,CAAC,CAAC;CAEF,IAAI,QAAQ,WAEV,QAAQ,KAAK,QAAQ,QAAQ,CAC3B;EACE,MAAM;EACN,OAAO,CAAC,GAAG,YAAY;EACvB,OAAO,QAAQ;CACjB,CACF,CAAC,CAAC;CAGJ,OAAO;AACT"}