interface StackItem { value : any ; previousKey : string | null ; } const hasOwnProperty = ( obj , property ) => Object . prototype . hasOwnProperty . call ( obj , property ) ; const isObject = ( obj ) => typeof obj === 'object' && obj !== null ; export function validateObject ( obj ) { if ( ! isObject ( obj ) ) { return ; } const stack = [ { value : obj , previousKey : null , } , ] ; const seen = new WeakSet ( [ obj ] ) ; while ( stack . length > 0 ) { const { value , previousKey } = stack . pop ( ) ! ; if ( ! isObject ( value ) ) { continue ; } if ( hasOwnProperty ( value , '__proto__' ) ) { throw new Error ( `'__proto__' is an invalid key` ) ; } if ( hasOwnProperty ( value , 'prototype' ) && previousKey === 'constructor' ) { throw new Error ( `'constructor.prototype' is an invalid key` ) ; } const entries = Object . entries ( value ) ; for ( let i = entries . length - 1 ; i >= 0 ; -- i ) { const [ key , childValue ] = entries [ i ] ; if ( isObject ( childValue ) ) { if ( seen . has ( childValue ) ) { throw new Error ( 'circular reference detected' ) ; } seen . add ( childValue ) ; } stack . push ( { value : childValue , previousKey : key , } ) ; } } }