@santi020k/eslint-config-basic 1.6.0 → 2.0.0-beta.1

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