Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 597e9e15c3 | |||
| 03a33195bc | |||
| 47d339bb2b | |||
| bf3b4e832a | |||
| 685f4ebb3b | |||
| 2ff7efe6d8 | |||
| 99072d5fdf | |||
| 4442ddffcd | |||
| 7c5b3825ac | |||
| 84babb3cd4 | |||
| 5d9624bd56 | |||
| 32397a97cd | |||
| 753b829d18 | |||
| 4be2784bf4 | |||
| cd08cf370c | |||
| b64fe567a8 | |||
| 2a68c9ad90 | |||
| aa978413d1 | |||
| f24636ba80 | |||
| 5e31dbb504 | |||
| b2ca6e13e7 | |||
| 052322fb98 | |||
| 9e1eb0b3a0 |
91
changelog.md
Normal file
91
changelog.md
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-03-01 - 6.3.0 - feat(tooling)
|
||||||
|
update build tooling, developer dependencies, npmextra configuration, and expand README documentation
|
||||||
|
|
||||||
|
- Bump devDependencies for @git.zone toolchain and related packages (@git.zone/tsbuild, tsbundle, tsrun, tstest, @push.rocks/tapbundle, @types/node)
|
||||||
|
- Bump runtime deps: @push.rocks/smartrx and @push.rocks/smarttime
|
||||||
|
- Adjust npm build script: remove trailing 'npm' argument from tsbundle invocation
|
||||||
|
- Rework npmextra.json: rename/unify keys to @git.zone/* scoped entries, add release registries and accessLevel, add tsbundle bundle configuration, and reorganize CI/tool settings
|
||||||
|
- Significant README rewrite: expanded descriptions, clearer usage examples and API snippets, formatting and example updates
|
||||||
|
|
||||||
|
## 2026-03-01 - 6.2.3 - fix(interestmap)
|
||||||
|
remove interest from InterestMap immediately after fulfillment
|
||||||
|
|
||||||
|
- Call destroy() in fullfillInterest to remove the interest entry from the InterestMap right after resolving interestDeferred.
|
||||||
|
- Prevents stale entries and ensures immediate cleanup of fulfilled interests
|
||||||
|
|
||||||
|
## 2025-04-25 - 6.2.2 - fix(docs)
|
||||||
|
Update @push.rocks/tapbundle dependency and refine AsyncExecutionStack documentation examples
|
||||||
|
|
||||||
|
- Bump @push.rocks/tapbundle from ^5.0.8 to ^5.5.6 in package.json
|
||||||
|
- Improve README documentation for AsyncExecutionStack with clearer examples for exclusive and non-exclusive task execution
|
||||||
|
- Demonstrate usage of concurrency controls in AsyncExecutionStack
|
||||||
|
|
||||||
|
## 2025-04-25 - 6.2.1 - fix(AsyncExecutionStack tests)
|
||||||
|
Refactor AsyncExecutionStack tests: update non-exclusive concurrency assertions and clean up test logic
|
||||||
|
|
||||||
|
- Replace 'toBe' with 'toEqual' for active and pending counts to ensure consistency
|
||||||
|
- Simplify default non-exclusive concurrency test by asserting Infinity is non-finite using toBeFalse
|
||||||
|
- Adjust test comments and scheduling for clarity in concurrency behavior
|
||||||
|
|
||||||
|
## 2025-04-25 - 6.2.0 - feat(AsyncExecutionStack)
|
||||||
|
Improve non-exclusive task management with concurrency limit controls and enhanced monitoring in AsyncExecutionStack.
|
||||||
|
|
||||||
|
- Added methods to set and get non-exclusive concurrency limits and statistics (setNonExclusiveMaxConcurrency, getActiveNonExclusiveCount, getPendingNonExclusiveCount, and getNonExclusiveMaxConcurrency).
|
||||||
|
- Integrated proper waiting and release mechanisms for non-exclusive slots.
|
||||||
|
- Extended test coverage to validate concurrency limits and ensure correct behavior.
|
||||||
|
|
||||||
|
## 2024-10-13 - 6.1.0 - feat(BackpressuredArray)
|
||||||
|
Add method to check if items are present in BackpressuredArray
|
||||||
|
|
||||||
|
- Implemented a new method `checkHasItems` in the BackpressuredArray class to determine if the array contains any items.
|
||||||
|
|
||||||
|
## 2024-05-29 to 2024-04-18 - 6.0.15
|
||||||
|
Minor updates were made to documentation and descriptions.
|
||||||
|
|
||||||
|
- Update project description
|
||||||
|
|
||||||
|
## 2024-04-18 to 2024-02-25 - 6.0.14
|
||||||
|
Several updates were made to configurations and json files.
|
||||||
|
|
||||||
|
- Updated core components in the codebase
|
||||||
|
- Modified tsconfig settings
|
||||||
|
- Revised npmextra.json with githost configurations
|
||||||
|
|
||||||
|
## 2024-02-25 to 2024-02-23 - 6.0.13
|
||||||
|
No relevant changes.
|
||||||
|
|
||||||
|
## 2024-02-23 to 2023-11-13 - 6.0.12 to 6.0.8
|
||||||
|
Multiple core updates were performed to ensure stability and performance.
|
||||||
|
|
||||||
|
- Fixed various issues in core components
|
||||||
|
|
||||||
|
## 2023-11-13 to 2023-08-14 - 6.0.7 to 6.0.3
|
||||||
|
Minor internal core updates.
|
||||||
|
|
||||||
|
## 2023-08-14 to 2023-07-12 - 6.0.2
|
||||||
|
Implemented a switch to a new organizational scheme.
|
||||||
|
|
||||||
|
## 2023-01-18 to 2022-05-27 - 6.0.0
|
||||||
|
Updated core functionalities; introduced breaking changes for compatibility with ECMAScript modules.
|
||||||
|
|
||||||
|
- Core updates
|
||||||
|
- Switching from CommonJS to ECMAScript modules
|
||||||
|
|
||||||
|
## 2022-05-27 to 2022-05-27 - 5.0.6 to 5.0.0
|
||||||
|
Minor updates and a significant change in `objectmap` behavior to support async operations.
|
||||||
|
|
||||||
|
- Included async behaviors in objectmap as a breaking change
|
||||||
|
|
||||||
|
## 2020-05-04 to 2020-02-17 - 4.0.0
|
||||||
|
Refactored ObjectMap; introduced new features.
|
||||||
|
|
||||||
|
- Refactored ObjectMap with concat functionality as a breaking change
|
||||||
|
- Added .clean() to FastMap
|
||||||
|
|
||||||
|
## 2020-02-17 to 2020-02-06 - 3.0.19 to 3.0.15
|
||||||
|
Enhancements and new functionality in ObjectMap.
|
||||||
|
|
||||||
|
- Added object mapping enhancements
|
||||||
|
- Introduced object map with unique keys
|
||||||
@@ -1,17 +1,49 @@
|
|||||||
{
|
{
|
||||||
"npmci": {
|
"@git.zone/cli": {
|
||||||
"npmGlobalTools": [],
|
|
||||||
"npmAccessLevel": "public"
|
|
||||||
},
|
|
||||||
"gitzone": {
|
|
||||||
"projectType": "npm",
|
"projectType": "npm",
|
||||||
"module": {
|
"module": {
|
||||||
"githost": "gitlab.com",
|
"githost": "code.foss.global",
|
||||||
"gitscope": "push.rocks",
|
"gitscope": "push.rocks",
|
||||||
"gitrepo": "lik",
|
"gitrepo": "lik",
|
||||||
"description": "light little helpers for node",
|
"description": "Provides a collection of lightweight helpers and utilities for Node.js projects.",
|
||||||
"npmPackagename": "@push.rocks/lik",
|
"npmPackagename": "@push.rocks/lik",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"Utilities",
|
||||||
|
"Helpers",
|
||||||
|
"Typescript",
|
||||||
|
"Node.js",
|
||||||
|
"String manipulation",
|
||||||
|
"Object management",
|
||||||
|
"Execution control",
|
||||||
|
"Data structures",
|
||||||
|
"Asynchronous programming",
|
||||||
|
"Event handling",
|
||||||
|
"Data aggregation"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"release": {
|
||||||
|
"registries": [
|
||||||
|
"https://verdaccio.lossless.digital",
|
||||||
|
"https://registry.npmjs.org"
|
||||||
|
],
|
||||||
|
"accessLevel": "public"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"@git.zone/tsdoc": {
|
||||||
|
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
|
||||||
|
},
|
||||||
|
"@git.zone/tsbundle": {
|
||||||
|
"bundles": [
|
||||||
|
{
|
||||||
|
"from": "./ts/index.ts",
|
||||||
|
"to": "./dist_bundle/bundle.js",
|
||||||
|
"outputMode": "bundle",
|
||||||
|
"bundler": "esbuild"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"@ship.zone/szci": {
|
||||||
|
"npmGlobalTools": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
49
package.json
49
package.json
@@ -1,40 +1,40 @@
|
|||||||
{
|
{
|
||||||
"name": "@push.rocks/lik",
|
"name": "@push.rocks/lik",
|
||||||
"version": "6.0.12",
|
"version": "6.3.0",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "light little helpers for node",
|
"description": "Provides a collection of lightweight helpers and utilities for Node.js projects.",
|
||||||
"main": "dist_ts/index.js",
|
"main": "dist_ts/index.js",
|
||||||
"typings": "dist_ts/index.d.ts",
|
"typings": "dist_ts/index.d.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "(tstest test/)",
|
"test": "(tstest test/)",
|
||||||
"build": "(tsbuild --web --allowimplicitany && tsbundle npm)",
|
"build": "(tsbuild --web --allowimplicitany && tsbundle)",
|
||||||
"buildDocs": "tsdoc"
|
"buildDocs": "tsdoc"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+ssh://git@gitlab.com/pushrocks/lik.git"
|
"url": "https://code.foss.global/push.rocks/lik.git"
|
||||||
},
|
},
|
||||||
"author": "Lossless GmbH",
|
"author": "Lossless GmbH",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://gitlab.com/pushrocks/lik/issues"
|
"url": "https://gitlab.com/pushrocks/lik/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://gitlab.com/pushrocks/lik#README",
|
"homepage": "https://code.foss.global/push.rocks/lik",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@git.zone/tsbuild": "^2.1.66",
|
"@git.zone/tsbuild": "^4.1.2",
|
||||||
"@git.zone/tsbundle": "^2.0.8",
|
"@git.zone/tsbundle": "^2.9.0",
|
||||||
"@git.zone/tsrun": "^1.2.44",
|
"@git.zone/tsrun": "^2.0.1",
|
||||||
"@git.zone/tstest": "^1.0.77",
|
"@git.zone/tstest": "^3.1.8",
|
||||||
"@pushrocks/tapbundle": "^5.0.8",
|
"@push.rocks/tapbundle": "^6.0.3",
|
||||||
"@types/node": "^20.9.0"
|
"@types/node": "^25.3.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@push.rocks/smartdelay": "^3.0.5",
|
"@push.rocks/smartdelay": "^3.0.5",
|
||||||
"@push.rocks/smartmatch": "^2.0.0",
|
"@push.rocks/smartmatch": "^2.0.0",
|
||||||
"@push.rocks/smartpromise": "^4.0.3",
|
"@push.rocks/smartpromise": "^4.0.3",
|
||||||
"@push.rocks/smartrx": "^3.0.7",
|
"@push.rocks/smartrx": "^3.0.10",
|
||||||
"@push.rocks/smarttime": "^4.0.6",
|
"@push.rocks/smarttime": "^4.2.3",
|
||||||
"@types/minimatch": "^5.1.2",
|
"@types/minimatch": "^5.1.2",
|
||||||
"@types/symbol-tree": "^3.2.5",
|
"@types/symbol-tree": "^3.2.5",
|
||||||
"symbol-tree": "^3.2.4"
|
"symbol-tree": "^3.2.4"
|
||||||
@@ -53,5 +53,26 @@
|
|||||||
],
|
],
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"last 1 chrome versions"
|
"last 1 chrome versions"
|
||||||
]
|
],
|
||||||
|
"keywords": [
|
||||||
|
"Utilities",
|
||||||
|
"Helpers",
|
||||||
|
"Typescript",
|
||||||
|
"Node.js",
|
||||||
|
"String manipulation",
|
||||||
|
"Object management",
|
||||||
|
"Execution control",
|
||||||
|
"Data structures",
|
||||||
|
"Asynchronous programming",
|
||||||
|
"Event handling",
|
||||||
|
"Data aggregation"
|
||||||
|
],
|
||||||
|
"pnpm": {
|
||||||
|
"onlyBuiltDependencies": [
|
||||||
|
"esbuild",
|
||||||
|
"mongodb-memory-server",
|
||||||
|
"puppeteer"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6"
|
||||||
}
|
}
|
||||||
|
|||||||
14645
pnpm-lock.yaml
generated
14645
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
1
readme.hints.md
Normal file
1
readme.hints.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
333
readme.md
333
readme.md
@@ -1,52 +1,315 @@
|
|||||||
# @push.rocks/lik
|
# @push.rocks/lik
|
||||||
light little helpers for node
|
|
||||||
|
|
||||||
## Availabililty and Links
|
A collection of lightweight utility classes for TypeScript/Node.js projects, providing efficient data structures and async helpers.
|
||||||
* [npmjs.org (npm package)](https://www.npmjs.com/package/@push.rocks/lik)
|
|
||||||
* [gitlab.com (source)](https://gitlab.com/push.rocks/lik)
|
|
||||||
* [github.com (source mirror)](https://github.com/push.rocks/lik)
|
|
||||||
* [docs (typedoc)](https://push.rocks.gitlab.io/lik/)
|
|
||||||
|
|
||||||
## Status for master
|
## Install
|
||||||
|
|
||||||
Status Category | Status Badge
|
```bash
|
||||||
-- | --
|
npm install @push.rocks/lik
|
||||||
GitLab Pipelines | [](https://lossless.cloud)
|
```
|
||||||
GitLab Pipline Test Coverage | [](https://lossless.cloud)
|
|
||||||
npm | [](https://lossless.cloud)
|
|
||||||
Snyk | [](https://lossless.cloud)
|
|
||||||
TypeScript Support | [](https://lossless.cloud)
|
|
||||||
node Support | [](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
|
||||||
Code Style | [](https://lossless.cloud)
|
|
||||||
PackagePhobia (total standalone install weight) | [](https://lossless.cloud)
|
|
||||||
PackagePhobia (package size on registry) | [](https://lossless.cloud)
|
|
||||||
BundlePhobia (total size when bundled) | [](https://lossless.cloud)
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Use TypeScript for best in class instellisense.
|
`@push.rocks/lik` provides a set of focused helper classes for common programming tasks: managing collections, controlling async execution, tracking interests, and more. All classes are fully typed and work in both Node.js and browser environments.
|
||||||
|
|
||||||
```javascript
|
### AsyncExecutionStack
|
||||||
// import any tool that you need from lik
|
|
||||||
import { Stringmap, Objectmap, Observablemap } from 'lik';
|
Controls execution of asynchronous tasks in two modes:
|
||||||
|
|
||||||
|
- **Exclusive**: tasks run one at a time, blocking all others until complete.
|
||||||
|
- **Non-exclusive**: tasks run in parallel with optional concurrency limits.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { AsyncExecutionStack } from '@push.rocks/lik';
|
||||||
|
|
||||||
|
const stack = new AsyncExecutionStack();
|
||||||
|
|
||||||
|
// Exclusive execution (sequential, blocks other tasks)
|
||||||
|
await stack.getExclusiveExecutionSlot(async () => {
|
||||||
|
// critical section work
|
||||||
|
}, 5000); // optional timeout in ms
|
||||||
|
|
||||||
|
// Non-exclusive execution (parallel)
|
||||||
|
const p1 = stack.getNonExclusiveExecutionSlot(async () => {
|
||||||
|
// concurrent work 1
|
||||||
|
});
|
||||||
|
const p2 = stack.getNonExclusiveExecutionSlot(async () => {
|
||||||
|
// concurrent work 2
|
||||||
|
});
|
||||||
|
await Promise.all([p1, p2]);
|
||||||
|
|
||||||
|
// Control concurrency
|
||||||
|
stack.setNonExclusiveMaxConcurrency(3);
|
||||||
|
console.log(stack.getNonExclusiveMaxConcurrency()); // 3
|
||||||
|
console.log(stack.getActiveNonExclusiveCount()); // currently running
|
||||||
|
console.log(stack.getPendingNonExclusiveCount()); // waiting for slots
|
||||||
```
|
```
|
||||||
|
|
||||||
### class Stringmap
|
### BackpressuredArray
|
||||||
|
|
||||||
Stringmap allows you to keep track of strings. It allows you to register triggers for certain events
|
An array with backpressure support using RxJS subjects. Useful for producer/consumer patterns where you need to throttle the producer when the consumer can't keep up.
|
||||||
like when a certain string is removed or added to the map
|
|
||||||
|
|
||||||
### class Objectmap
|
```typescript
|
||||||
|
import { BackpressuredArray } from '@push.rocks/lik';
|
||||||
|
|
||||||
Sometimes you need to keep track of objects, but implementing logic for removing, finding or updating is tedious.
|
const buffer = new BackpressuredArray<string>(16); // high water mark of 16
|
||||||
Objectmap takes care of keeping track of objects for you.
|
|
||||||
|
|
||||||
## Contribution
|
// Producer: push items, returns false when full
|
||||||
|
const hasSpace = buffer.push('item1');
|
||||||
|
if (!hasSpace) {
|
||||||
|
await buffer.waitForSpace(); // wait until consumer frees space
|
||||||
|
}
|
||||||
|
|
||||||
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
|
// Consumer: shift items out
|
||||||
|
await buffer.waitForItems(); // wait until items are available
|
||||||
|
const item = buffer.shift();
|
||||||
|
|
||||||
For further information read the linked docs at the top of this readme.
|
// Check state
|
||||||
|
buffer.checkSpaceAvailable(); // true if below high water mark
|
||||||
|
buffer.checkHasItems(); // true if items exist
|
||||||
|
```
|
||||||
|
|
||||||
## Legal
|
### FastMap
|
||||||
> MIT licensed | **©** [Task Venture Capital GmbH](https://task.vc)
|
|
||||||
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
|
A high-performance key-value map optimized for rapid lookups and modifications.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { FastMap } from '@push.rocks/lik';
|
||||||
|
|
||||||
|
const map = new FastMap<string>();
|
||||||
|
|
||||||
|
map.addToMap('key1', 'value1');
|
||||||
|
map.addToMap('key2', 'value2');
|
||||||
|
|
||||||
|
const value = map.getByKey('key1'); // 'value1'
|
||||||
|
map.isUniqueKey('key1'); // false (already exists)
|
||||||
|
map.removeFromMap('key1');
|
||||||
|
|
||||||
|
// Merge maps
|
||||||
|
const otherMap = new FastMap<string>();
|
||||||
|
otherMap.addToMap('key3', 'value3');
|
||||||
|
const merged = map.concat(otherMap);
|
||||||
|
|
||||||
|
// Or merge in place
|
||||||
|
map.addAllFromOther(otherMap);
|
||||||
|
|
||||||
|
// Async find
|
||||||
|
const found = await map.find(async (item) => item === 'value2');
|
||||||
|
```
|
||||||
|
|
||||||
|
### InterestMap
|
||||||
|
|
||||||
|
Manages subscriptions/interests in events or entities. Multiple parties can express interest in the same thing; the interest is deduplicated and fulfilled once.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { InterestMap } from '@push.rocks/lik';
|
||||||
|
|
||||||
|
const interestMap = new InterestMap<string, number>(
|
||||||
|
(str) => str, // comparison function to deduplicate interests
|
||||||
|
{ markLostAfterDefault: 30000 } // optional: auto-mark lost after 30s
|
||||||
|
);
|
||||||
|
|
||||||
|
// Express interest
|
||||||
|
const interest = await interestMap.addInterest('event1');
|
||||||
|
|
||||||
|
// Wait for fulfillment
|
||||||
|
interest.interestFullfilled.then((result) => {
|
||||||
|
console.log('Got result:', result);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fulfill from elsewhere
|
||||||
|
const found = interestMap.findInterest('event1');
|
||||||
|
found.fullfillInterest(42);
|
||||||
|
|
||||||
|
// Check and manage interests
|
||||||
|
interestMap.checkInterest('event1'); // true/false
|
||||||
|
interestMap.informLostInterest('event1'); // starts destruction timer
|
||||||
|
|
||||||
|
// Observable stream of new interests
|
||||||
|
interestMap.interestObservable; // ObservableIntake<Interest>
|
||||||
|
```
|
||||||
|
|
||||||
|
### LimitedArray
|
||||||
|
|
||||||
|
An array that automatically enforces a maximum size, discarding oldest items when the limit is exceeded.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { LimitedArray } from '@push.rocks/lik';
|
||||||
|
|
||||||
|
const arr = new LimitedArray<number>(5);
|
||||||
|
|
||||||
|
arr.addMany([1, 2, 3, 4, 5, 6]);
|
||||||
|
console.log(arr.array.length); // 5 (oldest items dropped)
|
||||||
|
|
||||||
|
arr.addOne(7);
|
||||||
|
arr.setLimit(3); // dynamically adjust limit
|
||||||
|
|
||||||
|
// Compute average (for numeric arrays)
|
||||||
|
const numArr = new LimitedArray<number>(10);
|
||||||
|
numArr.addMany([10, 20, 30]);
|
||||||
|
console.log(numArr.getAverage()); // 20
|
||||||
|
```
|
||||||
|
|
||||||
|
### LoopTracker
|
||||||
|
|
||||||
|
Detects and prevents infinite loops by tracking object references during iterations.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { LoopTracker } from '@push.rocks/lik';
|
||||||
|
|
||||||
|
const tracker = new LoopTracker<object>();
|
||||||
|
const obj1 = {};
|
||||||
|
|
||||||
|
tracker.checkAndTrack(obj1); // true (first time, tracked)
|
||||||
|
tracker.checkAndTrack(obj1); // false (already seen - loop detected!)
|
||||||
|
```
|
||||||
|
|
||||||
|
### ObjectMap
|
||||||
|
|
||||||
|
A managed collection of objects with add/remove/find operations and event notifications via RxJS.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { ObjectMap } from '@push.rocks/lik';
|
||||||
|
|
||||||
|
interface IUser {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const users = new ObjectMap<IUser>();
|
||||||
|
|
||||||
|
// Add objects
|
||||||
|
const key = users.add({ id: 1, name: 'Alice' });
|
||||||
|
users.addArray([{ id: 2, name: 'Bob' }, { id: 3, name: 'Carol' }]);
|
||||||
|
|
||||||
|
// Find objects
|
||||||
|
const alice = users.findSync((u) => u.id === 1);
|
||||||
|
const bob = await users.find(async (u) => u.id === 2);
|
||||||
|
|
||||||
|
// Find and remove in one step
|
||||||
|
const removed = await users.findOneAndRemove(async (u) => u.id === 3);
|
||||||
|
const removedSync = users.findOneAndRemoveSync((u) => u.id === 2);
|
||||||
|
|
||||||
|
// Direct add/get by unique key
|
||||||
|
users.addMappedUnique('admin', { id: 99, name: 'Admin' });
|
||||||
|
const admin = users.getMappedUnique('admin');
|
||||||
|
|
||||||
|
// Get one and remove (FIFO-style)
|
||||||
|
const first = users.getOneAndRemove();
|
||||||
|
|
||||||
|
// Iterate, check, and manage
|
||||||
|
await users.forEach((u) => console.log(u.name));
|
||||||
|
users.checkForObject(alice); // true/false
|
||||||
|
users.isEmpty(); // true/false
|
||||||
|
users.getArray(); // cloned array of all objects
|
||||||
|
users.wipe(); // remove all
|
||||||
|
|
||||||
|
// Listen for changes
|
||||||
|
users.eventSubject.subscribe((event) => {
|
||||||
|
console.log(event.operation, event.payload); // 'add' | 'remove'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Merge object maps
|
||||||
|
const merged = users.concat(otherObjectMap);
|
||||||
|
users.addAllFromOther(otherObjectMap);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stringmap
|
||||||
|
|
||||||
|
Manages a collection of strings with add/remove/query operations and minimatch pattern matching.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Stringmap } from '@push.rocks/lik';
|
||||||
|
|
||||||
|
const strings = new Stringmap();
|
||||||
|
|
||||||
|
strings.addString('hello');
|
||||||
|
strings.addStringArray(['world', 'example']);
|
||||||
|
|
||||||
|
strings.checkString('hello'); // true
|
||||||
|
strings.checkMinimatch('hel*'); // true (glob matching)
|
||||||
|
strings.checkIsEmpty(); // false
|
||||||
|
|
||||||
|
strings.removeString('hello');
|
||||||
|
strings.getStringArray(); // ['world', 'example']
|
||||||
|
|
||||||
|
// Register trigger that fires when condition is met
|
||||||
|
await strings.registerUntilTrue((arr) => arr.length === 0);
|
||||||
|
strings.wipe(); // triggers the above
|
||||||
|
```
|
||||||
|
|
||||||
|
### TimedAggregator
|
||||||
|
|
||||||
|
Batches items over a time interval, then processes them in bulk. Useful for aggregating logs, metrics, or events.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { TimedAggregtor } from '@push.rocks/lik';
|
||||||
|
|
||||||
|
const aggregator = new TimedAggregtor<string>({
|
||||||
|
aggregationIntervalInMillis: 5000,
|
||||||
|
functionForAggregation: (items) => {
|
||||||
|
console.log('Batch:', items);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
aggregator.add('event1');
|
||||||
|
aggregator.add('event2');
|
||||||
|
// After 5 seconds: Batch: ['event1', 'event2']
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tree
|
||||||
|
|
||||||
|
A typed wrapper around `symbol-tree` for managing hierarchical data structures with parent/child/sibling relationships.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Tree } from '@push.rocks/lik';
|
||||||
|
|
||||||
|
class TreeNode {
|
||||||
|
constructor(public value: string) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tree = new Tree<TreeNode>();
|
||||||
|
const root = new TreeNode('root');
|
||||||
|
tree.initialize(root);
|
||||||
|
|
||||||
|
const child1 = new TreeNode('child1');
|
||||||
|
const child2 = new TreeNode('child2');
|
||||||
|
tree.appendChild(root, child1);
|
||||||
|
tree.appendChild(root, child2);
|
||||||
|
|
||||||
|
// Navigate
|
||||||
|
tree.hasChildren(root); // true
|
||||||
|
tree.firstChild(root); // child1
|
||||||
|
tree.lastChild(root); // child2
|
||||||
|
tree.nextSibling(child1); // child2
|
||||||
|
tree.parent(child1); // root
|
||||||
|
|
||||||
|
// Query
|
||||||
|
tree.childrenCount(root); // 2
|
||||||
|
tree.index(child2); // 1
|
||||||
|
tree.childrenToArray(root, {}); // [child1, child2]
|
||||||
|
tree.treeToArray(root, {}); // full tree as array
|
||||||
|
|
||||||
|
// Mutate
|
||||||
|
tree.insertBefore(child2, new TreeNode('between'));
|
||||||
|
tree.remove(child2);
|
||||||
|
```
|
||||||
|
|
||||||
|
## License and Legal Information
|
||||||
|
|
||||||
|
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||||
|
|
||||||
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
### Trademarks
|
||||||
|
|
||||||
|
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||||
|
|
||||||
|
### Company Information
|
||||||
|
|
||||||
|
Task Venture Capital GmbH
|
||||||
|
Registered at District court Bremen HRB 35230 HB, Germany
|
||||||
|
|
||||||
|
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||||
|
|
||||||
|
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { tap, expect } from '@pushrocks/tapbundle';
|
import { tap, expect } from '@push.rocks/tapbundle';
|
||||||
import * as lik from '../ts/index.js';
|
import * as lik from '../ts/index.js';
|
||||||
|
|
||||||
let testAsyncExecutionStack: lik.AsyncExecutionStack;
|
let testAsyncExecutionStack: lik.AsyncExecutionStack;
|
||||||
@@ -26,4 +26,66 @@ tap.test('should run in parallel', async (toolsArg) => {
|
|||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
await tap.start();
|
// Test default non-exclusive has no concurrency limit property (Infinity)
|
||||||
|
tap.test('default non-exclusive has no concurrency limit', () => {
|
||||||
|
const stack = new lik.AsyncExecutionStack();
|
||||||
|
// default maxConcurrency is Infinity (not finite)
|
||||||
|
expect(Number.isFinite(stack.getNonExclusiveMaxConcurrency())).toBeFalse();
|
||||||
|
});
|
||||||
|
// Test respecting a non-exclusive concurrency limit
|
||||||
|
tap.test('non-exclusive respects maxConcurrency', async (tools) => {
|
||||||
|
const stack = new lik.AsyncExecutionStack();
|
||||||
|
stack.setNonExclusiveMaxConcurrency(2);
|
||||||
|
const activeCounts: number[] = [];
|
||||||
|
const tasks: Promise<void>[] = [];
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
tasks.push(
|
||||||
|
stack.getNonExclusiveExecutionSlot(async () => {
|
||||||
|
activeCounts.push(stack.getActiveNonExclusiveCount());
|
||||||
|
await tools.delayFor(50);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await Promise.all(tasks);
|
||||||
|
// never more than 2 at once
|
||||||
|
const maxActive = Math.max(...activeCounts);
|
||||||
|
expect(maxActive).toBeLessThanOrEqual(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test concurrency stats (active vs pending) for non-exclusive tasks
|
||||||
|
tap.test('non-exclusive concurrency stats reflect active and pending', async (tools) => {
|
||||||
|
const stack = new lik.AsyncExecutionStack();
|
||||||
|
stack.setNonExclusiveMaxConcurrency(2);
|
||||||
|
// initially, no tasks
|
||||||
|
expect(stack.getActiveNonExclusiveCount()).toEqual(0);
|
||||||
|
expect(stack.getPendingNonExclusiveCount()).toEqual(0);
|
||||||
|
|
||||||
|
// enqueue four tasks
|
||||||
|
const p1 = stack.getNonExclusiveExecutionSlot(async () => {
|
||||||
|
await tools.delayFor(30);
|
||||||
|
});
|
||||||
|
const p2 = stack.getNonExclusiveExecutionSlot(async () => {
|
||||||
|
await tools.delayFor(30);
|
||||||
|
});
|
||||||
|
const p3 = stack.getNonExclusiveExecutionSlot(async () => {
|
||||||
|
await tools.delayFor(30);
|
||||||
|
});
|
||||||
|
const p4 = stack.getNonExclusiveExecutionSlot(async () => {
|
||||||
|
await tools.delayFor(30);
|
||||||
|
});
|
||||||
|
|
||||||
|
// wait for first task to finish and scheduling of next batch
|
||||||
|
await p1;
|
||||||
|
await tools.delayFor(0);
|
||||||
|
// second batch: two active, one pending (4 tasks, limit=2)
|
||||||
|
expect(stack.getActiveNonExclusiveCount()).toEqual(2);
|
||||||
|
expect(stack.getPendingNonExclusiveCount()).toEqual(1);
|
||||||
|
|
||||||
|
// wait for remaining tasks to complete
|
||||||
|
await Promise.all([p2, p3, p4]);
|
||||||
|
// after completion, counts reset
|
||||||
|
expect(stack.getActiveNonExclusiveCount()).toEqual(0);
|
||||||
|
expect(stack.getPendingNonExclusiveCount()).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default tap.start();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { tap, expect } from '@pushrocks/tapbundle';
|
import { tap, expect } from '@push.rocks/tapbundle';
|
||||||
|
|
||||||
import * as lik from '../ts/index.js';
|
import * as lik from '../ts/index.js';
|
||||||
|
|
||||||
@@ -27,4 +27,4 @@ tap.test('should find an entry', async () => {
|
|||||||
expect(result.value1).toEqual('heyho3');
|
expect(result.value1).toEqual('heyho3');
|
||||||
});
|
});
|
||||||
|
|
||||||
await tap.start();
|
export default tap.start();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { tap, expect } from '@pushrocks/tapbundle';
|
import { tap, expect } from '@push.rocks/tapbundle';
|
||||||
import * as lik from '../ts/index.js';
|
import * as lik from '../ts/index.js';
|
||||||
|
|
||||||
let testInterestmap: lik.InterestMap<number, number>;
|
let testInterestmap: lik.InterestMap<number, number>;
|
||||||
@@ -22,4 +22,4 @@ tap.test('should be able to inform about a lost interest', async () => {
|
|||||||
testInterestmap.informLostInterest(3);
|
testInterestmap.informLostInterest(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
await tap.start();
|
export default tap.start();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { tap, expect } from '@pushrocks/tapbundle';
|
import { tap, expect } from '@push.rocks/tapbundle';
|
||||||
|
|
||||||
import { LimitedArray } from '../ts/index.js';
|
import { LimitedArray } from '../ts/index.js';
|
||||||
|
|
||||||
@@ -14,4 +14,4 @@ tap.test('should never be longer than the set length', async () => {
|
|||||||
expect(testLimitedArray.array.length < 7).toBeTrue();
|
expect(testLimitedArray.array.length < 7).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
await tap.start();
|
export default tap.start();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// import test framework
|
// import test framework
|
||||||
import { expect, tap } from '@pushrocks/tapbundle';
|
import { expect, tap } from '@push.rocks/tapbundle';
|
||||||
|
|
||||||
// import the module
|
// import the module
|
||||||
import * as lik from '../ts/index.js';
|
import * as lik from '../ts/index.js';
|
||||||
@@ -21,4 +21,4 @@ tap.test('should add objects once and return true', async () => {
|
|||||||
expect(myLoopTracker.checkAndTrack(object2)).toBeFalse();
|
expect(myLoopTracker.checkAndTrack(object2)).toBeFalse();
|
||||||
});
|
});
|
||||||
|
|
||||||
await tap.start();
|
export default tap.start();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// import test framework
|
// import test framework
|
||||||
import { expect, tap } from '@pushrocks/tapbundle';
|
import { expect, tap } from '@push.rocks/tapbundle';
|
||||||
|
|
||||||
// import the module
|
// import the module
|
||||||
import * as lik from '../ts/index.js';
|
import * as lik from '../ts/index.js';
|
||||||
@@ -73,4 +73,4 @@ tap.test('should get one object and then remove it', async () => {
|
|||||||
expect(testObjectmap.getArray()).not.toContain(oneObject);
|
expect(testObjectmap.getArray()).not.toContain(oneObject);
|
||||||
});
|
});
|
||||||
|
|
||||||
await tap.start();
|
export default tap.start();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// import test framework
|
// import test framework
|
||||||
import { expect, tap } from '@pushrocks/tapbundle';
|
import { expect, tap } from '@push.rocks/tapbundle';
|
||||||
|
|
||||||
// import the module
|
// import the module
|
||||||
import * as lik from '../ts/index.js';
|
import * as lik from '../ts/index.js';
|
||||||
@@ -83,4 +83,4 @@ tap.test('lik.Stringmap.empty() -> should remove wipe and then notify', async ()
|
|||||||
testStringmap.wipe();
|
testStringmap.wipe();
|
||||||
});
|
});
|
||||||
|
|
||||||
await tap.start();
|
export default tap.start();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// import test framework
|
// import test framework
|
||||||
import { expect, tap } from '@pushrocks/tapbundle';
|
import { expect, tap } from '@push.rocks/tapbundle';
|
||||||
|
|
||||||
// import the module
|
// import the module
|
||||||
import * as lik from '../ts/index.js';
|
import * as lik from '../ts/index.js';
|
||||||
@@ -20,4 +20,4 @@ tap.test('should create a timed aggregaotor', async (tools) => {
|
|||||||
await tools.delayFor(2000);
|
await tools.delayFor(2000);
|
||||||
});
|
});
|
||||||
|
|
||||||
await tap.start();
|
export default tap.start();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { tap, expect } from '@pushrocks/tapbundle';
|
import { tap, expect } from '@push.rocks/tapbundle';
|
||||||
import * as lik from '../ts/index.js';
|
import * as lik from '../ts/index.js';
|
||||||
|
|
||||||
class TestClass {
|
class TestClass {
|
||||||
@@ -37,4 +37,4 @@ tap.test("should create a JSON object that reflects a tree's hierachy", async ()
|
|||||||
const jsonTreet = testTree.toJsonWithHierachy(testInstance);
|
const jsonTreet = testTree.toJsonWithHierachy(testInstance);
|
||||||
});
|
});
|
||||||
|
|
||||||
await tap.start();
|
export default tap.start();
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* autocreated commitinfo by @pushrocks/commitinfo
|
* autocreated commitinfo by @push.rocks/commitinfo
|
||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/lik',
|
name: '@push.rocks/lik',
|
||||||
version: '6.0.12',
|
version: '6.3.0',
|
||||||
description: 'light little helpers for node'
|
description: 'Provides a collection of lightweight helpers and utilities for Node.js projects.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from './lik.plugins.js';
|
import * as plugins from './classes.plugins.js';
|
||||||
|
|
||||||
interface IExecutionSlot<T> {
|
interface IExecutionSlot<T> {
|
||||||
executionDeferred: plugins.smartpromise.Deferred<T>;
|
executionDeferred: plugins.smartpromise.Deferred<T>;
|
||||||
@@ -10,6 +10,12 @@ interface IExecutionSlot<T> {
|
|||||||
export class AsyncExecutionStack {
|
export class AsyncExecutionStack {
|
||||||
private executionSlots: IExecutionSlot<any>[] = [];
|
private executionSlots: IExecutionSlot<any>[] = [];
|
||||||
private isProcessing = false;
|
private isProcessing = false;
|
||||||
|
/** Maximum concurrent non-exclusive tasks (Infinity = unlimited) */
|
||||||
|
private nonExclusiveMaxConcurrency: number = Infinity;
|
||||||
|
/** Currently running non-exclusive task count */
|
||||||
|
private nonExclusiveCurrentCount: number = 0;
|
||||||
|
/** Queue of resolvers waiting for a non-exclusive slot */
|
||||||
|
private nonExclusivePendingQueue: Array<() => void> = [];
|
||||||
|
|
||||||
public async getExclusiveExecutionSlot<T = any>(
|
public async getExclusiveExecutionSlot<T = any>(
|
||||||
funcArg: () => Promise<T>,
|
funcArg: () => Promise<T>,
|
||||||
@@ -42,6 +48,28 @@ export class AsyncExecutionStack {
|
|||||||
this.processExecutionSlots();
|
this.processExecutionSlots();
|
||||||
return executionDeferred.promise;
|
return executionDeferred.promise;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Set the maximum number of concurrent non-exclusive tasks.
|
||||||
|
* @param concurrency minimum 1 (Infinity means unlimited)
|
||||||
|
*/
|
||||||
|
public setNonExclusiveMaxConcurrency(concurrency: number): void {
|
||||||
|
if (!Number.isFinite(concurrency) || concurrency < 1) {
|
||||||
|
throw new Error('nonExclusiveMaxConcurrency must be a finite number >= 1');
|
||||||
|
}
|
||||||
|
this.nonExclusiveMaxConcurrency = concurrency;
|
||||||
|
}
|
||||||
|
/** Get the configured max concurrency for non-exclusive tasks */
|
||||||
|
public getNonExclusiveMaxConcurrency(): number {
|
||||||
|
return this.nonExclusiveMaxConcurrency;
|
||||||
|
}
|
||||||
|
/** Number of non-exclusive tasks currently running */
|
||||||
|
public getActiveNonExclusiveCount(): number {
|
||||||
|
return this.nonExclusiveCurrentCount;
|
||||||
|
}
|
||||||
|
/** Number of non-exclusive tasks waiting for a free slot */
|
||||||
|
public getPendingNonExclusiveCount(): number {
|
||||||
|
return this.nonExclusivePendingQueue.length;
|
||||||
|
}
|
||||||
|
|
||||||
private async processExecutionSlots() {
|
private async processExecutionSlots() {
|
||||||
if (this.isProcessing) {
|
if (this.isProcessing) {
|
||||||
@@ -87,13 +115,14 @@ export class AsyncExecutionStack {
|
|||||||
|
|
||||||
private async executeNonExclusiveSlots(slots: IExecutionSlot<any>[]) {
|
private async executeNonExclusiveSlots(slots: IExecutionSlot<any>[]) {
|
||||||
const promises = slots.map(async (slot) => {
|
const promises = slots.map(async (slot) => {
|
||||||
|
// wait for an available non-exclusive slot
|
||||||
|
await this.waitForNonExclusiveSlot();
|
||||||
try {
|
try {
|
||||||
|
// execute with optional timeout
|
||||||
if (slot.timeout) {
|
if (slot.timeout) {
|
||||||
const result = await Promise.race([
|
const result = await Promise.race([
|
||||||
slot.funcToExecute(),
|
slot.funcToExecute(),
|
||||||
plugins.smartdelay.delayFor(slot.timeout).then(() => {
|
plugins.smartdelay.delayFor(slot.timeout).then(() => { throw new Error('Timeout reached'); }),
|
||||||
throw new Error('Timeout reached');
|
|
||||||
}),
|
|
||||||
]);
|
]);
|
||||||
slot.executionDeferred.resolve(result);
|
slot.executionDeferred.resolve(result);
|
||||||
} else {
|
} else {
|
||||||
@@ -102,9 +131,33 @@ export class AsyncExecutionStack {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
slot.executionDeferred.reject(error);
|
slot.executionDeferred.reject(error);
|
||||||
|
} finally {
|
||||||
|
this.releaseNonExclusiveSlot();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Wait until a non-exclusive slot is available (respects max concurrency).
|
||||||
|
*/
|
||||||
|
private waitForNonExclusiveSlot(): Promise<void> {
|
||||||
|
if (this.nonExclusiveCurrentCount < this.nonExclusiveMaxConcurrency) {
|
||||||
|
this.nonExclusiveCurrentCount++;
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.nonExclusivePendingQueue.push(() => {
|
||||||
|
this.nonExclusiveCurrentCount++;
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** Release a non-exclusive slot and wake the next waiter, if any. */
|
||||||
|
private releaseNonExclusiveSlot(): void {
|
||||||
|
this.nonExclusiveCurrentCount--;
|
||||||
|
const next = this.nonExclusivePendingQueue.shift();
|
||||||
|
if (next) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from './lik.plugins.js';
|
import * as plugins from './classes.plugins.js';
|
||||||
|
|
||||||
export class BackpressuredArray<T> {
|
export class BackpressuredArray<T> {
|
||||||
public data: T[];
|
public data: T[];
|
||||||
@@ -34,6 +34,10 @@ export class BackpressuredArray<T> {
|
|||||||
return this.data.length < this.highWaterMark;
|
return this.data.length < this.highWaterMark;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public checkHasItems(): boolean {
|
||||||
|
return this.data.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
waitForSpace(): Promise<void> {
|
waitForSpace(): Promise<void> {
|
||||||
return new Promise<void>((resolve) => {
|
return new Promise<void>((resolve) => {
|
||||||
if (this.checkSpaceAvailable()) {
|
if (this.checkSpaceAvailable()) {
|
||||||
@@ -47,7 +51,6 @@ export class BackpressuredArray<T> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// New method to wait for items
|
|
||||||
waitForItems(): Promise<void> {
|
waitForItems(): Promise<void> {
|
||||||
return new Promise<void>((resolve) => {
|
return new Promise<void>((resolve) => {
|
||||||
if (this.data.length > 0) {
|
if (this.data.length > 0) {
|
||||||
@@ -3,7 +3,7 @@ The FastMap has the goal of creating the fastes to use map possible in JS
|
|||||||
|
|
||||||
============ */
|
============ */
|
||||||
|
|
||||||
import * as plugins from './lik.plugins.js';
|
import * as plugins from './classes.plugins.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fast map allows for very quick lookups of objects with a unique key
|
* fast map allows for very quick lookups of objects with a unique key
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as plugins from './lik.plugins.js';
|
import * as plugins from './classes.plugins.js';
|
||||||
|
|
||||||
import { InterestMap, type IInterestComparisonFunc } from './lik.interestmap.js';
|
import { InterestMap, type IInterestComparisonFunc } from './classes.interestmap.js';
|
||||||
|
|
||||||
export interface IInterestOptions<DTInterestFullfillment> {
|
export interface IInterestOptions<DTInterestFullfillment> {
|
||||||
markLostAfterDefault: number;
|
markLostAfterDefault: number;
|
||||||
@@ -39,6 +39,7 @@ export class Interest<DTInterestId, DTInterestFullfillment> {
|
|||||||
this.isFullfilled = true;
|
this.isFullfilled = true;
|
||||||
this.fullfillmentStore = [];
|
this.fullfillmentStore = [];
|
||||||
this.interestDeferred.resolve(objectArg);
|
this.interestDeferred.resolve(objectArg);
|
||||||
|
this.destroy(); // Remove from InterestMap immediately after fulfillment
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -8,9 +8,9 @@ Subssequent interests will be mapped to the same interest
|
|||||||
which is then is only fullfilled once.
|
which is then is only fullfilled once.
|
||||||
=========== */
|
=========== */
|
||||||
|
|
||||||
import * as plugins from './lik.plugins.js';
|
import * as plugins from './classes.plugins.js';
|
||||||
import { ObjectMap } from './lik.objectmap.js';
|
import { ObjectMap } from './classes.objectmap.js';
|
||||||
import { Interest } from './lik.interestmap.interest.js';
|
import { Interest } from './classes.interestmap.interest.js';
|
||||||
|
|
||||||
export type IInterestComparisonFunc<T> = (objectArg: T) => string;
|
export type IInterestComparisonFunc<T> = (objectArg: T) => string;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from './lik.plugins.js';
|
import * as plugins from './classes.plugins.js';
|
||||||
|
|
||||||
export class LimitedArray<T> {
|
export class LimitedArray<T> {
|
||||||
array: T[] = [];
|
array: T[] = [];
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as plugins from './lik.plugins.js';
|
import * as plugins from './classes.plugins.js';
|
||||||
|
|
||||||
import { ObjectMap } from './lik.objectmap.js';
|
import { ObjectMap } from './classes.objectmap.js';
|
||||||
|
|
||||||
export class LoopTracker<T> {
|
export class LoopTracker<T> {
|
||||||
referenceObjectMap = new ObjectMap<any>();
|
referenceObjectMap = new ObjectMap<any>();
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as plugins from './lik.plugins.js';
|
import * as plugins from './classes.plugins.js';
|
||||||
import { FastMap } from './lik.fastmap.js';
|
import { FastMap } from './classes.fastmap.js';
|
||||||
|
|
||||||
export const uni = (prefix: string = 'uni') => {
|
export const uni = (prefix: string = 'uni') => {
|
||||||
return `${prefix}xxxxxxxxxxx`.replace(/[xy]/g, (c) => {
|
return `${prefix}xxxxxxxxxxx`.replace(/[xy]/g, (c) => {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from './lik.plugins.js';
|
import * as plugins from './classes.plugins.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* allows you to easily keep track of a bunch of strings
|
* allows you to easily keep track of a bunch of strings
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from './lik.plugins.js';
|
import * as plugins from './classes.plugins.js';
|
||||||
|
|
||||||
export interface ITimedAggregatorOptions<T> {
|
export interface ITimedAggregatorOptions<T> {
|
||||||
aggregationIntervalInMillis: number;
|
aggregationIntervalInMillis: number;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as plugins from './lik.plugins.js';
|
import * as plugins from './classes.plugins.js';
|
||||||
|
|
||||||
export class Tree<T> {
|
export class Tree<T> {
|
||||||
symbolTree: any;
|
symbolTree: any;
|
||||||
22
ts/index.ts
22
ts/index.ts
@@ -1,11 +1,11 @@
|
|||||||
export * from './lik.asyncexecutionstack.js';
|
export * from './classes.asyncexecutionstack.js';
|
||||||
export * from './backpressuredarray.js';
|
export * from './classes.backpressuredarray.js';
|
||||||
export * from './lik.fastmap.js';
|
export * from './classes.fastmap.js';
|
||||||
export * from './lik.interestmap.js';
|
export * from './classes.interestmap.js';
|
||||||
export * from './lik.interestmap.interest.js';
|
export * from './classes.interestmap.interest.js';
|
||||||
export * from './lik.limitedarray.js';
|
export * from './classes.limitedarray.js';
|
||||||
export * from './lik.looptracker.js';
|
export * from './classes.looptracker.js';
|
||||||
export * from './lik.objectmap.js';
|
export * from './classes.objectmap.js';
|
||||||
export * from './lik.stringmap.js';
|
export * from './classes.stringmap.js';
|
||||||
export * from './lik.timedaggregator.js';
|
export * from './classes.timedaggregator.js';
|
||||||
export * from './lik.tree.js';
|
export * from './classes.tree.js';
|
||||||
|
|||||||
@@ -3,8 +3,12 @@
|
|||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"useDefineForClassFields": false,
|
"useDefineForClassFields": false,
|
||||||
"target": "ES2022",
|
"target": "ES2022",
|
||||||
"module": "ES2022",
|
"module": "NodeNext",
|
||||||
"moduleResolution": "nodenext",
|
"moduleResolution": "NodeNext",
|
||||||
"esModuleInterop": true
|
"esModuleInterop": true,
|
||||||
}
|
"verbatimModuleSyntax": true
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist_*/**/*.d.ts"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user