@temperlang/core 0.3.0 → 0.5.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/async.js +71 -0
- package/bitvector.js +103 -0
- package/check-type.js +65 -0
- package/core.js +186 -0
- package/date.js +45 -0
- package/deque.js +67 -0
- package/float.js +74 -0
- package/index.js +13 -1254
- package/interface.js +56 -0
- package/listed.js +289 -0
- package/mapped.js +216 -0
- package/net.js +41 -0
- package/package.json +1 -1
- package/pair.js +69 -0
- package/regex.js +98 -77
- package/string.js +221 -0
- package/interface-types.js +0 -121
package/interface.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* A temper Super-Type.
|
|
4
|
+
*
|
|
5
|
+
* Returns a `Union`.
|
|
6
|
+
* Temper types always extend a Union made by this function.
|
|
7
|
+
* Only takes temper types as inputs.
|
|
8
|
+
*
|
|
9
|
+
* Examples:
|
|
10
|
+
*
|
|
11
|
+
* Basic usage with multiple inheritance.
|
|
12
|
+
* ```js
|
|
13
|
+
* class Plant extends type() {}
|
|
14
|
+
* class Potato extends type(Plant) {}
|
|
15
|
+
* class Snack extends type() {}
|
|
16
|
+
* class Fry extends type(Potato, Snack) {}
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* The following will not work because Basic does not extend `type()`.
|
|
20
|
+
* ```
|
|
21
|
+
* class Basic {}
|
|
22
|
+
* class Sub extends type(Basic) {}
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* The following will work.
|
|
26
|
+
* ```
|
|
27
|
+
* class Pet extends type() {}
|
|
28
|
+
* class Dog extends Pet {}
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* type()
|
|
32
|
+
* @param {typeof Union} superTypes
|
|
33
|
+
* @return {Union}
|
|
34
|
+
*/
|
|
35
|
+
export const type = (...superTypes) => {
|
|
36
|
+
const key = Symbol();
|
|
37
|
+
|
|
38
|
+
class Union {
|
|
39
|
+
static [Symbol.hasInstance] = (instance) => {
|
|
40
|
+
return typeof instance === 'object' && instance !== null && key in instance;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
Union.prototype[key] = null;
|
|
45
|
+
|
|
46
|
+
for (const superType of superTypes.reverse()) {
|
|
47
|
+
let proto = Object.getPrototypeOf(superType.prototype);
|
|
48
|
+
for (const sym of Object.getOwnPropertySymbols(proto)) {
|
|
49
|
+
Union.prototype[sym] = null;
|
|
50
|
+
}
|
|
51
|
+
Object.defineProperties(Union.prototype, Object.getOwnPropertyDescriptors(proto));
|
|
52
|
+
Object.defineProperties(Union.prototype, Object.getOwnPropertyDescriptors(superType.prototype));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return Union;
|
|
56
|
+
};
|
package/listed.js
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
|
|
2
|
+
// Implements extension method Listed::mapDropping
|
|
3
|
+
import {bubble} from "./core.js";
|
|
4
|
+
|
|
5
|
+
export const listedMapDropping = () => {
|
|
6
|
+
throw new Error("TODO List::mapDropping");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Implements extension method Listed::map
|
|
11
|
+
* @template T
|
|
12
|
+
* @template R
|
|
13
|
+
* @param {T[]} ls
|
|
14
|
+
* @param {(prev: T) => R} transform
|
|
15
|
+
* @returns {Readonly<R[]>}
|
|
16
|
+
*/
|
|
17
|
+
export const listedMap = (ls, transform) => {
|
|
18
|
+
let mapped = [];
|
|
19
|
+
let { length } = ls;
|
|
20
|
+
for (let i = 0; i < length; ++i) {
|
|
21
|
+
mapped[i] = transform(ls[i]);
|
|
22
|
+
}
|
|
23
|
+
return Object.freeze(mapped);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Implements extension method Listed::reduceFrom
|
|
28
|
+
* @template T, R
|
|
29
|
+
* @param {T[]} ls
|
|
30
|
+
* @param {R} initial
|
|
31
|
+
* @param {(prev: T, cur: R) => R}accumulate
|
|
32
|
+
* @returns {R}
|
|
33
|
+
*/
|
|
34
|
+
export const listedReduceFrom = (ls, initial, accumulate) => {
|
|
35
|
+
return ls.reduce(accumulate, initial);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Implements extension method Listed::sort
|
|
40
|
+
* @template T
|
|
41
|
+
* @param {T[]} ls
|
|
42
|
+
* @param {(lhs: T, rhs: T) => number} compare
|
|
43
|
+
*/
|
|
44
|
+
export const listedSorted = (ls, compare) => {
|
|
45
|
+
return Object.freeze(ls.slice().sort(compare));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Implements extension method Listed::toList
|
|
50
|
+
* @template T
|
|
51
|
+
* @param {T[] | Readonly<T[]>} ls
|
|
52
|
+
* @returns {Readonly<T[]>}
|
|
53
|
+
*/
|
|
54
|
+
export const listedToList = (ls) => {
|
|
55
|
+
if (Object.isFrozen(ls)) {
|
|
56
|
+
return ls;
|
|
57
|
+
} else {
|
|
58
|
+
return listBuilderToList(ls);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Implements extension method ListBuilder::add
|
|
65
|
+
* @template T
|
|
66
|
+
* @param {T[]} ls
|
|
67
|
+
* @param {T} newItem
|
|
68
|
+
* @param {number | null} [at]
|
|
69
|
+
*/
|
|
70
|
+
export const listBuilderAdd = (ls, newItem, at) => {
|
|
71
|
+
if (at == null) {
|
|
72
|
+
// Technically, we could also use splice instead of push for this case.
|
|
73
|
+
// Which is better might depend on minifiers and/or execution speed.
|
|
74
|
+
ls.push(newItem);
|
|
75
|
+
} else {
|
|
76
|
+
if (at < 0 || at > ls.length) {
|
|
77
|
+
bubble();
|
|
78
|
+
}
|
|
79
|
+
ls.splice(at, 0, newItem);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Implements extension method ListBuilder::addAll
|
|
85
|
+
* @template T
|
|
86
|
+
* @param {T[]} ls
|
|
87
|
+
* @param {T[]} newItems
|
|
88
|
+
* @param {number | null} [at]
|
|
89
|
+
*/
|
|
90
|
+
export const listBuilderAddAll = (ls, newItems, at) => {
|
|
91
|
+
if (at == null) {
|
|
92
|
+
ls.push(...newItems);
|
|
93
|
+
} else {
|
|
94
|
+
if (at < 0 || at > ls.length) {
|
|
95
|
+
bubble();
|
|
96
|
+
}
|
|
97
|
+
ls.splice(at, 0, ...newItems);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Implements extension method Listed::filter
|
|
103
|
+
* @template T
|
|
104
|
+
* @param {T[]} ls
|
|
105
|
+
* @param {(T) => boolean} predicate
|
|
106
|
+
* @returns {Readonly<T[]>}
|
|
107
|
+
*/
|
|
108
|
+
export const listedFilter = (ls, predicate) => {
|
|
109
|
+
let filtered = null;
|
|
110
|
+
let nFiltered = 0; // Just past index of last element of ls filtered onto filtered
|
|
111
|
+
let { length } = ls;
|
|
112
|
+
for (let i = 0; i < length; ++i) {
|
|
113
|
+
let element = ls[i];
|
|
114
|
+
let ok = predicate(element);
|
|
115
|
+
if (!ok) {
|
|
116
|
+
if (!filtered) {
|
|
117
|
+
filtered = [];
|
|
118
|
+
}
|
|
119
|
+
filtered.push(...ls.slice(nFiltered, i));
|
|
120
|
+
nFiltered = i + 1;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
let fullyFiltered;
|
|
124
|
+
if (filtered) {
|
|
125
|
+
filtered.push(...ls.slice(nFiltered, length));
|
|
126
|
+
fullyFiltered = filtered;
|
|
127
|
+
} else {
|
|
128
|
+
fullyFiltered = ls;
|
|
129
|
+
}
|
|
130
|
+
return Object.freeze(fullyFiltered);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Implements extension method Listed::get
|
|
135
|
+
* @template T
|
|
136
|
+
* @param {T[]} ls
|
|
137
|
+
* @param {number} i
|
|
138
|
+
* @returns {T}
|
|
139
|
+
*/
|
|
140
|
+
export const listedGet = (ls, i) => {
|
|
141
|
+
let { length } = ls;
|
|
142
|
+
if (0 <= i && i < length) {
|
|
143
|
+
return ls[i];
|
|
144
|
+
}
|
|
145
|
+
bubble();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Implements extension method Listed::getOr
|
|
150
|
+
* @template T
|
|
151
|
+
* @param {T[]} ls
|
|
152
|
+
* @param {number} i
|
|
153
|
+
* @param {T} fallback
|
|
154
|
+
* @returns {T}
|
|
155
|
+
*/
|
|
156
|
+
export const listedGetOr = (ls, i, fallback) => {
|
|
157
|
+
let { length } = ls;
|
|
158
|
+
return 0 <= i && i < length ? ls[i] : fallback;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Implements extension method List::isEmpty
|
|
163
|
+
* @template T
|
|
164
|
+
* @param {T[]} ls
|
|
165
|
+
* @returns {boolean}
|
|
166
|
+
*/
|
|
167
|
+
export const listIsEmpty = (ls) => {
|
|
168
|
+
return !ls.length;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Implements extension method Listed::join
|
|
173
|
+
* @template T
|
|
174
|
+
* @param {T[]} ls
|
|
175
|
+
* @param {string} separator
|
|
176
|
+
* @param {(T) => string} elementStringifier
|
|
177
|
+
* @returns {string}
|
|
178
|
+
*/
|
|
179
|
+
export const listedJoin = (ls, separator, elementStringifier) => {
|
|
180
|
+
let joined = "";
|
|
181
|
+
let { length } = ls;
|
|
182
|
+
for (let i = 0; i < length; ++i) {
|
|
183
|
+
if (i) {
|
|
184
|
+
joined += separator;
|
|
185
|
+
}
|
|
186
|
+
let element = ls[i];
|
|
187
|
+
let stringifiedElement = elementStringifier(element);
|
|
188
|
+
joined += stringifiedElement;
|
|
189
|
+
}
|
|
190
|
+
return joined;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* @template T
|
|
195
|
+
* @param {T[]} ls
|
|
196
|
+
*/
|
|
197
|
+
// Implements extension method ListBuilder::clear
|
|
198
|
+
export const listBuilderClear = (ls) => {
|
|
199
|
+
ls.length = 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Implements extension method ListBuilder::removeLast
|
|
204
|
+
* @template T
|
|
205
|
+
* @param {T[]} ls
|
|
206
|
+
* @returns {T}
|
|
207
|
+
*/
|
|
208
|
+
export const listBuilderRemoveLast = (ls) => {
|
|
209
|
+
if (ls.length) {
|
|
210
|
+
return ls.pop();
|
|
211
|
+
} else {
|
|
212
|
+
bubble();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Implements extension method ListBuilder::reverse
|
|
218
|
+
* @template T
|
|
219
|
+
* @param {T[]} ls
|
|
220
|
+
*/
|
|
221
|
+
export const listBuilderReverse = (ls) => {
|
|
222
|
+
let { length } = ls;
|
|
223
|
+
let lastIndex = length - 1;
|
|
224
|
+
let mid = length >> 1;
|
|
225
|
+
for (let i = 0; i < mid; ++i) {
|
|
226
|
+
let j = lastIndex - i;
|
|
227
|
+
let a = ls[i];
|
|
228
|
+
ls[i] = ls[j];
|
|
229
|
+
ls[j] = a;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Implements extension method ListBuilder::set
|
|
235
|
+
* @template T
|
|
236
|
+
* @param {T[]} ls
|
|
237
|
+
* @param {number} i
|
|
238
|
+
* @param {T} newValue
|
|
239
|
+
*/
|
|
240
|
+
export const listBuilderSet = (ls, i, newValue) => {
|
|
241
|
+
if (0 <= i && i <= ls.length) {
|
|
242
|
+
ls[i] = newValue;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Implements extension method ListBuilder::removeLast
|
|
248
|
+
* @template T
|
|
249
|
+
* @param {T[]} ls
|
|
250
|
+
* @param {number} index
|
|
251
|
+
* @param {number | null} [removeCount]
|
|
252
|
+
* @param {T[] | null} [newValues]
|
|
253
|
+
* @returns {Readonly<T[]>}
|
|
254
|
+
*/
|
|
255
|
+
export const listBuilderSplice = (ls, index, removeCount, newValues) => {
|
|
256
|
+
// Missing count is all, but explicit undefined is 0, so give explicit length.
|
|
257
|
+
if (removeCount == null) {
|
|
258
|
+
removeCount = ls.length;
|
|
259
|
+
}
|
|
260
|
+
return Object.freeze(ls.splice(index, removeCount, ...(newValues || [])));
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Implements extension method ListBuilder::toList
|
|
265
|
+
* @template T
|
|
266
|
+
* @param {T[]} ls
|
|
267
|
+
* @returns {Readonly<T[]>}
|
|
268
|
+
*/
|
|
269
|
+
export const listBuilderToList = (ls) => {
|
|
270
|
+
return Object.freeze(ls.slice());
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Implements extension method Listed::slice
|
|
275
|
+
* @template T
|
|
276
|
+
* @param {T[]} ls
|
|
277
|
+
* @param {number} startInclusive
|
|
278
|
+
* @param {number} endExclusive
|
|
279
|
+
* @returns {Readonly<T[]>}
|
|
280
|
+
*/
|
|
281
|
+
export const listedSlice = (ls, startInclusive, endExclusive) => {
|
|
282
|
+
if (startInclusive < 0) {
|
|
283
|
+
startInclusive = 0;
|
|
284
|
+
}
|
|
285
|
+
if (endExclusive < 0) {
|
|
286
|
+
endExclusive = 0;
|
|
287
|
+
}
|
|
288
|
+
return Object.freeze(ls.slice(startInclusive, endExclusive));
|
|
289
|
+
}
|
package/mapped.js
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { pairConstructor } from "./pair.js";
|
|
2
|
+
import { bubble } from "./core.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {import("./pair.js").Pair} Pair
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @template K, V
|
|
10
|
+
* @extends {Map<K, V>}
|
|
11
|
+
*/
|
|
12
|
+
export class FreezeMap extends Map {
|
|
13
|
+
// TODO Don't worry to freeze? Or worry more by wrapping private map?
|
|
14
|
+
// TODO Wrapping/Object.proxy presumably pays an extra cost when wrapped.
|
|
15
|
+
clear() {
|
|
16
|
+
throw new TypeError();
|
|
17
|
+
}
|
|
18
|
+
delete() {
|
|
19
|
+
throw new TypeError();
|
|
20
|
+
}
|
|
21
|
+
set(key, value) {
|
|
22
|
+
if (Object.isFrozen(this)) {
|
|
23
|
+
// Crash only after frozen because constructor calls set.
|
|
24
|
+
throw new TypeError();
|
|
25
|
+
}
|
|
26
|
+
return super.set(key, value);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @template K, V
|
|
32
|
+
* @param {Pair<K, V>} entries
|
|
33
|
+
* @returns {Map<K, V>}
|
|
34
|
+
*/
|
|
35
|
+
export const mapConstructor = (entries) => {
|
|
36
|
+
return Object.freeze(new FreezeMap(entries));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @template K, V
|
|
41
|
+
* @param {Map<K, V>} entries
|
|
42
|
+
* @returns {Map<K, V>}
|
|
43
|
+
*/
|
|
44
|
+
export const mapBuilderConstructor = (entries) => {
|
|
45
|
+
return new Map();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @template K, V
|
|
50
|
+
* @param {Map<K, V>} builder
|
|
51
|
+
* @param {K} key
|
|
52
|
+
* @returns {V}
|
|
53
|
+
*/
|
|
54
|
+
export const mapBuilderRemove = (builder, key) => {
|
|
55
|
+
const result = builder.get(key);
|
|
56
|
+
if (builder.delete(key)) {
|
|
57
|
+
return result;
|
|
58
|
+
} else {
|
|
59
|
+
bubble();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @template K, V
|
|
65
|
+
* @param {Map<K, V>} builder
|
|
66
|
+
* @param {K} key
|
|
67
|
+
* @param {V} value
|
|
68
|
+
*/
|
|
69
|
+
export const mapBuilderSet = (builder, key, value) => {
|
|
70
|
+
builder.set(key, value);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @template K, V
|
|
75
|
+
* @param {Map<K, V>} builder
|
|
76
|
+
* @returns {FreezeMap<K, V>}
|
|
77
|
+
*/
|
|
78
|
+
export const mappedToMap = (mapped) => {
|
|
79
|
+
if (mapped instanceof FreezeMap) {
|
|
80
|
+
return mapped;
|
|
81
|
+
}
|
|
82
|
+
return Object.freeze(new FreezeMap(mapped));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @template K, V
|
|
87
|
+
* @param {Map<K, V>} mapped
|
|
88
|
+
* @returns {Readonly<FreezeMap<K, V>>}
|
|
89
|
+
*/
|
|
90
|
+
export const mapBuilderToMap = (mapped) => {
|
|
91
|
+
return Object.freeze(new FreezeMap(mapped));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @template K, V
|
|
96
|
+
* @param {Map<K, V>} mapped
|
|
97
|
+
* @returns {Map<K, V>}
|
|
98
|
+
*/
|
|
99
|
+
export const mappedToMapBuilder = (mapped) => {
|
|
100
|
+
return new Map(mapped);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
////////////
|
|
104
|
+
// Mapped //
|
|
105
|
+
////////////
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @template K, V
|
|
109
|
+
* @param {Map<K, V>} map
|
|
110
|
+
* @returns {number}
|
|
111
|
+
*/
|
|
112
|
+
export const mappedLength = (map) => {
|
|
113
|
+
return map.size;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @template K, V
|
|
118
|
+
* @param {Map<K, V>} map
|
|
119
|
+
* @param {K} key
|
|
120
|
+
* @returns {V}
|
|
121
|
+
*/
|
|
122
|
+
export const mappedGet = (map, key) => {
|
|
123
|
+
const result = map.get(key);
|
|
124
|
+
// TODO Under compiler-error-free Temper, could undefined values get set?
|
|
125
|
+
// TODO Would Map<?, Void> be impossible to feed once we get checks in place?
|
|
126
|
+
if (result === undefined) {
|
|
127
|
+
bubble();
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @template K, V
|
|
134
|
+
* @param {Map<K, V>} map
|
|
135
|
+
* @param {K} key
|
|
136
|
+
* @param {V} fallback
|
|
137
|
+
* @returns {V}
|
|
138
|
+
*/
|
|
139
|
+
export const mappedGetOr = (map, key, fallback) => {
|
|
140
|
+
return map.get(key) ?? fallback;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @template K, V
|
|
145
|
+
* @param {Map<K, V>} map
|
|
146
|
+
* @param {K} key
|
|
147
|
+
* @returns {boolean}
|
|
148
|
+
*/
|
|
149
|
+
export const mappedHas = (map, key) => {
|
|
150
|
+
return map.has(key);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @template K, V
|
|
155
|
+
* @param {Map<K, V>} map
|
|
156
|
+
* @returns {Readonly<K[]>}
|
|
157
|
+
*/
|
|
158
|
+
export const mappedKeys = (map) => {
|
|
159
|
+
return Object.freeze(Array.from(map.keys()));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* @template K, V
|
|
164
|
+
* @param {Map<K, V>} map
|
|
165
|
+
* @returns {Readonly<V[]>}
|
|
166
|
+
*/
|
|
167
|
+
export const mappedValues = (map) => {
|
|
168
|
+
return Object.freeze(Array.from(map.values()));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @template K, V
|
|
173
|
+
* @param {Map<K, V>} map
|
|
174
|
+
* @returns {Readonly<Readonly<Pair<K, V>>[]>}
|
|
175
|
+
*/
|
|
176
|
+
export const mappedToList = (map) => {
|
|
177
|
+
return Object.freeze(Array.from(map, ([key, value]) => pairConstructor(key, value)));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* @template K, V, R
|
|
182
|
+
* @param {Map<K, V>} map
|
|
183
|
+
* @param {(value: K) => R} func
|
|
184
|
+
* @returns {Readonly<R[]>}
|
|
185
|
+
*/
|
|
186
|
+
export const mappedToListWith = (map, func) => {
|
|
187
|
+
return Object.freeze(Array.from(map, ([key, value]) => func(key, value)));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @template K, V, R
|
|
192
|
+
* @param {Map<K, V>} map
|
|
193
|
+
* @returns {Readonly<Pair<K, V>>[]}
|
|
194
|
+
*/
|
|
195
|
+
export const mappedToListBuilder = (map) => {
|
|
196
|
+
return Object.freeze(Array.from(map, ([key, value]) => pairConstructor(key, value)));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* @template K, V, R
|
|
201
|
+
* @param {Map<K, V>} map
|
|
202
|
+
* @param {(value: K) => R} func
|
|
203
|
+
* @returns {Readonly<R[]>}
|
|
204
|
+
*/
|
|
205
|
+
export const mappedToListBuilderWith = (map, func) => {
|
|
206
|
+
return Object.freeze(Array.from(map, ([key, value]) => func(key, value)));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* @template K, V
|
|
211
|
+
* @param {Map<K, V>} map
|
|
212
|
+
* @param {(key: K, value: V) => void} func
|
|
213
|
+
*/
|
|
214
|
+
export const mappedForEach = (map, func) => {
|
|
215
|
+
map.forEach((v, k) => func(k, v));
|
|
216
|
+
}
|
package/net.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {string} url
|
|
3
|
+
* @param {"GET" | "POST"} method
|
|
4
|
+
* @param {string | null} bodyContent
|
|
5
|
+
* @param {string | null} bodyMimeType
|
|
6
|
+
* @return {Promise<Response>}
|
|
7
|
+
*/
|
|
8
|
+
export function stdNetSend(url, method, bodyContent, bodyMimeType) {
|
|
9
|
+
let details = { method };
|
|
10
|
+
if (typeof bodyContent === 'string') {
|
|
11
|
+
details.body = bodyContent;
|
|
12
|
+
if (typeof bodyMimeType === 'string') {
|
|
13
|
+
details.headers = { 'Content-Type': bodyMimeType };
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return fetch(url, details);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {Response} r
|
|
21
|
+
* @return {number} an HTTP status code
|
|
22
|
+
*/
|
|
23
|
+
export function netResponseGetStatus(r) {
|
|
24
|
+
return r.status;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {Response} r
|
|
29
|
+
* @return {string | null} the mime-type of the body.
|
|
30
|
+
*/
|
|
31
|
+
export function netResponseGetContentType(r) {
|
|
32
|
+
return r.headers.get('Content-Type') || null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {Response} r
|
|
37
|
+
* @return {Promise<string | null>} the body content.
|
|
38
|
+
*/
|
|
39
|
+
export function netResponseGetBodyContent(r) {
|
|
40
|
+
return r.text();
|
|
41
|
+
}
|
package/package.json
CHANGED
package/pair.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* @template K, V
|
|
4
|
+
*/
|
|
5
|
+
export class Pair {
|
|
6
|
+
/** @type {K} */
|
|
7
|
+
key;
|
|
8
|
+
|
|
9
|
+
/** @type {V} */
|
|
10
|
+
value;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {K} key
|
|
14
|
+
* @param {V} value
|
|
15
|
+
*/
|
|
16
|
+
constructor(key, value) {
|
|
17
|
+
this.key = key;
|
|
18
|
+
this.value = value;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The key held by this pair.
|
|
23
|
+
* @returns {K}
|
|
24
|
+
*/
|
|
25
|
+
get key() {
|
|
26
|
+
return this.key;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The value held by this pair.
|
|
31
|
+
* @returns {V}
|
|
32
|
+
*/
|
|
33
|
+
get value() {
|
|
34
|
+
return this.value;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The first index is the same as the key.
|
|
39
|
+
* @returns {K}
|
|
40
|
+
*/
|
|
41
|
+
get [0]() {
|
|
42
|
+
return this.key;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The second index is the same as the value.
|
|
47
|
+
* @returns {V}
|
|
48
|
+
*/
|
|
49
|
+
get [1]() {
|
|
50
|
+
return this.value;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @returns {2}
|
|
55
|
+
*/
|
|
56
|
+
get length() {
|
|
57
|
+
return 2;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @template K, V
|
|
63
|
+
* @param {K} key
|
|
64
|
+
* @param {V} value
|
|
65
|
+
* @returns {Readonly<Pair<K, V>>}
|
|
66
|
+
*/
|
|
67
|
+
export const pairConstructor = (key, value) => {
|
|
68
|
+
return Object.freeze(new Pair(key, value));
|
|
69
|
+
}
|