# trekhleb/javascript-algorithms — codebase unpack

> Canonical page: https://codevetter.com/unpack/javascript-algorithms

This is a deterministic Repo Unpack scan of trekhleb/javascript-algorithms — a structural map, not a review, security audit, or maintainer-endorsed description.

- Scanned commit: 85293e3e2b88f4d2ce330d956b139cf628aa1e82 (2026-07-25)
- Last upstream commit: Remove Project Backers section
- Generated by codevetter 1.12.0 on 2026-09-22
- 630 files scanned · 1.8 MB

## Languages

- JavaScript: 361 files
- Markdown: 259 files
- JSON: 1 files
- YAML: 1 files

## Repository structure

- src/ — 597 files
- .husky/ — 1 files
- .github/ — 1 files

Probable source entrypoint: `src/` (inferred from the tree, not upstream docs)

## Source layout — src/

- src/algorithms/ — 100 files
- src/data-structures/ — 161 files
- src/playground/ — 3 files

## Package

- package.json: javascript-algorithms-and-data-structures v0.0.4 — 11 declared dependencies

## Structural health signals

Average score 8.2/10 across 96 files; 0 hotspots. These are deterministic review leads, not proof of a bug.

## Recent history

- 85293e3e2b88 (2026-07-25) Remove Project Backers section
- e087629d2a41 (2026-07-25) Add links to sattelite apps (thinking and drawing)
- 5fcf3d713606 (2026-07-25) Add links to sattelite apps (thinking and drawing)
- 0f52fbaced5d (2026-06-26) Recompute graph edge key after reverse to reflect new direction
- dc12f1f5da28 (2022-07-30) Fix graph reverse method

## Overview

trekhleb/javascript-algorithms is a curated, test-driven educational collection of classic computer-science data structures and algorithms implemented in plain ES-module JavaScript, organized as ~150 self-contained topic folders under src/data-structures and src/algorithms, each paired with a README (often translated into ~20 locales) and a Jest test suite. It is not an application or published library — there is no runtime entrypoint, no index.js despite the package.json "main" field, and the only 'product' surface is the code itself plus the npm test/lint/coverage scripts. Distinctive traits: a shared Comparator/abstract-Sort callback design lets learners inject custom comparison and visiting hooks, and Jest coverage thresholds of 100% statements/functions/lines are enforced via npm run coverage in CI.

## System map

