@keeex/utils 7.2.0 → 7.3.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/lib/bits/triggers/base.d.ts +30 -0
- package/lib/bits/triggers/base.js +171 -0
- package/lib/bits/triggers/debounce.d.ts +30 -0
- package/lib/bits/triggers/debounce.js +36 -0
- package/lib/bits/triggers/grenade.d.ts +33 -0
- package/lib/bits/triggers/grenade.js +37 -0
- package/lib/bits/triggers/types.d.ts +43 -0
- package/lib/bits/triggers/types.js +30 -0
- package/lib/promise.d.ts +20 -1
- package/lib/promise.js +46 -3
- package/lib/triggers.d.ts +21 -0
- package/lib/triggers.js +21 -0
- package/lib/units.js +6 -5
- package/package.json +1 -1
- package/web/bits/triggers/base.d.ts +30 -0
- package/web/bits/triggers/base.js +173 -0
- package/web/bits/triggers/debounce.d.ts +30 -0
- package/web/bits/triggers/debounce.js +36 -0
- package/web/bits/triggers/grenade.d.ts +33 -0
- package/web/bits/triggers/grenade.js +37 -0
- package/web/bits/triggers/types.d.ts +43 -0
- package/web/bits/triggers/types.js +30 -0
- package/web/promise.d.ts +20 -1
- package/web/promise.js +40 -3
- package/web/triggers.d.ts +21 -0
- package/web/triggers.js +21 -0
- package/web/units.js +6 -5
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { Logger } from "@keeex/log";
|
|
17
|
+
import * as types from "./types.js";
|
|
18
|
+
/**
|
|
19
|
+
* Base implementation for all triggers.
|
|
20
|
+
*/
|
|
21
|
+
export declare abstract class BaseTrigger implements types.Trigger {
|
|
22
|
+
#private;
|
|
23
|
+
constructor(handler: types.TriggerHandler, delayMs: number, logger?: Logger | string);
|
|
24
|
+
protected get state(): types.TriggerState;
|
|
25
|
+
protected set state(value: types.TriggerState);
|
|
26
|
+
protected get logger(): Logger;
|
|
27
|
+
abstract trigger(): void;
|
|
28
|
+
cancel: () => void;
|
|
29
|
+
stop: () => void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { createLogger } from "@keeex/log";
|
|
17
|
+
import { dropPromise } from "../../promise.js";
|
|
18
|
+
import * as types from "./types.js";
|
|
19
|
+
/**
|
|
20
|
+
* Base implementation for all triggers.
|
|
21
|
+
*/
|
|
22
|
+
export class BaseTrigger {
|
|
23
|
+
#state = types.TriggerState.inactive;
|
|
24
|
+
#timeout = null;
|
|
25
|
+
#delay;
|
|
26
|
+
#handler;
|
|
27
|
+
#logger;
|
|
28
|
+
constructor(handler, delayMs, logger) {
|
|
29
|
+
this.#handler = handler;
|
|
30
|
+
this.#delay = delayMs;
|
|
31
|
+
if (typeof logger === "string") {
|
|
32
|
+
this.#logger = createLogger({ tag: logger, numbered: true });
|
|
33
|
+
}
|
|
34
|
+
else if (logger) {
|
|
35
|
+
this.#logger = logger;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
this.#logger = createLogger({ tag: "PromiseTrigger", numbered: true });
|
|
39
|
+
}
|
|
40
|
+
this.#logger.debug(`Initialized with timer of ${delayMs}`);
|
|
41
|
+
}
|
|
42
|
+
get state() {
|
|
43
|
+
return this.#state;
|
|
44
|
+
}
|
|
45
|
+
set state(value) {
|
|
46
|
+
const oldState = this.#state;
|
|
47
|
+
this.#logger.debug(`State transition: ${oldState} → ${value}`);
|
|
48
|
+
this.#state = value;
|
|
49
|
+
switch (oldState) {
|
|
50
|
+
case types.TriggerState.inactive:
|
|
51
|
+
this.#stateFromInactive(value);
|
|
52
|
+
break;
|
|
53
|
+
case types.TriggerState.pending:
|
|
54
|
+
this.#stateFromPending(value);
|
|
55
|
+
break;
|
|
56
|
+
case types.TriggerState.running:
|
|
57
|
+
this.#stateFromRunning(value);
|
|
58
|
+
break;
|
|
59
|
+
case types.TriggerState.runningRetrigger:
|
|
60
|
+
this.#stateFromRunningRetrigger(value);
|
|
61
|
+
break;
|
|
62
|
+
case types.TriggerState.runningStop:
|
|
63
|
+
this.#stateFromRunningStop(value);
|
|
64
|
+
break;
|
|
65
|
+
case types.TriggerState.stop:
|
|
66
|
+
this.#stateFromStop(value);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
get logger() {
|
|
71
|
+
return this.#logger;
|
|
72
|
+
}
|
|
73
|
+
cancel = () => {
|
|
74
|
+
this.state = types.TriggerState.inactive;
|
|
75
|
+
};
|
|
76
|
+
stop = () => {
|
|
77
|
+
this.state = types.TriggerState.stop;
|
|
78
|
+
};
|
|
79
|
+
#stateFromInactive = (value) => {
|
|
80
|
+
switch (value) {
|
|
81
|
+
case types.TriggerState.pending:
|
|
82
|
+
this.#armTimeout();
|
|
83
|
+
break;
|
|
84
|
+
case types.TriggerState.running:
|
|
85
|
+
case types.TriggerState.runningRetrigger:
|
|
86
|
+
throw new Error("Cannot transition from inactive to running");
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
#stateFromPending = (value) => {
|
|
90
|
+
switch (value) {
|
|
91
|
+
case types.TriggerState.inactive:
|
|
92
|
+
this.#disarmTimeout();
|
|
93
|
+
break;
|
|
94
|
+
case types.TriggerState.running:
|
|
95
|
+
this.#timeout = null;
|
|
96
|
+
break;
|
|
97
|
+
case types.TriggerState.stop:
|
|
98
|
+
this.#disarmTimeout();
|
|
99
|
+
this.#runHandler();
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
#stateFromRunning = (value) => {
|
|
103
|
+
switch (value) {
|
|
104
|
+
case types.TriggerState.pending:
|
|
105
|
+
this.state = types.TriggerState.runningRetrigger;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
#stateFromRunningRetrigger = (value) => {
|
|
109
|
+
switch (value) {
|
|
110
|
+
case types.TriggerState.inactive:
|
|
111
|
+
this.state = types.TriggerState.pending;
|
|
112
|
+
break;
|
|
113
|
+
case types.TriggerState.pending:
|
|
114
|
+
this.state = types.TriggerState.runningRetrigger;
|
|
115
|
+
break;
|
|
116
|
+
case types.TriggerState.running:
|
|
117
|
+
throw new Error("Cannot transition from retrigger to running");
|
|
118
|
+
case types.TriggerState.stop:
|
|
119
|
+
this.#runHandler();
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
#stateFromRunningStop = (value) => {
|
|
123
|
+
switch (value) {
|
|
124
|
+
case types.TriggerState.inactive:
|
|
125
|
+
this.state = types.TriggerState.stop;
|
|
126
|
+
break;
|
|
127
|
+
case types.TriggerState.pending:
|
|
128
|
+
case types.TriggerState.running:
|
|
129
|
+
case types.TriggerState.runningRetrigger:
|
|
130
|
+
case types.TriggerState.runningStop:
|
|
131
|
+
throw new Error("Invalid state transition from runningStop");
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
#stateFromStop = (value) => {
|
|
135
|
+
switch (value) {
|
|
136
|
+
case types.TriggerState.inactive:
|
|
137
|
+
case types.TriggerState.pending:
|
|
138
|
+
case types.TriggerState.runningRetrigger:
|
|
139
|
+
this.state = types.TriggerState.stop;
|
|
140
|
+
break;
|
|
141
|
+
case types.TriggerState.running:
|
|
142
|
+
this.state = types.TriggerState.runningStop;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
#armTimeout = () => {
|
|
147
|
+
this.#disarmTimeout();
|
|
148
|
+
this.#logger.debug("Arming timeout");
|
|
149
|
+
this.#timeout = setTimeout(this.#runHandler, this.#delay);
|
|
150
|
+
};
|
|
151
|
+
#disarmTimeout = () => {
|
|
152
|
+
if (this.#timeout === null)
|
|
153
|
+
return;
|
|
154
|
+
this.#logger.debug("Disarming previous timeout");
|
|
155
|
+
clearTimeout(this.#timeout);
|
|
156
|
+
this.#timeout = null;
|
|
157
|
+
};
|
|
158
|
+
#runHandler = () => {
|
|
159
|
+
this.#logger.debug("Running handler");
|
|
160
|
+
this.state = types.TriggerState.running;
|
|
161
|
+
dropPromise(this.#runHandlerPromise, this.#logger);
|
|
162
|
+
};
|
|
163
|
+
#runHandlerPromise = async () => {
|
|
164
|
+
try {
|
|
165
|
+
await this.#handler();
|
|
166
|
+
}
|
|
167
|
+
finally {
|
|
168
|
+
this.state = types.TriggerState.inactive;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { Logger } from "@keeex/log";
|
|
17
|
+
import { BaseTrigger } from "./base.js";
|
|
18
|
+
import * as types from "./types.js";
|
|
19
|
+
/**
|
|
20
|
+
* Debouncing trigger.
|
|
21
|
+
*
|
|
22
|
+
* Each time the trigger is triggered, the timer rearms itself, delaying the callback ever more.
|
|
23
|
+
* Once there is no trigger for the duration of the trigger, the callback is finally called.
|
|
24
|
+
*
|
|
25
|
+
* Useful for debouncing.
|
|
26
|
+
*/
|
|
27
|
+
export declare class DebounceTrigger extends BaseTrigger {
|
|
28
|
+
constructor(handler: types.TriggerHandler, delayMs: number, logger?: Logger | string);
|
|
29
|
+
trigger: () => void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { BaseTrigger } from "./base.js";
|
|
17
|
+
import * as types from "./types.js";
|
|
18
|
+
/**
|
|
19
|
+
* Debouncing trigger.
|
|
20
|
+
*
|
|
21
|
+
* Each time the trigger is triggered, the timer rearms itself, delaying the callback ever more.
|
|
22
|
+
* Once there is no trigger for the duration of the trigger, the callback is finally called.
|
|
23
|
+
*
|
|
24
|
+
* Useful for debouncing.
|
|
25
|
+
*/
|
|
26
|
+
export class DebounceTrigger extends BaseTrigger {
|
|
27
|
+
constructor(handler, delayMs, logger = "DebounceTrigger") {
|
|
28
|
+
super(handler, delayMs, logger);
|
|
29
|
+
}
|
|
30
|
+
trigger = () => {
|
|
31
|
+
if (this.state === types.TriggerState.pending) {
|
|
32
|
+
this.state = types.TriggerState.inactive;
|
|
33
|
+
}
|
|
34
|
+
this.state = types.TriggerState.pending;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { Logger } from "@keeex/log";
|
|
17
|
+
import { BaseTrigger } from "./base.js";
|
|
18
|
+
import * as types from "./types.js";
|
|
19
|
+
/**
|
|
20
|
+
* Trigger that *will* fire its event after the time is elapsed, no matter how many times it is
|
|
21
|
+
* triggered afterward.
|
|
22
|
+
*
|
|
23
|
+
* After a call to `trigger()`, the timer is started.
|
|
24
|
+
* When it runs out, the even function is called.
|
|
25
|
+
* Multiple calls to `trigger()` will not delay the call, and they will not cause additional calls
|
|
26
|
+
* to occur.
|
|
27
|
+
* Calling `trigger()` while the callback is running will reschedule a call *after* the callback
|
|
28
|
+
* completes.
|
|
29
|
+
*/
|
|
30
|
+
export declare class GrenadeTrigger extends BaseTrigger {
|
|
31
|
+
constructor(handler: types.TriggerHandler, delayMs: number, logger?: Logger | string);
|
|
32
|
+
trigger: () => void;
|
|
33
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { BaseTrigger } from "./base.js";
|
|
17
|
+
import * as types from "./types.js";
|
|
18
|
+
/**
|
|
19
|
+
* Trigger that *will* fire its event after the time is elapsed, no matter how many times it is
|
|
20
|
+
* triggered afterward.
|
|
21
|
+
*
|
|
22
|
+
* After a call to `trigger()`, the timer is started.
|
|
23
|
+
* When it runs out, the even function is called.
|
|
24
|
+
* Multiple calls to `trigger()` will not delay the call, and they will not cause additional calls
|
|
25
|
+
* to occur.
|
|
26
|
+
* Calling `trigger()` while the callback is running will reschedule a call *after* the callback
|
|
27
|
+
* completes.
|
|
28
|
+
*/
|
|
29
|
+
export class GrenadeTrigger extends BaseTrigger {
|
|
30
|
+
constructor(handler, delayMs, logger = "GrenadeTrigger") {
|
|
31
|
+
super(handler, delayMs, logger);
|
|
32
|
+
}
|
|
33
|
+
trigger = () => {
|
|
34
|
+
this.logger.debug("Triggered");
|
|
35
|
+
this.state = types.TriggerState.pending;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { Awaitable } from "../../types/types.js";
|
|
17
|
+
export type TriggerHandler = () => Awaitable<void>;
|
|
18
|
+
export declare enum TriggerState {
|
|
19
|
+
/** Trigger was not triggered */
|
|
20
|
+
inactive = "inactive",
|
|
21
|
+
/** Trigger was triggered, fuse timer is counting down */
|
|
22
|
+
pending = "pending",
|
|
23
|
+
/** Trigger was triggered and timer expired, the handler is running */
|
|
24
|
+
running = "running",
|
|
25
|
+
/** Handler is running, and trigger was called again */
|
|
26
|
+
runningRetrigger = "runningTrigger",
|
|
27
|
+
/** Last run after stop */
|
|
28
|
+
runningStop = "runningStop",
|
|
29
|
+
/** Handler is killed, will never run except for currently triggered call */
|
|
30
|
+
stop = "stop"
|
|
31
|
+
}
|
|
32
|
+
/** Generic interface for delayed triggers */
|
|
33
|
+
export interface Trigger {
|
|
34
|
+
/** Call when the trigger should start (or restart, depending on the implementation) */
|
|
35
|
+
trigger: () => void;
|
|
36
|
+
/** Call when the trigger should be canceled */
|
|
37
|
+
cancel: () => void;
|
|
38
|
+
/**
|
|
39
|
+
* Call when the trigger should stop (it can't be triggered again).
|
|
40
|
+
* If there is an execution pending, it is run immediately.
|
|
41
|
+
*/
|
|
42
|
+
stop: () => void;
|
|
43
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
export var TriggerState;
|
|
17
|
+
(function (TriggerState) {
|
|
18
|
+
/** Trigger was not triggered */
|
|
19
|
+
TriggerState["inactive"] = "inactive";
|
|
20
|
+
/** Trigger was triggered, fuse timer is counting down */
|
|
21
|
+
TriggerState["pending"] = "pending";
|
|
22
|
+
/** Trigger was triggered and timer expired, the handler is running */
|
|
23
|
+
TriggerState["running"] = "running";
|
|
24
|
+
/** Handler is running, and trigger was called again */
|
|
25
|
+
TriggerState["runningRetrigger"] = "runningTrigger";
|
|
26
|
+
/** Last run after stop */
|
|
27
|
+
TriggerState["runningStop"] = "runningStop";
|
|
28
|
+
/** Handler is killed, will never run except for currently triggered call */
|
|
29
|
+
TriggerState["stop"] = "stop";
|
|
30
|
+
})(TriggerState || (TriggerState = {}));
|
package/lib/promise.d.ts
CHANGED
|
@@ -36,10 +36,29 @@ export type PromiseFunc<T> = () => Promise<T | void>;
|
|
|
36
36
|
*/
|
|
37
37
|
export declare const firstTruthy: <T>(promiseFuncs: Array<PromiseFunc<T>>) => Promise<T>;
|
|
38
38
|
type AwaitableFn<T> = () => Awaitable<T>;
|
|
39
|
+
type ErrorHandler = boolean | ((e: Error) => void) | {
|
|
40
|
+
error: (e: unknown) => void;
|
|
41
|
+
};
|
|
39
42
|
/**
|
|
40
43
|
* Drop a promise and silence any exception.
|
|
41
44
|
*
|
|
42
45
|
* This is to be used *only* on dropped promises to explicitly silence any warning.
|
|
46
|
+
*
|
|
47
|
+
* @param errorHandler - How to handle rejection
|
|
48
|
+
* If not provided or true, an error message is printed on the error output.
|
|
49
|
+
* If false, the error is silently ignored.
|
|
50
|
+
* If a function is provided, it is called with an Error object.
|
|
51
|
+
* If an object with an `error()` function is provided, this error function is called.
|
|
52
|
+
*/
|
|
53
|
+
export declare const dropPromise: <T>(promise: Awaitable<T> | AwaitableFn<T>, errorHandler?: ErrorHandler) => void;
|
|
54
|
+
/**
|
|
55
|
+
* Wait for a promise to complete, but ignore rejection.
|
|
56
|
+
|
|
57
|
+
* @param errorHandler - How to handle rejection
|
|
58
|
+
* If not provided or false, the error is silently ignored.
|
|
59
|
+
* If true, an error message is printed on the error output.
|
|
60
|
+
* If a function is provided, it is called with an Error object.
|
|
61
|
+
* If an object with an `error()` function is provided, this error function is called.
|
|
43
62
|
*/
|
|
44
|
-
export declare const
|
|
63
|
+
export declare const ignorePromise: <T>(promise: Awaitable<T> | AwaitableFn<T>, errorHandler?: ErrorHandler) => Promise<void>;
|
|
45
64
|
export {};
|
package/lib/promise.js
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
*
|
|
15
15
|
*/
|
|
16
16
|
/* eslint-env node */
|
|
17
|
+
import * as log from "@keeex/log";
|
|
18
|
+
import { asError } from "./error.js";
|
|
17
19
|
import { timeConvert } from "./units.js";
|
|
18
20
|
/**
|
|
19
21
|
* Create a promise that resolves after a given delay.
|
|
@@ -67,18 +69,59 @@ export const firstTruthy = async (promiseFuncs) => {
|
|
|
67
69
|
}
|
|
68
70
|
throw new Error("No result");
|
|
69
71
|
};
|
|
72
|
+
const logger = log.createLogger("dropPromise");
|
|
73
|
+
const handleError = (handler, outputDefault, error) => {
|
|
74
|
+
if (handler === undefined) {
|
|
75
|
+
if (outputDefault)
|
|
76
|
+
logger.error("Dropped promise rejected:", error);
|
|
77
|
+
}
|
|
78
|
+
else if (handler === true) {
|
|
79
|
+
logger.error("Dropped promise rejected:", error);
|
|
80
|
+
}
|
|
81
|
+
else if (typeof handler === "function") {
|
|
82
|
+
handler(asError(error));
|
|
83
|
+
}
|
|
84
|
+
else if (handler !== false) {
|
|
85
|
+
handler.error(error);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
70
88
|
/**
|
|
71
89
|
* Drop a promise and silence any exception.
|
|
72
90
|
*
|
|
73
91
|
* This is to be used *only* on dropped promises to explicitly silence any warning.
|
|
92
|
+
*
|
|
93
|
+
* @param errorHandler - How to handle rejection
|
|
94
|
+
* If not provided or true, an error message is printed on the error output.
|
|
95
|
+
* If false, the error is silently ignored.
|
|
96
|
+
* If a function is provided, it is called with an Error object.
|
|
97
|
+
* If an object with an `error()` function is provided, this error function is called.
|
|
74
98
|
*/
|
|
75
|
-
export const dropPromise = (promise) => {
|
|
99
|
+
export const dropPromise = (promise, errorHandler) => {
|
|
76
100
|
if (typeof promise === "function") {
|
|
77
101
|
dropPromise(promise());
|
|
78
102
|
return;
|
|
79
103
|
}
|
|
80
104
|
if (promise instanceof Promise) {
|
|
81
|
-
// eslint-disable-next-line
|
|
82
|
-
promise.catch(() =>
|
|
105
|
+
// eslint-disable-next-line promise/prefer-await-to-then
|
|
106
|
+
promise.catch((e) => handleError(errorHandler, true, e));
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Wait for a promise to complete, but ignore rejection.
|
|
111
|
+
|
|
112
|
+
* @param errorHandler - How to handle rejection
|
|
113
|
+
* If not provided or false, the error is silently ignored.
|
|
114
|
+
* If true, an error message is printed on the error output.
|
|
115
|
+
* If a function is provided, it is called with an Error object.
|
|
116
|
+
* If an object with an `error()` function is provided, this error function is called.
|
|
117
|
+
*/
|
|
118
|
+
export const ignorePromise = async (promise, errorHandler) => {
|
|
119
|
+
try {
|
|
120
|
+
if (typeof promise === "function")
|
|
121
|
+
return await ignorePromise(promise());
|
|
122
|
+
await promise;
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
handleError(errorHandler, false, e);
|
|
83
126
|
}
|
|
84
127
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { Logger } from "@keeex/log";
|
|
17
|
+
import { Trigger, TriggerHandler } from "./bits/triggers/types.js";
|
|
18
|
+
/** Return a simple trigger that is run after the initial delay is passed after a trigger call */
|
|
19
|
+
export declare const simpleTrigger: (handler: TriggerHandler, delayMs: number, logger?: Logger) => Trigger;
|
|
20
|
+
/** Return a debouncing trigger that will rearm as long as it is triggered during the grace delay */
|
|
21
|
+
export declare const debouncingTrigger: (handler: TriggerHandler, delayMs: number, logger?: Logger) => Trigger;
|
package/lib/triggers.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { DebounceTrigger } from "./bits/triggers/debounce.js";
|
|
17
|
+
import { GrenadeTrigger } from "./bits/triggers/grenade.js";
|
|
18
|
+
/** Return a simple trigger that is run after the initial delay is passed after a trigger call */
|
|
19
|
+
export const simpleTrigger = (handler, delayMs, logger) => new GrenadeTrigger(handler, delayMs, logger);
|
|
20
|
+
/** Return a debouncing trigger that will rearm as long as it is triggered during the grace delay */
|
|
21
|
+
export const debouncingTrigger = (handler, delayMs, logger) => new DebounceTrigger(handler, delayMs, logger);
|
package/lib/units.js
CHANGED
|
@@ -92,8 +92,8 @@ const convertUnit = (unitDescription, fromUnit, toUnit) => {
|
|
|
92
92
|
}
|
|
93
93
|
return { from, to };
|
|
94
94
|
};
|
|
95
|
-
const regexBefore = /^(?<unit>[^\d]+)\d
|
|
96
|
-
const regexAfter =
|
|
95
|
+
const regexBefore = /^(?<unit>[^\d,.]+)(?:(?:\d+)|(?:\d*[.,]\d+)|(?:\d+[.,]\d*))$/u;
|
|
96
|
+
const regexAfter = /^(?:(?:\d+)|(?:\d*[.,]\d+)|(?:\d+[.,]\d*))(?<unit>[^\d,.]+)$/u;
|
|
97
97
|
/** Get the unit text from an input value */
|
|
98
98
|
const getUnitFromValue = (value, unitDesc) => {
|
|
99
99
|
if (typeof value !== "string")
|
|
@@ -105,12 +105,13 @@ const getUnitFromValue = (value, unitDesc) => {
|
|
|
105
105
|
const unit = res.groups.unit;
|
|
106
106
|
return unit.trim();
|
|
107
107
|
};
|
|
108
|
-
const
|
|
108
|
+
const regexFloatValue = /^(?:[^\d,.]*)(?<value>(?:\d+)|(?:\d*[.,]\d+)|(?:\d+[.,]\d*))(?:[^\d,.]*)$/u;
|
|
109
|
+
const regexIntOnlyValue = /^(?:[^\d,.]*)(?<value>\d+)(?:[^\d,.]*)$/u;
|
|
109
110
|
/** Get the numeric value, stripping units */
|
|
110
111
|
const getNumberValue = (value) => {
|
|
111
112
|
if (typeof value === "number")
|
|
112
113
|
return value;
|
|
113
|
-
const res =
|
|
114
|
+
const res = regexFloatValue.exec(value);
|
|
114
115
|
if (!res?.groups)
|
|
115
116
|
throw new Error(`Missing value (${value})`);
|
|
116
117
|
return parseFloat(res.groups.value);
|
|
@@ -121,7 +122,7 @@ const getBigintValue = (value) => {
|
|
|
121
122
|
return value;
|
|
122
123
|
if (typeof value === "number")
|
|
123
124
|
return BigInt(value);
|
|
124
|
-
const res =
|
|
125
|
+
const res = regexIntOnlyValue.exec(value);
|
|
125
126
|
if (!res?.groups)
|
|
126
127
|
throw new Error(`Missing value (${value})`);
|
|
127
128
|
return BigInt(res.groups.value);
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@keeex/utils","version":"7.
|
|
1
|
+
{"name":"@keeex/utils","version":"7.3.0","description":"Various utility functions for pure JavaScript","scripts":{},"author":"KeeeX SAS","contributors":[{"name":"Gabriel Paul \"Cley Faye\" Risterucci","email":"gabriel@keeex.net"}],"homepage":"https://keeex.me/oss","keywords":["utility"],"type":"module","license":"MIT","dependencies":{"@keeex/bubble_babble":"^3.0.1","@keeex/log":"^1.7.1","base64-arraybuffer":"^1.0.2","cron-parser":"^5.3.0","ms":"^2.1.3","text-encoding-shim":"^1.0.5"},"exports":{"./array.js":{"node":"./lib/array.js","browser":"./web/array.js","react-native":"./web/array.js","default":"./lib/array.js"},"./arraybuffer.js":{"node":"./lib/arraybuffer.js","browser":"./web/arraybuffer.js","react-native":"./web/arraybuffer.js","default":"./lib/arraybuffer.js"},"./async/asynctrigger.js":{"node":"./lib/async/asynctrigger.js","browser":"./web/async/asynctrigger.js","react-native":"./web/async/asynctrigger.js","default":"./lib/async/asynctrigger.js"},"./async/deferredpromise.js":{"node":"./lib/async/deferredpromise.js","browser":"./web/async/deferredpromise.js","react-native":"./web/async/deferredpromise.js","default":"./lib/async/deferredpromise.js"},"./async/keycache.js":{"node":"./lib/async/keycache.js","browser":"./web/async/keycache.js","react-native":"./web/async/keycache.js","default":"./lib/async/keycache.js"},"./async/queues.js":{"node":"./lib/async/queues.js","browser":"./web/async/queues.js","react-native":"./web/async/queues.js","default":"./lib/async/queues.js"},"./async/timecache.js":{"node":"./lib/async/timecache.js","browser":"./web/async/timecache.js","react-native":"./web/async/timecache.js","default":"./lib/async/timecache.js"},"./base58.js":{"node":"./lib/base58.js","browser":"./web/base58.js","react-native":"./web/base58.js","default":"./lib/base58.js"},"./base64.js":{"node":"./lib/base64.js","browser":"./web/base64.js","react-native":"./web/base64.js","default":"./lib/base64.js"},"./benchmark.js":{"node":"./lib/benchmark.js","browser":"./web/benchmark.js","react-native":"./web/benchmark.js","default":"./lib/benchmark.js"},"./bytebuffer.js":{"node":"./lib/bytebuffer.js","browser":"./web/bytebuffer.js","react-native":"./web/bytebuffer.js","default":"./lib/bytebuffer.js"},"./consts.js":{"node":"./lib/consts.js","browser":"./web/consts.js","react-native":"./web/consts.js","default":"./lib/consts.js"},"./cron.js":{"node":"./lib/cron.js","browser":"./web/cron.js","react-native":"./web/cron.js","default":"./lib/cron.js"},"./dict.js":{"node":"./lib/dict.js","browser":"./web/dict.js","react-native":"./web/dict.js","default":"./lib/dict.js"},"./error.js":{"node":"./lib/error.js","browser":"./web/error.js","react-native":"./web/error.js","default":"./lib/error.js"},"./global.js":{"node":"./lib/global.js","browser":"./web/global.js","react-native":"./web/global.js","default":"./lib/global.js"},"./hex.js":{"node":"./lib/hex.js","browser":"./web/hex.js","react-native":"./web/hex.js","default":"./lib/hex.js"},"./idx.js":{"node":"./lib/idx.js","browser":"./web/idx.js","react-native":"./web/idx.js","default":"./lib/idx.js"},"./json.js":{"node":"./lib/json.js","browser":"./web/json.js","react-native":"./web/json.js","default":"./lib/json.js"},"./linebuffer.js":{"node":"./lib/linebuffer.js","browser":"./web/linebuffer.js","react-native":"./web/linebuffer.js","default":"./lib/linebuffer.js"},"./marshalling/marshaller.js":{"node":"./lib/marshalling/marshaller.js","browser":"./web/marshalling/marshaller.js","react-native":"./web/marshalling/marshaller.js","default":"./lib/marshalling/marshaller.js"},"./marshalling/unmarshaller.js":{"node":"./lib/marshalling/unmarshaller.js","browser":"./web/marshalling/unmarshaller.js","react-native":"./web/marshalling/unmarshaller.js","default":"./lib/marshalling/unmarshaller.js"},"./number.js":{"node":"./lib/number.js","browser":"./web/number.js","react-native":"./web/number.js","default":"./lib/number.js"},"./path.js":{"node":"./lib/path.js","browser":"./web/path.js","react-native":"./web/path.js","default":"./lib/path.js"},"./promise.js":{"node":"./lib/promise.js","browser":"./web/promise.js","react-native":"./web/promise.js","default":"./lib/promise.js"},"./starttime.js":{"node":"./lib/starttime.js","browser":"./web/starttime.js","react-native":"./web/starttime.js","default":"./lib/starttime.js"},"./string.js":{"node":"./lib/string.js","browser":"./web/string.js","react-native":"./web/string.js","default":"./lib/string.js"},"./triggers.js":{"node":"./lib/triggers.js","browser":"./web/triggers.js","react-native":"./web/triggers.js","default":"./lib/triggers.js"},"./types/array.js":{"node":"./lib/types/array.js","browser":"./web/types/array.js","react-native":"./web/types/array.js","default":"./lib/types/array.js"},"./types/enum.js":{"node":"./lib/types/enum.js","browser":"./web/types/enum.js","react-native":"./web/types/enum.js","default":"./lib/types/enum.js"},"./types/predicateerror.js":{"node":"./lib/types/predicateerror.js","browser":"./web/types/predicateerror.js","react-native":"./web/types/predicateerror.js","default":"./lib/types/predicateerror.js"},"./types/primitive.js":{"node":"./lib/types/primitive.js","browser":"./web/types/primitive.js","react-native":"./web/types/primitive.js","default":"./lib/types/primitive.js"},"./types/record.js":{"node":"./lib/types/record.js","browser":"./web/types/record.js","react-native":"./web/types/record.js","default":"./lib/types/record.js"},"./types/types.js":{"node":"./lib/types/types.js","browser":"./web/types/types.js","react-native":"./web/types/types.js","default":"./lib/types/types.js"},"./types/utils.js":{"node":"./lib/types/utils.js","browser":"./web/types/utils.js","react-native":"./web/types/utils.js","default":"./lib/types/utils.js"},"./uint8array.js":{"node":"./lib/uint8array.js","browser":"./web/uint8array.js","react-native":"./web/uint8array.js","default":"./lib/uint8array.js"},"./units.js":{"node":"./lib/units.js","browser":"./web/units.js","react-native":"./web/units.js","default":"./lib/units.js"}},"files":["/lib","/web"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { Logger } from "@keeex/log";
|
|
17
|
+
import * as types from "./types.js";
|
|
18
|
+
/**
|
|
19
|
+
* Base implementation for all triggers.
|
|
20
|
+
*/
|
|
21
|
+
export declare abstract class BaseTrigger implements types.Trigger {
|
|
22
|
+
#private;
|
|
23
|
+
constructor(handler: types.TriggerHandler, delayMs: number, logger?: Logger | string);
|
|
24
|
+
protected get state(): types.TriggerState;
|
|
25
|
+
protected set state(value: types.TriggerState);
|
|
26
|
+
protected get logger(): Logger;
|
|
27
|
+
abstract trigger(): void;
|
|
28
|
+
cancel: () => void;
|
|
29
|
+
stop: () => void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { createLogger } from "@keeex/log";
|
|
17
|
+
import { dropPromise } from "../../promise.js";
|
|
18
|
+
import * as types from "./types.js";
|
|
19
|
+
/**
|
|
20
|
+
* Base implementation for all triggers.
|
|
21
|
+
*/
|
|
22
|
+
export class BaseTrigger {
|
|
23
|
+
#state = types.TriggerState.inactive;
|
|
24
|
+
#timeout = null;
|
|
25
|
+
#delay;
|
|
26
|
+
#handler;
|
|
27
|
+
#logger;
|
|
28
|
+
constructor(handler, delayMs, logger) {
|
|
29
|
+
this.#handler = handler;
|
|
30
|
+
this.#delay = delayMs;
|
|
31
|
+
if (typeof logger === "string") {
|
|
32
|
+
this.#logger = createLogger({
|
|
33
|
+
tag: logger,
|
|
34
|
+
numbered: true
|
|
35
|
+
});
|
|
36
|
+
} else if (logger) {
|
|
37
|
+
this.#logger = logger;
|
|
38
|
+
} else {
|
|
39
|
+
this.#logger = createLogger({
|
|
40
|
+
tag: "PromiseTrigger",
|
|
41
|
+
numbered: true
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
this.#logger.debug(`Initialized with timer of ${delayMs}`);
|
|
45
|
+
}
|
|
46
|
+
get state() {
|
|
47
|
+
return this.#state;
|
|
48
|
+
}
|
|
49
|
+
set state(value) {
|
|
50
|
+
const oldState = this.#state;
|
|
51
|
+
this.#logger.debug(`State transition: ${oldState} → ${value}`);
|
|
52
|
+
this.#state = value;
|
|
53
|
+
switch (oldState) {
|
|
54
|
+
case types.TriggerState.inactive:
|
|
55
|
+
this.#stateFromInactive(value);
|
|
56
|
+
break;
|
|
57
|
+
case types.TriggerState.pending:
|
|
58
|
+
this.#stateFromPending(value);
|
|
59
|
+
break;
|
|
60
|
+
case types.TriggerState.running:
|
|
61
|
+
this.#stateFromRunning(value);
|
|
62
|
+
break;
|
|
63
|
+
case types.TriggerState.runningRetrigger:
|
|
64
|
+
this.#stateFromRunningRetrigger(value);
|
|
65
|
+
break;
|
|
66
|
+
case types.TriggerState.runningStop:
|
|
67
|
+
this.#stateFromRunningStop(value);
|
|
68
|
+
break;
|
|
69
|
+
case types.TriggerState.stop:
|
|
70
|
+
this.#stateFromStop(value);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
get logger() {
|
|
75
|
+
return this.#logger;
|
|
76
|
+
}
|
|
77
|
+
cancel = () => {
|
|
78
|
+
this.state = types.TriggerState.inactive;
|
|
79
|
+
};
|
|
80
|
+
stop = () => {
|
|
81
|
+
this.state = types.TriggerState.stop;
|
|
82
|
+
};
|
|
83
|
+
#stateFromInactive = value => {
|
|
84
|
+
switch (value) {
|
|
85
|
+
case types.TriggerState.pending:
|
|
86
|
+
this.#armTimeout();
|
|
87
|
+
break;
|
|
88
|
+
case types.TriggerState.running:
|
|
89
|
+
case types.TriggerState.runningRetrigger:
|
|
90
|
+
throw new Error("Cannot transition from inactive to running");
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
#stateFromPending = value => {
|
|
94
|
+
switch (value) {
|
|
95
|
+
case types.TriggerState.inactive:
|
|
96
|
+
this.#disarmTimeout();
|
|
97
|
+
break;
|
|
98
|
+
case types.TriggerState.running:
|
|
99
|
+
this.#timeout = null;
|
|
100
|
+
break;
|
|
101
|
+
case types.TriggerState.stop:
|
|
102
|
+
this.#disarmTimeout();
|
|
103
|
+
this.#runHandler();
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
#stateFromRunning = value => {
|
|
107
|
+
switch (value) {
|
|
108
|
+
case types.TriggerState.pending:
|
|
109
|
+
this.state = types.TriggerState.runningRetrigger;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
#stateFromRunningRetrigger = value => {
|
|
113
|
+
switch (value) {
|
|
114
|
+
case types.TriggerState.inactive:
|
|
115
|
+
this.state = types.TriggerState.pending;
|
|
116
|
+
break;
|
|
117
|
+
case types.TriggerState.pending:
|
|
118
|
+
this.state = types.TriggerState.runningRetrigger;
|
|
119
|
+
break;
|
|
120
|
+
case types.TriggerState.running:
|
|
121
|
+
throw new Error("Cannot transition from retrigger to running");
|
|
122
|
+
case types.TriggerState.stop:
|
|
123
|
+
this.#runHandler();
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
#stateFromRunningStop = value => {
|
|
127
|
+
switch (value) {
|
|
128
|
+
case types.TriggerState.inactive:
|
|
129
|
+
this.state = types.TriggerState.stop;
|
|
130
|
+
break;
|
|
131
|
+
case types.TriggerState.pending:
|
|
132
|
+
case types.TriggerState.running:
|
|
133
|
+
case types.TriggerState.runningRetrigger:
|
|
134
|
+
case types.TriggerState.runningStop:
|
|
135
|
+
throw new Error("Invalid state transition from runningStop");
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
#stateFromStop = value => {
|
|
139
|
+
switch (value) {
|
|
140
|
+
case types.TriggerState.inactive:
|
|
141
|
+
case types.TriggerState.pending:
|
|
142
|
+
case types.TriggerState.runningRetrigger:
|
|
143
|
+
this.state = types.TriggerState.stop;
|
|
144
|
+
break;
|
|
145
|
+
case types.TriggerState.running:
|
|
146
|
+
this.state = types.TriggerState.runningStop;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
#armTimeout = () => {
|
|
151
|
+
this.#disarmTimeout();
|
|
152
|
+
this.#logger.debug("Arming timeout");
|
|
153
|
+
this.#timeout = setTimeout(this.#runHandler, this.#delay);
|
|
154
|
+
};
|
|
155
|
+
#disarmTimeout = () => {
|
|
156
|
+
if (this.#timeout === null) return;
|
|
157
|
+
this.#logger.debug("Disarming previous timeout");
|
|
158
|
+
clearTimeout(this.#timeout);
|
|
159
|
+
this.#timeout = null;
|
|
160
|
+
};
|
|
161
|
+
#runHandler = () => {
|
|
162
|
+
this.#logger.debug("Running handler");
|
|
163
|
+
this.state = types.TriggerState.running;
|
|
164
|
+
dropPromise(this.#runHandlerPromise, this.#logger);
|
|
165
|
+
};
|
|
166
|
+
#runHandlerPromise = async () => {
|
|
167
|
+
try {
|
|
168
|
+
await this.#handler();
|
|
169
|
+
} finally {
|
|
170
|
+
this.state = types.TriggerState.inactive;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { Logger } from "@keeex/log";
|
|
17
|
+
import { BaseTrigger } from "./base.js";
|
|
18
|
+
import * as types from "./types.js";
|
|
19
|
+
/**
|
|
20
|
+
* Debouncing trigger.
|
|
21
|
+
*
|
|
22
|
+
* Each time the trigger is triggered, the timer rearms itself, delaying the callback ever more.
|
|
23
|
+
* Once there is no trigger for the duration of the trigger, the callback is finally called.
|
|
24
|
+
*
|
|
25
|
+
* Useful for debouncing.
|
|
26
|
+
*/
|
|
27
|
+
export declare class DebounceTrigger extends BaseTrigger {
|
|
28
|
+
constructor(handler: types.TriggerHandler, delayMs: number, logger?: Logger | string);
|
|
29
|
+
trigger: () => void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { BaseTrigger } from "./base.js";
|
|
17
|
+
import * as types from "./types.js";
|
|
18
|
+
/**
|
|
19
|
+
* Debouncing trigger.
|
|
20
|
+
*
|
|
21
|
+
* Each time the trigger is triggered, the timer rearms itself, delaying the callback ever more.
|
|
22
|
+
* Once there is no trigger for the duration of the trigger, the callback is finally called.
|
|
23
|
+
*
|
|
24
|
+
* Useful for debouncing.
|
|
25
|
+
*/
|
|
26
|
+
export class DebounceTrigger extends BaseTrigger {
|
|
27
|
+
constructor(handler, delayMs, logger = "DebounceTrigger") {
|
|
28
|
+
super(handler, delayMs, logger);
|
|
29
|
+
}
|
|
30
|
+
trigger = () => {
|
|
31
|
+
if (this.state === types.TriggerState.pending) {
|
|
32
|
+
this.state = types.TriggerState.inactive;
|
|
33
|
+
}
|
|
34
|
+
this.state = types.TriggerState.pending;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { Logger } from "@keeex/log";
|
|
17
|
+
import { BaseTrigger } from "./base.js";
|
|
18
|
+
import * as types from "./types.js";
|
|
19
|
+
/**
|
|
20
|
+
* Trigger that *will* fire its event after the time is elapsed, no matter how many times it is
|
|
21
|
+
* triggered afterward.
|
|
22
|
+
*
|
|
23
|
+
* After a call to `trigger()`, the timer is started.
|
|
24
|
+
* When it runs out, the even function is called.
|
|
25
|
+
* Multiple calls to `trigger()` will not delay the call, and they will not cause additional calls
|
|
26
|
+
* to occur.
|
|
27
|
+
* Calling `trigger()` while the callback is running will reschedule a call *after* the callback
|
|
28
|
+
* completes.
|
|
29
|
+
*/
|
|
30
|
+
export declare class GrenadeTrigger extends BaseTrigger {
|
|
31
|
+
constructor(handler: types.TriggerHandler, delayMs: number, logger?: Logger | string);
|
|
32
|
+
trigger: () => void;
|
|
33
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { BaseTrigger } from "./base.js";
|
|
17
|
+
import * as types from "./types.js";
|
|
18
|
+
/**
|
|
19
|
+
* Trigger that *will* fire its event after the time is elapsed, no matter how many times it is
|
|
20
|
+
* triggered afterward.
|
|
21
|
+
*
|
|
22
|
+
* After a call to `trigger()`, the timer is started.
|
|
23
|
+
* When it runs out, the even function is called.
|
|
24
|
+
* Multiple calls to `trigger()` will not delay the call, and they will not cause additional calls
|
|
25
|
+
* to occur.
|
|
26
|
+
* Calling `trigger()` while the callback is running will reschedule a call *after* the callback
|
|
27
|
+
* completes.
|
|
28
|
+
*/
|
|
29
|
+
export class GrenadeTrigger extends BaseTrigger {
|
|
30
|
+
constructor(handler, delayMs, logger = "GrenadeTrigger") {
|
|
31
|
+
super(handler, delayMs, logger);
|
|
32
|
+
}
|
|
33
|
+
trigger = () => {
|
|
34
|
+
this.logger.debug("Triggered");
|
|
35
|
+
this.state = types.TriggerState.pending;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { Awaitable } from "../../types/types.js";
|
|
17
|
+
export type TriggerHandler = () => Awaitable<void>;
|
|
18
|
+
export declare enum TriggerState {
|
|
19
|
+
/** Trigger was not triggered */
|
|
20
|
+
inactive = "inactive",
|
|
21
|
+
/** Trigger was triggered, fuse timer is counting down */
|
|
22
|
+
pending = "pending",
|
|
23
|
+
/** Trigger was triggered and timer expired, the handler is running */
|
|
24
|
+
running = "running",
|
|
25
|
+
/** Handler is running, and trigger was called again */
|
|
26
|
+
runningRetrigger = "runningTrigger",
|
|
27
|
+
/** Last run after stop */
|
|
28
|
+
runningStop = "runningStop",
|
|
29
|
+
/** Handler is killed, will never run except for currently triggered call */
|
|
30
|
+
stop = "stop"
|
|
31
|
+
}
|
|
32
|
+
/** Generic interface for delayed triggers */
|
|
33
|
+
export interface Trigger {
|
|
34
|
+
/** Call when the trigger should start (or restart, depending on the implementation) */
|
|
35
|
+
trigger: () => void;
|
|
36
|
+
/** Call when the trigger should be canceled */
|
|
37
|
+
cancel: () => void;
|
|
38
|
+
/**
|
|
39
|
+
* Call when the trigger should stop (it can't be triggered again).
|
|
40
|
+
* If there is an execution pending, it is run immediately.
|
|
41
|
+
*/
|
|
42
|
+
stop: () => void;
|
|
43
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
export var TriggerState;
|
|
17
|
+
(function (TriggerState) {
|
|
18
|
+
/** Trigger was not triggered */
|
|
19
|
+
TriggerState["inactive"] = "inactive";
|
|
20
|
+
/** Trigger was triggered, fuse timer is counting down */
|
|
21
|
+
TriggerState["pending"] = "pending";
|
|
22
|
+
/** Trigger was triggered and timer expired, the handler is running */
|
|
23
|
+
TriggerState["running"] = "running";
|
|
24
|
+
/** Handler is running, and trigger was called again */
|
|
25
|
+
TriggerState["runningRetrigger"] = "runningTrigger";
|
|
26
|
+
/** Last run after stop */
|
|
27
|
+
TriggerState["runningStop"] = "runningStop";
|
|
28
|
+
/** Handler is killed, will never run except for currently triggered call */
|
|
29
|
+
TriggerState["stop"] = "stop";
|
|
30
|
+
})(TriggerState || (TriggerState = {}));
|
package/web/promise.d.ts
CHANGED
|
@@ -36,10 +36,29 @@ export type PromiseFunc<T> = () => Promise<T | void>;
|
|
|
36
36
|
*/
|
|
37
37
|
export declare const firstTruthy: <T>(promiseFuncs: Array<PromiseFunc<T>>) => Promise<T>;
|
|
38
38
|
type AwaitableFn<T> = () => Awaitable<T>;
|
|
39
|
+
type ErrorHandler = boolean | ((e: Error) => void) | {
|
|
40
|
+
error: (e: unknown) => void;
|
|
41
|
+
};
|
|
39
42
|
/**
|
|
40
43
|
* Drop a promise and silence any exception.
|
|
41
44
|
*
|
|
42
45
|
* This is to be used *only* on dropped promises to explicitly silence any warning.
|
|
46
|
+
*
|
|
47
|
+
* @param errorHandler - How to handle rejection
|
|
48
|
+
* If not provided or true, an error message is printed on the error output.
|
|
49
|
+
* If false, the error is silently ignored.
|
|
50
|
+
* If a function is provided, it is called with an Error object.
|
|
51
|
+
* If an object with an `error()` function is provided, this error function is called.
|
|
52
|
+
*/
|
|
53
|
+
export declare const dropPromise: <T>(promise: Awaitable<T> | AwaitableFn<T>, errorHandler?: ErrorHandler) => void;
|
|
54
|
+
/**
|
|
55
|
+
* Wait for a promise to complete, but ignore rejection.
|
|
56
|
+
|
|
57
|
+
* @param errorHandler - How to handle rejection
|
|
58
|
+
* If not provided or false, the error is silently ignored.
|
|
59
|
+
* If true, an error message is printed on the error output.
|
|
60
|
+
* If a function is provided, it is called with an Error object.
|
|
61
|
+
* If an object with an `error()` function is provided, this error function is called.
|
|
43
62
|
*/
|
|
44
|
-
export declare const
|
|
63
|
+
export declare const ignorePromise: <T>(promise: Awaitable<T> | AwaitableFn<T>, errorHandler?: ErrorHandler) => Promise<void>;
|
|
45
64
|
export {};
|
package/web/promise.js
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
*
|
|
15
15
|
*/
|
|
16
16
|
/* eslint-env node */
|
|
17
|
+
import * as log from "@keeex/log";
|
|
18
|
+
import { asError } from "./error.js";
|
|
17
19
|
import { timeConvert } from "./units.js";
|
|
18
20
|
/**
|
|
19
21
|
* Create a promise that resolves after a given delay.
|
|
@@ -63,18 +65,53 @@ export const firstTruthy = async promiseFuncs => {
|
|
|
63
65
|
}
|
|
64
66
|
throw new Error("No result");
|
|
65
67
|
};
|
|
68
|
+
const logger = log.createLogger("dropPromise");
|
|
69
|
+
const handleError = (handler, outputDefault, error) => {
|
|
70
|
+
if (handler === undefined) {
|
|
71
|
+
if (outputDefault) logger.error("Dropped promise rejected:", error);
|
|
72
|
+
} else if (handler === true) {
|
|
73
|
+
logger.error("Dropped promise rejected:", error);
|
|
74
|
+
} else if (typeof handler === "function") {
|
|
75
|
+
handler(asError(error));
|
|
76
|
+
} else if (handler !== false) {
|
|
77
|
+
handler.error(error);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
66
80
|
/**
|
|
67
81
|
* Drop a promise and silence any exception.
|
|
68
82
|
*
|
|
69
83
|
* This is to be used *only* on dropped promises to explicitly silence any warning.
|
|
84
|
+
*
|
|
85
|
+
* @param errorHandler - How to handle rejection
|
|
86
|
+
* If not provided or true, an error message is printed on the error output.
|
|
87
|
+
* If false, the error is silently ignored.
|
|
88
|
+
* If a function is provided, it is called with an Error object.
|
|
89
|
+
* If an object with an `error()` function is provided, this error function is called.
|
|
70
90
|
*/
|
|
71
|
-
export const dropPromise = promise => {
|
|
91
|
+
export const dropPromise = (promise, errorHandler) => {
|
|
72
92
|
if (typeof promise === "function") {
|
|
73
93
|
dropPromise(promise());
|
|
74
94
|
return;
|
|
75
95
|
}
|
|
76
96
|
if (promise instanceof Promise) {
|
|
77
|
-
// eslint-disable-next-line
|
|
78
|
-
promise.catch(
|
|
97
|
+
// eslint-disable-next-line promise/prefer-await-to-then
|
|
98
|
+
promise.catch(e => handleError(errorHandler, true, e));
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Wait for a promise to complete, but ignore rejection.
|
|
103
|
+
|
|
104
|
+
* @param errorHandler - How to handle rejection
|
|
105
|
+
* If not provided or false, the error is silently ignored.
|
|
106
|
+
* If true, an error message is printed on the error output.
|
|
107
|
+
* If a function is provided, it is called with an Error object.
|
|
108
|
+
* If an object with an `error()` function is provided, this error function is called.
|
|
109
|
+
*/
|
|
110
|
+
export const ignorePromise = async (promise, errorHandler) => {
|
|
111
|
+
try {
|
|
112
|
+
if (typeof promise === "function") return await ignorePromise(promise());
|
|
113
|
+
await promise;
|
|
114
|
+
} catch (e) {
|
|
115
|
+
handleError(errorHandler, false, e);
|
|
79
116
|
}
|
|
80
117
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { Logger } from "@keeex/log";
|
|
17
|
+
import { Trigger, TriggerHandler } from "./bits/triggers/types.js";
|
|
18
|
+
/** Return a simple trigger that is run after the initial delay is passed after a trigger call */
|
|
19
|
+
export declare const simpleTrigger: (handler: TriggerHandler, delayMs: number, logger?: Logger) => Trigger;
|
|
20
|
+
/** Return a debouncing trigger that will rearm as long as it is triggered during the grace delay */
|
|
21
|
+
export declare const debouncingTrigger: (handler: TriggerHandler, delayMs: number, logger?: Logger) => Trigger;
|
package/web/triggers.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* @preserve
|
|
4
|
+
*
|
|
5
|
+
* MIT License
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2023 KeeeX SAS
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
import { DebounceTrigger } from "./bits/triggers/debounce.js";
|
|
17
|
+
import { GrenadeTrigger } from "./bits/triggers/grenade.js";
|
|
18
|
+
/** Return a simple trigger that is run after the initial delay is passed after a trigger call */
|
|
19
|
+
export const simpleTrigger = (handler, delayMs, logger) => new GrenadeTrigger(handler, delayMs, logger);
|
|
20
|
+
/** Return a debouncing trigger that will rearm as long as it is triggered during the grace delay */
|
|
21
|
+
export const debouncingTrigger = (handler, delayMs, logger) => new DebounceTrigger(handler, delayMs, logger);
|
package/web/units.js
CHANGED
|
@@ -125,8 +125,8 @@ const convertUnit = (unitDescription, fromUnit, toUnit) => {
|
|
|
125
125
|
to
|
|
126
126
|
};
|
|
127
127
|
};
|
|
128
|
-
const regexBefore = /^(?<unit>[^\d]+)\d
|
|
129
|
-
const regexAfter =
|
|
128
|
+
const regexBefore = /^(?<unit>[^\d,.]+)(?:(?:\d+)|(?:\d*[.,]\d+)|(?:\d+[.,]\d*))$/u;
|
|
129
|
+
const regexAfter = /^(?:(?:\d+)|(?:\d*[.,]\d+)|(?:\d+[.,]\d*))(?<unit>[^\d,.]+)$/u;
|
|
130
130
|
/** Get the unit text from an input value */
|
|
131
131
|
const getUnitFromValue = (value, unitDesc) => {
|
|
132
132
|
if (typeof value !== "string") return unitDesc.basename;
|
|
@@ -136,11 +136,12 @@ const getUnitFromValue = (value, unitDesc) => {
|
|
|
136
136
|
const unit = res.groups.unit;
|
|
137
137
|
return unit.trim();
|
|
138
138
|
};
|
|
139
|
-
const
|
|
139
|
+
const regexFloatValue = /^(?:[^\d,.]*)(?<value>(?:\d+)|(?:\d*[.,]\d+)|(?:\d+[.,]\d*))(?:[^\d,.]*)$/u;
|
|
140
|
+
const regexIntOnlyValue = /^(?:[^\d,.]*)(?<value>\d+)(?:[^\d,.]*)$/u;
|
|
140
141
|
/** Get the numeric value, stripping units */
|
|
141
142
|
const getNumberValue = value => {
|
|
142
143
|
if (typeof value === "number") return value;
|
|
143
|
-
const res =
|
|
144
|
+
const res = regexFloatValue.exec(value);
|
|
144
145
|
if (!res?.groups) throw new Error(`Missing value (${value})`);
|
|
145
146
|
return parseFloat(res.groups.value);
|
|
146
147
|
};
|
|
@@ -148,7 +149,7 @@ const getNumberValue = value => {
|
|
|
148
149
|
const getBigintValue = value => {
|
|
149
150
|
if (typeof value === "bigint") return value;
|
|
150
151
|
if (typeof value === "number") return BigInt(value);
|
|
151
|
-
const res =
|
|
152
|
+
const res = regexIntOnlyValue.exec(value);
|
|
152
153
|
if (!res?.groups) throw new Error(`Missing value (${value})`);
|
|
153
154
|
return BigInt(res.groups.value);
|
|
154
155
|
};
|