Skip to content

Commit f49e1a0

Browse files
Copilotcamc314Sysix
authored
fix: detect and skip ESLint AND glob patterns (nested arrays in files) (#323)
* Initial plan * Initial plan for fixing nested arrays in files field Co-authored-by: camc314 <18101008+camc314@users.noreply.github.com> * Fix nested arrays in files field by flattening them Co-authored-by: camc314 <18101008+camc314@users.noreply.github.com> * Remove package-lock.json and add to gitignore (project uses pnpm) Co-authored-by: camc314 <18101008+camc314@users.noreply.github.com> * u * Apply suggestions from code review Signed-off-by: Cameron <cameron.clark@hey.com> * Detect and skip ESLint AND glob patterns (nested arrays) with reporting Co-authored-by: Sysix <3897725+Sysix@users.noreply.github.com> * Refactor files processing logic into separate files.ts module with unit tests Co-authored-by: Sysix <3897725+Sysix@users.noreply.github.com> * Simplify processConfigFiles to return array directly and report nested arrays individually Co-authored-by: Sysix <3897725+Sysix@users.noreply.github.com> * Remove unnecessary undefined check in processConfigFiles Co-authored-by: Sysix <3897725+Sysix@users.noreply.github.com> * Fix lint errors: use DefaultReporter instead of inline objects in tests Co-authored-by: Sysix <3897725+Sysix@users.noreply.github.com> * Apply suggestion from @Sysix Signed-off-by: Alexander S. <sysix@sysix-coding.de> * u --------- Signed-off-by: Cameron <cameron.clark@hey.com> Signed-off-by: Alexander S. <sysix@sysix-coding.de> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: camc314 <18101008+camc314@users.noreply.github.com> Co-authored-by: Cameron Clark <cameron.clark@hey.com> Co-authored-by: Sysix <3897725+Sysix@users.noreply.github.com> Co-authored-by: Alexander S. <sysix@sysix-coding.de>
1 parent d0b6897 commit f49e1a0

File tree

3 files changed

+129
-3
lines changed

3 files changed

+129
-3
lines changed

src/files.spec.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { describe, expect, test } from 'vitest';
2+
import { processConfigFiles } from './files.js';
3+
import { DefaultReporter } from './reporter.js';
4+
5+
describe('processConfigFiles', () => {
6+
test('handles single string by wrapping it in an array', () => {
7+
const result = processConfigFiles('**/*.js');
8+
9+
expect(result).toStrictEqual(['**/*.js']);
10+
});
11+
12+
test('handles array of strings without modification', () => {
13+
const result = processConfigFiles(['**/*.js', '**/*.ts']);
14+
15+
expect(result).toStrictEqual(['**/*.js', '**/*.ts']);
16+
});
17+
18+
test('separates nested arrays from simple strings and reports them', () => {
19+
const reporter = new DefaultReporter();
20+
21+
const result = processConfigFiles(
22+
[
23+
['**/*.ts', '**/*.tsx'], // AND pattern - unsupported
24+
'**/*.js', // Simple pattern - supported
25+
],
26+
reporter
27+
);
28+
29+
expect(result).toStrictEqual(['**/*.js']);
30+
31+
const reports = reporter.getReports();
32+
expect(reports).toHaveLength(1);
33+
expect(reports[0]).toContain('AND glob patterns');
34+
expect(reports[0]).toContain('nested arrays');
35+
expect(reports[0]).toContain('**/*.ts');
36+
});
37+
38+
test('returns empty array when all files are nested arrays', () => {
39+
const reporter = new DefaultReporter();
40+
41+
const result = processConfigFiles(
42+
[
43+
['**/*.ts', '**/*.tsx'],
44+
['**/*.js', '**/*.jsx'],
45+
],
46+
reporter
47+
);
48+
49+
expect(result).toStrictEqual([]);
50+
51+
const reports = reporter.getReports();
52+
expect(reports).toHaveLength(2);
53+
expect(reports[0]).toContain('AND glob patterns');
54+
expect(reports[1]).toContain('AND glob patterns');
55+
});
56+
57+
test('handles multiple nested arrays correctly', () => {
58+
const reporter = new DefaultReporter();
59+
60+
const result = processConfigFiles(
61+
[
62+
['**/*.ts', '**/*.tsx'],
63+
'**/*.js',
64+
['**/*.mjs', '**/*.cjs'],
65+
'**/*.jsx',
66+
],
67+
reporter
68+
);
69+
70+
expect(result).toStrictEqual(['**/*.js', '**/*.jsx']);
71+
72+
const reports = reporter.getReports();
73+
expect(reports).toHaveLength(2);
74+
expect(reports[0]).toContain('**/*.ts');
75+
expect(reports[1]).toContain('**/*.mjs');
76+
});
77+
78+
test('does not report when no nested arrays present', () => {
79+
const reporter = new DefaultReporter();
80+
81+
const result = processConfigFiles(['**/*.js', '**/*.ts'], reporter);
82+
83+
expect(result).toStrictEqual(['**/*.js', '**/*.ts']);
84+
85+
expect(reporter.getReports()).toHaveLength(0);
86+
});
87+
});

src/files.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import type { Reporter } from './types.js';
2+
3+
/**
4+
* Process ESLint config files field, separating simple string patterns
5+
* from nested arrays (AND glob patterns which are unsupported in oxlint).
6+
*
7+
* @param files - The files field from ESLint config (can be string, array of strings, or array with nested arrays)
8+
* @param reporter - Optional reporter to report unsupported AND patterns
9+
* @returns Array of simple string patterns (valid files)
10+
*/
11+
export function processConfigFiles(
12+
files: string | (string | string[])[],
13+
reporter?: Reporter
14+
): string[] {
15+
// Normalize files to an array
16+
const filesArray = Array.isArray(files) ? files : [files];
17+
18+
// Separate nested arrays (AND patterns) from simple strings
19+
const simpleFiles: string[] = [];
20+
21+
for (const file of filesArray) {
22+
if (Array.isArray(file)) {
23+
// Report nested array (AND glob pattern) as unsupported
24+
reporter?.report(
25+
`ESLint AND glob patterns (nested arrays in files) are not supported in oxlint: ${JSON.stringify(file)}`
26+
);
27+
} else {
28+
simpleFiles.push(file);
29+
}
30+
}
31+
32+
return simpleFiles;
33+
}

src/index.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from './plugins_rules.js';
1313
import { detectSameOverride } from './overrides.js';
1414
import fixForJsPlugins from './js_plugin_fixes.js';
15+
import { processConfigFiles } from './files.js';
1516

1617
const buildConfig = (
1718
configs: Linter.Config[],
@@ -76,10 +77,15 @@ const buildConfig = (
7677
if (config.files === undefined) {
7778
targetConfig = oxlintConfig;
7879
} else {
80+
const validFiles = processConfigFiles(config.files, options?.reporter);
81+
82+
// If no valid files remain after filtering nested arrays, skip this config
83+
if (validFiles.length === 0) {
84+
continue;
85+
}
86+
7987
targetConfig = {
80-
files: (Array.isArray(config.files)
81-
? config.files
82-
: [config.files]) as string[],
88+
files: validFiles,
8389
};
8490
const [push, result] = detectSameOverride(oxlintConfig, targetConfig);
8591

0 commit comments

Comments
 (0)