ripple 0.2.208 → 0.2.210
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/CHANGELOG.md +43 -0
- package/README.md +2 -1
- package/package.json +2 -6
- package/shims/rollup-estree-types.d.ts +1 -1
- package/src/compiler/index.d.ts +1 -0
- package/src/compiler/index.js +7 -1
- package/src/compiler/phases/1-parse/index.js +15 -6
- package/src/compiler/phases/2-analyze/css-analyze.js +100 -104
- package/src/compiler/phases/2-analyze/index.js +215 -2
- package/src/compiler/phases/3-transform/client/index.js +388 -50
- package/src/compiler/phases/3-transform/segments.js +123 -39
- package/src/compiler/phases/3-transform/server/index.js +266 -13
- package/src/compiler/types/index.d.ts +16 -3
- package/src/compiler/utils.js +1 -15
- package/src/constants.js +0 -2
- package/src/helpers.d.ts +4 -0
- package/src/html-tree-validation.js +211 -0
- package/src/jsx-runtime.d.ts +260 -259
- package/src/jsx-runtime.js +12 -12
- package/src/runtime/array.js +17 -17
- package/src/runtime/create-subscriber.js +1 -1
- package/src/runtime/index-client.js +1 -5
- package/src/runtime/index-server.js +15 -0
- package/src/runtime/internal/client/compat.js +3 -3
- package/src/runtime/internal/client/composite.js +6 -1
- package/src/runtime/internal/client/head.js +50 -4
- package/src/runtime/internal/client/html.js +73 -12
- package/src/runtime/internal/client/hydration.js +12 -0
- package/src/runtime/internal/client/index.js +1 -1
- package/src/runtime/internal/client/portal.js +54 -29
- package/src/runtime/internal/client/rpc.js +3 -1
- package/src/runtime/internal/client/switch.js +5 -0
- package/src/runtime/internal/client/template.js +117 -11
- package/src/runtime/internal/client/try.js +1 -0
- package/src/runtime/internal/server/index.js +113 -1
- package/src/runtime/internal/server/rpc.js +4 -4
- package/src/runtime/map.js +2 -2
- package/src/runtime/object.js +6 -6
- package/src/runtime/proxy.js +12 -11
- package/src/runtime/reactive-value.js +9 -1
- package/src/runtime/set.js +12 -7
- package/src/runtime/url-search-params.js +0 -1
- package/src/server/index.js +4 -0
- package/src/utils/hashing.js +15 -0
- package/src/utils/normalize_css_property_name.js +1 -1
- package/tests/client/array/array.mutations.test.ripple +8 -8
- package/tests/client/basic/basic.errors.test.ripple +28 -0
- package/tests/client/basic/basic.events.test.ripple +6 -3
- package/tests/client/basic/basic.utilities.test.ripple +1 -1
- package/tests/client/compiler/compiler.regex.test.ripple +10 -8
- package/tests/client/composite/composite.generics.test.ripple +5 -2
- package/tests/client/dynamic-elements.test.ripple +30 -1
- package/tests/client/function-overload-import.ripple +6 -7
- package/tests/client/html.test.ripple +0 -1
- package/tests/client/object.test.ripple +2 -2
- package/tests/client/portal.test.ripple +3 -3
- package/tests/client/return.test.ripple +2500 -0
- package/tests/client/try.test.ripple +69 -0
- package/tests/client/typescript-generics.test.ripple +1 -1
- package/tests/client/url/url.derived.test.ripple +1 -1
- package/tests/client/url/url.parsing.test.ripple +3 -3
- package/tests/client/url/url.partial-removal.test.ripple +7 -7
- package/tests/client/url/url.reactivity.test.ripple +15 -15
- package/tests/client/url/url.serialization.test.ripple +2 -2
- package/tests/hydration/basic.test.js +23 -0
- package/tests/hydration/build-components.js +10 -4
- package/tests/hydration/compiled/client/basic.js +165 -3
- package/tests/hydration/compiled/client/for.js +1140 -23
- package/tests/hydration/compiled/client/head.js +234 -0
- package/tests/hydration/compiled/client/html.js +135 -0
- package/tests/hydration/compiled/client/portal.js +172 -0
- package/tests/hydration/compiled/client/reactivity.js +3 -1
- package/tests/hydration/compiled/client/return.js +1976 -0
- package/tests/hydration/compiled/client/switch.js +162 -0
- package/tests/hydration/compiled/server/basic.js +249 -0
- package/tests/hydration/compiled/server/events.js +1 -1
- package/tests/hydration/compiled/server/for.js +891 -1
- package/tests/hydration/compiled/server/head.js +291 -0
- package/tests/hydration/compiled/server/html.js +133 -0
- package/tests/hydration/compiled/server/if.js +1 -1
- package/tests/hydration/compiled/server/portal.js +250 -0
- package/tests/hydration/compiled/server/reactivity.js +1 -1
- package/tests/hydration/compiled/server/return.js +1969 -0
- package/tests/hydration/compiled/server/switch.js +130 -0
- package/tests/hydration/components/basic.ripple +55 -0
- package/tests/hydration/components/for.ripple +403 -0
- package/tests/hydration/components/head.ripple +111 -0
- package/tests/hydration/components/html.ripple +38 -0
- package/tests/hydration/components/portal.ripple +49 -0
- package/tests/hydration/components/return.ripple +564 -0
- package/tests/hydration/components/switch.ripple +51 -0
- package/tests/hydration/for.test.js +363 -0
- package/tests/hydration/head.test.js +105 -0
- package/tests/hydration/html.test.js +46 -0
- package/tests/hydration/portal.test.js +71 -0
- package/tests/hydration/return.test.js +544 -0
- package/tests/hydration/switch.test.js +42 -0
- package/tests/server/basic.attributes.test.ripple +1 -1
- package/tests/server/compiler.test.ripple +22 -0
- package/tests/server/composite.test.ripple +5 -2
- package/tests/server/html-nesting-validation.test.ripple +237 -0
- package/tests/server/return.test.ripple +1379 -0
- package/tests/setup-hydration.js +6 -1
- package/tests/utils/escaping.test.js +3 -1
- package/tests/utils/normalize_css_property_name.test.js +0 -1
- package/tests/utils/patterns.test.js +6 -2
- package/tests/utils/sanitize_template_string.test.js +3 -2
- package/types/server.d.ts +16 -0
|
@@ -5,9 +5,11 @@ import {
|
|
|
5
5
|
TEMPLATE_USE_IMPORT_NODE,
|
|
6
6
|
TEMPLATE_SVG_NAMESPACE,
|
|
7
7
|
TEMPLATE_MATHML_NAMESPACE,
|
|
8
|
+
HYDRATION_START,
|
|
9
|
+
HYDRATION_END,
|
|
8
10
|
} from '../../../constants.js';
|
|
9
11
|
import { hydrate_next, hydrate_node, hydrating, pop } from './hydration.js';
|
|
10
|
-
import { create_text, get_first_child, is_firefox } from './operations.js';
|
|
12
|
+
import { create_text, get_first_child, get_next_sibling, is_firefox } from './operations.js';
|
|
11
13
|
import { active_block, active_namespace } from './runtime.js';
|
|
12
14
|
|
|
13
15
|
/**
|
|
@@ -68,30 +70,103 @@ export function template(content, flags) {
|
|
|
68
70
|
var is_comment = content === '<!>';
|
|
69
71
|
var has_start = !is_comment && !content.startsWith('<!>');
|
|
70
72
|
|
|
73
|
+
// For fragments, eagerly create the node so we can walk its children
|
|
74
|
+
// during hydration to find the correct end node. The eagerly-created
|
|
75
|
+
// node is reused as the clone template in the non-hydrating path.
|
|
76
|
+
if (is_fragment) {
|
|
77
|
+
node = create_fragment_from_html(
|
|
78
|
+
has_start ? content : '<!>' + content,
|
|
79
|
+
use_svg_namespace,
|
|
80
|
+
use_mathml_namespace,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
71
84
|
return () => {
|
|
72
85
|
if (hydrating) {
|
|
73
|
-
|
|
86
|
+
if (is_fragment) {
|
|
87
|
+
// Walk the template fragment's children in lockstep with hydrated
|
|
88
|
+
// DOM siblings. Comment nodes (<!>) are control flow anchors whose
|
|
89
|
+
// hydration markers (<!--[-->...<!--]-->) are consumed by block
|
|
90
|
+
// processing, so we skip them and only advance for element/text nodes.
|
|
91
|
+
var start = /** @type {Node} */ (hydrate_node);
|
|
92
|
+
var end = start;
|
|
93
|
+
var children = /** @type {DocumentFragment} */ (node).childNodes;
|
|
94
|
+
var is_first = true;
|
|
95
|
+
|
|
96
|
+
for (var i = 0; i < children.length; i++) {
|
|
97
|
+
if (children[i].nodeType === 8) continue;
|
|
98
|
+
|
|
99
|
+
if (is_first) {
|
|
100
|
+
is_first = false;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Advance past comment nodes in the hydrated DOM. Each <!>
|
|
105
|
+
// anchor in the template expands to a <!--[-->...<!--]-->
|
|
106
|
+
// region, and there may be consecutive ones. Track depth so
|
|
107
|
+
// nested blocks are skipped, and stop at the first non-comment
|
|
108
|
+
// node at depth 0.
|
|
109
|
+
var next = get_next_sibling(end);
|
|
110
|
+
var depth = 0;
|
|
111
|
+
|
|
112
|
+
while (next !== null) {
|
|
113
|
+
if (next.nodeType === 8) {
|
|
114
|
+
var data = /** @type {Comment} */ (next).data;
|
|
115
|
+
if (data === HYDRATION_START) {
|
|
116
|
+
depth++;
|
|
117
|
+
} else if (data === HYDRATION_END) {
|
|
118
|
+
if (depth > 0) {
|
|
119
|
+
depth--;
|
|
120
|
+
} else {
|
|
121
|
+
// Reached a close marker that belongs to a parent block
|
|
122
|
+
next = null;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
next = get_next_sibling(next);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (depth === 0) {
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
next = get_next_sibling(next);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (next === null) {
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
end = next;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
assign_nodes(start, end);
|
|
143
|
+
return start;
|
|
144
|
+
} else {
|
|
145
|
+
assign_nodes(/** @type {Node} */ (hydrate_node), /** @type {Node} */ (hydrate_node));
|
|
146
|
+
}
|
|
74
147
|
return /** @type {Node} */ (hydrate_node);
|
|
75
148
|
}
|
|
76
149
|
// If using runtime namespace, check active_namespace
|
|
77
150
|
var svg = !is_comment && (use_svg_namespace || active_namespace === 'svg');
|
|
78
151
|
var mathml = !is_comment && (use_mathml_namespace || active_namespace === 'mathml');
|
|
79
152
|
|
|
80
|
-
if (node === undefined) {
|
|
153
|
+
if (node === undefined || use_svg_namespace !== svg || use_mathml_namespace !== mathml) {
|
|
81
154
|
node = create_fragment_from_html(has_start ? content : '<!>' + content, svg, mathml);
|
|
82
155
|
if (!is_fragment) node = /** @type {Node} */ (get_first_child(node));
|
|
83
156
|
}
|
|
84
157
|
|
|
158
|
+
/** @type {DocumentFragment | Node} */
|
|
85
159
|
var clone =
|
|
86
160
|
use_import_node || is_firefox
|
|
87
161
|
? document.importNode(/** @type {Node} */ (node), true)
|
|
88
162
|
: /** @type {Node} */ (node).cloneNode(true);
|
|
89
163
|
|
|
90
164
|
if (is_fragment) {
|
|
91
|
-
|
|
92
|
-
var
|
|
165
|
+
// we know for sure that children exist
|
|
166
|
+
var start = /** @type {Node} */ (get_first_child(/** @type {DocumentFragment} */ (clone)));
|
|
167
|
+
var end = /** @type {Node} */ (/** @type {DocumentFragment} */ (clone).lastChild);
|
|
93
168
|
|
|
94
|
-
assign_nodes(
|
|
169
|
+
assign_nodes(start, end);
|
|
95
170
|
} else {
|
|
96
171
|
assign_nodes(clone, clone);
|
|
97
172
|
}
|
|
@@ -104,15 +179,44 @@ export function template(content, flags) {
|
|
|
104
179
|
* Appends a DOM node before the anchor node.
|
|
105
180
|
* @param {ChildNode} anchor - The anchor node.
|
|
106
181
|
* @param {Node} dom - The DOM node to append.
|
|
182
|
+
* @param {boolean} [skip_advance] - If true, don't advance hydrate_node (used when next() already positioned it).
|
|
107
183
|
*/
|
|
108
|
-
export function append(anchor, dom) {
|
|
184
|
+
export function append(anchor, dom, skip_advance) {
|
|
109
185
|
if (hydrating) {
|
|
110
|
-
|
|
186
|
+
// When skip_advance is true, the caller (e.g., a fragment component) has already
|
|
187
|
+
// used next() to position hydrate_node correctly. We must NOT reset it.
|
|
188
|
+
if (skip_advance) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
111
192
|
// During hydration, if anchor === dom, we're hydrating a child component
|
|
112
193
|
// where the "anchor" IS the content. Don't advance past it.
|
|
113
|
-
if (anchor
|
|
114
|
-
|
|
194
|
+
if (anchor === dom) {
|
|
195
|
+
pop(dom);
|
|
196
|
+
return;
|
|
115
197
|
}
|
|
198
|
+
|
|
199
|
+
// If the hydration cursor has descended into dom's children (e.g. after
|
|
200
|
+
// child()/sibling() traversal inside a single-node template), we need
|
|
201
|
+
// pop() to reset back to dom's sibling level before advancing.
|
|
202
|
+
// But if the cursor is already at dom's sibling level (e.g. because
|
|
203
|
+
// nested control flow blocks advanced it past dom via sibling traversal),
|
|
204
|
+
// pop() would incorrectly reset backwards — so we skip it.
|
|
205
|
+
if (hydrate_node?.parentNode === dom) {
|
|
206
|
+
pop(dom);
|
|
207
|
+
} else if (hydrate_node !== dom) {
|
|
208
|
+
// Cursor has advanced past dom via sibling traversal (due to nested
|
|
209
|
+
// block processing). Update the branch block's end to reflect the
|
|
210
|
+
// actual extent, which may be past the statically-assigned end from
|
|
211
|
+
// the template's assign_nodes call.
|
|
212
|
+
var block = /** @type {Block} */ (active_block);
|
|
213
|
+
var s = block.s;
|
|
214
|
+
if (s !== null) {
|
|
215
|
+
s.end = /** @type {Node} */ (hydrate_node);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
hydrate_next();
|
|
116
220
|
return;
|
|
117
221
|
}
|
|
118
222
|
anchor.before(/** @type {Node} */ (dom));
|
|
@@ -123,7 +227,9 @@ export function text(data = '') {
|
|
|
123
227
|
assign_nodes(/** @type {Node} */ (hydrate_node), /** @type {Node} */ (hydrate_node));
|
|
124
228
|
return /** @type {Node} */ (hydrate_node);
|
|
125
229
|
}
|
|
126
|
-
|
|
230
|
+
var node = create_text(data);
|
|
231
|
+
assign_nodes(node, node);
|
|
232
|
+
return node;
|
|
127
233
|
}
|
|
128
234
|
|
|
129
235
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
@import { Component, Dependency, Derived, Tracked } from '#server';
|
|
3
|
-
@import {
|
|
3
|
+
@import { SSRComponent } from 'ripple/server';
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Readable } from 'stream';
|
|
@@ -11,9 +11,14 @@ import { is_boolean_attribute } from '../../../compiler/utils.js';
|
|
|
11
11
|
import { clsx } from 'clsx';
|
|
12
12
|
import { normalize_css_property_name } from '../../../utils/normalize_css_property_name.js';
|
|
13
13
|
import { BLOCK_CLOSE, BLOCK_OPEN } from '../../../constants.js';
|
|
14
|
+
import {
|
|
15
|
+
is_tag_valid_with_parent,
|
|
16
|
+
is_tag_valid_with_ancestor,
|
|
17
|
+
} from '../../../html-tree-validation.js';
|
|
14
18
|
|
|
15
19
|
export { escape };
|
|
16
20
|
export { register_component_css as register_css } from './css-registry.js';
|
|
21
|
+
export { hash } from '../../../utils/hashing.js';
|
|
17
22
|
|
|
18
23
|
/** @type {null | Component} */
|
|
19
24
|
export let active_component = null;
|
|
@@ -225,6 +230,9 @@ export async function render(component) {
|
|
|
225
230
|
let body = '';
|
|
226
231
|
let css = new Set();
|
|
227
232
|
|
|
233
|
+
// Reset dev-mode element tracking state at the start of each render
|
|
234
|
+
reset_element_state();
|
|
235
|
+
|
|
228
236
|
try {
|
|
229
237
|
if (component.async) {
|
|
230
238
|
await component(output, {});
|
|
@@ -240,6 +248,8 @@ export async function render(component) {
|
|
|
240
248
|
css = output.css;
|
|
241
249
|
} catch (error) {
|
|
242
250
|
console.log(error);
|
|
251
|
+
} finally {
|
|
252
|
+
reset_element_state();
|
|
243
253
|
}
|
|
244
254
|
return { head, body, css };
|
|
245
255
|
}
|
|
@@ -260,6 +270,9 @@ export function renderToStream(component) {
|
|
|
260
270
|
* @param {Output} output
|
|
261
271
|
*/
|
|
262
272
|
async function render_in_chunks(component, stream, output) {
|
|
273
|
+
// Reset dev-mode element tracking state at the start of each render
|
|
274
|
+
reset_element_state();
|
|
275
|
+
|
|
263
276
|
try {
|
|
264
277
|
if (component.async) {
|
|
265
278
|
await component(output, {});
|
|
@@ -273,6 +286,8 @@ async function render_in_chunks(component, stream, output) {
|
|
|
273
286
|
} catch (error) {
|
|
274
287
|
console.error(error);
|
|
275
288
|
stream.emit('error', error);
|
|
289
|
+
} finally {
|
|
290
|
+
reset_element_state();
|
|
276
291
|
}
|
|
277
292
|
}
|
|
278
293
|
/**
|
|
@@ -294,6 +309,103 @@ export function pop_component() {
|
|
|
294
309
|
active_component = component.p;
|
|
295
310
|
}
|
|
296
311
|
|
|
312
|
+
/**
|
|
313
|
+
* @typedef {{
|
|
314
|
+
* tag: string;
|
|
315
|
+
* parent: undefined | ElementContext;
|
|
316
|
+
* filename: undefined | string;
|
|
317
|
+
* line: number;
|
|
318
|
+
* column: number;
|
|
319
|
+
* }} ElementContext
|
|
320
|
+
*/
|
|
321
|
+
|
|
322
|
+
/** @type {ElementContext | undefined} */
|
|
323
|
+
let current_element;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* @type {Set<string>}
|
|
327
|
+
*/
|
|
328
|
+
let seen_warnings = new Set();
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* @param {string} message
|
|
332
|
+
*/
|
|
333
|
+
function print_nesting_error(message) {
|
|
334
|
+
message =
|
|
335
|
+
`node_invalid_placement_ssr: ${message}\n\n` +
|
|
336
|
+
'This can cause content to shift around as the browser repairs the HTML, and will likely result in a hydration mismatch.';
|
|
337
|
+
|
|
338
|
+
if (seen_warnings.has(message)) return;
|
|
339
|
+
seen_warnings.add(message);
|
|
340
|
+
|
|
341
|
+
// eslint-disable-next-line no-console
|
|
342
|
+
console.error(message);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Pushes an element onto the element stack and validates its nesting.
|
|
347
|
+
* Used during DEV mode SSR to detect invalid HTML nesting that would cause
|
|
348
|
+
* the browser to repair the HTML, breaking hydration.
|
|
349
|
+
* @param {string} tag
|
|
350
|
+
* @param {string} filename
|
|
351
|
+
* @param {number} line
|
|
352
|
+
* @param {number} column
|
|
353
|
+
* @returns {void}
|
|
354
|
+
*/
|
|
355
|
+
export function push_element(tag, filename, line, column) {
|
|
356
|
+
var parent = current_element;
|
|
357
|
+
var element = { tag, parent, filename, line, column };
|
|
358
|
+
|
|
359
|
+
if (parent !== undefined) {
|
|
360
|
+
var ancestor = parent.parent;
|
|
361
|
+
var ancestors = [parent.tag];
|
|
362
|
+
|
|
363
|
+
const child_loc = filename ? `${filename}:${line}:${column}` : undefined;
|
|
364
|
+
const parent_loc = parent.filename
|
|
365
|
+
? `${parent.filename}:${parent.line}:${parent.column}`
|
|
366
|
+
: undefined;
|
|
367
|
+
|
|
368
|
+
const message = is_tag_valid_with_parent(tag, parent.tag, child_loc, parent_loc);
|
|
369
|
+
if (message) print_nesting_error(message);
|
|
370
|
+
|
|
371
|
+
while (ancestor != null) {
|
|
372
|
+
ancestors.push(ancestor.tag);
|
|
373
|
+
const ancestor_loc = ancestor.filename
|
|
374
|
+
? `${ancestor.filename}:${ancestor.line}:${ancestor.column}`
|
|
375
|
+
: undefined;
|
|
376
|
+
|
|
377
|
+
const ancestor_message = is_tag_valid_with_ancestor(tag, ancestors, child_loc, ancestor_loc);
|
|
378
|
+
if (ancestor_message) print_nesting_error(ancestor_message);
|
|
379
|
+
|
|
380
|
+
ancestor = ancestor.parent;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
current_element = element;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Pops the current element from the element stack.
|
|
389
|
+
* @returns {void}
|
|
390
|
+
*/
|
|
391
|
+
export function pop_element() {
|
|
392
|
+
if (current_element !== undefined) {
|
|
393
|
+
current_element = current_element.parent;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Resets the dev-mode element tracking state.
|
|
399
|
+
* Called automatically at the start/end of each render to prevent
|
|
400
|
+
* state from leaking between renders (e.g., if a render throws).
|
|
401
|
+
* Also exported for testing purposes.
|
|
402
|
+
* @returns {void}
|
|
403
|
+
*/
|
|
404
|
+
export function reset_element_state() {
|
|
405
|
+
seen_warnings = new Set();
|
|
406
|
+
current_element = undefined;
|
|
407
|
+
}
|
|
408
|
+
|
|
297
409
|
/**
|
|
298
410
|
* @param {() => any} fn
|
|
299
411
|
* @returns {Promise<void>}
|
|
@@ -3,11 +3,11 @@ import * as devalue from 'devalue';
|
|
|
3
3
|
/**
|
|
4
4
|
* @template {any[]} T
|
|
5
5
|
* @template V
|
|
6
|
-
* @param {(...args: T) => Promise<V>} fn
|
|
6
|
+
* @param {(...args: T) => Promise<V>} fn
|
|
7
7
|
* @param {string} rpc_arguments_string
|
|
8
8
|
*/
|
|
9
9
|
export async function executeServerFunction(fn, rpc_arguments_string) {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const rpc_arguments = devalue.parse(rpc_arguments_string);
|
|
11
|
+
const result = await fn.apply(null, rpc_arguments);
|
|
12
12
|
return devalue.stringify({ value: result });
|
|
13
|
-
}
|
|
13
|
+
}
|
package/src/runtime/map.js
CHANGED
|
@@ -24,7 +24,7 @@ export class TrackedMap extends Map {
|
|
|
24
24
|
constructor(iterable) {
|
|
25
25
|
super();
|
|
26
26
|
|
|
27
|
-
var block = this.#block = safe_scope();
|
|
27
|
+
var block = (this.#block = safe_scope());
|
|
28
28
|
|
|
29
29
|
if (iterable) {
|
|
30
30
|
for (var [key, value] of iterable) {
|
|
@@ -49,7 +49,7 @@ export class TrackedMap extends Map {
|
|
|
49
49
|
var map_proto = Map.prototype;
|
|
50
50
|
|
|
51
51
|
for (const method of introspect_methods) {
|
|
52
|
-
|
|
52
|
+
/** @type {any} */ (proto)[method] = function (/** @type {...any} */ ...v) {
|
|
53
53
|
this.size;
|
|
54
54
|
this.#read_all();
|
|
55
55
|
|
package/src/runtime/object.js
CHANGED
|
@@ -9,13 +9,13 @@ import { object_proxy } from './proxy.js';
|
|
|
9
9
|
* @returns {TrackedObject<T>}
|
|
10
10
|
*/
|
|
11
11
|
export function TrackedObject(obj) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
if (!new.target) {
|
|
13
|
+
throw new Error("TrackedObject must be called with 'new'");
|
|
14
|
+
}
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
var block = safe_scope();
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
return object_proxy(obj, block);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -25,5 +25,5 @@ export function TrackedObject(obj) {
|
|
|
25
25
|
* @returns {TrackedObject<T>}
|
|
26
26
|
*/
|
|
27
27
|
export function tracked_object(obj, block) {
|
|
28
|
-
|
|
28
|
+
return object_proxy(obj, block);
|
|
29
29
|
}
|
package/src/runtime/proxy.js
CHANGED
|
@@ -26,10 +26,10 @@ import {
|
|
|
26
26
|
export function proxy(value, block) {
|
|
27
27
|
// if non-proxyable, or is already a proxy, return `value`
|
|
28
28
|
if (
|
|
29
|
-
typeof value !== 'object'
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
typeof value !== 'object' ||
|
|
30
|
+
value === null ||
|
|
31
|
+
TRACKED_ARRAY in value ||
|
|
32
|
+
TRACKED_OBJECT in value
|
|
33
33
|
) {
|
|
34
34
|
return value;
|
|
35
35
|
}
|
|
@@ -153,7 +153,9 @@ export function proxy(value, block) {
|
|
|
153
153
|
},
|
|
154
154
|
|
|
155
155
|
setPrototypeOf() {
|
|
156
|
-
throw new Error(
|
|
156
|
+
throw new Error(
|
|
157
|
+
`Cannot set prototype of ${is_proxied_array ? '\`TrackedArray\`' : '\`TrackedObject\`'}`,
|
|
158
|
+
);
|
|
157
159
|
},
|
|
158
160
|
|
|
159
161
|
deleteProperty(target, prop) {
|
|
@@ -185,7 +187,7 @@ export function proxy(value, block) {
|
|
|
185
187
|
|
|
186
188
|
if (t !== undefined || !exists || get_descriptor(target, prop)?.writable) {
|
|
187
189
|
if (t === undefined) {
|
|
188
|
-
t = tracked(exists ?
|
|
190
|
+
t = tracked(exists ? /** @type {any} */ (target)[prop] : UNINITIALIZED, block);
|
|
189
191
|
|
|
190
192
|
tracked_elements.set(prop, t);
|
|
191
193
|
}
|
|
@@ -257,14 +259,13 @@ export function proxy(value, block) {
|
|
|
257
259
|
enumerable: true,
|
|
258
260
|
configurable: true,
|
|
259
261
|
value,
|
|
260
|
-
writable: true
|
|
262
|
+
writable: true,
|
|
261
263
|
};
|
|
262
264
|
}
|
|
263
265
|
}
|
|
264
266
|
|
|
265
267
|
return descriptor;
|
|
266
268
|
},
|
|
267
|
-
|
|
268
269
|
});
|
|
269
270
|
}
|
|
270
271
|
|
|
@@ -284,7 +285,7 @@ export function array_proxy({ elements, block, from_static = false, use_array =
|
|
|
284
285
|
|
|
285
286
|
if (
|
|
286
287
|
from_static &&
|
|
287
|
-
(first = get_first_if_length(/** @type {Array<T>} */(elements))) !== undefined
|
|
288
|
+
(first = get_first_if_length(/** @type {Array<T>} */ (elements))) !== undefined
|
|
288
289
|
) {
|
|
289
290
|
arr = new Array();
|
|
290
291
|
arr[0] = first;
|
|
@@ -334,8 +335,8 @@ function get_first_if_length(array) {
|
|
|
334
335
|
array.length === 1 &&
|
|
335
336
|
0 in array &&
|
|
336
337
|
Number.isInteger(first) &&
|
|
337
|
-
|
|
338
|
-
|
|
338
|
+
/** @type {number} */ (first) >= 0 &&
|
|
339
|
+
/** @type {number} */ (first) <= MAX_ARRAY_LENGTH
|
|
339
340
|
) {
|
|
340
341
|
return /** @type {number} */ (first);
|
|
341
342
|
}
|
|
@@ -17,5 +17,13 @@ export function ReactiveValue(fn, start) {
|
|
|
17
17
|
const s = createSubscriber(start);
|
|
18
18
|
const block = safe_scope();
|
|
19
19
|
|
|
20
|
-
return
|
|
20
|
+
return derived(
|
|
21
|
+
fn,
|
|
22
|
+
block,
|
|
23
|
+
() => {
|
|
24
|
+
s();
|
|
25
|
+
return fn();
|
|
26
|
+
},
|
|
27
|
+
(_, prev) => prev,
|
|
28
|
+
);
|
|
21
29
|
}
|
package/src/runtime/set.js
CHANGED
|
@@ -28,7 +28,7 @@ export class TrackedSet extends Set {
|
|
|
28
28
|
constructor(iterable) {
|
|
29
29
|
super();
|
|
30
30
|
|
|
31
|
-
var block = this.#block = safe_scope();
|
|
31
|
+
var block = (this.#block = safe_scope());
|
|
32
32
|
|
|
33
33
|
if (iterable) {
|
|
34
34
|
for (var item of iterable) {
|
|
@@ -57,7 +57,7 @@ export class TrackedSet extends Set {
|
|
|
57
57
|
continue;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
/** @type {any} */ (proto)[method] = function (/** @type {...any} */ ...v) {
|
|
61
61
|
this.size;
|
|
62
62
|
|
|
63
63
|
return /** @type {any} */ (set_proto)[method].apply(this, v);
|
|
@@ -69,7 +69,10 @@ export class TrackedSet extends Set {
|
|
|
69
69
|
continue;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
/** @type {any} */ (proto)[method] = function (
|
|
73
|
+
/** @type {any} */ other,
|
|
74
|
+
/** @type {...any} */ ...v
|
|
75
|
+
) {
|
|
73
76
|
this.size;
|
|
74
77
|
|
|
75
78
|
if (other instanceof TrackedSet) {
|
|
@@ -85,14 +88,17 @@ export class TrackedSet extends Set {
|
|
|
85
88
|
continue;
|
|
86
89
|
}
|
|
87
90
|
|
|
88
|
-
|
|
91
|
+
/** @type {any} */ (proto)[method] = function (
|
|
92
|
+
/** @type {any} */ other,
|
|
93
|
+
/** @type {...any} */ ...v
|
|
94
|
+
) {
|
|
89
95
|
this.size;
|
|
90
96
|
|
|
91
97
|
if (other instanceof TrackedSet) {
|
|
92
98
|
other.size;
|
|
93
99
|
}
|
|
94
100
|
|
|
95
|
-
return new TrackedSet(/** @type {any} */(set_proto)[method].apply(this, [other, ...v]));
|
|
101
|
+
return new TrackedSet(/** @type {any} */ (set_proto)[method].apply(this, [other, ...v]));
|
|
96
102
|
};
|
|
97
103
|
}
|
|
98
104
|
}
|
|
@@ -138,9 +144,8 @@ export class TrackedSet extends Set {
|
|
|
138
144
|
/**
|
|
139
145
|
* @param {T} value
|
|
140
146
|
* @return {boolean}
|
|
141
|
-
|
|
147
|
+
*/
|
|
142
148
|
has(value) {
|
|
143
|
-
|
|
144
149
|
var has = super.has(value);
|
|
145
150
|
var tracked_items = this.#tracked_items;
|
|
146
151
|
var t = tracked_items.get(value);
|
package/src/server/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// SSR helpers
|
|
1
2
|
export { render, renderToStream } from '../runtime/internal/server/index.js';
|
|
2
3
|
export { get_css_for_hashes } from '../runtime/internal/server/css-registry.js';
|
|
3
4
|
export { executeServerFunction } from '../runtime/internal/server/rpc.js';
|
|
5
|
+
|
|
6
|
+
// Re-export server runtime for components compiled for SSR
|
|
7
|
+
export * from '../runtime/index-server.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const regex_return_characters = /\r/g;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Hashes a string to a base36 value
|
|
5
|
+
* @param {string} str
|
|
6
|
+
* @returns {string}
|
|
7
|
+
*/
|
|
8
|
+
export function hash(str) {
|
|
9
|
+
str = str.replace(regex_return_characters, '');
|
|
10
|
+
let hash = 5381;
|
|
11
|
+
let i = str.length;
|
|
12
|
+
|
|
13
|
+
while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i);
|
|
14
|
+
return (hash >>> 0).toString(36);
|
|
15
|
+
}
|
|
@@ -16,7 +16,7 @@ export function normalize_css_property_name(str) {
|
|
|
16
16
|
return normalized_result;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
normalized_result = str.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
|
|
19
|
+
normalized_result = str.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase());
|
|
20
20
|
normalized_properties_cache.set(str, normalized_result);
|
|
21
21
|
|
|
22
22
|
return normalized_result;
|
|
@@ -5,7 +5,7 @@ describe('TrackedArray > mutations', () => {
|
|
|
5
5
|
component ArrayTest() {
|
|
6
6
|
let items = new TrackedArray(1, 2, 3);
|
|
7
7
|
|
|
8
|
-
<button onClick={() => items[items.length] = items.length + 1}>{'increment'}</button>
|
|
8
|
+
<button onClick={() => (items[items.length] = items.length + 1)}>{'increment'}</button>
|
|
9
9
|
|
|
10
10
|
<Child {items} />
|
|
11
11
|
}
|
|
@@ -234,7 +234,7 @@ describe('TrackedArray > mutations', () => {
|
|
|
234
234
|
component ArrayTest() {
|
|
235
235
|
let items = new TrackedArray(1, 2, 3);
|
|
236
236
|
|
|
237
|
-
<button onClick={() => items.forEach((item, i) => items[i] = item * 2)}>
|
|
237
|
+
<button onClick={() => items.forEach((item, i) => (items[i] = item * 2))}>
|
|
238
238
|
{'double all'}
|
|
239
239
|
</button>
|
|
240
240
|
<pre>{JSON.stringify(items)}</pre>
|
|
@@ -258,7 +258,7 @@ describe('TrackedArray > mutations', () => {
|
|
|
258
258
|
component ArrayTest() {
|
|
259
259
|
let items = new TrackedArray(1, 2, 3);
|
|
260
260
|
|
|
261
|
-
<button onClick={() => items.forEach((item, i) => items[i] = item * 2)}>
|
|
261
|
+
<button onClick={() => items.forEach((item, i) => (items[i] = item * 2))}>
|
|
262
262
|
{'double all'}
|
|
263
263
|
</button>
|
|
264
264
|
|
|
@@ -291,7 +291,7 @@ describe('TrackedArray > mutations', () => {
|
|
|
291
291
|
let firstItem = track(() => items[0]);
|
|
292
292
|
let secondItem = track(() => items[1]);
|
|
293
293
|
|
|
294
|
-
<button onClick={() => items[0] = 100}>{'change first'}</button>
|
|
294
|
+
<button onClick={() => (items[0] = 100)}>{'change first'}</button>
|
|
295
295
|
<pre>{@firstItem}</pre>
|
|
296
296
|
<pre>{@secondItem}</pre>
|
|
297
297
|
<pre>{items[0]}</pre>
|
|
@@ -323,8 +323,8 @@ describe('TrackedArray > mutations', () => {
|
|
|
323
323
|
let items = new TrackedArray(1, 2, 3);
|
|
324
324
|
let length = track(() => items.length);
|
|
325
325
|
|
|
326
|
-
<button onClick={() => items.length = 5}>{'expand'}</button>
|
|
327
|
-
<button onClick={() => items.length = 2}>{'shrink'}</button>
|
|
326
|
+
<button onClick={() => (items.length = 5)}>{'expand'}</button>
|
|
327
|
+
<button onClick={() => (items.length = 2)}>{'shrink'}</button>
|
|
328
328
|
<pre>{JSON.stringify(items)}</pre>
|
|
329
329
|
<pre>{@length}</pre>
|
|
330
330
|
}
|
|
@@ -357,8 +357,8 @@ describe('TrackedArray > mutations', () => {
|
|
|
357
357
|
component ArrayTest() {
|
|
358
358
|
let items = new TrackedArray(1, 2, 3, 4, 5);
|
|
359
359
|
|
|
360
|
-
<button onClick={() => items.length = 3}>{'truncate'}</button>
|
|
361
|
-
<button onClick={() => items.length = 7}>{'expand'}</button>
|
|
360
|
+
<button onClick={() => (items.length = 3)}>{'truncate'}</button>
|
|
361
|
+
<button onClick={() => (items.length = 7)}>{'expand'}</button>
|
|
362
362
|
<pre>{JSON.stringify(items)}</pre>
|
|
363
363
|
<pre>{items.length}</pre>
|
|
364
364
|
}
|