diff --git a/README.md b/README.md index e60feab..cfc2853 100644 --- a/README.md +++ b/README.md @@ -280,7 +280,7 @@ This pattern is particularly useful when you need to handle initialization error - `defaultPriority` (number, default: 0) - Default task priority - `maxQueue` (number, default: Infinity) - Maximum queued tasks. Use `-1` for unlimited queue capacity (equivalent to `Infinity`) - `delays` (object, default: {}) - **DEPRECATED:** Priority-to-delay mapping for completion delays (use `priorities` instead) -- `priorities` (object, default: {}) - Priority-specific configuration: `{ [priority]: { concurrency, postDelay, startDelay } }` +- `priorities` (object, default: {}) - Priority-specific configuration: `{ [priority]: { concurrency, postDelay, startDelay } }`. Keys must be integers; any other key emits a `warning` event with `type: "invalid-priority"` (and is ignored when it isn't numeric at all) - `concurrency` (number) - Maximum concurrent tasks for this priority (defaults to global concurrency limit) - `postDelay` (number) - Delay after task completion before next task of same priority - `startDelay` (number) - Delay before task execution (pre-execution delay) diff --git a/src/hold-my-task.mjs b/src/hold-my-task.mjs index c335c26..c10af99 100644 --- a/src/hold-my-task.mjs +++ b/src/hold-my-task.mjs @@ -35,7 +35,7 @@ export class HoldMyTask extends EventEmitter { * @param {boolean} [options.smartScheduling=true] - Use dynamic timeouts instead of constant polling for better performance * @param {number} [options.tick=25] - Polling interval in milliseconds when smartScheduling is disabled * @param {number} [options.healingInterval=5000] - Self-healing check interval in milliseconds (smart scheduling only) - * @param {Object} [options.priorities={}] - Priority-specific default configurations + * @param {Object} [options.priorities={}] - Priority-specific default configurations, keyed by integer priority. A non-integer key emits an "invalid-priority" warning event * @param {number} [options.priorities[priority].concurrency] - Maximum concurrent tasks for this priority (defaults to global concurrency limit) * @param {number} [options.priorities[priority].postDelay] - Delay after task completion before next task of same priority * @param {number} [options.priorities[priority].startDelay] - Delay before task execution (pre-execution delay) @@ -210,6 +210,41 @@ export class HoldMyTask extends EventEmitter { } } + /** + * Resolves a `priorities` / `delays` object key to a numeric priority. + * Integer keys ("0", "10", "-1") resolve silently. Any other key emits a `warning` event of + * type "invalid-priority" so a typo can't silently disable a priority config: a key + * parseInt can't read (e.g. "high") is ignored, and a key it truncates (e.g. "2.5") keeps + * its historical meaning - the truncated priority - but is reported. + * @param {string} key - The object key as written in the config + * @param {string} option - The option the key came from ("priorities" or "delays") + * @returns {number|null} The numeric priority, or null when the key is ignored + * @private + * @internal + */ + _resolvePriorityKey(key, option) { + if (/^-?\d+$/.test(key)) { + return Number(key); + } + + const parsed = parseInt(key); + const priority = isNaN(parsed) ? null : parsed; + const message = + priority === null + ? `Priority key '${key}' in '${option}' is not an integer and was ignored. Priority keys must be integers.` + : `Priority key '${key}' in '${option}' is not an integer; it was applied to priority ${priority}. Priority keys must be integers.`; + setImmediate(() => + this.emit("warning", { + type: "invalid-priority", + message, + option, + key, + priority + }) + ); + return priority; + } + /** * Synchronous initialization for backwards compatibility * @private @@ -304,8 +339,9 @@ export class HoldMyTask extends EventEmitter { // First, transform any existing priority configurations to use new property names if (cleanOptions.priorities && typeof cleanOptions.priorities === "object") { for (const [priority, config] of Object.entries(cleanOptions.priorities)) { - const priorityNum = parseInt(priority); - if (!isNaN(priorityNum) && config != null) { + if (config == null) continue; + const priorityNum = this._resolvePriorityKey(priority, "priorities"); + if (priorityNum !== null) { transformedPriorities[priorityNum] = HoldMyTask._transformDelayProperties(config, this); } } @@ -325,8 +361,9 @@ export class HoldMyTask extends EventEmitter { ); for (const [priority, delay] of Object.entries(cleanOptions.delays)) { - const priorityNum = parseInt(priority); - if (!isNaN(priorityNum) && delay != null) { + if (delay == null) continue; + const priorityNum = this._resolvePriorityKey(priority, "delays"); + if (priorityNum !== null) { transformedPriorities[priorityNum] = { postDelay: delay, // Use new property name startDelay: 0, // Use new property name diff --git a/tests/PriorityKeyValidation.test.vitest.mjs b/tests/PriorityKeyValidation.test.vitest.mjs new file mode 100644 index 0000000..d54aa21 --- /dev/null +++ b/tests/PriorityKeyValidation.test.vitest.mjs @@ -0,0 +1,73 @@ +/** + * + * @Project: @cldmv/holdmytask + * @Filename: /tests/PriorityKeyValidation.test.vitest.mjs + * @Date: 2026-10-03T17:24:45-07:00 (1791073485) + * @Author: Nate Corcoran + * @Email: + * ----- + * @Last modified by: Nate Corcoran (Shinrai@users.noreply.github.com) + * @Last modified time: 2026-10-03T17:25:44-07:00 (1791073544) + * ----- + * @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. + * + */ + +import { test, expect, describe } from "vitest"; +import { HoldMyTask } from "../src/hold-my-task.mjs"; + +// #54: priority keys that aren't integers used to be dropped (or truncated) silently. +const collectWarnings = async (options) => { + const queue = new HoldMyTask({ autoStart: false, ...options }); + const warnings = []; + queue.on("warning", (w) => warnings.push(w)); + await new Promise((resolve) => setImmediate(resolve)); + return { queue, warnings: warnings.filter((w) => w.type === "invalid-priority") }; +}; + +describe("priority key validation", () => { + test("a non-numeric priorities key emits an invalid-priority warning and is ignored", async () => { + const { queue, warnings } = await collectWarnings({ priorities: { high: { postDelay: 100 }, 1: { postDelay: 50 } } }); + expect(warnings).toEqual([ + { + type: "invalid-priority", + message: expect.stringContaining("'high'"), + option: "priorities", + key: "high", + priority: null + } + ]); + expect(queue.getPriorityConfigurations()).toEqual({ 1: expect.objectContaining({ postDelay: 50 }) }); + queue.destroy(); + }); + + test("a non-integer key that parseInt truncates warns and keeps the truncated priority", async () => { + const { queue, warnings } = await collectWarnings({ priorities: { "2.5": { postDelay: 25 } } }); + expect(warnings).toEqual([expect.objectContaining({ type: "invalid-priority", option: "priorities", key: "2.5", priority: 2 })]); + expect(warnings[0].message).toContain("priority 2"); + expect(queue.getPriorityConfig(2).postDelay).toBe(25); + queue.destroy(); + }); + + test("the deprecated delays option is validated the same way", async () => { + const { queue, warnings } = await collectWarnings({ delays: { low: 10, 3: 30 } }); + expect(warnings).toEqual([expect.objectContaining({ type: "invalid-priority", option: "delays", key: "low", priority: null })]); + expect(queue.getPriorityConfig(3).postDelay).toBe(30); + queue.destroy(); + }); + + test("integer keys, including negative ones, produce no invalid-priority warning", async () => { + const { queue, warnings } = await collectWarnings({ + priorities: { 0: { postDelay: 1 }, 10: { postDelay: 2 }, "-1": { postDelay: 3 } } + }); + expect(warnings).toEqual([]); + expect(queue.getPriorityConfig(-1).postDelay).toBe(3); + queue.destroy(); + }); + + test("a key with a null config is skipped without a warning", async () => { + const { queue, warnings } = await collectWarnings({ priorities: { 1: null } }); + expect(warnings).toEqual([]); + queue.destroy(); + }); +}); diff --git a/types/src/hold-my-task.d.mts.map b/types/src/hold-my-task.d.mts.map index 86dfc37..53ead91 100644 --- a/types/src/hold-my-task.d.mts.map +++ b/types/src/hold-my-task.d.mts.map @@ -1 +1 @@ -{"version":3,"file":"hold-my-task.d.mts","sourceRoot":"","sources":["../../src/hold-my-task.mjs"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"hold-my-task.d.mts","sourceRoot":"","sources":["../../src/hold-my-task.mjs"],"names":[],"mappings":"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"} \ No newline at end of file