ripple 0.2.125 → 0.2.128
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/compiler/phases/2-analyze/index.js +36 -24
- package/src/compiler/phases/3-transform/client/index.js +63 -33
- package/src/compiler/phases/3-transform/segments.js +36 -0
- package/src/compiler/utils.js +8 -8
- package/src/runtime/internal/client/bindings.js +2 -0
- package/src/runtime/internal/client/render.js +5 -1
- package/src/runtime/internal/client/runtime.js +65 -23
- package/src/runtime/internal/client/types.d.ts +4 -2
- package/src/runtime/internal/server/index.js +3 -1
- package/src/runtime/proxy.js +9 -8
- package/tests/client/function-overload-import.ripple +10 -0
- package/tests/client/function-overload.test.ripple +40 -0
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Ripple is an elegant TypeScript UI framework",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dominic Gannaway",
|
|
6
|
-
"version": "0.2.
|
|
6
|
+
"version": "0.2.128",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"module": "src/runtime/index-client.js",
|
|
9
9
|
"main": "src/runtime/index-client.js",
|
|
@@ -109,7 +109,7 @@ const visitors = {
|
|
|
109
109
|
const parent = context.path.at(-1);
|
|
110
110
|
|
|
111
111
|
if (
|
|
112
|
-
is_reference(node, /** @type {Node} */
|
|
112
|
+
is_reference(node, /** @type {Node} */(parent)) &&
|
|
113
113
|
binding &&
|
|
114
114
|
context.state.inside_server_block &&
|
|
115
115
|
context.state.scope.server_block
|
|
@@ -144,7 +144,7 @@ const visitors = {
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
if (
|
|
147
|
-
is_reference(node, /** @type {Node} */
|
|
147
|
+
is_reference(node, /** @type {Node} */(parent)) &&
|
|
148
148
|
node.tracked &&
|
|
149
149
|
binding?.node !== node
|
|
150
150
|
) {
|
|
@@ -155,7 +155,7 @@ const visitors = {
|
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
if (
|
|
158
|
-
is_reference(node, /** @type {Node} */
|
|
158
|
+
is_reference(node, /** @type {Node} */(parent)) &&
|
|
159
159
|
node.tracked &&
|
|
160
160
|
binding?.node !== node
|
|
161
161
|
) {
|
|
@@ -174,6 +174,18 @@ const visitors = {
|
|
|
174
174
|
context.state.metadata.tracking = true;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
if (node.object.type === 'Identifier' && !node.object.tracked) {
|
|
178
|
+
const binding = context.state.scope.get(node.object.name);
|
|
179
|
+
|
|
180
|
+
if (binding !== null && binding.initial?.type === 'CallExpression' && is_ripple_track_call(binding.initial.callee, context)) {
|
|
181
|
+
error(
|
|
182
|
+
`Accessing a tracked object directly is not allowed, use the \`@\` prefix to read the value inside a tracked object - for example \`@${node.object.name}${node.property.type === 'Identifier' ? `.${node.property.name}` : ''}\``,
|
|
183
|
+
context.state.analysis.module.filename,
|
|
184
|
+
node,
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
177
189
|
context.next();
|
|
178
190
|
},
|
|
179
191
|
|
|
@@ -424,10 +436,10 @@ const visitors = {
|
|
|
424
436
|
|
|
425
437
|
if (!node.metadata.has_template && !node.metadata.has_await) {
|
|
426
438
|
error(
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
439
|
+
'Component for...of loops must contain a template or an await expression in their body. Move the for loop into an effect if it does not render anything.',
|
|
440
|
+
context.state.analysis.module.filename,
|
|
441
|
+
node,
|
|
442
|
+
);
|
|
431
443
|
}
|
|
432
444
|
},
|
|
433
445
|
|
|
@@ -477,10 +489,10 @@ const visitors = {
|
|
|
477
489
|
|
|
478
490
|
if (!node.metadata.has_template && !node.metadata.has_await) {
|
|
479
491
|
error(
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
492
|
+
'Component if statements must contain a template or an await expression in their "then" body. Move the if statement into an effect if it does not render anything.',
|
|
493
|
+
context.state.analysis.module.filename,
|
|
494
|
+
node,
|
|
495
|
+
);
|
|
484
496
|
}
|
|
485
497
|
|
|
486
498
|
if (node.alternate) {
|
|
@@ -490,10 +502,10 @@ const visitors = {
|
|
|
490
502
|
|
|
491
503
|
if (!node.metadata.has_template && !node.metadata.has_await) {
|
|
492
504
|
error(
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
505
|
+
'Component if statements must contain a template or an await expression in their "else" body. Move the if statement into an effect if it does not render anything.',
|
|
506
|
+
context.state.analysis.module.filename,
|
|
507
|
+
node,
|
|
508
|
+
);
|
|
497
509
|
}
|
|
498
510
|
}
|
|
499
511
|
},
|
|
@@ -599,9 +611,9 @@ const visitors = {
|
|
|
599
611
|
state.elements.push(node);
|
|
600
612
|
// Mark dynamic elements as scoped by default since we can't match CSS at compile time
|
|
601
613
|
if (state.component?.css) {
|
|
602
|
-
|
|
614
|
+
node.metadata.scoped = true;
|
|
603
615
|
}
|
|
604
|
-
|
|
616
|
+
}
|
|
605
617
|
}
|
|
606
618
|
|
|
607
619
|
if (is_dom_element) {
|
|
@@ -756,12 +768,12 @@ const visitors = {
|
|
|
756
768
|
mark_control_flow_has_template(context.path);
|
|
757
769
|
context.next();
|
|
758
770
|
},
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
*
|
|
774
|
+
* @param {any} node
|
|
775
|
+
* @param {any} context
|
|
776
|
+
*/
|
|
765
777
|
AwaitExpression(node, context) {
|
|
766
778
|
if (is_inside_component(context)) {
|
|
767
779
|
if (context.state.metadata?.await === false) {
|
|
@@ -786,7 +798,7 @@ const visitors = {
|
|
|
786
798
|
}
|
|
787
799
|
parent_block.metadata.has_await = true;
|
|
788
800
|
}
|
|
789
|
-
|
|
801
|
+
|
|
790
802
|
context.next();
|
|
791
803
|
},
|
|
792
804
|
};
|
|
@@ -48,6 +48,12 @@ function add_ripple_internal_import(context) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
function visit_function(node, context) {
|
|
51
|
+
// Function overload signatures don't have a body - they're TypeScript-only
|
|
52
|
+
// Remove them when compiling to JavaScript
|
|
53
|
+
if (!context.state.to_ts && !node.body) {
|
|
54
|
+
return b.empty;
|
|
55
|
+
}
|
|
56
|
+
|
|
51
57
|
if (context.state.to_ts) {
|
|
52
58
|
return context.next(context.state);
|
|
53
59
|
}
|
|
@@ -545,10 +551,9 @@ const visitors = {
|
|
|
545
551
|
|
|
546
552
|
const handle_static_attr = (name, value) => {
|
|
547
553
|
const attr_value = b.literal(
|
|
548
|
-
` ${name}${
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
: `="${value === true ? '' : escape_html(value, true)}"`
|
|
554
|
+
` ${name}${is_boolean_attribute(name) && value === true
|
|
555
|
+
? ''
|
|
556
|
+
: `="${value === true ? '' : escape_html(value, true)}"`
|
|
552
557
|
}`,
|
|
553
558
|
);
|
|
554
559
|
|
|
@@ -880,16 +885,16 @@ const visitors = {
|
|
|
880
885
|
}
|
|
881
886
|
}
|
|
882
887
|
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
888
|
+
if (node.metadata.scoped && state.component.css) {
|
|
889
|
+
const hasClassAttr = node.attributes.some(attr =>
|
|
890
|
+
attr.type === 'Attribute' && attr.name.type === 'Identifier' && attr.name.name === 'class'
|
|
891
|
+
);
|
|
892
|
+
if (!hasClassAttr) {
|
|
893
|
+
const name = is_spreading ? '#class' : 'class';
|
|
894
|
+
const value = state.component.css.hash;
|
|
895
|
+
props.push(b.prop('init', b.key(name), b.literal(value)));
|
|
896
|
+
}
|
|
891
897
|
}
|
|
892
|
-
}
|
|
893
898
|
|
|
894
899
|
const children_filtered = [];
|
|
895
900
|
|
|
@@ -1039,10 +1044,10 @@ const visitors = {
|
|
|
1039
1044
|
operator === '='
|
|
1040
1045
|
? context.visit(right)
|
|
1041
1046
|
: b.binary(
|
|
1042
|
-
|
|
1043
|
-
/** @type {Expression} */
|
|
1044
|
-
/** @type {Expression} */
|
|
1045
|
-
|
|
1047
|
+
operator === '+=' ? '+' : operator === '-=' ? '-' : operator === '*=' ? '*' : '/',
|
|
1048
|
+
/** @type {Expression} */(context.visit(left)),
|
|
1049
|
+
/** @type {Expression} */(context.visit(right)),
|
|
1050
|
+
),
|
|
1046
1051
|
b.id('__block'),
|
|
1047
1052
|
);
|
|
1048
1053
|
}
|
|
@@ -1058,12 +1063,12 @@ const visitors = {
|
|
|
1058
1063
|
operator === '='
|
|
1059
1064
|
? context.visit(right)
|
|
1060
1065
|
: b.binary(
|
|
1061
|
-
|
|
1062
|
-
/** @type {Expression} */
|
|
1063
|
-
|
|
1064
|
-
),
|
|
1065
|
-
/** @type {Expression} */ (context.visit(right)),
|
|
1066
|
+
operator === '+=' ? '+' : operator === '-=' ? '-' : operator === '*=' ? '*' : '/',
|
|
1067
|
+
/** @type {Expression} */(
|
|
1068
|
+
context.visit(left, { ...context.state, metadata: { tracking: false } })
|
|
1066
1069
|
),
|
|
1070
|
+
/** @type {Expression} */(context.visit(right)),
|
|
1071
|
+
),
|
|
1067
1072
|
b.id('__block'),
|
|
1068
1073
|
);
|
|
1069
1074
|
}
|
|
@@ -1270,12 +1275,12 @@ const visitors = {
|
|
|
1270
1275
|
b.stmt(b.call(b.id('__render'), b.id(consequent_id))),
|
|
1271
1276
|
alternate_id
|
|
1272
1277
|
? b.stmt(
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1278
|
+
b.call(
|
|
1279
|
+
b.id('__render'),
|
|
1280
|
+
b.id(alternate_id),
|
|
1281
|
+
node.alternate ? b.literal(false) : undefined,
|
|
1282
|
+
),
|
|
1283
|
+
)
|
|
1279
1284
|
: undefined,
|
|
1280
1285
|
),
|
|
1281
1286
|
]),
|
|
@@ -1307,6 +1312,22 @@ const visitors = {
|
|
|
1307
1312
|
return b.empty;
|
|
1308
1313
|
}
|
|
1309
1314
|
|
|
1315
|
+
// Remove TSDeclareFunction nodes (function overload signatures) in JavaScript mode
|
|
1316
|
+
if (!context.state.to_ts && node.declaration?.type === 'TSDeclareFunction') {
|
|
1317
|
+
return b.empty;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
return context.next();
|
|
1321
|
+
},
|
|
1322
|
+
|
|
1323
|
+
TSDeclareFunction(node, context) {
|
|
1324
|
+
// TSDeclareFunction nodes are TypeScript overload signatures - remove in JavaScript mode
|
|
1325
|
+
if (!context.state.to_ts) {
|
|
1326
|
+
return b.empty;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
// In TypeScript mode, keep as TSDeclareFunction - esrap will print it with 'declare'
|
|
1330
|
+
// We'll remove the 'declare' keyword in post-processing
|
|
1310
1331
|
return context.next();
|
|
1311
1332
|
},
|
|
1312
1333
|
|
|
@@ -1336,9 +1357,9 @@ const visitors = {
|
|
|
1336
1357
|
node.handler === null
|
|
1337
1358
|
? b.literal(null)
|
|
1338
1359
|
: b.arrow(
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1360
|
+
[b.id('__anchor'), ...(node.handler.param ? [node.handler.param] : [])],
|
|
1361
|
+
b.block(transform_body(node.handler.body.body, context)),
|
|
1362
|
+
),
|
|
1342
1363
|
node.pending === null
|
|
1343
1364
|
? undefined
|
|
1344
1365
|
: b.arrow([b.id('__anchor')], b.block(transform_body(node.pending.body, context))),
|
|
@@ -1464,7 +1485,7 @@ function join_template(items) {
|
|
|
1464
1485
|
}
|
|
1465
1486
|
|
|
1466
1487
|
for (const quasi of template.quasis) {
|
|
1467
|
-
quasi.value.raw = sanitize_template_string(/** @type {string} */
|
|
1488
|
+
quasi.value.raw = sanitize_template_string(/** @type {string} */(quasi.value.cooked));
|
|
1468
1489
|
}
|
|
1469
1490
|
|
|
1470
1491
|
quasi.tail = true;
|
|
@@ -1947,7 +1968,7 @@ export function transform_client(filename, source, analysis, to_ts) {
|
|
|
1947
1968
|
};
|
|
1948
1969
|
|
|
1949
1970
|
const program = /** @type {Program} */ (
|
|
1950
|
-
walk(/** @type {Node} */
|
|
1971
|
+
walk(/** @type {Node} */(analysis.ast), { ...state, namespace: 'html' }, visitors)
|
|
1951
1972
|
);
|
|
1952
1973
|
|
|
1953
1974
|
for (const hoisted of state.hoisted) {
|
|
@@ -1971,6 +1992,15 @@ export function transform_client(filename, source, analysis, to_ts) {
|
|
|
1971
1992
|
sourceMapSource: path.basename(filename),
|
|
1972
1993
|
});
|
|
1973
1994
|
|
|
1995
|
+
// Post-process TypeScript output to remove 'declare' from function overload signatures
|
|
1996
|
+
// Function overload signatures in regular .ts files should not have 'declare' keyword
|
|
1997
|
+
if (to_ts) {
|
|
1998
|
+
// Remove 'export declare function' -> 'export function' (for overloads only, not implementations)
|
|
1999
|
+
// Match: export declare function name(...): type;
|
|
2000
|
+
// Don't match: export declare function name(...): type { (has body)
|
|
2001
|
+
js.code = js.code.replace(/^(export\s+)declare\s+(function\s+\w+[^{\n]*;)$/gm, '$1$2');
|
|
2002
|
+
}
|
|
2003
|
+
|
|
1974
2004
|
const css = render_stylesheets(state.stylesheets);
|
|
1975
2005
|
|
|
1976
2006
|
return {
|
|
@@ -1111,6 +1111,42 @@ export function convert_source_map_to_mappings(ast, source, generated_code, sour
|
|
|
1111
1111
|
} else if (node.type === 'TSAnyKeyword' || node.type === 'TSUnknownKeyword' || node.type === 'TSNumberKeyword' || node.type === 'TSObjectKeyword' || node.type === 'TSBooleanKeyword' || node.type === 'TSBigIntKeyword' || node.type === 'TSStringKeyword' || node.type === 'TSSymbolKeyword' || node.type === 'TSVoidKeyword' || node.type === 'TSUndefinedKeyword' || node.type === 'TSNullKeyword' || node.type === 'TSNeverKeyword' || node.type === 'TSThisType' || node.type === 'TSIntrinsicKeyword') {
|
|
1112
1112
|
// Primitive type keywords - leaf nodes, no children
|
|
1113
1113
|
return;
|
|
1114
|
+
} else if (node.type === 'TSDeclareFunction') {
|
|
1115
|
+
// TypeScript declare function: declare function foo(): void;
|
|
1116
|
+
// Visit in source order: id, typeParameters, params, returnType
|
|
1117
|
+
if (node.id) {
|
|
1118
|
+
visit(node.id);
|
|
1119
|
+
}
|
|
1120
|
+
if (node.typeParameters) {
|
|
1121
|
+
visit(node.typeParameters);
|
|
1122
|
+
}
|
|
1123
|
+
if (node.params) {
|
|
1124
|
+
for (const param of node.params) {
|
|
1125
|
+
visit(param);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
if (node.returnType) {
|
|
1129
|
+
visit(node.returnType);
|
|
1130
|
+
}
|
|
1131
|
+
return;
|
|
1132
|
+
} else if (node.type === 'TSExportAssignment') {
|
|
1133
|
+
// TypeScript export assignment: export = foo;
|
|
1134
|
+
if (node.expression) {
|
|
1135
|
+
visit(node.expression);
|
|
1136
|
+
}
|
|
1137
|
+
return;
|
|
1138
|
+
} else if (node.type === 'TSNamespaceExportDeclaration') {
|
|
1139
|
+
// TypeScript namespace export: export as namespace foo;
|
|
1140
|
+
if (node.id) {
|
|
1141
|
+
visit(node.id);
|
|
1142
|
+
}
|
|
1143
|
+
return;
|
|
1144
|
+
} else if (node.type === 'TSExternalModuleReference') {
|
|
1145
|
+
// TypeScript external module reference: import foo = require('bar');
|
|
1146
|
+
if (node.expression) {
|
|
1147
|
+
visit(node.expression);
|
|
1148
|
+
}
|
|
1149
|
+
return;
|
|
1114
1150
|
}
|
|
1115
1151
|
|
|
1116
1152
|
throw new Error(`Unhandled AST node type in mapping walker: ${node.type}`);
|
package/src/compiler/utils.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @import { Identifier, Pattern, Super, FunctionExpression, FunctionDeclaration, ArrowFunctionExpression, MemberExpression, AssignmentExpression, Expression, Node, AssignmentOperator } from 'estree' */
|
|
1
|
+
/** @import { Identifier, Pattern, Super, FunctionExpression, FunctionDeclaration, ArrowFunctionExpression, MemberExpression, AssignmentExpression, Expression, Node, AssignmentOperator, CallExpression } from 'estree' */
|
|
2
2
|
/** @import { Component, Element, Attribute, SpreadAttribute, ScopeInterface, Binding, RippleNode, CompilerState, TransformContext, DelegatedEventResult, TextNode } from '#compiler' */
|
|
3
3
|
import { build_assignment_value, extract_paths } from '../utils/ast.js';
|
|
4
4
|
import * as b from '../utils/builders.js';
|
|
@@ -352,7 +352,7 @@ export function build_hoisted_params(node, context) {
|
|
|
352
352
|
}
|
|
353
353
|
} else {
|
|
354
354
|
for (const param of node.params) {
|
|
355
|
-
params.push(/** @type {Pattern} */
|
|
355
|
+
params.push(/** @type {Pattern} */(context.visit(param)));
|
|
356
356
|
}
|
|
357
357
|
}
|
|
358
358
|
|
|
@@ -554,7 +554,7 @@ export function is_ripple_import(callee, context) {
|
|
|
554
554
|
* @returns {boolean}
|
|
555
555
|
*/
|
|
556
556
|
export function is_declared_function_within_component(node, context) {
|
|
557
|
-
const component = context.path?.find(/** @param {RippleNode} n */
|
|
557
|
+
const component = context.path?.find(/** @param {RippleNode} n */(n) => n.type === 'Component');
|
|
558
558
|
|
|
559
559
|
if (node.type === 'Identifier' && component) {
|
|
560
560
|
const binding = context.state.scope.get(node.name);
|
|
@@ -611,8 +611,8 @@ export function visit_assignment_expression(node, context, build_assignment) {
|
|
|
611
611
|
assignment ??
|
|
612
612
|
b.assignment(
|
|
613
613
|
'=',
|
|
614
|
-
/** @type {Pattern} */
|
|
615
|
-
/** @type {Expression} */
|
|
614
|
+
/** @type {Pattern} */(context.visit(path.node)),
|
|
615
|
+
/** @type {Expression} */(context.visit(value)),
|
|
616
616
|
)
|
|
617
617
|
);
|
|
618
618
|
});
|
|
@@ -702,8 +702,8 @@ export function build_assignment(operator, left, right, context) {
|
|
|
702
702
|
object,
|
|
703
703
|
b.assignment(
|
|
704
704
|
operator,
|
|
705
|
-
/** @type {Pattern} */
|
|
706
|
-
/** @type {Expression} */
|
|
705
|
+
/** @type {Pattern} */(context.visit(left)),
|
|
706
|
+
/** @type {Expression} */(context.visit(right)),
|
|
707
707
|
),
|
|
708
708
|
);
|
|
709
709
|
}
|
|
@@ -830,7 +830,7 @@ function normalize_child(node, normalized, context) {
|
|
|
830
830
|
*/
|
|
831
831
|
export function get_parent_block_node(context) {
|
|
832
832
|
const path = context.path;
|
|
833
|
-
|
|
833
|
+
|
|
834
834
|
for (let i = path.length - 1; i >= 0; i -= 1) {
|
|
835
835
|
const context_node = path[i];
|
|
836
836
|
if (
|
|
@@ -167,6 +167,7 @@ export function bindValue(maybe_tracked) {
|
|
|
167
167
|
value = [].map.call(select.querySelectorAll(query), get_option_value);
|
|
168
168
|
} else {
|
|
169
169
|
/** @type {HTMLOptionElement | null} */
|
|
170
|
+
// @ts-ignore
|
|
170
171
|
var selected_option =
|
|
171
172
|
select.querySelector(query) ??
|
|
172
173
|
// will fall back to first non-disabled option if no option is selected
|
|
@@ -184,6 +185,7 @@ export function bindValue(maybe_tracked) {
|
|
|
184
185
|
// Mounting and value undefined -> take selection from dom
|
|
185
186
|
if (mounting && value === undefined) {
|
|
186
187
|
/** @type {HTMLOptionElement | null} */
|
|
188
|
+
// @ts-ignore
|
|
187
189
|
var selected_option = select.querySelector(':checked');
|
|
188
190
|
if (selected_option !== null) {
|
|
189
191
|
value = get_option_value(selected_option);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @import { Block } from '#client' */
|
|
2
2
|
|
|
3
3
|
import { destroy_block, ref } from './blocks.js';
|
|
4
|
-
import { REF_PROP } from './constants.js';
|
|
4
|
+
import { REF_PROP, TRACKED, TRACKED_OBJECT } from './constants.js';
|
|
5
5
|
import {
|
|
6
6
|
get_descriptors,
|
|
7
7
|
get_own_property_symbols,
|
|
@@ -310,6 +310,10 @@ export function apply_element_spread(element, fn) {
|
|
|
310
310
|
}
|
|
311
311
|
|
|
312
312
|
for (const symbol of get_own_property_symbols(next)) {
|
|
313
|
+
// Ensure we are not trying to write to a proxied object
|
|
314
|
+
if (TRACKED_OBJECT in next) {
|
|
315
|
+
next = {...next};
|
|
316
|
+
}
|
|
313
317
|
var ref_fn = next[symbol];
|
|
314
318
|
|
|
315
319
|
if (symbol.description === REF_PROP && (!prev || ref_fn !== prev[symbol])) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** @import { Block, Component, Dependency, Derived, Tracked } from '#client' */
|
|
2
2
|
|
|
3
|
+
import { DEV } from 'esm-env';
|
|
3
4
|
import {
|
|
4
5
|
destroy_block,
|
|
5
6
|
destroy_non_branch_children,
|
|
@@ -24,6 +25,7 @@ import {
|
|
|
24
25
|
TRY_BLOCK,
|
|
25
26
|
UNINITIALIZED,
|
|
26
27
|
REF_PROP,
|
|
28
|
+
TRACKED_OBJECT,
|
|
27
29
|
} from './constants.js';
|
|
28
30
|
import { capture, suspend } from './try.js';
|
|
29
31
|
import {
|
|
@@ -137,13 +139,13 @@ export function run_teardown(block) {
|
|
|
137
139
|
* @param {Derived} computed
|
|
138
140
|
*/
|
|
139
141
|
function update_derived(computed) {
|
|
140
|
-
var value = computed.
|
|
142
|
+
var value = computed.__v;
|
|
141
143
|
|
|
142
144
|
if (value === UNINITIALIZED || is_tracking_dirty(computed.d)) {
|
|
143
145
|
value = run_derived(computed);
|
|
144
146
|
|
|
145
|
-
if (value !== computed.
|
|
146
|
-
computed.
|
|
147
|
+
if (value !== computed.__v) {
|
|
148
|
+
computed.__v = value;
|
|
147
149
|
computed.c = increment_clock();
|
|
148
150
|
}
|
|
149
151
|
}
|
|
@@ -276,12 +278,23 @@ var empty_get_set = { get: undefined, set: undefined };
|
|
|
276
278
|
*/
|
|
277
279
|
export function tracked(v, block, get, set) {
|
|
278
280
|
// TODO: now we expose tracked, we should likely block access in DEV somehow
|
|
281
|
+
if (DEV) {
|
|
282
|
+
return {
|
|
283
|
+
DO_NOT_ACCESS_THIS_OBJECT_DIRECTLY: true,
|
|
284
|
+
a: get || set ? { get, set } : empty_get_set,
|
|
285
|
+
b: block || active_block,
|
|
286
|
+
c: 0,
|
|
287
|
+
f: TRACKED,
|
|
288
|
+
__v: v,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
279
292
|
return {
|
|
280
293
|
a: get || set ? { get, set } : empty_get_set,
|
|
281
294
|
b: block || active_block,
|
|
282
295
|
c: 0,
|
|
283
296
|
f: TRACKED,
|
|
284
|
-
v,
|
|
297
|
+
__v: v,
|
|
285
298
|
};
|
|
286
299
|
}
|
|
287
300
|
|
|
@@ -293,6 +306,21 @@ export function tracked(v, block, get, set) {
|
|
|
293
306
|
* @returns {Derived}
|
|
294
307
|
*/
|
|
295
308
|
export function derived(fn, block, get, set) {
|
|
309
|
+
if (DEV) {
|
|
310
|
+
return {
|
|
311
|
+
DO_NOT_ACCESS_THIS_OBJECT_DIRECTLY: true,
|
|
312
|
+
a: get || set ? { get, set } : empty_get_set,
|
|
313
|
+
b: block || active_block,
|
|
314
|
+
blocks: null,
|
|
315
|
+
c: 0,
|
|
316
|
+
co: active_component,
|
|
317
|
+
d: null,
|
|
318
|
+
f: TRACKED | DERIVED,
|
|
319
|
+
fn,
|
|
320
|
+
__v: UNINITIALIZED,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
296
324
|
return {
|
|
297
325
|
a: get || set ? { get, set } : empty_get_set,
|
|
298
326
|
b: block || active_block,
|
|
@@ -302,7 +330,7 @@ export function derived(fn, block, get, set) {
|
|
|
302
330
|
d: null,
|
|
303
331
|
f: TRACKED | DERIVED,
|
|
304
332
|
fn,
|
|
305
|
-
|
|
333
|
+
__v: UNINITIALIZED,
|
|
306
334
|
};
|
|
307
335
|
}
|
|
308
336
|
|
|
@@ -353,7 +381,7 @@ export function track_split(v, l, b) {
|
|
|
353
381
|
t = tracked(undefined, b);
|
|
354
382
|
exists = !!descriptors[key];
|
|
355
383
|
if (exists) {
|
|
356
|
-
t = define_property(t, '
|
|
384
|
+
t = define_property(t, '__v', descriptors[key]);
|
|
357
385
|
}
|
|
358
386
|
}
|
|
359
387
|
|
|
@@ -412,7 +440,7 @@ function is_tracking_dirty(tracking) {
|
|
|
412
440
|
var tracked = tracking.t;
|
|
413
441
|
|
|
414
442
|
if ((tracked.f & DERIVED) !== 0) {
|
|
415
|
-
update_derived(/** @type {Derived} **/
|
|
443
|
+
update_derived(/** @type {Derived} **/(tracked));
|
|
416
444
|
}
|
|
417
445
|
|
|
418
446
|
if (tracked.c > tracking.c) {
|
|
@@ -467,19 +495,19 @@ export function async_computed(fn, block) {
|
|
|
467
495
|
} else {
|
|
468
496
|
for (var i = 0; i < deferred.length; i++) {
|
|
469
497
|
var tracked = deferred[i];
|
|
470
|
-
new_values.set(tracked, { v: tracked.
|
|
498
|
+
new_values.set(tracked, { v: tracked.__v, c: tracked.c });
|
|
471
499
|
}
|
|
472
500
|
}
|
|
473
501
|
|
|
474
502
|
promise.then((v) => {
|
|
475
|
-
if (parent && is_destroyed(/** @type {Block} */
|
|
503
|
+
if (parent && is_destroyed(/** @type {Block} */(parent))) {
|
|
476
504
|
return;
|
|
477
505
|
}
|
|
478
|
-
if (promise === current && t.
|
|
506
|
+
if (promise === current && t.__v !== v) {
|
|
479
507
|
restore();
|
|
480
508
|
|
|
481
|
-
if (t.
|
|
482
|
-
t.
|
|
509
|
+
if (t.__v === UNINITIALIZED) {
|
|
510
|
+
t.__v = v;
|
|
483
511
|
} else {
|
|
484
512
|
set(t, v, block);
|
|
485
513
|
}
|
|
@@ -492,7 +520,7 @@ export function async_computed(fn, block) {
|
|
|
492
520
|
var tracked = deferred[i];
|
|
493
521
|
var stored = /** @type {{ v: any, c: number }} */ (new_values.get(tracked));
|
|
494
522
|
var { v, c } = stored;
|
|
495
|
-
tracked.
|
|
523
|
+
tracked.__v = v;
|
|
496
524
|
tracked.c = c;
|
|
497
525
|
schedule_update(tracked.b);
|
|
498
526
|
}
|
|
@@ -730,10 +758,10 @@ export function get_derived(computed) {
|
|
|
730
758
|
}
|
|
731
759
|
var get = computed.a.get;
|
|
732
760
|
if (get !== undefined) {
|
|
733
|
-
computed.
|
|
761
|
+
computed.__v = trigger_track_get(get, computed.__v);
|
|
734
762
|
}
|
|
735
763
|
|
|
736
|
-
return computed.
|
|
764
|
+
return computed.__v;
|
|
737
765
|
}
|
|
738
766
|
|
|
739
767
|
/**
|
|
@@ -746,7 +774,7 @@ export function get(tracked) {
|
|
|
746
774
|
}
|
|
747
775
|
|
|
748
776
|
return (tracked.f & DERIVED) !== 0
|
|
749
|
-
? get_derived(/** @type {Derived} */
|
|
777
|
+
? get_derived(/** @type {Derived} */(tracked))
|
|
750
778
|
: get_tracked(tracked);
|
|
751
779
|
}
|
|
752
780
|
|
|
@@ -754,7 +782,7 @@ export function get(tracked) {
|
|
|
754
782
|
* @param {Tracked} tracked
|
|
755
783
|
*/
|
|
756
784
|
export function get_tracked(tracked) {
|
|
757
|
-
var value = tracked.
|
|
785
|
+
var value = tracked.__v;
|
|
758
786
|
if (tracking) {
|
|
759
787
|
register_dependency(tracked);
|
|
760
788
|
}
|
|
@@ -790,7 +818,7 @@ export function set(tracked, value, block) {
|
|
|
790
818
|
);
|
|
791
819
|
}
|
|
792
820
|
|
|
793
|
-
var old_value = tracked.
|
|
821
|
+
var old_value = tracked.__v;
|
|
794
822
|
|
|
795
823
|
if (value !== old_value) {
|
|
796
824
|
var tracked_block = tracked.b;
|
|
@@ -808,7 +836,7 @@ export function set(tracked, value, block) {
|
|
|
808
836
|
value = untrack(() => set(value, old_value));
|
|
809
837
|
}
|
|
810
838
|
|
|
811
|
-
tracked.
|
|
839
|
+
tracked.__v = value;
|
|
812
840
|
tracked.c = increment_clock();
|
|
813
841
|
schedule_update(tracked_block);
|
|
814
842
|
}
|
|
@@ -872,7 +900,7 @@ export function flush_sync(fn) {
|
|
|
872
900
|
* @returns {Object}
|
|
873
901
|
*/
|
|
874
902
|
export function spread_props(fn, block) {
|
|
875
|
-
|
|
903
|
+
var computed = derived(fn, block);
|
|
876
904
|
|
|
877
905
|
return new Proxy(
|
|
878
906
|
{},
|
|
@@ -882,9 +910,23 @@ export function spread_props(fn, block) {
|
|
|
882
910
|
return obj[property];
|
|
883
911
|
},
|
|
884
912
|
has(target, property) {
|
|
913
|
+
if (property === TRACKED_OBJECT) {
|
|
914
|
+
return true;
|
|
915
|
+
}
|
|
885
916
|
const obj = get_derived(computed);
|
|
886
917
|
return property in obj;
|
|
887
918
|
},
|
|
919
|
+
getOwnPropertyDescriptor(target, key) {
|
|
920
|
+
const obj = get_derived(computed);
|
|
921
|
+
|
|
922
|
+
if (key in obj) {
|
|
923
|
+
return {
|
|
924
|
+
enumerable: true,
|
|
925
|
+
configurable: true,
|
|
926
|
+
value: obj[key],
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
},
|
|
888
930
|
ownKeys() {
|
|
889
931
|
const obj = get_derived(computed);
|
|
890
932
|
return Reflect.ownKeys(obj);
|
|
@@ -976,7 +1018,7 @@ export function update(tracked, block, d = 1) {
|
|
|
976
1018
|
* @returns {void}
|
|
977
1019
|
*/
|
|
978
1020
|
export function increment(tracked, block) {
|
|
979
|
-
set(tracked, tracked.
|
|
1021
|
+
set(tracked, tracked.__v + 1, block);
|
|
980
1022
|
}
|
|
981
1023
|
|
|
982
1024
|
/**
|
|
@@ -985,7 +1027,7 @@ export function increment(tracked, block) {
|
|
|
985
1027
|
* @returns {void}
|
|
986
1028
|
*/
|
|
987
1029
|
export function decrement(tracked, block) {
|
|
988
|
-
set(tracked, tracked.
|
|
1030
|
+
set(tracked, tracked.__v - 1, block);
|
|
989
1031
|
}
|
|
990
1032
|
|
|
991
1033
|
/**
|
|
@@ -1164,7 +1206,7 @@ export async function maybe_tracked(v) {
|
|
|
1164
1206
|
} else {
|
|
1165
1207
|
value = await async_computed(async () => {
|
|
1166
1208
|
return await get_tracked(v);
|
|
1167
|
-
}, /** @type {Block} */
|
|
1209
|
+
}, /** @type {Block} */(active_block));
|
|
1168
1210
|
}
|
|
1169
1211
|
} else {
|
|
1170
1212
|
value = await v;
|
|
@@ -18,14 +18,16 @@ export type Dependency = {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
export type Tracked<V = any> = {
|
|
21
|
+
DO_NOT_ACCESS_THIS_OBJECT_DIRECTLY?: true;
|
|
21
22
|
a: { get?: Function, set?: Function };
|
|
22
23
|
b: Block;
|
|
23
24
|
c: number;
|
|
24
25
|
f: number;
|
|
25
|
-
|
|
26
|
+
__v: V;
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
export type Derived = {
|
|
30
|
+
DO_NOT_ACCESS_THIS_OBJECT_DIRECTLY?: true;
|
|
29
31
|
a: { get?: Function, set?: Function };
|
|
30
32
|
b: Block;
|
|
31
33
|
blocks: null | Block[];
|
|
@@ -34,7 +36,7 @@ export type Derived = {
|
|
|
34
36
|
d: null;
|
|
35
37
|
f: number;
|
|
36
38
|
fn: Function;
|
|
37
|
-
|
|
39
|
+
__v: any;
|
|
38
40
|
};
|
|
39
41
|
|
|
40
42
|
export type Block = {
|
package/src/runtime/proxy.js
CHANGED
|
@@ -40,6 +40,7 @@ export function proxy(value, block) {
|
|
|
40
40
|
return value;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/** @type {Map<any,Tracked>} */
|
|
43
44
|
var tracked_elements = new Map();
|
|
44
45
|
var is_proxied_array = is_array(value);
|
|
45
46
|
/** @type {Tracked} */
|
|
@@ -97,8 +98,8 @@ export function proxy(value, block) {
|
|
|
97
98
|
var t = tracked_elements.get(prop);
|
|
98
99
|
var exists = prop in target;
|
|
99
100
|
|
|
100
|
-
if (is_proxied_array && prop === 'length') {
|
|
101
|
-
for (var i = value; i < t.
|
|
101
|
+
if (is_proxied_array && prop === 'length' && t !== undefined) {
|
|
102
|
+
for (var i = value; i < t.__v; i += 1) {
|
|
102
103
|
var other_t = tracked_elements.get(i + '');
|
|
103
104
|
if (other_t !== undefined) {
|
|
104
105
|
set(other_t, UNINITIALIZED, block);
|
|
@@ -124,7 +125,7 @@ export function proxy(value, block) {
|
|
|
124
125
|
tracked_elements.set(prop, t);
|
|
125
126
|
}
|
|
126
127
|
} else {
|
|
127
|
-
exists = t.
|
|
128
|
+
exists = t.__v !== UNINITIALIZED;
|
|
128
129
|
|
|
129
130
|
set(t, value, block);
|
|
130
131
|
}
|
|
@@ -143,7 +144,7 @@ export function proxy(value, block) {
|
|
|
143
144
|
// will not cause the length to be out of sync.
|
|
144
145
|
var n = Number(prop);
|
|
145
146
|
|
|
146
|
-
if (Number.isInteger(n) && n >= tracked_len.
|
|
147
|
+
if (Number.isInteger(n) && n >= tracked_len.__v) {
|
|
147
148
|
set(tracked_len, n + 1, block);
|
|
148
149
|
}
|
|
149
150
|
}
|
|
@@ -180,7 +181,7 @@ export function proxy(value, block) {
|
|
|
180
181
|
}
|
|
181
182
|
|
|
182
183
|
var t = tracked_elements.get(prop);
|
|
183
|
-
var exists = (t !== undefined && t.
|
|
184
|
+
var exists = (t !== undefined && t.__v !== UNINITIALIZED) || Reflect.has(target, prop);
|
|
184
185
|
|
|
185
186
|
if (t !== undefined || !exists || get_descriptor(target, prop)?.writable) {
|
|
186
187
|
if (t === undefined) {
|
|
@@ -229,11 +230,11 @@ export function proxy(value, block) {
|
|
|
229
230
|
ownKeys(target) {
|
|
230
231
|
var own_keys = Reflect.ownKeys(target).filter((key) => {
|
|
231
232
|
var t = tracked_elements.get(key);
|
|
232
|
-
return t === undefined || t.
|
|
233
|
+
return t === undefined || t.__v !== UNINITIALIZED;
|
|
233
234
|
});
|
|
234
235
|
|
|
235
236
|
for (var [key, t] of tracked_elements) {
|
|
236
|
-
if (t.
|
|
237
|
+
if (t.__v !== UNINITIALIZED && !(key in target)) {
|
|
237
238
|
own_keys.push(key);
|
|
238
239
|
}
|
|
239
240
|
}
|
|
@@ -249,7 +250,7 @@ export function proxy(value, block) {
|
|
|
249
250
|
if (t) descriptor.value = get(t);
|
|
250
251
|
} else if (descriptor === undefined) {
|
|
251
252
|
var t = tracked_elements.get(prop);
|
|
252
|
-
var value = t?.
|
|
253
|
+
var value = t?.__v;
|
|
253
254
|
|
|
254
255
|
if (t !== undefined && value !== UNINITIALIZED) {
|
|
255
256
|
return {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mount, flushSync } from 'ripple';
|
|
3
|
+
|
|
4
|
+
import { test } from './function-overload-import.ripple';
|
|
5
|
+
|
|
6
|
+
describe('function overload import tests', () => {
|
|
7
|
+
describe('function overloads', () => {
|
|
8
|
+
it('test function with string argument returns the string', () => {
|
|
9
|
+
const result = test('hello');
|
|
10
|
+
expect(result).toBe('hello');
|
|
11
|
+
expect(typeof result).toBe('string');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('test function with number argument returns string representation', () => {
|
|
15
|
+
const result = test(42);
|
|
16
|
+
expect(result).toBe('42');
|
|
17
|
+
expect(typeof result).toBe('string');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('test function with zero returns "0"', () => {
|
|
21
|
+
const result = test(0);
|
|
22
|
+
expect(result).toBe('0');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('test function with negative number returns string representation', () => {
|
|
26
|
+
const result = test(-100);
|
|
27
|
+
expect(result).toBe('-100');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('test function with empty string returns empty string', () => {
|
|
31
|
+
const result = test('');
|
|
32
|
+
expect(result).toBe('');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('test function with decimal number returns string representation', () => {
|
|
36
|
+
const result = test(3.14159);
|
|
37
|
+
expect(result).toBe('3.14159');
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|