From f346cee585ea9e9fb721a578ad634cf97400fd75 Mon Sep 17 00:00:00 2001 From: Spencer Snyder Date: Sun, 18 Aug 2024 15:49:03 -0400 Subject: [PATCH] feat: cleanup and options improvements --- lib/cli.ts | 65 +++-- .../handle-prettier-options.ts | 5 +- lib/create-eslint-config/index.ts | 96 +------ lib/create-eslint-config/xo-plugins-config.ts | 78 ++++++ .../xo-to-eslint-config-item.ts | 6 +- lib/rules.ts | 10 +- lib/types.ts | 12 +- lib/xo.ts | 27 +- package-lock.json | 253 +++++++++++------- package.json | 14 +- test/cli.test.ts | 4 +- test/create-eslint-config.test.ts | 7 +- test/helpers/get-rule.ts | 6 +- tsconfig.json | 2 +- types.d.ts | 12 +- 15 files changed, 332 insertions(+), 265 deletions(-) create mode 100644 lib/create-eslint-config/xo-plugins-config.ts diff --git a/lib/cli.ts b/lib/cli.ts index 1e1fbf0..7d30588 100644 --- a/lib/cli.ts +++ b/lib/cli.ts @@ -1,9 +1,13 @@ -#!/usr/bin/env node +#!/usr/bin/env -S node --no-warnings=ExperimentalWarning +// no-use-extend-native plugin creates an experimental warning so we silence it +// https://github.com/nodejs/node/issues/30810#issuecomment-1893682691 + import path from 'node:path'; import process from 'node:process'; -import {type Rule} from 'eslint'; -import formatterPretty, {type LintResult} from 'eslint-formatter-pretty'; -import meow from 'meow'; +import {type Rule, type ESLint} from 'eslint'; +import formatterPretty from 'eslint-formatter-pretty'; +// eslint-disable-next-line import-x/no-named-default +import {default as meow} from 'meow'; import _debug from 'debug'; import type {LinterOptions, XoConfigOptions} from './types.js'; import {XO} from './xo.js'; @@ -17,12 +21,12 @@ const cli = meow( Options --fix Automagically fix issues - --space Use space indent instead of tabs [Default: 2] - --no-semicolon Prevent use of semicolons - --prettier Conform to Prettier code style + --space Use space indent instead of tabs [Default: 2] + --semicolon Use semicolons [Default: true] + --prettier Conform to Prettier code style [Default: false] --print-config Print the effective ESLint config for the given file --ignore Ignore pattern globs, can be set multiple times - --cwd= Working directory for files + --cwd= Working directory for files [Default: process.cwd()] Examples $ xo @@ -46,6 +50,12 @@ const cli = meow( space: { type: 'string', }, + config: { + type: 'string', + }, + quiet: { + type: 'boolean', + }, semicolon: { type: 'boolean', }, @@ -85,6 +95,7 @@ const baseXoConfigOptions: XoConfigOptions = { const linterOptions: LinterOptions = { fix: cliOptions.fix, cwd: (cliOptions.cwd && path.resolve(cliOptions.cwd)) ?? process.cwd(), + quiet: cliOptions.quiet, }; // Make data types for `options.space` match those of the API @@ -107,27 +118,29 @@ if (typeof cliOptions.space === 'string') { } } -// if ( -// process.env['GITHUB_ACTIONS'] && -// !linterOptions.fix && -// !linterOptions.reporter -// ) { -// linterOptions.quiet = true; -// } +if ( + process.env['GITHUB_ACTIONS'] + && !linterOptions.fix + && !cliOptions.reporter +) { + linterOptions.quiet = true; +} const log = async (report: { - cwd: string; - results: Array>; - rulesMeta: Record & {cwd: string}; - errorCount?: number; + errorCount: number; + warningCount: number; + fixableErrorCount: number; + fixableWarningCount: number; + results: ESLint.LintResult[]; + rulesMeta: Record; }) => { - const reporter = formatterPretty; - // cliOptions.reporter - // ? await new XO(cliOptions).getFormatter(cliOptions.reporter ?? 'compact') - // : + const reporter + = cliOptions.reporter + ? await new XO(linterOptions, baseXoConfigOptions).getFormatter(cliOptions.reporter) + : {format: formatterPretty}; - // @ts-expect-error upgrade stuff - console.log(reporter(report.results, report)); + // @ts-expect-error the types don't quite match up here + console.log(reporter.format(report.results, {cwd: linterOptions.cwd, ...report})); process.exitCode = report.errorCount === 0 ? 0 : 1; }; @@ -156,6 +169,6 @@ if (typeof cliOptions.printConfig === 'string') { debug('xo.outputFixes success'); } - // @ts-expect-error idk man + // @ts-expect-error dues to the types in the formatter await log(report); } diff --git a/lib/create-eslint-config/handle-prettier-options.ts b/lib/create-eslint-config/handle-prettier-options.ts index 4f9aef4..97f93e6 100644 --- a/lib/create-eslint-config/handle-prettier-options.ts +++ b/lib/create-eslint-config/handle-prettier-options.ts @@ -1,8 +1,7 @@ // eslint-disable-next-line import-x/no-named-default import {default as prettier} from 'prettier'; -import {type FlatESLintConfig} from 'eslint-define-config'; +import {type Linter, type ESLint} from 'eslint'; import pluginPrettier from 'eslint-plugin-prettier'; -import {type ESLint} from 'eslint'; import configPrettier from 'eslint-config-prettier'; import {type XoConfigItem} from '../types.js'; @@ -17,7 +16,7 @@ let cachedPrettierConfig: Record; * @param xoUserConfig * @param eslintConfigItem */ -export async function handlePrettierOptions(cwd: string, xoUserConfig: XoConfigItem, eslintConfigItem: FlatESLintConfig): Promise { +export async function handlePrettierOptions(cwd: string, xoUserConfig: XoConfigItem, eslintConfigItem: Linter.Config): Promise { const prettierOptions = cachedPrettierConfig ?? (await prettier.resolveConfig(cwd, {editorconfig: true})) ?? {}; // Only look up prettier once per run diff --git a/lib/create-eslint-config/index.ts b/lib/create-eslint-config/index.ts index 81cf094..99d3cfd 100644 --- a/lib/create-eslint-config/index.ts +++ b/lib/create-eslint-config/index.ts @@ -1,92 +1,18 @@ -/* eslint-disable complexity */ -import pluginAva from 'eslint-plugin-ava'; -import pluginUnicorn from 'eslint-plugin-unicorn'; -import pluginImport from 'eslint-plugin-import-x'; -import pluginN from 'eslint-plugin-n'; -import pluginComments from '@eslint-community/eslint-plugin-eslint-comments'; -import pluginPromise from 'eslint-plugin-promise'; -import pluginNoUseExtendNative from 'eslint-plugin-no-use-extend-native'; + +import process from 'node:process'; import configXoTypescript from 'eslint-config-xo-typescript'; -import stylisticPlugin from '@stylistic/eslint-plugin'; import arrify from 'arrify'; -import globals from 'globals'; -import {type FlatESLintConfig} from 'eslint-define-config'; -import { - DEFAULT_IGNORES, - TS_EXTENSIONS, - TS_FILES_GLOB, - ALL_FILES_GLOB, - JS_EXTENSIONS, - ALL_EXTENSIONS, -} from '../constants.js'; +import {type Linter} from 'eslint'; import {type XoConfigItem} from '../types.js'; -import {jsRules, tsRules, baseRules} from '../rules.js'; +import {xoPluginsConfig} from './xo-plugins-config.js'; import {xoToEslintConfigItem} from './xo-to-eslint-config-item.js'; import {handlePrettierOptions} from './handle-prettier-options.js'; /** * Takes a xo flat config and returns an eslint flat config */ -async function createConfig(userConfigs?: XoConfigItem[]): Promise { - const cwd = ''; - - const baseConfig: FlatESLintConfig[] = [ - { - ignores: DEFAULT_IGNORES, - }, - { - files: [ALL_FILES_GLOB], - plugins: { - 'no-use-extend-native': pluginNoUseExtendNative, - ava: pluginAva, - unicorn: pluginUnicorn, - 'import-x': pluginImport, - n: pluginN, - '@eslint-community/eslint-comments': pluginComments, - promise: pluginPromise, - '@stylistic': stylisticPlugin, - }, - languageOptions: { - globals: { - ...globals.es2021, - ...globals.node, - }, - ecmaVersion: configXoTypescript[0]?.languageOptions?.ecmaVersion, - sourceType: configXoTypescript[0]?.languageOptions?.sourceType, - parserOptions: { - ...configXoTypescript[0]?.languageOptions?.parserOptions, - }, - }, - settings: { - 'import-x/extensions': ALL_EXTENSIONS, - 'import-x/core-modules': ['electron', 'atom'], - 'import-x/parsers': { - espree: JS_EXTENSIONS, - '@typescript-eslint/parser': TS_EXTENSIONS, - }, - 'import-x/external-module-folders': [ - 'node_modules', - 'node_modules/@types', - ], - 'import-x/resolver': { - node: ALL_EXTENSIONS, - }, - }, - /** - * These are the base rules that are always applied to all js and ts file types - */ - rules: {...baseRules, ...jsRules}, - }, - { - plugins: configXoTypescript[1]?.plugins, - files: [TS_FILES_GLOB], - languageOptions: configXoTypescript[1]?.languageOptions, - /** This turns on rules in typescript-eslint and turns off rules from eslint that conflict */ - rules: tsRules, - }, - ...configXoTypescript.slice(2), - ]; - +export async function createConfig(userConfigs?: XoConfigItem[], cwd?: string): Promise { + const baseConfig: Linter.Config[] = [...xoPluginsConfig]; /** * Since configs are merged and the last config takes precedence * this means we need to handle both true AND false cases for each option. @@ -99,10 +25,7 @@ async function createConfig(userConfigs?: XoConfigItem[]): Promise => { +export const xoToEslintConfigItem = (xoConfig: XoConfigItem): SetRequired => { const {files, rules, space, prettier, ignores, semicolon, ..._xoConfig} = xoConfig; - const eslintConfig: SetRequired = { + const eslintConfig: SetRequired = { ..._xoConfig, files: arrify(xoConfig.files ?? ALL_FILES_GLOB), rules: xoConfig.rules ?? {}, diff --git a/lib/rules.ts b/lib/rules.ts index eada7b3..50ac694 100644 --- a/lib/rules.ts +++ b/lib/rules.ts @@ -1,13 +1,13 @@ import pluginAva from 'eslint-plugin-ava'; import pluginUnicorn from 'eslint-plugin-unicorn'; import configXoTypescript from 'eslint-config-xo-typescript'; -import {type Rules} from 'eslint-define-config'; +import {type Linter} from 'eslint'; if (Array.isArray(pluginAva?.configs?.['recommended'])) { throw new TypeError('Invalid pluginAva'); } -export const baseRules: Partial = { +export const baseRules: Partial = { ...pluginAva?.configs?.['recommended']?.rules, ...pluginUnicorn.configs?.recommended?.rules, 'no-use-extend-native/no-use-extend-native': 'error', @@ -298,12 +298,12 @@ export const baseRules: Partial = { '@eslint-community/eslint-comments/no-unused-enable': 'error', }; -export const jsRules: Partial = { +export const jsRules: Partial = { ...configXoTypescript[0]?.rules, 'capitalized-comments': 'off', }; -const customTsRules: Partial = { +const customTsRules: Partial = { 'unicorn/import-style': 'off', 'n/file-extension-in-import': 'off', // Disabled because of https://github.com/benmosher/eslint-plugin-import-x/issues/1590 @@ -315,7 +315,7 @@ const customTsRules: Partial = { 'import-x/named': 'off', }; -export const tsRules: Partial = { +export const tsRules: Partial = { ...configXoTypescript[1]?.rules, ...customTsRules, }; diff --git a/lib/types.ts b/lib/types.ts index 87c2edb..52ce924 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,5 +1,5 @@ -import {type FlatESLintConfig} from 'eslint-define-config'; -import {type ESLint, type Rule} from 'eslint'; +import type {Simplify} from 'type-fest'; +import {type ESLint, type Rule, type Linter} from 'eslint'; export type Space = boolean | number | string | undefined; @@ -36,6 +36,10 @@ export type LinterOptions = { * The path to the file being linted. */ filePath?: string; + /** + * If true,show only errors and NOT warnings. false by default. + */ + quiet?: boolean; }; export type LintTextOptions = { @@ -49,7 +53,7 @@ export type LintTextOptions = { warnIgnored?: boolean; }; -export type XoConfigItem = XoConfigOptions & Omit & { +export type XoConfigItem = Simplify & { /** * An array of glob patterns indicating the files that the configuration object should apply to. If not specified, the configuration object applies to all files. * @@ -62,7 +66,7 @@ export type XoConfigItem = XoConfigOptions & Omit; export type FlatXoConfig = XoConfigItem[]; diff --git a/lib/xo.ts b/lib/xo.ts index 9585669..6af3d3f 100644 --- a/lib/xo.ts +++ b/lib/xo.ts @@ -6,7 +6,6 @@ import findCacheDir from 'find-cache-dir'; import {globby} from 'globby'; import arrify from 'arrify'; import defineLazyProperty from 'define-lazy-prop'; -import {type FlatESLintConfig} from 'eslint-define-config'; import _debug from 'debug'; import { type XoLintResult, @@ -65,7 +64,7 @@ export class XO { /** * The ESLint config calculated from the resolved XO config */ - eslintConfig?: FlatESLintConfig[]; + eslintConfig?: Linter.Config[]; /** * The xo flat config path, if there is one */ @@ -108,7 +107,7 @@ export class XO { throw new Error('"XO.setEslintConfig" failed'); } - this.eslintConfig ??= await createConfig([...this.xoConfig]); + this.eslintConfig ??= await createConfig([...this.xoConfig], this.linterOptions.cwd); } /** @@ -223,11 +222,7 @@ export class XO { lintFilesDebug('get rulesMeta success'); - return { - results, - rulesMeta, - ...results[0], - }; + return this.processReport(results, {rulesMeta}); } /** @@ -270,11 +265,21 @@ export class XO { return this.eslint.calculateConfigForFile(filePath) as Promise; } + async getFormatter(name: string) { + await this.initEslint(); + + if (!this.eslint) { + throw new Error('Failed to initialize ESLint'); + } + + return this.eslint.loadFormatter(name); + } + processReport( report: ESLint.LintResult[], - {isQuiet = false, rulesMeta = {}} = {}, + {rulesMeta = {}} = {}, ) { - if (isQuiet) { + if (this.linterOptions.quiet) { report = ESLint.getErrorResults(report); } @@ -324,4 +329,6 @@ export class XO { }; } +export * from './types.js'; +export * from './create-eslint-config/index.js'; export default XO; diff --git a/package-lock.json b/package-lock.json index 69ff1f8..08a74fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,8 +19,7 @@ "eslint": "^9.9.0", "eslint-config-prettier": "^9.1.0", "eslint-config-xo-typescript": "^6.0.0", - "eslint-define-config": "~2.1.0", - "eslint-formatter-pretty": "^5.0.0", + "eslint-formatter-pretty": "^6.0.1", "eslint-plugin-ava": "^15.0.1", "eslint-plugin-import-x": "^3.1.0", "eslint-plugin-n": "^17.10.2", @@ -40,7 +39,7 @@ "json-stable-stringify-without-jsonify": "^1.0.1", "json5": "^2.2.3", "lodash.isempty": "^4.4.0", - "lodash.pick": "^4.4.0", + "lodash.pick": "^3.1.0", "meow": "^13.2.0", "micromatch": "^4.0.7", "open-editor": "^5.0.0", @@ -54,7 +53,7 @@ "webpack": "^5.93.0" }, "bin": { - "xo": "dist/cli.js" + "xo": "dist/lib/cli.js" }, "devDependencies": { "@commitlint/cli": "^19.4.0", @@ -74,11 +73,11 @@ "path-exists": "^5.0.0", "prettier-plugin-packagejson": "^2.5.1", "temp-dir": "^3.0.0", - "xo": "file:./dist/lib/xo.js" + "xo": "file:." } }, "dist/lib/xo.js": { - "dev": true + "extraneous": true }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", @@ -2259,6 +2258,18 @@ "ajv": ">=5.0.0" } }, + "node_modules/ansi-escapes": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -3509,42 +3520,23 @@ "typescript": ">=5.5.0" } }, - "node_modules/eslint-define-config": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-define-config/-/eslint-define-config-2.1.0.tgz", - "integrity": "sha512-QUp6pM9pjKEVannNAbSJNeRuYwW3LshejfyBBpjeMGaJjaDUpVps4C6KVR8R7dWZnD3i0synmrE36znjTkJvdQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/Shinigami92" - }, - { - "type": "paypal", - "url": "https://www.paypal.com/donate/?hosted_button_id=L7GY729FBKTZY" - } - ], - "engines": { - "node": ">=18.0.0", - "npm": ">=9.0.0", - "pnpm": ">=8.6.0" - } - }, "node_modules/eslint-formatter-pretty": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-formatter-pretty/-/eslint-formatter-pretty-5.0.0.tgz", - "integrity": "sha512-Uick451FoL22/wXqyScX3inW8ZlD/GQO7eFXj3bqb6N/ZtuuF00/CwSNIKLbFCJPrX5V4EdQBSgJ/UVnmLRnug==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/eslint-formatter-pretty/-/eslint-formatter-pretty-6.0.1.tgz", + "integrity": "sha512-znAUcXmBthdIUmlnRkPSxz3zSJHFUhfHF/nJPcCMVKg/mOa4yUie2Olqg1Ghbi5JJRBZVU3rIgzWSObvIspxMA==", + "license": "MIT", "dependencies": { - "@types/eslint": "^8.0.0", - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", + "@types/eslint": "^8.44.6", + "ansi-escapes": "^6.2.0", + "chalk": "^5.3.0", "eslint-rule-docs": "^1.1.235", - "log-symbols": "^4.0.0", - "plur": "^4.0.0", - "string-width": "^4.2.0", - "supports-hyperlinks": "^2.0.0" + "log-symbols": "^6.0.0", + "plur": "^5.1.0", + "string-width": "^7.0.0", + "supports-hyperlinks": "^3.0.0" }, "engines": { - "node": ">=14.16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3559,85 +3551,64 @@ "@types/json-schema": "*" } }, - "node_modules/eslint-formatter-pretty/node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dependencies": { - "type-fest": "^0.21.3" - }, + "node_modules/eslint-formatter-pretty/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "license": "MIT", "engines": { - "node": ">=8" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-formatter-pretty/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/eslint-formatter-pretty/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "license": "MIT" }, - "node_modules/eslint-formatter-pretty/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/eslint-formatter-pretty/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-formatter-pretty/node_modules/plur": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/plur/-/plur-4.0.0.tgz", - "integrity": "sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==", + "node_modules/eslint-formatter-pretty/node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "license": "MIT", "dependencies": { - "irregular-plurals": "^3.2.0" + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint-formatter-pretty/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint-formatter-pretty/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/eslint-formatter-pretty/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4707,7 +4678,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", - "dev": true, "engines": { "node": ">=18" }, @@ -5861,12 +5831,62 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash._baseflatten": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz", + "integrity": "sha512-fESngZd+X4k+GbTxdMutf8ohQa0s3sJEHIcwtu4/LsIQ2JTDzdRxDCMQjW+ezzwRitLmHnacVVmosCbxifefbw==", + "license": "MIT", + "dependencies": { + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "node_modules/lodash._basefor": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", + "integrity": "sha512-6bc3b8grkpMgDcVJv9JYZAk/mHgcqMljzm7OsbmcE2FGUMmmLQTPHlh/dFqR8LA0GQ7z4K67JSotVKu5058v1A==", + "license": "MIT" + }, + "node_modules/lodash._bindcallback": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", + "integrity": "sha512-2wlI0JRAGX8WEf4Gm1p/mv/SZ+jLijpj0jyaE/AXeuQphzCgD8ZQW4oSpoN8JAopujOFGU3KMuq7qfHBWlGpjQ==", + "license": "MIT" + }, + "node_modules/lodash._pickbyarray": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash._pickbyarray/-/lodash._pickbyarray-3.0.2.tgz", + "integrity": "sha512-tHzBIfgugzI7HV0y8MJS1z/ryWDh8NyD6AV+so9vlplRnhD4qBuwoyDt7g241ad3F43YDFghCN+R3iaFd4Azvw==", + "license": "MIT" + }, + "node_modules/lodash._pickbycallback": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._pickbycallback/-/lodash._pickbycallback-3.0.0.tgz", + "integrity": "sha512-DVP27YmN0lB+j/Tgd/+gtxfmW/XihgWpQpHptBuwyp2fD9zEBRwwcnw6Qej16LUV8LRFuTqyoc0i6ON97d/C5w==", + "license": "MIT", + "dependencies": { + "lodash._basefor": "^3.0.0", + "lodash.keysin": "^3.0.0" + } + }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", "dev": true }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", + "license": "MIT" + }, + "node_modules/lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==", + "license": "MIT" + }, "node_modules/lodash.isempty": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz", @@ -5885,6 +5905,16 @@ "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", "dev": true }, + "node_modules/lodash.keysin": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz", + "integrity": "sha512-YDB/5xkL3fBKFMDaC+cfGV00pbiJ6XoJIfRmBhv7aR6wWtbCW6IzkiWnTfkiHTF6ALD7ff83dAtB3OEaSoyQPg==", + "license": "MIT", + "dependencies": { + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5898,9 +5928,22 @@ "license": "MIT" }, "node_modules/lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-3.1.0.tgz", + "integrity": "sha512-Y04wnFghB7l1dkYINfjdMLpeAGM1IYEjlsGFxvjeewCbVQUlD9jw3M20ThuNrsf6yGmuPLwj60PKP+D6gZ+o2w==", + "license": "MIT", + "dependencies": { + "lodash._baseflatten": "^3.0.0", + "lodash._bindcallback": "^3.0.0", + "lodash._pickbyarray": "^3.0.0", + "lodash._pickbycallback": "^3.0.0", + "lodash.restparam": "^3.0.0" + } + }, + "node_modules/lodash.restparam": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==", "license": "MIT" }, "node_modules/lodash.snakecase": { @@ -5932,6 +5975,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -5947,6 +5991,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, "engines": { "node": ">=10" }, @@ -7067,7 +7112,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/plur/-/plur-5.1.0.tgz", "integrity": "sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==", - "dev": true, "dependencies": { "irregular-plurals": "^3.3.0" }, @@ -8108,15 +8152,16 @@ } }, "node_modules/supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz", + "integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==", + "license": "MIT", "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=14.18" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -8885,7 +8930,7 @@ } }, "node_modules/xo": { - "resolved": "dist/lib/xo.js", + "resolved": "", "link": true }, "node_modules/y18n": { diff --git a/package.json b/package.json index 6fd1c50..1149e94 100644 --- a/package.json +++ b/package.json @@ -3,17 +3,16 @@ "version": "0.0.0", "description": "xo with eslint flat config", "type": "module", - "main": "dist/lib/cli.js", + "main": "dist/lib/xo.js", "bin": { - "xo": "dist/cli.js" + "xo": "dist/lib/cli.js" }, "scripts": { "build": "npm run clean && tsc", "build:watch": "tsc --watch", "clean": "rm -rf dist", "test": "npm run test:setup && npm run build && ava", - "test:setup": "node scripts/setup-tests", - "test:watch": "npm run test:setup && ava --watch" + "test:setup": "node scripts/setup-tests" }, "prettier": { "plugins": [ @@ -47,8 +46,7 @@ "eslint": "^9.9.0", "eslint-config-prettier": "^9.1.0", "eslint-config-xo-typescript": "^6.0.0", - "eslint-define-config": "~2.1.0", - "eslint-formatter-pretty": "^5.0.0", + "eslint-formatter-pretty": "^6.0.1", "eslint-plugin-ava": "^15.0.1", "eslint-plugin-import-x": "^3.1.0", "eslint-plugin-n": "^17.10.2", @@ -68,7 +66,7 @@ "json-stable-stringify-without-jsonify": "^1.0.1", "json5": "^2.2.3", "lodash.isempty": "^4.4.0", - "lodash.pick": "^4.4.0", + "lodash.pick": "^3.1.0", "meow": "^13.2.0", "micromatch": "^4.0.7", "open-editor": "^5.0.0", @@ -99,6 +97,6 @@ "path-exists": "^5.0.0", "prettier-plugin-packagejson": "^2.5.1", "temp-dir": "^3.0.0", - "xo": "file:./dist/lib/xo.js" + "xo": "file:." } } diff --git a/test/cli.test.ts b/test/cli.test.ts index efa957e..3c2f55c 100644 --- a/test/cli.test.ts +++ b/test/cli.test.ts @@ -19,13 +19,13 @@ test('xo --cwd', async t => { const filePath = path.join(t.context.cwd, 'test.js'); await fs.writeFile(filePath, dedent`console.log('hello');\n`, 'utf8'); - await t.notThrowsAsync($`node . --cwd ${t.context.cwd}`); + await t.notThrowsAsync($`node ./dist/lib/cli --cwd ${t.context.cwd}`); }); test('xo --fix', async t => { const filePath = path.join(t.context.cwd, 'test.js'); await fs.writeFile(filePath, dedent`console.log('hello')\n`, 'utf8'); - await t.notThrowsAsync($`node . --cwd ${t.context.cwd} --fix`); + await t.notThrowsAsync($`node ./dist/lib/cli --cwd ${t.context.cwd} --fix`); const fileContent = await fs.readFile(filePath, 'utf8'); t.is(fileContent, dedent`console.log('hello');\n`); }); diff --git a/test/create-eslint-config.test.ts b/test/create-eslint-config.test.ts index 0d845f6..003a428 100644 --- a/test/create-eslint-config.test.ts +++ b/test/create-eslint-config.test.ts @@ -1,3 +1,4 @@ +import process from 'node:process'; import test from 'ava'; import createConfig from '../lib/create-eslint-config/index.js'; import {getJsRule} from './helpers/get-rule.js'; @@ -68,7 +69,6 @@ test('with prettier option', async t => { { bracketSameLine: false, bracketSpacing: false, - plugins: ['prettier-plugin-packagejson'], semi: undefined, singleQuote: true, tabWidth: 2, @@ -82,7 +82,6 @@ test('with prettier option', async t => { { bracketSameLine: false, bracketSpacing: false, - plugins: ['prettier-plugin-packagejson'], semi: undefined, singleQuote: true, tabWidth: 2, @@ -112,7 +111,6 @@ test('with prettier option and space', async t => { { bracketSameLine: false, bracketSpacing: false, - plugins: ['prettier-plugin-packagejson'], semi: undefined, singleQuote: true, tabWidth: 2, @@ -121,12 +119,13 @@ test('with prettier option and space', async t => { }, ]); + t.log(process.cwd()); + t.deepEqual(prettierConfigTs?.rules?.['prettier/prettier'], [ 'error', { bracketSameLine: false, bracketSpacing: false, - plugins: ['prettier-plugin-packagejson'], semi: undefined, singleQuote: true, tabWidth: 2, diff --git a/test/helpers/get-rule.ts b/test/helpers/get-rule.ts index 595b321..e7eda73 100644 --- a/test/helpers/get-rule.ts +++ b/test/helpers/get-rule.ts @@ -1,4 +1,4 @@ -import {type FlatESLintConfig} from 'eslint-define-config'; +import {type Linter} from 'eslint'; import { ALL_FILES_GLOB, JS_FILES_GLOB, @@ -11,7 +11,7 @@ import { * @param flatConfig * @param ruleId */ -export const getJsRule = (flatConfig: FlatESLintConfig[], ruleId: string) => { +export const getJsRule = (flatConfig: Linter.Config[], ruleId: string) => { const config = [...flatConfig].reverse().find(config => (typeof config !== 'string' && config?.rules?.[ruleId] @@ -31,7 +31,7 @@ export const getJsRule = (flatConfig: FlatESLintConfig[], ruleId: string) => { * @param flatConfig * @param ruleId */ -export const getTsRule = (flatConfig: FlatESLintConfig[], ruleId: string) => { +export const getTsRule = (flatConfig: Linter.Config[], ruleId: string) => { const config = [...flatConfig] .reverse() .find(config => diff --git a/tsconfig.json b/tsconfig.json index bde2f42..90a2ef1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,6 @@ "outDir": "dist", "sourceMap": true }, - "include": ["**/*.ts", "scripts/setup-tests.js", "xo.config.ts"], + "include": ["**/*.ts", "scripts/setup-tests.js"], "exclude": ["node_modules", "dist"] } diff --git a/types.d.ts b/types.d.ts index 5ebbbb3..c6ea910 100644 --- a/types.d.ts +++ b/types.d.ts @@ -62,22 +62,22 @@ declare module 'eslint-plugin-promise' { } declare module 'eslint-config-xo-typescript' { - import {type FlatESLintConfig} from 'eslint-define-config'; + import {type Linter} from 'eslint'; - const config: FlatESLintConfig[]; + const config: Linter.Config[]; export default config; } declare module 'eslint-config-xo' { - import {type FlatESLintConfig} from 'eslint-define-config'; + import {type Linter} from 'eslint'; - const config: FlatESLintConfig[]; + const config: Linter.Config[]; export default config; } declare module 'eslint-config-prettier' { - import {type ESLintConfig} from 'eslint-define-config'; + import {type Linter} from 'eslint'; - const config: ESLintConfig; + const config: Linter.Config; export default config; }