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.
Files changed (119) hide show
  1. package/README.md +1 -1
  2. package/bin/onejs-build.js +32 -0
  3. package/package.json +11 -3
  4. package/scripts/README-template-compiler.md +133 -0
  5. package/scripts/README.md +61 -0
  6. package/scripts/__pycache__/build.cpython-314.pyc +0 -0
  7. package/scripts/__pycache__/compile.cpython-313.pyc +0 -0
  8. package/scripts/__pycache__/compile.cpython-314.pyc +0 -0
  9. package/scripts/build.py +573 -0
  10. package/scripts/check-system-errors.php +214 -0
  11. package/scripts/compile.py +101 -0
  12. package/scripts/compiler/README_CONFIG.md +196 -0
  13. package/scripts/compiler/__init__.py +18 -0
  14. package/scripts/compiler/__pycache__/__init__.cpython-313.pyc +0 -0
  15. package/scripts/compiler/__pycache__/__init__.cpython-314.pyc +0 -0
  16. package/scripts/compiler/__pycache__/binding_directive_service.cpython-314.pyc +0 -0
  17. package/scripts/compiler/__pycache__/class_binding_handler.cpython-314.pyc +0 -0
  18. package/scripts/compiler/__pycache__/compiler_utils.cpython-313.pyc +0 -0
  19. package/scripts/compiler/__pycache__/compiler_utils.cpython-314.pyc +0 -0
  20. package/scripts/compiler/__pycache__/conditional_handlers.cpython-313.pyc +0 -0
  21. package/scripts/compiler/__pycache__/conditional_handlers.cpython-314.pyc +0 -0
  22. package/scripts/compiler/__pycache__/config.cpython-313.pyc +0 -0
  23. package/scripts/compiler/__pycache__/config.cpython-314.pyc +0 -0
  24. package/scripts/compiler/__pycache__/declaration_tracker.cpython-314.pyc +0 -0
  25. package/scripts/compiler/__pycache__/directive_processors.cpython-313.pyc +0 -0
  26. package/scripts/compiler/__pycache__/directive_processors.cpython-314.pyc +0 -0
  27. package/scripts/compiler/__pycache__/echo_processor.cpython-314.pyc +0 -0
  28. package/scripts/compiler/__pycache__/event_directive_processor.cpython-313.pyc +0 -0
  29. package/scripts/compiler/__pycache__/event_directive_processor.cpython-314.pyc +0 -0
  30. package/scripts/compiler/__pycache__/function_generators.cpython-313.pyc +0 -0
  31. package/scripts/compiler/__pycache__/function_generators.cpython-314.pyc +0 -0
  32. package/scripts/compiler/__pycache__/loop_handlers.cpython-313.pyc +0 -0
  33. package/scripts/compiler/__pycache__/loop_handlers.cpython-314.pyc +0 -0
  34. package/scripts/compiler/__pycache__/main_compiler.cpython-313.pyc +0 -0
  35. package/scripts/compiler/__pycache__/main_compiler.cpython-314.pyc +0 -0
  36. package/scripts/compiler/__pycache__/parsers.cpython-313.pyc +0 -0
  37. package/scripts/compiler/__pycache__/parsers.cpython-314.pyc +0 -0
  38. package/scripts/compiler/__pycache__/php_converter.cpython-313.pyc +0 -0
  39. package/scripts/compiler/__pycache__/php_converter.cpython-314.pyc +0 -0
  40. package/scripts/compiler/__pycache__/php_js_converter.cpython-313.pyc +0 -0
  41. package/scripts/compiler/__pycache__/php_js_converter.cpython-314.pyc +0 -0
  42. package/scripts/compiler/__pycache__/register_parser.cpython-313.pyc +0 -0
  43. package/scripts/compiler/__pycache__/register_parser.cpython-314.pyc +0 -0
  44. package/scripts/compiler/__pycache__/section_handlers.cpython-313.pyc +0 -0
  45. package/scripts/compiler/__pycache__/section_handlers.cpython-314.pyc +0 -0
  46. package/scripts/compiler/__pycache__/show_directive_handler.cpython-314.pyc +0 -0
  47. package/scripts/compiler/__pycache__/style_directive_handler.cpython-314.pyc +0 -0
  48. package/scripts/compiler/__pycache__/template_analyzer.cpython-313.pyc +0 -0
  49. package/scripts/compiler/__pycache__/template_analyzer.cpython-314.pyc +0 -0
  50. package/scripts/compiler/__pycache__/template_processor.cpython-313.pyc +0 -0
  51. package/scripts/compiler/__pycache__/template_processor.cpython-314.pyc +0 -0
  52. package/scripts/compiler/__pycache__/template_processors.cpython-313.pyc +0 -0
  53. package/scripts/compiler/__pycache__/template_processors.cpython-314.pyc +0 -0
  54. package/scripts/compiler/__pycache__/utils.cpython-313.pyc +0 -0
  55. package/scripts/compiler/__pycache__/utils.cpython-314.pyc +0 -0
  56. package/scripts/compiler/__pycache__/wrapper_parser.cpython-313.pyc +0 -0
  57. package/scripts/compiler/__pycache__/wrapper_parser.cpython-314.pyc +0 -0
  58. package/scripts/compiler/binding_directive_service.py +103 -0
  59. package/scripts/compiler/class_binding_handler.py +347 -0
  60. package/scripts/compiler/cli.py +34 -0
  61. package/scripts/compiler/code_generator.py +141 -0
  62. package/scripts/compiler/compiler.config.json +36 -0
  63. package/scripts/compiler/compiler_utils.py +55 -0
  64. package/scripts/compiler/conditional_handlers.py +252 -0
  65. package/scripts/compiler/config.py +107 -0
  66. package/scripts/compiler/declaration_tracker.py +420 -0
  67. package/scripts/compiler/directive_processors.py +603 -0
  68. package/scripts/compiler/echo_processor.py +667 -0
  69. package/scripts/compiler/event_directive_processor.py +1099 -0
  70. package/scripts/compiler/fetch_parser.py +49 -0
  71. package/scripts/compiler/function_generators.py +310 -0
  72. package/scripts/compiler/loop_handlers.py +224 -0
  73. package/scripts/compiler/main_compiler.py +1763 -0
  74. package/scripts/compiler/parsers.py +1418 -0
  75. package/scripts/compiler/php_converter.py +470 -0
  76. package/scripts/compiler/php_js_converter.py +603 -0
  77. package/scripts/compiler/register_parser.py +480 -0
  78. package/scripts/compiler/section_handlers.py +122 -0
  79. package/scripts/compiler/show_directive_handler.py +85 -0
  80. package/scripts/compiler/style_directive_handler.py +169 -0
  81. package/scripts/compiler/template_analyzer.py +162 -0
  82. package/scripts/compiler/template_processor.py +1167 -0
  83. package/scripts/compiler/template_processors.py +1557 -0
  84. package/scripts/compiler/test_compiler.py +69 -0
  85. package/scripts/compiler/utils.py +54 -0
  86. package/scripts/compiler/variables_analyzer.py +135 -0
  87. package/scripts/compiler/view_identifier_generator.py +278 -0
  88. package/scripts/compiler/wrapper_parser.py +78 -0
  89. package/scripts/dev-context.js +311 -0
  90. package/scripts/dev.js +109 -0
  91. package/scripts/generate-assets-order.js +200 -0
  92. package/scripts/migrate-namespace.php +146 -0
  93. package/scripts/node/MIGRATION.md +190 -0
  94. package/scripts/node/README.md +269 -0
  95. package/scripts/node/build.js +208 -0
  96. package/scripts/node/compiler/compiler-utils.js +38 -0
  97. package/scripts/node/compiler/conditional-handlers.js +45 -0
  98. package/scripts/node/compiler/config.js +178 -0
  99. package/scripts/node/compiler/directive-processors.js +51 -0
  100. package/scripts/node/compiler/event-directive-processor.js +182 -0
  101. package/scripts/node/compiler/function-generators.js +239 -0
  102. package/scripts/node/compiler/loop-handlers.js +45 -0
  103. package/scripts/node/compiler/main-compiler.js +236 -0
  104. package/scripts/node/compiler/parsers.js +358 -0
  105. package/scripts/node/compiler/php-converter.js +227 -0
  106. package/scripts/node/compiler/register-parser.js +32 -0
  107. package/scripts/node/compiler/section-handlers.js +46 -0
  108. package/scripts/node/compiler/template-analyzer.js +50 -0
  109. package/scripts/node/compiler/template-processor.js +371 -0
  110. package/scripts/node/compiler/template-processors.js +219 -0
  111. package/scripts/node/compiler/utils.js +203 -0
  112. package/scripts/node/compiler/wrapper-parser.js +25 -0
  113. package/scripts/node/package.json +24 -0
  114. package/scripts/node/test-compiler.js +52 -0
  115. package/scripts/node-run.cjs +28 -0
  116. package/scripts/standardize-directories.php +92 -0
  117. package/templates/view.module.js +2 -0
  118. package/templates/view.tpl-raw.js +13 -0
  119. 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