coll.mjs provides extended versions of JS data classes such as Set and Map, with better and/or additional APIs.
Port and rework of https://github.com/mitranim/jol.
import * as c from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/coll.mjs'Links: source; test/example.
Same as new #Bset but syntactically shorter and a function.
Links: source; test/example.
Same as #Bset .of but syntactically shorter and a function. The following is equivalent:
c.bsetOf(10, 20, 30)
c.Bset.of(10, 20, 30)
new c.Bset([10, 20, 30])
new c.Bset().add(10).add(20).add(30)Links: source; test/example.
Short for "better set". Variant of built-in Set with additional common-sense behaviors:
- Supports JSON encoding, behaving like an array.
- Supports adding other collections at any time by calling
.mut, not just in the constructor. - Has additional instantiation shortcuts such as static
.of.
Links: source; test/example.
Same as new #Bmap but syntactically shorter and a function.
Links: source; test/example.
Same as #Bmap .of but syntactically shorter and a function. The following is equivalent:
c.bmapOf(10, 20, 30, 40)
c.Bmap.of(10, 20, 30, 40)
new c.Bmap([[10, 20], [30, 40]])
new c.Bmap().set(10, 20).set(30, 40)Links: source; test/example.
Short for "better map". Variant of built-in Map with additional common-sense behaviors:
- Supports p:
- Can be instantiated from a dict.
- Can be patched by a dict by calling
.mut. - Can be converted to a dict by calling
.toDict. - Behaves like a dict in JSON.
- Supports JSON encoding. Only entries with string keys are sent to JSON, other entries are ignored.
- Adding entries from another collection can be done any time by calling
.mut, not just in the constructor. - Has additional instantiation shortcuts such as static
.of.
Links: source; test/example.
Variant of #Bmap with support for key and value checks. Subclasses must override methods .reqKey and .reqVal. These methods are automatically called by .set. Method .reqKey must validate and return the given key, and method .reqVal must validate and return the given value. Use type assertions provided by lang.
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
import * as c from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/coll.mjs'
class StrNatMap extends c.TypedMap {
reqKey(key) {return l.reqStr(key)}
reqVal(val) {return l.reqNat(val)}
}Links: source; test/example.
Short for "primary key optional". Takes an arbitrary value and returns its "primary key". This is used internally by #Coll and #ClsColl.
Currently this uses the following interface:
interface Pkable {pk(): any}Example use:
class Person {
constructor({name}) {this.name = name}
pk() {return this.name}
}
console.log(c.pkOpt(new Person({name: `Kara`})))
// 'Kara'Links: source; test/example.
Short for "primary key". Similar to #pkOpt, but the input must produce a non-nil primary key, otherwise this panics. This is used internally by #Coll and #ClsColl.
c.pk({})
// Uncaught TypeError: unable to get primary key of {}
class Person {
constructor({name}) {this.name = name}
pk() {return this.name}
}
c.pk(new Person({name: `Mira`}))
// 'Mira'Links: source; test/example.
Short for "collection". Ordered map where values are indexed on their "primary key" determined by the function #pk which is also exported by this module. Unlike a normal JS map, this is considered a sequence of values, not a sequence of key-value pairs. Order is preserved, iterating the values is decently fast, and the index allows fast access by key without additional iteration.
class Person {
constructor({name}) {this.name = name}
pk() {return this.name}
}
const coll = new c.Coll()
.add(new Person({name: `Mira`}))
.add(new Person({name: `Kara`}))
console.log(coll)
/*
Coll {
"Mira" => Person { name: "Mira" },
"Kara" => Person { name: "Kara" },
}
*/
console.log([...coll])
/*
[
Person { name: "Mira" },
Person { name: "Kara" },
]
*/Links: source; test/example.
Variant of #Coll where values must belong to a specific class, determined by its getter cls. The default element class is Object. Override it when subclassing. Elements added with .add are idempotently instantiated.
Also see #ClsVec.
class Person {
constructor({name}) {this.name = name}
pk() {return this.name}
}
class Persons extends c.ClsColl {
get cls() {return Person}
}
const coll = new Persons()
.add({name: `Mira`})
.add({name: `Kara`})
console.log(coll)
/*
Persons {
"Mira" => Person { name: "Mira" },
"Kara" => Person { name: "Kara" },
}
*/Links: source; test/example.
Short for "vector". Thin wrapper around a plain array. Features:
- Implements the iterable interface.
- Compatible with spread operator
.... - Compatible with
for of. - JSON-encodes like an array.
- Can wrap a pre-existing array.
Differences and advantages over Array:
- Better constructor signature.
- Can be subclassed without trashing performance.
- At the time of writing, subclasses of
Arraysuffer horrible deoptimization in V8. Vecalways wraps a t, avoiding this problem.
- At the time of writing, subclasses of
The overhead of the wrapper is insignificant.
import * as c from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/coll.mjs'
console.log(new c.Vec())
// Vec{Symbol(val): []}
console.log(new c.Vec([10, 20, 30]))
// Vec{Symbol(val): [10, 20, 30]}
console.log(c.Vec.of(10, 20, 30))
// Vec{Symbol(val): [10, 20, 30]}
console.log(c.Vec.from(new Set([10, 20, 30])))
// Vec{Symbol(val): [10, 20, 30]}
for (const val of c.Vec.of(10, 20, 30)) console.log(val)
// 10 20 30Links: source; test/example.
Variant of #Vec where values must belong to a specific class, determined by its getter cls. The default element class is Object. Override it when subclassing ClsVec. Elements added with .add are idempotently instantiated.
Also see #ClsColl.
class Person {
constructor({name}) {this.name = name}
pk() {return this.name}
}
class Persons extends c.ClsVec {
get cls() {return Person}
}
const coll = new Persons()
.add({name: `Mira`})
.add({name: `Kara`})
console.log(coll)
/*
Persons {
Symbol(val): [
Person {name: "Mira"},
Person {name: "Kara"},
]
}
*/The following APIs are exported but undocumented. Check coll.mjs.