@prosopo/util
Advanced tools
Comparing version 1.0.1 to 1.0.2
@@ -9,3 +9,10 @@ export * from './util.js'; | ||
export * from './url.js'; | ||
export * from './at.js'; | ||
export * from './get.js'; | ||
export * from './merge.js'; | ||
export * from './choice.js'; | ||
export * from './permutations.js'; | ||
export * from './version.js'; | ||
export * from './hex.js'; | ||
export * from './checks.js'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -9,3 +9,10 @@ export * from './util.js'; | ||
export * from './url.js'; | ||
export * from './at.js'; | ||
export * from './get.js'; | ||
export * from './merge.js'; | ||
export * from './choice.js'; | ||
export * from './permutations.js'; | ||
export * from './version.js'; | ||
export * from './hex.js'; | ||
export * from './checks.js'; | ||
//# sourceMappingURL=index.js.map |
@@ -1,198 +0,19 @@ | ||
import { at, get, merge, permutations } from '../util.js'; | ||
import { describe, expect, test } from 'vitest'; | ||
import { flatten } from '../util.js'; | ||
describe('util', () => { | ||
describe('merge', () => { | ||
test('array in array', () => { | ||
expect(merge([ | ||
[0, 1, 2], | ||
[3, 4, 5], | ||
], [ | ||
[6, 7], | ||
[8, 9], | ||
])).to.deep.equal([ | ||
[6, 7, 2], | ||
[8, 9, 5], | ||
]); | ||
test('flatten obj', () => { | ||
const obj = { | ||
a: { | ||
b: { | ||
c: 1, | ||
}, | ||
}, | ||
d: 2, | ||
}; | ||
expect(flatten(obj)).to.deep.equal({ | ||
'a.b.c': 1, | ||
d: 2, | ||
}); | ||
test('array in array atomic', () => { | ||
expect(merge([ | ||
[0, 1, 2], | ||
[3, 4, 5], | ||
], [ | ||
[6, 7], | ||
[8, 9], | ||
], { atomicArrays: true })).to.deep.equal([ | ||
[6, 7], | ||
[8, 9], | ||
]); | ||
}); | ||
test('array in object', () => { | ||
expect(merge({ a: [0, 1, 2] }, { a: [3, 4] })).to.deep.equal({ a: [3, 4, 2] }); | ||
}); | ||
test('array in object atomic', () => { | ||
expect(merge({ a: [0, 1, 2] }, { a: [3, 4] }, { atomicArrays: true })).to.deep.equal({ a: [3, 4] }); | ||
}); | ||
test('array in object in array', () => { | ||
expect(merge([{ a: [0, 1, 2] }, { b: [3, 4, 5] }], [{ a: [6, 7] }, { b: [8, 9] }])).to.deep.equal([ | ||
{ a: [6, 7, 2] }, | ||
{ b: [8, 9, 5] }, | ||
]); | ||
}); | ||
test('array in object in array atomic', () => { | ||
expect(merge([{ a: [0, 1, 2] }, { b: [3, 4, 5] }], [{ a: [6, 7] }, { b: [8, 9] }], { atomicArrays: true })).to.deep.equal([{ a: [6, 7] }, { b: [8, 9] }]); | ||
}); | ||
test('primitive replaces array', () => { | ||
expect(merge({ a: [1] }, { a: 1 })).to.deep.equal({ a: 1 }); | ||
}); | ||
test('primitive replaces object', () => { | ||
expect(merge({ a: { b: 1 } }, { a: 1 })).to.deep.equal({ a: 1 }); | ||
}); | ||
test('primitive replaces primitive', () => { | ||
expect(merge({ a: 1 }, { a: 2 })).to.deep.equal({ a: 2 }); | ||
}); | ||
test('array replaces primitive', () => { | ||
expect(merge({ a: 1 }, { a: [1] })).to.deep.equal({ a: [1] }); | ||
}); | ||
test('array replaces array', () => { | ||
expect(merge({ a: [1] }, { a: [2] })).to.deep.equal({ a: [2] }); | ||
}); | ||
test('array replaces object', () => { | ||
expect(merge({ a: { b: 1 } }, { a: [1] })).to.deep.equal({ a: [1] }); | ||
}); | ||
test('object replaces primitive', () => { | ||
expect(merge({ a: 1 }, { a: { b: 1 } })).to.deep.equal({ a: { b: 1 } }); | ||
}); | ||
test('object replaces array', () => { | ||
expect(merge({ a: [1] }, { a: { b: 1 } })).to.deep.equal({ a: { b: 1 } }); | ||
}); | ||
test('object replaces object', () => { | ||
expect(merge({ a: { b: 1 } }, { a: { c: 1 } })).to.deep.equal({ a: { b: 1, c: 1 } }); | ||
}); | ||
}); | ||
describe('at', () => { | ||
test('types', () => { | ||
const v1 = at([1, 2, 3], 0); | ||
const v2 = at([1, 2, 3, undefined], 0); | ||
const v3 = at('abc', 0); | ||
const v4 = at('abc', 0, { optional: true }); | ||
const v5 = at([1, 2, 3], 0, { optional: true }); | ||
const v6 = at('abc', 0, { optional: false }); | ||
const v7 = at([1, 2, 3], 0, { optional: false }); | ||
const a3 = at([1, 2, 3], 0); | ||
const a4 = at([1, 2, 3, undefined], 0); | ||
const a6 = at([1, 2, 3], 0, { optional: true }); | ||
const a7 = at([1, 2, 3], 0, { optional: false }); | ||
const a8 = at([1, 2, 3], 0, {}); | ||
const a9 = at([1, 2, 3], 0, { noWrap: true }); | ||
const a5 = at('abc', 0); | ||
const a10 = at('abc', 0, { optional: false }); | ||
const a11 = at('abc', 0, { optional: true }); | ||
const a12 = at([undefined, undefined, undefined], 0); | ||
const a13 = at([undefined, undefined, undefined], 0, { optional: true }); | ||
const a14 = at([undefined, undefined, undefined], 0, { optional: false }); | ||
}); | ||
test('compatible with string', () => { | ||
expect(at('abc', 0)).to.equal('a'); | ||
expect(at('abc', 1)).to.equal('b'); | ||
expect(at('abc', 2)).to.equal('c'); | ||
expect(at('abc', 3)).to.equal('a'); | ||
expect(at('abc', 4)).to.equal('b'); | ||
expect(at('abc', 5)).to.equal('c'); | ||
expect(at('abc', -1)).to.equal('c'); | ||
expect(at('abc', -2)).to.equal('b'); | ||
expect(at('abc', -3)).to.equal('a'); | ||
expect(at('abc', -4)).to.equal('c'); | ||
expect(at('abc', -5)).to.equal('b'); | ||
expect(at('abc', -6)).to.equal('a'); | ||
}); | ||
test('empty string', () => { | ||
expect(() => at('', 0)).to.throw(); | ||
}); | ||
test('throw on empty array', () => { | ||
expect(() => at([], 0)).to.throw(); | ||
}); | ||
test('throw on index out of bounds high', () => { | ||
expect(() => at([1, 2, 3], 3, { noWrap: true })).to.throw(); | ||
}); | ||
test('throw on index out of bounds low', () => { | ||
expect(() => at([1, 2, 3], -1, { noWrap: true })).to.throw(); | ||
}); | ||
test('returns correct value', () => { | ||
expect(at([1, 2, 3], 0)).to.equal(1); | ||
expect(at([1, 2, 3], 1)).to.equal(2); | ||
expect(at([1, 2, 3], 2)).to.equal(3); | ||
}); | ||
test('wraps index high', () => { | ||
expect(at([1, 2, 3], 3, { noWrap: false })).to.equal(1); | ||
expect(at([1, 2, 3], 4, { noWrap: false })).to.equal(2); | ||
expect(at([1, 2, 3], 5, { noWrap: false })).to.equal(3); | ||
}); | ||
test('wraps index low', () => { | ||
expect(at([1, 2, 3], -1, { noWrap: false })).to.equal(3); | ||
expect(at([1, 2, 3], -2, { noWrap: false })).to.equal(2); | ||
expect(at([1, 2, 3], -3, { noWrap: false })).to.equal(1); | ||
expect(at([1, 2, 3], -4, { noWrap: false })).to.equal(3); | ||
expect(at([1, 2, 3], -5, { noWrap: false })).to.equal(2); | ||
expect(at([1, 2, 3], -6, { noWrap: false })).to.equal(1); | ||
}); | ||
test('allow undefined in bounds', () => { | ||
expect(at([undefined, undefined, undefined], 0, { optional: true })).to.equal(undefined); | ||
expect(at([undefined, undefined, undefined], 1, { optional: true })).to.equal(undefined); | ||
expect(at([undefined, undefined, undefined], 2, { optional: true })).to.equal(undefined); | ||
}); | ||
}); | ||
describe('get', () => { | ||
test('types', () => { | ||
const v1 = get({ a: 1 }, 'a'); | ||
const v2 = get({ a: 1 }, 'a', false); | ||
const v3 = get({ a: 1 }, 'a', true); | ||
const v4 = get({ a: 1, b: undefined }, 'a'); | ||
const v5 = get({ a: 1, b: undefined }, 'a', false); | ||
const v6 = get(JSON.parse('{"a": 1}'), 'a'); | ||
const v7 = get(JSON.parse('{"a": 1}'), 'a'); | ||
}); | ||
test('throw on undefined field string', () => { | ||
expect(() => get({ a: 1 }, 'b')).to.throw(); | ||
}); | ||
test('throw on undefined field number', () => { | ||
expect(() => get({ a: 1 }, 1)).to.throw(); | ||
}); | ||
test('get correct field string', () => { | ||
expect(get({ a: 1 }, 'a')).to.equal(1); | ||
}); | ||
test('get correct field number', () => { | ||
expect(get({ 1: 1 }, 1)).to.equal(1); | ||
}); | ||
}); | ||
describe('permutations', () => { | ||
test('handles empty array', () => { | ||
expect([...permutations([])]).to.deep.equal([]); | ||
}); | ||
test('handles empty array with empty set', () => { | ||
expect([...permutations([], { includeEmpty: true })]).to.deep.equal([[]]); | ||
}); | ||
test('permutes correctly using same size bins', () => { | ||
expect([...permutations([2, 2, 2])]).to.deep.equal([ | ||
[0, 0, 0], | ||
[0, 0, 1], | ||
[0, 1, 0], | ||
[0, 1, 1], | ||
[1, 0, 0], | ||
[1, 0, 1], | ||
[1, 1, 0], | ||
[1, 1, 1], | ||
]); | ||
}); | ||
test('permutes correctly using different size bins', () => { | ||
expect([...permutations([1, 2, 3])]).to.deep.equal([ | ||
[0, 0, 0], | ||
[0, 0, 1], | ||
[0, 0, 2], | ||
[0, 1, 0], | ||
[0, 1, 1], | ||
[0, 1, 2], | ||
]); | ||
}); | ||
}); | ||
}); | ||
//# sourceMappingURL=util.test.js.map |
export declare const sleep: (ms: number) => Promise<unknown>; | ||
export declare function permutations(bins: number[], options?: { | ||
includeEmpty?: boolean; | ||
}): Generator<number[]>; | ||
export declare function get<T>(obj: T, key: unknown, required?: true): Exclude<T[keyof T], undefined>; | ||
export declare function get<T>(obj: T, key: unknown, required: false): T[keyof T] | undefined; | ||
export declare function get<T>(obj: unknown, key: string | number | symbol, required?: true): Exclude<T, undefined>; | ||
export declare function get<T>(obj: unknown, key: string | number | symbol, required: false): T | undefined; | ||
export type AtOptions = { | ||
optional?: boolean; | ||
noWrap?: boolean; | ||
}; | ||
export declare function at(str: string, index: number, options: AtOptions & { | ||
optional: true; | ||
}): string | undefined; | ||
export declare function at(str: string, index: number, options?: AtOptions): string; | ||
export declare function at<T>(items: T[] | string, index: number, options: AtOptions & { | ||
optional: false; | ||
}): T; | ||
export declare function at<T>(items: (T | undefined)[] | string, index: number, options: AtOptions & { | ||
optional: true; | ||
}): T | undefined; | ||
export declare function at<T>(items: T[], index: number, options?: AtOptions): T; | ||
export declare function getCurrentFileDirectory(url: string): string; | ||
export declare const flattenObj: (obj: object, prefix?: string) => Record<string, unknown>; | ||
export declare const flatten: (obj: object, prefix?: string) => Record<string, unknown>; | ||
export declare const kebabCase: (str: string) => string; | ||
export type MergeOptions = { | ||
atomicArrays?: boolean; | ||
}; | ||
export declare function merge<T extends object | A[], U extends object | B[], A, B>(dest: T, src: U, options?: MergeOptions): T & U; | ||
export declare const isArray: (value: unknown) => boolean; | ||
export declare const isObject: (value: unknown) => boolean; | ||
export type Hash = string | number[]; | ||
export declare const hashToHex: (hash: Hash) => string; | ||
//# sourceMappingURL=util.d.ts.map |
144
dist/util.js
@@ -1,80 +0,13 @@ | ||
import { u8aToHex } from '@polkadot/util'; | ||
export const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); | ||
export function* permutations(bins, options) { | ||
if (options?.includeEmpty) { | ||
yield []; | ||
} | ||
if (bins.length === 0) { | ||
return; | ||
} | ||
const arr = Array.from({ length: bins.length }, () => 0); | ||
let i = arr.length - 1; | ||
while (true) { | ||
yield [...arr]; | ||
arr[i]++; | ||
while (arr[i] === bins[i]) { | ||
arr[i] = 0; | ||
i--; | ||
if (i < 0) { | ||
return; | ||
} | ||
arr[i]++; | ||
} | ||
i = arr.length - 1; | ||
} | ||
} | ||
export function get(obj, key, required = true) { | ||
const value = obj[key]; | ||
if (required && value === undefined) { | ||
throw new Error(`Object has no property '${String(key)}': ${JSON.stringify(obj, null, 2)}`); | ||
} | ||
return value; | ||
} | ||
export function at(items, index, options) { | ||
if (items.length === 0) { | ||
throw new Error('Array is empty'); | ||
} | ||
if (!options?.noWrap) { | ||
if (index > 0) { | ||
index = index % items.length; | ||
} | ||
else { | ||
index = Math.ceil(Math.abs(index) / items.length) * items.length + index; | ||
} | ||
} | ||
if (index >= items.length) { | ||
throw new Error(`Index ${index} larger than array length ${items.length}`); | ||
} | ||
if (index < 0) { | ||
throw new Error(`Index ${index} smaller than 0`); | ||
} | ||
return items[index]; | ||
} | ||
function choice(items, n, random, options) { | ||
if (n > items.length) { | ||
throw new Error(`Cannot choose ${n} items from array of length ${items.length}`); | ||
} | ||
const result = []; | ||
const indices = []; | ||
for (let i = 0; i < n; i++) { | ||
let index; | ||
do { | ||
index = Math.floor(Math.abs(random()) * items.length) % items.length; | ||
} while (options?.withReplacement === false && indices.includes(index)); | ||
indices.push(index); | ||
result.push(items[index]); | ||
} | ||
return result; | ||
} | ||
export function getCurrentFileDirectory(url) { | ||
return new URL(url).pathname.split('/').slice(0, -1).join('/'); | ||
} | ||
export const flattenObj = (obj, prefix = '') => { | ||
export const flatten = (obj, prefix = '') => { | ||
const flattenedObj = {}; | ||
for (const [key, value] of Object.entries(obj)) { | ||
if (value instanceof Object) { | ||
Object.assign(flattenedObj, flattenObj(value, prefix + '.' + key)); | ||
Object.assign(flattenedObj, flatten(value, prefix + key + '.')); | ||
} | ||
else { | ||
flattenedObj[prefix + '.' + key] = value; | ||
flattenedObj[prefix + key] = value; | ||
} | ||
@@ -85,73 +18,2 @@ } | ||
export const kebabCase = (str) => str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, ($, ofs) => (ofs ? '-' : '') + $.toLowerCase()); | ||
export function merge(dest, src, options) { | ||
const atomicArrays = options?.atomicArrays; | ||
const queue = [ | ||
{ | ||
src, | ||
dest, | ||
}, | ||
]; | ||
while (queue.length > 0) { | ||
const task = queue.pop(); | ||
if (task === undefined) { | ||
throw new Error('queue is empty'); | ||
} | ||
if (isArray(task.dest)) { | ||
const src = task.src; | ||
const dest = task.dest; | ||
if (atomicArrays) { | ||
while (dest.length > src.length) { | ||
dest.pop(); | ||
} | ||
for (let i = 0; i < src.length; i++) { | ||
dest[i] = src[i]; | ||
} | ||
} | ||
else { | ||
for (let i = 0; i < src.length; i++) { | ||
if ((isArray(dest[i]) && isArray(src[i])) || (isObject(dest[i]) && isObject(src[i]))) { | ||
queue.push({ | ||
src: src[i], | ||
dest: dest[i], | ||
}); | ||
} | ||
else { | ||
dest[i] = src[i]; | ||
} | ||
} | ||
} | ||
} | ||
else if (isObject(task.dest)) { | ||
const src = task.src; | ||
const destAny = task.dest; | ||
for (const [key, value] of Object.entries(src)) { | ||
if ((isArray(value) && isArray(destAny[key])) || (isObject(value) && isObject(destAny[key]))) { | ||
queue.push({ | ||
src: value, | ||
dest: destAny[key], | ||
}); | ||
} | ||
else { | ||
destAny[key] = value; | ||
} | ||
} | ||
} | ||
else { | ||
throw new Error(`cannot handle type in queue: ${typeof task.dest}`); | ||
} | ||
} | ||
return dest; | ||
} | ||
export const isArray = (value) => { | ||
return Array.isArray(value); | ||
}; | ||
export const isObject = (value) => { | ||
return value instanceof Object && !isArray(value); | ||
}; | ||
export const hashToHex = (hash) => { | ||
if (isArray(hash)) { | ||
return u8aToHex(new Uint8Array(hash)); | ||
} | ||
return hash.toString(); | ||
}; | ||
//# sourceMappingURL=util.js.map |
{ | ||
"name": "@prosopo/util", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"author": "PROSOPO LIMITED <info@prosopo.io>", | ||
@@ -8,3 +8,3 @@ "license": "Apache-2.0", | ||
"engines": { | ||
"node": ">=18", | ||
"node": ">=20", | ||
"npm": ">=9" | ||
@@ -16,5 +16,5 @@ }, | ||
"build:cjs": "npx vite --config vite.cjs.config.ts build", | ||
"eslint": "npx eslint . --no-error-on-unmatched-pattern --ignore-path ../../.eslintignore --quiet", | ||
"eslint": "npx eslint . --cache --cache-location ../../node_modules/.cache/eslint/.eslintcache --no-error-on-unmatched-pattern --ignore-path ../../.eslintignore --quiet", | ||
"eslint:fix": "npm run eslint -- --fix", | ||
"prettier": "npx prettier . --check --no-error-on-unmatched-pattern --ignore-path ../../.eslintignore", | ||
"prettier": "npx prettier . --cache --cache-location ../../node_modules/.cache/prettier/.prettiercache --check --no-error-on-unmatched-pattern --ignore-path ../../.eslintignore", | ||
"prettier:fix": "npm run prettier -- --write", | ||
@@ -21,0 +21,0 @@ "lint": "npm run eslint && npm run prettier", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
783104
138
4819