@lsdsoftware/utils 1.0.2 → 1.0.3

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 CHANGED
@@ -1,168 +1,62 @@
1
1
  # Useful JavaScript utilities
2
2
 
3
3
 
4
- ### State Machine
5
- Make implementing state machines less error prone.
6
-
7
- ```typescript
8
- import { makeStateMachine } from "@lsdsoftware/utils"
9
-
10
- const sm = makeStateMachine({
11
- IDLE: {
12
- startIt() {
13
- //do something
14
- return "BUSY"
15
- }
16
- },
17
- BUSY: {
18
- stopIt() {
19
- //stop doing it
20
- return "IDLE"
21
- },
22
- stopAfterDelay() {
23
- return "STOPPING"
24
- }
25
- },
26
- STOPPING: {
27
- onTransitionIn(this: any) {
28
- //do some clean up
29
- this.timer = setTimeout(() => sm.trigger("onDone"), 3000)
30
- },
31
- onDone() {
32
- return "IDLE"
33
- },
34
- stopIt() {
35
- console.log("Already stopping, be patient!")
36
- //return void to stay in same state
37
- },
38
- forceIt(this: any) {
39
- clearTimeout(this.timer)
40
- return "IDLE"
41
- }
42
- }
43
- })
44
-
45
- sm.trigger("startIt")
46
- sm.getState() //BUSY
47
- ```
48
-
49
-
50
-
51
- ### Message Dispatcher
52
- Dispatch messages to handlers. This utility assumes messages are one of three types: request, response, or notification; and follow a predefined format (see type definition below).
4
+ ### Line Reader
5
+ Split text into lines
53
6
 
54
7
  ```typescript
55
- interface Request {
56
- to: string
57
- type: "request"
58
- id: "string"
59
- method: string
60
- args: Record<string, unknown>
61
- }
62
-
63
- interface Notification {
64
- to: string
65
- type: "notification"
66
- method: string
67
- args: Record<string, unknown>
68
- }
8
+ import { makeLineReader } from "@lsdsoftware/utils"
69
9
 
70
- interface Response {
71
- type: "response"
72
- id: string
73
- error: unknown
74
- result: unknown
75
- }
10
+ myStream.pipe(makeLineReader(line => console.log(line)))
76
11
  ```
77
12
 
78
- Call `dispatch` to dispatch a message you received. Requests and notifications are dispatched to request handlers that you provide at construction. Responses are dispatched to response listeners; to listen for a response, call `waitForResponse` with the request ID.
79
13
 
80
- A _myAddress_ parameter provided at construction is used to filter messages. Only requests and notifications whose _to_ attribute matches _myAddress_ will be processed.
14
+ ### Semaphore
15
+ Control concurrent access to resources
81
16
 
82
17
  ```typescript
83
- import { makeMessageDispatcher } from "@lsdsoftware/utils"
84
-
85
- const requestHandlers = {
86
- method1({paramA, paramB}, sender) {
87
- //do something
88
- return result
89
- },
90
- async method2({x, y, z}, sender) {
91
- //do something
92
- return result
93
- }
94
- }
95
-
96
- const dispatcher = makeMessageDispatcher("myAddress", requestHandlers)
18
+ import { makeSemaphore } from "@lsdsoftware/utils"
97
19
 
98
- //sample usage
20
+ const semaphore = makeSemaphore(3)
99
21
 
100
- //processing requests and responses
101
- window.addEventListener("message", event => {
102
- const sender = {window: event.source, origin: event.origin}
103
- const sendResponse = response => sender.window.postMessage(response, sender.origin)
104
- dispatcher.dispatch(event.data, sender, sendResponse)
22
+ const result = await semaphore.runTask(async () => {
23
+ //use the limited resource
105
24
  })
106
-
107
- //sending requests
108
- const id = String(Math.random())
109
- const request = {to: "someAddress", type: "request", id, method: "someMethod", args: {}}
110
- iframeWindow.postMessage(request, "*")
111
- dispatcher.waitForResponse(id)
112
- .then(result => console.log(result))
113
- .catch(console.error)
114
25
  ```
115
26
 
116
27
 
