-
Notifications
You must be signed in to change notification settings - Fork 151
new: queue package upgrade for Solid 2.0 #918
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: next
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| --- | ||
| "@solid-primitives/queue": minor | ||
| --- | ||
|
|
||
| Initial release of `@solid-primitives/queue` | ||
|
|
||
| Six primitives for managing queues: | ||
|
|
||
| - **`makeQueue<T>(initialValues?)`** — non-reactive FIFO queue backed by a plain array. | ||
| - **`createQueue<T>(initialValues?)`** — reactive FIFO queue backed by Solid signals. Exposes reactive accessors (`queue`, `first`, `last`, `size`, `isEmpty`) and imperative methods (`add`, `remove`, `clear`). | ||
| - **`makePriorityQueue<T>(comparator, initialValues?)`** — non-reactive priority queue; items are dequeued in comparator order rather than insertion order. | ||
| - **`createPriorityQueue<T>(comparator, initialValues?)`** — reactive priority queue; same interface as `createQueue`. | ||
| - **`createTaskQueue<T>()`** — reactive async task queue. Tasks execute one at a time in FIFO order. `enqueue(task)` returns a `Promise<T>`. Exposes reactive `size` (pending count) and `active` (`boolean`). | ||
| - **`createConcurrentTaskQueue<T>(concurrency)`** — reactive async task queue running up to `concurrency` tasks simultaneously. `active` is a count (`Accessor<number>`). | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| # @solid-primitives/queue | ||
|
|
||
| ## 0.1.0 | ||
|
|
||
| ### Initial release | ||
|
|
||
| - `makeQueue<T>(initialValues?)` — non-reactive FIFO queue backed by a plain array | ||
| - `createQueue<T>(initialValues?)` — reactive FIFO queue backed by Solid signals; exposes `first`, `last`, `size`, `isEmpty`, `add`, `remove`, `clear` | ||
| - `makePriorityQueue<T>(comparator, initialValues?)` — non-reactive priority queue; items dequeued in comparator order | ||
| - `createPriorityQueue<T>(comparator, initialValues?)` — reactive priority queue; same interface as `createQueue` | ||
|
Comment on lines
+8
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct API docs to match released signatures. Line 8 and Line 9 appear out of sync with the PR’s described API: 🤖 Prompt for AI Agents |
||
| - `createTaskQueue<T>()` — reactive async task queue; tasks execute one at a time in FIFO order; `enqueue(task)` returns a Promise for the task's result; exposes reactive `size` and `active` | ||
| - `createConcurrentTaskQueue<T>(concurrency)` — reactive async task queue running up to `concurrency` tasks simultaneously; `active` is a count (`Accessor<number>`) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| MIT License | ||
|
|
||
| Copyright (c) 2021 Solid Primitives Working Group | ||
|
|
||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
|
|
||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
|
|
||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,276 @@ | ||
| <p> | ||
| <img width="100%" src="https://assets.solidjs.com/banner?type=Primitives&background=tiles&project=queue" alt="Solid Primitives queue"> | ||
| </p> | ||
|
|
||
| # @solid-primitives/queue | ||
|
|
||
| [](https://bundlephobia.com/package/@solid-primitives/queue) | ||
| [](https://www.npmjs.com/package/@solid-primitives/queue) | ||
| [](https://github.com/solidjs-community/solid-primitives#contribution-process) | ||
|
|
||
| Queue primitives for Solid.js. | ||
|
|
||
| - **`makeQueue`** — non-reactive FIFO queue backed by a plain array. No Solid lifecycle hooks; suitable for non-reactive contexts. | ||
| - **`createQueue`** — reactive FIFO queue backed by Solid signals. All accessor properties (`queue`, `first`, `last`, `size`, `isEmpty`) track reactively. | ||
| - **`makePriorityQueue`** — non-reactive priority queue. Items are dequeued by comparator order rather than insertion order. | ||
| - **`createPriorityQueue`** — reactive priority queue backed by Solid signals. | ||
| - **`createTaskQueue`** — reactive queue of async tasks that execute one at a time in FIFO order. Each `enqueue` call returns a Promise. | ||
| - **`createConcurrentTaskQueue`** — like `createTaskQueue` but runs up to `concurrency` tasks simultaneously. | ||
|
|
||
| ## Installation | ||
|
|
||
| ```bash | ||
| npm install @solid-primitives/queue | ||
| # or | ||
| yarn add @solid-primitives/queue | ||
| # or | ||
| pnpm add @solid-primitives/queue | ||
| ``` | ||
|
|
||
| ## `makeQueue` | ||
|
|
||
| Creates a plain, non-reactive FIFO queue. | ||
|
|
||
| ```ts | ||
| import { makeQueue } from "@solid-primitives/queue"; | ||
|
|
||
| const q = makeQueue([1, 2, 3]); | ||
|
|
||
| q.first; // 1 | ||
| q.last; // 3 | ||
| q.size; // 3 | ||
| q.isEmpty; // false | ||
|
|
||
| q.add(4, 5); | ||
| q.remove(); // 1 | ||
| q.first; // 2 | ||
|
|
||
| q.clear(); | ||
| q.isEmpty; // true | ||
| ``` | ||
|
|
||
| ### Type | ||
|
|
||
| ```ts | ||
| type Queue<T> = { | ||
| readonly first: T | undefined; | ||
| readonly last: T | undefined; | ||
| readonly size: number; | ||
| readonly isEmpty: boolean; | ||
| add: (...items: T[]) => void; | ||
| remove: () => T | undefined; | ||
| clear: () => void; | ||
| }; | ||
|
Comment on lines
+55
to
+63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Both runtime implementations expose Suggested README fix type Queue<T> = {
readonly first: T | undefined;
readonly last: T | undefined;
readonly size: number;
readonly isEmpty: boolean;
add: (...items: T[]) => void;
+ push: (comparator: (a: T, b: T) => number, ...items: T[]) => void;
remove: () => T | undefined;
clear: () => void;
}; type ReactiveQueue<T> = {
readonly queue: Accessor<T[]>;
readonly first: Accessor<T | undefined>;
readonly last: Accessor<T | undefined>;
readonly size: Accessor<number>;
readonly isEmpty: Accessor<boolean>;
add: (...items: T[]) => void;
+ push: (comparator: (a: T, b: T) => number, ...items: T[]) => void;
remove: () => T | undefined;
clear: () => void;
};Also applies to: 97-106 🤖 Prompt for AI Agents |
||
|
|
||
| function makeQueue<T>(initialValues?: T[]): Queue<T>; | ||
| ``` | ||
|
|
||
| ## `createQueue` | ||
|
|
||
| Creates a reactive FIFO queue. All accessor properties establish reactive dependencies when read inside a tracking scope (JSX, `createMemo`, `createEffect`, etc.). | ||
|
|
||
| Mutations (`add`, `remove`, `clear`) are batched by Solid's scheduler and applied on the next microtask. In tests, call `flush()` after mutations before reading reactive values. | ||
|
|
||
| ```ts | ||
| import { createQueue } from "@solid-primitives/queue"; | ||
|
|
||
| const { queue, first, last, size, isEmpty, add, remove, clear } = createQueue(["a", "b", "c"]); | ||
|
|
||
| // Read reactive state | ||
| size(); // 3 | ||
| first(); // "a" | ||
| isEmpty(); // false | ||
|
|
||
| // Mutate | ||
| add("d", "e"); | ||
| remove(); // "a" — returned synchronously | ||
|
|
||
| // In JSX — updates automatically | ||
| <For each={queue()}>{item => <li>{item}</li>}</For> | ||
| <p>Next: {first()}</p> | ||
| <p>Remaining: {size()}</p> | ||
| ``` | ||
|
|
||
| ### Type | ||
|
|
||
| ```ts | ||
| type ReactiveQueue<T> = { | ||
| readonly queue: Accessor<T[]>; | ||
| readonly first: Accessor<T | undefined>; | ||
| readonly last: Accessor<T | undefined>; | ||
| readonly size: Accessor<number>; | ||
| readonly isEmpty: Accessor<boolean>; | ||
| add: (...items: T[]) => void; | ||
| remove: () => T | undefined; | ||
| clear: () => void; | ||
| }; | ||
|
|
||
| function createQueue<T>(initialValues?: T[]): ReactiveQueue<T>; | ||
| ``` | ||
|
|
||
| ### Notes | ||
|
|
||
| - `remove()` returns the dequeued item **synchronously**, even though the reactive signal update is batched. | ||
| - Initial values are **copied** — the source array is never mutated. | ||
| - Calling `add` or `remove` inside a Solid reactive computation (memo, effect compute phase) will throw in development. Call mutations from event handlers or effect **apply** phases. | ||
|
|
||
| ## `makePriorityQueue` | ||
|
|
||
| Creates a plain, non-reactive priority queue. Items are kept in sorted order; `remove()` always returns the highest-priority item (smallest by the comparator). | ||
|
|
||
| ```ts | ||
| import { makePriorityQueue } from "@solid-primitives/queue"; | ||
|
|
||
| const q = makePriorityQueue((a, b) => a - b, [3, 1, 2]); | ||
|
|
||
|
Comment on lines
+121
to
+125
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The README currently documents and demonstrates Suggested README fix-import { makePriorityQueue } from "`@solid-primitives/queue`";
+import { makePriorityQueue, makeQueue } from "`@solid-primitives/queue`";
-const q = makePriorityQueue((a, b) => a - b, [3, 1, 2]);
+const asc = (a, b) => a - b;
+const q = makePriorityQueue(makeQueue([3, 1, 2].sort(asc)), asc);-function makePriorityQueue<T>(
- comparator: (a: T, b: T) => number,
- initialValues?: T[],
-): Queue<T>;
+function makePriorityQueue<T, Q extends { add: (...items: T[]) => void; push: (comparator: (a: T, b: T) => number, ...items: T[]) => void }>(
+ q: Q,
+ comparator: (a: T, b: T) => number,
+): Q;Also applies to: 137-142 🤖 Prompt for AI Agents |
||
| q.first; // 1 | ||
| q.last; // 3 | ||
| q.remove(); // 1 | ||
| q.first; // 2 | ||
|
|
||
| q.add(0); | ||
| q.first; // 0 | ||
| ``` | ||
|
|
||
| ### Type | ||
|
|
||
| ```ts | ||
| function makePriorityQueue<T>( | ||
| comparator: (a: T, b: T) => number, | ||
| initialValues?: T[], | ||
| ): Queue<T>; | ||
| ``` | ||
|
|
||
| ## `createPriorityQueue` | ||
|
|
||
| Creates a reactive priority queue. All accessor properties establish reactive dependencies. Mutations are batched; call `flush()` in tests before reading reactive values. | ||
|
|
||
| ```ts | ||
| import { createPriorityQueue } from "@solid-primitives/queue"; | ||
|
|
||
| const { queue, first, size, add, remove } = createPriorityQueue( | ||
| (a, b) => a.priority - b.priority, | ||
| initialItems, | ||
| ); | ||
|
|
||
| first(); // highest-priority item | ||
|
|
||
| add({ priority: 0, label: "urgent" }); | ||
| // In JSX | ||
| <For each={queue()}>{item => <Task item={item} />}</For> | ||
| ``` | ||
|
|
||
| ### Type | ||
|
|
||
| ```ts | ||
| function createPriorityQueue<T>( | ||
| comparator: (a: T, b: T) => number, | ||
| initialValues?: T[], | ||
| ): ReactiveQueue<T>; | ||
| ``` | ||
|
|
||
| ### Notes | ||
|
|
||
| - `remove()` returns the dequeued item **synchronously**, even though the reactive signal update is batched. | ||
| - Initial values are **copied** — the source array is never mutated. | ||
| - `queue()` returns items in priority order (lowest comparator value first). | ||
|
|
||
| ## `createTaskQueue` | ||
|
|
||
| Creates a reactive queue that runs async tasks one at a time in FIFO order. | ||
|
|
||
| Each task is a zero-argument function returning a plain value or a Promise. Tasks execute sequentially: the next task starts only after the current one resolves or rejects. `enqueue` returns a `Promise<T>` that settles with the task's result. | ||
|
|
||
| `size` counts tasks **waiting** (not including the one currently executing). | ||
| `active` is `true` while any task is running. | ||
|
|
||
| ```ts | ||
| import { createTaskQueue } from "@solid-primitives/queue"; | ||
|
|
||
| const { enqueue, size, active } = createTaskQueue<User>(); | ||
|
|
||
| // Each call runs after the previous one finishes | ||
| const [alice, bob] = await Promise.all([ | ||
| enqueue(() => fetchUser("alice")), | ||
| enqueue(() => fetchUser("bob")), | ||
| ]); | ||
|
|
||
| // In JSX | ||
| <Show when={active()}> | ||
| <p>Processing… ({size()} remaining)</p> | ||
| </Show> | ||
| ``` | ||
|
|
||
| ### Type | ||
|
|
||
| ```ts | ||
| type Task<T> = () => Promise<T> | T; | ||
|
|
||
| type ReactiveTaskQueue<T> = { | ||
| /** Number of tasks waiting to start (excludes the task currently executing). */ | ||
| readonly size: Accessor<number>; | ||
| /** `true` while a task is executing. */ | ||
| readonly active: Accessor<boolean>; | ||
| /** Adds a task to the back of the queue; resolves/rejects with its result. */ | ||
| enqueue: (task: Task<T>) => Promise<T>; | ||
| /** | ||
| * Removes all waiting tasks and rejects their Promises with `"Queue cleared"`. | ||
| * The currently-executing task (if any) runs to completion unaffected. | ||
| */ | ||
| clear: () => void; | ||
| }; | ||
|
|
||
| function createTaskQueue<T>(): ReactiveTaskQueue<T>; | ||
| ``` | ||
|
|
||
| ### Notes | ||
|
|
||
| - Tasks added while the queue is draining are picked up automatically — `enqueue` never restarts the drain. | ||
| - `clear()` does **not** cancel the active task; only unstarted tasks are rejected. | ||
| - All tasks share the same return type `T`. For heterogeneous task types use `createTaskQueue<unknown>()`. | ||
|
|
||
| ## `createConcurrentTaskQueue` | ||
|
|
||
| Creates a reactive task queue that runs up to `concurrency` tasks at a time. Tasks beyond the limit wait until a slot opens. | ||
|
|
||
| `size` counts tasks **waiting** (not including those executing). | ||
| `active` is the **number** of tasks currently executing (0 when idle). | ||
|
|
||
| ```ts | ||
| import { createConcurrentTaskQueue } from "@solid-primitives/queue"; | ||
|
|
||
| const { enqueue, active, size } = createConcurrentTaskQueue<Response>(3); | ||
|
|
||
| // Up to 3 fetches run at once; the rest wait | ||
| urls.forEach(url => enqueue(() => fetch(url))); | ||
|
|
||
| // In JSX | ||
| <Show when={active() > 0}> | ||
| <p>Fetching… ({active()} active, {size()} waiting)</p> | ||
| </Show> | ||
| ``` | ||
|
|
||
| ### Type | ||
|
|
||
| ```ts | ||
| type ReactiveConcurrentTaskQueue<T> = { | ||
| /** Number of tasks waiting to start (excludes tasks currently executing). */ | ||
| readonly size: Accessor<number>; | ||
| /** Number of tasks currently executing (0 when idle). */ | ||
| readonly active: Accessor<number>; | ||
| enqueue: (task: Task<T>) => Promise<T>; | ||
| clear: () => void; | ||
| }; | ||
|
|
||
| function createConcurrentTaskQueue<T>(concurrency: number): ReactiveConcurrentTaskQueue<T>; | ||
| ``` | ||
|
|
||
| ### Notes | ||
|
|
||
| - `active` is a **count** (`Accessor<number>`), unlike `createTaskQueue` where it is a boolean. | ||
| - `clear()` rejects all **waiting** tasks; tasks currently executing run to completion. | ||
| - For heterogeneous task types use `createConcurrentTaskQueue<unknown>()`. | ||
|
|
||
| ## Changelog | ||
|
|
||
| See [CHANGELOG.md](./CHANGELOG.md) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| import { type Component, createSignal } from "solid-js"; | ||
| import { For } from "@solidjs/web"; | ||
| import { createQueue } from "../src/index.js"; | ||
|
|
||
| const App: Component = () => { | ||
| const [input, setInput] = createSignal(""); | ||
| const { queue, first, size, isEmpty, add, remove, clear } = createQueue<string>(); | ||
|
|
||
| const enqueue = () => { | ||
| const val = input().trim(); | ||
| if (val) { | ||
| add(val); | ||
| setInput(""); | ||
| } | ||
| }; | ||
|
|
||
| return ( | ||
| <div class="box-border flex min-h-screen w-full flex-col items-center justify-center space-y-4 bg-gray-800 p-24 text-white"> | ||
| <div class="wrapper-v"> | ||
| <h4>Queue Primitive</h4> | ||
| <p class="caption">FIFO queue — items added to back, removed from front</p> | ||
| <div class="flex gap-2"> | ||
| <input | ||
| class="input" | ||
| placeholder="Add item..." | ||
| value={input()} | ||
| onInput={e => setInput(e.currentTarget.value)} | ||
| onKeyDown={e => e.key === "Enter" && enqueue()} | ||
| /> | ||
| <button class="btn" onClick={enqueue}> | ||
| Enqueue | ||
| </button> | ||
| </div> | ||
| <div class="flex gap-2"> | ||
| <button class="btn" onClick={remove} disabled={isEmpty()}> | ||
| Dequeue | ||
| </button> | ||
| <button class="btn" onClick={clear} disabled={isEmpty()}> | ||
| Clear | ||
| </button> | ||
| </div> | ||
| <p> | ||
| Size: <strong>{size()}</strong> | Next up: <strong>{first() ?? "—"}</strong> | ||
| </p> | ||
| <ul> | ||
| <For each={queue()}>{item => <li>{item}</li>}</For> | ||
| </ul> | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default App; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update
makePriorityQueuesignature in changeset text.Line 11 documents
makePriorityQueue<T>(comparator, initialValues?), but the PR contract describes a queue modifier form (makePriorityQueue(q, comparator)). This should be corrected before release notes are generated.🤖 Prompt for AI Agents