onelaraveljs 1.0.0 → 1.1.3
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/index.js +3 -1
- 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 +574 -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 +208 -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/src/core/ViewManager.js +4 -4
- package/templates/view.module.js +2 -0
- package/templates/view.tpl-raw.js +13 -0
- package/templates/wraper.js +71 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utility methods cho compiler
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from config import JS_FUNCTION_PREFIX
|
|
7
|
+
|
|
8
|
+
class CompilerUtils:
|
|
9
|
+
def __init__(self):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
def format_fetch_config(self, fetch_config):
|
|
13
|
+
"""Format fetch config without extra quotes around template strings"""
|
|
14
|
+
if not fetch_config:
|
|
15
|
+
return 'null'
|
|
16
|
+
|
|
17
|
+
# Format the config manually to avoid json.dumps adding quotes
|
|
18
|
+
config_parts = []
|
|
19
|
+
for key, value in fetch_config.items():
|
|
20
|
+
if isinstance(value, str):
|
|
21
|
+
# Check if it's a template string (starts with ` and ends with `)
|
|
22
|
+
if value.startswith('`') and value.endswith('`'):
|
|
23
|
+
# Template string - don't add quotes
|
|
24
|
+
config_parts.append(f'"{key}": {value}')
|
|
25
|
+
else:
|
|
26
|
+
# Regular string - add quotes
|
|
27
|
+
config_parts.append(f'"{key}": "{value}"')
|
|
28
|
+
elif isinstance(value, (dict, list)):
|
|
29
|
+
# Object or array - use json.dumps
|
|
30
|
+
config_parts.append(f'"{key}": {json.dumps(value, ensure_ascii=False)}')
|
|
31
|
+
else:
|
|
32
|
+
# Other types (numbers, booleans, etc.) - use json.dumps
|
|
33
|
+
config_parts.append(f'"{key}": {json.dumps(value, ensure_ascii=False)}')
|
|
34
|
+
|
|
35
|
+
return '{' + ', '.join(config_parts) + '}'
|
|
36
|
+
|
|
37
|
+
def format_attrs(self, attrs_dict):
|
|
38
|
+
"""Format attributes dictionary to JavaScript object string"""
|
|
39
|
+
import json
|
|
40
|
+
return json.dumps(attrs_dict, separators=(',', ':'))
|
|
41
|
+
|
|
42
|
+
def format_attributes_to_json(self, attributes):
|
|
43
|
+
"""Format attributes dictionary to JSON string for scripts/styles"""
|
|
44
|
+
if not attributes:
|
|
45
|
+
return '{}'
|
|
46
|
+
|
|
47
|
+
# Handle boolean and string attributes properly
|
|
48
|
+
formatted_attrs = {}
|
|
49
|
+
for key, value in attributes.items():
|
|
50
|
+
if isinstance(value, bool):
|
|
51
|
+
formatted_attrs[key] = value
|
|
52
|
+
else:
|
|
53
|
+
formatted_attrs[key] = str(value)
|
|
54
|
+
|
|
55
|
+
return json.dumps(formatted_attrs, separators=(',', ':'))
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Handlers cho các conditional directives (@if, @switch, etc.)
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from config import JS_FUNCTION_PREFIX
|
|
6
|
+
from php_converter import php_to_js
|
|
7
|
+
from utils import extract_balanced_parentheses
|
|
8
|
+
import re
|
|
9
|
+
|
|
10
|
+
class ConditionalHandlers:
|
|
11
|
+
def __init__(self, state_variables=None, processor=None):
|
|
12
|
+
self.state_variables = state_variables or set()
|
|
13
|
+
self.processor = processor
|
|
14
|
+
|
|
15
|
+
def _extract_variables(self, expr):
|
|
16
|
+
"""Extract variable names from expression, excluding method names after dot notation"""
|
|
17
|
+
variables = set()
|
|
18
|
+
|
|
19
|
+
# Remove method calls after dots (e.g., App.Helper.count -> remove count)
|
|
20
|
+
# Replace .methodName( with .PLACEHOLDER( to avoid extracting method names
|
|
21
|
+
expr_cleaned = re.sub(r'\.([a-zA-Z_][a-zA-Z0-9_]*)\s*\(', '.METHODCALL(', expr)
|
|
22
|
+
|
|
23
|
+
var_pattern = r'\b([a-zA-Z_][a-zA-Z0-9_]*)\b'
|
|
24
|
+
matches = re.findall(var_pattern, expr_cleaned)
|
|
25
|
+
for var_name in matches:
|
|
26
|
+
# Exclude JS keywords, common functions, and placeholder
|
|
27
|
+
if var_name not in ['if', 'else', 'return', 'function', 'const', 'let', 'var', 'true', 'false', 'null', 'undefined', 'Array', 'Object', 'String', 'Number', 'METHODCALL', 'App', 'View', 'Helper']:
|
|
28
|
+
variables.add(var_name)
|
|
29
|
+
return variables
|
|
30
|
+
|
|
31
|
+
def process_if_directive(self, line, stack, output, is_attribute_context=False):
|
|
32
|
+
"""Process @if directive
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
is_attribute_context: True if directive is in tag attributes (e.g., <div @if(...)>)
|
|
36
|
+
False if directive is in block/content (e.g., <div>@if(...))
|
|
37
|
+
"""
|
|
38
|
+
if_pos = line.find('(')
|
|
39
|
+
if if_pos != -1:
|
|
40
|
+
condition_text, end_pos = extract_balanced_parentheses(line, if_pos)
|
|
41
|
+
if condition_text is not None:
|
|
42
|
+
condition_php = condition_text.strip()
|
|
43
|
+
condition = php_to_js(condition_php)
|
|
44
|
+
|
|
45
|
+
# Extract variables from condition
|
|
46
|
+
variables = self._extract_variables(condition)
|
|
47
|
+
state_vars_used = variables & self.state_variables
|
|
48
|
+
|
|
49
|
+
# Store state vars for this if block (will be used in endif)
|
|
50
|
+
watch_keys = list(state_vars_used) if state_vars_used else []
|
|
51
|
+
|
|
52
|
+
# Check if inside a loop (for/while only, NOT foreach)
|
|
53
|
+
# @foreach uses callback that returns template literal directly
|
|
54
|
+
# Only @for and @while use __outputContent__ concatenation pattern
|
|
55
|
+
parent_is_loop = False
|
|
56
|
+
parent_concat_var = ""
|
|
57
|
+
if stack:
|
|
58
|
+
parent_type = stack[-1][0]
|
|
59
|
+
if parent_type in ['for', 'while']:
|
|
60
|
+
parent_is_loop = True
|
|
61
|
+
parent_concat_var = f"__{parent_type}OutputContent__"
|
|
62
|
+
|
|
63
|
+
# If inside a loop and has state vars, use concat += with __watch
|
|
64
|
+
if parent_is_loop and watch_keys:
|
|
65
|
+
if self.processor:
|
|
66
|
+
self.processor.watch_counter += 1
|
|
67
|
+
watch_id = f"`${{__VIEW_ID__}}-watch-{self.processor.watch_counter}-${{__loop.index}}`"
|
|
68
|
+
else:
|
|
69
|
+
watch_id = "`${__VIEW_ID__}-watch-0-${__loop.index}`"
|
|
70
|
+
result = f"{parent_concat_var} += this.__watch({watch_id}, {watch_keys}, () => {{ if({condition}){{ return `"
|
|
71
|
+
# If inside a loop but no state vars, use concat += with IIFE
|
|
72
|
+
elif parent_is_loop:
|
|
73
|
+
result = f"{parent_concat_var} += (() => {{ if({condition}){{ return `"
|
|
74
|
+
# Only wrap with __watch for block-level directives (not attributes, not in loops)
|
|
75
|
+
elif is_attribute_context or not watch_keys:
|
|
76
|
+
# Attribute directive or no state vars - no watch wrapping
|
|
77
|
+
result = f"${{this.__execute(() => {{ if({condition}){{ return `"
|
|
78
|
+
else:
|
|
79
|
+
# Block directive with state vars - wrap with __watch
|
|
80
|
+
if self.processor:
|
|
81
|
+
self.processor.watch_counter += 1
|
|
82
|
+
watch_id = f"`${{__VIEW_ID__}}-watch-{self.processor.watch_counter}`"
|
|
83
|
+
else:
|
|
84
|
+
watch_id = "`${__VIEW_ID__}-watch-0`"
|
|
85
|
+
result = f"${{this.__watch({watch_id}, {watch_keys}, () => {{ if({condition}){{ return `"
|
|
86
|
+
|
|
87
|
+
output.append(result)
|
|
88
|
+
stack.append(('if', len(output), watch_keys, is_attribute_context, parent_is_loop))
|
|
89
|
+
return True
|
|
90
|
+
return False
|
|
91
|
+
|
|
92
|
+
def process_elseif_directive(self, line, stack, output):
|
|
93
|
+
"""Process @elseif directive"""
|
|
94
|
+
elseif_pos = line.find('(')
|
|
95
|
+
if elseif_pos != -1:
|
|
96
|
+
condition_text, end_pos = extract_balanced_parentheses(line, elseif_pos)
|
|
97
|
+
if condition_text is not None:
|
|
98
|
+
condition_php = condition_text.strip()
|
|
99
|
+
condition = php_to_js(condition_php)
|
|
100
|
+
|
|
101
|
+
# Extract variables and merge with existing if block's watch keys
|
|
102
|
+
variables = self._extract_variables(condition)
|
|
103
|
+
state_vars_used = variables & self.state_variables
|
|
104
|
+
|
|
105
|
+
# Update watch_keys in stack
|
|
106
|
+
if stack and stack[-1][0] == 'if':
|
|
107
|
+
existing_keys = set(stack[-1][2]) if len(stack[-1]) > 2 else set()
|
|
108
|
+
new_keys = existing_keys | state_vars_used
|
|
109
|
+
stack[-1] = ('if', stack[-1][1], list(new_keys))
|
|
110
|
+
|
|
111
|
+
result = f"`; }} else if({condition}){{ return `"
|
|
112
|
+
output.append(result)
|
|
113
|
+
return True
|
|
114
|
+
return False
|
|
115
|
+
|
|
116
|
+
def process_else_directive(self, line, stack, output):
|
|
117
|
+
"""Process @else directive"""
|
|
118
|
+
# Check if we're inside a loop (need to escape backticks)
|
|
119
|
+
parent_is_loop = False
|
|
120
|
+
if stack and stack[-1][0] == 'if':
|
|
121
|
+
parent_is_loop = stack[-1][4] if len(stack[-1]) > 4 else False
|
|
122
|
+
|
|
123
|
+
result = f"`; }} else {{ return `"
|
|
124
|
+
output.append(result)
|
|
125
|
+
return True
|
|
126
|
+
|
|
127
|
+
def process_endif_directive(self, stack, output):
|
|
128
|
+
"""Process @endif directive"""
|
|
129
|
+
if stack and stack[-1][0] == 'if':
|
|
130
|
+
is_attribute = stack[-1][3] if len(stack[-1]) > 3 else False
|
|
131
|
+
parent_is_loop = stack[-1][4] if len(stack[-1]) > 4 else False
|
|
132
|
+
watch_keys = stack[-1][2] if len(stack[-1]) > 2 else []
|
|
133
|
+
stack.pop()
|
|
134
|
+
|
|
135
|
+
output.append('`; }')
|
|
136
|
+
output.append("return '';")
|
|
137
|
+
|
|
138
|
+
if parent_is_loop and watch_keys:
|
|
139
|
+
# Inside loop with state vars - close watch without template wrapper
|
|
140
|
+
# Pattern: })); where } closes arrow func, )) closes watch call, ; ends statement
|
|
141
|
+
output.append('});')
|
|
142
|
+
elif parent_is_loop:
|
|
143
|
+
# Inside loop without state vars - close IIFE with immediate execution
|
|
144
|
+
output.append('})')
|
|
145
|
+
else:
|
|
146
|
+
# Normal block - close IIFE or watch
|
|
147
|
+
output.append('})}')
|
|
148
|
+
return True
|
|
149
|
+
|
|
150
|
+
def process_switch_directive(self, line, stack, output, is_attribute_context=False):
|
|
151
|
+
"""Process @switch directive
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
is_attribute_context: True if directive is in tag attributes
|
|
155
|
+
False if directive is in block/content
|
|
156
|
+
"""
|
|
157
|
+
switch_pos = line.find('(')
|
|
158
|
+
if switch_pos != -1:
|
|
159
|
+
switch_content, end_pos = extract_balanced_parentheses(line, switch_pos)
|
|
160
|
+
if switch_content is not None:
|
|
161
|
+
condition_php = switch_content.strip()
|
|
162
|
+
condition = php_to_js(condition_php)
|
|
163
|
+
|
|
164
|
+
# Extract variables from condition
|
|
165
|
+
variables = self._extract_variables(condition)
|
|
166
|
+
state_vars_used = variables & self.state_variables
|
|
167
|
+
watch_keys = list(state_vars_used) if state_vars_used else []
|
|
168
|
+
|
|
169
|
+
# Check if parent is a loop using concatenation pattern
|
|
170
|
+
parent_is_concat = False
|
|
171
|
+
parent_type_name = None
|
|
172
|
+
if stack:
|
|
173
|
+
parent_type = stack[-1][0]
|
|
174
|
+
if parent_type in ['for', 'foreach', 'while']:
|
|
175
|
+
parent_is_concat = True
|
|
176
|
+
parent_type_name = parent_type
|
|
177
|
+
|
|
178
|
+
# Generate switch statement
|
|
179
|
+
switch_logic = f"let __switchOutputContent__ = '';\nswitch({condition}) {{"
|
|
180
|
+
|
|
181
|
+
# Determine output format based on parent context
|
|
182
|
+
if parent_is_concat:
|
|
183
|
+
# Parent uses concatenation (+=), so add concat prefix and use this.__execute()
|
|
184
|
+
concat_var = f"__{parent_type_name}OutputContent__"
|
|
185
|
+
if is_attribute_context or not watch_keys:
|
|
186
|
+
result = f"{concat_var} += this.__execute(() => {{\n{switch_logic}"
|
|
187
|
+
else:
|
|
188
|
+
if self.processor:
|
|
189
|
+
self.processor.watch_counter += 1
|
|
190
|
+
watch_id = f"`${{__VIEW_ID__}}-watch-{self.processor.watch_counter}`"
|
|
191
|
+
else:
|
|
192
|
+
watch_id = "`${__VIEW_ID__}-watch-0`"
|
|
193
|
+
result = f"{concat_var} += this.__watch({watch_id}, {watch_keys}, () => {{\n{switch_logic}"
|
|
194
|
+
else:
|
|
195
|
+
# Parent uses template literal, so output template expression
|
|
196
|
+
if is_attribute_context or not watch_keys:
|
|
197
|
+
result = f"${{this.__execute(() => {{\n{switch_logic}"
|
|
198
|
+
else:
|
|
199
|
+
if self.processor:
|
|
200
|
+
self.processor.watch_counter += 1
|
|
201
|
+
watch_id = f"`${{__VIEW_ID__}}-watch-{self.processor.watch_counter}`"
|
|
202
|
+
else:
|
|
203
|
+
watch_id = "`${__VIEW_ID__}-watch-0`"
|
|
204
|
+
result = f"${{this.__watch({watch_id}, {watch_keys}, () => {{\n{switch_logic}"
|
|
205
|
+
|
|
206
|
+
output.append(result)
|
|
207
|
+
stack.append(('switch', len(output), watch_keys, is_attribute_context, parent_is_concat))
|
|
208
|
+
return True
|
|
209
|
+
return False
|
|
210
|
+
|
|
211
|
+
def process_case_directive(self, line, stack, output):
|
|
212
|
+
"""Process @case directive"""
|
|
213
|
+
case_pos = line.find('(')
|
|
214
|
+
if case_pos != -1:
|
|
215
|
+
case_content, end_pos = extract_balanced_parentheses(line, case_pos)
|
|
216
|
+
if case_content is not None:
|
|
217
|
+
condition = php_to_js(case_content.strip())
|
|
218
|
+
result = f"\ncase {condition}:\n__switchOutputContent__ += `"
|
|
219
|
+
output.append(result)
|
|
220
|
+
# Don't push to stack - case is part of switch
|
|
221
|
+
return True
|
|
222
|
+
return False
|
|
223
|
+
|
|
224
|
+
def process_default_directive(self, line, stack, output):
|
|
225
|
+
"""Process @default directive"""
|
|
226
|
+
result = f"\ndefault:\n__switchOutputContent__ += `"
|
|
227
|
+
output.append(result)
|
|
228
|
+
# Don't push to stack - default is part of switch
|
|
229
|
+
return True
|
|
230
|
+
|
|
231
|
+
def process_break_directive(self, line, stack, output):
|
|
232
|
+
"""Process @break directive"""
|
|
233
|
+
result = f"`;\nbreak;"
|
|
234
|
+
output.append(result)
|
|
235
|
+
return True
|
|
236
|
+
|
|
237
|
+
def process_endswitch_directive(self, stack, output):
|
|
238
|
+
"""Process @endswitch directive"""
|
|
239
|
+
if stack and stack[-1][0] == 'switch':
|
|
240
|
+
switch_info = stack.pop()
|
|
241
|
+
parent_is_concat = switch_info[4] if len(switch_info) > 4 else False
|
|
242
|
+
|
|
243
|
+
if parent_is_concat:
|
|
244
|
+
# Parent uses concatenation, close with })
|
|
245
|
+
result = "`;\n}\nreturn __switchOutputContent__;\n})"
|
|
246
|
+
else:
|
|
247
|
+
# Parent uses template literal, output template expression
|
|
248
|
+
result = "`;\n}\nreturn __switchOutputContent__;\n})}"
|
|
249
|
+
|
|
250
|
+
output.append(result)
|
|
251
|
+
return True
|
|
252
|
+
return False
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration file for Python Blade Compiler (Library Version)
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
class CompilerConfig:
|
|
8
|
+
"""Configuration class for Blade compiler paths and settings"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, config_file=None):
|
|
11
|
+
# 1. Project Root: Taken from environment variable (Passed by CLI wrapper)
|
|
12
|
+
self.project_root = os.environ.get('ONEJS_PROJECT_ROOT')
|
|
13
|
+
if not self.project_root:
|
|
14
|
+
# Fallback for dev/testing in library itself
|
|
15
|
+
self.project_root = os.getcwd()
|
|
16
|
+
|
|
17
|
+
# 2. Library Root: Taken from environment variable (Passed by CLI wrapper)
|
|
18
|
+
self.lib_root = os.environ.get('ONEJS_LIB_ROOT')
|
|
19
|
+
if not self.lib_root:
|
|
20
|
+
# Fallback relative to this file
|
|
21
|
+
self.lib_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
22
|
+
|
|
23
|
+
# Load build config from PROJECT root (User's project)
|
|
24
|
+
# It's usually build.config.json or compiler.config.json
|
|
25
|
+
# We try to find build.config.json first as it is the new standard
|
|
26
|
+
self.build_config_file = os.path.join(self.project_root, 'build.config.json')
|
|
27
|
+
self.build_config_data = {}
|
|
28
|
+
|
|
29
|
+
if os.path.exists(self.build_config_file):
|
|
30
|
+
try:
|
|
31
|
+
with open(self.build_config_file, 'r', encoding='utf-8') as f:
|
|
32
|
+
self.build_config_data = json.load(f)
|
|
33
|
+
except Exception as e:
|
|
34
|
+
print(f"Warning: Could not load build.config.json: {e}")
|
|
35
|
+
|
|
36
|
+
# Default paths
|
|
37
|
+
self.views_input_path = os.path.join(self.project_root, 'resources/views')
|
|
38
|
+
# Default js output: resources/js (The compiler will append /views or /config internally)
|
|
39
|
+
self.js_input_path = os.path.join(self.project_root, 'resources/js')
|
|
40
|
+
|
|
41
|
+
# Template path (Internal to Library)
|
|
42
|
+
self.wrapper_template_path = os.path.join(self.lib_root, 'templates')
|
|
43
|
+
|
|
44
|
+
# Files
|
|
45
|
+
self.view_templates_file = 'templates.js'
|
|
46
|
+
|
|
47
|
+
# Other settings from config or defaults
|
|
48
|
+
self.config_data = self.build_config_data # Alias for compatibility
|
|
49
|
+
|
|
50
|
+
def get_wrapper_template_path(self):
|
|
51
|
+
"""Get path to the wrapper template inside the library"""
|
|
52
|
+
return self.wrapper_template_path
|
|
53
|
+
|
|
54
|
+
def get_build_directories(self):
|
|
55
|
+
"""Get list of directories to build (relative to views root)"""
|
|
56
|
+
# If 'contexts' is defined in build.config.json, we don't use this old method usually,
|
|
57
|
+
# but for compatibility or simple usage:
|
|
58
|
+
return []
|
|
59
|
+
|
|
60
|
+
def get_views_path(self, scope=None):
|
|
61
|
+
if scope:
|
|
62
|
+
return os.path.join(self.views_input_path, scope)
|
|
63
|
+
return self.views_input_path
|
|
64
|
+
|
|
65
|
+
def get_js_input_path(self):
|
|
66
|
+
return self.js_input_path
|
|
67
|
+
|
|
68
|
+
# Constants for backward compatibility
|
|
69
|
+
JS_FUNCTION_PREFIX = "App.View"
|
|
70
|
+
HTML_ATTR_PREFIX = "data-"
|
|
71
|
+
SPA_YIELD_ATTR_PREFIX = "data-yield-attr"
|
|
72
|
+
SPA_YIELD_SUBSCRIBE_KEY_PREFIX = "data-yield-key"
|
|
73
|
+
SPA_YIELD_SUBSCRIBE_TARGET_PREFIX = "data-yield-target"
|
|
74
|
+
SPA_YIELD_SUBSCRIBE_ATTR_PREFIX = "data-yield-attr"
|
|
75
|
+
SPA_YIELD_CONTENT_PREFIX = "data-yield-content"
|
|
76
|
+
SPA_YIELD_CHILDREN_PREFIX = "data-yield-children"
|
|
77
|
+
SPA_STATECHANGE_PREFIX = "data-statechange-"
|
|
78
|
+
APP_VIEW_NAMESPACE = "App.View"
|
|
79
|
+
APP_HELPER_NAMESPACE = "App.Helper"
|
|
80
|
+
|
|
81
|
+
class ViewConfig:
|
|
82
|
+
VIEW_FUNCTIONS = [
|
|
83
|
+
'generateViewId', 'execute', 'evaluate', 'escString', 'text', 'templateToDom',
|
|
84
|
+
'view', 'loadView', 'renderView', 'include', 'includeIf', 'extendView',
|
|
85
|
+
'setSuperViewPath', 'addViewEngine', 'callViewEngineMounted',
|
|
86
|
+
'startWrapper', 'endWrapper', 'registerSubscribe',
|
|
87
|
+
'section', 'yield', 'yieldContent', 'renderSections', 'hasSection',
|
|
88
|
+
'getChangedSections', 'resetChangedSections', 'isChangedSection', 'emitChangedSections',
|
|
89
|
+
'push', 'stack', 'once', 'route', 'on', 'off', 'emit',
|
|
90
|
+
'init', 'setApp', 'setContainer', 'clearOldRendering',
|
|
91
|
+
'isAuth', 'can', 'cannot', 'hasError', 'firstError', 'csrfToken',
|
|
92
|
+
'foreach', 'foreachTemplate'
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
@classmethod
|
|
96
|
+
def is_view_function(cls, function_name):
|
|
97
|
+
return function_name in cls.VIEW_FUNCTIONS
|
|
98
|
+
|
|
99
|
+
@classmethod
|
|
100
|
+
def is_helper_function(cls, function_name):
|
|
101
|
+
return not cls.is_view_function(function_name)
|
|
102
|
+
|
|
103
|
+
@classmethod
|
|
104
|
+
def get_function_source(cls, function_name):
|
|
105
|
+
return 'View' if cls.is_view_function(function_name) else 'Helper'
|
|
106
|
+
|
|
107
|
+
config = CompilerConfig()
|