|
|
@ -1,77 +1,41 @@
|
|
|
|
import deindent from '../../../../utils/deindent.js';
|
|
|
|
import deindent from '../../../../utils/deindent.js';
|
|
|
|
import isReference from '../../../../utils/isReference.js';
|
|
|
|
|
|
|
|
import flattenReference from '../../../../utils/flattenReference.js';
|
|
|
|
import flattenReference from '../../../../utils/flattenReference.js';
|
|
|
|
|
|
|
|
import getSetter from './binding/getSetter.js';
|
|
|
|
|
|
|
|
|
|
|
|
export default function createBinding ( generator, node, attribute, current, local ) {
|
|
|
|
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 ) ) {
|
|
|
|
contexts.forEach( context => {
|
|
|
|
local.allUsedContexts.push( name );
|
|
|
|
if ( !~local.allUsedContexts.indexOf( context ) ) local.allUsedContexts.push( context );
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const contextual = name in current.contexts;
|
|
|
|
|
|
|
|
|
|
|
|
let obj;
|
|
|
|
let obj;
|
|
|
|
let prop;
|
|
|
|
let prop;
|
|
|
|
let value;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( contextual ) {
|
|
|
|
if ( contextual ) {
|
|
|
|
obj = current.listNames[ name ];
|
|
|
|
obj = current.listNames[ name ];
|
|
|
|
prop = current.indexNames[ 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 {
|
|
|
|
} else {
|
|
|
|
prop = `'${parts.slice( -1 )}'`;
|
|
|
|
obj = 'root';
|
|
|
|
obj = parts.length > 1 ? `root.${parts.slice( 0, -1 ).join( '.' )}` : `root`;
|
|
|
|
prop = `'${name}'`;
|
|
|
|
value = `root.${keypath}`;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
local.bindings.push({
|
|
|
|
}
|
|
|
|
name: attribute.name,
|
|
|
|
} while ( fragment = fragment.parent );
|
|
|
|
value: snippet,
|
|
|
|
|
|
|
|
obj,
|
|
|
|
generator.expectedProperties[ prop ] = true;
|
|
|
|
prop
|
|
|
|
|
|
|
|
});
|
|
|
|
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;
|
|
|
|
generator.hasComplexBindings = true;
|
|
|
|
|
|
|
|
|
|
|
@ -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`
|
|
|
|
local.update.addBlock( deindent`
|
|
|
|
if ( !${local.name}_updating && ${dependencies.map( dependency => `'${dependency}' in changed` ).join( '||' )} ) {
|
|
|
|
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} });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
` );
|
|
|
|
` );
|
|
|
|
}
|
|
|
|
}
|
|
|
|