117
-
118
- ### Rate Limiter
119
- Basic rate limiter using the token bucket algorithm.
28
+ ### Abortable
29
+ If you have an async operation, e.g.:
120
30
 
121
31
  ```typescript
122
- import { RateLimiter } from "@lsdsoftware/utils"
123
-
124
- const limiter = new RateLimiter({tokensPerInterval: 5, interval: 60*1000})
125
-
126
- function handleRequest(userId, req) {
127
- if (limiter.tryRemoveTokens(userId, 1)) return processRequest(req)
128
- else throw "Rate limit exceeded"
32
+ async function myTask() {
33
+ await step1()
34
+ await step2()
35
+ await step3()
129
36
  }
130
37
  ```
131
38
 
132
-
133
-
134
- ### Connection Manager
135
- Takes a connect() method and:
136
- - Only call it to create a connection when needed
137
- - Automatically retry on failure
138
- - Automatically reconnect if the previous connection was closed
139
- - Properly handle shutdown sequence
140
-
39
+ And you need to make it abortable:
141
40
  ```typescript
142
- import { makeConnectionManager } from "@lsdsoftware/utils"
143
-
144
- const conMgr = new ConnectionManager({
145
- async connect() {
146
- //...
147
- return connection
148
- },
149
- retryDelay: 10*1000
150
- })
151
-
152
- //wherever you need the connection
153
- const connection = await conMgr.get()
154
-
155
- //shutdown
156
- conMgr.shutdown()
157
- ```
158
-
41
+ import { makeAbortable } from "@lsdsoftware/utils"
159
42
 
43
+ const [abort, abortPromise, checkpoint] = makeAbortable()
160
44
 
161
- ### Line Reader
162
- Split text into lines
45
+ //modify task to support early termination
46
+ async function myTask() {
47
+ await step1
48
+ checkpoint() //will throw if aborted
49
+ await step2
50
+ checkpoint()
51
+ await step3
52
+ }
163
53
 
164
- ```typescript
165
- import { makeLineReader } from "@lsdsoftware/utils"
54
+ //call abort() when you need to
55
+ setTimeout(() => abort(new Error("Timeout")), 5000)
166
56
 
167
- myStream.pipe(makeLineReader(line => console.log(line)))
57
+ //use Promise.race to run your task
58
+ const result = await Promise.race([
59
+ abortPromise,
60
+ myTask()
61
+ ])
168
62
  ```
@@ -0,0 +1 @@
1
+ export declare function makeAbortable(): (Promise<never> | ((reason: unknown) => void))[];
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeAbortable = void 0;
4
+ function makeAbortable() {
5
+ let isAborted;
6
+ let reject;
7
+ const promise = new Promise((f, r) => reject = r);
8
+ function abort(reason) {
9
+ isAborted = { reason };
10
+ reject(reason);
11
+ }
12
+ function checkpoint() {
13
+ if (isAborted)
14
+ throw isAborted.reason;
15
+ }
16
+ return [
17
+ abort,
18
+ promise,
19
+ checkpoint
20
+ ];
21
+ }
22
+ exports.makeAbortable = makeAbortable;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,4 @@
1
1
  import { makeLineReader } from "./line-reader";
2
- import { makeStateMachine } from "./state-machine";
3
- import { makeConnectionManager } from "./connection-manager";
4
- import { makeMessageDispatcher } from "./message-dispatcher";
5
- import { makeRateLimiter } from "./rate-limiter";
6
2
  import { makeSemaphore } from "./semaphore";
7
- export { makeLineReader, makeStateMachine, makeConnectionManager, makeMessageDispatcher, makeRateLimiter, makeSemaphore, };
3
+ import { makeAbortable } from "./abortable";
4
+ export { makeLineReader, makeSemaphore, makeAbortable, };
package/dist/index.js CHANGED
@@ -1,15 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.makeSemaphore = exports.makeRateLimiter = exports.makeMessageDispatcher = exports.makeConnectionManager = exports.makeStateMachine = exports.makeLineReader = void 0;
3
+ exports.makeAbortable = exports.makeSemaphore = exports.makeLineReader = void 0;
4
4
  const line_reader_1 = require("./line-reader");
