├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── package.json ├── renovate.json ├── src ├── lib │ └── runExclusive.ts └── test │ ├── index.ts │ ├── legacyTests │ ├── index.ts │ ├── test1.ts │ ├── test10.ts │ ├── test11.ts │ ├── test12.ts │ ├── test13.ts │ ├── test14.ts │ ├── test15.ts │ ├── test16.ts │ ├── test17.ts │ ├── test18.ts │ ├── test19.ts │ ├── test2.ts │ ├── test20.ts │ ├── test21.ts │ ├── test3.ts │ ├── test4.ts │ ├── test5.ts │ ├── test6.ts │ ├── test7.ts │ ├── test8.ts │ └── test9.ts │ ├── mod.ts │ ├── test1.ts │ ├── test10.ts │ ├── test11.ts │ ├── test12.ts │ ├── test13.ts │ ├── test14.ts │ ├── test15.ts │ ├── test16.ts │ ├── test17.ts │ ├── test18.ts │ ├── test2.ts │ ├── test3.ts │ ├── test4.ts │ ├── test5.ts │ ├── test6.ts │ ├── test7.ts │ ├── test8.ts │ ├── test9.ts │ ├── testMem1.ts │ └── testMem2.ts ├── tea.yaml ├── tsconfig.json └── yarn.lock /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | 12 | test_node: 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | node: [ '14', '15' ,'16', '17' ] 17 | os: [ windows-latest, ubuntu-latest ] 18 | name: Test with Node v${{ matrix.node }} on ${{ matrix.os }} 19 | steps: 20 | - uses: actions/checkout@v3 21 | - uses: actions/setup-node@v3 22 | with: 23 | node-version: ${{ matrix.node }} 24 | - uses: bahmutov/npm-install@v1 25 | - run: yarn build 26 | env: 27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 28 | - run: yarn test:node 29 | test_deno: 30 | runs-on: ubuntu-latest 31 | name: test with Deno 32 | steps: 33 | - uses: actions/checkout@v3 34 | - uses: actions/setup-node@v3 35 | with: 36 | node-version: '15' 37 | - name: Cache 38 | uses: actions/cache@v3 39 | with: 40 | path: ~/.cache/deno 41 | key: deno-${{ runner.os }}-${{ hashFiles('deno-lock.json') }} 42 | restore-keys: | 43 | deno-${{ runner.os }}-${{ hashFiles('deno-lock.json') }} 44 | deno-${{ runner.os }}- 45 | deno- 46 | - uses: denoland/setup-deno@v1 47 | with: 48 | deno-version: v1.x 49 | - run: deno --version 50 | - uses: bahmutov/npm-install@v1 51 | - run: yarn build 52 | env: 53 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 54 | - run: yarn test:deno 55 | check_if_version_upgraded: 56 | name: Check if version upgrade 57 | # We run this only if it's a push on the default branch or if it's a PR from a 58 | # branch (meaning not a PR from a fork). It would be more straightforward to test if secrets.NPM_TOKEN is 59 | # defined but GitHub Action don't allow it yet. 60 | if: | 61 | github.event_name == 'push' || 62 | github.event.pull_request.head.repo.owner.login == github.event.pull_request.base.repo.owner.login 63 | runs-on: ubuntu-latest 64 | needs: 65 | - test_node 66 | - test_deno 67 | outputs: 68 | from_version: ${{ steps.step1.outputs.from_version }} 69 | to_version: ${{ steps.step1.outputs.to_version }} 70 | is_upgraded_version: ${{ steps.step1.outputs.is_upgraded_version }} 71 | is_pre_release: ${{steps.step1.outputs.is_pre_release }} 72 | steps: 73 | - uses: garronej/ts-ci@v2.1.0 74 | id: step1 75 | with: 76 | action_name: is_package_json_version_upgraded 77 | branch: ${{ github.head_ref || github.ref }} 78 | 79 | publish: 80 | runs-on: ubuntu-latest 81 | needs: 82 | - check_if_version_upgraded 83 | # We create a release only if the version have been upgraded and we are on the main branch 84 | # or if we are on a branch of the repo that has an PR open on main. 85 | if: | 86 | needs.check_if_version_upgraded.outputs.is_upgraded_version == 'true' && 87 | ( 88 | github.event_name == 'push' || 89 | needs.check_if_version_upgraded.outputs.is_pre_release == 'true' 90 | ) 91 | steps: 92 | - uses: actions/checkout@v3 93 | with: 94 | fetch-depth: 0 95 | ref: ${{ github.ref }} 96 | - run: rm -r .github 97 | - name: Remove tmp_branch if it exists 98 | run: git push origin :tmp_branch || true 99 | - run: git checkout -b tmp_branch 100 | - uses: actions/setup-node@v3 101 | with: 102 | registry-url: https://registry.npmjs.org/ 103 | - uses: bahmutov/npm-install@v1 104 | - run: yarn build 105 | env: 106 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 107 | - run: | 108 | npx -y -p denoify@1.4.8 enable_short_npm_import_path 109 | npx -y -p denoify@1.4.8 remove_deno_dist_from_gitignore 110 | env: 111 | DRY_RUN: "0" 112 | - run: | 113 | if [ "$(npm show . version)" = "$VERSION" ]; then 114 | echo "This version is already published" 115 | exit 0 116 | fi 117 | if [ "$NODE_AUTH_TOKEN" = "" ]; then 118 | echo "Can't publish on NPM, You must first create a secret called NPM_TOKEN that contains your NPM auth token. https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets" 119 | false 120 | fi 121 | EXTRA_ARGS="" 122 | if [ "$IS_PRE_RELEASE" = "true" ]; then 123 | EXTRA_ARGS="--tag next" 124 | fi 125 | npm publish $EXTRA_ARGS 126 | env: 127 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 128 | VERSION: ${{ needs.check_if_version_upgraded.outputs.to_version }} 129 | IS_PRE_RELEASE: ${{ needs.check_if_version_upgraded.outputs.is_pre_release }} 130 | - run: | 131 | git config --global user.name "actions" 132 | git config --global user.email actions@github.com 133 | git add -A 134 | git commit -am "Adding deno distribution files and moving files from /dist to /" 135 | git push origin tmp_branch 136 | - uses: softprops/action-gh-release@v1 137 | with: 138 | name: Release v${{ needs.check_if_version_upgraded.outputs.to_version }} 139 | tag_name: v${{ needs.check_if_version_upgraded.outputs.to_version }} 140 | target_commitish: tmp_branch 141 | generate_release_notes: false 142 | draft: false 143 | prerelease: ${{ needs.check_if_version_upgraded.outputs.is_pre_release == 'true' }} 144 | env: 145 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 146 | - name: Remove tmp_branch 147 | run: git push origin :tmp_branch -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | .DS_Store 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # nyc test coverage 19 | .nyc_output 20 | 21 | 22 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 23 | .grunt 24 | 25 | # node-waf configuration 26 | .lock-wscript 27 | 28 | # Compiled binary addons (http://nodejs.org/api/addons.html) 29 | build/Release 30 | 31 | # Dependency directories 32 | node_modules 33 | jspm_packages 34 | 35 | # Optional npm cache directory 36 | .npm 37 | 38 | # Optional REPL history 39 | .node_repl_history 40 | 41 | dist/test 42 | .vscode 43 | 44 | /dist 45 | /deno_dist 46 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### **2.2.15** (2022-07-24) 2 | 3 | - Update dependency minimal-polyfills to ^2.2.1 4 | - Merge pull request #19 from garronej/renovate_npm-minimist-vulnerability 5 | 6 | Update dependency minimist [SECURITY] 7 | - Merge pull request #18 from garronej/renovate_npm-glob-parent-vulnerability 8 | 9 | Update dependency glob-parent to 5.1.2 [SECURITY] 10 | - Update dependency minimist [SECURITY] 11 | - Update dependency glob-parent to 5.1.2 [SECURITY] 12 | - Merge pull request #16 from garronej/renovate/configure 13 | 14 | Configure Renovate 15 | - Update renovate.json 16 | - Add renovate.json 17 | - Merge pull request #15 from garronej/dependabot/npm_and_yarn/terser-4.8.1 18 | 19 | Bump terser from 4.6.13 to 4.8.1 20 | - Merge pull request #9 from garronej/dependabot/npm_and_yarn/shelljs-0.8.5 21 | 22 | Bump shelljs from 0.8.4 to 0.8.5 23 | - Update README.md 24 | - Merge pull request #7 from garronej/dependabot/npm_and_yarn/elliptic-6.5.4 25 | 26 | Bump elliptic from 6.5.3 to 6.5.4 27 | - Bump elliptic from 6.5.3 to 6.5.4 28 | 29 | Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.3 to 6.5.4. 30 | - [Release notes](https://github.com/indutny/elliptic/releases) 31 | - [Commits](https://github.com/indutny/elliptic/compare/v6.5.3...v6.5.4) 32 | 33 | Signed-off-by: dependabot[bot] 34 | - Merge pull request #6 from garronej/dependabot/npm_and_yarn/lodash-4.17.21 35 | 36 | Bump lodash from 4.17.20 to 4.17.21 37 | - Bump lodash from 4.17.20 to 4.17.21 38 | 39 | Bumps [lodash](https://github.com/lodash/lodash) from 4.17.20 to 4.17.21. 40 | - [Release notes](https://github.com/lodash/lodash/releases) 41 | - [Commits](https://github.com/lodash/lodash/compare/4.17.20...4.17.21) 42 | 43 | Signed-off-by: dependabot[bot] 44 | - Merge pull request #5 from garronej/dependabot/npm_and_yarn/node-fetch-2.6.1 45 | 46 | Bump node-fetch from 2.6.0 to 2.6.1 47 | 48 | ### **2.2.14** (2020-08-27) 49 | 50 | - Do not use .ts files as types definition, use .d.ts files instead #4 51 | 52 | ### **2.2.12** (2020-08-10) 53 | 54 | - Re-publish for deno.land/x, again (nothing changed) 55 | 56 | ### **2.2.12** (2020-08-10) 57 | 58 | - Re-publish for deno.land/x (nothing changed) 59 | 60 | ### **2.2.11** (2020-08-10) 61 | 62 | - merge dependabot PR 63 | - Merge pull request #3 from garronej/dependabot/npm_and_yarn/lodash-4.17.19 64 | 65 | Bump lodash from 4.17.15 to 4.17.19 66 | 67 | ### **2.2.9** (2020-08-05) 68 | 69 | - Switch back to tag version name prefixed with 'v' 70 | 71 | ### **2.2.8** (2020-07-19) 72 | 73 | - Support --isolatedModules flag 74 | 75 | ### **2.2.7** (2020-05-25) 76 | 77 | - FIX: Go to definition redirect to source .ts file ( instead of .d.ts ) 78 | 79 | ### **2.2.6** (2020-05-25) 80 | 81 | - Include minified CDN build 82 | - Fix link in readme 83 | 84 | ### **2.2.5** (2020-05-25) 85 | 86 | - update dep depencencies 87 | - Rename CDN build umd_bundle.js -> bundle.js 88 | 89 | ### **2.2.4** (2020-05-23) 90 | 91 | - Fix links 92 | 93 | ### **2.2.3** (2020-05-23) 94 | 95 | - Use mod.ts instead of deno_index.ts to align with conventions 96 | - Re-enable source map generation 97 | 98 | ### **2.2.2** (2020-05-23) 99 | 100 | - Minor readme changes 101 | 102 | ## **2.2.1** (2020-05-23) 103 | 104 | - Minor readme changes 105 | 106 | ## **2.2.0** (2020-05-23) 107 | 108 | - Global exposed by CDN build changed from run_exclusive to runExclusive for consistency 109 | - Fix source map. Go to definition redirect to source .ts file ( instead of .d.ts) 110 | - Adding CI badge 111 | 112 | ### **2.1.18** (2020-05-21) 113 | 114 | - include CDN build 115 | 116 | 117 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | 4 | Copyright (c) 2020 GitHub user u/garronej 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 |

5 | ⚡🔒 Generate functions that do not allow parallel executions 🔒 ⚡ 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |

