From ff18fe8f059a925896a1bdc217206a81245573d6 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 22 Jan 2025 14:31:00 -0500 Subject: [PATCH] Renames decorators/function for better clarity - Renames `serialize` decorator to `sequentialize` - Renames `sequentialize` function to `runSequentially` - Adds a new `sequentialize` which returns a new function which waits for previous calls to finish before executing the current --- src/commands/commandBase.ts | 4 ++-- .../integrationAuthentication.ts | 4 ++-- src/system/decorators/serialize.ts | 4 ++-- src/system/function.ts | 22 ++++++++++++++++--- src/views/viewCommands.ts | 4 ++-- src/webviews/webviewController.ts | 4 ++-- 6 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/commands/commandBase.ts b/src/commands/commandBase.ts index a02c8f0e074b5..1cb8e739dae9a 100644 --- a/src/commands/commandBase.ts +++ b/src/commands/commandBase.ts @@ -2,7 +2,7 @@ import type { TextEditor, TextEditorEdit } from 'vscode'; import { commands, Disposable } from 'vscode'; import type { GlCommands } from '../constants.commands'; import { registerCommand } from '../system/-webview/command'; -import { sequentialize } from '../system/function'; +import { runSequentially } from '../system/function'; import type { CommandContext } from './commandContext'; import type { CommandContextParsingOptions } from './commandContext.utils'; import { parseCommandContext } from './commandContext.utils'; @@ -41,7 +41,7 @@ export abstract class GlCommandBase implements Disposable { // If there an array of contexts, then we want to execute the command for each if (Array.isArray(context)) { - return sequentialize( + return runSequentially( this.preExecute, context.map<[CommandContext, ...any[]]>((c: CommandContext) => [c, ...rest]), this, diff --git a/src/plus/integrations/authentication/integrationAuthentication.ts b/src/plus/integrations/authentication/integrationAuthentication.ts index 566572339cc8e..ec7a66efccbf0 100644 --- a/src/plus/integrations/authentication/integrationAuthentication.ts +++ b/src/plus/integrations/authentication/integrationAuthentication.ts @@ -8,7 +8,7 @@ import type { Sources } from '../../../constants.telemetry'; import type { Container } from '../../../container'; import { gate } from '../../../system/decorators/-webview/gate'; import { debug, log } from '../../../system/decorators/log'; -import { serialize } from '../../../system/decorators/serialize'; +import { sequentialize } from '../../../system/decorators/serialize'; import type { DeferredEventExecutor } from '../../../system/event'; import { isCloudSelfHostedIntegrationId, @@ -480,7 +480,7 @@ class BuiltInAuthenticationProvider extends LocalIntegrationAuthenticationProvid } @debug() - @serialize() + @sequentialize() override async getSession( descriptor?: IntegrationAuthenticationSessionDescriptor, options?: { createIfNeeded?: boolean; forceNewSession?: boolean }, diff --git a/src/system/decorators/serialize.ts b/src/system/decorators/serialize.ts index 2ee2695476079..0b35bd3006d90 100644 --- a/src/system/decorators/serialize.ts +++ b/src/system/decorators/serialize.ts @@ -1,4 +1,4 @@ -export function serialize(): (target: any, key: string, descriptor: PropertyDescriptor) => void { +export function sequentialize(): (target: any, key: string, descriptor: PropertyDescriptor) => void { return (_target: any, key: string, descriptor: PropertyDescriptor) => { // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type let fn: Function | undefined; @@ -9,7 +9,7 @@ export function serialize(): (target: any, key: string, descriptor: PropertyDesc } if (fn === undefined) throw new Error('Not supported'); - const serializeKey = `$serialize$${key}`; + const serializeKey = `$sequentialize$${key}`; descriptor.value = function (this: any, ...args: any[]) { if (!Object.prototype.hasOwnProperty.call(this, serializeKey)) { diff --git a/src/system/function.ts b/src/system/function.ts index b18321a67bf6d..408df067b3baf 100644 --- a/src/system/function.ts +++ b/src/system/function.ts @@ -213,18 +213,34 @@ export function disposableInterval(fn: (...args: any[]) => void, ms: number): Di return disposable; } -export async function sequentialize unknown>( +export async function runSequentially unknown>( fn: T, - argArray: Parameters[], + arrayOfArgs: Parameters[], thisArg?: unknown, ): Promise { - for (const args of argArray) { + for (const args of arrayOfArgs) { try { void (await fn.apply(thisArg, args)); } catch {} } } +export function sequentialize Promise>(fn: T): T { + let promise: Promise | undefined; + + return function (...args: any[]): Promise { + // eslint-disable-next-line no-return-await, @typescript-eslint/no-unsafe-return + const run = async () => await fn(...args); + if (promise == null) { + promise = run(); + } else { + promise = promise.then(run, run); + } + + return promise; + } as T; +} + /** * Szudzik elegant pairing function * http://szudzik.com/ElegantPairing.pdf diff --git a/src/views/viewCommands.ts b/src/views/viewCommands.ts index 7812f1a6af666..f9ba873a12b5b 100644 --- a/src/views/viewCommands.ts +++ b/src/views/viewCommands.ts @@ -51,7 +51,7 @@ import type { OpenWorkspaceLocation } from '../system/-webview/utils'; import { openUrl, openWorkspace, revealInFileExplorer } from '../system/-webview/utils'; import { filterMap } from '../system/array'; import { log } from '../system/decorators/log'; -import { partial, sequentialize } from '../system/function'; +import { partial, runSequentially } from '../system/function'; import { join, map } from '../system/iterable'; import { DeepLinkActionType } from '../uris/deepLinks/deepLink'; import type { LaunchpadItemNode } from './launchpadView'; @@ -122,7 +122,7 @@ export function registerViewCommand( } // Execute the command for each node sequentially - return sequentialize( + return runSequentially( callback, nodes.map<[ViewNode, ...any[]]>(n => [n, ...rest]), thisArg, diff --git a/src/webviews/webviewController.ts b/src/webviews/webviewController.ts index a7566c41e53cd..248ff6699f3c1 100644 --- a/src/webviews/webviewController.ts +++ b/src/webviews/webviewController.ts @@ -9,7 +9,7 @@ import { executeCommand, executeCoreCommand } from '../system/-webview/command'; import { setContext } from '../system/-webview/context'; import { getScopedCounter } from '../system/counter'; import { debug, logName } from '../system/decorators/log'; -import { serialize } from '../system/decorators/serialize'; +import { sequentialize } from '../system/decorators/serialize'; import { getLoggableName, Logger } from '../system/logger'; import { getLogScope, getNewLogScope, setLogScopeExit } from '../system/logger.scope'; import { pauseOnCancelOrTimeout } from '../system/promise'; @@ -689,7 +689,7 @@ export class WebviewController< } } - @serialize() + @sequentialize() @debug['postMessage']>({ args: false, enter: m => `(${m.id}|${m.method}${m.completionId ? `+${m.completionId}` : ''})`,