@lsdsoftware/utils 1.0.0 → 1.0.1
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 +35 -16
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/index.test.js +2 -2
- package/dist/line-reader.d.ts +3 -0
- package/dist/line-reader.js +32 -0
- package/dist/{line-split-stream.test.js → line-reader.test.js} +14 -26
- package/package.json +1 -1
- package/dist/line-split-stream.d.ts +0 -3
- package/dist/line-split-stream.js +0 -28
- /package/dist/{line-split-stream.test.d.ts → line-reader.test.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Useful JavaScript utilities
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
### State Machine
|
|
5
5
|
Make implementing state machines less error prone.
|
|
6
6
|
|
|
7
7
|
```typescript
|
|
@@ -48,12 +48,36 @@ sm.getState() //BUSY
|
|
|
48
48
|
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
Dispatch messages to handlers. This utility assumes messages are one of three types: request, response, or notification
|
|
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).
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
```typescript
|
|
55
|
+
interface Request {
|
|
56
|
+
to: string
|
|
57
|
+
type: "request"
|
|
58
|
+
id: "string"
|
|
59
|
+
method: string
|
|
60
|
+
args: Record<string, unknown>
|
|
61
|
+
}
|
|
55
62
|
|
|
56
|
-
|
|
63
|
+
interface Notification {
|
|
64
|
+
to: string
|
|
65
|
+
type: "notification"
|
|
66
|
+
method: string
|
|
67
|
+
args: Record<string, unknown>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface Response {
|
|
71
|
+
type: "response"
|
|
72
|
+
id: string
|
|
73
|
+
error: unknown
|
|
74
|
+
result: unknown
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
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
|
+
|
|
80
|
+
A _myAddress_ parameter provided at construction is used to filter messages. Only requests and notifications whose _to_ attribute matches _myAddress_ will be processed.
|
|
57
81
|
|
|
58
82
|
```typescript
|
|
59
83
|
import { makeMessageDispatcher } from "@lsdsoftware/utils"
|
|
@@ -91,7 +115,7 @@ dispatcher.waitForResponse(id)
|
|
|
91
115
|
|
|
92
116
|
|
|
93
117
|
|
|
94
|
-
|
|
118
|
+
### Rate Limiter
|
|
95
119
|
Basic rate limiter using the token bucket algorithm.
|
|
96
120
|
|
|
97
121
|
```typescript
|
|
@@ -107,7 +131,7 @@ function handleRequest(userId, req) {
|
|
|
107
131
|
|
|
108
132
|
|
|
109
133
|
|
|
110
|
-
|
|
134
|
+
### Connection Manager
|
|
111
135
|
Takes a connect() method and:
|
|
112
136
|
- Only call it to create a connection when needed
|
|
113
137
|
- Automatically retry on failure
|
|
@@ -134,16 +158,11 @@ conMgr.shutdown()
|
|
|
134
158
|
|
|
135
159
|
|
|
136
160
|
|
|
137
|
-
|
|
138
|
-
|
|
161
|
+
### Line Reader
|
|
162
|
+
Split text into lines
|
|
139
163
|
|
|
140
164
|
```typescript
|
|
141
|
-
import {
|
|
142
|
-
|
|
143
|
-
const splitter = makeLineSplitStream()
|
|
144
|
-
splitter.on('data', line => console.log('Received line:', line))
|
|
165
|
+
import { makeLineReader } from "@lsdsoftware/utils"
|
|
145
166
|
|
|
146
|
-
|
|
147
|
-
splitter.write('This is a line\nThis is another line\nAnd this is a line as well')
|
|
148
|
-
splitter.end() // End the stream to see the _flush effect.
|
|
167
|
+
myStream.pipe(makeLineReader(line => console.log(line)))
|
|
149
168
|
```
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { makeLineReader } from "./line-reader";
|
|
2
2
|
import { makeStateMachine } from "./state-machine";
|
|
3
3
|
import { makeConnectionManager } from "./connection-manager";
|
|
4
4
|
import { makeMessageDispatcher } from "./message-dispatcher";
|
|
5
5
|
import { makeRateLimiter } from "./rate-limiter";
|
|
6
|
-
export {
|
|
6
|
+
export { makeLineReader, makeStateMachine, makeConnectionManager, makeMessageDispatcher, makeRateLimiter, };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.makeRateLimiter = exports.makeMessageDispatcher = exports.makeConnectionManager = exports.makeStateMachine = exports.
|
|
4
|
-
const
|
|
5
|
-
Object.defineProperty(exports, "
|
|
3
|
+
exports.makeRateLimiter = exports.makeMessageDispatcher = exports.makeConnectionManager = exports.makeStateMachine = exports.makeLineReader = void 0;
|
|
4
|
+
const line_reader_1 = require("./line-reader");
|
|
5
|
+
Object.defineProperty(exports, "makeLineReader", { enumerable: true, get: function () { return line_reader_1.makeLineReader; } });
|
|
6
6
|
const state_machine_1 = require("./state-machine");
|
|
7
7
|
Object.defineProperty(exports, "makeStateMachine", { enumerable: true, get: function () { return state_machine_1.makeStateMachine; } });
|
|
8
8
|
const connection_manager_1 = require("./connection-manager");
|
package/dist/index.test.js
CHANGED
|
@@ -9,10 +9,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
const
|
|
12
|
+
const line_reader_test_1 = require("./line-reader.test");
|
|
13
13
|
const rate_limiter_test_1 = require("./rate-limiter.test");
|
|
14
14
|
const state_machine_test_1 = require("./state-machine.test");
|
|
15
|
-
run(Object.assign(Object.assign(Object.assign({},
|
|
15
|
+
run(Object.assign(Object.assign(Object.assign({}, line_reader_test_1.default), rate_limiter_test_1.default), state_machine_test_1.default))
|
|
16
16
|
.catch(console.error);
|
|
17
17
|
function run(tests) {
|
|
18
18
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeLineReader = void 0;
|
|
4
|
+
const stream_1 = require("stream");
|
|
5
|
+
const string_decoder_1 = require("string_decoder");
|
|
6
|
+
function makeLineReader(lineCallback) {
|
|
7
|
+
// Buffer for the part of the chunk that doesn't form a complete line.
|
|
8
|
+
let remainder = '';
|
|
9
|
+
const decoder = new string_decoder_1.StringDecoder();
|
|
10
|
+
return new stream_1.Writable({
|
|
11
|
+
//prevent auto-decoding string to Buffer, so processed chunk could be either string or Buffer
|
|
12
|
+
decodeStrings: false,
|
|
13
|
+
write(chunk, encoding, callback) {
|
|
14
|
+
// encoding param here is irrelevant because it applies only to string chunks
|
|
15
|
+
const chunkStr = remainder + decoder.write(chunk);
|
|
16
|
+
const lines = chunkStr.split('\n');
|
|
17
|
+
// Keep the last line in remainder if it doesn't end with a newline character.
|
|
18
|
+
remainder = lines.pop();
|
|
19
|
+
// Push each complete line.
|
|
20
|
+
for (const line of lines)
|
|
21
|
+
lineCallback(line);
|
|
22
|
+
callback();
|
|
23
|
+
},
|
|
24
|
+
final(callback) {
|
|
25
|
+
// When the stream is ending, push any remainder as a line if it's not empty.
|
|
26
|
+
if (remainder)
|
|
27
|
+
lineCallback(remainder);
|
|
28
|
+
callback();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
exports.makeLineReader = makeLineReader;
|
|
@@ -9,50 +9,38 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
const
|
|
12
|
+
const line_reader_1 = require("./line-reader");
|
|
13
13
|
const assert = require("assert");
|
|
14
14
|
exports.default = {
|
|
15
15
|
lineSplitStream1() {
|
|
16
16
|
return __awaiter(this, void 0, void 0, function* () {
|
|
17
|
-
const
|
|
17
|
+
const lines = [];
|
|
18
|
+
const splitter = (0, line_reader_1.makeLineReader)(line => lines.push(line));
|
|
18
19
|
splitter.write('This is a line\nThis is another line\nAnd this is a line as well');
|
|
19
20
|
splitter.end();
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
splitter.on('end', () => fulfill(accum));
|
|
24
|
-
});
|
|
25
|
-
assert(lines[0] == "This is a line\n" &&
|
|
26
|
-
lines[1] == "This is another line\n" &&
|
|
27
|
-
lines[2] == "And this is a line as well\n");
|
|
21
|
+
assert(lines[0] == "This is a line" &&
|
|
22
|
+
lines[1] == "This is another line" &&
|
|
23
|
+
lines[2] == "And this is a line as well");
|
|
28
24
|
});
|
|
29
25
|
},
|
|
30
26
|
lineSplitStream2() {
|
|
31
27
|
return __awaiter(this, void 0, void 0, function* () {
|
|
32
|
-
const
|
|
28
|
+
const lines = [];
|
|
29
|
+
const splitter = (0, line_reader_1.makeLineReader)(line => lines.push(line));
|
|
33
30
|
splitter.write('\nThis is a line\n');
|
|
34
31
|
splitter.end();
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
splitter.on('data', line => accum.push(line));
|
|
38
|
-
splitter.on('end', () => fulfill(accum));
|
|
39
|
-
});
|
|
40
|
-
assert(lines[0] == "\n" &&
|
|
41
|
-
lines[1] == "This is a line\n");
|
|
32
|
+
assert(lines[0] == "" &&
|
|
33
|
+
lines[1] == "This is a line");
|
|
42
34
|
});
|
|
43
35
|
},
|
|
44
36
|
lineSplitStream3() {
|
|
45
37
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
-
const
|
|
38
|
+
const lines = [];
|
|
39
|
+
const splitter = (0, line_reader_1.makeLineReader)(line => lines.push(line));
|
|
47
40
|
splitter.write('\n\n');
|
|
48
41
|
splitter.end();
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
splitter.on('data', line => accum.push(line));
|
|
52
|
-
splitter.on('end', () => fulfill(accum));
|
|
53
|
-
});
|
|
54
|
-
assert(lines[0] == "\n" &&
|
|
55
|
-
lines[1] == "\n");
|
|
42
|
+
assert(lines[0] == "" &&
|
|
43
|
+
lines[1] == "");
|
|
56
44
|
});
|
|
57
45
|
},
|
|
58
46
|
};
|
package/package.json
CHANGED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.makeLineSplitStream = void 0;
|
|
4
|
-
const stream_1 = require("stream");
|
|
5
|
-
function makeLineSplitStream() {
|
|
6
|
-
// Buffer for the part of the chunk that doesn't form a complete line.
|
|
7
|
-
let remainder = '';
|
|
8
|
-
return new stream_1.Transform({
|
|
9
|
-
transform(chunk, encoding, callback) {
|
|
10
|
-
// Convert chunk to string and add it to the remainder.
|
|
11
|
-
const chunkStr = remainder + chunk.toString();
|
|
12
|
-
const lines = chunkStr.split('\n');
|
|
13
|
-
// Keep the last line in remainder if it doesn't end with a newline character.
|
|
14
|
-
remainder = lines.pop();
|
|
15
|
-
// Push each complete line.
|
|
16
|
-
for (const line of lines)
|
|
17
|
-
this.push(line + '\n');
|
|
18
|
-
callback();
|
|
19
|
-
},
|
|
20
|
-
flush(callback) {
|
|
21
|
-
// When the stream is ending, push any remainder as a line if it's not empty.
|
|
22
|
-
if (remainder)
|
|
23
|
-
this.push(remainder + '\n');
|
|
24
|
-
callback();
|
|
25
|
-
},
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
exports.makeLineSplitStream = makeLineSplitStream;
|
|
File without changes
|