xo 3.0.2 → 4.0.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.
@@ -23,8 +23,8 @@ const resultToFile = (result) => {
23
23
  column: message?.column,
24
24
  };
25
25
  };
26
- const getFiles = (report, predicate) => report.results
27
- .filter(result => predicate(result))
26
+ const getFiles = (report, isMatchingResult) => report.results
27
+ .filter(result => isMatchingResult(result))
28
28
  .toSorted(sortResults)
29
29
  .map(result => resultToFile(result));
30
30
  const openReport = async (report) => {
package/dist/lib/xo.d.ts CHANGED
@@ -38,7 +38,7 @@ export declare class Xo {
38
38
  Sets the XO config on the XO instance.
39
39
  */
40
40
  setXoConfig(): Promise<void>;
41
- setEslintConfig(cliIgnores?: string[], stripDefaultIgnores?: boolean): void;
41
+ setEslintConfig(cliIgnores?: string[], shouldStripDefaultIgnores?: boolean): void;
42
42
  /**
43
43
  Ensures the cache directory exists. This needs to run once before both tsconfig handling and running ESLint occur.
44
44
  */
@@ -52,7 +52,7 @@ export declare class Xo {
52
52
  /**
53
53
  Initializes the ESLint instance on the XO instance.
54
54
  */
55
- initEslint(files?: string[], cliIgnores?: string[], stripDefaultIgnores?: boolean): Promise<void>;
55
+ initEslint(files?: string[], cliIgnores?: string[], shouldStripDefaultIgnores?: boolean): Promise<void>;
56
56
  /**
57
57
  Create an ESLint flat config for editor integrations using the same XO pipeline as the CLI.
58
58
  */
package/dist/lib/xo.js CHANGED
@@ -39,7 +39,7 @@ const createIgnoredLintResult = (filePath) => ({
39
39
  usedDeprecatedRules: [],
40
40
  });
41
41
  const normalizeGlobPath = (filePath) => filePath.split(path.sep).join('/');
42
- const pathMatchesPattern = (filePath, pattern) => micromatch.isMatch(normalizeGlobPath(filePath), normalizeGlobPath(pattern), { dot: true });
42
+ const isPathMatchingPattern = (filePath, pattern) => micromatch.isMatch(normalizeGlobPath(filePath), normalizeGlobPath(pattern), { dot: true });
43
43
  const isPathInside = (parentPath, childPath) => {
44
44
  const relativePath = path.relative(parentPath, childPath);
45
45
  return relativePath === '' || (!relativePath.startsWith('..') && !path.isAbsolute(relativePath));
@@ -55,12 +55,12 @@ const isIgnoredByPatterns = (filePath, patterns) => {
55
55
  let isIgnored = false;
56
56
  for (const pattern of patterns) {
57
57
  if (pattern.startsWith('!')) {
58
- if (pathMatchesPattern(filePath, pattern.slice(1))) {
58
+ if (isPathMatchingPattern(filePath, pattern.slice(1))) {
59
59
  isIgnored = false;
60
60
  }
61
61
  continue;
62
62
  }
63
- if (pathMatchesPattern(filePath, pattern)) {
63
+ if (isPathMatchingPattern(filePath, pattern)) {
64
64
  isIgnored = true;
65
65
  }
66
66
  }
@@ -129,7 +129,7 @@ const stripDefaultIgnoreConfigs = (configs) => configs.map(configItem => {
129
129
  const { ignores: _ignored, ...configWithoutIgnores } = configItem;
130
130
  return configWithoutIgnores;
131
131
  });
132
- const defaultIgnoreOverlapsReopenedPattern = (defaultIgnore, pattern) => {
132
+ const doesDefaultIgnoreOverlapReopenedPattern = (defaultIgnore, pattern) => {
133
133
  const { base, isGlob } = micromatch.scan(pattern, { parts: true });
134
134
  const patternDirname = path.posix.dirname(pattern);
135
135
  const reopenedBase = isGlob ? base : (patternDirname === '' ? pattern : patternDirname);
@@ -145,7 +145,7 @@ const defaultIgnoreOverlapsReopenedPattern = (defaultIgnore, pattern) => {
145
145
  const getReopenedDefaultPatterns = (patterns) => patterns
146
146
  .filter(pattern => pattern.startsWith('!'))
147
147
  .map(pattern => pattern.slice(1))
148
- .filter(pattern => defaultIgnores.some(defaultIgnore => defaultIgnoreOverlapsReopenedPattern(defaultIgnore, pattern)));
148
+ .filter(pattern => defaultIgnores.some(defaultIgnore => doesDefaultIgnoreOverlapReopenedPattern(defaultIgnore, pattern)));
149
149
  /**
150
150
  XO only compensates for negations that reopen its built-in default ignores.
151
151
  User-provided positive ignores are still used only for pruning.
@@ -174,7 +174,7 @@ const discoverLintFiles = async ({ cwd, globs, positiveGlobalIgnores, discoveryI
174
174
  const reopenedFiles = await globby(globs, {
175
175
  ignore: [
176
176
  ...positiveGlobalIgnores,
177
- ...defaultIgnores.filter(defaultIgnore => reopenedDefaultPatterns.every(pattern => !defaultIgnoreOverlapsReopenedPattern(defaultIgnore, pattern))),
177
+ ...defaultIgnores.filter(defaultIgnore => reopenedDefaultPatterns.every(pattern => !doesDefaultIgnoreOverlapReopenedPattern(defaultIgnore, pattern))),
178
178
  ],
179
179
  onlyFiles: true,
180
180
  gitignore: true,
@@ -300,11 +300,11 @@ export class Xo {
300
300
  /**
301
301
  Initializes the ESLint flat config on the XO instance.
302
302
  */
303
- async prepareEslintConfig(files, cliIgnores = arrify(this.#baseXoConfig.ignores), stripDefaultIgnores = false) {
303
+ async prepareEslintConfig(files, cliIgnores = arrify(this.#baseXoConfig.ignores), shouldStripDefaultIgnores = false) {
304
304
  await this.setXoConfig();
305
305
  await this.ensureCacheDirectory();
306
306
  await this.handleUnincludedTsFiles(files);
307
- this.setEslintConfig(cliIgnores, stripDefaultIgnores);
307
+ this.setEslintConfig(cliIgnores, shouldStripDefaultIgnores);
308
308
  if (!this.#eslintConfig) {
309
309
  throw new Error('"Xo.prepareEslintConfig" failed');
310
310
  }
@@ -412,17 +412,14 @@ export class Xo {
412
412
  ...this.getReportStatistics(report),
413
413
  };
414
414
  defineLazyProperty(result, 'usedDeprecatedRules', () => {
415
- const seenRules = new Set();
416
- const rules = [];
417
- for (const { usedDeprecatedRules } of report) {
418
- for (const rule of usedDeprecatedRules) {
419
- if (!seenRules.has(rule.ruleId)) {
420
- seenRules.add(rule.ruleId);
421
- rules.push(rule);
422
- }
415
+ const seenRuleIds = new Set();
416
+ return report.flatMap(({ usedDeprecatedRules }) => usedDeprecatedRules).filter(rule => {
417
+ if (seenRuleIds.has(rule.ruleId)) {
418
+ return false;
423
419
  }
424
- }
425
- return rules;
420
+ seenRuleIds.add(rule.ruleId);
421
+ return true;
422
+ });
426
423
  });
427
424
  return result;
428
425
  }
@@ -474,7 +471,7 @@ export class Xo {
474
471
  this.#tsFilesGlob.push(...tsGlob);
475
472
  this.#tsFilesIgnoresGlob.push(...tsFilesIgnoresGlob);
476
473
  }
477
- setEslintConfig(cliIgnores = arrify(this.#baseXoConfig.ignores), stripDefaultIgnores = false) {
474
+ setEslintConfig(cliIgnores = arrify(this.#baseXoConfig.ignores), shouldStripDefaultIgnores = false) {
478
475
  if (!this.#xoConfig) {
479
476
  throw new Error('"Xo.setEslintConfig" failed');
480
477
  }
@@ -485,7 +482,7 @@ export class Xo {
485
482
  const allConfigs = [configWithoutCliIgnores, ...expandedResolvedConfigs, ...cliIgnoreConfig];
486
483
  // Always regenerate to support instance reuse with new files
487
484
  this.#eslintConfig = xoToEslintConfig(allConfigs);
488
- if (stripDefaultIgnores) {
485
+ if (shouldStripDefaultIgnores) {
489
486
  this.#eslintConfig = stripDefaultIgnoreConfigs(this.#eslintConfig);
490
487
  }
491
488
  }
@@ -532,8 +529,8 @@ export class Xo {
532
529
  /**
533
530
  Initializes the ESLint instance on the XO instance.
534
531
  */
535
- async initEslint(files, cliIgnores = arrify(this.#baseXoConfig.ignores), stripDefaultIgnores = false) {
536
- await this.prepareEslintConfig(files, cliIgnores, stripDefaultIgnores);
532
+ async initEslint(files, cliIgnores = arrify(this.#baseXoConfig.ignores), shouldStripDefaultIgnores = false) {
533
+ await this.prepareEslintConfig(files, cliIgnores, shouldStripDefaultIgnores);
537
534
  if (!this.#xoConfig) {
538
535
  throw new Error('"Xo.initEslint" failed');
539
536
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xo",
3
- "version": "3.0.2",
3
+ "version": "4.0.0",
4
4
  "description": "JavaScript/TypeScript linter (ESLint wrapper) with great defaults",
5
5
  "license": "MIT",
6
6
  "repository": "xojs/xo",
@@ -77,30 +77,30 @@
77
77
  "arrify": "^3.0.0",
78
78
  "cosmiconfig": "^9.0.2",
79
79
  "define-lazy-prop": "^3.0.0",
80
- "eslint": "^10.5.0",
81
- "eslint-config-xo": "^0.53.1",
80
+ "eslint": "^10.6.0",
81
+ "eslint-config-xo": "^0.57.0",
82
82
  "eslint-formatter-pretty": "^7.1.0",
83
83
  "find-cache-directory": "^6.0.0",
84
84
  "get-stdin": "^10.0.0",
85
85
  "get-tsconfig": "^4.14.0",
86
- "globby": "^16.2.0",
86
+ "globby": "^16.2.1",
87
87
  "jiti": "^2.7.0",
88
88
  "meow": "^14.1.0",
89
89
  "micromatch": "^4.0.8",
90
90
  "open-editor": "^6.0.0",
91
91
  "path-exists": "^5.0.0",
92
- "prettier": "^3.8.4",
93
- "type-fest": "^5.7.0",
92
+ "prettier": "^3.9.4",
93
+ "type-fest": "^5.8.0",
94
94
  "typescript": "^6.0.3"
95
95
  },
96
96
  "devDependencies": {
97
97
  "@types/micromatch": "^4.0.10",
98
- "@types/node": "^25.9.3",
98
+ "@types/node": "^26.1.0",
99
99
  "dedent": "^1.7.2",
100
100
  "eslint-plugin-vue": "^10.9.2",
101
101
  "execa": "^9.6.1",
102
102
  "husky": "^9.1.7",
103
- "np": "^11.2.1",
103
+ "np": "^11.2.2",
104
104
  "temp-dir": "^3.0.0",
105
105
  "xo": "file:."
106
106
  },