Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions packages/utils/source/chunk.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { slice } from "./slice.js";

export const chunk = <T>(iterable: T[], chunkSize: number): T[][] => {
const iterableLength: number = iterable.length;

Expand All @@ -12,7 +10,7 @@ export const chunk = <T>(iterable: T[], chunkSize: number): T[][] => {
const result: T[][] = Array.from({ length: Math.ceil(iterableLength / chunkSize) });

while (index < iterableLength) {
result[resIndex++] = slice<T>(iterable, index, (index += chunkSize));
result[resIndex++] = iterable.slice(index, (index += chunkSize));
}

return result;
Expand Down
4 changes: 0 additions & 4 deletions packages/utils/source/get-path-segments.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ import { describe } from "@mainsail/test-runner";
import { getPathSegments } from "./get-path-segments";

describe("getPathSegments", async ({ assert, it, nock, loader }) => {
it("should return an array as is", () => {
assert.equal(getPathSegments(["a", "b"]), ["a", "b"]);
});

it("should return the path as array", () => {
assert.equal(getPathSegments("a.b"), ["a", "b"]);
});
Expand Down
4 changes: 2 additions & 2 deletions packages/utils/source/get-path-segments.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const disallowedKeys = new Set(["__proto__", "prototype", "constructor"]);

export const getPathSegments = (value: string | string[]): string[] => {
const segments: string[] = Array.isArray(value) ? value : value.split(".");
export const getPathSegments = (value: string): string[] => {
const segments: string[] = value.split(".");

return segments.some((segment: string) => disallowedKeys.has(segment)) ? [] : segments;
};
2 changes: 1 addition & 1 deletion packages/utils/source/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { isEnumerable } from "./is-enumerable.js";
import { isObject } from "./is-object.js";
import { isString } from "./is-string.js";

export const get = <T, V>(object: T, path: string | string[], defaultValue?: V): V | undefined => {
export const get = <T, V>(object: T, path: string, defaultValue?: V): V | undefined => {
if (!isObject(object) || !isString(path)) {
return defaultValue;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/utils/source/group-by.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { FunctionReturning } from "./internal/index.js";
import type { FunctionReturning } from "./types.js";

export const groupBy = <T, K extends PropertyKey>(
iterable: T[],
Expand Down
2 changes: 1 addition & 1 deletion packages/utils/source/has.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { getPathSegments } from "./get-path-segments.js";
import { isObject } from "./is-object.js";
import { isString } from "./is-string.js";

export const has = <T>(object: T, path: string | string[]): boolean => {
export const has = <T>(object: T, path: string): boolean => {
if (!isObject(object) || !isString(path)) {
return false;
}
Expand Down
61 changes: 61 additions & 0 deletions packages/utils/source/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { describe } from "@mainsail/test-runner";
import * as utils from "./index";

describe("index", ({ assert, it }) => {
it("should export all functions and classes", () => {
for (const name of [
"ByteBuffer",
"HttpError",
"Lock",
"camelCase",
"chunk",
"cloneDeep",
"comparator",
"ensureError",
"expandTilde",
"formatEcdsaSignature",
"get",
"getPathSegments",
"groupBy",
"has",
"isArray",
"isBlacklisted",
"isEmpty",
"isEnumerable",
"isObject",
"isString",
"isWhitelisted",
"map",
"mapArray",
"mapObject",
"merge",
"minBy",
"orderBy",
"pascalCase",
"pluralize",
"prettyBytes",
"prettyTime",
"randomNumber",
"set",
"setTimeoutAsync",
"shuffle",
"sleep",
"take",
"unset",
"validatorSetPack",
"validatorSetUnpack",
]) {
assert.function(utils[name]);
}
});

it("should export all namespaces", () => {
for (const name of ["IpAddress", "assert", "dotenv", "http", "semver"]) {
assert.object(utils[name]);
}
});

it("should not export anything else", () => {
assert.equal(Object.keys(utils).length, 45);
});
});
2 changes: 1 addition & 1 deletion packages/utils/source/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export * from "./get.js";
export * from "./group-by.js";
export * from "./has.js";
export * from "./http.js";
export * from "./internal/index.js";
export * as IpAddress from "./ip-address.js";
export * from "./is-array.js";
export * from "./is-blacklisted.js";
Expand All @@ -38,5 +37,6 @@ export * from "./shuffle.js";
export * from "./sleep.js";
export * from "./string-case.js";
export * from "./take.js";
export * from "./types.js";
export * from "./unset.js";
export * from "./validator-set-pack.js";
1 change: 0 additions & 1 deletion packages/utils/source/internal/index.ts

This file was deleted.

5 changes: 5 additions & 0 deletions packages/utils/source/is-blacklisted.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,9 @@ describe("isBlacklisted", ({ assert, it }) => {
assert.true(isBlacklisted(["*:104"], "2001:3984:3989::104"));
assert.false(isBlacklisted(["*:104"], "2001:3984:3989::105"));
});

it("should skip invalid patterns instead of throwing", () => {
assert.false(isBlacklisted([""], "127.0.0.1"));
assert.true(isBlacklisted(["", "127.*"], "127.0.0.1"));
});
});
1 change: 0 additions & 1 deletion packages/utils/source/is-blacklisted.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import mm from "micromatch";

// @TODO review the implementation
export const isBlacklisted = (blacklist: string[], remoteAddress: string): boolean => {
if (!Array.isArray(blacklist) || blacklist.length === 0) {
return false;
Expand Down
14 changes: 14 additions & 0 deletions packages/utils/source/is-empty.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,18 @@ describe("at", async ({ assert, it, nock, loader }) => {
it("should return false if the value contains something", () => {
assert.false(isEmpty([1]));
});

it("should return false for non-empty strings, maps and sets", () => {
assert.false(isEmpty("a"));
assert.false(isEmpty(new Map([["a", 1]])));
assert.false(isEmpty(new Set([1])));
assert.false(isEmpty({ a: 1 }));
});

it("should return false for truthy primitives and functions", () => {
assert.false(isEmpty(1));
assert.false(isEmpty(true));
assert.false(isEmpty(() => {}));
assert.false(isEmpty(Symbol("a")));
});
});
5 changes: 5 additions & 0 deletions packages/utils/source/is-whitelisted.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ describe("isWhitelisted", ({ assert, it }) => {
assert.true(isWhitelisted(["*.127"], "1.1.1.127"));
assert.false(isWhitelisted(["*.127"], "1.1.1.128"));
});

it("should skip invalid patterns instead of throwing", () => {
assert.false(isWhitelisted([""], "127.0.0.1"));
assert.true(isWhitelisted(["", "127.*"], "127.0.0.1"));
});
});
1 change: 0 additions & 1 deletion packages/utils/source/is-whitelisted.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import mm from "micromatch";

// @TODO review the implementation
export const isWhitelisted = (whitelist: string[], remoteAddress: string): boolean => {
if (!Array.isArray(whitelist) || whitelist.length === 0) {
return true;
Expand Down
37 changes: 37 additions & 0 deletions packages/utils/source/lock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,41 @@ describe("Lock", ({ assert, it }) => {

assert.equal(await Promise.all(promises), [1, 3, 3]);
});

it("should let a non-exclusive execution run after a rejected exclusive one", async () => {
const lock = new Lock();
const error = new Error("boom");

const exclusive = lock.runExclusive(async () => {
throw error;
});
const nonExclusive = lock.runNonExclusive(async () => "ok");

await assert.rejects(() => exclusive, "boom");
assert.equal(await nonExclusive, "ok");
});

it("should let an exclusive execution run after a rejected exclusive one", async () => {
const lock = new Lock();

const first = lock.runExclusive(async () => {
throw new Error("boom");
});
const second = lock.runExclusive(async () => "ok");

await assert.rejects(() => first, "boom");
assert.equal(await second, "ok");
});

it("should let an exclusive execution run after a rejected non-exclusive one", async () => {
const lock = new Lock();

const nonExclusive = lock.runNonExclusive(async () => {
throw new Error("boom");
});
const exclusive = lock.runExclusive(async () => "ok");

await assert.rejects(() => nonExclusive, "boom");
assert.equal(await exclusive, "ok");
});
});
2 changes: 1 addition & 1 deletion packages/utils/source/min-by.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { FunctionReturning } from "./internal/index.js";
import type { FunctionReturning } from "./types.js";

import { mapArray } from "./map-array.js";

Expand Down
2 changes: 1 addition & 1 deletion packages/utils/source/order-by.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { ISortByObjectSorter } from "fast-sort";

import { sort } from "fast-sort";

import type { Iteratee } from "./internal/index.js";
import type { Iteratee } from "./types.js";

import { map } from "./map.js";

Expand Down
2 changes: 1 addition & 1 deletion packages/utils/source/set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { getPathSegments } from "./get-path-segments.js";
import { isObject } from "./is-object.js";
import { isString } from "./is-string.js";

export const set = <T>(object: T, path: string | string[], value: unknown): boolean => {
export const set = <T>(object: T, path: string, value: unknown): boolean => {
if (!isObject(object) || !isString(path)) {
return false;
}
Expand Down
27 changes: 0 additions & 27 deletions packages/utils/source/slice.ts

This file was deleted.

4 changes: 1 addition & 3 deletions packages/utils/source/take.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
import { slice } from "./slice.js";

export const take = <T>(iterable: T[], amount = 1): T[] => slice(iterable, 0, amount);
export const take = <T>(iterable: T[], amount = 1): T[] => iterable.slice(0, amount);
File renamed without changes.
15 changes: 15 additions & 0 deletions packages/utils/source/unset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,19 @@ describe("unset", async ({ assert, it, nock, loader }) => {

assert.equal(object, { a: { b: {} } });
});

it("should return false if an intermediate segment is not an object", () => {
const object = { a: 1 };

assert.false(unset(object, "a.b"));
assert.equal(object, { a: 1 });
});

it("should return false if the path contains dangerous segments", () => {
const object = { a: { b: 1 } };

assert.false(unset(object, "__proto__.a"));
assert.false(unset(object, "a.constructor"));
assert.equal(object, { a: { b: 1 } });
});
});
2 changes: 1 addition & 1 deletion packages/utils/source/unset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { getPathSegments } from "./get-path-segments.js";
import { isObject } from "./is-object.js";
import { isString } from "./is-string.js";

export const unset = <T>(object: T, path: string | string[]): boolean => {
export const unset = <T>(object: T, path: string): boolean => {
if (!isObject(object) || !isString(path)) {
return false;
}
Expand Down
Loading