@santi020k/eslint-config-basic 1.5.0 → 2.0.0-beta.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/dist/index.js CHANGED
@@ -1,52 +1,126 @@
1
- import { applyStrictMode } from "./compose.js";
2
- import { getOptionalConfigs, getPrettierConfig } from "./optionals.js";
3
- import { resolveFramework, resolvePreset } from "./resolvers.js";
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
4
3
  import {
5
4
  coreConfig,
6
5
  createCoreConfig,
7
6
  detectProjectOptions,
7
+ Extension,
8
+ Format,
8
9
  gitignore,
10
+ Library,
9
11
  NextMode,
12
+ Preset,
10
13
  Runtime,
11
- Setting
14
+ Setting,
15
+ Testing,
16
+ Tool
12
17
  } from "@santi020k/eslint-config-core";
13
18
  import { createTypescriptConfig } from "@santi020k/eslint-config-typescript";
19
+ import { applyStrictMode } from "./compose.js";
20
+ import { createDetectedFrameworkFlags } from "./frameworks.js";
21
+ import { getIntegrationConfigs, getPrettierConfig } from "./integrations.js";
22
+ import { resolveFramework, resolvePreset } from "./resolvers.js";
23
+ import {
24
+ AGENT_TARGETS,
25
+ generateAgentSkills,
26
+ generateSkillContent
27
+ } from "./agent-skill-generator.js";
28
+ import {
29
+ angular,
30
+ angularConfig,
31
+ astro,
32
+ expo,
33
+ expoConfig,
34
+ hono,
35
+ lit,
36
+ nest,
37
+ nestConfig,
38
+ next,
39
+ nextConfig,
40
+ nuxt,
41
+ preact,
42
+ preactConfig,
43
+ qwik,
44
+ react,
45
+ reactConfig,
46
+ reactRouter,
47
+ remix,
48
+ slidev,
49
+ solid,
50
+ solidConfig,
51
+ svelte,
52
+ svelteConfig,
53
+ tanstackStart,
54
+ vite,
55
+ vue,
56
+ vueConfig
57
+ } from "./frameworks.js";
14
58
  import {
15
59
  coreConfig as coreConfig2,
16
60
  createCoreConfig as createCoreConfig2,
61
+ createImportGroups,
17
62
  detectProjectOptions as detectProjectOptions2,
18
- Extension,
19
- Format,
63
+ Extension as Extension2,
64
+ Format as Format2,
20
65
  getGlobalsForRuntime,
21
66
  gitignore as gitignore2,
67
+ groups,
22
68
  hasReactConfig,
23
69
  jsConfig,
24
- Library,
70
+ Library as Library2,
25
71
  NextMode as NextMode2,
26
- Preset,
72
+ Preset as Preset2,
27
73
  ReactConfigKeys,
28
74
  Runtime as Runtime2,
29
75
  Setting as Setting2,
30
- Testing,
31
- Tool
76
+ Testing as Testing2,
77
+ Tool as Tool2
32
78
  } from "@santi020k/eslint-config-core";
