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
package/scripts/build.py
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Blade Template Builder
|
|
4
|
+
Usage: python3 build.py [context]
|
|
5
|
+
context: web, admin, or all (default: all)
|
|
6
|
+
Examples:
|
|
7
|
+
python3 build.py # Build all contexts
|
|
8
|
+
python3 build.py web # Build web context only
|
|
9
|
+
python3 build.py admin # Build admin context only
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
import sys
|
|
14
|
+
import json
|
|
15
|
+
import shutil
|
|
16
|
+
import argparse
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
# Import the compiler from the modular architecture
|
|
20
|
+
# Using the new modular compiler
|
|
21
|
+
try:
|
|
22
|
+
from compile import compile_blade_to_js
|
|
23
|
+
from compiler.config import CompilerConfig
|
|
24
|
+
config = CompilerConfig()
|
|
25
|
+
print("ā Using modular Blade compiler")
|
|
26
|
+
except ImportError as e:
|
|
27
|
+
print(f"Error: compiler module not found: {e}")
|
|
28
|
+
print("Please ensure the compiler directory exists.")
|
|
29
|
+
sys.exit(1)
|
|
30
|
+
|
|
31
|
+
def convert_path_to_view_name(file_path, views_root_path):
|
|
32
|
+
"""
|
|
33
|
+
Convert file path to view name format
|
|
34
|
+
Example: resources/views/web/abc.blade.php -> web.abc
|
|
35
|
+
"""
|
|
36
|
+
# Get relative path from resources/views
|
|
37
|
+
relative_path = os.path.relpath(file_path, views_root_path)
|
|
38
|
+
|
|
39
|
+
# Remove .blade.php extension
|
|
40
|
+
if relative_path.endswith('.blade.php'):
|
|
41
|
+
relative_path = relative_path[:-10] # Remove .blade.php
|
|
42
|
+
|
|
43
|
+
# Replace path separators with dots
|
|
44
|
+
view_name = relative_path.replace(os.path.sep, '.').replace('/', '.')
|
|
45
|
+
|
|
46
|
+
return view_name
|
|
47
|
+
|
|
48
|
+
def scan_directory(root_path):
|
|
49
|
+
"""
|
|
50
|
+
Recursively scan directory for .blade.php files
|
|
51
|
+
Returns list of blade file paths (excluding files starting with *)
|
|
52
|
+
"""
|
|
53
|
+
blade_files = []
|
|
54
|
+
|
|
55
|
+
for root, dirs, files in os.walk(root_path):
|
|
56
|
+
for file in files:
|
|
57
|
+
if file.endswith('.blade.php'):
|
|
58
|
+
# Skip files starting with asterisk (special files)
|
|
59
|
+
# Files starting with underscore (_) will be compiled
|
|
60
|
+
if file.startswith('*'):
|
|
61
|
+
print(f"Skipping special file: {file}")
|
|
62
|
+
continue
|
|
63
|
+
|
|
64
|
+
file_path = os.path.join(root, file)
|
|
65
|
+
blade_files.append(file_path)
|
|
66
|
+
|
|
67
|
+
return blade_files
|
|
68
|
+
|
|
69
|
+
def compile_blade_file(file_path, root_path):
|
|
70
|
+
"""
|
|
71
|
+
Compile a single blade file to JavaScript
|
|
72
|
+
"""
|
|
73
|
+
try:
|
|
74
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
75
|
+
blade_content = f.read()
|
|
76
|
+
|
|
77
|
+
view_name = convert_path_to_view_name(file_path, root_path)
|
|
78
|
+
result = compile_blade_to_js(blade_content, view_name)
|
|
79
|
+
return result
|
|
80
|
+
|
|
81
|
+
except Exception as e:
|
|
82
|
+
print(f"Error compiling {file_path}: {str(e)}")
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
def build_scope_file(scope, compiled_views, scopes_dir):
|
|
86
|
+
"""
|
|
87
|
+
Build a single scope file with new object structure
|
|
88
|
+
"""
|
|
89
|
+
# Create scopes directory if it doesn't exist
|
|
90
|
+
os.makedirs(scopes_dir, exist_ok=True)
|
|
91
|
+
|
|
92
|
+
# Build scope content
|
|
93
|
+
js_content = f"App.View.templates['{scope}'] = {{\n"
|
|
94
|
+
|
|
95
|
+
for view_name, view_function in compiled_views.items():
|
|
96
|
+
# view_function is now a complete function that returns an object
|
|
97
|
+
js_content += f" '{view_name}': {view_function},\n"
|
|
98
|
+
|
|
99
|
+
# Remove last comma and close the scope
|
|
100
|
+
if compiled_views:
|
|
101
|
+
js_content = js_content.rstrip(',\n') + '\n'
|
|
102
|
+
|
|
103
|
+
js_content += "};\n"
|
|
104
|
+
|
|
105
|
+
# Write to scope file (build location)
|
|
106
|
+
scope_file = config.get_build_scope_output_path(scope)
|
|
107
|
+
try:
|
|
108
|
+
with open(scope_file, 'w', encoding='utf-8') as f:
|
|
109
|
+
f.write(js_content)
|
|
110
|
+
print(f"Successfully built scope file: {scope_file}")
|
|
111
|
+
return True
|
|
112
|
+
except Exception as e:
|
|
113
|
+
print(f"Error writing to {scope_file}: {str(e)}")
|
|
114
|
+
return False
|
|
115
|
+
|
|
116
|
+
def build_individual_view_files(compiled_views, blade_files_data, context='all'):
|
|
117
|
+
"""
|
|
118
|
+
Build individual view files for each compiled view
|
|
119
|
+
"""
|
|
120
|
+
# Always use flat views directory (don't use context subdirectories)
|
|
121
|
+
views_dir = os.path.join(config.js_input_path, 'views')
|
|
122
|
+
|
|
123
|
+
# Clean views directory before building
|
|
124
|
+
if os.path.exists(views_dir):
|
|
125
|
+
shutil.rmtree(views_dir)
|
|
126
|
+
print(f"ā Cleaned views directory: {views_dir}")
|
|
127
|
+
|
|
128
|
+
os.makedirs(views_dir, exist_ok=True)
|
|
129
|
+
|
|
130
|
+
created_files = []
|
|
131
|
+
|
|
132
|
+
for view_name, view_function in compiled_views.items():
|
|
133
|
+
# Convert view name to function name (e.g., web.home -> WebHome)
|
|
134
|
+
function_name = convert_view_name_to_function_name(view_name)
|
|
135
|
+
|
|
136
|
+
# Create individual view file
|
|
137
|
+
view_file_path = os.path.join(views_dir, f'{function_name}.js')
|
|
138
|
+
|
|
139
|
+
# Build file content
|
|
140
|
+
file_content = ""
|
|
141
|
+
|
|
142
|
+
# Check if view_function starts with setup script (import statements)
|
|
143
|
+
if view_function.strip().startswith('import '):
|
|
144
|
+
# Split setup script and function
|
|
145
|
+
lines = view_function.split('\n')
|
|
146
|
+
setup_lines = []
|
|
147
|
+
function_lines = []
|
|
148
|
+
in_function = False
|
|
149
|
+
|
|
150
|
+
for line in lines:
|
|
151
|
+
if line.strip().startswith('export function ') and not in_function:
|
|
152
|
+
in_function = True
|
|
153
|
+
# Keep the export function line as is
|
|
154
|
+
function_lines.append(line)
|
|
155
|
+
elif in_function:
|
|
156
|
+
function_lines.append(line)
|
|
157
|
+
else:
|
|
158
|
+
# Only add non-empty lines to setup
|
|
159
|
+
if line.strip():
|
|
160
|
+
setup_lines.append(line)
|
|
161
|
+
|
|
162
|
+
# Add setup script first (without export)
|
|
163
|
+
if setup_lines:
|
|
164
|
+
file_content += '\n'.join(setup_lines) + '\n\n'
|
|
165
|
+
|
|
166
|
+
# Add function (already has export)
|
|
167
|
+
function_content = '\n'.join(function_lines)
|
|
168
|
+
file_content += function_content
|
|
169
|
+
else:
|
|
170
|
+
# Handle files without setup script - use as is (already has export)
|
|
171
|
+
file_content += view_function
|
|
172
|
+
|
|
173
|
+
# Write file
|
|
174
|
+
try:
|
|
175
|
+
with open(view_file_path, 'w', encoding='utf-8') as f:
|
|
176
|
+
f.write(file_content)
|
|
177
|
+
created_files.append((view_name, function_name, view_file_path))
|
|
178
|
+
print(f"Created view file: {function_name}.js")
|
|
179
|
+
except Exception as e:
|
|
180
|
+
print(f"Error writing {view_file_path}: {str(e)}")
|
|
181
|
+
return False
|
|
182
|
+
|
|
183
|
+
return created_files
|
|
184
|
+
|
|
185
|
+
def convert_view_name_to_function_name(view_name):
|
|
186
|
+
"""
|
|
187
|
+
Convert view name to function name
|
|
188
|
+
Example: web.home -> WebHome, admin.dashboard -> AdminDashboard, web.user-detail -> WebUserDetail, web.layouts-base_a1 -> WebLayoutsBaseA1
|
|
189
|
+
"""
|
|
190
|
+
# Split by dot and process each part
|
|
191
|
+
parts = view_name.split('.')
|
|
192
|
+
function_parts = []
|
|
193
|
+
|
|
194
|
+
for part in parts:
|
|
195
|
+
# Remove both - and _ and capitalize after each removal
|
|
196
|
+
# First split by - and _, then capitalize each segment
|
|
197
|
+
segments = []
|
|
198
|
+
for separator in ['-', '_']:
|
|
199
|
+
if separator in part:
|
|
200
|
+
part = part.replace(separator, ' ')
|
|
201
|
+
|
|
202
|
+
# Split by space and capitalize each word
|
|
203
|
+
words = part.split()
|
|
204
|
+
for word in words:
|
|
205
|
+
if word:
|
|
206
|
+
segments.append(word.capitalize())
|
|
207
|
+
|
|
208
|
+
if segments:
|
|
209
|
+
function_parts.append(''.join(segments))
|
|
210
|
+
|
|
211
|
+
return ''.join(function_parts)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def build_view_template_importer(created_files, output_path, context='all'):
|
|
216
|
+
"""
|
|
217
|
+
Build ViewTemplate.js that imports all individual view files
|
|
218
|
+
"""
|
|
219
|
+
# Get registry output path from build.config.json if context is specified
|
|
220
|
+
build_config = load_build_config()
|
|
221
|
+
|
|
222
|
+
if build_config and context != 'all' and context in build_config['contexts']:
|
|
223
|
+
# Use context-specific registry file
|
|
224
|
+
output_path = os.path.join(Path(__file__).parent.parent, build_config['contexts'][context]['output']['register'])
|
|
225
|
+
|
|
226
|
+
# Create output directory if it doesn't exist
|
|
227
|
+
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
|
228
|
+
|
|
229
|
+
# Build import statements
|
|
230
|
+
imports = []
|
|
231
|
+
template_assignments = []
|
|
232
|
+
|
|
233
|
+
for view_name, function_name, file_path in created_files:
|
|
234
|
+
# Extract actual function name from the compiled file
|
|
235
|
+
actual_function_name = function_name # Default to converted name
|
|
236
|
+
try:
|
|
237
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
238
|
+
first_line = f.readline()
|
|
239
|
+
# Extract function name from: export function _systemPageEnd(...
|
|
240
|
+
if 'export function ' in first_line:
|
|
241
|
+
start = first_line.index('export function ') + len('export function ')
|
|
242
|
+
end = first_line.index('(', start)
|
|
243
|
+
actual_function_name = first_line[start:end].strip()
|
|
244
|
+
except Exception as e:
|
|
245
|
+
print(f"Warning: Could not extract function name from {file_path}: {e}")
|
|
246
|
+
|
|
247
|
+
# Calculate relative path from output to view file
|
|
248
|
+
relative_path = os.path.relpath(file_path, os.path.dirname(output_path))
|
|
249
|
+
relative_path = relative_path.replace('\\', '/') # Normalize path separators
|
|
250
|
+
|
|
251
|
+
imports.append(f"import {{ {actual_function_name} }} from './{relative_path}';")
|
|
252
|
+
template_assignments.append(f" '{view_name}': {actual_function_name},")
|
|
253
|
+
|
|
254
|
+
# Build file content
|
|
255
|
+
file_content = "// Auto-generated ViewTemplate.js\n"
|
|
256
|
+
file_content += "// This file imports all view functions and assigns them to templates\n\n"
|
|
257
|
+
|
|
258
|
+
# Add imports
|
|
259
|
+
file_content += "\n".join(imports) + "\n\n"
|
|
260
|
+
|
|
261
|
+
# Add template assignment
|
|
262
|
+
file_content += "export const ViewTemplates = {\n"
|
|
263
|
+
file_content += "\n".join(template_assignments)
|
|
264
|
+
file_content += "\n};\n"
|
|
265
|
+
|
|
266
|
+
# Write file
|
|
267
|
+
try:
|
|
268
|
+
with open(output_path, 'w', encoding='utf-8') as f:
|
|
269
|
+
f.write(file_content)
|
|
270
|
+
print(f"Successfully built ViewTemplate.js: {output_path}")
|
|
271
|
+
return True
|
|
272
|
+
except Exception as e:
|
|
273
|
+
print(f"Error writing to {output_path}: {str(e)}")
|
|
274
|
+
return False
|
|
275
|
+
|
|
276
|
+
def copy_essential_files_to_build():
|
|
277
|
+
"""
|
|
278
|
+
Copy view.templates.js to resources/js/app/views/templates.js
|
|
279
|
+
"""
|
|
280
|
+
print("\n=== Copying view.templates.js to app/views ===")
|
|
281
|
+
|
|
282
|
+
# Create views directory if it doesn't exist
|
|
283
|
+
views_dir = os.path.join(config.js_input_path, 'views')
|
|
284
|
+
|
|
285
|
+
# Clean views directory before copying templates
|
|
286
|
+
if os.path.exists(views_dir):
|
|
287
|
+
shutil.rmtree(views_dir)
|
|
288
|
+
print(f"ā Cleaned views directory before copying templates: {views_dir}")
|
|
289
|
+
|
|
290
|
+
os.makedirs(views_dir, exist_ok=True)
|
|
291
|
+
|
|
292
|
+
# Copy view.templates.js to resources/js/app/views/templates.js
|
|
293
|
+
build_templates = config.get_build_view_templates_output_path()
|
|
294
|
+
app_templates = os.path.join(views_dir, 'templates.js')
|
|
295
|
+
|
|
296
|
+
if os.path.exists(build_templates):
|
|
297
|
+
shutil.copy2(build_templates, app_templates)
|
|
298
|
+
print(f"ā Copied view.templates.js: {build_templates} -> {app_templates}")
|
|
299
|
+
else:
|
|
300
|
+
print(f"ā Build view.templates.js not found: {build_templates}")
|
|
301
|
+
return False
|
|
302
|
+
|
|
303
|
+
print("=== Copy completed ===")
|
|
304
|
+
return True
|
|
305
|
+
|
|
306
|
+
def copy_build_to_public():
|
|
307
|
+
"""
|
|
308
|
+
Copy only main.js from resources/build to public/static/app
|
|
309
|
+
Keep original files in resources/build intact
|
|
310
|
+
"""
|
|
311
|
+
print("\n=== Copying main.js to public ===")
|
|
312
|
+
|
|
313
|
+
# Copy only main.js
|
|
314
|
+
build_main = config.get_build_main_output_path()
|
|
315
|
+
public_main = config.get_main_output_path()
|
|
316
|
+
|
|
317
|
+
if os.path.exists(build_main):
|
|
318
|
+
os.makedirs(os.path.dirname(public_main), exist_ok=True)
|
|
319
|
+
shutil.copy2(build_main, public_main)
|
|
320
|
+
print(f"ā Copied main.js: {build_main} -> {public_main}")
|
|
321
|
+
else:
|
|
322
|
+
print(f"ā Build main.js not found: {build_main}")
|
|
323
|
+
return False
|
|
324
|
+
|
|
325
|
+
print("=== Copy completed ===")
|
|
326
|
+
return True
|
|
327
|
+
|
|
328
|
+
def build_main_spa_file():
|
|
329
|
+
"""
|
|
330
|
+
Build the main spa file by combining all modules according to auto-generated build.config.json
|
|
331
|
+
"""
|
|
332
|
+
config_path = os.path.join(config.js_input_path, 'build.config.json')
|
|
333
|
+
|
|
334
|
+
try:
|
|
335
|
+
with open(config_path, 'r', encoding='utf-8') as f:
|
|
336
|
+
build_config = json.load(f)
|
|
337
|
+
|
|
338
|
+
# Check if config was auto-generated
|
|
339
|
+
if build_config.get('auto_discovery'):
|
|
340
|
+
print(f"š¦ Using auto-discovered modules ({len(build_config['modules'])} modules)")
|
|
341
|
+
else:
|
|
342
|
+
print(f"š¦ Using manual module configuration ({len(build_config['modules'])} modules)")
|
|
343
|
+
|
|
344
|
+
except Exception as e:
|
|
345
|
+
print(f"Error reading build config {config_path}: {str(e)}")
|
|
346
|
+
print("š” Run 'npm run discover' to auto-generate module configuration")
|
|
347
|
+
return False
|
|
348
|
+
|
|
349
|
+
output_file = build_config.get('output', 'main.js')
|
|
350
|
+
modules = build_config.get('modules', [])
|
|
351
|
+
|
|
352
|
+
if not modules:
|
|
353
|
+
print("No modules specified in build config")
|
|
354
|
+
return False
|
|
355
|
+
|
|
356
|
+
# Build the combined content
|
|
357
|
+
combined_content = ""
|
|
358
|
+
app_dir = config.js_input_path
|
|
359
|
+
|
|
360
|
+
for module in modules:
|
|
361
|
+
module_path = os.path.join(app_dir, module)
|
|
362
|
+
if os.path.exists(module_path):
|
|
363
|
+
try:
|
|
364
|
+
with open(module_path, 'r', encoding='utf-8') as f:
|
|
365
|
+
module_content = f.read()
|
|
366
|
+
combined_content += f"/* === {module} === */\n"
|
|
367
|
+
combined_content += module_content + "\n\n"
|
|
368
|
+
print(f"Added module: {module}")
|
|
369
|
+
except Exception as e:
|
|
370
|
+
print(f"Error reading module {module}: {str(e)}")
|
|
371
|
+
return False
|
|
372
|
+
else:
|
|
373
|
+
print(f"Warning: Module file not found: {module_path}")
|
|
374
|
+
|
|
375
|
+
# Write the combined file
|
|
376
|
+
output_path = config.get_build_main_output_path()
|
|
377
|
+
try:
|
|
378
|
+
with open(output_path, 'w', encoding='utf-8') as f:
|
|
379
|
+
f.write(combined_content)
|
|
380
|
+
print(f"Successfully built main spa file: {output_path}")
|
|
381
|
+
return True
|
|
382
|
+
except Exception as e:
|
|
383
|
+
print(f"Error writing to {output_path}: {str(e)}")
|
|
384
|
+
return False
|
|
385
|
+
|
|
386
|
+
def load_build_config():
|
|
387
|
+
"""Load build.config.json"""
|
|
388
|
+
config_path = Path(__file__).parent.parent / 'build.config.json'
|
|
389
|
+
if not config_path.exists():
|
|
390
|
+
return None
|
|
391
|
+
|
|
392
|
+
with open(config_path, 'r', encoding='utf-8') as f:
|
|
393
|
+
return json.load(f)
|
|
394
|
+
|
|
395
|
+
def get_contexts_to_build(requested_context='all'):
|
|
396
|
+
"""Get list of contexts to build based on request"""
|
|
397
|
+
build_config = load_build_config()
|
|
398
|
+
|
|
399
|
+
if not build_config or 'contexts' not in build_config:
|
|
400
|
+
return None
|
|
401
|
+
|
|
402
|
+
if requested_context == 'all':
|
|
403
|
+
return build_config['contexts'].keys()
|
|
404
|
+
elif requested_context in build_config['contexts']:
|
|
405
|
+
return [requested_context]
|
|
406
|
+
else:
|
|
407
|
+
print(f"Error: Unknown context '{requested_context}'")
|
|
408
|
+
print(f"Available contexts: {', '.join(build_config['contexts'].keys())}")
|
|
409
|
+
sys.exit(1)
|
|
410
|
+
|
|
411
|
+
def get_source_directories(context_name=None):
|
|
412
|
+
"""Get source directories for a specific context or all"""
|
|
413
|
+
# Try to load from build.config.json first
|
|
414
|
+
build_config = load_build_config()
|
|
415
|
+
|
|
416
|
+
if build_config and context_name and context_name in build_config['contexts']:
|
|
417
|
+
# Return sources for specific context
|
|
418
|
+
sources = build_config['contexts'][context_name]['sources']
|
|
419
|
+
# Convert relative paths to absolute
|
|
420
|
+
base_path = Path(__file__).parent.parent
|
|
421
|
+
return [str(base_path / src) for src in sources]
|
|
422
|
+
elif build_config and context_name == 'all':
|
|
423
|
+
# Return all sources from all contexts
|
|
424
|
+
base_path = Path(__file__).parent.parent
|
|
425
|
+
all_sources = set()
|
|
426
|
+
for ctx in build_config['contexts'].values():
|
|
427
|
+
for src in ctx['sources']:
|
|
428
|
+
all_sources.add(str(base_path / src))
|
|
429
|
+
return list(all_sources)
|
|
430
|
+
else:
|
|
431
|
+
# Fallback to config.get_build_directories()
|
|
432
|
+
return config.get_build_directories()
|
|
433
|
+
|
|
434
|
+
def main():
|
|
435
|
+
"""
|
|
436
|
+
Main build function
|
|
437
|
+
"""
|
|
438
|
+
# Parse arguments
|
|
439
|
+
parser = argparse.ArgumentParser(description='Build blade templates for specific context')
|
|
440
|
+
parser.add_argument('context', nargs='?', default='all',
|
|
441
|
+
help='Context to build: web, admin, or all (default: all)')
|
|
442
|
+
args = parser.parse_args()
|
|
443
|
+
|
|
444
|
+
print("Starting build script...")
|
|
445
|
+
print(f"Context: {args.context}")
|
|
446
|
+
|
|
447
|
+
# Get build directories based on context
|
|
448
|
+
build_directories = get_source_directories(args.context)
|
|
449
|
+
|
|
450
|
+
if not build_directories:
|
|
451
|
+
print("Error: No build directories configured")
|
|
452
|
+
print("Please add 'build_directories' to compiler.config.json or contexts to build.config.json")
|
|
453
|
+
sys.exit(1)
|
|
454
|
+
|
|
455
|
+
print(f"Build directories: {len(build_directories)} directories")
|
|
456
|
+
for i, dir_path in enumerate(build_directories, 1):
|
|
457
|
+
print(f" {i}. {dir_path}")
|
|
458
|
+
|
|
459
|
+
# Compile all directories
|
|
460
|
+
all_compiled_views = {}
|
|
461
|
+
all_blade_files_data = {}
|
|
462
|
+
total_success = 0
|
|
463
|
+
total_files = 0
|
|
464
|
+
|
|
465
|
+
for dir_path in build_directories:
|
|
466
|
+
print(f"\n=== Building directory: {dir_path} ===")
|
|
467
|
+
|
|
468
|
+
# Validate directory
|
|
469
|
+
if not os.path.exists(dir_path):
|
|
470
|
+
print(f"Warning: Directory '{dir_path}' does not exist, skipping...")
|
|
471
|
+
continue
|
|
472
|
+
|
|
473
|
+
if not os.path.isdir(dir_path):
|
|
474
|
+
print(f"Warning: '{dir_path}' is not a directory, skipping...")
|
|
475
|
+
continue
|
|
476
|
+
|
|
477
|
+
# Scan for blade files in this directory
|
|
478
|
+
blade_files = scan_directory(dir_path)
|
|
479
|
+
|
|
480
|
+
if not blade_files:
|
|
481
|
+
print(f"No .blade.php files found in {dir_path}")
|
|
482
|
+
continue
|
|
483
|
+
|
|
484
|
+
print(f"Found {len(blade_files)} blade files")
|
|
485
|
+
total_files += len(blade_files)
|
|
486
|
+
|
|
487
|
+
# Compile all blade files in this directory
|
|
488
|
+
compiled_views = {}
|
|
489
|
+
success_count = 0
|
|
490
|
+
|
|
491
|
+
for file_path in blade_files:
|
|
492
|
+
print(f"Compiling: {file_path}")
|
|
493
|
+
|
|
494
|
+
try:
|
|
495
|
+
# Convert file path to view name (relative to resources/views)
|
|
496
|
+
view_name = convert_path_to_view_name(file_path, config.views_input_path)
|
|
497
|
+
|
|
498
|
+
# Read blade code for script extraction
|
|
499
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
500
|
+
blade_code = f.read()
|
|
501
|
+
|
|
502
|
+
# Compile the blade file
|
|
503
|
+
view_data = compile_blade_file(file_path, config.views_input_path)
|
|
504
|
+
|
|
505
|
+
if view_data:
|
|
506
|
+
compiled_views[view_name] = view_data
|
|
507
|
+
all_compiled_views[view_name] = view_data
|
|
508
|
+
all_blade_files_data[view_name] = blade_code
|
|
509
|
+
success_count += 1
|
|
510
|
+
total_success += 1
|
|
511
|
+
print(f" -> {view_name} [SUCCESS]")
|
|
512
|
+
else:
|
|
513
|
+
print(f" -> Failed to compile [ERROR]")
|
|
514
|
+
except Exception as e:
|
|
515
|
+
print(f" -> Exception: {str(e)} [ERROR]")
|
|
516
|
+
|
|
517
|
+
print(f"Directory completed: {success_count}/{len(blade_files)} files successfully")
|
|
518
|
+
|
|
519
|
+
print(f"\n=== Overall Results ===")
|
|
520
|
+
print(f"Total compiled: {total_success}/{total_files} files successfully")
|
|
521
|
+
|
|
522
|
+
if all_compiled_views:
|
|
523
|
+
# Build individual view files
|
|
524
|
+
print(f"\n=== Building individual view files ===")
|
|
525
|
+
created_files = build_individual_view_files(all_compiled_views, all_blade_files_data, args.context)
|
|
526
|
+
|
|
527
|
+
if created_files:
|
|
528
|
+
# Build context-specific registry (templates.web.js, templates.admin.js)
|
|
529
|
+
view_template_path = os.path.join(config.js_input_path, 'core', 'ViewTemplate.js')
|
|
530
|
+
if build_view_template_importer(created_files, view_template_path, args.context):
|
|
531
|
+
# Get the actual registry path that was created
|
|
532
|
+
build_config = load_build_config()
|
|
533
|
+
if build_config and args.context != 'all' and args.context in build_config['contexts']:
|
|
534
|
+
registry_path = build_config['contexts'][args.context]['output']['register']
|
|
535
|
+
registry_filename = os.path.basename(registry_path)
|
|
536
|
+
|
|
537
|
+
# Create a proxy ViewTemplate.js in core/ that re-exports from context registry
|
|
538
|
+
core_template_path = os.path.join(config.js_input_path, 'core', 'ViewTemplate.js')
|
|
539
|
+
relative_to_registry = os.path.relpath(
|
|
540
|
+
os.path.join(Path(__file__).parent.parent, registry_path),
|
|
541
|
+
os.path.dirname(core_template_path)
|
|
542
|
+
).replace('\\', '/')
|
|
543
|
+
|
|
544
|
+
proxy_content = f"""// Auto-generated proxy to context-specific registry
|
|
545
|
+
// This file re-exports from {registry_filename}
|
|
546
|
+
|
|
547
|
+
export {{ ViewTemplates }} from '{relative_to_registry}';
|
|
548
|
+
"""
|
|
549
|
+
|
|
550
|
+
with open(core_template_path, 'w', encoding='utf-8') as f:
|
|
551
|
+
f.write(proxy_content)
|
|
552
|
+
|
|
553
|
+
print(f"Created proxy ViewTemplate.js: {core_template_path}")
|
|
554
|
+
print(f" -> Points to: {registry_filename}")
|
|
555
|
+
|
|
556
|
+
print(f"\nā
Python build completed successfully!")
|
|
557
|
+
print(f"š¦ Total views: {len(all_compiled_views)}")
|
|
558
|
+
print(f"š Views: {list(all_compiled_views.keys())}")
|
|
559
|
+
print(f"š Registry: {view_template_path}")
|
|
560
|
+
print(f"š Individual view files: {os.path.join(config.js_input_path, 'views')}")
|
|
561
|
+
print(f"\nš” Next step: Run 'npm run compile' to build main.js")
|
|
562
|
+
else:
|
|
563
|
+
print(f"Failed to build ViewTemplate.js!")
|
|
564
|
+
sys.exit(1)
|
|
565
|
+
else:
|
|
566
|
+
print(f"Failed to build individual view files!")
|
|
567
|
+
sys.exit(1)
|
|
568
|
+
else:
|
|
569
|
+
print("No files were successfully compiled!")
|
|
570
|
+
sys.exit(1)
|
|
571
|
+
|
|
572
|
+
if __name__ == "__main__":
|
|
573
|
+
main()
|