From e56f09dfe58cc5b279638ac8ef603da18cd45bbc Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Thu, 13 Apr 2017 22:27:45 -0400 Subject: [PATCH] =?UTF-8?q?clone=20before=20set=20=E2=80=94=20fixes=20#479?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/index.js | 100 +++++++++++++++++- src/shared/methods.js | 98 ----------------- .../samples/set-clones-input/_config.js | 10 ++ .../samples/set-clones-input/main.html | 7 ++ 4 files changed, 116 insertions(+), 99 deletions(-) delete mode 100644 src/shared/methods.js create mode 100644 test/runtime/samples/set-clones-input/_config.js create mode 100644 test/runtime/samples/set-clones-input/main.html diff --git a/src/shared/index.js b/src/shared/index.js index de2dee3126..9fa41f3122 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -1,5 +1,4 @@ export * from './dom.js'; -export * from './methods.js'; export function noop () {} @@ -38,3 +37,102 @@ export function dispatchObservers ( component, group, newState, oldState ) { } } } + +export function get ( key ) { + return key ? this._state[ key ] : this._state; +} + +export function fire ( eventName, data ) { + var handlers = eventName in this._handlers && this._handlers[ eventName ].slice(); + if ( !handlers ) return; + + for ( var i = 0; i < handlers.length; i += 1 ) { + handlers[i].call( this, data ); + } +} + +export function observe ( key, callback, options ) { + var group = ( options && options.defer ) ? this._observers.post : this._observers.pre; + + ( group[ key ] || ( group[ key ] = [] ) ).push( callback ); + + if ( !options || options.init !== false ) { + callback.__calling = true; + callback.call( this, this._state[ key ] ); + callback.__calling = false; + } + + return { + cancel: function () { + var index = group[ key ].indexOf( callback ); + if ( ~index ) group[ key ].splice( index, 1 ); + } + }; +} + +export function observeDev ( key, callback, options ) { + var c = ( key = '' + key ).search( /[^\w]/ ); + if ( c > -1 ) { + var message = "The first argument to component.observe(...) must be the name of a top-level property"; + if ( c > 0 ) message += ", i.e. '" + key.slice( 0, c ) + "' rather than '" + key + "'"; + + throw new Error( message ); + } + + return observe.call( this, key, callback, options ); +} + +export function on ( eventName, handler ) { + if ( eventName === 'teardown' ) return this.on( 'destroy', handler ); + + var handlers = this._handlers[ eventName ] || ( this._handlers[ eventName ] = [] ); + handlers.push( handler ); + + return { + cancel: function () { + var index = handlers.indexOf( handler ); + if ( ~index ) handlers.splice( index, 1 ); + } + }; +} + +export function onDev ( eventName, handler ) { + if ( eventName === 'teardown' ) { + console.warn( "Use component.on('destroy', ...) instead of component.on('teardown', ...) which has been deprecated and will be unsupported in Svelte 2" ); + return this.on( 'destroy', handler ); + } + + return on.call( this, eventName, handler ); +} + +export function set ( newState ) { + this._set( assign( {}, newState ) ); + ( this._root || this )._flush(); +} + +export function _flush () { + if ( !this._renderHooks ) return; + + while ( this._renderHooks.length ) { + var hook = this._renderHooks.pop(); + hook.fn.call( hook.context ); + } +} + +export var proto = { + get: get, + fire: fire, + observe: observe, + on: on, + set: set, + _flush: _flush +}; + +export var protoDev = { + get: get, + fire: fire, + observe: observeDev, + on: onDev, + set: set, + _flush: _flush +}; diff --git a/src/shared/methods.js b/src/shared/methods.js deleted file mode 100644 index d589184bd8..0000000000 --- a/src/shared/methods.js +++ /dev/null @@ -1,98 +0,0 @@ -export function get ( key ) { - return key ? this._state[ key ] : this._state; -} - -export function fire ( eventName, data ) { - var handlers = eventName in this._handlers && this._handlers[ eventName ].slice(); - if ( !handlers ) return; - - for ( var i = 0; i < handlers.length; i += 1 ) { - handlers[i].call( this, data ); - } -} - -export function observe ( key, callback, options ) { - var group = ( options && options.defer ) ? this._observers.post : this._observers.pre; - - ( group[ key ] || ( group[ key ] = [] ) ).push( callback ); - - if ( !options || options.init !== false ) { - callback.__calling = true; - callback.call( this, this._state[ key ] ); - callback.__calling = false; - } - - return { - cancel: function () { - var index = group[ key ].indexOf( callback ); - if ( ~index ) group[ key ].splice( index, 1 ); - } - }; -} - -export function observeDev ( key, callback, options ) { - var c = ( key = '' + key ).search( /[^\w]/ ); - if ( c > -1 ) { - var message = "The first argument to component.observe(...) must be the name of a top-level property"; - if ( c > 0 ) message += ", i.e. '" + key.slice( 0, c ) + "' rather than '" + key + "'"; - - throw new Error( message ); - } - - return observe.call( this, key, callback, options ); -} - -export function on ( eventName, handler ) { - if ( eventName === 'teardown' ) return this.on( 'destroy', handler ); - - var handlers = this._handlers[ eventName ] || ( this._handlers[ eventName ] = [] ); - handlers.push( handler ); - - return { - cancel: function () { - var index = handlers.indexOf( handler ); - if ( ~index ) handlers.splice( index, 1 ); - } - }; -} - -export function onDev ( eventName, handler ) { - if ( eventName === 'teardown' ) { - console.warn( "Use component.on('destroy', ...) instead of component.on('teardown', ...) which has been deprecated and will be unsupported in Svelte 2" ); - return this.on( 'destroy', handler ); - } - - return on.call( this, eventName, handler ); -} - -export function set ( newState ) { - this._set( newState ); - ( this._root || this )._flush(); -} - -export function _flush () { - if ( !this._renderHooks ) return; - - while ( this._renderHooks.length ) { - var hook = this._renderHooks.pop(); - hook.fn.call( hook.context ); - } -} - -export var proto = { - get: get, - fire: fire, - observe: observe, - on: on, - set: set, - _flush: _flush -}; - -export var protoDev = { - get: get, - fire: fire, - observe: observeDev, - on: onDev, - set: set, - _flush: _flush -}; \ No newline at end of file diff --git a/test/runtime/samples/set-clones-input/_config.js b/test/runtime/samples/set-clones-input/_config.js new file mode 100644 index 0000000000..af04f4b73e --- /dev/null +++ b/test/runtime/samples/set-clones-input/_config.js @@ -0,0 +1,10 @@ +export default { + dev: true, + + test ( assert, component ) { + const obj = { a: 1 }; + component.set( obj ); + component.set( obj ); // will fail if the object is not cloned + component.destroy(); + } +} \ No newline at end of file diff --git a/test/runtime/samples/set-clones-input/main.html b/test/runtime/samples/set-clones-input/main.html new file mode 100644 index 0000000000..68af076723 --- /dev/null +++ b/test/runtime/samples/set-clones-input/main.html @@ -0,0 +1,7 @@ + \ No newline at end of file