Skip to content

Commit

Permalink
more refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
Rich-Harris committed Mar 17, 2017
1 parent 574503d commit 17db22a
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 84 deletions.
82 changes: 22 additions & 60 deletions src/generators/dom/visitors/attributes/addComponentBinding.js
Original file line number Diff line number Diff line change
@@ -1,77 +1,41 @@
import deindent from '../../../../utils/deindent.js';
import isReference from '../../../../utils/isReference.js';
import flattenReference from '../../../../utils/flattenReference.js';
import getSetter from './binding/getSetter.js';

export default function createBinding ( generator, node, attribute, current, local ) {
const { name, parts, keypath } = flattenReference( attribute.value );
const { name } = flattenReference( attribute.value );
const { snippet, contexts, dependencies } = generator.contextualise( attribute.value );

const contextual = name in current.contexts;
if ( dependencies.length > 1 ) throw new Error( 'An unexpected situation arose. Please raise an issue at https://github.com/sveltejs/svelte/issues — thanks!' );

if ( contextual && !~local.allUsedContexts.indexOf( name ) ) {
local.allUsedContexts.push( name );
}
contexts.forEach( context => {
if ( !~local.allUsedContexts.indexOf( context ) ) local.allUsedContexts.push( context );
});

const contextual = name in current.contexts;

let obj;
let prop;
let value;

if ( contextual ) {
obj = current.listNames[ name ];
prop = current.indexNames[ name ];
value = keypath;
} else if ( attribute.value.type === 'MemberExpression' ) {
prop = `'[✂${attribute.value.property.start}-${attribute.value.property.end}✂]}'`;
obj = `root.[✂${attribute.value.object.start}-${attribute.value.object.end}✂]}`;
} else {
prop = `'${parts.slice( -1 )}'`;
obj = parts.length > 1 ? `root.${parts.slice( 0, -1 ).join( '.' )}` : `root`;
value = `root.${keypath}`;
obj = 'root';
prop = `'${name}'`;
}

local.bindings.push({ name: attribute.name, value, obj, prop });

let setter;

if ( contextual ) {
// find the top-level property that this is a child of
let fragment = current;
let prop = name;

do {
if ( fragment.expression && fragment.context === prop ) {
if ( !isReference( fragment.expression ) ) {
// TODO this should happen in prior validation step
throw new Error( `${prop} is read-only, it cannot be bound` );
}

prop = flattenReference( fragment.expression ).name;
}
} while ( fragment = fragment.parent );
local.bindings.push({
name: attribute.name,
value: snippet,
obj,
prop
});

generator.expectedProperties[ prop ] = true;

const listName = current.listNames[ name ];
const indexName = current.indexNames[ name ];

const context = local.isComponent ? `_context` : `__svelte`;

setter = deindent`
var list = this.${context}.${listName};
var index = this.${context}.${indexName};
list[index]${parts.slice( 1 ).map( part => `.${part}` ).join( '' )} = value;
component._set({ ${prop}: component.get( '${prop}' ) });
`;
} else {
if ( parts.length > 1 ) {
setter = deindent`
var ${name} = component.get( '${name}' );
${name}.${parts.slice( 1 ).join( '.' )} = value;
component._set({ ${name}: ${name} });
`;
} else {
setter = `component._set({ ${keypath}: value });`;
}

generator.expectedProperties[ name ] = true;
}
const setter = getSetter({ current, name, context: '_context', attribute, dependencies, snippet, value: 'value' });

generator.hasComplexBindings = true;

Expand All @@ -88,11 +52,9 @@ export default function createBinding ( generator, node, attribute, current, loc
});
` );

const dependencies = name in current.contexts ? current.contextDependencies[ name ] : [ name ];

local.update.addBlock( deindent`
if ( !${local.name}_updating && ${dependencies.map( dependency => `'${dependency}' in changed` ).join( '||' )} ) {
${local.name}._set({ ${attribute.name}: ${contextual ? keypath : `root.${keypath}`} });
${local.name}._set({ ${attribute.name}: ${snippet} });
}
` );
}
26 changes: 2 additions & 24 deletions src/generators/dom/visitors/attributes/addElementBinding.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import deindent from '../../../../utils/deindent.js';
import flattenReference from '../../../../utils/flattenReference.js';
import getSetter from './binding/getSetter.js';

export default function createBinding ( generator, node, attribute, current, local ) {
const { name } = flattenReference( attribute.value );
Expand All @@ -17,30 +18,7 @@ export default function createBinding ( generator, node, attribute, current, loc
const value = getBindingValue( local, node, attribute, isMultipleSelect );
const eventName = getBindingEventName( node );

let setter;

if ( name in current.contexts ) {
const prop = dependencies[0];
const tail = attribute.value.type === 'MemberExpression' ? getTailSnippet( attribute.value ) : '';

setter = deindent`
var list = this.__svelte.${current.listNames[ name ]};
var index = this.__svelte.${current.indexNames[ name ]};
list[index]${tail} = ${value};
component._set({ ${prop}: component.get( '${prop}' ) });
`;
} else {
if ( attribute.value.type === 'MemberExpression' ) {
setter = deindent`
var ${name} = component.get( '${name}' );
${snippet} = ${value};
component._set({ ${name}: ${name} });
`;
} else {
setter = `component._set({ ${name}: ${value} });`;
}
}
let setter = getSetter({ current, name, context: '__svelte', attribute, dependencies, snippet, value });

// special case
if ( node.name === 'select' && !isMultipleSelect ) {
Expand Down
34 changes: 34 additions & 0 deletions src/generators/dom/visitors/attributes/binding/getSetter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import deindent from '../../../../../utils/deindent.js';

export default function getSetter ({ current, name, context, attribute, dependencies, snippet, value }) {
if ( name in current.contexts ) {
const prop = dependencies[0];
const tail = attribute.value.type === 'MemberExpression' ? getTailSnippet( attribute.value ) : '';

return deindent`
var list = this.${context}.${current.listNames[ name ]};
var index = this.${context}.${current.indexNames[ name ]};
list[index]${tail} = ${value};
component._set({ ${prop}: component.get( '${prop}' ) });
`;
}

if ( attribute.value.type === 'MemberExpression' ) {
return deindent`
var ${name} = component.get( '${name}' );
${snippet} = ${value};
component._set({ ${name}: ${name} });
`;
}

return `component._set({ ${name}: ${value} });`;
}

function getTailSnippet ( node ) {
const end = node.end;
while ( node.type === 'MemberExpression' ) node = node.object;
const start = node.end;

return `[✂${start}-${end}✂]`;
}

0 comments on commit 17db22a

Please sign in to comment.