Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@timberio/tools

Package Overview
Dependencies
Maintainers
5
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@timberio/tools - npm Package Compare versions

Comparing version 0.3.0 to 0.4.0

10

dist/cjs/index.js
"use strict";
var __importDefault =
(this && this.__importDefault) ||
function(mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -12,2 +10,2 @@ const queue_1 = __importDefault(require("./queue"));

exports.makeThrottle = throttle_1.default;
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map

42

dist/cjs/queue.d.ts

@@ -6,23 +6,23 @@ /**

export default class Queue<T> {
/**
* First node in the tree
*/
private first?;
/**
* Last node in the tree
*/
private last?;
/**
* Number of items in the queue
*/
length: number;
/**
* Pushes a value into the queue.
* @param value - Any object to push into the queue
*/
push(value: any): void;
/**
* Remove a value from the start of the queue (FIFO) and return it
*/
shift(): T | undefined;
/**
* First node in the tree
*/
private first?;
/**
* Last node in the tree
*/
private last?;
/**
* Number of items in the queue
*/
length: number;
/**
* Pushes a value into the queue.
* @param value - Any object to push into the queue
*/
push(value: any): void;
/**
* Remove a value from the start of the queue (FIFO) and return it
*/
shift(): T | undefined;
}

@@ -8,35 +8,35 @@ "use strict";

