import { BasicEnumerable } from '../enumerables/BasicEnumerable'; import { ArrayExtensions } from '../extensions/ArrayExtensions'; import { from } from './from'; export function bindLinqToNativeTypes(options?: { types?: (new () => Iterable)[]; functionsToIgnore?: (keyof BasicEnumerable)[]; bindingOptions?: { writable?: boolean; configurable?: boolean; enumerable?: boolean }; }): void { const { types = [ Array, Int8Array, Int16Array, Int32Array, Uint8ClampedArray, Uint16Array, Uint32Array, Float32Array, Float64Array, Set, Map, String ] as (new () => Iterable)[], functionsToIgnore = [], bindingOptions: { writable = false, configurable = false, enumerable = false } = { writable: false, configurable: false, enumerable: false } } = options ?? {}; const descriptor = { writable, configurable, enumerable }; for (const type of types) { let test: Iterable; try { test = new type(); } catch { throw new TypeError(`Unsupported type: ${type.name}. All types must support the 'new' keyword.`); } if (!(Symbol.iterator in test)) { throw new TypeError(`Unsupported type: ${type.name}. Types must have Symbol.iterator.`); } } const alwaysIgnore: (keyof BasicEnumerable)[] = ['toJSON', 'toString']; const ignore = new Set>([...alwaysIgnore, ...functionsToIgnore]); const enumProps = BasicEnumerable.prototype; const protos = types.map(t => t.prototype); const enumPropNames = Object.getOwnPropertyNames(enumProps).filter( name => typeof enumProps[name as keyof BasicEnumerable] === 'function' && !ignore.has(name as keyof BasicEnumerable) ); for (const proto of protos) { for (const prop of enumPropNames) { if (!Object.prototype.hasOwnProperty.call(proto, prop)) { Object.defineProperty(proto, prop, { value: function (...params: unknown[]) { return (from(this) as any)[prop](...params); }, ...descriptor }); } } } const arrayExtensionPropNames = Object.getOwnPropertyNames(ArrayExtensions); for (const prop of arrayExtensionPropNames) { if ( typeof ArrayExtensions[prop as keyof ArrayExtensions] === 'function' && !Object.prototype.hasOwnProperty.call(Array, prop) && !Object.prototype.hasOwnProperty.call(Array.prototype, prop) ) { Object.defineProperty(Array.prototype, prop, { value: function (...params: unknown[]) { return (ArrayExtensions as any)[prop](this, ...params); }, ...descriptor }); } } }