diff --git a/src/compile/Component.ts b/src/compile/Component.ts index d0b7f35ebe..21321e732a 100644 --- a/src/compile/Component.ts +++ b/src/compile/Component.ts @@ -481,10 +481,6 @@ export default class Component { this.userVars.add(specifier.local.name); this.declarations.push(specifier.local.name); // TODO we don't really want this, but it's convenient for now }); - - if (this.options.sveltePath && node.source.value === 'svelte') { - code.overwrite(node.source.start, node.source.end, this.options.sveltePath); - } } }); } diff --git a/src/compile/nodes/Attribute.ts b/src/compile/nodes/Attribute.ts index 0a85d6b850..ec5743b08a 100644 --- a/src/compile/nodes/Attribute.ts +++ b/src/compile/nodes/Attribute.ts @@ -75,7 +75,7 @@ export default class Attribute extends Node { if (this.chunks.length === 1) { return this.chunks[0].type === 'Text' ? stringify(this.chunks[0].data) - : this.chunks[0].snippet; + : this.chunks[0].render(); } return (this.chunks[0].type === 'Text' ? '' : `"" + `) + @@ -84,7 +84,7 @@ export default class Attribute extends Node { if (chunk.type === 'Text') { return stringify(chunk.data); } else { - return chunk.getPrecedence() <= 13 ? `(${chunk.snippet})` : chunk.snippet; + return chunk.getPrecedence() <= 13 ? `(${chunk.render()})` : chunk.render(); } }) .join(' + '); diff --git a/src/compile/nodes/EventHandler.ts b/src/compile/nodes/EventHandler.ts index 73f59be939..c561cedbeb 100644 --- a/src/compile/nodes/EventHandler.ts +++ b/src/compile/nodes/EventHandler.ts @@ -7,7 +7,7 @@ export default class EventHandler extends Node { name: string; modifiers: Set; expression: Expression; - callee: any; // TODO + handler_name: string; usesComponent: boolean; usesContext: boolean; @@ -25,9 +25,7 @@ export default class EventHandler extends Node { this.modifiers = new Set(info.modifiers); if (info.expression) { - this.expression = new Expression(component, this, template_scope, info.expression, true); - this.snippet = this.expression.snippet; - + this.expression = new Expression(component, this, template_scope, info.expression); this.usesContext = this.expression.usesContext; } else { component.init_uses_self = true; @@ -41,10 +39,19 @@ export default class EventHandler extends Node { } `); - this.snippet = `ctx.${name}`; + this.handler_name = name; + + Object.defineProperty(this, 'snippet', { + get: () => { + throw new Error('here'); + } + }); } + } - // TODO figure out what to do about custom events - // this.isCustomEvent = component.events.has(this.name); + render() { + return this.expression + ? this.expression.render() + : `ctx.${this.handler_name}`; } } \ No newline at end of file diff --git a/src/compile/nodes/InlineComponent.ts b/src/compile/nodes/InlineComponent.ts index 9b4b22a664..32f1425059 100644 --- a/src/compile/nodes/InlineComponent.ts +++ b/src/compile/nodes/InlineComponent.ts @@ -20,7 +20,7 @@ export default class InlineComponent extends Node { constructor(component: Component, parent, scope, info) { super(component, parent, scope, info); - if (info.name !== 'svelte:component') { + if (info.name !== 'svelte:component' && info.name !== 'svelte:self') { component.warn_if_undefined(info, scope); component.expectedProperties.add(info.name); } diff --git a/src/compile/nodes/shared/Expression.ts b/src/compile/nodes/shared/Expression.ts index 77bd17f677..36a2ae74d6 100644 --- a/src/compile/nodes/shared/Expression.ts +++ b/src/compile/nodes/shared/Expression.ts @@ -2,13 +2,14 @@ import Component from '../../Component'; import { walk } from 'estree-walker'; import isReference from 'is-reference'; import flattenReference from '../../../utils/flattenReference'; -import { createScopes } from '../../../utils/annotateWithScopes'; +import { createScopes, Scope } from '../../../utils/annotateWithScopes'; import { Node } from '../../../interfaces'; import addToSet from '../../../utils/addToSet'; import globalWhitelist from '../../../utils/globalWhitelist'; import deindent from '../../../utils/deindent'; import Wrapper from '../../render-dom/wrappers/shared/Wrapper'; import sanitize from '../../../utils/sanitize'; +import TemplateScope from './TemplateScope'; const binaryOperators: Record = { '**': 15, @@ -60,27 +61,43 @@ const precedence: Record number> = { export default class Expression { component: Component; + owner: Wrapper; node: any; snippet: string; references: Set; dependencies: Set; contextual_dependencies: Set; + template_scope: TemplateScope; + scope: Scope; + scope_map: WeakMap; + + is_synthetic: boolean; declarations: string[] = []; usesContext = false; usesEvent = false; - constructor(component: Component, owner: Wrapper, scope, info, isEventHandler?: boolean) { + rendered: string; + + constructor(component: Component, owner: Wrapper, template_scope: TemplateScope, info) { // TODO revert to direct property access in prod? Object.defineProperties(this, { component: { value: component + }, + + // TODO remove this, is just for debugging + snippet: { + get: () => { + throw new Error(`cannot access expression.snippet, use expression.render() instead`) + } } }); this.node = info; - - this.snippet = `[✂${info.start}-${info.end}✂]`; + this.template_scope = template_scope; + this.owner = owner; + this.is_synthetic = owner.isSynthetic; const expression_dependencies = new Set(); const expression_contextual_dependencies = new Set(); @@ -88,48 +105,34 @@ export default class Expression { let dependencies = expression_dependencies; let contextual_dependencies = expression_contextual_dependencies; - const { declarations } = this; - const { code } = component; - - let { map, scope: currentScope } = createScopes(info); + let { map, scope } = createScopes(info); + this.scope = scope; + this.scope_map = map; const expression = this; - const isSynthetic = owner.isSynthetic; - - let function_expression; - let pending_assignments = new Set(); + // discover dependencies, but don't change the code yet walk(info, { enter(node: any, parent: any, key: string) { // don't manipulate shorthand props twice if (key === 'value' && parent.shorthand) return; - code.addSourcemapLocation(node.start); - code.addSourcemapLocation(node.end); - if (map.has(node)) { - currentScope = map.get(node); + scope = map.get(node); } if (isReference(node, parent)) { - const { name, nodes } = flattenReference(node); + const { name } = flattenReference(node); - if (currentScope.has(name)) return; + if (scope.has(name)) return; if (globalWhitelist.has(name) && component.declarations.indexOf(name) === -1) return; - if (!isSynthetic && !function_expression) { - //