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.
Files changed (121) hide show
  1. package/README.md +1 -1
  2. package/bin/onejs-build.js +32 -0
  3. package/index.js +3 -1
  4. package/package.json +11 -3
  5. package/scripts/README-template-compiler.md +133 -0
  6. package/scripts/README.md +61 -0
  7. package/scripts/__pycache__/build.cpython-314.pyc +0 -0
  8. package/scripts/__pycache__/compile.cpython-313.pyc +0 -0
  9. package/scripts/__pycache__/compile.cpython-314.pyc +0 -0
  10. package/scripts/build.py +574 -0
  11. package/scripts/check-system-errors.php +214 -0
  12. package/scripts/compile.py +101 -0
  13. package/scripts/compiler/README_CONFIG.md +196 -0
  14. package/scripts/compiler/__init__.py +18 -0
  15. package/scripts/compiler/__pycache__/__init__.cpython-313.pyc +0 -0
  16. package/scripts/compiler/__pycache__/__init__.cpython-314.pyc +0 -0
  17. package/scripts/compiler/__pycache__/binding_directive_service.cpython-314.pyc +0 -0
  18. package/scripts/compiler/__pycache__/class_binding_handler.cpython-314.pyc +0 -0
  19. package/scripts/compiler/__pycache__/compiler_utils.cpython-313.pyc +0 -0
  20. package/scripts/compiler/__pycache__/compiler_utils.cpython-314.pyc +0 -0
  21. package/scripts/compiler/__pycache__/conditional_handlers.cpython-313.pyc +0 -0
  22. package/scripts/compiler/__pycache__/conditional_handlers.cpython-314.pyc +0 -0
  23. package/scripts/compiler/__pycache__/config.cpython-313.pyc +0 -0
  24. package/scripts/compiler/__pycache__/config.cpython-314.pyc +0 -0
  25. package/scripts/compiler/__pycache__/declaration_tracker.cpython-314.pyc +0 -0
  26. package/scripts/compiler/__pycache__/directive_processors.cpython-313.pyc +0 -0
  27. package/scripts/compiler/__pycache__/directive_processors.cpython-314.pyc +0 -0
  28. package/scripts/compiler/__pycache__/echo_processor.cpython-314.pyc +0 -0
  29. package/scripts/compiler/__pycache__/event_directive_processor.cpython-313.pyc +0 -0
  30. package/scripts/compiler/__pycache__/event_directive_processor.cpython-314.pyc +0 -0
  31. package/scripts/compiler/__pycache__/function_generators.cpython-313.pyc +0 -0
  32. package/scripts/compiler/__pycache__/function_generators.cpython-314.pyc +0 -0
  33. package/scripts/compiler/__pycache__/loop_handlers.cpython-313.pyc +0 -0
  34. package/scripts/compiler/__pycache__/loop_handlers.cpython-314.pyc +0 -0
  35. package/scripts/compiler/__pycache__/main_compiler.cpython-313.pyc +0 -0
  36. package/scripts/compiler/__pycache__/main_compiler.cpython-314.pyc +0 -0
  37. package/scripts/compiler/__pycache__/parsers.cpython-313.pyc +0 -0
  38. package/scripts/compiler/__pycache__/parsers.cpython-314.pyc +0 -0
  39. package/scripts/compiler/__pycache__/php_converter.cpython-313.pyc +0 -0
  40. package/scripts/compiler/__pycache__/php_converter.cpython-314.pyc +0 -0
  41. package/scripts/compiler/__pycache__/php_js_converter.cpython-313.pyc +0 -0
  42. package/scripts/compiler/__pycache__/php_js_converter.cpython-314.pyc +0 -0
  43. package/scripts/compiler/__pycache__/register_parser.cpython-313.pyc +0 -0
  44. package/scripts/compiler/__pycache__/register_parser.cpython-314.pyc +0 -0
  45. package/scripts/compiler/__pycache__/section_handlers.cpython-313.pyc +0 -0
  46. package/scripts/compiler/__pycache__/section_handlers.cpython-314.pyc +0 -0
  47. package/scripts/compiler/__pycache__/show_directive_handler.cpython-314.pyc +0 -0
  48. package/scripts/compiler/__pycache__/style_directive_handler.cpython-314.pyc +0 -0
  49. package/scripts/compiler/__pycache__/template_analyzer.cpython-313.pyc +0 -0
  50. package/scripts/compiler/__pycache__/template_analyzer.cpython-314.pyc +0 -0
  51. package/scripts/compiler/__pycache__/template_processor.cpython-313.pyc +0 -0
  52. package/scripts/compiler/__pycache__/template_processor.cpython-314.pyc +0 -0
  53. package/scripts/compiler/__pycache__/template_processors.cpython-313.pyc +0 -0
  54. package/scripts/compiler/__pycache__/template_processors.cpython-314.pyc +0 -0
  55. package/scripts/compiler/__pycache__/utils.cpython-313.pyc +0 -0
  56. package/scripts/compiler/__pycache__/utils.cpython-314.pyc +0 -0
  57. package/scripts/compiler/__pycache__/wrapper_parser.cpython-313.pyc +0 -0
  58. package/scripts/compiler/__pycache__/wrapper_parser.cpython-314.pyc +0 -0
  59. package/scripts/compiler/binding_directive_service.py +103 -0
  60. package/scripts/compiler/class_binding_handler.py +347 -0
  61. package/scripts/compiler/cli.py +34 -0
  62. package/scripts/compiler/code_generator.py +141 -0
  63. package/scripts/compiler/compiler.config.json +36 -0
  64. package/scripts/compiler/compiler_utils.py +55 -0
  65. package/scripts/compiler/conditional_handlers.py +252 -0
  66. package/scripts/compiler/config.py +107 -0
  67. package/scripts/compiler/declaration_tracker.py +420 -0
  68. package/scripts/compiler/directive_processors.py +603 -0
  69. package/scripts/compiler/echo_processor.py +667 -0
  70. package/scripts/compiler/event_directive_processor.py +1099 -0
  71. package/scripts/compiler/fetch_parser.py +49 -0
  72. package/scripts/compiler/function_generators.py +310 -0
  73. package/scripts/compiler/loop_handlers.py +224 -0
  74. package/scripts/compiler/main_compiler.py +1763 -0
  75. package/scripts/compiler/parsers.py +1418 -0
  76. package/scripts/compiler/php_converter.py +470 -0
  77. package/scripts/compiler/php_js_converter.py +603 -0
  78. package/scripts/compiler/register_parser.py +480 -0
  79. package/scripts/compiler/section_handlers.py +122 -0
  80. package/scripts/compiler/show_directive_handler.py +85 -0
  81. package/scripts/compiler/style_directive_handler.py +169 -0
  82. package/scripts/compiler/template_analyzer.py +162 -0
  83. package/scripts/compiler/template_processor.py +1167 -0
  84. package/scripts/compiler/template_processors.py +1557 -0
  85. package/scripts/compiler/test_compiler.py +69 -0
  86. package/scripts/compiler/utils.py +54 -0
  87. package/scripts/compiler/variables_analyzer.py +135 -0
  88. package/scripts/compiler/view_identifier_generator.py +278 -0
  89. package/scripts/compiler/wrapper_parser.py +78 -0
  90. package/scripts/dev-context.js +311 -0
  91. package/scripts/dev.js +109 -0
  92. package/scripts/generate-assets-order.js +208 -0
  93. package/scripts/migrate-namespace.php +146 -0
  94. package/scripts/node/MIGRATION.md +190 -0
  95. package/scripts/node/README.md +269 -0
  96. package/scripts/node/build.js +208 -0
  97. package/scripts/node/compiler/compiler-utils.js +38 -0
  98. package/scripts/node/compiler/conditional-handlers.js +45 -0
  99. package/scripts/node/compiler/config.js +178 -0
  100. package/scripts/node/compiler/directive-processors.js +51 -0
  101. package/scripts/node/compiler/event-directive-processor.js +182 -0
  102. package/scripts/node/compiler/function-generators.js +239 -0
  103. package/scripts/node/compiler/loop-handlers.js +45 -0
  104. package/scripts/node/compiler/main-compiler.js +236 -0
  105. package/scripts/node/compiler/parsers.js +358 -0
  106. package/scripts/node/compiler/php-converter.js +227 -0
  107. package/scripts/node/compiler/register-parser.js +32 -0
  108. package/scripts/node/compiler/section-handlers.js +46 -0
  109. package/scripts/node/compiler/template-analyzer.js +50 -0
  110. package/scripts/node/compiler/template-processor.js +371 -0
  111. package/scripts/node/compiler/template-processors.js +219 -0
  112. package/scripts/node/compiler/utils.js +203 -0
  113. package/scripts/node/compiler/wrapper-parser.js +25 -0
  114. package/scripts/node/package.json +24 -0
  115. package/scripts/node/test-compiler.js +52 -0
  116. package/scripts/node-run.cjs +28 -0
  117. package/scripts/standardize-directories.php +92 -0
  118. package/src/core/ViewManager.js +4 -4
  119. package/templates/view.module.js +2 -0
  120. package/templates/view.tpl-raw.js +13 -0
  121. package/templates/wraper.js +71 -0
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Node.js Build Script - Main entry point
3
+ */
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const glob = require('glob');
8
+ const { CompilerConfig } = require('./compiler/config');
9
+ const BladeCompiler = require('./compiler/main-compiler');
10
+
11
+ class NodeBuildScript {
12
+ constructor() {
13
+ this.config = new CompilerConfig();
14
+ this.compiler = new BladeCompiler();
15
+ this.verbose = false;
16
+ }
17
+
18
+ async run() {
19
+ /** Main build function */
20
+ console.log('✓ Using Node.js Blade compiler');
21
+ console.log('Starting build script...');
22
+
23
+ if (this.verbose) {
24
+ this.config.printConfig();
25
+ }
26
+
27
+ const buildDirectories = this.config.get('build_directories');
28
+ console.log(`Build directories: ${buildDirectories.length} directories`);
29
+
30
+ for (let i = 0; i < buildDirectories.length; i++) {
31
+ const dir = buildDirectories[i];
32
+ const dirPath = path.join(this.config.get('paths.views_input'), dir);
33
+ console.log(` ${i + 1}. ${dirPath}`);
34
+ }
35
+
36
+ let totalCompiled = 0;
37
+ let totalViews = [];
38
+
39
+ // Build each directory
40
+ for (const dir of buildDirectories) {
41
+ const result = await this.buildDirectory(dir);
42
+ totalCompiled += result.compiled;
43
+ totalViews.push(...result.views);
44
+ }
45
+
46
+ console.log('\n=== Overall Results ===');
47
+ console.log(`Total compiled: ${totalCompiled}/${totalCompiled} files successfully`);
48
+
49
+ // Build individual view files
50
+ await this.buildIndividualViews(totalViews);
51
+
52
+ console.log('\n✅ Node.js build completed successfully!');
53
+ console.log(`📦 Total views: ${totalViews.length}`);
54
+ console.log(`📄 Views: [${totalViews.map(v => `'${v}'`).join(', ')}]`);
55
+ console.log(`📁 ViewTemplate.js: ${path.join(this.config.get('paths.js_input'), 'core', 'ViewTemplate.js')}`);
56
+ console.log(`📁 Individual view files: ${path.join(this.config.get('paths.js_input'), 'views')}`);
57
+ console.log('\n💡 Next step: Run \'npm run compile\' to build main.js');
58
+ }
59
+
60
+ async buildDirectory(dirName) {
61
+ /** Build a single directory */
62
+ const dirPath = path.join(this.config.get('paths.views_input'), dirName);
63
+
64
+ if (!fs.existsSync(dirPath)) {
65
+ console.log(`\n=== Building directory: ${dirPath} ===`);
66
+ console.log(`Directory not found: ${dirPath}`);
67
+ return { compiled: 0, views: [] };
68
+ }
69
+
70
+ console.log(`\n=== Building directory: ${dirPath} ===`);
71
+
72
+ // Find all blade files
73
+ const pattern = path.join(dirPath, '**/*.blade.php');
74
+ const files = glob.sync(pattern);
75
+
76
+ console.log(`Found ${files.length} blade files`);
77
+
78
+ let compiled = 0;
79
+ const views = [];
80
+
81
+ for (const file of files) {
82
+ const relativePath = path.relative(this.config.get('paths.views_input'), file);
83
+ const viewName = relativePath.replace(/\.blade\.php$/, '').replace(/\//g, '.');
84
+
85
+ try {
86
+ const bladeCode = fs.readFileSync(file, 'utf8');
87
+ const jsCode = this.compiler.compileBladeToJs(bladeCode, viewName);
88
+
89
+ // Generate function name
90
+ const functionName = this.compiler.convertViewPathToFunctionName(viewName);
91
+
92
+ console.log(`Compiling: ${file}`);
93
+ console.log(` -> ${viewName} [SUCCESS]`);
94
+
95
+ // Store for later processing
96
+ views.push({
97
+ name: viewName,
98
+ functionName: functionName,
99
+ code: jsCode
100
+ });
101
+
102
+ compiled++;
103
+ } catch (error) {
104
+ console.log(`Compiling: ${file}`);
105
+ console.log(` -> ${viewName} [ERROR: ${error.message}]`);
106
+ }
107
+ }
108
+
109
+ console.log(`Directory completed: ${compiled}/${files.length} files successfully`);
110
+ return { compiled, views };
111
+ }
112
+
113
+ async buildIndividualViews(views) {
114
+ /** Build individual view files */
115
+ const viewsDir = path.join(this.config.get('paths.js_input'), 'views');
116
+
117
+ // Clean views directory
118
+ if (fs.existsSync(viewsDir)) {
119
+ const files = fs.readdirSync(viewsDir);
120
+ for (const file of files) {
121
+ if (file.endsWith('.js')) {
122
+ fs.unlinkSync(path.join(viewsDir, file));
123
+ }
124
+ }
125
+ } else {
126
+ fs.mkdirSync(viewsDir, { recursive: true });
127
+ }
128
+
129
+ console.log(`✓ Cleaned views directory: ${viewsDir}`);
130
+
131
+ // Write individual view files
132
+ for (const view of views) {
133
+ const fileName = `${view.functionName}.js`;
134
+ const filePath = path.join(viewsDir, fileName);
135
+
136
+ fs.writeFileSync(filePath, view.code);
137
+ console.log(`Created view file: ${fileName}`);
138
+ }
139
+
140
+ // Build ViewTemplate.js
141
+ await this.buildViewTemplate(views);
142
+
143
+ console.log(`Successfully built ViewTemplate.js: ${path.join(this.config.get('paths.js_input'), 'core', 'ViewTemplate.js')}`);
144
+ console.log(`ViewTemplate.js built successfully: ${path.join(this.config.get('paths.js_input'), 'core', 'ViewTemplate.js')}`);
145
+ }
146
+
147
+ async buildViewTemplate(views) {
148
+ /** Build ViewTemplate.js file */
149
+ const viewTemplateContent = this.generateViewTemplateContent(views);
150
+ const viewTemplatePath = path.join(this.config.get('paths.js_input'), 'core', 'ViewTemplate.js');
151
+
152
+ // Ensure core directory exists
153
+ const coreDir = path.dirname(viewTemplatePath);
154
+ if (!fs.existsSync(coreDir)) {
155
+ fs.mkdirSync(coreDir, { recursive: true });
156
+ }
157
+
158
+ fs.writeFileSync(viewTemplatePath, viewTemplateContent);
159
+ }
160
+
161
+ generateViewTemplateContent(views) {
162
+ /** Generate ViewTemplate.js content */
163
+ const imports = views.map(view =>
164
+ `import { ${view.functionName} } from '../views/${view.functionName}.js';`
165
+ ).join('\n');
166
+
167
+ const viewObjects = views.map(view =>
168
+ ` '${view.name}': ${view.functionName}`
169
+ ).join(',\n');
170
+
171
+ return `// Auto-generated ViewTemplate.js
172
+ // Generated by Node.js Blade Compiler
173
+
174
+ ${imports}
175
+
176
+ const ViewTemplate = {
177
+ ${viewObjects}
178
+ };
179
+
180
+ export default ViewTemplate;
181
+ `;
182
+ }
183
+
184
+ setVerbose(verbose) {
185
+ /** Set verbose mode */
186
+ this.verbose = verbose;
187
+ }
188
+ }
189
+
190
+ // CLI interface
191
+ if (require.main === module) {
192
+ const buildScript = new NodeBuildScript();
193
+
194
+ // Parse command line arguments
195
+ const args = process.argv.slice(2);
196
+ if (args.includes('--verbose') || args.includes('-v')) {
197
+ buildScript.setVerbose(true);
198
+ }
199
+
200
+ // Run build
201
+ buildScript.run().catch(error => {
202
+ console.error('Build failed:', error);
203
+ process.exit(1);
204
+ });
205
+ }
206
+
207
+ module.exports = NodeBuildScript;
208
+
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Compiler utilities
3
+ */
4
+
5
+ class CompilerUtils {
6
+ constructor() {
7
+ // No initialization needed
8
+ }
9
+
10
+ generateSectionsInfo(sections, analysis) {
11
+ /** Generate sections info */
12
+ const sectionsInfo = [];
13
+
14
+ for (const section of sections) {
15
+ sectionsInfo.push({
16
+ name: section.name,
17
+ type: section.type || 'long',
18
+ preloader: section.preloader || false,
19
+ useVars: section.useVars || false,
20
+ script: section.script || {}
21
+ });
22
+ }
23
+
24
+ return sectionsInfo;
25
+ }
26
+
27
+ formatFetchConfig(fetchConfig) {
28
+ /** Format fetch config */
29
+ if (typeof fetchConfig === 'string') {
30
+ return fetchConfig;
31
+ }
32
+
33
+ return JSON.stringify(fetchConfig);
34
+ }
35
+ }
36
+
37
+ module.exports = CompilerUtils;
38
+
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Conditional handlers for @if, @unless, etc.
3
+ */
4
+
5
+ class ConditionalHandlers {
6
+ constructor() {
7
+ // No initialization needed
8
+ }
9
+
10
+ processConditionalDirective(line, stack, output) {
11
+ /** Process conditional directives */
12
+ const trimmedLine = line.trim();
13
+
14
+ if (trimmedLine.startsWith('@if')) {
15
+ stack.push(['if', trimmedLine]);
16
+ return null;
17
+ } else if (trimmedLine.startsWith('@elseif')) {
18
+ if (stack.length > 0 && stack[stack.length - 1][0] === 'if') {
19
+ return '} else if (';
20
+ }
21
+ } else if (trimmedLine.startsWith('@else')) {
22
+ if (stack.length > 0 && stack[stack.length - 1][0] === 'if') {
23
+ return '} else {';
24
+ }
25
+ } else if (trimmedLine.startsWith('@endif')) {
26
+ if (stack.length > 0 && stack[stack.length - 1][0] === 'if') {
27
+ stack.pop();
28
+ return '}';
29
+ }
30
+ } else if (trimmedLine.startsWith('@unless')) {
31
+ stack.push(['unless', trimmedLine]);
32
+ return null;
33
+ } else if (trimmedLine.startsWith('@endunless')) {
34
+ if (stack.length > 0 && stack[stack.length - 1][0] === 'unless') {
35
+ stack.pop();
36
+ return '}';
37
+ }
38
+ }
39
+
40
+ return null;
41
+ }
42
+ }
43
+
44
+ module.exports = ConditionalHandlers;
45
+
@@ -0,0 +1,178 @@
1
+ const path = require('path');
2
+
3
+ class CompilerConfig {
4
+ constructor() {
5
+ this.config = {
6
+ paths: {
7
+ views_input: "resources/views",
8
+ js_input: "resources/js/app",
9
+ build_output: "resources/js/build",
10
+ build_scopes: "resources/js/build/scopes",
11
+ public_static: "public/static",
12
+ app_output: "public/static/app",
13
+ scopes_output: "public/static/app/scopes"
14
+ },
15
+ files: {
16
+ view_templates: "view.templates.js",
17
+ wrapper: "wraper.js",
18
+ main: "main.js"
19
+ },
20
+ patterns: {
21
+ blade: "**/*.blade.php",
22
+ js: "**/*.js"
23
+ },
24
+ settings: {
25
+ default_scope: "web",
26
+ auto_create_dirs: true,
27
+ verbose: false
28
+ },
29
+ build_directories: [
30
+ "web",
31
+ "admin",
32
+ "layouts",
33
+ "partials",
34
+ "custom",
35
+ "base"
36
+ ]
37
+ };
38
+ }
39
+
40
+ get(key) {
41
+ return key.split('.').reduce((obj, k) => obj && obj[k], this.config);
42
+ }
43
+
44
+ set(key, value) {
45
+ const keys = key.split('.');
46
+ const lastKey = keys.pop();
47
+ const target = keys.reduce((obj, k) => obj[k] = obj[k] || {}, this.config);
48
+ target[lastKey] = value;
49
+ }
50
+
51
+ printConfig() {
52
+ console.log("=============================");
53
+ console.log("Compiler Configuration:");
54
+ console.log("=============================");
55
+ console.log("Views input:", this.get('paths.views_input'));
56
+ console.log("JS input:", this.get('paths.js_input'));
57
+ console.log("Build output:", this.get('paths.build_output'));
58
+ console.log("App output:", this.get('paths.app_output'));
59
+ console.log("Default scope:", this.get('settings.default_scope'));
60
+ console.log("Auto create dirs:", this.get('settings.auto_create_dirs'));
61
+ console.log("Verbose:", this.get('settings.verbose'));
62
+ console.log("Build directories:");
63
+ this.get('build_directories').forEach((dir, i) => {
64
+ console.log(` ${i + 1}. ${dir}`);
65
+ });
66
+ console.log("=============================");
67
+ }
68
+ }
69
+
70
+ // Constants for backward compatibility
71
+ const JS_FUNCTION_PREFIX = "App.View";
72
+ const HTML_ATTR_PREFIX = "one-";
73
+ const SPA_YIELD_ATTR_PREFIX = "one-yield-attr";
74
+ const SPA_YIELD_SUBSCRIBE_KEY_PREFIX = "one-yield-key";
75
+ const SPA_YIELD_SUBSCRIBE_TARGET_PREFIX = "one-yield-target";
76
+ const SPA_YIELD_SUBSCRIBE_ATTR_PREFIX = "one-yield-attr";
77
+ const SPA_YIELD_CONTENT_PREFIX = "one-yield-content";
78
+ const SPA_YIELD_CHILDREN_PREFIX = "one-yield-children";
79
+ const APP_VIEW_NAMESPACE = "App.View";
80
+ const APP_HELPER_NAMESPACE = "App.Helper";
81
+
82
+ // View functions configuration
83
+ class ViewConfig {
84
+ constructor() {
85
+ // View functions - all other functions go to Helper
86
+ this.VIEW_FUNCTIONS = [
87
+ // Core functions
88
+ 'generateViewId',
89
+ 'execute',
90
+ 'evaluate',
91
+ 'escString',
92
+ 'text',
93
+ 'templateToDom',
94
+
95
+ // View management
96
+ 'view',
97
+ 'loadView',
98
+ 'renderView',
99
+ 'include',
100
+ 'includeIf',
101
+ 'extendView',
102
+
103
+ // View lifecycle
104
+ 'setSuperViewPath',
105
+ 'addViewEngine',
106
+ 'callViewEngineMounted',
107
+
108
+ // Wrapper functions
109
+ 'startWrapper',
110
+ 'endWrapper',
111
+ 'registerSubscribe',
112
+ 'wrapAttr',
113
+ // Sections
114
+ 'section',
115
+ 'yield',
116
+ 'yieldContent',
117
+ 'renderSections',
118
+ 'hasSection',
119
+ 'getChangedSections',
120
+ 'resetChangedSections',
121
+ 'isChangedSection',
122
+ 'emitChangedSections',
123
+
124
+ // Stacks
125
+ 'push',
126
+ 'stack',
127
+
128
+ // Once
129
+ 'once',
130
+
131
+ // Route
132
+ 'route',
133
+
134
+ // Events
135
+ 'on',
136
+ 'off',
137
+ 'emit',
138
+
139
+ // Initialization
140
+ 'init',
141
+ 'setApp',
142
+ 'setContainer',
143
+ 'clearOldRendering',
144
+
145
+ // Auth & Error functions (for Blade compatibility)
146
+ 'isAuth',
147
+ 'can',
148
+ 'cannot',
149
+ 'hasError',
150
+ 'firstError',
151
+ 'csrfToken',
152
+
153
+ // Loop functions (for Blade compatibility)
154
+ 'foreach',
155
+ 'foreachTemplate'
156
+ ];
157
+ }
158
+
159
+ isViewFunction(functionName) {
160
+ return this.VIEW_FUNCTIONS.includes(functionName);
161
+ }
162
+ }
163
+
164
+ module.exports = {
165
+ CompilerConfig,
166
+ JS_FUNCTION_PREFIX,
167
+ HTML_ATTR_PREFIX,
168
+ SPA_YIELD_ATTR_PREFIX,
169
+ SPA_YIELD_SUBSCRIBE_KEY_PREFIX,
170
+ SPA_YIELD_SUBSCRIBE_TARGET_PREFIX,
171
+ SPA_YIELD_SUBSCRIBE_ATTR_PREFIX,
172
+ SPA_YIELD_CONTENT_PREFIX,
173
+ SPA_YIELD_CHILDREN_PREFIX,
174
+ APP_VIEW_NAMESPACE,
175
+ APP_HELPER_NAMESPACE,
176
+ ViewConfig
177
+ };
178
+
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Directive processors for various Blade directives
3
+ */
4
+
5
+ class DirectiveProcessor {
6
+ constructor() {
7
+ // No initialization needed
8
+ }
9
+
10
+ processDirective(line, stack, output) {
11
+ /** Process various directives */
12
+ const trimmedLine = line.trim();
13
+
14
+ // Handle @include
15
+ if (trimmedLine.startsWith('@include')) {
16
+ const match = trimmedLine.match(/@include\s*\(\s*['"]([^'"]+)['"]\s*\)/);
17
+ if (match) {
18
+ const viewName = match[1];
19
+ return `\${App.View.include('${viewName}')}`;
20
+ }
21
+ }
22
+
23
+ // Handle @csrf
24
+ if (trimmedLine.startsWith('@csrf')) {
25
+ return `\${App.View.csrfToken()}`;
26
+ }
27
+
28
+ // Handle @method
29
+ if (trimmedLine.startsWith('@method')) {
30
+ const match = trimmedLine.match(/@method\s*\(\s*['"]([^'"]+)['"]\s*\)/);
31
+ if (match) {
32
+ const method = match[1];
33
+ return `<input type="hidden" name="_method" value="${method}">`;
34
+ }
35
+ }
36
+
37
+ // Handle @error
38
+ if (trimmedLine.startsWith('@error')) {
39
+ const match = trimmedLine.match(/@error\s*\(\s*['"]([^'"]+)['"]\s*\)/);
40
+ if (match) {
41
+ const field = match[1];
42
+ return `\${App.View.hasError('${field}') ? App.View.firstError('${field}') : ''}`;
43
+ }
44
+ }
45
+
46
+ return null;
47
+ }
48
+ }
49
+
50
+ module.exports = DirectiveProcessor;
51
+
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Event directive processor
3
+ */
4
+
5
+ class EventDirectiveProcessor {
6
+ constructor() {
7
+ // No initialization needed
8
+ }
9
+
10
+ processEventDirective(eventType, expression) {
11
+ /** Process event directive */
12
+ try {
13
+ // Parse expression to extract handlers
14
+ const handlers = this.parseEventHandlers(expression);
15
+
16
+ if (!handlers || handlers.length === 0) {
17
+ return '';
18
+ }
19
+
20
+ // Build event config
21
+ const eventConfig = this.buildEventConfig(eventType, handlers);
22
+
23
+ // Return event config with template string wrapper
24
+ return `\${${eventConfig}}`;
25
+
26
+ } catch (error) {
27
+ console.error(`Event directive error: ${error.message}`);
28
+ return '';
29
+ }
30
+ }
31
+
32
+ parseEventHandlers(expression) {
33
+ /** Parse multiple event handlers from expression */
34
+ const handlers = [];
35
+
36
+ // Split by comma, respecting nested parentheses
37
+ const handlerStrings = this.splitByComma(expression);
38
+
39
+ for (const handlerString of handlerStrings) {
40
+ const trimmed = handlerString.trim();
41
+ if (!trimmed) {
42
+ continue;
43
+ }
44
+
45
+ // Parse handler name and parameters
46
+ const handler = this.parseHandler(trimmed);
47
+ if (handler) {
48
+ handlers.push(handler);
49
+ }
50
+ }
51
+
52
+ return handlers;
53
+ }
54
+
55
+ parseHandler(handlerString) {
56
+ /** Parse handler name and parameters */
57
+ const parenIndex = handlerString.indexOf('(');
58
+
59
+ if (parenIndex === -1) {
60
+ // No parameters
61
+ return {
62
+ handler: handlerString.trim(),
63
+ params: []
64
+ };
65
+ }
66
+
67
+ const handlerName = handlerString.substring(0, parenIndex).trim();
68
+ const paramsString = handlerString.substring(parenIndex + 1, handlerString.lastIndexOf(')'));
69
+
70
+ const params = this.parseHandlerParameters(paramsString);
71
+
72
+ return {
73
+ handler: handlerName,
74
+ params: params
75
+ };
76
+ }
77
+
78
+ parseHandlerParameters(paramsString) {
79
+ /** Parse handler parameters */
80
+ if (!paramsString.trim()) {
81
+ return [];
82
+ }
83
+
84
+ const params = this.splitByComma(paramsString);
85
+ const processedParams = [];
86
+
87
+ for (const param of params) {
88
+ const processedParam = this.processParameter(param.trim());
89
+ processedParams.push(processedParam);
90
+ }
91
+
92
+ return processedParams;
93
+ }
94
+
95
+ processParameter(param) {
96
+ /** Process individual parameter */
97
+ // Handle Event parameters in all contexts first
98
+ param = this.processEventInString(param);
99
+
100
+ // Handle @attr(...) -> "#ATTR:..."
101
+ param = this.processAttrPropInString(param, '@attr', '#ATTR');
102
+
103
+ // Handle @prop(...) -> "#PROP:..."
104
+ param = this.processAttrPropInString(param, '@prop', '#PROP');
105
+
106
+ // Handle @val(...) -> "#VALUE:..."
107
+ param = this.processAttrPropInString(param, '@val', '#VALUE');
108
+
109
+ // Handle @value(...) -> "#VALUE:..."
110
+ param = this.processAttrPropInString(param, '@value', '#VALUE');
111
+
112
+ // Convert PHP array syntax to JavaScript object syntax
113
+ param = this.convertPhpArrayToJsObject(param);
114
+
115
+ return param;
116
+ }
117
+
118
+ processEventInString(str) {
119
+ /** Process Event parameters */
120
+ return str.replace(/Event/g, '@EVENT');
121
+ }
122
+
123
+ processAttrPropInString(str, prefix, replacement) {
124
+ /** Process @attr/@prop/@val/@value parameters */
125
+ const regex = new RegExp(`${prefix}\\(([^)]+)\\)`, 'g');
126
+ return str.replace(regex, (match, content) => {
127
+ return `${replacement}:${content}`;
128
+ });
129
+ }
130
+
131
+ convertPhpArrayToJsObject(phpCode) {
132
+ /** Convert PHP array syntax to JavaScript object syntax */
133
+ // Simple conversion for now
134
+ return phpCode.replace(/\$(\w+)/g, '$1');
135
+ }
136
+
137
+ splitByComma(text) {
138
+ /** Split text by comma, respecting nested parentheses and quotes */
139
+ const result = [];
140
+ let current = '';
141
+ let depth = 0;
142
+ let inQuotes = false;
143
+ let quoteChar = '';
144
+
145
+ for (let i = 0; i < text.length; i++) {
146
+ const char = text[i];
147
+
148
+ if (!inQuotes && (char === '"' || char === "'")) {
149
+ inQuotes = true;
150
+ quoteChar = char;
151
+ } else if (inQuotes && char === quoteChar) {
152
+ inQuotes = false;
153
+ quoteChar = '';
154
+ } else if (!inQuotes && char === '(') {
155
+ depth++;
156
+ } else if (!inQuotes && char === ')') {
157
+ depth--;
158
+ } else if (!inQuotes && depth === 0 && char === ',') {
159
+ result.push(current.trim());
160
+ current = '';
161
+ continue;
162
+ }
163
+
164
+ current += char;
165
+ }
166
+
167
+ if (current.trim()) {
168
+ result.push(current.trim());
169
+ }
170
+
171
+ return result;
172
+ }
173
+
174
+ buildEventConfig(eventType, handlers) {
175
+ /** Build event config */
176
+ const handlersJson = JSON.stringify(handlers);
177
+ return `self.addEventConfig("${eventType}", ${handlersJson})`;
178
+ }
179
+ }
180
+
181
+ module.exports = EventDirectiveProcessor;
182
+