Merge pull request #378 from sveltejs/dev-helpers

[WIP] Dev helpers
pull/384/head
Rich Harris 8 years ago committed by GitHub
commit 75abd0e6c7

@ -9,12 +9,13 @@ import getOutro from './shared/utils/getOutro.js';
import annotateWithScopes from './annotateWithScopes.js'; import annotateWithScopes from './annotateWithScopes.js';
export default class Generator { export default class Generator {
constructor ( parsed, source, name, names, visitors ) { constructor ( parsed, source, name, names, visitors, options ) {
this.parsed = parsed; this.parsed = parsed;
this.source = source; this.source = source;
this.name = name; this.name = name;
this.names = names; this.names = names;
this.visitors = visitors; this.visitors = visitors;
this.options = options;
this.imports = []; this.imports = [];
this.helpers = {}; this.helpers = {};

@ -8,8 +8,8 @@ import Generator from '../Generator.js';
import * as shared from '../../shared/index.js'; import * as shared from '../../shared/index.js';
class DomGenerator extends Generator { class DomGenerator extends Generator {
constructor ( parsed, source, name, names, visitors ) { constructor ( parsed, source, name, names, visitors, options ) {
super( parsed, source, name, names, visitors ); super( parsed, source, name, names, visitors, options );
this.renderers = []; this.renderers = [];
this.uses = {}; this.uses = {};
@ -132,6 +132,10 @@ class DomGenerator extends Generator {
} }
helper ( name ) { helper ( name ) {
if ( this.options.dev && `${name}Dev` in shared ) {
name = `${name}Dev`;
}
this.uses[ name ] = true; this.uses[ name ] = true;
if ( !( name in this.aliases ) ) { if ( !( name in this.aliases ) ) {
@ -152,7 +156,7 @@ export default function dom ( parsed, source, options, names ) {
const format = options.format || 'es'; const format = options.format || 'es';
const name = options.name || 'SvelteComponent'; const name = options.name || 'SvelteComponent';
const generator = new DomGenerator( parsed, source, name, names, visitors ); const generator = new DomGenerator( parsed, source, name, names, visitors, options );
const { computations, templateProperties } = generator.parseJs(); const { computations, templateProperties } = generator.parseJs();
@ -359,34 +363,20 @@ export default function dom ( parsed, source, options, names ) {
} }
` ); ` );
const sharedPath = options.shared === true ? 'svelte/shared.js' : options.shared;
if ( sharedPath ) {
const base = templateProperties.methods ? `{}, template.methods` : `{}`;
builders.main.addBlock( `${name}.prototype = Object.assign( ${base}, ${generator.helper( 'proto' )} );` );
} else {
if ( templateProperties.methods ) { if ( templateProperties.methods ) {
builders.main.addBlock( `${name}.prototype = template.methods;` ); builders.main.addBlock( `${name}.prototype = template.methods;` );
} }
const sharedPath = options.shared === true ? 'svelte/shared.js' : options.shared; [ 'get', 'fire', 'observe', 'on', 'set', '_flush' ].forEach( methodName => {
builders.main.addLine( `${name}.prototype.${methodName} = ${generator.helper( methodName )};` );
builders.main.addBlock( sharedPath ? });
deindent` }
${name}.prototype.get = ${generator.helper( 'get' )};
${name}.prototype.fire = ${generator.helper( 'fire' )};
${name}.prototype.observe = ${generator.helper( 'observe' )};
${name}.prototype.on = ${generator.helper( 'on' )};
${name}.prototype.set = ${generator.helper( 'set' )};
${name}.prototype._flush = ${generator.helper( '_flush' )};
` :
deindent`
${name}.prototype.get = ${shared.get};
${name}.prototype.fire = ${shared.fire};
${name}.prototype.observe = ${shared.observe};
${name}.prototype.on = ${shared.on};
${name}.prototype.set = ${shared.set};
${name}.prototype._flush = ${shared._flush};
` );
// TODO deprecate component.teardown() // TODO deprecate component.teardown()
builders.main.addBlock( deindent` builders.main.addBlock( deindent`
@ -395,7 +385,7 @@ export default function dom ( parsed, source, options, names ) {
}; };
${name}.prototype.teardown = ${name}.prototype.destroy = function destroy ( detach ) { ${name}.prototype.teardown = ${name}.prototype.destroy = function destroy ( detach ) {
this.fire( 'teardown' );${templateProperties.ondestroy ? `\ntemplate.ondestroy.call( this );` : ``} this.fire( 'destroy' );${templateProperties.ondestroy ? `\ntemplate.ondestroy.call( this );` : ``}
this._fragment.teardown( detach !== false ); this._fragment.teardown( detach !== false );
this._fragment = null; this._fragment = null;
@ -420,11 +410,7 @@ export default function dom ( parsed, source, options, names ) {
} else { } else {
Object.keys( generator.uses ).forEach( key => { Object.keys( generator.uses ).forEach( key => {
const fn = shared[ key ]; // eslint-disable-line import/namespace const fn = shared[ key ]; // eslint-disable-line import/namespace
if ( key !== generator.aliases[ key ] ) { builders.main.addBlock( fn.toString().replace( /^function [^(]*/, 'function ' + generator.aliases[ key ] ) );
builders.main.addBlock( `var ${generator.aliases[ key ]} = ${fn.toString()}}` );
} else {
builders.main.addBlock( fn.toString() );
}
}); });
} }

@ -5,8 +5,8 @@ import visitors from './visitors/index.js';
import Generator from '../Generator.js'; import Generator from '../Generator.js';
class SsrGenerator extends Generator { class SsrGenerator extends Generator {
constructor ( parsed, source, name, names, visitors ) { constructor ( parsed, source, name, names, visitors, options ) {
super( parsed, source, name, names, visitors ); super( parsed, source, name, names, visitors, options );
this.bindings = []; this.bindings = [];
this.renderCode = ''; this.renderCode = '';
} }
@ -36,7 +36,7 @@ export default function ssr ( parsed, source, options, names ) {
const format = options.format || 'cjs'; const format = options.format || 'cjs';
const name = options.name || 'SvelteComponent'; const name = options.name || 'SvelteComponent';
const generator = new SsrGenerator( parsed, source, name, names, visitors ); const generator = new SsrGenerator( parsed, source, name, names, visitors, options );
const { computations, templateProperties } = generator.parseJs(); const { computations, templateProperties } = generator.parseJs();

@ -30,7 +30,53 @@ export function observe ( key, callback, options ) {
}; };
} }
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 );
}
var group = ( options && options.defer ) ? this._observers.pre : this._observers.post;
( 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 on ( eventName, handler ) { 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 );
}
var handlers = this._handlers[ eventName ] || ( this._handlers[ eventName ] = [] ); var handlers = this._handlers[ eventName ] || ( this._handlers[ eventName ] = [] );
handlers.push( handler ); handlers.push( handler );
@ -55,3 +101,21 @@ export function _flush () {
hook.fn.call( hook.context ); 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
};

@ -98,16 +98,31 @@ describe( 'generate', () => {
const target = window.document.querySelector( 'main' ); const target = window.document.querySelector( 'main' );
const warnings = [];
const warn = console.warn;
console.warn = warning => {
warnings.push( warning );
};
const component = new SvelteComponent({ const component = new SvelteComponent({
target, target,
data: config.data data: config.data
}); });
console.warn = warn;
if ( config.error ) { if ( config.error ) {
unintendedError = true; unintendedError = true;
throw new Error( 'Expected a runtime error' ); throw new Error( 'Expected a runtime error' );
} }
if ( config.warnings ) {
assert.deepEqual( warnings, config.warnings );
} else if ( warnings.length ) {
unintendedError = true;
throw new Error( 'Received unexpected warnings' );
}
if ( config.html ) { if ( config.html ) {
assert.htmlEqual( target.innerHTML, config.html ); assert.htmlEqual( target.innerHTML, config.html );
} }

@ -0,0 +1,7 @@
export default {
dev: true,
error ( assert, err ) {
assert.equal( err.message, `The first argument to component.observe(...) must be the name of a top-level property, i.e. 'nested' rather than 'nested.data'` );
}
};

@ -0,0 +1,9 @@
<script>
export default {
oncreate () {
this.observe( 'nested.data', data => {
console.log( 'nope' );
});
}
};
</script>

@ -0,0 +1,7 @@
export default {
dev: true,
warnings: [
`Use component.on('destroy', ...) instead of component.on('teardown', ...) which has been deprecated and will be unsupported in Svelte 2`
]
};

@ -0,0 +1,9 @@
<script>
export default {
oncreate () {
this.on( 'teardown', () => {
this.destroyed = true;
});
}
};
</script>

@ -2,7 +2,7 @@ export default {
test ( assert, component ) { test ( assert, component ) {
let count = 0; let count = 0;
component.on( 'teardown', function () { component.on( 'destroy', function () {
assert.equal( this, component ); assert.equal( this, component );
count += 1; count += 1;
}); });

Loading…
Cancel
Save