npm package: @sirhc77/listmap
Description: An ordered map
Author: Chris Carrington
Latest version: 1.4.0

# @sirhc77/listmap

An ordered Map with O(1) key lookups and stable iteration order. Provides familiar Map-like APIs plus efficient operations to push/unshift, pop/shift, and move entries to the front/back.

- Type-safe (written in TypeScript)
- Iterates in list order (head → tail)
- Efficient reordering without reallocation
- JSON-serializable helper

## Install

```shell script
npm install @sirhc77/listmap
```


## Quick start

```typescript
import { ListMap } from 'listmap';

const lm = new ListMap<number, string>([
  [1, 'a'],
  [2, 'b'],
]);

lm.set(3, 'c');         // add/update without changing position for existing keys
lm.push(4, 'd');        // add to tail (or move existing key to tail)
lm.unshift(0, 'z');     // add to head (or move existing key to head)

lm.moveToFront(2);      // move key 2 to head
lm.moveToBack(1);       // move key 1 to tail

console.log(lm.first()); // [2, 'b']
console.log(lm.last());  // [1, 'a']

for (const [k, v] of lm) {
  console.log(k, v);
}
// Order: 2 -> 0 -> 3 -> 4 -> 1
```


CommonJS usage:

```typescript
const { ListMap } = require('listmap');
```


## Why ListMap?

- Need predictable iteration order with Map semantics
- Want to efficiently move entries to the front/back (e.g., LRU-like behaviors)
- Prefer iterable collection with convenient helpers like toArray and toJSON

## API

All methods are chainable when appropriate.

- constructor(entries?: Iterable<[K, V]>)
    - Initialize with entries in order.

- size(): number
    - Number of items.

- set(key: K, value: V): this
    - Insert or update value for key. Updates do not change the current position.

- push(key: K, value: V): this
    - Add to tail. If key exists, it is moved to the tail and updated.

- unshift(key: K, value: V): this
    - Add to head. If key exists, it is moved to the head and updated.

- get(key: K): V | undefined

- has(key: K): boolean

- delete(key: K): boolean
    - Removes key if present.

- clear(): void

- first(): [K, V] | undefined
    - Head entry without removal.

- last(): [K, V] | undefined
    - Tail entry without removal.

- pop(): [K, V] | undefined
    - Remove and return the tail entry.

- shift(): [K, V] | undefined
    - Remove and return the head entry.

- moveToFront(key: K): boolean
    - Moves an existing key to head; returns false if not found.

- moveToBack(key: K): boolean
    - Moves an existing key to tail; returns false if not found.

- entries(): IterableIterator<[K, V]>
    - Also used for iteration with for...of.

- keys(): IterableIterator<K>

- values(): IterableIterator<V>

- forEach<T>(f: (this: T, v: V, k: K, m: this) => void, thisArg?: T): void
    - Iterates in list order (head → tail).

- toArray(): [K, V][]
    - Snapshot in iteration order.

- toJSON(): { key: K; value: V }[]
    - Convenient for JSON.stringify.

## Iteration and ordering rules

- Default iteration (for...of) yields [key, value] pairs from head to tail.
- set updates the value in place and does not change the position.
- push/unshift insert new keys or reposition existing keys to tail/head respectively.
- delete, pop, and shift update head/tail accordingly.

## TypeScript

Full type inference:

```typescript
const m = new ListMap<string, number>();
m.set('a', 1); // OK
// m.set(123, 'x'); // Type error
```


## JSON helpers

```typescript
const lm = new ListMap<string, any>([
  ['id', 1],
  ['name', 'Alice'],
]);

JSON.stringify(lm.toJSON());
// => [{"key":"id","value":1},{"key":"name","value":"Alice"}]
```


## Build and test

- Build: npm run build
- Test: npm test

## License

MIT