This is an automated email from the ASF dual-hosted git repository.

maximebeauchemin pushed a commit to branch js-to-ts
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 960a31f2117499168d7297ca4b307166c7cb2ef8
Author: Maxime Beauchemin <[email protected]>
AuthorDate: Sun Sep 7 14:58:22 2025 -0700

    feat(migration): complete DebouncedMessageQueue TypeScript migration
    
    - Migrate DebouncedMessageQueue.js to TypeScript with proper generics
    - Add DebouncedMessageQueueOptions interface for type-safe configuration
    - Implement proper class properties with private/readonly modifiers
    - CREATE missing test file: DebouncedMessageQueue.test.ts
    - All TypeScript compilation and tests pass
    - Improve js-to-ts command with test creation requirements
    
    🤖 Generated with [Claude Code](https://claude.ai/code)
    
    Co-Authored-By: Claude <[email protected]>
---
 .claude/commands/js-to-ts.md                       | 14 ++++-
 .../src/utils/DebouncedMessageQueue.test.ts        | 66 ++++++++++++++++++++++
 ...cedMessageQueue.js => DebouncedMessageQueue.ts} | 31 ++++++++--
 3 files changed, 104 insertions(+), 7 deletions(-)

diff --git a/.claude/commands/js-to-ts.md b/.claude/commands/js-to-ts.md
index c34726faaf..36de748057 100644
--- a/.claude/commands/js-to-ts.md
+++ b/.claude/commands/js-to-ts.md
@@ -8,6 +8,7 @@ Atomically migrate a core JS/JSX file to TypeScript along with 
all related tests
 ```
 - `<core-filename>` - Path to CORE file relative to `superset-frontend/` 
(e.g., `src/utils/common.js`, `src/middleware/loggerMiddleware.js`)
 - **CORE FILES ONLY**: No test files, mock files - agent will find and migrate 
related files automatically
+- **Task Title**: Use core filename as task title (e.g., 
"DebouncedMessageQueue.js migration")
 
 ---
 
@@ -54,13 +55,19 @@ find "$dirname" -name "${basename}.mock.js"
 
 **Migration Requirement:** All discovered related files MUST be migrated 
together as one atomic unit.
 
+**Test File Creation:** If NO test files exist for the core file, CREATE a 
minimal test file using the following pattern:
+- Location: Same directory as core file
+- Name: `{basename}.test.ts` (e.g., `DebouncedMessageQueue.test.ts`)
+- Content: Basic test structure importing and testing the main functionality
+- Use proper TypeScript types in test file
+
 ### Success Report Format
 ```
 SUCCESS: Atomic Migration of {core-filename}
 
 ## Files Migrated (Atomic Unit)
 - Core: {core-filename} → {core-filename.ts/tsx}
-- Tests: {list-of-test-files} → {list-of-test-files.ts/tsx}
+- Tests: {list-of-test-files} → {list-of-test-files.ts/tsx} OR "CREATED: 
{basename}.test.ts"
 - Mocks: {list-of-mock-files} → {list-of-mock-files.ts}
 - Type files modified: {list-of-type-files}
 
@@ -124,6 +131,11 @@ DEPENDENCY_BLOCK: Cannot migrate {filename}
 
 ## Coordinator Actions
 
+### Task Creation (Coordinator)
+When triggering the `/js-to-ts` command:
+- **Task Title**: Use the core filename as the task title (e.g., 
"DebouncedMessageQueue.js migration", "hostNamesConfig.js migration")
+- **Task Description**: Include the full relative path to help agent locate 
the file
+
 ### Global Integration (Coordinator Only)
 When agents report `SUCCESS`:
 - Review agent's type improvements for consistency
diff --git a/superset-frontend/src/utils/DebouncedMessageQueue.test.ts 
b/superset-frontend/src/utils/DebouncedMessageQueue.test.ts
new file mode 100644
index 0000000000..2631d7c20c
--- /dev/null
+++ b/superset-frontend/src/utils/DebouncedMessageQueue.test.ts
@@ -0,0 +1,66 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import DebouncedMessageQueue from './DebouncedMessageQueue';
+
+describe('DebouncedMessageQueue', () => {
+  it('should create a queue with default options', () => {
+    const queue = new DebouncedMessageQueue();
+    expect(queue).toBeDefined();
+    expect(queue.trigger).toBeInstanceOf(Function);
+  });
+
+  it('should accept custom configuration options', () => {
+    const mockCallback = jest.fn();
+    const queue = new DebouncedMessageQueue({
+      callback: mockCallback,
+      sizeThreshold: 500,
+      delayThreshold: 2000,
+    });
+    expect(queue).toBeDefined();
+  });
+
+  it('should append items to the queue', () => {
+    const mockCallback = jest.fn();
+    const queue = new DebouncedMessageQueue({ callback: mockCallback });
+
+    const testEvent = { id: 1, message: 'test' };
+    queue.append(testEvent);
+
+    // Verify the append method doesn't throw
+    expect(() => queue.append(testEvent)).not.toThrow();
+  });
+
+  it('should handle generic types properly', () => {
+    interface TestEvent {
+      id: number;
+      data: string;
+    }
+
+    const mockCallback = jest.fn();
+    const queue = new DebouncedMessageQueue<TestEvent>({
+      callback: mockCallback,
+    });
+
+    const testEvent: TestEvent = { id: 1, data: 'test' };
+    queue.append(testEvent);
+
+    expect(() => queue.append(testEvent)).not.toThrow();
+  });
+});
diff --git a/superset-frontend/src/utils/DebouncedMessageQueue.js 
b/superset-frontend/src/utils/DebouncedMessageQueue.ts
similarity index 69%
rename from superset-frontend/src/utils/DebouncedMessageQueue.js
rename to superset-frontend/src/utils/DebouncedMessageQueue.ts
index 6fd6c5b778..99b50650ae 100644
--- a/superset-frontend/src/utils/DebouncedMessageQueue.js
+++ b/superset-frontend/src/utils/DebouncedMessageQueue.ts
@@ -18,26 +18,45 @@
  */
 import { debounce } from 'lodash';
 
-class DebouncedMessageQueue {
+export interface DebouncedMessageQueueOptions<T> {
+  callback?: (events: T[]) => void;
+  sizeThreshold?: number;
+  delayThreshold?: number;
+}
+
+class DebouncedMessageQueue<T = Record<string, unknown>> {
+  private queue: T[];
+
+  private readonly sizeThreshold: number;
+
+  private readonly delayThreshold: number;
+
+  private readonly callback: (events: T[]) => void;
+
+  public readonly trigger: () => void;
+
   constructor({
     callback = () => {},
     sizeThreshold = 1000,
     delayThreshold = 1000,
-  }) {
+  }: DebouncedMessageQueueOptions<T> = {}) {
     this.queue = [];
     this.sizeThreshold = sizeThreshold;
     this.delayThreshold = delayThreshold;
-
-    this.trigger = debounce(this.trigger.bind(this), this.delayThreshold);
     this.callback = callback;
+
+    this.trigger = debounce(
+      this.triggerInternal.bind(this),
+      this.delayThreshold,
+    );
   }
 
-  append(eventData) {
+  append(eventData: T): void {
     this.queue.push(eventData);
     this.trigger();
   }
 
-  trigger() {
+  private triggerInternal(): void {
     if (this.queue.length > 0) {
       const events = this.queue.splice(0, this.sizeThreshold);
       this.callback.call(null, events);

Reply via email to