Skip to content

Commit bfb2c47

Browse files
committed
update the code
1 parent 52e08b0 commit bfb2c47

File tree

7 files changed

+434
-62
lines changed

7 files changed

+434
-62
lines changed

README.md

+6-14
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![tests](https://github.com/kethan/usub/actions/workflows/node.js.yml/badge.svg)](https://github.com/kethan/usub/actions/workflows/node.js.yml) [![Version](https://img.shields.io/npm/v/usub.svg?color=success&style=flat-square)](https://www.npmjs.com/package/usub) [![Badge size](https://deno.bundlejs.com/badge?q=usub&treeshake=[*]&config={"compression":"brotli"})](https://unpkg.com/usub) [![Badge size](https://deno.bundlejs.com/badge?q=usub&treeshake=[*]&config={"compression":"gzip"})](https://unpkg.com/usub)
44

5-
This JavaScript library provides utility functions for handling observables, signals, and asynchronous data streams across various reactive programming libraries. It supports flexible customization to integrate with different libraries, ensuring seamless subscription management and automatic cleanup.
5+
This javascript library provides utility functions for handling observables, signals, and asynchronous data streams across various reactive programming libraries. It supports flexible customization to integrate with different libraries, ensuring seamless subscription management and automatic cleanup.
66

77
## Table of Contents
88

@@ -18,9 +18,9 @@ This JavaScript library provides utility functions for handling observables, sig
1818
- [Any Source](#any-source)
1919
- [Solid.js](#solidjs)
2020
- [Preact Signals](#preact-signals)
21-
- [uSignal](#usignal)
21+
- [usignal](#usignal)
2222
- [@webreflection/signal](#webreflectionsignal)
23-
- [uLive](#ulive)
23+
- [ulive](#ulive)
2424
- [RxJS Subject](#rxjs-subject)
2525
- [Async Iterable](#async-iterable)
2626
- [Synchronous Iterable](#synchronous-iterable)
@@ -50,18 +50,12 @@ import { is, api, sub, get } from "usub";
5050

5151
### Basic Setup
5252

53-
The library exports three primary functions:
53+
The library exports four primary functions:
5454

55-
- **`any`**: Add any type of source to react
5655
- **`is`**: Checks if a value is considered an observable or reactive signal.
5756
- **`api`**: Provides utility functions that can be customized to work with different reactive libraries.
5857
- **`sub`**: Subscribes to an observable or other async/reactive patterns.
59-
60-
Import the functions in your JavaScript file:
61-
62-
```js
63-
import { is, api, sub } from "usub";
64-
```
58+
- **`get`**: get function to retrieve reactive data
6559

6660
### Subscribing to Observables
6761

@@ -345,9 +339,7 @@ const myIterable = {
345339
},
346340
};
347341

348-
for (const value of myIterable) {
349-
console.log(value);
350-
}
342+
sub(myIterable)(console.log);
351343
```
352344
353345
### Finalization and Cleanup

package-lock.json

+15-15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+11-14
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
{
22
"name": "usub",
33
"description": "Subscribe to any reactive sources",
4-
"version": "0.2.4",
4+
"version": "0.3.0",
55
"type": "module",
66
"source": "./src/index.js",
77
"main": "./dist/index.js",
8-
"module": "./dist/index.js",
8+
"module": "./dist/index.es.js",
99
"unpkg": "./dist/index.min.js",
1010
"umd:main": "./dist/index.umd.js",
1111
"exports": {
12-
".": {
13-
"browser": "./dist/index.es.js",
14-
"umd": "./dist/index.umd.js",
15-
"require": "./dist/index.js",
16-
"import": "./dist/index.es.js",
17-
"default": "./dist/index.es.js"
18-
},
19-
"./package.json": "./package.json"
12+
"browser": "./dist/index.es.js",
13+
"umd": "./dist/index.umd.js",
14+
"require": "./dist/index.js",
15+
"import": "./dist/index.es.js",
16+
"default": "./dist/index.es.js"
2017
},
2118
"repository": {
2219
"type": "git",
@@ -27,22 +24,22 @@
2724
],
2825
"scripts": {
2926
"build": "rollup --config rollup.config.js",
30-
"test": "vitest",
31-
"prepare": "husky"
27+
"test": "node --allow-natives-syntax --loader ./test/https-loader.js --expose-gc ./test/index.js"
3228
},
3329
"devDependencies": {
3430
"@rollup/plugin-terser": "^0.4.4",
35-
"husky": "^9.1.4",
3631
"rollup": "^4.20.0",
3732
"rollup-plugin-bundle-size": "^1.0.3",
38-
"vitest": "^2.0.5"
33+
"tst": "^7.3.0"
3934
},
4035
"keywords": [
36+
"rxjs",
4137
"usub",
4238
"reactive",
4339
"state",
4440
"signal",
4541
"async",
42+
"observable",
4643
"observables",
4744
"subscribe",
4845
"effect",

src/index.js

+16-15
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
// Ensure the Symbol for observables is defined
22
Symbol.observable ||= Symbol('observable');
33

4-
// FinalizationRegistry to clean up subscriptions when objects are garbage collected
54
const
6-
registry = new FinalizationRegistry((unsub) => {
7-
if (!unsub?._) {
8-
unsub?.call?.();
9-
}
10-
}),
5+
// FinalizationRegistry to clean up subscriptions when objects are garbage collected
6+
registry = new FinalizationRegistry(unsub => (!unsub?._ && unsub?.call?.())),
7+
118
// Utility function to handle unsubscription and complete callback
129
unsubr = (unsub, cleanup, out) => (
1310
unsub && (out = () => (unsub?.call ? unsub() : unsub?.unsubscribe?.(), out._ = true, cleanup?.()))
@@ -22,37 +19,41 @@ const
2219
// Executes the provided function
2320
effect: (f) => f(),
2421
// Returns false for any value (placeholder implementation)
25-
is: (v) => false,
22+
is: (v) => v?.call,
2623
// Retrieves the value (returns it as is)
27-
get: (v) => v,
24+
get: (v) => v?.call(),
2825
},
2926

30-
// Utility function to handle and unwrap values, especially functions
31-
get = (v) => v?.call ? get(v()) : api.is(v) ? get(api.get(v)) : v,
27+
// Utility function to handle and unwrap values of signals, observable, etc especially functions
28+
get = (v) => api.is(v) ? get(api.get(v)) : v?.call ? get(v()) : v,
3229

3330
// Checks if the argument is considered an observable
3431
is = (arg) => arg && !!(
3532
arg[Symbol.observable] || // Observable symbol
3633
arg[Symbol.asyncIterator] || // Async iterator
34+
arg[Symbol.iterator] || // Sync iterator
35+
arg.call && arg.set || // Observ-*
3736
arg.then || // Promise
38-
(target?.call && !api?.any) || // Function
3937
arg.subscribe || // Observable with subscribe method
40-
api.is(arg) // Custom observable check
38+
api.is(arg) || // Custom observable check
39+
arg.call // Function
4140
),
41+
// Subscribe to an observable or value, and provide a callback for each value
4242
sub = (target, stop, unsub) => (next, error, cleanup) => target && (
4343
unsub = unsubr((target[Symbol.observable]?.() || target).subscribe?.((v) => next(get(v)), error, cleanup), cleanup) ||
44-
(((target?.call && !api?.any) || api.is(target)) && api.effect(() => (next(get(target)), api?.cleanup?.(cleanup) || cleanup))) ||
44+
target.set && target.call?.(stop, next) ||
45+
((!api?.any && (api.is(target) || target?.call)) && api.effect(() => (next(get(target)), api?.cleanup?.(cleanup), cleanup))) ||
4546
(
4647
target.then?.(v => (!stop && next(get(v)), cleanup?.()), error) ||
47-
target[Symbol.asyncIterator] && (async v => {
48+
(target[Symbol.asyncIterator] || target[Symbol.iterator]) && (async v => {
4849
try {
4950
// FIXME: possible drawback: it will catch error happened in next, not only in iterator
5051
for await (v of target) { if (stop) return; next(get(v)) }
5152
cleanup?.()
5253
} catch (err) { error?.(err) }
5354
})()
5455
) && (_ => stop = 1) ||
55-
(api?.any?.(target)?.(next, error, cleanup)),
56+
(api?.any?.(target)?.(next, cleanup, error)),
5657
// register autocleanup
5758
registry.register(target, unsub),
5859
unsub

test.spec.js

-4
This file was deleted.

test/https-loader.js

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// https-loader.mjs
2+
import { get } from 'https';
3+
4+
export function resolve(specifier, context, defaultResolve) {
5+
const { parentURL = null } = context;
6+
7+
// Normally Node.js would error on specifiers starting with 'https://', so
8+
// this hook intercepts them and converts them into absolute URLs to be
9+
// passed along to the later hooks below.
10+
if (specifier.startsWith('https://')) {
11+
return {
12+
shortCircuit: true,
13+
url: specifier
14+
};
15+
} else if (parentURL && parentURL.startsWith('https://')) {
16+
return {
17+
shortCircuit: true,
18+
url: new URL(specifier, parentURL).href
19+
};
20+
}
21+
22+
// Let Node.js handle all other specifiers.
23+
return defaultResolve(specifier, context, defaultResolve);
24+
}
25+
26+
export async function load(url, context, defaultLoad) {
27+
// For JavaScript to be loaded over the network, we need to fetch and
28+
// return it.
29+
if (url.startsWith('https://')) {
30+
return await new Promise((resolve, reject) => {
31+
get(url, (res) => {
32+
let data = '';
33+
res.on('data', (chunk) => data += chunk);
34+
res.on('end', () => resolve({
35+
// This example assumes all network-provided JavaScript is ES module
36+
// code.
37+
shortCircuit: true,
38+
format: 'module',
39+
source: data,
40+
}));
41+
}).on('error', (err) => reject(err));
42+
});
43+
}
44+
45+
// Let Node.js handle all other URLs.
46+
return defaultLoad(url, context, defaultLoad);
47+
}

0 commit comments

Comments
 (0)