patroon 0.0.5 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.nycrc +6 -0
- package/README.md +115 -23
- package/README.mz +94 -15
- package/package.json +10 -2
- package/src/helpers.js +6 -4
- package/src/index.js +13 -5
- package/src/index.test.js +32 -0
- package/src/walkable.js +2 -2
package/.nycrc
ADDED
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# Patroon
|
|
2
2
|
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
3
6
|
Pattern matching in Javascript without additional syntax.
|
|
4
7
|
|
|
5
8
|
## Implementation
|
|
@@ -13,10 +16,41 @@ Pattern matching in Javascript without additional syntax.
|
|
|
13
16
|
3. [./src/helpers.js][4] - You might have noticed that both the patroon and
|
|
14
17
|
walkable modules have common helper functions.
|
|
15
18
|
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
[Patroon][9] is hosted on the NPM repository.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install patroon
|
|
25
|
+
```
|
|
26
|
+
|
|
16
27
|
## Specifications
|
|
17
28
|
|
|
18
29
|
Let's see what valid and less valid uses of patroon are.
|
|
19
30
|
|
|
31
|
+
### Primitives
|
|
32
|
+
|
|
33
|
+
The simplest thing one can do is match on a primitive.
|
|
34
|
+
|
|
35
|
+
```js ./tape-test
|
|
36
|
+
t.equal(patroon(
|
|
37
|
+
2, 3,
|
|
38
|
+
1, 2
|
|
39
|
+
)(1), 2)
|
|
40
|
+
t.end()
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Regular Expressions
|
|
44
|
+
|
|
45
|
+
Will check if a Regex matches the passed string using the `.test` method.
|
|
46
|
+
|
|
47
|
+
```js ./tape-test
|
|
48
|
+
patroon(
|
|
49
|
+
/^bunion/, fail,
|
|
50
|
+
/^banana/,end
|
|
51
|
+
)('banana tree')
|
|
52
|
+
```
|
|
53
|
+
|
|
20
54
|
### Arrays
|
|
21
55
|
|
|
22
56
|
A less intuitive case (at least initially) is the matching with an empty array.
|
|
@@ -31,7 +65,7 @@ patroon(
|
|
|
31
65
|
Notice that the empty array matches with `[1]`. This is because the empty array
|
|
32
66
|
is a subset of `[1]`.
|
|
33
67
|
|
|
34
|
-
|
|
68
|
+
You might as well write the following for readability sake:
|
|
35
69
|
|
|
36
70
|
```js ./tape-test
|
|
37
71
|
patroon(
|
|
@@ -39,8 +73,8 @@ patroon(
|
|
|
39
73
|
)([1])
|
|
40
74
|
```
|
|
41
75
|
|
|
42
|
-
Patroon
|
|
43
|
-
|
|
76
|
+
Patroon tries to determine if something is a constructor. No need to use typed
|
|
77
|
+
for this case.
|
|
44
78
|
|
|
45
79
|
```js ./tape-test
|
|
46
80
|
patroon(
|
|
@@ -49,7 +83,8 @@ patroon(
|
|
|
49
83
|
)([1])
|
|
50
84
|
```
|
|
51
85
|
|
|
52
|
-
If you wish to match on the reference of a constructor you can use the `ref`
|
|
86
|
+
If you wish to match on the reference of a constructor you can use the `ref`
|
|
87
|
+
helper.
|
|
53
88
|
|
|
54
89
|
```js ./tape-test
|
|
55
90
|
patroon(
|
|
@@ -76,6 +111,20 @@ t.equal(arrayMatch([2, 3]), 1)
|
|
|
76
111
|
t.end()
|
|
77
112
|
```
|
|
78
113
|
|
|
114
|
+
How to define default argument values:
|
|
115
|
+
|
|
116
|
+
```js ./tape-test
|
|
117
|
+
const count = patroon(
|
|
118
|
+
[_], ([, ...xs], n=0) => count(xs, n + 1),
|
|
119
|
+
[], (array, c=0) => c
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
t.equal(count([]), 0)
|
|
123
|
+
t.equal(count([1]), 1)
|
|
124
|
+
t.equal(count([1, 2]), 2)
|
|
125
|
+
t.end()
|
|
126
|
+
```
|
|
127
|
+
|
|
79
128
|
The array pattern assumes that the array has rest elements. It's a design
|
|
80
129
|
choice which avoids adding additional helpers with little to no downsides.
|
|
81
130
|
|
|
@@ -116,10 +165,10 @@ const toPairs = patroon(
|
|
|
116
165
|
_, (_, p = []) => p
|
|
117
166
|
)
|
|
118
167
|
|
|
119
|
-
t.
|
|
120
|
-
t.
|
|
121
|
-
t.
|
|
122
|
-
t.
|
|
168
|
+
t.deepEqual(toPairs([1]), [])
|
|
169
|
+
t.deepEqual(toPairs([1, 2]), [[1, 2]])
|
|
170
|
+
t.deepEqual(toPairs([1, 2, 3]), [[1, 2]])
|
|
171
|
+
t.deepEqual(toPairs([1, 2, 3, 4]), [[1, 2], [3, 4]])
|
|
123
172
|
t.end()
|
|
124
173
|
```
|
|
125
174
|
|
|
@@ -131,7 +180,7 @@ So that's arrays. What about objects.
|
|
|
131
180
|
|
|
132
181
|
### Objects
|
|
133
182
|
|
|
134
|
-
Just like an empty array; matching on an empty object can be written in
|
|
183
|
+
Just like an empty array; matching on an empty object can be written in three
|
|
135
184
|
ways.
|
|
136
185
|
|
|
137
186
|
```js ./tape-test
|
|
@@ -195,6 +244,7 @@ patroon(
|
|
|
195
244
|
```
|
|
196
245
|
|
|
197
246
|
An object of a certain type might also have values we would want to match on.
|
|
247
|
+
Here you do need to use the typed helper.
|
|
198
248
|
|
|
199
249
|
```js ./tape-test
|
|
200
250
|
patroon(
|
|
@@ -250,37 +300,72 @@ patroon(
|
|
|
250
300
|
)([{a: 42}])
|
|
251
301
|
```
|
|
252
302
|
|
|
303
|
+
### Custom Helpers
|
|
304
|
+
|
|
305
|
+
It is very easy to write your own helpers. All the builtin helpers are really
|
|
306
|
+
just predicates. Let's look at the source of one of these helpers, the simplest
|
|
307
|
+
one being the `_` helper.
|
|
308
|
+
|
|
309
|
+
```js
|
|
310
|
+
const _ = () => true
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Other more complex helpers like the typed helper are also predicates. See the
|
|
314
|
+
[./src/index.js][3] if you are interested in their implementation.
|
|
315
|
+
|
|
253
316
|
## Tests
|
|
254
317
|
|
|
255
318
|
Now for some additional edge cases and some generative testing.
|
|
256
319
|
[./src/index.test.js][5]
|
|
257
320
|
|
|
321
|
+
First make sure the dependencies are clean.
|
|
322
|
+
|
|
323
|
+
```bash bash &> /dev/null
|
|
324
|
+
npm i && npm prune
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
We also care about code coverage so we'll use [nyc][8] to generate a coverage
|
|
328
|
+
report.
|
|
329
|
+
|
|
258
330
|
```bash bash
|
|
259
|
-
npm
|
|
331
|
+
npx nyc npm t && npx nyc check-coverage
|
|
260
332
|
```
|
|
261
333
|
```
|
|
262
334
|
|
|
263
|
-
> patroon@0.
|
|
335
|
+
> patroon@0.1.2 test
|
|
264
336
|
> tape ./src/index.test.js
|
|
265
337
|
|
|
266
338
|
TAP version 13
|
|
339
|
+
# Matches on a simple primitive
|
|
340
|
+
ok 1 should be strictly equal
|
|
341
|
+
# Matches using a RegExp
|
|
342
|
+
# Match using reference
|
|
343
|
+
# Matches on type and value
|
|
267
344
|
# Matches always when pattern equals value
|
|
268
345
|
# Matches none of the patterns and throws
|
|
269
|
-
ok
|
|
346
|
+
ok 2 should be truthy
|
|
270
347
|
# Does not match when a value does not exist
|
|
271
348
|
# Throws when a typed does not receice a constructor
|
|
272
|
-
ok 2 should be truthy
|
|
273
|
-
# Throws in a predicate function
|
|
274
349
|
ok 3 should be truthy
|
|
275
|
-
# Throws
|
|
350
|
+
# Throws in a predicate function
|
|
276
351
|
ok 4 should be truthy
|
|
352
|
+
# Throws when an uneven amount of arguments are passed
|
|
353
|
+
ok 5 should be truthy
|
|
277
354
|
|
|
278
|
-
1..
|
|
279
|
-
# tests
|
|
280
|
-
# pass
|
|
355
|
+
1..5
|
|
356
|
+
# tests 5
|
|
357
|
+
# pass 5
|
|
281
358
|
|
|
282
359
|
# ok
|
|
283
360
|
|
|
361
|
+
-------------|---------|----------|---------|---------|-------------------
|
|
362
|
+
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
|
|
363
|
+
-------------|---------|----------|---------|---------|-------------------
|
|
364
|
+
All files | 100 | 100 | 100 | 100 |
|
|
365
|
+
helpers.js | 100 | 100 | 100 | 100 |
|
|
366
|
+
index.js | 100 | 100 | 100 | 100 |
|
|
367
|
+
walkable.js | 100 | 100 | 100 | 100 |
|
|
368
|
+
-------------|---------|----------|---------|---------|-------------------
|
|
284
369
|
```
|
|
285
370
|
|
|
286
371
|
## Formatting
|
|
@@ -291,12 +376,16 @@ Standard is good enough.
|
|
|
291
376
|
npx standard || npx standard --fix
|
|
292
377
|
```
|
|
293
378
|
|
|
379
|
+
## Stackoverflow
|
|
380
|
+
|
|
381
|
+
This project is mentioned in the following [stackoverflow question][7].
|
|
382
|
+
|
|
294
383
|
## Documentation
|
|
295
384
|
|
|
296
385
|
The README.md is generated using [markatzea][6].
|
|
297
386
|
|
|
298
|
-
```bash
|
|
299
|
-
|
|
387
|
+
```bash
|
|
388
|
+
markatzea README.mz > README.md
|
|
300
389
|
```
|
|
301
390
|
|
|
302
391
|
## Contribute
|
|
@@ -304,11 +393,11 @@ test "$RECUR" -eq 1 || RECUR=1 markatzea README.mz | tee README.md
|
|
|
304
393
|
You may contribute in whatever manner you see fit. Do try to be helpful and
|
|
305
394
|
polite. Some suggestions for contributions:
|
|
306
395
|
|
|
307
|
-
- [ ]
|
|
308
|
-
- [ ] Allow regular expressions for matching strings.
|
|
396
|
+
- [ ] A fitting logo.
|
|
309
397
|
- [ ] Find and report bugs and inconsistencies.
|
|
398
|
+
- [ ] Improve documentation.
|
|
399
|
+
- [ ] Prevent exceeding stack size by managing recursive patterns.
|
|
310
400
|
- [ ] Suggest API improvements in naming and functionality.
|
|
311
|
-
- [ ] A fitting logo.
|
|
312
401
|
|
|
313
402
|
[1]:https://en.wikipedia.org/wiki/Tree_traversal
|
|
314
403
|
[2]:https://github.com/bas080/patroon/blob/master/src/walkable.js
|
|
@@ -316,3 +405,6 @@ polite. Some suggestions for contributions:
|
|
|
316
405
|
[4]:https://github.com/bas080/patroon/blob/master/src/helpers.js
|
|
317
406
|
[5]:https://github.com/bas080/patroon/blob/master/src/index.test.js
|
|
318
407
|
[6]:https://github.com/bas080/markatzea
|
|
408
|
+
[7]:https://stackoverflow.com/questions/50452844/functional-programming-style-pattern-matching-in-javascript/67376827#67376827
|
|
409
|
+
[8]:https://github.com/istanbuljs/nyc
|
|
410
|
+
[9]:https://www.npmjs.com/package/patroon
|
package/README.mz
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# Patroon
|
|
2
2
|
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
3
6
|
Pattern matching in Javascript without additional syntax.
|
|
4
7
|
|
|
5
8
|
## Implementation
|
|
@@ -13,10 +16,41 @@ Pattern matching in Javascript without additional syntax.
|
|
|
13
16
|
3. [./src/helpers.js][4] - You might have noticed that both the patroon and
|
|
14
17
|
walkable modules have common helper functions.
|
|
15
18
|
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
[Patroon][9] is hosted on the NPM repository.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install patroon
|
|
25
|
+
```
|
|
26
|
+
|
|
16
27
|
## Specifications
|
|
17
28
|
|
|
18
29
|
Let's see what valid and less valid uses of patroon are.
|
|
19
30
|
|
|
31
|
+
### Primitives
|
|
32
|
+
|
|
33
|
+
The simplest thing one can do is match on a primitive.
|
|
34
|
+
|
|
35
|
+
```js ./tape-test
|
|
36
|
+
t.equal(patroon(
|
|
37
|
+
2, 3,
|
|
38
|
+
1, 2
|
|
39
|
+
)(1), 2)
|
|
40
|
+
t.end()
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Regular Expressions
|
|
44
|
+
|
|
45
|
+
Will check if a Regex matches the passed string using the `.test` method.
|
|
46
|
+
|
|
47
|
+
```js ./tape-test
|
|
48
|
+
patroon(
|
|
49
|
+
/^bunion/, fail,
|
|
50
|
+
/^banana/,end
|
|
51
|
+
)('banana tree')
|
|
52
|
+
```
|
|
53
|
+
|
|
20
54
|
### Arrays
|
|
21
55
|
|
|
22
56
|
A less intuitive case (at least initially) is the matching with an empty array.
|
|
@@ -31,7 +65,7 @@ patroon(
|
|
|
31
65
|
Notice that the empty array matches with `[1]`. This is because the empty array
|
|
32
66
|
is a subset of `[1]`.
|
|
33
67
|
|
|
34
|
-
|
|
68
|
+
You might as well write the following for readability sake:
|
|
35
69
|
|
|
36
70
|
```js ./tape-test
|
|
37
71
|
patroon(
|
|
@@ -39,8 +73,8 @@ patroon(
|
|
|
39
73
|
)([1])
|
|
40
74
|
```
|
|
41
75
|
|
|
42
|
-
Patroon
|
|
43
|
-
|
|
76
|
+
Patroon tries to determine if something is a constructor. No need to use typed
|
|
77
|
+
for this case.
|
|
44
78
|
|
|
45
79
|
```js ./tape-test
|
|
46
80
|
patroon(
|
|
@@ -49,7 +83,8 @@ patroon(
|
|
|
49
83
|
)([1])
|
|
50
84
|
```
|
|
51
85
|
|
|
52
|
-
If you wish to match on the reference of a constructor you can use the `ref`
|
|
86
|
+
If you wish to match on the reference of a constructor you can use the `ref`
|
|
87
|
+
helper.
|
|
53
88
|
|
|
54
89
|
```js ./tape-test
|
|
55
90
|
patroon(
|
|
@@ -76,6 +111,20 @@ t.equal(arrayMatch([2, 3]), 1)
|
|
|
76
111
|
t.end()
|
|
77
112
|
```
|
|
78
113
|
|
|
114
|
+
How to define default argument values:
|
|
115
|
+
|
|
116
|
+
```js ./tape-test
|
|
117
|
+
const count = patroon(
|
|
118
|
+
[_], ([, ...xs], n=0) => count(xs, n + 1),
|
|
119
|
+
[], (array, c=0) => c
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
t.equal(count([]), 0)
|
|
123
|
+
t.equal(count([1]), 1)
|
|
124
|
+
t.equal(count([1, 2]), 2)
|
|
125
|
+
t.end()
|
|
126
|
+
```
|
|
127
|
+
|
|
79
128
|
The array pattern assumes that the array has rest elements. It's a design
|
|
80
129
|
choice which avoids adding additional helpers with little to no downsides.
|
|
81
130
|
|
|
@@ -116,10 +165,10 @@ const toPairs = patroon(
|
|
|
116
165
|
_, (_, p = []) => p
|
|
117
166
|
)
|
|
118
167
|
|
|
119
|
-
t.
|
|
120
|
-
t.
|
|
121
|
-
t.
|
|
122
|
-
t.
|
|
168
|
+
t.deepEqual(toPairs([1]), [])
|
|
169
|
+
t.deepEqual(toPairs([1, 2]), [[1, 2]])
|
|
170
|
+
t.deepEqual(toPairs([1, 2, 3]), [[1, 2]])
|
|
171
|
+
t.deepEqual(toPairs([1, 2, 3, 4]), [[1, 2], [3, 4]])
|
|
123
172
|
t.end()
|
|
124
173
|
```
|
|
125
174
|
|
|
@@ -131,7 +180,7 @@ So that's arrays. What about objects.
|
|
|
131
180
|
|
|
132
181
|
### Objects
|
|
133
182
|
|
|
134
|
-
Just like an empty array; matching on an empty object can be written in
|
|
183
|
+
Just like an empty array; matching on an empty object can be written in three
|
|
135
184
|
ways.
|
|
136
185
|
|
|
137
186
|
```js ./tape-test
|
|
@@ -195,6 +244,7 @@ patroon(
|
|
|
195
244
|
```
|
|
196
245
|
|
|
197
246
|
An object of a certain type might also have values we would want to match on.
|
|
247
|
+
Here you do need to use the typed helper.
|
|
198
248
|
|
|
199
249
|
```js ./tape-test
|
|
200
250
|
patroon(
|
|
@@ -250,13 +300,35 @@ patroon(
|
|
|
250
300
|
)([{a: 42}])
|
|
251
301
|
```
|
|
252
302
|
|
|
303
|
+
### Custom Helpers
|
|
304
|
+
|
|
305
|
+
It is very easy to write your own helpers. All the builtin helpers are really
|
|
306
|
+
just predicates. Let's look at the source of one of these helpers, the simplest
|
|
307
|
+
one being the `_` helper.
|
|
308
|
+
|
|
309
|
+
```js
|
|
310
|
+
const _ = () => true
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Other more complex helpers like the typed helper are also predicates. See the
|
|
314
|
+
[./src/index.js][3] if you are interested in their implementation.
|
|
315
|
+
|
|
253
316
|
## Tests
|
|
254
317
|
|
|
255
318
|
Now for some additional edge cases and some generative testing.
|
|
256
319
|
[./src/index.test.js][5]
|
|
257
320
|
|
|
321
|
+
First make sure the dependencies are clean.
|
|
322
|
+
|
|
323
|
+
```bash bash &> /dev/null
|
|
324
|
+
npm i && npm prune
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
We also care about code coverage so we'll use [nyc][8] to generate a coverage
|
|
328
|
+
report.
|
|
329
|
+
|
|
258
330
|
```bash bash
|
|
259
|
-
npm
|
|
331
|
+
npx nyc npm t && npx nyc check-coverage
|
|
260
332
|
```
|
|
261
333
|
|
|
262
334
|
## Formatting
|
|
@@ -267,12 +339,16 @@ Standard is good enough.
|
|
|
267
339
|
npx standard || npx standard --fix
|
|
268
340
|
```
|
|
269
341
|
|
|
342
|
+
## Stackoverflow
|
|
343
|
+
|
|
344
|
+
This project is mentioned in the following [stackoverflow question][7].
|
|
345
|
+
|
|
270
346
|
## Documentation
|
|
271
347
|
|
|
272
348
|
The README.md is generated using [markatzea][6].
|
|
273
349
|
|
|
274
|
-
```bash
|
|
275
|
-
|
|
350
|
+
```bash
|
|
351
|
+
markatzea README.mz > README.md
|
|
276
352
|
```
|
|
277
353
|
|
|
278
354
|
## Contribute
|
|
@@ -280,11 +356,11 @@ test "$RECUR" -eq 1 || RECUR=1 markatzea README.mz | tee README.md
|
|
|
280
356
|
You may contribute in whatever manner you see fit. Do try to be helpful and
|
|
281
357
|
polite. Some suggestions for contributions:
|
|
282
358
|
|
|
283
|
-
- [ ]
|
|
284
|
-
- [ ] Allow regular expressions for matching strings.
|
|
359
|
+
- [ ] A fitting logo.
|
|
285
360
|
- [ ] Find and report bugs and inconsistencies.
|
|
361
|
+
- [ ] Improve documentation.
|
|
362
|
+
- [ ] Prevent exceeding stack size by managing recursive patterns.
|
|
286
363
|
- [ ] Suggest API improvements in naming and functionality.
|
|
287
|
-
- [ ] A fitting logo.
|
|
288
364
|
|
|
289
365
|
[1]:https://en.wikipedia.org/wiki/Tree_traversal
|
|
290
366
|
[2]:https://github.com/bas080/patroon/blob/master/src/walkable.js
|
|
@@ -292,3 +368,6 @@ polite. Some suggestions for contributions:
|
|
|
292
368
|
[4]:https://github.com/bas080/patroon/blob/master/src/helpers.js
|
|
293
369
|
[5]:https://github.com/bas080/patroon/blob/master/src/index.test.js
|
|
294
370
|
[6]:https://github.com/bas080/markatzea
|
|
371
|
+
[7]:https://stackoverflow.com/questions/50452844/functional-programming-style-pattern-matching-in-javascript/67376827#67376827
|
|
372
|
+
[8]:https://github.com/istanbuljs/nyc
|
|
373
|
+
[9]:https://www.npmjs.com/package/patroon
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patroon",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Pattern matching library",
|
|
5
5
|
"repository": "github:bas080/patroon",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -8,8 +8,16 @@
|
|
|
8
8
|
"test": "tape ./src/index.test.js"
|
|
9
9
|
},
|
|
10
10
|
"keywords": [
|
|
11
|
+
"array",
|
|
12
|
+
"condition",
|
|
13
|
+
"match",
|
|
14
|
+
"matching",
|
|
15
|
+
"object",
|
|
11
16
|
"pattern",
|
|
12
|
-
"matching"
|
|
17
|
+
"pattern-matching",
|
|
18
|
+
"predicate",
|
|
19
|
+
"types",
|
|
20
|
+
"string"
|
|
13
21
|
],
|
|
14
22
|
"author": "Bassim Huis",
|
|
15
23
|
"license": "GPLv3",
|
package/src/helpers.js
CHANGED
|
@@ -12,7 +12,12 @@ function isConstructor (func) {
|
|
|
12
12
|
return Boolean(func && typeof func === 'function' && func.prototype && func.prototype.constructor)
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
function isDefined (x) {
|
|
16
|
+
return x != null
|
|
17
|
+
}
|
|
18
|
+
|
|
15
19
|
module.exports = {
|
|
20
|
+
isDefined,
|
|
16
21
|
always: x => () => x,
|
|
17
22
|
isConstructor,
|
|
18
23
|
toPairs,
|
|
@@ -26,7 +31,7 @@ module.exports = {
|
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
return instance =>
|
|
29
|
-
instance.constructor === Ctor || instance instanceof Ctor
|
|
34
|
+
isDefined(instance) && (instance.constructor === Ctor || instance instanceof Ctor)
|
|
30
35
|
},
|
|
31
36
|
tryCatch (tryFn, catchFn) {
|
|
32
37
|
return (...args) => {
|
|
@@ -45,8 +50,5 @@ module.exports = {
|
|
|
45
50
|
},
|
|
46
51
|
isFunction (x) {
|
|
47
52
|
return typeof x === 'function'
|
|
48
|
-
},
|
|
49
|
-
isDefined (x) {
|
|
50
|
-
return x != null
|
|
51
53
|
}
|
|
52
54
|
}
|
package/src/index.js
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
const { mapLeaves, path, PathError } = require('./walkable')()
|
|
2
2
|
const { isConstructor, isFunction, equals, T, is, tryCatch, isEven, isNil, toPairs, always } = require('./helpers')
|
|
3
3
|
|
|
4
|
+
const isRegExp = is(RegExp)
|
|
5
|
+
|
|
4
6
|
const match = pattern => {
|
|
5
7
|
// TODO: also check if something is a constructor
|
|
6
8
|
|
|
9
|
+
const normalize = (value, pth) => {
|
|
10
|
+
if (isRegExp(value)) return arg => value.test(arg)
|
|
11
|
+
|
|
12
|
+
if (isConstructor(value)) { return typed(value) }
|
|
13
|
+
|
|
14
|
+
if (isFunction(value)) { return arg => value(path(pth, arg)) }
|
|
15
|
+
|
|
16
|
+
return arg => equals(path(pth, arg), value)
|
|
17
|
+
}
|
|
18
|
+
|
|
7
19
|
const patternPredicates = mapLeaves(
|
|
8
20
|
(value, pth) => tryCatch(
|
|
9
|
-
|
|
10
|
-
? typed(value)
|
|
11
|
-
: (isFunction(value)
|
|
12
|
-
? arg => value(path(pth, arg))
|
|
13
|
-
: arg => equals(path(pth, arg), value)),
|
|
21
|
+
normalize(value, pth),
|
|
14
22
|
e => {
|
|
15
23
|
if (e instanceof PathError) { return false }
|
|
16
24
|
|
package/src/index.test.js
CHANGED
|
@@ -1,12 +1,44 @@
|
|
|
1
1
|
const { test } = require('tape')
|
|
2
2
|
const { check, gen } = require('tape-check')
|
|
3
3
|
const {
|
|
4
|
+
ref,
|
|
4
5
|
patroon,
|
|
5
6
|
typed,
|
|
6
7
|
NoMatchError,
|
|
7
8
|
_
|
|
8
9
|
} = require('./index')
|
|
9
10
|
|
|
11
|
+
test('Matches on a simple primitive', t => {
|
|
12
|
+
t.equal(patroon(
|
|
13
|
+
1, 2,
|
|
14
|
+
2, 3
|
|
15
|
+
)(2), 3)
|
|
16
|
+
t.end()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('Matches using a RegExp', t => {
|
|
20
|
+
patroon(
|
|
21
|
+
/^bunion/, () => t.fail(),
|
|
22
|
+
/^banana/, () => t.end()
|
|
23
|
+
)('banana tree')
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('Match using reference', t => {
|
|
27
|
+
patroon(
|
|
28
|
+
1, () => t.fail(),
|
|
29
|
+
Number, () => t.fail(),
|
|
30
|
+
ref(Number), t.end()
|
|
31
|
+
)(Number)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('Matches on type and value', t => {
|
|
35
|
+
patroon(
|
|
36
|
+
typed(Error, { x: 20 }), () => t.fail(),
|
|
37
|
+
typed(Error, { x: 10 }), () => t.end(),
|
|
38
|
+
typed(Error), () => t.fail()
|
|
39
|
+
)(Object.assign(new Error(), { x: 10 }))
|
|
40
|
+
})
|
|
41
|
+
|
|
10
42
|
test('Matches always when pattern equals value', check(gen.any, (t, val) => {
|
|
11
43
|
patroon(val, () => t.end())(val)
|
|
12
44
|
}))
|
package/src/walkable.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { isFunction,
|
|
1
|
+
const { isFunction, isNil } = require('./helpers')
|
|
2
2
|
|
|
3
3
|
function walk (config, transform, item, path = []) {
|
|
4
4
|
if (config.isLeafe(item)) { return transform(item, path) }
|
|
@@ -25,7 +25,7 @@ function isObject (v) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
function isLeafe (x) {
|
|
28
|
-
return Number.isNaN(x) ||
|
|
28
|
+
return Number.isNaN(x) || isNil(x) || x instanceof RegExp || isFunction(x) || (!isObject(x) && !isArray(x))
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
function mapLeaves (config, cb, item) {
|