onelaraveljs 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/onejs-build.js +32 -0
- package/package.json +11 -3
- package/scripts/README-template-compiler.md +133 -0
- package/scripts/README.md +61 -0
- package/scripts/__pycache__/build.cpython-314.pyc +0 -0
- package/scripts/__pycache__/compile.cpython-313.pyc +0 -0
- package/scripts/__pycache__/compile.cpython-314.pyc +0 -0
- package/scripts/build.py +573 -0
- package/scripts/check-system-errors.php +214 -0
- package/scripts/compile.py +101 -0
- package/scripts/compiler/README_CONFIG.md +196 -0
- package/scripts/compiler/__init__.py +18 -0
- package/scripts/compiler/__pycache__/__init__.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/__init__.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/binding_directive_service.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/class_binding_handler.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/compiler_utils.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/compiler_utils.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/conditional_handlers.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/conditional_handlers.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/config.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/config.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/declaration_tracker.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/directive_processors.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/directive_processors.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/echo_processor.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/event_directive_processor.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/event_directive_processor.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/function_generators.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/function_generators.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/loop_handlers.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/loop_handlers.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/main_compiler.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/main_compiler.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/parsers.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/parsers.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/php_converter.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/php_converter.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/php_js_converter.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/php_js_converter.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/register_parser.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/register_parser.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/section_handlers.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/section_handlers.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/show_directive_handler.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/style_directive_handler.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/template_analyzer.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/template_analyzer.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/template_processor.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/template_processor.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/template_processors.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/template_processors.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/utils.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/utils.cpython-314.pyc +0 -0
- package/scripts/compiler/__pycache__/wrapper_parser.cpython-313.pyc +0 -0
- package/scripts/compiler/__pycache__/wrapper_parser.cpython-314.pyc +0 -0
- package/scripts/compiler/binding_directive_service.py +103 -0
- package/scripts/compiler/class_binding_handler.py +347 -0
- package/scripts/compiler/cli.py +34 -0
- package/scripts/compiler/code_generator.py +141 -0
- package/scripts/compiler/compiler.config.json +36 -0
- package/scripts/compiler/compiler_utils.py +55 -0
- package/scripts/compiler/conditional_handlers.py +252 -0
- package/scripts/compiler/config.py +107 -0
- package/scripts/compiler/declaration_tracker.py +420 -0
- package/scripts/compiler/directive_processors.py +603 -0
- package/scripts/compiler/echo_processor.py +667 -0
- package/scripts/compiler/event_directive_processor.py +1099 -0
- package/scripts/compiler/fetch_parser.py +49 -0
- package/scripts/compiler/function_generators.py +310 -0
- package/scripts/compiler/loop_handlers.py +224 -0
- package/scripts/compiler/main_compiler.py +1763 -0
- package/scripts/compiler/parsers.py +1418 -0
- package/scripts/compiler/php_converter.py +470 -0
- package/scripts/compiler/php_js_converter.py +603 -0
- package/scripts/compiler/register_parser.py +480 -0
- package/scripts/compiler/section_handlers.py +122 -0
- package/scripts/compiler/show_directive_handler.py +85 -0
- package/scripts/compiler/style_directive_handler.py +169 -0
- package/scripts/compiler/template_analyzer.py +162 -0
- package/scripts/compiler/template_processor.py +1167 -0
- package/scripts/compiler/template_processors.py +1557 -0
- package/scripts/compiler/test_compiler.py +69 -0
- package/scripts/compiler/utils.py +54 -0
- package/scripts/compiler/variables_analyzer.py +135 -0
- package/scripts/compiler/view_identifier_generator.py +278 -0
- package/scripts/compiler/wrapper_parser.py +78 -0
- package/scripts/dev-context.js +311 -0
- package/scripts/dev.js +109 -0
- package/scripts/generate-assets-order.js +200 -0
- package/scripts/migrate-namespace.php +146 -0
- package/scripts/node/MIGRATION.md +190 -0
- package/scripts/node/README.md +269 -0
- package/scripts/node/build.js +208 -0
- package/scripts/node/compiler/compiler-utils.js +38 -0
- package/scripts/node/compiler/conditional-handlers.js +45 -0
- package/scripts/node/compiler/config.js +178 -0
- package/scripts/node/compiler/directive-processors.js +51 -0
- package/scripts/node/compiler/event-directive-processor.js +182 -0
- package/scripts/node/compiler/function-generators.js +239 -0
- package/scripts/node/compiler/loop-handlers.js +45 -0
- package/scripts/node/compiler/main-compiler.js +236 -0
- package/scripts/node/compiler/parsers.js +358 -0
- package/scripts/node/compiler/php-converter.js +227 -0
- package/scripts/node/compiler/register-parser.js +32 -0
- package/scripts/node/compiler/section-handlers.js +46 -0
- package/scripts/node/compiler/template-analyzer.js +50 -0
- package/scripts/node/compiler/template-processor.js +371 -0
- package/scripts/node/compiler/template-processors.js +219 -0
- package/scripts/node/compiler/utils.js +203 -0
- package/scripts/node/compiler/wrapper-parser.js +25 -0
- package/scripts/node/package.json +24 -0
- package/scripts/node/test-compiler.js +52 -0
- package/scripts/node-run.cjs +28 -0
- package/scripts/standardize-directories.php +92 -0
- package/templates/view.module.js +2 -0
- package/templates/view.tpl-raw.js +13 -0
- package/templates/wraper.js +71 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsers for directives (@extends, @vars, @fetch, @onInit)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { extractBalancedParentheses } = require('./utils');
|
|
6
|
+
const { phpToJs, convertPhpArrayToJson } = require('./php-converter');
|
|
7
|
+
|
|
8
|
+
class DirectiveParsers {
|
|
9
|
+
constructor() {
|
|
10
|
+
// No initialization needed
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
_removeScriptTags(bladeCode) {
|
|
14
|
+
/** Remove JavaScript code in <script> tags to avoid processing useState in JS */
|
|
15
|
+
// Remove all content in <script> tags
|
|
16
|
+
const filteredCode = bladeCode.replace(/<script[^>]*>.*?<\/script>/gis, '');
|
|
17
|
+
return filteredCode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
parseExtends(bladeCode) {
|
|
21
|
+
/** Parse @extends directive */
|
|
22
|
+
const extendsMatch = bladeCode.match(/@extends\s*\(\s*([^)]+)\s*\)/s);
|
|
23
|
+
if (!extendsMatch) {
|
|
24
|
+
return { extendedView: null, extendsExpression: null, extendsData: null };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let extendsContent = extendsMatch[1].trim();
|
|
28
|
+
|
|
29
|
+
// Check if there's a comma (indicating data parameter)
|
|
30
|
+
const commaPos = extendsContent.indexOf(',');
|
|
31
|
+
let viewExpr, dataExpr, extendsData;
|
|
32
|
+
|
|
33
|
+
if (commaPos !== -1) {
|
|
34
|
+
viewExpr = extendsContent.substring(0, commaPos).trim();
|
|
35
|
+
dataExpr = extendsContent.substring(commaPos + 1).trim();
|
|
36
|
+
extendsData = this._convertExtendsData(dataExpr);
|
|
37
|
+
} else {
|
|
38
|
+
viewExpr = extendsContent;
|
|
39
|
+
extendsData = null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Check if it's a simple string literal (avoid $ issues)
|
|
43
|
+
const dollarChar = '$';
|
|
44
|
+
let extendedView, extendsExpression;
|
|
45
|
+
|
|
46
|
+
if ((viewExpr.startsWith('"') && viewExpr.endsWith('"') && !viewExpr.includes(dollarChar)) ||
|
|
47
|
+
(viewExpr.startsWith("'") && viewExpr.endsWith("'") && !viewExpr.includes(dollarChar))) {
|
|
48
|
+
extendedView = viewExpr.slice(1, -1); // Remove quotes
|
|
49
|
+
extendsExpression = null;
|
|
50
|
+
} else {
|
|
51
|
+
// Complex expression - need to evaluate at runtime
|
|
52
|
+
if (viewExpr.startsWith('"') && viewExpr.endsWith('"')) {
|
|
53
|
+
const innerContent = viewExpr.slice(1, -1);
|
|
54
|
+
const processedContent = innerContent.replace(/\$(\w+)/g, '${$1}');
|
|
55
|
+
extendsExpression = "`" + processedContent + "`";
|
|
56
|
+
} else {
|
|
57
|
+
extendsExpression = phpToJs(viewExpr);
|
|
58
|
+
}
|
|
59
|
+
extendedView = null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return { extendedView, extendsExpression, extendsData };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
parseVars(bladeCode) {
|
|
66
|
+
/** Parse @vars directive - improved to handle complex arrays like Event directive */
|
|
67
|
+
const varsMatch = bladeCode.match(/@vars\s*\(\s*(.*?)\s*\)/s);
|
|
68
|
+
if (!varsMatch) {
|
|
69
|
+
return '';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const varsContent = varsMatch[1];
|
|
73
|
+
const varParts = [];
|
|
74
|
+
|
|
75
|
+
// Special handling for object destructuring syntax {var1, var2}
|
|
76
|
+
const trimmedContent = varsContent.trim();
|
|
77
|
+
let parts;
|
|
78
|
+
|
|
79
|
+
if (trimmedContent.startsWith('{') && trimmedContent.endsWith('}')) {
|
|
80
|
+
// Extract content inside braces
|
|
81
|
+
const innerContent = trimmedContent.slice(1, -1);
|
|
82
|
+
// Split by comma at level 0
|
|
83
|
+
parts = this._splitVarsContentCorrect(innerContent);
|
|
84
|
+
} else {
|
|
85
|
+
// Use improved splitting logic (same as Event directive)
|
|
86
|
+
parts = this._splitVarsContentCorrect(varsContent);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (const varItem of parts) {
|
|
90
|
+
const varStr = varItem.trim();
|
|
91
|
+
if (varStr.includes('=')) {
|
|
92
|
+
const equalsPos = this._findFirstEquals(varStr);
|
|
93
|
+
if (equalsPos !== -1) {
|
|
94
|
+
const varName = varStr.substring(0, equalsPos).trim().replace(/^\$/, '');
|
|
95
|
+
const varValue = varStr.substring(equalsPos + 1).trim();
|
|
96
|
+
// Convert PHP array syntax to JavaScript
|
|
97
|
+
const convertedValue = this._convertPhpToJs(varValue);
|
|
98
|
+
varParts.push(`${varName} = ${convertedValue}`);
|
|
99
|
+
} else {
|
|
100
|
+
const varName = varStr.trim().replace(/^\$/, '');
|
|
101
|
+
varParts.push(varName);
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
const varName = varStr.trim().replace(/^\$/, '');
|
|
105
|
+
varParts.push(varName);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return `let {${varParts.join(', ')}} = $$$DATA$$$ || {};`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
parseLetDirectives(bladeCode) {
|
|
113
|
+
/** Parse @let directives - only process Blade directives, not JavaScript code */
|
|
114
|
+
// Remove JavaScript code in <script> tags before parsing
|
|
115
|
+
const bladeCodeFiltered = this._removeScriptTags(bladeCode);
|
|
116
|
+
|
|
117
|
+
// Use balanced parentheses to parse correctly
|
|
118
|
+
const letMatches = [];
|
|
119
|
+
const letPattern = /@let\s*\(/g;
|
|
120
|
+
let match;
|
|
121
|
+
|
|
122
|
+
while ((match = letPattern.exec(bladeCodeFiltered)) !== null) {
|
|
123
|
+
const startPos = match.index + match[0].length - 1; // Position of opening parenthesis
|
|
124
|
+
const [content, endPos] = extractBalancedParentheses(bladeCodeFiltered, startPos);
|
|
125
|
+
|
|
126
|
+
if (content !== null) {
|
|
127
|
+
letMatches.push(content);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const letDeclarations = [];
|
|
132
|
+
for (const match of letMatches) {
|
|
133
|
+
const parts = this._splitVarsContentCorrect(match);
|
|
134
|
+
for (const part of parts) {
|
|
135
|
+
const trimmedPart = part.trim();
|
|
136
|
+
if (trimmedPart) {
|
|
137
|
+
letDeclarations.push(`let ${trimmedPart};`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return letDeclarations;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
parseConstDirectives(bladeCode) {
|
|
146
|
+
/** Parse @const directives */
|
|
147
|
+
const constMatches = [];
|
|
148
|
+
const constPattern = /@const\s*\(/g;
|
|
149
|
+
let match;
|
|
150
|
+
|
|
151
|
+
while ((match = constPattern.exec(bladeCode)) !== null) {
|
|
152
|
+
const startPos = match.index + match[0].length - 1;
|
|
153
|
+
const [content, endPos] = extractBalancedParentheses(bladeCode, startPos);
|
|
154
|
+
|
|
155
|
+
if (content !== null) {
|
|
156
|
+
constMatches.push(content);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const constDeclarations = [];
|
|
161
|
+
for (const match of constMatches) {
|
|
162
|
+
const parts = this._splitVarsContentCorrect(match);
|
|
163
|
+
for (const part of parts) {
|
|
164
|
+
const trimmedPart = part.trim();
|
|
165
|
+
if (trimmedPart) {
|
|
166
|
+
constDeclarations.push(`const ${trimmedPart};`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return constDeclarations;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
parseUseStateDirectives(bladeCode) {
|
|
175
|
+
/** Parse @useState directives */
|
|
176
|
+
const useStateMatches = [];
|
|
177
|
+
const useStatePattern = /@useState\s*\(/g;
|
|
178
|
+
let match;
|
|
179
|
+
|
|
180
|
+
while ((match = useStatePattern.exec(bladeCode)) !== null) {
|
|
181
|
+
const startPos = match.index + match[0].length - 1;
|
|
182
|
+
const [content, endPos] = extractBalancedParentheses(bladeCode, startPos);
|
|
183
|
+
|
|
184
|
+
if (content !== null) {
|
|
185
|
+
useStateMatches.push(content);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const useStateDeclarations = [];
|
|
190
|
+
for (const match of useStateMatches) {
|
|
191
|
+
const parts = this._splitVarsContentCorrect(match);
|
|
192
|
+
for (const part of parts) {
|
|
193
|
+
const trimmedPart = part.trim();
|
|
194
|
+
if (trimmedPart) {
|
|
195
|
+
useStateDeclarations.push(`const [${trimmedPart}] = this.useState(${trimmedPart} || null);`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return useStateDeclarations;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
parseFetch(bladeCode) {
|
|
204
|
+
/** Parse @fetch directive */
|
|
205
|
+
const fetchMatch = bladeCode.match(/@fetch\s*\(\s*(.*?)\s*\)/s);
|
|
206
|
+
if (!fetchMatch) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const fetchContent = fetchMatch[1];
|
|
211
|
+
try {
|
|
212
|
+
// Try to parse as JSON first
|
|
213
|
+
return JSON.parse(fetchContent);
|
|
214
|
+
} catch (e) {
|
|
215
|
+
// If not valid JSON, treat as JavaScript expression
|
|
216
|
+
return fetchContent;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
parseInit(bladeCode) {
|
|
221
|
+
/** Parse @onInit directive */
|
|
222
|
+
const initMatches = [];
|
|
223
|
+
const initPattern = /@onInit\s*\(\s*(.*?)\s*\)/gs;
|
|
224
|
+
let match;
|
|
225
|
+
|
|
226
|
+
while ((match = initPattern.exec(bladeCode)) !== null) {
|
|
227
|
+
initMatches.push(match[1]);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const initFunctions = [];
|
|
231
|
+
const cssContent = [];
|
|
232
|
+
|
|
233
|
+
for (const initContent of initMatches) {
|
|
234
|
+
// Check if it contains CSS
|
|
235
|
+
if (initContent.includes('addCSS') || initContent.includes('style')) {
|
|
236
|
+
cssContent.push(initContent);
|
|
237
|
+
} else {
|
|
238
|
+
initFunctions.push(initContent);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return { initFunctions, cssContent };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
parseViewType(bladeCode) {
|
|
246
|
+
/** Parse @viewType directive */
|
|
247
|
+
const viewTypeMatch = bladeCode.match(/@viewType\s*\(\s*([^)]+)\s*\)/);
|
|
248
|
+
if (!viewTypeMatch) {
|
|
249
|
+
return { type: 'component' };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const viewTypeContent = viewTypeMatch[1].trim().replace(/['"]/g, '');
|
|
253
|
+
return { type: viewTypeContent };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
parseRegister(bladeCode) {
|
|
257
|
+
/** Parse @register directive */
|
|
258
|
+
const registerMatch = bladeCode.match(/@register\s*\(\s*(.*?)\s*\)/s);
|
|
259
|
+
if (!registerMatch) {
|
|
260
|
+
return '';
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return registerMatch[1];
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
parseWrapper(bladeCode) {
|
|
267
|
+
/** Parse @wrapper directive */
|
|
268
|
+
const wrapperMatch = bladeCode.match(/@wrapper\s*\(\s*(.*?)\s*\)/s);
|
|
269
|
+
if (!wrapperMatch) {
|
|
270
|
+
return '';
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return wrapperMatch[1];
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
_splitVarsContentCorrect(content) {
|
|
277
|
+
/** Split content by comma, respecting nested parentheses and quotes */
|
|
278
|
+
const result = [];
|
|
279
|
+
let current = '';
|
|
280
|
+
let depth = 0;
|
|
281
|
+
let inQuotes = false;
|
|
282
|
+
let quoteChar = '';
|
|
283
|
+
|
|
284
|
+
for (let i = 0; i < content.length; i++) {
|
|
285
|
+
const char = content[i];
|
|
286
|
+
|
|
287
|
+
if (!inQuotes && (char === '"' || char === "'")) {
|
|
288
|
+
inQuotes = true;
|
|
289
|
+
quoteChar = char;
|
|
290
|
+
} else if (inQuotes && char === quoteChar) {
|
|
291
|
+
inQuotes = false;
|
|
292
|
+
quoteChar = '';
|
|
293
|
+
} else if (!inQuotes && char === '(') {
|
|
294
|
+
depth++;
|
|
295
|
+
} else if (!inQuotes && char === ')') {
|
|
296
|
+
depth--;
|
|
297
|
+
} else if (!inQuotes && depth === 0 && char === ',') {
|
|
298
|
+
result.push(current.trim());
|
|
299
|
+
current = '';
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
current += char;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (current.trim()) {
|
|
307
|
+
result.push(current.trim());
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return result;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
_findFirstEquals(str) {
|
|
314
|
+
/** Find first equals sign not inside quotes or parentheses */
|
|
315
|
+
let depth = 0;
|
|
316
|
+
let inQuotes = false;
|
|
317
|
+
let quoteChar = '';
|
|
318
|
+
|
|
319
|
+
for (let i = 0; i < str.length; i++) {
|
|
320
|
+
const char = str[i];
|
|
321
|
+
|
|
322
|
+
if (!inQuotes && (char === '"' || char === "'")) {
|
|
323
|
+
inQuotes = true;
|
|
324
|
+
quoteChar = char;
|
|
325
|
+
} else if (inQuotes && char === quoteChar) {
|
|
326
|
+
inQuotes = false;
|
|
327
|
+
quoteChar = '';
|
|
328
|
+
} else if (!inQuotes && char === '(') {
|
|
329
|
+
depth++;
|
|
330
|
+
} else if (!inQuotes && char === ')') {
|
|
331
|
+
depth--;
|
|
332
|
+
} else if (!inQuotes && depth === 0 && char === '=') {
|
|
333
|
+
return i;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return -1;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
_convertPhpToJs(phpCode) {
|
|
341
|
+
/** Convert PHP code to JavaScript */
|
|
342
|
+
return phpToJs(phpCode);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
_convertExtendsData(dataExpr) {
|
|
346
|
+
/** Convert extends data expression */
|
|
347
|
+
if (!dataExpr) return null;
|
|
348
|
+
|
|
349
|
+
try {
|
|
350
|
+
return JSON.parse(dataExpr);
|
|
351
|
+
} catch (e) {
|
|
352
|
+
return dataExpr;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
module.exports = DirectiveParsers;
|
|
358
|
+
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert PHP expressions to JavaScript
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { JS_FUNCTION_PREFIX } = require('./config');
|
|
6
|
+
const { normalizeQuotes } = require('./utils');
|
|
7
|
+
|
|
8
|
+
function convertPhpArrayToJson(expr) {
|
|
9
|
+
/** Convert PHP array syntax to JSON object/array syntax */
|
|
10
|
+
if (!expr || !expr.includes('[')) {
|
|
11
|
+
return expr;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Find all array patterns and convert them
|
|
15
|
+
function replaceArray(match) {
|
|
16
|
+
const inner = match[1].trim();
|
|
17
|
+
if (!inner) {
|
|
18
|
+
return '[]';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Check if this is array access vs array literal
|
|
22
|
+
if ((("'" in inner && (inner.match(/'/g) || []).length === 2 && !inner.includes('=>')) ||
|
|
23
|
+
('"' in inner && (inner.match(/"/g) || []).length === 2 && !inner.includes('=>')) ||
|
|
24
|
+
(inner.replace(/[_\.]/g, '').match(/^\w+$/) && !inner.includes('=>')))) {
|
|
25
|
+
return '[' + inner + ']'; // Keep as array access
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Process array elements
|
|
29
|
+
const elements = [];
|
|
30
|
+
let currentElement = '';
|
|
31
|
+
let parenCount = 0;
|
|
32
|
+
let bracketCount = 0;
|
|
33
|
+
let inQuotes = false;
|
|
34
|
+
let quoteChar = '';
|
|
35
|
+
let i = 0;
|
|
36
|
+
|
|
37
|
+
while (i < inner.length) {
|
|
38
|
+
const char = inner[i];
|
|
39
|
+
|
|
40
|
+
if ((char === '"' || char === "'") && !inQuotes) {
|
|
41
|
+
inQuotes = true;
|
|
42
|
+
quoteChar = char;
|
|
43
|
+
} else if (char === quoteChar && inQuotes) {
|
|
44
|
+
inQuotes = false;
|
|
45
|
+
quoteChar = '';
|
|
46
|
+
} else if (!inQuotes) {
|
|
47
|
+
if (char === '(') {
|
|
48
|
+
parenCount += 1;
|
|
49
|
+
} else if (char === ')') {
|
|
50
|
+
parenCount -= 1;
|
|
51
|
+
} else if (char === '[') {
|
|
52
|
+
bracketCount += 1;
|
|
53
|
+
} else if (char === ']') {
|
|
54
|
+
bracketCount -= 1;
|
|
55
|
+
} else if (char === ',' && parenCount === 0 && bracketCount === 0) {
|
|
56
|
+
elements.push(currentElement.trim());
|
|
57
|
+
currentElement = '';
|
|
58
|
+
i++;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
currentElement += char;
|
|
64
|
+
i++;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (currentElement.trim()) {
|
|
68
|
+
elements.push(currentElement.trim());
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Process each element
|
|
72
|
+
const processedElements = elements.map(element => {
|
|
73
|
+
element = element.trim();
|
|
74
|
+
|
|
75
|
+
// Check if it's a key => value pair
|
|
76
|
+
if (element.includes('=>')) {
|
|
77
|
+
const arrowIndex = element.indexOf('=>');
|
|
78
|
+
const key = element.substring(0, arrowIndex).trim();
|
|
79
|
+
const value = element.substring(arrowIndex + 2).trim();
|
|
80
|
+
|
|
81
|
+
// Process key
|
|
82
|
+
let processedKey = key;
|
|
83
|
+
if ((key.startsWith("'") && key.endsWith("'")) ||
|
|
84
|
+
(key.startsWith('"') && key.endsWith('"'))) {
|
|
85
|
+
processedKey = key; // Keep as string literal
|
|
86
|
+
} else if (key.match(/^\d+$/)) {
|
|
87
|
+
processedKey = key; // Keep as number
|
|
88
|
+
} else {
|
|
89
|
+
processedKey = `"${key}"`; // Convert to string
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Process value
|
|
93
|
+
const processedValue = convertPhpArrayToJson(value);
|
|
94
|
+
|
|
95
|
+
return `${processedKey}: ${processedValue}`;
|
|
96
|
+
} else {
|
|
97
|
+
return convertPhpArrayToJson(element);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Check if all elements are key-value pairs
|
|
102
|
+
const hasKeyValuePairs = elements.some(element => element.includes('=>'));
|
|
103
|
+
|
|
104
|
+
if (hasKeyValuePairs) {
|
|
105
|
+
return `{${processedElements.join(', ')}}`;
|
|
106
|
+
} else {
|
|
107
|
+
return `[${processedElements.join(', ')}]`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Replace array patterns
|
|
112
|
+
return expr.replace(/\[(.*?)\]/g, replaceArray);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function phpToJs(phpCode) {
|
|
116
|
+
/** Convert PHP code to JavaScript */
|
|
117
|
+
if (!phpCode) return phpCode;
|
|
118
|
+
|
|
119
|
+
let jsCode = phpCode;
|
|
120
|
+
|
|
121
|
+
// Convert PHP variables ($var -> var)
|
|
122
|
+
jsCode = jsCode.replace(/\$(\w+)/g, '$1');
|
|
123
|
+
|
|
124
|
+
// Convert PHP array syntax to JavaScript
|
|
125
|
+
jsCode = convertPhpArrayToJson(jsCode);
|
|
126
|
+
|
|
127
|
+
// Convert PHP function calls to JavaScript
|
|
128
|
+
jsCode = jsCode.replace(/App\.Helper\.(\w+)/g, `${JS_FUNCTION_PREFIX}.Helper.$1`);
|
|
129
|
+
|
|
130
|
+
// Convert PHP string concatenation
|
|
131
|
+
jsCode = jsCode.replace(/\s*\.\s*/g, ' + ');
|
|
132
|
+
|
|
133
|
+
// Normalize quotes
|
|
134
|
+
jsCode = normalizeQuotes(jsCode);
|
|
135
|
+
|
|
136
|
+
return jsCode;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function phpToJsAdvanced(phpCode) {
|
|
140
|
+
/** Advanced PHP to JavaScript conversion */
|
|
141
|
+
if (!phpCode) return phpCode;
|
|
142
|
+
|
|
143
|
+
let jsCode = phpCode;
|
|
144
|
+
|
|
145
|
+
// Convert PHP variables
|
|
146
|
+
jsCode = jsCode.replace(/\$(\w+)/g, '$1');
|
|
147
|
+
|
|
148
|
+
// Convert PHP array syntax
|
|
149
|
+
jsCode = convertPhpArrayToJson(jsCode);
|
|
150
|
+
|
|
151
|
+
// Convert PHP operators
|
|
152
|
+
jsCode = jsCode.replace(/===/g, '===');
|
|
153
|
+
jsCode = jsCode.replace(/!==/g, '!==');
|
|
154
|
+
jsCode = jsCode.replace(/&&/g, '&&');
|
|
155
|
+
jsCode = jsCode.replace(/\|\|/g, '||');
|
|
156
|
+
|
|
157
|
+
// Convert PHP function calls
|
|
158
|
+
jsCode = jsCode.replace(/App\.Helper\.(\w+)/g, `${JS_FUNCTION_PREFIX}.Helper.$1`);
|
|
159
|
+
jsCode = jsCode.replace(/App\.View\.(\w+)/g, `${JS_FUNCTION_PREFIX}.$1`);
|
|
160
|
+
|
|
161
|
+
// Convert string concatenation
|
|
162
|
+
jsCode = jsCode.replace(/\s*\.\s*/g, ' + ');
|
|
163
|
+
|
|
164
|
+
// Convert PHP null coalescing operator
|
|
165
|
+
jsCode = jsCode.replace(/\?\?/g, '||');
|
|
166
|
+
|
|
167
|
+
// Convert PHP ternary operator
|
|
168
|
+
jsCode = jsCode.replace(/\?\s*([^:]+)\s*:\s*([^;]+)/g, '? $1 : $2');
|
|
169
|
+
|
|
170
|
+
// Normalize quotes
|
|
171
|
+
jsCode = normalizeQuotes(jsCode);
|
|
172
|
+
|
|
173
|
+
return jsCode;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function convertPhpExpression(expr) {
|
|
177
|
+
/** Convert PHP expression to JavaScript expression */
|
|
178
|
+
if (!expr) return expr;
|
|
179
|
+
|
|
180
|
+
// Handle different types of expressions
|
|
181
|
+
if (expr.includes('[') && expr.includes(']')) {
|
|
182
|
+
// Array expression
|
|
183
|
+
return convertPhpArrayToJson(expr);
|
|
184
|
+
} else if (expr.includes('$')) {
|
|
185
|
+
// Variable expression
|
|
186
|
+
return phpToJs(expr);
|
|
187
|
+
} else {
|
|
188
|
+
// Simple expression
|
|
189
|
+
return expr;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function isPhpExpression(expr) {
|
|
194
|
+
/** Check if expression contains PHP syntax */
|
|
195
|
+
return expr.includes('$') || expr.includes('[') || expr.includes('=>');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function escapePhpString(str) {
|
|
199
|
+
/** Escape PHP string for JavaScript */
|
|
200
|
+
return str.replace(/\\/g, '\\\\')
|
|
201
|
+
.replace(/'/g, "\\'")
|
|
202
|
+
.replace(/"/g, '\\"')
|
|
203
|
+
.replace(/\n/g, '\\n')
|
|
204
|
+
.replace(/\r/g, '\\r')
|
|
205
|
+
.replace(/\t/g, '\\t');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function unescapePhpString(str) {
|
|
209
|
+
/** Unescape PHP string */
|
|
210
|
+
return str.replace(/\\\\/g, '\\')
|
|
211
|
+
.replace(/\\'/g, "'")
|
|
212
|
+
.replace(/\\"/g, '"')
|
|
213
|
+
.replace(/\\n/g, '\n')
|
|
214
|
+
.replace(/\\r/g, '\r')
|
|
215
|
+
.replace(/\\t/g, '\t');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
module.exports = {
|
|
219
|
+
convertPhpArrayToJson,
|
|
220
|
+
phpToJs,
|
|
221
|
+
phpToJsAdvanced,
|
|
222
|
+
convertPhpExpression,
|
|
223
|
+
isPhpExpression,
|
|
224
|
+
escapePhpString,
|
|
225
|
+
unescapePhpString
|
|
226
|
+
};
|
|
227
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register parser
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
class RegisterParser {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.parseRegisterContent = {};
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
parseRegisterContent(registerContent) {
|
|
11
|
+
/** Parse register content */
|
|
12
|
+
if (!registerContent || !registerContent.trim()) {
|
|
13
|
+
return {};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
// Try to parse as JSON
|
|
18
|
+
return JSON.parse(registerContent);
|
|
19
|
+
} catch (e) {
|
|
20
|
+
// If not valid JSON, return empty object
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
reset() {
|
|
26
|
+
/** Reset parser state */
|
|
27
|
+
this.parseRegisterContent = {};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
module.exports = RegisterParser;
|
|
32
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section handlers for @section, @yield, etc.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
class SectionHandlers {
|
|
6
|
+
constructor() {
|
|
7
|
+
// No initialization needed
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
processSectionDirective(line, stack, output, sections) {
|
|
11
|
+
/** Process section directives */
|
|
12
|
+
const trimmedLine = line.trim();
|
|
13
|
+
|
|
14
|
+
if (trimmedLine.startsWith('@section')) {
|
|
15
|
+
const match = trimmedLine.match(/@section\s*\(\s*['"]([^'"]+)['"]\s*\)/);
|
|
16
|
+
if (match) {
|
|
17
|
+
const sectionName = match[1];
|
|
18
|
+
sections.push({
|
|
19
|
+
name: sectionName,
|
|
20
|
+
type: 'long',
|
|
21
|
+
preloader: false,
|
|
22
|
+
useVars: false,
|
|
23
|
+
script: {}
|
|
24
|
+
});
|
|
25
|
+
stack.push(['section', sectionName]);
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
} else if (trimmedLine.startsWith('@endsection')) {
|
|
29
|
+
if (stack.length > 0 && stack[stack.length - 1][0] === 'section') {
|
|
30
|
+
stack.pop();
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
} else if (trimmedLine.startsWith('@yield')) {
|
|
34
|
+
const match = trimmedLine.match(/@yield\s*\(\s*['"]([^'"]+)['"]\s*\)/);
|
|
35
|
+
if (match) {
|
|
36
|
+
const sectionName = match[1];
|
|
37
|
+
return `\${App.View.yield('${sectionName}')}`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = SectionHandlers;
|
|
46
|
+
|