├── .github
└── workflows
│ └── node.js.yml
├── .gitignore
├── .npmignore
├── .npmrc
├── LICENSE
├── README.md
├── cjs
├── async.js
├── fn
│ ├── async.js
│ ├── index.js
│ └── sync.js
├── index.js
├── package.json
├── solid
│ ├── async.js
│ ├── index.js
│ └── sync.js
└── sync.js
├── es.js
├── esm
├── async.js
├── fn
│ ├── async.js
│ ├── index.js
│ └── sync.js
├── index.js
├── solid
│ ├── async.js
│ ├── index.js
│ └── sync.js
└── sync.js
├── package-lock.json
├── package.json
├── rollup
└── es.config.js
├── test
├── .npmrc
├── async.js
├── benchmark.js
├── benchmark.old.png
├── benchmark.png
├── callstack.js
├── conditional.html
├── index.js
├── leak.js
├── package.json
├── preact.js
├── signal.js
├── solid-js-baseline.js
├── solid-to-usignal.js
├── solid.js
├── test.js
├── tsconfig.json
├── types.ts
├── usignal.js
└── weak-effects.html
├── tsconfig.json
└── types
├── async.d.ts
├── fn
├── async.d.ts
├── index.d.ts
└── sync.d.ts
├── index.d.ts
├── solid
├── async.d.ts
├── index.d.ts
└── sync.d.ts
└── sync.d.ts
/.github/workflows/node.js.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: build
5 |
6 | on: [push, pull_request]
7 |
8 | jobs:
9 | build:
10 |
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | matrix:
15 | node-version: [22]
16 |
17 | steps:
18 | - uses: actions/checkout@v4
19 | - name: Use Node.js ${{ matrix.node-version }}
20 | uses: actions/setup-node@v4
21 | with:
22 | node-version: ${{ matrix.node-version }}
23 | cache: 'npm'
24 | - run: npm ci
25 | - run: npm run build --if-present
26 | - run: npm test
27 | - run: npm run coverage --if-present
28 | - name: Coveralls
29 | uses: coverallsapp/github-action@master
30 | with:
31 | github-token: ${{ secrets.GITHUB_TOKEN }}
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .nyc_output
3 | coverage/
4 | node_modules/
5 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .nyc_output
3 | .eslintrc.json
4 | .travis.yml
5 | .github
6 | coverage/
7 | node_modules/
8 | rollup/
9 | test/
10 | tsconfig.json
11 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=true
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | ISC License
2 |
3 | Copyright (c) 2022, Andrea Giammarchi, @WebReflection
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any
6 | purpose with or without fee is hereby granted, provided that the above
7 | copyright notice and this permission notice appear in all copies.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 | OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 | PERFORMANCE OF THIS SOFTWARE.
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # µsignal
2 |
3 | [](https://www.npmjs.com/package/usignal) [](https://coveralls.io/github/WebReflection/usignal?branch=main) [](https://github.com/WebReflection/usignal/actions)
4 |
5 | **Social Media Photo by [Carlos Alberto Gómez Iñiguez](https://unsplash.com/@iniguez) on [Unsplash](https://unsplash.com/)**
6 |
7 | A blend of [@preact/signals-core](https://github.com/preactjs/signals) and [solid-js basic reactivity API](https://www.solidjs.com/docs/latest), with API and DX mostly identical to *@preact/signals-core* but extra goodness inspired by *solid-js*, 816 bytes minified with brotli.
8 |
9 | ```js
10 | import {signal, computed, effect, batch, Signal} from 'usignal';
11 | // const {signal, computed, effect, batch, Signal} = require('usignal');
12 |
13 | signal(0) instanceof Signal; // true
14 | computed(() => {}) instanceof Signal; // true
15 |
16 | effect(
17 | () => { console.log('fx') },
18 | void 0, // optional value to pass along the callback as initial/prev value
19 | {async: true} // optionally make the effect async: false by default
20 | );
21 |
22 | // try every example shown in
23 | // https://github.com/preactjs/signals
24 | // or see test/index.js file to see it in action
25 | ```
26 |
27 | #### Exports
28 |
29 | This is a *dual module* so it works in either *CommonJS* or *ECMAScript* module systems.
30 |
31 | * `usignal/sync` exports with an enforced *sync* effect
32 | * `usignal/async` exports with an enforced *async* effect
33 | * `usignal` in *browsers* exports `usignal/async` and `usignal/sync` in *servers* or by *default*
34 | * `usignal/core` just exports the *effect* as callback that accepts an effect and an optionally asynchronous `true` flag, used by all other exports by default, but you decide if a specific effect should sync or async.
35 | * the [unpkg/usignal](https://unpkg.com/usignal) default export points at the pre minified [es.js](./es.js) file without any enforcement around *effect*, like `usignal/core`, so that all effects are *sync* by default but can be *async* passing `true` as second parameter
36 |
37 | Current exports are exactly these:
38 |
39 | ```js
40 | import {
41 | signal,
42 | computed,
43 | effect,
44 | batch,
45 | Signal
46 | } from 'usignal';
47 | ```
48 |
49 | The `Signal` export is useful only as brand check for either *computed* or *signal* references, but it cannot be used as constructor right away.
50 |
51 |
52 | #### Exports - Extra
53 |
54 | To allow developers to try and use different patterns there are a few variants of this module, still based on the very same core primitives:
55 |
56 | * `usignal/fn`, with its `*/sync` and `*/async` variants, where signals are callbacks so that `signal()` returns a its value, and `signal(value)` updates its value and return the new one, [inspired by S](https://github.com/adamhaile/S). Computeds do not update anything so `computed()` returns values. This is a variant around the `.value` accessor pattern I don't necessarily disike, specially when we'd like to *signal* that a signal is being observed: `effect(() => { mySignal(); })`
57 | * `usignal/solid`, with its `*/sync` and `*/async` variants, where the module exports [createEffect](https://www.solidjs.com/docs/latest#createeffect), [createMemo](https://www.solidjs.com/docs/latest#creatememo), and [createSignal](https://www.solidjs.com/docs/latest#createsignal), mimicking the behavior (and returned values) as [solid-js basic reactivity API](https://www.solidjs.com/docs/latest/api). This is handy to compare the two or drop-in usignal in solid-js already based code.
58 |
59 | ---
60 |
61 | ## Differently thought ...
62 |
63 | * the default comparison for equality is not based on `===` but on [Object.is](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is). This might be a tiny, hopefully irrelevant, performance penalty, but I feel like guarding *NaN* cases in reactivity is a step forward to avoid infinite loops out of *NaN* poisoning some computation. *+0* and *-0* are less interesting cases to tackle, still these might be fundamental in some case, hence preserved in this moudle.
64 |
65 | * this library has lazy, non side-effecting, computed values, something [@preact/signals-core](https://github.com/preactjs/signals) recently introduced and [Solid 2.0 is planning to improve](https://twitter.com/RyanCarniato/status/1569815024964706304).
66 |
67 | * computed accepts an initial value otherwise passed as previous one by default, mimicking *solid-js* `useMemo(fn[, value[, options]])` signature.
68 |
69 | * effect passes along its initial value or the previoulsy returned one. If this is a function though, it runs it before re-executing, passing along its returned value, if any.
70 |
71 | * both `signal(value[, options])` and `computed(fn[, value[, options]])` accept an optionally *options* argument, currently implementing [equals](https://www.solidjs.com/docs/latest#options) as explained in *solid-js* documentation.
72 |
73 | * both *signal* and *computed* also have a `toJSON` and a `valueOf()` allowing to implicitly use their values, e.g.
74 |
75 | ```js
76 | const one = signal(1);
77 | const two = signal(2);
78 | const three = computed(() => one + two);
79 |
80 | three.value; // 3 indeed!
81 | ```
82 |
83 | ---
84 |
85 |
86 | ## Benchmark
87 |
88 | The benchmark currently compares *S*, *solid*, *preact/signals*, and *cellx* against *usignal*.
89 |
90 | Please note *preact* is currently not able to solve nested effects so its logic might be simpler than other libraries.
91 |
92 | ```sh
93 | npm run benchmark
94 | ```
95 |
96 | 
97 |
98 |
99 | ## Tests
100 |
101 | This module is 100% code covered, including ~~the *WeakRef*~~ possible leaks which is tested through the [test/leak.js](./test/leak.js) file, which is part of the *build* script process.
102 |
103 | To use other libraries as reference, I have also added *preact/signals-core* and *solid-js* dev-dependencies within the test folder.
104 |
105 | Please note *preact* is currently not able to solve nested effects so its logic might be simpler than other libraries.
106 |
107 | The following instructions are needed to test other libraries too:
108 |
109 | ```sh
110 | cd usignal
111 | npm i
112 | cd test
113 | npm i
114 | cd ..
115 |
116 | # normal tests
117 | npm test usignal # shows also code-coverage
118 | npm test solid
119 | npm test preact
120 |
121 | # leak test
122 | npm run leak usignal # calculate leaks via internals
123 | npm run leak solid
124 | npm run leak preact
125 | ```
126 |
127 | #### About the leak test
128 |
129 | This file is not meant at all as meaningful benchmark against other libraries, it's simply there to allow me to spot regressions on future updates of the library:
130 | * ~~there should be zero leaks on signals when a computed reference is garbage collected~~ v0.5.0 removed the *WeakRef*, computeds go when signals go ... [but why?!](https://twitter.com/WebReflection/status/1570380914613694466)
131 | * the amount of used memory should always be lower than the initial one
132 | * the performance should be competitive compared to others
133 |
134 | ## How to integrate with Lit
135 |
136 | You create a following [mixin](https://lit.dev/docs/composition/mixins/) function. Your class inherits from Mixin. Please see the [demo](https://lit.dev/playground/#project=W3sibmFtZSI6InNpZ25hbC1leGFtcGxlLmpzIiwiY29udGVudCI6ImltcG9ydCB7IGh0bWwsIGNzcywgTGl0RWxlbWVudCB9IGZyb20gJ2xpdCc7XG5pbXBvcnQgeyBXaXRoVXNpZ25hbCB9IGZyb20gJy4vd2l0aC11c2lnbmFsLmpzJztcbmltcG9ydCB7IHNpZ25hbCB9IGZyb20gJ3VzaWduYWwnO1xuXG5jb25zdCBjb3VudGVyID0gc2lnbmFsKDEpO1xuY29uc3QgY291bnRlcjIgPSBzaWduYWwoMSk7XG5cbmNsYXNzIFNpZ25hbEV4YW1wbGUgZXh0ZW5kcyBXaXRoVXNpZ25hbChMaXRFbGVtZW50KSB7XG4gIHN0YXRpYyBzdHlsZXMgPSBjc3NgXG4gICAgOmhvc3Qge1xuICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICBib3JkZXI6IHNvbGlkIDFweCBibHVlO1xuICAgICAgcGFkZGluZzogOHB4O1xuICAgICAgbWFyZ2luOiA0cHg7XG4gICAgfVxuICBgO1xuXG4gIHN0YXRpYyBwcm9wZXJ0aWVzID0ge1xuICAgIGNvdW50OiB7IHN0YXRlOiB0cnVlIH0sXG4gICAgbmFtZToge31cbiAgfVxuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKCk7XG4gICAgdGhpcy5jb3VudCA9IDE7XG4gIH1cblxuICByZW5kZXIoKSB7XG4gICAgcmV0dXJuIGh0bWxgXG4gICAgICA8aDQ-JHt0aGlzLm5hbWV9PC9oND5cbiAgICAgIDxwPlxuICAgICAgICBTaWduYWwgY291bnRlcjogJHtjb3VudGVyfVxuICAgICAgICA8YnV0dG9uIEBjbGljaz0keygpID0-IGNvdW50ZXIudmFsdWUrK30-Kys8L2J1dHRvbj5cbiAgICAgIDwvcD5cbiAgICAgIDxwPlxuICAgICAgICBSZWFjdGl2ZSBwcm9wZXJ0eSBjb3VudGVyOiAke3RoaXMuY291bnR9XG4gICAgICAgIDxidXR0b24gQGNsaWNrPSR7KCkgPT4gdGhpcy5jb3VudCsrfT4rKzwvYnV0dG9uPlxuICAgICAgPC9wPlxuICAgICAgJHsgdGhpcy5jb3VudCA-IDIgPyBodG1sYFxuICAgICAgIDxwPlxuICAgICAgICBTaWduYWwgY291bnRlcjogJHtjb3VudGVyMn1cbiAgICAgICAgPGJ1dHRvbiBAY2xpY2s9JHsoKSA9PiBjb3VudGVyMi52YWx1ZSsrfT4rKzwvYnV0dG9uPlxuICAgICAgIDwvcD5gIDogbnVsbH0gICAgICAgIFxuICAgIGA7XG4gIH1cbn1cblxuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdzaWduYWwtZXhhbXBsZScsIFNpZ25hbEV4YW1wbGUpOyJ9LHsibmFtZSI6ImluZGV4Lmh0bWwiLCJjb250ZW50IjoiPCFET0NUWVBFIGh0bWw-XG48aHRtbD5cbiAgPGhlYWQ-XG4gICAgPHNjcmlwdCB0eXBlPVwibW9kdWxlXCIgc3JjPVwiLi9zaWduYWwtZXhhbXBsZS5qc1wiPjwvc2NyaXB0PlxuICAgIDxzdHlsZT5cbiAgICAgIGJvZHkge1xuICAgICAgICBmb250LXNpemU6IDEuMjVyZW07XG4gICAgICAgIGZvbnQtZmFtaWx5OiBzYW5zLXNlcmlmO1xuICAgICAgfVxuICAgIDwvc3R5bGU-XG4gIDwvaGVhZD5cbiAgPGJvZHk-XG4gICAgPHNpZ25hbC1leGFtcGxlIG5hbWU9XCJJbnN0YW5jZSAxXCI-PC9zaWduYWwtZXhhbXBsZT5cbiAgICA8c2lnbmFsLWV4YW1wbGUgbmFtZT1cIkluc3RhbmNlIDJcIj48L3NpZ25hbC1leGFtcGxlPlxuICA8L2JvZHk-XG48L2h0bWw-In0seyJuYW1lIjoicGFja2FnZS5qc29uIiwiY29udGVudCI6IntcbiAgXCJkZXBlbmRlbmNpZXNcIjoge1xuICAgIFwibGl0XCI6IFwiXjIuMC4wXCIsXG4gICAgXCJAbGl0L3JlYWN0aXZlLWVsZW1lbnRcIjogXCJeMS4wLjBcIixcbiAgICBcImxpdC1lbGVtZW50XCI6IFwiXjMuMC4wXCIsXG4gICAgXCJsaXQtaHRtbFwiOiBcIl4yLjAuMFwiXG4gIH1cbn0iLCJoaWRkZW4iOnRydWV9LHsibmFtZSI6IndpdGgtdXNpZ25hbC5qcyIsImNvbnRlbnQiOiJpbXBvcnQgeyBlZmZlY3QsIHNpZ25hbCB9IGZyb20gJ3VzaWduYWwnO1xuXG5leHBvcnQgZnVuY3Rpb24gV2l0aFVzaWduYWwoQmFzZSl7XG4gIHJldHVybiBjbGFzcyBXaXRoVXNpZ25hbCBleHRlbmRzIEJhc2Uge1xuICAgICNkaXNwb3NlRWZmZWN0XG4gICAgI3JlYWN0aXZlUHJvcFVwZGF0ZSA9IHNpZ25hbCgwKTtcblxuICAgIGRpc2Nvbm5lY3RlZENhbGxiYWNrKCkge1xuICAgICAgdGhpcy4jZGlzcG9zZUVmZmVjdD8uKCk7XG4gICAgfVxuXG4gICAgcGVyZm9ybVVwZGF0ZSgpIHtcbiAgICAgIGlmICghdGhpcy5pc1VwZGF0ZVBlbmRpbmcpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy4jZGlzcG9zZUVmZmVjdCkge1xuICAgICAgICB0aGlzLiNyZWFjdGl2ZVByb3BVcGRhdGUudmFsdWUrKztcbiAgICAgIH1cblxuICAgICAgdGhpcy4jZGlzcG9zZUVmZmVjdCA9IGVmZmVjdCgoKSA9PiB7ICAgICAgXG4gICAgICAgIHRoaXMuaXNVcGRhdGVQZW5kaW5nID0gdHJ1ZTtcbiAgICAgICAgdGhpcy4jcmVhY3RpdmVQcm9wVXBkYXRlLnZhbHVlO1xuICAgICAgICBzdXBlci5wZXJmb3JtVXBkYXRlKCk7XG4gICAgICB9KTtcbiAgICB9XG4gIH07XG59In1d) for details.
137 |
138 | ```js
139 | import { effect, signal } from 'usignal';
140 |
141 | export function WithUsignal(Base){
142 | return class WithUsignal extends Base {
143 | #disposeEffect
144 | #reactivePropUpdate = signal(0);
145 |
146 | disconnectedCallback() {
147 | this.#disposeEffect?.();
148 | }
149 |
150 | performUpdate() {
151 | if (!this.isUpdatePending) {
152 | return;
153 | }
154 |
155 | if (this.#disposeEffect) {
156 | this.#reactivePropUpdate.value++;
157 | return;
158 | }
159 |
160 | this.#disposeEffect = effect(() => {
161 | this.isUpdatePending = true;
162 | this.#reactivePropUpdate.value;
163 | super.performUpdate();
164 | });
165 | }
166 | };
167 | }
168 | ```
169 |
--------------------------------------------------------------------------------
/cjs/async.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | (m => Object.keys(m).map(k => k !== 'default' && (exports[k] = m[k])))
3 | (require('./index.js'));
4 | const {effect: fx} = require('./index.js');
5 |
6 | const options = {async: true};
7 |
8 | /**
9 | * Invokes asynchronously a function when any of its internal signals or computed values change.
10 | *
11 | * Returns a dispose callback.
12 | * @template T
13 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
14 | */
15 | const effect = (fn, value) => fx(fn, value, options);
16 | exports.effect = effect;
17 |
--------------------------------------------------------------------------------
/cjs/fn/async.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | (m => Object.keys(m).map(k => k !== 'default' && (exports[k] = m[k])))
3 | (require('./index.js'));
4 | const {effect: fx} = require('../index.js');
5 |
6 | const options = {async: true};
7 |
8 | /**
9 | * Invokes asynchronously a function when any of its internal signals or computed values change.
10 | *
11 | * Returns a dispose callback.
12 | * @template T
13 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
14 | */
15 | const effect = (fn, value) => fx(fn, value, options);
16 | exports.effect = effect;
17 |
--------------------------------------------------------------------------------
/cjs/fn/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | (m => Object.keys(m).map(k => k !== 'default' && (exports[k] = m[k])))
3 | (require('../index.js'));
4 | const {computed: c, signal: s, Signal: S, Signal} = require('../index.js');
5 |
6 | const {setPrototypeOf} = Object;
7 | const {prototype} = Signal;
8 |
9 | /**
10 | * Returns a callback that is invoked only when any of the internally
11 | * used signals, as in within the callback, is unknown or updated.
12 | * @template T
13 | * @type {(fn: (v: T) => T, value?: T, options?: { equals?: boolean | ((prev: T, next: T) => boolean) }) => () => T}
14 | */
15 | const computed = (fn, value, options) => {
16 | const _ = c(fn, value, options);
17 | return setPrototypeOf(
18 | () => _.value,
19 | prototype
20 | );
21 | };
22 | exports.computed = computed;
23 |
24 | /**
25 | * Returns a callback that executed with no argument returns the signal value,
26 | * otherwise it updates the signal value and returns its new value.
27 | * @template T
28 | * @param {T} value the value the Signal should carry along
29 | * @param {{equals?: boolean | ((prev: T, next: T) => boolean)}} [options] signal options
30 | * @returns {(value?: T) => T}
31 | */
32 | const signal = (value, options) => {
33 | const _ = s(value, options);
34 | return setPrototypeOf(
35 | function (value) {
36 | return arguments.length ? (_.value = value) : _.value;
37 | },
38 | prototype
39 | );
40 | };
41 | exports.signal = signal;
42 |
--------------------------------------------------------------------------------
/cjs/fn/sync.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | (m => Object.keys(m).map(k => k !== 'default' && (exports[k] = m[k])))
3 | (require('./index.js'));
4 | const {effect: fx} = require('../index.js');
5 |
6 | const options = {async: false};
7 |
8 | /**
9 | * Invokes asynchronously a function when any of its internal signals or computed values change.
10 | *
11 | * Returns a dispose callback.
12 | * @template T
13 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
14 | */
15 | const effect = (fn, value) => fx(fn, value, options);
16 | exports.effect = effect;
17 |
--------------------------------------------------------------------------------
/cjs/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /*! (c) Andrea Giammarchi */
3 |
4 | const {is} = Object;
5 |
6 | let batches;
7 |
8 | /**
9 | * Execute a callback that will not side-effect until its top-most batch is
10 | * completed.
11 | * @param {() => void} callback a function that batches changes to be notified
12 | * through signals.
13 | */
14 | const batch = callback => {
15 | const prev = batches;
16 | batches = prev || [];
17 | try {
18 | callback();
19 | if (!prev)
20 | for (const {value} of batches);
21 | }
22 | finally { batches = prev }
23 | };
24 | exports.batch = batch;
25 |
26 | /**
27 | * A signal with a value property also exposed via toJSON, toString and valueOf.
28 | * When created via computed, the `value` property is **readonly**.
29 | * @template T
30 | */
31 | class Signal {
32 | constructor(value) {
33 | this._ = value;
34 | }
35 |
36 | /** @returns {T} */
37 | toJSON() { return this.value }
38 |
39 | /** @returns {string} */
40 | toString() { return String(this.value) }
41 |
42 | /** @returns {T} */
43 | valueOf() { return this.value }
44 | }
45 | exports.Signal = Signal
46 |
47 | let computedSignal;
48 | /**
49 | * @template T
50 | * @extends {Signal}
51 | */
52 | class Computed extends Signal {
53 | /**
54 | * @private
55 | * @type{Reactive}
56 | */
57 | s
58 | /**
59 | * @param {(v: T) => T} _
60 | * @param {T} v
61 | * @param {{ equals?: Equals }} o
62 | * @param {boolean} f
63 | */
64 | constructor(_, v, o, f) {
65 | super(_);
66 | this.f = f; // is effect?
67 | this.$ = true; // should update ("value for money")
68 | this.r = new Set; // related signals
69 | this.s = new Reactive(v, o); // signal
70 | }
71 | refresh() {
72 | if (!this.$) return
73 |
74 | const prev = computedSignal;
75 | computedSignal = this;
76 | try { this.s.value = this._(this.s._) }
77 | finally {
78 | this.$ = false;
79 | computedSignal = prev;
80 | }
81 | }
82 | peek() {
83 | this.refresh()
84 | return this.s.peek()
85 | }
86 | get value() {
87 | this.refresh()
88 | return this.s.value;
89 | }
90 | }
91 |
92 | const defaults = {async: false, equals: true};
93 |
94 | /**
95 | * Returns a read-only Signal that is invoked only when any of the internally
96 | * used signals, as in within the callback, is unknown or updated.
97 | * @type {(fn: (v: T) => R, value?: V, options?: { equals?: Equals }) => ComputedSignal}
98 | */
99 | const computed = (fn, value, options = defaults) =>
100 | new Computed(fn, value, options, false);
101 | exports.computed = computed;
102 |
103 | let outerEffect;
104 | const empty = [];
105 | const noop = () => {};
106 | const dispose = ({s}) => {
107 | if (typeof s._ === 'function')
108 | s._ = s._();
109 | };
110 |
111 | class FX extends Computed {
112 | constructor(_, v, o) {
113 | super(_, v, o, true);
114 | this.e = empty;
115 | }
116 | run() {
117 | this.$ = true;
118 | this.value;
119 | return this;
120 | }
121 | stop() {
122 | this._ = noop;
123 | this.r.clear();
124 | this.s.c.clear();
125 | }
126 | }
127 | exports.FX = FX
128 |
129 | class Effect extends FX {
130 | constructor(_, v, o) {
131 | super(_, v, o);
132 | this.i = 0; // index
133 | this.a = !!o.async; // async
134 | this.m = true; // microtask
135 | this.e = []; // effects
136 | // "I am effects" ^_^;;
137 | }
138 | get value() {
139 | this.a ? this.async() : this.sync();
140 | }
141 | async() {
142 | if (this.m) {
143 | this.m = false;
144 | queueMicrotask(() => {
145 | this.m = true;
146 | this.sync();
147 | });
148 | }
149 | }
150 | sync() {
151 | const prev = outerEffect;
152 | (outerEffect = this).i = 0;
153 | dispose(this);
154 | super.value;
155 | outerEffect = prev;
156 | }
157 | stop() {
158 | super.stop();
159 | dispose(this);
160 | for (const effect of this.e.splice(0))
161 | effect.stop();
162 | }
163 | }
164 | exports.Effect = Effect
165 |
166 | /**
167 | * Invokes a function when any of its internal signals or computed values change.
168 | *
169 | * Returns a dispose callback.
170 | * @template T
171 | * @type {(fn: (v: T) => T, value?: T, options?: { async?: boolean }) => () => void}
172 | */
173 | const effect = (callback, value, options = defaults) => {
174 | let unique;
175 | if (outerEffect) {
176 | const {i, e} = outerEffect;
177 | const isNew = i === e.length;
178 | // bottleneck:
179 | // there's literally no way to optimize this path *unless* the callback is
180 | // already a known one. however, latter case is not really common code so
181 | // the question is: should I optimize this more than this? 'cause I don't
182 | // think the amount of code needed to understand if a callback is *likely*
183 | // the same as before makes any sense + correctness would be trashed.
184 | if (isNew || e[i]._ !== callback) {
185 | if (!isNew) e[i].stop();
186 | e[i] = new Effect(callback, value, options).run();
187 | }
188 | unique = e[i];
189 | outerEffect.i++;
190 | }
191 | else
192 | unique = new Effect(callback, value, options).run();
193 | return () => { unique.stop() };
194 | };
195 | exports.effect = effect;
196 |
197 | const skip = () => false;
198 | /**
199 | * @template T
200 | * @extends {Signal}
201 | */
202 | class Reactive extends Signal {
203 | constructor(_, {equals}) {
204 | super(_)
205 | this.c = new Set; // computeds
206 | this.s = equals === true ? is : (equals || skip); // (don't) skip updates
207 | }
208 | /**
209 | * Allows to get signal.value without subscribing to updates in an effect
210 | * @returns {T}
211 | */
212 | peek() { return this._ }
213 | /** @returns {T} */
214 | get value() {
215 | if (computedSignal) {
216 | this.c.add(computedSignal);
217 | computedSignal.r.add(this);
218 | }
219 | return this._;
220 | }
221 | set value(_) {
222 | const prev = this._;
223 | if (!this.s((this._ = _), prev)) {
224 | if (this.c.size) {
225 | const effects = [];
226 | const stack = [this];
227 | for (const signal of stack) {
228 | for (const computed of signal.c) {
229 | if (!computed.$ && computed.r.has(signal)) {
230 | computed.r.clear();
231 | computed.$ = true;
232 | if (computed.f) {
233 | effects.push(computed);
234 | const stack = [computed];
235 | for (const c of stack) {
236 | for (const effect of c.e) {
237 | effect.r.clear();
238 | effect.$ = true;
239 | stack.push(effect);
240 | }
241 | }
242 | }
243 | else
244 | stack.push(computed.s);
245 | }
246 | }
247 | }
248 | for (const effect of effects)
249 | batches ? batches.push(effect) : effect.value;
250 | }
251 | }
252 | }
253 | }
254 |
255 | /**
256 | * Returns a writable Signal that side-effects whenever its value gets updated.
257 | * @template T
258 | * @type {(initialValue: T, options?: { equals?: Equals }) => ReactiveSignal}
259 | */
260 | const signal = (value, options = defaults) => new Reactive(value, options);
261 | exports.signal = signal;
262 |
263 | /**
264 | * @template [T=any]
265 | * @typedef {boolean | ((prev: T, next: T) => boolean)} Equals
266 | */
267 |
268 | /**
269 | * @public
270 | * @template T
271 | * @typedef {Omit, '_'|'s'|'c'>} ReactiveSignal
272 | */
273 |
274 | /**
275 | * @public
276 | * @template T
277 | * @typedef {Omit, '$'|'s'|'f'|'r'|'_'>} ComputedSignal
278 | */
279 |
--------------------------------------------------------------------------------
/cjs/package.json:
--------------------------------------------------------------------------------
1 | {"type":"commonjs"}
--------------------------------------------------------------------------------
/cjs/solid/async.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | (m => Object.keys(m).map(k => k !== 'default' && (exports[k] = m[k])))
3 | (require('./index.js'));
4 | const {createEffect: fx} = require('./index.js');
5 |
6 | const options = {async: true};
7 |
8 | /**
9 | * asynchronous https://www.solidjs.com/docs/latest/api#createeffect
10 | *
11 | * returns a dispose callback.
12 | * @template T
13 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
14 | */
15 | const createEffect = (fn, initialValue) => fx(fn, initialValue, options);
16 | exports.createEffect = createEffect;
--------------------------------------------------------------------------------
/cjs/solid/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const {computed, effect, signal} = require('../index.js');
3 |
4 | const asValue = value => typeof value === 'function' ? value() : value;
5 |
6 | /**
7 | * https://www.solidjs.com/docs/latest/api#createeffect
8 | *
9 | * returns a dispose callback.
10 | * @template T
11 | * @type {(fn: (v: T) => T, value?: T, options?: { async?: boolean }) => () => void}
12 | */
13 | const createEffect = effect;
14 | exports.createEffect = createEffect;
15 |
16 | /**
17 | * @template T
18 | * @type {(fn: (v: T) => T, value?: T, options?: { equals?: boolean | ((prev: T, next: T) => boolean) }) => () => T}
19 | */
20 | const createMemo = (fn, value, options) => {
21 | const _ = computed(fn, value, options);
22 | return () => _.value;
23 | };
24 | exports.createMemo = createMemo;
25 |
26 | /**
27 | * @template T
28 | * @type {(initialValue: T, options?: { equals?: boolean | ((prev: T, next: T) => boolean) }) => [get: () => T, set: (v: T) => T]}
29 | */
30 | const createSignal = (initialValue, options) => {
31 | const _ = signal(asValue(initialValue), options);
32 | return [
33 | () => _.value,
34 | value => {
35 | _.value = asValue(value);
36 | }
37 | ];
38 | };
39 | exports.createSignal = createSignal;
40 |
--------------------------------------------------------------------------------
/cjs/solid/sync.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | (m => Object.keys(m).map(k => k !== 'default' && (exports[k] = m[k])))
3 | (require('./index.js'));
4 | const {createEffect: fx} = require('./index.js');
5 |
6 | const options = {async: false};
7 |
8 | /**
9 | * synchronous https://www.solidjs.com/docs/latest/api#createeffect
10 | *
11 | * returns a dispose callback.
12 | * @template T
13 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
14 | */
15 | const createEffect = (fn, initialValue) => fx(fn, initialValue, options);
16 | exports.createEffect = createEffect;
--------------------------------------------------------------------------------
/cjs/sync.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | (m => Object.keys(m).map(k => k !== 'default' && (exports[k] = m[k])))
3 | (require('./index.js'));
4 | const {effect: fx} = require('./index.js');
5 |
6 | const options = {async: false};
7 |
8 | /**
9 | * Invokes synchronously a function when any of its internal signals or computed values change.
10 | *
11 | * Returns a dispose callback.
12 | * @template T
13 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
14 | */
15 | const effect = (fn, value) => fx(fn, value, options);
16 | exports.effect = effect;
17 |
--------------------------------------------------------------------------------
/es.js:
--------------------------------------------------------------------------------
1 | /*! (c) Andrea Giammarchi */
2 | const{is:s}=Object;let t;const e=s=>{const e=t;t=e||[];try{if(s(),!e)for(const{value:s}of t);}finally{t=e}};class i{constructor(s){this._=s}toJSON(){return this.value}toString(){return String(this.value)}valueOf(){return this.value}}let r;class n extends i{s;constructor(s,t,e,i){super(s),this.f=i,this.$=!0,this.r=new Set,this.s=new _(t,e)}refresh(){if(!this.$)return;const s=r;r=this;try{this.s.value=this._(this.s._)}finally{this.$=!1,r=s}}peek(){return this.refresh(),this.s.peek()}get value(){return this.refresh(),this.s.value}}const h={async:!1,equals:!0},o=(s,t,e=h)=>new n(s,t,e,!1);let c;const u=[],a=()=>{},l=({s:s})=>{"function"==typeof s._&&(s._=s._())};class f extends n{constructor(s,t,e){super(s,t,e,!0),this.e=u}run(){return this.$=!0,this.value,this}stop(){this._=a,this.r.clear(),this.s.c.clear()}}class p extends f{constructor(s,t,e){super(s,t,e),this.i=0,this.a=!!e.async,this.m=!0,this.e=[]}get value(){this.a?this.async():this.sync()}async(){this.m&&(this.m=!1,queueMicrotask((()=>{this.m=!0,this.sync()})))}sync(){const s=c;(c=this).i=0,l(this),super.value,c=s}stop(){super.stop(),l(this);for(const s of this.e.splice(0))s.stop()}}const v=(s,t,e=h)=>{let i;if(c){const{i:r,e:n}=c,h=r===n.length;(h||n[r]._!==s)&&(h||n[r].stop(),n[r]=new p(s,t,e).run()),i=n[r],c.i++}else i=new p(s,t,e).run();return()=>{i.stop()}},y=()=>!1;class _ extends i{constructor(t,{equals:e}){super(t),this.c=new Set,this.s=!0===e?s:e||y}peek(){return this._}get value(){return r&&(this.c.add(r),r.r.add(this)),this._}set value(s){const e=this._;if(!this.s(this._=s,e)&&this.c.size){const s=[],e=[this];for(const t of e)for(const i of t.c)if(!i.$&&i.r.has(t))if(i.r.clear(),i.$=!0,i.f){s.push(i);const t=[i];for(const s of t)for(const e of s.e)e.r.clear(),e.$=!0,t.push(e)}else e.push(i.s);for(const e of s)t?t.push(e):e.value}}}const d=(s,t=h)=>new _(s,t);export{p as Effect,f as FX,i as Signal,e as batch,o as computed,v as effect,d as signal};
3 |
--------------------------------------------------------------------------------
/esm/async.js:
--------------------------------------------------------------------------------
1 | export * from './index.js';
2 | import {effect as fx} from './index.js';
3 |
4 | const options = {async: true};
5 |
6 | /**
7 | * Invokes asynchronously a function when any of its internal signals or computed values change.
8 | *
9 | * Returns a dispose callback.
10 | * @template T
11 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
12 | */
13 | export const effect = (fn, value) => fx(fn, value, options);
14 |
--------------------------------------------------------------------------------
/esm/fn/async.js:
--------------------------------------------------------------------------------
1 | export * from './index.js';
2 | import {effect as fx} from '../index.js';
3 |
4 | const options = {async: true};
5 |
6 | /**
7 | * Invokes asynchronously a function when any of its internal signals or computed values change.
8 | *
9 | * Returns a dispose callback.
10 | * @template T
11 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
12 | */
13 | export const effect = (fn, value) => fx(fn, value, options);
14 |
--------------------------------------------------------------------------------
/esm/fn/index.js:
--------------------------------------------------------------------------------
1 | export * from '../index.js';
2 | import {computed as c, signal as s, Signal as S, Signal} from '../index.js';
3 |
4 | const {setPrototypeOf} = Object;
5 | const {prototype} = Signal;
6 |
7 | /**
8 | * Returns a callback that is invoked only when any of the internally
9 | * used signals, as in within the callback, is unknown or updated.
10 | * @template T
11 | * @type {(fn: (v: T) => T, value?: T, options?: { equals?: boolean | ((prev: T, next: T) => boolean) }) => () => T}
12 | */
13 | export const computed = (fn, value, options) => {
14 | const _ = c(fn, value, options);
15 | return setPrototypeOf(
16 | () => _.value,
17 | prototype
18 | );
19 | };
20 |
21 | /**
22 | * Returns a callback that executed with no argument returns the signal value,
23 | * otherwise it updates the signal value and returns its new value.
24 | * @template T
25 | * @param {T} value the value the Signal should carry along
26 | * @param {{equals?: boolean | ((prev: T, next: T) => boolean)}} [options] signal options
27 | * @returns {(value?: T) => T}
28 | */
29 | export const signal = (value, options) => {
30 | const _ = s(value, options);
31 | return setPrototypeOf(
32 | function (value) {
33 | return arguments.length ? (_.value = value) : _.value;
34 | },
35 | prototype
36 | );
37 | };
38 |
--------------------------------------------------------------------------------
/esm/fn/sync.js:
--------------------------------------------------------------------------------
1 | export * from './index.js';
2 | import {effect as fx} from '../index.js';
3 |
4 | const options = {async: false};
5 |
6 | /**
7 | * Invokes asynchronously a function when any of its internal signals or computed values change.
8 | *
9 | * Returns a dispose callback.
10 | * @template T
11 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
12 | */
13 | export const effect = (fn, value) => fx(fn, value, options);
14 |
--------------------------------------------------------------------------------
/esm/index.js:
--------------------------------------------------------------------------------
1 | /*! (c) Andrea Giammarchi */
2 |
3 | const {is} = Object;
4 |
5 | let batches;
6 |
7 | /**
8 | * Execute a callback that will not side-effect until its top-most batch is
9 | * completed.
10 | * @param {() => void} callback a function that batches changes to be notified
11 | * through signals.
12 | */
13 | export const batch = callback => {
14 | const prev = batches;
15 | batches = prev || [];
16 | try {
17 | callback();
18 | if (!prev)
19 | for (const {value} of batches);
20 | }
21 | finally { batches = prev }
22 | };
23 |
24 | /**
25 | * A signal with a value property also exposed via toJSON, toString and valueOf.
26 | * When created via computed, the `value` property is **readonly**.
27 | * @template T
28 | */
29 | export class Signal {
30 | constructor(value) {
31 | this._ = value;
32 | }
33 |
34 | /** @returns {T} */
35 | toJSON() { return this.value }
36 |
37 | /** @returns {string} */
38 | toString() { return String(this.value) }
39 |
40 | /** @returns {T} */
41 | valueOf() { return this.value }
42 | }
43 |
44 | let computedSignal;
45 | /**
46 | * @template T
47 | * @extends {Signal}
48 | */
49 | class Computed extends Signal {
50 | /**
51 | * @private
52 | * @type{Reactive}
53 | */
54 | s
55 | /**
56 | * @param {(v: T) => T} _
57 | * @param {T} v
58 | * @param {{ equals?: Equals }} o
59 | * @param {boolean} f
60 | */
61 | constructor(_, v, o, f) {
62 | super(_);
63 | this.f = f; // is effect?
64 | this.$ = true; // should update ("value for money")
65 | this.r = new Set; // related signals
66 | this.s = new Reactive(v, o); // signal
67 | }
68 | refresh() {
69 | if (!this.$) return
70 |
71 | const prev = computedSignal;
72 | computedSignal = this;
73 | try { this.s.value = this._(this.s._) }
74 | finally {
75 | this.$ = false;
76 | computedSignal = prev;
77 | }
78 | }
79 | peek() {
80 | this.refresh()
81 | return this.s.peek()
82 | }
83 | get value() {
84 | this.refresh()
85 | return this.s.value;
86 | }
87 | }
88 |
89 | const defaults = {async: false, equals: true};
90 |
91 | /**
92 | * Returns a read-only Signal that is invoked only when any of the internally
93 | * used signals, as in within the callback, is unknown or updated.
94 | * @type {(fn: (v: T) => R, value?: V, options?: { equals?: Equals }) => ComputedSignal}
95 | */
96 | export const computed = (fn, value, options = defaults) =>
97 | new Computed(fn, value, options, false);
98 |
99 | let outerEffect;
100 | const empty = [];
101 | const noop = () => {};
102 | const dispose = ({s}) => {
103 | if (typeof s._ === 'function')
104 | s._ = s._();
105 | };
106 |
107 | export class FX extends Computed {
108 | constructor(_, v, o) {
109 | super(_, v, o, true);
110 | this.e = empty;
111 | }
112 | run() {
113 | this.$ = true;
114 | this.value;
115 | return this;
116 | }
117 | stop() {
118 | this._ = noop;
119 | this.r.clear();
120 | this.s.c.clear();
121 | }
122 | }
123 |
124 | export class Effect extends FX {
125 | constructor(_, v, o) {
126 | super(_, v, o);
127 | this.i = 0; // index
128 | this.a = !!o.async; // async
129 | this.m = true; // microtask
130 | this.e = []; // effects
131 | // "I am effects" ^_^;;
132 | }
133 | get value() {
134 | this.a ? this.async() : this.sync();
135 | }
136 | async() {
137 | if (this.m) {
138 | this.m = false;
139 | queueMicrotask(() => {
140 | this.m = true;
141 | this.sync();
142 | });
143 | }
144 | }
145 | sync() {
146 | const prev = outerEffect;
147 | (outerEffect = this).i = 0;
148 | dispose(this);
149 | super.value;
150 | outerEffect = prev;
151 | }
152 | stop() {
153 | super.stop();
154 | dispose(this);
155 | for (const effect of this.e.splice(0))
156 | effect.stop();
157 | }
158 | }
159 |
160 | /**
161 | * Invokes a function when any of its internal signals or computed values change.
162 | *
163 | * Returns a dispose callback.
164 | * @template T
165 | * @type {(fn: (v: T) => T, value?: T, options?: { async?: boolean }) => () => void}
166 | */
167 | export const effect = (callback, value, options = defaults) => {
168 | let unique;
169 | if (outerEffect) {
170 | const {i, e} = outerEffect;
171 | const isNew = i === e.length;
172 | // bottleneck:
173 | // there's literally no way to optimize this path *unless* the callback is
174 | // already a known one. however, latter case is not really common code so
175 | // the question is: should I optimize this more than this? 'cause I don't
176 | // think the amount of code needed to understand if a callback is *likely*
177 | // the same as before makes any sense + correctness would be trashed.
178 | if (isNew || e[i]._ !== callback) {
179 | if (!isNew) e[i].stop();
180 | e[i] = new Effect(callback, value, options).run();
181 | }
182 | unique = e[i];
183 | outerEffect.i++;
184 | }
185 | else
186 | unique = new Effect(callback, value, options).run();
187 | return () => { unique.stop() };
188 | };
189 |
190 | const skip = () => false;
191 | /**
192 | * @template T
193 | * @extends {Signal}
194 | */
195 | class Reactive extends Signal {
196 | constructor(_, {equals}) {
197 | super(_)
198 | this.c = new Set; // computeds
199 | this.s = equals === true ? is : (equals || skip); // (don't) skip updates
200 | }
201 | /**
202 | * Allows to get signal.value without subscribing to updates in an effect
203 | * @returns {T}
204 | */
205 | peek() { return this._ }
206 | /** @returns {T} */
207 | get value() {
208 | if (computedSignal) {
209 | this.c.add(computedSignal);
210 | computedSignal.r.add(this);
211 | }
212 | return this._;
213 | }
214 | set value(_) {
215 | const prev = this._;
216 | if (!this.s((this._ = _), prev)) {
217 | if (this.c.size) {
218 | const effects = [];
219 | const stack = [this];
220 | for (const signal of stack) {
221 | for (const computed of signal.c) {
222 | if (!computed.$ && computed.r.has(signal)) {
223 | computed.r.clear();
224 | computed.$ = true;
225 | if (computed.f) {
226 | effects.push(computed);
227 | const stack = [computed];
228 | for (const c of stack) {
229 | for (const effect of c.e) {
230 | effect.r.clear();
231 | effect.$ = true;
232 | stack.push(effect);
233 | }
234 | }
235 | }
236 | else
237 | stack.push(computed.s);
238 | }
239 | }
240 | }
241 | for (const effect of effects)
242 | batches ? batches.push(effect) : effect.value;
243 | }
244 | }
245 | }
246 | }
247 |
248 | /**
249 | * Returns a writable Signal that side-effects whenever its value gets updated.
250 | * @template T
251 | * @type {(initialValue: T, options?: { equals?: Equals }) => ReactiveSignal}
252 | */
253 | export const signal = (value, options = defaults) => new Reactive(value, options);
254 |
255 | /**
256 | * @template [T=any]
257 | * @typedef {boolean | ((prev: T, next: T) => boolean)} Equals
258 | */
259 |
260 | /**
261 | * @public
262 | * @template T
263 | * @typedef {Omit, '_'|'s'|'c'>} ReactiveSignal
264 | */
265 |
266 | /**
267 | * @public
268 | * @template T
269 | * @typedef {Omit, '$'|'s'|'f'|'r'|'_'>} ComputedSignal
270 | */
271 |
--------------------------------------------------------------------------------
/esm/solid/async.js:
--------------------------------------------------------------------------------
1 | export * from './index.js';
2 | import {createEffect as fx} from './index.js';
3 |
4 | const options = {async: true};
5 |
6 | /**
7 | * asynchronous https://www.solidjs.com/docs/latest/api#createeffect
8 | *
9 | * returns a dispose callback.
10 | * @template T
11 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
12 | */
13 | export const createEffect = (fn, initialValue) => fx(fn, initialValue, options);
--------------------------------------------------------------------------------
/esm/solid/index.js:
--------------------------------------------------------------------------------
1 | import {computed, effect, signal} from '../index.js';
2 |
3 | const asValue = value => typeof value === 'function' ? value() : value;
4 |
5 | /**
6 | * https://www.solidjs.com/docs/latest/api#createeffect
7 | *
8 | * returns a dispose callback.
9 | * @template T
10 | * @type {(fn: (v: T) => T, value?: T, options?: { async?: boolean }) => () => void}
11 | */
12 | export const createEffect = effect;
13 |
14 | /**
15 | * @template T
16 | * @type {(fn: (v: T) => T, value?: T, options?: { equals?: boolean | ((prev: T, next: T) => boolean) }) => () => T}
17 | */
18 | export const createMemo = (fn, value, options) => {
19 | const _ = computed(fn, value, options);
20 | return () => _.value;
21 | };
22 |
23 | /**
24 | * @template T
25 | * @type {(initialValue: T, options?: { equals?: boolean | ((prev: T, next: T) => boolean) }) => [get: () => T, set: (v: T) => T]}
26 | */
27 | export const createSignal = (initialValue, options) => {
28 | const _ = signal(asValue(initialValue), options);
29 | return [
30 | () => _.value,
31 | value => {
32 | _.value = asValue(value);
33 | }
34 | ];
35 | };
36 |
--------------------------------------------------------------------------------
/esm/solid/sync.js:
--------------------------------------------------------------------------------
1 | export * from './index.js';
2 | import {createEffect as fx} from './index.js';
3 |
4 | const options = {async: false};
5 |
6 | /**
7 | * synchronous https://www.solidjs.com/docs/latest/api#createeffect
8 | *
9 | * returns a dispose callback.
10 | * @template T
11 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
12 | */
13 | export const createEffect = (fn, initialValue) => fx(fn, initialValue, options);
--------------------------------------------------------------------------------
/esm/sync.js:
--------------------------------------------------------------------------------
1 | export * from './index.js';
2 | import {effect as fx} from './index.js';
3 |
4 | const options = {async: false};
5 |
6 | /**
7 | * Invokes synchronously a function when any of its internal signals or computed values change.
8 | *
9 | * Returns a dispose callback.
10 | * @template T
11 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
12 | */
13 | export const effect = (fn, value) => fx(fn, value, options);
14 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "usignal",
3 | "version": "0.10.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "usignal",
9 | "version": "0.10.0",
10 | "license": "ISC",
11 | "devDependencies": {
12 | "@rollup/plugin-node-resolve": "^15.0.1",
13 | "@rollup/plugin-terser": "^0.4.0",
14 | "ascjs": "^5.0.1",
15 | "c8": "^7.12.0",
16 | "expect-type": "^0.15.0",
17 | "rollup": "^3.10.1",
18 | "typescript": "^4.9.4"
19 | }
20 | },
21 | "node_modules/@babel/parser": {
22 | "version": "7.20.13",
23 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.13.tgz",
24 | "integrity": "sha512-gFDLKMfpiXCsjt4za2JA9oTMn70CeseCehb11kRZgvd7+F67Hih3OHOK24cRrWECJ/ljfPGac6ygXAs/C8kIvw==",
25 | "dev": true,
26 | "bin": {
27 | "parser": "bin/babel-parser.js"
28 | },
29 | "engines": {
30 | "node": ">=6.0.0"
31 | }
32 | },
33 | "node_modules/@bcoe/v8-coverage": {
34 | "version": "0.2.3",
35 | "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
36 | "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
37 | "dev": true
38 | },
39 | "node_modules/@istanbuljs/schema": {
40 | "version": "0.1.3",
41 | "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
42 | "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
43 | "dev": true,
44 | "engines": {
45 | "node": ">=8"
46 | }
47 | },
48 | "node_modules/@jridgewell/gen-mapping": {
49 | "version": "0.3.2",
50 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
51 | "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
52 | "dev": true,
53 | "dependencies": {
54 | "@jridgewell/set-array": "^1.0.1",
55 | "@jridgewell/sourcemap-codec": "^1.4.10",
56 | "@jridgewell/trace-mapping": "^0.3.9"
57 | },
58 | "engines": {
59 | "node": ">=6.0.0"
60 | }
61 | },
62 | "node_modules/@jridgewell/resolve-uri": {
63 | "version": "3.1.0",
64 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
65 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
66 | "dev": true,
67 | "engines": {
68 | "node": ">=6.0.0"
69 | }
70 | },
71 | "node_modules/@jridgewell/set-array": {
72 | "version": "1.1.2",
73 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
74 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
75 | "dev": true,
76 | "engines": {
77 | "node": ">=6.0.0"
78 | }
79 | },
80 | "node_modules/@jridgewell/source-map": {
81 | "version": "0.3.2",
82 | "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
83 | "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
84 | "dev": true,
85 | "dependencies": {
86 | "@jridgewell/gen-mapping": "^0.3.0",
87 | "@jridgewell/trace-mapping": "^0.3.9"
88 | }
89 | },
90 | "node_modules/@jridgewell/sourcemap-codec": {
91 | "version": "1.4.14",
92 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
93 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
94 | "dev": true
95 | },
96 | "node_modules/@jridgewell/trace-mapping": {
97 | "version": "0.3.17",
98 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
99 | "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
100 | "dev": true,
101 | "dependencies": {
102 | "@jridgewell/resolve-uri": "3.1.0",
103 | "@jridgewell/sourcemap-codec": "1.4.14"
104 | }
105 | },
106 | "node_modules/@rollup/plugin-node-resolve": {
107 | "version": "15.0.1",
108 | "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.1.tgz",
109 | "integrity": "sha512-ReY88T7JhJjeRVbfCyNj+NXAG3IIsVMsX9b5/9jC98dRP8/yxlZdz7mHZbHk5zHr24wZZICS5AcXsFZAXYUQEg==",
110 | "dev": true,
111 | "dependencies": {
112 | "@rollup/pluginutils": "^5.0.1",
113 | "@types/resolve": "1.20.2",
114 | "deepmerge": "^4.2.2",
115 | "is-builtin-module": "^3.2.0",
116 | "is-module": "^1.0.0",
117 | "resolve": "^1.22.1"
118 | },
119 | "engines": {
120 | "node": ">=14.0.0"
121 | },
122 | "peerDependencies": {
123 | "rollup": "^2.78.0||^3.0.0"
124 | },
125 | "peerDependenciesMeta": {
126 | "rollup": {
127 | "optional": true
128 | }
129 | }
130 | },
131 | "node_modules/@rollup/plugin-terser": {
132 | "version": "0.4.0",
133 | "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.0.tgz",
134 | "integrity": "sha512-Ipcf3LPNerey1q9ZMjiaWHlNPEHNU/B5/uh9zXLltfEQ1lVSLLeZSgAtTPWGyw8Ip1guOeq+mDtdOlEj/wNxQw==",
135 | "dev": true,
136 | "dependencies": {
137 | "serialize-javascript": "^6.0.0",
138 | "smob": "^0.0.6",
139 | "terser": "^5.15.1"
140 | },
141 | "engines": {
142 | "node": ">=14.0.0"
143 | },
144 | "peerDependencies": {
145 | "rollup": "^2.x || ^3.x"
146 | },
147 | "peerDependenciesMeta": {
148 | "rollup": {
149 | "optional": true
150 | }
151 | }
152 | },
153 | "node_modules/@rollup/pluginutils": {
154 | "version": "5.0.2",
155 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz",
156 | "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==",
157 | "dev": true,
158 | "dependencies": {
159 | "@types/estree": "^1.0.0",
160 | "estree-walker": "^2.0.2",
161 | "picomatch": "^2.3.1"
162 | },
163 | "engines": {
164 | "node": ">=14.0.0"
165 | },
166 | "peerDependencies": {
167 | "rollup": "^1.20.0||^2.0.0||^3.0.0"
168 | },
169 | "peerDependenciesMeta": {
170 | "rollup": {
171 | "optional": true
172 | }
173 | }
174 | },
175 | "node_modules/@types/estree": {
176 | "version": "1.0.0",
177 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz",
178 | "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==",
179 | "dev": true
180 | },
181 | "node_modules/@types/istanbul-lib-coverage": {
182 | "version": "2.0.4",
183 | "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
184 | "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==",
185 | "dev": true
186 | },
187 | "node_modules/@types/resolve": {
188 | "version": "1.20.2",
189 | "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
190 | "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
191 | "dev": true
192 | },
193 | "node_modules/acorn": {
194 | "version": "8.8.1",
195 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
196 | "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
197 | "dev": true,
198 | "bin": {
199 | "acorn": "bin/acorn"
200 | },
201 | "engines": {
202 | "node": ">=0.4.0"
203 | }
204 | },
205 | "node_modules/ansi-regex": {
206 | "version": "5.0.1",
207 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
208 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
209 | "dev": true,
210 | "engines": {
211 | "node": ">=8"
212 | }
213 | },
214 | "node_modules/ansi-styles": {
215 | "version": "4.3.0",
216 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
217 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
218 | "dev": true,
219 | "dependencies": {
220 | "color-convert": "^2.0.1"
221 | },
222 | "engines": {
223 | "node": ">=8"
224 | },
225 | "funding": {
226 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
227 | }
228 | },
229 | "node_modules/ascjs": {
230 | "version": "5.0.1",
231 | "resolved": "https://registry.npmjs.org/ascjs/-/ascjs-5.0.1.tgz",
232 | "integrity": "sha512-1d/QdICzpywXiP53/Zz3fMdaC0/BB1ybLf+fK+QrqY8iyXNnWUHUrpmrowueXeswo+O+meJWm43TJSg2ClP3Sg==",
233 | "dev": true,
234 | "dependencies": {
235 | "@babel/parser": "^7.12.5"
236 | },
237 | "bin": {
238 | "ascjs": "bin.js"
239 | }
240 | },
241 | "node_modules/balanced-match": {
242 | "version": "1.0.2",
243 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
244 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
245 | "dev": true
246 | },
247 | "node_modules/brace-expansion": {
248 | "version": "1.1.11",
249 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
250 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
251 | "dev": true,
252 | "dependencies": {
253 | "balanced-match": "^1.0.0",
254 | "concat-map": "0.0.1"
255 | }
256 | },
257 | "node_modules/buffer-from": {
258 | "version": "1.1.2",
259 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
260 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
261 | "dev": true
262 | },
263 | "node_modules/builtin-modules": {
264 | "version": "3.3.0",
265 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
266 | "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
267 | "dev": true,
268 | "engines": {
269 | "node": ">=6"
270 | },
271 | "funding": {
272 | "url": "https://github.com/sponsors/sindresorhus"
273 | }
274 | },
275 | "node_modules/c8": {
276 | "version": "7.12.0",
277 | "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz",
278 | "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==",
279 | "dev": true,
280 | "dependencies": {
281 | "@bcoe/v8-coverage": "^0.2.3",
282 | "@istanbuljs/schema": "^0.1.3",
283 | "find-up": "^5.0.0",
284 | "foreground-child": "^2.0.0",
285 | "istanbul-lib-coverage": "^3.2.0",
286 | "istanbul-lib-report": "^3.0.0",
287 | "istanbul-reports": "^3.1.4",
288 | "rimraf": "^3.0.2",
289 | "test-exclude": "^6.0.0",
290 | "v8-to-istanbul": "^9.0.0",
291 | "yargs": "^16.2.0",
292 | "yargs-parser": "^20.2.9"
293 | },
294 | "bin": {
295 | "c8": "bin/c8.js"
296 | },
297 | "engines": {
298 | "node": ">=10.12.0"
299 | }
300 | },
301 | "node_modules/cliui": {
302 | "version": "7.0.4",
303 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
304 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
305 | "dev": true,
306 | "dependencies": {
307 | "string-width": "^4.2.0",
308 | "strip-ansi": "^6.0.0",
309 | "wrap-ansi": "^7.0.0"
310 | }
311 | },
312 | "node_modules/color-convert": {
313 | "version": "2.0.1",
314 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
315 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
316 | "dev": true,
317 | "dependencies": {
318 | "color-name": "~1.1.4"
319 | },
320 | "engines": {
321 | "node": ">=7.0.0"
322 | }
323 | },
324 | "node_modules/color-name": {
325 | "version": "1.1.4",
326 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
327 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
328 | "dev": true
329 | },
330 | "node_modules/commander": {
331 | "version": "2.20.3",
332 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
333 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
334 | "dev": true
335 | },
336 | "node_modules/concat-map": {
337 | "version": "0.0.1",
338 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
339 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
340 | "dev": true
341 | },
342 | "node_modules/convert-source-map": {
343 | "version": "1.9.0",
344 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
345 | "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
346 | "dev": true
347 | },
348 | "node_modules/cross-spawn": {
349 | "version": "7.0.3",
350 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
351 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
352 | "dev": true,
353 | "dependencies": {
354 | "path-key": "^3.1.0",
355 | "shebang-command": "^2.0.0",
356 | "which": "^2.0.1"
357 | },
358 | "engines": {
359 | "node": ">= 8"
360 | }
361 | },
362 | "node_modules/deepmerge": {
363 | "version": "4.2.2",
364 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
365 | "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
366 | "dev": true,
367 | "engines": {
368 | "node": ">=0.10.0"
369 | }
370 | },
371 | "node_modules/emoji-regex": {
372 | "version": "8.0.0",
373 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
374 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
375 | "dev": true
376 | },
377 | "node_modules/escalade": {
378 | "version": "3.1.1",
379 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
380 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
381 | "dev": true,
382 | "engines": {
383 | "node": ">=6"
384 | }
385 | },
386 | "node_modules/estree-walker": {
387 | "version": "2.0.2",
388 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
389 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
390 | "dev": true
391 | },
392 | "node_modules/expect-type": {
393 | "version": "0.15.0",
394 | "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-0.15.0.tgz",
395 | "integrity": "sha512-yWnriYB4e8G54M5/fAFj7rCIBiKs1HAACaY13kCz6Ku0dezjS9aMcfcdVK2X8Tv2tEV1BPz/wKfQ7WA4S/d8aA==",
396 | "dev": true
397 | },
398 | "node_modules/find-up": {
399 | "version": "5.0.0",
400 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
401 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
402 | "dev": true,
403 | "dependencies": {
404 | "locate-path": "^6.0.0",
405 | "path-exists": "^4.0.0"
406 | },
407 | "engines": {
408 | "node": ">=10"
409 | },
410 | "funding": {
411 | "url": "https://github.com/sponsors/sindresorhus"
412 | }
413 | },
414 | "node_modules/foreground-child": {
415 | "version": "2.0.0",
416 | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
417 | "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
418 | "dev": true,
419 | "dependencies": {
420 | "cross-spawn": "^7.0.0",
421 | "signal-exit": "^3.0.2"
422 | },
423 | "engines": {
424 | "node": ">=8.0.0"
425 | }
426 | },
427 | "node_modules/fs.realpath": {
428 | "version": "1.0.0",
429 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
430 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
431 | "dev": true
432 | },
433 | "node_modules/fsevents": {
434 | "version": "2.3.2",
435 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
436 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
437 | "dev": true,
438 | "hasInstallScript": true,
439 | "optional": true,
440 | "os": [
441 | "darwin"
442 | ],
443 | "engines": {
444 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
445 | }
446 | },
447 | "node_modules/function-bind": {
448 | "version": "1.1.1",
449 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
450 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
451 | "dev": true
452 | },
453 | "node_modules/get-caller-file": {
454 | "version": "2.0.5",
455 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
456 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
457 | "dev": true,
458 | "engines": {
459 | "node": "6.* || 8.* || >= 10.*"
460 | }
461 | },
462 | "node_modules/glob": {
463 | "version": "7.2.3",
464 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
465 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
466 | "dev": true,
467 | "dependencies": {
468 | "fs.realpath": "^1.0.0",
469 | "inflight": "^1.0.4",
470 | "inherits": "2",
471 | "minimatch": "^3.1.1",
472 | "once": "^1.3.0",
473 | "path-is-absolute": "^1.0.0"
474 | },
475 | "engines": {
476 | "node": "*"
477 | },
478 | "funding": {
479 | "url": "https://github.com/sponsors/isaacs"
480 | }
481 | },
482 | "node_modules/has": {
483 | "version": "1.0.3",
484 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
485 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
486 | "dev": true,
487 | "dependencies": {
488 | "function-bind": "^1.1.1"
489 | },
490 | "engines": {
491 | "node": ">= 0.4.0"
492 | }
493 | },
494 | "node_modules/has-flag": {
495 | "version": "4.0.0",
496 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
497 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
498 | "dev": true,
499 | "engines": {
500 | "node": ">=8"
501 | }
502 | },
503 | "node_modules/html-escaper": {
504 | "version": "2.0.2",
505 | "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
506 | "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
507 | "dev": true
508 | },
509 | "node_modules/inflight": {
510 | "version": "1.0.6",
511 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
512 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
513 | "dev": true,
514 | "dependencies": {
515 | "once": "^1.3.0",
516 | "wrappy": "1"
517 | }
518 | },
519 | "node_modules/inherits": {
520 | "version": "2.0.4",
521 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
522 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
523 | "dev": true
524 | },
525 | "node_modules/is-builtin-module": {
526 | "version": "3.2.0",
527 | "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz",
528 | "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==",
529 | "dev": true,
530 | "dependencies": {
531 | "builtin-modules": "^3.3.0"
532 | },
533 | "engines": {
534 | "node": ">=6"
535 | },
536 | "funding": {
537 | "url": "https://github.com/sponsors/sindresorhus"
538 | }
539 | },
540 | "node_modules/is-core-module": {
541 | "version": "2.11.0",
542 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
543 | "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
544 | "dev": true,
545 | "dependencies": {
546 | "has": "^1.0.3"
547 | },
548 | "funding": {
549 | "url": "https://github.com/sponsors/ljharb"
550 | }
551 | },
552 | "node_modules/is-fullwidth-code-point": {
553 | "version": "3.0.0",
554 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
555 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
556 | "dev": true,
557 | "engines": {
558 | "node": ">=8"
559 | }
560 | },
561 | "node_modules/is-module": {
562 | "version": "1.0.0",
563 | "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
564 | "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
565 | "dev": true
566 | },
567 | "node_modules/isexe": {
568 | "version": "2.0.0",
569 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
570 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
571 | "dev": true
572 | },
573 | "node_modules/istanbul-lib-coverage": {
574 | "version": "3.2.0",
575 | "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
576 | "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
577 | "dev": true,
578 | "engines": {
579 | "node": ">=8"
580 | }
581 | },
582 | "node_modules/istanbul-lib-report": {
583 | "version": "3.0.0",
584 | "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
585 | "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
586 | "dev": true,
587 | "dependencies": {
588 | "istanbul-lib-coverage": "^3.0.0",
589 | "make-dir": "^3.0.0",
590 | "supports-color": "^7.1.0"
591 | },
592 | "engines": {
593 | "node": ">=8"
594 | }
595 | },
596 | "node_modules/istanbul-reports": {
597 | "version": "3.1.5",
598 | "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
599 | "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
600 | "dev": true,
601 | "dependencies": {
602 | "html-escaper": "^2.0.0",
603 | "istanbul-lib-report": "^3.0.0"
604 | },
605 | "engines": {
606 | "node": ">=8"
607 | }
608 | },
609 | "node_modules/locate-path": {
610 | "version": "6.0.0",
611 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
612 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
613 | "dev": true,
614 | "dependencies": {
615 | "p-locate": "^5.0.0"
616 | },
617 | "engines": {
618 | "node": ">=10"
619 | },
620 | "funding": {
621 | "url": "https://github.com/sponsors/sindresorhus"
622 | }
623 | },
624 | "node_modules/make-dir": {
625 | "version": "3.1.0",
626 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
627 | "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
628 | "dev": true,
629 | "dependencies": {
630 | "semver": "^6.0.0"
631 | },
632 | "engines": {
633 | "node": ">=8"
634 | },
635 | "funding": {
636 | "url": "https://github.com/sponsors/sindresorhus"
637 | }
638 | },
639 | "node_modules/minimatch": {
640 | "version": "3.1.2",
641 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
642 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
643 | "dev": true,
644 | "dependencies": {
645 | "brace-expansion": "^1.1.7"
646 | },
647 | "engines": {
648 | "node": "*"
649 | }
650 | },
651 | "node_modules/once": {
652 | "version": "1.4.0",
653 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
654 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
655 | "dev": true,
656 | "dependencies": {
657 | "wrappy": "1"
658 | }
659 | },
660 | "node_modules/p-limit": {
661 | "version": "3.1.0",
662 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
663 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
664 | "dev": true,
665 | "dependencies": {
666 | "yocto-queue": "^0.1.0"
667 | },
668 | "engines": {
669 | "node": ">=10"
670 | },
671 | "funding": {
672 | "url": "https://github.com/sponsors/sindresorhus"
673 | }
674 | },
675 | "node_modules/p-locate": {
676 | "version": "5.0.0",
677 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
678 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
679 | "dev": true,
680 | "dependencies": {
681 | "p-limit": "^3.0.2"
682 | },
683 | "engines": {
684 | "node": ">=10"
685 | },
686 | "funding": {
687 | "url": "https://github.com/sponsors/sindresorhus"
688 | }
689 | },
690 | "node_modules/path-exists": {
691 | "version": "4.0.0",
692 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
693 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
694 | "dev": true,
695 | "engines": {
696 | "node": ">=8"
697 | }
698 | },
699 | "node_modules/path-is-absolute": {
700 | "version": "1.0.1",
701 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
702 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
703 | "dev": true,
704 | "engines": {
705 | "node": ">=0.10.0"
706 | }
707 | },
708 | "node_modules/path-key": {
709 | "version": "3.1.1",
710 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
711 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
712 | "dev": true,
713 | "engines": {
714 | "node": ">=8"
715 | }
716 | },
717 | "node_modules/path-parse": {
718 | "version": "1.0.7",
719 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
720 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
721 | "dev": true
722 | },
723 | "node_modules/picomatch": {
724 | "version": "2.3.1",
725 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
726 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
727 | "dev": true,
728 | "engines": {
729 | "node": ">=8.6"
730 | },
731 | "funding": {
732 | "url": "https://github.com/sponsors/jonschlinkert"
733 | }
734 | },
735 | "node_modules/randombytes": {
736 | "version": "2.1.0",
737 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
738 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
739 | "dev": true,
740 | "dependencies": {
741 | "safe-buffer": "^5.1.0"
742 | }
743 | },
744 | "node_modules/require-directory": {
745 | "version": "2.1.1",
746 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
747 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
748 | "dev": true,
749 | "engines": {
750 | "node": ">=0.10.0"
751 | }
752 | },
753 | "node_modules/resolve": {
754 | "version": "1.22.1",
755 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
756 | "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
757 | "dev": true,
758 | "dependencies": {
759 | "is-core-module": "^2.9.0",
760 | "path-parse": "^1.0.7",
761 | "supports-preserve-symlinks-flag": "^1.0.0"
762 | },
763 | "bin": {
764 | "resolve": "bin/resolve"
765 | },
766 | "funding": {
767 | "url": "https://github.com/sponsors/ljharb"
768 | }
769 | },
770 | "node_modules/rimraf": {
771 | "version": "3.0.2",
772 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
773 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
774 | "dev": true,
775 | "dependencies": {
776 | "glob": "^7.1.3"
777 | },
778 | "bin": {
779 | "rimraf": "bin.js"
780 | },
781 | "funding": {
782 | "url": "https://github.com/sponsors/isaacs"
783 | }
784 | },
785 | "node_modules/rollup": {
786 | "version": "3.10.1",
787 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.10.1.tgz",
788 | "integrity": "sha512-3Er+yel3bZbZX1g2kjVM+FW+RUWDxbG87fcqFM5/9HbPCTpbVp6JOLn7jlxnNlbu7s/N/uDA4EV/91E2gWnxzw==",
789 | "dev": true,
790 | "bin": {
791 | "rollup": "dist/bin/rollup"
792 | },
793 | "engines": {
794 | "node": ">=14.18.0",
795 | "npm": ">=8.0.0"
796 | },
797 | "optionalDependencies": {
798 | "fsevents": "~2.3.2"
799 | }
800 | },
801 | "node_modules/safe-buffer": {
802 | "version": "5.2.1",
803 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
804 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
805 | "dev": true,
806 | "funding": [
807 | {
808 | "type": "github",
809 | "url": "https://github.com/sponsors/feross"
810 | },
811 | {
812 | "type": "patreon",
813 | "url": "https://www.patreon.com/feross"
814 | },
815 | {
816 | "type": "consulting",
817 | "url": "https://feross.org/support"
818 | }
819 | ]
820 | },
821 | "node_modules/semver": {
822 | "version": "6.3.0",
823 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
824 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
825 | "dev": true,
826 | "bin": {
827 | "semver": "bin/semver.js"
828 | }
829 | },
830 | "node_modules/serialize-javascript": {
831 | "version": "6.0.1",
832 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
833 | "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
834 | "dev": true,
835 | "dependencies": {
836 | "randombytes": "^2.1.0"
837 | }
838 | },
839 | "node_modules/shebang-command": {
840 | "version": "2.0.0",
841 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
842 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
843 | "dev": true,
844 | "dependencies": {
845 | "shebang-regex": "^3.0.0"
846 | },
847 | "engines": {
848 | "node": ">=8"
849 | }
850 | },
851 | "node_modules/shebang-regex": {
852 | "version": "3.0.0",
853 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
854 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
855 | "dev": true,
856 | "engines": {
857 | "node": ">=8"
858 | }
859 | },
860 | "node_modules/signal-exit": {
861 | "version": "3.0.7",
862 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
863 | "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
864 | "dev": true
865 | },
866 | "node_modules/smob": {
867 | "version": "0.0.6",
868 | "resolved": "https://registry.npmjs.org/smob/-/smob-0.0.6.tgz",
869 | "integrity": "sha512-V21+XeNni+tTyiST1MHsa84AQhT1aFZipzPpOFAVB8DkHzwJyjjAmt9bgwnuZiZWnIbMo2duE29wybxv/7HWUw==",
870 | "dev": true
871 | },
872 | "node_modules/source-map": {
873 | "version": "0.6.1",
874 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
875 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
876 | "dev": true,
877 | "engines": {
878 | "node": ">=0.10.0"
879 | }
880 | },
881 | "node_modules/source-map-support": {
882 | "version": "0.5.21",
883 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
884 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
885 | "dev": true,
886 | "dependencies": {
887 | "buffer-from": "^1.0.0",
888 | "source-map": "^0.6.0"
889 | }
890 | },
891 | "node_modules/string-width": {
892 | "version": "4.2.3",
893 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
894 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
895 | "dev": true,
896 | "dependencies": {
897 | "emoji-regex": "^8.0.0",
898 | "is-fullwidth-code-point": "^3.0.0",
899 | "strip-ansi": "^6.0.1"
900 | },
901 | "engines": {
902 | "node": ">=8"
903 | }
904 | },
905 | "node_modules/strip-ansi": {
906 | "version": "6.0.1",
907 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
908 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
909 | "dev": true,
910 | "dependencies": {
911 | "ansi-regex": "^5.0.1"
912 | },
913 | "engines": {
914 | "node": ">=8"
915 | }
916 | },
917 | "node_modules/supports-color": {
918 | "version": "7.2.0",
919 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
920 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
921 | "dev": true,
922 | "dependencies": {
923 | "has-flag": "^4.0.0"
924 | },
925 | "engines": {
926 | "node": ">=8"
927 | }
928 | },
929 | "node_modules/supports-preserve-symlinks-flag": {
930 | "version": "1.0.0",
931 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
932 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
933 | "dev": true,
934 | "engines": {
935 | "node": ">= 0.4"
936 | },
937 | "funding": {
938 | "url": "https://github.com/sponsors/ljharb"
939 | }
940 | },
941 | "node_modules/terser": {
942 | "version": "5.16.1",
943 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz",
944 | "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==",
945 | "dev": true,
946 | "dependencies": {
947 | "@jridgewell/source-map": "^0.3.2",
948 | "acorn": "^8.5.0",
949 | "commander": "^2.20.0",
950 | "source-map-support": "~0.5.20"
951 | },
952 | "bin": {
953 | "terser": "bin/terser"
954 | },
955 | "engines": {
956 | "node": ">=10"
957 | }
958 | },
959 | "node_modules/test-exclude": {
960 | "version": "6.0.0",
961 | "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
962 | "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
963 | "dev": true,
964 | "dependencies": {
965 | "@istanbuljs/schema": "^0.1.2",
966 | "glob": "^7.1.4",
967 | "minimatch": "^3.0.4"
968 | },
969 | "engines": {
970 | "node": ">=8"
971 | }
972 | },
973 | "node_modules/typescript": {
974 | "version": "4.9.4",
975 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
976 | "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
977 | "dev": true,
978 | "bin": {
979 | "tsc": "bin/tsc",
980 | "tsserver": "bin/tsserver"
981 | },
982 | "engines": {
983 | "node": ">=4.2.0"
984 | }
985 | },
986 | "node_modules/v8-to-istanbul": {
987 | "version": "9.0.1",
988 | "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz",
989 | "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==",
990 | "dev": true,
991 | "dependencies": {
992 | "@jridgewell/trace-mapping": "^0.3.12",
993 | "@types/istanbul-lib-coverage": "^2.0.1",
994 | "convert-source-map": "^1.6.0"
995 | },
996 | "engines": {
997 | "node": ">=10.12.0"
998 | }
999 | },
1000 | "node_modules/which": {
1001 | "version": "2.0.2",
1002 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
1003 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
1004 | "dev": true,
1005 | "dependencies": {
1006 | "isexe": "^2.0.0"
1007 | },
1008 | "bin": {
1009 | "node-which": "bin/node-which"
1010 | },
1011 | "engines": {
1012 | "node": ">= 8"
1013 | }
1014 | },
1015 | "node_modules/wrap-ansi": {
1016 | "version": "7.0.0",
1017 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
1018 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
1019 | "dev": true,
1020 | "dependencies": {
1021 | "ansi-styles": "^4.0.0",
1022 | "string-width": "^4.1.0",
1023 | "strip-ansi": "^6.0.0"
1024 | },
1025 | "engines": {
1026 | "node": ">=10"
1027 | },
1028 | "funding": {
1029 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
1030 | }
1031 | },
1032 | "node_modules/wrappy": {
1033 | "version": "1.0.2",
1034 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1035 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
1036 | "dev": true
1037 | },
1038 | "node_modules/y18n": {
1039 | "version": "5.0.8",
1040 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
1041 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
1042 | "dev": true,
1043 | "engines": {
1044 | "node": ">=10"
1045 | }
1046 | },
1047 | "node_modules/yargs": {
1048 | "version": "16.2.0",
1049 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
1050 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
1051 | "dev": true,
1052 | "dependencies": {
1053 | "cliui": "^7.0.2",
1054 | "escalade": "^3.1.1",
1055 | "get-caller-file": "^2.0.5",
1056 | "require-directory": "^2.1.1",
1057 | "string-width": "^4.2.0",
1058 | "y18n": "^5.0.5",
1059 | "yargs-parser": "^20.2.2"
1060 | },
1061 | "engines": {
1062 | "node": ">=10"
1063 | }
1064 | },
1065 | "node_modules/yargs-parser": {
1066 | "version": "20.2.9",
1067 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
1068 | "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
1069 | "dev": true,
1070 | "engines": {
1071 | "node": ">=10"
1072 | }
1073 | },
1074 | "node_modules/yocto-queue": {
1075 | "version": "0.1.0",
1076 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
1077 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
1078 | "dev": true,
1079 | "engines": {
1080 | "node": ">=10"
1081 | },
1082 | "funding": {
1083 | "url": "https://github.com/sponsors/sindresorhus"
1084 | }
1085 | }
1086 | },
1087 | "dependencies": {
1088 | "@babel/parser": {
1089 | "version": "7.20.13",
1090 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.13.tgz",
1091 | "integrity": "sha512-gFDLKMfpiXCsjt4za2JA9oTMn70CeseCehb11kRZgvd7+F67Hih3OHOK24cRrWECJ/ljfPGac6ygXAs/C8kIvw==",
1092 | "dev": true
1093 | },
1094 | "@bcoe/v8-coverage": {
1095 | "version": "0.2.3",
1096 | "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
1097 | "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
1098 | "dev": true
1099 | },
1100 | "@istanbuljs/schema": {
1101 | "version": "0.1.3",
1102 | "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
1103 | "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
1104 | "dev": true
1105 | },
1106 | "@jridgewell/gen-mapping": {
1107 | "version": "0.3.2",
1108 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
1109 | "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
1110 | "dev": true,
1111 | "requires": {
1112 | "@jridgewell/set-array": "^1.0.1",
1113 | "@jridgewell/sourcemap-codec": "^1.4.10",
1114 | "@jridgewell/trace-mapping": "^0.3.9"
1115 | }
1116 | },
1117 | "@jridgewell/resolve-uri": {
1118 | "version": "3.1.0",
1119 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
1120 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
1121 | "dev": true
1122 | },
1123 | "@jridgewell/set-array": {
1124 | "version": "1.1.2",
1125 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
1126 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
1127 | "dev": true
1128 | },
1129 | "@jridgewell/source-map": {
1130 | "version": "0.3.2",
1131 | "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
1132 | "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
1133 | "dev": true,
1134 | "requires": {
1135 | "@jridgewell/gen-mapping": "^0.3.0",
1136 | "@jridgewell/trace-mapping": "^0.3.9"
1137 | }
1138 | },
1139 | "@jridgewell/sourcemap-codec": {
1140 | "version": "1.4.14",
1141 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
1142 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
1143 | "dev": true
1144 | },
1145 | "@jridgewell/trace-mapping": {
1146 | "version": "0.3.17",
1147 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
1148 | "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
1149 | "dev": true,
1150 | "requires": {
1151 | "@jridgewell/resolve-uri": "3.1.0",
1152 | "@jridgewell/sourcemap-codec": "1.4.14"
1153 | }
1154 | },
1155 | "@rollup/plugin-node-resolve": {
1156 | "version": "15.0.1",
1157 | "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.1.tgz",
1158 | "integrity": "sha512-ReY88T7JhJjeRVbfCyNj+NXAG3IIsVMsX9b5/9jC98dRP8/yxlZdz7mHZbHk5zHr24wZZICS5AcXsFZAXYUQEg==",
1159 | "dev": true,
1160 | "requires": {
1161 | "@rollup/pluginutils": "^5.0.1",
1162 | "@types/resolve": "1.20.2",
1163 | "deepmerge": "^4.2.2",
1164 | "is-builtin-module": "^3.2.0",
1165 | "is-module": "^1.0.0",
1166 | "resolve": "^1.22.1"
1167 | }
1168 | },
1169 | "@rollup/plugin-terser": {
1170 | "version": "0.4.0",
1171 | "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.0.tgz",
1172 | "integrity": "sha512-Ipcf3LPNerey1q9ZMjiaWHlNPEHNU/B5/uh9zXLltfEQ1lVSLLeZSgAtTPWGyw8Ip1guOeq+mDtdOlEj/wNxQw==",
1173 | "dev": true,
1174 | "requires": {
1175 | "serialize-javascript": "^6.0.0",
1176 | "smob": "^0.0.6",
1177 | "terser": "^5.15.1"
1178 | }
1179 | },
1180 | "@rollup/pluginutils": {
1181 | "version": "5.0.2",
1182 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz",
1183 | "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==",
1184 | "dev": true,
1185 | "requires": {
1186 | "@types/estree": "^1.0.0",
1187 | "estree-walker": "^2.0.2",
1188 | "picomatch": "^2.3.1"
1189 | }
1190 | },
1191 | "@types/estree": {
1192 | "version": "1.0.0",
1193 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz",
1194 | "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==",
1195 | "dev": true
1196 | },
1197 | "@types/istanbul-lib-coverage": {
1198 | "version": "2.0.4",
1199 | "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
1200 | "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==",
1201 | "dev": true
1202 | },
1203 | "@types/resolve": {
1204 | "version": "1.20.2",
1205 | "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
1206 | "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
1207 | "dev": true
1208 | },
1209 | "acorn": {
1210 | "version": "8.8.1",
1211 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
1212 | "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
1213 | "dev": true
1214 | },
1215 | "ansi-regex": {
1216 | "version": "5.0.1",
1217 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
1218 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
1219 | "dev": true
1220 | },
1221 | "ansi-styles": {
1222 | "version": "4.3.0",
1223 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
1224 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
1225 | "dev": true,
1226 | "requires": {
1227 | "color-convert": "^2.0.1"
1228 | }
1229 | },
1230 | "ascjs": {
1231 | "version": "5.0.1",
1232 | "resolved": "https://registry.npmjs.org/ascjs/-/ascjs-5.0.1.tgz",
1233 | "integrity": "sha512-1d/QdICzpywXiP53/Zz3fMdaC0/BB1ybLf+fK+QrqY8iyXNnWUHUrpmrowueXeswo+O+meJWm43TJSg2ClP3Sg==",
1234 | "dev": true,
1235 | "requires": {
1236 | "@babel/parser": "^7.12.5"
1237 | }
1238 | },
1239 | "balanced-match": {
1240 | "version": "1.0.2",
1241 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
1242 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
1243 | "dev": true
1244 | },
1245 | "brace-expansion": {
1246 | "version": "1.1.11",
1247 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
1248 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
1249 | "dev": true,
1250 | "requires": {
1251 | "balanced-match": "^1.0.0",
1252 | "concat-map": "0.0.1"
1253 | }
1254 | },
1255 | "buffer-from": {
1256 | "version": "1.1.2",
1257 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
1258 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
1259 | "dev": true
1260 | },
1261 | "builtin-modules": {
1262 | "version": "3.3.0",
1263 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
1264 | "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
1265 | "dev": true
1266 | },
1267 | "c8": {
1268 | "version": "7.12.0",
1269 | "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz",
1270 | "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==",
1271 | "dev": true,
1272 | "requires": {
1273 | "@bcoe/v8-coverage": "^0.2.3",
1274 | "@istanbuljs/schema": "^0.1.3",
1275 | "find-up": "^5.0.0",
1276 | "foreground-child": "^2.0.0",
1277 | "istanbul-lib-coverage": "^3.2.0",
1278 | "istanbul-lib-report": "^3.0.0",
1279 | "istanbul-reports": "^3.1.4",
1280 | "rimraf": "^3.0.2",
1281 | "test-exclude": "^6.0.0",
1282 | "v8-to-istanbul": "^9.0.0",
1283 | "yargs": "^16.2.0",
1284 | "yargs-parser": "^20.2.9"
1285 | }
1286 | },
1287 | "cliui": {
1288 | "version": "7.0.4",
1289 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
1290 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
1291 | "dev": true,
1292 | "requires": {
1293 | "string-width": "^4.2.0",
1294 | "strip-ansi": "^6.0.0",
1295 | "wrap-ansi": "^7.0.0"
1296 | }
1297 | },
1298 | "color-convert": {
1299 | "version": "2.0.1",
1300 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
1301 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
1302 | "dev": true,
1303 | "requires": {
1304 | "color-name": "~1.1.4"
1305 | }
1306 | },
1307 | "color-name": {
1308 | "version": "1.1.4",
1309 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
1310 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
1311 | "dev": true
1312 | },
1313 | "commander": {
1314 | "version": "2.20.3",
1315 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
1316 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
1317 | "dev": true
1318 | },
1319 | "concat-map": {
1320 | "version": "0.0.1",
1321 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
1322 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
1323 | "dev": true
1324 | },
1325 | "convert-source-map": {
1326 | "version": "1.9.0",
1327 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
1328 | "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
1329 | "dev": true
1330 | },
1331 | "cross-spawn": {
1332 | "version": "7.0.3",
1333 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
1334 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
1335 | "dev": true,
1336 | "requires": {
1337 | "path-key": "^3.1.0",
1338 | "shebang-command": "^2.0.0",
1339 | "which": "^2.0.1"
1340 | }
1341 | },
1342 | "deepmerge": {
1343 | "version": "4.2.2",
1344 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
1345 | "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
1346 | "dev": true
1347 | },
1348 | "emoji-regex": {
1349 | "version": "8.0.0",
1350 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
1351 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
1352 | "dev": true
1353 | },
1354 | "escalade": {
1355 | "version": "3.1.1",
1356 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
1357 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
1358 | "dev": true
1359 | },
1360 | "estree-walker": {
1361 | "version": "2.0.2",
1362 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
1363 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
1364 | "dev": true
1365 | },
1366 | "expect-type": {
1367 | "version": "0.15.0",
1368 | "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-0.15.0.tgz",
1369 | "integrity": "sha512-yWnriYB4e8G54M5/fAFj7rCIBiKs1HAACaY13kCz6Ku0dezjS9aMcfcdVK2X8Tv2tEV1BPz/wKfQ7WA4S/d8aA==",
1370 | "dev": true
1371 | },
1372 | "find-up": {
1373 | "version": "5.0.0",
1374 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
1375 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
1376 | "dev": true,
1377 | "requires": {
1378 | "locate-path": "^6.0.0",
1379 | "path-exists": "^4.0.0"
1380 | }
1381 | },
1382 | "foreground-child": {
1383 | "version": "2.0.0",
1384 | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
1385 | "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
1386 | "dev": true,
1387 | "requires": {
1388 | "cross-spawn": "^7.0.0",
1389 | "signal-exit": "^3.0.2"
1390 | }
1391 | },
1392 | "fs.realpath": {
1393 | "version": "1.0.0",
1394 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
1395 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
1396 | "dev": true
1397 | },
1398 | "fsevents": {
1399 | "version": "2.3.2",
1400 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
1401 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
1402 | "dev": true,
1403 | "optional": true
1404 | },
1405 | "function-bind": {
1406 | "version": "1.1.1",
1407 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
1408 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
1409 | "dev": true
1410 | },
1411 | "get-caller-file": {
1412 | "version": "2.0.5",
1413 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
1414 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
1415 | "dev": true
1416 | },
1417 | "glob": {
1418 | "version": "7.2.3",
1419 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
1420 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
1421 | "dev": true,
1422 | "requires": {
1423 | "fs.realpath": "^1.0.0",
1424 | "inflight": "^1.0.4",
1425 | "inherits": "2",
1426 | "minimatch": "^3.1.1",
1427 | "once": "^1.3.0",
1428 | "path-is-absolute": "^1.0.0"
1429 | }
1430 | },
1431 | "has": {
1432 | "version": "1.0.3",
1433 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
1434 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
1435 | "dev": true,
1436 | "requires": {
1437 | "function-bind": "^1.1.1"
1438 | }
1439 | },
1440 | "has-flag": {
1441 | "version": "4.0.0",
1442 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
1443 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
1444 | "dev": true
1445 | },
1446 | "html-escaper": {
1447 | "version": "2.0.2",
1448 | "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
1449 | "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
1450 | "dev": true
1451 | },
1452 | "inflight": {
1453 | "version": "1.0.6",
1454 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
1455 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
1456 | "dev": true,
1457 | "requires": {
1458 | "once": "^1.3.0",
1459 | "wrappy": "1"
1460 | }
1461 | },
1462 | "inherits": {
1463 | "version": "2.0.4",
1464 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
1465 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
1466 | "dev": true
1467 | },
1468 | "is-builtin-module": {
1469 | "version": "3.2.0",
1470 | "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz",
1471 | "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==",
1472 | "dev": true,
1473 | "requires": {
1474 | "builtin-modules": "^3.3.0"
1475 | }
1476 | },
1477 | "is-core-module": {
1478 | "version": "2.11.0",
1479 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
1480 | "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
1481 | "dev": true,
1482 | "requires": {
1483 | "has": "^1.0.3"
1484 | }
1485 | },
1486 | "is-fullwidth-code-point": {
1487 | "version": "3.0.0",
1488 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
1489 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
1490 | "dev": true
1491 | },
1492 | "is-module": {
1493 | "version": "1.0.0",
1494 | "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
1495 | "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
1496 | "dev": true
1497 | },
1498 | "isexe": {
1499 | "version": "2.0.0",
1500 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
1501 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
1502 | "dev": true
1503 | },
1504 | "istanbul-lib-coverage": {
1505 | "version": "3.2.0",
1506 | "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
1507 | "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
1508 | "dev": true
1509 | },
1510 | "istanbul-lib-report": {
1511 | "version": "3.0.0",
1512 | "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
1513 | "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
1514 | "dev": true,
1515 | "requires": {
1516 | "istanbul-lib-coverage": "^3.0.0",
1517 | "make-dir": "^3.0.0",
1518 | "supports-color": "^7.1.0"
1519 | }
1520 | },
1521 | "istanbul-reports": {
1522 | "version": "3.1.5",
1523 | "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
1524 | "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
1525 | "dev": true,
1526 | "requires": {
1527 | "html-escaper": "^2.0.0",
1528 | "istanbul-lib-report": "^3.0.0"
1529 | }
1530 | },
1531 | "locate-path": {
1532 | "version": "6.0.0",
1533 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
1534 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
1535 | "dev": true,
1536 | "requires": {
1537 | "p-locate": "^5.0.0"
1538 | }
1539 | },
1540 | "make-dir": {
1541 | "version": "3.1.0",
1542 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
1543 | "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
1544 | "dev": true,
1545 | "requires": {
1546 | "semver": "^6.0.0"
1547 | }
1548 | },
1549 | "minimatch": {
1550 | "version": "3.1.2",
1551 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
1552 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
1553 | "dev": true,
1554 | "requires": {
1555 | "brace-expansion": "^1.1.7"
1556 | }
1557 | },
1558 | "once": {
1559 | "version": "1.4.0",
1560 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1561 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
1562 | "dev": true,
1563 | "requires": {
1564 | "wrappy": "1"
1565 | }
1566 | },
1567 | "p-limit": {
1568 | "version": "3.1.0",
1569 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
1570 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
1571 | "dev": true,
1572 | "requires": {
1573 | "yocto-queue": "^0.1.0"
1574 | }
1575 | },
1576 | "p-locate": {
1577 | "version": "5.0.0",
1578 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
1579 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
1580 | "dev": true,
1581 | "requires": {
1582 | "p-limit": "^3.0.2"
1583 | }
1584 | },
1585 | "path-exists": {
1586 | "version": "4.0.0",
1587 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
1588 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
1589 | "dev": true
1590 | },
1591 | "path-is-absolute": {
1592 | "version": "1.0.1",
1593 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
1594 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
1595 | "dev": true
1596 | },
1597 | "path-key": {
1598 | "version": "3.1.1",
1599 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
1600 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
1601 | "dev": true
1602 | },
1603 | "path-parse": {
1604 | "version": "1.0.7",
1605 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
1606 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
1607 | "dev": true
1608 | },
1609 | "picomatch": {
1610 | "version": "2.3.1",
1611 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
1612 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
1613 | "dev": true
1614 | },
1615 | "randombytes": {
1616 | "version": "2.1.0",
1617 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
1618 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
1619 | "dev": true,
1620 | "requires": {
1621 | "safe-buffer": "^5.1.0"
1622 | }
1623 | },
1624 | "require-directory": {
1625 | "version": "2.1.1",
1626 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
1627 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
1628 | "dev": true
1629 | },
1630 | "resolve": {
1631 | "version": "1.22.1",
1632 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
1633 | "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
1634 | "dev": true,
1635 | "requires": {
1636 | "is-core-module": "^2.9.0",
1637 | "path-parse": "^1.0.7",
1638 | "supports-preserve-symlinks-flag": "^1.0.0"
1639 | }
1640 | },
1641 | "rimraf": {
1642 | "version": "3.0.2",
1643 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
1644 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
1645 | "dev": true,
1646 | "requires": {
1647 | "glob": "^7.1.3"
1648 | }
1649 | },
1650 | "rollup": {
1651 | "version": "3.10.1",
1652 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.10.1.tgz",
1653 | "integrity": "sha512-3Er+yel3bZbZX1g2kjVM+FW+RUWDxbG87fcqFM5/9HbPCTpbVp6JOLn7jlxnNlbu7s/N/uDA4EV/91E2gWnxzw==",
1654 | "dev": true,
1655 | "requires": {
1656 | "fsevents": "~2.3.2"
1657 | }
1658 | },
1659 | "safe-buffer": {
1660 | "version": "5.2.1",
1661 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1662 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1663 | "dev": true
1664 | },
1665 | "semver": {
1666 | "version": "6.3.0",
1667 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
1668 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
1669 | "dev": true
1670 | },
1671 | "serialize-javascript": {
1672 | "version": "6.0.1",
1673 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
1674 | "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
1675 | "dev": true,
1676 | "requires": {
1677 | "randombytes": "^2.1.0"
1678 | }
1679 | },
1680 | "shebang-command": {
1681 | "version": "2.0.0",
1682 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
1683 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
1684 | "dev": true,
1685 | "requires": {
1686 | "shebang-regex": "^3.0.0"
1687 | }
1688 | },
1689 | "shebang-regex": {
1690 | "version": "3.0.0",
1691 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
1692 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
1693 | "dev": true
1694 | },
1695 | "signal-exit": {
1696 | "version": "3.0.7",
1697 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
1698 | "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
1699 | "dev": true
1700 | },
1701 | "smob": {
1702 | "version": "0.0.6",
1703 | "resolved": "https://registry.npmjs.org/smob/-/smob-0.0.6.tgz",
1704 | "integrity": "sha512-V21+XeNni+tTyiST1MHsa84AQhT1aFZipzPpOFAVB8DkHzwJyjjAmt9bgwnuZiZWnIbMo2duE29wybxv/7HWUw==",
1705 | "dev": true
1706 | },
1707 | "source-map": {
1708 | "version": "0.6.1",
1709 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
1710 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
1711 | "dev": true
1712 | },
1713 | "source-map-support": {
1714 | "version": "0.5.21",
1715 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
1716 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
1717 | "dev": true,
1718 | "requires": {
1719 | "buffer-from": "^1.0.0",
1720 | "source-map": "^0.6.0"
1721 | }
1722 | },
1723 | "string-width": {
1724 | "version": "4.2.3",
1725 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
1726 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
1727 | "dev": true,
1728 | "requires": {
1729 | "emoji-regex": "^8.0.0",
1730 | "is-fullwidth-code-point": "^3.0.0",
1731 | "strip-ansi": "^6.0.1"
1732 | }
1733 | },
1734 | "strip-ansi": {
1735 | "version": "6.0.1",
1736 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
1737 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
1738 | "dev": true,
1739 | "requires": {
1740 | "ansi-regex": "^5.0.1"
1741 | }
1742 | },
1743 | "supports-color": {
1744 | "version": "7.2.0",
1745 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
1746 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
1747 | "dev": true,
1748 | "requires": {
1749 | "has-flag": "^4.0.0"
1750 | }
1751 | },
1752 | "supports-preserve-symlinks-flag": {
1753 | "version": "1.0.0",
1754 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
1755 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
1756 | "dev": true
1757 | },
1758 | "terser": {
1759 | "version": "5.16.1",
1760 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz",
1761 | "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==",
1762 | "dev": true,
1763 | "requires": {
1764 | "@jridgewell/source-map": "^0.3.2",
1765 | "acorn": "^8.5.0",
1766 | "commander": "^2.20.0",
1767 | "source-map-support": "~0.5.20"
1768 | }
1769 | },
1770 | "test-exclude": {
1771 | "version": "6.0.0",
1772 | "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
1773 | "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
1774 | "dev": true,
1775 | "requires": {
1776 | "@istanbuljs/schema": "^0.1.2",
1777 | "glob": "^7.1.4",
1778 | "minimatch": "^3.0.4"
1779 | }
1780 | },
1781 | "typescript": {
1782 | "version": "4.9.4",
1783 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
1784 | "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
1785 | "dev": true
1786 | },
1787 | "v8-to-istanbul": {
1788 | "version": "9.0.1",
1789 | "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz",
1790 | "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==",
1791 | "dev": true,
1792 | "requires": {
1793 | "@jridgewell/trace-mapping": "^0.3.12",
1794 | "@types/istanbul-lib-coverage": "^2.0.1",
1795 | "convert-source-map": "^1.6.0"
1796 | }
1797 | },
1798 | "which": {
1799 | "version": "2.0.2",
1800 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
1801 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
1802 | "dev": true,
1803 | "requires": {
1804 | "isexe": "^2.0.0"
1805 | }
1806 | },
1807 | "wrap-ansi": {
1808 | "version": "7.0.0",
1809 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
1810 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
1811 | "dev": true,
1812 | "requires": {
1813 | "ansi-styles": "^4.0.0",
1814 | "string-width": "^4.1.0",
1815 | "strip-ansi": "^6.0.0"
1816 | }
1817 | },
1818 | "wrappy": {
1819 | "version": "1.0.2",
1820 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1821 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
1822 | "dev": true
1823 | },
1824 | "y18n": {
1825 | "version": "5.0.8",
1826 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
1827 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
1828 | "dev": true
1829 | },
1830 | "yargs": {
1831 | "version": "16.2.0",
1832 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
1833 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
1834 | "dev": true,
1835 | "requires": {
1836 | "cliui": "^7.0.2",
1837 | "escalade": "^3.1.1",
1838 | "get-caller-file": "^2.0.5",
1839 | "require-directory": "^2.1.1",
1840 | "string-width": "^4.2.0",
1841 | "y18n": "^5.0.5",
1842 | "yargs-parser": "^20.2.2"
1843 | }
1844 | },
1845 | "yargs-parser": {
1846 | "version": "20.2.9",
1847 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
1848 | "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
1849 | "dev": true
1850 | },
1851 | "yocto-queue": {
1852 | "version": "0.1.0",
1853 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
1854 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
1855 | "dev": true
1856 | }
1857 | }
1858 | }
1859 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "usignal",
3 | "version": "0.10.0",
4 | "main": "./cjs/index.js",
5 | "types": "./types/index.d.ts",
6 | "typesVersions": {
7 | ">=4.9": {
8 | "*": [
9 | "types/*",
10 | "types/index.d.ts"
11 | ]
12 | }
13 | },
14 | "scripts": {
15 | "benchmark": "node test/benchmark.js",
16 | "build": "npm run cjs && npm run rollup:es && npm run types && npm run readme-size && npm run test && npm run size",
17 | "cjs": "ascjs esm cjs",
18 | "rollup:es": "rollup --config rollup/es.config.js",
19 | "test": "tsc -p test && c8 node --expose-gc test/index.js $@",
20 | "size": "cat es.js | brotli | wc -c",
21 | "leak": "node --expose-gc ./test/leak.js $@",
22 | "types": "tsc -p . && npm run fix:types",
23 | "fix:types": "sed -i \"s/_: T;/value: T;/\" types/index.d.ts",
24 | "fix:exports": "sed -i \"s/\\.js/.d.ts/\" types/{async,sync}.d.ts; sed -i \"s/\\.js/.d.ts/\" types/solid/{async,sync}.d.ts; sed -i \"s/\\.js/.d.ts/\" types/fn/{index,async,sync}.d.ts",
25 | "readme-size": "sed -i \"s/, \\([0-9]\\+\\) bytes/, $(cat es.js | brotli | wc -c) bytes/\" README.md",
26 | "coverage": "mkdir -p ./coverage; c8 report --reporter=text-lcov > ./coverage/lcov.info"
27 | },
28 | "keywords": [
29 | "signal",
30 | "signals",
31 | "alternative"
32 | ],
33 | "author": "Andrea Gimmarchi",
34 | "license": "ISC",
35 | "devDependencies": {
36 | "@rollup/plugin-node-resolve": "^15.0.1",
37 | "@rollup/plugin-terser": "^0.4.0",
38 | "ascjs": "^5.0.1",
39 | "c8": "^7.12.0",
40 | "expect-type": "^0.15.0",
41 | "rollup": "^3.10.1",
42 | "typescript": "^4.9.4"
43 | },
44 | "module": "./esm/index.js",
45 | "type": "module",
46 | "exports": {
47 | ".": {
48 | "browser": {
49 | "types": "./types/async.d.ts",
50 | "import": "./esm/async.js",
51 | "default": "./cjs/async.js"
52 | },
53 | "default": {
54 | "types": "./types/sync.d.ts",
55 | "import": "./esm/sync.js",
56 | "default": "./cjs/sync.js"
57 | }
58 | },
59 | "./core": {
60 | "types": "./types/index.d.ts",
61 | "import": "./esm/index.js",
62 | "default": "./cjs/index.js"
63 | },
64 | "./sync": {
65 | "types": "./types/sync.d.ts",
66 | "import": "./esm/sync.js",
67 | "default": "./cjs/sync.js"
68 | },
69 | "./async": {
70 | "types": "./types/async.d.ts",
71 | "import": "./esm/async.js",
72 | "default": "./cjs/async.js"
73 | },
74 | "./fn": {
75 | "browser": {
76 | "types": "./types/fn/async.d.ts",
77 | "import": "./esm/fn/async.js",
78 | "default": "./cjs/fn/async.js"
79 | },
80 | "default": {
81 | "types": "./types/fn/sync.d.ts",
82 | "import": "./esm/fn/sync.js",
83 | "default": "./cjs/fn/sync.js"
84 | }
85 | },
86 | "./fn/core": {
87 | "types": "./types/fn/index.d.ts",
88 | "import": "./esm/fn/index.js",
89 | "default": "./cjs/fn/index.js"
90 | },
91 | "./fn/async": {
92 | "types": "./types/fn/async.d.ts",
93 | "import": "./esm/fn/async.js",
94 | "default": "./cjs/fn/async.js"
95 | },
96 | "./fn/sync": {
97 | "types": "./types/fn/sync.d.ts",
98 | "import": "./esm/fn/sync.js",
99 | "default": "./cjs/fn/sync.js"
100 | },
101 | "./solid": {
102 | "browser": {
103 | "types": "./types/solid/async.d.ts",
104 | "import": "./esm/solid/async.js",
105 | "default": "./cjs/solid/async.js"
106 | },
107 | "default": {
108 | "types": "./types/solid/sync.d.ts",
109 | "import": "./esm/solid/sync.js",
110 | "default": "./cjs/solid/sync.js"
111 | }
112 | },
113 | "./solid/core": {
114 | "types": "./types/solid/index.d.ts",
115 | "import": "./esm/solid/index.js",
116 | "default": "./cjs/solid/index.js"
117 | },
118 | "./solid/async": {
119 | "types": "./types/solid/async.d.ts",
120 | "import": "./esm/solid/async.js",
121 | "default": "./cjs/solid/async.js"
122 | },
123 | "./solid/sync": {
124 | "types": "./types/solid/sync.d.ts",
125 | "import": "./esm/solid/sync.js",
126 | "default": "./cjs/solid/sync.js"
127 | },
128 | "./package.json": "./package.json"
129 | },
130 | "unpkg": "es.js",
131 | "repository": {
132 | "type": "git",
133 | "url": "git+https://github.com/WebReflection/usignal.git"
134 | },
135 | "bugs": {
136 | "url": "https://github.com/WebReflection/usignal/issues"
137 | },
138 | "homepage": "https://github.com/WebReflection/usignal#readme",
139 | "description": "A blend of @preact/signals-core and solid-js basic reactivity API"
140 | }
141 |
--------------------------------------------------------------------------------
/rollup/es.config.js:
--------------------------------------------------------------------------------
1 | import {nodeResolve} from '@rollup/plugin-node-resolve';
2 | import terser from '@rollup/plugin-terser';
3 |
4 | export default {
5 | input: './esm/index.js',
6 | plugins: [
7 | nodeResolve(),
8 | terser()
9 | ],
10 | output: {
11 | file: './es.js',
12 | format: 'module'
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/test/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/test/async.js:
--------------------------------------------------------------------------------
1 | export default (library, {signal, computed, effect}) => {
2 |
3 | console.log('');
4 | console.log(`\x1b[1m${library} async\x1b[0m`);
5 |
6 | const assert = (what, why) => {
7 | console.assert(what);
8 | if (!what)
9 | throw new Error(`\x1b[1m${library}\x1b[0m: ${why}`);
10 | };
11 |
12 | testEffect();
13 |
14 | function testEffect() {
15 | const invokes = [];
16 | const name = signal('Jane');
17 | const surname = signal('Doe');
18 | const fullName = computed(() => name.value + ' ' + surname.value);
19 |
20 | effect(
21 | prev => {
22 | invokes.push(fullName.value + prev);
23 | },
24 | 1,
25 | {async: true}
26 | );
27 |
28 | assert(invokes.length === 0, 'effect should not be invoked');
29 |
30 | name.value = 'John';
31 | assert(invokes.length === 0, 'effect still not re-invoked');
32 |
33 | queueMicrotask(() => {
34 | assert(invokes.length === 1, 'effect should have been invoked once');
35 | assert(invokes.join('\n') === 'John Doe1', 'unexpected effect');
36 | });
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/test/benchmark.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Extracted from: https://github.com/Riim/cellx#benchmark
3 | * Readapted from: https://github.com/maverick-js/observables#layers
4 | */
5 |
6 | import kleur from 'kleur';
7 |
8 | import * as cellx from 'cellx';
9 | import * as Sjs from 's-js';
10 | // @ts-expect-error
11 | import * as solid from './solid-js-baseline.js';
12 | import * as preact from '@preact/signals-core';
13 | import * as usignal from '../esm/index.js';
14 | import * as signal from '@webreflection/signal';
15 | import * as alien from 'alien-signals';
16 | import Table from 'cli-table';
17 |
18 | const RUNS_PER_TIER = 150;
19 | const LAYER_TIERS = [10, 100, 500, 1000, 2000, 2500];
20 | const BATCHED = process.argv.includes('--batched');
21 |
22 | const sum = (array) => array.reduce((a, b) => a + b, 0);
23 | const avg = (array) => sum(array) / array.length || 0;
24 |
25 | const SOLUTIONS = {
26 | 10: [2, 4, -2, -3],
27 | 100: [2, 2, 4, 2],
28 | 500: [-2, 1, -4, -4],
29 | 1000: [2, 2, 4, 2],
30 | 2000: [-2, 1, -4, -4],
31 | 2500: [2, 2, 4, 2],
32 | };
33 |
34 | let rand = 0;
35 |
36 | /**
37 | * @param {number} layers
38 | * @param {number[]} answer
39 | */
40 | const isSolution = (layers, answer) => answer.every((_, i) => {
41 | // if (SOLUTIONS[layers][i] !== _) console.log(layers, i, SOLUTIONS[layers][i], _);
42 | return SOLUTIONS[layers][i] === _;
43 | });
44 |
45 | async function main() {
46 | const report = {
47 | S: { fn: runS, runs: [] },
48 | solid: { fn: runSolid, runs: [] },
49 | 'preact/signals': { fn: runPreact, runs: [] },
50 | // TODO: running too slow so I need to leave it out for now - maybe something is wrong.
51 | // sinuous: { fn: runSinuous, runs: [] },
52 | cellx: { fn: runCellx, runs: [] },
53 | usignal: { fn: runUsignal, runs: [] },
54 | signal: { fn: runSignal, runs: [] },
55 | alien: { fn: runAlien, runs: [] },
56 | };
57 |
58 | for (const lib of Object.keys(report)) {
59 | const current = report[lib];
60 |
61 | for (let i = 0; i < LAYER_TIERS.length; i += 1) {
62 | let layers = LAYER_TIERS[i];
63 | const runs = [];
64 | rand++;
65 | for (let j = 0; j < RUNS_PER_TIER; j += 1) {
66 | runs.push(await start(current.fn, layers));
67 | }
68 | // Give cellx time to release its global pendingCells array
69 | await new Promise((resolve) => setTimeout(resolve, 0));
70 |
71 | current.runs[i] = avg(runs) * 1000;
72 | }
73 | }
74 |
75 | const table = new Table({
76 | head: ['', ...LAYER_TIERS.map((n) => kleur.bold(kleur.cyan(n)))],
77 | });
78 |
79 | for (let i = 0; i < LAYER_TIERS.length; i += 1) {
80 | let min = Infinity,
81 | max = -1,
82 | fastestLib,
83 | slowestLib;
84 |
85 | for (const lib of Object.keys(report)) {
86 | const time = report[lib].runs[i];
87 |
88 | if (time < min) {
89 | min = time;
90 | fastestLib = lib;
91 | }
92 |
93 | if (time > max) {
94 | max = time;
95 | slowestLib = lib;
96 | }
97 | }
98 |
99 | report[fastestLib].runs[i] = kleur.green(report[fastestLib].runs[i].toFixed(2));
100 | report[slowestLib].runs[i] = kleur.red(report[slowestLib].runs[i].toFixed(2));
101 | }
102 |
103 | for (const lib of Object.keys(report)) {
104 | table.push([
105 | kleur.magenta(lib),
106 | ...report[lib].runs.map((n) => (typeof n === 'number' ? n.toFixed(2) : n)),
107 | ]);
108 | }
109 |
110 | console.log(table.toString());
111 | }
112 |
113 | async function start(runner, layers) {
114 | return new Promise((done) => {
115 | runner(layers, done);
116 | }).catch(() => -1);
117 | }
118 |
119 | /**
120 | * @see {@link https://github.com/adamhaile/S}
121 | */
122 | function runS(layers, done) {
123 | const S = Sjs.default;
124 |
125 | S.root(() => {
126 | const start = {
127 | a: S.data(1),
128 | b: S.data(2),
129 | c: S.data(3),
130 | d: S.data(4),
131 | };
132 |
133 | let layer = start;
134 |
135 | for (let i = layers; i--; ) {
136 | layer = ((m) => {
137 | const props = {
138 | a: S(() => rand % 2 ? m.b() : m.c()),
139 | b: S(() => m.a() - m.c()),
140 | c: S(() => m.b() + m.d()),
141 | d: S(() => m.c()),
142 | };
143 |
144 | S(props.a), S(props.b), S(props.c), S(props.d);
145 | return props;
146 | })(layer);
147 | }
148 |
149 | const startTime = performance.now();
150 |
151 | const run = BATCHED ? (fn) => fn() : (fn) => fn();
152 | run(() => {
153 | start.a(4), start.b(3), start.c(2), start.d(1);
154 | });
155 |
156 | const end = layer;
157 | const solution = [end.a(), end.b(), end.c(), end.d()];
158 | const endTime = performance.now() - startTime;
159 |
160 | done(isSolution(layers, solution) ? endTime : -1);
161 | });
162 | }
163 |
164 | /**
165 | * @see {@link https://github.com/solidjs/solid}
166 | */
167 | function runSolid(layers, done) {
168 | solid.createRoot(async (dispose) => {
169 | const [a, setA] = solid.createSignal(1),
170 | [b, setB] = solid.createSignal(2),
171 | [c, setC] = solid.createSignal(3),
172 | [d, setD] = solid.createSignal(4);
173 |
174 | const start = { a, b, c, d };
175 |
176 | let layer = start;
177 |
178 | for (let i = layers; i--; ) {
179 | layer = ((m) => {
180 | const props = {
181 | a: solid.createMemo(() => rand % 2 ? m.b() : m.c()),
182 | b: solid.createMemo(() => m.a() - m.c()),
183 | c: solid.createMemo(() => m.b() + m.d()),
184 | d: solid.createMemo(() => m.c()),
185 | };
186 |
187 | return props;
188 | })(layer);
189 | }
190 |
191 | const startTime = performance.now();
192 |
193 | const run = BATCHED ? solid.batch : (fn) => fn();
194 | run(() => {
195 | setA(4), setB(3), setC(2), setD(1);
196 | });
197 |
198 | const end = layer;
199 | const solution = [end.a(), end.b(), end.c(), end.d()];
200 | const endTime = performance.now() - startTime;
201 |
202 | dispose();
203 | done(isSolution(layers, solution) ? endTime : -1);
204 | });
205 | }
206 |
207 | /**
208 | * @see {@link https://github.com/preactjs/signals}
209 | */
210 | function runPreact(layers, done) {
211 | const a = preact.signal(1),
212 | b = preact.signal(2),
213 | c = preact.signal(3),
214 | d = preact.signal(4);
215 |
216 | const start = { a, b, c, d };
217 |
218 | let layer = start;
219 |
220 | for (let i = layers; i--; ) {
221 | layer = ((m) => {
222 | const props = {
223 | a: preact.computed(() => rand % 2 ? m.b.value : m.c.value),
224 | b: preact.computed(() => m.a.value - m.c.value),
225 | c: preact.computed(() => m.b.value + m.d.value),
226 | d: preact.computed(() => m.c.value),
227 | };
228 |
229 | return props;
230 | })(layer);
231 | }
232 |
233 | const startTime = performance.now();
234 |
235 | const run = BATCHED ? preact.batch : (fn) => fn();
236 | run(() => {
237 | (a.value = 4), (b.value = 3), (c.value = 2), (d.value = 1);
238 |
239 | const end = layer;
240 | const solution = [end.a.value, end.b.value, end.c.value, end.d.value];
241 | const endTime = performance.now() - startTime;
242 |
243 | done(isSolution(layers, solution) ? endTime : -1);
244 | });
245 | }
246 |
247 | /**
248 | * @see {@link https://github.com/Riim/cellx}
249 | */
250 | function runCellx(layers, done) {
251 | const start = {
252 | a: new cellx.Cell(1),
253 | b: new cellx.Cell(2),
254 | c: new cellx.Cell(3),
255 | d: new cellx.Cell(4),
256 | };
257 |
258 | let layer = start;
259 |
260 | for (let i = layers; i--; ) {
261 | layer = ((m) => {
262 | const props = {
263 | a: new cellx.Cell(() => rand % 2 ? m.b.get() : m.c.get()),
264 | b: new cellx.Cell(() => m.a.get() - m.c.get()),
265 | c: new cellx.Cell(() => m.b.get() + m.d.get()),
266 | d: new cellx.Cell(() => m.c.get()),
267 | };
268 |
269 | props.a.on('change', function () {});
270 | props.b.on('change', function () {});
271 | props.c.on('change', function () {});
272 | props.d.on('change', function () {});
273 |
274 | return props;
275 | })(layer);
276 | }
277 |
278 | const startTime = performance.now();
279 |
280 | start.a.set(4);
281 | start.b.set(3);
282 | start.c.set(2);
283 | start.d.set(1);
284 |
285 | const end = layer;
286 | const solution = [end.a.get(), end.b.get(), end.c.get(), end.d.get()];
287 | const endTime = performance.now() - startTime;
288 |
289 | start.a.dispose();
290 | start.b.dispose();
291 | start.c.dispose();
292 | start.d.dispose();
293 |
294 | done(isSolution(layers, solution) ? endTime : -1);
295 | }
296 |
297 | /**
298 | * @see {@link https://github.com/WebReflection/usignal}
299 | */
300 | function runUsignal(layers, done) {
301 | const a = usignal.signal(1),
302 | b = usignal.signal(2),
303 | c = usignal.signal(3),
304 | d = usignal.signal(4);
305 |
306 | const start = { a, b, c, d };
307 |
308 | let layer = start;
309 |
310 | for (let i = layers; i--; ) {
311 | layer = ((m) => {
312 | const props = {
313 | a: usignal.computed(() => rand % 2 ? m.b.value : m.c.value),
314 | b: usignal.computed(() => m.a.value - m.c.value),
315 | c: usignal.computed(() => m.b.value + m.d.value),
316 | d: usignal.computed(() => m.c.value),
317 | };
318 |
319 | return props;
320 | })(layer);
321 | }
322 |
323 | const startTime = performance.now();
324 |
325 | const run = BATCHED ? usignal.batch : (fn) => fn();
326 | run(() => {
327 | (a.value = 4), (b.value = 3), (c.value = 2), (d.value = 1);
328 |
329 | const end = layer;
330 | const solution = [end.a.value, end.b.value, end.c.value, end.d.value];
331 | const endTime = performance.now() - startTime;
332 |
333 | done(isSolution(layers, solution) ? endTime : -1);
334 | });
335 | }
336 |
337 | /**
338 | * @see {@link https://github.com/WebReflection/signal}
339 | */
340 | function runSignal(layers, done) {
341 | const a = signal.signal(1),
342 | b = signal.signal(2),
343 | c = signal.signal(3),
344 | d = signal.signal(4);
345 |
346 | const start = { a, b, c, d };
347 |
348 | let layer = start;
349 |
350 | for (let i = layers; i--; ) {
351 | layer = ((m) => {
352 | const props = {
353 | a: signal.computed(() => rand % 2 ? m.b.value : m.c.value),
354 | b: signal.computed(() => m.a.value - m.c.value),
355 | c: signal.computed(() => m.b.value + m.d.value),
356 | d: signal.computed(() => m.c.value),
357 | };
358 |
359 | return props;
360 | })(layer);
361 | }
362 |
363 | const startTime = performance.now();
364 |
365 | const run = BATCHED ? signal.batch : (fn) => fn();
366 | run(() => {
367 | (a.value = 4), (b.value = 3), (c.value = 2), (d.value = 1);
368 |
369 | const end = layer;
370 | const solution = [end.a.value, end.b.value, end.c.value, end.d.value];
371 | const endTime = performance.now() - startTime;
372 |
373 | done(isSolution(layers, solution) ? endTime : -1);
374 | });
375 | }
376 |
377 | /**
378 | * @see {@link https://github.com/stackblitz/native-signals}
379 | */
380 | function runAlien(layers, done) {
381 | const a = alien.signal(1),
382 | b = alien.signal(2),
383 | c = alien.signal(3),
384 | d = alien.signal(4);
385 |
386 | const start = { a, b, c, d };
387 |
388 | let layer = start;
389 |
390 | for (let i = layers; i--; ) {
391 | layer = ((m) => {
392 | const props = {
393 | a: alien.computed(() => rand % 2 ? m.b.get() : m.c.get()),
394 | b: alien.computed(() => m.a.get() - m.c.get()),
395 | c: alien.computed(() => m.b.get() + m.d.get()),
396 | d: alien.computed(() => m.c.get()),
397 | };
398 |
399 | return props;
400 | })(layer);
401 | }
402 |
403 | const startTime = performance.now();
404 |
405 | const run = BATCHED ? (fn) => {
406 | alien.startBatch();
407 | fn();
408 | alien.endBatch();
409 | } : (fn) => fn();
410 | run(() => {
411 | (a.set(4)), (b.set(3)), (c.set(2)), (d.set(1));
412 |
413 | const end = layer;
414 | const solution = [end.a.get(), end.b.get(), end.c.get(), end.d.get()];
415 | const endTime = performance.now() - startTime;
416 |
417 | done(isSolution(layers, solution) ? endTime : -1);
418 | });
419 | }
420 |
421 | main();
422 |
--------------------------------------------------------------------------------
/test/benchmark.old.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WebReflection/usignal/babeca11279d1da72e10f2e400f9cef8cd1b7c3a/test/benchmark.old.png
--------------------------------------------------------------------------------
/test/benchmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WebReflection/usignal/babeca11279d1da72e10f2e400f9cef8cd1b7c3a/test/benchmark.png
--------------------------------------------------------------------------------
/test/callstack.js:
--------------------------------------------------------------------------------
1 | import * as usignal from '../esm/index.js';
2 |
3 | const report = {};
4 |
5 | testUsignal(report, 4829);
6 |
7 | console.table(report);
8 |
9 | function testUsignal(report, layerCount) {
10 | var start = {
11 | prop1: usignal.signal(1),
12 | prop2: usignal.signal(2),
13 | prop3: usignal.signal(3),
14 | prop4: usignal.signal(4)
15 | };
16 |
17 | var layer = start;
18 |
19 | for (var i = layerCount; i--; ) {
20 | layer = (function (m) {
21 | var s = {
22 | prop1: usignal.computed(function () {
23 | return m.prop2.value;
24 | }),
25 | prop2: usignal.computed(function () {
26 | return m.prop1.value - m.prop3.value;
27 | }),
28 | prop3: usignal.computed(function () {
29 | return m.prop2.value + m.prop4.value;
30 | }),
31 | prop4: usignal.computed(function () {
32 | return m.prop3.value;
33 | })
34 | };
35 |
36 | usignal.computed(() => s.prop1.value);
37 | usignal.computed(() => s.prop2.value);
38 | usignal.computed(() => s.prop3.value);
39 | usignal.computed(() => s.prop4.value);
40 |
41 | s.prop1.value;
42 | s.prop2.value;
43 | s.prop3.value;
44 | s.prop4.value;
45 |
46 | return s;
47 | })(layer);
48 | }
49 |
50 | var end = layer;
51 |
52 | report.layers = layerCount;
53 | report.beforeChange = [end.prop1.value, end.prop2.value, end.prop3.value, end.prop4.value];
54 |
55 | var st = performance.now();
56 |
57 | start.prop1.value = 4;
58 | start.prop2.value = 3;
59 | start.prop3.value = 2;
60 | start.prop4.value = 1;
61 |
62 | report.afterChange = [end.prop1.value, end.prop2.value, end.prop3.value, end.prop4.value];
63 |
64 | report.recalculationTime = performance.now() - st;
65 | }
--------------------------------------------------------------------------------
/test/conditional.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | µsignal version
8 |
9 |
10 |
11 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | import {argv} from 'node:process';
2 |
3 | const library = argv.find(arg => /^(?:preact|signal|solid|solid-js)$/.test(arg));
4 |
5 | import(
6 | library ?
7 | (library === 'preact' ?
8 | './preact.js' :
9 | (library === 'signal' ?
10 | './signal.js' :
11 | './solid.js'
12 | )
13 | ) :
14 | './usignal.js'
15 | );
16 |
--------------------------------------------------------------------------------
/test/leak.js:
--------------------------------------------------------------------------------
1 | import {argv, memoryUsage} from 'node:process';
2 |
3 | const BATCHED = argv.includes('batched');
4 | const library = argv.find(arg => /^(?:preact|signal|solid|solid-js)$/.test(arg));
5 |
6 | console.log('');
7 | console.log(`\x1b[1m${library || 'usignal'}\x1b[0m`, BATCHED ? 'batched' : '');
8 |
9 | const {batch, effect, signal, computed} = await import(
10 | library ?
11 | (library === 'preact' ?
12 | '@preact/signals-core' :
13 | (library === 'signal' ?
14 | '@webreflection/signal' :
15 | './solid-to-usignal.js'
16 | )
17 | ) :
18 | '../esm/index.js'
19 | );
20 |
21 | const signals = [];
22 |
23 | for (let i = 65; i <= 90; i++)
24 | signals.push(signal(i));
25 |
26 | let computeds = 0;
27 |
28 | console.time('total time');
29 | console.time('computed value creation');
30 | let comp = computed(() => {
31 | computeds++;
32 | const out = [];
33 | for (const s of signals)
34 | out.push(`${String.fromCharCode(s.value)} => ${s.value}`);
35 | return out.join(', ');
36 | });
37 | console.timeEnd('computed value creation');
38 |
39 | let compute = true;
40 |
41 | console.time('effect creation');
42 | const dispose = effect(() => {
43 | if (compute) {
44 | compute = false;
45 | console.time('computed value retrieval');
46 | console.log('\x1b[2m', comp.value.slice(0, 50) + '...', '\x1b[0m');
47 | console.timeEnd('computed value retrieval');
48 | }
49 | });
50 | console.timeEnd('effect creation');
51 |
52 | console.time('updating 26 signals');
53 |
54 | const updates = () => {
55 | for (const s of signals)
56 | s.value++;
57 | };
58 |
59 | if (BATCHED)
60 | batch(updates);
61 | else
62 | updates();
63 |
64 | console.timeEnd('updating 26 signals');
65 |
66 | console.log('\x1b[1mcomputed\x1b[0m', computeds);
67 |
68 | if (dispose) {
69 | console.time('effect disposal');
70 | dispose();
71 | console.timeEnd('effect disposal');
72 | }
73 |
74 | console.time('computed value retrieval after update');
75 | comp.value;
76 | console.timeEnd('computed value retrieval after update');
77 | console.timeEnd('total time');
78 |
79 | comp = null;
80 | signals.splice(0);
81 |
82 | setTimeout(() => {
83 | gc();
84 | showMem('AFTER');
85 |
86 | if (dispose) {
87 | console.time('effect disposal');
88 | dispose();
89 | console.timeEnd('effect disposal');
90 | }
91 | });
92 |
93 | const showMem = title => {
94 | console.log(`\n\x1b[1m${title}\x1b[0m`);
95 | const prev = memory;
96 | memory = memoryUsage();
97 | if (prev && memory.heapUsed > prev.heapUsed)
98 | throw new Error(`\n\x1b[1m\x1b[7m MEMORY INCREASED \x1b[0m ${memory.heapUsed - prev.heapUsed}\n`);
99 | console.table(memory);
100 | };
101 |
102 | let memory;
103 | showMem('BEFORE');
104 |
--------------------------------------------------------------------------------
/test/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "module",
3 | "devDependencies": {
4 | "@preact/signals-core": "latest",
5 | "@webreflection/signal": "latest",
6 | "cellx": "latest",
7 | "cli-table": "latest",
8 | "kleur": "latest",
9 | "alien-signals": "latest",
10 | "s-js": "latest",
11 | "solid-js": "latest"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/test/preact.js:
--------------------------------------------------------------------------------
1 | import test from './test.js';
2 | import * as preact from '@preact/signals-core';
3 |
4 | test('@preact/signals-core', preact);
5 |
--------------------------------------------------------------------------------
/test/signal.js:
--------------------------------------------------------------------------------
1 | import test from './test.js';
2 | import * as signal from '@webreflection/signal';
3 |
4 | test('@webreflection/signal', signal);
5 |
--------------------------------------------------------------------------------
/test/solid-js-baseline.js:
--------------------------------------------------------------------------------
1 | const equalFn = (a, b) => a === b;
2 | const signalOptions = {
3 | equals: equalFn,
4 | };
5 | let ERROR = null;
6 | let runEffects = runQueue;
7 | const NOTPENDING = {};
8 | const STALE = 1;
9 | const PENDING = 2;
10 | const UNOWNED = {
11 | owned: null,
12 | cleanups: null,
13 | context: null,
14 | owner: null,
15 | };
16 | var Owner = null;
17 | let Listener = null;
18 | let Pending = null;
19 | let Updates = null;
20 | let Effects = null;
21 | let ExecCount = 0;
22 | function createRoot(fn, detachedOwner) {
23 | detachedOwner && (Owner = detachedOwner);
24 | const listener = Listener,
25 | owner = Owner,
26 | root =
27 | fn.length === 0 && !false
28 | ? UNOWNED
29 | : {
30 | owned: null,
31 | cleanups: null,
32 | context: null,
33 | owner,
34 | };
35 | Owner = root;
36 | Listener = null;
37 | let result;
38 | try {
39 | runUpdates(() => (result = fn(() => cleanNode(root))), true);
40 | } finally {
41 | Listener = listener;
42 | Owner = owner;
43 | }
44 | return result;
45 | }
46 | function createSignal(value, options) {
47 | options = options ? Object.assign({}, signalOptions, options) : signalOptions;
48 | const s = {
49 | value,
50 | observers: null,
51 | observerSlots: null,
52 | pending: NOTPENDING,
53 | comparator: options.equals || undefined,
54 | };
55 | return [
56 | readSignal.bind(s),
57 | (value) => {
58 | if (typeof value === 'function') {
59 | value = value(s.pending !== NOTPENDING ? s.pending : s.value);
60 | }
61 | return writeSignal(s, value);
62 | },
63 | ];
64 | }
65 | function createComputed(fn, value) {
66 | updateComputation(createComputation(fn, value, true, STALE));
67 | }
68 | function createMemo(fn, value, options) {
69 | options = options ? Object.assign({}, signalOptions, options) : signalOptions;
70 | const c = createComputation(fn, value, true, 0);
71 | c.pending = NOTPENDING;
72 | c.observers = null;
73 | c.observerSlots = null;
74 | c.comparator = options.equals || undefined;
75 | updateComputation(c);
76 | return readSignal.bind(c);
77 | }
78 |
79 | function batch(fn) {
80 | if (Pending) return fn();
81 | let result;
82 | const q = (Pending = []);
83 | try {
84 | result = fn();
85 | } finally {
86 | Pending = null;
87 | }
88 | runUpdates(() => {
89 | for (let i = 0; i < q.length; i += 1) {
90 | const data = q[i];
91 | if (data.pending !== NOTPENDING) {
92 | const pending = data.pending;
93 | data.pending = NOTPENDING;
94 | writeSignal(data, pending);
95 | }
96 | }
97 | }, false);
98 | return result;
99 | }
100 | function untrack(fn) {
101 | let result,
102 | listener = Listener;
103 | Listener = null;
104 | result = fn();
105 | Listener = listener;
106 | return result;
107 | }
108 |
109 | function readSignal() {
110 | if (this.state && this.sources) {
111 | const updates = Updates;
112 | Updates = null;
113 | this.state === STALE ? updateComputation(this) : lookDownstream(this);
114 | Updates = updates;
115 | }
116 | if (Listener) {
117 | const sSlot = this.observers ? this.observers.length : 0;
118 | if (!Listener.sources) {
119 | Listener.sources = [this];
120 | Listener.sourceSlots = [sSlot];
121 | } else {
122 | Listener.sources.push(this);
123 | Listener.sourceSlots.push(sSlot);
124 | }
125 | if (!this.observers) {
126 | this.observers = [Listener];
127 | this.observerSlots = [Listener.sources.length - 1];
128 | } else {
129 | this.observers.push(Listener);
130 | this.observerSlots.push(Listener.sources.length - 1);
131 | }
132 | }
133 | return this.value;
134 | }
135 | function writeSignal(node, value, isComp) {
136 | if (node.comparator) {
137 | if (node.comparator(node.value, value)) return value;
138 | }
139 | if (Pending) {
140 | if (node.pending === NOTPENDING) Pending.push(node);
141 | node.pending = value;
142 | return value;
143 | }
144 | node.value = value;
145 | if (node.observers && node.observers.length) {
146 | runUpdates(() => {
147 | for (let i = 0; i < node.observers.length; i += 1) {
148 | const o = node.observers[i];
149 | if (!o.state) {
150 | if (o.pure) Updates.push(o);
151 | else Effects.push(o);
152 | if (o.observers) markUpstream(o);
153 | }
154 | o.state = STALE;
155 | }
156 | if (Updates.length > 10e5) {
157 | Updates = [];
158 | throw new Error();
159 | }
160 | }, false);
161 | }
162 | return value;
163 | }
164 | function updateComputation(node) {
165 | if (!node.fn) return;
166 | cleanNode(node);
167 | const owner = Owner,
168 | listener = Listener,
169 | time = ExecCount;
170 | Listener = Owner = node;
171 | runComputation(node, node.value, time);
172 | Listener = listener;
173 | Owner = owner;
174 | }
175 | function runComputation(node, value, time) {
176 | let nextValue;
177 | nextValue = node.fn(value);
178 | if (!node.updatedAt || node.updatedAt <= time) {
179 | if (node.observers && node.observers.length) {
180 | writeSignal(node, nextValue, true);
181 | } else node.value = nextValue;
182 | node.updatedAt = time;
183 | }
184 | }
185 | function createComputation(fn, init, pure, state = STALE, options) {
186 | const c = {
187 | fn,
188 | state: state,
189 | updatedAt: null,
190 | owned: null,
191 | sources: null,
192 | sourceSlots: null,
193 | cleanups: null,
194 | value: init,
195 | owner: Owner,
196 | context: null,
197 | pure,
198 | };
199 | if (Owner === null);
200 | else if (Owner !== UNOWNED) {
201 | if (!Owner.owned) Owner.owned = [c];
202 | else Owner.owned.push(c);
203 | }
204 | return c;
205 | }
206 | function runTop(node) {
207 | if (node.state !== STALE) return lookDownstream(node);
208 | const ancestors = [node];
209 | while ((node = node.owner) && (!node.updatedAt || node.updatedAt < ExecCount)) {
210 | if (node.state) ancestors.push(node);
211 | }
212 | for (let i = ancestors.length - 1; i >= 0; i--) {
213 | node = ancestors[i];
214 | if (node.state === STALE) {
215 | updateComputation(node);
216 | } else if (node.state === PENDING) {
217 | const updates = Updates;
218 | Updates = null;
219 | lookDownstream(node);
220 | Updates = updates;
221 | }
222 | }
223 | }
224 | function runUpdates(fn, init) {
225 | if (Updates) return fn();
226 | let wait = false;
227 | if (!init) Updates = [];
228 | if (Effects) wait = true;
229 | else Effects = [];
230 | ExecCount++;
231 | try {
232 | fn();
233 | } finally {
234 | completeUpdates(wait);
235 | }
236 | }
237 | function completeUpdates(wait) {
238 | if (Updates) {
239 | runQueue(Updates);
240 | Updates = null;
241 | }
242 | if (wait) return;
243 | if (Effects.length)
244 | batch(() => {
245 | runEffects(Effects);
246 | Effects = null;
247 | });
248 | else {
249 | Effects = null;
250 | }
251 | }
252 | function runQueue(queue) {
253 | for (let i = 0; i < queue.length; i++) runTop(queue[i]);
254 | }
255 | function lookDownstream(node) {
256 | node.state = 0;
257 | for (let i = 0; i < node.sources.length; i += 1) {
258 | const source = node.sources[i];
259 | if (source.sources) {
260 | if (source.state === STALE) runTop(source);
261 | else if (source.state === PENDING) lookDownstream(source);
262 | }
263 | }
264 | }
265 | function markUpstream(node) {
266 | for (let i = 0; i < node.observers.length; i += 1) {
267 | const o = node.observers[i];
268 | if (!o.state) {
269 | o.state = PENDING;
270 | if (o.pure) Updates.push(o);
271 | else Effects.push(o);
272 | o.observers && markUpstream(o);
273 | }
274 | }
275 | }
276 | function cleanNode(node) {
277 | let i;
278 | if (node.sources) {
279 | while (node.sources.length) {
280 | const source = node.sources.pop(),
281 | index = node.sourceSlots.pop(),
282 | obs = source.observers;
283 | if (obs && obs.length) {
284 | const n = obs.pop(),
285 | s = source.observerSlots.pop();
286 | if (index < obs.length) {
287 | n.sourceSlots[s] = index;
288 | obs[index] = n;
289 | source.observerSlots[index] = s;
290 | }
291 | }
292 | }
293 | }
294 | if (node.owned) {
295 | for (i = 0; i < node.owned.length; i++) cleanNode(node.owned[i]);
296 | node.owned = null;
297 | }
298 | if (node.cleanups) {
299 | for (i = 0; i < node.cleanups.length; i++) node.cleanups[i]();
300 | node.cleanups = null;
301 | }
302 | node.state = 0;
303 | node.context = null;
304 | }
305 | export { createComputed, createMemo, createRoot, createSignal, batch };
306 |
--------------------------------------------------------------------------------
/test/solid-to-usignal.js:
--------------------------------------------------------------------------------
1 | import {batch, createEffect, createMemo, createSignal} from "./node_modules/solid-js/dist/solid.js";
2 |
3 | class Computed {
4 | constructor(_) {
5 | this._ = createMemo(_);
6 | }
7 | get value() {
8 | return this._();
9 | }
10 | toString() {
11 | return this.value;
12 | }
13 | }
14 |
15 | class Signal {
16 | constructor(_) {
17 | const [s, u] = createSignal(_);
18 | this.s = s;
19 | this.u = u;
20 | this._ = _;
21 | }
22 | get value() {
23 | return this.s();
24 | }
25 | set value(_) {
26 | this._ = _;
27 | this.u(_);
28 | }
29 | peek() {
30 | return this._;
31 | }
32 | toString() {
33 | return this.value;
34 | }
35 | }
36 |
37 | const computed = _ => new Computed(_);
38 | const effect = createEffect;
39 | const signal = _ => new Signal(_);
40 |
41 | export {batch, computed, effect, signal, Signal};
42 |
--------------------------------------------------------------------------------
/test/solid.js:
--------------------------------------------------------------------------------
1 | import test from './test.js';
2 | import * as solidJS from './solid-to-usignal.js';
3 |
4 | test('solid-js', solidJS);
5 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | export default (library, {signal, computed, effect, batch, Signal}) => {
2 |
3 | console.log('');
4 | console.log(`\x1b[1m${library}\x1b[0m`);
5 |
6 | const assert = (what, why) => {
7 | console.assert(what);
8 | if (!what)
9 | throw new Error(`\x1b[1m${library}\x1b[0m: ${why}`);
10 | };
11 |
12 | if (library === 'usignal') {
13 | assert(JSON.stringify(signal(1)) === '1', 'JSON not working');
14 | assert((signal(1) + signal(2)) === 3, 'valueOf not working');
15 | testStoppedAsyncEffect();
16 | // (async t => {
17 | // assert(await signal(3) === 3, 'await signal broke');
18 | // assert(await signal(3).then(String) === '3', 'signal.then broke');
19 | // assert(await computed(() => 4) === 4, 'thenable computed');
20 | // clearTimeout(t);
21 | // })(setTimeout(assert, 1000, false, 'promise does not resolve'));
22 |
23 | const one = signal(1, {equals: false});
24 | const invokes = [];
25 | const dispose = effect(() => {
26 | invokes.push(one.value);
27 | });
28 | one.value = 1;
29 | assert(invokes.join(',') === '1,1', 'equals false not working');
30 | }
31 |
32 | assert(signal(0) instanceof Signal, 'signals are not instances of Signal');
33 |
34 | if (/^(?:usignal|@preact\/signals-core)$/.test(library)) {
35 | assert(computed(() => {}) instanceof Signal, 'computeds are not instances of Signal');
36 | let calls = 0;
37 | const $ = signal(0);
38 | const dispose = effect(() => {
39 | calls++;
40 | $.value;
41 | return () => calls++;
42 | });
43 |
44 | $.value = 1;
45 | assert(calls === 3, 'effect did not call again');
46 |
47 | dispose();
48 | assert(calls === 4, 'dispose did not invoke the calllback');
49 | }
50 |
51 | testPrimitive();
52 | testComputed();
53 | testEffect();
54 | testBatch();
55 | if (!/^(?:@webreflection\/signal)$/.test(library))
56 | testBatchMore();
57 | nestedBatch();
58 | readOnly();
59 | testPeek();
60 | testComputedPeek();
61 | testComputedUniqueness();
62 | if (!/^(?:@webreflection\/signal)$/.test(library))
63 | testComputedMoar();
64 |
65 | if (/^(?:usignal|@preact\/signals-core|@webreflection\/signal)$/.test(library))
66 | implicitToString();
67 |
68 | if (!/^(?:@webreflection\/signal)$/.test(library)) {
69 | testDiamond();
70 | loopedEffects();
71 | }
72 |
73 | nestedEffects();
74 | nestedIndependentEffects();
75 | testConditional();
76 |
77 | function testPrimitive() {
78 | const str = signal('string');
79 | assert(`a ${str}` === 'a string', 'toString not working');
80 | }
81 |
82 | function testComputed() {
83 | const name = signal('Jane');
84 | const surname = signal('Doe');
85 |
86 | const fullName = computed(() => name.value + ' ' + surname.value);
87 |
88 | assert(fullName.value === 'Jane Doe', 'computed not working');
89 | assert(`${fullName}` === 'Jane Doe', 'computed toString not working');
90 | assert(`${fullName + ''}` === 'Jane Doe', 'computed valueOf not working');
91 |
92 | name.value = 'John';
93 | assert(fullName.value === 'John Doe', 'computed not updating');
94 | }
95 |
96 | function testEffect() {
97 | const invokes = [];
98 | const name = signal('Jane');
99 | const surname = signal('Doe');
100 | const fullName = computed(() => name.value + ' ' + surname.value);
101 |
102 | const dispose = effect(() => {
103 | invokes.push(fullName.value);
104 | });
105 |
106 | assert(invokes.length === 1, 'effect not invoked');
107 |
108 | name.value = 'John';
109 | assert(invokes.length === 2, 'effect not re-invoked');
110 | assert(invokes.join('\n') === 'Jane Doe\nJohn Doe', 'unexpected effect');
111 |
112 | // testing same value doesn't side-effect
113 | name.value = 'John';
114 | assert(invokes.length === 2, 'effect side-effecting');
115 | assert(invokes.join('\n') === 'Jane Doe\nJohn Doe', 'unexpected side-effect');
116 |
117 | name.value = 'Jane';
118 | surname.value = 'Deo';
119 | assert(invokes.length === 4, 'non batched not working');
120 | assert(invokes.join('\n') === 'Jane Doe\nJohn Doe\nJane Doe\nJane Deo', 'unexpected non batched');
121 |
122 | if (dispose) {
123 | dispose();
124 | name.value = 'What';
125 | surname.value = 'Ever';
126 | assert(invokes.length === 4, 'dispose is not working');
127 | }
128 | }
129 |
130 | function testStoppedAsyncEffect() {
131 | const invokes = [];
132 | const dispose = effect(
133 | () => {
134 | invokes.push('this should not happen');
135 | },
136 | void 0,
137 | {async: true}
138 | );
139 | dispose();
140 | setTimeout(() => {
141 | assert(invokes.length === 0, 'async effect shold not have been triggered');
142 | });
143 | }
144 |
145 | function testBatch() {
146 | const invokes = [];
147 | const name = signal("Jane");
148 | const surname = signal("Doe");
149 | const fullName = computed(() => name.value + " " + surname.value);
150 |
151 | effect(() => {
152 | invokes.push(fullName.value);
153 | });
154 |
155 | assert(invokes.length === 1, 'effect not working in bached');
156 |
157 | batch(() => {
158 | name.value = "Foo";
159 | surname.value = "Bar";
160 | });
161 |
162 | assert(invokes.length === 2, 'batch not working');
163 | assert(invokes.join('\n') === 'Jane Doe\nFoo Bar', 'batch not updating');
164 | }
165 |
166 | function testBatchMore() {
167 | const invokes = [];
168 | const counter = signal(0);
169 | const double = computed(() => counter.value * 2);
170 | const tripple = computed(() => counter.value * 3);
171 |
172 | effect(() => {
173 | invokes.push([double.value, tripple.value]);
174 | });
175 |
176 | assert(invokes.length === 1, 'effect not working in bached more');
177 |
178 | batch(() => {
179 | counter.value = 1;
180 | assert(double.value === 2, 'computed side-effecting within batch');
181 | });
182 |
183 | assert(invokes.length === 2, 'unexpected more batched result');
184 | assert(invokes[0].join(',') === '0,0', 'unexpected batched more values');
185 | assert(invokes[1].join(',') === '2,3');
186 | }
187 |
188 | function nestedBatch() {
189 | const invokes = [];
190 | const counter = signal(0);
191 |
192 | effect(() => {
193 | invokes.push(counter.value);
194 | });
195 |
196 | assert(invokes.length === 1, 'effect not working in nested batches');
197 |
198 | batch(() => {
199 | batch(() => {
200 | counter.value = 1;
201 | });
202 | assert(invokes.length === 1, 'nested batch not working');
203 | assert(invokes[0] === 0, 'unexpected nested batch result');
204 | });
205 |
206 | assert(invokes.length === 2, 'nested batches fully not working');
207 | assert(invokes[1] === 1, 'unexpected nested batched invokes');
208 | }
209 |
210 | function readOnly() {
211 | const name = signal('Jane');
212 | const surname = signal('Doe');
213 | const fullName = computed(() => name.value + ' ' + surname.value);
214 | try {
215 | fullName.value = "";
216 | assert(false, 'read-only not working');
217 | }
218 | catch (expected) {}
219 | }
220 |
221 | function testPeek() {
222 | const invokes = [];
223 | const counter = signal(0);
224 |
225 | effect(() => {
226 | invokes.push(counter.peek());
227 | });
228 |
229 | assert(invokes.length === 1, 'effect not working in peek');
230 | assert(invokes[0] === 0, 'peek not returning right value');
231 |
232 | counter.value = 1;
233 | assert(invokes.length === 1, 'peek not working as expected');
234 | }
235 |
236 | function testComputedPeek() {
237 | const invokes = [];
238 | const counter = signal(0);
239 | const doubleCounter = computed(() => counter.value * 2)
240 | doubleCounter.value
241 |
242 | effect(() => {
243 | invokes.push(doubleCounter.peek());
244 | });
245 |
246 | assert(invokes.length === 1, 'effect not working in computed peek');
247 | assert(invokes[0] === 0, 'computed peek not returning right value');
248 |
249 | counter.value = 1;
250 | assert(invokes.length === 1, 'computed peek not working as expected');
251 | assert(doubleCounter.peek() === 2, 'computed peek not returning right value');
252 | }
253 |
254 | function testComputedUniqueness() {
255 | let invokes = 0;
256 | const name = signal('Jane');
257 | const surname = {
258 | get value() {
259 | invokes++;
260 | return 'Doe';
261 | }
262 | };
263 | const fullName = computed(() => name.value + ' ' + surname.value);
264 | assert(fullName.value === 'Jane Doe', 'computed not working');
265 | assert(invokes === 1, 'computed value should have been invoked once');
266 | name.value = 'John';
267 | if (/^(?:usignal|@preact\/signals-core|@webreflection\/signal)$/.test(library)) fullName.value;
268 | assert(invokes === 2, 'computed value should have been invoked again');
269 | name.value = 'John';
270 | if (/^(?:usignal|@preact\/signals-core|@webreflection\/signal)$/.test(library)) fullName.value;
271 | assert(invokes === 2, 'computed value should NOT have been invoked again');
272 | }
273 |
274 | function testComputedMoar() {
275 | let BCalc = 0;
276 | let CCalc = 0;
277 | const A = signal(0);
278 | const B = computed(()=> {
279 | BCalc++;
280 | return A.value + 1;
281 | });
282 | const C = computed(() => {
283 | CCalc++;
284 | return A.value + B.value;
285 | });
286 |
287 | assert(
288 | JSON.stringify({
289 | B: [B.value, BCalc],
290 | C: [C.value, CCalc]
291 | }) === '{"B":[1,1],"C":[1,1]}',
292 | 'unexpected amount of invokes'
293 | );
294 |
295 | A.value = 1;
296 |
297 | assert(
298 | JSON.stringify({
299 | B: [B.value, BCalc],
300 | C: [C.value, CCalc]
301 | }) === '{"B":[2,2],"C":[3,2]}',
302 | 'unexpected amount of invokes after single change'
303 | );
304 | }
305 |
306 | function implicitToString() {
307 | let invokes = 0;
308 | const number = signal(1);
309 | const sum = computed(() => {
310 | invokes++;
311 | return `${number} + 2 = 3`;
312 | });
313 | assert(sum.value === '1 + 2 = 3', 'computed with toString() did not return the expected value');
314 | number.value = 0;
315 | assert(sum.value === '0 + 2 = 3', 'computed with toString() after value did not return the expected value');
316 | assert(invokes === 2, 'computed with toString() did not get invoked');
317 | }
318 |
319 | function testDiamond() {
320 | let BCalc = 0;
321 | let CCalc = 0;
322 | let DCalc = 0;
323 | const a = signal(1);
324 | const b = computed(() => {
325 | BCalc++;
326 | return a.value;
327 | });
328 | const c = computed(() => {
329 | CCalc++;
330 | return a.value;
331 | });
332 | const d = computed(() => {
333 | DCalc++;
334 | return b.value + c.value;
335 | });
336 |
337 | assert(d.value === 2, 'initial d value is wrong');
338 | assert([BCalc, CCalc, DCalc].join(',') === '1,1,1', 'initial calculation is wrong');
339 | a.value = 2;
340 | assert(d.value === 4, 'second d value is wrong');
341 | assert([BCalc, CCalc, DCalc].join(',') === '2,2,2', 'second calculation is wrong: ');
342 | a.value = 3;
343 | assert(d.value === 6, 'third d value is wrong');
344 | assert([BCalc, CCalc, DCalc].join(',') === '3,3,3', 'third calculation is wrong');
345 | }
346 |
347 | function loopedEffects() {
348 | const invokes = [];
349 | const num = signal(0);
350 | let loop = 2;
351 |
352 | effect(() => {
353 | invokes.push(num.value);
354 | for (let i = 0; i < loop; i++)
355 | effect(() => {
356 | invokes.push(num.value + i);
357 | });
358 | });
359 |
360 | assert(invokes.length === 3, 'looped effects not working');
361 | assert(invokes.join(',') === '0,0,1', 'looped values not matching');
362 |
363 | invokes.splice(0);
364 | loop = 1;
365 | num.value = 1;
366 |
367 | if (!/^(?:@preact\/signals-core)$/.test(library)) {
368 | assert(invokes.length === 2, 'looped effects not working after changes');
369 | assert(invokes.join(',') === '1,1', 'looped values not matching after changes');
370 | }
371 | }
372 |
373 | // check different output in preact/usignal/solid
374 | // even if the logic / result is almost same output
375 | function nestedEffects() {
376 | console.log('------');
377 |
378 | const counter = signal(1);
379 | const double = computed(() => {
380 | console.log('double');
381 | return counter.value * 2
382 | });
383 | const tripple = computed(() => {
384 | console.log('triple');
385 | return counter.value * 3;
386 | });
387 |
388 | const dispose1 = effect(() => {
389 | console.log('outer', double.value);
390 | effect(() => {
391 | console.log('nested', tripple.value);
392 | });
393 | });
394 |
395 | const dispose2 = effect(() => {
396 | console.log('a part', tripple.value);
397 | });
398 |
399 | console.log('- - -');
400 | counter.value = 20;
401 | console.log('------');
402 | console.log('');
403 |
404 | if (dispose1 && dispose2) {
405 | dispose1();
406 | dispose2();
407 | counter.value = 40;
408 | }
409 | }
410 |
411 | function nestedIndependentEffects() {
412 | console.log('------');
413 |
414 | const a = signal(1);
415 | const b = signal(1);
416 |
417 | effect(() => {
418 | console.log('outer', a.value);
419 | effect(() => {
420 | console.log('nested', b.value);
421 | });
422 | });
423 |
424 | effect(() => {
425 | console.log('a part', a.value);
426 | });
427 |
428 | console.log('- - -');
429 | a.value = 2;
430 | console.log('- - -');
431 | b.value = 3;
432 | console.log('- - -');
433 | a.value = 3;
434 | console.log('------');
435 | console.log('');
436 | }
437 |
438 | function testConditional() {
439 | const first = signal('John');
440 | const last = signal('Doe');
441 | const full = computed(() => {
442 | console.log('Computing name', first.value, last.value);
443 | return `${first.value} ${last.value}`;
444 | });
445 | const nickname = signal(undefined);
446 |
447 | effect(() => {
448 | if (nickname.value) {
449 | console.log('profile name', nickname.value);
450 | } else {
451 | console.log('profile name', full.value);
452 | }
453 | });
454 |
455 | nickname.value = 'jdoe';
456 |
457 | // this should _not_ execute effects, right?
458 | last.value = 'Smith';
459 | }
460 | };
461 |
--------------------------------------------------------------------------------
/test/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "ES2022",
4 | "target": "ES2022",
5 | "moduleResolution": "node",
6 | "declaration": false,
7 | "noEmit": true
8 | },
9 | "include": [
10 | "types.ts"
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/test/types.ts:
--------------------------------------------------------------------------------
1 | import { signal, computed, ReactiveSignal, ComputedSignal } from '..'
2 | import {expectTypeOf} from 'expect-type'
3 |
4 | const sig = signal(123)
5 | expectTypeOf(sig).toEqualTypeOf>()
6 | expectTypeOf(sig.value).toEqualTypeOf()
7 | expectTypeOf(sig.valueOf()).toEqualTypeOf()
8 | expectTypeOf(sig.toString()).toEqualTypeOf()
9 | expectTypeOf(sig.peek()).toEqualTypeOf()
10 | expectTypeOf(sig.toJSON()).toEqualTypeOf()
11 | // expectTypeOf(await sig).toEqualTypeOf()
12 | // sig.then(v => expectTypeOf(v).toEqualTypeOf())
13 |
14 | const comp = computed(() => 213)
15 | expectTypeOf(comp).toEqualTypeOf>()
16 | expectTypeOf(comp.value).toEqualTypeOf()
17 | expectTypeOf(comp.valueOf()).toEqualTypeOf()
18 | expectTypeOf(comp.toString()).toEqualTypeOf()
19 | expectTypeOf(comp.peek()).toEqualTypeOf()
20 | expectTypeOf(comp.toJSON()).toEqualTypeOf()
21 | // expectTypeOf(await comp).toEqualTypeOf()
22 | // comp.then(v => expectTypeOf(v).toEqualTypeOf())
23 |
24 | const compMix = computed(() => 'asd', 123)
25 | expectTypeOf(compMix).toEqualTypeOf>()
26 | expectTypeOf(compMix.value).toEqualTypeOf()
27 | expectTypeOf(compMix.valueOf()).toEqualTypeOf()
28 | expectTypeOf(compMix.toString()).toEqualTypeOf()
29 | expectTypeOf(compMix.peek()).toEqualTypeOf()
30 | expectTypeOf(compMix.toJSON()).toEqualTypeOf()
31 | // expectTypeOf(await compMix).toEqualTypeOf()
32 | // compMix.then(v => expectTypeOf(v).toEqualTypeOf())
33 |
--------------------------------------------------------------------------------
/test/usignal.js:
--------------------------------------------------------------------------------
1 | import './leak.js';
2 | import * as usignal from '../esm/index.js';
3 |
4 | const library = 'usignal';
5 |
6 | const assert = (what, why) => {
7 | console.assert(what);
8 | if (!what)
9 | throw new Error(`\x1b[1m${library}\x1b[0m: ${why}`);
10 | };
11 |
12 | let invokes = 0;
13 | const fx = new usignal.FX(() => { invokes++; }, null, {equals: true});
14 | fx.run();
15 | assert(invokes === 1);
16 | fx.run();
17 | assert(invokes === 2);
18 |
19 |
20 | setTimeout(
21 | async () => {
22 | (await import('./test.js')).default('usignal', usignal);
23 | (await import('./async.js')).default('usignal', usignal);
24 | },
25 | 250
26 | );
27 |
28 | import {signal, computed} from '../esm/fn/index.js';
29 |
30 | var s = signal(0);
31 | var c = computed(() => s());
32 |
33 | assert(s() === 0 && c() === 0, 'wrong initial value');
34 | assert(s(1) === 1 && c() === 1, 'wrong updated value');
35 |
36 | import {createEffect, createMemo, createSignal} from '../esm/solid/index.js';
37 |
38 | var [s, u] = createSignal(() => 0);
39 | var c = createMemo(() => s());
40 |
41 | createEffect(
42 | prev => {
43 | assert(s() === prev && c() === prev);
44 | return s() + 1;
45 | },
46 | 0
47 | );
48 |
49 | assert(s() === 0);
50 | u(1);
51 | assert(s() === 1);
52 |
--------------------------------------------------------------------------------
/test/weak-effects.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "ES2020",
4 | "target": "ES2020",
5 | "moduleResolution": "Classic",
6 | "allowJs": true,
7 | "declaration": true,
8 | "emitDeclarationOnly": true,
9 | "declarationDir": "types"
10 | },
11 | "include": [
12 | "esm/**/*.js"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/types/async.d.ts:
--------------------------------------------------------------------------------
1 | export * from "./index.js";
2 | /**
3 | * Invokes asynchronously a function when any of its internal signals or computed values change.
4 | *
5 | * Returns a dispose callback.
6 | * @template T
7 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
8 | */
9 | export const effect: (fn: (v?: T) => T, value?: T) => () => void;
10 |
--------------------------------------------------------------------------------
/types/fn/async.d.ts:
--------------------------------------------------------------------------------
1 | export * from "./index.js";
2 | /**
3 | * Invokes asynchronously a function when any of its internal signals or computed values change.
4 | *
5 | * Returns a dispose callback.
6 | * @template T
7 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
8 | */
9 | export const effect: (fn: (v?: T) => T, value?: T) => () => void;
10 |
--------------------------------------------------------------------------------
/types/fn/index.d.ts:
--------------------------------------------------------------------------------
1 | export * from "../index.js";
2 | /**
3 | * Returns a callback that is invoked only when any of the internally
4 | * used signals, as in within the callback, is unknown or updated.
5 | * @template T
6 | * @type {(fn: (v: T) => T, value?: T, options?: { equals?: boolean | ((prev: T, next: T) => boolean) }) => () => T}
7 | */
8 | export const computed: (fn: (v: T) => T, value?: T, options?: {
9 | equals?: boolean | ((prev: T, next: T) => boolean);
10 | }) => () => T;
11 | export function signal(value: T, options?: {
12 | equals?: boolean | ((prev: T, next: T) => boolean);
13 | }): (value?: T) => T;
14 |
--------------------------------------------------------------------------------
/types/fn/sync.d.ts:
--------------------------------------------------------------------------------
1 | export * from "./index.js";
2 | /**
3 | * Invokes asynchronously a function when any of its internal signals or computed values change.
4 | *
5 | * Returns a dispose callback.
6 | * @template T
7 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
8 | */
9 | export const effect: (fn: (v?: T) => T, value?: T) => () => void;
10 |
--------------------------------------------------------------------------------
/types/index.d.ts:
--------------------------------------------------------------------------------
1 | export function batch(callback: () => void): void;
2 | /**
3 | * A signal with a value property also exposed via toJSON, toString and valueOf.
4 | * When created via computed, the `value` property is **readonly**.
5 | * @template T
6 | */
7 | export class Signal {
8 | constructor(value: any);
9 | _: any;
10 | /** @returns {T} */
11 | toJSON(): T;
12 | /** @returns {string} */
13 | toString(): string;
14 | /** @returns {T} */
15 | valueOf(): T;
16 | }
17 | /**
18 | * Returns a read-only Signal that is invoked only when any of the internally
19 | * used signals, as in within the callback, is unknown or updated.
20 | * @type {(fn: (v: T) => R, value?: V, options?: { equals?: Equals }) => ComputedSignal}
21 | */
22 | export const computed: (fn: (v: T) => R, value?: V, options?: {
23 | equals?: Equals;
24 | }) => ComputedSignal;
25 | export class FX extends Computed {
26 | constructor(_: any, v: any, o: any);
27 | e: any[];
28 | run(): FX;
29 | stop(): void;
30 | }
31 | export class Effect extends FX {
32 | i: number;
33 | a: boolean;
34 | m: boolean;
35 | get value(): void;
36 | async(): void;
37 | sync(): void;
38 | }
39 | /**
40 | * Invokes a function when any of its internal signals or computed values change.
41 | *
42 | * Returns a dispose callback.
43 | * @template T
44 | * @type {(fn: (v: T) => T, value?: T, options?: { async?: boolean }) => () => void}
45 | */
46 | export const effect: (fn: (v: T) => T, value?: T, options?: {
47 | async?: boolean;
48 | }) => () => void;
49 | /**
50 | * Returns a writable Signal that side-effects whenever its value gets updated.
51 | * @template T
52 | * @type {(initialValue: T, options?: { equals?: Equals }) => ReactiveSignal}
53 | */
54 | export const signal: (initialValue: T, options?: {
55 | equals?: Equals;
56 | }) => ReactiveSignal;
57 | export type Equals = boolean | ((prev: T, next: T) => boolean);
58 | /**
59 | *
60 | */
61 | export type ReactiveSignal = Omit, '_' | 's' | 'c'>;
62 | /**
63 | *
64 | */
65 | export type ComputedSignal = Omit, '$' | 's' | 'f' | 'r' | '_'>;
66 | /**
67 | * @template T
68 | * @extends {Signal}
69 | */
70 | declare class Computed extends Signal {
71 | /**
72 | * @param {(v: T) => T} _
73 | * @param {T} v
74 | * @param {{ equals?: Equals }} o
75 | * @param {boolean} f
76 | */
77 | constructor(_: (v: T) => T, v: T, o: {
78 | equals?: Equals;
79 | }, f: boolean);
80 | /**
81 | * @private
82 | * @type{Reactive}
83 | */
84 | private s;
85 | f: boolean;
86 | $: boolean;
87 | r: Set;
88 | refresh(): void;
89 | peek(): T;
90 | get value(): T;
91 | }
92 | /**
93 | * @template T
94 | * @extends {Signal}
95 | */
96 | declare class Reactive extends Signal {
97 | constructor(_: any, { equals }: {
98 | equals: any;
99 | });
100 | c: Set;
101 | s: any;
102 | /**
103 | * Allows to get signal.value without subscribing to updates in an effect
104 | * @returns {T}
105 | */
106 | peek(): T;
107 | set value(arg: T);
108 | /** @returns {T} */
109 | get value(): T;
110 | }
111 | export {};
112 |
--------------------------------------------------------------------------------
/types/solid/async.d.ts:
--------------------------------------------------------------------------------
1 | export * from "./index.js";
2 | /**
3 | * asynchronous https://www.solidjs.com/docs/latest/api#createeffect
4 | *
5 | * returns a dispose callback.
6 | * @template T
7 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
8 | */
9 | export const createEffect: (fn: (v?: T) => T, value?: T) => () => void;
10 |
--------------------------------------------------------------------------------
/types/solid/index.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * https://www.solidjs.com/docs/latest/api#createeffect
3 | *
4 | * returns a dispose callback.
5 | * @template T
6 | * @type {(fn: (v: T) => T, value?: T, options?: { async?: boolean }) => () => void}
7 | */
8 | export const createEffect: (fn: (v: T_1) => T_1, value?: T_1, options?: {
9 | async?: boolean;
10 | }) => () => void;
11 | /**
12 | * @template T
13 | * @type {(fn: (v: T) => T, value?: T, options?: { equals?: boolean | ((prev: T, next: T) => boolean) }) => () => T}
14 | */
15 | export const createMemo: (fn: (v: T_1) => T_1, value?: T_1, options?: {
16 | equals?: boolean | ((prev: T_1, next: T_1) => boolean);
17 | }) => () => T_1;
18 | /**
19 | * @template T
20 | * @type {(initialValue: T, options?: { equals?: boolean | ((prev: T, next: T) => boolean) }) => [get: () => T, set: (v: T) => T]}
21 | */
22 | export const createSignal: (initialValue: T_1, options?: {
23 | equals?: boolean | ((prev: T_1, next: T_1) => boolean);
24 | }) => [get: () => T_1, set: (v: T_1) => T_1];
25 |
--------------------------------------------------------------------------------
/types/solid/sync.d.ts:
--------------------------------------------------------------------------------
1 | export * from "./index.js";
2 | /**
3 | * synchronous https://www.solidjs.com/docs/latest/api#createeffect
4 | *
5 | * returns a dispose callback.
6 | * @template T
7 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
8 | */
9 | export const createEffect: (fn: (v?: T) => T, value?: T) => () => void;
10 |
--------------------------------------------------------------------------------
/types/sync.d.ts:
--------------------------------------------------------------------------------
1 | export * from "./index.js";
2 | /**
3 | * Invokes synchronously a function when any of its internal signals or computed values change.
4 | *
5 | * Returns a dispose callback.
6 | * @template T
7 | * @type {(fn: (v?: T) => T?, value?: T) => () => void 0}
8 | */
9 | export const effect: (fn: (v?: T) => T, value?: T) => () => void;
10 |
--------------------------------------------------------------------------------