Skip to content

Commit d4b6623

Browse files
committed
more
1 parent f87b3d5 commit d4b6623

File tree

2 files changed

+79
-43
lines changed

2 files changed

+79
-43
lines changed

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

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
/** @import { Expression, ExpressionStatement, Program, Property, Statement, VariableDeclarator } from 'estree' */
2-
/** @import { Namespace, SvelteNode, ValidatedCompileOptions, ValidatedModuleCompileOptions } from '#compiler' */
1+
/** @import { Expression, ExpressionStatement, MethodDefinition, Pattern, Program, Property, PropertyDefinition, Statement, VariableDeclarator } from 'estree' */
2+
/** @import { Binding, Namespace, SvelteNode, ValidatedCompileOptions, ValidatedModuleCompileOptions } from '#compiler' */
33
/** @import { ComponentServerTransformState, ComponentVisitors, ServerTransformState, Visitors } from './types.js' */
44
/** @import { Analysis, ComponentAnalysis } from '../../types.js' */
55
/** @import { Scope } from '../../scope.js' */
66
/** @import { StateField } from '../../3-transform/client/types.js' */ // TODO move this type
77
import { walk } from 'zimmerframe';
88
import { set_scope } from '../../scope.js';
9-
import { extract_identifiers } from '../../../utils/ast.js';
9+
import { extract_identifiers, extract_paths, is_expression_async } from '../../../utils/ast.js';
1010
import * as b from '../../../utils/builders.js';
1111
import { filename } from '../../../state.js';
1212
import { render_stylesheet } from '../css/index.js';
@@ -44,6 +44,28 @@ import { SvelteHead } from './visitors/template/SvelteHead.js';
4444
import { SvelteSelf } from './visitors/template/SvelteSelf.js';
4545
import { TitleElement } from './visitors/template/TitleElement.js';
4646

