@oxog/kindof
Version:
Zero-dependency advanced type detection library with TypeScript support, plugin system, and 100% test coverage
732 lines (723 loc) • 18.8 kB
JavaScript
'use strict';
const TYPE_TAG_MAP = {
"[object Arguments]": "arguments",
"[object Array]": "array",
"[object ArrayBuffer]": "arraybuffer",
"[object AsyncFunction]": "asyncfunction",
"[object AsyncGeneratorFunction]": "asyncgeneratorfunction",
"[object BigInt]": "bigint",
"[object BigInt64Array]": "bigint64array",
"[object BigUint64Array]": "biguint64array",
"[object Boolean]": "boolean",
"[object DataView]": "dataview",
"[object Date]": "date",
"[object Error]": "error",
"[object Float32Array]": "float32array",
"[object Float64Array]": "float64array",
"[object Function]": "function",
"[object GeneratorFunction]": "generatorfunction",
"[object Int8Array]": "int8array",
"[object Int16Array]": "int16array",
"[object Int32Array]": "int32array",
"[object Map]": "map",
"[object Number]": "number",
"[object Object]": "object",
"[object Promise]": "promise",
"[object Proxy]": "proxy",
"[object RegExp]": "regexp",
"[object Set]": "set",
"[object SharedArrayBuffer]": "sharedarraybuffer",
"[object String]": "string",
"[object Symbol]": "symbol",
"[object Uint8Array]": "uint8array",
"[object Uint8ClampedArray]": "uint8clampedarray",
"[object Uint16Array]": "uint16array",
"[object Uint32Array]": "uint32array",
"[object WeakMap]": "weakmap",
"[object WeakSet]": "weakset",
"[object Window]": "window",
"[object HTMLDocument]": "document",
"[object Document]": "document",
"[object Null]": "null",
"[object Undefined]": "undefined"
};
const toString$1 = Object.prototype.toString;
const toStringTag = Symbol.toStringTag;
function getNativeType(value) {
if (value === void 0) return "undefined";
if (value === null) return "null";
const primitiveType = typeof value;
switch (primitiveType) {
case "boolean":
return "boolean";
case "number":
return "number";
case "string":
return "string";
case "symbol":
return "symbol";
case "bigint":
return "bigint";
case "function":
return getFunctionType(value);
case "object":
return getObjectType(value);
default:
return null;
}
}
function getFunctionType(fn) {
const fnString = fn.toString();
if (/^class\s/.test(fnString)) {
return "function";
}
if (/^async\s*function\s*\*/.test(fnString) || /^async\s*\*/.test(fnString)) {
return "asyncgeneratorfunction";
}
if (/^async\s/.test(fnString)) {
return "asyncfunction";
}
if (/^function\s*\*/.test(fnString) || /^\*/.test(fnString)) {
return "generatorfunction";
}
const ctorName = fn.constructor?.name;
if (ctorName === "AsyncFunction") return "asyncfunction";
if (ctorName === "GeneratorFunction") return "generatorfunction";
if (ctorName === "AsyncGeneratorFunction") return "asyncgeneratorfunction";
return "function";
}
function getObjectType(obj) {
const tag = toString$1.call(obj);
const mappedType = TYPE_TAG_MAP[tag];
if (mappedType) {
return mappedType;
}
if (typeof Buffer !== "undefined" && Buffer.isBuffer && Buffer.isBuffer(obj)) {
return "buffer";
}
if (typeof obj === "object" && "callee" in obj && typeof obj.callee === "function") {
return "arguments";
}
if (isStream(obj)) {
return "stream";
}
if (isEventEmitter(obj)) {
return "eventemitter";
}
if (tag === "[object Object]") {
const customTag = obj[toStringTag];
if (typeof customTag === "string") {
return customTag.toLowerCase();
}
const ctor = obj.constructor;
if (ctor && ctor !== Object) {
const ctorName = ctor.name;
if (ctorName && ctorName !== "Object") {
return ctorName.toLowerCase();
}
}
}
if (isDOMElement(obj)) {
return "element";
}
if (isDOMNode(obj)) {
return "node";
}
if (isGlobal(obj)) {
return "global";
}
return "object";
}
function isStream(obj) {
return obj !== null && typeof obj === "object" && typeof obj.pipe === "function";
}
function isEventEmitter(obj) {
return obj !== null && typeof obj === "object" && typeof obj.on === "function" && typeof obj.emit === "function" && typeof obj.removeListener === "function";
}
function isDOMElement(obj) {
if (typeof HTMLElement === "undefined") return false;
return obj instanceof HTMLElement;
}
function isDOMNode(obj) {
if (typeof Node === "undefined") return false;
return obj instanceof Node;
}
function isGlobal(obj) {
if (typeof globalThis !== "undefined" && obj === globalThis) return true;
if (typeof global !== "undefined" && obj === global) return true;
if (typeof window !== "undefined" && obj === window) return true;
if (typeof self !== "undefined" && obj === self) return true;
return false;
}
const WeakMapPrototype = WeakMap.prototype;
const WeakSetPrototype = WeakSet.prototype;
const MapPrototype = Map.prototype;
const SetPrototype = Set.prototype;
const ArrayBufferPrototype = ArrayBuffer.prototype;
const DataViewPrototype = DataView.prototype;
const SharedArrayBufferPrototype = typeof SharedArrayBuffer !== "undefined" ? SharedArrayBuffer.prototype : null;
function checkModernType(value) {
if (value === null || value === void 0) {
return null;
}
try {
if (value instanceof Promise || isThenable(value)) {
return "promise";
}
if (value instanceof Map || value.__proto__ === MapPrototype) {
return "map";
}
if (value instanceof Set || value.__proto__ === SetPrototype) {
return "set";
}
if (value instanceof WeakMap || value.__proto__ === WeakMapPrototype) {
return "weakmap";
}
if (value instanceof WeakSet || value.__proto__ === WeakSetPrototype) {
return "weakset";
}
if (value instanceof ArrayBuffer || value.__proto__ === ArrayBufferPrototype) {
return "arraybuffer";
}
if (SharedArrayBufferPrototype && (value instanceof SharedArrayBuffer || value.__proto__ === SharedArrayBufferPrototype)) {
return "sharedarraybuffer";
}
if (value instanceof DataView || value.__proto__ === DataViewPrototype) {
return "dataview";
}
if (isProxy(value)) {
return "proxy";
}
} catch {
}
return null;
}
function isThenable(value) {
return value !== null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
}
function isProxy(value) {
try {
if (typeof value !== "object" && typeof value !== "function") {
return false;
}
new Proxy({}, value);
const descriptor = Object.getOwnPropertyDescriptor(value, Symbol.toStringTag);
if (descriptor && !descriptor.configurable && descriptor.value === "Proxy") {
return true;
}
return false;
} catch {
return false;
}
}
function getTypedArrayType(value) {
if (!ArrayBuffer.isView(value)) {
return null;
}
const proto = Object.getPrototypeOf(value);
const ctorName = proto?.constructor?.name;
switch (ctorName) {
case "Int8Array":
return "int8array";
case "Uint8Array":
return "uint8array";
case "Uint8ClampedArray":
return "uint8clampedarray";
case "Int16Array":
return "int16array";
case "Uint16Array":
return "uint16array";
case "Int32Array":
return "int32array";
case "Uint32Array":
return "uint32array";
case "Float32Array":
return "float32array";
case "Float64Array":
return "float64array";
case "BigInt64Array":
return "bigint64array";
case "BigUint64Array":
return "biguint64array";
default:
return null;
}
}
let typeCache = null;
let cacheEnabled = true;
function kindOfCore(value) {
if (value === void 0) return "undefined";
if (value === null) return "null";
const primitiveType = getPrimitiveType(value);
if (primitiveType) return primitiveType;
if (typeof value === "object" && cacheEnabled && typeCache) {
const cached = typeCache.get(value);
if (cached) return cached;
}
let type = getNativeType(value);
if (!type || type === "object") {
const modernType = checkModernType(value);
if (modernType) {
type = modernType;
} else {
const arrayType = getTypedArrayType(value);
if (arrayType) {
type = arrayType;
} else {
type = getCustomType(value) || type || "object";
}
}
}
if (typeof value === "object" && cacheEnabled && type) {
if (!typeCache) typeCache = /* @__PURE__ */ new WeakMap();
typeCache.set(value, type);
}
return type || "object";
}
function getPrimitiveType(value) {
const type = typeof value;
switch (type) {
case "boolean":
case "number":
case "string":
case "symbol":
case "bigint":
return type;
default:
return null;
}
}
function getCustomType(value) {
try {
const toStringTag = value[Symbol.toStringTag];
if (typeof toStringTag === "string") {
return toStringTag.toLowerCase();
}
if (value.constructor && value.constructor !== Object) {
const ctorName = value.constructor.name;
if (ctorName && ctorName !== "Object") {
return ctorName.toLowerCase();
}
}
} catch {
}
return null;
}
function toString(value) {
const type = kindOfCore(value);
switch (type) {
case "string":
return value;
case "number":
case "boolean":
case "bigint":
return String(value);
case "symbol":
return value.toString();
case "undefined":
return "undefined";
case "null":
return "null";
case "date":
return value.toISOString();
case "regexp":
return value.toString();
case "function":
return value.toString();
case "array":
return JSON.stringify(value);
case "object":
try {
return JSON.stringify(value);
} catch {
return Object.prototype.toString.call(value);
}
default:
return String(value);
}
}
function toNumber(value) {
const type = kindOfCore(value);
switch (type) {
case "number":
return value;
case "string": {
const num = Number(value);
return isNaN(num) ? null : num;
}
case "boolean":
return value ? 1 : 0;
case "null":
return 0;
case "bigint": {
const bigIntValue = Number(value);
return bigIntValue > Number.MAX_SAFE_INTEGER || bigIntValue < Number.MIN_SAFE_INTEGER ? null : bigIntValue;
}
case "date":
return value.getTime();
default:
return null;
}
}
function toBoolean(value) {
const type = kindOfCore(value);
switch (type) {
case "boolean":
return value;
case "string": {
const str = value.toLowerCase();
return str !== "" && str !== "false" && str !== "0" && str !== "no" && str !== "null" && str !== "undefined";
}
case "number":
return value !== 0 && !isNaN(value);
case "null":
case "undefined":
return false;
case "array":
return value.length > 0;
case "object":
return Object.keys(value).length > 0;
default:
return !!value;
}
}
function toBigInt(value) {
const type = kindOfCore(value);
switch (type) {
case "bigint":
return value;
case "number":
if (Number.isInteger(value)) {
return BigInt(value);
}
return null;
case "string":
try {
return BigInt(value);
} catch {
return null;
}
case "boolean":
return BigInt(value ? 1 : 0);
default:
return null;
}
}
function toSymbol(value) {
const type = kindOfCore(value);
switch (type) {
case "symbol":
return value;
case "string":
return Symbol(value);
case "number":
return Symbol(String(value));
default:
return Symbol(toString(value));
}
}
function toArray(value) {
const type = kindOfCore(value);
switch (type) {
case "array":
return value;
case "string":
return Array.from(value);
case "set":
return Array.from(value);
case "map":
return Array.from(value);
case "arguments":
return Array.from(value);
case "null":
case "undefined":
return [];
default:
if (value !== null && typeof value === "object" && "length" in value) {
return Array.from(value);
}
return [value];
}
}
function toObject(value) {
const type = kindOfCore(value);
switch (type) {
case "object":
return value;
case "array": {
const arr = value;
const obj = {};
arr.forEach((item, index) => {
obj[index] = item;
});
return obj;
}
case "map": {
const map = value;
const obj = {};
for (const [key, val] of map) {
obj[String(key)] = val;
}
return obj;
}
case "set": {
const set = value;
const obj = {};
let index = 0;
for (const item of set) {
obj[index++] = item;
}
return obj;
}
case "string": {
const str = value;
const obj = {};
for (let i = 0; i < str.length; i++) {
obj[i] = str[i];
}
return obj;
}
case "null":
case "undefined":
return {};
default:
return { value };
}
}
function toMap(value) {
const type = kindOfCore(value);
switch (type) {
case "map":
return value;
case "object": {
const obj = value;
const map = /* @__PURE__ */ new Map();
for (const [key, val] of Object.entries(obj)) {
map.set(key, val);
}
return map;
}
case "array": {
const arr = value;
const map = /* @__PURE__ */ new Map();
arr.forEach((item, index) => {
map.set(index, item);
});
return map;
}
case "set": {
const set = value;
const map = /* @__PURE__ */ new Map();
let index = 0;
for (const item of set) {
map.set(index++, item);
}
return map;
}
default:
return null;
}
}
function toSet(value) {
const type = kindOfCore(value);
switch (type) {
case "set":
return value;
case "array":
return new Set(value);
case "string":
return new Set(Array.from(value));
case "map":
return new Set(value.values());
case "object":
return new Set(Object.values(value));
default:
return value !== null && value !== void 0 ? /* @__PURE__ */ new Set([value]) : /* @__PURE__ */ new Set();
}
}
function toDate(value) {
const type = kindOfCore(value);
switch (type) {
case "date":
return value;
case "string": {
const date = new Date(value);
return isNaN(date.getTime()) ? null : date;
}
case "number": {
const date = new Date(value);
return isNaN(date.getTime()) ? null : date;
}
default:
return null;
}
}
function toRegExp(value) {
const type = kindOfCore(value);
switch (type) {
case "regexp":
return value;
case "string":
try {
return new RegExp(value);
} catch {
return null;
}
default:
return null;
}
}
function toError(value) {
const type = kindOfCore(value);
switch (type) {
case "error":
return value;
case "string":
return new Error(value);
case "object":
if (value && typeof value === "object" && "message" in value) {
return new Error(String(value.message));
}
return new Error(String(value));
default:
return new Error(String(value));
}
}
function toFunction(value) {
const type = kindOfCore(value);
switch (type) {
case "function":
case "asyncfunction":
case "generatorfunction":
case "asyncgeneratorfunction":
return value;
case "string":
try {
return new Function("return " + String(value));
} catch {
return null;
}
default:
return null;
}
}
function toPromise(value) {
const type = kindOfCore(value);
switch (type) {
case "promise":
return value;
case "function":
try {
const result = value();
return Promise.resolve(result);
} catch (error) {
return Promise.reject(error);
}
default:
return Promise.resolve(value);
}
}
function toBuffer(value) {
if (typeof Buffer === "undefined") {
return null;
}
const type = kindOfCore(value);
switch (type) {
case "buffer":
return value;
case "string":
return Buffer.from(value);
case "array":
return Buffer.from(value);
case "uint8array":
return Buffer.from(value);
case "arraybuffer":
return Buffer.from(value);
default:
return null;
}
}
function toTypedArray(value, TypedArrayConstructor) {
const type = kindOfCore(value);
switch (type) {
case "arraybuffer":
return new TypedArrayConstructor(value);
case "array": {
const arr = value;
const buffer = new ArrayBuffer(arr.length * 4);
const view = new TypedArrayConstructor(buffer);
for (let i = 0; i < arr.length; i++) {
view[i] = arr[i];
}
return view;
}
default:
if (type.includes("array") && value instanceof ArrayBuffer) {
return new TypedArrayConstructor(value);
}
return null;
}
}
function coerceType(value, targetType) {
const currentType = kindOfCore(value);
if (currentType === targetType) {
return value;
}
switch (targetType) {
case "string":
return toString(value);
case "number":
return toNumber(value);
case "boolean":
return toBoolean(value);
case "bigint":
return toBigInt(value);
case "symbol":
return toSymbol(value);
case "undefined":
return void 0;
case "null":
return null;
case "array":
if (currentType === "object" && value !== null) {
const arr = Array.from(value);
return arr.length > 0 ? arr : null;
}
return null;
case "object":
if (currentType === "array") {
const obj = {};
value.forEach((item, index) => {
obj[index] = item;
});
return obj;
}
return null;
case "date":
if (currentType === "string") {
const date = new Date(value);
return isNaN(date.getTime()) ? null : date;
}
return null;
default:
return null;
}
}
exports.coerceType = coerceType;
exports.toArray = toArray;
exports.toBigInt = toBigInt;
exports.toBoolean = toBoolean;
exports.toBuffer = toBuffer;
exports.toDate = toDate;
exports.toError = toError;
exports.toFunction = toFunction;
exports.toMap = toMap;
exports.toNumber = toNumber;
exports.toObject = toObject;
exports.toPromise = toPromise;
exports.toRegExp = toRegExp;
exports.toSet = toSet;
exports.toString = toString;
exports.toSymbol = toSymbol;
exports.toTypedArray = toTypedArray;
//# sourceMappingURL=index.cjs.map