5
5
  Object.defineProperty(exports, "makeLineReader", { enumerable: true, get: function () { return line_reader_1.makeLineReader; } });
6
- const state_machine_1 = require("./state-machine");
7
- Object.defineProperty(exports, "makeStateMachine", { enumerable: true, get: function () { return state_machine_1.makeStateMachine; } });
8
- const connection_manager_1 = require("./connection-manager");
9
- Object.defineProperty(exports, "makeConnectionManager", { enumerable: true, get: function () { return connection_manager_1.makeConnectionManager; } });
10
- const message_dispatcher_1 = require("./message-dispatcher");
11
- Object.defineProperty(exports, "makeMessageDispatcher", { enumerable: true, get: function () { return message_dispatcher_1.makeMessageDispatcher; } });
12
- const rate_limiter_1 = require("./rate-limiter");
13
- Object.defineProperty(exports, "makeRateLimiter", { enumerable: true, get: function () { return rate_limiter_1.makeRateLimiter; } });
14
6
  const semaphore_1 = require("./semaphore");
15
7
  Object.defineProperty(exports, "makeSemaphore", { enumerable: true, get: function () { return semaphore_1.makeSemaphore; } });
8
+ const abortable_1 = require("./abortable");
9
+ Object.defineProperty(exports, "makeAbortable", { enumerable: true, get: function () { return abortable_1.makeAbortable; } });
@@ -10,9 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const line_reader_test_1 = require("./line-reader.test");
13
- const rate_limiter_test_1 = require("./rate-limiter.test");
14
- const state_machine_test_1 = require("./state-machine.test");
15
- run(Object.assign(Object.assign(Object.assign({}, line_reader_test_1.default), rate_limiter_test_1.default), state_machine_test_1.default))
13
+ run(Object.assign({}, line_reader_test_1.default))
16
14
  .catch(console.error);
