import {types} from 'node:util'; export const valid_plugin_name = (value: unknown): value is string => typeof value === 'string' && /^[a-zA-Z0-9_-]+$/.test(value); export const valid_plugin_path = (value: unknown): value is string => typeof value === 'string' && /^[a-zA-Z0-9_-]+(?:\/[a-zA-Z0-9_-]+)*$/.test(value); export function plain_plugin_object(value: unknown): value is Record { if (!value || typeof value !== 'object' || types.isProxy(value)) return false; const prototype = Object.getPrototypeOf(value); if (!prototype || types.isProxy(prototype)) return false; const constructor = Object.getOwnPropertyDescriptor(prototype, 'constructor'); // Accept ordinary objects from other realms, but never custom prototypes. if (Object.getPrototypeOf(prototype) !== null || !constructor || typeof constructor.value !== 'function' || types.isProxy(constructor.value) || constructor.value.prototype !== prototype || Function.prototype.toString.call(constructor.value) !== 'function Object() { [native code] }') return false; return Reflect.ownKeys(value).every(key => typeof key === 'string' && Object.getOwnPropertyDescriptor(value, key)?.enumerable && Object.hasOwn(Object.getOwnPropertyDescriptor(value, key)!, 'value')); } export function valid_plugin_config(value: unknown): value is Record { if (!plain_plugin_object(value)) return false; return Object.values(value).every(item => { if (item === null || typeof item === 'string' || typeof item === 'boolean') return true; if (typeof item === 'number') return Number.isFinite(item); if (!Array.isArray(item) || types.isProxy(item)) return false; const prototype = Object.getPrototypeOf(item); if (!prototype || types.isProxy(prototype)) return false; const constructor = Object.getOwnPropertyDescriptor(prototype, 'constructor'); if (!constructor || typeof constructor.value !== 'function' || types.isProxy(constructor.value) || constructor.value.prototype !== prototype || Function.prototype.toString.call(constructor.value) !== 'function Array() { [native code] }') return false; const keys = Reflect.ownKeys(item); return keys.length === item.length + 1 && keys.every(key => key === 'length' || typeof key === 'string' && /^(0|[1-9]\d*)$/.test(key) && Object.hasOwn(Object.getOwnPropertyDescriptor(item, key)!, 'value')) && Array.from(item).every(value => typeof value === 'string' || typeof value === 'number' && Number.isFinite(value)); }); }