UNPKG

3.15 kBPlain TextView Raw
1/*!
2 * Copyright (c) 2017-2018 by The Funfix Project Developers.
3 * Some rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18import { Constructor, Setoid, Monad } from "funland"
19
20/**
21 * Given a function, converts it into a method where `this` gets
22 * passed around as the last argument.
23 */
24export function convertToMethod(f: Function): Function {
25 return function (this: any) {
26 const args = Array.prototype.slice.call(arguments)
27 args.push(this)
28 return f.apply(undefined, args)
29 }
30}
31
32/**
33 * Given a constructor, searches for all Fantasy-Land compatible
34 * methods registered on its `prototype` and also registers them
35 * using Fantasy-Land compatible symbols.
36 *
37 * For example:
38 *
39 * ```typescript
40 * class Box<A> {
41 * constructor(public readonly value: A) {}
42 *
43 * // Setoid
44 * equals(that: Box<A>) {
45 * return that && this.value === that.value
46 * }
47 * // Functor
48 * map<B>(f: (a: A) => B): Box<B> {
49 * return new Box(f(this.value))
50 * }
51 * }
52 *
53 * // Registering Fantasy-Land compatible symbols
54 * fantasyLandRegister(Box)
55 * ```
56 *
57 * The above registration call would make `fantasy-land/equals` and
58 * `fantasy-land/functor` available on `Box.prototype`.
59 *
60 * @private
61 * @Hidden
62 */
63export function fantasyLandRegister<A>(
64 cls: Constructor<A>,
65 monad?: Monad<any>,
66 setoid?: Setoid<any>): void {
67
68 const c = cls as any
69 const p = c.prototype
70
71 const fl = "fantasy-land/"
72 const equals = "equals"
73 const flEquals = fl + equals
74 const map = "map"
75 const flMap = fl + map
76 const ap = "ap"
77 const flAp = fl + ap
78 const flOf = fl + "of"
79 const chain = "chain"
80 const flChain = fl + chain
81 const chainRec = "chainRec"
82 const flChainRec = fl + chainRec
83
84 // Setoid
85 if (p[equals]) {
86 p[flEquals] = p[equals]
87 } else {
88 /* istanbul ignore else */
89 if (setoid) p[flEquals] = convertToMethod(setoid.equals)
90 }
91 // Functor
92 if (p[map]) {
93 p[flMap] = p[map]
94 } else {
95 /* istanbul ignore else */
96 if (monad) p[flMap] = convertToMethod(monad.map)
97 }
98 // Apply
99 if (p[ap]) {
100 p[flAp] = p[ap]
101 } else {
102 /* istanbul ignore else */
103 if (monad) p[flAp] = convertToMethod(monad.ap)
104 }
105 // Applicative
106 if (c["pure"]) {
107 c[flOf] = c["pure"]
108 } else {
109 /* istanbul ignore else */
110 if (monad) c[flOf] = monad.of
111 }
112 // Chain
113 if (p[chain]) {
114 p[flChain] = p[chain]
115 } else {
116 /* istanbul ignore else */
117 if (monad) p[flChain] = convertToMethod(monad.chain)
118 }
119 // ChainRec
120 if (c[chainRec]) {
121 c[flChainRec] = c[chainRec]
122 } else {
123 /* istanbul ignore else */
124 if (monad) c[flChainRec] = monad.chainRec
125 }
126}