xo 1.1.0 → 1.2.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/cli.d.ts +2 -1
- package/dist/cli.js +6 -3
- package/dist/lib/handle-ts-files.js +0 -3
- package/dist/lib/resolve-config.js +3 -1
- package/dist/lib/types.d.ts +4 -0
- package/dist/lib/utils.d.ts +24 -1
- package/dist/lib/utils.js +98 -1
- package/dist/lib/xo.d.ts +11 -1
- package/dist/lib/xo.js +21 -50
- package/package.json +15 -14
- package/readme.md +17 -7
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -21,7 +21,7 @@ const cli = meow(`
|
|
|
21
21
|
--config Path to a XO configuration file
|
|
22
22
|
--semicolon Use semicolons [Default: true]
|
|
23
23
|
--react Include React specific parsing and xo-react linting rules [Default: false]
|
|
24
|
-
--prettier Format with prettier or turn off
|
|
24
|
+
--prettier Format with prettier or turn off Prettier-conflicted rules when set to 'compat' [Default: false]
|
|
25
25
|
--print-config Print the effective ESLint config for the given file
|
|
26
26
|
--version Print XO version
|
|
27
27
|
--open Open files with issues in your editor
|
|
@@ -52,8 +52,9 @@ const cli = meow(`
|
|
|
52
52
|
space: {
|
|
53
53
|
type: 'string',
|
|
54
54
|
},
|
|
55
|
-
|
|
55
|
+
configPath: {
|
|
56
56
|
type: 'string',
|
|
57
|
+
aliases: ['config'],
|
|
57
58
|
},
|
|
58
59
|
quiet: {
|
|
59
60
|
type: 'boolean',
|
|
@@ -108,6 +109,7 @@ const linterOptions = {
|
|
|
108
109
|
cwd: (cliOptions.cwd && path.resolve(cliOptions.cwd)) ?? process.cwd(),
|
|
109
110
|
quiet: cliOptions.quiet,
|
|
110
111
|
ts: true,
|
|
112
|
+
configPath: cliOptions.configPath,
|
|
111
113
|
};
|
|
112
114
|
// Make data types for `options.space` match those of the API
|
|
113
115
|
if (typeof cliOptions.space === 'string') {
|
|
@@ -196,7 +198,8 @@ if (typeof cliOptions.printConfig === 'string') {
|
|
|
196
198
|
console.error('The `--print-config` flag must be used with exactly one filename');
|
|
197
199
|
process.exit(1);
|
|
198
200
|
}
|
|
199
|
-
const
|
|
201
|
+
const absoluteFilePath = path.resolve(cliOptions.cwd, cliOptions.printConfig);
|
|
202
|
+
const config = await new Xo(linterOptions, baseXoConfigOptions).calculateConfigForFile(absoluteFilePath);
|
|
200
203
|
console.log(JSON.stringify(config, undefined, '\t'));
|
|
201
204
|
}
|
|
202
205
|
else {
|
|
@@ -25,9 +25,6 @@ export async function handleTsconfig({ cwd, files }) {
|
|
|
25
25
|
unincludedFiles.push(filePath);
|
|
26
26
|
}
|
|
27
27
|
const fallbackTsConfigPath = path.join(cwd, 'node_modules', '.cache', cacheDirName, 'tsconfig.xo.json');
|
|
28
|
-
delete tsConfig.include;
|
|
29
|
-
delete tsConfig.exclude;
|
|
30
|
-
delete tsConfig.files;
|
|
31
28
|
tsConfig.files = unincludedFiles;
|
|
32
29
|
if (unincludedFiles.length > 0) {
|
|
33
30
|
try {
|
|
@@ -32,7 +32,9 @@ export async function resolveXoConfig(options) {
|
|
|
32
32
|
});
|
|
33
33
|
options.filePath &&= path.resolve(options.cwd, options.filePath);
|
|
34
34
|
const searchPath = options.filePath ?? options.cwd;
|
|
35
|
-
let { config: flatOptions = [], filepath: flatConfigPath = '', } = await
|
|
35
|
+
let { config: flatOptions = [], filepath: flatConfigPath = '', } = await (options.configPath
|
|
36
|
+
? flatConfigExplorer.load(path.resolve(options.cwd, options.configPath))
|
|
37
|
+
: flatConfigExplorer.search(searchPath)) ?? {};
|
|
36
38
|
flatOptions = arrify(flatOptions);
|
|
37
39
|
return {
|
|
38
40
|
flatOptions,
|
package/dist/lib/types.d.ts
CHANGED
package/dist/lib/utils.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type SetRequired } from 'type-fest';
|
|
2
1
|
import { type Linter } from 'eslint';
|
|
2
|
+
import { type SetRequired } from 'type-fest';
|
|
3
3
|
import { type XoConfigItem } from './types.js';
|
|
4
4
|
/**
|
|
5
5
|
Convert a `xo` config item to an ESLint config item.
|
|
@@ -12,3 +12,26 @@ Files and rules will always be defined and all other ESLint config properties ar
|
|
|
12
12
|
@returns eslintConfig
|
|
13
13
|
*/
|
|
14
14
|
export declare const xoToEslintConfigItem: (xoConfig: XoConfigItem) => SetRequired<Linter.Config, "rules" | "files">;
|
|
15
|
+
/**
|
|
16
|
+
Function used to match files which should be included in the `tsconfig.json` files.
|
|
17
|
+
|
|
18
|
+
@param cwd - The current working directory to resolve relative filepaths.
|
|
19
|
+
@param files - The _absolute_ file paths to match against the globs.
|
|
20
|
+
@param globs - The globs to match the files against.
|
|
21
|
+
@param ignores - The globs to ignore when matching the files.
|
|
22
|
+
@returns An array of file paths that match the globs and do not match the ignores.
|
|
23
|
+
*/
|
|
24
|
+
export declare const matchFilesForTsConfig: (cwd: string, files: string[], globs: string[], ignores: string[]) => string[];
|
|
25
|
+
/**
|
|
26
|
+
Once a config is resolved, it is pre-processed to ensure that all properties are set correctly.
|
|
27
|
+
|
|
28
|
+
This includes ensuring that user-defined properties can override XO defaults, and that files are parsed correctly and performantly based on the users XO config.
|
|
29
|
+
|
|
30
|
+
@param xoConfig - The flat XO config to pre-process.
|
|
31
|
+
@returns The pre-processed flat XO config.
|
|
32
|
+
*/
|
|
33
|
+
export declare const preProcessXoConfig: (xoConfig: XoConfigItem[]) => {
|
|
34
|
+
config: XoConfigItem[];
|
|
35
|
+
tsFilesGlob: string[];
|
|
36
|
+
tsFilesIgnoresGlob: string[];
|
|
37
|
+
};
|
package/dist/lib/utils.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import micromatch from 'micromatch';
|
|
1
3
|
import arrify from 'arrify';
|
|
2
|
-
import
|
|
4
|
+
import configXoTypescript from 'eslint-config-xo-typescript';
|
|
5
|
+
import { allFilesGlob, jsExtensions, jsFilesGlob, } from './constants.js';
|
|
3
6
|
/**
|
|
4
7
|
Convert a `xo` config item to an ESLint config item.
|
|
5
8
|
|
|
@@ -20,4 +23,98 @@ export const xoToEslintConfigItem = (xoConfig) => {
|
|
|
20
23
|
eslintConfig.ignores &&= arrify(xoConfig.ignores);
|
|
21
24
|
return eslintConfig;
|
|
22
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
Function used to match files which should be included in the `tsconfig.json` files.
|
|
28
|
+
|
|
29
|
+
@param cwd - The current working directory to resolve relative filepaths.
|
|
30
|
+
@param files - The _absolute_ file paths to match against the globs.
|
|
31
|
+
@param globs - The globs to match the files against.
|
|
32
|
+
@param ignores - The globs to ignore when matching the files.
|
|
33
|
+
@returns An array of file paths that match the globs and do not match the ignores.
|
|
34
|
+
*/
|
|
35
|
+
export const matchFilesForTsConfig = (cwd, files, globs, ignores) => micromatch(files.map(file => path.normalize(path.relative(cwd, file))),
|
|
36
|
+
// https://github.com/micromatch/micromatch/issues/217
|
|
37
|
+
globs.map(glob => path.normalize(glob)), {
|
|
38
|
+
dot: true,
|
|
39
|
+
ignore: ignores.map(file => path.normalize(file)),
|
|
40
|
+
cwd,
|
|
41
|
+
}).map(file => path.resolve(cwd, file));
|
|
42
|
+
/**
|
|
43
|
+
Once a config is resolved, it is pre-processed to ensure that all properties are set correctly.
|
|
44
|
+
|
|
45
|
+
This includes ensuring that user-defined properties can override XO defaults, and that files are parsed correctly and performantly based on the users XO config.
|
|
46
|
+
|
|
47
|
+
@param xoConfig - The flat XO config to pre-process.
|
|
48
|
+
@returns The pre-processed flat XO config.
|
|
49
|
+
*/
|
|
50
|
+
export const preProcessXoConfig = (xoConfig) => {
|
|
51
|
+
const tsFilesGlob = [];
|
|
52
|
+
const tsFilesIgnoresGlob = [];
|
|
53
|
+
const processedConfig = [];
|
|
54
|
+
for (const [idx, { ...config }] of xoConfig.entries()) {
|
|
55
|
+
// We can skip the first config item, as it is the base config item.
|
|
56
|
+
if (idx === 0) {
|
|
57
|
+
processedConfig.push(config);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
// Use TS parser/plugin for JS files if the config contains TypeScript rules which are applied to JS files.
|
|
61
|
+
// typescript-eslint rules set to "off" are ignored and not applied to JS files.
|
|
62
|
+
if (config.rules
|
|
63
|
+
&& !config.languageOptions?.parser
|
|
64
|
+
&& !config.languageOptions?.parserOptions?.['project']
|
|
65
|
+
&& !config.plugins?.['@typescript-eslint']) {
|
|
66
|
+
const hasTsRules = Object.entries(config.rules).some(rulePair => {
|
|
67
|
+
// If its not a @typescript-eslint rule, we don't care
|
|
68
|
+
if (!rulePair[0].startsWith('@typescript-eslint/')) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
if (Array.isArray(rulePair[1])) {
|
|
72
|
+
return rulePair[1]?.[0] !== 'off' && rulePair[1]?.[0] !== 0;
|
|
73
|
+
}
|
|
74
|
+
return rulePair[1] !== 'off'
|
|
75
|
+
&& rulePair[1] !== 0;
|
|
76
|
+
});
|
|
77
|
+
if (hasTsRules) {
|
|
78
|
+
let isAppliedToJsFiles = false;
|
|
79
|
+
if (config.files) {
|
|
80
|
+
const normalizedFiles = arrify(config.files).map(file => path.normalize(file));
|
|
81
|
+
// Strip the basename off any globs
|
|
82
|
+
const globs = normalizedFiles.map(file => micromatch.scan(file, { dot: true }).glob).filter(Boolean);
|
|
83
|
+
// Check if the files globs match a test file with a js extension
|
|
84
|
+
// If not, check that the file paths match a js extension
|
|
85
|
+
isAppliedToJsFiles = micromatch.some(jsExtensions.map(ext => `test.${ext}`), globs, { dot: true })
|
|
86
|
+
|| micromatch.some(normalizedFiles, jsFilesGlob, { dot: true });
|
|
87
|
+
}
|
|
88
|
+
else if (config.files === undefined) {
|
|
89
|
+
isAppliedToJsFiles = true;
|
|
90
|
+
}
|
|
91
|
+
if (isAppliedToJsFiles) {
|
|
92
|
+
config.languageOptions ??= {};
|
|
93
|
+
config.plugins ??= {};
|
|
94
|
+
config.plugins = {
|
|
95
|
+
...config.plugins,
|
|
96
|
+
...configXoTypescript[1]?.plugins,
|
|
97
|
+
};
|
|
98
|
+
config.languageOptions.parser = configXoTypescript[1]?.languageOptions?.parser;
|
|
99
|
+
tsFilesGlob.push(...arrify(config.files ?? allFilesGlob));
|
|
100
|
+
tsFilesIgnoresGlob.push(...arrify(config.ignores));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// If a user sets the `parserOptions.project` or `projectService` or `tsconfigRootDir`, we need to ensure that the tsFilesGlob is set to exclude those files,
|
|
105
|
+
// as this indicates the user has opted out of the default TypeScript handling for those files.
|
|
106
|
+
if (config.languageOptions?.parserOptions?.['project'] !== undefined
|
|
107
|
+
|| config.languageOptions?.parserOptions?.['projectService'] !== undefined
|
|
108
|
+
|| config.languageOptions?.parserOptions?.['tsconfigRootDir'] !== undefined) {
|
|
109
|
+
// The glob itself should NOT be negated
|
|
110
|
+
tsFilesIgnoresGlob.push(...arrify(config.files ?? allFilesGlob));
|
|
111
|
+
}
|
|
112
|
+
processedConfig.push(config);
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
config: processedConfig,
|
|
116
|
+
tsFilesGlob,
|
|
117
|
+
tsFilesIgnoresGlob,
|
|
118
|
+
};
|
|
119
|
+
};
|
|
23
120
|
//# sourceMappingURL=utils.js.map
|
package/dist/lib/xo.d.ts
CHANGED
|
@@ -48,13 +48,23 @@ export declare class Xo {
|
|
|
48
48
|
*/
|
|
49
49
|
flatConfigPath?: string | undefined;
|
|
50
50
|
/**
|
|
51
|
-
If any user configs
|
|
51
|
+
If any user configs contains Prettier, we will need to fetch the Prettier config.
|
|
52
52
|
*/
|
|
53
53
|
prettier?: boolean;
|
|
54
54
|
/**
|
|
55
55
|
The Prettier config if it exists and is needed.
|
|
56
56
|
*/
|
|
57
57
|
prettierConfig?: prettier.Options;
|
|
58
|
+
/**
|
|
59
|
+
The glob pattern for TypeScript files, for which we will handle TS files and tsconfig.
|
|
60
|
+
|
|
61
|
+
We expand this based on the XO config and the files glob patterns.
|
|
62
|
+
*/
|
|
63
|
+
tsFilesGlob: string[];
|
|
64
|
+
/**
|
|
65
|
+
We use this to also add negative glob patterns in case a user overrides the parserOptions in their XO config.
|
|
66
|
+
*/
|
|
67
|
+
tsFilesIgnoresGlob: string[];
|
|
58
68
|
constructor(_linterOptions: LinterOptions, _baseXoConfig?: XoConfigOptions);
|
|
59
69
|
/**
|
|
60
70
|
Sets the XO config on the XO instance.
|
package/dist/lib/xo.js
CHANGED
|
@@ -6,13 +6,12 @@ import findCacheDirectory from 'find-cache-directory';
|
|
|
6
6
|
import { globby } from 'globby';
|
|
7
7
|
import arrify from 'arrify';
|
|
8
8
|
import defineLazyProperty from 'define-lazy-prop';
|
|
9
|
-
import micromatch from 'micromatch';
|
|
10
9
|
import prettier from 'prettier';
|
|
11
|
-
import { defaultIgnores, cacheDirName, allExtensions, tsFilesGlob,
|
|
10
|
+
import { defaultIgnores, cacheDirName, allExtensions, tsFilesGlob, } from './constants.js';
|
|
12
11
|
import { xoToEslintConfig } from './xo-to-eslint.js';
|
|
13
12
|
import resolveXoConfig from './resolve-config.js';
|
|
14
13
|
import { handleTsconfig } from './handle-ts-files.js';
|
|
15
|
-
|
|
14
|
+
import { matchFilesForTsConfig, preProcessXoConfig } from './utils.js';
|
|
16
15
|
export class Xo {
|
|
17
16
|
/**
|
|
18
17
|
Static helper to convert an XO config to an ESLint config to be used in `eslint.config.js`.
|
|
@@ -28,6 +27,7 @@ export class Xo {
|
|
|
28
27
|
filePath: options.filePath,
|
|
29
28
|
quiet: options.quiet,
|
|
30
29
|
ts: options.ts ?? true,
|
|
30
|
+
configPath: options.configPath,
|
|
31
31
|
}, {
|
|
32
32
|
react: options.react,
|
|
33
33
|
space: options.space,
|
|
@@ -50,6 +50,7 @@ export class Xo {
|
|
|
50
50
|
filePath: options.filePath,
|
|
51
51
|
quiet: options.quiet,
|
|
52
52
|
ts: options.ts,
|
|
53
|
+
configPath: options.configPath,
|
|
53
54
|
}, {
|
|
54
55
|
react: options.react,
|
|
55
56
|
space: options.space,
|
|
@@ -94,13 +95,23 @@ export class Xo {
|
|
|
94
95
|
*/
|
|
95
96
|
flatConfigPath;
|
|
96
97
|
/**
|
|
97
|
-
If any user configs
|
|
98
|
+
If any user configs contains Prettier, we will need to fetch the Prettier config.
|
|
98
99
|
*/
|
|
99
100
|
prettier;
|
|
100
101
|
/**
|
|
101
102
|
The Prettier config if it exists and is needed.
|
|
102
103
|
*/
|
|
103
104
|
prettierConfig;
|
|
105
|
+
/**
|
|
106
|
+
The glob pattern for TypeScript files, for which we will handle TS files and tsconfig.
|
|
107
|
+
|
|
108
|
+
We expand this based on the XO config and the files glob patterns.
|
|
109
|
+
*/
|
|
110
|
+
tsFilesGlob = [tsFilesGlob];
|
|
111
|
+
/**
|
|
112
|
+
We use this to also add negative glob patterns in case a user overrides the parserOptions in their XO config.
|
|
113
|
+
*/
|
|
114
|
+
tsFilesIgnoresGlob = [];
|
|
104
115
|
constructor(_linterOptions, _baseXoConfig = {}) {
|
|
105
116
|
this.linterOptions = _linterOptions;
|
|
106
117
|
this.baseXoConfig = _baseXoConfig;
|
|
@@ -123,53 +134,13 @@ export class Xo {
|
|
|
123
134
|
const { flatOptions, flatConfigPath } = await resolveXoConfig({
|
|
124
135
|
...this.linterOptions,
|
|
125
136
|
});
|
|
126
|
-
|
|
137
|
+
const { config, tsFilesGlob, tsFilesIgnoresGlob } = preProcessXoConfig([
|
|
127
138
|
this.baseXoConfig,
|
|
128
139
|
...flatOptions,
|
|
129
|
-
];
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
this.
|
|
133
|
-
// If the user does not specify files, then we can assume they want everything to work correctly and
|
|
134
|
-
// for rules to apply to all files. However, TS rules will error with JS files, so we need to split them off.
|
|
135
|
-
// if the user supplies files, then we cannot make the same assumption, so we will not split them off.
|
|
136
|
-
if (config.files) {
|
|
137
|
-
return config;
|
|
138
|
-
}
|
|
139
|
-
const ruleEntries = Object.entries(config.rules ?? {});
|
|
140
|
-
const otherRules = [];
|
|
141
|
-
const tsRules = [];
|
|
142
|
-
for (const [rule, ruleValue] of ruleEntries) {
|
|
143
|
-
if (!rule || !ruleValue) {
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
if (rule.startsWith('@typescript-eslint')) {
|
|
147
|
-
tsRules.push([rule, ruleValue]);
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
otherRules.push([rule, ruleValue]);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
// If no TS rules, return the config as is
|
|
154
|
-
if (tsRules.length === 0) {
|
|
155
|
-
return config;
|
|
156
|
-
}
|
|
157
|
-
// If there are TS rules, we need to split them off into a new config
|
|
158
|
-
const tsConfig = {
|
|
159
|
-
...config,
|
|
160
|
-
rules: Object.fromEntries(tsRules),
|
|
161
|
-
};
|
|
162
|
-
// Apply TS rules to all files
|
|
163
|
-
tsConfig.files = [tsFilesGlob];
|
|
164
|
-
const otherConfig = {
|
|
165
|
-
...config,
|
|
166
|
-
// Set the other rules to the original config
|
|
167
|
-
rules: Object.fromEntries(otherRules),
|
|
168
|
-
};
|
|
169
|
-
// These rules should still apply to all files
|
|
170
|
-
otherConfig.files = [allFilesGlob];
|
|
171
|
-
return [tsConfig, otherConfig];
|
|
172
|
-
});
|
|
140
|
+
]);
|
|
141
|
+
this.xoConfig = config;
|
|
142
|
+
this.tsFilesGlob.push(...tsFilesGlob);
|
|
143
|
+
this.tsFilesIgnoresGlob.push(...tsFilesIgnoresGlob);
|
|
173
144
|
this.prettier = this.xoConfig.some(config => config.prettier);
|
|
174
145
|
this.prettierConfig = await prettier.resolveConfig(flatConfigPath, { editorconfig: true }) ?? {};
|
|
175
146
|
this.flatConfigPath = flatConfigPath;
|
|
@@ -218,7 +189,7 @@ export class Xo {
|
|
|
218
189
|
if (!this.linterOptions.ts || !files || files.length === 0) {
|
|
219
190
|
return;
|
|
220
191
|
}
|
|
221
|
-
const tsFiles =
|
|
192
|
+
const tsFiles = matchFilesForTsConfig(this.linterOptions.cwd, files, this.tsFilesGlob, this.tsFilesIgnoresGlob);
|
|
222
193
|
if (tsFiles.length === 0) {
|
|
223
194
|
return;
|
|
224
195
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xo",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "JavaScript/TypeScript linter (ESLint wrapper) with great defaults",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "xojs/xo",
|
|
@@ -68,34 +68,34 @@
|
|
|
68
68
|
"@eslint-community/eslint-plugin-eslint-comments": "^4.5.0",
|
|
69
69
|
"@sindresorhus/tsconfig": "^7.0.0",
|
|
70
70
|
"@stylistic/eslint-plugin": "^4.2.0",
|
|
71
|
-
"@typescript-eslint/parser": "^8.
|
|
71
|
+
"@typescript-eslint/parser": "^8.37.0",
|
|
72
72
|
"arrify": "^3.0.0",
|
|
73
73
|
"cosmiconfig": "^9.0.0",
|
|
74
74
|
"define-lazy-prop": "^3.0.0",
|
|
75
|
-
"eslint": "^9.
|
|
75
|
+
"eslint": "^9.31.0",
|
|
76
76
|
"eslint-config-prettier": "^10.1.5",
|
|
77
77
|
"eslint-config-xo-react": "^0.28.0",
|
|
78
78
|
"eslint-config-xo-typescript": "^7.0.0",
|
|
79
79
|
"eslint-formatter-pretty": "^6.0.1",
|
|
80
80
|
"eslint-plugin-ava": "^15.0.1",
|
|
81
|
-
"eslint-plugin-import-x": "^4.
|
|
82
|
-
"eslint-plugin-n": "^17.
|
|
81
|
+
"eslint-plugin-import-x": "^4.16.1",
|
|
82
|
+
"eslint-plugin-n": "^17.21.0",
|
|
83
83
|
"eslint-plugin-no-use-extend-native": "^0.7.2",
|
|
84
|
-
"eslint-plugin-prettier": "^5.
|
|
84
|
+
"eslint-plugin-prettier": "^5.5.1",
|
|
85
85
|
"eslint-plugin-promise": "^7.2.1",
|
|
86
86
|
"eslint-plugin-unicorn": "^59.0.1",
|
|
87
87
|
"find-cache-directory": "^6.0.0",
|
|
88
88
|
"get-stdin": "^9.0.0",
|
|
89
89
|
"get-tsconfig": "^4.10.1",
|
|
90
|
-
"globals": "^16.
|
|
90
|
+
"globals": "^16.3.0",
|
|
91
91
|
"globby": "^14.1.0",
|
|
92
92
|
"meow": "^13.2.0",
|
|
93
93
|
"micromatch": "^4.0.8",
|
|
94
94
|
"open-editor": "^5.1.0",
|
|
95
95
|
"path-exists": "^5.0.0",
|
|
96
|
-
"prettier": "^3.
|
|
96
|
+
"prettier": "^3.6.2",
|
|
97
97
|
"type-fest": "^4.41.0",
|
|
98
|
-
"typescript-eslint": "^8.
|
|
98
|
+
"typescript-eslint": "^8.37.0"
|
|
99
99
|
},
|
|
100
100
|
"devDependencies": {
|
|
101
101
|
"@commitlint/cli": "^19.8.1",
|
|
@@ -103,15 +103,15 @@
|
|
|
103
103
|
"@types/eslint": "9.6.1",
|
|
104
104
|
"@types/micromatch": "^4.0.9",
|
|
105
105
|
"@types/prettier": "^3.0.0",
|
|
106
|
-
"ava": "^6.
|
|
106
|
+
"ava": "^6.4.1",
|
|
107
107
|
"dedent": "^1.6.0",
|
|
108
108
|
"execa": "^9.5.3",
|
|
109
109
|
"husky": "^9.1.7",
|
|
110
110
|
"lint-staged": "^16.0.0",
|
|
111
111
|
"np": "^10.2.0",
|
|
112
|
-
"npm-package-json-lint": "^
|
|
113
|
-
"npm-package-json-lint-config-default": "^
|
|
114
|
-
"prettier-plugin-packagejson": "^2.5.
|
|
112
|
+
"npm-package-json-lint": "^9.0.0",
|
|
113
|
+
"npm-package-json-lint-config-default": "^8.0.1",
|
|
114
|
+
"prettier-plugin-packagejson": "^2.5.18",
|
|
115
115
|
"temp-dir": "^3.0.0",
|
|
116
116
|
"xo": "file:."
|
|
117
117
|
},
|
|
@@ -133,7 +133,8 @@
|
|
|
133
133
|
".history/**/*",
|
|
134
134
|
"node_modules",
|
|
135
135
|
"package.json",
|
|
136
|
-
"xo.config.*"
|
|
136
|
+
"xo.config.*",
|
|
137
|
+
"**/*.ts"
|
|
137
138
|
]
|
|
138
139
|
}
|
|
139
140
|
},
|
package/readme.md
CHANGED
|
@@ -34,7 +34,7 @@ It uses [ESLint](https://eslint.org) underneath, so issues regarding built-in ru
|
|
|
34
34
|
- Open all files with errors at the correct line in your editor with `$ xo --open`.
|
|
35
35
|
- Specify [indent](#space) and [semicolon](#semicolon) preferences easily without messing with the rule config.
|
|
36
36
|
- Optionally use the [Prettier](https://github.com/prettier/prettier) code style or turn off all Prettier rules with the `compat` option.
|
|
37
|
-
- Optionally use `eslint-config-xo-react` for easy
|
|
37
|
+
- Optionally use `eslint-config-xo-react` for easy JSX and React linting with zero config.
|
|
38
38
|
- Optionally use with ESLint [directly](#usage-as-an-eslint-configuration)
|
|
39
39
|
- Great [editor plugins](#editor-plugins).
|
|
40
40
|
|
|
@@ -63,7 +63,7 @@ $ xo --help
|
|
|
63
63
|
--config Path to a XO configuration file
|
|
64
64
|
--semicolon Use semicolons [Default: true]
|
|
65
65
|
--react Include React specific parsing and xo-react linting rules [Default: false]
|
|
66
|
-
--prettier Format with prettier or turn off prettier
|
|
66
|
+
--prettier Format with prettier or turn off prettier-conflicted rules when set to 'compat' [Default: false]
|
|
67
67
|
--print-config Print the effective ESLint config for the given file
|
|
68
68
|
--version Print XO version
|
|
69
69
|
--open Open files with issues in your editor
|
|
@@ -108,7 +108,7 @@ Simply run `$ npm init xo` (with any options) to add XO to create an `xo.config.
|
|
|
108
108
|
|
|
109
109
|
## Config
|
|
110
110
|
|
|
111
|
-
You can configure XO options by creating an `xo.config.js` or an `xo.config.ts` file in the root directory of your project. XO supports all js/ts file extensions (js,cjs,mjs,ts,cts,mts) automatically. A XO config is an extension of ESLint's Flat Config. Like ESLint, an XO config exports an array of XO config objects. XO config objects extend [ESLint Configuration Objects](https://eslint.org/docs/latest/use/configure/configuration-files#configuration-objects). This means all the available configuration params for ESLint also work for `XO`. However, `XO` enhances and adds extra params to the configuration objects to make them easier to work with.
|
|
111
|
+
You can configure XO options by creating an `xo.config.js` or an `xo.config.ts` file in the root directory of your project, or you can add an `xo` field to your `package.json`. XO supports all js/ts file extensions (js,cjs,mjs,ts,cts,mts) automatically. A XO config is an extension of ESLint's Flat Config. Like ESLint, an XO config exports an array of XO config objects. XO config objects extend [ESLint Configuration Objects](https://eslint.org/docs/latest/use/configure/configuration-files#configuration-objects). This means all the available configuration params for ESLint also work for `XO`. However, `XO` enhances and adds extra params to the configuration objects to make them easier to work with.
|
|
112
112
|
|
|
113
113
|
### Config types
|
|
114
114
|
|
|
@@ -124,12 +124,16 @@ const xoConfig = [...]
|
|
|
124
124
|
|
|
125
125
|
`xo.config.ts`
|
|
126
126
|
|
|
127
|
-
```
|
|
127
|
+
```ts
|
|
128
128
|
import {type FlatXoConfig} from 'xo';
|
|
129
129
|
|
|
130
130
|
const xoConfig: FlatXoConfig = [...]
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
+
```ts
|
|
134
|
+
export default [...] satisfies import('xo').FlatXoConfig
|
|
135
|
+
```
|
|
136
|
+
|
|
133
137
|
### files
|
|
134
138
|
|
|
135
139
|
Type: `string | string[] | undefined`\
|
|
@@ -137,11 +141,15 @@ Default: `**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}`
|
|
|
137
141
|
|
|
138
142
|
A glob or array of glob strings which the config object will apply. By default `XO` will apply the configuration to [all files](lib/constants.ts).
|
|
139
143
|
|
|
144
|
+
> Tip: If you are adding additional `@typescript-eslint` rules to your config, these rules will apply to JS files as well unless you separate them appropriately with the `files` option. `@typescript-eslint` rules set to `'off'` or `0`, however, will have no effect on JS linting.
|
|
145
|
+
|
|
140
146
|
### ignores
|
|
141
147
|
|
|
142
148
|
Type: `string[]`
|
|
143
149
|
|
|
144
|
-
Some [paths](lib/constants.ts) are ignored by default, including paths in `.gitignore`. Additional ignores can be added here.
|
|
150
|
+
Some [paths](lib/constants.ts) are ignored by default, including paths in `.gitignore`. Additional ignores can be added here.
|
|
151
|
+
|
|
152
|
+
> Tip: For *global* ignores, keep `ignores` as the only key in the config item. You can optionally set a `name` property. Adding more properties will cause ignores to be scoped down to your files selection, which may have unexpected effects.
|
|
145
153
|
|
|
146
154
|
### space
|
|
147
155
|
|
|
@@ -202,15 +210,17 @@ XO will automatically lint TypeScript files (`.ts`, `.mts`, `.cts`, and `.tsx`)
|
|
|
202
210
|
|
|
203
211
|
XO will handle the [@typescript-eslint/parser `project` option](https://typescript-eslint.io/packages/parser/#project) automatically even if you don't have a `tsconfig.json` in your project.
|
|
204
212
|
|
|
213
|
+
You can opt out of XO's automatic tsconfig handling by specifying your own `languageOptions.parserOptions.project`, `languageOptions.parserOptions.projectService`, or `languageOptions.parserOptions.tsconfigRootDir`. Files in a config with these properties will be excluded from automatic tsconfig handling.
|
|
214
|
+
|
|
205
215
|
## Usage as an ESLint Configuration
|
|
206
216
|
|
|
207
217
|
With the introduction of the ESLint flat config, many of the original goals of `xo` were brought into the ESLint core, and shareable configs with plugins became possible. Although we highly recommend the use of the `xo` cli, we understand that some teams need to rely on ESLint directly.
|
|
208
218
|
|
|
209
219
|
For these purposes, you can still get most of the features of `xo` by using our ESLint configuration helpers.
|
|
210
220
|
|
|
211
|
-
###
|
|
221
|
+
### xoToEslintConfig
|
|
212
222
|
|
|
213
|
-
The `xoToEslintConfig` function is designed for use in an `eslint.config.js` file. It is NOT for use in an `xo.config.js` file. This function takes a `FlatXoConfig` and outputs an ESLint config object. This function will neither be able to automatically handle TS integration for you nor automatic Prettier integration. You are responsible for configuring your other tools appropriately. The `xo` cli, will however, handle all of these details for you.
|
|
223
|
+
The `xoToEslintConfig` function is designed for use in an `eslint.config.js` file. It is NOT for use in an `xo.config.js` file. This function takes a `FlatXoConfig` and outputs an ESLint config object. This function will neither be able to automatically handle TS integration for you nor automatic Prettier integration. You are responsible for configuring your other tools appropriately. The `xo` cli, will, however, handle all of these details for you.
|
|
214
224
|
|
|
215
225
|
`eslint.config.js`
|
|
216
226
|
|