From f65af564be0bdd2a7a178b610da40e24612d5b37 Mon Sep 17 00:00:00 2001 From: kirillgroshkov Date: Wed, 17 Apr 2024 13:06:49 +0200 Subject: [PATCH] feat: TransformMapOptions.onDone which allows to "export" the stats after the pipeline is done --- src/stream/progressLogger.ts | 8 + .../transform/transformLogProgress.test.ts | 18 +- src/stream/transform/transformMap.test.ts | 69 ++++++- src/stream/transform/transformMap.ts | 53 ++++++ src/stream/transform/transformMapSync.test.ts | 42 ++++- src/stream/transform/transformMapSync.ts | 44 ++++- yarn.lock | 178 +++++++++--------- 7 files changed, 308 insertions(+), 104 deletions(-) diff --git a/src/stream/progressLogger.ts b/src/stream/progressLogger.ts index 3ff9350..57add8b 100644 --- a/src/stream/progressLogger.ts +++ b/src/stream/progressLogger.ts @@ -101,6 +101,12 @@ export interface ProgressLoggerCfg { */ extra?: (chunk: T | undefined, index: number) => AnyObject + /** + * Hook that is called when the last item is passed through. + * Passes the final stats as `ProgressLogItem`. + */ + onProgressDone?: (stats: ProgressLogItem) => any + /** * If specified - will multiply the counter by this number. * Useful e.g when using `transformChunk({ chunkSize: 500 })`, so @@ -298,6 +304,8 @@ export class ProgressLogger implements Disposable { batchedProgress, )} rows with total RPS of ${yellow(rpsTotal)}`, ) + + this.cfg.onProgressDone?.(o) } } } diff --git a/src/stream/transform/transformLogProgress.test.ts b/src/stream/transform/transformLogProgress.test.ts index ce63584..56f3ea1 100644 --- a/src/stream/transform/transformLogProgress.test.ts +++ b/src/stream/transform/transformLogProgress.test.ts @@ -1,6 +1,12 @@ import { Readable } from 'node:stream' import { pDelay } from '@naturalcycles/js-lib' -import { _pipeline, progressReadableMapper, readableFrom, writableVoid } from '../..' +import { + _pipeline, + ProgressLogItem, + progressReadableMapper, + readableFrom, + writableVoid, +} from '../..' import { transformLogProgress } from './transformLogProgress' // todo: AsyncIterable2 (or Iterable2.mapAsync) should be implemented in js-lib @@ -19,6 +25,7 @@ test('transformLogProgress', async () => { // const readable = readableFromArray(_range(0, 11), i => pDelay(10, i)) // const readable = Readable.from(AsyncSequence.create(1, i => (i === 10 ? END : pDelay(10, i + 1)))) const readable = Readable.from(rangeItAsync(1, 11, 10)) + let stats: ProgressLogItem await _pipeline([ readable, @@ -36,10 +43,19 @@ test('transformLogProgress', async () => { aaa: index, } }, + onProgressDone: s => (stats = s), }), // transformLogProgress({logProgressInterval: 10}), writableVoid(), ]) + + expect(stats!).toEqual({ + progress_final: 10, + peakRSS: expect.any(Number), + rps10: expect.any(Number), + rpsTotal: expect.any(Number), + rss: expect.any(Number), + }) }) test('progressReadableMapper', async () => { diff --git a/src/stream/transform/transformMap.test.ts b/src/stream/transform/transformMap.test.ts index 059eb04..058921a 100644 --- a/src/stream/transform/transformMap.test.ts +++ b/src/stream/transform/transformMap.test.ts @@ -1,6 +1,12 @@ import { Readable } from 'node:stream' import { AsyncMapper, ErrorMode, _range, pExpectedError, _stringify } from '@naturalcycles/js-lib' -import { readableFromArray, _pipeline, _pipelineToArray, transformMap } from '../../index' +import { + readableFromArray, + _pipeline, + _pipelineToArray, + transformMap, + TransformMapStats, +} from '../../index' interface Item { id: string @@ -37,10 +43,15 @@ test('transformMap with mapping', async () => { }) test('transformMap emit array as multiple items', async () => { + let stats: TransformMapStats const data = _range(1, 4) const data2 = await _pipelineToArray([ readableFromArray(data), - transformMap(n => [n * 2, n * 2 + 1], { flattenArrayOutput: true }), + transformMap(n => [n * 2, n * 2 + 1], { + flattenArrayOutput: true, + // async is to test that it's awaited + onDone: async s => (stats = s), + }), ]) const expected: number[] = [] @@ -51,6 +62,16 @@ test('transformMap emit array as multiple items', async () => { // console.log(data2) expect(data2).toEqual(expected) + + expect(stats!).toMatchInlineSnapshot(` +{ + "collectedErrors": [], + "countErrors": 0, + "countIn": 3, + "countOut": 6, + "ok": true, +} +`) }) // non-object mode is not supported anymore @@ -69,6 +90,7 @@ test('transformMap emit array as multiple items', async () => { // }) test('transformMap errorMode=THROW_IMMEDIATELY', async () => { + let stats: TransformMapStats const data: Item[] = _range(1, 5).map(n => ({ id: String(n) })) const readable = readableFromArray(data) const data2: Item[] = [] @@ -76,7 +98,7 @@ test('transformMap errorMode=THROW_IMMEDIATELY', async () => { await expect( _pipeline([ readable, - transformMap(mapperError3, { concurrency: 1 }), + transformMap(mapperError3, { concurrency: 1, onDone: s => (stats = s) }), transformMap(r => void data2.push(r)), ]), ).rejects.toThrow('my error') @@ -84,9 +106,20 @@ test('transformMap errorMode=THROW_IMMEDIATELY', async () => { expect(data2).toEqual(data.filter(r => Number(r.id) < 3)) // expect(readable.destroyed).toBe(true) + + expect(stats!).toMatchInlineSnapshot(` +{ + "collectedErrors": [], + "countErrors": 1, + "countIn": 3, + "countOut": 2, + "ok": false, +} +`) }) test('transformMap errorMode=THROW_AGGREGATED', async () => { + let stats: TransformMapStats const data: Item[] = _range(1, 5).map(n => ({ id: String(n) })) const readable = readableFromArray(data) const data2: Item[] = [] @@ -94,7 +127,10 @@ test('transformMap errorMode=THROW_AGGREGATED', async () => { const err = await pExpectedError( _pipeline([ readable, - transformMap(mapperError3, { errorMode: ErrorMode.THROW_AGGREGATED }), + transformMap(mapperError3, { + errorMode: ErrorMode.THROW_AGGREGATED, + onDone: s => (stats = s), + }), transformMap(r => void data2.push(r)), ]), AggregateError, @@ -108,20 +144,43 @@ test('transformMap errorMode=THROW_AGGREGATED', async () => { expect(data2).toEqual(data.filter(r => r.id !== '3')) // expect(readable.destroyed).toBe(true) + + expect(stats!).toMatchInlineSnapshot(` +{ + "collectedErrors": [ + [Error: my error], + ], + "countErrors": 1, + "countIn": 4, + "countOut": 3, + "ok": false, +} +`) }) test('transformMap errorMode=SUPPRESS', async () => { + let stats: TransformMapStats const data: Item[] = _range(1, 5).map(n => ({ id: String(n) })) const readable = readableFromArray(data) const data2: Item[] = [] await _pipeline([ readable, - transformMap(mapperError3, { errorMode: ErrorMode.SUPPRESS }), + transformMap(mapperError3, { errorMode: ErrorMode.SUPPRESS, onDone: s => (stats = s) }), transformMap(r => void data2.push(r)), ]) expect(data2).toEqual(data.filter(r => r.id !== '3')) // expect(readable.destroyed).toBe(true) + + expect(stats!).toMatchInlineSnapshot(` +{ + "collectedErrors": [], + "countErrors": 1, + "countIn": 4, + "countOut": 3, + "ok": true, +} +`) }) diff --git a/src/stream/transform/transformMap.ts b/src/stream/transform/transformMap.ts index 8883914..330f33d 100644 --- a/src/stream/transform/transformMap.ts +++ b/src/stream/transform/transformMap.ts @@ -49,6 +49,18 @@ export interface TransformMapOptions { */ onError?: (err: Error, input: IN) => any + /** + * A hook that is called when the last item is finished processing. + * stats object is passed, containing countIn and countOut - + * number of items that entered the transform and number of items that left it. + * + * Callback is called **before** [possible] Aggregated error is thrown, + * and before [possible] THROW_IMMEDIATELY error. + * + * onDone callback will be called before Error is thrown. + */ + onDone?: (stats: TransformMapStats) => any + /** * Progress metric * @@ -59,6 +71,20 @@ export interface TransformMapOptions { logger?: CommonLogger } +export interface TransformMapStats { + /** + * True if transform was successful (didn't throw Immediate or Aggregated error). + */ + ok: boolean + /** + * Only used (and returned) for ErrorMode.Aggregated + */ + collectedErrors: Error[] + countErrors: number + countIn: number + countOut: number +} + // doesn't work, cause here we don't construct our Transform instance ourselves // export class TransformMap extends AbortableTransform {} @@ -84,11 +110,13 @@ export function transformMap( errorMode = ErrorMode.THROW_IMMEDIATELY, flattenArrayOutput, onError, + onDone, metric = 'stream', logger = console, } = opt let index = -1 + let countOut = 0 let isSettled = false let errors = 0 const collectedErrors: Error[] = [] // only used if errorMode == THROW_AGGREGATED @@ -102,6 +130,14 @@ export function transformMap( logErrorStats(true) if (collectedErrors.length) { + onDone?.({ + ok: false, + collectedErrors, + countErrors: errors, + countIn: index + 1, + countOut, + }) + // emit Aggregated error cb( new AggregateError( @@ -111,6 +147,15 @@ export function transformMap( ) } else { // emit no error + + onDone?.({ + ok: true, + collectedErrors, + countErrors: errors, + countIn: index + 1, + countOut, + }) + cb() } }, @@ -134,6 +179,7 @@ export function transformMap( }, ) + countOut += passedResults.length passedResults.forEach(r => this.push(r)) if (isSettled) { @@ -155,6 +201,13 @@ export function transformMap( if (errorMode === ErrorMode.THROW_IMMEDIATELY) { isSettled = true + onDone?.({ + ok: false, + collectedErrors, + countErrors: errors, + countIn: index + 1, + countOut, + }) return cb(err) // Emit error immediately } diff --git a/src/stream/transform/transformMapSync.test.ts b/src/stream/transform/transformMapSync.test.ts index 71ee2da..ab22330 100644 --- a/src/stream/transform/transformMapSync.test.ts +++ b/src/stream/transform/transformMapSync.test.ts @@ -1,6 +1,6 @@ import { Readable } from 'node:stream' import { AppError, ErrorMode, _range, pTry } from '@naturalcycles/js-lib' -import { writableVoid, _pipeline } from '../..' +import { writableVoid, _pipeline, TransformMapStats } from '../..' import { transformMapSync } from './transformMapSync' interface Item { @@ -20,19 +20,25 @@ test('transformMapSync simple', async () => { }) test('transformMapSync error', async () => { + let stats: TransformMapStats const data = _range(100).map(String) const data2: string[] = [] const [err] = await pTry( _pipeline([ Readable.from(data), - transformMapSync((r, i) => { - if (i === 50) { - throw new AppError('error on 50th') - } + transformMapSync( + (r, i) => { + if (i === 50) { + throw new AppError('error on 50th') + } - data2.push(r) - }), + data2.push(r) + }, + { + onDone: s => (stats = s), + }, + ), writableVoid(), ]), ) @@ -41,9 +47,20 @@ test('transformMapSync error', async () => { expect(err).toMatchInlineSnapshot(`[AppError: error on 50th]`) expect(data2).toEqual(data.slice(0, 50)) + + expect(stats!).toMatchInlineSnapshot(` +{ + "collectedErrors": [], + "countErrors": 1, + "countIn": 51, + "countOut": 50, + "ok": false, +} +`) }) test('transformMapSync suppressed error', async () => { + let stats: TransformMapStats const data = _range(100).map(String) const data2: string[] = [] @@ -59,10 +76,21 @@ test('transformMapSync suppressed error', async () => { }, { errorMode: ErrorMode.SUPPRESS, + onDone: s => (stats = s), }, ), writableVoid(), ]) expect(data2).toEqual(data.filter(r => r !== '50')) + + expect(stats!).toMatchInlineSnapshot(` +{ + "collectedErrors": [], + "countErrors": 1, + "countIn": 100, + "countOut": 99, + "ok": true, +} +`) }) diff --git a/src/stream/transform/transformMapSync.ts b/src/stream/transform/transformMapSync.ts index 280f662..bdeedb7 100644 --- a/src/stream/transform/transformMapSync.ts +++ b/src/stream/transform/transformMapSync.ts @@ -11,6 +11,7 @@ import { yellow } from '../../colors/colors' import { AbortableTransform } from '../pipeline/pipeline' import { TransformTyped } from '../stream.model' import { pipelineClose } from '../stream.util' +import { TransformMapStats } from './transformMap' export interface TransformMapSyncOptions { /** @@ -44,6 +45,18 @@ export interface TransformMapSyncOptions { */ onError?: (err: Error, input: IN) => any + /** + * A hook that is called when the last item is finished processing. + * stats object is passed, containing countIn and countOut - + * number of items that entered the transform and number of items that left it. + * + * Callback is called **before** [possible] Aggregated error is thrown, + * and before [possible] THROW_IMMEDIATELY error. + * + * onDone callback will be called before Error is thrown. + */ + onDone?: (stats: TransformMapStats) => any + /** * Progress metric * @@ -64,17 +77,19 @@ export function transformMapSync( mapper: Mapper, opt: TransformMapSyncOptions = {}, ): TransformTyped { - let index = -1 - const { predicate, // defaults to "no predicate" (pass everything) errorMode = ErrorMode.THROW_IMMEDIATELY, flattenArrayOutput = false, onError, + onDone, metric = 'stream', objectMode = true, logger = console, } = opt + + let index = -1 + let countOut = 0 let isSettled = false let errors = 0 const collectedErrors: Error[] = [] // only used if errorMode == THROW_AGGREGATED @@ -100,6 +115,7 @@ export function transformMapSync( return r !== SKIP && (!predicate || predicate(r, currentIndex)) }) + countOut += passedResults.length passedResults.forEach(r => this.push(r)) if (isSettled) { @@ -122,6 +138,13 @@ export function transformMapSync( if (errorMode === ErrorMode.THROW_IMMEDIATELY) { isSettled = true + onDone?.({ + ok: false, + collectedErrors, + countErrors: errors, + countIn: index + 1, + countOut, + }) // Emit error immediately return cb(err as Error) } @@ -139,6 +162,14 @@ export function transformMapSync( logErrorStats(true) if (collectedErrors.length) { + onDone?.({ + ok: false, + collectedErrors, + countErrors: errors, + countIn: index + 1, + countOut, + }) + // emit Aggregated error cb( new AggregateError( @@ -148,6 +179,15 @@ export function transformMapSync( ) } else { // emit no error + + onDone?.({ + ok: true, + collectedErrors, + countErrors: errors, + countIn: index + 1, + countOut, + }) + cb() } }, diff --git a/yarn.lock b/yarn.lock index 3981d5b..d738c27 100644 --- a/yarn.lock +++ b/yarn.lock @@ -314,12 +314,12 @@ integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== "@commitlint/cli@^19.0.0": - version "19.2.1" - resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-19.2.1.tgz#8f00d27a8b7c7780e75b06fd4658fdc1e9209f1b" - integrity sha512-cbkYUJsLqRomccNxvoJTyv5yn0bSy05BBizVyIcLACkRbVUqYorC351Diw/XFSWC/GtpwiwT2eOvQgFZa374bg== + version "19.2.2" + resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-19.2.2.tgz#7b6d78596dcf6d716942b147aa07c04c4ee126df" + integrity sha512-P8cbOHfg2PQRzfICLSrzUVOCVMqjEZ8Hlth6mtJ4yOEjT47Q5PbIGymgX3rLVylNw+3IAT2Djn9IJ2wHbXFzBg== dependencies: "@commitlint/format" "^19.0.3" - "@commitlint/lint" "^19.1.0" + "@commitlint/lint" "^19.2.2" "@commitlint/load" "^19.2.0" "@commitlint/read" "^19.2.1" "@commitlint/types" "^19.0.3" @@ -327,9 +327,9 @@ yargs "^17.0.0" "@commitlint/config-conventional@^19.0.0": - version "19.1.0" - resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-19.1.0.tgz#6b4b7938aa3bc308214a683247520f602e55961e" - integrity sha512-KIKD2xrp6Uuk+dcZVj3++MlzIr/Su6zLE8crEDQCZNvWHNQSeeGbzOlNtsR32TUy6H3JbP7nWgduAHCaiGQ6EA== + version "19.2.2" + resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-19.2.2.tgz#1f4e6975d428985deacf2b3ff6547e02c9302054" + integrity sha512-mLXjsxUVLYEGgzbxbxicGPggDuyWNkf25Ht23owXIH+zV2pv1eJuzLK3t1gDY5Gp6pxdE60jZnWUY5cvgL3ufw== dependencies: "@commitlint/types" "^19.0.3" conventional-changelog-conventionalcommits "^7.0.2" @@ -367,20 +367,20 @@ "@commitlint/types" "^19.0.3" chalk "^5.3.0" -"@commitlint/is-ignored@^19.0.3": - version "19.0.3" - resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-19.0.3.tgz#a64e0e217044f2d916127369d21ea12324a834fe" - integrity sha512-MqDrxJaRSVSzCbPsV6iOKG/Lt52Y+PVwFVexqImmYYFhe51iVJjK2hRhOG2jUAGiUHk4jpdFr0cZPzcBkSzXDQ== +"@commitlint/is-ignored@^19.2.2": + version "19.2.2" + resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-19.2.2.tgz#503ddcf908ac6b2bc4586a49cb53893a1856f5b2" + integrity sha512-eNX54oXMVxncORywF4ZPFtJoBm3Tvp111tg1xf4zWXGfhBPKpfKG6R+G3G4v5CPlRROXpAOpQ3HMhA9n1Tck1g== dependencies: "@commitlint/types" "^19.0.3" semver "^7.6.0" -"@commitlint/lint@^19.1.0": - version "19.1.0" - resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-19.1.0.tgz#0f4b26b1452d59a92a28b5fa6de9bdbee18399a1" - integrity sha512-ESjaBmL/9cxm+eePyEr6SFlBUIYlYpI80n+Ltm7IA3MAcrmiP05UMhJdAD66sO8jvo8O4xdGn/1Mt2G5VzfZKw== +"@commitlint/lint@^19.2.2": + version "19.2.2" + resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-19.2.2.tgz#57f69e24bd832a7dcce8ebf82d11e3bf03ccc2a9" + integrity sha512-xrzMmz4JqwGyKQKTpFzlN0dx0TAiT7Ran1fqEBgEmEj+PU98crOFtysJgY+QdeSagx6EDRigQIXJVnfrI0ratA== dependencies: - "@commitlint/is-ignored" "^19.0.3" + "@commitlint/is-ignored" "^19.2.2" "@commitlint/parse" "^19.0.3" "@commitlint/rules" "^19.0.3" "@commitlint/types" "^19.0.3" @@ -871,17 +871,17 @@ yargs "^17.0.0" "@naturalcycles/js-lib@^14.0.0": - version "14.225.0" - resolved "https://registry.yarnpkg.com/@naturalcycles/js-lib/-/js-lib-14.225.0.tgz#d7e8166e05ee6f430aac2c3477c105d2a63f5a56" - integrity sha512-REBbdFMUFNt5PaAtgUL0lp7tO81s/rQ/KJ7FbJj6Avhr2RzPByStBXbonbqjA4if8UjlVhU0c8+0vtM/gwJZNA== + version "14.226.0" + resolved "https://registry.yarnpkg.com/@naturalcycles/js-lib/-/js-lib-14.226.0.tgz#aef25b310e69e92772e39d02c72db7632d0446a4" + integrity sha512-xdq003OXR6l8oRJMS/Ltm5zcttiOlS13cs/4VElcCVK3i7D65UH38QTO5PuPP2MdETzC5lGUmcRWffYMB2lLYw== dependencies: tslib "^2.0.0" zod "^3.20.2" "@naturalcycles/nodejs-lib@^13.0.1", "@naturalcycles/nodejs-lib@^13.0.2": - version "13.12.0" - resolved "https://registry.yarnpkg.com/@naturalcycles/nodejs-lib/-/nodejs-lib-13.12.0.tgz#cbf7e17642ad4d80710b201456e6c239f426532d" - integrity sha512-9PhjT38smpBpP5xgTnIU57iPriLnFqC6G035LoXUgH/TBHJRZF360SA1hi/ERS8S/6sGPDxIyiAjpJNEWvTqxg== + version "13.15.0" + resolved "https://registry.yarnpkg.com/@naturalcycles/nodejs-lib/-/nodejs-lib-13.15.0.tgz#47160aaaa36ae14df7b1d9aa9c4f96d404fdb35b" + integrity sha512-5hEx0fTYAH2pccG0ZgA4TpWp0Ptxbd22qmp4Mw7/cYYjFm3mrZPSuef6Uz3AJp6q4UM7F0jkly2m2guZKv/MtQ== dependencies: "@naturalcycles/js-lib" "^14.0.0" "@types/js-yaml" "^4.0.9" @@ -1133,15 +1133,15 @@ "@types/yargs-parser" "*" "@typescript-eslint/eslint-plugin@^7.0.1": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.6.0.tgz#1f5df5cda490a0bcb6fbdd3382e19f1241024242" - integrity sha512-gKmTNwZnblUdnTIJu3e9kmeRRzV2j1a/LUO27KNNAnIC5zjy1aSvXSRp4rVNlmAoHlQ7HzX42NbKpcSr4jF80A== + version "7.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz#bf34a02f221811505b8bf2f31060c8560c1bb0a3" + integrity sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ== dependencies: "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "7.6.0" - "@typescript-eslint/type-utils" "7.6.0" - "@typescript-eslint/utils" "7.6.0" - "@typescript-eslint/visitor-keys" "7.6.0" + "@typescript-eslint/scope-manager" "7.7.0" + "@typescript-eslint/type-utils" "7.7.0" + "@typescript-eslint/utils" "7.7.0" + "@typescript-eslint/visitor-keys" "7.7.0" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.3.1" @@ -1150,14 +1150,14 @@ ts-api-utils "^1.3.0" "@typescript-eslint/parser@^7.0.1": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.6.0.tgz#0aca5de3045d68b36e88903d15addaf13d040a95" - integrity sha512-usPMPHcwX3ZoPWnBnhhorc14NJw9J4HpSXQX4urF2TPKG0au0XhJoZyX62fmvdHONUkmyUe74Hzm1//XA+BoYg== - dependencies: - "@typescript-eslint/scope-manager" "7.6.0" - "@typescript-eslint/types" "7.6.0" - "@typescript-eslint/typescript-estree" "7.6.0" - "@typescript-eslint/visitor-keys" "7.6.0" + version "7.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.7.0.tgz#6b1b3ce76c5de002c43af8ae933613b0f2b4bcc6" + integrity sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg== + dependencies: + "@typescript-eslint/scope-manager" "7.7.0" + "@typescript-eslint/types" "7.7.0" + "@typescript-eslint/typescript-estree" "7.7.0" + "@typescript-eslint/visitor-keys" "7.7.0" debug "^4.3.4" "@typescript-eslint/scope-manager@6.21.0": @@ -1168,21 +1168,21 @@ "@typescript-eslint/types" "6.21.0" "@typescript-eslint/visitor-keys" "6.21.0" -"@typescript-eslint/scope-manager@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.6.0.tgz#1e9972f654210bd7500b31feadb61a233f5b5e9d" - integrity sha512-ngttyfExA5PsHSx0rdFgnADMYQi+Zkeiv4/ZxGYUWd0nLs63Ha0ksmp8VMxAIC0wtCFxMos7Lt3PszJssG/E6w== +"@typescript-eslint/scope-manager@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz#3f0db079b275bb8b0cb5be7613fb3130cfb5de77" + integrity sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw== dependencies: - "@typescript-eslint/types" "7.6.0" - "@typescript-eslint/visitor-keys" "7.6.0" + "@typescript-eslint/types" "7.7.0" + "@typescript-eslint/visitor-keys" "7.7.0" -"@typescript-eslint/type-utils@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.6.0.tgz#644f75075f379827d25fe0713e252ccd4e4a428c" - integrity sha512-NxAfqAPNLG6LTmy7uZgpK8KcuiS2NZD/HlThPXQRGwz6u7MDBWRVliEEl1Gj6U7++kVJTpehkhZzCJLMK66Scw== +"@typescript-eslint/type-utils@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz#36792ff4209a781b058de61631a48df17bdefbc5" + integrity sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg== dependencies: - "@typescript-eslint/typescript-estree" "7.6.0" - "@typescript-eslint/utils" "7.6.0" + "@typescript-eslint/typescript-estree" "7.7.0" + "@typescript-eslint/utils" "7.7.0" debug "^4.3.4" ts-api-utils "^1.3.0" @@ -1191,10 +1191,10 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== -"@typescript-eslint/types@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.6.0.tgz#53dba7c30c87e5f10a731054266dd905f1fbae38" - integrity sha512-h02rYQn8J+MureCvHVVzhl69/GAfQGPQZmOMjG1KfCl7o3HtMSlPaPUAPu6lLctXI5ySRGIYk94clD/AUMCUgQ== +"@typescript-eslint/types@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.7.0.tgz#23af4d24bf9ce15d8d301236e3e3014143604f27" + integrity sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w== "@typescript-eslint/typescript-estree@6.21.0": version "6.21.0" @@ -1210,13 +1210,13 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/typescript-estree@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.6.0.tgz#112a3775563799fd3f011890ac8322f80830ac17" - integrity sha512-+7Y/GP9VuYibecrCQWSKgl3GvUM5cILRttpWtnAu8GNL9j11e4tbuGZmZjJ8ejnKYyBRb2ddGQ3rEFCq3QjMJw== +"@typescript-eslint/typescript-estree@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz#b5dd6383b4c6a852d7b256a37af971e8982be97f" + integrity sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ== dependencies: - "@typescript-eslint/types" "7.6.0" - "@typescript-eslint/visitor-keys" "7.6.0" + "@typescript-eslint/types" "7.7.0" + "@typescript-eslint/visitor-keys" "7.7.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -1224,17 +1224,17 @@ semver "^7.6.0" ts-api-utils "^1.3.0" -"@typescript-eslint/utils@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.6.0.tgz#e400d782280b6f724c8a1204269d984c79202282" - integrity sha512-x54gaSsRRI+Nwz59TXpCsr6harB98qjXYzsRxGqvA5Ue3kQH+FxS7FYU81g/omn22ML2pZJkisy6Q+ElK8pBCA== +"@typescript-eslint/utils@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.7.0.tgz#3d2b6606a60ac34f3c625facfb3b3ab7e126f58d" + integrity sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.15" "@types/semver" "^7.5.8" - "@typescript-eslint/scope-manager" "7.6.0" - "@typescript-eslint/types" "7.6.0" - "@typescript-eslint/typescript-estree" "7.6.0" + "@typescript-eslint/scope-manager" "7.7.0" + "@typescript-eslint/types" "7.7.0" + "@typescript-eslint/typescript-estree" "7.7.0" semver "^7.6.0" "@typescript-eslint/utils@^6.0.0": @@ -1258,12 +1258,12 @@ "@typescript-eslint/types" "6.21.0" eslint-visitor-keys "^3.4.1" -"@typescript-eslint/visitor-keys@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.6.0.tgz#d1ce13145844379021e1f9bd102c1d78946f4e76" - integrity sha512-4eLB7t+LlNUmXzfOu1VAIAdkjbu5xNSerURS9X/S5TUKWFRpXRQZbmtPqgKmYx8bj3J0irtQXSiWAOY82v+cgw== +"@typescript-eslint/visitor-keys@7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz#950148cf1ac11562a2d903fdf7acf76714a2dc9e" + integrity sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA== dependencies: - "@typescript-eslint/types" "7.6.0" + "@typescript-eslint/types" "7.7.0" eslint-visitor-keys "^3.4.3" JSONStream@^1.3.5: @@ -1738,9 +1738,9 @@ camelcase@^6.2.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001587: - version "1.0.30001608" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001608.tgz#7ae6e92ffb300e4b4ec2f795e0abab456ec06cc0" - integrity sha512-cjUJTQkk9fQlJR2s4HMuPMvTiRggl0rAVMtthQuyOlDWuqHXqN8azLq+pi8B2TjwKJ32diHjUqRIKeFX4z1FoA== + version "1.0.30001610" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001610.tgz#2f44ed6e21d359e914271ae35b68903632628ccf" + integrity sha512-QFutAY4NgaelojVMjY63o6XlZyORPaLfyMnsl3HgnWdJUcX6K0oaJymHjH8PT5Gk7sTm8rvC/c5COUQKXqmOMA== chalk@5.3.0, chalk@^5.3.0: version "5.3.0" @@ -1955,9 +1955,9 @@ cookie@0.6.0: integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== core-js-compat@^3.34.0: - version "3.36.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.36.1.tgz#1818695d72c99c25d621dca94e6883e190cea3c8" - integrity sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA== + version "3.37.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.37.0.tgz#d9570e544163779bb4dff1031c7972f44918dc73" + integrity sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA== dependencies: browserslist "^4.23.0" @@ -2074,9 +2074,9 @@ debug@^3.2.7: ms "^2.1.1" dedent@^1.0.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" - integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + version "1.5.3" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== deep-is@^0.1.3: version "0.1.4" @@ -2175,9 +2175,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.4.668: - version "1.4.731" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.731.tgz#d3dc19f359045b750a1fb0bc42315a502d950187" - integrity sha512-+TqVfZjpRz2V/5SPpmJxq9qK620SC5SqCnxQIOi7i/U08ZDcTpKbT7Xjj9FU5CbXTMUb4fywbIr8C7cGv4hcjw== + version "1.4.738" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.738.tgz#9a7fca98abaee61e20c9c25013d5ce60bb533436" + integrity sha512-lwKft2CLFztD+vEIpesrOtCrko/TFnEJlHFdRhazU7Y/jx5qc4cqsocfVrBg4So4gGe9lvxnbLIoev47WMpg+A== emittery@^0.13.1: version "0.13.1" @@ -2428,9 +2428,9 @@ eslint-plugin-unused-imports@^3.0.0: eslint-rule-composer "^0.3.0" eslint-plugin-vue@^9.0.0: - version "9.24.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.24.1.tgz#0d90330c939f9dd2f4c759da5a2ad91dc1c8bac4" - integrity sha512-wk3SuwmS1pZdcuJlokGYEi/buDOwD6KltvhIZyOnpJ/378dcQ4zchu9PAMbbLAaydCz1iYc5AozszcOOgZIIOg== + version "9.25.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.25.0.tgz#615cb7bb6d0e2140d21840b9aa51dce69e803e7a" + integrity sha512-tDWlx14bVe6Bs+Nnh3IGrD+hb11kf2nukfm6jLsmJIhmiRQ1SUaksvwY9U5MvPB0pcrg0QK0xapQkfITs3RKOA== dependencies: "@eslint-community/eslint-utils" "^4.4.0" globals "^13.24.0" @@ -5397,9 +5397,9 @@ typed-array-length@^1.0.6: possible-typed-array-names "^1.0.0" typescript@^5.0.2: - version "5.4.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.4.tgz#eb2471e7b0a5f1377523700a21669dce30c2d952" - integrity sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw== + version "5.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" + integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== unbox-primitive@^1.0.2: version "1.0.2"