Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@thi.ng/defmulti

Package Overview
Dependencies
Maintainers
1
Versions
186
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@thi.ng/defmulti - npm Package Compare versions

Comparing version 0.4.1 to 0.5.0

11

CHANGELOG.md

@@ -6,2 +6,13 @@ # Change Log

# [0.5.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/defmulti@0.4.1...@thi.ng/defmulti@0.5.0) (2018-10-24)
### Features
* **defmulti:** add support for dispatch value relationships / hierarchy ([a8c3898](https://github.com/thi-ng/umbrella/commit/a8c3898))
## [0.4.1](https://github.com/thi-ng/umbrella/compare/@thi.ng/defmulti@0.4.0...@thi.ng/defmulti@0.4.1) (2018-10-21)

@@ -8,0 +19,0 @@

64

index.d.ts

@@ -0,1 +1,2 @@

import { IObjectOf } from "@thi.ng/api/api";
export declare const DEFAULT: unique symbol;

@@ -20,38 +21,29 @@ export declare type DispatchFn = (...args: any[]) => PropertyKey;

export declare type Implementation8<A, B, C, D, E, F, G, H, T> = (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, ...xs: any[]) => T;
export interface MultiFn<T> extends Implementation<T> {
add: (id: PropertyKey, g: Implementation<T>) => boolean;
remove: (id: PropertyKey) => boolean;
export interface MultiFnBase<I> {
add(id: PropertyKey, g: I): boolean;
remove(id: PropertyKey): boolean;
isa(id: PropertyKey, parent: PropertyKey): any;
rels(): IObjectOf<Set<PropertyKey>>;
parents(id: PropertyKey): Set<PropertyKey>;
ancestors(id: PropertyKey): Set<PropertyKey>;
}
export interface MultiFn1<A, T> extends Implementation1<A, T> {
add: (id: PropertyKey, g: Implementation1<A, T>) => boolean;
remove: (id: PropertyKey) => boolean;
export interface MultiFn<T> extends Implementation<T>, MultiFnBase<Implementation<T>> {
}
export interface MultiFn2<A, B, T> extends Implementation2<A, B, T> {
add: (id: PropertyKey, g: Implementation2<A, B, T>) => boolean;
remove: (id: PropertyKey) => boolean;
export interface MultiFn1<A, T> extends Implementation1<A, T>, MultiFnBase<Implementation1<A, T>> {
}
export interface MultiFn3<A, B, C, T> extends Implementation3<A, B, C, T> {
add: (id: PropertyKey, g: Implementation3<A, B, C, T>) => boolean;
remove: (id: PropertyKey) => boolean;
export interface MultiFn2<A, B, T> extends Implementation2<A, B, T>, MultiFnBase<Implementation2<A, B, T>> {
}
export interface MultiFn4<A, B, C, D, T> extends Implementation4<A, B, C, D, T> {
add: (id: PropertyKey, g: Implementation4<A, B, C, D, T>) => boolean;
remove: (id: PropertyKey) => boolean;
export interface MultiFn3<A, B, C, T> extends Implementation3<A, B, C, T>, MultiFnBase<Implementation3<A, B, C, T>> {
}
export interface MultiFn5<A, B, C, D, E, T> extends Implementation5<A, B, C, D, E, T> {
add: (id: PropertyKey, g: Implementation5<A, B, C, D, E, T>) => boolean;
remove: (id: PropertyKey) => boolean;
export interface MultiFn4<A, B, C, D, T> extends Implementation4<A, B, C, D, T>, MultiFnBase<Implementation4<A, B, C, D, T>> {
}
export interface MultiFn6<A, B, C, D, E, F, T> extends Implementation6<A, B, C, D, E, F, T> {
add: (id: PropertyKey, g: Implementation6<A, B, C, D, E, F, T>) => boolean;
remove: (id: PropertyKey) => boolean;
export interface MultiFn5<A, B, C, D, E, T> extends Implementation5<A, B, C, D, E, T>, MultiFnBase<Implementation5<A, B, C, D, E, T>> {
}
export interface MultiFn7<A, B, C, D, E, F, G, T> extends Implementation7<A, B, C, D, E, F, G, T> {
add: (id: PropertyKey, g: Implementation7<A, B, C, D, E, F, G, T>) => boolean;
remove: (id: PropertyKey) => boolean;
export interface MultiFn6<A, B, C, D, E, F, T> extends Implementation6<A, B, C, D, E, F, T>, MultiFnBase<Implementation6<A, B, C, D, E, F, T>> {
}
export interface MultiFn8<A, B, C, D, E, F, G, H, T> extends Implementation8<A, B, C, D, E, F, G, H, T> {
add: (id: PropertyKey, g: Implementation8<A, B, C, D, E, F, G, H, T>) => boolean;
remove: (id: PropertyKey) => boolean;
export interface MultiFn7<A, B, C, D, E, F, G, T> extends Implementation7<A, B, C, D, E, F, G, T>, MultiFnBase<Implementation7<A, B, C, D, E, F, G, T>> {
}
export interface MultiFn8<A, B, C, D, E, F, G, H, T> extends Implementation8<A, B, C, D, E, F, G, H, T>, MultiFnBase<Implementation8<A, B, C, D, E, F, G, H, T>> {
}
export declare type AncestorDefs = IObjectOf<Iterable<PropertyKey>>;
/**

@@ -76,11 +68,11 @@ * Returns a new multi-dispatch function using the provided dispatcher.

*/
export declare function defmulti<T>(f: DispatchFn): MultiFn<T>;
export declare function defmulti<A, T>(f: DispatchFn1<A>): MultiFn1<A, T>;
export declare function defmulti<A, B, T>(f: DispatchFn2<A, B>): MultiFn2<A, B, T>;
export declare function defmulti<A, B, C, T>(f: DispatchFn3<A, B, C>): MultiFn3<A, B, C, T>;
export declare function defmulti<A, B, C, D, T>(f: DispatchFn4<A, B, C, D>): MultiFn4<A, B, C, D, T>;
export declare function defmulti<A, B, C, D, E, T>(f: DispatchFn5<A, B, C, D, E>): MultiFn5<A, B, C, D, E, T>;
export declare function defmulti<A, B, C, D, E, F, T>(f: DispatchFn6<A, B, C, D, E, F>): MultiFn6<A, B, C, D, E, F, T>;
export declare function defmulti<A, B, C, D, E, F, G, T>(f: DispatchFn7<A, B, C, D, E, F, G>): MultiFn7<A, B, C, D, E, F, G, T>;
export declare function defmulti<A, B, C, D, E, F, G, H, T>(f: DispatchFn8<A, B, C, D, E, F, G, H>): MultiFn8<A, B, C, D, E, F, G, H, T>;
export declare function defmulti<T>(f: DispatchFn, rels?: AncestorDefs): MultiFn<T>;
export declare function defmulti<A, T>(f: DispatchFn1<A>, rels?: AncestorDefs): MultiFn1<A, T>;
export declare function defmulti<A, B, T>(f: DispatchFn2<A, B>, rels?: AncestorDefs): MultiFn2<A, B, T>;
export declare function defmulti<A, B, C, T>(f: DispatchFn3<A, B, C>, rels?: AncestorDefs): MultiFn3<A, B, C, T>;
export declare function defmulti<A, B, C, D, T>(f: DispatchFn4<A, B, C, D>, rels?: AncestorDefs): MultiFn4<A, B, C, D, T>;
export declare function defmulti<A, B, C, D, E, T>(f: DispatchFn5<A, B, C, D, E>, rels?: AncestorDefs): MultiFn5<A, B, C, D, E, T>;
export declare function defmulti<A, B, C, D, E, F, T>(f: DispatchFn6<A, B, C, D, E, F>, rels?: AncestorDefs): MultiFn6<A, B, C, D, E, F, T>;
export declare function defmulti<A, B, C, D, E, F, G, T>(f: DispatchFn7<A, B, C, D, E, F, G>, rels?: AncestorDefs): MultiFn7<A, B, C, D, E, F, G, T>;
export declare function defmulti<A, B, C, D, E, F, G, H, T>(f: DispatchFn8<A, B, C, D, E, F, G, H>, rels?: AncestorDefs): MultiFn8<A, B, C, D, E, F, G, H, T>;
/**

@@ -87,0 +79,0 @@ * Returns a multi-dispatch function which delegates to one of the

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const illegal_arguments_1 = require("@thi.ng/errors/illegal-arguments");
const unsupported_1 = require("@thi.ng/errors/unsupported");
const illegal_arity_1 = require("@thi.ng/errors/illegal-arity");
exports.DEFAULT = Symbol();
function defmulti(f) {
function defmulti(f, ancestors) {
let impls = {};
let rels = ancestors ? makeRels(ancestors) : {};
let fn = (...args) => {
const id = f(...args);
const g = impls[id] || impls[exports.DEFAULT];
return g ? g(...args) : illegal_arguments_1.illegalArgs(`missing implementation for: "${id.toString()}"`);
const g = impls[id] || findImpl(impls, rels, id) || impls[exports.DEFAULT];
return g ? g(...args) : unsupported_1.unsupported(`missing implementation for: "${id.toString()}"`);
};

@@ -25,2 +26,10 @@ fn.add = (id, g) => {

};
fn.isa = (id, parent) => {
let val = rels[id];
!val && (rels[id] = val = new Set());
val.add(parent);
};
fn.rels = () => rels;
fn.parents = (id) => rels[id];
fn.ancestors = (id) => new Set(findAncestors([], rels, id));
return fn;

@@ -30,2 +39,30 @@ }

;
const findImpl = (impls, rels, id) => {
const parents = rels[id];
if (!parents)
return;
for (let p of parents) {
let impl = impls[p] || findImpl(impls, rels, p);
if (impl)
return impl;
}
};
const findAncestors = (acc, rels, id) => {
const parents = rels[id];
if (parents) {
for (let p of parents) {
acc.push(p);
findAncestors(acc, rels, p);
}
}
return acc;
};
const makeRels = (spec) => {
const rels = {};
for (let k in spec) {
const val = spec[k];
rels[k] = val instanceof Set ? val : new Set(val);
}
return rels;
};
/**

@@ -32,0 +69,0 @@ * Returns a multi-dispatch function which delegates to one of the

{
"name": "@thi.ng/defmulti",
"version": "0.4.1",
"version": "0.5.0",
"description": "Dynamically extensible multiple dispatch via user supplied dispatch function.",

@@ -41,3 +41,3 @@ "main": "./index.js",

},
"gitHead": "5bb513915cb3c533bd4278f6f365389b3664f4d1"
"gitHead": "673bf50ff571fc65bd984d1f83929bcc69a8b394"
}

@@ -14,10 +14,6 @@ # @thi.ng/defmulti

dispatch](https://en.wikipedia.org/wiki/Multiple_dispatch) via user
supplied dispatch function, with minimal overhead. Provides generics for
type checking up to 8 args, but generally works with any number of
arguments. Why "only" 8?
supplied dispatch function, with minimal overhead and support for
dispatch value inheritance hierarchies (more flexible and independent of
any actual JS type relationships).
> "If you have a procedure with ten parameters, you probably missed some."
>
> -- Alan Perlis
## Installation

@@ -34,3 +30,3 @@

## Usage examples
## API

@@ -56,3 +52,92 @@ ### defmulti

#### Dispatch value hierarchies
To avoid code duplication, dispatch values can be associated in
child-parent relationships and implementations only defined for some
ancestors. Iff no implementation exists for a concrete dispatch value,
`defmulti` first attempts to find an implementation for any ancestor
dispatch value before using the `DEFAULT` implementation.
These relationships can be defined via an additional (optional) object
arg to `defmulti` and/or dynamically extended via the `.isa(child,
parent)` call to the multi-function. Relationships can also be queried
via `.parents(id)` and `.ancestors(id)`.
Note: If multiple direct parents are defined for a dispatch value, then
it's currently undefined which implementation will be picked. If this
causes issues to people, parents could be implemented as sorted list
(each parent with weight) instead of Sets, but this will have perf
impact... please open an issue if you run into problems!
```ts
const foo = defmulti((x )=> x);
foo.isa(23, "odd");
foo.isa(42, "even");
foo.isa("odd", "number");
foo.isa("even", "number");
foo.parents(23); // Set { "odd" }
foo.ancestors(23); // Set { "odd", "number" }
foo.parents(1); // undefined
foo.ancestors(1); // Set { }
// add some implementations
foo.add("odd", (x) => `${x} is odd`);
foo.add("number", (x) => `${x} is a number`);
foo(23); // "23 is odd"
foo(42); // "42 is a number"
foo(1); // error (missing impl & no default)
```
Same example, but with relationships provided as argument to `defmulti`:
```ts
const foo = defmulti((x) => x, {
23: ["odd"],
42: ["even"],
"odd": ["number"],
"even": ["number"],
});
foo.rels();
// { "23": Set { "odd" },
// "42": Set { "even" },
// odd: Set { "number" },
// even: Set { "number" } }
```
### defmultiN
Returns a multi-dispatch function which delegates to one of the provided
implementations, based on the arity (number of args) when the function
is called. Internally uses `defmulti`, so new arities can be dynamically
added (or removed) at a later time. `defmultiN` also registers a
`DEFAULT` implementation which simply throws an `IllegalArityError` when
invoked.
**Note:** Unlike `defmulti` no argument type checking is supported,
however you can specify the return type for the generated function.
```ts
const foo = defmultiN<string>({
0: () => "zero",
1: (x) => `one: ${x}`,
3: (x, y, z) => `three: ${x}, ${y}, ${z}`
});
foo();
// zero
foo(23);
// one: 23
foo(1, 2, 3);
// three: 1, 2, 3
foo(1, 2);
// Error: illegal arity: 2
```
## Usage examples
```ts
import { defmulti, DEFAULT } from "@thi.ng/defmulti";

@@ -85,2 +170,3 @@

#### Dynamic dispatch: Simple S-expression interpreter

@@ -127,31 +213,4 @@

### defmultiN
Returns a multi-dispatch function which delegates to one of the provided
implementations, based on the arity (number of args) when the function
is called. Internally uses `defmulti`, so new arities can be dynamically
added (or removed) at a later time. `defmultiN` also registers a
`DEFAULT` implementation which simply throws an `IllegalArityError` when
invoked.
**Note:** Unlike `defmulti` no argument type checking is supported,
however you can specify the return type for the generated function.
```ts
const foo = defmultiN<string>({
0: () => "zero",
1: (x) => `one: ${x}`,
3: (x, y, z) => `three: ${x}, ${y}, ${z}`
});
foo();
// zero
foo(23);
// one: 23
foo(1, 2, 3);
// three: 1, 2, 3
foo(1, 2);
// Error: illegal arity: 2
```
## Authors

@@ -158,0 +217,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc