|
|
|
@ -26,9 +26,6 @@ type ComponentOptions = {
|
|
|
|
|
namespace?: string;
|
|
|
|
|
tag?: string;
|
|
|
|
|
immutable?: boolean;
|
|
|
|
|
props?: string;
|
|
|
|
|
props_object?: string;
|
|
|
|
|
props_node?: Node;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// We need to tell estree-walker that it should always
|
|
|
|
@ -132,33 +129,8 @@ export default class Component {
|
|
|
|
|
this.walk_module_js();
|
|
|
|
|
this.walk_instance_js_pre_template();
|
|
|
|
|
|
|
|
|
|
if (this.componentOptions.props) {
|
|
|
|
|
this.has_reactive_assignments = true;
|
|
|
|
|
|
|
|
|
|
const name = this.componentOptions.props_object;
|
|
|
|
|
|
|
|
|
|
if (!this.ast.module && !this.ast.instance) {
|
|
|
|
|
this.add_var({
|
|
|
|
|
name,
|
|
|
|
|
export_name: name,
|
|
|
|
|
implicit: true
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const variable = this.var_lookup.get(name);
|
|
|
|
|
|
|
|
|
|
if (!variable) {
|
|
|
|
|
this.error(this.componentOptions.props_node, {
|
|
|
|
|
code: 'missing-declaration',
|
|
|
|
|
message: `'${name}' is not defined`
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
variable.reassigned = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.name = this.getUniqueName(name);
|
|
|
|
|
this.fragment = new Fragment(this, ast.html);
|
|
|
|
|
this.name = this.getUniqueName(name);
|
|
|
|
|
|
|
|
|
|
this.walk_instance_js_post_template();
|
|
|
|
|
|
|
|
|
@ -177,6 +149,12 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
if (variable) {
|
|
|
|
|
variable.referenced = true;
|
|
|
|
|
} else if (name === '$$props') {
|
|
|
|
|
this.add_var({
|
|
|
|
|
name,
|
|
|
|
|
injected: true,
|
|
|
|
|
referenced: true
|
|
|
|
|
});
|
|
|
|
|
} else if (name[0] === '$') {
|
|
|
|
|
this.add_var({
|
|
|
|
|
name,
|
|
|
|
@ -200,6 +178,8 @@ export default class Component {
|
|
|
|
|
referenced: true,
|
|
|
|
|
writable: true
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
this.usedNames.add(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -235,8 +215,9 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
const banner = `/* ${this.file ? `${this.file} ` : ``}generated by Svelte v${"__VERSION__"} */`;
|
|
|
|
|
|
|
|
|
|
// TODO use same regex for both
|
|
|
|
|
result = result.replace(compileOptions.generate === 'ssr' ? /(@+|#+)(\w*(?:-\w*)?)/g : /(@+)(\w*(?:-\w*)?)/g, (match: string, sigil: string, name: string) => {
|
|
|
|
|
result = result
|
|
|
|
|
.replace(/__svelte:self__/g, this.name)
|
|
|
|
|
.replace(compileOptions.generate === 'ssr' ? /(@+|#+)(\w*(?:-\w*)?)/g : /(@+)(\w*(?:-\w*)?)/g, (match: string, sigil: string, name: string) => {
|
|
|
|
|
if (sigil === '@') {
|
|
|
|
|
if (internal_exports.has(name)) {
|
|
|
|
|
if (compileOptions.dev && internal_exports.has(`${name}Dev`)) name = `${name}Dev`;
|
|
|
|
@ -623,6 +604,11 @@ export default class Component {
|
|
|
|
|
reassigned: true,
|
|
|
|
|
initialised: true
|
|
|
|
|
});
|
|
|
|
|
} else if (name === '$$props') {
|
|
|
|
|
this.add_var({
|
|
|
|
|
name,
|
|
|
|
|
injected: true
|
|
|
|
|
});
|
|
|
|
|
} else if (name[0] === '$') {
|
|
|
|
|
this.add_var({
|
|
|
|
|
name,
|
|
|
|
@ -770,7 +756,7 @@ export default class Component {
|
|
|
|
|
extractNames(declarator.id).forEach(name => {
|
|
|
|
|
const variable = component.var_lookup.get(name);
|
|
|
|
|
|
|
|
|
|
if (variable.export_name || name === componentOptions.props_object) {
|
|
|
|
|
if (variable.export_name) {
|
|
|
|
|
component.error(declarator, {
|
|
|
|
|
code: 'destructured-prop',
|
|
|
|
|
message: `Cannot declare props in destructured declaration`
|
|
|
|
@ -796,53 +782,35 @@ export default class Component {
|
|
|
|
|
const { name } = declarator.id;
|
|
|
|
|
const variable = component.var_lookup.get(name);
|
|
|
|
|
|
|
|
|
|
if (name === componentOptions.props_object) {
|
|
|
|
|
if (variable.export_name) {
|
|
|
|
|
component.error(declarator, {
|
|
|
|
|
code: 'exported-options-props',
|
|
|
|
|
message: `Cannot export props binding`
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// can't use the @ trick here, because we're
|
|
|
|
|
// manipulating the underlying magic string
|
|
|
|
|
const exclude_internal_props = component.helper('exclude_internal_props');
|
|
|
|
|
|
|
|
|
|
const suffix = code.original[declarator.end] === ';'
|
|
|
|
|
? ` = ${exclude_internal_props}($$props)`
|
|
|
|
|
: ` = ${exclude_internal_props}($$props);`
|
|
|
|
|
|
|
|
|
|
if (declarator.id.end === declarator.end) {
|
|
|
|
|
code.appendLeft(declarator.end, suffix);
|
|
|
|
|
} else {
|
|
|
|
|
code.overwrite(declarator.id.end, declarator.end, suffix);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (variable.export_name) {
|
|
|
|
|
if (variable.subscribable) {
|
|
|
|
|
coalesced_declarations.push({
|
|
|
|
|
kind: node.kind,
|
|
|
|
|
declarators: [declarator],
|
|
|
|
|
insert: get_insert(variable)
|
|
|
|
|
});
|
|
|
|
|
current_group = null;
|
|
|
|
|
} else {
|
|
|
|
|
if (current_group && current_group.kind !== node.kind) {
|
|
|
|
|
current_group = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!current_group) {
|
|
|
|
|
current_group = { kind: node.kind, declarators: [], insert: null };
|
|
|
|
|
const insert = variable.subscribable
|
|
|
|
|
? get_insert(variable)
|
|
|
|
|
: null;
|
|
|
|
|
|
|
|
|
|
if (!current_group || (current_group.insert && insert)) {
|
|
|
|
|
current_group = { kind: node.kind, declarators: [declarator], insert };
|
|
|
|
|
coalesced_declarations.push(current_group);
|
|
|
|
|
} else if (insert) {
|
|
|
|
|
current_group.insert = insert
|
|
|
|
|
current_group.declarators.push(declarator);
|
|
|
|
|
} else {
|
|
|
|
|
current_group.declarators.push(declarator);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current_group.declarators.push(declarator);
|
|
|
|
|
if (variable.name !== variable.export_name) {
|
|
|
|
|
code.prependRight(declarator.id.start, `${variable.export_name}:`)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (next) {
|
|
|
|
|
const next_variable = component.var_lookup.get(next.id.name)
|
|
|
|
|
if (next_variable && !next_variable.export_name) {
|
|
|
|
|
const new_declaration = !next_variable.export_name
|
|
|
|
|
|| (current_group.insert && next_variable.subscribable)
|
|
|
|
|
|
|
|
|
|
if (new_declaration) {
|
|
|
|
|
code.overwrite(declarator.end, next.start, ` ${node.kind} `);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -919,6 +887,11 @@ export default class Component {
|
|
|
|
|
const all_hoistable = node.declarations.every(d => {
|
|
|
|
|
if (!d.init) return false;
|
|
|
|
|
if (d.init.type !== 'Literal') return false;
|
|
|
|
|
|
|
|
|
|
const v = this.var_lookup.get(d.id.name)
|
|
|
|
|
if (v.reassigned) return false
|
|
|
|
|
if (v.export_name && v.export_name !== v.name) return false
|
|
|
|
|
|
|
|
|
|
if (this.var_lookup.get(d.id.name).reassigned) return false;
|
|
|
|
|
if (this.vars.find(variable => variable.name === d.id.name && variable.module)) return false;
|
|
|
|
|
|
|
|
|
@ -1037,6 +1010,7 @@ export default class Component {
|
|
|
|
|
this.reactive_declaration_nodes.add(node);
|
|
|
|
|
|
|
|
|
|
const assignees = new Set();
|
|
|
|
|
const assignee_nodes = new Set();
|
|
|
|
|
const dependencies = new Set();
|
|
|
|
|
|
|
|
|
|
let scope = this.instance_scope;
|
|
|
|
@ -1049,19 +1023,22 @@ export default class Component {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (node.type === 'AssignmentExpression') {
|
|
|
|
|
const { name } = getObject(node.left)
|
|
|
|
|
assignees.add(name);
|
|
|
|
|
dependencies.delete(name);
|
|
|
|
|
const identifier = getObject(node.left)
|
|
|
|
|
assignee_nodes.add(identifier);
|
|
|
|
|
assignees.add(identifier.name);
|
|
|
|
|
} else if (node.type === 'UpdateExpression') {
|
|
|
|
|
const { name } = getObject(node.argument);
|
|
|
|
|
assignees.add(name);
|
|
|
|
|
dependencies.delete(name);
|
|
|
|
|
const identifier = getObject(node.argument);
|
|
|
|
|
assignee_nodes.add(identifier);
|
|
|
|
|
assignees.add(identifier.name);
|
|
|
|
|
} else if (isReference(node, parent)) {
|
|
|
|
|
const { name } = getObject(node);
|
|
|
|
|
const identifier = getObject(node);
|
|
|
|
|
if (!assignee_nodes.has(identifier)) {
|
|
|
|
|
const { name } = identifier;
|
|
|
|
|
const owner = scope.findOwner(name);
|
|
|
|
|
if ((!owner || owner === component.instance_scope) && (name[0] === '$' || component.var_lookup.has(name)) && !assignees.has(name)) {
|
|
|
|
|
if ((!owner || owner === component.instance_scope) && (name[0] === '$' || component.var_lookup.has(name))) {
|
|
|
|
|
dependencies.add(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.skip();
|
|
|
|
|
}
|
|
|
|
@ -1144,6 +1121,8 @@ export default class Component {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qualify(name) {
|
|
|
|
|
if (name === `$$props`) return `ctx.$$props`;
|
|
|
|
|
|
|
|
|
|
const variable = this.var_lookup.get(name);
|
|
|
|
|
|
|
|
|
|
if (!variable) return name;
|
|
|
|
@ -1267,26 +1246,10 @@ function process_component_options(component: Component, nodes) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (attribute.type === 'Binding') {
|
|
|
|
|
if (attribute.name !== 'props') {
|
|
|
|
|
component.error(attribute, {
|
|
|
|
|
code: `invalid-options-binding`,
|
|
|
|
|
message: `<svelte:options> only supports bind:props`
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { start, end } = attribute.expression;
|
|
|
|
|
const { name } = flattenReference(attribute.expression);
|
|
|
|
|
|
|
|
|
|
componentOptions.props = `[✂${start}-${end}✂]`;
|
|
|
|
|
componentOptions.props_node = attribute.expression;
|
|
|
|
|
componentOptions.props_object = name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
component.error(attribute, {
|
|
|
|
|
code: `invalid-options-attribute`,
|
|
|
|
|
message: `<svelte:options> can only have static 'tag', 'namespace' and 'immutable' attributes, or a bind:props directive`
|
|
|
|
|
message: `<svelte:options> can only have static 'tag', 'namespace' and 'immutable' attributes`
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|