diff --git a/package.json b/package.json index 805c96114..bee342bf0 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "chai-as-promised": "^7.1.1", "commitlint": "^17.7.2", "cross-env": "^7.0.3", - "eslint": "^8.49.0", + "eslint": "^8.50.0", "eslint-config-oclif": "^5.0.0", "eslint-config-oclif-typescript": "^2.0.1", "eslint-config-prettier": "^9.0.0", diff --git a/src/config/config.ts b/src/config/config.ts index 98d750141..9a3293cf4 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -4,13 +4,13 @@ import {CLIError, error, exit, warn} from '../errors' import {Debug, collectUsableIds, getCommandIdPermutations} from './util' import {Hook, Hooks, PJSON, Topic} from '../interfaces' import {Plugin as IPlugin, Options} from '../interfaces/plugin' +import { OCLIF_MARKER_OWNER, Performance } from '../performance' import {URL, fileURLToPath} from 'node:url' import {arch, userInfo as osUserInfo, release, tmpdir, type} from 'node:os' import {compact, isProd} from '../util/util' import {getHomeDir, getPlatform} from '../util/os' -import {join, sep} from 'node:path' +import { join, sep } from 'node:path' import {Command} from '../command' -import {Performance} from '../performance' import PluginLoader from './plugin-loader' import WSL from 'is-wsl' import {format} from 'node:util' @@ -153,9 +153,8 @@ export class Config implements IConfig { // eslint-disable-next-line complexity public async load(): Promise { - settings.performanceEnabled = - (settings.performanceEnabled === undefined ? this.options.enablePerf : settings.performanceEnabled) ?? false - const marker = Performance.mark('config.load') + settings.performanceEnabled = (settings.performanceEnabled === undefined ? this.options.enablePerf : settings.performanceEnabled) ?? false + const marker = Performance.mark(OCLIF_MARKER_OWNER, 'config.load') this.pluginLoader = new PluginLoader({root: this.options.root, plugins: this.options.plugins}) Config._rootPlugin = await this.pluginLoader.loadRoot() @@ -235,7 +234,7 @@ export class Config implements IConfig { } async loadPluginsAndCommands(opts?: {force: boolean}): Promise { - const pluginsMarker = Performance.mark('config.loadAllPlugins') + const pluginsMarker = Performance.mark(OCLIF_MARKER_OWNER, 'config.loadAllPlugins') const {plugins, errors} = await this.pluginLoader.loadChildren({ devPlugins: this.options.devPlugins, userPlugins: this.options.userPlugins, @@ -247,7 +246,7 @@ export class Config implements IConfig { this.plugins = plugins pluginsMarker?.stop() - const commandsMarker = Performance.mark('config.loadAllCommands') + const commandsMarker = Performance.mark(OCLIF_MARKER_OWNER, 'config.loadAllCommands') for (const plugin of this.plugins.values()) { this.loadCommands(plugin) this.loadTopics(plugin) @@ -266,7 +265,7 @@ export class Config implements IConfig { timeout?: number, captureErrors?: boolean, ): Promise> { - const marker = Performance.mark(`config.runHook#${event}`) + const marker = Performance.mark(OCLIF_MARKER_OWNER, `config.runHook#${event}`) debug('start %s hook', event) const search = (m: any): Hook => { if (typeof m === 'function') return m @@ -314,7 +313,7 @@ export class Config implements IConfig { const hooks = p.hooks[event] || [] for (const hook of hooks) { - const marker = Performance.mark(`config.runHook#${p.name}(${hook})`) + const marker = Performance.mark(OCLIF_MARKER_OWNER, `config.runHook#${p.name}(${hook})`) try { /* eslint-disable no-await-in-loop */ const {isESM, module, filePath} = await loadWithData(p, join(p.root, hook)) @@ -358,7 +357,7 @@ export class Config implements IConfig { argv: string[] = [], cachedCommand: Command.Loadable | null = null, ): Promise { - const marker = Performance.mark(`config.runCommand#${id}`) + const marker = Performance.mark(OCLIF_MARKER_OWNER, `config.runCommand#${id}`) debug('runCommand %s %o', id, argv) let c = cachedCommand ?? this.findCommand(id) if (!c) { @@ -681,7 +680,7 @@ export class Config implements IConfig { } private loadCommands(plugin: IPlugin) { - const marker = Performance.mark(`config.loadCommands#${plugin.name}`, {plugin: plugin.name}) + const marker = Performance.mark(OCLIF_MARKER_OWNER, `config.loadCommands#${plugin.name}`, {plugin: plugin.name}) for (const command of plugin.commands) { // set canonical command id if (this._commands.has(command.id)) { @@ -731,7 +730,7 @@ export class Config implements IConfig { } private loadTopics(plugin: IPlugin) { - const marker = Performance.mark(`config.loadTopics#${plugin.name}`, {plugin: plugin.name}) + const marker = Performance.mark(OCLIF_MARKER_OWNER, `config.loadTopics#${plugin.name}`, {plugin: plugin.name}) for (const topic of compact(plugin.topics)) { const existing = this._topics.get(topic.name) if (existing) { diff --git a/src/config/plugin-loader.ts b/src/config/plugin-loader.ts index ce01e68c7..9b0352714 100644 --- a/src/config/plugin-loader.ts +++ b/src/config/plugin-loader.ts @@ -1,8 +1,8 @@ import * as Plugin from './plugin' import {Plugin as IPlugin, Options} from '../interfaces/plugin' +import {OCLIF_MARKER_OWNER, Performance} from '../performance' import {Debug} from './util' import {PJSON} from '../interfaces' -import {Performance} from '../performance' import {isProd} from '../util/util' import {join} from 'node:path' import {readJson} from '../util/fs' @@ -43,7 +43,7 @@ export default class PluginLoader { const plugins = [...this.plugins.values()] rootPlugin = plugins.find((p) => p.root === this.options.root) ?? plugins[0] } else { - const marker = Performance.mark('plugin.load#root') + const marker = Performance.mark(OCLIF_MARKER_OWNER, 'plugin.load#root') rootPlugin = new Plugin.Plugin({root: this.options.root, isRoot: true}) await rootPlugin.load() marker?.addDetails({ @@ -121,7 +121,7 @@ export default class PluginLoader { parent?: Plugin.Plugin, ): Promise { if (!plugins || plugins.length === 0) return - const mark = Performance.mark(`config.loadPlugins#${type}`) + const mark = Performance.mark(OCLIF_MARKER_OWNER, `config.loadPlugins#${type}`) debug('loading plugins', plugins) await Promise.all( (plugins || []).map(async (plugin) => { @@ -142,7 +142,7 @@ export default class PluginLoader { } if (this.plugins.has(name)) return - const pluginMarker = Performance.mark(`plugin.load#${name}`) + const pluginMarker = Performance.mark(OCLIF_MARKER_OWNER, `plugin.load#${name}`) const instance = new Plugin.Plugin(opts) await instance.load() pluginMarker?.addDetails({ diff --git a/src/config/plugin.ts b/src/config/plugin.ts index af5a9fe67..28b884041 100644 --- a/src/config/plugin.ts +++ b/src/config/plugin.ts @@ -1,6 +1,7 @@ import {CLIError, error} from '../errors' import {Debug, getCommandIdPermutations, resolvePackage} from './util' import {Plugin as IPlugin, PluginOptions} from '../interfaces/plugin' +import {OCLIF_MARKER_OWNER, Performance} from '../performance' import {compact, isProd, mapValues} from '../util/util' import {dirname, join, parse, relative, sep} from 'node:path' import {exists, readJson, requireJson} from '../util/fs' @@ -8,7 +9,6 @@ import {loadWithData, loadWithDataFromManifest} from '../module-loader' import {Command} from '../command' import {Manifest} from '../interfaces/manifest' import {PJSON} from '../interfaces/pjson' -import {Performance} from '../performance' import {Topic} from '../interfaces/topic' import {cacheCommand} from '../util/cache-command' import {inspect} from 'node:util' @@ -206,7 +206,7 @@ export class Plugin implements IPlugin { public get commandIDs(): string[] { if (!this.commandsDir) return [] - const marker = Performance.mark(`plugin.commandIDs#${this.name}`, {plugin: this.name}) + const marker = Performance.mark(OCLIF_MARKER_OWNER, `plugin.commandIDs#${this.name}`, {plugin: this.name}) this._debug(`loading IDs from ${this.commandsDir}`) const patterns = ['**/*.+(js|cjs|mjs|ts|tsx)', '!**/*.+(d.ts|test.ts|test.js|spec.ts|spec.js)?(x)'] const ids = sync(patterns, {cwd: this.commandsDir}).map((file) => { @@ -227,7 +227,7 @@ export class Plugin implements IPlugin { public async findCommand(id: string, opts?: {must: boolean}): Promise public async findCommand(id: string, opts: {must?: boolean} = {}): Promise { - const marker = Performance.mark(`plugin.findCommand#${this.name}.${id}`, {id, plugin: this.name}) + const marker = Performance.mark(OCLIF_MARKER_OWNER, `plugin.findCommand#${this.name}.${id}`, {id, plugin: this.name}) const fetch = async () => { if (!this.commandsDir) return @@ -286,7 +286,7 @@ export class Plugin implements IPlugin { } } - const marker = Performance.mark(`plugin.manifest#${this.name}`, {plugin: this.name}) + const marker = Performance.mark(OCLIF_MARKER_OWNER, `plugin.manifest#${this.name}`, {plugin: this.name}) if (!ignoreManifest) { const manifest = await readManifest() if (manifest) { diff --git a/src/main.ts b/src/main.ts index 435346c45..037c1270f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,10 +1,9 @@ import * as Interfaces from './interfaces' +import {OCLIF_MARKER_OWNER, Performance} from './performance' import {URL, fileURLToPath} from 'node:url' import {format, inspect} from 'node:util' import {getHelpFlagAdditions, loadHelpClass, normalizeArgv} from './help' - import {Config} from './config' -import {Performance} from './performance' import {stdout} from './cli-ux/stream' const debug = require('debug')('oclif:main') @@ -33,9 +32,9 @@ export const versionAddition = (argv: string[], config?: Interfaces.Config): boo } export async function run(argv?: string[], options?: Interfaces.LoadOptions): Promise { - const marker = Performance.mark('main.run') + const marker = Performance.mark(OCLIF_MARKER_OWNER, 'main.run') - const initMarker = Performance.mark('main.run#init') + const initMarker = Performance.mark(OCLIF_MARKER_OWNER, 'main.run#init') const collectPerf = async () => { marker?.stop() diff --git a/src/performance.ts b/src/performance.ts index 0792dd84d..52baca076 100644 --- a/src/performance.ts +++ b/src/performance.ts @@ -12,17 +12,21 @@ type PerfResult = { } type PerfHighlights = { - configLoadTime: number - runTime: number - initTime: number - commandLoadTime: number - commandRunTime: number - pluginLoadTimes: Record - corePluginsLoadTime: number - userPluginsLoadTime: number - linkedPluginsLoadTime: number - hookRunTimes: Record> + 'oclif.configLoadMs': number; + 'oclif.runMs': number; + 'oclif.initMs': number; + 'oclif.commandLoadMs': number; + 'oclif.initHookMs': number; + 'oclif.prerunHookMs': number; + 'oclif.postrunHookMs': number; + 'oclif.commandRunMs': number; + 'oclif.corePluginsLoadMs': number; + 'oclif.userPluginsLoadMs': number; + 'oclif.linkedPluginsLoadMs': number; + pluginLoadTimes: Record; + hookRunTimes: Record>; } +export const OCLIF_MARKER_OWNER = '@oclif/core' class Marker { public module: string @@ -33,10 +37,7 @@ class Marker { private startMarker: string private stopMarker: string - constructor( - public name: string, - public details: Details = {}, - ) { + constructor(public owner:string, public name: string, public details: Details = {}) { this.startMarker = `${this.name}-start` this.stopMarker = `${this.name}-stop` const [caller, scope] = name.split('#') @@ -63,29 +64,30 @@ class Marker { } export class Performance { - private static markers: Record = {} - private static _results: PerfResult[] = [] - private static _highlights: PerfHighlights + /* Key: marker.name */ + private static markers = new Map() + /* Key: marker.owner */ + private static _results = new Map() + private static _oclifPerf: PerfHighlights public static get enabled(): boolean { return settings.performanceEnabled ?? false } - public static get results(): PerfResult[] { - if (!Performance.enabled) return [] - if (Performance._results.length > 0) return Performance._results - - throw new Error('Perf results not available. Did you forget to call await Performance.collect()?') + /** returns a map of owner, PerfResult[]. Excludes oclif PerfResult, which you can get from oclifPerf */ + public static get results(): Map { + if (!Performance.enabled) return new Map() + return new Map([...Performance._results.entries()].filter(([owner]) => owner !== OCLIF_MARKER_OWNER)) } - public static getResult(name: string): PerfResult | undefined { - return Performance.results.find((r) => r.name === name) + public static getResult(owner: string, name: string): PerfResult | undefined { + return Performance._results.get(owner)?.find(r => r.name === name) } - public static get highlights(): PerfHighlights { - if (!Performance.enabled) return {} as PerfHighlights + public static get oclifPerf(): PerfHighlights | Record { + if (!Performance.enabled) return {} - if (Performance._highlights) return Performance._highlights + if (Performance._oclifPerf) return Performance._oclifPerf throw new Error('Perf results not available. Did you forget to call await Performance.collect()?') } @@ -93,15 +95,17 @@ export class Performance { /** * Add a new performance marker * + * @param owner An npm package like `@oclif/core` or `@salesforce/source-tracking` * @param name Name of the marker. Use `module.method#scope` format * @param details Arbitrary details to attach to the marker * @returns Marker instance */ - public static mark(name: string, details: Details = {}): Marker | undefined { + public static mark(owner:string, name: string, details: Details = {}): Marker | undefined { if (!Performance.enabled) return - const marker = new Marker(name, details) - Performance.markers[marker.name] = marker + const marker = new Marker(owner, name, details) + Performance.markers.set(marker.name, marker) + return marker } @@ -113,9 +117,9 @@ export class Performance { public static async collect(): Promise { if (!Performance.enabled) return - if (Performance._results.length > 0) return + if (Performance._results.size > 0) return - const markers = Object.values(Performance.markers) + const markers = [...Performance.markers.values()] if (markers.length === 0) return for (const marker of markers.filter((m) => !m.stopped)) { @@ -125,72 +129,69 @@ export class Performance { return new Promise((resolve) => { const perfObserver = new PerformanceObserver((items) => { for (const entry of items.getEntries()) { - if (Performance.markers[entry.name]) { - const marker = Performance.markers[entry.name] - Performance._results.push({ + const marker = Performance.markers.get(entry.name) + if (marker) { + const result = { name: entry.name, module: marker.module, method: marker.method, scope: marker.scope, duration: entry.duration, details: marker.details, - }) + } + + const existing = Performance._results.get(marker.owner) ?? [] + Performance._results.set(marker.owner, [...existing, result]) } } - const command = Performance.results.find((r) => r.name.startsWith('config.runCommand')) - const commandLoadTime = command - ? Performance.getResult(`plugin.findCommand#${command.details.plugin}.${command.details.command}`) - ?.duration ?? 0 - : 0 - - const pluginLoadTimes = Object.fromEntries( - Performance.results - .filter(({name}) => name.startsWith('plugin.load#')) - .sort((a, b) => b.duration - a.duration) - .map(({scope, duration, details}) => [scope, {duration, details}]), - ) - - const hookRunTimes = Performance.results - .filter(({name}) => name.startsWith('config.runHook#')) - .reduce( - (acc, perfResult) => { - const event = perfResult.details.event as string - if (event) { - if (!acc[event]) acc[event] = {} - acc[event][perfResult.scope!] = perfResult.duration - } else { - const event = perfResult.scope! - if (!acc[event]) acc[event] = {} - acc[event].total = perfResult.duration - } + const oclifResults = Performance._results.get(OCLIF_MARKER_OWNER) ?? [] + const command = oclifResults.find(r => r.name.startsWith('config.runCommand')) + const commandLoadTime = command ? Performance.getResult(OCLIF_MARKER_OWNER, `plugin.findCommand#${command.details.plugin}.${command.details.command}`)?.duration ?? 0 : 0 + + const pluginLoadTimes = Object.fromEntries(oclifResults + .filter(({name}) => name.startsWith('plugin.load#')) + .sort((a, b) => b.duration - a.duration) + .map(({scope, duration, details}) => [scope, {duration, details}])) + + const hookRunTimes = oclifResults + .filter(({name}) => name.startsWith('config.runHook#')) + .reduce((acc, perfResult) => { + const event = perfResult.details.event as string + if (event) { + if (!acc[event]) acc[event] = {} + acc[event][perfResult.scope!] = perfResult.duration + } else { + const event = perfResult.scope! + if (!acc[event]) acc[event] = {} + acc[event].total = perfResult.duration + } return acc }, {} as Record>, ) - const pluginLoadTimeByType = Object.fromEntries( - Performance.results - .filter(({name}) => name.startsWith('config.loadPlugins#')) - .sort((a, b) => b.duration - a.duration) - .map(({scope, duration}) => [scope, duration]), - ) - - const commandRunTime = - Performance.results.find(({name}) => name.startsWith('config.runCommand#'))?.duration ?? 0 - - Performance._highlights = { - configLoadTime: Performance.getResult('config.load')?.duration ?? 0, - runTime: Performance.getResult('main.run')?.duration ?? 0, - initTime: Performance.getResult('main.run#init')?.duration ?? 0, - commandRunTime, - commandLoadTime, + const pluginLoadTimeByType = Object.fromEntries(oclifResults + .filter(({name}) => name.startsWith('config.loadPlugins#')) + .sort((a, b) => b.duration - a.duration) + .map(({scope, duration}) => [scope, duration])) + + Performance._oclifPerf = { + 'oclif.configLoadMs': Performance.getResult(OCLIF_MARKER_OWNER, 'config.load')?.duration ?? 0, + 'oclif.runMs': Performance.getResult(OCLIF_MARKER_OWNER, 'main.run')?.duration ?? 0, + 'oclif.initMs': Performance.getResult(OCLIF_MARKER_OWNER, 'main.run#init')?.duration ?? 0, + 'oclif.commandRunMs': oclifResults.find(({name}) => name.startsWith('config.runCommand#'))?.duration ?? 0, + 'oclif.commandLoadMs': commandLoadTime, + 'oclif.corePluginsLoadMs': pluginLoadTimeByType.core ?? 0, + 'oclif.userPluginsLoadMs': pluginLoadTimeByType.user ?? 0, + 'oclif.linkedPluginsLoadMs': pluginLoadTimeByType.link ?? 0, + + 'oclif.postrunHookMs': hookRunTimes.postrun?.total ?? 0, + 'oclif.prerunHookMs': hookRunTimes.prerun?.total ?? 0, + 'oclif.initHookMs': hookRunTimes.init?.total ?? 0, pluginLoadTimes, hookRunTimes, - corePluginsLoadTime: pluginLoadTimeByType.core ?? 0, - userPluginsLoadTime: pluginLoadTimeByType.user ?? 0, - linkedPluginsLoadTime: pluginLoadTimeByType.link ?? 0, } resolve() @@ -216,33 +217,46 @@ export class Performance { public static debug(): void { if (!Performance.enabled) return - const debug = require('debug')('perf') - debug('Total Time: %sms', Performance.highlights.runTime.toFixed(4)) - debug('Init Time: %sms', Performance.highlights.initTime.toFixed(4)) - debug('Config Load Time: %sms', Performance.highlights.configLoadTime.toFixed(4)) - debug(' • Plugins Load Time: %sms', Performance.getResult('config.loadAllPlugins')?.duration.toFixed(4) ?? 0) - debug(' • Commands Load Time: %sms', Performance.getResult('config.loadAllCommands')?.duration.toFixed(4) ?? 0) - debug('Core Plugin Load Time: %sms', Performance.highlights.corePluginsLoadTime.toFixed(4)) - debug('User Plugin Load Time: %sms', Performance.highlights.userPluginsLoadTime.toFixed(4)) - debug('Linked Plugin Load Time: %sms', Performance.highlights.linkedPluginsLoadTime.toFixed(4)) - debug('Plugin Load Times:') - for (const [plugin, result] of Object.entries(Performance.highlights.pluginLoadTimes)) { + const oclifDebug = require('debug')('oclif-perf') + oclifDebug('Total Time: %sms', Performance.oclifPerf['oclif.runMs'].toFixed(4)) + oclifDebug('Init Time: %sms', Performance.oclifPerf['oclif.initMs'].toFixed(4)) + oclifDebug('Config Load Time: %sms', Performance.oclifPerf['oclif.configLoadMs'].toFixed(4)) + oclifDebug(' • Plugins Load Time: %sms', Performance.getResult(OCLIF_MARKER_OWNER, 'config.loadAllPlugins')?.duration.toFixed(4) ?? 0) + oclifDebug(' • Commands Load Time: %sms', Performance.getResult(OCLIF_MARKER_OWNER, 'config.loadAllCommands')?.duration.toFixed(4) ?? 0) + oclifDebug('Core Plugin Load Time: %sms', Performance.oclifPerf['oclif.corePluginsLoadMs'].toFixed(4)) + oclifDebug('User Plugin Load Time: %sms', Performance.oclifPerf['oclif.userPluginsLoadMs'].toFixed(4)) + oclifDebug('Linked Plugin Load Time: %sms', Performance.oclifPerf['oclif.linkedPluginsLoadMs'].toFixed(4)) + oclifDebug('Plugin Load Times:') + for (const [plugin, result] of Object.entries(Performance.oclifPerf.pluginLoadTimes)) { if (result.details.hasManifest) { - debug(` ${plugin}: ${result.duration.toFixed(4)}ms`) + oclifDebug(` ${plugin}: ${result.duration.toFixed(4)}ms`) } else { - debug(` ${plugin}: ${result.duration.toFixed(4)}ms (no manifest!)`) + oclifDebug(` ${plugin}: ${result.duration.toFixed(4)}ms (no manifest!)`) } } - debug('Hook Run Times:') - for (const [event, runTimes] of Object.entries(Performance.highlights.hookRunTimes)) { - debug(` ${event}:`) + oclifDebug('Hook Run Times:') + for (const [event, runTimes] of Object.entries(Performance.oclifPerf.hookRunTimes)) { + oclifDebug(` ${event}:`) for (const [plugin, duration] of Object.entries(runTimes)) { - debug(` ${plugin}: ${duration.toFixed(4)}ms`) + oclifDebug(` ${plugin}: ${duration.toFixed(4)}ms`) } } - debug('Command Load Time: %sms', Performance.highlights.commandLoadTime.toFixed(4)) - debug('Command Run Time: %sms', Performance.highlights.commandRunTime.toFixed(4)) + oclifDebug('Command Load Time: %sms', Performance.oclifPerf['oclif.commandLoadMs'].toFixed(4)) + oclifDebug('Command Run Time: %sms', Performance.oclifPerf['oclif.commandRunMs'].toFixed(4)) + + const nonCoreDebug = require('debug')('non-oclif-perf') + + const nonCorePerf = Performance.results + if (nonCorePerf.size > 0) { + nonCoreDebug('Non-Core Performance Measurements:') + for (const [owner, results] of nonCorePerf) { + nonCoreDebug(` ${owner}:`) + for (const result of results) { + nonCoreDebug(` ${result.name}: ${result.duration.toFixed(4)}ms`) + } + } + } } } diff --git a/yarn.lock b/yarn.lock index 5f778d4ee..116f2dc54 100644 --- a/yarn.lock +++ b/yarn.lock @@ -423,10 +423,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.49.0": - version "8.49.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.49.0.tgz#86f79756004a97fa4df866835093f1df3d03c333" - integrity sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w== +"@eslint/js@8.50.0": + version "8.50.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.50.0.tgz#9e93b850f0f3fa35f5fa59adfd03adae8488e484" + integrity sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ== "@humanwhocodes/config-array@^0.11.11": version "0.11.11" @@ -2898,15 +2898,15 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^8.49.0: - version "8.49.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.49.0.tgz#09d80a89bdb4edee2efcf6964623af1054bf6d42" - integrity sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ== +eslint@^8.50.0: + version "8.50.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.50.0.tgz#2ae6015fee0240fcd3f83e1e25df0287f487d6b2" + integrity sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.49.0" + "@eslint/js" "8.50.0" "@humanwhocodes/config-array" "^0.11.11" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8"