@okikio/observables 1.0.2 → 1.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/README.md +117 -6
- package/esm/helpers/_types.d.ts +62 -0
- package/esm/helpers/_types.d.ts.map +1 -1
- package/esm/helpers/operations/combination.d.ts +112 -3
- package/esm/helpers/operations/combination.d.ts.map +1 -1
- package/esm/helpers/operations/combination.js +682 -115
- package/esm/helpers/operations/conditional.d.ts +77 -1
- package/esm/helpers/operations/conditional.d.ts.map +1 -1
- package/esm/helpers/operations/conditional.js +139 -0
- package/esm/helpers/operators.d.ts +57 -0
- package/esm/helpers/operators.d.ts.map +1 -1
- package/esm/helpers/operators.js +139 -4
- package/esm/helpers/utils.d.ts +73 -1
- package/esm/helpers/utils.d.ts.map +1 -1
- package/esm/helpers/utils.js +168 -0
- package/package.json +1 -1
- package/script/helpers/_types.d.ts +62 -0
- package/script/helpers/_types.d.ts.map +1 -1
- package/script/helpers/operations/combination.d.ts +112 -3
- package/script/helpers/operations/combination.d.ts.map +1 -1
- package/script/helpers/operations/combination.js +686 -115
- package/script/helpers/operations/conditional.d.ts +77 -1
- package/script/helpers/operations/conditional.d.ts.map +1 -1
- package/script/helpers/operations/conditional.js +143 -0
- package/script/helpers/operators.d.ts +57 -0
- package/script/helpers/operators.d.ts.map +1 -1
- package/script/helpers/operators.js +141 -4
- package/script/helpers/utils.d.ts +73 -1
- package/script/helpers/utils.d.ts.map +1 -1
- package/script/helpers/utils.js +172 -0
package/script/helpers/utils.js
CHANGED
|
@@ -4,8 +4,13 @@ exports.isTransformStreamOptions = isTransformStreamOptions;
|
|
|
4
4
|
exports.isTransformFunctionOptions = isTransformFunctionOptions;
|
|
5
5
|
exports.applyOperator = applyOperator;
|
|
6
6
|
exports.toStream = toStream;
|
|
7
|
+
exports.fromStreamPair = fromStreamPair;
|
|
8
|
+
exports.streamAsObservable = streamAsObservable;
|
|
9
|
+
exports.observableInputToStream = observableInputToStream;
|
|
10
|
+
exports.fromObservableOperator = fromObservableOperator;
|
|
7
11
|
exports.injectError = injectError;
|
|
8
12
|
const error_js_1 = require("../error.js");
|
|
13
|
+
const observable_js_1 = require("../observable.js");
|
|
9
14
|
/**
|
|
10
15
|
* Type guard to check if options is a TransformStreamOptions
|
|
11
16
|
*
|
|
@@ -125,6 +130,173 @@ function toStream(iterable) {
|
|
|
125
130
|
},
|
|
126
131
|
});
|
|
127
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Adapts a readable/writable stream pair into an Observable operator.
|
|
135
|
+
*
|
|
136
|
+
* Some platform transforms, such as `CompressionStream`, expose a writable side
|
|
137
|
+
* and a readable side without being created through this library's operator
|
|
138
|
+
* builders. This helper turns that pair into a normal `Operator` so it can be
|
|
139
|
+
* used inside `pipe()` like any built-in operator.
|
|
140
|
+
*
|
|
141
|
+
* A fresh pair is created for each operator application. That preserves the
|
|
142
|
+
* cold semantics of the surrounding Observable pipeline and avoids reusing a
|
|
143
|
+
* consumed stream pair across subscriptions.
|
|
144
|
+
*
|
|
145
|
+
* @typeParam TIn - Chunk type written into the pair
|
|
146
|
+
* @typeParam TOut - Chunk type read from the pair
|
|
147
|
+
* @param createPair - Factory that returns a fresh readable/writable pair
|
|
148
|
+
* @returns An operator that pipes input through the created pair
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* const gzip = fromStreamPair<Uint8Array, Uint8Array>(
|
|
153
|
+
* () => new CompressionStream('gzip')
|
|
154
|
+
* );
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
function fromStreamPair(createPair) {
|
|
158
|
+
return (source) => source.pipeThrough(createPair());
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Wraps a `ReadableStream` as an Observable so foreign Observable-style
|
|
162
|
+
* operators can subscribe to it directly.
|
|
163
|
+
*
|
|
164
|
+
* This avoids first converting the stream into an async-iterable Observable via
|
|
165
|
+
* `Observable.from()`, which would add an extra adaptation layer before the
|
|
166
|
+
* foreign operator even starts running.
|
|
167
|
+
*/
|
|
168
|
+
function streamAsObservable(stream) {
|
|
169
|
+
return new observable_js_1.Observable((observer) => {
|
|
170
|
+
const reader = stream.getReader();
|
|
171
|
+
let cancelled = false;
|
|
172
|
+
void (async () => {
|
|
173
|
+
try {
|
|
174
|
+
while (!cancelled && !observer.closed) {
|
|
175
|
+
const { done, value } = await reader.read();
|
|
176
|
+
if (done) {
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
observer.next(value);
|
|
180
|
+
}
|
|
181
|
+
if (!cancelled && !observer.closed) {
|
|
182
|
+
observer.complete();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
if (!cancelled && !observer.closed) {
|
|
187
|
+
observer.error(err);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
finally {
|
|
191
|
+
try {
|
|
192
|
+
reader.releaseLock();
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// Releasing the reader is best-effort during teardown.
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
})();
|
|
199
|
+
return () => {
|
|
200
|
+
cancelled = true;
|
|
201
|
+
void reader.cancel();
|
|
202
|
+
};
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Returns true when a value exposes a direct `subscribe()` method.
|
|
207
|
+
*
|
|
208
|
+
* Many Observable libraries return subscribable objects that are usable without
|
|
209
|
+
* first going through this library's `Observable.from()`. Detecting that shape
|
|
210
|
+
* lets interop stay direct for outputs such as RxJS Observables.
|
|
211
|
+
*/
|
|
212
|
+
function hasSubscribe(input) {
|
|
213
|
+
return typeof input === "object" && input !== null &&
|
|
214
|
+
typeof input.subscribe === "function";
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Subscribes to an Observable-like output and exposes it as a ReadableStream.
|
|
218
|
+
*
|
|
219
|
+
* Foreign operators are allowed to return either a normal `Observable.from()`
|
|
220
|
+
* input or a direct subscribable from another Observable implementation.
|
|
221
|
+
* Converting the result with a direct subscription avoids the extra
|
|
222
|
+
* async-generator and stream layers that `pull(...)+toStream()` would add.
|
|
223
|
+
*/
|
|
224
|
+
function observableInputToStream(input, errorContext) {
|
|
225
|
+
let subscription;
|
|
226
|
+
return new ReadableStream({
|
|
227
|
+
start(controller) {
|
|
228
|
+
const source = hasSubscribe(input) ? input : observable_js_1.Observable.from(input);
|
|
229
|
+
subscription = source.subscribe({
|
|
230
|
+
next(value) {
|
|
231
|
+
try {
|
|
232
|
+
controller.enqueue(value);
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
// Downstream cancellation already decided the stream outcome.
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
error(error) {
|
|
239
|
+
try {
|
|
240
|
+
controller.enqueue(error_js_1.ObservableError.from(error, errorContext));
|
|
241
|
+
controller.close();
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// Downstream cancellation already decided the stream outcome.
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
complete() {
|
|
248
|
+
try {
|
|
249
|
+
controller.close();
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
// Downstream cancellation already decided the stream outcome.
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
},
|
|
257
|
+
cancel() {
|
|
258
|
+
subscription?.unsubscribe?.();
|
|
259
|
+
subscription = undefined;
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Adapts a foreign Observable-style operator into a stream operator.
|
|
265
|
+
*
|
|
266
|
+
* Libraries such as RxJS model operators as functions from one Observable-like
|
|
267
|
+
* source to another Observable-like result. This helper bridges that shape into
|
|
268
|
+
* this library's `Operator` contract by:
|
|
269
|
+
*
|
|
270
|
+
* 1. wrapping the input stream as an Observable-like source
|
|
271
|
+
* 2. calling the foreign operator
|
|
272
|
+
* 3. converting the resulting Observable-like output back into a stream
|
|
273
|
+
*
|
|
274
|
+
* The result keeps this library's buffered error behavior by converting the
|
|
275
|
+
* foreign output into a `ReadableStream` that enqueues wrapped
|
|
276
|
+
* `ObservableError` values instead of failing the readable side outright.
|
|
277
|
+
*
|
|
278
|
+
* @typeParam TIn - Value type accepted by the foreign operator
|
|
279
|
+
* @typeParam TOut - Value type produced by the foreign operator
|
|
280
|
+
* @param operator - Foreign operator function to adapt
|
|
281
|
+
* @returns An operator compatible with this library's `pipe()`
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* ```ts
|
|
285
|
+
* const foreignTakeOne = fromObservableOperator<number, number>((source) =>
|
|
286
|
+
* rxTake(1)(source)
|
|
287
|
+
* , { sourceAdapter: (source) => rxFrom(source) });
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
function fromObservableOperator(operator, options) {
|
|
291
|
+
return (source) => {
|
|
292
|
+
const observableSource = streamAsObservable(source);
|
|
293
|
+
const foreignSource = options?.sourceAdapter
|
|
294
|
+
? options.sourceAdapter(observableSource)
|
|
295
|
+
: observableSource;
|
|
296
|
+
const output = operator(foreignSource);
|
|
297
|
+
return observableInputToStream(output, options?.errorContext ?? "operator:fromObservableOperator:output");
|
|
298
|
+
};
|
|
299
|
+
}
|
|
128
300
|
/**
|
|
129
301
|
* Creates a TransformStream that injects an error at the start and passes through all original data.
|
|
130
302
|
*
|