ripple 0.2.116 → 0.2.118
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 +16 -16
- package/src/compiler/index.js +20 -1
- package/src/compiler/phases/3-transform/segments.js +99 -57
- package/src/compiler/phases/3-transform/server/index.js +21 -11
- package/src/runtime/index-client.js +1 -1
- package/src/runtime/index-server.js +24 -0
- package/src/runtime/internal/client/runtime.js +10 -0
- package/src/runtime/internal/client/utils.js +0 -8
- package/tests/client/__snapshots__/for.test.ripple.snap +80 -0
- package/tests/client/_etc.test.ripple +5 -0
- package/tests/client/array/array.copy-within.test.ripple +120 -0
- package/tests/client/array/array.derived.test.ripple +495 -0
- package/tests/client/array/array.iteration.test.ripple +115 -0
- package/tests/client/array/array.mutations.test.ripple +385 -0
- package/tests/client/array/array.static.test.ripple +237 -0
- package/tests/client/array/array.to-methods.test.ripple +93 -0
- package/tests/client/basic/__snapshots__/basic.attributes.test.ripple.snap +60 -0
- package/tests/client/basic/__snapshots__/basic.rendering.test.ripple.snap +106 -0
- package/tests/client/basic/__snapshots__/basic.text.test.ripple.snap +49 -0
- package/tests/client/basic/basic.attributes.test.ripple +474 -0
- package/tests/client/basic/basic.collections.test.ripple +94 -0
- package/tests/client/basic/basic.components.test.ripple +225 -0
- package/tests/client/basic/basic.errors.test.ripple +126 -0
- package/tests/client/basic/basic.events.test.ripple +222 -0
- package/tests/client/basic/basic.reactivity.test.ripple +476 -0
- package/tests/client/basic/basic.rendering.test.ripple +204 -0
- package/tests/client/basic/basic.styling.test.ripple +63 -0
- package/tests/client/basic/basic.utilities.test.ripple +25 -0
- package/tests/client/boundaries.test.ripple +2 -21
- package/tests/client/compiler/__snapshots__/compiler.assignments.test.ripple.snap +12 -0
- package/tests/client/compiler/__snapshots__/compiler.typescript.test.ripple.snap +22 -0
- package/tests/client/compiler/compiler.assignments.test.ripple +112 -0
- package/tests/client/compiler/compiler.attributes.test.ripple +95 -0
- package/tests/client/compiler/compiler.basic.test.ripple +203 -0
- package/tests/client/compiler/compiler.regex.test.ripple +87 -0
- package/tests/client/compiler/compiler.typescript.test.ripple +29 -0
- package/tests/client/{__snapshots__/composite.test.ripple.snap → composite/__snapshots__/composite.render.test.ripple.snap} +2 -2
- package/tests/client/composite/composite.dynamic-components.test.ripple +100 -0
- package/tests/client/composite/composite.generics.test.ripple +211 -0
- package/tests/client/composite/composite.props.test.ripple +106 -0
- package/tests/client/composite/composite.reactivity.test.ripple +184 -0
- package/tests/client/composite/composite.render.test.ripple +84 -0
- package/tests/client/computed-properties.test.ripple +2 -21
- package/tests/client/context.test.ripple +5 -22
- package/tests/client/date.test.ripple +1 -20
- package/tests/client/dynamic-elements.test.ripple +16 -24
- package/tests/client/for.test.ripple +4 -23
- package/tests/client/head.test.ripple +11 -23
- package/tests/client/html.test.ripple +1 -20
- package/tests/client/input-value.test.ripple +11 -31
- package/tests/client/map.test.ripple +3 -22
- package/tests/client/media-query.test.ripple +10 -23
- package/tests/client/object.test.ripple +5 -24
- package/tests/client/portal.test.ripple +2 -19
- package/tests/client/ref.test.ripple +8 -26
- package/tests/client/set.test.ripple +3 -22
- package/tests/client/svg.test.ripple +1 -22
- package/tests/client/switch.test.ripple +6 -25
- package/tests/client/tracked-expression.test.ripple +2 -21
- package/tests/client/typescript-generics.test.ripple +0 -21
- package/tests/client/url/url.derived.test.ripple +83 -0
- package/tests/client/url/url.parsing.test.ripple +165 -0
- package/tests/client/url/url.partial-removal.test.ripple +198 -0
- package/tests/client/url/url.reactivity.test.ripple +449 -0
- package/tests/client/url/url.serialization.test.ripple +50 -0
- package/tests/client/url-search-params/url-search-params.derived.test.ripple +84 -0
- package/tests/client/url-search-params/url-search-params.initialization.test.ripple +61 -0
- package/tests/client/url-search-params/url-search-params.iteration.test.ripple +153 -0
- package/tests/client/url-search-params/url-search-params.mutation.test.ripple +343 -0
- package/tests/client/url-search-params/url-search-params.retrieval.test.ripple +160 -0
- package/tests/client/url-search-params/url-search-params.serialization.test.ripple +53 -0
- package/tests/client/url-search-params/url-search-params.tracked-url.test.ripple +55 -0
- package/tests/client.d.ts +12 -0
- package/tests/server/if.test.ripple +66 -0
- package/tests/setup-client.js +28 -0
- package/tsconfig.json +4 -2
- package/types/index.d.ts +5 -1
- package/LICENSE +0 -21
- package/tests/client/__snapshots__/basic.test.ripple.snap +0 -117
- package/tests/client/__snapshots__/compiler.test.ripple.snap +0 -33
- package/tests/client/array.test.ripple +0 -1455
- package/tests/client/basic.test.ripple +0 -1892
- package/tests/client/compiler.test.ripple +0 -541
- package/tests/client/composite.test.ripple +0 -692
- package/tests/client/url-search-params.test.ripple +0 -912
- package/tests/client/url.test.ripple +0 -954
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.118",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"module": "src/runtime/index-client.js",
|
|
9
9
|
"main": "src/runtime/index-client.js",
|
|
@@ -63,21 +63,21 @@
|
|
|
63
63
|
"#public": "./types/index.d.ts"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@jridgewell/sourcemap-codec": "
|
|
67
|
-
"@sveltejs/acorn-typescript": "
|
|
68
|
-
"acorn": "
|
|
69
|
-
"clsx": "
|
|
70
|
-
"devalue": "
|
|
71
|
-
"esm-env": "
|
|
72
|
-
"esrap": "
|
|
73
|
-
"is-reference": "
|
|
74
|
-
"magic-string": "
|
|
75
|
-
"muggle-string": "
|
|
76
|
-
"zimmerframe": "
|
|
66
|
+
"@jridgewell/sourcemap-codec": "catalog:default",
|
|
67
|
+
"@sveltejs/acorn-typescript": "catalog:default",
|
|
68
|
+
"acorn": "catalog:default",
|
|
69
|
+
"clsx": "catalog:default",
|
|
70
|
+
"devalue": "catalog:default",
|
|
71
|
+
"esm-env": "catalog:default",
|
|
72
|
+
"esrap": "catalog:default",
|
|
73
|
+
"is-reference": "catalog:default",
|
|
74
|
+
"magic-string": "catalog:default",
|
|
75
|
+
"muggle-string": "catalog:default",
|
|
76
|
+
"zimmerframe": "catalog:default"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
|
-
"@types/estree": "
|
|
80
|
-
"@types/node": "
|
|
81
|
-
"typescript": "
|
|
79
|
+
"@types/estree": "catalog:default",
|
|
80
|
+
"@types/node": "catalog:default",
|
|
81
|
+
"typescript": "catalog:default"
|
|
82
82
|
}
|
|
83
|
-
}
|
|
83
|
+
}
|
package/src/compiler/index.js
CHANGED
|
@@ -41,9 +41,28 @@ export function compile(source, filename, options = {}) {
|
|
|
41
41
|
export function compile_to_volar_mappings(source, filename) {
|
|
42
42
|
// Parse and transform
|
|
43
43
|
const ast = parse_module(source);
|
|
44
|
+
|
|
45
|
+
// Add unique IDs to import declarations before transformation
|
|
46
|
+
// This allows us to match source imports with generated imports reliably
|
|
47
|
+
// This strategy can potentially be used for other node types in the future
|
|
48
|
+
let gen_id = 0;
|
|
49
|
+
const source_import_map = new Map();
|
|
50
|
+
for (const node of ast.body) {
|
|
51
|
+
if (node.type === 'ImportDeclaration') {
|
|
52
|
+
const start = /** @type {any} */ (node).start;
|
|
53
|
+
const end = /** @type {any} */ (node).end;
|
|
54
|
+
if (start !== undefined && end !== undefined) {
|
|
55
|
+
// Add a unique ID as a string property that will be copied during transformation
|
|
56
|
+
const id = `__volar_import_${gen_id++}__`;
|
|
57
|
+
/** @type {any} */ (node).__volar_id = id;
|
|
58
|
+
source_import_map.set(id, { start, end });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
44
63
|
const analysis = analyze(ast, filename);
|
|
45
64
|
const transformed = transform_client(filename, source, analysis, true);
|
|
46
65
|
|
|
47
66
|
// Create volar mappings directly from the AST instead of relying on esrap's sourcemap
|
|
48
|
-
return convert_source_map_to_mappings(transformed.ast, source, transformed.js.code);
|
|
67
|
+
return convert_source_map_to_mappings(transformed.ast, source, transformed.js.code, source_import_map);
|
|
49
68
|
}
|
|
@@ -20,22 +20,23 @@ export const mapping_data = {
|
|
|
20
20
|
* @param {any} ast - The transformed AST
|
|
21
21
|
* @param {string} source - Original source code
|
|
22
22
|
* @param {string} generated_code - Generated code from esrap
|
|
23
|
+
* @param {Map<string, {start: number, end: number}>} [source_import_map] - Map of __volar_id strings to source positions
|
|
23
24
|
* @returns {object}
|
|
24
25
|
*/
|
|
25
|
-
export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
26
|
+
export function convert_source_map_to_mappings(ast, source, generated_code, source_import_map) {
|
|
26
27
|
/** @type {Array<{sourceOffsets: number[], generatedOffsets: number[], lengths: number[], data: any}>} */
|
|
27
28
|
const mappings = [];
|
|
28
29
|
|
|
29
30
|
// Maintain indices that walk through source and generated code
|
|
30
|
-
let
|
|
31
|
-
let
|
|
31
|
+
let source_index = 0;
|
|
32
|
+
let generated_index = 0;
|
|
32
33
|
|
|
33
34
|
// Map to track capitalized names: original name -> capitalized name
|
|
34
35
|
/** @type {Map<string, string>} */
|
|
35
|
-
const
|
|
36
|
+
const capitalized_names = new Map();
|
|
36
37
|
// Reverse map: capitalized name -> original name
|
|
37
38
|
/** @type {Map<string, string>} */
|
|
38
|
-
const
|
|
39
|
+
const reverse_capitalized_names = new Map();
|
|
39
40
|
|
|
40
41
|
// Pre-walk to collect capitalized names from JSXElement nodes (transformed AST)
|
|
41
42
|
// These are identifiers that are used as dynamic components/elements
|
|
@@ -43,8 +44,8 @@ export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
|
43
44
|
_(node, { next }) {
|
|
44
45
|
// Check JSXElement nodes with metadata (preserved from Element nodes)
|
|
45
46
|
if (node.type === 'JSXElement' && node.metadata?.ts_name && node.metadata?.original_name) {
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
capitalized_names.set(node.metadata.original_name, node.metadata.ts_name);
|
|
48
|
+
reverse_capitalized_names.set(node.metadata.ts_name, node.metadata.original_name);
|
|
48
49
|
}
|
|
49
50
|
next();
|
|
50
51
|
}
|
|
@@ -55,7 +56,7 @@ export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
|
55
56
|
* @param {string} char
|
|
56
57
|
* @returns {boolean}
|
|
57
58
|
*/
|
|
58
|
-
const
|
|
59
|
+
const is_word_boundary = (char) => {
|
|
59
60
|
return char === undefined || !/[a-zA-Z0-9_$]/.test(char);
|
|
60
61
|
};
|
|
61
62
|
|
|
@@ -64,7 +65,7 @@ export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
|
64
65
|
* @param {number} pos - Position to check
|
|
65
66
|
* @returns {boolean}
|
|
66
67
|
*/
|
|
67
|
-
const
|
|
68
|
+
const is_in_comment = (pos) => {
|
|
68
69
|
// Check for single-line comment: find start of line and check if there's // before this position
|
|
69
70
|
let lineStart = source.lastIndexOf('\n', pos - 1) + 1;
|
|
70
71
|
const lineBeforePos = source.substring(lineStart, pos);
|
|
@@ -87,8 +88,8 @@ export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
|
87
88
|
* @param {string} text - Text to find
|
|
88
89
|
* @returns {number|null} - Source position or null
|
|
89
90
|
*/
|
|
90
|
-
const
|
|
91
|
-
for (let i =
|
|
91
|
+
const find_in_source = (text) => {
|
|
92
|
+
for (let i = source_index; i <= source.length - text.length; i++) {
|
|
92
93
|
let match = true;
|
|
93
94
|
for (let j = 0; j < text.length; j++) {
|
|
94
95
|
if (source[i + j] !== text[j]) {
|
|
@@ -98,7 +99,7 @@ export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
|
98
99
|
}
|
|
99
100
|
if (match) {
|
|
100
101
|
// Skip if this match is inside a comment
|
|
101
|
-
if (
|
|
102
|
+
if (is_in_comment(i)) {
|
|
102
103
|
continue;
|
|
103
104
|
}
|
|
104
105
|
|
|
@@ -107,12 +108,12 @@ export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
|
107
108
|
if (isIdentifierLike) {
|
|
108
109
|
const charBefore = source[i - 1];
|
|
109
110
|
const charAfter = source[i + text.length];
|
|
110
|
-
if (!
|
|
111
|
+
if (!is_word_boundary(charBefore) || !is_word_boundary(charAfter)) {
|
|
111
112
|
continue; // Not a whole word match, keep searching
|
|
112
113
|
}
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
source_index = i + text.length;
|
|
116
117
|
return i;
|
|
117
118
|
}
|
|
118
119
|
}
|
|
@@ -120,12 +121,12 @@ export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
|
120
121
|
};
|
|
121
122
|
|
|
122
123
|
/**
|
|
123
|
-
* Find text in generated code, searching character by character from
|
|
124
|
+
* Find text in generated code, searching character by character from generated_index
|
|
124
125
|
* @param {string} text - Text to find
|
|
125
126
|
* @returns {number|null} - Generated position or null
|
|
126
127
|
*/
|
|
127
|
-
const
|
|
128
|
-
for (let i =
|
|
128
|
+
const find_in_generated = (text) => {
|
|
129
|
+
for (let i = generated_index; i <= generated_code.length - text.length; i++) {
|
|
129
130
|
let match = true;
|
|
130
131
|
for (let j = 0; j < text.length; j++) {
|
|
131
132
|
if (generated_code[i + j] !== text[j]) {
|
|
@@ -139,12 +140,12 @@ export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
|
139
140
|
if (isIdentifierLike) {
|
|
140
141
|
const charBefore = generated_code[i - 1];
|
|
141
142
|
const charAfter = generated_code[i + text.length];
|
|
142
|
-
if (!
|
|
143
|
+
if (!is_word_boundary(charBefore) || !is_word_boundary(charAfter)) {
|
|
143
144
|
continue; // Not a whole word match, keep searching
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
147
|
|
|
147
|
-
|
|
148
|
+
generated_index = i + text.length;
|
|
148
149
|
return i;
|
|
149
150
|
}
|
|
150
151
|
}
|
|
@@ -157,8 +158,8 @@ export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
|
157
158
|
const tokens = [];
|
|
158
159
|
|
|
159
160
|
// Collect import declarations for full-statement mappings
|
|
160
|
-
/** @type {Array<{
|
|
161
|
-
const
|
|
161
|
+
/** @type {Array<{id: string, node: any}>} */
|
|
162
|
+
const import_declarations = [];
|
|
162
163
|
|
|
163
164
|
// We have to visit everything in generated order to maintain correct indices
|
|
164
165
|
walk(ast, null, {
|
|
@@ -172,17 +173,23 @@ export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
|
172
173
|
tokens.push({ source: node.metadata.tracked_shorthand, generated: node.name });
|
|
173
174
|
} else {
|
|
174
175
|
// Check if this identifier was capitalized (reverse lookup)
|
|
175
|
-
const
|
|
176
|
-
if (
|
|
176
|
+
const original_name = reverse_capitalized_names.get(node.name);
|
|
177
|
+
if (original_name) {
|
|
177
178
|
// This is a capitalized name in generated code, map to lowercase in source
|
|
178
|
-
tokens.push({ source:
|
|
179
|
+
tokens.push({ source: original_name, generated: node.name });
|
|
179
180
|
} else {
|
|
180
181
|
// Check if this identifier should be capitalized (forward lookup)
|
|
181
|
-
const
|
|
182
|
-
if (
|
|
183
|
-
tokens.push({ source: node.name, generated:
|
|
182
|
+
const cap_name = capitalized_names.get(node.name);
|
|
183
|
+
if (cap_name) {
|
|
184
|
+
tokens.push({ source: node.name, generated: cap_name });
|
|
184
185
|
} else {
|
|
185
|
-
|
|
186
|
+
// Check if this identifier should be capitalized (forward lookup)
|
|
187
|
+
const cap_name = capitalized_names.get(node.name);
|
|
188
|
+
if (cap_name) {
|
|
189
|
+
tokens.push({ source: node.name, generated: cap_name });
|
|
190
|
+
} else {
|
|
191
|
+
tokens.push(node.name);
|
|
192
|
+
}
|
|
186
193
|
}
|
|
187
194
|
}
|
|
188
195
|
}
|
|
@@ -191,12 +198,12 @@ export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
|
191
198
|
} else if (node.type === 'JSXIdentifier' && node.name) {
|
|
192
199
|
if (node.loc) {
|
|
193
200
|
// Check if this was capitalized (reverse lookup)
|
|
194
|
-
const originalName =
|
|
201
|
+
const originalName = reverse_capitalized_names.get(node.name);
|
|
195
202
|
if (originalName) {
|
|
196
203
|
tokens.push({ source: originalName, generated: node.name });
|
|
197
204
|
} else {
|
|
198
205
|
// Check if this should be capitalized (forward lookup)
|
|
199
|
-
const capitalizedName =
|
|
206
|
+
const capitalizedName = capitalized_names.get(node.name);
|
|
200
207
|
if (capitalizedName) {
|
|
201
208
|
tokens.push({ source: node.name, generated: capitalizedName });
|
|
202
209
|
} else {
|
|
@@ -211,10 +218,16 @@ export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
|
211
218
|
}
|
|
212
219
|
return; // Leaf node, don't traverse further
|
|
213
220
|
} else if (node.type === 'ImportDeclaration') {
|
|
214
|
-
// Collect import declaration
|
|
221
|
+
// Collect import declaration for full-statement mapping
|
|
215
222
|
// TypeScript reports unused imports with diagnostics covering the entire statement
|
|
216
|
-
|
|
217
|
-
|
|
223
|
+
// Store the __volar_id - we'll find the generated position later by searching
|
|
224
|
+
const volar_id = /** @type {any} */ (node).__volar_id;
|
|
225
|
+
if (volar_id) {
|
|
226
|
+
import_declarations.push({
|
|
227
|
+
id: volar_id,
|
|
228
|
+
// We'll calculate genStart/genEnd later by searching in generated code
|
|
229
|
+
node: node
|
|
230
|
+
});
|
|
218
231
|
}
|
|
219
232
|
|
|
220
233
|
// Visit specifiers in source order
|
|
@@ -315,12 +328,12 @@ export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
|
315
328
|
if (!node.openingElement?.selfClosing && node.closingElement?.name?.type === 'JSXIdentifier') {
|
|
316
329
|
const closingName = node.closingElement.name.name;
|
|
317
330
|
// Check if this was capitalized (reverse lookup)
|
|
318
|
-
const originalName =
|
|
331
|
+
const originalName = reverse_capitalized_names.get(closingName);
|
|
319
332
|
if (originalName) {
|
|
320
333
|
tokens.push({ source: originalName, generated: closingName });
|
|
321
334
|
} else {
|
|
322
335
|
// Check if this should be capitalized (forward lookup)
|
|
323
|
-
const capitalizedName =
|
|
336
|
+
const capitalizedName = capitalized_names.get(closingName);
|
|
324
337
|
if (capitalizedName) {
|
|
325
338
|
tokens.push({ source: closingName, generated: capitalizedName });
|
|
326
339
|
} else {
|
|
@@ -1106,25 +1119,25 @@ export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
|
1106
1119
|
|
|
1107
1120
|
// Process each token in order
|
|
1108
1121
|
for (const token of tokens) {
|
|
1109
|
-
let
|
|
1122
|
+
let source_text, generated_text;
|
|
1110
1123
|
|
|
1111
1124
|
if (typeof token === 'string') {
|
|
1112
|
-
|
|
1113
|
-
|
|
1125
|
+
source_text = token;
|
|
1126
|
+
generated_text = token;
|
|
1114
1127
|
} else {
|
|
1115
1128
|
// Token with different source and generated names
|
|
1116
|
-
|
|
1117
|
-
|
|
1129
|
+
source_text = token.source;
|
|
1130
|
+
generated_text = token.generated;
|
|
1118
1131
|
}
|
|
1119
1132
|
|
|
1120
|
-
const
|
|
1121
|
-
const
|
|
1133
|
+
const source_pos = find_in_source(source_text);
|
|
1134
|
+
const gen_pos = find_in_generated(generated_text);
|
|
1122
1135
|
|
|
1123
|
-
if (
|
|
1136
|
+
if (source_pos !== null && gen_pos !== null) {
|
|
1124
1137
|
mappings.push({
|
|
1125
|
-
sourceOffsets: [
|
|
1126
|
-
generatedOffsets: [
|
|
1127
|
-
lengths: [
|
|
1138
|
+
sourceOffsets: [source_pos],
|
|
1139
|
+
generatedOffsets: [gen_pos],
|
|
1140
|
+
lengths: [source_text.length],
|
|
1128
1141
|
data: mapping_data,
|
|
1129
1142
|
});
|
|
1130
1143
|
}
|
|
@@ -1133,17 +1146,46 @@ export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
|
1133
1146
|
// Add full-statement mappings for import declarations
|
|
1134
1147
|
// TypeScript reports unused import diagnostics covering the entire import statement
|
|
1135
1148
|
// Use verification-only mapping to avoid duplicate hover/completion
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1149
|
+
|
|
1150
|
+
// Use the source import map from the original AST (before transformation)
|
|
1151
|
+
// The __volar_id property is preserved through transformation via object spread
|
|
1152
|
+
if (source_import_map && import_declarations.length > 0) {
|
|
1153
|
+
// We need to find where each import appears in the generated code
|
|
1154
|
+
// Search for "import" keywords and match them to our collected imports
|
|
1155
|
+
let gen_search_index = 0;
|
|
1156
|
+
|
|
1157
|
+
for (const import_decl of import_declarations) {
|
|
1158
|
+
// Look up the source position using the __volar_id
|
|
1159
|
+
const source_range = source_import_map.get(import_decl.id);
|
|
1160
|
+
if (!source_range) continue; // Skip if we don't have source info for this ID
|
|
1161
|
+
|
|
1162
|
+
// Find this import statement in the generated code
|
|
1163
|
+
// Search for "import " starting from our last position
|
|
1164
|
+
const import_keyword_index = generated_code.indexOf('import ', gen_search_index);
|
|
1165
|
+
if (import_keyword_index === -1) continue; // Couldn't find it
|
|
1166
|
+
|
|
1167
|
+
// Find the semicolon or end of line for this import
|
|
1168
|
+
let gen_end = generated_code.indexOf(';', import_keyword_index);
|
|
1169
|
+
if (gen_end === -1) gen_end = generated_code.indexOf('\n', import_keyword_index);
|
|
1170
|
+
if (gen_end === -1) gen_end = generated_code.length;
|
|
1171
|
+
else gen_end += 1; // Include the semicolon
|
|
1172
|
+
|
|
1173
|
+
const get_start = import_keyword_index;
|
|
1174
|
+
gen_search_index = gen_end; // Next search starts after this import
|
|
1175
|
+
|
|
1176
|
+
const source_length = source_range.end - source_range.start;
|
|
1177
|
+
const get_length = gen_end - get_start;
|
|
1178
|
+
|
|
1179
|
+
mappings.push({
|
|
1180
|
+
sourceOffsets: [source_range.start],
|
|
1181
|
+
generatedOffsets: [get_start],
|
|
1182
|
+
lengths: [Math.min(source_length, get_length)],
|
|
1183
|
+
data: {
|
|
1184
|
+
// only verification (diagnostics) to avoid duplicate hover/completion
|
|
1185
|
+
verification: true
|
|
1186
|
+
},
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1147
1189
|
}
|
|
1148
1190
|
|
|
1149
1191
|
// Sort mappings by source offset
|
|
@@ -525,18 +525,28 @@ const visitors = {
|
|
|
525
525
|
return;
|
|
526
526
|
}
|
|
527
527
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
context.
|
|
532
|
-
|
|
533
|
-
transform_body(node.consequent.body, {
|
|
534
|
-
...context,
|
|
535
|
-
state: { ...context.state, scope: context.state.scopes.get(node.consequent) },
|
|
536
|
-
}),
|
|
537
|
-
),
|
|
538
|
-
),
|
|
528
|
+
const consequent = b.block(
|
|
529
|
+
transform_body(node.consequent.body, {
|
|
530
|
+
...context,
|
|
531
|
+
state: { ...context.state, scope: context.state.scopes.get(node.consequent) },
|
|
532
|
+
}),
|
|
539
533
|
);
|
|
534
|
+
|
|
535
|
+
let alternate = null;
|
|
536
|
+
if (node.alternate) {
|
|
537
|
+
const alternate_scope = context.state.scopes.get(node.alternate) || context.state.scope;
|
|
538
|
+
const alternate_body_nodes =
|
|
539
|
+
node.alternate.type === 'IfStatement' ? [node.alternate] : node.alternate.body;
|
|
540
|
+
|
|
541
|
+
alternate = b.block(
|
|
542
|
+
transform_body(alternate_body_nodes, {
|
|
543
|
+
...context,
|
|
544
|
+
state: { ...context.state, scope: alternate_scope },
|
|
545
|
+
}),
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
context.state.init.push(b.if(context.visit(node.test), consequent, alternate));
|
|
540
550
|
},
|
|
541
551
|
|
|
542
552
|
Identifier(node, context) {
|
|
@@ -74,7 +74,7 @@ export { user_effect as effect } from './internal/client/blocks.js';
|
|
|
74
74
|
|
|
75
75
|
export { Portal } from './internal/client/portal.js';
|
|
76
76
|
|
|
77
|
-
export { ref_prop as createRefKey } from './internal/client/runtime.js';
|
|
77
|
+
export { ref_prop as createRefKey, get, public_set as set } from './internal/client/runtime.js';
|
|
78
78
|
|
|
79
79
|
export { on } from './internal/client/events.js';
|
|
80
80
|
|
|
@@ -12,6 +12,30 @@ export function effect() {
|
|
|
12
12
|
|
|
13
13
|
var empty_get_set = { get: undefined, set: undefined };
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* @param {Derived | Tracked} tracked
|
|
17
|
+
* @returns {any}
|
|
18
|
+
*/
|
|
19
|
+
export function get(tracked) {
|
|
20
|
+
if (!is_tracked_object(tracked)) {
|
|
21
|
+
return tracked;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var g = tracked.a.get;
|
|
25
|
+
|
|
26
|
+
return g ? g(tracked.v) : tracked.v;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {Tracked} tracked
|
|
31
|
+
* @param {any} value
|
|
32
|
+
*/
|
|
33
|
+
export function set(tracked, value) {
|
|
34
|
+
var s = tracked.a.set;
|
|
35
|
+
|
|
36
|
+
tracked.v = s ? s(value, tracked.v) : value;
|
|
37
|
+
}
|
|
38
|
+
|
|
15
39
|
/**
|
|
16
40
|
*
|
|
17
41
|
* @param {any} v
|
|
@@ -768,6 +768,16 @@ export function get_tracked(tracked) {
|
|
|
768
768
|
return value;
|
|
769
769
|
}
|
|
770
770
|
|
|
771
|
+
/**
|
|
772
|
+
* Exposed version of `set` to avoid internal bugs
|
|
773
|
+
* since block is required on the internal `set`
|
|
774
|
+
* @param {Derived | Tracked} tracked
|
|
775
|
+
* @param {any} value
|
|
776
|
+
*/
|
|
777
|
+
export function public_set(tracked, value) {
|
|
778
|
+
set(tracked, value, safe_scope());
|
|
779
|
+
}
|
|
780
|
+
|
|
771
781
|
/**
|
|
772
782
|
* @param {Derived | Tracked} tracked
|
|
773
783
|
* @param {any} value
|
|
@@ -35,14 +35,6 @@ export function create_anchor() {
|
|
|
35
35
|
return t;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
/**
|
|
39
|
-
* @param {any} value
|
|
40
|
-
* @returns {boolean}
|
|
41
|
-
*/
|
|
42
|
-
export function is_positive_integer(value) {
|
|
43
|
-
return Number.isInteger(value) && /**@type {number} */ (value) >= 0;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
38
|
/**
|
|
47
39
|
* Checks if an object is a tracked object (has a numeric 'f' property).
|
|
48
40
|
* @param {any} v - The object to check.
|
|
@@ -317,3 +317,83 @@ exports[`for statements > render a simple static array 1`] = `
|
|
|
317
317
|
|
|
318
318
|
</div>
|
|
319
319
|
`;
|
|
320
|
+
|
|
321
|
+
exports[`for statements > renders a simple dynamic array 1`] = `
|
|
322
|
+
<div>
|
|
323
|
+
<!---->
|
|
324
|
+
<div
|
|
325
|
+
class="Item 1"
|
|
326
|
+
>
|
|
327
|
+
Item 1
|
|
328
|
+
</div>
|
|
329
|
+
<div
|
|
330
|
+
class="Item 2"
|
|
331
|
+
>
|
|
332
|
+
Item 2
|
|
333
|
+
</div>
|
|
334
|
+
<div
|
|
335
|
+
class="Item 3"
|
|
336
|
+
>
|
|
337
|
+
Item 3
|
|
338
|
+
</div>
|
|
339
|
+
<!---->
|
|
340
|
+
<button>
|
|
341
|
+
Add Item
|
|
342
|
+
</button>
|
|
343
|
+
|
|
344
|
+
</div>
|
|
345
|
+
`;
|
|
346
|
+
|
|
347
|
+
exports[`for statements > renders a simple dynamic array 2`] = `
|
|
348
|
+
<div>
|
|
349
|
+
<!---->
|
|
350
|
+
<div
|
|
351
|
+
class="Item 1"
|
|
352
|
+
>
|
|
353
|
+
Item 1
|
|
354
|
+
</div>
|
|
355
|
+
<div
|
|
356
|
+
class="Item 2"
|
|
357
|
+
>
|
|
358
|
+
Item 2
|
|
359
|
+
</div>
|
|
360
|
+
<div
|
|
361
|
+
class="Item 3"
|
|
362
|
+
>
|
|
363
|
+
Item 3
|
|
364
|
+
</div>
|
|
365
|
+
<div
|
|
366
|
+
class="Item 4"
|
|
367
|
+
>
|
|
368
|
+
Item 4
|
|
369
|
+
</div>
|
|
370
|
+
<!---->
|
|
371
|
+
<button>
|
|
372
|
+
Add Item
|
|
373
|
+
</button>
|
|
374
|
+
|
|
375
|
+
</div>
|
|
376
|
+
`;
|
|
377
|
+
|
|
378
|
+
exports[`for statements > renders a simple static array 1`] = `
|
|
379
|
+
<div>
|
|
380
|
+
<!---->
|
|
381
|
+
<div
|
|
382
|
+
class="Item 1"
|
|
383
|
+
>
|
|
384
|
+
Item 1
|
|
385
|
+
</div>
|
|
386
|
+
<div
|
|
387
|
+
class="Item 2"
|
|
388
|
+
>
|
|
389
|
+
Item 2
|
|
390
|
+
</div>
|
|
391
|
+
<div
|
|
392
|
+
class="Item 3"
|
|
393
|
+
>
|
|
394
|
+
Item 3
|
|
395
|
+
</div>
|
|
396
|
+
<!---->
|
|
397
|
+
|
|
398
|
+
</div>
|
|
399
|
+
`;
|