ripple 0.2.33 → 0.2.35
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 +11 -0
- package/src/compiler/phases/3-transform/index.js +80 -40
- package/src/compiler/utils.js +27 -0
- package/src/runtime/internal/client/array.js +352 -0
- package/src/runtime/internal/client/index.js +18 -0
- package/tests/basic.test.ripple +67 -1
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
is_ripple_import,
|
|
9
9
|
is_tracked_computed_property,
|
|
10
10
|
is_tracked_name,
|
|
11
|
+
is_void_element,
|
|
11
12
|
} from '../../utils.js';
|
|
12
13
|
import { extract_paths } from '../../../utils/ast.js';
|
|
13
14
|
import is_reference from 'is-reference';
|
|
@@ -432,6 +433,8 @@ const visitors = {
|
|
|
432
433
|
const attribute_names = new Set();
|
|
433
434
|
|
|
434
435
|
if (is_dom_element) {
|
|
436
|
+
const is_void = is_void_element(node.id.name);
|
|
437
|
+
|
|
435
438
|
if (state.elements) {
|
|
436
439
|
state.elements.push(node);
|
|
437
440
|
}
|
|
@@ -468,6 +471,14 @@ const visitors = {
|
|
|
468
471
|
);
|
|
469
472
|
}
|
|
470
473
|
}
|
|
474
|
+
|
|
475
|
+
if (is_void && node.children.length > 0) {
|
|
476
|
+
error(
|
|
477
|
+
`The <${node.id.name}> element is a void element and cannot have children`,
|
|
478
|
+
state.analysis.module.filename,
|
|
479
|
+
node,
|
|
480
|
+
);
|
|
481
|
+
}
|
|
471
482
|
} else {
|
|
472
483
|
for (const attr of node.attributes) {
|
|
473
484
|
if (attr.type === 'Attribute') {
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
is_inside_call_expression,
|
|
22
22
|
is_tracked_computed_property,
|
|
23
23
|
is_value_static,
|
|
24
|
+
is_void_element,
|
|
24
25
|
} from '../../utils.js';
|
|
25
26
|
import is_reference from 'is-reference';
|
|
26
27
|
import { extract_paths, object } from '../../../utils/ast.js';
|
|
@@ -148,6 +149,45 @@ const visitors = {
|
|
|
148
149
|
return context.next();
|
|
149
150
|
}
|
|
150
151
|
|
|
152
|
+
// Handle array methods that access the array
|
|
153
|
+
if (
|
|
154
|
+
callee.type === 'MemberExpression' &&
|
|
155
|
+
!callee.optional &&
|
|
156
|
+
callee.property.type === 'Identifier'
|
|
157
|
+
) {
|
|
158
|
+
const name = callee.property.name;
|
|
159
|
+
if (
|
|
160
|
+
// TODO support the missing array methods
|
|
161
|
+
name === 'reduce' ||
|
|
162
|
+
name === 'map' ||
|
|
163
|
+
name === 'forEach' ||
|
|
164
|
+
name === 'join' ||
|
|
165
|
+
name === 'includes' ||
|
|
166
|
+
name === 'indexOf' ||
|
|
167
|
+
name === 'lastIndexOf' ||
|
|
168
|
+
name === 'filter' ||
|
|
169
|
+
name === 'every' ||
|
|
170
|
+
name === 'some' ||
|
|
171
|
+
name === 'toSpliced' ||
|
|
172
|
+
name === 'toSorted' ||
|
|
173
|
+
name === 'toString' ||
|
|
174
|
+
name === 'values' ||
|
|
175
|
+
name === 'entries'
|
|
176
|
+
) {
|
|
177
|
+
return b.call(
|
|
178
|
+
'$.with_scope',
|
|
179
|
+
b.id('__block'),
|
|
180
|
+
b.thunk(
|
|
181
|
+
b.call(
|
|
182
|
+
'$.array_' + name,
|
|
183
|
+
context.visit(callee.object),
|
|
184
|
+
...node.arguments.map((arg) => context.visit(arg)),
|
|
185
|
+
),
|
|
186
|
+
),
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
151
191
|
return b.call(
|
|
152
192
|
'$.with_scope',
|
|
153
193
|
b.id('__block'),
|
|
@@ -399,6 +439,7 @@ const visitors = {
|
|
|
399
439
|
if (is_dom_element) {
|
|
400
440
|
let class_attribute = null;
|
|
401
441
|
const local_updates = [];
|
|
442
|
+
const is_void = is_void_element(node.id.name);
|
|
402
443
|
|
|
403
444
|
state.template.push(`<${node.id.name}`);
|
|
404
445
|
|
|
@@ -590,7 +631,14 @@ const visitors = {
|
|
|
590
631
|
const init = [];
|
|
591
632
|
const update = [];
|
|
592
633
|
|
|
593
|
-
|
|
634
|
+
if (!is_void) {
|
|
635
|
+
transform_children(node.children, {
|
|
636
|
+
visit,
|
|
637
|
+
state: { ...state, init, update },
|
|
638
|
+
root: false,
|
|
639
|
+
});
|
|
640
|
+
state.template.push(`</${node.id.name}>`);
|
|
641
|
+
}
|
|
594
642
|
|
|
595
643
|
update.push(...local_updates);
|
|
596
644
|
|
|
@@ -601,8 +649,6 @@ const visitors = {
|
|
|
601
649
|
if (update.length > 0) {
|
|
602
650
|
state.init.push(b.stmt(b.call('$.render', b.thunk(b.block(update)))));
|
|
603
651
|
}
|
|
604
|
-
|
|
605
|
-
state.template.push(`</${node.id.name}>`);
|
|
606
652
|
} else {
|
|
607
653
|
const id = state.flush_node();
|
|
608
654
|
|
|
@@ -975,43 +1021,37 @@ const visitors = {
|
|
|
975
1021
|
},
|
|
976
1022
|
|
|
977
1023
|
ArrayExpression(node, context) {
|
|
978
|
-
//
|
|
979
|
-
//
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
// i++;
|
|
1010
|
-
// }
|
|
1011
|
-
|
|
1012
|
-
// if (tracked.length > 0) {
|
|
1013
|
-
// return b.call('$.tracked_object', { ...node, elements }, b.array(tracked), b.id('__block'));
|
|
1014
|
-
// }
|
|
1024
|
+
// TODO we can bail out of all of this if we know we're inside a computed fn expression
|
|
1025
|
+
// as the reactivity will hold from the reference of the $ binding itself
|
|
1026
|
+
const elements = [];
|
|
1027
|
+
const tracked = [];
|
|
1028
|
+
let i = 0;
|
|
1029
|
+
|
|
1030
|
+
for (const element of node.elements) {
|
|
1031
|
+
if (element === null) {
|
|
1032
|
+
elements.push(null);
|
|
1033
|
+
} else if (element.type === 'Identifier' && is_tracked_name(element.name)) {
|
|
1034
|
+
const metadata = { tracking: false, await: false };
|
|
1035
|
+
const tracked_identifier = context.visit(element, { ...context.state, metadata });
|
|
1036
|
+
|
|
1037
|
+
if (metadata.tracking) {
|
|
1038
|
+
tracked.push(b.literal(i));
|
|
1039
|
+
elements.push(
|
|
1040
|
+
b.call('$.computed_property', b.thunk(tracked_identifier), b.id('__block')),
|
|
1041
|
+
);
|
|
1042
|
+
} else {
|
|
1043
|
+
elements.push(tracked_identifier);
|
|
1044
|
+
}
|
|
1045
|
+
} else {
|
|
1046
|
+
const metadata = { tracking: false, await: false };
|
|
1047
|
+
elements.push(context.visit(element, { ...context.state, metadata }));
|
|
1048
|
+
}
|
|
1049
|
+
i++;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
if (tracked.length > 0) {
|
|
1053
|
+
return b.call('$.tracked_object', { ...node, elements }, b.array(tracked), b.id('__block'));
|
|
1054
|
+
}
|
|
1015
1055
|
|
|
1016
1056
|
context.next();
|
|
1017
1057
|
},
|
package/src/compiler/utils.js
CHANGED
|
@@ -3,6 +3,33 @@ import * as b from '../utils/builders.js';
|
|
|
3
3
|
|
|
4
4
|
const regex_return_characters = /\r/g;
|
|
5
5
|
|
|
6
|
+
const VOID_ELEMENT_NAMES = [
|
|
7
|
+
'area',
|
|
8
|
+
'base',
|
|
9
|
+
'br',
|
|
10
|
+
'col',
|
|
11
|
+
'command',
|
|
12
|
+
'embed',
|
|
13
|
+
'hr',
|
|
14
|
+
'img',
|
|
15
|
+
'input',
|
|
16
|
+
'keygen',
|
|
17
|
+
'link',
|
|
18
|
+
'meta',
|
|
19
|
+
'param',
|
|
20
|
+
'source',
|
|
21
|
+
'track',
|
|
22
|
+
'wbr'
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Returns `true` if `name` is of a void element
|
|
27
|
+
* @param {string} name
|
|
28
|
+
*/
|
|
29
|
+
export function is_void_element(name) {
|
|
30
|
+
return VOID_ELEMENT_NAMES.includes(name) || name.toLowerCase() === '!doctype';
|
|
31
|
+
}
|
|
32
|
+
|
|
6
33
|
const RESERVED_WORDS = [
|
|
7
34
|
'arguments',
|
|
8
35
|
'await',
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import { TRACKED_OBJECT } from './constants';
|
|
2
|
+
import { get_property } from './runtime';
|
|
3
|
+
|
|
4
|
+
const array_proto = Array.prototype;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @template T
|
|
8
|
+
* @param {Array<T>} array
|
|
9
|
+
* @param {(previousValue: T, currentValue: T, currentIndex: number, array: Array<T>) => T} callback
|
|
10
|
+
* @param {T} initial_value
|
|
11
|
+
* @returns {T}
|
|
12
|
+
*/
|
|
13
|
+
export function array_reduce(array, callback, initial_value) {
|
|
14
|
+
// @ts-expect-error
|
|
15
|
+
var tracked_properties = array[TRACKED_OBJECT];
|
|
16
|
+
|
|
17
|
+
if (tracked_properties === undefined || array.reduce !== array_proto.reduce) {
|
|
18
|
+
return array.reduce(callback, initial_value);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let accumulator = initial_value;
|
|
22
|
+
|
|
23
|
+
for (let i = 0; i < array.length; i++) {
|
|
24
|
+
accumulator = callback(accumulator, get_property(array, i), i, array);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return accumulator;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @template T
|
|
32
|
+
* @param {Array<T>} array
|
|
33
|
+
* @param {string} [separator]
|
|
34
|
+
* @returns {string}
|
|
35
|
+
*/
|
|
36
|
+
export function array_join(array, separator) {
|
|
37
|
+
// @ts-expect-error
|
|
38
|
+
var tracked_properties = array[TRACKED_OBJECT];
|
|
39
|
+
if (tracked_properties === undefined || array.join !== array_proto.join) {
|
|
40
|
+
return array.join(separator);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let result = '';
|
|
44
|
+
for (let i = 0; i < array.length; i++) {
|
|
45
|
+
if (i > 0 && separator !== undefined) {
|
|
46
|
+
result += separator;
|
|
47
|
+
}
|
|
48
|
+
result += String(get_property(array, i));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @template T
|
|
56
|
+
* @template U
|
|
57
|
+
* @param {Array<T>} array
|
|
58
|
+
* @param {(value: T, index: number, array: Array<T>) => U} callback
|
|
59
|
+
* @returns {Array<U>}
|
|
60
|
+
*/
|
|
61
|
+
export function array_map(array, callback) {
|
|
62
|
+
// @ts-expect-error
|
|
63
|
+
var tracked_properties = array[TRACKED_OBJECT];
|
|
64
|
+
if (tracked_properties === undefined || array.map !== array_proto.map) {
|
|
65
|
+
return array.map(callback);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const result = [];
|
|
69
|
+
for (let i = 0; i < array.length; i++) {
|
|
70
|
+
if (i in array) {
|
|
71
|
+
result[i] = callback(get_property(array, i), i, array);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @template T
|
|
80
|
+
* @param {Array<T>} array
|
|
81
|
+
* @param {(value: T, index: number, array: Array<T>) => boolean} callback
|
|
82
|
+
* @returns {Array<T>}
|
|
83
|
+
*/
|
|
84
|
+
export function array_filter(array, callback) {
|
|
85
|
+
// @ts-expect-error
|
|
86
|
+
var tracked_properties = array[TRACKED_OBJECT];
|
|
87
|
+
if (tracked_properties === undefined || array.filter !== array_proto.filter) {
|
|
88
|
+
return array.filter(callback);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const result = [];
|
|
92
|
+
for (let i = 0; i < array.length; i++) {
|
|
93
|
+
if (i in array) {
|
|
94
|
+
const value = get_property(array, i);
|
|
95
|
+
if (callback(value, i, array)) {
|
|
96
|
+
result.push(value);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @template T
|
|
106
|
+
* @param {Array<T>} array
|
|
107
|
+
* @param {(value: T, index: number, array: Array<T>) => boolean} callback
|
|
108
|
+
* @returns {void}
|
|
109
|
+
*/
|
|
110
|
+
export function array_forEach(array, callback) {
|
|
111
|
+
// @ts-expect-error
|
|
112
|
+
var tracked_properties = array[TRACKED_OBJECT];
|
|
113
|
+
if (tracked_properties === undefined || array.forEach !== array_proto.forEach) {
|
|
114
|
+
return array.forEach(callback);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
for (let i = 0; i < array.length; i++) {
|
|
118
|
+
if (i in array) {
|
|
119
|
+
callback(get_property(array, i), i, array);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* @template T
|
|
126
|
+
* @param {Array<T>} array
|
|
127
|
+
* @param {T} value
|
|
128
|
+
* @returns {boolean}
|
|
129
|
+
*/
|
|
130
|
+
export function array_includes(array, value) {
|
|
131
|
+
// @ts-expect-error
|
|
132
|
+
var tracked_properties = array[TRACKED_OBJECT];
|
|
133
|
+
if (tracked_properties === undefined || array.includes !== array_proto.includes) {
|
|
134
|
+
return array.includes(value);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
for (let i = 0; i < array.length; i++) {
|
|
138
|
+
if (i in array && get_property(array, i) === value) {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @template T
|
|
148
|
+
* @param {Array<T>} array
|
|
149
|
+
* @param {T} value
|
|
150
|
+
* @returns {number}
|
|
151
|
+
*/
|
|
152
|
+
export function array_indexOf(array, value) {
|
|
153
|
+
// @ts-expect-error
|
|
154
|
+
var tracked_properties = array[TRACKED_OBJECT];
|
|
155
|
+
if (tracked_properties === undefined || array.indexOf !== array_proto.indexOf) {
|
|
156
|
+
return array.indexOf(value);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
for (let i = 0; i < array.length; i++) {
|
|
160
|
+
if (i in array && get_property(array, i) === value) {
|
|
161
|
+
return i;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return -1;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* @template T
|
|
170
|
+
* @param {Array<T>} array
|
|
171
|
+
* @param {T} value
|
|
172
|
+
* @returns {number}
|
|
173
|
+
*/
|
|
174
|
+
export function array_lastIndexOf(array, value) {
|
|
175
|
+
// @ts-expect-error
|
|
176
|
+
var tracked_properties = array[TRACKED_OBJECT];
|
|
177
|
+
if (tracked_properties === undefined || array.lastIndexOf !== array_proto.lastIndexOf) {
|
|
178
|
+
return array.lastIndexOf(value);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
for (let i = array.length - 1; i >= 0; i--) {
|
|
182
|
+
if (i in array && get_property(array, i) === value) {
|
|
183
|
+
return i;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return -1;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @template T
|
|
192
|
+
* @param {Array<T>} array
|
|
193
|
+
* @param {(value: T, index: number, array: Array<T>) => boolean} callback
|
|
194
|
+
* @returns {boolean}
|
|
195
|
+
*/
|
|
196
|
+
export function array_every(array, callback) {
|
|
197
|
+
// @ts-expect-error
|
|
198
|
+
var tracked_properties = array[TRACKED_OBJECT];
|
|
199
|
+
if (tracked_properties === undefined || array.every !== array_proto.every) {
|
|
200
|
+
return array.every(callback);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
for (let i = 0; i < array.length; i++) {
|
|
204
|
+
if (i in array && !callback(get_property(array, i), i, array)) {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @template T
|
|
214
|
+
* @param {Array<T>} array
|
|
215
|
+
* @param {(value: T, index: number, array: Array<T>) => boolean} callback
|
|
216
|
+
* @returns {boolean}
|
|
217
|
+
*/
|
|
218
|
+
export function array_some(array, callback) {
|
|
219
|
+
// @ts-expect-error
|
|
220
|
+
var tracked_properties = array[TRACKED_OBJECT];
|
|
221
|
+
if (tracked_properties === undefined || array.some !== array_proto.some) {
|
|
222
|
+
return array.some(callback);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
for (let i = 0; i < array.length; i++) {
|
|
226
|
+
if (i in array && callback(get_property(array, i), i, array)) {
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* @template T
|
|
236
|
+
* @param {Array<T>} array
|
|
237
|
+
* @returns {string}
|
|
238
|
+
*/
|
|
239
|
+
export function array_toString(array) {
|
|
240
|
+
// @ts-expect-error
|
|
241
|
+
var tracked_properties = array[TRACKED_OBJECT];
|
|
242
|
+
if (tracked_properties === undefined || array.toString !== array_proto.toString) {
|
|
243
|
+
return array.toString();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
let result = '';
|
|
247
|
+
for (let i = 0; i < array.length; i++) {
|
|
248
|
+
if (i > 0) {
|
|
249
|
+
result += ',';
|
|
250
|
+
}
|
|
251
|
+
if (i in array) {
|
|
252
|
+
result += String(get_property(array, i));
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return result;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* @template T
|
|
261
|
+
* @param {Array<T>} array
|
|
262
|
+
* @param {((a: T, b: T) => number) | undefined} compare_fn
|
|
263
|
+
* @returns {Array<T>}
|
|
264
|
+
*/
|
|
265
|
+
export function array_toSorted(array, compare_fn) {
|
|
266
|
+
// @ts-expect-error
|
|
267
|
+
var tracked_properties = array[TRACKED_OBJECT];
|
|
268
|
+
if (tracked_properties === undefined || array.toSorted !== array_proto.toSorted) {
|
|
269
|
+
return array.toSorted(compare_fn);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const result = [];
|
|
273
|
+
for (let i = 0; i < array.length; i++) {
|
|
274
|
+
if (i in array) {
|
|
275
|
+
result.push(get_property(array, i));
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return result.sort(compare_fn);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* @template T
|
|
284
|
+
* @param {Array<T>} array
|
|
285
|
+
* @param {number} start
|
|
286
|
+
* @param {number} delete_count
|
|
287
|
+
* @param {...T} items
|
|
288
|
+
* @returns {Array<T>}
|
|
289
|
+
*/
|
|
290
|
+
export function array_toSpliced(array, start, delete_count, ...items) {
|
|
291
|
+
// @ts-expect-error
|
|
292
|
+
var tracked_properties = array[TRACKED_OBJECT];
|
|
293
|
+
if (tracked_properties === undefined || array.toSpliced !== array_proto.toSpliced) {
|
|
294
|
+
return array.toSpliced(start, delete_count, ...items);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const result = [];
|
|
298
|
+
for (let i = 0; i < array.length; i++) {
|
|
299
|
+
if (i in array) {
|
|
300
|
+
result.push(get_property(array, i));
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
result.splice(start, delete_count, ...items);
|
|
305
|
+
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* @template T
|
|
311
|
+
* @param {Array<T>} array
|
|
312
|
+
* @returns {IterableIterator<T>}
|
|
313
|
+
*/
|
|
314
|
+
export function array_values(array) {
|
|
315
|
+
// @ts-expect-error
|
|
316
|
+
var tracked_properties = array[TRACKED_OBJECT];
|
|
317
|
+
if (tracked_properties === undefined || array.values !== array_proto.values) {
|
|
318
|
+
return array.values();
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const result = [];
|
|
322
|
+
for (let i = 0; i < array.length; i++) {
|
|
323
|
+
if (i in array) {
|
|
324
|
+
result.push(get_property(array, i));
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return result[Symbol.iterator]();
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* @template T
|
|
333
|
+
* @param {Array<T>} array
|
|
334
|
+
* @returns {IterableIterator<[number, T]>}
|
|
335
|
+
*/
|
|
336
|
+
export function array_entries(array) {
|
|
337
|
+
// @ts-expect-error
|
|
338
|
+
var tracked_properties = array[TRACKED_OBJECT];
|
|
339
|
+
if (tracked_properties === undefined || array.entries !== array_proto.entries) {
|
|
340
|
+
return array.entries();
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/** @type {Array<[number, T]>} */
|
|
344
|
+
const result = [];
|
|
345
|
+
for (let i = 0; i < array.length; i++) {
|
|
346
|
+
if (i in array) {
|
|
347
|
+
result.push([i, get_property(array, i)]);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return result[Symbol.iterator]();
|
|
352
|
+
}
|
|
@@ -46,6 +46,24 @@ export {
|
|
|
46
46
|
exclude_from_object,
|
|
47
47
|
} from './runtime.js';
|
|
48
48
|
|
|
49
|
+
export {
|
|
50
|
+
array_reduce,
|
|
51
|
+
array_join,
|
|
52
|
+
array_map,
|
|
53
|
+
array_filter,
|
|
54
|
+
array_forEach,
|
|
55
|
+
array_includes,
|
|
56
|
+
array_indexOf,
|
|
57
|
+
array_lastIndexOf,
|
|
58
|
+
array_every,
|
|
59
|
+
array_some,
|
|
60
|
+
array_toString,
|
|
61
|
+
array_toSorted,
|
|
62
|
+
array_toSpliced,
|
|
63
|
+
array_values,
|
|
64
|
+
array_entries,
|
|
65
|
+
} from './array.js';
|
|
66
|
+
|
|
49
67
|
export { for_block as for } from './for.js';
|
|
50
68
|
|
|
51
69
|
export { if_block as if } from './if.js';
|
package/tests/basic.test.ripple
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { mount, flushSync } from 'ripple';
|
|
2
|
+
import { mount, flushSync, effect } from 'ripple';
|
|
3
3
|
|
|
4
4
|
describe('basic', () => {
|
|
5
5
|
let container;
|
|
@@ -832,4 +832,70 @@ describe('basic', () => {
|
|
|
832
832
|
expect(paragraphs[0].className).toBe('parent-class');
|
|
833
833
|
expect(paragraphs[1].className).toBe('nested-class');
|
|
834
834
|
});
|
|
835
|
+
|
|
836
|
+
it('basic reactivity with standard arrays should work', () => {
|
|
837
|
+
let logs = [];
|
|
838
|
+
|
|
839
|
+
component App() {
|
|
840
|
+
let $first = 0;
|
|
841
|
+
let $second = 0;
|
|
842
|
+
const arr = [$first, $second];
|
|
843
|
+
|
|
844
|
+
const $total = arr.reduce((a, b) => a + b, 0);
|
|
845
|
+
|
|
846
|
+
<button onClick={() => { $first++; }}>{'first:' + $first}</button>
|
|
847
|
+
<button onClick={() => { $second++; }}>{'second: ' + $second}</button>
|
|
848
|
+
|
|
849
|
+
effect(() => {
|
|
850
|
+
let _arr = [];
|
|
851
|
+
|
|
852
|
+
arr.forEach((item) => {
|
|
853
|
+
_arr.push(item);
|
|
854
|
+
});
|
|
855
|
+
|
|
856
|
+
logs.push(_arr.join(', '));
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
effect(() => {
|
|
860
|
+
if (arr.includes(1)) {
|
|
861
|
+
logs.push('arr includes 1');
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
<div>{'Sum: ' + $total}</div>
|
|
866
|
+
<div>{'Comma Separated: ' + arr.join(', ')}</div>
|
|
867
|
+
<div>{'Number to string: ' + arr.map(a => String(a))}</div>
|
|
868
|
+
<div>{'Even numbers: ' + arr.filter(a => a % 2 === 0)}</div>
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
render(App);
|
|
872
|
+
flushSync();
|
|
873
|
+
|
|
874
|
+
const buttons = container.querySelectorAll('button');
|
|
875
|
+
const divs = container.querySelectorAll('div');
|
|
876
|
+
|
|
877
|
+
expect(divs[0].textContent).toBe('Sum: 0');
|
|
878
|
+
expect(divs[1].textContent).toBe('Comma Separated: 0, 0');
|
|
879
|
+
expect(divs[2].textContent).toBe('Number to string: 0,0');
|
|
880
|
+
expect(divs[3].textContent).toBe('Even numbers: 0,0');
|
|
881
|
+
expect(logs).toEqual(['0, 0']);
|
|
882
|
+
|
|
883
|
+
buttons[0].click();
|
|
884
|
+
flushSync();
|
|
885
|
+
|
|
886
|
+
expect(divs[0].textContent).toBe('Sum: 1');
|
|
887
|
+
expect(divs[1].textContent).toBe('Comma Separated: 1, 0');
|
|
888
|
+
expect(divs[2].textContent).toBe('Number to string: 1,0');
|
|
889
|
+
expect(divs[3].textContent).toBe('Even numbers: 0');
|
|
890
|
+
expect(logs).toEqual(['0, 0', '1, 0', 'arr includes 1']);
|
|
891
|
+
|
|
892
|
+
buttons[1].click();
|
|
893
|
+
flushSync();
|
|
894
|
+
|
|
895
|
+
expect(divs[0].textContent).toBe('Sum: 2');
|
|
896
|
+
expect(divs[1].textContent).toBe('Comma Separated: 1, 1');
|
|
897
|
+
expect(divs[2].textContent).toBe('Number to string: 1,1');
|
|
898
|
+
expect(divs[3].textContent).toBe('Even numbers: ');
|
|
899
|
+
expect(logs).toEqual(['0, 0', '1, 0', 'arr includes 1', '1, 1']);
|
|
900
|
+
})
|
|
835
901
|
});
|