|
1 | 1 | /** @import { VariableDeclaration, Node, VariableDeclarator, Expression, CallExpression, Pattern } from 'estree' */
|
2 | 2 | /** @import { Context } from '../../types' */
|
3 | 3 | /** @import { Scope } from '../../../../scope' */
|
4 |
| -import { extract_paths } from '../../../../../utils/ast.js'; |
| 4 | +import { extract_paths, is_expression_async } from '../../../../../utils/ast.js'; |
5 | 5 | import * as b from '../../../../../utils/builders.js';
|
6 | 6 | import { get_rune } from '../../../../scope.js';
|
7 | 7 | import { walk } from 'zimmerframe';
|
@@ -74,58 +74,72 @@ export function VariableDeclarationRunes(node, context) {
|
74 | 74 | * @param {VariableDeclaration} node
|
75 | 75 | * @param {Context} context
|
76 | 76 | */
|
77 |
| -export function VariableDeclarationLegacy(node, context) { |
| 77 | +export function VariableDeclarationLegacy(node, { state, visit }) { |
| 78 | + /** @type {VariableDeclarator[]} */ |
78 | 79 | const declarations = [];
|
79 | 80 |
|
80 | 81 | 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'); |
87 | 85 |
|
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))); |
104 | 88 | continue;
|
105 | 89 | }
|
106 | 90 |
|
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 |
114 | 120 | );
|
115 |
| - continue; |
116 |
| - } |
117 | 121 |
|
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)); |
122 | 132 |
|
123 |
| - if (rune === '$derived') { |
124 |
| - declarations.push(b.declarator(/** @type {Pattern} */ (context.visit(declarator.id)), value)); |
125 | 133 | continue;
|
126 | 134 | }
|
127 | 135 |
|
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 | + ); |
129 | 143 | }
|
130 | 144 |
|
131 | 145 | return {
|
|
0 commit comments