UNPKG

tiny-ai-api

Version:

A customizable and extensible client api for managing conversations and AI interactions, currently supporting the **Google Gemini** API — with flexibility to support any similar AI APIs.

223 lines (219 loc) 9.08 kB
'use strict'; var buffer = require('buffer'); var objChecker = require('./objChecker.cjs'); const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined'; /** * An object containing type validation functions and their evaluation order. * * Each item in `typeValidator.items` is a function that receives any value * and returns a boolean indicating whether the value matches the corresponding type. * * The `order` array defines the priority in which types should be checked, * which can be useful for functions that infer types in a consistent manner. * */ const typeValidator = { items: {}, /** * Evaluation order of the type checkers. * @type {string[]} * */ order: [] }; /** @typedef {Object.<string, (val: any) => *>} ExtendObjType */ /** @typedef {Array<[string, (val: any) => *]>} ExtendObjTypeArray */ /** * Adds new type checkers to the typeValidator without overwriting existing ones. * * Accepts either an object with named functions or an array of [key, fn] arrays. * If no index is provided, the type is inserted just before 'object' (if it exists), or at the end. * * @param {ExtendObjType|ExtendObjTypeArray} newItems * - New type validators to be added. * @param {number} [index] - Optional. Position at which to insert each new type. Ignored if the type already exists. * @returns {string[]} - A list of successfully added type names. * * @example * extendObjType({ * htmlElement2: val => typeof HTMLElement !== 'undefined' && val instanceof HTMLElement * }); * * @example * extendObjType([ * ['alpha', val => typeof val === 'string'], * ['beta', val => Array.isArray(val)] * ]); */ function extendObjType(newItems, index) { const added = []; const entries = Array.isArray(newItems) ? newItems : Object.entries(newItems); for (const [key, fn] of entries) { if (!typeValidator.items.hasOwnProperty(key)) { // @ts-ignore typeValidator.items[key] = fn; let insertAt = typeof index === 'number' ? index : -1; // Default to -1 if index isn't provided // Default to before 'object', or to the end if (insertAt === -1) { const objectIndex = typeValidator.order.indexOf('object'); insertAt = objectIndex > -1 ? objectIndex : typeValidator.order.length; } // Ensure insertAt is a valid number and not out of bounds insertAt = Math.min(Math.max(0, insertAt), typeValidator.order.length); typeValidator.order.splice(insertAt, 0, key); added.push(key); } } return added; } /** * Reorders the typeValidator.order array according to a custom new order. * All values in the new order must already exist in the current order. * The function does not mutate the original array structure directly. * * @param {string[]} newOrder - The new order of type names. * @returns {boolean} - Returns true if the reorder was successful, false if invalid keys were found. * * @example * reorderObjTypeOrder([ * 'string', 'number', 'array', 'object' * ]); */ function reorderObjTypeOrder(newOrder) { const currentOrder = [...typeValidator.order]; // shallow clone // All keys in newOrder must exist in currentOrder const isValid = newOrder.every(type => currentOrder.includes(type)); if (!isValid) return false; // Reassign only if valid typeValidator.order = newOrder.slice(); // assign shallow copy return true; } /** * Returns a cloned version of the `typeValidator.order` array. * The cloned array will not be affected by future changes to the original `order`. * * @returns {string[]} - A new array with the same values as `typeValidator.order`. */ function cloneObjTypeOrder() { return [...typeValidator.order]; // Creates a shallow copy of the array } /** * Returns the detected type name of a given value based on predefined type validators. * * This function uses `getType` with a predefined `typeValidator` to determine or compare types safely. * in the specified `typeValidator.order`. The first matching type is returned. * * If `val` is `null`, it immediately returns `'null'`. * If no match is found, it returns `'unknown'`. * * @param {any} val - The value whose type should be determined. * @returns {string} - The type name of the value (e.g., "array", "date", "map"), or "unknown" if no match is found. * * @example * getType([]); // "array" * getType(null); // "null" * getType(new Set()); // "set" * getType(() => {}); // "unknown" */ const getType = val => { if (val === null) return 'null'; // @ts-ignore for (const name of typeValidator.order) { // @ts-ignore if (typeof typeValidator.items[name] !== 'function' || typeValidator.items[name](val)) return name; } return 'unknown'; }; /** * Checks the type of a given object or returns its type as a string. * * @param {*} obj - The object to check or identify. * @param {string} [type] - Optional. If provided, checks whether the object matches this type (e.g., "object", "array", "string"). * @returns {boolean|string|null} - Returns `true` if the type matches, `false` if not, * the type string if no type is provided, or `null` if the object is `undefined`. * * @example * objType([], 'array'); // true * objType({}, 'object'); // true * objType('hello'); // "string" * objType(undefined); // null */ function objType(obj, type) { if (typeof obj === 'undefined') return null; const result = getType(obj); if (typeof type === 'string') return result === type.toLowerCase(); return result; } /** * Checks the type of a given object and returns the validation value if a known type is detected. * * @param {*} obj - The object to check or identify. * @returns {{ valid:*; type: string | null }} - Returns the type result. */ function checkObj(obj) { /** @type {{ valid:*; type: string | null }} */ const data = { valid: null, type: null }; for (const name of typeValidator.order) { // @ts-ignore if (typeof typeValidator.items[name] === 'function') { // @ts-ignore const result = typeValidator.items[name](obj); if (result) { data.valid = result; data.type = name; break; } } } return data; } /** * Creates a clone of the functions from the `typeValidator` object. * It returns a new object where the keys are the same and the values are the cloned functions. */ function getCheckObj() { return Object.fromEntries(Object.entries(typeValidator.items).map(([key, fn]) => [key, fn])); } // Insert obj types extendObjType([['undefined', /** @param {*} val @returns {val is undefined} */ val => typeof val === 'undefined'], ['null', /** @param {*} val @returns {val is null} */ val => val === null], ['boolean', /** @param {*} val @returns {val is boolean} */ val => typeof val === 'boolean'], ['number', /** @param {*} val @returns {val is number} */ val => typeof val === 'number' && !Number.isNaN(val)], ['bigint', /** @param {*} val @returns {val is bigint} */ val => typeof val === 'bigint'], ['string', /** @param {*} val @returns {val is string} */ val => typeof val === 'string'], ['symbol', /** @param {*} val @returns {val is symbol} */ val => typeof val === 'symbol'], ['function', /** @param {*} val @returns {val is Function} */ val => typeof val === 'function'], ['array', /** @param {*} val @returns {val is any[]} */ val => Array.isArray(val)]]); if (!isBrowser) { extendObjType([['buffer', /** @param {*} val @returns {val is Buffer} */ val => typeof buffer.Buffer !== 'undefined' && buffer.Buffer.isBuffer(val)]]); } if (isBrowser) { extendObjType([['file', /** @param {*} val @returns {val is File} */ val => typeof File !== 'undefined' && val instanceof File]]); } extendObjType([['date', /** @param {*} val @returns {val is Date} */ val => val instanceof Date], ['regexp', /** @param {*} val @returns {val is RegExp} */ val => val instanceof RegExp], ['map', /** @param {*} val @returns {val is Map<unknown, unknown>} */ val => val instanceof Map], ['set', /** @param {*} val @returns {val is Set<unknown>} */ val => val instanceof Set], ['weakmap', /** @param {*} val @returns {val is WeakMap<unknown, unknown>} */ val => val instanceof WeakMap], ['weakset', /** @param {*} val @returns {val is WeakSet<unknown>} */ val => val instanceof WeakSet], ['promise', /** @param {*} val @returns {val is Promise<unknown>} */ val => val instanceof Promise]]); if (isBrowser) { extendObjType([['htmlelement', /** @param {*} val @returns {val is HTMLElement} */ val => typeof HTMLElement !== 'undefined' && val instanceof HTMLElement]]); } extendObjType([['object', /** @param {*} val @returns {val is Record<string | number | symbol, unknown>} */ val => objChecker.isJsonObject(val)]]); exports.countObj = objChecker.countObj; exports.isJsonObject = objChecker.isJsonObject; exports.checkObj = checkObj; exports.cloneObjTypeOrder = cloneObjTypeOrder; exports.extendObjType = extendObjType; exports.getCheckObj = getCheckObj; exports.objType = objType; exports.reorderObjTypeOrder = reorderObjTypeOrder;