thaw 5.0.4 → 6.0.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 +101 -33
- package/dist/index.cjs +51 -32
- package/package.json +3 -4
- package/src/index.js +73 -51
package/README.md
CHANGED
|
@@ -2,6 +2,14 @@ The narrow belt for AOP 🎀
|
|
|
2
2
|
---
|
|
3
3
|
This package provides **narrow-trench** methods for aspect-oriented programming (AOP).
|
|
4
4
|
|
|
5
|
+
## Abstract
|
|
6
|
+
|
|
7
|
+
* Consistent advice pattern semantics 📐
|
|
8
|
+
* Deterministic behavior (tested with mocked timers) ⚖️
|
|
9
|
+
* Preserves `this` context 🔒
|
|
10
|
+
* Small, predictable behavior 🎯
|
|
11
|
+
* Zero dependencies 🗽
|
|
12
|
+
|
|
5
13
|
## Prerequisites
|
|
6
14
|
|
|
7
15
|
* Node.js `>= 20.0.0`
|
|
@@ -15,37 +23,97 @@ npm install thaw --save
|
|
|
15
23
|
### Usage
|
|
16
24
|
|
|
17
25
|
```javascript
|
|
18
|
-
import
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
26
|
+
import {
|
|
27
|
+
after,
|
|
28
|
+
afterReturning,
|
|
29
|
+
afterThrowing,
|
|
30
|
+
around,
|
|
31
|
+
before,
|
|
32
|
+
debounce,
|
|
33
|
+
pipe,
|
|
34
|
+
throttle,
|
|
35
|
+
} from 'thaw';
|
|
36
|
+
|
|
37
|
+
{
|
|
38
|
+
const fn = after(
|
|
39
|
+
(v) => v + 1,
|
|
40
|
+
(...args) => console.log('args passed to fn', args), // [ 1 ]
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
console.log('after', fn(1)); // 2
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
{
|
|
47
|
+
const fn = afterReturning(
|
|
48
|
+
(a, b) => a + b,
|
|
49
|
+
(result, ...args) => `${ result }-${ args }`,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
console.log('afterReturning', fn(2, 3)); // 5-2,3
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
{
|
|
56
|
+
const fn = afterThrowing(
|
|
57
|
+
() => { throw new Error('boom'); },
|
|
58
|
+
(err, ...args) => console.error('afterThrowing', `${ err.message }-${ args }`), // boom-2,3
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
fn(2, 3);
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.error('afterThrowing', err.message); // boom
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
{
|
|
69
|
+
const fn = around(
|
|
70
|
+
(v) => v + 1,
|
|
71
|
+
(proceed, ...args) => proceed() + args.at(0),
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
console.log('around', fn(1)); // 3
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
{
|
|
78
|
+
const fn = before(
|
|
79
|
+
(v) => v + 1,
|
|
80
|
+
(...args) => console.log('args passed to fn', args), // [ 1 ]
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
console.log('before', fn(1)); // 2
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
{
|
|
87
|
+
const fn = debounce((v) => {
|
|
88
|
+
console.log('debounce', v); // 3; after -> 200ms
|
|
89
|
+
}, 200);
|
|
90
|
+
|
|
91
|
+
fn(1);
|
|
92
|
+
fn(2);
|
|
93
|
+
fn(3);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
{
|
|
97
|
+
const fn = pipe(
|
|
98
|
+
(v) => v + 2,
|
|
99
|
+
(v) => v + 3,
|
|
100
|
+
(v) => v + 4,
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
console.log('pipe', fn(1)); // 10
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
{
|
|
107
|
+
const fn = throttle((v) => {
|
|
108
|
+
console.log('throttle', v); // 1; idle -> 200ms
|
|
109
|
+
}, 200);
|
|
110
|
+
|
|
111
|
+
fn(1);
|
|
112
|
+
fn(2);
|
|
113
|
+
fn(3);
|
|
114
|
+
}
|
|
51
115
|
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
For more details, please check tests in the repository.
|
package/dist/index.cjs
CHANGED
|
@@ -3,52 +3,71 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.throttle = exports.
|
|
7
|
-
const
|
|
8
|
-
return (...args)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
exports.around = around;
|
|
13
|
-
const after = (fn, cb) => {
|
|
14
|
-
return (...args) => {
|
|
15
|
-
return cb(fn(...args));
|
|
6
|
+
exports.throttle = exports.pipe = exports.debounce = exports.before = exports.around = exports.afterThrowing = exports.afterReturning = exports.after = void 0;
|
|
7
|
+
const after = (fn, advice) => {
|
|
8
|
+
return function (...args) {
|
|
9
|
+
const result = fn.apply(this, args);
|
|
10
|
+
advice.apply(this, args);
|
|
11
|
+
return result;
|
|
16
12
|
};
|
|
17
13
|
};
|
|
18
14
|
exports.after = after;
|
|
19
|
-
const
|
|
20
|
-
return (...args)
|
|
21
|
-
return fn(
|
|
15
|
+
const afterReturning = (fn, advice) => {
|
|
16
|
+
return function (...args) {
|
|
17
|
+
return advice.call(this, fn.apply(this, args), ...args);
|
|
22
18
|
};
|
|
23
19
|
};
|
|
24
|
-
exports.
|
|
25
|
-
const
|
|
26
|
-
return (...args)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
exports.afterReturning = afterReturning;
|
|
21
|
+
const afterThrowing = (fn, advice) => {
|
|
22
|
+
return function (...args) {
|
|
23
|
+
try {
|
|
24
|
+
return fn.apply(this, args);
|
|
25
|
+
} catch (err) {
|
|
26
|
+
advice.call(this, err, ...args);
|
|
27
|
+
throw err;
|
|
30
28
|
}
|
|
31
|
-
return result;
|
|
32
29
|
};
|
|
33
30
|
};
|
|
34
|
-
exports.
|
|
31
|
+
exports.afterThrowing = afterThrowing;
|
|
32
|
+
const around = (fn, advice) => {
|
|
33
|
+
return function (...args) {
|
|
34
|
+
const proceed = () => fn.apply(this, args);
|
|
35
|
+
return advice.call(this, proceed, ...args);
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
exports.around = around;
|
|
39
|
+
const before = (fn, advice) => {
|
|
40
|
+
return function (...args) {
|
|
41
|
+
advice.apply(this, args);
|
|
42
|
+
return fn.apply(this, args);
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
exports.before = before;
|
|
35
46
|
const debounce = (fn, wait = 0) => {
|
|
36
|
-
let
|
|
37
|
-
return (...args)
|
|
38
|
-
clearTimeout(
|
|
39
|
-
|
|
40
|
-
fn(
|
|
47
|
+
let timer;
|
|
48
|
+
return function (...args) {
|
|
49
|
+
clearTimeout(timer);
|
|
50
|
+
timer = setTimeout(() => {
|
|
51
|
+
fn.apply(this, args);
|
|
41
52
|
}, wait);
|
|
42
53
|
};
|
|
43
54
|
};
|
|
44
55
|
exports.debounce = debounce;
|
|
56
|
+
const pipe = (...fns) => {
|
|
57
|
+
if (fns.length === 0) {
|
|
58
|
+
return (...args) => args.length <= 1 ? args.at(0) : args;
|
|
59
|
+
}
|
|
60
|
+
return function (...args) {
|
|
61
|
+
return fns.reduce((acc, fn, idx) => idx ? fn.call(this, acc) : fn.apply(this, acc), args);
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
exports.pipe = pipe;
|
|
45
65
|
const throttle = (fn, wait = 0) => {
|
|
46
|
-
let
|
|
47
|
-
return (...args)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}, wait);
|
|
66
|
+
let timer;
|
|
67
|
+
return function (...args) {
|
|
68
|
+
timer ||= (fn.apply(this, args), setTimeout(() => {
|
|
69
|
+
timer = null;
|
|
70
|
+
}, wait));
|
|
52
71
|
};
|
|
53
72
|
};
|
|
54
73
|
exports.throttle = throttle;
|
package/package.json
CHANGED
|
@@ -11,11 +11,10 @@
|
|
|
11
11
|
"devDependencies": {
|
|
12
12
|
"@babel/cli": "^7.28.6",
|
|
13
13
|
"@babel/core": "^7.29.0",
|
|
14
|
-
"@babel/eslint-parser": "^7.28.6",
|
|
15
14
|
"@babel/preset-env": "^7.29.0",
|
|
16
15
|
"c8": "^10.1.3",
|
|
17
|
-
"eslint": "^
|
|
18
|
-
"eslint-config-ultra-refined": "^
|
|
16
|
+
"eslint": "^10.0.0",
|
|
17
|
+
"eslint-config-ultra-refined": "^4.0.1",
|
|
19
18
|
"mocha": "^11.7.5"
|
|
20
19
|
},
|
|
21
20
|
"engines": {
|
|
@@ -51,5 +50,5 @@
|
|
|
51
50
|
"test:cover": "c8 --include=src --reporter=lcov --reporter=text npm test"
|
|
52
51
|
},
|
|
53
52
|
"type": "module",
|
|
54
|
-
"version": "
|
|
53
|
+
"version": "6.0.0"
|
|
55
54
|
}
|
package/src/index.js
CHANGED
|
@@ -1,51 +1,73 @@
|
|
|
1
|
-
export const
|
|
2
|
-
return (...args)
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
};
|
|
1
|
+
export const after = (fn, advice) => {
|
|
2
|
+
return function (...args) {
|
|
3
|
+
const result = fn.apply(this, args);
|
|
4
|
+
|
|
5
|
+
advice.apply(this, args);
|
|
6
|
+
|
|
7
|
+
return result;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const afterReturning = (fn, advice) => {
|
|
12
|
+
return function (...args) {
|
|
13
|
+
return advice.call(this, fn.apply(this, args), ...args);
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const afterThrowing = (fn, advice) => {
|
|
18
|
+
return function (...args) {
|
|
19
|
+
try {
|
|
20
|
+
return fn.apply(this, args);
|
|
21
|
+
} catch (err) {
|
|
22
|
+
advice.call(this, err, ...args);
|
|
23
|
+
throw err;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const around = (fn, advice) => {
|
|
29
|
+
return function (...args) {
|
|
30
|
+
const proceed = () => fn.apply(this, args);
|
|
31
|
+
|
|
32
|
+
return advice.call(this, proceed, ...args);
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const before = (fn, advice) => {
|
|
37
|
+
return function (...args) {
|
|
38
|
+
advice.apply(this, args);
|
|
39
|
+
|
|
40
|
+
return fn.apply(this, args);
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const debounce = (fn, wait = 0) => {
|
|
45
|
+
let timer;
|
|
46
|
+
|
|
47
|
+
return function (...args) {
|
|
48
|
+
clearTimeout(timer);
|
|
49
|
+
timer = setTimeout(() => {
|
|
50
|
+
fn.apply(this, args);
|
|
51
|
+
}, wait);
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const pipe = (...fns) => {
|
|
56
|
+
if (fns.length === 0) {
|
|
57
|
+
return (...args) => args.length <= 1 ? args.at(0) : args;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return function (...args) {
|
|
61
|
+
return fns.reduce((acc, fn, idx) => idx ? fn.call(this, acc) : fn.apply(this, acc), args);
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const throttle = (fn, wait = 0) => {
|
|
66
|
+
let timer;
|
|
67
|
+
|
|
68
|
+
return function (...args) {
|
|
69
|
+
timer ||= (fn.apply(this, args), setTimeout(() => {
|
|
70
|
+
timer = null;
|
|
71
|
+
}, wait));
|
|
72
|
+
};
|
|
73
|
+
};
|