Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Dev helpers #378

Merged
merged 5 commits into from
Mar 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/generators/Generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import getOutro from './shared/utils/getOutro.js';
import annotateWithScopes from './annotateWithScopes.js';

export default class Generator {
constructor ( parsed, source, name, names, visitors ) {
constructor ( parsed, source, name, names, visitors, options ) {
this.parsed = parsed;
this.source = source;
this.name = name;
this.names = names;
this.visitors = visitors;
this.options = options;

this.imports = [];
this.helpers = {};
Expand Down
56 changes: 21 additions & 35 deletions src/generators/dom/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import Generator from '../Generator.js';
import * as shared from '../../shared/index.js';

class DomGenerator extends Generator {
constructor ( parsed, source, name, names, visitors ) {
super( parsed, source, name, names, visitors );
constructor ( parsed, source, name, names, visitors, options ) {
super( parsed, source, name, names, visitors, options );
this.renderers = [];
this.uses = {};

Expand Down Expand Up @@ -132,6 +132,10 @@ class DomGenerator extends Generator {
}

helper ( name ) {
if ( this.options.dev && `${name}Dev` in shared ) {
name = `${name}Dev`;
}

this.uses[ name ] = true;

if ( !( name in this.aliases ) ) {
Expand All @@ -152,7 +156,7 @@ export default function dom ( parsed, source, options, names ) {
const format = options.format || 'es';
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();

Expand Down Expand Up @@ -359,34 +363,20 @@ export default function dom ( parsed, source, options, names ) {
}
` );

if ( templateProperties.methods ) {
builders.main.addBlock( `${name}.prototype = template.methods;` );
}

const sharedPath = options.shared === true ? 'svelte/shared.js' : options.shared;

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};
if ( sharedPath ) {
const base = templateProperties.methods ? `{}, template.methods` : `{}`;
builders.main.addBlock( `${name}.prototype = Object.assign( ${base}, ${generator.helper( 'proto' )} );` );
} else {
if ( templateProperties.methods ) {
builders.main.addBlock( `${name}.prototype = template.methods;` );
}

${name}.prototype._flush = ${shared._flush};
` );
[ 'get', 'fire', 'observe', 'on', 'set', '_flush' ].forEach( methodName => {
builders.main.addLine( `${name}.prototype.${methodName} = ${generator.helper( methodName )};` );
});
}

// TODO deprecate component.teardown()
builders.main.addBlock( deindent`
Expand All @@ -395,7 +385,7 @@ export default function dom ( parsed, source, options, names ) {
};

${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 = null;
Expand All @@ -420,13 +410,9 @@ export default function dom ( parsed, source, options, names ) {
} else {
Object.keys( generator.uses ).forEach( key => {
const fn = shared[ key ]; // eslint-disable-line import/namespace
if ( key !== generator.aliases[ key ] ) {
builders.main.addBlock( `var ${generator.aliases[ key ]} = ${fn.toString()}}` );
} else {
builders.main.addBlock( fn.toString() );
}
builders.main.addBlock( fn.toString().replace( /^function [^(]*/, 'function ' + generator.aliases[ key ] ) );
});
}

return generator.generate( builders.main.toString(), options, { name, format } );
}
}
6 changes: 3 additions & 3 deletions src/generators/server-side-rendering/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import visitors from './visitors/index.js';
import Generator from '../Generator.js';

class SsrGenerator extends Generator {
constructor ( parsed, source, name, names, visitors ) {
super( parsed, source, name, names, visitors );
constructor ( parsed, source, name, names, visitors, options ) {
super( parsed, source, name, names, visitors, options );
this.bindings = [];
this.renderCode = '';
}
Expand Down Expand Up @@ -36,7 +36,7 @@ export default function ssr ( parsed, source, options, names ) {
const format = options.format || 'cjs';
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();

Expand Down
64 changes: 64 additions & 0 deletions src/shared/methods.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) {
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 ] = [] );
handlers.push( handler );

Expand All @@ -55,3 +101,21 @@ export function _flush () {
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
};
15 changes: 15 additions & 0 deletions test/generator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,16 +98,31 @@ describe( 'generate', () => {

const target = window.document.querySelector( 'main' );

const warnings = [];
const warn = console.warn;
console.warn = warning => {
warnings.push( warning );
};

const component = new SvelteComponent({
target,
data: config.data
});

console.warn = warn;

if ( config.error ) {
unintendedError = true;
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 ) {
assert.htmlEqual( target.innerHTML, config.html );
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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'` );
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script>
export default {
oncreate () {
this.observe( 'nested.data', data => {
console.log( 'nope' );
});
}
};
</script>
Original file line number Diff line number Diff line change
@@ -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`
]
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script>
export default {
oncreate () {
this.on( 'teardown', () => {
this.destroyed = true;
});
}
};
</script>
2 changes: 1 addition & 1 deletion test/generator/samples/events-lifecycle/_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export default {
test ( assert, component ) {
let count = 0;

component.on( 'teardown', function () {
component.on( 'destroy', function () {
assert.equal( this, component );
count += 1;
});
Expand Down