17
15
  function run(tests) {
18
16
  return __awaiter(this, void 0, void 0, function* () {
@@ -1,3 +1,3 @@
1
1
  export declare function makeSemaphore(count: number): {
2
- runTask<T>(task: () => Promise<T>): Promise<T>;
2
+ runTask<T>(task: () => Promise<T>, checkpoint?: () => void): Promise<T>;
3
3
  };
package/dist/semaphore.js CHANGED
@@ -13,12 +13,13 @@ exports.makeSemaphore = void 0;
13
13
  function makeSemaphore(count) {
14
14
  const waiters = [];
15
15
  return {
16
- runTask(task) {
16
+ runTask(task, checkpoint) {
17
17
  return __awaiter(this, void 0, void 0, function* () {
18
18
  if (count > 0)
19
19
  count--;
20
20
  else
21
21
  yield new Promise(f => waiters.push(f));
22
+ checkpoint === null || checkpoint === void 0 ? void 0 : checkpoint();
22
23
  try {
23
24
  return yield task();
24
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lsdsoftware/utils",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Useful JavaScript utilities",
5
5
  "main": "dist/index.js",
6
6
  "files": [
@@ -1,13 +0,0 @@
1
- interface Closeable {
2
- close(): void;
3
- once(event: "close", callback: Function): void;
4
- }
5
- export interface ConnectionManager<Connection> {
6
- get(): Promise<Connection>;
7
- shutdown(): void;
8
- }
9
- export declare function makeConnectionManager<Connection extends Closeable>({ connect, retryDelay }: {
10
- connect(): Promise<Connection>;
11
- retryDelay: number;
12
- }): ConnectionManager<Connection>;
13
- export {};
@@ -1,70 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.makeConnectionManager = void 0;
13
- function makeConnectionManager({ connect, retryDelay }) {
14
- let connectionPromise;
15
- let shutdownFlag = false;
16
- return {
17
- get() {
18
- if (!connectionPromise)
19
- connectionPromise = start();
20
- return connectionPromise;
21
- },
22
- shutdown() {
23
- shutdownFlag = true;
24
- connectionPromise === null || connectionPromise === void 0 ? void 0 : connectionPromise.then(con => con.close()).catch(err => "OK");
25
- }
26
- };
27
- function start() {
28
- return new Promise(fulfill => {
29
- let firstTime = true;
30
- keepAlive(promise => {
31
- if (firstTime) {
32
- fulfill(promise);
33
- firstTime = false;
34
- }
35
- else {
36
- connectionPromise = promise;
37
- }
38
- });
39
- });
40
- }
41
- function keepAlive(onUpdate) {
42
- return __awaiter(this, void 0, void 0, function* () {
43
- try {
44
- while (true) {
45
- const promise = connectUntilSucceed();
46
- onUpdate(promise);
47
- const connection = yield promise;
48
- yield new Promise(f => connection.once("close", f));
49
- }
50
- }
51
- catch (err) {
52
- }
53
- });
54
- }
55
- function connectUntilSucceed() {
56
- return __awaiter(this, void 0, void 0, function* () {
57
- while (true) {
58
- if (shutdownFlag)
59
- throw new Error("Shutting down");
60
- try {
61
- return yield connect();
62
- }
63
- catch (err) {
64
- yield new Promise(f => setTimeout(f, retryDelay));
65
- }
66
- }
67
- });
68
- }
69
- }
70
- exports.makeConnectionManager = makeConnectionManager;
@@ -1,29 +0,0 @@
1
- export type Message = Request | Notification | Response;
2
- interface Request {
3
- to: string;
4
- type: "request";
5
- id: "string";
6
- method: string;
7
- args: Record<string, unknown>;
8
- }
9
- interface Notification {
10
- to: string;
11
- type: "notification";
12
- method: string;
13
- args: Record<string, unknown>;
14
- }
15
- interface Response {
16
- type: "response";
17
- id: string;
18
- error: unknown;
19
- result: unknown;
20
- }
21
- interface RequestHandler {
22
- (args: Record<string, unknown>, sender: unknown): unknown;
23
- }
24
- export declare function makeMessageDispatcher(myAddress: string, requestHandlers: Record<string, RequestHandler>): {
25
- waitForResponse<T>(requestId: string): Promise<T>;
26
- dispatch(message: Message, sender: unknown, sendResponse: (res: Response) => void): boolean | void;
27
- updateRequestHandlers(newHandlers: typeof requestHandlers): void;
28
- };
29
- export {};
@@ -1,72 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.makeMessageDispatcher = void 0;
4
- function makeMessageDispatcher(myAddress, requestHandlers) {
5
- const pendingRequests = new Map();
6
- return {
7
- waitForResponse(requestId) {
8
- let pending = pendingRequests.get(requestId);
9
- if (!pending)
10
- pendingRequests.set(requestId, pending = makePending());
11
- return pending.promise;
12
- },
13
- dispatch(message, sender, sendResponse) {
14
- switch (message.type) {
15
- case "request": return handleRequest(message, sender, sendResponse);
16
- case "notification": return handleNotification(message, sender);
17
- case "response": return handleResponse(message);
18
- }
19
- },
20
- updateRequestHandlers(newHandlers) {
21
- requestHandlers = newHandlers;
22
- }
23
- };
24
- function makePending() {
25
- const pending = {};
26
- pending.promise = new Promise((fulfill, reject) => {
27
- pending.fulfill = fulfill;
28
- pending.reject = reject;
29
- });
30
- return pending;
31
- }
32
- function handleRequest(req, sender, sendResponse) {
33
- if (req.to == myAddress) {
34
- if (requestHandlers[req.method]) {
35
- Promise.resolve()
36
- .then(() => requestHandlers[req.method](req.args, sender))
37
- .then(result => sendResponse({ type: "response", id: req.id, result, error: undefined }), error => sendResponse({ type: "response", id: req.id, result: undefined, error }));
38
- //let caller know that sendResponse will be called asynchronously
39
- return true;
40
- }
41
- else {
42
- console.error("No handler for method", req);
43
- }
44
- }
45
- }
46
- function handleNotification(ntf, sender) {
47
- if (ntf.to == myAddress) {
48
- if (requestHandlers[ntf.method]) {
49
- Promise.resolve()
50
- .then(() => requestHandlers[ntf.method](ntf.args, sender))
51
- .catch(error => console.error("Failed to handle notification", ntf, error));
52
- }
53
- else {
54
- console.error("No handler for method", ntf);
55
- }
56
- }
57
- }
58
- function handleResponse(res) {
59
- const pending = pendingRequests.get(res.id);
60
- if (pending) {
61
- pendingRequests.delete(res.id);
62
- if (res.error)
63
- pending.reject(res.error);
64
- else
65
- pending.fulfill(res.result);
66
- }
67
- else {
68
- console.error("Stray response", res);
69
- }
70
- }
71
- }
72
- exports.makeMessageDispatcher = makeMessageDispatcher;
@@ -1,7 +0,0 @@
1
- export declare function makeRateLimiter({ interval, tokensPerInterval }: {
2
- interval: number;
3
- tokensPerInterval: number;
4
- }): {
5
- getTokensRemaining(key: unknown): number;
6
- tryRemoveTokens(key: unknown, numTokens: number): boolean;
7
- };
@@ -1,43 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.makeRateLimiter = void 0;
4
- class Bucket {
5
- constructor(count, expire) {
6
- this.count = count;
7
- this.expire = expire;
8
- }
9
- isValid() {
10
- return this.expire > Date.now();
11
- }
12
- }
13
- function makeRateLimiter({ interval, tokensPerInterval }) {
14
- const buckets = new Map();
15
- let lastCleanup = Date.now();
16
- return {
17
- getTokensRemaining(key) {
18
- const bucket = buckets.get(key);
19
- return (bucket === null || bucket === void 0 ? void 0 : bucket.isValid()) ? bucket.count : tokensPerInterval;
20
- },
21
- tryRemoveTokens(key, numTokens) {
22
- if (Date.now() - lastCleanup > 2 * interval) {
23
- lastCleanup = Date.now();
24
- for (const [key, bucket] of buckets)
25
- if (!bucket.isValid())
26
- buckets.delete(key);
27
- }
28
- let bucket = buckets.get(key);
29
- if (!(bucket === null || bucket === void 0 ? void 0 : bucket.isValid())) {
30
- bucket = new Bucket(tokensPerInterval, Date.now() + interval);
31
- buckets.set(key, bucket);
32
- }
33
- if (numTokens <= bucket.count) {
34
- bucket.count -= numTokens;
35
- return true;
36
- }
37
- else {
38
- return false;
39
- }
40
- }
41
- };
42
- }
43
- exports.makeRateLimiter = makeRateLimiter;
@@ -1,4 +0,0 @@
1
- declare const _default: {
2
- rateLimiter1(): Promise<void>;
3
- };
4
- export default _default;
@@ -1,39 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- const rate_limiter_1 = require("./rate-limiter");
13
- const assert = require("assert");
14
- exports.default = {
15
- rateLimiter1() {
16
- return __awaiter(this, void 0, void 0, function* () {
17
- const limiter = (0, rate_limiter_1.makeRateLimiter)({ tokensPerInterval: 5, interval: 2000 });
18
- assert(limiter.getTokensRemaining("k1") == 5);
19
- assert(limiter.tryRemoveTokens("k1", 3) == true);
20
- assert(limiter.getTokensRemaining("k1") == 2);
21
- assert(limiter.tryRemoveTokens("k1", 4) == false);
22
- assert(limiter.tryRemoveTokens("k2", 4) == true);
23
- yield new Promise(f => setTimeout(f, 1500));
24
- assert(limiter.tryRemoveTokens("k1", 4) == false);
25
- assert(limiter.getTokensRemaining("k1") == 2);
26
- yield new Promise(f => setTimeout(f, 1000));
27
- assert(limiter.tryRemoveTokens("k1", 4) == true);
28
- //new bucket, won't expire until 2 seconds from now
29
- assert(limiter.getTokensRemaining("k1") == 1);
30
- assert(limiter.tryRemoveTokens("k1", 2) == false);
31
- yield new Promise(f => setTimeout(f, 1900));
32
- assert(limiter.tryRemoveTokens("k1", 2) == false);
33
- assert(limiter.getTokensRemaining("k1") == 1);
34
- yield new Promise(f => setTimeout(f, 200));
35
- assert(limiter.tryRemoveTokens("k1", 2) == true);
36
- assert(limiter.getTokensRemaining("k1") == 3);
37
- });
38
- }
39
- };
@@ -1,7 +0,0 @@
1
- type EventHandler<StateName> = (...args: any) => StateName | void;
2
- export type State<StateName extends string, EventName extends string> = Partial<Record<EventName | "onTransitionIn", EventHandler<StateName>>>;
3
- export declare function makeStateMachine<StateName extends string, EventName extends string>(states: Record<StateName | "IDLE", State<StateName, EventName>>): {
4
- trigger(eventName: EventName, ...args: any): void;
5
- getState(): StateName | "IDLE";
6
- };
7
- export {};
@@ -1,36 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.makeStateMachine = void 0;
4
- function makeStateMachine(states) {
5
- var _a, _b;
6
- let currentStateName = "IDLE";
7
- (_b = (_a = states[currentStateName]).onTransitionIn) === null || _b === void 0 ? void 0 : _b.call(_a);
8
- let lock = 0;
9
- return {
10
- trigger(eventName, ...args) {
11
- var _a, _b;
12
- if (lock)
13
- throw new Error("Cannot trigger an event synchronously while inside an event handler");
14
- lock++;
15
- try {
16
- const currentState = states[currentStateName];
17
- if (!(eventName in currentState))
18
- throw new Error("Missing handler " + currentStateName + "." + eventName);
19
- const nextStateName = currentState[eventName](...args);
20
- if (nextStateName) {
21
- if (!(nextStateName in states))
22
- throw new Error("Missing state " + nextStateName);
23
- currentStateName = nextStateName;
24
- (_b = (_a = states[currentStateName]).onTransitionIn) === null || _b === void 0 ? void 0 : _b.call(_a);
25
- }
26
- }
27
- finally {
28
- lock--;
29
- }
30
- },
31
- getState() {
32
- return currentStateName;
33
- }
34
- };
35
- }
36
- exports.makeStateMachine = makeStateMachine;
@@ -1,4 +0,0 @@
1
- declare const _default: {
2
- stateMachine1(): Promise<void>;
3
- };
4
- export default _default;
@@ -1,69 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- const state_machine_1 = require("./state-machine");
13
- const assert = require("assert");
14
- exports.default = {
15
- stateMachine1() {
16
- return __awaiter(this, void 0, void 0, function* () {
17
- const sm = (0, state_machine_1.makeStateMachine)({
18
- IDLE: {
19
- play() {
20
- return "PLAYING";
21
- },
22
- stop() { },
23
- goto(state) {
24
- return state;
25
- }
26
- },
27
- PLAYING: {
28
- play() { },
29
- stop() {
30
- return "STOPPING";
31
- }
32
- },
33
- STOPPING: {
34
- onTransitionIn() {
35
- this.timer = setTimeout(() => sm.trigger("onStop"), 2000);
36
- },
37
- onStop() {
38
- return "IDLE";
39
- },
40
- play() {
41
- clearTimeout(this.timer);
42
- return "PLAYING";
43
- },
44
- stop() { }
45
- },
46
- STUCK: {}
47
- });
48
- assert(sm.getState() == "IDLE");
49
- sm.trigger("play");
50
- assert(sm.getState() == "PLAYING");
51
- sm.trigger("stop");
52
- assert(sm.getState() == "STOPPING");
53
- yield sleep(1000);
54
- sm.trigger("play");
55
- assert(sm.getState() == "PLAYING");
56
- yield sleep(3000);
57
- assert(sm.getState() == "PLAYING");
58
- sm.trigger("stop");
59
- assert(sm.getState() == "STOPPING");
60
- yield sleep(3000);
61
- assert(sm.getState() == "IDLE");
62
- sm.trigger("goto", "STUCK");
63
- assert(sm.getState() == "STUCK");
64
- });
65
- },
66
- };
67
- function sleep(ms) {
68
- return new Promise(f => setTimeout(f, ms));
69
- }