Skip to content

Commit

Permalink
dry {#each}/{#await} destructuring (#4596)
Browse files Browse the repository at this point in the history
  • Loading branch information
tanhauhau authored May 11, 2020
1 parent c743e72 commit 37cc588
Show file tree
Hide file tree
Showing 22 changed files with 453 additions and 432 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Svelte changelog

## Unreleased

* Support default values and trailing commas in destructuring `{#await}` ([#4560](https://github.com/sveltejs/svelte/issues/4560), [#4810](https://github.com/sveltejs/svelte/issues/4810))

## 3.22.2

* Fix compiler exception with `a11y-img-redundant-alt` and value-less `alt` attribute ([#4777](https://github.com/sveltejs/svelte/issues/4777))
Expand Down
39 changes: 20 additions & 19 deletions src/compiler/compile/nodes/AwaitBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@ import PendingBlock from './PendingBlock';
import ThenBlock from './ThenBlock';
import CatchBlock from './CatchBlock';
import Expression from './shared/Expression';
import { Pattern } from 'estree';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
import traverse_destructure_pattern from '../utils/traverse_destructure_pattern';
import { Context, unpack_destructuring } from './shared/Context';
import { Node as ESTreeNode } from 'estree';

export default class AwaitBlock extends Node {
type: 'AwaitBlock';
expression: Expression;
value: DestructurePattern;
error: DestructurePattern;

then_contexts: Context[];
catch_contexts: Context[];

then_node: ESTreeNode | null;
catch_node: ESTreeNode | null;

pending: PendingBlock;
then: ThenBlock;
Expand All @@ -24,24 +28,21 @@ export default class AwaitBlock extends Node {

this.expression = new Expression(component, this, scope, info.expression);

this.value = info.value && new DestructurePattern(info.value);
this.error = info.error && new DestructurePattern(info.error);
this.then_node = info.value;
this.catch_node = info.error;

if (this.then_node) {
this.then_contexts = [];
unpack_destructuring(this.then_contexts, info.value, node => node);
}

if (this.catch_node) {
this.catch_contexts = [];
unpack_destructuring(this.catch_contexts, info.error, node => node);
}

this.pending = new PendingBlock(component, this, scope, info.pending);
this.then = new ThenBlock(component, this, scope, info.then);
this.catch = new CatchBlock(component, this, scope, info.catch);
}
}

export class DestructurePattern {
pattern: Pattern;
expressions: string[];
identifier_name: string | undefined;

constructor(pattern: Pattern) {
this.pattern = pattern;
this.expressions = [];
traverse_destructure_pattern(pattern, (node) => this.expressions.push(node.name));
this.identifier_name = this.pattern.type === 'Identifier' ? this.pattern.name : undefined;
}
}
6 changes: 3 additions & 3 deletions src/compiler/compile/nodes/CatchBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ export default class CatchBlock extends AbstractBlock {
super(component, parent, scope, info);

this.scope = scope.child();
if (parent.error) {
parent.error.expressions.forEach(expression => {
this.scope.add(expression, parent.expression.dependencies, this);
if (parent.catch_node) {
parent.catch_contexts.forEach(context => {
this.scope.add(context.key.name, parent.expression.dependencies, this);
});
}
this.children = map_children(component, parent, this.scope, info.children);
Expand Down
52 changes: 2 additions & 50 deletions src/compiler/compile/nodes/EachBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,56 +4,8 @@ import map_children from './shared/map_children';
import TemplateScope from './shared/TemplateScope';
import AbstractBlock from './shared/AbstractBlock';
import Element from './Element';
import { x } from 'code-red';
import { Node, Identifier, RestElement } from 'estree';

interface Context {
key: Identifier;
name?: string;
modifier: (node: Node) => Node;
}

function unpack_destructuring(contexts: Context[], node: Node, modifier: (node: Node) => Node) {
if (!node) return;

if (node.type === 'Identifier' || (node as any).type === 'RestIdentifier') { // TODO is this right? not RestElement?
contexts.push({
key: node as Identifier,
modifier
});
} else if (node.type === 'ArrayPattern') {
node.elements.forEach((element, i) => {
if (element && (element as any).type === 'RestIdentifier') {
unpack_destructuring(contexts, element, node => x`${modifier(node)}.slice(${i})` as Node);
} else {
unpack_destructuring(contexts, element, node => x`${modifier(node)}[${i}]` as Node);
}
});
} else if (node.type === 'ObjectPattern') {
const used_properties = [];

node.properties.forEach((property, i) => {
if ((property as any).kind === 'rest') { // TODO is this right?
const replacement: RestElement = {
type: 'RestElement',
argument: property.key as Identifier
};

node.properties[i] = replacement as any;

unpack_destructuring(
contexts,
property.value,
node => x`@object_without_properties(${modifier(node)}, [${used_properties}])` as Node
);
} else {
used_properties.push(x`"${(property.key as Identifier).name}"`);

unpack_destructuring(contexts, property.value, node => x`${modifier(node)}.${(property.key as Identifier).name}` as Node);
}
});
}
}
import { Context, unpack_destructuring } from './shared/Context';
import { Node } from 'estree';

export default class EachBlock extends AbstractBlock {
type: 'EachBlock';
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/compile/nodes/ThenBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ export default class ThenBlock extends AbstractBlock {
super(component, parent, scope, info);

this.scope = scope.child();
if (parent.value) {
parent.value.expressions.forEach(expression => {
this.scope.add(expression, parent.expression.dependencies, this);
if (parent.then_node) {
parent.then_contexts.forEach(context => {
this.scope.add(context.key.name, parent.expression.dependencies, this);
});
}
this.children = map_children(component, parent, this.scope, info.children);
Expand Down
58 changes: 58 additions & 0 deletions src/compiler/compile/nodes/shared/Context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { x } from 'code-red';
import { Node, Identifier, RestElement, Property } from 'estree';

export interface Context {
key: Identifier;
name?: string;
modifier: (node: Node) => Node;
}

export function unpack_destructuring(contexts: Context[], node: Node, modifier: (node: Node) => Node) {
if (!node) return;

if (node.type === 'Identifier') {
contexts.push({
key: node as Identifier,
modifier
});
} else if (node.type === 'RestElement') {
contexts.push({
key: node.argument as Identifier,
modifier
});
} else if (node.type === 'ArrayPattern') {
node.elements.forEach((element, i) => {
if (element && element.type === 'RestElement') {
unpack_destructuring(contexts, element, node => x`${modifier(node)}.slice(${i})` as Node);
} else if (element && element.type === 'AssignmentPattern') {
unpack_destructuring(contexts, element.left, node => x`${modifier(node)}[${i}] !== undefined ? ${modifier(node)}[${i}] : ${element.right}` as Node);
} else {
unpack_destructuring(contexts, element, node => x`${modifier(node)}[${i}]` as Node);
}
});
} else if (node.type === 'ObjectPattern') {
const used_properties = [];

node.properties.forEach((property) => {
const props: (RestElement | Property) = (property as any);

if (props.type === 'RestElement') {
unpack_destructuring(
contexts,
props.argument,
node => x`@object_without_properties(${modifier(node)}, [${used_properties}])` as Node
);
} else {
const key = property.key as Identifier;
const value = property.value;

used_properties.push(x`"${(key as Identifier).name}"`);
if (value.type === 'AssignmentPattern') {
unpack_destructuring(contexts, value.left, node => x`${modifier(node)}.${key.name} !== undefined ? ${modifier(node)}.${key.name} : ${value.right}` as Node);
} else {
unpack_destructuring(contexts, value, node => x`${modifier(node)}.${key.name}` as Node);
}
}
});
}
}
Loading

0 comments on commit 37cc588

Please sign in to comment.