ripple 0.2.104 → 0.2.106
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 +2 -1
- package/src/compiler/phases/1-parse/index.js +54 -1
- package/src/compiler/phases/2-analyze/index.js +45 -4
- package/src/compiler/phases/3-transform/client/index.js +94 -30
- package/src/compiler/types/index.d.ts +5 -0
- package/src/compiler/utils.js +1 -1
- package/src/runtime/create-subscriber.js +34 -0
- package/src/runtime/index-client.js +8 -0
- package/src/runtime/index-server.js +27 -2
- package/src/runtime/internal/client/constants.js +13 -12
- package/src/runtime/internal/client/css.js +4 -2
- package/src/runtime/internal/client/index.js +2 -0
- package/src/runtime/internal/client/runtime.js +19 -19
- package/src/runtime/internal/client/switch.js +32 -0
- package/src/runtime/media-query.js +39 -0
- package/src/runtime/reactive-value.js +21 -0
- package/src/runtime/url-search-params.js +147 -0
- package/src/runtime/url.js +164 -0
- package/src/utils/builders.js +33 -0
- package/tests/client/__snapshots__/compiler.test.ripple.snap +12 -0
- package/tests/client/__snapshots__/tracked-expression.test.ripple.snap +34 -0
- package/tests/client/basic.test.ripple +46 -1
- package/tests/client/compiler.test.ripple +131 -10
- package/tests/client/media-query.test.ripple +130 -0
- package/tests/client/tracked-expression.test.ripple +46 -0
- package/tests/client/url-search-params.test.ripple +912 -0
- package/tests/client/url.test.ripple +954 -0
- package/types/index.d.ts +41 -11
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.106",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"module": "src/runtime/index-client.js",
|
|
9
9
|
"main": "src/runtime/index-client.js",
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"@sveltejs/acorn-typescript": "^1.0.6",
|
|
68
68
|
"acorn": "^8.15.0",
|
|
69
69
|
"clsx": "^2.1.1",
|
|
70
|
+
"esm-env": "^1.2.2",
|
|
70
71
|
"esrap": "^2.1.0",
|
|
71
72
|
"is-reference": "^3.0.3",
|
|
72
73
|
"magic-string": "^0.30.18",
|
|
@@ -167,9 +167,17 @@ function RipplePlugin(config) {
|
|
|
167
167
|
|
|
168
168
|
if (code === 64) {
|
|
169
169
|
// @ character
|
|
170
|
-
// Look ahead to see if this is followed by a valid identifier character
|
|
170
|
+
// Look ahead to see if this is followed by a valid identifier character or opening paren
|
|
171
171
|
if (this.pos + 1 < this.input.length) {
|
|
172
172
|
const nextChar = this.input.charCodeAt(this.pos + 1);
|
|
173
|
+
|
|
174
|
+
// Check if this is @( for unboxing expression syntax
|
|
175
|
+
if (nextChar === 40) {
|
|
176
|
+
// ( character
|
|
177
|
+
this.pos += 2; // skip '@('
|
|
178
|
+
return this.finishToken(tt.parenL, '@(');
|
|
179
|
+
}
|
|
180
|
+
|
|
173
181
|
// Check if the next character can start an identifier
|
|
174
182
|
if (
|
|
175
183
|
(nextChar >= 65 && nextChar <= 90) || // A-Z
|
|
@@ -348,6 +356,11 @@ function RipplePlugin(config) {
|
|
|
348
356
|
* @returns {any} Parsed expression atom
|
|
349
357
|
*/
|
|
350
358
|
parseExprAtom(refDestructuringErrors, forNew, forInit) {
|
|
359
|
+
// Check if this is @(expression) for unboxing tracked values
|
|
360
|
+
if (this.type === tt.parenL && this.value === '@(') {
|
|
361
|
+
return this.parseTrackedExpression();
|
|
362
|
+
}
|
|
363
|
+
|
|
351
364
|
// Check if this is a tuple literal starting with #[
|
|
352
365
|
if (this.type === tt.bracketL && this.value === '#[') {
|
|
353
366
|
return this.parseTrackedArrayExpression();
|
|
@@ -358,6 +371,33 @@ function RipplePlugin(config) {
|
|
|
358
371
|
return super.parseExprAtom(refDestructuringErrors, forNew, forInit);
|
|
359
372
|
}
|
|
360
373
|
|
|
374
|
+
/**
|
|
375
|
+
* Parse `@(expression)` syntax for unboxing tracked values
|
|
376
|
+
* Creates a TrackedExpression node with the argument property
|
|
377
|
+
* @returns {any} TrackedExpression node
|
|
378
|
+
*/
|
|
379
|
+
parseTrackedExpression() {
|
|
380
|
+
const node = this.startNode();
|
|
381
|
+
this.next(); // consume '@(' token
|
|
382
|
+
node.argument = this.parseExpression();
|
|
383
|
+
this.expect(tt.parenR); // expect ')'
|
|
384
|
+
return this.finishNode(node, 'TrackedExpression');
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Override to allow TrackedExpression as a valid lvalue for update expressions
|
|
389
|
+
* @param {any} expr - Expression to check
|
|
390
|
+
* @param {any} bindingType - Binding type
|
|
391
|
+
* @param {any} checkClashes - Check for clashes
|
|
392
|
+
*/
|
|
393
|
+
checkLValSimple(expr, bindingType, checkClashes) {
|
|
394
|
+
// Allow TrackedExpression as a valid lvalue for ++/-- operators
|
|
395
|
+
if (expr.type === 'TrackedExpression') {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
return super.checkLValSimple(expr, bindingType, checkClashes);
|
|
399
|
+
}
|
|
400
|
+
|
|
361
401
|
parseTrackedArrayExpression() {
|
|
362
402
|
const node = this.startNode();
|
|
363
403
|
this.next(); // consume the '#['
|
|
@@ -1280,6 +1320,19 @@ function RipplePlugin(config) {
|
|
|
1280
1320
|
}
|
|
1281
1321
|
}
|
|
1282
1322
|
|
|
1323
|
+
if (this.type.label === 'jsxTagStart') {
|
|
1324
|
+
this.next();
|
|
1325
|
+
if (this.value === '/') {
|
|
1326
|
+
this.unexpected();
|
|
1327
|
+
}
|
|
1328
|
+
const node = this.parseElement();
|
|
1329
|
+
|
|
1330
|
+
if (!node) {
|
|
1331
|
+
this.unexpected();
|
|
1332
|
+
}
|
|
1333
|
+
return node;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1283
1336
|
return super.parseStatement(context, topLevel, exports);
|
|
1284
1337
|
}
|
|
1285
1338
|
|
|
@@ -34,7 +34,8 @@ function mark_control_flow_has_template(path) {
|
|
|
34
34
|
node.type === 'ForInStatement' ||
|
|
35
35
|
node.type === 'ForOfStatement' ||
|
|
36
36
|
node.type === 'TryStatement' ||
|
|
37
|
-
node.type === 'IfStatement'
|
|
37
|
+
node.type === 'IfStatement' ||
|
|
38
|
+
node.type === 'SwitchStatement'
|
|
38
39
|
) {
|
|
39
40
|
node.metadata.has_template = true;
|
|
40
41
|
}
|
|
@@ -106,7 +107,7 @@ const visitors = {
|
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
if (
|
|
109
|
-
is_reference(node, /** @type {Node} */(parent)) &&
|
|
110
|
+
is_reference(node, /** @type {Node} */ (parent)) &&
|
|
110
111
|
node.tracked &&
|
|
111
112
|
binding?.node !== node
|
|
112
113
|
) {
|
|
@@ -117,7 +118,7 @@ const visitors = {
|
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
if (
|
|
120
|
-
is_reference(node, /** @type {Node} */(parent)) &&
|
|
121
|
+
is_reference(node, /** @type {Node} */ (parent)) &&
|
|
121
122
|
node.tracked &&
|
|
122
123
|
binding?.node !== node
|
|
123
124
|
) {
|
|
@@ -253,7 +254,12 @@ const visitors = {
|
|
|
253
254
|
// Track metadata for this component
|
|
254
255
|
const metadata = { await: false };
|
|
255
256
|
|
|
256
|
-
context.next({
|
|
257
|
+
context.next({
|
|
258
|
+
...context.state,
|
|
259
|
+
elements,
|
|
260
|
+
function_depth: context.state.function_depth + 1,
|
|
261
|
+
metadata,
|
|
262
|
+
});
|
|
257
263
|
|
|
258
264
|
const css = node.css;
|
|
259
265
|
|
|
@@ -282,6 +288,41 @@ const visitors = {
|
|
|
282
288
|
context.next();
|
|
283
289
|
},
|
|
284
290
|
|
|
291
|
+
SwitchStatement(node, context) {
|
|
292
|
+
if (!is_inside_component(context)) {
|
|
293
|
+
return context.next();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
context.visit(node.discriminant, context.state);
|
|
297
|
+
|
|
298
|
+
for (const switch_case of node.cases) {
|
|
299
|
+
// Validate that each cases ends in a break statement, except for the last case
|
|
300
|
+
const last = switch_case.consequent?.[switch_case.consequent.length - 1];
|
|
301
|
+
|
|
302
|
+
if (last.type !== 'BreakStatement' && node.cases.indexOf(switch_case) !== node.cases.length - 1) {
|
|
303
|
+
error(
|
|
304
|
+
'Template switch cases must end with a break statement (with the exception of the last case).',
|
|
305
|
+
context.state.analysis.module.filename,
|
|
306
|
+
switch_case,
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
node.metadata = {
|
|
311
|
+
has_template: false,
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
context.visit(switch_case, context.state);
|
|
315
|
+
|
|
316
|
+
if (!node.metadata.has_template) {
|
|
317
|
+
error(
|
|
318
|
+
'Component switch statements must contain a template in each of their cases. Move the switch statement into an effect if it does not render anything.',
|
|
319
|
+
context.state.analysis.module.filename,
|
|
320
|
+
node,
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
|
|
285
326
|
ForOfStatement(node, context) {
|
|
286
327
|
if (!is_inside_component(context)) {
|
|
287
328
|
return context.next();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @import {Expression, FunctionExpression, Pattern} from 'estree' */
|
|
1
|
+
/** @import {Expression, FunctionExpression, Pattern, Node, Program} from 'estree' */
|
|
2
2
|
|
|
3
3
|
import { walk } from 'zimmerframe';
|
|
4
4
|
import path from 'node:path';
|
|
@@ -72,7 +72,7 @@ function visit_function(node, context) {
|
|
|
72
72
|
let body = context.visit(node.body, {
|
|
73
73
|
...state,
|
|
74
74
|
// we are new context so tracking no longer applies
|
|
75
|
-
metadata: { ...state.metadata,
|
|
75
|
+
metadata: { ...state.metadata, tracking: false },
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
if (metadata?.tracked === true) {
|
|
@@ -159,9 +159,11 @@ const visitors = {
|
|
|
159
159
|
}
|
|
160
160
|
} else {
|
|
161
161
|
const binding = context.state.scope.get(node.name);
|
|
162
|
+
const isRightSideOfAssignment = parent.type === 'AssignmentExpression' && parent.right === node;
|
|
162
163
|
if (
|
|
163
164
|
(context.state.metadata?.tracking === false ||
|
|
164
|
-
(parent.type !== 'AssignmentExpression' && parent.type !== 'UpdateExpression')
|
|
165
|
+
(parent.type !== 'AssignmentExpression' && parent.type !== 'UpdateExpression') ||
|
|
166
|
+
isRightSideOfAssignment) &&
|
|
165
167
|
(node.tracked ||
|
|
166
168
|
binding?.kind === 'prop' ||
|
|
167
169
|
binding?.kind === 'index' ||
|
|
@@ -175,10 +177,10 @@ const visitors = {
|
|
|
175
177
|
add_ripple_internal_import(context);
|
|
176
178
|
return b.call('_$_.get', build_getter(node, context));
|
|
177
179
|
}
|
|
178
|
-
}
|
|
179
180
|
|
|
180
|
-
|
|
181
|
-
|
|
181
|
+
add_ripple_internal_import(context);
|
|
182
|
+
return build_getter(node, context);
|
|
183
|
+
}
|
|
182
184
|
}
|
|
183
185
|
}
|
|
184
186
|
},
|
|
@@ -362,6 +364,10 @@ const visitors = {
|
|
|
362
364
|
);
|
|
363
365
|
},
|
|
364
366
|
|
|
367
|
+
TrackedExpression(node, context) {
|
|
368
|
+
return b.call('_$_.get', context.visit(node.argument));
|
|
369
|
+
},
|
|
370
|
+
|
|
365
371
|
MemberExpression(node, context) {
|
|
366
372
|
const parent = context.path.at(-1);
|
|
367
373
|
|
|
@@ -463,10 +469,9 @@ const visitors = {
|
|
|
463
469
|
|
|
464
470
|
const handle_static_attr = (name, value) => {
|
|
465
471
|
const attr_value = b.literal(
|
|
466
|
-
` ${name}${
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
: `="${value === true ? '' : escape_html(value, true)}"`
|
|
472
|
+
` ${name}${is_boolean_attribute(name) && value === true
|
|
473
|
+
? ''
|
|
474
|
+
: `="${value === true ? '' : escape_html(value, true)}"`
|
|
470
475
|
}`,
|
|
471
476
|
);
|
|
472
477
|
|
|
@@ -938,10 +943,10 @@ const visitors = {
|
|
|
938
943
|
operator === '='
|
|
939
944
|
? context.visit(right)
|
|
940
945
|
: b.binary(
|
|
941
|
-
|
|
942
|
-
/** @type {Pattern} */
|
|
943
|
-
/** @type {Expression} */
|
|
944
|
-
|
|
946
|
+
operator === '+=' ? '+' : operator === '-=' ? '-' : operator === '*=' ? '*' : '/',
|
|
947
|
+
/** @type {Pattern} */(context.visit(left)),
|
|
948
|
+
/** @type {Expression} */(context.visit(right)),
|
|
949
|
+
),
|
|
945
950
|
b.id('__block'),
|
|
946
951
|
);
|
|
947
952
|
}
|
|
@@ -957,12 +962,12 @@ const visitors = {
|
|
|
957
962
|
operator === '='
|
|
958
963
|
? context.visit(right)
|
|
959
964
|
: b.binary(
|
|
960
|
-
|
|
961
|
-
/** @type {Pattern} */
|
|
962
|
-
|
|
963
|
-
),
|
|
964
|
-
/** @type {Expression} */ (context.visit(right)),
|
|
965
|
+
operator === '+=' ? '+' : operator === '-=' ? '-' : operator === '*=' ? '*' : '/',
|
|
966
|
+
/** @type {Pattern} */(
|
|
967
|
+
context.visit(left, { ...context.state, metadata: { tracking: false } })
|
|
965
968
|
),
|
|
969
|
+
/** @type {Expression} */(context.visit(right)),
|
|
970
|
+
),
|
|
966
971
|
b.id('__block'),
|
|
967
972
|
);
|
|
968
973
|
}
|
|
@@ -1001,6 +1006,15 @@ const visitors = {
|
|
|
1001
1006
|
);
|
|
1002
1007
|
}
|
|
1003
1008
|
|
|
1009
|
+
if (argument.type === 'TrackedExpression') {
|
|
1010
|
+
return b.call(
|
|
1011
|
+
node.prefix ? '_$_.update_pre' : '_$_.update',
|
|
1012
|
+
context.visit(argument.argument, { ...context.state, metadata: { tracking: null } }),
|
|
1013
|
+
b.id('__block'),
|
|
1014
|
+
node.operator === '--' ? b.literal(-1) : undefined,
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1004
1018
|
const left = object(argument);
|
|
1005
1019
|
const binding = context.state.scope.get(left.name);
|
|
1006
1020
|
const transformers = left && binding?.transform;
|
|
@@ -1061,6 +1075,52 @@ const visitors = {
|
|
|
1061
1075
|
);
|
|
1062
1076
|
},
|
|
1063
1077
|
|
|
1078
|
+
SwitchStatement(node, context) {
|
|
1079
|
+
if (!is_inside_component(context)) {
|
|
1080
|
+
return context.next();
|
|
1081
|
+
}
|
|
1082
|
+
context.state.template.push('<!>');
|
|
1083
|
+
|
|
1084
|
+
const id = context.state.flush_node();
|
|
1085
|
+
const statements = [];
|
|
1086
|
+
const cases = [];
|
|
1087
|
+
|
|
1088
|
+
let i = 1;
|
|
1089
|
+
|
|
1090
|
+
for (const switch_case of node.cases) {
|
|
1091
|
+
const consequent_scope =
|
|
1092
|
+
context.state.scopes.get(switch_case.consequent) || context.state.scope;
|
|
1093
|
+
const consequent_id = context.state.scope.generate('switch_case_' + (switch_case.test == null ? 'default' : i));
|
|
1094
|
+
const consequent = b.block(
|
|
1095
|
+
transform_body(switch_case.consequent, {
|
|
1096
|
+
...context,
|
|
1097
|
+
state: { ...context.state, scope: consequent_scope },
|
|
1098
|
+
}),
|
|
1099
|
+
);
|
|
1100
|
+
|
|
1101
|
+
statements.push(b.var(b.id(consequent_id), b.arrow([b.id('__anchor')], consequent)));
|
|
1102
|
+
|
|
1103
|
+
cases.push(
|
|
1104
|
+
b.switch_case(switch_case.test ? context.visit(switch_case.test) : null, [
|
|
1105
|
+
b.return(b.id(consequent_id)),
|
|
1106
|
+
]),
|
|
1107
|
+
);
|
|
1108
|
+
i++;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
statements.push(
|
|
1112
|
+
b.stmt(
|
|
1113
|
+
b.call(
|
|
1114
|
+
'_$_.switch',
|
|
1115
|
+
id,
|
|
1116
|
+
b.thunk(b.block([b.switch(context.visit(node.discriminant), cases)])),
|
|
1117
|
+
),
|
|
1118
|
+
),
|
|
1119
|
+
);
|
|
1120
|
+
|
|
1121
|
+
context.state.init.push(b.block(statements));
|
|
1122
|
+
},
|
|
1123
|
+
|
|
1064
1124
|
IfStatement(node, context) {
|
|
1065
1125
|
if (!is_inside_component(context)) {
|
|
1066
1126
|
return context.next();
|
|
@@ -1112,12 +1172,12 @@ const visitors = {
|
|
|
1112
1172
|
b.stmt(b.call(b.id('__render'), b.id(consequent_id))),
|
|
1113
1173
|
alternate_id
|
|
1114
1174
|
? b.stmt(
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1175
|
+
b.call(
|
|
1176
|
+
b.id('__render'),
|
|
1177
|
+
b.id(alternate_id),
|
|
1178
|
+
node.alternate ? b.literal(false) : undefined,
|
|
1179
|
+
),
|
|
1180
|
+
)
|
|
1121
1181
|
: undefined,
|
|
1122
1182
|
),
|
|
1123
1183
|
]),
|
|
@@ -1170,9 +1230,9 @@ const visitors = {
|
|
|
1170
1230
|
node.handler === null
|
|
1171
1231
|
? b.literal(null)
|
|
1172
1232
|
: b.arrow(
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1233
|
+
[b.id('__anchor'), ...(node.handler.param ? [node.handler.param] : [])],
|
|
1234
|
+
b.block(transform_body(node.handler.body.body, context)),
|
|
1235
|
+
),
|
|
1176
1236
|
node.pending === null
|
|
1177
1237
|
? undefined
|
|
1178
1238
|
: b.arrow([b.id('__anchor')], b.block(transform_body(node.pending.body, context))),
|
|
@@ -1268,7 +1328,7 @@ function join_template(items) {
|
|
|
1268
1328
|
}
|
|
1269
1329
|
|
|
1270
1330
|
for (const quasi of template.quasis) {
|
|
1271
|
-
quasi.value.raw = sanitize_template_string(/** @type {string} */
|
|
1331
|
+
quasi.value.raw = sanitize_template_string(/** @type {string} */(quasi.value.cooked));
|
|
1272
1332
|
}
|
|
1273
1333
|
|
|
1274
1334
|
quasi.tail = true;
|
|
@@ -1469,6 +1529,7 @@ function transform_children(children, context) {
|
|
|
1469
1529
|
node.type === 'IfStatement' ||
|
|
1470
1530
|
node.type === 'TryStatement' ||
|
|
1471
1531
|
node.type === 'ForOfStatement' ||
|
|
1532
|
+
node.type === 'SwitchStatement' ||
|
|
1472
1533
|
node.type === 'Html' ||
|
|
1473
1534
|
(node.type === 'Element' &&
|
|
1474
1535
|
(node.id.type !== 'Identifier' || !is_element_dom_element(node))),
|
|
@@ -1620,6 +1681,9 @@ function transform_children(children, context) {
|
|
|
1620
1681
|
} else if (node.type === 'TryStatement') {
|
|
1621
1682
|
node.is_controlled = is_controlled;
|
|
1622
1683
|
visit(node, { ...state, flush_node, namespace: state.namespace });
|
|
1684
|
+
} else if (node.type === 'SwitchStatement') {
|
|
1685
|
+
node.is_controlled = is_controlled;
|
|
1686
|
+
visit(node, { ...state, flush_node, namespace: state.namespace });
|
|
1623
1687
|
} else {
|
|
1624
1688
|
debugger;
|
|
1625
1689
|
}
|
|
@@ -1701,7 +1765,7 @@ export function transform_client(filename, source, analysis, to_ts) {
|
|
|
1701
1765
|
to_ts,
|
|
1702
1766
|
};
|
|
1703
1767
|
|
|
1704
|
-
const program = /** @type {
|
|
1768
|
+
const program = /** @type {Program} */ (
|
|
1705
1769
|
walk(analysis.ast, { ...state, namespace: 'html' }, visitors)
|
|
1706
1770
|
);
|
|
1707
1771
|
|
|
@@ -65,6 +65,11 @@ export interface TrackedArrayExpression extends Omit<ArrayExpression, 'type'> {
|
|
|
65
65
|
elements: (Expression | null)[];
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
export interface TrackedExpression extends Omit<Expression, 'type'> {
|
|
69
|
+
argument: Expression;
|
|
70
|
+
type: 'TrackedExpression';
|
|
71
|
+
}
|
|
72
|
+
|
|
68
73
|
/**
|
|
69
74
|
* Tracked object expression node
|
|
70
75
|
*/
|
package/src/compiler/utils.js
CHANGED
|
@@ -808,7 +808,7 @@ export function normalize_children(children, context) {
|
|
|
808
808
|
* @param {TransformContext} context
|
|
809
809
|
*/
|
|
810
810
|
function normalize_child(node, normalized, context) {
|
|
811
|
-
if (node.type === 'EmptyStatement') {
|
|
811
|
+
if (node.type === 'EmptyStatement' || node.type === 'BreakStatement') {
|
|
812
812
|
return;
|
|
813
813
|
} else if (
|
|
814
814
|
node.type === 'Element' &&
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** @import { createSubscriber } from '#public' */
|
|
2
|
+
import { untrack, queue_microtask } from './internal/client/runtime.js';
|
|
3
|
+
import { effect } from './internal/client/blocks.js'
|
|
4
|
+
|
|
5
|
+
/** @type {createSubscriber} */
|
|
6
|
+
export function createSubscriber(start) {
|
|
7
|
+
let subscribers = 0;
|
|
8
|
+
/** @type {(() => void) | void} */
|
|
9
|
+
let stop;
|
|
10
|
+
|
|
11
|
+
return () => {
|
|
12
|
+
effect(() => {
|
|
13
|
+
if (subscribers === 0) {
|
|
14
|
+
stop = untrack(start);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
subscribers += 1;
|
|
18
|
+
|
|
19
|
+
return () => {
|
|
20
|
+
queue_microtask(() => {
|
|
21
|
+
// Only count down after a microtask, else we would reach 0 before our own render effect reruns,
|
|
22
|
+
// but reach 1 again when the tick callback of the prior teardown runs. That would mean we
|
|
23
|
+
// re-subcribe unnecessarily and create a memory leak because the old subscription is never cleaned up.
|
|
24
|
+
subscribers -= 1;
|
|
25
|
+
|
|
26
|
+
if (subscribers === 0) {
|
|
27
|
+
stop?.();
|
|
28
|
+
stop = undefined;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -62,6 +62,14 @@ export { TrackedMap } from './map.js';
|
|
|
62
62
|
|
|
63
63
|
export { TrackedDate } from './date.js';
|
|
64
64
|
|
|
65
|
+
export { TrackedURL } from './url.js';
|
|
66
|
+
|
|
67
|
+
export { TrackedURLSearchParams } from './url-search-params.js';
|
|
68
|
+
|
|
69
|
+
export { createSubscriber } from './create-subscriber.js';
|
|
70
|
+
|
|
71
|
+
export { MediaQuery } from './media-query.js';
|
|
72
|
+
|
|
65
73
|
export { user_effect as effect } from './internal/client/blocks.js';
|
|
66
74
|
|
|
67
75
|
export { Portal } from './internal/client/portal.js';
|
|
@@ -10,8 +10,6 @@ export function effect() {
|
|
|
10
10
|
// NO-OP
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export const TrackedArray = Array;
|
|
14
|
-
|
|
15
13
|
var empty_get_set = { get: undefined, set: undefined };
|
|
16
14
|
|
|
17
15
|
/**
|
|
@@ -44,3 +42,30 @@ export function track(v, get, set) {
|
|
|
44
42
|
v,
|
|
45
43
|
};
|
|
46
44
|
}
|
|
45
|
+
|
|
46
|
+
export const TrackedObject = globalThis.Object;
|
|
47
|
+
export const TrackedArray = globalThis.Array;
|
|
48
|
+
export const TrackedDate = globalThis.Date;
|
|
49
|
+
export const TrackedSet = globalThis.Set;
|
|
50
|
+
export const TrackedMap = globalThis.Map;
|
|
51
|
+
export const TrackedURL = globalThis.URL;
|
|
52
|
+
export const TrackedURLSearchParams = globalThis.URLSearchParams;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {string} query A media query string
|
|
56
|
+
* @param {boolean} [matches] Fallback value for the server
|
|
57
|
+
*/
|
|
58
|
+
export function MediaQuery(query, matches = false) {
|
|
59
|
+
if (!new.target) {
|
|
60
|
+
throw new TypeError('MediaQuery must be called with new');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return matches;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {any} _
|
|
68
|
+
*/
|
|
69
|
+
export function createSubscriber(_) {
|
|
70
|
+
return () => { /* NO-OP */ };
|
|
71
|
+
}
|
|
@@ -5,19 +5,20 @@ export var BRANCH_BLOCK = 1 << 4;
|
|
|
5
5
|
export var FOR_BLOCK = 1 << 5;
|
|
6
6
|
export var TRY_BLOCK = 1 << 6;
|
|
7
7
|
export var IF_BLOCK = 1 << 7;
|
|
8
|
-
export var
|
|
9
|
-
export var
|
|
10
|
-
export var
|
|
11
|
-
export var
|
|
12
|
-
export var
|
|
13
|
-
export var
|
|
14
|
-
export var
|
|
15
|
-
export var
|
|
16
|
-
export var
|
|
17
|
-
export var
|
|
18
|
-
export var
|
|
8
|
+
export var SWITCH_BLOCK = 1 << 8;
|
|
9
|
+
export var COMPOSITE_BLOCK = 1 << 9;
|
|
10
|
+
export var ASYNC_BLOCK = 1 << 10;
|
|
11
|
+
export var HEAD_BLOCK = 1 << 11;
|
|
12
|
+
export var CONTAINS_UPDATE = 1 << 12;
|
|
13
|
+
export var CONTAINS_TEARDOWN = 1 << 13;
|
|
14
|
+
export var BLOCK_HAS_RUN = 1 << 14;
|
|
15
|
+
export var TRACKED = 1 << 15;
|
|
16
|
+
export var DERIVED = 1 << 16;
|
|
17
|
+
export var DEFERRED = 1 << 17;
|
|
18
|
+
export var PAUSED = 1 << 18;
|
|
19
|
+
export var DESTROYED = 1 << 19;
|
|
19
20
|
|
|
20
|
-
export var CONTROL_FLOW_BLOCK = FOR_BLOCK | IF_BLOCK | TRY_BLOCK | COMPOSITE_BLOCK;
|
|
21
|
+
export var CONTROL_FLOW_BLOCK = FOR_BLOCK | IF_BLOCK | SWITCH_BLOCK | TRY_BLOCK | COMPOSITE_BLOCK;
|
|
21
22
|
|
|
22
23
|
export var UNINITIALIZED = Symbol();
|
|
23
24
|
/** @type {unique symbol} */
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { DEV } from 'esm-env';
|
|
2
|
+
|
|
1
3
|
export function remove_ssr_css() {
|
|
2
4
|
if (!document || typeof requestAnimationFrame !== "function") {
|
|
3
5
|
return;
|
|
@@ -7,14 +9,14 @@ export function remove_ssr_css() {
|
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
function remove_styles() {
|
|
10
|
-
if (
|
|
12
|
+
if (DEV) {
|
|
11
13
|
const styles = document.querySelector('style[data-vite-dev-id]');
|
|
12
14
|
if (styles) {
|
|
13
15
|
remove();
|
|
14
16
|
} else {
|
|
15
17
|
requestAnimationFrame(remove_styles);
|
|
16
18
|
}
|
|
17
|
-
} else
|
|
19
|
+
} else {
|
|
18
20
|
remove_when_css_loaded(() => requestAnimationFrame(remove));
|
|
19
21
|
}
|
|
20
22
|
}
|
|
@@ -57,6 +57,8 @@ export { if_block as if } from './if.js';
|
|
|
57
57
|
|
|
58
58
|
export { try_block as try, aborted } from './try.js';
|
|
59
59
|
|
|
60
|
+
export { switch_block as switch } from './switch.js';
|
|
61
|
+
|
|
60
62
|
export { template, append } from './template.js';
|
|
61
63
|
|
|
62
64
|
export { tracked_array } from '../../array.js';
|
|
@@ -172,7 +172,7 @@ function run_derived(computed) {
|
|
|
172
172
|
var previous_tracking = tracking;
|
|
173
173
|
var previous_dependency = active_dependency;
|
|
174
174
|
var previous_component = active_component;
|
|
175
|
-
|
|
175
|
+
var previous_is_mutating_allowed = is_mutating_allowed;
|
|
176
176
|
|
|
177
177
|
try {
|
|
178
178
|
active_block = computed.b;
|
|
@@ -180,7 +180,7 @@ function run_derived(computed) {
|
|
|
180
180
|
tracking = true;
|
|
181
181
|
active_dependency = null;
|
|
182
182
|
active_component = computed.co;
|
|
183
|
-
|
|
183
|
+
is_mutating_allowed = false;
|
|
184
184
|
|
|
185
185
|
destroy_computed_children(computed);
|
|
186
186
|
|
|
@@ -195,7 +195,7 @@ function run_derived(computed) {
|
|
|
195
195
|
tracking = previous_tracking;
|
|
196
196
|
active_dependency = previous_dependency;
|
|
197
197
|
active_component = previous_component;
|
|
198
|
-
|
|
198
|
+
is_mutating_allowed = previous_is_mutating_allowed;
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
|
|
@@ -270,8 +270,8 @@ var empty_get_set = { get: undefined, set: undefined };
|
|
|
270
270
|
*
|
|
271
271
|
* @param {any} v
|
|
272
272
|
* @param {Block} b
|
|
273
|
-
* @param {
|
|
274
|
-
* @param {
|
|
273
|
+
* @param {(value: any) => any} [get]
|
|
274
|
+
* @param {(next: any, prev: any) => any} [set]
|
|
275
275
|
* @returns {Tracked}
|
|
276
276
|
*/
|
|
277
277
|
export function tracked(v, b, get, set) {
|
|
@@ -288,8 +288,8 @@ export function tracked(v, b, get, set) {
|
|
|
288
288
|
/**
|
|
289
289
|
* @param {any} fn
|
|
290
290
|
* @param {any} block
|
|
291
|
-
* @param {
|
|
292
|
-
* @param {
|
|
291
|
+
* @param {(value: any) => any} [get]
|
|
292
|
+
* @param {(next: any, prev: any) => any} [set]
|
|
293
293
|
* @returns {Derived}
|
|
294
294
|
*/
|
|
295
295
|
export function derived(fn, block, get, set) {
|
|
@@ -510,17 +510,17 @@ export function async_computed(fn, block) {
|
|
|
510
510
|
|
|
511
511
|
/**
|
|
512
512
|
* @template V
|
|
513
|
-
* @param {Function} fn
|
|
514
|
-
* @param {V} v
|
|
513
|
+
* @param {Function} fn
|
|
514
|
+
* @param {V} v
|
|
515
515
|
*/
|
|
516
516
|
function trigger_track_get(fn, v) {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
517
|
+
var previous_is_mutating_allowed = is_mutating_allowed;
|
|
518
|
+
try {
|
|
519
|
+
is_mutating_allowed = false;
|
|
520
|
+
return untrack(() => fn(v));
|
|
521
|
+
} finally {
|
|
522
|
+
is_mutating_allowed = previous_is_mutating_allowed;
|
|
523
|
+
}
|
|
524
524
|
}
|
|
525
525
|
|
|
526
526
|
/**
|
|
@@ -774,9 +774,9 @@ export function get_tracked(tracked) {
|
|
|
774
774
|
* @param {Block} block
|
|
775
775
|
*/
|
|
776
776
|
export function set(tracked, value, block) {
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
777
|
+
if (!is_mutating_allowed) {
|
|
778
|
+
throw new Error('Assignments or updates to tracked values are not allowed during computed "track(() => ...)" evaluation');
|
|
779
|
+
}
|
|
780
780
|
|
|
781
781
|
var old_value = tracked.v;
|
|
782
782
|
|