ripple 0.2.76 → 0.2.78
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 +6 -6
- package/src/compiler/index.js +2 -2
- package/src/compiler/phases/1-parse/index.js +0 -5
- package/src/compiler/phases/3-transform/client/index.js +1621 -1673
- package/src/compiler/phases/3-transform/server/index.js +350 -77
- package/src/compiler/utils.js +60 -0
- package/src/runtime/{index.js → index-client.js} +6 -0
- package/src/runtime/index-server.js +32 -0
- package/src/runtime/internal/client/runtime.js +4 -0
- package/src/runtime/internal/server/context.js +67 -0
- package/src/runtime/internal/server/index.js +107 -22
- package/src/server/index.js +1 -1
- package/src/utils/escaping.js +26 -0
- package/tests/client/__snapshots__/basic.test.ripple.snap +9 -0
- package/tests/client/basic.test.ripple +13 -0
|
@@ -3,93 +3,366 @@ import { walk } from 'zimmerframe';
|
|
|
3
3
|
import ts from 'esrap/languages/ts';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { print } from 'esrap';
|
|
6
|
+
import {
|
|
7
|
+
build_getter,
|
|
8
|
+
escape_html,
|
|
9
|
+
is_boolean_attribute,
|
|
10
|
+
is_element_dom_element,
|
|
11
|
+
is_inside_component,
|
|
12
|
+
is_void_element,
|
|
13
|
+
normalize_children,
|
|
14
|
+
} from '../../../utils.js';
|
|
15
|
+
import is_reference from 'is-reference';
|
|
16
|
+
import { escape } from '../../../../utils/escaping.js';
|
|
17
|
+
import { is_event_attribute } from '../../../../utils/events.js';
|
|
6
18
|
|
|
7
19
|
function add_ripple_internal_import(context) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
20
|
+
if (!context.state.to_ts) {
|
|
21
|
+
if (!context.state.imports.has(`import * as _$_ from 'ripple/internal/server'`)) {
|
|
22
|
+
context.state.imports.add(`import * as _$_ from 'ripple/internal/server'`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function transform_children(children, context) {
|
|
28
|
+
const { visit, state, root } = context;
|
|
29
|
+
const normalized = normalize_children(children);
|
|
30
|
+
|
|
31
|
+
for (const node of normalized) {
|
|
32
|
+
if (
|
|
33
|
+
node.type === 'VariableDeclaration' ||
|
|
34
|
+
node.type === 'ExpressionStatement' ||
|
|
35
|
+
node.type === 'ThrowStatement' ||
|
|
36
|
+
node.type === 'FunctionDeclaration' ||
|
|
37
|
+
node.type === 'DebuggerStatement' ||
|
|
38
|
+
node.type === 'ClassDeclaration' ||
|
|
39
|
+
node.type === 'TSTypeAliasDeclaration' ||
|
|
40
|
+
node.type === 'TSInterfaceDeclaration' ||
|
|
41
|
+
node.type === 'Component'
|
|
42
|
+
) {
|
|
43
|
+
const metadata = { await: false };
|
|
44
|
+
state.init.push(visit(node, { ...state, metadata }));
|
|
45
|
+
if (metadata.await) {
|
|
46
|
+
state.init.push(b.if(b.call('_$_.aborted'), b.return(null)));
|
|
47
|
+
if (state.metadata?.await === false) {
|
|
48
|
+
state.metadata.await = true;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
visit(node, { ...state, root: false });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
13
55
|
}
|
|
14
56
|
|
|
15
57
|
function transform_body(body, { visit, state }) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
58
|
+
const body_state = {
|
|
59
|
+
...state,
|
|
60
|
+
init: [],
|
|
61
|
+
metadata: state.metadata,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
transform_children(body, { visit, state: body_state, root: true });
|
|
21
65
|
|
|
22
|
-
|
|
66
|
+
return body_state.init;
|
|
23
67
|
}
|
|
24
68
|
|
|
25
69
|
const visitors = {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
70
|
+
_: function set_scope(node, { next, state }) {
|
|
71
|
+
const scope = state.scopes.get(node);
|
|
72
|
+
|
|
73
|
+
if (scope && scope !== state.scope) {
|
|
74
|
+
return next({ ...state, scope });
|
|
75
|
+
} else {
|
|
76
|
+
return next();
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
Component(node, context) {
|
|
81
|
+
add_ripple_internal_import(context);
|
|
82
|
+
|
|
83
|
+
const metadata = { await: false };
|
|
84
|
+
const body_statements = [
|
|
85
|
+
b.stmt(b.call('_$_.push_component')),
|
|
86
|
+
...transform_body(node.body, {
|
|
87
|
+
...context,
|
|
88
|
+
state: { ...context.state, component: node, metadata },
|
|
89
|
+
}),
|
|
90
|
+
b.stmt(b.call('_$_.pop_component')),
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
if (node.css !== null && node.css) {
|
|
94
|
+
context.state.stylesheets.push(node.css);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return b.function(
|
|
98
|
+
node.id,
|
|
99
|
+
node.params.length > 0 ? [b.id('__output'), node.params[0]] : [b.id('__output')],
|
|
100
|
+
b.block([
|
|
101
|
+
...(metadata.await
|
|
102
|
+
? [b.stmt(b.call('_$_.async', b.thunk(b.block(body_statements), true)))]
|
|
103
|
+
: body_statements),
|
|
104
|
+
]),
|
|
105
|
+
);
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
Element(node, context) {
|
|
109
|
+
const { state, visit } = context;
|
|
110
|
+
|
|
111
|
+
const is_dom_element = is_element_dom_element(node);
|
|
112
|
+
const is_spreading = node.attributes.some((attr) => attr.type === 'SpreadAttribute');
|
|
113
|
+
const spread_attributes = is_spreading ? [] : null;
|
|
114
|
+
|
|
115
|
+
if (is_dom_element) {
|
|
116
|
+
const is_void = is_void_element(node.id.name);
|
|
117
|
+
|
|
118
|
+
state.init.push(
|
|
119
|
+
b.stmt(b.call(b.member(b.id('__output'), b.id('push')), b.literal(`<${node.id.name}`))),
|
|
120
|
+
);
|
|
121
|
+
let class_attribute = null;
|
|
122
|
+
|
|
123
|
+
const handle_static_attr = (name, value) => {
|
|
124
|
+
const attr_value = b.literal(
|
|
125
|
+
` ${name}${
|
|
126
|
+
is_boolean_attribute(name) && value === true
|
|
127
|
+
? ''
|
|
128
|
+
: `="${value === true ? '' : escape_html(value, true)}"`
|
|
129
|
+
}`,
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
if (is_spreading) {
|
|
133
|
+
// For spread attributes, store just the actual value, not the full attribute string
|
|
134
|
+
const actual_value =
|
|
135
|
+
is_boolean_attribute(name) && value === true
|
|
136
|
+
? b.literal(true)
|
|
137
|
+
: b.literal(value === true ? '' : value);
|
|
138
|
+
spread_attributes.push(b.prop('init', b.literal(name), actual_value));
|
|
139
|
+
} else {
|
|
140
|
+
state.init.push(
|
|
141
|
+
b.stmt(b.call(b.member(b.id('__output'), b.id('push')), b.literal(String(attr_value)))),
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
for (const attr of node.attributes) {
|
|
147
|
+
if (attr.type === 'Attribute') {
|
|
148
|
+
if (attr.name.type === 'Identifier') {
|
|
149
|
+
const name = attr.name.name;
|
|
150
|
+
|
|
151
|
+
if (attr.value === null) {
|
|
152
|
+
handle_static_attr(name, true);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (attr.value.type === 'Literal' && name !== 'class') {
|
|
157
|
+
handle_static_attr(name, attr.value.value);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (name === 'class') {
|
|
162
|
+
class_attribute = attr;
|
|
163
|
+
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (is_event_attribute(name)) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const metadata = { tracking: false, await: false };
|
|
171
|
+
const expression = visit(attr.value, { ...state, metadata });
|
|
172
|
+
|
|
173
|
+
state.init.push(
|
|
174
|
+
b.stmt(
|
|
175
|
+
b.call(
|
|
176
|
+
b.member(b.id('__output'), b.id('push')),
|
|
177
|
+
b.call('_$_.attr', b.literal(name), expression),
|
|
178
|
+
),
|
|
179
|
+
),
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
} else if (attr.type === 'SpreadAttribute') {
|
|
183
|
+
spread_attributes.push(b.spread(visit(attr.argument, state)));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (class_attribute !== null) {
|
|
188
|
+
if (class_attribute.value.type === 'Literal') {
|
|
189
|
+
let value = class_attribute.value.value;
|
|
190
|
+
|
|
191
|
+
if (node.metadata.scoped && state.component.css) {
|
|
192
|
+
value = `${state.component.css.hash} ${value}`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
handle_static_attr(class_attribute.name.name, value);
|
|
196
|
+
} else {
|
|
197
|
+
const metadata = { tracking: false, await: false };
|
|
198
|
+
let expression = visit(class_attribute.value, { ...state, metadata });
|
|
199
|
+
|
|
200
|
+
if (node.metadata.scoped && state.component.css) {
|
|
201
|
+
expression = b.binary('+', b.literal(state.component.css.hash + ' '), expression);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
state.init.push(
|
|
205
|
+
b.stmt(
|
|
206
|
+
b.call(
|
|
207
|
+
b.member(b.id('__output'), b.id('push')),
|
|
208
|
+
b.call('_$_.attr', b.literal('class'), expression),
|
|
209
|
+
),
|
|
210
|
+
),
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
} else if (node.metadata.scoped && state.component.css) {
|
|
214
|
+
const value = state.component.css.hash;
|
|
215
|
+
|
|
216
|
+
// TOOO
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (spread_attributes !== null && spread_attributes.length > 0) {
|
|
220
|
+
state.init.push(
|
|
221
|
+
b.stmt(
|
|
222
|
+
b.call(
|
|
223
|
+
b.member(b.id('__output'), b.id('push')),
|
|
224
|
+
b.call(
|
|
225
|
+
'_$_.spread_attrs',
|
|
226
|
+
b.object(spread_attributes),
|
|
227
|
+
node.metadata.scoped && state.component.css
|
|
228
|
+
? b.literal(state.component.css.hash)
|
|
229
|
+
: undefined,
|
|
230
|
+
),
|
|
231
|
+
),
|
|
232
|
+
),
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
state.init.push(b.stmt(b.call(b.member(b.id('__output'), b.id('push')), b.literal(`>`))));
|
|
237
|
+
|
|
238
|
+
if (!is_void) {
|
|
239
|
+
transform_children(node.children, { visit, state: { ...state, root: false } });
|
|
240
|
+
|
|
241
|
+
state.init.push(
|
|
242
|
+
b.stmt(b.call(b.member(b.id('__output'), b.id('push')), b.literal(`</${node.id.name}>`))),
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
const props = [];
|
|
247
|
+
|
|
248
|
+
for (const attr of node.attributes) {
|
|
249
|
+
if (attr.type === 'Attribute') {
|
|
250
|
+
if (attr.name.type === 'Identifier') {
|
|
251
|
+
const metadata = { tracking: false, await: false };
|
|
252
|
+
let property = visit(attr.value, { ...state, metadata });
|
|
253
|
+
|
|
254
|
+
props.push(b.prop('init', attr.name, property));
|
|
255
|
+
} else if (attr.type === 'SpreadAttribute') {
|
|
256
|
+
props.push(
|
|
257
|
+
b.spread(
|
|
258
|
+
visit(attr.argument, { ...state, metadata: { ...state.metadata, spread: true } }),
|
|
259
|
+
),
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
state.init.push(b.stmt(b.call(node.id.name, b.id('__output'), b.object(props))));
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
ForOfStatement(node, context) {
|
|
270
|
+
if (!is_inside_component(context)) {
|
|
271
|
+
context.next();
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const body_scope = context.state.scopes.get(node.body);
|
|
275
|
+
|
|
276
|
+
const body = transform_body(node.body.body, {
|
|
277
|
+
...context,
|
|
278
|
+
state: { ...context.state, scope: body_scope },
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
if (node.index) {
|
|
282
|
+
context.state.init.push(b.var(node.index, b.literal(0)));
|
|
283
|
+
body.push(b.update('++', node.index));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
context.state.init.push(
|
|
287
|
+
b.for_of(context.visit(node.left), context.visit(node.right), b.block(body)),
|
|
288
|
+
);
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
IfStatement(node, context) {
|
|
292
|
+
if (!is_inside_component(context)) {
|
|
293
|
+
context.next();
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// TODO: alternative (else if / else)
|
|
298
|
+
context.state.init.push(
|
|
299
|
+
b.if(
|
|
300
|
+
context.visit(node.test),
|
|
301
|
+
b.block(
|
|
302
|
+
transform_body(node.consequent.body, {
|
|
303
|
+
...context,
|
|
304
|
+
state: { ...context.state, scope: context.state.scopes.get(node.consequent) },
|
|
305
|
+
}),
|
|
306
|
+
),
|
|
307
|
+
),
|
|
308
|
+
);
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
Identifier(node, context) {
|
|
312
|
+
const parent = /** @type {Node} */ (context.path.at(-1));
|
|
313
|
+
|
|
314
|
+
if (is_reference(node, parent) && node.tracked) {
|
|
315
|
+
add_ripple_internal_import(context);
|
|
316
|
+
return b.call('_$_.get', build_getter(node, context));
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
|
|
320
|
+
Text(node, { visit, state }) {
|
|
321
|
+
const metadata = { await: false };
|
|
322
|
+
const expression = visit(node.expression, { ...state, metadata });
|
|
323
|
+
|
|
324
|
+
if (expression.type === 'Literal') {
|
|
325
|
+
state.init.push(
|
|
326
|
+
b.stmt(
|
|
327
|
+
b.call(b.member(b.id('__output'), b.id('push')), b.literal(escape(expression.value))),
|
|
328
|
+
),
|
|
329
|
+
);
|
|
330
|
+
} else {
|
|
331
|
+
state.init.push(
|
|
332
|
+
b.stmt(b.call(b.member(b.id('__output'), b.id('push')), b.call('_$_.escape', expression))),
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
},
|
|
63
336
|
};
|
|
64
337
|
|
|
65
338
|
export function transform_server(filename, source, analysis) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
339
|
+
const state = {
|
|
340
|
+
imports: new Set(),
|
|
341
|
+
init: null,
|
|
342
|
+
scope: analysis.scope,
|
|
343
|
+
scopes: analysis.scopes,
|
|
344
|
+
stylesheets: [],
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
const program = /** @type {ESTree.Program} */ (
|
|
348
|
+
walk(analysis.ast, { ...state, namespace: 'html' }, visitors)
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
for (const import_node of state.imports) {
|
|
352
|
+
program.body.unshift(b.stmt(b.id(import_node)));
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const js = print(program, ts(), {
|
|
356
|
+
sourceMapContent: source,
|
|
357
|
+
sourceMapSource: path.basename(filename),
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
// TODO: extract css
|
|
361
|
+
const css = '';
|
|
362
|
+
|
|
363
|
+
return {
|
|
364
|
+
ast: program,
|
|
365
|
+
js,
|
|
366
|
+
css,
|
|
367
|
+
};
|
|
95
368
|
}
|
package/src/compiler/utils.js
CHANGED
|
@@ -647,3 +647,63 @@ export function is_element_dom_element(node) {
|
|
|
647
647
|
!node.id.tracked
|
|
648
648
|
);
|
|
649
649
|
}
|
|
650
|
+
|
|
651
|
+
export function normalize_children(children) {
|
|
652
|
+
const normalized = [];
|
|
653
|
+
|
|
654
|
+
for (const node of children) {
|
|
655
|
+
normalize_child(node, normalized);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
for (let i = normalized.length - 1; i >= 0; i--) {
|
|
659
|
+
const child = normalized[i];
|
|
660
|
+
const prev_child = normalized[i - 1];
|
|
661
|
+
|
|
662
|
+
if (child.type === 'Text' && prev_child?.type === 'Text') {
|
|
663
|
+
if (child.expression.type === 'Literal' && prev_child.expression.type === 'Literal') {
|
|
664
|
+
prev_child.expression = b.literal(
|
|
665
|
+
prev_child.expression.value + String(child.expression.value),
|
|
666
|
+
);
|
|
667
|
+
} else {
|
|
668
|
+
prev_child.expression = b.binary(
|
|
669
|
+
'+',
|
|
670
|
+
prev_child.expression,
|
|
671
|
+
b.call('String', child.expression),
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
normalized.splice(i, 1);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
return normalized;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
function normalize_child(node, normalized) {
|
|
682
|
+
if (node.type === 'EmptyStatement') {
|
|
683
|
+
return;
|
|
684
|
+
} else if (node.type === 'Element' && node.id.type === 'Identifier' && node.id.name === 'style') {
|
|
685
|
+
return;
|
|
686
|
+
} else {
|
|
687
|
+
normalized.push(node);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
export function build_getter(node, context) {
|
|
692
|
+
const state = context.state;
|
|
693
|
+
|
|
694
|
+
for (let i = context.path.length - 1; i >= 0; i -= 1) {
|
|
695
|
+
const binding = state.scope.get(node.name);
|
|
696
|
+
const transform = binding?.transform;
|
|
697
|
+
|
|
698
|
+
// don't transform the declaration itself
|
|
699
|
+
if (node !== binding?.node) {
|
|
700
|
+
const read_fn = transform?.read;
|
|
701
|
+
|
|
702
|
+
if (read_fn) {
|
|
703
|
+
return read_fn(node, context.state?.metadata?.spread, context.visit);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
return node;
|
|
709
|
+
}
|
|
@@ -20,6 +20,12 @@ export function mount(component, options) {
|
|
|
20
20
|
const props = options.props || {};
|
|
21
21
|
const target = options.target;
|
|
22
22
|
const anchor = create_anchor();
|
|
23
|
+
|
|
24
|
+
// Clear target content in case of SSR
|
|
25
|
+
if (target.firstChild) {
|
|
26
|
+
target.textContent = '';
|
|
27
|
+
}
|
|
28
|
+
|
|
23
29
|
target.append(anchor);
|
|
24
30
|
|
|
25
31
|
const cleanup_events = handle_root_events(target);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { DERIVED, TRACKED, UNINITIALIZED } from './internal/client/constants';
|
|
2
|
+
import { is_tracked_object } from './internal/client/utils';
|
|
3
|
+
|
|
4
|
+
export { create_context as createContext } from './internal/server/context.js';
|
|
5
|
+
|
|
6
|
+
export function effect() {
|
|
7
|
+
// NO-OP
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const TrackedArray = Array;
|
|
11
|
+
|
|
12
|
+
export function track(v, o) {
|
|
13
|
+
var is_tracked = is_tracked_object(v);
|
|
14
|
+
|
|
15
|
+
if (is_tracked) {
|
|
16
|
+
return v;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (typeof v === 'function') {
|
|
20
|
+
return {
|
|
21
|
+
f: TRACKED | DERIVED,
|
|
22
|
+
fn: v,
|
|
23
|
+
v: UNINITIALIZED,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
f: TRACKED,
|
|
29
|
+
v,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
@@ -762,6 +762,10 @@ export function set(tracked, value, block) {
|
|
|
762
762
|
if (value !== old_value) {
|
|
763
763
|
var tracked_block = tracked.b;
|
|
764
764
|
|
|
765
|
+
if (!tracked_block) {
|
|
766
|
+
debugger;
|
|
767
|
+
}
|
|
768
|
+
|
|
765
769
|
if ((block.f & CONTAINS_TEARDOWN) !== 0) {
|
|
766
770
|
if (teardown) {
|
|
767
771
|
old_values.set(tracked, value);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { active_component } from './index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @template T
|
|
5
|
+
*/
|
|
6
|
+
export class Context {
|
|
7
|
+
/**
|
|
8
|
+
* @param {T} initial_value
|
|
9
|
+
*/
|
|
10
|
+
constructor(initial_value) {
|
|
11
|
+
/** @type {T} */
|
|
12
|
+
this._v = initial_value;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
get() {
|
|
16
|
+
const component = active_component;
|
|
17
|
+
const context = this;
|
|
18
|
+
|
|
19
|
+
if (component === null) {
|
|
20
|
+
throw new Error('No active component found, cannot get context');
|
|
21
|
+
}
|
|
22
|
+
/** @type {Component | null} */
|
|
23
|
+
let current_component = component;
|
|
24
|
+
|
|
25
|
+
while (current_component !== null) {
|
|
26
|
+
const context_map = current_component.c;
|
|
27
|
+
|
|
28
|
+
if (context_map?.has(context)) {
|
|
29
|
+
return context_map.get(context);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
current_component = current_component.p;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return context._v;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @template T
|
|
40
|
+
* @param {T} value
|
|
41
|
+
*/
|
|
42
|
+
set(value) {
|
|
43
|
+
const component = active_component;
|
|
44
|
+
const context = this;
|
|
45
|
+
|
|
46
|
+
if (component === null) {
|
|
47
|
+
throw new Error('No active component found, cannot set context');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let current_context = component.c;
|
|
51
|
+
|
|
52
|
+
if (current_context === null) {
|
|
53
|
+
current_context = component.c = new Map();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
current_context.set(context, value);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @template T
|
|
62
|
+
* @param {T} initial_value
|
|
63
|
+
* @returns {Context<T>}
|
|
64
|
+
*/
|
|
65
|
+
export function create_context(initial_value) {
|
|
66
|
+
return new Context(initial_value);
|
|
67
|
+
}
|