onelaraveljs 1.0.0 → 1.1.1
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/README.md +1 -1
- package/bin/onejs-build.js +32 -0
- package/package.json +11 -3
- package/scripts/README-template-compiler.md +133 -0
- package/scripts/README.md +61 -0
- package/scripts/__pycache__/build.cpython-314.pyc +0 -0
- package/scripts/__pycache__/compile.cpython-313.pyc +0 -0
- package/scripts/__pycache__/compile.cpython-314.pyc +0 -0
- package/scripts/build.py +573 -0
- package/scripts/check-system-errors.php +214 -0
- package/scripts/compile.py +101 -0
- package/scripts/compiler/README_CONFIG.md +196 -0
- package/scripts/compiler/__init__.py +18 -0
- package/scripts/compiler/__pycache__/__init__.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/__init__.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/binding_directive_service.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/class_binding_handler.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/compiler_utils.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/compiler_utils.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/conditional_handlers.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/conditional_handlers.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/config.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/config.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/declaration_tracker.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/directive_processors.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/directive_processors.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/echo_processor.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/event_directive_processor.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/event_directive_processor.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/function_generators.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/function_generators.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/loop_handlers.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/loop_handlers.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/main_compiler.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/main_compiler.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/parsers.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/parsers.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/php_converter.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/php_converter.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/php_js_converter.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/php_js_converter.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/register_parser.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/register_parser.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/section_handlers.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/section_handlers.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/show_directive_handler.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/style_directive_handler.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/template_analyzer.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/template_analyzer.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/template_processor.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/template_processor.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/template_processors.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/template_processors.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/utils.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/utils.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/wrapper_parser.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/wrapper_parser.cpython-314.pyc +0 -0
- package/scripts/compiler/binding_directive_service.py +103 -0
- package/scripts/compiler/class_binding_handler.py +347 -0
- package/scripts/compiler/cli.py +34 -0
- package/scripts/compiler/code_generator.py +141 -0
- package/scripts/compiler/compiler.config.json +36 -0
- package/scripts/compiler/compiler_utils.py +55 -0
- package/scripts/compiler/conditional_handlers.py +252 -0
- package/scripts/compiler/config.py +107 -0
- package/scripts/compiler/declaration_tracker.py +420 -0
- package/scripts/compiler/directive_processors.py +603 -0
- package/scripts/compiler/echo_processor.py +667 -0
- package/scripts/compiler/event_directive_processor.py +1099 -0
- package/scripts/compiler/fetch_parser.py +49 -0
- package/scripts/compiler/function_generators.py +310 -0
- package/scripts/compiler/loop_handlers.py +224 -0
- package/scripts/compiler/main_compiler.py +1763 -0
- package/scripts/compiler/parsers.py +1418 -0
- package/scripts/compiler/php_converter.py +470 -0
- package/scripts/compiler/php_js_converter.py +603 -0
- package/scripts/compiler/register_parser.py +480 -0
- package/scripts/compiler/section_handlers.py +122 -0
- package/scripts/compiler/show_directive_handler.py +85 -0
- package/scripts/compiler/style_directive_handler.py +169 -0
- package/scripts/compiler/template_analyzer.py +162 -0
- package/scripts/compiler/template_processor.py +1167 -0
- package/scripts/compiler/template_processors.py +1557 -0
- package/scripts/compiler/test_compiler.py +69 -0
- package/scripts/compiler/utils.py +54 -0
- package/scripts/compiler/variables_analyzer.py +135 -0
- package/scripts/compiler/view_identifier_generator.py +278 -0
- package/scripts/compiler/wrapper_parser.py +78 -0
- package/scripts/dev-context.js +311 -0
- package/scripts/dev.js +109 -0
- package/scripts/generate-assets-order.js +200 -0
- package/scripts/migrate-namespace.php +146 -0
- package/scripts/node/MIGRATION.md +190 -0
- package/scripts/node/README.md +269 -0
- package/scripts/node/build.js +208 -0
- package/scripts/node/compiler/compiler-utils.js +38 -0
- package/scripts/node/compiler/conditional-handlers.js +45 -0
- package/scripts/node/compiler/config.js +178 -0
- package/scripts/node/compiler/directive-processors.js +51 -0
- package/scripts/node/compiler/event-directive-processor.js +182 -0
- package/scripts/node/compiler/function-generators.js +239 -0
- package/scripts/node/compiler/loop-handlers.js +45 -0
- package/scripts/node/compiler/main-compiler.js +236 -0
- package/scripts/node/compiler/parsers.js +358 -0
- package/scripts/node/compiler/php-converter.js +227 -0
- package/scripts/node/compiler/register-parser.js +32 -0
- package/scripts/node/compiler/section-handlers.js +46 -0
- package/scripts/node/compiler/template-analyzer.js +50 -0
- package/scripts/node/compiler/template-processor.js +371 -0
- package/scripts/node/compiler/template-processors.js +219 -0
- package/scripts/node/compiler/utils.js +203 -0
- package/scripts/node/compiler/wrapper-parser.js +25 -0
- package/scripts/node/package.json +24 -0
- package/scripts/node/test-compiler.js +52 -0
- package/scripts/node-run.cjs +28 -0
- package/scripts/standardize-directories.php +92 -0
- package/templates/view.module.js +2 -0
- package/templates/view.tpl-raw.js +13 -0
- package/templates/wraper.js +71 -0
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Declaration Tracker - Track thứ tự khai báo của @vars, @let, @const, @useState
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from utils import extract_balanced_parentheses
|
|
7
|
+
from php_converter import php_to_js, convert_php_array_to_json
|
|
8
|
+
|
|
9
|
+
class DeclarationTracker:
|
|
10
|
+
"""Track all variable declarations in order"""
|
|
11
|
+
|
|
12
|
+
def __init__(self):
|
|
13
|
+
self.reset()
|
|
14
|
+
|
|
15
|
+
def reset(self):
|
|
16
|
+
"""Reset tracker state"""
|
|
17
|
+
self.declarations = [] # List of {type, position, content, variables}
|
|
18
|
+
|
|
19
|
+
def parse_all_declarations(self, blade_code):
|
|
20
|
+
"""Parse all declarations and track their order"""
|
|
21
|
+
# Reset to avoid contamination from previous parses
|
|
22
|
+
self.reset()
|
|
23
|
+
|
|
24
|
+
# Remove script tags to avoid parsing JS code
|
|
25
|
+
blade_code_filtered = self._remove_script_tags(blade_code)
|
|
26
|
+
|
|
27
|
+
# Remove @verbatim blocks to avoid parsing declarations inside them
|
|
28
|
+
blade_code_filtered = self._remove_verbatim_blocks(blade_code_filtered)
|
|
29
|
+
|
|
30
|
+
# Find all @vars, @let, @const, @useState with their positions
|
|
31
|
+
self._find_vars_declarations(blade_code_filtered)
|
|
32
|
+
self._find_let_declarations(blade_code_filtered)
|
|
33
|
+
self._find_const_declarations(blade_code_filtered)
|
|
34
|
+
self._find_usestate_declarations(blade_code_filtered)
|
|
35
|
+
|
|
36
|
+
# Sort by position
|
|
37
|
+
self.declarations.sort(key=lambda x: x['position'])
|
|
38
|
+
|
|
39
|
+
return self.declarations
|
|
40
|
+
|
|
41
|
+
def _remove_script_tags(self, blade_code):
|
|
42
|
+
"""Remove JavaScript code in <script> tags"""
|
|
43
|
+
return re.sub(r'<script[^>]*>.*?</script>', '', blade_code, flags=re.DOTALL | re.IGNORECASE)
|
|
44
|
+
|
|
45
|
+
def _remove_verbatim_blocks(self, blade_code):
|
|
46
|
+
"""Remove @verbatim...@endverbatim blocks to avoid parsing declarations inside them"""
|
|
47
|
+
return re.sub(r'@verbatim\s*.*?\s*@endverbatim', '', blade_code, flags=re.DOTALL | re.IGNORECASE)
|
|
48
|
+
|
|
49
|
+
def _find_vars_declarations(self, blade_code):
|
|
50
|
+
"""Find all @vars declarations"""
|
|
51
|
+
pattern = r'@vars\s*\('
|
|
52
|
+
for match in re.finditer(pattern, blade_code):
|
|
53
|
+
start_pos = match.end() - 1
|
|
54
|
+
content, end_pos = extract_balanced_parentheses(blade_code, start_pos)
|
|
55
|
+
if content is not None and content.strip():
|
|
56
|
+
variables = self._parse_vars_content(content.strip())
|
|
57
|
+
self.declarations.append({
|
|
58
|
+
'type': 'vars',
|
|
59
|
+
'position': match.start(),
|
|
60
|
+
'content': content.strip(),
|
|
61
|
+
'variables': variables
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
def _find_let_declarations(self, blade_code):
|
|
65
|
+
"""Find all @let declarations"""
|
|
66
|
+
pattern = r'@let\s*\('
|
|
67
|
+
for match in re.finditer(pattern, blade_code):
|
|
68
|
+
start_pos = match.end() - 1
|
|
69
|
+
content, end_pos = extract_balanced_parentheses(blade_code, start_pos)
|
|
70
|
+
if content is not None and content.strip():
|
|
71
|
+
variables = self._parse_let_content(content.strip())
|
|
72
|
+
self.declarations.append({
|
|
73
|
+
'type': 'let',
|
|
74
|
+
'position': match.start(),
|
|
75
|
+
'content': content.strip(),
|
|
76
|
+
'variables': variables
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
def _find_const_declarations(self, blade_code):
|
|
80
|
+
"""Find all @const declarations"""
|
|
81
|
+
pattern = r'@const\s*\('
|
|
82
|
+
for match in re.finditer(pattern, blade_code):
|
|
83
|
+
start_pos = match.end() - 1
|
|
84
|
+
content, end_pos = extract_balanced_parentheses(blade_code, start_pos)
|
|
85
|
+
if content is not None and content.strip():
|
|
86
|
+
variables = self._parse_const_content(content.strip())
|
|
87
|
+
self.declarations.append({
|
|
88
|
+
'type': 'const',
|
|
89
|
+
'position': match.start(),
|
|
90
|
+
'content': content.strip(),
|
|
91
|
+
'variables': variables
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
def _find_usestate_declarations(self, blade_code):
|
|
95
|
+
"""Find all @useState declarations with format @useState($value, $varName, $setVarName)"""
|
|
96
|
+
pattern = r'@useState\s*\('
|
|
97
|
+
for match in re.finditer(pattern, blade_code):
|
|
98
|
+
start_pos = match.end() - 1
|
|
99
|
+
content, end_pos = extract_balanced_parentheses(blade_code, start_pos)
|
|
100
|
+
if content is not None and content.strip():
|
|
101
|
+
variables = self._parse_usestate_content(content.strip())
|
|
102
|
+
if variables: # Only add if we found valid variables
|
|
103
|
+
self.declarations.append({
|
|
104
|
+
'type': 'useState',
|
|
105
|
+
'position': match.start(),
|
|
106
|
+
'content': content.strip(),
|
|
107
|
+
'variables': variables
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
def _parse_vars_content(self, content):
|
|
111
|
+
"""Parse @vars content and extract variables"""
|
|
112
|
+
variables = []
|
|
113
|
+
|
|
114
|
+
# Handle object destructuring {var1, var2}
|
|
115
|
+
if content.startswith('{') and content.endswith('}'):
|
|
116
|
+
inner = content[1:-1]
|
|
117
|
+
parts = self._split_by_comma(inner)
|
|
118
|
+
else:
|
|
119
|
+
parts = self._split_by_comma(content)
|
|
120
|
+
|
|
121
|
+
for part in parts:
|
|
122
|
+
part = part.strip()
|
|
123
|
+
if '=' in part:
|
|
124
|
+
# Has default value: $user = ...
|
|
125
|
+
equals_pos = self._find_first_equals(part)
|
|
126
|
+
if equals_pos != -1:
|
|
127
|
+
var_name = part[:equals_pos].strip().lstrip('$')
|
|
128
|
+
var_value = part[equals_pos + 1:].strip()
|
|
129
|
+
# Convert PHP to JS
|
|
130
|
+
var_value_js = self._convert_php_to_js(var_value)
|
|
131
|
+
variables.append({
|
|
132
|
+
'name': var_name,
|
|
133
|
+
'value': var_value_js,
|
|
134
|
+
'hasDefault': True
|
|
135
|
+
})
|
|
136
|
+
else:
|
|
137
|
+
# No default value: $test
|
|
138
|
+
var_name = part.strip().lstrip('$')
|
|
139
|
+
variables.append({
|
|
140
|
+
'name': var_name,
|
|
141
|
+
'value': None,
|
|
142
|
+
'hasDefault': False
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
return variables
|
|
146
|
+
|
|
147
|
+
def _parse_let_content(self, content):
|
|
148
|
+
"""Parse @let content and extract variables"""
|
|
149
|
+
variables = []
|
|
150
|
+
|
|
151
|
+
# Split by comma
|
|
152
|
+
parts = self._split_by_comma(content)
|
|
153
|
+
|
|
154
|
+
for part in parts:
|
|
155
|
+
part = part.strip().lstrip('$')
|
|
156
|
+
|
|
157
|
+
# Check for destructuring: [$a, $b] = ... or {a, b} = ...
|
|
158
|
+
if self._is_destructuring(part):
|
|
159
|
+
var_info = self._parse_destructuring(part)
|
|
160
|
+
if var_info:
|
|
161
|
+
variables.append(var_info)
|
|
162
|
+
continue
|
|
163
|
+
|
|
164
|
+
# Check for assignment: $d = $a
|
|
165
|
+
if '=' in part:
|
|
166
|
+
equals_pos = self._find_first_equals(part)
|
|
167
|
+
if equals_pos != -1:
|
|
168
|
+
var_name = part[:equals_pos].strip().lstrip('$')
|
|
169
|
+
var_value = part[equals_pos + 1:].strip()
|
|
170
|
+
var_value_js = self._convert_php_to_js(var_value)
|
|
171
|
+
variables.append({
|
|
172
|
+
'name': var_name,
|
|
173
|
+
'value': var_value_js,
|
|
174
|
+
'hasDefault': True,
|
|
175
|
+
'isDestructuring': False
|
|
176
|
+
})
|
|
177
|
+
else:
|
|
178
|
+
# No assignment
|
|
179
|
+
var_name = part.strip().lstrip('$')
|
|
180
|
+
variables.append({
|
|
181
|
+
'name': var_name,
|
|
182
|
+
'value': None,
|
|
183
|
+
'hasDefault': False,
|
|
184
|
+
'isDestructuring': False
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
return variables
|
|
188
|
+
|
|
189
|
+
def _parse_const_content(self, content):
|
|
190
|
+
"""Parse @const content and extract variables"""
|
|
191
|
+
variables = []
|
|
192
|
+
|
|
193
|
+
# Split by comma
|
|
194
|
+
parts = self._split_by_comma(content)
|
|
195
|
+
|
|
196
|
+
for part in parts:
|
|
197
|
+
part = part.strip().lstrip('$')
|
|
198
|
+
|
|
199
|
+
# Check for destructuring with useState: [$userState, $setUserState] = useState($user)
|
|
200
|
+
if self._is_destructuring(part):
|
|
201
|
+
var_info = self._parse_destructuring(part)
|
|
202
|
+
if var_info:
|
|
203
|
+
# Check if it's useState
|
|
204
|
+
if var_info.get('value') and 'useState(' in var_info['value']:
|
|
205
|
+
var_info['isUseState'] = True
|
|
206
|
+
variables.append(var_info)
|
|
207
|
+
continue
|
|
208
|
+
|
|
209
|
+
# Regular const assignment
|
|
210
|
+
if '=' in part:
|
|
211
|
+
equals_pos = self._find_first_equals(part)
|
|
212
|
+
if equals_pos != -1:
|
|
213
|
+
var_name = part[:equals_pos].strip().lstrip('$')
|
|
214
|
+
var_value = part[equals_pos + 1:].strip()
|
|
215
|
+
var_value_js = self._convert_php_to_js(var_value)
|
|
216
|
+
variables.append({
|
|
217
|
+
'name': var_name,
|
|
218
|
+
'value': var_value_js,
|
|
219
|
+
'hasDefault': True,
|
|
220
|
+
'isDestructuring': False,
|
|
221
|
+
'isUseState': False
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
return variables
|
|
225
|
+
|
|
226
|
+
def _is_destructuring(self, part):
|
|
227
|
+
"""Check if part is destructuring pattern"""
|
|
228
|
+
return ('[' in part and ']' in part and '=' in part) or ('{' in part and '}' in part and '=' in part)
|
|
229
|
+
|
|
230
|
+
def _parse_destructuring(self, part):
|
|
231
|
+
"""Parse destructuring pattern: [$a, $b] = ... or {a, b} = ..."""
|
|
232
|
+
equals_pos = self._find_first_equals(part)
|
|
233
|
+
if equals_pos == -1:
|
|
234
|
+
return None
|
|
235
|
+
|
|
236
|
+
left = part[:equals_pos].strip()
|
|
237
|
+
right = part[equals_pos + 1:].strip()
|
|
238
|
+
|
|
239
|
+
# Extract variable names from left side
|
|
240
|
+
if left.startswith('[') and ']' in left:
|
|
241
|
+
# Array destructuring
|
|
242
|
+
inner = left[1:left.index(']')]
|
|
243
|
+
var_names = [v.strip().lstrip('$') for v in inner.split(',')]
|
|
244
|
+
elif left.startswith('{') and '}' in left:
|
|
245
|
+
# Object destructuring
|
|
246
|
+
inner = left[1:left.index('}')]
|
|
247
|
+
var_names = [v.strip().lstrip('$') for v in inner.split(',')]
|
|
248
|
+
else:
|
|
249
|
+
return None
|
|
250
|
+
|
|
251
|
+
# Convert right side to JS
|
|
252
|
+
right_js = self._convert_php_to_js(right)
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
'names': var_names,
|
|
256
|
+
'value': right_js,
|
|
257
|
+
'isDestructuring': True,
|
|
258
|
+
'destructuringType': 'array' if '[' in left else 'object',
|
|
259
|
+
'isUseState': 'useState(' in right_js
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
def _split_by_comma(self, text):
|
|
263
|
+
"""Split by comma, respecting brackets and parentheses"""
|
|
264
|
+
parts = []
|
|
265
|
+
current = ''
|
|
266
|
+
depth = 0
|
|
267
|
+
in_string = False
|
|
268
|
+
string_char = ''
|
|
269
|
+
|
|
270
|
+
for char in text:
|
|
271
|
+
if char in ['"', "'"]:
|
|
272
|
+
if in_string and char == string_char:
|
|
273
|
+
in_string = False
|
|
274
|
+
elif not in_string:
|
|
275
|
+
in_string = True
|
|
276
|
+
string_char = char
|
|
277
|
+
elif not in_string:
|
|
278
|
+
if char in ['(', '[', '{']:
|
|
279
|
+
depth += 1
|
|
280
|
+
elif char in [')', ']', '}']:
|
|
281
|
+
depth -= 1
|
|
282
|
+
elif char == ',' and depth == 0:
|
|
283
|
+
parts.append(current.strip())
|
|
284
|
+
current = ''
|
|
285
|
+
continue
|
|
286
|
+
|
|
287
|
+
current += char
|
|
288
|
+
|
|
289
|
+
if current.strip():
|
|
290
|
+
parts.append(current.strip())
|
|
291
|
+
|
|
292
|
+
return parts
|
|
293
|
+
|
|
294
|
+
def _find_first_equals(self, text):
|
|
295
|
+
"""Find first = sign outside of brackets/parentheses"""
|
|
296
|
+
depth = 0
|
|
297
|
+
in_string = False
|
|
298
|
+
string_char = ''
|
|
299
|
+
|
|
300
|
+
for i, char in enumerate(text):
|
|
301
|
+
if char in ['"', "'"]:
|
|
302
|
+
if in_string and char == string_char:
|
|
303
|
+
in_string = False
|
|
304
|
+
elif not in_string:
|
|
305
|
+
in_string = True
|
|
306
|
+
string_char = char
|
|
307
|
+
elif not in_string:
|
|
308
|
+
if char in ['(', '[', '{']:
|
|
309
|
+
depth += 1
|
|
310
|
+
elif char in [')', ']', '}']:
|
|
311
|
+
depth -= 1
|
|
312
|
+
elif char == '=' and depth == 0:
|
|
313
|
+
return i
|
|
314
|
+
|
|
315
|
+
return -1
|
|
316
|
+
|
|
317
|
+
def _convert_php_to_js(self, expr):
|
|
318
|
+
"""Convert PHP expression to JavaScript"""
|
|
319
|
+
# Use existing converter
|
|
320
|
+
expr = php_to_js(expr)
|
|
321
|
+
# Remove $ from variables
|
|
322
|
+
expr = re.sub(r'\$(\w+)', r'\1', expr)
|
|
323
|
+
return expr
|
|
324
|
+
|
|
325
|
+
def _parse_usestate_content(self, content):
|
|
326
|
+
"""Parse @useState content with three formats:
|
|
327
|
+
1. @useState($value, $varName, $setVarName) - Single state with 3 params
|
|
328
|
+
2. @useState($varName, value) - Single state with 2 params (auto-generate setter)
|
|
329
|
+
3. @useState(['key1' => value1, 'key2' => value2]) - Multiple states in array
|
|
330
|
+
"""
|
|
331
|
+
content = content.strip()
|
|
332
|
+
|
|
333
|
+
# Check if it's array format ['key' => value, ...]
|
|
334
|
+
if content.startswith('[') and content.endswith(']'):
|
|
335
|
+
return self._parse_usestate_array_format(content)
|
|
336
|
+
|
|
337
|
+
# Parse parameters
|
|
338
|
+
parts = self._split_by_comma(content)
|
|
339
|
+
|
|
340
|
+
# New 2-parameter format: @useState($varName, value)
|
|
341
|
+
if len(parts) == 2:
|
|
342
|
+
var_name = parts[0].strip()
|
|
343
|
+
value = parts[1].strip()
|
|
344
|
+
|
|
345
|
+
# Check if first param is a variable (starts with $)
|
|
346
|
+
if var_name.startswith('$'):
|
|
347
|
+
var_name = var_name.lstrip('$')
|
|
348
|
+
# Auto-generate setter name: user -> setUser
|
|
349
|
+
setter_name = f'set{var_name[0].upper()}{var_name[1:]}' if var_name else 'setValue'
|
|
350
|
+
|
|
351
|
+
# Convert value to JS
|
|
352
|
+
value_js = self._convert_php_to_js(value)
|
|
353
|
+
|
|
354
|
+
# Create a destructuring variable like @const([$varName, $setVarName] = useState(value))
|
|
355
|
+
return [{
|
|
356
|
+
'names': [var_name, setter_name],
|
|
357
|
+
'value': f'useState({value_js})',
|
|
358
|
+
'isDestructuring': True,
|
|
359
|
+
'destructuringType': 'array',
|
|
360
|
+
'isUseState': True
|
|
361
|
+
}]
|
|
362
|
+
|
|
363
|
+
# Original 3-parameter format
|
|
364
|
+
if len(parts) == 3:
|
|
365
|
+
value = parts[0].strip()
|
|
366
|
+
var_name = parts[1].strip()
|
|
367
|
+
setter_name = parts[2].strip()
|
|
368
|
+
|
|
369
|
+
# Remove $ prefix
|
|
370
|
+
value = value.lstrip('$')
|
|
371
|
+
var_name = var_name.lstrip('$')
|
|
372
|
+
setter_name = setter_name.lstrip('$')
|
|
373
|
+
|
|
374
|
+
# Create a destructuring variable like @let([$varName, $setVarName] = useState($value))
|
|
375
|
+
return [{
|
|
376
|
+
'names': [var_name, setter_name],
|
|
377
|
+
'value': f'useState({self._convert_php_to_js(value)})',
|
|
378
|
+
'isDestructuring': True,
|
|
379
|
+
'destructuringType': 'array',
|
|
380
|
+
'isUseState': True
|
|
381
|
+
}]
|
|
382
|
+
|
|
383
|
+
return []
|
|
384
|
+
|
|
385
|
+
def _parse_usestate_array_format(self, content):
|
|
386
|
+
"""Parse array format: @useState(['key1' => value1, 'key2' => value2])
|
|
387
|
+
Each key becomes a state variable with its setter
|
|
388
|
+
"""
|
|
389
|
+
variables = []
|
|
390
|
+
|
|
391
|
+
# Remove [ and ]
|
|
392
|
+
inner = content[1:-1].strip()
|
|
393
|
+
|
|
394
|
+
# Split by comma (handle nested structures)
|
|
395
|
+
parts = self._split_by_comma(inner)
|
|
396
|
+
|
|
397
|
+
for part in parts:
|
|
398
|
+
part = part.strip()
|
|
399
|
+
if '=>' in part:
|
|
400
|
+
# Split by =>
|
|
401
|
+
arrow_pos = part.find('=>')
|
|
402
|
+
key = part[:arrow_pos].strip().strip("'\"").lstrip('$')
|
|
403
|
+
value = part[arrow_pos + 2:].strip()
|
|
404
|
+
|
|
405
|
+
# Convert value to JS
|
|
406
|
+
value_js = self._convert_php_to_js(value)
|
|
407
|
+
|
|
408
|
+
# Create setter name: key -> setKey or set_key
|
|
409
|
+
setter_name = f'set{key[0].upper()}{key[1:]}' if key else 'setValue'
|
|
410
|
+
|
|
411
|
+
# Create destructuring for each state
|
|
412
|
+
variables.append({
|
|
413
|
+
'names': [key, setter_name],
|
|
414
|
+
'value': f'useState({value_js})',
|
|
415
|
+
'isDestructuring': True,
|
|
416
|
+
'destructuringType': 'array',
|
|
417
|
+
'isUseState': True
|
|
418
|
+
})
|
|
419
|
+
|
|
420
|
+
return variables
|