27 | 28 | --- 29 | 30 | Let you create functions that enforce no more than one execution happens at the same time. 31 | If the function is called again while there is already an execution ongoing the new call will be queued and executed once all the queued calls have completed. 32 | 33 | This is a higher-level approach to the problem addressed by [`DirtyHairy/async-mutex`](https://www.npmjs.com/package/async-mutex). 34 | 35 | Suitable for any JS runtime env (deno, node, old browser, react-native ...) 36 | - ✅ It is both a [Deno](https://deno.land/x/run_exclusive) and an [NPM](https://www.npmjs.com/run-exclusive) module. 37 | - ✅ Lightweight, no dependency. 38 | - ✅ No polyfills needed, the NPM module is transpiled down to ES3 39 | 40 | # Examples 41 | 42 | ## Basic example 43 | 44 | ```typescript 45 | import * as runExclusive from "run-exclusive"; 46 | 47 | const f= runExclusive.build(async ()=> { 48 | 49 | await new Promise(resolve=> setTimeout(resolve, 1000)); 50 | 51 | console.log("Hello world"); 52 | 53 | }); 54 | 55 | f(); 56 | f(); 57 | ``` 58 | Result: 59 | ```bash 60 | # One second.. 61 | Hello World 62 | # One second 63 | Hello World 64 | ``` 65 | 66 | ## Group of mutually run exclusive functions 67 | 68 | ```typescript 69 | import * as runExclusive from "run-exclusive"; 70 | 71 | const groupRef= runExclusive.createGroupRef(); 72 | 73 | const f1= runExclusive.build(groupRef, async ()=> { 74 | 75 | await new Promise(resolve=> setTimeout(resolve, 1000)); 76 | 77 | console.log("Hello world 1"); 78 | 79 | }); 80 | 81 | const f2= runExclusive.build(groupRef, async ()=> { 82 | 83 | await new Promise(resolve=> setTimeout(resolve, 1000)); 84 | 85 | console.log("Hello world 2"); 86 | 87 | }); 88 | 89 | f1(); 90 | f2(); 91 | ``` 92 | Result: 93 | ```bash 94 | # One second.. 95 | Hello World 1 96 | # One second 97 | Hello World 2 98 | ``` 99 | 100 | # Install / Import 101 | 102 | ## Deno 103 | 104 | ```typescript 105 | import * as runExclusive from "https://deno.land/x/run_exclusive/mod.ts"; 106 | ``` 107 | 108 | ## Other javascript runtime environnement: 109 | 110 | ```bash 111 | $ npm install --save run-exclusive 112 | ``` 113 | ```typescript 114 | import * as runExclusive from "run-exclusive"; 115 | ``` 116 | 117 | # Try it now 118 | 119 | Thanks to Stackblitz you can try this lib within your browser like if you where in VSCode. 120 | 121 | ![Screenshot 2020-02-14 at 12 48 04](https://user-images.githubusercontent.com/6702424/74528376-70531280-4f28-11ea-9545-46d258b74454.png) 122 | 123 | [__Run the example__](https://stackblitz.com/edit/run-exclusive-hello-world?embed=1&file=index.ts) 124 | 125 | # Table of content 126 | 127 | - [Examples](#examples) 128 | - [Basic example](#basic-example) 129 | - [Group of mutually run exclusive functions](#group-of-mutually-run-exclusive-functions) 130 | - [Install / Import](#install--import) 131 | - [Deno](#deno) 132 | - [Other javascript runtime environnement:](#other-javascript-runtime-environnement) 133 | - [Import from HTML, with CDN](#import-from-html-with-cdn) 134 | - [Try it now](#try-it-now) 135 | - [Table of content](#table-of-content) 136 | - [Documentation](#documentation) 137 | - [``build()``](#build) 138 | - [``createGroupRef()``](#creategroupref) 139 | - [``buildMethod()``](#buildmethod) 140 | - [``buildCb()`` and ``buildMethodCb()``](#buildcb-and-buildmethodcb) 141 | - [Queued calls](#queued-calls) 142 | - [``getQueuedCallCount()``](#getqueuedcallcount) 143 | - [``cancelAllQueuedCalls()``](#cancelallqueuedcalls) 144 | - [``isRunning()``](#isrunning) 145 | - [``getPrComplete()``](#getprcomplete) 146 | 147 | # Documentation 148 | 149 | ## ``build()`` 150 | 151 | Let us compare regular functions with `run-exclusive` functions. 152 | 153 | ````typescript 154 | let alphabet= ""; 155 | 156 | //This function wait a random time then append a letter to alphabet. 157 | async function spell(letter: string): Promise{ 158 | 159 | await new Promise( 160 | resolve=> setTimeout( 161 | resolve, 162 | Math.random()*100 163 | ) 164 | ); 165 | 166 | alphabet+=letter; 167 | 168 | return alphabet; 169 | 170 | } 171 | 172 | spell("a"); 173 | spell("b"); 174 | spell("c").then( message => console.log(message)); 175 | //We cant predict what will be printed to the console, 176 | //it can be "c", "ca", "ac", "cb", "bc", "cab", "cba", "bac", "bca", "acb" or "abc" 177 | 178 | ```` 179 | Now the same example using ``run-exclusive``: 180 | 181 | ````typescript 182 | import * as runExclusive from "run-exclusive"; 183 | 184 | let alphabet= ""; 185 | 186 | const spell= runExclusive.build( 187 | async (letter: string): Promise => { 188 | 189 | await new Promise( 190 | resolve=>setTimeout( 191 | resolve, 192 | Math.random()*100 193 | ) 194 | ); 195 | 196 | alphabet+=letter; 197 | 198 | return alphabet; 199 | 200 | } 201 | ); 202 | 203 | spell("a"); 204 | spell("b"); 205 | spell("c").then( message => console.log(message)); // Always prints "abc" 206 | 207 | ```` 208 | 209 | The types definition of the function passed as argument are conserved. 210 | ![Screenshot 2020-02-08 at 15 42 09](https://user-images.githubusercontent.com/6702424/74087111-9a6c8680-4a89-11ea-99f5-d5db809835f2.png) 211 | 212 | ## ``createGroupRef()`` 213 | 214 | To share a unique lock among a group of functions. 215 | 216 | ````typescript 217 | import * as runExclusive from "run-exclusive"; 218 | 219 | let alphabet= ""; 220 | 221 | const groupSpelling= runExclusive.createGroupRef(); 222 | 223 | const spellUpperCase= runExclusive.build(groupSpelling 224 | async (letter: string) => { 225 | 226 | await new Promise(resolve=> setTimeout(resolve, Math.random()*100)); 227 | 228 | alphabet+=letter.toUpperCase(); 229 | 230 | } 231 | ); 232 | 233 | const spellLowerCase= runExclusive.build(groupSpelling 234 | async (letter: string) => { 235 | 236 | await new Promise(resolve=> setTimeout(resolve, Math.random()*100)); 237 | 238 | alphabet+=letter.toLowerCase(); 239 | 240 | } 241 | ); 242 | 243 | spell("a"); 244 | spellUpperCase("b"); 245 | spell("c").then(()=> console.log(alphabet)); //prints "aBc". 246 | ```` 247 | 248 | ## ``buildMethod()`` 249 | 250 | If you define run exclusive class methods chances are you want the lock to be restricted 251 | to the class's object instance. 252 | This is what ``buildMethod()``is for. 253 | 254 | ````typescript 255 | 256 | class Student { 257 | 258 | public alphabet= ""; 259 | 260 | public spell= runExclusive.buildMethod( 261 | async (letter: string) => { 262 | 263 | await new Promise(resolve=> setTimeout(resolve, 1000)); 264 | 265 | this.alphabet+=letter.toLowerCase(); 266 | 267 | } 268 | ); 269 | 270 | } 271 | 272 | const alice= new Student(); 273 | const bob= new Student(); 274 | 275 | alice.spell("A"); 276 | bob.spell("a"); 277 | alice.spell("B"); 278 | bob.spell("b"); 279 | alice.spell("C").then( ()=> console.log(alice.alphabet)); //prints after 3s: "ABC" 280 | bob.spell("c").then( ()=> console.log(bob.alphabet)); //prints after 3s: "abc" 281 | 282 | ```` 283 | 284 | ## ``buildCb()`` and ``buildMethodCb()`` 285 | 286 | `buildCb()` is the pending of `build()` for creating run exclusive functions that complete by invoking a callback. (Instead of resolving a promise). 287 | 288 | The only valid reason to use this instead of `build()` is to be able to retrieve the result synchronously. 289 | 290 | WARNING: If you make the callback optional the argument before it cannot be a function. 291 | Be aware that the compiler won't warn you against it. 292 | Example: ``(getLetter: ()=> string, callback?: (message: string)=> voidA) => {..}`` 293 | is NOT a valid function to pass to ``buildCb()`` or ``buildMethodCb()``. 294 | *Thanks @AnyhowStep* 295 | 296 | WARNING: The function should never throw as the exception wont be catchable. 297 | 298 | ````typescript 299 | 300 | let alphabet= ""; 301 | 302 | const spell= runExclusive.buildCb( 303 | (letter: string, callback?: (message: string)=> void) => { 304 | 305 | setTimeout(()=>{ 306 | 307 | alphabet+= letter; 308 | 309 | /* 310 | Callback must always be called, event if the user 311 | does not provide one, it is the only way for the module 312 | to know that the function has completed it's execution. 313 | You can assume that the callback function is not undefined. 314 | To tell if the user has provided à callback you can access (callback as any).hasCallback; 315 | */ 316 | callback!(alphabet); 317 | 318 | }, Math.rand()*100); 319 | 320 | } 321 | }; 322 | 323 | spell("a"); 324 | spell("b"); 325 | spell("c", message => console.log(message)); // prints "abc" 326 | 327 | ```` 328 | 329 | NOTE: ``runExclusive.buildMethodCb()`` also available. 330 | 331 | ## Queued calls 332 | 333 | It is possible to check, for a given run exclusive function, if there is currently 334 | an ongoing execution and how many calls are queued. 335 | It is also possible to cancel the queued calls. 336 | 337 | ### ``getQueuedCallCount()`` 338 | 339 | Get the number of queued call of a run-exclusive function. 340 | Note that if you call a runExclusive function and call this 341 | directly after it will return 0 as there is one function call 342 | execution ongoing but 0 queued. 343 | 344 | The classInstanceObject parameter is to provide only for the run-exclusive 345 | function created with 'buildMethod[Cb]. 346 | 347 | ```typescript 348 | export declare function getQueuedCallCount( 349 | runExclusiveFunction: Function, 350 | classInstanceObject?: Object 351 | ): number; 352 | ``` 353 | 354 | ### ``cancelAllQueuedCalls()`` 355 | Cancel all queued calls of a run-exclusive function. 356 | Note that the current running call will not be cancelled. 357 | 358 | The classInstanceObject parameter is to provide only for the run-exclusive 359 | function created with 'buildMethod[Cb]. 360 | ```typescript 361 | export declare function cancelAllQueuedCalls( 362 | runExclusiveFunction: Function, 363 | classInstanceObject?: Object 364 | ): number; 365 | ``` 366 | ### ``isRunning()`` 367 | 368 | Tell if a run-exclusive function has an instance of it's call currently being 369 | performed. 370 | 371 | The classInstanceObject parameter is to provide only for the run-exclusive 372 | function created with 'buildMethod[Cb]. 373 | ```typescript 374 | export declare function isRunning( 375 | runExclusiveFunction: Function, 376 | classInstanceObject?: Object 377 | ): boolean; 378 | ``` 379 | 380 | ### ``getPrComplete()`` 381 | 382 | Return a promise that resolve when all the current queued call of a runExclusive functions have completed. 383 | The classInstanceObject parameter is to provide only for the run-exclusive 384 | function created with 'buildMethod[Cb]. 385 | 386 | ````typescript 387 | export declare function getPrComplete( 388 | runExclusiveFunction: Function, 389 | classInstanceObject?: Object 390 | ): Promise; 391 | ```` 392 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "run-exclusive", 3 | "version": "2.2.19", 4 | "description": "Generate functions that do not allow parallel executions", 5 | "repository": { 6 | "type": "git", 7 | "url": "git://github.com/garronej/run_exclusive.git" 8 | }, 9 | "scripts": { 10 | "test:node": "node ./dist/test", 11 | "test:deno": "deno run --reload ./deno_dist/test/mod.ts", 12 | "test": "npm run test:node && npm run test:deno", 13 | "build": "tsc && denoify" 14 | }, 15 | "main": "dist/lib/runExclusive.js", 16 | "types": "dist/lib/runExclusive.d.ts", 17 | "author": "u/garronej", 18 | "license": "MIT", 19 | "keywords": [ 20 | "deno", 21 | "mutex", 22 | "async-await", 23 | "lock", 24 | "callback", 25 | "promise", 26 | "typescript", 27 | "type-safe" 28 | ], 29 | "homepage": "https://github.com/garronej/run_exclusive", 30 | "dependencies": { 31 | "minimal-polyfills": "^2.2.3" 32 | }, 33 | "devDependencies": { 34 | "@types/node": "^10.3.2", 35 | "evt": "^2.4.18", 36 | "typescript": "^3.9.7", 37 | "denoify": "^1.5.3" 38 | }, 39 | "files": [ 40 | "src/", 41 | "!src/test/", 42 | "dist/", 43 | "!dist/test/", 44 | "!dist/tsconfig.tsbuildinfo" 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:base"], 4 | "rangeStrategy": "bump", 5 | "ignorePaths": [".github/**"], 6 | "bumpVersion": "patch", 7 | "vulnerabilityAlerts": { 8 | "enabled": false 9 | }, 10 | "packageRules": [ 11 | { 12 | "packagePatterns": ["*"], 13 | "excludePackagePatterns": [ "minimal-polyfills" ], 14 | "enabled": false 15 | }, 16 | { 17 | "packagePatterns": [ "minimal-polyfills" ], 18 | "matchUpdateTypes": ["minor", "patch"], 19 | "automerge": true, 20 | "automergeType": "branch", 21 | "branchName": "renovate_garronej_dependencies_update" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /src/lib/runExclusive.ts: -------------------------------------------------------------------------------- 1 | // @denoify-line-ignore 2 | import { Polyfill as WeakMap } from "minimal-polyfills/WeakMap"; 3 | 4 | class ExecQueue { 5 | 6 | public readonly queuedCalls: Function[]=[]; 7 | 8 | public isRunning: boolean= false; 9 | 10 | //TODO: move where it is used. 11 | public cancelAllQueuedCalls(): number { 12 | 13 | let n: number; 14 | 15 | this.queuedCalls.splice(0, n=this.queuedCalls.length); 16 | 17 | return n; 18 | 19 | } 20 | 21 | public prComplete: Promise= Promise.resolve(); 22 | 23 | 24 | } 25 | 26 | 27 | const globalContext: Object = {}; 28 | 29 | const clusters = new WeakMap>(); 30 | 31 | //console.log("Map version"); 32 | //export const clusters = new Map>(); 33 | 34 | 35 | function getOrCreateExecQueue( 36 | context: Object, 37 | groupRef: GroupRef 38 | ): ExecQueue { 39 | 40 | let execQueueByGroup = clusters.get(context); 41 | 42 | if (!execQueueByGroup) { 43 | execQueueByGroup = new WeakMap(); 44 | clusters.set(context, execQueueByGroup); 45 | } 46 | 47 | let execQueue= execQueueByGroup.get(groupRef); 48 | 49 | if (!execQueue){ 50 | execQueue= new ExecQueue(); 51 | execQueueByGroup.set(groupRef, execQueue); 52 | } 53 | 54 | return execQueue; 55 | 56 | } 57 | 58 | export type GroupRef = never[]; 59 | 60 | export function createGroupRef(): GroupRef { 61 | return new Array(0); 62 | } 63 | 64 | /** 65 | * Built a run-exclusive function from a function that return a promise. 66 | */ 67 | export function build Promise>(fun: T): T; 68 | /** 69 | * Built a run-exclusive function from a function that return a promise. 70 | * 71 | * The group ref parameter is used when in need that two or more different functions do nor run simultaneously. 72 | * Group refs are created by calling createGroupRef(). 73 | */ 74 | export function build Promise>(groupRef: GroupRef, fun: T): T; 75 | export function build(...inputs: any[]): any { 76 | 77 | switch (inputs.length) { 78 | case 1: return buildFnPromise(true, createGroupRef(), inputs[0]); 79 | case 2: return buildFnPromise(true, inputs[0], inputs[1]); 80 | } 81 | 82 | } 83 | 84 | 85 | /** Same as build but to restrict the exclusion to a class instance object. */ 86 | export function buildMethod Promise>(fun: T): T; 87 | export function buildMethod Promise>(groupRef: GroupRef, fun: T): T; 88 | export function buildMethod(...inputs: any[]): any { 89 | 90 | switch (inputs.length) { 91 | case 1: return buildFnPromise(false, createGroupRef(), inputs[0]); 92 | case 2: return buildFnPromise(false, inputs[0], inputs[1]); 93 | } 94 | 95 | } 96 | 97 | /** 98 | * 99 | * Get the number of queued call of a run-exclusive function. 100 | * Note that if you call a runExclusive function and call this 101 | * directly after it will return 0 as there is one function call 102 | * execution ongoing but 0 queued. 103 | * 104 | * The classInstanceObject parameter is to provide only for the run-exclusive 105 | * function created with 'buildMethod[Cb]. 106 | * 107 | * */ 108 | export function getQueuedCallCount( 109 | runExclusiveFunction: Function, 110 | classInstanceObject?: Object 111 | ): number { 112 | 113 | const execQueue= getExecQueueByFunctionAndContext(runExclusiveFunction, classInstanceObject); 114 | 115 | return execQueue?execQueue.queuedCalls.length:0; 116 | 117 | } 118 | 119 | /** 120 | * 121 | * Cancel all queued calls of a run-exclusive function. 122 | * Note that the current running call will not be cancelled. 123 | * 124 | * The classInstanceObject parameter is to provide only for the run-exclusive 125 | * function created with 'buildMethod[Cb]. 126 | * 127 | */ 128 | export function cancelAllQueuedCalls( 129 | runExclusiveFunction: Function, 130 | classInstanceObject?: Object 131 | ): number { 132 | 133 | const execQueue= getExecQueueByFunctionAndContext(runExclusiveFunction, classInstanceObject); 134 | 135 | return execQueue?execQueue.cancelAllQueuedCalls():0; 136 | 137 | } 138 | 139 | /** 140 | * Tell if a run-exclusive function has an instance of it's call currently being 141 | * performed. 142 | * 143 | * The classInstanceObject parameter is to provide only for the run-exclusive 144 | * function created with 'buildMethod[Cb]. 145 | */ 146 | export function isRunning( 147 | runExclusiveFunction: Function, 148 | classInstanceObject?: Object 149 | ): boolean { 150 | 151 | const execQueue= getExecQueueByFunctionAndContext(runExclusiveFunction, classInstanceObject); 152 | 153 | return execQueue?execQueue.isRunning:false; 154 | 155 | } 156 | 157 | /** 158 | * Return a promise that resolve when all the current queued call of a runExclusive functions 159 | * have completed. 160 | * 161 | * The classInstanceObject parameter is to provide only for the run-exclusive 162 | * function created with 'buildMethod[Cb]. 163 | */ 164 | export function getPrComplete( 165 | runExclusiveFunction: Function, 166 | classInstanceObject?: Object 167 | ): Promise{ 168 | 169 | const execQueue= getExecQueueByFunctionAndContext(runExclusiveFunction, classInstanceObject); 170 | 171 | return execQueue?execQueue.prComplete:Promise.resolve(); 172 | 173 | } 174 | 175 | const groupByRunExclusiveFunction= new WeakMap(); 176 | 177 | function getExecQueueByFunctionAndContext( 178 | runExclusiveFunction: Function, 179 | context = globalContext 180 | ): ExecQueue | undefined { 181 | 182 | const groupRef= groupByRunExclusiveFunction.get(runExclusiveFunction); 183 | 184 | if( !groupRef ){ 185 | throw Error("Not a run exclusiveFunction"); 186 | } 187 | 188 | const execQueueByGroup= clusters.get(context); 189 | 190 | if( !execQueueByGroup ){ 191 | return undefined; 192 | } 193 | 194 | return execQueueByGroup.get(groupRef)!; 195 | 196 | } 197 | 198 | 199 | function buildFnPromise Promise>( 200 | isGlobal: boolean, 201 | groupRef: GroupRef, 202 | fun: T 203 | ): T { 204 | 205 | let execQueue: ExecQueue; 206 | 207 | const runExclusiveFunction = (function (this: any, ...inputs) { 208 | 209 | if (!isGlobal) { 210 | 211 | if (!(this instanceof Object)) { 212 | throw new Error("Run exclusive, should be an object"); 213 | } 214 | 215 | execQueue = getOrCreateExecQueue(this, groupRef); 216 | 217 | } 218 | 219 | return new Promise((resolve, reject) => { 220 | 221 | let onPrCompleteResolve: () => void; 222 | 223 | execQueue.prComplete = new Promise(resolve => 224 | onPrCompleteResolve = () => resolve() 225 | ); 226 | 227 | const onComplete = (result: { data: any } | { reason: any }) => { 228 | 229 | onPrCompleteResolve(); 230 | 231 | execQueue.isRunning = false; 232 | 233 | if (execQueue.queuedCalls.length) { 234 | execQueue.queuedCalls.shift()!(); 235 | } 236 | 237 | if ("data" in result) { 238 | resolve(result.data); 239 | } else { 240 | reject(result.reason); 241 | } 242 | 243 | }; 244 | 245 | (function callee(this: any,...inputs: any[]) { 246 | 247 | if (execQueue.isRunning) { 248 | execQueue.queuedCalls.push(() => callee.apply(this, inputs)); 249 | return; 250 | } 251 | 252 | execQueue.isRunning = true; 253 | 254 | try { 255 | 256 | fun.apply(this, inputs) 257 | .then(data => onComplete({ data })) 258 | .catch(reason => onComplete({ reason })) 259 | ; 260 | 261 | } catch (error) { 262 | 263 | onComplete({ "reason": error }); 264 | 265 | } 266 | 267 | }).apply(this, inputs); 268 | 269 | }); 270 | 271 | }) as T; 272 | 273 | if (isGlobal) { 274 | 275 | execQueue = getOrCreateExecQueue(globalContext, groupRef); 276 | 277 | } 278 | 279 | groupByRunExclusiveFunction.set(runExclusiveFunction, groupRef); 280 | 281 | return runExclusiveFunction; 282 | 283 | } 284 | 285 | /** 286 | * (Read all before using) 287 | * 288 | * The pending of 'build' for creating run exclusive functions that complete 289 | * via calling a callback function. (Instead of returning a promise). 290 | * 291 | * The only valid reason to use this instead of ``build()`` is to be able to 292 | * retrieve the result and/or release the lock synchronously when it's possible. 293 | * 294 | * If you want the callback to be optional it is possible to 295 | * define the function as such: 296 | * ``const myRunExclusiveFunction = buildCb((callback?)=> { ... });`` 297 | * Anyway you must call it every time and assume it has been defined: 298 | * ``callback!(...)``. 299 | * 300 | * To see if the user has actually provided a callback you can access the hidden property 301 | * ``callback.hasCallback``. 302 | * 303 | * WARNING: You must also make sure, if you use an optional callback 304 | * that the argument before it cannot be a function. 305 | * Be aware that the compiler won't warn you against it. 306 | * Example: ``(getLetter:()=> string, callback?:(res:string)=> void)=>{..}`` 307 | * is NOT a valid function to pass to ``buildCb()`` 308 | * 309 | * WARNING: the source function should NEVER throw exception! 310 | */ 311 | export function buildCb void>(fun: T): T; 312 | export function buildCb void>(groupRef: GroupRef, fun: T): T; 313 | export function buildCb(...inputs: any[]): any { 314 | 315 | switch (inputs.length) { 316 | case 1: return buildFnCallback(true, createGroupRef(), inputs[0]); 317 | case 2: return buildFnCallback(true, inputs[0], inputs[1]); 318 | } 319 | 320 | } 321 | 322 | /** 323 | * (Read all before using) 324 | * 325 | * Pending of 'buildMethod' for function that return with callback instead of promise. 326 | * 327 | * The pending of 'build' for creating run exclusive functions that complete 328 | * via calling a callback function. (Instead of returning a promise). 329 | * 330 | * The only valid reason to use this instead of ``build()`` is to be able to 331 | * retrieve the result and/or release the lock synchronously when it's possible. 332 | * 333 | * If you want the callback to be optional it is possible to 334 | * define the function as such: 335 | * ``const myRunExclusiveFunction = buildCb((callback?)=> { ... });`` 336 | * Anyway you must call it every time and assume it has been defined: 337 | * ``callback!(...)``. 338 | * 339 | * To see if the user has actually provided a callback you can access the hidden property 340 | * ``callback.hasCallback``. 341 | * 342 | * WARNING: You must also make sure, if you use an optional callback 343 | * that the argument before it cannot be a function. 344 | * Be aware that the compiler won't warn you against it. 345 | * Example: ``(getLetter:()=> string, callback?:(res:string)=> void)=>{..}`` 346 | * is NOT a valid function to pass to ``buildMethodCb()`` 347 | * 348 | * WARNING: the source function should NEVER throw exception! 349 | * 350 | */ 351 | export function buildMethodCb void>(fun: T): T; 352 | export function buildMethodCb void>(groupRef: GroupRef, fun: T): T; 353 | export function buildMethodCb(...inputs: any[]): any { 354 | 355 | switch (inputs.length) { 356 | case 1: return buildFnCallback(false, createGroupRef(), inputs[0]); 357 | case 2: return buildFnCallback(false, inputs[0], inputs[1]); 358 | } 359 | 360 | } 361 | 362 | function buildFnCallback Promise>( 363 | isGlobal: boolean, 364 | groupRef: GroupRef, 365 | fun: T 366 | ): T { 367 | 368 | let execQueue: ExecQueue; 369 | 370 | const runExclusiveFunction = (function (this: any,...inputs) { 371 | 372 | 373 | if (!isGlobal) { 374 | 375 | if (!(this instanceof Object)) { 376 | throw new Error("Run exclusive, should be an object"); 377 | } 378 | 379 | execQueue = getOrCreateExecQueue(this, groupRef); 380 | 381 | } 382 | 383 | let callback: Function | undefined = undefined; 384 | 385 | if (inputs.length && typeof inputs[inputs.length - 1] === "function") { 386 | callback = inputs.pop(); 387 | } 388 | 389 | let onPrCompleteResolve: () => void; 390 | 391 | execQueue.prComplete = new Promise(resolve => 392 | onPrCompleteResolve = () => resolve() 393 | ); 394 | 395 | const onComplete = (...inputs: any[]) => { 396 | 397 | onPrCompleteResolve(); 398 | 399 | execQueue!.isRunning = false; 400 | 401 | if (execQueue.queuedCalls.length) { 402 | execQueue.queuedCalls.shift()!(); 403 | } 404 | 405 | if (callback) { 406 | callback.apply(this, inputs); 407 | } 408 | 409 | }; 410 | 411 | (onComplete as any).hasCallback = !!callback; 412 | 413 | (function callee(this: any, ...inputs: any[]) { 414 | 415 | if (execQueue.isRunning) { 416 | execQueue.queuedCalls.push(() => callee.apply(this, inputs)); 417 | return; 418 | } 419 | 420 | execQueue.isRunning = true; 421 | 422 | try { 423 | 424 | fun.apply(this, [...inputs, onComplete]); 425 | 426 | } catch (error) { 427 | 428 | error.message += " ( This exception should not have been thrown, miss use of run-exclusive buildCb )"; 429 | 430 | throw error; 431 | 432 | } 433 | 434 | }).apply(this, inputs); 435 | 436 | }) as T; 437 | 438 | if (isGlobal) { 439 | 440 | execQueue = getOrCreateExecQueue(globalContext, groupRef); 441 | 442 | } 443 | 444 | groupByRunExclusiveFunction.set(runExclusiveFunction, groupRef); 445 | 446 | return runExclusiveFunction; 447 | 448 | } 449 | 450 | -------------------------------------------------------------------------------- /src/test/index.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | process.on("unhandledRejection", error=> { 4 | console.log("INTERNAL ERROR"); 5 | console.log(error); 6 | throw error; 7 | }); 8 | 9 | let n = process.argv[2]; 10 | 11 | if (n) { 12 | 13 | require("./test" + n); 14 | 15 | } else { 16 | 17 | require("./legacyTests/index"); 18 | 19 | for (let i = 1; i <= 18; i++) { 20 | 21 | try { 22 | require("./test" + i); 23 | } catch (error) { 24 | 25 | console.log(`Fail test ${i}`); 26 | 27 | throw error; 28 | 29 | 30 | } 31 | 32 | } 33 | 34 | 35 | } 36 | 37 | export {} -------------------------------------------------------------------------------- /src/test/legacyTests/index.ts: -------------------------------------------------------------------------------- 1 | 2 | for (let i = 1; i <= 21; i++) { 3 | 4 | try { 5 | require("./test" + i); 6 | } catch (error) { 7 | 8 | console.log(`Fail test ${i}`); 9 | 10 | throw error; 11 | 12 | 13 | } 14 | 15 | } 16 | 17 | export {} -------------------------------------------------------------------------------- /src/test/legacyTests/test1.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | private alphabetStack = ""; 8 | 9 | public myMethodStack = runExclusive.buildMethodCb( 10 | (char: string, callback?: (alphabet: string) => void): void => { 11 | 12 | setTimeout(() => { 13 | this.alphabetStack += char; 14 | callback!(this.alphabetStack); 15 | }, Math.random() * 1000); 16 | 17 | } 18 | ); 19 | 20 | 21 | } 22 | 23 | let inst = new MyClass(); 24 | 25 | for (let char of ["a", "b", "c", "d", "e", "f"]) 26 | inst.myMethodStack(char, alphabet => console.log(`step ${alphabet}`)); 27 | 28 | 29 | for (let char of ["g", "h", "i"]) 30 | inst.myMethodStack(char); 31 | 32 | inst.myMethodStack("j", alphabet => { 33 | 34 | console.log(`completed ${alphabet}`); 35 | 36 | //cSpell: disable 37 | console.assert(alphabet === "abcdefghij"); 38 | //cSpell: enable 39 | 40 | console.log("PASS"); 41 | 42 | }); 43 | 44 | -------------------------------------------------------------------------------- /src/test/legacyTests/test10.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | 10 | public myMethod = runExclusive.buildMethodCb( 11 | (char: string, callback?: (alphabet: string) => void): void => { 12 | 13 | setTimeout(() => { 14 | this.alphabet += char; 15 | callback!(this.alphabet); 16 | }, 1000); 17 | 18 | } 19 | ); 20 | 21 | 22 | } 23 | 24 | let inst = new MyClass(); 25 | 26 | 27 | setTimeout(() => { 28 | 29 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 3); 30 | 31 | console.assert(inst.alphabet === "ab"); 32 | 33 | runExclusive.cancelAllQueuedCalls(inst.myMethod, inst); 34 | 35 | setTimeout(() => { 36 | 37 | console.assert(inst.alphabet === "abc"); 38 | 39 | console.log("PASS"); 40 | 41 | }, 2000); 42 | 43 | }, 2900); 44 | 45 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 46 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 47 | inst.myMethod("a"); 48 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 49 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true); 50 | 51 | for (let char of ["b", "c", "d", "e", "f"]) 52 | inst.myMethod(char, alphabet => console.log(`step ${alphabet}`)); 53 | 54 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 5); 55 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true); 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/test/legacyTests/test11.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | 10 | public myMethod = runExclusive.buildMethodCb( 11 | (char: string, callback?: (alphabet: string) => void): void => { 12 | 13 | setTimeout(() => { 14 | this.alphabet += char; 15 | callback!(this.alphabet); 16 | }, 1000); 17 | 18 | } 19 | ); 20 | 21 | 22 | } 23 | 24 | class MyClassProxy { 25 | 26 | constructor() { }; 27 | 28 | private myClassInst = new MyClass(); 29 | 30 | public callCount = 0; 31 | 32 | public getAlphabet(): typeof MyClass.prototype.alphabet { 33 | return this.myClassInst.alphabet; 34 | } 35 | 36 | 37 | public myMethod: typeof MyClass.prototype.myMethod = 38 | runExclusive.buildMethodCb( 39 | (...inputs) => { 40 | 41 | this.callCount++; 42 | 43 | return this.myClassInst.myMethod.apply(this.myClassInst, inputs); 44 | 45 | } 46 | ); 47 | 48 | } 49 | 50 | let inst = new MyClassProxy(); 51 | 52 | 53 | setTimeout(() => { 54 | 55 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 3); 56 | 57 | console.assert(inst.getAlphabet() === "ab"); 58 | 59 | runExclusive.cancelAllQueuedCalls(inst.myMethod, inst); 60 | 61 | setTimeout(() => { 62 | 63 | console.assert(inst.getAlphabet() === "abc"); 64 | 65 | console.log("PASS"); 66 | 67 | }, 2000); 68 | 69 | }, 2900); 70 | 71 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 72 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false ); 73 | inst.myMethod("a"); 74 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 75 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true ); 76 | 77 | for (let char of ["b", "c", "d", "e", "f"]) 78 | inst.myMethod(char, alphabet => console.log(`step ${alphabet}`)); 79 | 80 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 5); 81 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true ); 82 | 83 | 84 | console.assert(inst.callCount === 1); 85 | 86 | -------------------------------------------------------------------------------- /src/test/legacyTests/test12.ts: -------------------------------------------------------------------------------- 1 | //Import ExecStack to be able to export stacked function 2 | import * as runExclusive from "../../lib/runExclusive"; 3 | import { Evt } from "evt"; 4 | 5 | export class MyClass { 6 | 7 | constructor() { }; 8 | 9 | public alphabet = ""; 10 | 11 | public myMethod = runExclusive.buildMethodCb( 12 | (char: string, callback?: (alphabet: string) => void): void => { 13 | 14 | setTimeout(() => { 15 | this.alphabet += char; 16 | callback!(this.alphabet); 17 | }, 1000); 18 | 19 | } 20 | ); 21 | 22 | 23 | } 24 | 25 | export class MyClassProxy { 26 | 27 | 28 | private myClassInst: MyClass | undefined = undefined; 29 | 30 | public readonly evtCreate = Evt.create(); 31 | 32 | public getAlphabet(): typeof MyClass.prototype.alphabet { 33 | if (!this.myClassInst) return ""; 34 | else return this.myClassInst.alphabet; 35 | } 36 | 37 | constructor() { 38 | 39 | setTimeout(() => { 40 | this.myClassInst = new MyClass(); 41 | this.evtCreate.post(); 42 | }, 1000); 43 | 44 | } 45 | 46 | public myMethod = runExclusive.buildMethodCb( 47 | function callee(this: any, ...inputs) { 48 | 49 | let self = this as MyClassProxy; 50 | 51 | if (!self.myClassInst) { 52 | 53 | self.evtCreate.attachOnce(() => callee.apply(this, inputs)); 54 | return; 55 | 56 | } 57 | 58 | self.myClassInst.myMethod.apply(self.myClassInst, inputs); 59 | 60 | 61 | } as typeof MyClass.prototype.myMethod); 62 | 63 | } 64 | 65 | let inst = new MyClassProxy(); 66 | 67 | 68 | setTimeout(() => { 69 | 70 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 3); 71 | 72 | console.assert(inst.getAlphabet() === "ab"); 73 | 74 | runExclusive.cancelAllQueuedCalls(inst.myMethod, inst); 75 | 76 | setTimeout(() => { 77 | 78 | console.assert(inst.getAlphabet() === "abc"); 79 | 80 | console.log("PASS"); 81 | 82 | }, 2000); 83 | 84 | }, 2900 + 1000); 85 | 86 | 87 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 88 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 89 | inst.myMethod("a"); 90 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 91 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true); 92 | 93 | 94 | for (let char of ["b", "c", "d", "e", "f"]) 95 | inst.myMethod(char, alphabet => console.log(`step ${alphabet}`)); 96 | 97 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 5); 98 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true); 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /src/test/legacyTests/test13.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | public myMethod = runExclusive.buildMethodCb( 10 | (char: string, callback?: (alphabet: string) => void): void => { 11 | 12 | setTimeout(() => { 13 | this.alphabet += char; 14 | callback!(this.alphabet); 15 | }, 1000); 16 | 17 | } 18 | ); 19 | 20 | 21 | } 22 | 23 | let inst = new MyClass(); 24 | 25 | 26 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 27 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 28 | 29 | inst.myMethod("a", () => { 30 | 31 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 32 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 33 | 34 | console.log("PASS"); 35 | 36 | }); 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/test/legacyTests/test14.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | 10 | public myMethod = runExclusive.buildMethodCb( 11 | (char: string, callback?: (alphabet: string) => void): void => { 12 | 13 | setTimeout(() => { 14 | this.alphabet += char; 15 | callback!(this.alphabet); 16 | }, 1000); 17 | 18 | } 19 | ); 20 | 21 | 22 | } 23 | 24 | let inst = new MyClass(); 25 | 26 | 27 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 28 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 29 | 30 | inst.myMethod("a", () => { 31 | 32 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 33 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true); 34 | 35 | console.log("PASS"); 36 | 37 | }); 38 | inst.myMethod("b"); 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/test/legacyTests/test15.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | 10 | public myMethod = runExclusive.buildMethodCb( 11 | (char: string, callback?: (alphabet: string) => void): void => { 12 | 13 | setTimeout(() => { 14 | this.alphabet += char; 15 | callback!(this.alphabet); 16 | }, 1000); 17 | 18 | } 19 | ); 20 | 21 | 22 | } 23 | 24 | let inst = new MyClass(); 25 | 26 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 27 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 28 | 29 | inst.myMethod("a", () => { 30 | 31 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 1); 32 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true); 33 | 34 | }); 35 | inst.myMethod("b", () => { 36 | 37 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 38 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true); 39 | 40 | }); 41 | inst.myMethod("c", () => { 42 | 43 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 44 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 45 | console.log("PASS"); 46 | 47 | }); 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/test/legacyTests/test16.ts: -------------------------------------------------------------------------------- 1 | //Import ExecStack to be able to export stacked function 2 | import * as runExclusive from "../../lib/runExclusive"; 3 | import { Evt } from "evt"; 4 | 5 | export class MyClass { 6 | 7 | constructor() { }; 8 | 9 | public alphabet = ""; 10 | 11 | 12 | public myMethod = runExclusive.buildMethodCb( 13 | (char: string, callback?: (alphabet: string) => void): void => { 14 | 15 | setTimeout(() => { 16 | this.alphabet += char; 17 | callback!(this.alphabet); 18 | }, 1000); 19 | 20 | } 21 | ); 22 | 23 | 24 | } 25 | 26 | export class MyClassProxy { 27 | 28 | 29 | private myClassInst: MyClass | undefined = undefined; 30 | 31 | public readonly evtCreate = Evt.create(); 32 | 33 | public getAlphabet(): typeof MyClass.prototype.alphabet { 34 | if (!this.myClassInst) return ""; 35 | else return this.myClassInst.alphabet; 36 | } 37 | 38 | constructor() { 39 | 40 | setTimeout(() => { 41 | this.myClassInst = new MyClass(); 42 | this.evtCreate.post(); 43 | }, 1000); 44 | 45 | } 46 | 47 | public myMethod = runExclusive.buildMethodCb( 48 | function callee(this: any,...inputs) { 49 | 50 | let self = this as MyClassProxy; 51 | 52 | if (!self.myClassInst) { 53 | 54 | self.evtCreate.attachOnce(() => callee.apply(this, inputs)); 55 | return; 56 | 57 | } 58 | 59 | self.myClassInst.myMethod.apply(self.myClassInst, inputs); 60 | 61 | 62 | } as typeof MyClass.prototype.myMethod); 63 | 64 | 65 | 66 | } 67 | 68 | let inst = new MyClassProxy(); 69 | 70 | 71 | setTimeout(() => { 72 | 73 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 3); 74 | 75 | console.assert(inst.getAlphabet() === "ab"); 76 | 77 | runExclusive.cancelAllQueuedCalls(inst.myMethod, inst); 78 | 79 | setTimeout(() => { 80 | 81 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 82 | 83 | console.assert(inst.getAlphabet() === "abc"); 84 | 85 | console.log("PASS"); 86 | 87 | }, 2000); 88 | 89 | }, 2900 + 1000); 90 | 91 | 92 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 93 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 94 | inst.myMethod("a"); 95 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 96 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true); 97 | 98 | 99 | for (let char of ["b", "c", "d", "e", "f"]) 100 | inst.myMethod(char, alphabet => console.log(`step ${alphabet}`)); 101 | 102 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 5); 103 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true); 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /src/test/legacyTests/test17.ts: -------------------------------------------------------------------------------- 1 | //Import ExecStack to be able to export stacked function 2 | import * as runExclusive from "../../lib/runExclusive"; 3 | import { Evt } from "evt"; 4 | 5 | export class MyClass { 6 | 7 | constructor() { }; 8 | 9 | public readonly evtNoCallback = new Evt(); 10 | 11 | public myMethod = runExclusive.buildMethodCb( 12 | (message: string, callback?: (alphabet: string) => void): void => { 13 | 14 | setTimeout(() => { 15 | 16 | if (!(callback as any).hasCallback) 17 | this.evtNoCallback.post(message); 18 | 19 | 20 | callback!(message) 21 | }, 1000); 22 | 23 | } 24 | ); 25 | 26 | 27 | } 28 | 29 | 30 | let inst = new MyClass(); 31 | 32 | let success = false 33 | 34 | inst.evtNoCallback.attach(message => { 35 | 36 | console.assert(message === "noCallback"); 37 | 38 | success = true; 39 | 40 | }); 41 | 42 | inst.myMethod("callback", message => console.assert("callback" === message)); 43 | inst.myMethod("noCallback"); 44 | 45 | setTimeout(() => { 46 | 47 | console.assert(success); 48 | 49 | console.log("DONE"); 50 | 51 | 52 | }, 2500); 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/test/legacyTests/test18.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | import { Evt } from "evt"; 3 | 4 | export class MyClass { 5 | 6 | constructor() { }; 7 | 8 | public readonly evtNoCallback = new Evt(); 9 | 10 | public myMethod = runExclusive.buildMethodCb( 11 | (message: string, callback?: (alphabet: string) => void): void => { 12 | 13 | if (!(callback as any).hasCallback) 14 | this.evtNoCallback.post(message); 15 | 16 | callback!(message) 17 | 18 | } 19 | ); 20 | 21 | 22 | } 23 | 24 | 25 | let inst = new MyClass(); 26 | 27 | let success = false 28 | 29 | inst.evtNoCallback.attach(message => { 30 | 31 | console.assert(message === "noCallback"); 32 | 33 | success = true; 34 | 35 | }); 36 | 37 | inst.myMethod("noCallback"); 38 | inst.myMethod("callback", message => console.assert("callback" === message)); 39 | 40 | 41 | console.assert(success); 42 | 43 | console.log("DONE"); -------------------------------------------------------------------------------- /src/test/legacyTests/test19.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | let runCount= 0; 4 | 5 | export class MyClass{ 6 | 7 | constructor() { }; 8 | 9 | public myMethod = runExclusive.buildMethodCb( 10 | (input: string, callback?: (out1: string, out2: number) => void): Promise<[string, number]> => { 11 | 12 | setTimeout(()=> { 13 | 14 | runCount++; 15 | 16 | callback!(input + " 0K", 666) 17 | 18 | }, 1000); 19 | 20 | return null as any; 21 | 22 | } 23 | ); 24 | 25 | } 26 | 27 | let inst= new MyClass(); 28 | 29 | (async()=> { 30 | 31 | let [ out1, out2 ]= await new Promise<[string, number]>( 32 | resolve=> inst.myMethod("yo", (out1, out2)=> resolve([ out1, out2 ])) 33 | ); 34 | 35 | console.assert(out1 === "yo 0K" && out2 === 666 ); 36 | 37 | inst.myMethod("ya", (out1, out2)=> console.assert(out1 == "ya 0K" && out2 === 666)); 38 | 39 | inst.myMethod("foo"); 40 | 41 | setTimeout(()=> { 42 | 43 | console.assert(runCount === 2); 44 | 45 | }, 1100); 46 | 47 | setTimeout(()=> { 48 | 49 | console.assert(runCount === 3); 50 | 51 | console.log("DONE"); 52 | 53 | }, 3100); 54 | 55 | 56 | })(); 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/test/legacyTests/test2.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | private alphabetStack = ""; 8 | 9 | private groupRef = runExclusive.createGroupRef(); 10 | 11 | public myMethodUpperCase = runExclusive.buildMethodCb( 12 | this.groupRef, 13 | (char: string, callback?: (alphabet: string) => void): void => { 14 | 15 | setTimeout(() => { 16 | this.alphabetStack += char.toUpperCase(); 17 | callback!(this.alphabetStack); 18 | }, Math.random() * 1000); 19 | 20 | } 21 | ); 22 | 23 | 24 | public myMethod = runExclusive.buildMethodCb( 25 | this.groupRef, 26 | (char: string, callback?: (alphabet: string) => void): void => { 27 | 28 | setTimeout(() => { 29 | this.alphabetStack += char; 30 | callback!(this.alphabetStack); 31 | }, Math.random() * 1000); 32 | 33 | } 34 | ); 35 | 36 | 37 | } 38 | 39 | let inst = new MyClass(); 40 | 41 | 42 | inst.myMethod("a"); 43 | 44 | for (let char of ["b", "c", "d", "e", "f"]) 45 | inst.myMethodUpperCase(char, alphabet => console.log(`step ${alphabet}`)); 46 | 47 | 48 | for (let char of ["g", "h", "i"]) 49 | inst.myMethod(char, alphabet => console.log(`step ${alphabet}`)); 50 | 51 | inst.myMethod("j", alphabet => { 52 | 53 | console.log(`completed ${alphabet}`) 54 | 55 | //cSpell: disable 56 | console.assert(alphabet === "aBCDEFghij"); 57 | //cSpell: enable 58 | 59 | console.log("PASS"); 60 | 61 | }); -------------------------------------------------------------------------------- /src/test/legacyTests/test20.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | let runCount= 0; 4 | 5 | export class MyClass{ 6 | 7 | constructor() { }; 8 | 9 | public myMethod = runExclusive.buildMethodCb( 10 | (input: number, callback?: (out: string) => void): Promise => { 11 | 12 | setTimeout(()=> { 13 | 14 | runCount++; 15 | 16 | callback!("input: " + input.toString()) 17 | 18 | }, 1000); 19 | 20 | return null as any; 21 | 22 | } 23 | ); 24 | 25 | } 26 | 27 | let inst= new MyClass(); 28 | 29 | (async()=> { 30 | 31 | let out= await new Promise( 32 | resolve=> inst.myMethod(111, out=> resolve(out)) 33 | ); 34 | 35 | console.log(out); 36 | console.log( out === "input: 111"); 37 | 38 | inst.myMethod(222, out => console.log(out === "input: 222")); 39 | 40 | inst.myMethod(333); 41 | 42 | 43 | setTimeout(()=> { 44 | 45 | console.assert(runCount === 2); 46 | 47 | }, 1100); 48 | 49 | setTimeout(()=> { 50 | 51 | console.assert(runCount === 3); 52 | 53 | console.log("DONE"); 54 | 55 | }, 3100); 56 | 57 | 58 | })(); -------------------------------------------------------------------------------- /src/test/legacyTests/test21.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | let runExclusiveFunction= runExclusive.buildCb( 4 | (callback)=> callback() 5 | ); 6 | 7 | let cbTriggered= false; 8 | 9 | 10 | runExclusiveFunction(()=> cbTriggered = true ); 11 | 12 | console.assert( cbTriggered ); 13 | 14 | console.log("PASS"); -------------------------------------------------------------------------------- /src/test/legacyTests/test3.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | 10 | public myMethod = runExclusive.buildMethodCb( 11 | runExclusive.createGroupRef(), 12 | (char: string, wait: number, callback?: (alphabet: string) => void): void => { 13 | 14 | setTimeout(() => { 15 | this.alphabet += char; 16 | callback!(this.alphabet); 17 | }, wait); 18 | 19 | } 20 | ); 21 | 22 | 23 | } 24 | 25 | 26 | let start = Date.now(); 27 | 28 | let inst1 = new MyClass(); 29 | 30 | inst1.myMethod("a", 1000, alphabet => console.log(alphabet)); 31 | inst1.myMethod("b", 1000, alphabet => console.log(alphabet)); 32 | 33 | let inst2 = new MyClass(); 34 | 35 | let rev = ["n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b"]; 36 | let wait = 500; 37 | 38 | for (let char of rev) 39 | inst2.myMethod(char, wait, alphabet => console.log(alphabet)); 40 | inst2.myMethod("a", wait, function (this: any) { 41 | 42 | let duration = Date.now() - start; 43 | 44 | //cSpell: disable 45 | console.assert(this.alphabet === "nmlkjihgfedcba"); 46 | //cSpell: enable 47 | 48 | let expectedDuration = (rev.length + 1) * 500; 49 | 50 | console.log("expectedDuration: ", expectedDuration); 51 | console.log("duration: ", duration); 52 | 53 | console.assert(Math.abs(duration - expectedDuration) < 300); 54 | console.assert(duration - expectedDuration >= 0); 55 | 56 | console.log("PASS"); 57 | 58 | 59 | }); 60 | 61 | inst1.myMethod("c", 1000, alphabet => console.log(alphabet)); 62 | inst1.myMethod("d", 1000, () => { 63 | 64 | let duration = Date.now() - start; 65 | 66 | //cSpell: disable 67 | console.assert(inst1.alphabet === "abcd"); 68 | //cSpell: enable 69 | 70 | let expectedDuration = 1000 * 4; 71 | 72 | console.log("expectedDuration: ", expectedDuration); 73 | console.log("duration: ", duration); 74 | 75 | console.assert(Math.abs(duration - expectedDuration) < 300); 76 | console.assert(duration - expectedDuration >= 0); 77 | 78 | }); -------------------------------------------------------------------------------- /src/test/legacyTests/test4.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | public myMethod = runExclusive.buildMethodCb( 10 | (char: string, wait: number, callback?: (alphabet: string) => void): void => { 11 | 12 | setTimeout(() => { 13 | this.alphabet += char; 14 | callback!(this.alphabet); 15 | }, wait); 16 | 17 | } 18 | ); 19 | 20 | } 21 | 22 | 23 | let start = Date.now(); 24 | 25 | let inst1 = new MyClass(); 26 | 27 | inst1.myMethod("a", 1000, alphabet => console.log(alphabet)); 28 | inst1.myMethod("b", 1000, alphabet => console.log(alphabet)); 29 | 30 | let inst2 = new MyClass(); 31 | 32 | let rev = ["n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b"]; 33 | let wait = 500; 34 | 35 | for (let char of rev) 36 | inst2.myMethod(char, wait, alphabet => console.log(alphabet)); 37 | inst2.myMethod("a", wait, function (this: any) { 38 | 39 | let duration = Date.now() - start; 40 | 41 | //cSpell: disable 42 | console.assert(this.alphabet === "nmlkjihgfedcba"); 43 | //cSpell: enable 44 | 45 | let expectedDuration = (rev.length + 1) * wait; 46 | 47 | console.log("expectedDuration: ", expectedDuration); 48 | console.log("duration: ", duration); 49 | 50 | console.assert(Math.abs(duration - expectedDuration) < 300); 51 | console.assert(duration - expectedDuration >= 0); 52 | 53 | console.log("PASS"); 54 | 55 | 56 | }); 57 | 58 | inst1.myMethod("c", 1000, alphabet => console.log(alphabet)); 59 | inst1.myMethod("d", 1000, () => { 60 | 61 | let duration = Date.now() - start; 62 | 63 | //cSpell: disable 64 | console.assert(inst1.alphabet === "abcd"); 65 | //cSpell: enable 66 | 67 | let expectedDuration = 1000 * 4; 68 | 69 | console.log("expectedDuration: ", expectedDuration); 70 | console.log("duration: ", duration); 71 | 72 | console.assert(Math.abs(duration - expectedDuration) < 300); 73 | console.assert(duration - expectedDuration >= 0); 74 | 75 | }); -------------------------------------------------------------------------------- /src/test/legacyTests/test5.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | public static readonly groupRef = runExclusive.createGroupRef(); 10 | 11 | public myMethod = runExclusive.buildMethodCb(MyClass.groupRef, 12 | (char: string, wait: number, callback?: (alphabet: string)=> void): void => { 13 | 14 | setTimeout(() => { 15 | this.alphabet += char; 16 | callback!(this.alphabet); 17 | }, wait); 18 | 19 | } 20 | ); 21 | 22 | 23 | } 24 | 25 | 26 | let start = Date.now(); 27 | 28 | let inst1 = new MyClass(); 29 | 30 | inst1.myMethod.call(MyClass, "a", 1000, alphabet => console.log(alphabet)); 31 | inst1.myMethod.call(MyClass, "b", 1000, alphabet => console.log(alphabet)); 32 | 33 | let inst2 = new MyClass(); 34 | 35 | let rev = ["n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b"]; 36 | let wait = 500; 37 | 38 | for (let char of rev) 39 | inst2.myMethod.call(MyClass, char, wait, alphabet => console.log(alphabet)); 40 | 41 | inst2.myMethod.call(MyClass, "a", wait, function () { 42 | 43 | //cSpell: disable 44 | console.assert(inst2.alphabet === "nmlkjihgfedcba"); 45 | //cSpell: enable 46 | 47 | }); 48 | 49 | inst1.myMethod.call(MyClass, "c", 1000, alphabet => console.log(alphabet)); 50 | inst1.myMethod.call(MyClass, "d", 1000, () => { 51 | 52 | let duration = Date.now() - start; 53 | 54 | //cSpell: disable 55 | console.assert(inst1.alphabet === "abcd"); 56 | //cSpell: enable 57 | 58 | let expectedDuration = 1000 * 4 + (rev.length + 1) * wait; 59 | 60 | console.log("expectedDuration: ", expectedDuration); 61 | console.log("duration: ", duration); 62 | 63 | console.assert(Math.abs(duration - expectedDuration) < 300); 64 | console.assert(duration - expectedDuration >= 0); 65 | 66 | console.log("PASS"); 67 | 68 | }); 69 | -------------------------------------------------------------------------------- /src/test/legacyTests/test6.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | const groupRefAlphabet = runExclusive.createGroupRef(); 4 | 5 | class MyClass1 { 6 | 7 | constructor() { }; 8 | 9 | public alphabet = ""; 10 | 11 | public myMethod = runExclusive.buildCb(groupRefAlphabet, 12 | (char: string, wait: number, callback?: (alphabet: string) => void): void => { 13 | 14 | setTimeout(() => { 15 | this.alphabet += char.toUpperCase(); 16 | callback!(this.alphabet); 17 | }, wait); 18 | 19 | }); 20 | 21 | } 22 | 23 | 24 | 25 | class MyClass2 { 26 | 27 | constructor() { }; 28 | 29 | public alphabet = ""; 30 | 31 | public myMethod = runExclusive.buildCb(groupRefAlphabet, 32 | (char: string, wait: number, callback?: (alphabet: string) => void): void => { 33 | 34 | setTimeout(() => { 35 | this.alphabet += char; 36 | callback!(this.alphabet); 37 | }, wait); 38 | 39 | } 40 | ); 41 | 42 | } 43 | 44 | 45 | 46 | 47 | let start = Date.now(); 48 | 49 | let inst1 = new MyClass1(); 50 | 51 | inst1.myMethod("a", 1000, alphabet => console.log(alphabet)); 52 | inst1.myMethod("b", 1000, alphabet => console.log(alphabet)); 53 | 54 | let inst2 = new MyClass2(); 55 | 56 | let rev = ["n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b"]; 57 | let wait = 500; 58 | 59 | for (let char of rev){ 60 | inst2.myMethod(char, wait, alphabet => console.log(alphabet)); 61 | } 62 | 63 | inst2.myMethod("a", wait, function (this: any) { 64 | 65 | //cSpell: disable 66 | console.assert(this.alphabet === "nmlkjihgfedcba"); 67 | //cSpell: enable 68 | 69 | }); 70 | 71 | inst1.myMethod("c", 1000, alphabet => console.log(alphabet)); 72 | inst1.myMethod("d", 1000, () => { 73 | 74 | let duration = Date.now() - start; 75 | 76 | //cSpell: disable 77 | console.assert(inst1.alphabet === "ABCD"); 78 | //cSpell: enable 79 | 80 | let expectedDuration = 1000 * 4 + (rev.length + 1) * 500; 81 | 82 | console.log("expectedDuration: ", expectedDuration); 83 | console.log("duration: ", duration); 84 | 85 | console.assert(Math.abs(duration - expectedDuration) < 300); 86 | console.assert(duration - expectedDuration >= 0); 87 | 88 | console.log("PASS"); 89 | 90 | }); -------------------------------------------------------------------------------- /src/test/legacyTests/test7.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | 10 | public myMethod1 = runExclusive.buildMethodCb(runExclusive.createGroupRef(), 11 | (char: string, wait: number, callback?: (alphabet: string) => void): void => { 12 | 13 | setTimeout(() => { 14 | this.alphabet += char; 15 | callback!(this.alphabet); 16 | }, wait); 17 | 18 | } 19 | ); 20 | 21 | public alphabet2 = ""; 22 | 23 | public myMethod2 = runExclusive.buildMethodCb( 24 | (char: string, wait: number, callback?: (alphabet: string) => void): void => { 25 | 26 | let safeCallback = callback || function () { }; 27 | 28 | setTimeout(() => { 29 | this.alphabet2 += char; 30 | safeCallback(this.alphabet2); 31 | }, wait); 32 | 33 | } 34 | ); 35 | 36 | 37 | } 38 | 39 | 40 | let start = Date.now(); 41 | 42 | let inst = new MyClass(); 43 | 44 | inst.myMethod1("a", 1000, alphabet => console.log(alphabet)); 45 | inst.myMethod1("b", 1000, alphabet => console.log(alphabet)); 46 | 47 | 48 | let rev = ["n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b"]; 49 | let wait = 500; 50 | 51 | for (let char of rev) 52 | inst.myMethod2(char, wait, alphabet => console.log(alphabet)); 53 | inst.myMethod2("a", wait, function (this: any) { 54 | 55 | let duration = Date.now() - start; 56 | 57 | //cSpell: disable 58 | console.assert(this.alphabet2 === "nmlkjihgfedcba"); 59 | //cSpell: enable 60 | 61 | let expectedDuration = (rev.length + 1) * wait; 62 | 63 | console.log("expectedDuration: ", expectedDuration); 64 | console.log("duration: ", duration); 65 | 66 | console.assert(Math.abs(duration - expectedDuration) < 300); 67 | console.assert(duration - expectedDuration >= 0); 68 | 69 | console.log("PASS"); 70 | 71 | 72 | }); 73 | 74 | inst.myMethod1("c", 1000, alphabet => console.log(alphabet)); 75 | inst.myMethod1("d", 1000, () => { 76 | 77 | let duration = Date.now() - start; 78 | 79 | //cSpell: disable 80 | console.assert(inst.alphabet === "abcd"); 81 | //cSpell: enable 82 | 83 | let expectedDuration = 1000 * 4; 84 | 85 | console.log("expectedDuration: ", expectedDuration); 86 | console.log("duration: ", duration); 87 | 88 | console.assert(Math.abs(duration - expectedDuration) < 300); 89 | console.assert(duration - expectedDuration >= 0); 90 | 91 | 92 | }); -------------------------------------------------------------------------------- /src/test/legacyTests/test8.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | public myMethod1 = runExclusive.buildMethodCb( 10 | (char: string, wait: number, callback?: (alphabet: string) => void): void => { 11 | 12 | let safeCallback = callback || function () { }; 13 | 14 | setTimeout(() => { 15 | this.alphabet += char; 16 | safeCallback(this.alphabet); 17 | }, wait); 18 | 19 | } 20 | ); 21 | 22 | 23 | public alphabet2 = ""; 24 | 25 | public myMethod2 = runExclusive.buildMethodCb( 26 | (char: string, wait: number, callback?: (alphabet: string) => void): void => { 27 | 28 | setTimeout(() => { 29 | this.alphabet2 += char; 30 | callback!(this.alphabet2); 31 | }, wait); 32 | 33 | } 34 | ); 35 | 36 | 37 | 38 | 39 | } 40 | 41 | 42 | let start = Date.now(); 43 | 44 | let inst = new MyClass(); 45 | 46 | inst.myMethod1("a", 1000, alphabet => console.log(alphabet)); 47 | inst.myMethod1("b", 1000, alphabet => console.log(alphabet)); 48 | 49 | 50 | let rev = ["n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b"]; 51 | let wait = 500; 52 | 53 | for (let char of rev) 54 | inst.myMethod2(char, wait, alphabet => console.log(alphabet)); 55 | inst.myMethod2("a", wait, function (this: any) { 56 | 57 | let duration = Date.now() - start; 58 | 59 | //cSpell: disable 60 | console.assert(this.alphabet2 === "nmlkjihgfedcba"); 61 | //cSpell: enable 62 | 63 | let expectedDuration = (rev.length + 1) * 500; 64 | 65 | 66 | console.log("expectedDuration: ", expectedDuration); 67 | console.log("duration: ", duration); 68 | 69 | console.assert(Math.abs(duration - expectedDuration) < 300); 70 | console.assert(duration - expectedDuration >= 0); 71 | 72 | console.log("PASS"); 73 | 74 | 75 | }); 76 | 77 | inst.myMethod1("c", 1000, alphabet => console.log(alphabet)); 78 | inst.myMethod1("d", 1000, () => { 79 | 80 | let duration = Date.now() - start; 81 | 82 | //cSpell: disable 83 | console.assert(inst.alphabet === "abcd"); 84 | //cSpell: enable 85 | 86 | let expectedDuration = 1000 * 4; 87 | 88 | 89 | console.log("expectedDuration: ", expectedDuration); 90 | console.log("duration: ", duration); 91 | 92 | console.assert(Math.abs(duration - expectedDuration) < 300); 93 | console.assert(duration - expectedDuration >= 0); 94 | 95 | }); -------------------------------------------------------------------------------- /src/test/legacyTests/test9.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | 10 | public myMethod = runExclusive.buildMethodCb( 11 | (char: string, callback?: (alphabet: string) => void): void => { 12 | 13 | setTimeout(() => { 14 | this.alphabet += char; 15 | callback!(this.alphabet); 16 | }, 1000); 17 | 18 | } 19 | ); 20 | 21 | 22 | } 23 | 24 | let inst = new MyClass(); 25 | 26 | 27 | setTimeout(() => { 28 | 29 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 3); 30 | 31 | console.assert(inst.alphabet === "ab"); 32 | 33 | runExclusive.cancelAllQueuedCalls(inst.myMethod, inst); 34 | 35 | setTimeout(() => { 36 | 37 | console.assert(inst.alphabet === "abc"); 38 | 39 | console.log("PASS"); 40 | 41 | }, 2000); 42 | 43 | }, 2900); 44 | 45 | for (let char of ["a", "b", "c", "d", "e", "f"]){ 46 | 47 | inst.myMethod(char, alphabet => console.log(`step ${alphabet}`)); 48 | 49 | } -------------------------------------------------------------------------------- /src/test/mod.ts: -------------------------------------------------------------------------------- 1 | 2 | declare const console: any; 3 | 4 | console.log("DENO TEST"); 5 | 6 | import "./test1"; 7 | import "./test2"; 8 | import "./test3"; 9 | import "./test4"; 10 | import "./test5"; 11 | import "./test6"; 12 | import "./test7"; 13 | import "./test8"; 14 | import "./test9"; 15 | import "./test10"; 16 | import "./test11"; 17 | 18 | import "./test13"; 19 | import "./test14"; 20 | import "./test15"; 21 | import "./test16"; 22 | import "./test17"; 23 | import "./test18"; -------------------------------------------------------------------------------- /src/test/test1.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | private alphabetStack = ""; 8 | 9 | public myMethodStack = runExclusive.buildMethod( 10 | (char: string): Promise => { 11 | 12 | return new Promise(resolve => { 13 | 14 | setTimeout(() => { 15 | this.alphabetStack += char; 16 | resolve(this.alphabetStack); 17 | }, Math.random() * 1000); 18 | 19 | }); 20 | 21 | } 22 | ); 23 | 24 | 25 | } 26 | 27 | let inst = new MyClass(); 28 | 29 | for (let char of ["a", "b", "c", "d", "e", "f"]) 30 | inst.myMethodStack(char).then( alphabet => console.log(`step ${alphabet}`) ); 31 | 32 | 33 | for (let char of ["g", "h", "i"]) 34 | inst.myMethodStack(char); 35 | 36 | inst.myMethodStack("j").then( alphabet => { 37 | 38 | console.log(`completed ${alphabet}`); 39 | 40 | //cSpell: disable 41 | console.assert(alphabet === "abcdefghij"); 42 | //cSpell: enable 43 | 44 | console.log("PASS"); 45 | 46 | }); 47 | -------------------------------------------------------------------------------- /src/test/test10.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | public myMethod = runExclusive.buildMethod( 10 | async (char: string): Promise => { 11 | 12 | await new Promise(resolve => setTimeout(()=> resolve(), 1000)); 13 | 14 | this.alphabet += char; 15 | 16 | return this.alphabet; 17 | 18 | } 19 | ); 20 | 21 | 22 | } 23 | 24 | let inst = new MyClass(); 25 | 26 | 27 | setTimeout(() => { 28 | 29 | 30 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 3); 31 | 32 | console.assert(inst.alphabet === "ab"); 33 | 34 | runExclusive.cancelAllQueuedCalls(inst.myMethod, inst); 35 | 36 | setTimeout(() => { 37 | 38 | console.assert(inst.alphabet === "abc"); 39 | 40 | console.log("PASS"); 41 | 42 | }, 2000); 43 | 44 | }, 2900); 45 | 46 | 47 | 48 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 49 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false ); 50 | inst.myMethod("a"); 51 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst)===0); 52 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true ); 53 | 54 | for (let char of ["b", "c", "d", "e", "f"]) 55 | inst.myMethod(char).then( alphabet => console.log(`step ${alphabet}`)); 56 | 57 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst)=== 5); 58 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true ); -------------------------------------------------------------------------------- /src/test/test11.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | public myMethod = runExclusive.buildMethod( 10 | async (char: string): Promise => { 11 | 12 | await new Promise(resolve => setTimeout(()=>resolve(), 1000)); 13 | 14 | this.alphabet += char; 15 | 16 | return this.alphabet; 17 | 18 | } 19 | ); 20 | 21 | 22 | } 23 | 24 | class MyClassProxy { 25 | 26 | constructor() { }; 27 | 28 | private myClassInst = new MyClass(); 29 | 30 | public callCount = 0; 31 | 32 | public getAlphabet(): typeof MyClass.prototype.alphabet { 33 | return this.myClassInst.alphabet; 34 | } 35 | 36 | public myMethod: typeof MyClass.prototype.myMethod = 37 | runExclusive.buildMethod( 38 | (...inputs)=>{ 39 | 40 | this.callCount++; 41 | 42 | return this.myClassInst.myMethod.apply(this.myClassInst, inputs); 43 | 44 | } 45 | ); 46 | 47 | 48 | } 49 | 50 | let inst = new MyClassProxy(); 51 | 52 | setTimeout(() => { 53 | 54 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 3); 55 | 56 | console.assert(inst.getAlphabet() === "ab"); 57 | 58 | runExclusive.cancelAllQueuedCalls(inst.myMethod, inst); 59 | 60 | setTimeout(() => { 61 | 62 | console.assert(inst.getAlphabet() === "abc"); 63 | 64 | console.log("PASS"); 65 | 66 | }, 2000); 67 | 68 | }, 2900); 69 | 70 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 71 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false ); 72 | inst.myMethod("a"); 73 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 74 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true ); 75 | 76 | for (let char of ["b", "c", "d", "e", "f"]) 77 | inst.myMethod(char).then( alphabet => console.log(`step ${alphabet}`)); 78 | 79 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 5); 80 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true ); 81 | 82 | console.assert(inst.callCount === 1); 83 | -------------------------------------------------------------------------------- /src/test/test12.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | import { Evt } from "evt"; 3 | 4 | export class MyClass { 5 | 6 | constructor() { }; 7 | 8 | public alphabet = ""; 9 | 10 | 11 | public myMethod = runExclusive.buildMethod( 12 | async (char: string): Promise => { 13 | 14 | await new Promise(resolve => setTimeout(resolve, 1000)); 15 | 16 | this.alphabet += char; 17 | 18 | return this.alphabet; 19 | 20 | } 21 | ); 22 | 23 | 24 | } 25 | 26 | export class MyClassProxy { 27 | 28 | private myClassInst: MyClass | undefined = undefined; 29 | 30 | public readonly evtCreate = Evt.create(); 31 | 32 | public getAlphabet(): typeof MyClass.prototype.alphabet { 33 | if (!this.myClassInst) return ""; 34 | else return this.myClassInst.alphabet; 35 | } 36 | 37 | constructor() { 38 | 39 | setTimeout(() => { 40 | this.myClassInst = new MyClass(); 41 | this.evtCreate.post(); 42 | }, 1000); 43 | 44 | } 45 | 46 | public myMethod: typeof MyClass.prototype.myMethod = 47 | runExclusive.buildMethod( 48 | (...inputs) => { 49 | 50 | let self = this; 51 | 52 | return new Promise(function callee(resolve, reject) { 53 | 54 | if (!self.myClassInst) { 55 | 56 | self.evtCreate.attachOnce(() => callee(resolve, reject)); 57 | return; 58 | 59 | } 60 | 61 | self.myClassInst.myMethod.apply(self.myClassInst, inputs) 62 | .then(resolve) 63 | .catch(reject); 64 | 65 | }); 66 | 67 | } 68 | ); 69 | 70 | 71 | } 72 | 73 | let inst = new MyClassProxy(); 74 | 75 | 76 | setTimeout(() => { 77 | 78 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 3); 79 | 80 | console.assert(inst.getAlphabet() === "ab"); 81 | 82 | runExclusive.cancelAllQueuedCalls(inst.myMethod, inst); 83 | 84 | setTimeout(() => { 85 | 86 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 87 | 88 | console.assert(inst.getAlphabet() === "abc"); 89 | 90 | console.log("PASS"); 91 | 92 | }, 2000); 93 | 94 | }, 2900 + 1000); 95 | 96 | 97 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 98 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 99 | inst.myMethod("a"); 100 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 101 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true); 102 | 103 | 104 | for (let char of ["b", "c", "d", "e", "f"]) 105 | inst.myMethod(char).then(alphabet => console.log(`step ${alphabet}`)); 106 | 107 | 108 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 5); 109 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true); 110 | -------------------------------------------------------------------------------- /src/test/test13.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | public myMethod = runExclusive.buildMethod( 10 | async (char: string): Promise => { 11 | 12 | await new Promise(resolve => setTimeout(()=>resolve(), 1000)); 13 | 14 | this.alphabet += char; 15 | 16 | return this.alphabet; 17 | 18 | } 19 | ); 20 | 21 | 22 | } 23 | 24 | let inst = new MyClass(); 25 | 26 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 27 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 28 | 29 | inst.myMethod("a").then( () => { 30 | 31 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 32 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 33 | 34 | console.log("PASS"); 35 | 36 | }); 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/test/test14.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | public myMethod = runExclusive.buildMethod( 10 | async (char: string): Promise => { 11 | 12 | await new Promise(resolve => setTimeout(()=>resolve(), 1000)); 13 | 14 | this.alphabet += char; 15 | 16 | return this.alphabet; 17 | 18 | } 19 | ); 20 | 21 | 22 | } 23 | 24 | let inst = new MyClass(); 25 | 26 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 27 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 28 | 29 | inst.myMethod("a").then(() => { 30 | 31 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 32 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true); 33 | 34 | console.log("PASS"); 35 | 36 | }); 37 | inst.myMethod("b"); 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/test/test15.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | 10 | public myMethod = runExclusive.buildMethod( 11 | async (char: string): Promise => { 12 | 13 | await new Promise(resolve => setTimeout(()=>resolve(), 1000)); 14 | 15 | this.alphabet += char; 16 | 17 | return this.alphabet; 18 | 19 | }); 20 | 21 | 22 | } 23 | 24 | let inst = new MyClass(); 25 | 26 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 27 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 28 | 29 | inst.myMethod("a").then(() => { 30 | 31 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 1); 32 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true); 33 | 34 | }); 35 | inst.myMethod("b").then(() => { 36 | 37 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 38 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === true); 39 | 40 | 41 | }); 42 | inst.myMethod("c").then(() => { 43 | 44 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 0); 45 | console.assert(runExclusive.isRunning(inst.myMethod, inst) === false); 46 | 47 | console.log("PASS"); 48 | 49 | }); 50 | -------------------------------------------------------------------------------- /src/test/test16.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | let runCount= 0; 4 | 5 | export class MyClass{ 6 | 7 | constructor() { }; 8 | 9 | public myMethod = runExclusive.buildMethod( 10 | async (input: string): Promise<[string, number]> => { 11 | 12 | await new Promise(resolve=> setTimeout(()=>resolve(), 1000)); 13 | 14 | runCount++; 15 | 16 | return [input + " 0K", 666]; 17 | 18 | } 19 | ); 20 | 21 | } 22 | 23 | let inst= new MyClass(); 24 | 25 | (async()=> { 26 | 27 | let [ out1, out2 ]= await inst.myMethod("yo") 28 | 29 | console.assert(out1 === "yo 0K" && out2 === 666 ); 30 | 31 | inst.myMethod("ya").then(([out1, out2])=> console.assert(out1 == "ya 0K" && out2 === 666)); 32 | 33 | inst.myMethod("foo"); 34 | 35 | setTimeout(()=> { 36 | 37 | console.assert(runCount === 2); 38 | 39 | }, 1100); 40 | 41 | setTimeout(()=> { 42 | 43 | console.assert(runCount === 3); 44 | 45 | console.log("DONE"); 46 | 47 | }, 3100); 48 | 49 | 50 | })(); 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/test/test17.ts: -------------------------------------------------------------------------------- 1 | //Import ExecStack to be able to export stacked function 2 | 3 | import * as runExclusive from "../lib/runExclusive"; 4 | 5 | let runCount = 0; 6 | 7 | export class MyClass { 8 | 9 | constructor() { }; 10 | 11 | public myMethod = runExclusive.buildMethod( 12 | async (input: number): Promise => { 13 | 14 | await new Promise(resolve => setTimeout(()=>resolve(), 1000)); 15 | 16 | runCount++; 17 | 18 | return "input: " + input.toString(); 19 | 20 | 21 | } 22 | ); 23 | 24 | } 25 | 26 | let inst = new MyClass(); 27 | 28 | (async () => { 29 | 30 | let out = await inst.myMethod(111); 31 | 32 | console.log(out); 33 | console.log(out === "input: 111"); 34 | 35 | inst.myMethod(222).then(out => console.log(out === "input: 222")); 36 | 37 | inst.myMethod(333); 38 | 39 | setTimeout(() => { 40 | 41 | console.assert(runCount === 2); 42 | 43 | }, 1100); 44 | 45 | setTimeout(() => { 46 | 47 | console.assert(runCount === 3); 48 | 49 | console.log("DONE"); 50 | 51 | }, 3100); 52 | 53 | 54 | })(); 55 | -------------------------------------------------------------------------------- /src/test/test18.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | let alphabet= ""; 4 | 5 | const myFunction = runExclusive.build( 6 | async (char: string) => { 7 | 8 | await new Promise(resolve=> setTimeout(resolve, 10)); 9 | 10 | alphabet+= char; 11 | 12 | } 13 | ); 14 | 15 | 16 | (async ()=>{ 17 | 18 | 19 | myFunction("a"); 20 | 21 | myFunction("b"); 22 | 23 | runExclusive.getPrComplete(myFunction).then(()=> { 24 | 25 | console.assert(alphabet === "ab"); 26 | }); 27 | 28 | await myFunction("c"); 29 | 30 | console.assert(alphabet === "abc"); 31 | 32 | })(); 33 | -------------------------------------------------------------------------------- /src/test/test2.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | class MyClass{ 4 | 5 | constructor(){}; 6 | 7 | private readonly groupRefAlphabet= runExclusive.createGroupRef(); 8 | 9 | private alphabetStack= ""; 10 | 11 | public myMethodUpperCase = runExclusive.buildMethod(this.groupRefAlphabet, 12 | async (char: string ): Promise => { 13 | 14 | await new Promise(resolve=> setTimeout(()=>resolve(), Math.random()*1000)); 15 | 16 | this.alphabetStack += char.toUpperCase(); 17 | 18 | return this.alphabetStack; 19 | 20 | } 21 | ); 22 | 23 | public myMethod = runExclusive.buildMethod(this.groupRefAlphabet, 24 | async (char: string ): Promise => { 25 | 26 | await new Promise(resolve=> setTimeout(()=>resolve(), Math.random()*1000)); 27 | 28 | this.alphabetStack += char; 29 | 30 | return this.alphabetStack; 31 | 32 | } 33 | ); 34 | 35 | 36 | } 37 | 38 | let inst = new MyClass(); 39 | 40 | inst.myMethod("a"); 41 | 42 | for (let char of ["b", "c", "d", "e", "f"]) 43 | inst.myMethodUpperCase(char).then( alphabet => console.log(`step ${alphabet}`)); 44 | 45 | 46 | for (let char of ["g", "h", "i"]) 47 | inst.myMethod(char).then( alphabet => console.log(`step ${alphabet}`)); 48 | 49 | inst.myMethod("j").then( alphabet => { 50 | 51 | console.log(`completed ${alphabet}`) 52 | 53 | //cSpell: disable 54 | console.assert(alphabet === "aBCDEFghij"); 55 | //cSpell: enable 56 | 57 | console.log("PASS"); 58 | 59 | }); -------------------------------------------------------------------------------- /src/test/test3.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | class MyClass{ 4 | 5 | constructor(){}; 6 | 7 | public alphabet= ""; 8 | 9 | public myMethod= runExclusive.buildMethod(runExclusive.createGroupRef(), 10 | async (char: string, wait: number): Promise => { 11 | 12 | await new Promise(resolve=> setTimeout(()=>resolve(), wait)); 13 | 14 | this.alphabet += char; 15 | 16 | return this.alphabet; 17 | 18 | }); 19 | 20 | 21 | } 22 | 23 | 24 | let start= Date.now(); 25 | 26 | let inst1= new MyClass(); 27 | 28 | inst1.myMethod("a", 1000).then( alphabet=> console.log(alphabet)); 29 | inst1.myMethod("b", 1000).then( alphabet=> console.log(alphabet)); 30 | 31 | let inst2= new MyClass(); 32 | 33 | let rev= [ "n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b" ]; 34 | let wait= 500; 35 | 36 | for( let char of rev) 37 | inst2.myMethod(char, wait).then( alphabet => console.log(alphabet)); 38 | 39 | inst2.myMethod("a", wait).then( function() { 40 | 41 | let duration= Date.now() - start; 42 | 43 | //cSpell: disable 44 | console.assert(inst2.alphabet === "nmlkjihgfedcba" ); 45 | //cSpell: enable 46 | 47 | let expectedDuration= (rev.length+1)*500; 48 | 49 | console.log("expectedDuration: ", expectedDuration); 50 | console.log("duration: ", duration); 51 | 52 | console.assert( Math.abs( duration - expectedDuration) < 300 ); 53 | console.assert( duration - expectedDuration >= 0 ); 54 | 55 | console.log("PASS"); 56 | 57 | 58 | }); 59 | 60 | inst1.myMethod("c", 1000).then( alphabet=> console.log(alphabet)); 61 | inst1.myMethod("d", 1000).then( ()=>{ 62 | 63 | let duration= Date.now() - start; 64 | 65 | //cSpell: disable 66 | console.assert(inst1.alphabet === "abcd" ); 67 | //cSpell: enable 68 | 69 | let expectedDuration= 1000*4; 70 | 71 | console.log("expectedDuration: ", expectedDuration); 72 | console.log("duration: ", duration); 73 | 74 | console.assert( Math.abs( duration - expectedDuration) < 300 ); 75 | console.assert( duration - expectedDuration >= 0 ); 76 | 77 | }); -------------------------------------------------------------------------------- /src/test/test4.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | public myMethod = runExclusive.buildMethod( 10 | async (char: string, wait: number): Promise => { 11 | 12 | await new Promise(resolve => setTimeout(()=>resolve(), wait)); 13 | 14 | this.alphabet += char; 15 | 16 | return this.alphabet; 17 | 18 | } 19 | ); 20 | 21 | } 22 | 23 | 24 | let start = Date.now(); 25 | 26 | let inst1 = new MyClass(); 27 | 28 | inst1.myMethod("a", 1000).then( alphabet => console.log(alphabet)); 29 | inst1.myMethod("b", 1000).then( alphabet => console.log(alphabet)); 30 | 31 | let inst2 = new MyClass(); 32 | 33 | let rev = ["n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b"]; 34 | let wait = 500; 35 | 36 | for (let char of rev) 37 | inst2.myMethod(char, wait).then( alphabet => console.log(alphabet)); 38 | 39 | inst2.myMethod("a", wait).then( function () { 40 | 41 | let duration = Date.now() - start; 42 | 43 | //cSpell: disable 44 | console.assert(inst2.alphabet === "nmlkjihgfedcba"); 45 | //cSpell: enable 46 | 47 | let expectedDuration = (rev.length + 1) * wait; 48 | 49 | console.log("expectedDuration: ", expectedDuration); 50 | console.log("duration: ", duration); 51 | 52 | console.assert(Math.abs(duration - expectedDuration) < 300); 53 | console.assert(duration - expectedDuration >= 0); 54 | 55 | console.log("PASS"); 56 | 57 | 58 | }); 59 | 60 | inst1.myMethod("c", 1000).then( alphabet => console.log(alphabet)); 61 | inst1.myMethod("d", 1000).then( () => { 62 | 63 | let duration = Date.now() - start; 64 | 65 | //cSpell: disable 66 | console.assert(inst1.alphabet === "abcd"); 67 | //cSpell: enable 68 | 69 | let expectedDuration = 1000 * 4; 70 | 71 | console.log("expectedDuration: ", expectedDuration); 72 | console.log("duration: ", duration); 73 | 74 | console.assert(Math.abs(duration - expectedDuration) < 300); 75 | console.assert(duration - expectedDuration >= 0); 76 | 77 | }); -------------------------------------------------------------------------------- /src/test/test5.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | public static readonly groupRef = runExclusive.createGroupRef(); 10 | 11 | public myMethod = runExclusive.buildMethod(MyClass.groupRef, 12 | async (char: string, wait: number): Promise => { 13 | 14 | await new Promise(resolve => setTimeout(()=>resolve(), wait)); 15 | 16 | this.alphabet += char; 17 | 18 | return this.alphabet; 19 | 20 | } 21 | ); 22 | 23 | 24 | } 25 | 26 | 27 | let start = Date.now(); 28 | 29 | let inst1 = new MyClass(); 30 | 31 | inst1.myMethod.call(MyClass, "a", 1000).then(alphabet => console.log(alphabet)); 32 | inst1.myMethod.call(MyClass, "b", 1000).then(alphabet => console.log(alphabet)); 33 | 34 | let inst2 = new MyClass(); 35 | 36 | let rev = ["n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b"]; 37 | let wait = 500; 38 | 39 | for (let char of rev) 40 | inst2.myMethod.call(MyClass, char, wait).then(alphabet => console.log(alphabet)); 41 | 42 | inst2.myMethod.call(MyClass, "a", wait).then(function () { 43 | 44 | //cSpell: disable 45 | console.assert(inst2.alphabet === "nmlkjihgfedcba"); 46 | //cSpell: enable 47 | 48 | }); 49 | 50 | inst1.myMethod.call(MyClass, "c", 1000).then(alphabet => console.log(alphabet)); 51 | inst1.myMethod.call(MyClass, "d", 1000).then(() => { 52 | 53 | let duration = Date.now() - start; 54 | 55 | //cSpell: disable 56 | console.assert(inst1.alphabet === "abcd"); 57 | //cSpell: enable 58 | 59 | let expectedDuration = 1000 * 4 + (rev.length + 1) * wait; 60 | 61 | console.log("expectedDuration: ", expectedDuration); 62 | console.log("duration: ", duration); 63 | 64 | console.assert(Math.abs(duration - expectedDuration) < 300); 65 | console.assert(duration - expectedDuration >= 0); 66 | 67 | console.log("PASS"); 68 | 69 | }); -------------------------------------------------------------------------------- /src/test/test6.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | const groupRefAlphabet= runExclusive.createGroupRef(); 4 | 5 | class MyClass1 { 6 | 7 | constructor() { }; 8 | 9 | public alphabet = ""; 10 | 11 | public myMethod = runExclusive.build(groupRefAlphabet, 12 | async (char: string, wait: number): Promise => { 13 | 14 | await new Promise(resolve => setTimeout(()=>resolve(), wait)); 15 | 16 | this.alphabet += char.toUpperCase(); 17 | 18 | return this.alphabet; 19 | 20 | }); 21 | 22 | } 23 | 24 | class MyClass2 { 25 | 26 | constructor() { }; 27 | 28 | public alphabet = ""; 29 | 30 | public myMethod = runExclusive.build(groupRefAlphabet, 31 | async (char: string, wait: number): Promise => { 32 | 33 | await new Promise(resolve => setTimeout(()=>resolve(), wait)); 34 | 35 | this.alphabet += char; 36 | 37 | return this.alphabet; 38 | 39 | }); 40 | 41 | } 42 | 43 | 44 | 45 | 46 | let start = Date.now(); 47 | 48 | let inst1 = new MyClass1(); 49 | 50 | inst1.myMethod("a", 1000).then( alphabet => console.log(alphabet)); 51 | inst1.myMethod("b", 1000).then( alphabet => console.log(alphabet)); 52 | 53 | let inst2 = new MyClass2(); 54 | 55 | let rev = ["n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b"]; 56 | let wait = 500; 57 | 58 | for (let char of rev) 59 | inst2.myMethod(char, wait).then( alphabet => console.log(alphabet)); 60 | 61 | inst2.myMethod("a", wait).then( function () { 62 | 63 | //cSpell: disable 64 | console.assert(inst2.alphabet === "nmlkjihgfedcba"); 65 | //cSpell: enable 66 | 67 | }); 68 | 69 | inst1.myMethod("c", 1000 ).then( alphabet => console.log(alphabet)); 70 | inst1.myMethod("d", 1000 ).then( () => { 71 | 72 | let duration = Date.now() - start; 73 | 74 | //cSpell: disable 75 | console.assert(inst1.alphabet === "ABCD"); 76 | //cSpell: enable 77 | 78 | let expectedDuration = 1000 * 4 + (rev.length + 1) * 500; 79 | 80 | console.log("expectedDuration: ", expectedDuration); 81 | console.log("duration: ", duration); 82 | 83 | console.assert(Math.abs(duration - expectedDuration) < 300); 84 | console.assert(duration - expectedDuration >= 0); 85 | 86 | console.log("PASS"); 87 | 88 | }); -------------------------------------------------------------------------------- /src/test/test7.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | class MyClass{ 4 | 5 | constructor(){}; 6 | 7 | public alphabet= ""; 8 | 9 | public myMethod1= runExclusive.buildMethod(runExclusive.createGroupRef(), 10 | async (char: string, wait: number): Promise => { 11 | 12 | await new Promise(resolve => setTimeout(()=>resolve(), wait)); 13 | 14 | this.alphabet += char; 15 | 16 | return this.alphabet; 17 | 18 | } 19 | ); 20 | 21 | public alphabet2 = ""; 22 | 23 | public myMethod2 = runExclusive.buildMethod( 24 | async (char: string, wait: number): Promise => { 25 | 26 | await new Promise(resolve => setTimeout(()=>resolve(), wait)); 27 | 28 | this.alphabet2 += char; 29 | 30 | return this.alphabet2; 31 | 32 | } 33 | ); 34 | 35 | 36 | 37 | 38 | } 39 | 40 | 41 | let start = Date.now(); 42 | 43 | let inst = new MyClass(); 44 | 45 | inst.myMethod1("a", 1000).then( alphabet => console.log(alphabet) ); 46 | inst.myMethod1("b", 1000).then( alphabet => console.log(alphabet) ); 47 | 48 | 49 | let rev = ["n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b"]; 50 | let wait = 500; 51 | 52 | for (let char of rev) 53 | inst.myMethod2(char, wait).then( alphabet => console.log(alphabet)); 54 | 55 | inst.myMethod2("a", wait ).then( function () { 56 | 57 | let duration = Date.now() - start; 58 | 59 | //cSpell: disable 60 | console.assert(inst.alphabet2 === "nmlkjihgfedcba"); 61 | //cSpell: enable 62 | 63 | let expectedDuration = (rev.length + 1) * wait; 64 | 65 | console.log("expectedDuration: ", expectedDuration); 66 | console.log("duration: ", duration); 67 | 68 | console.assert(Math.abs(duration - expectedDuration) < 300); 69 | console.assert(duration - expectedDuration >= 0); 70 | 71 | console.log("PASS"); 72 | 73 | 74 | }); 75 | 76 | inst.myMethod1("c", 1000).then( alphabet => console.log(alphabet)); 77 | inst.myMethod1("d", 1000).then( () => { 78 | 79 | let duration = Date.now() - start; 80 | 81 | //cSpell: disable 82 | console.assert(inst.alphabet === "abcd"); 83 | //cSpell: enable 84 | 85 | let expectedDuration = 1000 * 4; 86 | 87 | console.log("expectedDuration: ", expectedDuration); 88 | console.log("duration: ", duration); 89 | 90 | console.assert(Math.abs(duration - expectedDuration) < 300); 91 | console.assert(duration - expectedDuration >= 0); 92 | 93 | 94 | }); -------------------------------------------------------------------------------- /src/test/test8.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | class MyClass{ 4 | 5 | constructor(){}; 6 | 7 | public alphabet= ""; 8 | 9 | public myMethod1= runExclusive.buildMethod( 10 | async (char: string, wait: number): Promise => { 11 | 12 | await new Promise(resolve=>setTimeout(()=>resolve(),wait)); 13 | 14 | this.alphabet+= char; 15 | 16 | return this.alphabet; 17 | 18 | }); 19 | 20 | public alphabet2= ""; 21 | 22 | public myMethod2= runExclusive.buildMethod( 23 | async (char: string, wait: number): Promise => { 24 | 25 | await new Promise(resolve=>setTimeout(()=>resolve(),wait)); 26 | 27 | this.alphabet2+= char; 28 | 29 | return this.alphabet2; 30 | 31 | }); 32 | 33 | } 34 | 35 | 36 | let start= Date.now(); 37 | 38 | let inst= new MyClass(); 39 | 40 | inst.myMethod1("a", 1000).then( alphabet=> console.log(alphabet)); 41 | inst.myMethod1("b", 1000).then( alphabet=> console.log(alphabet)); 42 | 43 | 44 | let rev= [ "n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b" ]; 45 | let wait= 500; 46 | 47 | for( let char of rev) 48 | inst.myMethod2(char, wait ).then( alphabet => console.log(alphabet)); 49 | inst.myMethod2("a", wait ).then( function() { 50 | 51 | let duration= Date.now() - start; 52 | 53 | //cSpell: disable 54 | console.assert(inst.alphabet2 === "nmlkjihgfedcba" ); 55 | //cSpell: enable 56 | 57 | let expectedDuration= (rev.length+1)*500; 58 | 59 | 60 | console.log("expectedDuration: ", expectedDuration); 61 | console.log("duration: ", duration); 62 | 63 | console.assert( Math.abs(duration - expectedDuration) < 300 ); 64 | console.assert( duration - expectedDuration >= 0 ); 65 | 66 | console.log("PASS"); 67 | 68 | 69 | }); 70 | 71 | inst.myMethod1("c", 1000).then( alphabet=> console.log(alphabet)); 72 | inst.myMethod1("d", 1000).then( ()=>{ 73 | 74 | let duration= Date.now() - start; 75 | 76 | //cSpell: disable 77 | console.assert(inst.alphabet === "abcd" ); 78 | //cSpell: enable 79 | 80 | let expectedDuration= 1000*4; 81 | 82 | 83 | console.log("expectedDuration: ", expectedDuration); 84 | console.log("duration: ", duration); 85 | 86 | console.assert( Math.abs(duration - expectedDuration) < 300 ); 87 | console.assert( duration - expectedDuration >= 0 ); 88 | 89 | }); -------------------------------------------------------------------------------- /src/test/test9.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | class MyClass { 4 | 5 | constructor() { }; 6 | 7 | public alphabet = ""; 8 | 9 | public myMethod = runExclusive.buildMethod( 10 | async (char: string): Promise => { 11 | 12 | await new Promise(resolve => setTimeout(()=>resolve(), 1000)); 13 | 14 | this.alphabet += char; 15 | 16 | return this.alphabet; 17 | 18 | } 19 | ); 20 | 21 | 22 | } 23 | 24 | let inst = new MyClass(); 25 | 26 | setTimeout(() => { 27 | 28 | console.assert(runExclusive.getQueuedCallCount(inst.myMethod, inst) === 3) 29 | 30 | console.assert(inst.alphabet === "ab"); 31 | 32 | runExclusive.cancelAllQueuedCalls(inst.myMethod, inst); 33 | 34 | setTimeout(() => { 35 | 36 | console.assert(inst.alphabet === "abc"); 37 | 38 | console.log("PASS"); 39 | 40 | }, 2000); 41 | 42 | }, 2900); 43 | 44 | for (let char of ["a", "b", "c", "d", "e", "f"]){ 45 | inst.myMethod(char).then(alphabet => console.log(`step ${alphabet}`)); 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/test/testMem1.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as runExclusive from "../lib/runExclusive"; 3 | 4 | function print_mem() { 5 | 6 | const used = process.memoryUsage(); 7 | for (let key in used) { 8 | console.log(`${key} ${Math.round((used as any)[key] / 1024 / 1024 * 100) / 100} MB`); 9 | } 10 | 11 | } 12 | 13 | class A { 14 | 15 | public alphabet= ""; 16 | 17 | public myMethod = runExclusive.buildMethod( 18 | async (char: string) => { 19 | 20 | if( char === "a" ){ 21 | 22 | await new Promise(resolve => process.nextTick(resolve)); 23 | //await new Promise(resolve => setTimeout(resolve,0)); 24 | 25 | } 26 | 27 | this.alphabet+= char; 28 | } 29 | ); 30 | 31 | } 32 | 33 | (async () => { 34 | 35 | while (true) { 36 | 37 | for (let i = 0; i < 7000; i++) { 38 | 39 | const a = new A(); 40 | 41 | a.myMethod("a"); 42 | await a.myMethod("b"); 43 | 44 | console.assert(a.alphabet === "ab"); 45 | 46 | } 47 | 48 | print_mem(); 49 | 50 | } 51 | 52 | })(); -------------------------------------------------------------------------------- /src/test/testMem2.ts: -------------------------------------------------------------------------------- 1 | import * as runExclusive from "../lib/runExclusive"; 2 | 3 | function print_mem() { 4 | 5 | const used = process.memoryUsage(); 6 | for (let key in used) { 7 | console.log(`${key} ${Math.round((used as any)[key] / 1024 / 1024 * 100) / 100} MB`); 8 | } 9 | 10 | } 11 | 12 | console.log("GLOBAL"); 13 | 14 | (async () => { 15 | 16 | while (true) { 17 | 18 | for (let i = 0; i < 7000; i++) { 19 | 20 | let alphabet= ""; 21 | 22 | const myFunction= runExclusive.build(async (char: string)=> { 23 | 24 | if( char === "a" ){ 25 | 26 | await new Promise(resolve=> process.nextTick(resolve)); 27 | 28 | } 29 | 30 | alphabet+= char 31 | 32 | }); 33 | 34 | myFunction("a"); 35 | await myFunction("b"); 36 | 37 | console.assert(alphabet === "ab"); 38 | 39 | } 40 | 41 | print_mem(); 42 | 43 | } 44 | 45 | })(); 46 | 47 | 48 | -------------------------------------------------------------------------------- /tea.yaml: -------------------------------------------------------------------------------- 1 | # https://tea.xyz/what-is-this-file 2 | --- 3 | version: 1.0.0 4 | codeOwners: 5 | - '0x5137A2A9632B8211C9e31dE99DEA14E070a833Dc' 6 | quorum: 1 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es3", 5 | "lib": [ 6 | "es5", 7 | "es2015" 8 | ], 9 | "declaration": true, 10 | "outDir": "./dist", 11 | "sourceMap": true, 12 | "newLine": "LF", 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "incremental": true, 16 | "strict": true, 17 | "isolatedModules": true 18 | }, 19 | "filesGlob": [ 20 | "src/**/*" 21 | ], 22 | "exclude": [ 23 | "node_modules", 24 | "dist/**/*", 25 | "deno_dist/**/*", 26 | "mod.ts" 27 | ] 28 | } -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/code-frame@^7.0.0": 6 | version "7.18.6" 7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" 8 | integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== 9 | dependencies: 10 | "@babel/highlight" "^7.18.6" 11 | 12 | "@babel/helper-validator-identifier@^7.18.6": 13 | version "7.19.1" 14 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" 15 | integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== 16 | 17 | "@babel/highlight@^7.18.6": 18 | version "7.18.6" 19 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" 20 | integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== 21 | dependencies: 22 | "@babel/helper-validator-identifier" "^7.18.6" 23 | chalk "^2.0.0" 24 | js-tokens "^4.0.0" 25 | 26 | "@octokit/auth-token@^2.4.4": 27 | version "2.5.0" 28 | resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36" 29 | integrity sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g== 30 | dependencies: 31 | "@octokit/types" "^6.0.3" 32 | 33 | "@octokit/core@^3.5.1": 34 | version "3.6.0" 35 | resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.6.0.tgz#3376cb9f3008d9b3d110370d90e0a1fcd5fe6085" 36 | integrity sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q== 37 | dependencies: 38 | "@octokit/auth-token" "^2.4.4" 39 | "@octokit/graphql" "^4.5.8" 40 | "@octokit/request" "^5.6.3" 41 | "@octokit/request-error" "^2.0.5" 42 | "@octokit/types" "^6.0.3" 43 | before-after-hook "^2.2.0" 44 | universal-user-agent "^6.0.0" 45 | 46 | "@octokit/endpoint@^6.0.1": 47 | version "6.0.12" 48 | resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" 49 | integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA== 50 | dependencies: 51 | "@octokit/types" "^6.0.3" 52 | is-plain-object "^5.0.0" 53 | universal-user-agent "^6.0.0" 54 | 55 | "@octokit/graphql@^4.5.8": 56 | version "4.8.0" 57 | resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3" 58 | integrity sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg== 59 | dependencies: 60 | "@octokit/request" "^5.6.0" 61 | "@octokit/types" "^6.0.3" 62 | universal-user-agent "^6.0.0" 63 | 64 | "@octokit/openapi-types@^12.10.0": 65 | version "12.10.1" 66 | resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-12.10.1.tgz#57b5cc6c7b4e55d8642c93d06401fb1af4839899" 67 | integrity sha512-P+SukKanjFY0ZhsK6wSVnQmxTP2eVPPE8OPSNuxaMYtgVzwJZgfGdwlYjf4RlRU4vLEw4ts2fsE2icG4nZ5ddQ== 68 | 69 | "@octokit/plugin-paginate-rest@^2.16.8": 70 | version "2.21.3" 71 | resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz#7f12532797775640dbb8224da577da7dc210c87e" 72 | integrity sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw== 73 | dependencies: 74 | "@octokit/types" "^6.40.0" 75 | 76 | "@octokit/plugin-request-log@^1.0.4": 77 | version "1.0.4" 78 | resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85" 79 | integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== 80 | 81 | "@octokit/plugin-rest-endpoint-methods@^5.12.0": 82 | version "5.16.2" 83 | resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz#7ee8bf586df97dd6868cf68f641354e908c25342" 84 | integrity sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw== 85 | dependencies: 86 | "@octokit/types" "^6.39.0" 87 | deprecation "^2.3.1" 88 | 89 | "@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0": 90 | version "2.1.0" 91 | resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677" 92 | integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg== 93 | dependencies: 94 | "@octokit/types" "^6.0.3" 95 | deprecation "^2.0.0" 96 | once "^1.4.0" 97 | 98 | "@octokit/request@^5.6.0", "@octokit/request@^5.6.3": 99 | version "5.6.3" 100 | resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.3.tgz#19a022515a5bba965ac06c9d1334514eb50c48b0" 101 | integrity sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A== 102 | dependencies: 103 | "@octokit/endpoint" "^6.0.1" 104 | "@octokit/request-error" "^2.1.0" 105 | "@octokit/types" "^6.16.1" 106 | is-plain-object "^5.0.0" 107 | node-fetch "^2.6.7" 108 | universal-user-agent "^6.0.0" 109 | 110 | "@octokit/rest@^18.0.0": 111 | version "18.12.0" 112 | resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.12.0.tgz#f06bc4952fc87130308d810ca9d00e79f6988881" 113 | integrity sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q== 114 | dependencies: 115 | "@octokit/core" "^3.5.1" 116 | "@octokit/plugin-paginate-rest" "^2.16.8" 117 | "@octokit/plugin-request-log" "^1.0.4" 118 | "@octokit/plugin-rest-endpoint-methods" "^5.12.0" 119 | 120 | "@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.39.0", "@octokit/types@^6.40.0": 121 | version "6.40.0" 122 | resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.40.0.tgz#f2e665196d419e19bb4265603cf904a820505d0e" 123 | integrity sha512-MFZOU5r8SwgJWDMhrLUSvyJPtVsqA6VnbVI3TNbsmw+Jnvrktzvq2fYES/6RiJA/5Ykdwq4mJmtlYUfW7CGjmw== 124 | dependencies: 125 | "@octokit/openapi-types" "^12.10.0" 126 | 127 | "@types/comment-json@^1.1.1": 128 | version "1.1.1" 129 | resolved "https://registry.yarnpkg.com/@types/comment-json/-/comment-json-1.1.1.tgz#b4ae889912a93e64619f97989aecaff8ce889dca" 130 | integrity sha512-U70oEqvnkeSSp8BIJwJclERtT13rd9ejK7XkIzMCQQePZe3VW1b7iQggXyW4ZvfGtGeXD0pZw24q5iWNe++HqQ== 131 | 132 | "@types/node@^10.3.2": 133 | version "10.17.60" 134 | resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" 135 | integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== 136 | 137 | "@types/parse-json@^4.0.0": 138 | version "4.0.0" 139 | resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" 140 | integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== 141 | 142 | ansi-styles@^3.2.1: 143 | version "3.2.1" 144 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 145 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 146 | dependencies: 147 | color-convert "^1.9.0" 148 | 149 | balanced-match@^1.0.0: 150 | version "1.0.2" 151 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 152 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 153 | 154 | before-after-hook@^2.2.0: 155 | version "2.2.2" 156 | resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" 157 | integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ== 158 | 159 | brace-expansion@^1.1.7: 160 | version "1.1.11" 161 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 162 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 163 | dependencies: 164 | balanced-match "^1.0.0" 165 | concat-map "0.0.1" 166 | 167 | callsites@^3.0.0: 168 | version "3.1.0" 169 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" 170 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== 171 | 172 | chalk@^2.0.0: 173 | version "2.4.2" 174 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 175 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 176 | dependencies: 177 | ansi-styles "^3.2.1" 178 | escape-string-regexp "^1.0.5" 179 | supports-color "^5.3.0" 180 | 181 | color-convert@^1.9.0: 182 | version "1.9.3" 183 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 184 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 185 | dependencies: 186 | color-name "1.1.3" 187 | 188 | color-name@1.1.3: 189 | version "1.1.3" 190 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 191 | integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== 192 | 193 | commander@^4.1.1: 194 | version "4.1.1" 195 | resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" 196 | integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== 197 | 198 | comment-json@^3.0.2: 199 | version "3.0.3" 200 | resolved "https://registry.yarnpkg.com/comment-json/-/comment-json-3.0.3.tgz#0cadacd6278602b57b8c51b1814dc5d311d228c4" 201 | integrity sha512-P7XwYkC3qjIK45EAa9c5Y3lR7SMXhJqwFdWg3niAIAcbk3zlpKDdajV8Hyz/Y3sGNn3l+YNMl8A2N/OubSArHg== 202 | dependencies: 203 | core-util-is "^1.0.2" 204 | esprima "^4.0.1" 205 | has-own-prop "^2.0.0" 206 | repeat-string "^1.6.1" 207 | 208 | concat-map@0.0.1: 209 | version "0.0.1" 210 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 211 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 212 | 213 | core-util-is@^1.0.2: 214 | version "1.0.3" 215 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" 216 | integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== 217 | 218 | cosmiconfig@^7.0.1: 219 | version "7.0.1" 220 | resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" 221 | integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== 222 | dependencies: 223 | "@types/parse-json" "^4.0.0" 224 | import-fresh "^3.2.1" 225 | parse-json "^5.0.0" 226 | path-type "^4.0.0" 227 | yaml "^1.10.0" 228 | 229 | denoify@^1.5.3: 230 | version "1.5.3" 231 | resolved "https://registry.yarnpkg.com/denoify/-/denoify-1.5.3.tgz#8f912721968063354e1e75e403b20fa8c446c997" 232 | integrity sha512-CFXRRBeTfggSdPuhUmfrjnzmrvfY3Cn5YHFt7abTHfYoVBq7gV51k/V2dwwiIMsqplW/xfwPX3wO2TNej/4o+g== 233 | dependencies: 234 | "@octokit/rest" "^18.0.0" 235 | "@types/comment-json" "^1.1.1" 236 | commander "^4.1.1" 237 | comment-json "^3.0.2" 238 | cosmiconfig "^7.0.1" 239 | evt "^2.4.18" 240 | get-github-default-branch-name "^0.0.4" 241 | gitignore-parser "0.0.2" 242 | glob "^7.1.6" 243 | minimal-polyfills "^2.2.2" 244 | node-fetch "^2.6.7" 245 | parse-dont-validate "^4.0.1" 246 | path-depth "^1.0.0" 247 | scripting-tools "^0.19.14" 248 | tsafe "^1.6.0" 249 | url-join "^4.0.1" 250 | 251 | deprecation@^2.0.0, deprecation@^2.3.1: 252 | version "2.3.1" 253 | resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" 254 | integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== 255 | 256 | error-ex@^1.3.1: 257 | version "1.3.2" 258 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" 259 | integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== 260 | dependencies: 261 | is-arrayish "^0.2.1" 262 | 263 | escape-string-regexp@^1.0.5: 264 | version "1.0.5" 265 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 266 | integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== 267 | 268 | esprima@^4.0.1: 269 | version "4.0.1" 270 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 271 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 272 | 273 | evt@^2.4.18: 274 | version "2.4.19" 275 | resolved "https://registry.yarnpkg.com/evt/-/evt-2.4.19.tgz#91e5adc264905f4fbf708894c6167c8537948a10" 276 | integrity sha512-7eSvZt7awZ14ZSpcbWY/MujuGjo1O8IZBeCPkOKNguSU5a0awl93UQVdDm4LyUBLE5ATiLPpQykYmSDZ5zX2GQ== 277 | dependencies: 278 | minimal-polyfills "^2.2.2" 279 | run-exclusive "^2.2.18" 280 | tsafe "^1.6.3" 281 | 282 | fs.realpath@^1.0.0: 283 | version "1.0.0" 284 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 285 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 286 | 287 | get-github-default-branch-name@^0.0.4: 288 | version "0.0.4" 289 | resolved "https://registry.yarnpkg.com/get-github-default-branch-name/-/get-github-default-branch-name-0.0.4.tgz#9c0c6606ba606edb136d2fd26e4d515b69f2de90" 290 | integrity sha512-ltOGC9Jk0k8boe48Gk7SkJErwxt7MhwXtbNrBUyNCZcwcXSmGRdkKb2u0YO250PGvPsUtdqRjg7lVuIk1VtpCg== 291 | dependencies: 292 | "@octokit/rest" "^18.0.0" 293 | scripting-tools "^0.19.12" 294 | 295 | gitignore-parser@0.0.2: 296 | version "0.0.2" 297 | resolved "https://registry.yarnpkg.com/gitignore-parser/-/gitignore-parser-0.0.2.tgz#f61259b985dd91414b9a7168faef9171c2eec5df" 298 | integrity sha512-X6mpqUv59uWLGD4n3hZ8Cu8KbF2PMWPSFYmxZjdkpm3yOU7hSUYnzTkZI1mcWqchphvqyuz3/BhgBR4E/JtkCg== 299 | 300 | glob@^7.1.6: 301 | version "7.2.3" 302 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 303 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 304 | dependencies: 305 | fs.realpath "^1.0.0" 306 | inflight "^1.0.4" 307 | inherits "2" 308 | minimatch "^3.1.1" 309 | once "^1.3.0" 310 | path-is-absolute "^1.0.0" 311 | 312 | has-flag@^3.0.0: 313 | version "3.0.0" 314 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 315 | integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== 316 | 317 | has-own-prop@^2.0.0: 318 | version "2.0.0" 319 | resolved "https://registry.yarnpkg.com/has-own-prop/-/has-own-prop-2.0.0.tgz#f0f95d58f65804f5d218db32563bb85b8e0417af" 320 | integrity sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ== 321 | 322 | import-fresh@^3.2.1: 323 | version "3.3.0" 324 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" 325 | integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== 326 | dependencies: 327 | parent-module "^1.0.0" 328 | resolve-from "^4.0.0" 329 | 330 | inflight@^1.0.4: 331 | version "1.0.6" 332 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 333 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 334 | dependencies: 335 | once "^1.3.0" 336 | wrappy "1" 337 | 338 | inherits@2: 339 | version "2.0.4" 340 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 341 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 342 | 343 | is-arrayish@^0.2.1: 344 | version "0.2.1" 345 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 346 | integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== 347 | 348 | is-plain-object@^5.0.0: 349 | version "5.0.0" 350 | resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" 351 | integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== 352 | 353 | js-tokens@^4.0.0: 354 | version "4.0.0" 355 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 356 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 357 | 358 | json-parse-even-better-errors@^2.3.0: 359 | version "2.3.1" 360 | resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" 361 | integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== 362 | 363 | lines-and-columns@^1.1.6: 364 | version "1.2.4" 365 | resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" 366 | integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== 367 | 368 | minimal-polyfills@^2.2.1: 369 | version "2.2.1" 370 | resolved "https://registry.yarnpkg.com/minimal-polyfills/-/minimal-polyfills-2.2.1.tgz#7249d7ece666d3b4e1ec1c1b8f949eb9d44e2308" 371 | integrity sha512-WLmHQrsZob4rVYf8yHapZPNJZ3sspGa/sN8abuSD59b0FifDEE7HMfLUi24z7mPZqTpBXy4Svp+iGvAmclCmXg== 372 | 373 | minimal-polyfills@^2.2.2: 374 | version "2.2.2" 375 | resolved "https://registry.yarnpkg.com/minimal-polyfills/-/minimal-polyfills-2.2.2.tgz#6b06a004acce420eb91cf94698f5e6e7f2518378" 376 | integrity sha512-eEOUq/LH/DbLWihrxUP050Wi7H/N/I2dQT98Ep6SqOpmIbk4sXOI4wqalve66QoZa+6oljbZWU6I6T4dehQGmw== 377 | 378 | minimal-polyfills@^2.2.3: 379 | version "2.2.3" 380 | resolved "https://registry.yarnpkg.com/minimal-polyfills/-/minimal-polyfills-2.2.3.tgz#22af58de16807b325f29b83ca38ffb83e75ec3f4" 381 | integrity sha512-oxdmJ9cL+xV72h0xYxp4tP2d5/fTBpP45H8DIOn9pASuF8a3IYTf+25fMGDYGiWW+MFsuog6KD6nfmhZJQ+uUw== 382 | 383 | minimatch@^3.1.1: 384 | version "3.1.2" 385 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 386 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 387 | dependencies: 388 | brace-expansion "^1.1.7" 389 | 390 | node-fetch@^2.6.7: 391 | version "2.6.7" 392 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" 393 | integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== 394 | dependencies: 395 | whatwg-url "^5.0.0" 396 | 397 | once@^1.3.0, once@^1.4.0: 398 | version "1.4.0" 399 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 400 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 401 | dependencies: 402 | wrappy "1" 403 | 404 | parent-module@^1.0.0: 405 | version "1.0.1" 406 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" 407 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== 408 | dependencies: 409 | callsites "^3.0.0" 410 | 411 | parse-dont-validate@^4.0.1: 412 | version "4.1.2" 413 | resolved "https://registry.yarnpkg.com/parse-dont-validate/-/parse-dont-validate-4.1.2.tgz#c36ef48c1c99a6a664a47902d5c3353fc5e419f4" 414 | integrity sha512-TxkoQH9lTztT66iUKivXmBVH1xtVJK49VC+45wX7hbD9TCBLW57JulQOq8W4bN5DERMvShGECfwmZs9Rz3WlFA== 415 | 416 | parse-json@^5.0.0: 417 | version "5.2.0" 418 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" 419 | integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== 420 | dependencies: 421 | "@babel/code-frame" "^7.0.0" 422 | error-ex "^1.3.1" 423 | json-parse-even-better-errors "^2.3.0" 424 | lines-and-columns "^1.1.6" 425 | 426 | path-depth@^1.0.0: 427 | version "1.0.0" 428 | resolved "https://registry.yarnpkg.com/path-depth/-/path-depth-1.0.0.tgz#88cf881097e171b8b54d450d2167ea76063d3086" 429 | integrity sha512-dEiwdXAQyLvOi6ktLqhFhjVelJiVsdp2xBX3BaUtYCCkMRZTwUiq7cha+A0myvAVXRHbXfjhfTf4mNoAWzm2iA== 430 | 431 | path-is-absolute@^1.0.0: 432 | version "1.0.1" 433 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 434 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 435 | 436 | path-type@^4.0.0: 437 | version "4.0.0" 438 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" 439 | integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== 440 | 441 | repeat-string@^1.6.1: 442 | version "1.6.1" 443 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" 444 | integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== 445 | 446 | resolve-from@^4.0.0: 447 | version "4.0.0" 448 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 449 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== 450 | 451 | run-exclusive@^2.2.18: 452 | version "2.2.18" 453 | resolved "https://registry.yarnpkg.com/run-exclusive/-/run-exclusive-2.2.18.tgz#ec930edc3a7044750dc827df9372bde8f610f586" 454 | integrity sha512-TXr1Gkl1iEAOCCpBTRm/2m0+1KGjORcWpZZ+VGGTe7dYX8E4y8/fMvrHk0zf+kclec2R//tpvdBxgG0bDgaJfw== 455 | dependencies: 456 | minimal-polyfills "^2.2.1" 457 | 458 | scripting-tools@^0.19.12: 459 | version "0.19.13" 460 | resolved "https://registry.yarnpkg.com/scripting-tools/-/scripting-tools-0.19.13.tgz#836df7d9c2ec99aea91984d1d5b2bd110670afec" 461 | integrity sha512-d09H8vzSVa8p4XUTJqHZDbjKDyl5TG3SyPfNPUUkfyOwjwykStmfK8AXyWq7VRWjcgzTpkTiJ9uMk1NytMQY7w== 462 | 463 | scripting-tools@^0.19.14: 464 | version "0.19.14" 465 | resolved "https://registry.yarnpkg.com/scripting-tools/-/scripting-tools-0.19.14.tgz#d46cdea3dcf042b103b1712103b007e72c4901d5" 466 | integrity sha512-KGRES70dEmcaCdpx3R88bLWmfA4mQ/EGikCQy0FGTZwx3y9F5yYkzEhwp02+ZTgpvF25JcNOhDBbOqL6z92kwg== 467 | 468 | supports-color@^5.3.0: 469 | version "5.5.0" 470 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 471 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 472 | dependencies: 473 | has-flag "^3.0.0" 474 | 475 | tr46@~0.0.3: 476 | version "0.0.3" 477 | resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" 478 | integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== 479 | 480 | tsafe@^1.6.0, tsafe@^1.6.3: 481 | version "1.6.3" 482 | resolved "https://registry.yarnpkg.com/tsafe/-/tsafe-1.6.3.tgz#93a77510f542d9043c6f3ab9ed46267729431a59" 483 | integrity sha512-55Tbbxn6XAx1NX7X+fNfIsKsM6XxcbFbUMZ47fjXlef1g9jV8w+mZi3rse0+9Dj5nQefyWLeYT4cAwyiakWszQ== 484 | 485 | typescript@^3.9.7: 486 | version "3.9.10" 487 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" 488 | integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== 489 | 490 | universal-user-agent@^6.0.0: 491 | version "6.0.0" 492 | resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" 493 | integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== 494 | 495 | url-join@^4.0.1: 496 | version "4.0.1" 497 | resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" 498 | integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== 499 | 500 | webidl-conversions@^3.0.0: 501 | version "3.0.1" 502 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" 503 | integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== 504 | 505 | whatwg-url@^5.0.0: 506 | version "5.0.0" 507 | resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" 508 | integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== 509 | dependencies: 510 | tr46 "~0.0.3" 511 | webidl-conversions "^3.0.0" 512 | 513 | wrappy@1: 514 | version "1.0.2" 515 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 516 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 517 | 518 | yaml@^1.10.0: 519 | version "1.10.2" 520 | resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" 521 | integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== 522 | --------------------------------------------------------------------------------