From 734257001d9d8f439d7228e83d64dc53f8aae09f Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Tue, 5 Jan 2021 05:51:55 +0800 Subject: [PATCH] deconflict conextual action variable (#5839) --- CHANGELOG.md | 1 + src/compiler/compile/nodes/Action.ts | 7 +++++-- .../compile/nodes/shared/Expression.ts | 16 +--------------- .../compile/nodes/shared/is_contextual.ts | 18 ++++++++++++++++++ .../render_dom/wrappers/shared/add_actions.ts | 7 +++++-- .../deconflict-contextual-action/_config.js | 13 +++++++++++++ .../deconflict-contextual-action/main.svelte | 17 +++++++++++++++++ .../deconflict-contextual-action/util.js | 3 +++ 8 files changed, 63 insertions(+), 19 deletions(-) create mode 100644 src/compiler/compile/nodes/shared/is_contextual.ts create mode 100644 test/runtime/samples/deconflict-contextual-action/_config.js create mode 100644 test/runtime/samples/deconflict-contextual-action/main.svelte create mode 100644 test/runtime/samples/deconflict-contextual-action/util.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 2afd2b2706ed..584c6f1fb363 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Rework SSR store handling to subscribe and unsubscribe as in DOM mode ([#3375](https://github.com/sveltejs/svelte/issues/3375), [#3582](https://github.com/sveltejs/svelte/issues/3582), [#3636](https://github.com/sveltejs/svelte/issues/3636)) * Fix error when removing elements that are already transitioning out ([#5789](https://github.com/sveltejs/svelte/issues/5789), [#5808](https://github.com/sveltejs/svelte/issues/5808)) * Fix duplicate content race condition with `{#await}` blocks and out transitions ([#5815](https://github.com/sveltejs/svelte/issues/5815)) +* Deconflict variable names used for contextual actions ([#5839](https://github.com/sveltejs/svelte/issues/5839)) ## 3.31.1 diff --git a/src/compiler/compile/nodes/Action.ts b/src/compiler/compile/nodes/Action.ts index 3cd6ed8b6704..347ea2fb3081 100644 --- a/src/compiler/compile/nodes/Action.ts +++ b/src/compiler/compile/nodes/Action.ts @@ -2,15 +2,16 @@ import Node from './shared/Node'; import Expression from './shared/Expression'; import Component from '../Component'; import TemplateScope from './shared/TemplateScope'; -import { TemplateNode } from '../../interfaces'; +import { Directive } from '../../interfaces'; export default class Action extends Node { type: 'Action'; name: string; expression: Expression; uses_context: boolean; + template_scope: TemplateScope; - constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) { + constructor(component: Component, parent: Node, scope: TemplateScope, info: Directive) { super(component, parent, scope, info); const object = info.name.split('.')[0]; @@ -23,6 +24,8 @@ export default class Action extends Node { ? new Expression(component, this, scope, info.expression) : null; + this.template_scope = scope; + this.uses_context = this.expression && this.expression.uses_context; } } diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index a0babac993b0..6b051157f53d 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -14,6 +14,7 @@ import { Node, FunctionExpression, Identifier } from 'estree'; import { INode } from '../interfaces'; import { is_reserved_keyword } from '../../utils/reserved_keywords'; import replace_object from '../../utils/replace_object'; +import is_contextual from './is_contextual'; import EachBlock from '../EachBlock'; type Owner = INode; @@ -409,18 +410,3 @@ function get_function_name(_node, parent) { return 'func'; } - -function is_contextual(component: Component, scope: TemplateScope, name: string) { - if (is_reserved_keyword(name)) return true; - - // if it's a name below root scope, it's contextual - if (!scope.is_top_level(name)) return true; - - const variable = component.var_lookup.get(name); - - // hoistables, module declarations, and imports are non-contextual - if (!variable || variable.hoistable) return false; - - // assume contextual - return true; -} diff --git a/src/compiler/compile/nodes/shared/is_contextual.ts b/src/compiler/compile/nodes/shared/is_contextual.ts new file mode 100644 index 000000000000..b1ef39823795 --- /dev/null +++ b/src/compiler/compile/nodes/shared/is_contextual.ts @@ -0,0 +1,18 @@ +import Component from '../../Component'; +import TemplateScope from './TemplateScope'; +import { is_reserved_keyword } from '../../utils/reserved_keywords'; + +export default function is_contextual(component: Component, scope: TemplateScope, name: string) { + if (is_reserved_keyword(name)) return true; + + // if it's a name below root scope, it's contextual + if (!scope.is_top_level(name)) return true; + + const variable = component.var_lookup.get(name); + + // hoistables, module declarations, and imports are non-contextual + if (!variable || variable.hoistable) return false; + + // assume contextual + return true; +} diff --git a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts index 85aee6cd36f9..b57820beb3ed 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts @@ -1,6 +1,7 @@ import { b, x } from 'code-red'; import Block from '../../Block'; import Action from '../../../nodes/Action'; +import is_contextual from '../../../nodes/shared/is_contextual'; export default function add_actions( block: Block, @@ -11,7 +12,7 @@ export default function add_actions( } export function add_action(block: Block, target: string, action: Action) { - const { expression } = action; + const { expression, template_scope } = action; let snippet; let dependencies; @@ -28,7 +29,9 @@ export function add_action(block: Block, target: string, action: Action) { const [obj, ...properties] = action.name.split('.'); - const fn = block.renderer.reference(obj); + const fn = is_contextual(action.component, template_scope, obj) + ? block.renderer.reference(obj) + : obj; if (properties.length) { const member_expression = properties.reduce((lhs, rhs) => x`${lhs}.${rhs}`, fn); diff --git a/test/runtime/samples/deconflict-contextual-action/_config.js b/test/runtime/samples/deconflict-contextual-action/_config.js new file mode 100644 index 000000000000..542ec2fe08c2 --- /dev/null +++ b/test/runtime/samples/deconflict-contextual-action/_config.js @@ -0,0 +1,13 @@ +let result; + +export default { + before_test() { + result = []; + }, + props: { + collect: (str) => result.push(str) + }, + test({ assert }) { + assert.deepEqual(result, ['each_action', 'import_action']); + } +}; diff --git a/test/runtime/samples/deconflict-contextual-action/main.svelte b/test/runtime/samples/deconflict-contextual-action/main.svelte new file mode 100644 index 000000000000..48862e5f9fbd --- /dev/null +++ b/test/runtime/samples/deconflict-contextual-action/main.svelte @@ -0,0 +1,17 @@ + + +
+ + diff --git a/test/runtime/samples/deconflict-contextual-action/util.js b/test/runtime/samples/deconflict-contextual-action/util.js new file mode 100644 index 000000000000..32bf0ffd2ebd --- /dev/null +++ b/test/runtime/samples/deconflict-contextual-action/util.js @@ -0,0 +1,3 @@ +export default function (_, fn) { + fn('import_action'); +}