ripple 0.2.91 → 0.2.93
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/index.js +17 -10
- package/src/compiler/phases/1-parse/index.js +55 -7
- package/src/compiler/phases/3-transform/client/index.js +82 -55
- package/src/compiler/phases/3-transform/segments.js +422 -224
- package/src/compiler/scope.js +478 -404
- package/src/compiler/types/index.d.ts +299 -3
- package/src/compiler/utils.js +173 -30
- package/src/runtime/index-client.js +1 -0
- package/src/runtime/internal/client/html.js +18 -8
- package/src/runtime/internal/client/index.js +1 -0
- package/src/runtime/internal/client/portal.js +55 -32
- package/src/runtime/internal/client/render.js +31 -1
- package/src/runtime/internal/client/runtime.js +53 -22
- package/src/utils/normalize_css_property_name.js +23 -0
- package/tests/client/basic.test.ripple +207 -1
- package/tests/client/compiler.test.ripple +95 -1
- package/tests/client/html.test.ripple +29 -1
- package/tests/client/portal.test.ripple +167 -0
- package/types/index.d.ts +4 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { walk } from 'zimmerframe';
|
|
2
2
|
|
|
3
3
|
export const mapping_data = {
|
|
4
4
|
verification: true,
|
|
@@ -8,252 +8,450 @@ export const mapping_data = {
|
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* @param {string}
|
|
14
|
-
* @param {
|
|
15
|
-
* @param {number} direction
|
|
16
|
-
*/
|
|
17
|
-
function findTokenBoundary(text, start, direction = 1) {
|
|
18
|
-
if (start < 0 || start >= text.length) return start;
|
|
19
|
-
|
|
20
|
-
let pos = start;
|
|
21
|
-
/** @param {string} c */
|
|
22
|
-
const isAlphaNum = (c) => /[a-zA-Z0-9_$]/.test(c);
|
|
23
|
-
|
|
24
|
-
// If we're at whitespace or punctuation, find the next meaningful character
|
|
25
|
-
while (pos >= 0 && pos < text.length && /\s/.test(text[pos])) {
|
|
26
|
-
pos += direction;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (pos < 0 || pos >= text.length) return start;
|
|
30
|
-
|
|
31
|
-
// If we're in the middle of a word/identifier, find the boundary
|
|
32
|
-
if (isAlphaNum(text[pos])) {
|
|
33
|
-
if (direction > 0) {
|
|
34
|
-
while (pos < text.length && isAlphaNum(text[pos])) pos++;
|
|
35
|
-
} else {
|
|
36
|
-
while (pos >= 0 && isAlphaNum(text[pos])) pos--;
|
|
37
|
-
pos++; // Adjust back to start of token
|
|
38
|
-
}
|
|
39
|
-
} else {
|
|
40
|
-
// For punctuation, just move one character in the given direction
|
|
41
|
-
pos += direction;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return Math.max(0, Math.min(text.length, pos));
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Check if source and generated content are meaningfully similar
|
|
49
|
-
* @param {string} sourceContent
|
|
50
|
-
* @param {string} generatedContent
|
|
51
|
-
*/
|
|
52
|
-
function isValidMapping(sourceContent, generatedContent) {
|
|
53
|
-
// Remove whitespace for comparison
|
|
54
|
-
const cleanSource = sourceContent.replace(/\s+/g, '');
|
|
55
|
-
const cleanGenerated = generatedContent.replace(/\s+/g, '');
|
|
56
|
-
|
|
57
|
-
// If either is empty, skip
|
|
58
|
-
if (!cleanSource || !cleanGenerated) return false;
|
|
59
|
-
|
|
60
|
-
// Skip obvious template transformations that don't make sense to map
|
|
61
|
-
const templateTransforms = [
|
|
62
|
-
/^\{.*\}$/, // Curly brace expressions
|
|
63
|
-
/^<.*>$/, // HTML tags
|
|
64
|
-
/^\(\(\)\s*=>\s*\{$/, // Generated function wrappers
|
|
65
|
-
/^\}\)\(\)\}$/, // Generated function closures
|
|
66
|
-
];
|
|
67
|
-
|
|
68
|
-
for (const transform of templateTransforms) {
|
|
69
|
-
if (transform.test(cleanSource) || transform.test(cleanGenerated)) {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Check if content is similar (exact match, or generated contains source)
|
|
75
|
-
if (cleanSource === cleanGenerated) return true;
|
|
76
|
-
if (cleanGenerated.includes(cleanSource)) return true;
|
|
77
|
-
if (cleanSource.includes(cleanGenerated) && cleanGenerated.length > 2) return true;
|
|
78
|
-
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Convert esrap SourceMap to Volar mappings
|
|
84
|
-
* @param {{ mappings: string }} source_map
|
|
85
|
-
* @param {string} source
|
|
86
|
-
* @param {string} generated_code
|
|
11
|
+
* Create Volar mappings by walking the transformed AST
|
|
12
|
+
* @param {any} ast - The transformed AST
|
|
13
|
+
* @param {string} source - Original source code
|
|
14
|
+
* @param {string} generated_code - Generated code from esrap
|
|
87
15
|
* @returns {object}
|
|
88
16
|
*/
|
|
89
|
-
export function convert_source_map_to_mappings(
|
|
17
|
+
export function convert_source_map_to_mappings(ast, source, generated_code) {
|
|
90
18
|
/** @type {Array<{sourceOffsets: number[], generatedOffsets: number[], lengths: number[], data: any}>} */
|
|
91
19
|
const mappings = [];
|
|
92
20
|
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
let generated_offset = 0;
|
|
97
|
-
const generated_lines = generated_code.split('\n');
|
|
98
|
-
const source_lines = source.split('\n');
|
|
21
|
+
// Maintain indices that walk through source and generated code
|
|
22
|
+
let sourceIndex = 0;
|
|
23
|
+
let generatedIndex = 0;
|
|
99
24
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
for (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Find text in source string, searching character by character from sourceIndex
|
|
27
|
+
* @param {string} text - Text to find
|
|
28
|
+
* @returns {number|null} - Source position or null
|
|
29
|
+
*/
|
|
30
|
+
const findInSource = (text) => {
|
|
31
|
+
for (let i = sourceIndex; i <= source.length - text.length; i++) {
|
|
32
|
+
let match = true;
|
|
33
|
+
for (let j = 0; j < text.length; j++) {
|
|
34
|
+
if (source[i + j] !== text[j]) {
|
|
35
|
+
match = false;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
112
38
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
for (let i = 0; i < Math.min(source_line, source_lines.length - 1); i++) {
|
|
117
|
-
source_offset += source_lines[i].length + 1; // +1 for newline
|
|
39
|
+
if (match) {
|
|
40
|
+
sourceIndex = i + text.length;
|
|
41
|
+
return i;
|
|
118
42
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const current_generated_offset = generated_offset + generated_column;
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
};
|
|
123
46
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
// Try different segment boundaries to find the best match
|
|
137
|
-
const candidates = [
|
|
138
|
-
// Forward boundaries
|
|
139
|
-
{
|
|
140
|
-
source: source.substring(source_offset, source_token_end),
|
|
141
|
-
generated: generated_code.substring(current_generated_offset, generated_token_end)
|
|
142
|
-
},
|
|
143
|
-
// Backward boundaries
|
|
144
|
-
{
|
|
145
|
-
source: source.substring(source_token_start, source_offset + 1),
|
|
146
|
-
generated: generated_code.substring(generated_token_start, current_generated_offset + 1)
|
|
147
|
-
},
|
|
148
|
-
// Single character
|
|
149
|
-
{
|
|
150
|
-
source: source.charAt(source_offset),
|
|
151
|
-
generated: generated_code.charAt(current_generated_offset)
|
|
152
|
-
},
|
|
153
|
-
// Try to find exact matches in nearby content
|
|
154
|
-
];
|
|
155
|
-
|
|
156
|
-
// Look for the best candidate match
|
|
157
|
-
let best_match = null;
|
|
158
|
-
for (const candidate of candidates) {
|
|
159
|
-
if (isValidMapping(candidate.source, candidate.generated)) {
|
|
160
|
-
best_match = candidate;
|
|
47
|
+
/**
|
|
48
|
+
* Find text in generated code, searching character by character from generatedIndex
|
|
49
|
+
* @param {string} text - Text to find
|
|
50
|
+
* @returns {number|null} - Generated position or null
|
|
51
|
+
*/
|
|
52
|
+
const findInGenerated = (text) => {
|
|
53
|
+
for (let i = generatedIndex; i <= generated_code.length - text.length; i++) {
|
|
54
|
+
let match = true;
|
|
55
|
+
for (let j = 0; j < text.length; j++) {
|
|
56
|
+
if (generated_code[i + j] !== text[j]) {
|
|
57
|
+
match = false;
|
|
161
58
|
break;
|
|
162
59
|
}
|
|
163
60
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const sourceIdMatch = source.substring(source_offset).match(/^[a-zA-Z_$][a-zA-Z0-9_$]*/);
|
|
168
|
-
const generatedIdMatch = generated_code.substring(current_generated_offset).match(/^[a-zA-Z_$][a-zA-Z0-9_$]*/);
|
|
169
|
-
|
|
170
|
-
if (sourceIdMatch && generatedIdMatch && sourceIdMatch[0] === generatedIdMatch[0]) {
|
|
171
|
-
best_match = {
|
|
172
|
-
source: sourceIdMatch[0],
|
|
173
|
-
generated: generatedIdMatch[0]
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Handle special cases for Ripple keywords that might not have generated equivalents
|
|
179
|
-
if (!best_match || best_match.source.length === 0) {
|
|
180
|
-
continue;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Special handling for Ripple-specific syntax that may be omitted in generated code
|
|
184
|
-
const sourceAtOffset = source.substring(source_offset, source_offset + 10);
|
|
185
|
-
if (sourceAtOffset.includes('index ')) {
|
|
186
|
-
// For the 'index' keyword, create a mapping even if there's no generated equivalent
|
|
187
|
-
const indexMatch = sourceAtOffset.match(/index\s+/);
|
|
188
|
-
if (indexMatch) {
|
|
189
|
-
best_match = {
|
|
190
|
-
source: indexMatch[0].trim(),
|
|
191
|
-
generated: '' // Empty generated content for keywords that are transformed away
|
|
192
|
-
};
|
|
61
|
+
if (match) {
|
|
62
|
+
generatedIndex = i + text.length;
|
|
63
|
+
return i;
|
|
193
64
|
}
|
|
194
65
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
//
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
66
|
+
return null;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Collect text tokens from AST nodes
|
|
70
|
+
/** @type {string[]} */
|
|
71
|
+
const tokens = [];
|
|
72
|
+
|
|
73
|
+
walk(ast, null, {
|
|
74
|
+
_(node, { next, visit }) {
|
|
75
|
+
// Collect key node types: Identifiers, Literals, and JSX Elements
|
|
76
|
+
if (node.type === 'Identifier' && node.name) {
|
|
77
|
+
tokens.push(node.name);
|
|
78
|
+
} else if (node.type === 'JSXIdentifier' && node.name) {
|
|
79
|
+
tokens.push(node.name);
|
|
80
|
+
} else if (node.type === 'Literal' && node.raw) {
|
|
81
|
+
tokens.push(node.raw);
|
|
82
|
+
} else if (node.type === 'ImportDeclaration') {
|
|
83
|
+
// Visit specifiers in source order
|
|
84
|
+
if (node.specifiers) {
|
|
85
|
+
for (const specifier of node.specifiers) {
|
|
86
|
+
visit(specifier);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Skip source (just a string literal)
|
|
90
|
+
return;
|
|
91
|
+
} else if (node.type === 'ImportSpecifier') {
|
|
92
|
+
// If local and imported are the same, only visit local to avoid duplicates
|
|
93
|
+
// Otherwise visit both in order
|
|
94
|
+
if (node.imported && node.local && node.imported.name !== node.local.name) {
|
|
95
|
+
visit(node.imported);
|
|
96
|
+
visit(node.local);
|
|
97
|
+
} else if (node.local) {
|
|
98
|
+
visit(node.local);
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
} else if (node.type === 'ImportDefaultSpecifier' || node.type === 'ImportNamespaceSpecifier') {
|
|
102
|
+
// Just visit local
|
|
103
|
+
if (node.local) {
|
|
104
|
+
visit(node.local);
|
|
105
|
+
}
|
|
106
|
+
return;
|
|
107
|
+
} else if (node.type === 'ExportNamedDeclaration') {
|
|
108
|
+
// Visit in source order: declaration, specifiers
|
|
109
|
+
if (node.declaration) {
|
|
110
|
+
visit(node.declaration);
|
|
111
|
+
}
|
|
112
|
+
if (node.specifiers) {
|
|
113
|
+
for (const specifier of node.specifiers) {
|
|
114
|
+
visit(specifier);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return;
|
|
118
|
+
} else if (node.type === 'ExportDefaultDeclaration') {
|
|
119
|
+
// Visit the declaration
|
|
120
|
+
if (node.declaration) {
|
|
121
|
+
visit(node.declaration);
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
} else if (node.type === 'ExportAllDeclaration') {
|
|
125
|
+
// Nothing to visit (just source string)
|
|
126
|
+
return;
|
|
127
|
+
} else if (node.type === 'JSXElement') {
|
|
128
|
+
// Manually visit in source order: opening element, children, closing element
|
|
129
|
+
|
|
130
|
+
// 1. Visit opening element (name and attributes)
|
|
131
|
+
if (node.openingElement) {
|
|
132
|
+
visit(node.openingElement);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 2. Visit children in order
|
|
136
|
+
if (node.children) {
|
|
137
|
+
for (const child of node.children) {
|
|
138
|
+
visit(child);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 3. Push closing tag name (not visited by AST walker)
|
|
143
|
+
if (!node.openingElement?.selfClosing && node.closingElement?.name?.type === 'JSXIdentifier') {
|
|
144
|
+
tokens.push(node.closingElement.name.name);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return;
|
|
148
|
+
} else if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') {
|
|
149
|
+
// Visit in source order: id, params, body
|
|
150
|
+
if (node.id) {
|
|
151
|
+
visit(node.id);
|
|
152
|
+
}
|
|
153
|
+
if (node.params) {
|
|
154
|
+
for (const param of node.params) {
|
|
155
|
+
visit(param);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (node.body) {
|
|
159
|
+
visit(node.body);
|
|
160
|
+
}
|
|
161
|
+
return;
|
|
162
|
+
} else if (node.type === 'VariableDeclaration') {
|
|
163
|
+
// Visit declarators in order
|
|
164
|
+
if (node.declarations) {
|
|
165
|
+
for (const declarator of node.declarations) {
|
|
166
|
+
visit(declarator);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return;
|
|
170
|
+
} else if (node.type === 'VariableDeclarator') {
|
|
171
|
+
// Visit in source order: id, init
|
|
172
|
+
if (node.id) {
|
|
173
|
+
visit(node.id);
|
|
174
|
+
}
|
|
175
|
+
if (node.init) {
|
|
176
|
+
visit(node.init);
|
|
177
|
+
}
|
|
178
|
+
return;
|
|
179
|
+
} else if (node.type === 'IfStatement') {
|
|
180
|
+
// Visit in source order: test, consequent, alternate
|
|
181
|
+
if (node.test) {
|
|
182
|
+
visit(node.test);
|
|
183
|
+
}
|
|
184
|
+
if (node.consequent) {
|
|
185
|
+
visit(node.consequent);
|
|
186
|
+
}
|
|
187
|
+
if (node.alternate) {
|
|
188
|
+
visit(node.alternate);
|
|
189
|
+
}
|
|
190
|
+
return;
|
|
191
|
+
} else if (node.type === 'ForStatement') {
|
|
192
|
+
// Visit in source order: init, test, update, body
|
|
193
|
+
if (node.init) {
|
|
194
|
+
visit(node.init);
|
|
195
|
+
}
|
|
196
|
+
if (node.test) {
|
|
197
|
+
visit(node.test);
|
|
198
|
+
}
|
|
199
|
+
if (node.update) {
|
|
200
|
+
visit(node.update);
|
|
201
|
+
}
|
|
202
|
+
if (node.body) {
|
|
203
|
+
visit(node.body);
|
|
204
|
+
}
|
|
205
|
+
return;
|
|
206
|
+
} else if (node.type === 'ForOfStatement' || node.type === 'ForInStatement') {
|
|
207
|
+
// Visit in source order: left, right, body
|
|
208
|
+
if (node.left) {
|
|
209
|
+
visit(node.left);
|
|
210
|
+
}
|
|
211
|
+
if (node.right) {
|
|
212
|
+
visit(node.right);
|
|
213
|
+
}
|
|
214
|
+
if (node.body) {
|
|
215
|
+
visit(node.body);
|
|
216
|
+
}
|
|
217
|
+
return;
|
|
218
|
+
} else if (node.type === 'WhileStatement' || node.type === 'DoWhileStatement') {
|
|
219
|
+
// Visit in source order: test, body (while) or body, test (do-while)
|
|
220
|
+
if (node.type === 'WhileStatement') {
|
|
221
|
+
if (node.test) {
|
|
222
|
+
visit(node.test);
|
|
223
|
+
}
|
|
224
|
+
if (node.body) {
|
|
225
|
+
visit(node.body);
|
|
226
|
+
}
|
|
227
|
+
} else {
|
|
228
|
+
if (node.body) {
|
|
229
|
+
visit(node.body);
|
|
230
|
+
}
|
|
231
|
+
if (node.test) {
|
|
232
|
+
visit(node.test);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return;
|
|
236
|
+
} else if (node.type === 'TryStatement') {
|
|
237
|
+
// Visit in source order: block, handler, finalizer
|
|
238
|
+
if (node.block) {
|
|
239
|
+
visit(node.block);
|
|
240
|
+
}
|
|
241
|
+
if (node.handler) {
|
|
242
|
+
visit(node.handler);
|
|
243
|
+
}
|
|
244
|
+
if (node.finalizer) {
|
|
245
|
+
visit(node.finalizer);
|
|
246
|
+
}
|
|
247
|
+
return;
|
|
248
|
+
} else if (node.type === 'CatchClause') {
|
|
249
|
+
// Visit in source order: param, body
|
|
250
|
+
if (node.param) {
|
|
251
|
+
visit(node.param);
|
|
252
|
+
}
|
|
253
|
+
if (node.body) {
|
|
254
|
+
visit(node.body);
|
|
255
|
+
}
|
|
256
|
+
return;
|
|
257
|
+
} else if (node.type === 'CallExpression' || node.type === 'NewExpression') {
|
|
258
|
+
// Visit in source order: callee, arguments
|
|
259
|
+
if (node.callee) {
|
|
260
|
+
visit(node.callee);
|
|
261
|
+
}
|
|
262
|
+
if (node.arguments) {
|
|
263
|
+
for (const arg of node.arguments) {
|
|
264
|
+
visit(arg);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return;
|
|
268
|
+
} else if (node.type === 'LogicalExpression' || node.type === 'BinaryExpression') {
|
|
269
|
+
// Visit in source order: left, right
|
|
270
|
+
if (node.left) {
|
|
271
|
+
visit(node.left);
|
|
272
|
+
}
|
|
273
|
+
if (node.right) {
|
|
274
|
+
visit(node.right);
|
|
275
|
+
}
|
|
276
|
+
return;
|
|
277
|
+
} else if (node.type === 'MemberExpression') {
|
|
278
|
+
// Visit in source order: object, property
|
|
279
|
+
if (node.object) {
|
|
280
|
+
visit(node.object);
|
|
281
|
+
}
|
|
282
|
+
if (!node.computed && node.property) {
|
|
283
|
+
visit(node.property);
|
|
284
|
+
}
|
|
285
|
+
return;
|
|
286
|
+
} else if (node.type === 'AssignmentExpression' || node.type === 'AssignmentPattern') {
|
|
287
|
+
// Visit in source order: left, right
|
|
288
|
+
if (node.left) {
|
|
289
|
+
visit(node.left);
|
|
290
|
+
}
|
|
291
|
+
if (node.right) {
|
|
292
|
+
visit(node.right);
|
|
293
|
+
}
|
|
294
|
+
return;
|
|
295
|
+
} else if (node.type === 'ObjectExpression' || node.type === 'ObjectPattern') {
|
|
296
|
+
// Visit properties in order
|
|
297
|
+
if (node.properties) {
|
|
298
|
+
for (const prop of node.properties) {
|
|
299
|
+
visit(prop);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return;
|
|
303
|
+
} else if (node.type === 'Property') {
|
|
304
|
+
// Visit in source order: key, value
|
|
305
|
+
if (node.key) {
|
|
306
|
+
visit(node.key);
|
|
307
|
+
}
|
|
308
|
+
if (node.value) {
|
|
309
|
+
visit(node.value);
|
|
310
|
+
}
|
|
311
|
+
return;
|
|
312
|
+
} else if (node.type === 'ArrayExpression' || node.type === 'ArrayPattern') {
|
|
313
|
+
// Visit elements in order
|
|
314
|
+
if (node.elements) {
|
|
315
|
+
for (const element of node.elements) {
|
|
316
|
+
if (element) visit(element);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return;
|
|
320
|
+
} else if (node.type === 'ConditionalExpression') {
|
|
321
|
+
// Visit in source order: test, consequent, alternate
|
|
322
|
+
if (node.test) {
|
|
323
|
+
visit(node.test);
|
|
324
|
+
}
|
|
325
|
+
if (node.consequent) {
|
|
326
|
+
visit(node.consequent);
|
|
327
|
+
}
|
|
328
|
+
if (node.alternate) {
|
|
329
|
+
visit(node.alternate);
|
|
330
|
+
}
|
|
331
|
+
return;
|
|
332
|
+
} else if (node.type === 'UnaryExpression' || node.type === 'UpdateExpression') {
|
|
333
|
+
// Visit argument
|
|
334
|
+
if (node.argument) {
|
|
335
|
+
visit(node.argument);
|
|
336
|
+
}
|
|
337
|
+
return;
|
|
338
|
+
} else if (node.type === 'TemplateLiteral') {
|
|
339
|
+
// Visit quasis and expressions in order
|
|
340
|
+
for (let i = 0; i < node.quasis.length; i++) {
|
|
341
|
+
if (node.quasis[i]) {
|
|
342
|
+
visit(node.quasis[i]);
|
|
343
|
+
}
|
|
344
|
+
if (i < node.expressions.length && node.expressions[i]) {
|
|
345
|
+
visit(node.expressions[i]);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return;
|
|
349
|
+
} else if (node.type === 'TaggedTemplateExpression') {
|
|
350
|
+
// Visit in source order: tag, quasi
|
|
351
|
+
if (node.tag) {
|
|
352
|
+
visit(node.tag);
|
|
353
|
+
}
|
|
354
|
+
if (node.quasi) {
|
|
355
|
+
visit(node.quasi);
|
|
356
|
+
}
|
|
357
|
+
return;
|
|
358
|
+
} else if (node.type === 'ReturnStatement' || node.type === 'ThrowStatement') {
|
|
359
|
+
// Visit argument
|
|
360
|
+
if (node.argument) {
|
|
361
|
+
visit(node.argument);
|
|
362
|
+
}
|
|
363
|
+
return;
|
|
364
|
+
} else if (node.type === 'ExpressionStatement') {
|
|
365
|
+
// Visit expression
|
|
366
|
+
if (node.expression) {
|
|
367
|
+
visit(node.expression);
|
|
368
|
+
}
|
|
369
|
+
return;
|
|
370
|
+
} else if (node.type === 'BlockStatement' || node.type === 'Program') {
|
|
371
|
+
// Visit body statements in order
|
|
372
|
+
if (node.body) {
|
|
373
|
+
for (const statement of node.body) {
|
|
374
|
+
visit(statement);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return;
|
|
378
|
+
} else if (node.type === 'SwitchStatement') {
|
|
379
|
+
// Visit in source order: discriminant, cases
|
|
380
|
+
if (node.discriminant) {
|
|
381
|
+
visit(node.discriminant);
|
|
382
|
+
}
|
|
383
|
+
if (node.cases) {
|
|
384
|
+
for (const caseNode of node.cases) {
|
|
385
|
+
visit(caseNode);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return;
|
|
389
|
+
} else if (node.type === 'SwitchCase') {
|
|
390
|
+
// Visit in source order: test, consequent
|
|
391
|
+
if (node.test) {
|
|
392
|
+
visit(node.test);
|
|
393
|
+
}
|
|
394
|
+
if (node.consequent) {
|
|
395
|
+
for (const statement of node.consequent) {
|
|
396
|
+
visit(statement);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return;
|
|
400
|
+
} else if (node.type === 'ClassDeclaration' || node.type === 'ClassExpression') {
|
|
401
|
+
// Visit in source order: id, superClass, body
|
|
402
|
+
if (node.id) {
|
|
403
|
+
visit(node.id);
|
|
404
|
+
}
|
|
405
|
+
if (node.superClass) {
|
|
406
|
+
visit(node.superClass);
|
|
407
|
+
}
|
|
408
|
+
if (node.body) {
|
|
409
|
+
visit(node.body);
|
|
410
|
+
}
|
|
411
|
+
return;
|
|
412
|
+
} else if (node.type === 'ClassBody') {
|
|
413
|
+
// Visit body in order
|
|
414
|
+
if (node.body) {
|
|
415
|
+
for (const member of node.body) {
|
|
416
|
+
visit(member);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return;
|
|
420
|
+
} else if (node.type === 'MethodDefinition') {
|
|
421
|
+
// Visit in source order: key, value
|
|
422
|
+
if (node.key) {
|
|
423
|
+
visit(node.key);
|
|
424
|
+
}
|
|
425
|
+
if (node.value) {
|
|
426
|
+
visit(node.value);
|
|
427
|
+
}
|
|
428
|
+
return;
|
|
242
429
|
}
|
|
430
|
+
|
|
431
|
+
next();
|
|
243
432
|
}
|
|
433
|
+
});
|
|
244
434
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
435
|
+
// Process each token in order
|
|
436
|
+
for (const text of tokens) {
|
|
437
|
+
const sourcePos = findInSource(text);
|
|
438
|
+
const genPos = findInGenerated(text);
|
|
439
|
+
|
|
440
|
+
if (sourcePos !== null && genPos !== null) {
|
|
441
|
+
mappings.push({
|
|
442
|
+
sourceOffsets: [sourcePos],
|
|
443
|
+
generatedOffsets: [genPos],
|
|
444
|
+
lengths: [text.length],
|
|
445
|
+
data: mapping_data,
|
|
446
|
+
});
|
|
249
447
|
}
|
|
250
448
|
}
|
|
251
449
|
|
|
252
|
-
// Sort mappings by source offset
|
|
450
|
+
// Sort mappings by source offset
|
|
253
451
|
mappings.sort((a, b) => a.sourceOffsets[0] - b.sourceOffsets[0]);
|
|
254
452
|
|
|
255
453
|
return {
|
|
256
454
|
code: generated_code,
|
|
257
455
|
mappings,
|
|
258
456
|
};
|
|
259
|
-
}
|
|
457
|
+
}
|