Skip to content

Commit 2b44100

Browse files
committed
dry out
1 parent 12fffb9 commit 2b44100

File tree

10 files changed

+99
-164
lines changed

10 files changed

+99
-164
lines changed

packages/svelte/src/compiler/phases/3-transform/client/transform-client.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import { UpdateExpression } from './visitors/UpdateExpression.js';
5959
import { UseDirective } from './visitors/UseDirective.js';
6060
import { AttachTag } from './visitors/AttachTag.js';
6161
import { VariableDeclaration } from './visitors/VariableDeclaration.js';
62+
import { Memoizer } from './visitors/shared/utils.js';
6263

6364
/** @type {Visitors} */
6465
const visitors = {
@@ -170,10 +171,9 @@ export function client_component(analysis, options) {
170171
// these are set inside the `Fragment` visitor, and cannot be used until then
171172
init: /** @type {any} */ (null),
172173
update: /** @type {any} */ (null),
173-
expressions: /** @type {any} */ (null),
174-
async_expressions: /** @type {any} */ (null),
175174
after_update: /** @type {any} */ (null),
176-
template: /** @type {any} */ (null)
175+
template: /** @type {any} */ (null),
176+
memoizer: /** @type {any} */ (null)
177177
};
178178

179179
const module = /** @type {ESTree.Program} */ (

packages/svelte/src/compiler/phases/3-transform/client/types.d.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type { AST, Namespace, ValidatedCompileOptions } from '#compiler';
1212
import type { TransformState } from '../types.js';
1313
import type { ComponentAnalysis } from '../../types.js';
1414
import type { Template } from './transform-template/template.js';
15+
import type { Memoizer } from './visitors/shared/utils.js';
1516

1617
export interface ClientTransformState extends TransformState {
1718
/**
@@ -49,10 +50,8 @@ export interface ComponentClientTransformState extends ClientTransformState {
4950
readonly update: Statement[];
5051
/** Stuff that happens after the render effect (control blocks, dynamic elements, bindings, actions, etc) */
5152
readonly after_update: Statement[];
52-
/** Expressions used inside the render effect */
53-
readonly expressions: Array<{ id: Identifier; expression: Expression }>;
54-
/** Expressions used inside the render effect */
55-
readonly async_expressions: Array<{ id: Identifier; expression: Expression }>;
53+
/** Memoized expressions */
54+
readonly memoizer: Memoizer;
5655
/** The HTML template string */
5756
readonly template: Template;
5857
readonly metadata: {
@@ -87,8 +86,3 @@ export type ComponentVisitors = import('zimmerframe').Visitors<
8786
AST.SvelteNode,
8887
ComponentClientTransformState
8988
>;
90-
91-
export interface MemoizedExpression {
92-
id: Identifier;
93-
expression: Expression;
94-
}

packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as b from '#compiler/builders';
66
import { clean_nodes, infer_namespace } from '../../utils.js';
77
import { transform_template } from '../transform-template/index.js';
88
import { process_children } from './shared/fragment.js';
9-
import { build_render_statement } from './shared/utils.js';
9+
import { build_render_statement, Memoizer } from './shared/utils.js';
1010
import { Template } from '../transform-template/template.js';
1111

1212
/**
@@ -62,9 +62,8 @@ export function Fragment(node, context) {
6262
...context.state,
6363
init: [],
6464
update: [],
65-
expressions: [],
66-
async_expressions: [],
6765
after_update: [],
66+
memoizer: new Memoizer(),
6867
template: new Template(),
6968
transform: { ...context.state.transform },
7069
metadata: {

packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
build_set_style
2323
} from './shared/element.js';
2424
import { process_children } from './shared/fragment.js';
25-
import { build_render_statement, build_template_chunk, get_expression_id } from './shared/utils.js';
25+
import { build_render_statement, build_template_chunk, Memoizer } from './shared/utils.js';
2626
import { visit_event_attribute } from './shared/events.js';
2727

2828
/**
@@ -255,10 +255,7 @@ export function RegularElement(node, context) {
255255
context,
256256
(value, metadata) =>
257257
metadata.has_call || metadata.has_await
258-
? get_expression_id(
259-
metadata.has_await ? context.state.async_expressions : context.state.expressions,
260-
value
261-
)
258+
? context.state.memoizer.add(value, metadata.has_await)
262259
: value
263260
);
264261

@@ -465,15 +462,13 @@ function setup_select_synchronization(value_binding, context) {
465462
/**
466463
* @param {AST.ClassDirective[]} class_directives
467464
* @param {ComponentContext} context
468-
* @param {MemoizedExpression[]} async_expressions
469-
* @param {MemoizedExpression[]} expressions
465+
* @param {Memoizer} memoizer
470466
* @return {ObjectExpression | Identifier}
471467
*/
472468
export function build_class_directives_object(
473469
class_directives,
474470
context,
475-
async_expressions = context.state.async_expressions,
476-
expressions = context.state.expressions
471+
memoizer = context.state.memoizer
477472
) {
478473
let properties = [];
479474
let has_call_or_state = false;
@@ -488,23 +483,19 @@ export function build_class_directives_object(
488483

489484
const directives = b.object(properties);
490485

491-
return has_call_or_state || has_await
492-
? get_expression_id(has_await ? async_expressions : expressions, directives)
493-
: directives;
486+
return has_call_or_state || has_await ? memoizer.add(directives, has_await) : directives;
494487
}
495488

496489
/**
497490
* @param {AST.StyleDirective[]} style_directives
498491
* @param {ComponentContext} context
499-
* @param {MemoizedExpression[]} async_expressions
500-
* @param {MemoizedExpression[]} expressions
492+
* @param {Memoizer} memoizer
501493
* @return {ObjectExpression | ArrayExpression | Identifier}}
502494
*/
503495
export function build_style_directives_object(
504496
style_directives,
505497
context,
506-
async_expressions = context.state.async_expressions,
507-
expressions = context.state.expressions
498+
memoizer = context.state.memoizer
508499
) {
509500
const normal = b.object([]);
510501
const important = b.object([]);
@@ -527,9 +518,7 @@ export function build_style_directives_object(
527518

528519
const directives = important.properties.length ? b.array([normal, important]) : normal;
529520

530-
return has_call_or_state || has_await
531-
? get_expression_id(has_await ? async_expressions : expressions, directives)
532-
: directives;
521+
return has_call_or_state || has_await ? memoizer.add(directives, has_await) : directives;
533522
}
534523

535524
/**
@@ -651,9 +640,7 @@ function build_element_special_value_attribute(element, node_id, attribute, cont
651640
element === 'select' && attribute.value !== true && !is_text_attribute(attribute);
652641

653642
const { value, has_state } = build_attribute_value(attribute.value, context, (value, metadata) =>
654-
metadata.has_call || metadata.has_await
655-
? get_expression_id(metadata.has_await ? state.async_expressions : state.expressions, value)
656-
: value
643+
metadata.has_call || metadata.has_await ? state.memoizer.add(value, metadata.has_await) : value
657644
);
658645

659646
const evaluated = context.state.scope.evaluate(value);

packages/svelte/src/compiler/phases/3-transform/client/visitors/RenderTag.js

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/** @import { Expression, Statement } from 'estree' */
22
/** @import { AST } from '#compiler' */
3-
/** @import { ComponentContext, MemoizedExpression } from '../types' */
3+
/** @import { ComponentContext } from '../types' */
44
import { unwrap_optional } from '../../../../utils/ast.js';
55
import * as b from '#compiler/builders';
66
import { create_derived } from '../utils.js';
7-
import { get_expression_id, build_expression } from './shared/utils.js';
7+
import { build_expression, Memoizer } from './shared/utils.js';
88

99
/**
1010
* @param {AST.RenderTag} node
@@ -18,11 +18,7 @@ export function RenderTag(node, context) {
1818
/** @type {Expression[]} */
1919
let args = [];
2020

21-
/** @type {MemoizedExpression[]} */
22-
const expressions = [];
23-
24-
/** @type {MemoizedExpression[]} */
25-
const async_expressions = [];
21+
const memoizer = new Memoizer();
2622

2723
for (let i = 0; i < call.arguments.length; i++) {
2824
const arg = /** @type {Expression} */ (call.arguments[i]);
@@ -31,21 +27,16 @@ export function RenderTag(node, context) {
3127
let expression = build_expression(context, arg, metadata);
3228

3329
if (metadata.has_await || metadata.has_call) {
34-
expression = b.call(
35-
'$.get',
36-
get_expression_id(metadata.has_await ? async_expressions : expressions, expression)
37-
);
30+
expression = b.call('$.get', memoizer.add(expression, metadata.has_await));
3831
}
3932

4033
args.push(b.thunk(expression));
4134
}
4235

43-
[...async_expressions, ...expressions].forEach((memo, i) => {
44-
memo.id.name = `$${i}`;
45-
});
36+
memoizer.apply();
4637

4738
/** @type {Statement[]} */
48-
const statements = expressions.map((memo) =>
39+
const statements = memoizer.sync.map((memo) =>
4940
b.var(memo.id, create_derived(context.state, b.thunk(memo.expression)))
5041
);
5142

@@ -76,15 +67,15 @@ export function RenderTag(node, context) {
7667
);
7768
}
7869

79-
if (async_expressions.length > 0) {
70+
if (memoizer.async.length > 0) {
8071
context.state.init.push(
8172
b.stmt(
8273
b.call(
8374
'$.async',
8475
context.state.node,
85-
b.array(async_expressions.map((memo) => b.thunk(memo.expression, true))),
76+
b.array(memoizer.async.map((memo) => b.thunk(memo.expression, true))),
8677
b.arrow(
87-
[context.state.node, ...async_expressions.map((memo) => memo.id)],
78+
[context.state.node, ...memoizer.async.map((memo) => memo.id)],
8879
b.block(statements)
8980
)
9081
)

packages/svelte/src/compiler/phases/3-transform/client/visitors/SlotElement.js

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/** @import { BlockStatement, Expression, ExpressionStatement, Literal, Property, Statement } from 'estree' */
22
/** @import { AST } from '#compiler' */
3-
/** @import { ComponentContext, MemoizedExpression } from '../types' */
3+
/** @import { ComponentContext } from '../types' */
44
import * as b from '#compiler/builders';
55
import { create_derived } from '../utils.js';
66
import { build_attribute_value } from './shared/element.js';
7-
import { get_expression_id } from './shared/utils.js';
7+
import { Memoizer } from './shared/utils.js';
88

99
/**
1010
* @param {AST.SlotElement} node
@@ -23,11 +23,7 @@ export function SlotElement(node, context) {
2323
/** @type {ExpressionStatement[]} */
2424
const lets = [];
2525

26-
/** @type {MemoizedExpression[]} */
27-
const expressions = [];
28-
29-
/** @type {MemoizedExpression[]} */
30-
const async_expressions = [];
26+
const memoizer = new Memoizer();
3127

3228
let name = b.literal('default');
3329

@@ -40,10 +36,7 @@ export function SlotElement(node, context) {
4036
context,
4137
(value, metadata) =>
4238
metadata.has_call || metadata.has_await
43-
? b.call(
44-
'$.get',
45-
get_expression_id(metadata.has_await ? async_expressions : expressions, value)
46-
)
39+
? b.call('$.get', memoizer.add(value, metadata.has_await))
4740
: value
4841
);
4942

@@ -61,15 +54,13 @@ export function SlotElement(node, context) {
6154
}
6255
}
6356

64-
[...async_expressions, ...expressions].forEach((memo, i) => {
65-
memo.id.name = `$${i}`;
66-
});
57+
memoizer.apply();
6758

6859
// Let bindings first, they can be used on attributes
6960
context.state.init.push(...lets);
7061

7162
/** @type {Statement[]} */
72-
const statements = expressions.map((memo) =>
63+
const statements = memoizer.sync.map((memo) =>
7364
b.var(memo.id, create_derived(context.state, b.thunk(memo.expression)))
7465
);
7566

@@ -85,15 +76,15 @@ export function SlotElement(node, context) {
8576
b.stmt(b.call('$.slot', context.state.node, b.id('$$props'), name, props_expression, fallback))
8677
);
8778

88-
if (async_expressions.length > 0) {
79+
if (memoizer.async.length > 0) {
8980
context.state.init.push(
9081
b.stmt(
9182
b.call(
9283
'$.async',
9384
context.state.node,
94-
b.array(async_expressions.map((memo) => b.thunk(memo.expression, true))),
85+
b.array(memoizer.async.map((memo) => b.thunk(memo.expression, true))),
9586
b.arrow(
96-
[context.state.node, ...async_expressions.map((memo) => memo.id)],
87+
[context.state.node, ...memoizer.async.map((memo) => memo.id)],
9788
b.block(statements)
9889
)
9990
)

packages/svelte/src/compiler/phases/3-transform/client/visitors/SvelteElement.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
build_attribute_effect,
1111
build_set_class
1212
} from './shared/element.js';
13-
import { build_render_statement } from './shared/utils.js';
13+
import { build_render_statement, Memoizer } from './shared/utils.js';
1414

1515
/**
1616
* @param {AST.SvelteElement} node
@@ -46,9 +46,8 @@ export function SvelteElement(node, context) {
4646
node: element_id,
4747
init: [],
4848
update: [],
49-
expressions: [],
50-
async_expressions: [],
51-
after_update: []
49+
after_update: [],
50+
memoizer: new Memoizer()
5251
}
5352
};
5453

0 commit comments

Comments
 (0)