/**
 * Copyright (c) 2016-2018 Dmitry Panyushkin
 * Available under MIT license
 */ import * as ko from "knockout" ; import { defineProperty , getPrototypeOf , hasOwnProperty , isArray , objectForEach , PATCHED_KEY , } from "./common-functions" ; import { defineObservableArray } from "./observable-array" ; import { applyExtenders } from "./property-extenders" ; export function defineObservableProperty ( instance , key , value , deep , expose ) { const observable = applyExtenders ( instance , key , ko . observable ( ) ) ; let setter = observable as any ; if ( deep ) { setter = function ( newValue ) { observable ( prepareDeepValue ( newValue , expose ) ) ; } ; } defineProperty ( instance , key , { enumerable : true , get : observable , set : setter , } ) ; if ( expose ) { defineProperty ( instance , "_" + String ( key ) , { value : observable , } ) ; } setter ( value ) ; } export function prepareDeepValue ( value , expose ) { if ( typeof value === "object" ) { if ( isArray ( value ) || value === null ) { return value ; } else if ( hasOwnProperty ( value , "constructor" ) ) { const prototype = getPrototypeOf ( value ) ; if ( prototype === Object . prototype || prototype === null ) { return prepareDeepObject ( value , expose ) ; } } else if ( value . constructor === Object ) { return prepareDeepObject ( value , expose ) ; } } return value ; } export function prepareDeepObject ( instance , expose ) { if ( ! hasOwnProperty ( instance , PATCHED_KEY ) ) { defineProperty ( instance , PATCHED_KEY , { value : true , } ) ; objectForEach ( instance , ( key , value ) => { if ( isArray ( value ) ) { defineObservableArray ( instance , key , value , true , expose ) ; } else { defineObservableProperty ( instance , key , value , true , expose ) ; } } ) ; } return instance ; }