33
- import { tsConfig, typescriptConfig } from "@santi020k/eslint-config-typescript";
34
79
  import {
80
+ a11y,
81
+ aiSdk,
82
+ autogen,
35
83
  bestPractices,
84
+ biome,
85
+ command,
86
+ compat,
36
87
  cspell,
88
+ css,
37
89
  cypress,
90
+ deMorgan,
91
+ depend,
92
+ docker,
93
+ drizzle,
94
+ githubActions,
95
+ googleGenAi,
38
96
  graphql,
97
+ html,
39
98
  i18next,
40
99
  jest,
100
+ jestDom,
41
101
  jsdoc,
42
102
  jsonc,
103
+ langchain,
104
+ llamaIndex,
43
105
  markdown,
106
+ mastra,
107
+ mcp,
44
108
  mdx,
109
+ mikroOrm,
110
+ node,
111
+ noOnlyTests,
112
+ nx,
113
+ openAiAgents,
114
+ oxlint,
115
+ packageJson,
45
116
  perfectionist,
46
117
  playwright,
118
+ pnpm,
47
119
  prettier,
120
+ prisma,
48
121
  regexp,
49
122
  security,
123
+ sequelize,
50
124
  sonarjs,
51
125
  stencil,
52
126
  storybook,
@@ -56,77 +130,379 @@ import {
56
130
  tanstackRouter,
57
131
  testingLibrary,
58
132
  toml,
133
+ turbo,
134
+ typeorm,
59
135
  unicorn,
60
136
  vitest,
61
- yaml
62
- } from "@santi020k/eslint-config-optionals";
63
- const eslintConfig = (options) => {
64
- const detected = detectProjectOptions();
65
- const preset = options?.preset ?? detected.preset;
66
- const presetDefaults = preset ? resolvePreset(preset) : {};
67
- const {
68
- typescript = presetDefaults.typescript ?? detected.typescript ?? false,
69
- libraries = presetDefaults.libraries ?? detected.libraries ?? [],
70
- testing = presetDefaults.testing ?? detected.testing ?? [],
71
- formats = presetDefaults.formats ?? detected.formats ?? [],
72
- tools = presetDefaults.tools ?? detected.tools ?? [],
73
- extensions = presetDefaults.extensions ?? detected.extensions ?? [],
74
- settings = options?.settings ?? detected.settings ?? [],
75
- strict = options?.strict ?? false,
76
- runtime = presetDefaults.runtime ?? detected.runtime ?? Runtime.Universal,
77
- tsconfigRootDir = options?.tsconfigRootDir,
78
- nextMode = presetDefaults.nextMode ?? detected.nextMode ?? NextMode.Pages,
79
- frameworks = { ...presetDefaults.frameworks, ...options?.frameworks }
80
- } = options ?? {};
81
- const uniqueLibraries = [...new Set(libraries)];
82
- const uniqueTesting = [...new Set(testing)];
83
- const uniqueFormats = [...new Set(formats)];
84
- const uniqueTools = [...new Set(tools)];
85
- const uniqueExtensions = [...new Set(extensions)];
86
- const uniqueSettings = [...new Set(settings)];
87
- if ((frameworks.next || frameworks.expo) && !frameworks.react) {
88
- throw new TypeError(
89
- "Next and Expo configurations require frameworks.react. Import @santi020k/eslint-config-react and pass it via frameworks.react."
137
+ yaml,
138
+ zod
139
+ } from "@santi020k/eslint-config-integrations";
140
+ import { tsConfig, typescriptConfig } from "@santi020k/eslint-config-typescript";
141
+ const toUniqueArray = (values) => [...new Set(values)];
142
+ const DEFAULT_IGNORES = [
143
+ "**/dist/**",
144
+ "**/build/**",
145
+ "**/coverage/**",
146
+ "**/.turbo/**",
147
+ "**/.next/**",
148
+ "**/.open-next/**",
149
+ "**/.astro/**",
150
+ "**/.svelte-kit/**",
151
+ "**/.vercel/**",
152
+ "**/.wrangler/**",
153
+ "**/playwright-report/**",
154
+ "**/test-results/**",
155
+ "**/node_modules/**",
156
+ "**/tsconfig.tsbuildinfo",
157
+ // Package manager lock files (machine-generated, slow to lint)
158
+ "**/pnpm-lock.yaml",
159
+ "**/yarn.lock",
160
+ "**/package-lock.json",
161
+ "**/bun.lock",
162
+ "**/bun.lockb",
163
+ // AI coding-assistant artifacts (rule/skill folders managed by tools, not source code)
164
+ "**/.agent/**",
165
+ "**/.agents/**",
166
+ "**/.aider*",
167
+ "**/.aider*/**",
168
+ "**/.claude/**",
169
+ "**/.clinerules/**",
170
+ "**/.codex/**",
171
+ "**/.copilot/**",
172
+ "**/.cursor/**",
173
+ "**/.gemini/**",
174
+ "**/.kiro/**",
175
+ "**/.opencode/**",
176
+ "**/.roo/**",
177
+ "**/.windsurf/**"
178
+ ];
179
+ const GENERATED_CODE_IGNORES = [
180
+ "**/__generated__/**",
181
+ "**/generated/**",
182
+ "**/codegen/**",
183
+ "**/*.generated.*",
184
+ "**/*.gen.*",
185
+ "**/graphql.ts",
186
+ "**/graphql.tsx",
187
+ "**/gql/**",
188
+ "**/.prisma/**"
189
+ ];
190
+ const TAILWIND_ENTRYPOINT_CANDIDATES = [
191
+ "src/styles/global.css",
192
+ "src/app/globals.css",
193
+ "src/globals.css",
194
+ "src/index.css",
195
+ "app/globals.css",
196
+ "styles/global.css"
197
+ ];
198
+ const OPTIONAL_BUCKETS = {
199
+ extensions: Object.values(Extension),
200
+ formats: Object.values(Format),
201
+ libraries: Object.values(Library),
202
+ testing: Object.values(Testing),
203
+ tools: Object.values(Tool)
204
+ };
205
+ const mergeArrayOption = (detectedValues, presetValues, explicitValues, strategy) => {
206
+ if (strategy === "replace") {
207
+ if (explicitValues) return toUniqueArray(explicitValues);
208
+ if (presetValues) return toUniqueArray(presetValues);
209
+ return toUniqueArray(detectedValues);
210
+ }
211
+ return toUniqueArray([
212
+ ...detectedValues,
213
+ ...presetValues ?? [],
214
+ ...explicitValues ?? []
215
+ ]);
216
+ };
217
+ const isOptionalBucketValue = (bucket, value) => OPTIONAL_BUCKETS[bucket].includes(value);
218
+ const getFeatureEntries = (options, bucket, enabled) => [
219
+ ...Object.entries(options?.features ?? {}),
220
+ ...Object.entries(options?.integrations ?? {})
221
+ ].filter(([name, value]) => value === enabled && isOptionalBucketValue(bucket, name)).map(([name]) => name);
222
+ const applyFeatureDisables = (values, options, bucket) => {
223
+ const disabled = new Set(getFeatureEntries(options, bucket, false));
224
+ return values.filter((value) => !disabled.has(value));
225
+ };
226
+ const mergeOptionalBucket = (bucket, detectedValues, presetValues, explicitValues, options, strategy) => {
227
+ const featureEntries = getFeatureEntries(options, bucket, true);
228
+ const combined = explicitValues !== void 0 || featureEntries.length > 0 ? [...explicitValues ?? [], ...featureEntries] : void 0;
229
+ return applyFeatureDisables(
230
+ mergeArrayOption(detectedValues, presetValues, combined, strategy),
231
+ options,
232
+ bucket
233
+ );
234
+ };
235
+ const mergeFrameworkOption = (detectedFrameworks, presetFrameworks, explicitFrameworks, strategy) => {
236
+ if (strategy === "replace") {
237
+ if (explicitFrameworks) return { ...explicitFrameworks };
238
+ if (presetFrameworks) return { ...presetFrameworks };
239
+ return { ...detectedFrameworks };
240
+ }
241
+ return {
242
+ ...detectedFrameworks,
243
+ ...presetFrameworks ?? {},
244
+ ...explicitFrameworks ?? {}
245
+ };
246
+ };
247
+ const resolveDetectionOptions = (detection, defaults = {}) => {
248
+ const defaultControls = {
249
+ extensions: true,
250
+ formats: true,
251
+ frameworks: true,
252
+ libraries: true,
253
+ nextMode: true,
254
+ projects: false,
255
+ runtime: true,
256
+ testing: true,
257
+ tools: true,
258
+ typescript: true,
259
+ ...defaults
260
+ };
261
+ if (detection === false) {
262
+ return Object.fromEntries(
263
+ Object.keys(defaultControls).map((key) => [key, false])
90
264
  );
91
265
  }
92
- const hasReact = !!frameworks.react;
93
- const hasVue = !!frameworks.vue;
94
- const hasSvelte = !!frameworks.svelte;
95
- const hasSolid = !!frameworks.solid;
96
- const useGitignore = !uniqueSettings.includes(Setting.NoGitignore);
97
- const reactParam = resolveFramework("react", frameworks.react);
98
- const nextParam = resolveFramework("next", frameworks.next);
99
- const astroParam = resolveFramework("astro", frameworks.astro, {
100
- hasReact,
101
- hasVue,
102
- hasSvelte,
103
- hasSolid
104
- });
105
- const expoParam = resolveFramework("expo", frameworks.expo);
106
- const nestParam = resolveFramework("nest", frameworks.nest);
107
- const honoParam = resolveFramework("hono", frameworks.hono, { runtime });
108
- const vueParam = resolveFramework("vue", frameworks.vue);
109
- const svelteParam = resolveFramework("svelte", frameworks.svelte);
110
- const solidParam = resolveFramework("solid", frameworks.solid);
111
- const angularParam = resolveFramework("angular", frameworks.angular);
112
- const qwikParam = resolveFramework("qwik", frameworks.qwik);
113
- const remixParam = resolveFramework("remix", frameworks.remix);
114
- const runtimeCoreConfig = runtime !== Runtime.Universal ? createCoreConfig(runtime) : coreConfig;
115
- const configs = [
116
- // Settings
117
- ...useGitignore ? gitignore : [],
118
- // Global TSConfig Root Dir fix
266
+ if (detection === true || detection === void 0) {
267
+ return defaultControls;
268
+ }
269
+ return {
270
+ ...defaultControls,
271
+ ...detection
272
+ };
273
+ };
274
+ const applyArrayControls = (controls, detected) => ({
275
+ detectedFrameworks: controls.frameworks ? detected.detectedFrameworks : [],
276
+ extensions: controls.extensions ? detected.extensions : [],
277
+ formats: controls.formats ? detected.formats : [],
278
+ libraries: controls.libraries ? detected.libraries : [],
279
+ testing: controls.testing ? detected.testing : [],
280
+ tools: controls.tools ? detected.tools : []
281
+ });
282
+ const applyScalarControls = (controls, detected) => ({
283
+ nextMode: controls.nextMode ? detected.nextMode : void 0,
284
+ preset: controls.typescript && controls.runtime ? detected.preset : void 0,
285
+ projects: controls.projects ? detected.projects : void 0,
286
+ runtime: controls.runtime ? detected.runtime : void 0,
287
+ typescript: controls.typescript ? detected.typescript : false
288
+ });
289
+ const applyDetectionControls = (detected, detection, defaults) => {
290
+ const controls = resolveDetectionOptions(detection, defaults);
291
+ return { ...detected, ...applyArrayControls(controls, detected), ...applyScalarControls(controls, detected) };
292
+ };
293
+ const getStrictMode = (explicitStrict, presetStrict) => explicitStrict ?? presetStrict ?? false;
294
+ const applyStrictProfileDefaults = (extensions, strict) => {
295
+ if (strict !== "pedantic") return extensions;
296
+ return toUniqueArray([...extensions, Extension.BestPractices]);
297
+ };
298
+ const hasTsconfig = (rootDir) => [
299
+ "tsconfig.eslint.json",
300
+ "tsconfig.json",
301
+ "tsconfig.base.json",
302
+ "tsconfig.app.json",
303
+ "tsconfig.node.json"
304
+ ].some((fileName) => existsSync(join(rootDir, fileName)));
305
+ const resolveTypescriptOptions = (typescript) => {
306
+ if (!typescript || typescript === "off") return false;
307
+ if (typescript === true) return { mode: "type-aware" };
308
+ if (typeof typescript === "string") return { mode: typescript };
309
+ if (typescript.mode === "off") return false;
310
+ return {
311
+ ...typescript,
312
+ mode: typescript.mode ?? "type-aware"
313
+ };
314
+ };
315
+ const resolveTsconfigRootDir = (rootDir, typescript, explicitRootDir) => {
316
+ if (explicitRootDir) return explicitRootDir;
317
+ return resolveTypescriptOptions(typescript) && hasTsconfig(rootDir) ? rootDir : void 0;
318
+ };
319
+ const findTailwindEntryPoint = (rootDir) => TAILWIND_ENTRYPOINT_CANDIDATES.find(
320
+ (candidate) => existsSync(join(rootDir, candidate))
321
+ );
322
+ const scopeFilePattern = (projectPath, pattern) => {
323
+ if (typeof pattern === "string") {
324
+ const isNegated = pattern.startsWith("!");
325
+ const basePattern = (isNegated ? pattern.slice(1) : pattern).replace(/^\.\//, "");
326
+ const scoped = `${projectPath.replace(/\/$/, "")}/${basePattern}`;
327
+ return isNegated ? `!${scoped}` : scoped;
328
+ }
329
+ if (Array.isArray(pattern)) {
330
+ return pattern.map((item) => scopeFilePattern(projectPath, item));
331
+ }
332
+ return pattern;
333
+ };
334
+ const scopeConfigToProject = (config, projectPath) => {
335
+ if ("ignores" in config && !config.files) {
336
+ return {
337
+ ...config,
338
+ ignores: config.ignores?.map((pattern) => scopeFilePattern(projectPath, pattern))
339
+ };
340
+ }
341
+ return {
342
+ ...config,
343
+ files: Array.isArray(config.files) ? config.files.map((pattern) => scopeFilePattern(projectPath, pattern)) : [`${projectPath.replace(/\/$/, "")}/**/*`]
344
+ };
345
+ };
346
+ const patchImportGroupsConfig = (config, workspacePatterns) => {
347
+ const rule = config.rules?.["simple-import-sort/imports"];
348
+ if (!Array.isArray(rule) || !rule[1]) return config;
349
+ const ruleOpts = rule[1];
350
+ const existingGroups = ruleOpts.groups ?? [];
351
+ if (existingGroups.length === 0) return config;
352
+ const externalIdx = existingGroups.findIndex((g) => g.some((p) => p.includes("^@?\\w")));
353
+ const insertAt = externalIdx >= 0 ? externalIdx : existingGroups.length;
354
+ return {
355
+ ...config,
356
+ rules: {
357
+ ...config.rules,
358
+ "simple-import-sort/imports": [
359
+ rule[0],
360
+ { ...ruleOpts, groups: [...existingGroups.slice(0, insertAt), workspacePatterns, ...existingGroups.slice(insertAt)] }
361
+ ]
362
+ }
363
+ };
364
+ };
365
+ const patchImportGroups = (allConfigs, workspacePrefixes) => {
366
+ const workspacePatterns = workspacePrefixes.map(
367
+ (p) => `^${p.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&")}(/.*|$)`
368
+ );
369
+ return allConfigs.map(
370
+ (item) => Array.isArray(item) ? item : patchImportGroupsConfig(item, workspacePatterns)
371
+ );
372
+ };
373
+ const resolveConfigSetup = (options) => ({
374
+ autoFrameworks: options?.autoFrameworks ?? true,
375
+ detectRootDir: options?.detectRootDir ?? options?.tsconfigRootDir,
376
+ optionMergeStrategy: options?.optionMergeStrategy ?? "merge",
377
+ requestedPreset: options?.preset
378
+ });
379
+ const resolvePresetMeta = (requestedPreset, detected, autoFrameworks) => {
380
+ const preset = requestedPreset ?? detected.preset;
381
+ const presetDefaults = preset ? resolvePreset(preset) : {};
382
+ const frameworkDefaults = autoFrameworks ? createDetectedFrameworkFlags(detected.detectedFrameworks) : {};
383
+ return { frameworkDefaults, preset, presetDefaults };
384
+ };
385
+ const resolveConfiguredProjects = (detected, options) => ({
386
+ ...detected.projects ?? {},
387
+ ...options?.projects ?? {}
388
+ });
389
+ const resolveBucketDefaults = (detected) => ({
390
+ detectedExtensions: detected.extensions ?? [],
391
+ detectedFormats: detected.formats ?? [],
392
+ detectedLibraries: detected.libraries ?? [],
393
+ detectedTesting: detected.testing ?? [],
394
+ detectedTools: detected.tools ?? []
395
+ });
396
+ const resolveNextModeValue = (options, presetDefaults, detected) => options?.nextMode ?? presetDefaults.nextMode ?? detected.nextMode ?? NextMode.Pages;
397
+ const resolveRuntimeValue = (options, presetDefaults, detected) => options?.runtime ?? presetDefaults.runtime ?? detected.runtime ?? Runtime.Universal;
398
+ const resolveSettingsValue = (options, detected) => options?.settings ?? detected.settings ?? [];
399
+ const resolveTypescriptValue = (options, presetDefaults, detected) => options?.typescript ?? presetDefaults.typescript ?? detected.typescript ?? false;
400
+ const needsReactAutoAdd = (frameworks) => Boolean(
401
+ frameworks.next ?? frameworks.expo ?? frameworks.remix ?? frameworks["react-router"] ?? (frameworks["tanstack-start"] && !frameworks.solid)
402
+ ) && !frameworks.react;
403
+ const applyFrameworkImpliedDeps = (frameworks) => {
404
+ const result = { ...frameworks };
405
+ if (needsReactAutoAdd(result)) result.react = true;
406
+ if (result.slidev && !result.vue) result.vue = true;
407
+ if (result.nuxt && !result.vue) result.vue = true;
408
+ return result;
409
+ };
410
+ const buildIgnoresConfig = (useDefaultIgnores, useGeneratedCodeIgnores, useGitignore, options) => ({
411
+ defaultIgnores: useDefaultIgnores ? [{
412
+ ignores: [...DEFAULT_IGNORES, ...useGeneratedCodeIgnores ? GENERATED_CODE_IGNORES : []],
413
+ name: "eslint-config-basic/default-ignores"
414
+ }] : [],
415
+ gitignoreConfig: useGitignore ? gitignore : [],
416
+ userIgnores: options?.ignores?.length ? [{
417
+ ignores: options.ignores,
418
+ name: "eslint-config-basic/ignores"
419
+ }] : []
420
+ });
421
+ const buildEslintConfigs = async (params) => {
422
+ const {
423
+ astroOptions,
424
+ defaultIgnores,
425
+ gitignoreConfig,
426
+ nextMode,
427
+ resolvedFrameworks,
428
+ resolvedTypescript,
429
+ rootDir: _rootDir,
430
+ runtime,
431
+ runtimeCoreConfig,
432
+ tailwindEntryPoint,
433
+ tsconfigRootDir,
434
+ uniqueExtensions,
435
+ uniqueFormats,
436
+ uniqueLibraries,
437
+ uniqueTesting,
438
+ uniqueTools,
439
+ userIgnores
440
+ } = params;
441
+ const { hasReact, hasSolid, hasSvelte, hasVue } = astroOptions;
442
+ const [
443
+ reactParam,
444
+ nextParam,
445
+ astroParam,
446
+ expoParam,
447
+ nestParam,
448
+ honoParam,
449
+ vueParam,
450
+ svelteParam,
451
+ solidParam,
452
+ angularParam,
453
+ qwikParam,
454
+ remixParam,
455
+ reactRouterParam,
456
+ tanstackStartParam,
457
+ nuxtParam,
458
+ preactParam,
459
+ litParam,
460
+ slidevParam,
461
+ viteParam
462
+ ] = await Promise.all([
463
+ resolveFramework("react", resolvedFrameworks.react),
464
+ resolveFramework("next", resolvedFrameworks.next),
465
+ resolveFramework("astro", resolvedFrameworks.astro, { hasReact, hasSolid, hasSvelte, hasVue }),
466
+ resolveFramework("expo", resolvedFrameworks.expo),
467
+ resolveFramework("nest", resolvedFrameworks.nest),
468
+ resolveFramework("hono", resolvedFrameworks.hono, { runtime }),
469
+ resolveFramework("vue", resolvedFrameworks.vue),
470
+ resolveFramework("svelte", resolvedFrameworks.svelte),
471
+ resolveFramework("solid", resolvedFrameworks.solid),
472
+ resolveFramework("angular", resolvedFrameworks.angular),
473
+ resolveFramework("qwik", resolvedFrameworks.qwik),
474
+ resolveFramework("remix", resolvedFrameworks.remix),
475
+ resolveFramework("react-router", resolvedFrameworks["react-router"]),
476
+ resolveFramework("tanstack-start", resolvedFrameworks["tanstack-start"]),
477
+ resolveFramework("nuxt", resolvedFrameworks.nuxt),
478
+ resolveFramework("preact", resolvedFrameworks.preact),
479
+ resolveFramework("lit", resolvedFrameworks.lit),
480
+ resolveFramework("slidev", resolvedFrameworks.slidev, { runtime }),
481
+ resolveFramework("vite", resolvedFrameworks.vite, { runtime })
482
+ ]);
483
+ return [
484
+ ...defaultIgnores,
485
+ ...userIgnores,
486
+ ...gitignoreConfig,
119
487
  ...tsconfigRootDir ? [{
120
- name: "eslint-config-basic/tsconfig-root-dir",
121
- languageOptions: {
122
- parserOptions: {
123
- tsconfigRootDir
124
- }
125
- }
488
+ languageOptions: { parserOptions: { tsconfigRootDir } },
489
+ name: "eslint-config-basic/tsconfig-root-dir"
126
490
  }] : [],
127
- // Core JS config with runtime-aware globals
491
+ {
492
+ files: ["**/*.cjs", "**/*.cts"],
493
+ languageOptions: {
494
+ globals: {
495
+ __dirname: "readonly",
496
+ __filename: "readonly",
497
+ exports: "readonly",
498
+ module: "readonly",
499
+ require: "readonly"
500
+ },
501
+ sourceType: "commonjs"
502
+ },
503
+ name: "eslint-config-basic/commonjs"
504
+ },
128
505
  ...runtimeCoreConfig,
129
- // React config (included if any React-based framework is used/passed)
130
506
  ...hasReact ? reactParam : [],
131
507
  ...nextParam,
132
508
  ...expoParam,
@@ -138,79 +514,310 @@ const eslintConfig = (options) => {
138
514
  ...angularParam,
139
515
  ...qwikParam,
140
516
  ...remixParam,
141
- ...typescript ? createTypescriptConfig({ tsconfigRootDir }) : [],
142
- // Astro needs to run after generic TypeScript so its parser and false-positive
143
- // workarounds win for .astro files and embedded expressions.
517
+ ...reactRouterParam,
518
+ ...tanstackStartParam,
519
+ ...nuxtParam,
520
+ ...preactParam,
521
+ ...litParam,
522
+ ...slidevParam,
523
+ ...viteParam,
524
+ ...resolvedTypescript ? createTypescriptConfig({
525
+ ...resolvedTypescript,
526
+ tsconfigRootDir: resolvedTypescript.tsconfigRootDir ?? tsconfigRootDir
527
+ }) : [],
144
528
  ...astroParam,
145
- // Next.js App Router overrides (#12)
146
- ...frameworks.next && nextMode === NextMode.AppRouter ? [
147
- {
148
- name: "eslint-config-next/app-router-overrides",
149
- files: ["app/**/*.{ts,tsx}"],
150
- rules: {
151
- "@next/next/no-html-link-for-pages": "off"
529
+ ...resolvedFrameworks.next && nextMode === NextMode.AppRouter ? [{
530
+ files: ["app/**/*.{ts,tsx}", "src/**/*.{ts,tsx}"],
531
+ name: "eslint-config-next/app-router-overrides",
532
+ rules: { "@next/next/no-html-link-for-pages": "off" }
533
+ }] : [],
534
+ ...await getIntegrationConfigs(uniqueLibraries, uniqueTools, uniqueTesting, uniqueFormats, uniqueExtensions),
535
+ ...tailwindEntryPoint ? [{
536
+ name: "eslint-config-basic/tailwind-settings",
537
+ settings: {
538
+ "better-tailwindcss": {
539
+ detectComponentClasses: true,
540
+ entryPoint: tailwindEntryPoint
152
541
  }
153
542
  }
154
- ] : [],
155
- // Optionals
156
- ...getOptionalConfigs(
157
- uniqueLibraries,
158
- uniqueTools,
159
- uniqueTesting,
160
- uniqueFormats,
161
- uniqueExtensions
162
- ),
163
- // Prettier always last
164
- ...getPrettierConfig(uniqueTools)
543
+ }] : [],
544
+ ...await getPrettierConfig(uniqueTools)
165
545
  ];
166
- return applyStrictMode(configs, strict);
167
546
  };
547
+ const logEslintDebug = (autoFrameworks, detectRootDir, nextMode, optionMergeStrategy, preset, resolvedFrameworks, resolvedTypescript, runtime, tsconfigRootDir, uniqueExtensions, uniqueFormats, uniqueLibraries, uniqueTesting, uniqueTools) => {
548
+ if (!process.env.ESLINT_BASIC_DEBUG) return;
549
+ process.stdout.write(`[ESLint Basic] Resolved options: ${JSON.stringify({
550
+ autoFrameworks,
551
+ detectRootDir: detectRootDir ?? process.cwd(),
552
+ extensions: uniqueExtensions,
553
+ formats: uniqueFormats,
554
+ frameworks: Object.entries(resolvedFrameworks).filter(([, value]) => Boolean(value)).map(([key]) => key),
555
+ libraries: uniqueLibraries,
556
+ nextMode,
557
+ optionMergeStrategy,
558
+ preset,
559
+ runtime,
560
+ testing: uniqueTesting,
561
+ tools: uniqueTools,
562
+ tsconfigRootDir,
563
+ typescript: resolvedTypescript ? resolvedTypescript.mode : false
564
+ }, null, 2)}
565
+ `);
566
+ };
567
+ const eslintConfig = async (options) => {
568
+ const {
569
+ detection,
570
+ extensions: optExtensions,
571
+ formats: optFormats,
572
+ frameworks: optFrameworks,
573
+ libraries: optLibraries,
574
+ strict: optStrict,
575
+ testing: optTesting,
576
+ tools: optTools,
577
+ tsconfigRootDir: optTsconfigRootDir,
578
+ workspacePrefixes
579
+ } = options ?? {};
580
+ const { autoFrameworks, detectRootDir, optionMergeStrategy, requestedPreset } = resolveConfigSetup(options);
581
+ const shouldDefaultProjectDetection = requestedPreset === Preset.Monorepo;
582
+ const detected = applyDetectionControls(
583
+ detectProjectOptions(detectRootDir),
584
+ detection,
585
+ { projects: shouldDefaultProjectDetection }
586
+ );
587
+ const { frameworkDefaults, preset, presetDefaults } = resolvePresetMeta(requestedPreset, detected, autoFrameworks);
588
+ const configuredProjects = resolveConfiguredProjects(detected, options);
589
+ const { detectedExtensions, detectedFormats, detectedLibraries, detectedTesting, detectedTools } = resolveBucketDefaults(detected);
590
+ const configuredExtensions = mergeOptionalBucket(
591
+ "extensions",
592
+ detectedExtensions,
593
+ presetDefaults.extensions,
594
+ optExtensions,
595
+ options,
596
+ optionMergeStrategy
597
+ );
598
+ const formats = mergeOptionalBucket(
599
+ "formats",
600
+ detectedFormats,
601
+ presetDefaults.formats,
602
+ optFormats,
603
+ options,
604
+ optionMergeStrategy
605
+ );
606
+ const frameworks = mergeFrameworkOption(frameworkDefaults, presetDefaults.frameworks, optFrameworks, optionMergeStrategy);
607
+ const libraries = mergeOptionalBucket(
608
+ "libraries",
609
+ detectedLibraries,
610
+ presetDefaults.libraries,
611
+ optLibraries,
612
+ options,
613
+ optionMergeStrategy
614
+ );
615
+ const nextMode = resolveNextModeValue(options, presetDefaults, detected);
616
+ const runtime = resolveRuntimeValue(options, presetDefaults, detected);
617
+ const settings = resolveSettingsValue(options, detected);
618
+ const strict = getStrictMode(optStrict, presetDefaults.strict);
619
+ const testing = mergeOptionalBucket(
620
+ "testing",
621
+ detectedTesting,
622
+ presetDefaults.testing,
623
+ optTesting,
624
+ options,
625
+ optionMergeStrategy
626
+ );
627
+ const tools = mergeOptionalBucket(
628
+ "tools",
629
+ detectedTools,
630
+ presetDefaults.tools,
631
+ optTools,
632
+ options,
633
+ optionMergeStrategy
634
+ );
635
+ const typescript = resolveTypescriptValue(options, presetDefaults, detected);
636
+ const resolvedTypescript = resolveTypescriptOptions(typescript);
637
+ const rootDir = detectRootDir ?? process.cwd();
638
+ const tsconfigRootDir = resolveTsconfigRootDir(rootDir, typescript, optTsconfigRootDir);
639
+ const extensions = applyStrictProfileDefaults(configuredExtensions, strict);
640
+ const resolvedFrameworks = applyFrameworkImpliedDeps({ ...frameworks });
641
+ const uniqueLibraries = [...new Set(libraries)];
642
+ const uniqueTesting = [...new Set(testing)];
643
+ const uniqueFormats = [...new Set(formats)];
644
+ const uniqueTools = [...new Set(tools)];
645
+ const uniqueExtensions = [...new Set(extensions)];
646
+ const uniqueSettings = [...new Set(settings)];
647
+ const hasReact = !!resolvedFrameworks.react;
648
+ const hasVue = !!resolvedFrameworks.vue;
649
+ const hasSvelte = !!resolvedFrameworks.svelte;
650
+ const hasSolid = !!resolvedFrameworks.solid;
651
+ const useGitignore = !uniqueSettings.includes(Setting.NoGitignore);
652
+ const useDefaultIgnores = !uniqueSettings.includes(Setting.NoDefaultIgnores);
653
+ const useGeneratedCodeIgnores = !uniqueSettings.includes(Setting.NoGeneratedCodeIgnores);
654
+ const tailwindEntryPoint = uniqueLibraries.includes(Library.Tailwind) ? findTailwindEntryPoint(rootDir) : void 0;
655
+ const runtimeCoreConfig = runtime === Runtime.Universal ? coreConfig : createCoreConfig(runtime);
656
+ const { defaultIgnores, gitignoreConfig, userIgnores } = buildIgnoresConfig(useDefaultIgnores, useGeneratedCodeIgnores, useGitignore, options);
657
+ const configs = await buildEslintConfigs({
658
+ astroOptions: { hasReact, hasSolid, hasSvelte, hasVue },
659
+ defaultIgnores,
660
+ gitignoreConfig,
661
+ nextMode,
662
+ resolvedFrameworks,
663
+ resolvedTypescript,
664
+ rootDir,
665
+ runtime,
666
+ runtimeCoreConfig,
667
+ tailwindEntryPoint,
668
+ tsconfigRootDir,
669
+ uniqueExtensions,
670
+ uniqueFormats,
671
+ uniqueLibraries,
672
+ uniqueTesting,
673
+ uniqueTools,
674
+ userIgnores
675
+ });
676
+ logEslintDebug(
677
+ autoFrameworks,
678
+ detectRootDir,
679
+ nextMode,
680
+ optionMergeStrategy,
681
+ preset,
682
+ resolvedFrameworks,
683
+ resolvedTypescript,
684
+ runtime,
685
+ tsconfigRootDir,
686
+ uniqueExtensions,
687
+ uniqueFormats,
688
+ uniqueLibraries,
689
+ uniqueTesting,
690
+ uniqueTools
691
+ );
692
+ const projectConfigs = await Promise.all(
693
+ Object.entries(configuredProjects).map(async ([projectPath, projectOptions]) => {
694
+ const projectRoot = join(detectRootDir ?? process.cwd(), projectPath);
695
+ const scopedConfigs = await eslintConfig({
696
+ ...projectOptions,
697
+ detectRootDir: projectOptions.detectRootDir ?? projectRoot,
698
+ projects: void 0,
699
+ tsconfigRootDir: projectOptions.tsconfigRootDir ?? projectRoot
700
+ });
701
+ return scopedConfigs.map((config) => scopeConfigToProject(config, projectPath));
702
+ })
703
+ );
704
+ const allConfigs = [...configs, ...projectConfigs.flat()];
705
+ const patchedConfigs = workspacePrefixes?.length ? patchImportGroups(allConfigs, workspacePrefixes) : allConfigs;
706
+ return applyStrictMode(patchedConfigs, strict);
707
+ };
708
+ const defineConfig = eslintConfig;
168
709
  export {
169
- Extension,
170
- Format,
171
- Library,
710
+ AGENT_TARGETS,
711
+ Extension2 as Extension,
712
+ Format2 as Format,
713
+ Library2 as Library,
172
714
  NextMode2 as NextMode,
173
- Preset,
715
+ Preset2 as Preset,
174
716
  ReactConfigKeys,
175
717
  Runtime2 as Runtime,
176
718
  Setting2 as Setting,
177
- Testing,
178
- Tool,
719
+ Testing2 as Testing,
720
+ Tool2 as Tool,
721
+ a11y,
722
+ aiSdk,
723
+ angular,
724
+ angularConfig,
725
+ astro,
726
+ autogen,
179
727
  bestPractices,
728
+ biome,
729
+ command,
730
+ compat,
180
731
  coreConfig2 as coreConfig,
181
732
  createCoreConfig2 as createCoreConfig,
733
+ createImportGroups,
182
734
  cspell,
735
+ css,
183
736
  cypress,
737
+ deMorgan,
738
+ defineConfig,
739
+ depend,
184
740
  detectProjectOptions2 as detectProjectOptions,
741
+ docker,
742
+ drizzle,
185
743
  eslintConfig,
744
+ expo,
745
+ expoConfig,
746
+ generateAgentSkills,
747
+ generateSkillContent,
186
748
  getGlobalsForRuntime,
749
+ githubActions,
187
750
  gitignore2 as gitignore,
751
+ googleGenAi,
188
752
  graphql,
753
+ groups,
189
754
  hasReactConfig,
755
+ hono,
756
+ html,
190
757
  i18next,
191
758
  jest,
759
+ jestDom,
192
760
  jsConfig,
193
761
  jsdoc,
194
762
  jsonc,
763
+ langchain,
764
+ lit,
765
+ llamaIndex,
195
766
  markdown,
767
+ mastra,
768
+ mcp,
196
769
  mdx,
770
+ mikroOrm,
771
+ nest,
772
+ nestConfig,
773
+ next,
774
+ nextConfig,
775
+ noOnlyTests,
776
+ node,
777
+ nuxt,
778
+ nx,
779
+ openAiAgents,
780
+ oxlint,
781
+ packageJson,
197
782
  perfectionist,
198
783
  playwright,
784
+ pnpm,
785
+ preact,
786
+ preactConfig,
199
787
  prettier,
788
+ prisma,
789
+ qwik,
790
+ react,
791
+ reactConfig,
792
+ reactRouter,
200
793
  regexp,
794
+ remix,
201
795
  security,
796
+ sequelize,
797
+ slidev,
798
+ solid,
799
+ solidConfig,
202
800
  sonarjs,
203
801
  stencil,
204
802
  storybook,
803
+ svelte,
804
+ svelteConfig,
205
805
  swagger,
206
806
  tailwind,
207
807
  tanstackQuery,
208
808
  tanstackRouter,
809
+ tanstackStart,
209
810
  testingLibrary,
210
811
  toml,
211
812
  tsConfig,
813
+ turbo,
814
+ typeorm,
212
815
  typescriptConfig,
213
816
  unicorn,
817
+ vite,
214
818
  vitest,
215
- yaml
819
+ vue,
820
+ vueConfig,
821
+ yaml,
822
+ zod
216
823
  };