The repo is a flat monorepo of independent algorithm/data-structure modules — there is no app server, CLI, or build artifact; the runtime boundary is simply Node.js >=22 running Jest 30 over ES-module sources transpiled by @babel/preset-env. Code lives in three subtrees: src/data-structures (14 categories), src/algorithms (14 topic dirs), plus src/utils and a src/playground scratch area. Cross-cutting wiring is minimal: a single shared Comparator utility and a small inheritance graph (Sort -> QuickSort et al.; Heap -> MinHeap/MaxHeap -> PriorityQueue). Quality gates are npm run lint (eslint airbnb config) on pre-commit via husky, and npm run coverage in GitHub Actions CI on Node 22.x with Codecov upload.
- There is no application entrypoint or index.js at the repo root even though package.json declares "main": "index.js"; the package is a code collection consumed by reading/importing individual modules, not a runnable or publishable artifact. — [package.json#L29](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/package.json#L29) [README.md#L16-21](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/README.md#L16-L21)
- npm scripts define the entire developer workflow: `npm run lint` (eslint ./src/**), `npm test` (jest), `npm run coverage` (jest --coverage), `npm run ci` (lint + coverage), and `prepare` installs husky hooks. — [package.json#L30-36](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/package.json#L30-L36)
- Source is ES modules transpiled for tests by @babel/preset-env via .babelrc; there is no bundler, TypeScript, or build step. — [.babelrc](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/.babelrc) [package.json#L37-49](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/package.json#L37-L49)
- The code is organized into src/data-structures (linked-list, doubly-linked-list, queue, stack, deque, hash-table, heap, priority-queue, trie, tree/{avl,red-black,segment,fenwick,binary-search-tree}, graph, disjoint-set, bloom-filter, lru-cache) and src/algorithms (sorting, search, graph, tree, linked-list, math, string, sets, cryptography, image-processing, ml, statistics, stack, uncategorized). — [README.md#L43-80](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/README.md#L43-L80) [src/data-structures/linked-list/LinkedList.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js) [src/algorithms/sorting/quick-sort/QuickSort.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/quick-sort/QuickSort.js)
- src/utils/comparator/Comparator.js is the single shared utility: it wraps an optional custom compare function and exposes equal/lessThan/greaterThan/lessThanOrEqual/greaterThanOrEqual/reverse, and is injected into LinkedList, Heap, Sort, and PriorityQueue constructors. — [src/utils/comparator/Comparator.js#L7-23](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/utils/comparator/Comparator.js#L7-L23) [src/data-structures/linked-list/LinkedList.js#L15](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L15) [src/data-structures/heap/Heap.js#L18](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/heap/Heap.js#L18) [src/data-structures/priority-queue/PriorityQueue.js#L2-17](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/priority-queue/PriorityQueue.js#L2-L17)
- A small inheritance hierarchy provides shared structure: abstract Heap throws if constructed directly and is extended by MinHeap and MaxHeap; PriorityQueue extends MinHeap and swaps in a priority-aware Comparator. — [src/data-structures/heap/Heap.js#L6-19](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/heap/Heap.js#L6-L19) [src/data-structures/heap/MinHeap.js#L1](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/heap/MinHeap.js#L1) [src/data-structures/heap/MaxHeap.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/heap/MaxHeap.js) [src/data-structures/priority-queue/PriorityQueue.js#L1-17](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/priority-queue/PriorityQueue.js#L1-L17)
- The abstract Sort base class normalizes {compareCallback, visitingCallback} in initSortingCallbacks and forces subclasses to implement sort() (throws 'sort method must be implemented'); QuickSort and the other 10 sorting dirs subclass it. — [src/algorithms/sorting/Sort.js#L11-34](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/Sort.js#L11-L34) [src/algorithms/sorting/quick-sort/QuickSort.js#L3](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/quick-sort/QuickSort.js#L3)
- ESLint uses the airbnb preset with jest plugin and five relaxed rules (no-bitwise, no-lonely-if, class-methods-use-this, arrow-body-style, no-loop-func); a React version setting exists in .eslintrc despite the repo containing no React code. — [.eslintrc#L1-21](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/.eslintrc#L1-L21)
- GitHub Actions CI (.github/workflows/CI.yml) runs on push/PR to master on ubuntu-latest with a Node 22.x matrix: npm i -> npm run lint -> npm run coverage -> codecov/codecov-action@v4 upload. — [.github/workflows/CI.yml#L1-35](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/.github/workflows/CI.yml#L1-L35)
- Husky is wired through the `prepare` script and .husky/pre-commit runs `npm run lint` on every commit, so lint is the only client-side gate; tests are enforced only in CI. — [.husky/pre-commit](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/.husky/pre-commit) [package.json#L35](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/package.json#L35)
- Engines require node >=22.0.0 and npm >=10.0.0; devDependencies are limited to babel, eslint stack, jest 30, @types/jest, husky, and pngjs (used only by the seam-carving image test). — [package.json#L37-53](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/package.json#L37-L53)

## Feature catalog

Features here are the algorithm/data-structure modules themselves — each is a self-contained folder with one default-exported function or class, a README.md (frequently translated), and a co-located test directory. The catalog spans ~30 data-structure implementations across 14 categories and ~100 algorithm implementations across 14 topics, ranging from beginner (factorial, bubble sort) to advanced (red-black tree, seam carving, k-means). There are no routes, screens, or CLI subcommands; the 'user-facing' surface is the module APIs plus the playground scratch file.
- LinkedList provides a full fluent API — prepend, append, insert(value, rawIndex), delete(value), find({value, callback}), deleteTail, deleteHead, fromArray, toArray, toString(callback), reverse — with most mutating methods returning `this` for chaining. — [src/data-structures/linked-list/LinkedList.js#L22-271](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L22-L271)
- Graph supports directed and undirected modes via a constructor flag, auto-adds missing vertices on addEdge, throws on duplicate vertex/edge insertion, and offers getNeighbors, findEdge, getWeight, reverse (for directed graphs), getVerticesIndices and getAdjacencyMatrix. — [src/data-structures/graph/Graph.js#L5-200](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/graph/Graph.js#L5-L200)
- HashTable implements separate-chaining collision handling by filling each of its 32 default buckets with a LinkedList and tracking keys in a parallel `keys` object for O(1) has(). — [src/data-structures/hash-table/HashTable.js#L7-19](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/hash-table/HashTable.js#L7-L19) [src/data-structures/linked-list/LinkedList.js#L137-159](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L137-L159)
- LRUCache implements O(1) get/set using a nodesMap plus an internal doubly-linked list with sentinel head/tail nodes, promote() and evict() helpers, and a hard capacity eviction; an alternative LRUCacheOnMap implementation ships alongside it. — [src/data-structures/lru-cache/LRUCache.js#L31-151](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/lru-cache/LRUCache.js#L31-L151) [src/data-structures/lru-cache/LRUCacheOnMap.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/lru-cache/LRUCacheOnMap.js)
- BloomFilter exposes insert/mayContain backed by a closed-over boolean array (createStore) and three hand-rolled hash functions (hash1/hash2/hash3), demonstrating false-positive semantics. — [src/data-structures/bloom-filter/BloomFilter.js#L15-130](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/bloom-filter/BloomFilter.js#L15-L130)
- Eleven sorting algorithms live under src/algorithms/sorting (bubble, bucket, counting, heap, insertion, merge, quick, radix, selection, shell) all extending the abstract Sort class and honoring compareCallback/visitingCallback hooks. — [src/algorithms/sorting/Sort.js#L4-15](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/Sort.js#L4-L15) [src/algorithms/sorting/quick-sort/QuickSort.js#L8-47](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/quick-sort/QuickSort.js#L8-L47) [src/algorithms/sorting/SortTester.js#L9-21](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/SortTester.js#L9-L21)
- Graph algorithms cover traversals (breadthFirstSearch, depthFirstSearch) plus articulation-points, bellman-ford, bridges, detect-cycle, dijkstra, eulerian-path, floyd-warshall, hamiltonian-cycle, kruskal, prim, strongly-connected-components, topological-sorting and travelling-salesman. — [src/algorithms/graph/breadth-first-search/breadthFirstSearch.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/graph/breadth-first-search/breadthFirstSearch.js) [src/algorithms/graph/depth-first-search/depthFirstSearch.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/graph/depth-first-search/depthFirstSearch.js) [README.md#L74-80](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/README.md#L74-L80)
- The image-processing topic implements content-aware seam carving: resizeImageWidth shrinks an ImageData-like object width via energy-map calculation, DP lowest-energy seam finding, and in-place seam deletion. — [src/algorithms/image-processing/seam-carving/resizeImageWidth.js#L217-253](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/image-processing/seam-carving/resizeImageWidth.js#L217-L253)
- Math topics include factorial (iterative and recursive variants), fibonacci, primality-test, sieve-of-eratosthenes, euclidean-algorithm, fourier-transform, matrix operations, complex-number, bits manipulation and liu-hui pi approximation. — [src/algorithms/math/factorial/factorial.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/math/factorial/factorial.js) [src/algorithms/math/factorial/factorialRecursive.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/math/factorial/factorialRecursive.js) [README.md#L74-80](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/README.md#L74-L80)
- Cryptography offers caesar-cipher, hill-cipher, rail-fence-cipher and polynomial-hash (PolynomialHash plus a SimplePolynomialHash variant) — educational ciphers, not production crypto. — [src/algorithms/cryptography/polynomial-hash/PolynomialHash.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/cryptography/polynomial-hash/PolynomialHash.js) [src/algorithms/cryptography/polynomial-hash/SimplePolynomialHash.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/cryptography/polynomial-hash/SimplePolynomialHash.js)
- src/playground/playground.js is an explicit sandbox: it imports an algorithm (factorial by default), exposes a playground() function, and is exercised by src/playground/__test__/playground.test.js via `npm test -- 'playground'`. — [src/playground/playground.js#L1-12](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/playground/playground.js#L1-L12) [src/playground/__test__/playground.test.js#L1-8](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/playground/__test__/playground.test.js#L1-L8)
- Every topic folder ships a README.md with explanations and further-reading links, and most offer translations as README.xx-XX.md files (e.g., linked-list alone has 10 locale variants). — [README.md#L19-41](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/README.md#L19-L41) [CONTRIBUTING.md#L9-15](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/CONTRIBUTING.md#L9-L15)

## Data flow

Data flow is simple and uniform: callers (tests or the playground) invoke a module's default export with plain JS values; the module mutates or returns in-memory structures; results are compared with Jest matchers. There is no persistence, network, or external state — the only file IO is the seam-carving test streaming PNG fixtures through pngjs. The Comparator-injection pattern and traversal callbacks are the two mechanisms that let callers steer internal behavior without subclassing.
- Inputs are plain JS values passed directly to functions/classes (e.g., factorial(number), quickSort.sort(array), linkedList.append(value)); there is no request/response, CLI parsing, or stdin handling anywhere in src/. — [src/algorithms/math/factorial/factorial.js#L5-13](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/math/factorial/factorial.js#L5-L13) [src/data-structures/linked-list/LinkedList.js#L39-55](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L39-L55)
- Comparator is the primary data-normalization seam: constructors accept an optional compareFunction, and all ordering decisions flow through comparator.equal/lessThan/greaterThan rather than native operators. — [src/utils/comparator/Comparator.js#L7-53](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/utils/comparator/Comparator.js#L7-L53) [src/algorithms/sorting/quick-sort/QuickSort.js#L32-37](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/quick-sort/QuickSort.js#L32-L37) [src/data-structures/linked-list/LinkedList.js#L104-124](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L104-L124)
- Sorting transforms input -> cloned array -> pivot-partitioned left/center/right arrays -> recursively sorted concatenated output; QuickSort clones the input (`[...originalArray]`) so the caller's array is never mutated. — [src/algorithms/sorting/quick-sort/QuickSort.js#L8-47](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/quick-sort/QuickSort.js#L8-L47)
- Traversal algorithms move data through a callback pipeline: initCallbacks builds a closed-over `seen` map for allowTraversal, then each vertex flows enterVertex -> neighbor iteration gated by allowTraversal -> leaveVertex. — [src/algorithms/graph/breadth-first-search/breadthFirstSearch.js#L19-74](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/graph/breadth-first-search/breadthFirstSearch.js#L19-L74) [src/algorithms/graph/depth-first-search/depthFirstSearch.js#L17-58](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/graph/depth-first-search/depthFirstSearch.js#L17-L58)
- Queue is a thin adapter over LinkedList: enqueue delegates to append (tail), dequeue delegates to deleteHead (front), isEmpty checks linkedList.head — showing how data-structures compose as building blocks. — [src/data-structures/queue/Queue.js#L3-48](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/queue/Queue.js#L3-L48) [src/data-structures/linked-list/LinkedList.js#L195-210](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L195-L210)
- HashTable.set flows key -> hash() (char-code sum mod bucket count) -> buckets[hash] LinkedList -> find by callback -> append or update node.value.value; get/delete follow the same path. — [src/data-structures/hash-table/HashTable.js#L27-91](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/hash-table/HashTable.js#L27-L91)
- Seam carving is the only flow touching the filesystem, and only in tests: pngLoad streams a .png via fs.createReadStream into pngjs, converts to an ImageData-shaped object, then resizeImageWidth mutates img.data in place while tracking a separate logical {w,h} size. — [src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.node.js#L43-68](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.node.js#L43-L68) [src/algorithms/image-processing/seam-carving/resizeImageWidth.js#L217-251](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/image-processing/seam-carving/resizeImageWidth.js#L217-L251)
- State owners are instance fields on the structures: LinkedList.head/tail, Graph.vertices/edges (plain objects keyed by getKey()), HashTable.buckets/keys, Heap.heapContainer array, LRUCache.nodesMap/size plus sentinel nodes. — [src/data-structures/linked-list/LinkedList.js#L8-16](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L8-L16) [src/data-structures/graph/Graph.js#L5-9](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/graph/Graph.js#L5-L9) [src/data-structures/hash-table/HashTable.js#L13-19](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/hash-table/HashTable.js#L13-L19) [src/data-structures/heap/Heap.js#L16-18](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/heap/Heap.js#L16-L18) [src/data-structures/lru-cache/LRUCache.js#L36-42](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/lru-cache/LRUCache.js#L36-L42)
- Outputs are returned values (sorted arrays, found nodes, traversal orders accumulated by caller-supplied callbacks) plus toString() representations that tests use as the primary assertion mechanism (e.g., expect(linkedList.toString()).toBe('1,2')). — [src/data-structures/linked-list/LinkedList.js#L241-243](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L241-L243) [src/data-structures/linked-list/__test__/LinkedList.test.js#L18-33](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/__test__/LinkedList.test.js#L18-L33)
- Graph.getAdjacencyMatrix materializes a derived NxN weight matrix filled with Infinity for non-edges by iterating vertices and their neighbors — an explicit transform from adjacency-list storage to matrix output for algorithms like floyd-warshall. — [src/data-structures/graph/Graph.js#L169-200](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/graph/Graph.js#L169-L200)

## Behavior traces

Three flows were traced end-to-end. (1) Test execution: npm test -> jest -> testRegex match -> test file imports module under test -> assertions on return values/toString. (2) Sorting: QuickSort construction -> Sort.initSortingCallbacks -> sort() recursion driven by Comparator and visitingCallback. (3) BFS over a graph: callback init with seen-set -> Queue enqueue/dequeue -> getNeighbors -> allowTraversal gating. A fourth flow (seam carving) shows the only IO path: PNG load -> energy map -> DP seam -> in-place pixel shift.
- Test-run trace: `npm test` invokes jest, which applies testRegex '(/__tests__/.*|(\\.|/)(test|spec))\\.jsx?$' from jest.config.js, picks up files like src/data-structures/linked-list/__test__/LinkedList.test.js, which imports ../LinkedList, which imports LinkedListNode and ../../utils/comparator/Comparator. — [package.json#L32](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/package.json#L32) [jest.config.js#L22](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/jest.config.js#L22) [src/data-structures/linked-list/__test__/LinkedList.test.js#L1-6](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/__test__/LinkedList.test.js#L1-L6) [src/data-structures/linked-list/LinkedList.js#L1-2](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L1-L2)
- Sorting trace (QuickSort): new QuickSort(callbacks) -> Sort constructor -> Sort.initSortingCallbacks fills visitingCallback stub and wraps compareCallback in Comparator -> sort(originalArray) clones array -> shift() pivot -> partition loop calls callbacks.visitingCallback and comparator.equal/lessThan -> recursive sort of left/right -> concat result. — [src/algorithms/sorting/Sort.js#L12-29](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/Sort.js#L12-L29) [src/algorithms/sorting/quick-sort/QuickSort.js#L8-47](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/quick-sort/QuickSort.js#L8-L47)
- BFS trace: breadthFirstSearch(graph, startVertex, callbacks) -> initCallbacks builds allowTraversal closure with `seen` map -> new Queue() -> enqueue(startVertex) -> while !isEmpty: dequeue -> enterVertex -> graph.getNeighbors(currentVertex) -> allowTraversal decides enqueue -> leaveVertex -> repeat. — [src/algorithms/graph/breadth-first-search/breadthFirstSearch.js#L19-74](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/graph/breadth-first-search/breadthFirstSearch.js#L19-L74) [src/data-structures/queue/Queue.js#L36-48](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/queue/Queue.js#L36-L48) [src/data-structures/graph/Graph.js#L39-41](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/graph/Graph.js#L39-L41)
- DFS trace: depthFirstSearch -> initCallbacks (same seen-set pattern as BFS) -> depthFirstSearchRecursive -> enterVertex -> forEach neighbor -> allowTraversal gate -> recurse -> leaveVertex; recursion depth equals longest path, no explicit stack structure. — [src/algorithms/graph/depth-first-search/depthFirstSearch.js#L17-68](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/graph/depth-first-search/depthFirstSearch.js#L17-L68)
- Seam-carving trace: test calls pngLoad (fs.createReadStream.pipe(new PNG()).on('parsed')) to build an ImageData-shaped object -> resizeImageWidth({img,toWidth}) -> per removed column: calculateEnergyMap (getPixelEnergy of left/middle/right RGB deltas) -> findLowEnergySeam (DP seamPixelsMap then backtrack via `previous` links) -> deleteSeam (row-wise setPixel left-shift) -> return {img, size}. — [src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.node.js#L43-68](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.node.js#L43-L68) [src/algorithms/image-processing/seam-carving/resizeImageWidth.js#L92-251](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/image-processing/seam-carving/resizeImageWidth.js#L92-L251) [src/algorithms/image-processing/utils/imageData.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/image-processing/utils/imageData.js)
- HashTable write trace: set(key,value) -> hash(key) (charCode sum % buckets.length) -> this.keys[key]=keyHash -> bucket LinkedList.find({callback: nodeValue.key===key}) -> append new {key,value} node or overwrite node.value.value. — [src/data-structures/hash-table/HashTable.js#L27-64](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/hash-table/HashTable.js#L27-L64) [src/data-structures/linked-list/LinkedList.js#L137-159](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L137-L159)
- LinkedList deletion trace: delete(value) strips all matching head nodes in a while loop, then walks currentNode.next unlinking matches via compare.equal, finally reassigns this.tail if the tail matched — O(n) with the injected comparator deciding equality. — [src/data-structures/linked-list/LinkedList.js#L95-129](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L95-L129)
- LRUCache.get trace: get(key) -> nodesMap lookup -> promote(node) which evicts then re-appends the node to the tail of the doubly-linked list -> return node.val; set() appends a new node and evicts head.next when size exceeds capacity. — [src/data-structures/lru-cache/LRUCache.js#L50-150](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/lru-cache/LRUCache.js#L50-L150)
- CI pipeline trace: push/PR to master -> actions/checkout@v4 -> setup-node 22.x -> npm i -> npm run lint (eslint ./src/**) -> npm run coverage (jest --coverage, enforcing 100/95/100/100 thresholds) -> codecov upload. — [.github/workflows/CI.yml#L16-35](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/.github/workflows/CI.yml#L16-L35) [jest.config.js#L32-39](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/jest.config.js#L32-L39) [package.json#L30-34](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/package.json#L30-L34)

## Testing signals

Testing is the project's backbone: Jest 30 with ~112 __test__/__tests__ directories and ~178 spec files co-located beside implementations. Coverage thresholds are aspirational-strict (100% statements/functions/lines, 95% branches) but only enforced when the `coverage` script runs — plain `npm test` collects no coverage. Shared tester harnesses (SortTester, FourierTester) standardize whole algorithm families, and CI runs lint + coverage with Codecov upload on Node 22.
- Jest is configured in jest.config.js with testRegex '(/__tests__/.*|(\\.|/)(test|spec))\\.jsx?$', node_modules ignored, bail:false, verbose:false, and collectCoverage off by default. — [jest.config.js#L1-30](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/jest.config.js#L1-L30)
- coverageThreshold demands 100% statements/functions/lines and 95% branches globally, but because collectCoverage is false this only bites under `npm run coverage`/`npm run ci`. — [jest.config.js#L10-39](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/jest.config.js#L10-L39) [package.json#L33-34](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/package.json#L33-L34)
- Tests are co-located in `__test__` (singular, the dominant convention, ~112 dirs) or `__tests__` (plural, used by a few newer areas like seam-carving and matrix) directories next to the code they exercise. — [src/data-structures/linked-list/__test__/LinkedList.test.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/__test__/LinkedList.test.js) [src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.node.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.node.js)
- SortTester is a shared test harness exporting canned fixtures (sortedArr, reverseArr, notSortedArr, equalArr, negativeArr) plus static methods testSort, testNegativeNumbersSort, testSortWithCustomComparator, testSortStability and testAlgorithmTimeComplexity — the last uses jest.fn() to count visitingCallback invocations as a complexity proxy. — [src/algorithms/sorting/SortTester.js#L1-72](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/SortTester.js#L1-L72)
- The seam-carving spec uses a `.node.js` suffix inside a `__tests__` (plural) dir so the testRegex `__tests__/.*` alternative picks it up, and validates output against a reference PNG allowing <=10% of pixels to differ beyond a 50-value color threshold — a fuzzy image-equality assertion, not exact matching. (inferred) — [src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.node.js#L58-84](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.node.js#L58-L84) [jest.config.js#L22](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/jest.config.js#L22)
- Helper files like src/algorithms/sorting/SortTester.js and src/algorithms/math/fourier-transform/__test__/FourierTester.js are deliberately named so they are NOT matched by testRegex (no .test/.spec suffix, not in a `__tests__` dir) — they exist only to be imported by real specs. (inferred) — [src/algorithms/sorting/SortTester.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/SortTester.js) [jest.config.js#L22](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/jest.config.js#L22)
- LinkedList.test.js exemplifies the house test style: construct the structure, call mutating methods, and assert primarily on toString() output and head/tail invariants rather than internal state. — [src/data-structures/linked-list/__test__/LinkedList.test.js#L3-60](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/__test__/LinkedList.test.js#L3-L60)
- CI is the only place tests gate merges: the workflow runs `npm run coverage` after lint and uploads results via codecov/codecov-action@v4; the local pre-commit hook runs lint only, so a contributor can commit failing tests locally. — [.github/workflows/CI.yml#L28-35](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/.github/workflows/CI.yml#L28-L35) [.husky/pre-commit](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/.husky/pre-commit)
- The playground has its own spec asserting playground() === 120 (factorial(5)), giving contributors a sandbox that still participates in the coverage run. — [src/playground/__test__/playground.test.js#L1-8](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/playground/__test__/playground.test.js#L1-L8) [src/playground/playground.js#L7-10](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/playground/playground.js#L7-L10)
- CONTRIBUTING.md codifies the 100% coverage expectation for PRs and asks contributors to run npm run lint and npm test before submitting. — [CONTRIBUTING.md#L3-7](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/CONTRIBUTING.md#L3-L7)

## Risk map

Security exposure is minimal — no network, auth, secrets, or shell-out; the only file IO is the seam-carving test reading local PNG fixtures. The real risks are correctness and maintainability quirks: deliberately simplified primitives (char-sum hash, first-element pivot), mutating APIs, a missing package entrypoint, mixed test-dir naming, and a coverage gate that only runs in CI. Educational intent means several implementations trade robustness for clarity.
- package.json declares "main": "index.js" but no index.js exists at the root, and there is no "private" flag or exports map — the package cannot actually be require()'d as published; consumers must deep-import module files. — [package.json#L29](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/package.json#L29) [package.json#L1-8](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/package.json#L1-L8)
- HashTable.hash uses a naive sum of char codes mod bucket count with a tiny default size of 32, so real-world key sets collide heavily; the code comments acknowledge this and point to polynomial hashing as the better approach. — [src/data-structures/hash-table/HashTable.js#L7-45](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/hash-table/HashTable.js#L7-L45)
- QuickSort shifts elements out of the array in a while loop (array.shift() is O(n) per call) and always picks the first element as pivot — clean for teaching but quadratic on already-sorted input; SortTester's sortedArr/reverseArr fixtures exercise exactly that worst case. — [src/algorithms/sorting/quick-sort/QuickSort.js#L22-39](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/quick-sort/QuickSort.js#L22-L39) [src/algorithms/sorting/SortTester.js#L1-21](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/SortTester.js#L1-L21)
- Several APIs mutate in place, which can surprise consumers: Graph.reverse() deletes and re-adds every edge mutating the graph, resizeImageWidth rewrites img.data in place while reporting a smaller logical size, and LinkedList.reverse() rewrites node links. — [src/data-structures/graph/Graph.js#L145-164](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/graph/Graph.js#L145-L164) [src/algorithms/image-processing/seam-carving/resizeImageWidth.js#L217-251](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/image-processing/seam-carving/resizeImageWidth.js#L217-L251) [src/data-structures/linked-list/LinkedList.js#L249-271](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L249-L271)
- Graph.addVertex and addEdge throw generic Errors on duplicates ('Vertex has already been added before', 'Edge has already been added before') — callers must wrap or pre-check, and the error type gives no distinguishing subclass. — [src/data-structures/graph/Graph.js#L15-25](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/graph/Graph.js#L15-L25) [src/data-structures/graph/Graph.js#L79-83](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/graph/Graph.js#L79-L83)
- depthFirstSearch uses unbounded recursion (depthFirstSearchRecursive), so pathological deep graphs can hit the Node call-stack limit; the iterative alternative is not provided. (inferred) — [src/algorithms/graph/depth-first-search/depthFirstSearch.js#L48-58](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/graph/depth-first-search/depthFirstSearch.js#L48-L58)
- Test-directory naming is inconsistent (`__test__` vs `__tests__`) and helper files rely on precise filename conventions to avoid being executed as specs — a misplaced rename could silently drop or break tests. (inferred) — [jest.config.js#L22](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/jest.config.js#L22) [src/algorithms/sorting/SortTester.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/SortTester.js) [src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.node.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.node.js)
- The only filesystem access in the codebase is the seam-carving spec's fs.createReadStream of repo-relative PNG fixtures (./src/algorithms/image-processing/seam-carving/__tests__/test-image-*.png), so tests are CWD-sensitive — running jest from another directory breaks that spec. — [src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.node.js#L1-7](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.node.js#L1-L7)
- Coverage enforcement (100/95/100/100) runs only via `npm run coverage` in CI; local `npm test` skips coverage and pre-commit runs only lint, so coverage regressions are caught late. — [jest.config.js#L10-39](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/jest.config.js#L10-L39) [.husky/pre-commit](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/.husky/pre-commit) [.github/workflows/CI.yml#L28-35](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/.github/workflows/CI.yml#L28-L35)
- .eslintrc carries a react version setting and airbnb's jsx-a11y plugin chain despite zero JSX/React code in the repo — dead config that could confuse tooling choices. — [.eslintrc#L16-21](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/.eslintrc#L16-L21) [package.json#L41-45](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/package.json#L41-L45)

## Extension points

The whole repo is designed as an additive catalog: a new algorithm or data structure is a new folder that plugs in via file convention, not registration. Two deliberate seams exist inside the code — constructor-injected Comparator functions and the Sort/Heap/MinHeap inheritance chain plus traversal callbacks — and CONTRIBUTING.md spells out the social conventions (one algorithm per PR, README required, 100% coverage).
- Adding an algorithm means creating src/algorithms/<topic>/<name>/<name>.js with a default export plus a __test__ directory; no index file or registry needs updating — Jest discovers tests via testRegex. — [CONTRIBUTING.md#L17-25](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/CONTRIBUTING.md#L17-L25) [jest.config.js#L22](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/jest.config.js#L22)
- New sorting algorithms plug in by extending Sort: implement sort(), inherit this.comparator and this.callbacks (compareCallback, visitingCallback), then reuse SortTester.testSort/testSortStability/testAlgorithmTimeComplexity for free coverage. — [src/algorithms/sorting/Sort.js#L11-34](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/Sort.js#L11-L34) [src/algorithms/sorting/quick-sort/QuickSort.js#L3](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/quick-sort/QuickSort.js#L3) [src/algorithms/sorting/SortTester.js#L9-71](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/SortTester.js#L9-L71)
- Comparator injection is the universal customization point: LinkedList, Heap, Sort and PriorityQueue all accept a compareFunction in their constructor, letting the same structures order arbitrary objects. — [src/utils/comparator/Comparator.js#L7-9](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/utils/comparator/Comparator.js#L7-L9) [src/data-structures/linked-list/LinkedList.js#L8-16](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L8-L16) [src/data-structures/heap/Heap.js#L11-19](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/heap/Heap.js#L11-L19)
- Graph traversal behavior is extended through the {allowTraversal, enterVertex, leaveVertex} callback object — consumers implement cycle detection, ordering, or instrumentation without touching the traversal internals. — [src/algorithms/graph/breadth-first-search/breadthFirstSearch.js#L4-42](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/graph/breadth-first-search/breadthFirstSearch.js#L4-L42) [src/algorithms/graph/depth-first-search/depthFirstSearch.js#L2-40](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/graph/depth-first-search/depthFirstSearch.js#L2-L40)
- Heap is intentionally abstract (new.target guard throws on direct construction) so MinHeap/MaxHeap define ordering by overriding pairIsInCorrectOrder; PriorityQueue shows a second extension axis by overriding compare wholesale. — [src/data-structures/heap/Heap.js#L6-14](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/heap/Heap.js#L6-L14) [src/data-structures/priority-queue/PriorityQueue.js#L6-17](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/priority-queue/PriorityQueue.js#L6-L17)
- New heap-flavored structures can subclass MinHeap or swap in a custom Comparator, exactly as PriorityQueue does with its priorities Map. — [src/data-structures/priority-queue/PriorityQueue.js#L1-30](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/priority-queue/PriorityQueue.js#L1-L30) [src/data-structures/heap/MinHeap.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/heap/MinHeap.js)
- BloomFilter.createStore returns a closed-over storage interface ({getValue,setValue}), so the bit-array backend could be swapped without changing insert/mayContain. — [src/data-structures/bloom-filter/BloomFilter.js#L40-67](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/bloom-filter/BloomFilter.js#L40-L67)
- Translation is an extension surface: adding README.xx-XX.md files (root or per-topic) follows a documented locale-code convention in CONTRIBUTING.md. — [CONTRIBUTING.md#L9-15](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/CONTRIBUTING.md#L9-L15) [README.md#L23-41](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/README.md#L23-L41)
- The playground (src/playground/playground.js + __test__/playground.test.js) is a designed extension point for experimentation — it already demonstrates importing an algorithm and asserting on it. — [src/playground/playground.js#L1-12](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/playground/playground.js#L1-L12) [src/playground/__test__/playground.test.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/playground/__test__/playground.test.js)

## Contributor handoff

Safe mental model: this is an educational algorithm catalog, not an app — optimize for clarity and pedagogy over cleverness or performance. Before editing, read CONTRIBUTING.md, .eslintrc, jest.config.js and the target module's README. Conventions: one default export per file, file name matches export (camelCase for functions, PascalCase for classes), heavy JSDoc typedefs and explanatory comments, co-located __test__ dirs, toString()-based assertions. Verify with npm test and npm run lint; keep 100% coverage or CI fails.
- Read first: CONTRIBUTING.md (PR rules: focused one-algorithm PRs, README required, 100% coverage), jest.config.js (testRegex + thresholds), .eslintrc (airbnb + relaxed rules), and the module's own README.md for the math/intent. — [CONTRIBUTING.md](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/CONTRIBUTING.md) [jest.config.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/jest.config.js) [.eslintrc](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/.eslintrc)
- House style: every module default-exports one function or class, annotates params/returns with JSDoc (including @typedef blocks for callback shapes), and explains non-obvious steps with inline comments — match this rather than introducing terse idioms. — [src/algorithms/image-processing/seam-carving/resizeImageWidth.js#L1-48](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/image-processing/seam-carving/resizeImageWidth.js#L1-L48) [src/algorithms/graph/breadth-first-search/breadthFirstSearch.js#L4-14](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/graph/breadth-first-search/breadthFirstSearch.js#L4-L14) [src/data-structures/linked-list/LinkedList.js#L18-21](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L18-L21)
- Tests belong in a sibling `__test__` dir named <Module>.test.js; for shared algorithm families reuse the harness (SortTester statics) instead of duplicating fixtures. — [src/data-structures/linked-list/__test__/LinkedList.test.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/__test__/LinkedList.test.js) [src/algorithms/sorting/SortTester.js#L9-71](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/sorting/SortTester.js#L9-L71)
- Run `npm test -- <pattern>` for a single module (e.g. 'playground'), `npm test` for the full suite, `npm run lint` before committing (husky does this anyway), and `npm run coverage` to check the CI gate locally. — [package.json#L30-36](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/package.json#L30-L36) [src/playground/playground.js#L6](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/playground/playground.js#L6) [.husky/pre-commit](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/.husky/pre-commit)
- Node >=22 and npm >=10 are required; dependencies are dev-only — do not add runtime dependencies, and prefer plain JS over new libraries since pedagogy is the product. (inferred) — [package.json#L37-53](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/package.json#L37-L53)
- Do not create index.js or try to 'package' the repo — the missing main entry is the status quo; consumers deep-import files like src/data-structures/linked-list/LinkedList.js. (inferred) — [package.json#L29](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/package.json#L29) [src/data-structures/linked-list/LinkedList.js](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js)
- Mutating methods on data structures conventionally return `this` for chaining (append/prepend/insert/reverse); preserve that contract when editing or tests asserting chains will break. — [src/data-structures/linked-list/LinkedList.js#L22-55](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L22-L55)
- When touching Comparator behavior, remember Comparator.reverse() mutates the compare function in place — several tests rely on reversing sort order via this mechanism. — [src/utils/comparator/Comparator.js#L78-81](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/utils/comparator/Comparator.js#L78-L81)
- The seam-carving test resolves PNG fixtures relative to process CWD (./src/...), so always run jest from the repo root; new file-IO tests should follow the `__tests__` plural dir convention so testRegex matches. — [src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.node.js#L6-7](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.node.js#L6-L7) [jest.config.js#L22](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/jest.config.js#L22)
- Known traps: Graph throws on duplicate addVertex/addEdge (pre-check or expect the throw), HashTable keys must be strings (hash() iterates chars), and delete() on LinkedList removes ALL matching nodes, not just the first. — [src/data-structures/graph/Graph.js#L15-25](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/graph/Graph.js#L15-L25) [src/data-structures/hash-table/HashTable.js#L27-45](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/hash-table/HashTable.js#L27-L45) [src/data-structures/linked-list/LinkedList.js#L95-129](https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/linked-list/LinkedList.js#L95-L129)

Source repository: https://github.com/trekhleb/javascript-algorithms
Full evidence corpus: https://github.com/Codevetter/codevetter/tree/main/benchmarks/repo-unpacks/javascript-algorithms.json

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
