├── .gitignore ├── CHANGELOG.md ├── README.md ├── examples ├── attachTo.html ├── benchmark.html ├── bind.html ├── btn.html ├── computed.html ├── copyTo.html ├── renderFn-bind.html ├── renderFn.html └── subscriber.html ├── package-lock.json ├── package.json ├── src ├── Computed.ts ├── Signal.ts └── index.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | #### 0.4.1 (2023-03-30) 2 | 3 | ##### Documentation Changes 4 | 5 | * updated documentation ([ae627142](https://github.com/Cadienvan/super-simple-signal/commit/ae627142322407b3de1e96e1c8040e04b6413ee0)) 6 | * updated changelog ([c518756d](https://github.com/Cadienvan/super-simple-signal/commit/c518756d7a2ebb997ff43e719b7286eb10571a76)) 7 | * updated changelog ([1dd06c21](https://github.com/Cadienvan/super-simple-signal/commit/1dd06c2119320582ae9626063ab20eba88cdfc74)) 8 | 9 | ##### New Features 10 | 11 | * objects can now be used as a signal value ([b2e41591](https://github.com/Cadienvan/super-simple-signal/commit/b2e4159119d399dd6d027980c435ea292570574b)) 12 | 13 | #### 0.4.1 (2023-03-30) 14 | 15 | ##### Documentation Changes 16 | 17 | * updated changelog ([1dd06c21](https://github.com/Cadienvan/super-simple-signal/commit/1dd06c2119320582ae9626063ab20eba88cdfc74)) 18 | 19 | ##### New Features 20 | 21 | * objects can now be used as a signal value ([b2e41591](https://github.com/Cadienvan/super-simple-signal/commit/b2e4159119d399dd6d027980c435ea292570574b)) 22 | 23 | #### 0.4.1 (2023-03-30) 24 | 25 | ##### New Features 26 | 27 | * objects can now be used as a signal value ([b2e41591](https://github.com/Cadienvan/super-simple-signal/commit/b2e4159119d399dd6d027980c435ea292570574b)) 28 | 29 | ### 0.4.0 (2023-03-21) 30 | 31 | ##### New Features 32 | 33 | * implementing queueMicrotask for single re-render ([e22a0023](https://github.com/Cadienvan/super-simple-signal/commit/e22a0023c8e39d4c32fbaaf87992b66fad395b3f)) 34 | 35 | ### 0.3.0 (2023-03-21) 36 | 37 | ##### New Features 38 | 39 | * added allowDirty as option ([f73c083f](https://github.com/Cadienvan/super-simple-signal/commit/f73c083fdfff62737f67fef5bd6e19d464252e19)) 40 | 41 | #### 0.2.1 (2023-03-06) 42 | 43 | ##### Chores 44 | 45 | * removed unnecessary detachFrom ([60d96ab3](https://github.com/Cadienvan/super-simple-signal/commit/60d96ab3bc483001ba0cff72e2bfe76f00b065b6)) 46 | 47 | ##### Documentation Changes 48 | 49 | * updated docs ([96289228](https://github.com/Cadienvan/super-simple-signal/commit/9628922875762fc0327e4fbc706ff48075c83277)) 50 | 51 | ##### New Features 52 | 53 | * added terser for minification ([b4f514dd](https://github.com/Cadienvan/super-simple-signal/commit/b4f514dd1de189878fb7cd88c89ad82a1a30a179)) 54 | * implemented detach ([a326dac0](https://github.com/Cadienvan/super-simple-signal/commit/a326dac0f49e21db9ebc499a19316bdf6e306ecf)) 55 | 56 | ### 0.2.0 (2023-03-06) 57 | 58 | ### 0.1.0 (2023-03-06) 59 | 60 | ##### Chores 61 | 62 | * corrected changelog package ([b263e5a5](https://github.com/Cadienvan/super-simple-signal/commit/b263e5a5744b01066bb6e0e94913e88fd5d67ba6)) 63 | * updated package and lock for changelog and deploy ([700697df](https://github.com/Cadienvan/super-simple-signal/commit/700697dfeec157ad7a2f60262c7b1ee0559be6b5)) 64 | * updated examples ([a7b86920](https://github.com/Cadienvan/super-simple-signal/commit/a7b869207ed4b451952086d3d483ab7df47a339d)) 65 | * keepInSync changed default to true + brought defaultOptions to Computed ([4545fc5a](https://github.com/Cadienvan/super-simple-signal/commit/4545fc5a561df7423a863948ed2260dfee0457ee)) 66 | 67 | ##### Documentation Changes 68 | 69 | * updated changelog ([6ad7f9ff](https://github.com/Cadienvan/super-simple-signal/commit/6ad7f9ff5e020b426225c2d4cc98239279b1ec70)) 70 | * updated documentation ([899cc892](https://github.com/Cadienvan/super-simple-signal/commit/899cc892d65b8f80de9cf003cfe57b0bb7f8ef83)) 71 | 72 | ##### New Features 73 | 74 | * preventing undirty change ([532920e9](https://github.com/Cadienvan/super-simple-signal/commit/532920e9100f048b492bfd0b9ce0057b66051457)) 75 | * added render function + fixed binding events ([0ee4a54e](https://github.com/Cadienvan/super-simple-signal/commit/0ee4a54e4919f5730bf1b8d8438a70e6e99809ce)) 76 | * computed can now be attached directly to a node + tests on multi-signal ([351faedb](https://github.com/Cadienvan/super-simple-signal/commit/351faedb9fef31cbee510918b3b7306ed8b89fa8)) 77 | * first release - yet to complete ([3554f9ef](https://github.com/Cadienvan/super-simple-signal/commit/3554f9efed62320490e718c756172705e1134261)) 78 | 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # What Is This? 2 | This is a super simple signal library for browser. It's mostly an experiment which provided good benchmarks and a nice, clean and simple API. It's also very small, weighing in at 296B minified and gzipped. 3 | 4 | # Installation 5 | ```bash 6 | npm install super-simple-signal 7 | ``` 8 | 9 | # Usage 10 | 11 | ## Basic 12 | ```html 13 | 14 | 15 | 30 |
31 | 32 | 33 | ``` 34 | 35 | # API 36 | ## Signal 37 | A `Signal` is a reactive javascript variable which can be attached to a DOM node and create a one-way or two-way data binding mechanism with it. 38 | 39 | ### `new Signal(value)` 40 | Creates a new signal with the given initial value. 41 | 42 | ### `new Signal(node)` 43 | Creates a new signal which is attached to the given node. 44 | 45 | ### `new Signal(node, value)` 46 | Creates a new signal which is attached to the given node and has the given initial value. 47 | 48 | ### `new Signal(node, value, opts)` 49 | Creates a new signal which is attached to the given node and has the given initial value. The opts object can have the following properties: 50 | - `property` - The property of the node to attach to. Defaults to `innerHTML`. 51 | - `bind` - Whether to bind the signal to the node. Defaults to `true`. If so, the signal will be updated whenever the node's `bindEvents` are fired. 52 | - `bindEvents` - The events to bind to. Defaults to an empty array. 53 | - `render` - A function which will be called whenever the signal's value changes. The function will be called with the new value as the first argument. This means you can have a signal value of any type and render it however you want. 54 | - `allowDirty` - Whether to allow dirty values. Defaults to `false`. If so, the signal will fire its subscribers and re-render even if the value hasn't changed. 55 | 56 | ### `signal.value` 57 | The current value of the signal. Setting this will update the signal's value and call all the signal's subscribers and re-render the signal's node. 58 | 59 | ### `signal.subscribe(callback)` 60 | Subscribes the given callback to the signal. The callback will be called whenever the signal's value changes. The callback will be called with the new value as the first argument and the old value as the second argument. 61 | 62 | ### `signal.unsubscribe(callback)` 63 | Unsubscribes the given callback from the signal. 64 | 65 | ### `signal.attachTo(node, property)` 66 | Attaches the signal to the given node. The signal will update the node's given property whenever the signal's value changes. Defaults to `innerHTML`. If the signal already has a node attached, it will be detached first. 67 | 68 | ### `signal.detach()` 69 | Detaches the signal from the current node. 70 | 71 | ### `signal.copyTo(node, opts, keepInSync)` 72 | Copies the signal's value to the given node. This will actually create a new `Signal`. If `keepInSync` is `true`, the new signal will be updated whenever the initial signal changes. Defaults to `true`. To prevent circular updates, we only subscribe to the signal if keepInSync is true and don't subscribe back. 73 | 74 | ## Computed 75 | A `Computed` is a `Signal` which is dependent on given input signals. 76 | Its API, being a Signal itself, is totally compatible with the Signal, with some differences explained below. 77 | 78 | ### `new Computed(dependencies, fn, node, opts)` 79 | Creates a new Computed which is attached to the given node and has the given initial value. 80 | It takes the following parameters: 81 | - `dependencies`: An array of Signals from which the Computed depends. 82 | - `fn`: The function to be called whenever a dependency changes. It takes the Signal `value` as the first parameter, the Signal `oldValue` as the second parameter and the `computedOldValue` as the third parameter. 83 | - `node`: The node to attach the Computed to. 84 | - `opts`: A Signal-compatible opts parameter. 85 | 86 | # Benchmarks 87 | 88 | If you open the `examples/bechmark.html` file in your browser, you can see the time needed to update 3 signals 100.000 times with random numbers. The results are as follows on a 2021 Macbook Pro M1 Max with 32GB of RAM: 89 | `12ms for 300.000 updates` 90 | 91 | # ToDo 92 | - [ ] Add tests -------------------------------------------------------------------------------- /examples/attachTo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Signals Demo 8 | 9 | 10 |
11 |
12 | 13 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/benchmark.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Signals Demo 8 | 9 | 10 |
11 |
12 |
13 | 14 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /examples/bind.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Signals Demo 8 | 9 | 10 | 11 | 12 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/btn.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Signals Demo 8 | 9 | 10 | 11 | 23 |
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/computed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Signals Demo 8 | 9 | 10 |
11 |
12 |
13 | 14 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /examples/copyTo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Signals Demo 8 | 9 | 10 |
11 |
12 | 13 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /examples/renderFn-bind.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Signals Demo 8 | 9 | 10 | 11 |
12 | 13 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /examples/renderFn.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Signals Demo 8 | 9 | 10 |
11 | 12 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /examples/subscriber.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Signals Demo 8 | 9 | 10 |
11 | 12 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "super-simple-signal", 3 | "version": "0.4.1", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "super-simple-signal", 9 | "version": "0.4.1", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "generate-changelog": "^1.8.0", 13 | "rollup": "^4.9.1", 14 | "terser": "^5.26.0", 15 | "typescript": "^5.3.3" 16 | } 17 | }, 18 | "node_modules/@jridgewell/gen-mapping": { 19 | "version": "0.3.3", 20 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", 21 | "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", 22 | "dev": true, 23 | "dependencies": { 24 | "@jridgewell/set-array": "^1.0.1", 25 | "@jridgewell/sourcemap-codec": "^1.4.10", 26 | "@jridgewell/trace-mapping": "^0.3.9" 27 | }, 28 | "engines": { 29 | "node": ">=6.0.0" 30 | } 31 | }, 32 | "node_modules/@jridgewell/resolve-uri": { 33 | "version": "3.1.1", 34 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 35 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", 36 | "dev": true, 37 | "engines": { 38 | "node": ">=6.0.0" 39 | } 40 | }, 41 | "node_modules/@jridgewell/set-array": { 42 | "version": "1.1.2", 43 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 44 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 45 | "dev": true, 46 | "engines": { 47 | "node": ">=6.0.0" 48 | } 49 | }, 50 | "node_modules/@jridgewell/source-map": { 51 | "version": "0.3.5", 52 | "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", 53 | "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", 54 | "dev": true, 55 | "dependencies": { 56 | "@jridgewell/gen-mapping": "^0.3.0", 57 | "@jridgewell/trace-mapping": "^0.3.9" 58 | } 59 | }, 60 | "node_modules/@jridgewell/sourcemap-codec": { 61 | "version": "1.4.15", 62 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 63 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", 64 | "dev": true 65 | }, 66 | "node_modules/@jridgewell/trace-mapping": { 67 | "version": "0.3.20", 68 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", 69 | "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", 70 | "dev": true, 71 | "dependencies": { 72 | "@jridgewell/resolve-uri": "^3.1.0", 73 | "@jridgewell/sourcemap-codec": "^1.4.14" 74 | } 75 | }, 76 | "node_modules/@rollup/rollup-android-arm-eabi": { 77 | "version": "4.9.1", 78 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.1.tgz", 79 | "integrity": "sha512-6vMdBZqtq1dVQ4CWdhFwhKZL6E4L1dV6jUjuBvsavvNJSppzi6dLBbuV+3+IyUREaj9ZFvQefnQm28v4OCXlig==", 80 | "cpu": [ 81 | "arm" 82 | ], 83 | "dev": true, 84 | "optional": true, 85 | "os": [ 86 | "android" 87 | ] 88 | }, 89 | "node_modules/@rollup/rollup-android-arm64": { 90 | "version": "4.9.1", 91 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.1.tgz", 92 | "integrity": "sha512-Jto9Fl3YQ9OLsTDWtLFPtaIMSL2kwGyGoVCmPC8Gxvym9TCZm4Sie+cVeblPO66YZsYH8MhBKDMGZ2NDxuk/XQ==", 93 | "cpu": [ 94 | "arm64" 95 | ], 96 | "dev": true, 97 | "optional": true, 98 | "os": [ 99 | "android" 100 | ] 101 | }, 102 | "node_modules/@rollup/rollup-darwin-arm64": { 103 | "version": "4.9.1", 104 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.1.tgz", 105 | "integrity": "sha512-LtYcLNM+bhsaKAIGwVkh5IOWhaZhjTfNOkGzGqdHvhiCUVuJDalvDxEdSnhFzAn+g23wgsycmZk1vbnaibZwwA==", 106 | "cpu": [ 107 | "arm64" 108 | ], 109 | "dev": true, 110 | "optional": true, 111 | "os": [ 112 | "darwin" 113 | ] 114 | }, 115 | "node_modules/@rollup/rollup-darwin-x64": { 116 | "version": "4.9.1", 117 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.1.tgz", 118 | "integrity": "sha512-KyP/byeXu9V+etKO6Lw3E4tW4QdcnzDG/ake031mg42lob5tN+5qfr+lkcT/SGZaH2PdW4Z1NX9GHEkZ8xV7og==", 119 | "cpu": [ 120 | "x64" 121 | ], 122 | "dev": true, 123 | "optional": true, 124 | "os": [ 125 | "darwin" 126 | ] 127 | }, 128 | "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 129 | "version": "4.9.1", 130 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.1.tgz", 131 | "integrity": "sha512-Yqz/Doumf3QTKplwGNrCHe/B2p9xqDghBZSlAY0/hU6ikuDVQuOUIpDP/YcmoT+447tsZTmirmjgG3znvSCR0Q==", 132 | "cpu": [ 133 | "arm" 134 | ], 135 | "dev": true, 136 | "optional": true, 137 | "os": [ 138 | "linux" 139 | ] 140 | }, 141 | "node_modules/@rollup/rollup-linux-arm64-gnu": { 142 | "version": "4.9.1", 143 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.1.tgz", 144 | "integrity": "sha512-u3XkZVvxcvlAOlQJ3UsD1rFvLWqu4Ef/Ggl40WAVCuogf4S1nJPHh5RTgqYFpCOvuGJ7H5yGHabjFKEZGExk5Q==", 145 | "cpu": [ 146 | "arm64" 147 | ], 148 | "dev": true, 149 | "optional": true, 150 | "os": [ 151 | "linux" 152 | ] 153 | }, 154 | "node_modules/@rollup/rollup-linux-arm64-musl": { 155 | "version": "4.9.1", 156 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.1.tgz", 157 | "integrity": "sha512-0XSYN/rfWShW+i+qjZ0phc6vZ7UWI8XWNz4E/l+6edFt+FxoEghrJHjX1EY/kcUGCnZzYYRCl31SNdfOi450Aw==", 158 | "cpu": [ 159 | "arm64" 160 | ], 161 | "dev": true, 162 | "optional": true, 163 | "os": [ 164 | "linux" 165 | ] 166 | }, 167 | "node_modules/@rollup/rollup-linux-riscv64-gnu": { 168 | "version": "4.9.1", 169 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.1.tgz", 170 | "integrity": "sha512-LmYIO65oZVfFt9t6cpYkbC4d5lKHLYv5B4CSHRpnANq0VZUQXGcCPXHzbCXCz4RQnx7jvlYB1ISVNCE/omz5cw==", 171 | "cpu": [ 172 | "riscv64" 173 | ], 174 | "dev": true, 175 | "optional": true, 176 | "os": [ 177 | "linux" 178 | ] 179 | }, 180 | "node_modules/@rollup/rollup-linux-x64-gnu": { 181 | "version": "4.9.1", 182 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.1.tgz", 183 | "integrity": "sha512-kr8rEPQ6ns/Lmr/hiw8sEVj9aa07gh1/tQF2Y5HrNCCEPiCBGnBUt9tVusrcBBiJfIt1yNaXN6r1CCmpbFEDpg==", 184 | "cpu": [ 185 | "x64" 186 | ], 187 | "dev": true, 188 | "optional": true, 189 | "os": [ 190 | "linux" 191 | ] 192 | }, 193 | "node_modules/@rollup/rollup-linux-x64-musl": { 194 | "version": "4.9.1", 195 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.1.tgz", 196 | "integrity": "sha512-t4QSR7gN+OEZLG0MiCgPqMWZGwmeHhsM4AkegJ0Kiy6TnJ9vZ8dEIwHw1LcZKhbHxTY32hp9eVCMdR3/I8MGRw==", 197 | "cpu": [ 198 | "x64" 199 | ], 200 | "dev": true, 201 | "optional": true, 202 | "os": [ 203 | "linux" 204 | ] 205 | }, 206 | "node_modules/@rollup/rollup-win32-arm64-msvc": { 207 | "version": "4.9.1", 208 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.1.tgz", 209 | "integrity": "sha512-7XI4ZCBN34cb+BH557FJPmh0kmNz2c25SCQeT9OiFWEgf8+dL6ZwJ8f9RnUIit+j01u07Yvrsuu1rZGxJCc51g==", 210 | "cpu": [ 211 | "arm64" 212 | ], 213 | "dev": true, 214 | "optional": true, 215 | "os": [ 216 | "win32" 217 | ] 218 | }, 219 | "node_modules/@rollup/rollup-win32-ia32-msvc": { 220 | "version": "4.9.1", 221 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.1.tgz", 222 | "integrity": "sha512-yE5c2j1lSWOH5jp+Q0qNL3Mdhr8WuqCNVjc6BxbVfS5cAS6zRmdiw7ktb8GNpDCEUJphILY6KACoFoRtKoqNQg==", 223 | "cpu": [ 224 | "ia32" 225 | ], 226 | "dev": true, 227 | "optional": true, 228 | "os": [ 229 | "win32" 230 | ] 231 | }, 232 | "node_modules/@rollup/rollup-win32-x64-msvc": { 233 | "version": "4.9.1", 234 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.1.tgz", 235 | "integrity": "sha512-PyJsSsafjmIhVgaI1Zdj7m8BB8mMckFah/xbpplObyHfiXzKcI5UOUXRyOdHW7nz4DpMCuzLnF7v5IWHenCwYA==", 236 | "cpu": [ 237 | "x64" 238 | ], 239 | "dev": true, 240 | "optional": true, 241 | "os": [ 242 | "win32" 243 | ] 244 | }, 245 | "node_modules/acorn": { 246 | "version": "8.8.2", 247 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", 248 | "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", 249 | "dev": true, 250 | "bin": { 251 | "acorn": "bin/acorn" 252 | }, 253 | "engines": { 254 | "node": ">=0.4.0" 255 | } 256 | }, 257 | "node_modules/bluebird": { 258 | "version": "3.7.2", 259 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", 260 | "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", 261 | "dev": true 262 | }, 263 | "node_modules/buffer-from": { 264 | "version": "1.1.2", 265 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 266 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 267 | "dev": true 268 | }, 269 | "node_modules/commander": { 270 | "version": "2.20.3", 271 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 272 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 273 | "dev": true 274 | }, 275 | "node_modules/fsevents": { 276 | "version": "2.3.2", 277 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 278 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 279 | "dev": true, 280 | "hasInstallScript": true, 281 | "optional": true, 282 | "os": [ 283 | "darwin" 284 | ], 285 | "engines": { 286 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 287 | } 288 | }, 289 | "node_modules/generate-changelog": { 290 | "version": "1.8.0", 291 | "resolved": "https://registry.npmjs.org/generate-changelog/-/generate-changelog-1.8.0.tgz", 292 | "integrity": "sha512-msgpxeB75Ziyg3wGsZuPNl7c5RxChMKmYcAX5obnhUow90dBZW3nLic6nxGtst7Bpx453oS6zAIHcX7F3QVasw==", 293 | "dev": true, 294 | "dependencies": { 295 | "bluebird": "^3.0.6", 296 | "commander": "^2.9.0", 297 | "github-url-from-git": "^1.4.0" 298 | }, 299 | "bin": { 300 | "changelog": "bin/generate", 301 | "generate-changelog": "bin/generate" 302 | } 303 | }, 304 | "node_modules/github-url-from-git": { 305 | "version": "1.5.0", 306 | "resolved": "https://registry.npmjs.org/github-url-from-git/-/github-url-from-git-1.5.0.tgz", 307 | "integrity": "sha512-WWOec4aRI7YAykQ9+BHmzjyNlkfJFG8QLXnDTsLz/kZefq7qkzdfo4p6fkYYMIq1aj+gZcQs/1HQhQh3DPPxlQ==", 308 | "dev": true 309 | }, 310 | "node_modules/rollup": { 311 | "version": "4.9.1", 312 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.1.tgz", 313 | "integrity": "sha512-pgPO9DWzLoW/vIhlSoDByCzcpX92bKEorbgXuZrqxByte3JFk2xSW2JEeAcyLc9Ru9pqcNNW+Ob7ntsk2oT/Xw==", 314 | "dev": true, 315 | "bin": { 316 | "rollup": "dist/bin/rollup" 317 | }, 318 | "engines": { 319 | "node": ">=18.0.0", 320 | "npm": ">=8.0.0" 321 | }, 322 | "optionalDependencies": { 323 | "@rollup/rollup-android-arm-eabi": "4.9.1", 324 | "@rollup/rollup-android-arm64": "4.9.1", 325 | "@rollup/rollup-darwin-arm64": "4.9.1", 326 | "@rollup/rollup-darwin-x64": "4.9.1", 327 | "@rollup/rollup-linux-arm-gnueabihf": "4.9.1", 328 | "@rollup/rollup-linux-arm64-gnu": "4.9.1", 329 | "@rollup/rollup-linux-arm64-musl": "4.9.1", 330 | "@rollup/rollup-linux-riscv64-gnu": "4.9.1", 331 | "@rollup/rollup-linux-x64-gnu": "4.9.1", 332 | "@rollup/rollup-linux-x64-musl": "4.9.1", 333 | "@rollup/rollup-win32-arm64-msvc": "4.9.1", 334 | "@rollup/rollup-win32-ia32-msvc": "4.9.1", 335 | "@rollup/rollup-win32-x64-msvc": "4.9.1", 336 | "fsevents": "~2.3.2" 337 | } 338 | }, 339 | "node_modules/source-map": { 340 | "version": "0.6.1", 341 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 342 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 343 | "dev": true, 344 | "engines": { 345 | "node": ">=0.10.0" 346 | } 347 | }, 348 | "node_modules/source-map-support": { 349 | "version": "0.5.21", 350 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 351 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 352 | "dev": true, 353 | "dependencies": { 354 | "buffer-from": "^1.0.0", 355 | "source-map": "^0.6.0" 356 | } 357 | }, 358 | "node_modules/terser": { 359 | "version": "5.26.0", 360 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", 361 | "integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==", 362 | "dev": true, 363 | "dependencies": { 364 | "@jridgewell/source-map": "^0.3.3", 365 | "acorn": "^8.8.2", 366 | "commander": "^2.20.0", 367 | "source-map-support": "~0.5.20" 368 | }, 369 | "bin": { 370 | "terser": "bin/terser" 371 | }, 372 | "engines": { 373 | "node": ">=10" 374 | } 375 | }, 376 | "node_modules/typescript": { 377 | "version": "5.3.3", 378 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", 379 | "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", 380 | "dev": true, 381 | "bin": { 382 | "tsc": "bin/tsc", 383 | "tsserver": "bin/tsserver" 384 | }, 385 | "engines": { 386 | "node": ">=14.17" 387 | } 388 | } 389 | }, 390 | "dependencies": { 391 | "@jridgewell/gen-mapping": { 392 | "version": "0.3.3", 393 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", 394 | "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", 395 | "dev": true, 396 | "requires": { 397 | "@jridgewell/set-array": "^1.0.1", 398 | "@jridgewell/sourcemap-codec": "^1.4.10", 399 | "@jridgewell/trace-mapping": "^0.3.9" 400 | } 401 | }, 402 | "@jridgewell/resolve-uri": { 403 | "version": "3.1.1", 404 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 405 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", 406 | "dev": true 407 | }, 408 | "@jridgewell/set-array": { 409 | "version": "1.1.2", 410 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 411 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 412 | "dev": true 413 | }, 414 | "@jridgewell/source-map": { 415 | "version": "0.3.5", 416 | "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", 417 | "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", 418 | "dev": true, 419 | "requires": { 420 | "@jridgewell/gen-mapping": "^0.3.0", 421 | "@jridgewell/trace-mapping": "^0.3.9" 422 | } 423 | }, 424 | "@jridgewell/sourcemap-codec": { 425 | "version": "1.4.15", 426 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 427 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", 428 | "dev": true 429 | }, 430 | "@jridgewell/trace-mapping": { 431 | "version": "0.3.20", 432 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", 433 | "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", 434 | "dev": true, 435 | "requires": { 436 | "@jridgewell/resolve-uri": "^3.1.0", 437 | "@jridgewell/sourcemap-codec": "^1.4.14" 438 | } 439 | }, 440 | "@rollup/rollup-android-arm-eabi": { 441 | "version": "4.9.1", 442 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.1.tgz", 443 | "integrity": "sha512-6vMdBZqtq1dVQ4CWdhFwhKZL6E4L1dV6jUjuBvsavvNJSppzi6dLBbuV+3+IyUREaj9ZFvQefnQm28v4OCXlig==", 444 | "dev": true, 445 | "optional": true 446 | }, 447 | "@rollup/rollup-android-arm64": { 448 | "version": "4.9.1", 449 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.1.tgz", 450 | "integrity": "sha512-Jto9Fl3YQ9OLsTDWtLFPtaIMSL2kwGyGoVCmPC8Gxvym9TCZm4Sie+cVeblPO66YZsYH8MhBKDMGZ2NDxuk/XQ==", 451 | "dev": true, 452 | "optional": true 453 | }, 454 | "@rollup/rollup-darwin-arm64": { 455 | "version": "4.9.1", 456 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.1.tgz", 457 | "integrity": "sha512-LtYcLNM+bhsaKAIGwVkh5IOWhaZhjTfNOkGzGqdHvhiCUVuJDalvDxEdSnhFzAn+g23wgsycmZk1vbnaibZwwA==", 458 | "dev": true, 459 | "optional": true 460 | }, 461 | "@rollup/rollup-darwin-x64": { 462 | "version": "4.9.1", 463 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.1.tgz", 464 | "integrity": "sha512-KyP/byeXu9V+etKO6Lw3E4tW4QdcnzDG/ake031mg42lob5tN+5qfr+lkcT/SGZaH2PdW4Z1NX9GHEkZ8xV7og==", 465 | "dev": true, 466 | "optional": true 467 | }, 468 | "@rollup/rollup-linux-arm-gnueabihf": { 469 | "version": "4.9.1", 470 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.1.tgz", 471 | "integrity": "sha512-Yqz/Doumf3QTKplwGNrCHe/B2p9xqDghBZSlAY0/hU6ikuDVQuOUIpDP/YcmoT+447tsZTmirmjgG3znvSCR0Q==", 472 | "dev": true, 473 | "optional": true 474 | }, 475 | "@rollup/rollup-linux-arm64-gnu": { 476 | "version": "4.9.1", 477 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.1.tgz", 478 | "integrity": "sha512-u3XkZVvxcvlAOlQJ3UsD1rFvLWqu4Ef/Ggl40WAVCuogf4S1nJPHh5RTgqYFpCOvuGJ7H5yGHabjFKEZGExk5Q==", 479 | "dev": true, 480 | "optional": true 481 | }, 482 | "@rollup/rollup-linux-arm64-musl": { 483 | "version": "4.9.1", 484 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.1.tgz", 485 | "integrity": "sha512-0XSYN/rfWShW+i+qjZ0phc6vZ7UWI8XWNz4E/l+6edFt+FxoEghrJHjX1EY/kcUGCnZzYYRCl31SNdfOi450Aw==", 486 | "dev": true, 487 | "optional": true 488 | }, 489 | "@rollup/rollup-linux-riscv64-gnu": { 490 | "version": "4.9.1", 491 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.1.tgz", 492 | "integrity": "sha512-LmYIO65oZVfFt9t6cpYkbC4d5lKHLYv5B4CSHRpnANq0VZUQXGcCPXHzbCXCz4RQnx7jvlYB1ISVNCE/omz5cw==", 493 | "dev": true, 494 | "optional": true 495 | }, 496 | "@rollup/rollup-linux-x64-gnu": { 497 | "version": "4.9.1", 498 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.1.tgz", 499 | "integrity": "sha512-kr8rEPQ6ns/Lmr/hiw8sEVj9aa07gh1/tQF2Y5HrNCCEPiCBGnBUt9tVusrcBBiJfIt1yNaXN6r1CCmpbFEDpg==", 500 | "dev": true, 501 | "optional": true 502 | }, 503 | "@rollup/rollup-linux-x64-musl": { 504 | "version": "4.9.1", 505 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.1.tgz", 506 | "integrity": "sha512-t4QSR7gN+OEZLG0MiCgPqMWZGwmeHhsM4AkegJ0Kiy6TnJ9vZ8dEIwHw1LcZKhbHxTY32hp9eVCMdR3/I8MGRw==", 507 | "dev": true, 508 | "optional": true 509 | }, 510 | "@rollup/rollup-win32-arm64-msvc": { 511 | "version": "4.9.1", 512 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.1.tgz", 513 | "integrity": "sha512-7XI4ZCBN34cb+BH557FJPmh0kmNz2c25SCQeT9OiFWEgf8+dL6ZwJ8f9RnUIit+j01u07Yvrsuu1rZGxJCc51g==", 514 | "dev": true, 515 | "optional": true 516 | }, 517 | "@rollup/rollup-win32-ia32-msvc": { 518 | "version": "4.9.1", 519 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.1.tgz", 520 | "integrity": "sha512-yE5c2j1lSWOH5jp+Q0qNL3Mdhr8WuqCNVjc6BxbVfS5cAS6zRmdiw7ktb8GNpDCEUJphILY6KACoFoRtKoqNQg==", 521 | "dev": true, 522 | "optional": true 523 | }, 524 | "@rollup/rollup-win32-x64-msvc": { 525 | "version": "4.9.1", 526 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.1.tgz", 527 | "integrity": "sha512-PyJsSsafjmIhVgaI1Zdj7m8BB8mMckFah/xbpplObyHfiXzKcI5UOUXRyOdHW7nz4DpMCuzLnF7v5IWHenCwYA==", 528 | "dev": true, 529 | "optional": true 530 | }, 531 | "acorn": { 532 | "version": "8.8.2", 533 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", 534 | "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", 535 | "dev": true 536 | }, 537 | "bluebird": { 538 | "version": "3.7.2", 539 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", 540 | "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", 541 | "dev": true 542 | }, 543 | "buffer-from": { 544 | "version": "1.1.2", 545 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 546 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 547 | "dev": true 548 | }, 549 | "commander": { 550 | "version": "2.20.3", 551 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 552 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 553 | "dev": true 554 | }, 555 | "fsevents": { 556 | "version": "2.3.2", 557 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 558 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 559 | "dev": true, 560 | "optional": true 561 | }, 562 | "generate-changelog": { 563 | "version": "1.8.0", 564 | "resolved": "https://registry.npmjs.org/generate-changelog/-/generate-changelog-1.8.0.tgz", 565 | "integrity": "sha512-msgpxeB75Ziyg3wGsZuPNl7c5RxChMKmYcAX5obnhUow90dBZW3nLic6nxGtst7Bpx453oS6zAIHcX7F3QVasw==", 566 | "dev": true, 567 | "requires": { 568 | "bluebird": "^3.0.6", 569 | "commander": "^2.9.0", 570 | "github-url-from-git": "^1.4.0" 571 | } 572 | }, 573 | "github-url-from-git": { 574 | "version": "1.5.0", 575 | "resolved": "https://registry.npmjs.org/github-url-from-git/-/github-url-from-git-1.5.0.tgz", 576 | "integrity": "sha512-WWOec4aRI7YAykQ9+BHmzjyNlkfJFG8QLXnDTsLz/kZefq7qkzdfo4p6fkYYMIq1aj+gZcQs/1HQhQh3DPPxlQ==", 577 | "dev": true 578 | }, 579 | "rollup": { 580 | "version": "4.9.1", 581 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.1.tgz", 582 | "integrity": "sha512-pgPO9DWzLoW/vIhlSoDByCzcpX92bKEorbgXuZrqxByte3JFk2xSW2JEeAcyLc9Ru9pqcNNW+Ob7ntsk2oT/Xw==", 583 | "dev": true, 584 | "requires": { 585 | "@rollup/rollup-android-arm-eabi": "4.9.1", 586 | "@rollup/rollup-android-arm64": "4.9.1", 587 | "@rollup/rollup-darwin-arm64": "4.9.1", 588 | "@rollup/rollup-darwin-x64": "4.9.1", 589 | "@rollup/rollup-linux-arm-gnueabihf": "4.9.1", 590 | "@rollup/rollup-linux-arm64-gnu": "4.9.1", 591 | "@rollup/rollup-linux-arm64-musl": "4.9.1", 592 | "@rollup/rollup-linux-riscv64-gnu": "4.9.1", 593 | "@rollup/rollup-linux-x64-gnu": "4.9.1", 594 | "@rollup/rollup-linux-x64-musl": "4.9.1", 595 | "@rollup/rollup-win32-arm64-msvc": "4.9.1", 596 | "@rollup/rollup-win32-ia32-msvc": "4.9.1", 597 | "@rollup/rollup-win32-x64-msvc": "4.9.1", 598 | "fsevents": "~2.3.2" 599 | } 600 | }, 601 | "source-map": { 602 | "version": "0.6.1", 603 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 604 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 605 | "dev": true 606 | }, 607 | "source-map-support": { 608 | "version": "0.5.21", 609 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 610 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 611 | "dev": true, 612 | "requires": { 613 | "buffer-from": "^1.0.0", 614 | "source-map": "^0.6.0" 615 | } 616 | }, 617 | "terser": { 618 | "version": "5.26.0", 619 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", 620 | "integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==", 621 | "dev": true, 622 | "requires": { 623 | "@jridgewell/source-map": "^0.3.3", 624 | "acorn": "^8.8.2", 625 | "commander": "^2.20.0", 626 | "source-map-support": "~0.5.20" 627 | } 628 | }, 629 | "typescript": { 630 | "version": "5.3.3", 631 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", 632 | "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", 633 | "dev": true 634 | } 635 | } 636 | } 637 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "super-simple-signal", 3 | "version": "0.4.1", 4 | "description": "A super simple signal implementation in TypeScript for the browser.", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "files": [ 8 | "dist" 9 | ], 10 | "scripts": { 11 | "start": "tsc -w", 12 | "build-dev": "rm -rf ./dist/* && tsc && rollup ./dist/tmp/index.js --file ./dist/index.js --format iife --name SuperSimpleSignal --sourcemap && rm -rf ./dist/tmp", 13 | "build": "rm -rf ./dist/* && tsc && rollup ./dist/tmp/index.js --file ./dist/index.js --format iife --name SuperSimpleSignal --compact && rm -rf ./dist/tmp && terser --compress --mangle -o ./dist/index.js -- ./dist/index.js", 14 | "release:common": "npm run build && git push --follow-tags origin main && npm publish --access public", 15 | "release:patch": "changelog -p && git add CHANGELOG.md && git commit -m 'docs: updated changelog' && npm version patch && npm run release:common", 16 | "release:minor": "changelog -m && git add CHANGELOG.md && git commit -m 'docs: updated changelog' && npm version minor && npm run release:common", 17 | "release:major": "changelog -M && git add CHANGELOG.md && git commit -m 'docs: updated changelog' && npm version major && npm run release:common" 18 | }, 19 | "keywords": [ 20 | "signal", 21 | "typescript", 22 | "browser", 23 | "node", 24 | "event", 25 | "event emitter", 26 | "event dispatcher", 27 | "event bus", 28 | "event system", 29 | "event manager", 30 | "event handler", 31 | "event listener", 32 | "event binding" 33 | ], 34 | "author": "Michael Di Prisco ", 35 | "repository": { 36 | "type": "git", 37 | "url": "git://github.com/Cadienvan/super-simple-signal.git" 38 | }, 39 | "license": "MIT", 40 | "devDependencies": { 41 | "generate-changelog": "^1.8.0", 42 | "rollup": "^4.9.1", 43 | "terser": "^5.26.0", 44 | "typescript": "^5.3.3" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Computed.ts: -------------------------------------------------------------------------------- 1 | import Signal, { defaultOptions, SignalOptions } from "./Signal"; 2 | 3 | // Computed is a signal that is derived from other signals and is updated when any of its dependencies change. 4 | declare class Computed extends Signal { 5 | /** @internal */ 6 | _dependencies: Array; 7 | 8 | /** @internal */ 9 | _fn: (...args: any[]) => T; 10 | 11 | constructor(dependencies: Signal[], fn: () => T, node?: Node, opts?: SignalOptions); 12 | 13 | /** @internal */ 14 | _set(): void; 15 | } 16 | 17 | function Computed( 18 | this: Computed, 19 | dependencies: Signal | Signal[], 20 | fn: (...args: any[]) => any, 21 | node: Node | undefined = undefined, 22 | opts: SignalOptions = defaultOptions 23 | ) { 24 | dependencies = Array.isArray(dependencies) ? dependencies : [dependencies]; 25 | if (!(this instanceof Computed)) { 26 | return new Computed(dependencies, fn, node, opts); 27 | } 28 | 29 | // Call Signal constructor 30 | Signal.call(this, node, undefined, opts); 31 | 32 | this._dependencies = dependencies; 33 | this._fn = fn; 34 | 35 | for (const dependency of dependencies) { 36 | dependency.subscribe(this._set.bind(this)); 37 | } 38 | 39 | this._set(); 40 | } 41 | 42 | Computed.prototype = Object.create(Signal.prototype); 43 | Computed.prototype.constructor = Computed; 44 | 45 | Computed.prototype._set = function () { 46 | this._oldValue = this._value; 47 | this._value = this._fn(this._dependencies.length > 1 ? this._dependencies.map(dependency => dependency.value) : this._dependencies[0].value, this._dependencies.length > 1 ? this._dependencies.map(dependency => dependency._oldValue) : this._dependencies[0]._oldValue, this._oldValue); 48 | this._version++; 49 | this._listeners.forEach(listener => listener(this._value, this._oldValue)); 50 | this._refresh(); 51 | }; 52 | 53 | Object.defineProperty(Computed.prototype, "value", { 54 | set: function (value) { 55 | throw new Error("Computed signals cannot be set"); 56 | }, 57 | get: function () { 58 | return this._value; 59 | }, 60 | }); 61 | export default Computed; 62 | -------------------------------------------------------------------------------- /src/Signal.ts: -------------------------------------------------------------------------------- 1 | export type SignalOptions = { 2 | property: string; 3 | bind: boolean; 4 | bindEvents: string[]; 5 | render: (value: unknown) => string; 6 | allowDirty?: boolean; 7 | }; 8 | 9 | export const defaultOptions = { 10 | property: "innerHTML", 11 | bind: false, 12 | bindEvents: [], 13 | render: (value: any) => (value.hasOwnProperty("toString") ? value.toString() : JSON.stringify(value)) || "", 14 | allowDirty: false, 15 | }; 16 | 17 | declare class Signal { 18 | /** @internal */ 19 | _value: unknown; 20 | 21 | /** @internal */ 22 | _oldValue: unknown; 23 | 24 | /** 25 | * @internal 26 | */ 27 | _version: number; 28 | 29 | /** @internal */ 30 | _node?: Node; 31 | 32 | /** @internal */ 33 | _opts: SignalOptions; 34 | 35 | /** @internal */ 36 | _queuedForRerender: Boolean; 37 | 38 | /** @internal */ 39 | _listeners: Set<(...args: unknown[]) => void>; 40 | 41 | constructor(node?: Node | undefined, value?: T, opts?: SignalOptions); 42 | constructor(value?: T, node?: Node | undefined, opts?: SignalOptions); 43 | 44 | /** @internal */ 45 | _refresh(): boolean; 46 | 47 | /** @internal */ 48 | _setRaw(value: T): void; 49 | 50 | /** @internal */ 51 | _attachNodeEvents(): void; 52 | 53 | subscribe(fn: (value: T) => void): () => void; 54 | 55 | unsubscribe(fn: (value: T) => void): void; 56 | 57 | attachTo(node: Node, property?: string): void; 58 | 59 | copyTo(node: Node, opts?: SignalOptions, keepInSync?: boolean): Signal; 60 | 61 | detach(): void; 62 | 63 | toString(): string; 64 | 65 | get value(): T; 66 | set value(value: T); 67 | } 68 | 69 | function Signal(this: Signal, node: Node | undefined = undefined, value: unknown = undefined, opts: SignalOptions = defaultOptions) { 70 | opts = { ...defaultOptions, ...opts }; 71 | if (!(this instanceof Signal)) { 72 | return new Signal(node, value, opts); 73 | } 74 | 75 | if (!(node instanceof Node)) { 76 | // We can assume that the first argument is the value 77 | value = node; 78 | node = undefined; 79 | } 80 | 81 | this._value = value; 82 | this._oldValue = undefined; 83 | this._version = 0; 84 | this._node = node; 85 | this._opts = opts; 86 | this._queuedForRerender = false; 87 | this._listeners = new Set(); 88 | 89 | if (node && value) { 90 | node[opts.property] = value; 91 | } else if (node && !value) { 92 | this._value = node[opts.property]; 93 | } 94 | 95 | if (node && opts.bind) { 96 | this._attachNodeEvents(); 97 | } else if (node && !opts.bind) { 98 | this._refresh(); 99 | } 100 | return this; 101 | } 102 | 103 | Signal.prototype = { 104 | _value: undefined, 105 | _oldValue: undefined, 106 | _version: 0, 107 | _node: undefined, 108 | _opts: defaultOptions, 109 | _queuedForRerender: false, 110 | _listeners: new Set(), 111 | 112 | _refresh() { 113 | if (this._node) { 114 | this._node[this._opts.property] = this._opts.render(this._value); 115 | return true; 116 | } 117 | return false; 118 | }, 119 | 120 | _setRaw(value: unknown) { 121 | this._oldValue = this._value; 122 | this._value = value; 123 | this._version += 1; 124 | this._listeners.forEach(listener => listener(value, this._oldValue)); 125 | }, 126 | 127 | _attachNodeEvents() { 128 | this._node?.addEventListener("destroy", () => (this._node = undefined)); 129 | this._node?.addEventListener("remove", () => (this._node = undefined)); 130 | for (const event of this._opts.bindEvents) { 131 | this._node?.addEventListener(event, () => { 132 | this._setRaw(this._node?.[this._opts.property]); 133 | }); 134 | } 135 | }, 136 | 137 | subscribe(fn: (value: unknown) => void) { 138 | this._listeners.add(fn); 139 | return () => this.unsubscribe(fn); 140 | }, 141 | 142 | unsubscribe(fn: (value: unknown) => void) { 143 | this._listeners.delete(fn); 144 | }, 145 | 146 | attachTo(node: Node, property: string) { 147 | property = property || this._opts.property; 148 | this._node = node; 149 | node[property] = this._value; 150 | }, 151 | 152 | copyTo(node: Node, opts: SignalOptions, keepInSync: boolean = true) { 153 | const signal = new Signal(node, this._value, opts); 154 | if (keepInSync) this.subscribe(value => (signal.value = value)); 155 | return signal; 156 | }, 157 | 158 | detach() { 159 | this._node = undefined; 160 | }, 161 | 162 | toString() { 163 | return String(this._value); 164 | }, 165 | 166 | get value() { 167 | return this._value; 168 | }, 169 | 170 | set value(value: unknown) { 171 | if (this._value === value && !this._opts.allowDirty) return; 172 | this._oldValue = this._value; 173 | this._value = value; 174 | this._version += 1; 175 | this._listeners.forEach(fn => fn(value, this._oldValue)); 176 | if (!this._queuedForRerender) { 177 | this._queuedForRerender = true; 178 | window.queueMicrotask(() => { 179 | this._queuedForRerender = false; 180 | this._refresh(); 181 | }); 182 | } 183 | }, 184 | }; 185 | 186 | export default Signal; 187 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import Signal from "./Signal"; 2 | import Computed from "./Computed"; 3 | 4 | declare global { 5 | interface Window { 6 | Signal: typeof Signal; 7 | Computed: typeof Computed; 8 | } 9 | } 10 | 11 | window.Signal = Signal; 12 | window.Computed = Computed; 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "es6", 5 | "lib": ["es2015", "dom"], 6 | "outDir": "./dist/tmp", 7 | "moduleResolution": "node", 8 | "sourceMap": true, 9 | "declaration": true, 10 | "strict": true, 11 | "noImplicitAny": false 12 | }, 13 | "include": ["src/**/*.ts"], 14 | "exclude": ["node_modules", "dist"] 15 | } 16 | --------------------------------------------------------------------------------