47+
/**
48+
* @param {VariableDeclarator} declarator
49+
* @param {Scope} scope
50+
* @param {Expression} value
51+
* @returns {VariableDeclarator[]}
52+
*/
53+
function create_state_declarators(declarator, scope, value) {
54+
if (declarator.id.type === 'Identifier') {
55+
return [b.declarator(declarator.id, value)];
56+
}
57+
58+
const tmp = scope.generate('tmp');
59+
const paths = extract_paths(declarator.id);
60+
return [
61+
b.declarator(b.id(tmp), value), // TODO inject declarator for opts, so we can use it below
62+
...paths.map((path) => {
63+
const value = path.expression?.(b.id(tmp));
64+
return b.declarator(path.node, value);
65+
})
66+
];
67+
}
68+
4769
/** @type {Visitors} */
4870
const global_visitors = {
4971
AssignmentExpression,

packages/svelte/src/compiler/phases/3-transform/server/visitors/javascript/VariableDeclaration.js

Lines changed: 54 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/** @import { VariableDeclaration, Node, VariableDeclarator, Expression, CallExpression, Pattern } from 'estree' */
22
/** @import { Context } from '../../types' */
33
/** @import { Scope } from '../../../../scope' */
4-
import { extract_paths } from '../../../../../utils/ast.js';
4+
import { extract_paths, is_expression_async } from '../../../../../utils/ast.js';
55
import * as b from '../../../../../utils/builders.js';
66
import { get_rune } from '../../../../scope.js';
77
import { walk } from 'zimmerframe';
@@ -74,58 +74,72 @@ export function VariableDeclarationRunes(node, context) {
7474
* @param {VariableDeclaration} node
7575
* @param {Context} context
7676
*/
77-
export function VariableDeclarationLegacy(node, context) {
77+
export function VariableDeclarationLegacy(node, { state, visit }) {
78+
/** @type {VariableDeclarator[]} */
7879
const declarations = [];
7980

8081
for (const declarator of node.declarations) {
81-
const init = declarator.init;
82-
const rune = get_rune(init, context.state.scope);
83-
if (!rune || rune === '$effect.tracking' || rune === '$inspect' || rune === '$effect.root') {
84-
declarations.push(/** @type {VariableDeclarator} */ (context.visit(declarator)));
85-
continue;
86-
}
82+
const bindings = /** @type {Binding[]} */ (state.scope.get_bindings(declarator));
83+
const has_state = bindings.some((binding) => binding.kind === 'state');
84+
const has_props = bindings.some((binding) => binding.kind === 'bindable_prop');
8785

88-
if (rune === '$props') {
89-
// remove $bindable() from props declaration
90-
const id = walk(declarator.id, null, {
91-
AssignmentPattern(node) {
92-
if (
93-
node.right.type === 'CallExpression' &&
94-
get_rune(node.right, context.state.scope) === '$bindable'
95-
) {
96-
const right = node.right.arguments.length
97-
? /** @type {Expression} */ (context.visit(node.right.arguments[0]))
98-
: b.id('undefined');
99-
return b.assignment_pattern(node.left, right);
100-
}
101-
}
102-
});
103-
declarations.push(b.declarator(id, b.id('$$props')));
86+
if (!has_state && !has_props) {
87+
declarations.push(/** @type {VariableDeclarator} */ (visit(declarator)));
10488
continue;
10589
}
10690

107-
const args = /** @type {CallExpression} */ (init).arguments;
108-
const value =
109-
args.length === 0 ? b.id('undefined') : /** @type {Expression} */ (context.visit(args[0]));
110-
111-
if (rune === '$derived.by') {
112-
declarations.push(
113-
b.declarator(/** @type {Pattern} */ (context.visit(declarator.id)), b.call(value))
91+
if (has_props) {
92+
if (declarator.id.type !== 'Identifier') {
93+
// Turn export let into props. It's really really weird because export let { x: foo, z: [bar]} = ..
94+
// means that foo and bar are the props (i.e. the leafs are the prop names), not x and z.
95+
const tmp = state.scope.generate('tmp');
96+
const paths = extract_paths(declarator.id);
97+
declarations.push(
98+
b.declarator(
99+
b.id(tmp),
100+
/** @type {Expression} */ (visit(/** @type {Expression} */ (declarator.init)))
101+
)
102+
);
103+
for (const path of paths) {
104+
const value = path.expression?.(b.id(tmp));
105+
const name = /** @type {Identifier} */ (path.node).name;
106+
const binding = /** @type {Binding} */ (state.scope.get(name));
107+
const prop = b.member(b.id('$$props'), b.literal(binding.prop_alias ?? name), true);
108+
declarations.push(
109+
b.declarator(path.node, b.call('$.value_or_fallback', prop, b.thunk(value)))
110+
);
111+
}
112+
continue;
113+
}
114+
115+
const binding = /** @type {Binding} */ (state.scope.get(declarator.id.name));
116+
const prop = b.member(
117+
b.id('$$props'),
118+
b.literal(binding.prop_alias ?? declarator.id.name),
119+
true
114120
);
115-
continue;
116-
}
117121

118-
if (declarator.id.type === 'Identifier') {
119-
declarations.push(b.declarator(declarator.id, value));
120-
continue;
121-
}
122+
/** @type {Expression} */
123+
let init = prop;
124+
if (declarator.init) {
125+
const default_value = /** @type {Expression} */ (visit(declarator.init));
126+
init = is_expression_async(default_value)
127+
? b.await(b.call('$.value_or_fallback_async', prop, b.thunk(default_value, true)))
128+
: b.call('$.value_or_fallback', prop, b.thunk(default_value));
129+
}
130+
131+
declarations.push(b.declarator(declarator.id, init));
122132

123-
if (rune === '$derived') {
124-
declarations.push(b.declarator(/** @type {Pattern} */ (context.visit(declarator.id)), value));
125133
continue;
126134
}
127135

128-
declarations.push(...create_state_declarators(declarator, context.state.scope, value));
136+
declarations.push(
137+
...create_state_declarators(
138+
declarator,
139+
state.scope,
140+
/** @type {Expression} */ (declarator.init && visit(declarator.init))
141+
)
142+
);
129143
}
130144

131145
return {

0 commit comments

Comments
 (0)