From bbce43e5fa36510b7cf4b1b437ff27146ed15a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Tue, 21 Jul 2026 14:51:14 +0200 Subject: [PATCH] feat(x): add `xIsArray` and improve types of `xCheck` --- .../__snapshots__/index.test.ts.snap | 1 + src/x/__tests__/xCheck.test.ts | 10 ++++-- src/x/__tests__/xIsArray.test.ts | 16 ++++++++++ src/x/index.ts | 1 + src/x/xCheck.ts | 9 +++--- src/x/xIsArray.ts | 31 +++++++++++++++++++ 6 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 src/x/__tests__/xIsArray.test.ts create mode 100644 src/x/xIsArray.ts diff --git a/src/__tests__/__snapshots__/index.test.ts.snap b/src/__tests__/__snapshots__/index.test.ts.snap index 36390c1f2..b7eb3cb7d 100644 --- a/src/__tests__/__snapshots__/index.test.ts.snap +++ b/src/__tests__/__snapshots__/index.test.ts.snap @@ -37,6 +37,7 @@ exports[`existence of exported functions 1`] = ` "xGetTargetIndex", "xHilbertTransform", "xHistogram", + "xIsArray", "xIsEquallySpaced", "xIsMonotonic", "xMassCenterVectorSimilarity", diff --git a/src/x/__tests__/xCheck.test.ts b/src/x/__tests__/xCheck.test.ts index 9da51610c..151e13552 100644 --- a/src/x/__tests__/xCheck.test.ts +++ b/src/x/__tests__/xCheck.test.ts @@ -3,10 +3,16 @@ import { expect, test } from 'vitest'; import { xCheck } from '../xCheck.ts'; test('should throw on invalid value', () => { - expect(() => xCheck()).toThrow(/input must be an array/); + expect(() => xCheck(undefined)).toThrow(/input must be an array/); expect(() => xCheck([])).toThrow(/input must not be empty/); - expect(() => xCheck([1])).not.toThrow(); + expect(() => xCheck(['yo', 1])).toThrow(/input must contain numbers/); expect(() => xCheck([1], { minLength: 2 })).toThrow( /input must have a length of at least 2/, ); }); + +test('should not throw on valid value', () => { + expect(() => xCheck([1])).not.toThrow(); + expect(() => xCheck([1, 2], { minLength: 2 })).not.toThrow(); + expect(() => xCheck([1, 2, 3], { minLength: 2 })).not.toThrow(); +}); diff --git a/src/x/__tests__/xIsArray.test.ts b/src/x/__tests__/xIsArray.test.ts new file mode 100644 index 000000000..d0b62f71c --- /dev/null +++ b/src/x/__tests__/xIsArray.test.ts @@ -0,0 +1,16 @@ +import { expect, test } from 'vitest'; + +import { xIsArray } from '../xIsArray.ts'; + +test('should return false on invalid value', () => { + expect(xIsArray(undefined)).toBe(false); + expect(xIsArray([])).toBe(false); + expect(xIsArray(['yo', 1])).toBe(false); + expect(xIsArray([1], { minLength: 2 })).toBe(false); +}); + +test('should return true on valid value', () => { + expect(xIsArray([1])).toBe(true); + expect(xIsArray([1, 2], { minLength: 2 })).toBe(true); + expect(xIsArray([1, 2, 3], { minLength: 2 })).toBe(true); +}); diff --git a/src/x/index.ts b/src/x/index.ts index a252a6b19..d185ae2f8 100644 --- a/src/x/index.ts +++ b/src/x/index.ts @@ -27,6 +27,7 @@ export * from './xGetFromToIndex.ts'; export * from './xGetTargetIndex.ts'; export * from './xHilbertTransform.ts'; export * from './xHistogram.ts'; +export * from './xIsArray.ts'; export * from './xIsEquallySpaced.ts'; export * from './xIsMonotonic.ts'; export * from './xMassCenterVectorSimilarity.ts'; diff --git a/src/x/xCheck.ts b/src/x/xCheck.ts index 8370bd3b4..d267c9bcd 100644 --- a/src/x/xCheck.ts +++ b/src/x/xCheck.ts @@ -3,7 +3,8 @@ import { isAnyArray } from 'is-any-array'; export interface XCheckOptions { /** - * Minimum length + * Minimum length. + * Must be at least 1 because the first element is always checked. * @default 1 */ minLength?: number; @@ -16,10 +17,10 @@ export interface XCheckOptions { * @param options - additional checks. */ export function xCheck( - input?: NumberArray, + input: unknown, options: XCheckOptions = {}, ): asserts input is NumberArray { - const { minLength } = options; + const { minLength = 1 } = options; if (!isAnyArray(input)) { throw new TypeError('input must be an array'); } @@ -29,7 +30,7 @@ export function xCheck( if (typeof input[0] !== 'number') { throw new TypeError('input must contain numbers'); } - if (minLength && input.length < minLength) { + if (input.length < minLength) { throw new Error(`input must have a length of at least ${minLength}`); } } diff --git a/src/x/xIsArray.ts b/src/x/xIsArray.ts new file mode 100644 index 000000000..390b26d18 --- /dev/null +++ b/src/x/xIsArray.ts @@ -0,0 +1,31 @@ +import type { NumberArray } from 'cheminfo-types'; +import { isAnyArray } from 'is-any-array'; + +export interface XIsArrayOptions { + /** + * Minimum length. + * Must be at least 1 because the first element is always checked. + * @default 1 + */ + minLength?: number; +} + +/** + * Checks if the input is a non-empty array of numbers. + * Only checks the first element. + * @param input - array to check. + * @param options - additional checks. + * @returns Whether the value is a valid array of numbers. + */ +export function xIsArray( + input: unknown, + options: XIsArrayOptions = {}, +): input is NumberArray { + const { minLength = 1 } = options; + return ( + isAnyArray(input) && + input.length > 0 && + typeof input[0] === 'number' && + input.length >= minLength + ); +}