UNPKG

egg

Version:

A web application framework for Node.js

117 lines (116 loc) • 4.06 kB
import util from "node:util"; import { isAsyncFunction, isClass, isFunction, isGeneratorFunction, isPrimitive, isRegExp, isSymbol } from "is-type-of"; //#region src/lib/core/utils.ts function convertObject(obj, ignore = []) { if (!Array.isArray(ignore)) ignore = [ignore]; for (const key of Object.keys(obj)) obj[key] = convertValue(key, obj[key], ignore); return obj; } function convertValue(key, value, ignore) { if (value === null || value === void 0) return value; let hit = false; for (const matchKey of ignore) if (typeof matchKey === "string" && matchKey === key) { hit = true; break; } else if (isRegExp(matchKey) && matchKey.test(key)) { hit = true; break; } if (!hit) { if (isSymbol(value) || isRegExp(value) || value instanceof URL) return value.toString(); if (isPrimitive(value) || Array.isArray(value)) return value; } if (Object.getPrototypeOf(value) === Object.prototype) return convertObject(value, ignore); const name = value.name || "anonymous"; if (isClass(value)) return `<Class ${name}>`; if (isFunction(value)) { if (isGeneratorFunction(value)) return `<GeneratorFunction ${name}>`; if (isAsyncFunction(value)) return `<AsyncFunction ${name}>`; return `<Function ${name}>`; } const typeName = value.constructor.name; if (typeName) { if (Buffer.isBuffer(value) || typeof value === "string") return `<${typeName} len: ${value.length}>`; return `<${typeName}>`; } return util.format(value); } function safeParseURL(url) { try { return new URL(url); } catch { return null; } } /** * Create a Proxy that behaves like the real object, but remains transparent to * monkeypatch libraries (e.g. defineProperty-based overrides like egg-mock's `mm()`). * * - Lazily creates the real object on first access. * - Allows overriding properties on the proxy target (overlay) — e.g. via `Object.defineProperty`. * - Delegates everything else to the real object. * * This is used to defer HttpClient construction so plugins can modify * `config.httpclient.lookup` after the first access to `app.httpClient` but * before any actual HTTP request is made. */ function createTransparentProxy(options) { const { createReal, bindFunctions = true } = options; if (typeof createReal !== "function") throw new TypeError("createReal must be a function"); let real; let cachedError; const boundFnCache = /* @__PURE__ */ new WeakMap(); const getReal = () => { if (real) return real; if (cachedError) throw cachedError; try { return real = createReal(); } catch (err) { cachedError = err; throw err; } }; const hasOwn = (obj, prop) => Reflect.getOwnPropertyDescriptor(obj, prop) !== void 0; return new Proxy({}, { get(target, prop, receiver) { const r = getReal(); if (hasOwn(target, prop)) return Reflect.get(target, prop, receiver); const value = Reflect.get(r, prop); if (bindFunctions && typeof value === "function") { let bound = boundFnCache.get(value); if (!bound) { bound = value.bind(r); boundFnCache.set(value, bound); } return bound; } return value; }, set(target, prop, value) { const r = getReal(); if (hasOwn(target, prop)) return Reflect.set(target, prop, value); return Reflect.set(r, prop, value); }, has(target, prop) { return Reflect.has(target, prop) || Reflect.has(getReal(), prop); }, ownKeys(target) { return [.../* @__PURE__ */ new Set([...Reflect.ownKeys(getReal()), ...Reflect.ownKeys(target)])]; }, getOwnPropertyDescriptor(target, prop) { return Reflect.getOwnPropertyDescriptor(target, prop) ?? Reflect.getOwnPropertyDescriptor(getReal(), prop); }, deleteProperty(target, prop) { if (hasOwn(target, prop)) return Reflect.deleteProperty(target, prop); return Reflect.deleteProperty(getReal(), prop); }, getPrototypeOf() { return Reflect.getPrototypeOf(getReal()); }, defineProperty(target, prop, descriptor) { return Reflect.defineProperty(target, prop, descriptor); } }); } //#endregion export { convertObject, createTransparentProxy, safeParseURL };