thaw 5.0.2 → 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 +102 -34
- package/dist/index.cjs +73 -0
- package/package.json +17 -16
- package/src/index.js +73 -0
- package/dist/index.js +0 -54
- package/src/index.mjs +0 -51
package/README.md
CHANGED
|
@@ -2,9 +2,17 @@ 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
|
-
* Node.js `>= 20.
|
|
15
|
+
* Node.js `>= 20.0.0`
|
|
8
16
|
|
|
9
17
|
## Installation
|
|
10
18
|
|
|
@@ -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
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
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;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
exports.after = after;
|
|
15
|
+
const afterReturning = (fn, advice) => {
|
|
16
|
+
return function (...args) {
|
|
17
|
+
return advice.call(this, fn.apply(this, args), ...args);
|
|
18
|
+
};
|
|
19
|
+
};
|
|
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;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
};
|
|
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;
|
|
46
|
+
const debounce = (fn, wait = 0) => {
|
|
47
|
+
let timer;
|
|
48
|
+
return function (...args) {
|
|
49
|
+
clearTimeout(timer);
|
|
50
|
+
timer = setTimeout(() => {
|
|
51
|
+
fn.apply(this, args);
|
|
52
|
+
}, wait);
|
|
53
|
+
};
|
|
54
|
+
};
|
|
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;
|
|
65
|
+
const throttle = (fn, wait = 0) => {
|
|
66
|
+
let timer;
|
|
67
|
+
return function (...args) {
|
|
68
|
+
timer ||= (fn.apply(this, args), setTimeout(() => {
|
|
69
|
+
timer = null;
|
|
70
|
+
}, wait));
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
exports.throttle = throttle;
|
package/package.json
CHANGED
|
@@ -1,29 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": {
|
|
3
|
-
"name": "Yehor Sergeenko",
|
|
4
3
|
"email": "yehor.sergeenko@gmail.com",
|
|
4
|
+
"name": "Yehor Sergeenko",
|
|
5
5
|
"url": "https://github.com/bricss"
|
|
6
6
|
},
|
|
7
7
|
"bugs": {
|
|
8
8
|
"url": "https://github.com/bricss/thaw/issues"
|
|
9
9
|
},
|
|
10
|
+
"description": "The narrow belt for AOP 🎀",
|
|
10
11
|
"devDependencies": {
|
|
11
|
-
"@babel/cli": "^7.28.
|
|
12
|
-
"@babel/core": "^7.
|
|
13
|
-
"@babel/
|
|
14
|
-
"@babel/preset-env": "^7.28.5",
|
|
12
|
+
"@babel/cli": "^7.28.6",
|
|
13
|
+
"@babel/core": "^7.29.0",
|
|
14
|
+
"@babel/preset-env": "^7.29.0",
|
|
15
15
|
"c8": "^10.1.3",
|
|
16
|
-
"eslint": "^
|
|
17
|
-
"eslint-config-ultra-refined": "^
|
|
16
|
+
"eslint": "^10.0.0",
|
|
17
|
+
"eslint-config-ultra-refined": "^4.0.1",
|
|
18
18
|
"mocha": "^11.7.5"
|
|
19
19
|
},
|
|
20
|
-
"description": "The narrow belt for AOP 🎀",
|
|
21
20
|
"engines": {
|
|
22
|
-
"node": ">=20.
|
|
21
|
+
"node": ">=20.0.0"
|
|
23
22
|
},
|
|
24
23
|
"exports": {
|
|
25
|
-
"import": "./src/index.
|
|
26
|
-
"require": "./dist/index.
|
|
24
|
+
"import": "./src/index.js",
|
|
25
|
+
"require": "./dist/index.cjs"
|
|
27
26
|
},
|
|
28
27
|
"files": [
|
|
29
28
|
"dist",
|
|
@@ -42,12 +41,14 @@
|
|
|
42
41
|
"url": "git+https://github.com/bricss/thaw.git"
|
|
43
42
|
},
|
|
44
43
|
"scripts": {
|
|
45
|
-
"build": "rm -rf dist && npx babel src -
|
|
46
|
-
"lint": "eslint",
|
|
47
|
-
"prepack": "npm run build",
|
|
44
|
+
"build": "rm -rf dist && npx babel src --out-dir dist --out-file-extension .cjs",
|
|
45
|
+
"lint": "eslint --concurrency=auto",
|
|
46
|
+
"prepack": "npm run build && sh misc.sh && npm run lint",
|
|
48
47
|
"pretest": "rm -rf coverage",
|
|
49
|
-
"test": "mocha
|
|
48
|
+
"test": "mocha",
|
|
49
|
+
"test:bail": "mocha --bail",
|
|
50
50
|
"test:cover": "c8 --include=src --reporter=lcov --reporter=text npm test"
|
|
51
51
|
},
|
|
52
|
-
"
|
|
52
|
+
"type": "module",
|
|
53
|
+
"version": "6.0.0"
|
|
53
54
|
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
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
|
+
};
|
package/dist/index.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.throttle = exports.debounce = exports.compose = exports.before = exports.around = exports.after = void 0;
|
|
7
|
-
const around = (fn, cb) => {
|
|
8
|
-
return (...args) => {
|
|
9
|
-
return cb(fn(cb(...args)));
|
|
10
|
-
};
|
|
11
|
-
};
|
|
12
|
-
exports.around = around;
|
|
13
|
-
const after = (fn, cb) => {
|
|
14
|
-
return (...args) => {
|
|
15
|
-
return cb(fn(...args));
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
exports.after = after;
|
|
19
|
-
const before = (fn, cb) => {
|
|
20
|
-
return (...args) => {
|
|
21
|
-
return fn(cb(...args));
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
exports.before = before;
|
|
25
|
-
const compose = (...fns) => {
|
|
26
|
-
return (...args) => {
|
|
27
|
-
let result = null;
|
|
28
|
-
for (let i = 0; i < fns.length; i++) {
|
|
29
|
-
result = fns[i](...(i ? [result] : args));
|
|
30
|
-
}
|
|
31
|
-
return result;
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
exports.compose = compose;
|
|
35
|
-
const debounce = (fn, wait = 0) => {
|
|
36
|
-
let tick;
|
|
37
|
-
return (...args) => {
|
|
38
|
-
clearTimeout(tick);
|
|
39
|
-
tick = setTimeout(() => {
|
|
40
|
-
fn(...args);
|
|
41
|
-
}, wait);
|
|
42
|
-
};
|
|
43
|
-
};
|
|
44
|
-
exports.debounce = debounce;
|
|
45
|
-
const throttle = (fn, wait = 0) => {
|
|
46
|
-
let tick;
|
|
47
|
-
return (...args) => {
|
|
48
|
-
tick = !tick && setTimeout(() => {
|
|
49
|
-
tick = clearTimeout(tick);
|
|
50
|
-
fn(...args);
|
|
51
|
-
}, wait);
|
|
52
|
-
};
|
|
53
|
-
};
|
|
54
|
-
exports.throttle = throttle;
|
package/src/index.mjs
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
export const around = (fn, cb) => {
|
|
2
|
-
return (...args) => {
|
|
3
|
-
return cb(fn(cb(...args)));
|
|
4
|
-
};
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export const after = (fn, cb) => {
|
|
8
|
-
return (...args) => {
|
|
9
|
-
return cb(fn(...args));
|
|
10
|
-
};
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export const before = (fn, cb) => {
|
|
14
|
-
return (...args) => {
|
|
15
|
-
return fn(cb(...args));
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export const compose = (...fns) => {
|
|
20
|
-
return (...args) => {
|
|
21
|
-
let result = null;
|
|
22
|
-
|
|
23
|
-
for (let i = 0; i < fns.length; i++) {
|
|
24
|
-
result = fns[i](...(i ? [result] : args));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return result;
|
|
28
|
-
};
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export const debounce = (fn, wait = 0) => {
|
|
32
|
-
let tick;
|
|
33
|
-
|
|
34
|
-
return (...args) => {
|
|
35
|
-
clearTimeout(tick);
|
|
36
|
-
tick = setTimeout(() => {
|
|
37
|
-
fn(...args);
|
|
38
|
-
}, wait);
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const throttle = (fn, wait = 0) => {
|
|
43
|
-
let tick;
|
|
44
|
-
|
|
45
|
-
return (...args) => {
|
|
46
|
-
tick = !tick && setTimeout(() => {
|
|
47
|
-
tick = clearTimeout(tick);
|
|
48
|
-
fn(...args);
|
|
49
|
-
}, wait);
|
|
50
|
-
};
|
|
51
|
-
};
|