patroon 1.1.2 → 1.2.0
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/README.md +10 -10
- package/README.mz +2 -2
- package/package.json +1 -1
- package/src/helpers.js +10 -0
- package/src/index.js +6 -3
- package/src/index.test.js +48 -14
- package/src/walkable.js +17 -4
package/README.md
CHANGED
|
@@ -518,12 +518,12 @@ const oneIsTwo = patroon(1, 2)
|
|
|
518
518
|
oneIsTwo(3)
|
|
519
519
|
```
|
|
520
520
|
```
|
|
521
|
-
|
|
522
|
-
/home/ant/projects/patroon/src/index.js:93
|
|
521
|
+
/home/ant/projects/patroon/src/index.js:96
|
|
523
522
|
throw error
|
|
524
523
|
^
|
|
525
524
|
|
|
526
525
|
NoMatchError: Not able to match any pattern for arguments
|
|
526
|
+
at /home/ant/projects/patroon/src/index.js:90:21
|
|
527
527
|
```
|
|
528
528
|
|
|
529
529
|
#### UnevenArgumentCountError
|
|
@@ -534,12 +534,12 @@ Another error that occurs is when the patroon function is not used correctly.
|
|
|
534
534
|
patroon(1)
|
|
535
535
|
```
|
|
536
536
|
```
|
|
537
|
-
/home/ant/projects/patroon/src/index.js:
|
|
537
|
+
/home/ant/projects/patroon/src/index.js:82
|
|
538
538
|
if (!isEven(list.length)) { throw new UnevenArgumentCountError('Patroon should have an even amount of arguments.') }
|
|
539
539
|
^
|
|
540
540
|
|
|
541
541
|
UnevenArgumentCountError: Patroon should have an even amount of arguments.
|
|
542
|
-
at patroon (/home/ant/projects/patroon/src/index.js:
|
|
542
|
+
at patroon (/home/ant/projects/patroon/src/index.js:82:37)
|
|
543
543
|
```
|
|
544
544
|
|
|
545
545
|
#### PatroonError
|
|
@@ -573,8 +573,8 @@ We also care about code coverage so we'll use [nyc][8] to generate a coverage
|
|
|
573
573
|
report.
|
|
574
574
|
|
|
575
575
|
```bash bash -eo pipefail
|
|
576
|
-
#
|
|
577
|
-
|
|
576
|
+
# Clean install dependencies.
|
|
577
|
+
npm ci &> /dev/null
|
|
578
578
|
|
|
579
579
|
# Run tests and generate a coverage report
|
|
580
580
|
npx nyc npm t | npx tap-nyc
|
|
@@ -583,7 +583,7 @@ npx nyc npm t | npx tap-nyc
|
|
|
583
583
|
npx nyc check-coverage
|
|
584
584
|
```
|
|
585
585
|
```
|
|
586
|
-
> patroon@1.
|
|
586
|
+
> patroon@1.2.0 test
|
|
587
587
|
> tape ./src/index.test.js
|
|
588
588
|
-------------|---------|----------|---------|---------|-------------------
|
|
589
589
|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
|
|
@@ -594,10 +594,10 @@ npx nyc check-coverage
|
|
|
594
594
|
walkable.js | 100 | 100 | 100 | 100 |
|
|
595
595
|
-------------|---------|----------|---------|---------|-------------------
|
|
596
596
|
|
|
597
|
-
total:
|
|
598
|
-
passing:
|
|
597
|
+
total: 28
|
|
598
|
+
passing: 28
|
|
599
599
|
|
|
600
|
-
duration:
|
|
600
|
+
duration: 8.8s
|
|
601
601
|
|
|
602
602
|
```
|
|
603
603
|
|
package/README.mz
CHANGED
|
@@ -442,8 +442,8 @@ We also care about code coverage so we'll use [nyc][8] to generate a coverage
|
|
|
442
442
|
report.
|
|
443
443
|
|
|
444
444
|
```bash bash -eo pipefail
|
|
445
|
-
#
|
|
446
|
-
|
|
445
|
+
# Clean install dependencies.
|
|
446
|
+
npm ci &> /dev/null
|
|
447
447
|
|
|
448
448
|
# Run tests and generate a coverage report
|
|
449
449
|
npx nyc npm t | npx tap-nyc
|
package/package.json
CHANGED
package/src/helpers.js
CHANGED
|
@@ -17,7 +17,17 @@ const T = () => true
|
|
|
17
17
|
const is = Ctor => instance => isDefined(instance) && (instance.constructor ===
|
|
18
18
|
Ctor || instance instanceof Ctor)
|
|
19
19
|
|
|
20
|
+
function isPrimitive (x) {
|
|
21
|
+
return x !== Object(x)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isEmpty (x) {
|
|
25
|
+
return !isPrimitive(x) && (Object.keys(x).length === 0)
|
|
26
|
+
}
|
|
27
|
+
|
|
20
28
|
module.exports = {
|
|
29
|
+
isPrimitive,
|
|
30
|
+
isEmpty,
|
|
21
31
|
isDefined,
|
|
22
32
|
always: x => () => x,
|
|
23
33
|
is,
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { mapLeaves, path, PathError } = require('./walkable')()
|
|
2
|
-
const { isFunction, equals, T, is, tryCatch, isEven, isNil, toPairs, always } = require('./helpers')
|
|
2
|
+
const { isFunction, equals, T, is, tryCatch, isEven, isNil, toPairs, always, isEmpty, isPrimitive } = require('./helpers')
|
|
3
3
|
const { inspect } = require('util')
|
|
4
4
|
|
|
5
5
|
const deprecated = (fn, message) => (...args) => {
|
|
@@ -44,6 +44,8 @@ const predicate = pattern => {
|
|
|
44
44
|
|
|
45
45
|
if (isFunction(value)) { return arg => value(path(pth, arg)) }
|
|
46
46
|
|
|
47
|
+
if (isEmpty(value)) { return arg => !isPrimitive(path(pth, arg)) }
|
|
48
|
+
|
|
47
49
|
return arg => equals(path(pth, arg), value)
|
|
48
50
|
}
|
|
49
51
|
|
|
@@ -87,8 +89,9 @@ const patroon = (...list) => {
|
|
|
87
89
|
if (isNil(found)) {
|
|
88
90
|
const error = new NoMatchError('Not able to match any pattern for arguments')
|
|
89
91
|
error.arguments = args
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
error.patterns = list
|
|
93
|
+
error.arguments_inspect = inspect(args)
|
|
94
|
+
error.patterns_inspect = inspect(list)
|
|
92
95
|
|
|
93
96
|
throw error
|
|
94
97
|
}
|
package/src/index.test.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const { test } = require('tape')
|
|
2
|
+
const { isNil } = require('./helpers')
|
|
2
3
|
const { check, gen } = require('tape-check')
|
|
4
|
+
const { version } = require('../package')
|
|
3
5
|
const {
|
|
4
6
|
reference,
|
|
5
7
|
instanceOf,
|
|
@@ -56,16 +58,12 @@ test('Matches always when pattern equals value', check(gen.any, (t, val) => {
|
|
|
56
58
|
}))
|
|
57
59
|
|
|
58
60
|
test('Matches none of the patterns and throws', t => {
|
|
59
|
-
|
|
61
|
+
t.plan(1)
|
|
62
|
+
t.throws(() =>
|
|
60
63
|
patroon(
|
|
61
64
|
1, () => t.fail(),
|
|
62
65
|
2, () => t.fail()
|
|
63
|
-
)(3)
|
|
64
|
-
t.fail()
|
|
65
|
-
} catch (e) {
|
|
66
|
-
t.ok(e instanceof NoMatchError)
|
|
67
|
-
t.end()
|
|
68
|
-
}
|
|
66
|
+
)(3), NoMatchError)
|
|
69
67
|
})
|
|
70
68
|
|
|
71
69
|
test('Does not match when a value does not exist', t => {
|
|
@@ -150,11 +148,10 @@ test('Matches always when pattern equals value', check(gen.any, (t, val) => {
|
|
|
150
148
|
t.end()
|
|
151
149
|
}))
|
|
152
150
|
|
|
153
|
-
test('Matches when arguments match multi pattern', check(gen.any, (t,
|
|
151
|
+
test('Matches always when arguments match multi pattern', check(gen.array(gen.any, {}), (t, args) => {
|
|
154
152
|
patroon(
|
|
155
|
-
multi(
|
|
156
|
-
|
|
157
|
-
)(1, 2, 3)
|
|
153
|
+
multi(...args), () => t.end()
|
|
154
|
+
)(...args)
|
|
158
155
|
}))
|
|
159
156
|
|
|
160
157
|
test('Deprecated functions', ts => {
|
|
@@ -172,21 +169,58 @@ test('Deprecated functions', ts => {
|
|
|
172
169
|
ts.end()
|
|
173
170
|
})
|
|
174
171
|
|
|
172
|
+
test('Returns primitive values', check(gen.primitive, (t, primitive) => {
|
|
173
|
+
t.equals(patroon(true, primitive)(true), primitive)
|
|
174
|
+
t.end()
|
|
175
|
+
}))
|
|
176
|
+
|
|
177
|
+
test(
|
|
178
|
+
'Does not match primitive with empty object or array',
|
|
179
|
+
check(gen.primitive, (t, primitive) => {
|
|
180
|
+
t.plan(2)
|
|
181
|
+
t.throws(() => patroon([], true)(primitive), NoMatchError)
|
|
182
|
+
t.throws(() => patroon({}, true)(primitive), NoMatchError)
|
|
183
|
+
}))
|
|
184
|
+
|
|
185
|
+
test('Matching on nil values', check(gen.any, v => !isNil(v), (t, any) => {
|
|
186
|
+
t.plan(2)
|
|
187
|
+
t.throws(() => patroon(any, true)(undefined), NoMatchError)
|
|
188
|
+
t.throws(() => patroon(any, true)(null), NoMatchError)
|
|
189
|
+
}))
|
|
190
|
+
|
|
175
191
|
// Circular reference
|
|
176
192
|
const circular = {}
|
|
177
193
|
circular.a = circular
|
|
178
194
|
|
|
179
|
-
test('
|
|
195
|
+
test('Allows recursive patterns', t => {
|
|
180
196
|
t.plan(1)
|
|
181
|
-
t.
|
|
197
|
+
t.ok(patroon(circular, true)(circular))
|
|
182
198
|
})
|
|
183
199
|
|
|
184
200
|
test('Throws and prints because path is not defined', t => {
|
|
185
201
|
t.plan(1)
|
|
186
|
-
t.throws(() => patroon({ b: _ }, true)(circular))
|
|
202
|
+
t.throws(() => patroon({ b: _ }, true)(circular), NoMatchError)
|
|
187
203
|
})
|
|
188
204
|
|
|
189
205
|
test('Does not throw when value is recursive', t => {
|
|
190
206
|
t.plan(1)
|
|
191
207
|
t.ok(patroon({ a: _ }, true)(circular))
|
|
192
208
|
})
|
|
209
|
+
|
|
210
|
+
test('Does not match on reference', t => {
|
|
211
|
+
t.plan(4)
|
|
212
|
+
t.ok(patroon({ a: {} }, true)({ a: {} }))
|
|
213
|
+
t.ok(patroon({ a: [] }, true)({ a: [] }))
|
|
214
|
+
t.ok(patroon({ a: [] }, true)({ a: {} }))
|
|
215
|
+
t.ok(patroon({ a: {} }, true)({ a: [] }))
|
|
216
|
+
t.end()
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
if (version.startsWith('2')) {
|
|
220
|
+
test('Deprecated functions in version 2', t => {
|
|
221
|
+
t.plan(3)
|
|
222
|
+
t.ok(isNil(require('./index').typed))
|
|
223
|
+
t.ok(isNil(require('./index').t))
|
|
224
|
+
t.ok(isNil(require('./index').ref))
|
|
225
|
+
})
|
|
226
|
+
}
|
package/src/walkable.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
const { isFunction, isNil } = require('./helpers')
|
|
1
|
+
const { isEmpty, isFunction, isNil } = require('./helpers')
|
|
2
2
|
|
|
3
3
|
function walk (config, transform, item, path = []) {
|
|
4
4
|
if (config.isLeafe(item)) { return transform(item, path) }
|
|
5
5
|
|
|
6
|
+
if (config.isCircular(item)) { return transform(item, path) }
|
|
7
|
+
|
|
6
8
|
return config.map((v, i) => walk(config, transform, v, [...path, i]), item)
|
|
7
9
|
}
|
|
8
10
|
|
|
@@ -24,8 +26,16 @@ function isObject (v) {
|
|
|
24
26
|
return typeof v === 'object' && v !== null
|
|
25
27
|
}
|
|
26
28
|
|
|
29
|
+
const isCircular = (visited = []) => x => {
|
|
30
|
+
const isCircular = visited.includes(x)
|
|
31
|
+
|
|
32
|
+
visited.push(x)
|
|
33
|
+
|
|
34
|
+
return isCircular
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
function isLeafe (x) {
|
|
28
|
-
return Number.isNaN(x) || isNil(x) || x instanceof RegExp || isFunction(x) || (!isObject(x) && !isArray(x))
|
|
38
|
+
return Number.isNaN(x) || isNil(x) || x instanceof RegExp || isFunction(x) || isEmpty(x) || (!isObject(x) && !isArray(x))
|
|
29
39
|
}
|
|
30
40
|
|
|
31
41
|
function mapLeaves (config, cb, item) {
|
|
@@ -42,7 +52,7 @@ function path (pth, v, errorData) {
|
|
|
42
52
|
|
|
43
53
|
const [key, ...rest] = pth
|
|
44
54
|
|
|
45
|
-
if (!(key in v)) {
|
|
55
|
+
if (isNil(v) || !(key in v)) {
|
|
46
56
|
const error = new PathError(
|
|
47
57
|
`Cannot read path ${pth}.`)
|
|
48
58
|
|
|
@@ -83,7 +93,10 @@ function walkable (config = {}) {
|
|
|
83
93
|
reduce,
|
|
84
94
|
mapLeaves
|
|
85
95
|
].reduce((api, fn) => {
|
|
86
|
-
api[fn.name] = fn
|
|
96
|
+
api[fn.name] = (...args) => fn({
|
|
97
|
+
isCircular: isCircular(),
|
|
98
|
+
...config
|
|
99
|
+
}, ...args)
|
|
87
100
|
|
|
88
101
|
return api
|
|
89
102
|
}, api)
|