class Queue {
constructor() {
constructor() {
/**
* First node in the tree
*/
/**
* Number of items in the queue
*/
this.length = 0;
}
/**
* First node in the tree
* Pushes a value into the queue.
* @param value - Any object to push into the queue
*/
push(value) {
const node = { value };
this.last = this.last ? (this.last.next = node) : (this.first = node);
this.length++;
}
/**
* Number of items in the queue
* Remove a value from the start of the queue (FIFO) and return it
*/
this.length = 0;
}
/**
* Pushes a value into the queue.
* @param value - Any object to push into the queue
*/
push(value) {
const node = { value };
this.last = this.last ? (this.last.next = node) : (this.first = node);
this.length++;
}
/**
* Remove a value from the start of the queue (FIFO) and return it
*/
shift() {
if (this.first) {
const { value } = this.first;
this.first = this.first.next;
if (!--this.length) {
this.last = undefined;
}
return value;
shift() {
if (this.first) {
const { value } = this.first;
this.first = this.first.next;
if (!--this.length) {
this.last = undefined;
}
return value;
}
}
}
}
exports.default = Queue;
//# sourceMappingURL=queue.js.map
//# sourceMappingURL=queue.js.map
"use strict";
var __importDefault =
(this && this.__importDefault) ||
function(mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const queue_1 = __importDefault(require("./queue"));
describe("queue tests", () => {
it("should store correct number of items in queue", () => {
const q = new queue_1.default();
const numberOfItems = 10;
for (let i = 0; i < numberOfItems; i++) {
q.push(i);
}
expect(q.length).toEqual(numberOfItems);
});
it("should retrieve the items in FIFO order", () => {
const q = new queue_1.default();
const numberOfItems = 10;
const list = [];
// Insert items to both the array and queue
for (let i = 0; i < numberOfItems; i++) {
list.push(i);
q.push(i);
}
// Map over plain array (which is ordered), and test
// against the values from the queue
list.forEach(item => {
expect(q.shift()).toEqual(item);
it("should store correct number of items in queue", () => {
const q = new queue_1.default();
const numberOfItems = 10;
for (let i = 0; i < numberOfItems; i++) {
q.push(i);
}
expect(q.length).toEqual(numberOfItems);
});
// Queue should now be empty
expect(q.length).toEqual(0);
});
it("should handle 100,000 items", () => {
const q = new queue_1.default();
const numberOfItems = 100000;
for (let i = 0; i < numberOfItems; i++) {
q.push(i);
}
expect(q.length).toEqual(numberOfItems);
});
it("should return undefined if queue is empty", () => {
const q = new queue_1.default();
expect(q.shift()).toEqual(undefined);
});
it("should retrieve the items in FIFO order", () => {
const q = new queue_1.default();
const numberOfItems = 10;
const list = [];
// Insert items to both the array and queue
for (let i = 0; i < numberOfItems; i++) {
list.push(i);
q.push(i);
}
// Map over plain array (which is ordered), and test
// against the values from the queue
list.forEach(item => {
expect(q.shift()).toEqual(item);
});
// Queue should now be empty
expect(q.length).toEqual(0);
});
it("should handle 100,000 items", () => {
const q = new queue_1.default();
const numberOfItems = 100000;
for (let i = 0; i < numberOfItems; i++) {
q.push(i);
}
expect(q.length).toEqual(numberOfItems);
});
it("should return undefined if queue is empty", () => {
const q = new queue_1.default();
expect(q.shift()).toEqual(undefined);
});
});
//# sourceMappingURL=queue.test.js.map
//# sourceMappingURL=queue.test.js.map

@@ -6,4 +6,2 @@ import { InferArgs } from "./types";

*/
export default function makeThrottle<T extends (...args: any[]) => any>(
max: number
): (fn: T) => (...args: InferArgs<T>[]) => Promise<InferArgs<T>>;
export default function makeThrottle<T extends (...args: any[]) => any>(max: number): (fn: T) => (...args: InferArgs<T>[]) => Promise<InferArgs<T>>;
"use strict";
var __importDefault =
(this && this.__importDefault) ||
function(mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -14,49 +12,51 @@ const queue_1 = __importDefault(require("./queue"));

function makeThrottle(max) {
// Current iteration cycle
let current = 0;
// Create a FIFO queue
const queue = new queue_1.default();
/**
* Throttle function that throttles the passed func according to `max`
* @param fn - async function to resolve
*/
function throttle(fn) {
return async (...args) => {
return new Promise((resolve, reject) => {
/**
* Handler for resolving the Promise chain
*/
async function handler() {
// Only resolve if the `max` hasn't been exhausted
if (current < max) {
// Increment the available slot size
current++;
try {
// Await the passed function here first, to determine if any
// errors are thrown, so they can be handled by our outside `reject`
resolve(await fn(...args));
} catch (e) {
reject(e);
}
// Since this has now resolved, make the slot available again
current--;
// If there are items waiting in the queue, resolve the next
// Promise
if (queue.length > 0) {
queue.shift()();
}
} else {
// The `max` has been exceeded - push onto the queue to wait
queue.push(handler);
}
}
// Return the async handler
return handler();
});
};
}
// Return the throttle function
return throttle;
// Current iteration cycle
let current = 0;
// Create a FIFO queue
const queue = new queue_1.default();
/**
* Throttle function that throttles the passed func according to `max`
* @param fn - async function to resolve
*/
function throttle(fn) {
return async (...args) => {
return new Promise((resolve, reject) => {
/**
* Handler for resolving the Promise chain
*/
async function handler() {
// Only resolve if the `max` hasn't been exhausted
if (current < max) {
// Increment the available slot size
current++;
try {
// Await the passed function here first, to determine if any
// errors are thrown, so they can be handled by our outside `reject`
resolve(await fn(...args));
}
catch (e) {
reject(e);
}
// Since this has now resolved, make the slot available again
current--;
// If there are items waiting in the queue, resolve the next
// Promise
if (queue.length > 0) {
queue.shift()();
}
}
else {
// The `max` has been exceeded - push onto the queue to wait
queue.push(handler);
}
}
// Return the async handler
return handler();
});
};
}
// Return the throttle function
return throttle;
}
exports.default = makeThrottle;
//# sourceMappingURL=throttle.js.map
//# sourceMappingURL=throttle.js.map
"use strict";
var __importDefault =
(this && this.__importDefault) ||
function(mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const throttle_1 = __importDefault(require("./throttle"));
describe("Throttle tests", () => {
it("should throttle Promises", async () => {
// Fixtures
const max = 2;
const throttleTime = 20; // ms
const numberOfPromises = 10;
// Create the throttle function
const throttle = throttle_1.default(max);
// Create the pipeline function to use the throttle
const pipeline = throttle(
async log =>
new Promise(resolve => {
setTimeout(() => {
resolve(log);
}, throttleTime);
})
);
// Build the promises
const promises = [];
// Start the timer
const start = process.hrtime();
for (let i = 0; i < numberOfPromises; i++) {
promises.push(pipeline({ message: "Hey" }));
}
// Await until they've all finished
await Promise.all(promises);
// End the timer
const end = process.hrtime(start)[1] / 1000000;
// Expect time to have taken (numberOfPromises / max) * throttleTime
const expectedTime = (numberOfPromises / max) * throttleTime;
expect(end).toBeGreaterThanOrEqual(expectedTime);
});
it("should handle rejections", async () => {
// Fixtures
const numberOfPromises = 10;
// Create the throttle function
const throttle = throttle_1.default(5);
// Error counter
let errors = 0;
// Create a throttled function that will throw half the time
const pipeline = throttle(async i => {
if (i % 2 == 0) {
throw new Error("Thrown inside throttled function!");
}
return i;
it("should throttle Promises", async () => {
// Fixtures
const max = 2;
const throttleTime = 20; // ms
const numberOfPromises = 10;
// Create the throttle function
const throttle = throttle_1.default(max);
// Create the pipeline function to use the throttle
const pipeline = throttle(async (log) => new Promise(resolve => {
setTimeout(() => {
resolve(log);
}, throttleTime);
}));
// Build the promises
const promises = [];
// Start the timer
const start = process.hrtime();
for (let i = 0; i < numberOfPromises; i++) {
promises.push(pipeline({ message: "Hey" }));
}
// Await until they've all finished
await Promise.all(promises);
// End the timer
const end = process.hrtime(start)[1] / 1000000;
// Expect time to have taken (numberOfPromises / max) * throttleTime
const expectedTime = (numberOfPromises / max) * throttleTime;
expect(end).toBeGreaterThanOrEqual(expectedTime);
});
for (let i = 0; i < numberOfPromises; i++) {
await pipeline(i).catch(() => errors++);
}
expect(errors).toEqual(numberOfPromises / 2);
});
it("should handle rejections", async () => {
// Fixtures
const numberOfPromises = 10;
// Create the throttle function
const throttle = throttle_1.default(5);
// Error counter
let errors = 0;
// Create a throttled function that will throw half the time
const pipeline = throttle(async (i) => {
if (i % 2 == 0) {
throw new Error("Thrown inside throttled function!");
}
return i;
});
for (let i = 0; i < numberOfPromises; i++) {
await pipeline(i).catch(() => errors++);
}
expect(errors).toEqual(numberOfPromises / 2);
});
});
//# sourceMappingURL=throttle.test.js.map
//# sourceMappingURL=throttle.test.js.map

@@ -5,10 +5,10 @@ /**

export interface IQueue<T> {
/**
* Value of queue should be an object
*/
value: T;
/**
* Leaf node in queue, representing the next value
*/
next?: IQueue<T>;
/**
* Value of queue should be an object
*/
value: T;
/**
* Leaf node in queue, representing the next value
*/
next?: IQueue<T>;
}

@@ -18,6 +18,2 @@ /**

*/
export declare type InferArgs<T> = T extends (
...args: any[]
) => Promise<infer U>
? U
: void;
export declare type InferArgs<T> = T extends (...args: any[]) => Promise<infer U> ? U : void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map
//# sourceMappingURL=types.js.map
{
"name": "@timberio/tools",
"version": "0.3.0",
"version": "0.4.0",
"description": "Javascript logging tools",

@@ -10,3 +10,5 @@ "main": "dist/cjs/index.js",

"scripts": {
"build": "tsc && tsc -p tsconfig.es6.json",
"build:cjs": "tsc",
"build:es6": "tsc -p tsconfig.es6.json",
"build": "run-p build:*",
"prepublish": "npm run build",

@@ -29,2 +31,3 @@ "test": "jest"

"jest": "^23.6.0",
"npm-run-all": "^4.1.3",
"prettier": "^1.15.2",

@@ -31,0 +34,0 @@ "ts-jest": "^23.10.4",

@@ -7,4 +7,32 @@ # 🌲 Timber - Javascript tools

### `makeThrottle<TFunc>(max: number)`
### `Queue<T>`
Generic [FIFO](<https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)>) queue. Used by `makeThrottle` to store pipeline functions to be executed as concurrent 'slots' become available. Provides fast retrieval for any primitive or object that needs ordered, first-in, first-out retrieval.
**Usage example**
```typescript
import { Queue } from "@timberio/tools";
// Interface representing a person
interface IPerson {
name: string;
age: number;
}
// Create a queue to store `IPerson` objects
const q = new Queue<IPerson>();
// Add a couple of records...
q.push({ name: "Jeff", age: 50 });
q.push({ name: "Sally", age: 39 });
// Pull values from the queue...
while (q.length) {
console.log(q.shift().name); // <-- first Jeff, then Sally...
}
```
### `makeThrottle<T>(max: number)`
Returns a `throttle` higher-order function, which wraps an `async` function, and limits the number of active Promises to `max: number`

@@ -15,3 +43,3 @@

```
throttle(fn: TFunc): (...args: TFuncArg[]) => Promise<TFuncArg>
throttle(fn: T): (...args: InferArgs<T>[]) => Promise<InferArgs<T>>
```

@@ -18,0 +46,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc