create-prisma-php-app 1.22.0 → 1.22.2
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/dist/bootstrap.php +192 -155
- package/dist/index.js +1 -1
- package/dist/settings/bs-config.cjs +1 -0
- package/dist/settings/files-list-config.js +61 -0
- package/dist/settings/start-dev.js +4 -4
- package/dist/src/Lib/Headers/Boom.php +39 -0
- package/dist/src/app/layout.php +1 -1
- package/dist/tailwind.config.js +3 -6
- package/dist/tsconfig.json +9 -9
- package/package.json +1 -1
package/dist/bootstrap.php
CHANGED
|
@@ -25,8 +25,17 @@ function determineContentToInclude()
|
|
|
25
25
|
$baseDir = APP_PATH;
|
|
26
26
|
$includePath = '';
|
|
27
27
|
$layoutsToInclude = [];
|
|
28
|
-
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* ============ Middleware Management ============
|
|
31
|
+
* AuthMiddleware is invoked to handle authentication logic for the current route ($uri).
|
|
32
|
+
* ================================================
|
|
33
|
+
*/
|
|
29
34
|
AuthMiddleware::handle($uri);
|
|
35
|
+
/**
|
|
36
|
+
* ============ End of Middleware Management ======
|
|
37
|
+
* ================================================
|
|
38
|
+
*/
|
|
30
39
|
|
|
31
40
|
$isDirectAccessToPrivateRoute = preg_match('/\/_/', $uri);
|
|
32
41
|
if ($isDirectAccessToPrivateRoute) {
|
|
@@ -107,31 +116,23 @@ function getFilePrecedence()
|
|
|
107
116
|
global $_filesListRoutes;
|
|
108
117
|
|
|
109
118
|
// Normalize the file paths for consistent comparison
|
|
110
|
-
$_filesListRoutes
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return preg_match('/^\.\/src\/app\/route\.php$/', $route);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// If route.php is found, return just the file name
|
|
120
|
-
if (!empty($routeFile)) {
|
|
121
|
-
return '/route.php';
|
|
119
|
+
foreach ($_filesListRoutes as $route) {
|
|
120
|
+
$normalizedRoute = str_replace('\\', '/', $route);
|
|
121
|
+
// First, check for route.php
|
|
122
|
+
if (preg_match('/^\.\/src\/app\/route\.php$/', $normalizedRoute)) {
|
|
123
|
+
return '/route.php';
|
|
124
|
+
}
|
|
122
125
|
}
|
|
123
126
|
|
|
124
|
-
// If route.php is
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (!empty($indexFile)) {
|
|
131
|
-
return '/index.php';
|
|
127
|
+
// If no route.php is found, check for index.php
|
|
128
|
+
foreach ($_filesListRoutes as $route) {
|
|
129
|
+
$normalizedRoute = str_replace('\\', '/', $route);
|
|
130
|
+
if (preg_match('/^\.\/src\/app\/index\.php$/', $normalizedRoute)) {
|
|
131
|
+
return '/index.php';
|
|
132
|
+
}
|
|
132
133
|
}
|
|
133
134
|
|
|
134
|
-
// If neither file is found, return null
|
|
135
|
+
// If neither file is found, return null
|
|
135
136
|
return null;
|
|
136
137
|
}
|
|
137
138
|
|
|
@@ -145,42 +146,19 @@ function uriExtractor(string $scriptUrl): string
|
|
|
145
146
|
}
|
|
146
147
|
|
|
147
148
|
$escapedIdentifier = preg_quote($projectName, '/');
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (!empty($matches[1])) {
|
|
151
|
-
$leftTrim = ltrim($matches[1], '/');
|
|
152
|
-
$rightTrim = rtrim($leftTrim, '/');
|
|
153
|
-
return "$rightTrim";
|
|
154
|
-
}
|
|
149
|
+
if (preg_match("/(?:.*$escapedIdentifier)(\/.*)$/", $scriptUrl, $matches) && !empty($matches[1])) {
|
|
150
|
+
return rtrim(ltrim($matches[1], '/'), '/');
|
|
155
151
|
}
|
|
156
152
|
|
|
157
153
|
return "/";
|
|
158
154
|
}
|
|
159
155
|
|
|
160
|
-
function
|
|
156
|
+
function getFilesListRoutes()
|
|
161
157
|
{
|
|
162
|
-
|
|
163
|
-
$
|
|
158
|
+
$jsonFileName = SETTINGS_PATH . '/files-list.json';
|
|
159
|
+
$routeFiles = file_exists($jsonFileName) ? json_decode(file_get_contents($jsonFileName), true) : [];
|
|
164
160
|
|
|
165
|
-
|
|
166
|
-
$filesList = [];
|
|
167
|
-
|
|
168
|
-
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
|
|
169
|
-
|
|
170
|
-
foreach ($iterator as $file) {
|
|
171
|
-
if ($file->isFile()) {
|
|
172
|
-
$filesList[] = $file->getPathname();
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
$jsonData = json_encode($filesList, JSON_PRETTY_PRINT);
|
|
177
|
-
$jsonFileName = SETTINGS_PATH . '/files-list.json';
|
|
178
|
-
file_put_contents($jsonFileName, $jsonData);
|
|
179
|
-
|
|
180
|
-
if (file_exists($jsonFileName)) {
|
|
181
|
-
$_filesListRoutes = json_decode(file_get_contents($jsonFileName), true);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
161
|
+
return $routeFiles;
|
|
184
162
|
}
|
|
185
163
|
|
|
186
164
|
function findGroupFolder($uri): string
|
|
@@ -213,14 +191,21 @@ function dynamicRoute($uri)
|
|
|
213
191
|
foreach ($_filesListRoutes as $route) {
|
|
214
192
|
$normalizedRoute = trim(str_replace('\\', '/', $route), '.');
|
|
215
193
|
$routeSegments = explode('/', ltrim($normalizedRoute, '/'));
|
|
194
|
+
|
|
195
|
+
$filteredRouteSegments = array_values(array_filter($routeSegments, function ($segment) {
|
|
196
|
+
return !preg_match('/\(.+\)/', $segment); // Skip segments with parentheses (groups)
|
|
197
|
+
}));
|
|
198
|
+
|
|
216
199
|
$singleDynamic = preg_match_all('/\[[^\]]+\]/', $normalizedRoute, $matches) === 1 && !strpos($normalizedRoute, '[...');
|
|
217
200
|
if ($singleDynamic) {
|
|
218
|
-
$segmentMatch = singleDynamicRoute($uriSegments, $
|
|
219
|
-
|
|
201
|
+
$segmentMatch = singleDynamicRoute($uriSegments, $filteredRouteSegments);
|
|
202
|
+
$index = array_search($segmentMatch, $filteredRouteSegments);
|
|
203
|
+
if ($index !== false && isset($uriSegments[$index])) {
|
|
220
204
|
$trimSegmentMatch = trim($segmentMatch, '[]');
|
|
221
|
-
$dynamicRouteParams = new \ArrayObject([$trimSegmentMatch => $uriSegments[
|
|
222
|
-
|
|
223
|
-
$dynamicRouteUri =
|
|
205
|
+
$dynamicRouteParams = new \ArrayObject([$trimSegmentMatch => $uriSegments[$index]], \ArrayObject::ARRAY_AS_PROPS);
|
|
206
|
+
$dynamicRouteUri = str_replace($segmentMatch, $uriSegments[$index], $normalizedRoute);
|
|
207
|
+
$dynamicRouteUri = preg_replace('/\(.+\)/', '', $dynamicRouteUri);
|
|
208
|
+
$dynamicRouteUri = preg_replace('/\/+/', '/', $dynamicRouteUri);
|
|
224
209
|
$dynamicRouteUriDirname = dirname($dynamicRouteUri);
|
|
225
210
|
$dynamicRouteUriDirname = rtrim($dynamicRouteUriDirname, '/');
|
|
226
211
|
|
|
@@ -235,30 +220,41 @@ function dynamicRoute($uri)
|
|
|
235
220
|
}
|
|
236
221
|
}
|
|
237
222
|
} elseif (strpos($normalizedRoute, '[...') !== false) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
223
|
+
// Clean and normalize the route
|
|
224
|
+
$cleanedNormalizedRoute = preg_replace('/\(.+\)/', '', $normalizedRoute); // Remove any public/private segment
|
|
225
|
+
$cleanedNormalizedRoute = preg_replace('/\/+/', '/', $cleanedNormalizedRoute); // Replace multiple slashes
|
|
226
|
+
$dynamicSegmentRoute = preg_replace('/\[\.\.\..*?\].*/', '', $cleanedNormalizedRoute); // Remove the dynamic segment
|
|
227
|
+
|
|
228
|
+
// Check if the normalized URI starts with the cleaned route
|
|
229
|
+
if (strpos("/src/app/$normalizedUri", $dynamicSegmentRoute) === 0) {
|
|
230
|
+
$trimmedUri = str_replace($dynamicSegmentRoute, '', "/src/app/$normalizedUri");
|
|
231
|
+
$uriParts = explode('/', trim($trimmedUri, '/'));
|
|
232
|
+
|
|
233
|
+
// Extract the dynamic segment content
|
|
234
|
+
if (preg_match('/\[\.\.\.(.*?)\]/', $normalizedRoute, $matches)) {
|
|
235
|
+
$dynamicParam = $matches[1];
|
|
236
|
+
$dynamicRouteParams = new \ArrayObject([$dynamicParam => $uriParts], \ArrayObject::ARRAY_AS_PROPS);
|
|
248
237
|
}
|
|
238
|
+
|
|
239
|
+
// Check for 'route.php'
|
|
249
240
|
if (strpos($normalizedRoute, 'route.php') !== false) {
|
|
250
241
|
$uriMatch = $normalizedRoute;
|
|
251
242
|
break;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Handle matching routes ending with 'index.php'
|
|
246
|
+
if (strpos($normalizedRoute, 'index.php') !== false) {
|
|
247
|
+
$segmentMatch = "[...$dynamicParam]";
|
|
248
|
+
$index = array_search($segmentMatch, $filteredRouteSegments);
|
|
258
249
|
|
|
259
|
-
|
|
260
|
-
|
|
250
|
+
if ($index !== false && isset($uriSegments[$index])) {
|
|
251
|
+
// Generate the dynamic URI
|
|
252
|
+
$dynamicRouteUri = str_replace($segmentMatch, implode('/', $uriParts), $cleanedNormalizedRoute);
|
|
253
|
+
$dynamicRouteUriDirname = rtrim(dirname($dynamicRouteUri), '/');
|
|
261
254
|
|
|
255
|
+
$expectedUri = rtrim("/src/app/$normalizedUri", '/');
|
|
256
|
+
|
|
257
|
+
// Compare the expected and dynamic URIs
|
|
262
258
|
if ($expectedUri === $dynamicRouteUriDirname) {
|
|
263
259
|
$uriMatch = $normalizedRoute;
|
|
264
260
|
break;
|
|
@@ -280,6 +276,7 @@ function isGroupIdentifier($segment): bool
|
|
|
280
276
|
function matchGroupFolder($constructedPath): ?string
|
|
281
277
|
{
|
|
282
278
|
global $_filesListRoutes;
|
|
279
|
+
|
|
283
280
|
$bestMatch = null;
|
|
284
281
|
$normalizedConstructedPath = ltrim(str_replace('\\', '/', $constructedPath), './');
|
|
285
282
|
|
|
@@ -330,6 +327,10 @@ function singleDynamicRoute($uriSegments, $routeSegments)
|
|
|
330
327
|
|
|
331
328
|
function checkForDuplicateRoutes()
|
|
332
329
|
{
|
|
330
|
+
if ($_ENV['APP_ENV'] !== 'development') {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
|
|
333
334
|
global $_filesListRoutes;
|
|
334
335
|
$normalizedRoutesMap = [];
|
|
335
336
|
foreach ($_filesListRoutes as $route) {
|
|
@@ -363,72 +364,27 @@ function checkForDuplicateRoutes()
|
|
|
363
364
|
}
|
|
364
365
|
}
|
|
365
366
|
|
|
366
|
-
function setupErrorHandling(&$content)
|
|
367
|
-
{
|
|
368
|
-
set_error_handler(function ($severity, $message, $file, $line) use (&$content) {
|
|
369
|
-
$content .= "<div class='error'>Error: {$severity} - {$message} in {$file} on line {$line}</div>";
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
set_exception_handler(function ($exception) use (&$content) {
|
|
373
|
-
$content .= "<div class='error'>Exception: " . htmlspecialchars($exception->getMessage(), ENT_QUOTES, 'UTF-8') . "</div>";
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
register_shutdown_function(function () use (&$content) {
|
|
377
|
-
$error = error_get_last();
|
|
378
|
-
if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_RECOVERABLE_ERROR])) {
|
|
379
|
-
$formattedError = "<div class='error'>Fatal Error: " . htmlspecialchars($error['message'], ENT_QUOTES, 'UTF-8') .
|
|
380
|
-
" in " . htmlspecialchars($error['file'], ENT_QUOTES, 'UTF-8') .
|
|
381
|
-
" on line " . $error['line'] . "</div>";
|
|
382
|
-
$content .= $formattedError;
|
|
383
|
-
modifyOutputLayoutForError($content);
|
|
384
|
-
}
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
|
|
388
367
|
|
|
389
368
|
function containsChildContent($filePath)
|
|
390
369
|
{
|
|
391
370
|
$fileContent = file_get_contents($filePath);
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
)
|
|
398
|
-
return true;
|
|
399
|
-
} else {
|
|
400
|
-
return false;
|
|
401
|
-
}
|
|
371
|
+
|
|
372
|
+
// Regular expression to match different ways of echoing $childContent
|
|
373
|
+
$pattern = '/\<\?=\s*\$childContent\s*;?\s*\?>|echo\s*\$childContent\s*;?/';
|
|
374
|
+
|
|
375
|
+
// Return true if $childContent variables are found, false otherwise
|
|
376
|
+
return preg_match($pattern, $fileContent) === 1;
|
|
402
377
|
}
|
|
403
378
|
|
|
404
379
|
function containsContent($filePath)
|
|
405
380
|
{
|
|
406
381
|
$fileContent = file_get_contents($filePath);
|
|
407
|
-
if (
|
|
408
|
-
(strpos($fileContent, 'echo $content') === false &&
|
|
409
|
-
strpos($fileContent, 'echo $content;') === false) &&
|
|
410
|
-
(strpos($fileContent, '<?= $content ?>') === false) &&
|
|
411
|
-
(strpos($fileContent, '<?= $content; ?>') === false)
|
|
412
|
-
) {
|
|
413
|
-
return true;
|
|
414
|
-
} else {
|
|
415
|
-
return false;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
function modifyOutputLayoutForError($contentToAdd)
|
|
420
|
-
{
|
|
421
|
-
if ($_ENV['SHOW_ERRORS'] === "false") exit;
|
|
422
|
-
|
|
423
|
-
$layoutContent = file_get_contents(APP_PATH . '/layout.php');
|
|
424
|
-
if ($layoutContent !== false) {
|
|
425
|
-
$newBodyContent = "<body class=\"fatal-error\">$contentToAdd</body>";
|
|
426
382
|
|
|
427
|
-
|
|
383
|
+
// Improved regular expression to match different ways of echoing $content
|
|
384
|
+
$pattern = '/\<\?=\s*\$content\s*;?\s*\?>|echo\s*\$content\s*;?/';
|
|
428
385
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
386
|
+
// Return true if content variables are found, false otherwise
|
|
387
|
+
return preg_match($pattern, $fileContent) === 1;
|
|
432
388
|
}
|
|
433
389
|
|
|
434
390
|
function convertToArrayObject($data)
|
|
@@ -579,17 +535,7 @@ function getLoadingsFiles()
|
|
|
579
535
|
return '';
|
|
580
536
|
}
|
|
581
537
|
|
|
582
|
-
|
|
583
|
-
{
|
|
584
|
-
$token = getBearerToken();
|
|
585
|
-
if ($token) {
|
|
586
|
-
$auth = Auth::getInstance();
|
|
587
|
-
$verifyToken = $auth->verifyToken($token);
|
|
588
|
-
if ($verifyToken) {
|
|
589
|
-
$auth->authenticate($verifyToken);
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
}
|
|
538
|
+
|
|
593
539
|
|
|
594
540
|
function getPrismaSettings(): \ArrayObject
|
|
595
541
|
{
|
|
@@ -607,15 +553,103 @@ function getPrismaSettings(): \ArrayObject
|
|
|
607
553
|
}
|
|
608
554
|
}
|
|
609
555
|
|
|
610
|
-
|
|
556
|
+
function modifyOutputLayoutForError($contentToAdd)
|
|
557
|
+
{
|
|
558
|
+
global
|
|
559
|
+
$baseUrl,
|
|
560
|
+
$metadata,
|
|
561
|
+
$content,
|
|
562
|
+
$childContent,
|
|
563
|
+
$uri,
|
|
564
|
+
$pathname,
|
|
565
|
+
$dynamicRouteParams,
|
|
566
|
+
$params,
|
|
567
|
+
$referer,
|
|
568
|
+
$mainLayoutHead,
|
|
569
|
+
$mainLayoutFooter;
|
|
570
|
+
|
|
571
|
+
$errorFile = APP_PATH . '/error.php';
|
|
572
|
+
$errorFileExists = file_exists($errorFile);
|
|
573
|
+
|
|
574
|
+
if ($_ENV['SHOW_ERRORS'] === "false") {
|
|
575
|
+
if ($errorFileExists) {
|
|
576
|
+
$contentToAdd = "<div class='error'>An error occurred</div>";
|
|
577
|
+
} else {
|
|
578
|
+
exit; // Exit if SHOW_ERRORS is false and no error file exists
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
if ($errorFileExists) {
|
|
583
|
+
|
|
584
|
+
$errorContent = $contentToAdd;
|
|
585
|
+
|
|
586
|
+
$layoutFile = APP_PATH . '/layout.php';
|
|
587
|
+
if (file_exists($layoutFile)) {
|
|
588
|
+
|
|
589
|
+
ob_start();
|
|
590
|
+
include_once $errorFile;
|
|
591
|
+
$content = ob_get_clean();
|
|
592
|
+
include $layoutFile;
|
|
593
|
+
} else {
|
|
594
|
+
echo $errorContent;
|
|
595
|
+
}
|
|
596
|
+
} else {
|
|
597
|
+
echo $contentToAdd;
|
|
598
|
+
}
|
|
599
|
+
exit;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
set_error_handler(function ($severity, $message, $file, $line) {
|
|
603
|
+
if (!(error_reporting() & $severity)) {
|
|
604
|
+
// This error code is not included in error_reporting
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// Capture the specific severity types, including warnings (E_WARNING)
|
|
609
|
+
$errorContent = "<div class='error'>Error: {$severity} - {$message} in {$file} on line {$line}</div>";
|
|
610
|
+
|
|
611
|
+
// If needed, log it or output immediately based on severity
|
|
612
|
+
if ($severity === E_WARNING || $severity === E_NOTICE) {
|
|
613
|
+
modifyOutputLayoutForError($errorContent);
|
|
614
|
+
}
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
set_exception_handler(function ($exception) {
|
|
618
|
+
$errorContent = "<div class='error'>Exception: " . htmlspecialchars($exception->getMessage(), ENT_QUOTES, 'UTF-8') . "</div>";
|
|
619
|
+
modifyOutputLayoutForError($errorContent);
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
register_shutdown_function(function () {
|
|
623
|
+
$error = error_get_last();
|
|
624
|
+
if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_RECOVERABLE_ERROR])) {
|
|
625
|
+
$formattedError = "<div class='error'>Fatal Error: " . htmlspecialchars($error['message'], ENT_QUOTES, 'UTF-8') .
|
|
626
|
+
" in " . htmlspecialchars($error['file'], ENT_QUOTES, 'UTF-8') .
|
|
627
|
+
" on line " . $error['line'] . "</div>";
|
|
628
|
+
$errorContent = $formattedError;
|
|
629
|
+
modifyOutputLayoutForError($errorContent);
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
|
|
611
633
|
require_once SETTINGS_PATH . '/public-functions.php';
|
|
612
634
|
require_once SETTINGS_PATH . '/request-methods.php';
|
|
613
635
|
$_metadataFile = APP_PATH . '/metadata.php';
|
|
614
636
|
$_metadataArray = file_exists($_metadataFile) ? require_once $_metadataFile : [];
|
|
615
|
-
$_filesListRoutes =
|
|
637
|
+
$_filesListRoutes = getFilesListRoutes();
|
|
616
638
|
$_prismaPHPSettings = getPrismaSettings();
|
|
617
639
|
$_fileToInclude = '';
|
|
618
640
|
|
|
641
|
+
function authenticateUserToken()
|
|
642
|
+
{
|
|
643
|
+
$token = getBearerToken();
|
|
644
|
+
if ($token) {
|
|
645
|
+
$auth = Auth::getInstance();
|
|
646
|
+
$verifyToken = $auth->verifyToken($token);
|
|
647
|
+
if ($verifyToken) {
|
|
648
|
+
$auth->authenticate($verifyToken);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
619
653
|
/**
|
|
620
654
|
* @var array $metadata Metadata information
|
|
621
655
|
*/
|
|
@@ -651,12 +685,17 @@ $mainLayoutFooter = [];
|
|
|
651
685
|
|
|
652
686
|
try {
|
|
653
687
|
$_determineContentToInclude = determineContentToInclude();
|
|
654
|
-
checkForDuplicateRoutes();
|
|
655
688
|
$_contentToInclude = $_determineContentToInclude['path'] ?? '';
|
|
656
689
|
$_layoutsToInclude = $_determineContentToInclude['layouts'] ?? [];
|
|
657
690
|
$uri = $_determineContentToInclude['uri'] ?? '';
|
|
658
691
|
$pathname = $uri ? "/" . $uri : "/";
|
|
659
|
-
$_fileToInclude =
|
|
692
|
+
$_fileToInclude = null;
|
|
693
|
+
if (is_file($_contentToInclude)) {
|
|
694
|
+
$_fileToInclude = basename($_contentToInclude); // returns the file name
|
|
695
|
+
}
|
|
696
|
+
$metadata = $_metadataArray[$uri] ?? ($_metadataArray['default'] ?? []);
|
|
697
|
+
|
|
698
|
+
checkForDuplicateRoutes();
|
|
660
699
|
authenticateUserToken();
|
|
661
700
|
|
|
662
701
|
if (empty($_contentToInclude)) {
|
|
@@ -704,17 +743,16 @@ try {
|
|
|
704
743
|
exit;
|
|
705
744
|
}
|
|
706
745
|
|
|
707
|
-
$metadata = $_metadataArray[$uri] ?? ($_metadataArray['default'] ?? []);
|
|
708
746
|
$_parentLayoutPath = APP_PATH . '/layout.php';
|
|
709
747
|
$_isParentLayout = !empty($_layoutsToInclude) && strpos($_layoutsToInclude[0], 'src/app/layout.php') !== false;
|
|
710
748
|
|
|
711
749
|
$_isContentIncluded = false;
|
|
712
750
|
$_isChildContentIncluded = false;
|
|
713
|
-
|
|
751
|
+
$_isContentVariableIncluded = containsContent($_parentLayoutPath);
|
|
752
|
+
if (!$_isContentVariableIncluded) {
|
|
714
753
|
$_isContentIncluded = true;
|
|
715
754
|
}
|
|
716
755
|
|
|
717
|
-
ob_start();
|
|
718
756
|
if (!empty($_contentToInclude)) {
|
|
719
757
|
if (!$_isParentLayout) {
|
|
720
758
|
ob_start();
|
|
@@ -726,7 +764,8 @@ try {
|
|
|
726
764
|
continue;
|
|
727
765
|
}
|
|
728
766
|
|
|
729
|
-
|
|
767
|
+
$_isChildContentVariableIncluded = containsChildContent($layoutPath);
|
|
768
|
+
if (!$_isChildContentVariableIncluded) {
|
|
730
769
|
$_isChildContentIncluded = true;
|
|
731
770
|
}
|
|
732
771
|
|
|
@@ -759,18 +798,16 @@ try {
|
|
|
759
798
|
}
|
|
760
799
|
} else {
|
|
761
800
|
if ($_isContentIncluded) {
|
|
762
|
-
|
|
763
|
-
modifyOutputLayoutForError($content);
|
|
801
|
+
echo "<div class='error'>The parent layout file does not contain <?php echo \$content; ?> Or <?= \$content ?><br>" . "<strong>$_parentLayoutPath</strong></div>";
|
|
764
802
|
} else {
|
|
765
|
-
$
|
|
766
|
-
modifyOutputLayoutForError($
|
|
803
|
+
$errorDetails = "<div class='error'>The layout file does not contain <?php echo \$childContent; ?> or <?= \$childContent ?><br><strong>$layoutPath</strong></div>";
|
|
804
|
+
modifyOutputLayoutForError($errorDetails);
|
|
767
805
|
}
|
|
768
806
|
}
|
|
769
807
|
} catch (Throwable $e) {
|
|
770
|
-
$content = ob_get_clean();
|
|
771
808
|
$errorDetails = "Unhandled Exception: " . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8');
|
|
772
809
|
$errorDetails .= "<br>File: " . htmlspecialchars($e->getFile(), ENT_QUOTES, 'UTF-8');
|
|
773
810
|
$errorDetails .= "<br>Line: " . htmlspecialchars($e->getLine(), ENT_QUOTES, 'UTF-8');
|
|
774
|
-
$
|
|
775
|
-
modifyOutputLayoutForError($
|
|
811
|
+
$errorDetails = "<div class='error'>$errorDetails</div>";
|
|
812
|
+
modifyOutputLayoutForError($errorDetails);
|
|
776
813
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{execSync}from"child_process";import fs from"fs";import{fileURLToPath}from"url";import path from"path";import chalk from"chalk";import prompts from"prompts";import https from"https";const __filename=fileURLToPath(import.meta.url),__dirname=path.dirname(__filename);let updateAnswer=null;const nonBackendFiles=["favicon.ico","\\src\\app\\index.php","metadata.php","not-found.php"],dockerFiles=[".dockerignore","docker-compose.yml","Dockerfile","apache.conf"];function bsConfigUrls(e){const s=e.indexOf("\\htdocs\\");if(-1===s)return{bsTarget:"",bsPathRewrite:{}};const n=e.substring(0,s+"\\htdocs\\".length).replace(/\\/g,"\\\\"),t=e.replace(new RegExp(`^${n}`),"").replace(/\\/g,"/");let i=`http://localhost/${t}`;i=i.endsWith("/")?i.slice(0,-1):i;const c=i.replace(/(?<!:)(\/\/+)/g,"/"),r=t.replace(/\/\/+/g,"/");return{bsTarget:`${c}/`,bsPathRewrite:{"^/":`/${r.startsWith("/")?r.substring(1):r}/`}}}function configureBrowserSyncCommand(e){const s=path.join(e,"settings","bs-config.cjs");return fs.writeFileSync(s,'const { createProxyMiddleware } = require("http-proxy-middleware");\nconst fs = require("fs");\n\nconst jsonData = fs.readFileSync("prisma-php.json", "utf8");\nconst config = JSON.parse(jsonData);\n\nmodule.exports = {\n proxy: "http://localhost:3000",\n middleware: [\n (req, res, next) => {\n res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");\n res.setHeader("Pragma", "no-cache");\n res.setHeader("Expires", "0");\n next();\n },\n createProxyMiddleware({\n target: config.bsTarget,\n changeOrigin: true,\n pathRewrite: config.bsPathRewrite,\n }),\n ],\n files: "src/**/*.*",\n notify: false,\n open: false,\n ghostMode: false,\n codeSync: true, // Disable synchronization of code changes across clients\n};',"utf8"),"browser-sync start --config settings/bs-config.cjs"}async function updatePackageJson(e,s){const n=path.join(e,"package.json");if(checkExcludeFiles(n))return;const t=JSON.parse(fs.readFileSync(n,"utf8")),i=configureBrowserSyncCommand(e);t.scripts=Object.assign(Object.assign({},t.scripts),{projectName:"node settings/project-name.cjs"});let c=[];s.tailwindcss&&(t.scripts=Object.assign(Object.assign({},t.scripts),{tailwind:"postcss ./src/app/css/tailwind.css -o ./src/app/css/styles.css --watch"}),c.push("tailwind")),s.websocket&&(t.scripts=Object.assign(Object.assign({},t.scripts),{websocket:"node ./settings/restart-websocket.cjs"}),c.push("websocket")),s.docker&&(t.scripts=Object.assign(Object.assign({},t.scripts),{docker:"docker-compose up"}),c.push("docker")),s.swaggerDocs&&(t.scripts=Object.assign(Object.assign({},t.scripts),{"create-swagger-docs":"node settings/swagger-setup.js"}),c.push("create-swagger-docs"));let r=Object.assign({},t.scripts);r.browserSync=i,r._dev=c.length>0?`npm-run-all -p ${c.join(" ")}`:'echo "No additional scripts to run"',r.startDev="node settings/start-dev.js",r.dev="npm run startDev",t.scripts=r,t.type="module",s.prisma&&(t.prisma={seed:"node prisma/seed.js"}),fs.writeFileSync(n,JSON.stringify(t,null,2))}async function updateComposerJson(e,s){const n=path.join(e,"composer.json");if(checkExcludeFiles(n))return;let t;if(fs.existsSync(n)){{const e=fs.readFileSync(n,"utf8");t=JSON.parse(e)}s.websocket&&(t.require=Object.assign(Object.assign({},t.require),{"cboden/ratchet":"^0.4.4"})),s.prisma&&(t.require=Object.assign(Object.assign({},t.require),{"ramsey/uuid":"5.x-dev","hidehalo/nanoid-php":"1.x-dev"})),fs.writeFileSync(n,JSON.stringify(t,null,2))}}async function updateIndexJsForWebSocket(e,s){if(!s.websocket)return;const n=path.join(e,"src","app","js","index.js");if(checkExcludeFiles(n))return;let t=fs.readFileSync(n,"utf8");t+='\n// WebSocket initialization\nconst ws = new WebSocket("ws://localhost:8080");\n',fs.writeFileSync(n,t,"utf8")}async function createUpdateGitignoreFile(e,s){const n=path.join(e,".gitignore");if(checkExcludeFiles(n))return;let t="";s.forEach((e=>{t.includes(e)||(t+=`\n${e}`)})),t=t.trimStart(),fs.writeFileSync(n,t)}function copyRecursiveSync(e,s,n){var t;const i=fs.existsSync(e),c=i&&fs.statSync(e);if(i&&c&&c.isDirectory()){const i=s.toLowerCase();if(!n.websocket&&i.includes("src\\lib\\websocket"))return;if(!n.prisma&&i.includes("src\\lib\\prisma"))return;if(n.backendOnly&&i.includes("src\\app\\js")||n.backendOnly&&i.includes("src\\app\\css"))return;if(!n.swaggerDocs&&i.includes("src\\app\\swagger-docs"))return;const c=s.replace(/\\/g,"/");if(null===(t=null==updateAnswer?void 0:updateAnswer.excludeFilePath)||void 0===t?void 0:t.includes(c))return;fs.existsSync(s)||fs.mkdirSync(s,{recursive:!0}),fs.readdirSync(e).forEach((t=>{copyRecursiveSync(path.join(e,t),path.join(s,t),n)}))}else{if(checkExcludeFiles(s))return;if(!n.tailwindcss&&(s.includes("tailwind.css")||s.includes("styles.css")))return;if(!n.websocket&&(s.includes("restart-websocket.cjs")||s.includes("restart-websocket.bat")))return;if(!n.docker&&dockerFiles.some((e=>s.includes(e))))return;if(n.backendOnly&&nonBackendFiles.some((e=>s.includes(e))))return;if(!n.backendOnly&&s.includes("route.php"))return;if(n.backendOnly&&!n.swaggerDocs&&(s.includes("start-dev.js")||s.includes("swagger-setup.js")))return;fs.copyFileSync(e,s,0)}}async function executeCopy(e,s,n){s.forEach((({srcDir:s,destDir:t})=>{copyRecursiveSync(path.join(__dirname,s),path.join(e,t),n)}))}function createOrUpdateTailwindConfig(e){const s=path.join(e,"tailwind.config.js");if(checkExcludeFiles(s))return;let n=fs.readFileSync(s,"utf8");const t=["./src/app/**/*.{html,js,php}"].map((e=>` "${e}"`)).join(",\n");n=n.replace(/content: \[\],/g,`content: [\n${t}\n],`),fs.writeFileSync(s,n,{flag:"w"})}function modifyPostcssConfig(e){const s=path.join(e,"postcss.config.js");if(checkExcludeFiles(s))return;fs.writeFileSync(s,"export default {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n cssnano: {},\n },\n};",{flag:"w"})}function modifyLayoutPHP(e,s){const n=path.join(e,"src","app","layout.php");if(!checkExcludeFiles(n))try{let e=fs.readFileSync(n,"utf8"),t="";s.backendOnly||(t='\n <link href="<?= $baseUrl; ?>/css/index.css" rel="stylesheet">\n <script src="<?= $baseUrl; ?>/js/index.js"><\/script>');let i="";s.backendOnly||(i=s.tailwindcss?` <link href="<?= $baseUrl; ?>/css/styles.css" rel="stylesheet"> ${t}`:` <script src="https://cdn.tailwindcss.com"><\/script> ${t}`);const c=i.length>0?"\n":"";e=e.replace("</head>",`${i}${c} \x3c!-- Dynamic Head --\x3e\n <?= implode("\\n", $mainLayoutHead); ?>\n</head>`),fs.writeFileSync(n,e,{flag:"w"})}catch(e){}}async function createOrUpdateEnvFile(e,s){const n=path.join(e,".env");checkExcludeFiles(n)||fs.writeFileSync(n,s,{flag:"w"})}function checkExcludeFiles(e){var s,n;return!!(null==updateAnswer?void 0:updateAnswer.isUpdate)&&(null!==(n=null===(s=null==updateAnswer?void 0:updateAnswer.excludeFilePath)||void 0===s?void 0:s.includes(e.replace(/\\/g,"/")))&&void 0!==n&&n)}async function createDirectoryStructure(e,s){const n=[{src:"/bootstrap.php",dest:"/bootstrap.php"},{src:"/.htaccess",dest:"/.htaccess"},{src:"/../composer.json",dest:"/composer.json"}];(null==updateAnswer?void 0:updateAnswer.isUpdate)&&(n.push({src:"/tsconfig.json",dest:"/tsconfig.json"}),updateAnswer.tailwindcss&&n.push({src:"/postcss.config.js",dest:"/postcss.config.js"},{src:"/tailwind.config.js",dest:"/tailwind.config.js"}));const t=[{srcDir:"/settings",destDir:"/settings"},{srcDir:"/src",destDir:"/src"}];s.backendOnly&&s.swaggerDocs&&t.push({srcDir:"/swagger-docs-layout.php",destDir:"/src/app/layout.php"}),s.prisma&&t.push({srcDir:"/prisma",destDir:"/prisma"}),s.docker&&t.push({srcDir:"/.dockerignore",destDir:"/.dockerignore"},{srcDir:"/docker-compose.yml",destDir:"/docker-compose.yml"},{srcDir:"/Dockerfile",destDir:"/Dockerfile"},{srcDir:"/apache.conf",destDir:"/apache.conf"}),n.forEach((({src:s,dest:n})=>{const t=path.join(__dirname,s),i=path.join(e,n);if(checkExcludeFiles(i))return;const c=fs.readFileSync(t,"utf8");fs.writeFileSync(i,c,{flag:"w"})})),await executeCopy(e,t,s),await updatePackageJson(e,s),await updateComposerJson(e,s),s.backendOnly||await updateIndexJsForWebSocket(e,s),s.tailwindcss&&(createOrUpdateTailwindConfig(e),modifyPostcssConfig(e)),(s.tailwindcss||!s.backendOnly||s.swaggerDocs)&&modifyLayoutPHP(e,s);const i='# Prisma PHP Auth Secret Key For development only - Change this in production\nAUTH_SECRET=uxsjXVPHN038DEYls2Kw0QUgBcXKUyrjv416nIFWPY4= \n \n# PHPMailer\n# SMTP_HOST=smtp.gmail.com or your SMTP host\n# SMTP_USERNAME=john.doe@gmail.com or your SMTP username\n# SMTP_PASSWORD=123456\n# SMTP_PORT=587 for TLS, 465 for SSL or your SMTP port\n# SMTP_ENCRYPTION=ssl or tls\n# MAIL_FROM=john.doe@gmail.com\n# MAIL_FROM_NAME="John Doe"\n\n# SHOW ERRORS - Set to true to show errors in the browser for development only - Change this in production to false\nSHOW_ERRORS=true\n\n# ChatGPT API Key\n# CHATGPT_API_KEY=sk-your-api-key\n\n# APP TIMEZONE - Set your application timezone - Default is "UTC"\nAPP_TIMEZONE="UTC"';if(s.prisma){const s=`${'# Environment variables declared in this file are automatically made available to Prisma.\n# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema\n\n# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.\n# See the documentation for all the connection string options: https://pris.ly/d/connection-strings\n\nDATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"'}\n\n${i}`;await createOrUpdateEnvFile(e,s)}else await createOrUpdateEnvFile(e,i);await createUpdateGitignoreFile(e,["vendor",".env","node_modules"])}async function getAnswer(e={}){var s,n,t,i,c,r,o,a,l,p,d,u,h;const g=[];e.projectName||g.push({type:"text",name:"projectName",message:"What is your project named?",initial:"my-app"}),e.backendOnly||g.push({type:"toggle",name:"backendOnly",message:"Would you like to create a backend-only project?",initial:!1,active:"Yes",inactive:"No"});const m=()=>{process.exit(0)},f=await prompts(g,{onCancel:m}),y=[];f.backendOnly||e.backendOnly?(e.swaggerDocs||y.push({type:"toggle",name:"swaggerDocs",message:`Would you like to use ${chalk.blue("Swagger Docs")}?`,initial:!1,active:"Yes",inactive:"No"}),e.websocket||y.push({type:"toggle",name:"websocket",message:`Would you like to use ${chalk.blue("Websocket")}?`,initial:!0,active:"Yes",inactive:"No"}),e.prisma||y.push({type:"toggle",name:"prisma",message:`Would you like to use ${chalk.blue("Prisma PHP ORM")}?`,initial:!0,active:"Yes",inactive:"No"}),e.docker||y.push({type:"toggle",name:"docker",message:`Would you like to use ${chalk.blue("Docker")}?`,initial:!1,active:"Yes",inactive:"No"})):(e.swaggerDocs||y.push({type:"toggle",name:"swaggerDocs",message:`Would you like to use ${chalk.blue("Swagger Docs")}?`,initial:!1,active:"Yes",inactive:"No"}),e.tailwindcss||y.push({type:"toggle",name:"tailwindcss",message:`Would you like to use ${chalk.blue("Tailwind CSS")}?`,initial:!0,active:"Yes",inactive:"No"}),e.websocket||y.push({type:"toggle",name:"websocket",message:`Would you like to use ${chalk.blue("Websocket")}?`,initial:!0,active:"Yes",inactive:"No"}),e.prisma||y.push({type:"toggle",name:"prisma",message:`Would you like to use ${chalk.blue("Prisma PHP ORM")}?`,initial:!0,active:"Yes",inactive:"No"}),e.docker||y.push({type:"toggle",name:"docker",message:`Would you like to use ${chalk.blue("Docker")}?`,initial:!1,active:"Yes",inactive:"No"}));const w=await prompts(y,{onCancel:m});return{projectName:f.projectName?String(f.projectName).trim().replace(/ /g,"-"):null!==(s=e.projectName)&&void 0!==s?s:"my-app",backendOnly:null!==(t=null!==(n=f.backendOnly)&&void 0!==n?n:e.backendOnly)&&void 0!==t&&t,swaggerDocs:null!==(c=null!==(i=w.swaggerDocs)&&void 0!==i?i:e.swaggerDocs)&&void 0!==c&&c,tailwindcss:null!==(o=null!==(r=w.tailwindcss)&&void 0!==r?r:e.tailwindcss)&&void 0!==o&&o,websocket:null!==(l=null!==(a=w.websocket)&&void 0!==a?a:e.websocket)&&void 0!==l&&l,prisma:null!==(d=null!==(p=w.prisma)&&void 0!==p?p:e.prisma)&&void 0!==d&&d,docker:null!==(h=null!==(u=w.docker)&&void 0!==u?u:e.docker)&&void 0!==h&&h}}async function installDependencies(e,s,n=!1){fs.existsSync(path.join(e,"package.json"))||execSync("npm init -y",{stdio:"inherit",cwd:e}),s.forEach((e=>{}));const t=`npm install ${n?"--save-dev":""} ${s.join(" ")}`;execSync(t,{stdio:"inherit",cwd:e})}async function uninstallDependencies(e,s,n=!1){s.forEach((e=>{}));const t=`npm uninstall ${n?"--save-dev":"--save"} ${s.join(" ")}`;execSync(t,{stdio:"inherit",cwd:e})}function fetchPackageVersion(e){return new Promise(((s,n)=>{https.get(`https://registry.npmjs.org/${e}`,(e=>{let t="";e.on("data",(e=>t+=e)),e.on("end",(()=>{try{const e=JSON.parse(t);s(e["dist-tags"].latest)}catch(e){n(new Error("Failed to parse JSON response"))}}))})).on("error",(e=>n(e)))}))}const readJsonFile=e=>{const s=fs.readFileSync(e,"utf8");return JSON.parse(s)};function compareVersions(e,s){const n=e.split(".").map(Number),t=s.split(".").map(Number);for(let e=0;e<n.length;e++){if(n[e]>t[e])return 1;if(n[e]<t[e])return-1}return 0}function getInstalledPackageVersion(e){try{const s=execSync(`npm list -g ${e} --depth=0`).toString().match(new RegExp(`${e}@(\\d+\\.\\d+\\.\\d+)`));return s?s[1]:null}catch(e){return null}}async function main(){var e,s,n,t,i,c,r,o,a;try{const l=process.argv.slice(2);let p=l[0],d=null;if(p){const a={projectName:p,backendOnly:l.includes("--backend-only"),swaggerDocs:l.includes("--swagger-docs"),tailwindcss:l.includes("--tailwindcss"),websocket:l.includes("--websocket"),prisma:l.includes("--prisma"),docker:l.includes("--docker")};if(d=await getAnswer(a),null===d)return;const u=process.cwd(),h=path.join(u,"prisma-php.json"),g=readJsonFile(h);let m=[];null===(e=g.excludeFiles)||void 0===e||e.map((e=>{const s=path.join(u,e);fs.existsSync(s)&&m.push(s.replace(/\\/g,"/"))})),updateAnswer={projectName:p,backendOnly:null!==(s=null==d?void 0:d.backendOnly)&&void 0!==s&&s,swaggerDocs:null!==(n=null==d?void 0:d.swaggerDocs)&&void 0!==n&&n,tailwindcss:null!==(t=null==d?void 0:d.tailwindcss)&&void 0!==t&&t,websocket:null!==(i=null==d?void 0:d.websocket)&&void 0!==i&&i,prisma:null!==(c=null==d?void 0:d.prisma)&&void 0!==c&&c,docker:null!==(r=null==d?void 0:d.docker)&&void 0!==r&&r,isUpdate:!0,excludeFiles:null!==(o=g.excludeFiles)&&void 0!==o?o:[],excludeFilePath:null!=m?m:[],filePath:u}}else d=await getAnswer();if(null===d)return;const u=await fetchPackageVersion("create-prisma-php-app"),h=getInstalledPackageVersion("create-prisma-php-app");h?-1===compareVersions(h,u)&&(execSync("npm uninstall -g create-prisma-php-app",{stdio:"inherit"}),execSync("npm install -g create-prisma-php-app",{stdio:"inherit"})):execSync("npm install -g create-prisma-php-app",{stdio:"inherit"});const g=await fetchPackageVersion("browser-sync"),m=getInstalledPackageVersion("browser-sync");m?-1===compareVersions(m,g)&&(execSync("npm uninstall -g browser-sync",{stdio:"inherit"}),execSync("npm install -g browser-sync",{stdio:"inherit"})):execSync("npm install -g browser-sync",{stdio:"inherit"}),p||fs.mkdirSync(d.projectName);const f=process.cwd();let y=p?f:path.join(f,d.projectName);p||process.chdir(d.projectName);const w=["typescript","@types/node","ts-node","http-proxy-middleware@^3.0.0","chalk","npm-run-all"];d.swaggerDocs&&w.push("swagger-jsdoc"),d.tailwindcss&&w.push("tailwindcss","autoprefixer","postcss","postcss-cli","cssnano"),d.websocket&&w.push("chokidar-cli"),d.prisma&&w.push("prisma","@prisma/client"),await installDependencies(y,w,!0),p||execSync("npx tsc --init",{stdio:"inherit"}),d.tailwindcss&&execSync("npx tailwindcss init -p",{stdio:"inherit"}),d.prisma&&(fs.existsSync(path.join(y,"prisma"))||execSync("npx prisma init",{stdio:"inherit"})),await createDirectoryStructure(y,d);const k=path.join(y,"public");if(fs.existsSync(k)||fs.mkdirSync(k),d.swaggerDocs){const e=path.join(y,"src","app","swagger-docs");fs.existsSync(e)||fs.mkdirSync(e,{recursive:!0}),execSync(`git clone https://github.com/TheSteelNinjaCode/prisma-php-swagger-docs.git ${e}`,{stdio:"inherit"})}if(null==updateAnswer?void 0:updateAnswer.isUpdate){const e=[];if(updateAnswer.backendOnly){nonBackendFiles.forEach((e=>{const s=path.join(y,"src","app",e);fs.existsSync(s)&&fs.unlinkSync(s)}));["js","css"].forEach((e=>{const s=path.join(y,"src","app",e);fs.existsSync(s)&&fs.rmSync(s,{recursive:!0,force:!0})}))}if(!updateAnswer.swaggerDocs){const s=path.join(y,"src","app","swagger-docs");fs.existsSync(s)&&fs.rmSync(s,{recursive:!0,force:!0}),e.push("swagger-jsdoc")}if(!updateAnswer.tailwindcss){["postcss.config.js","tailwind.config.js"].forEach((e=>{const s=path.join(y,e);fs.existsSync(s)&&fs.unlinkSync(s)})),e.push("tailwindcss","autoprefixer","postcss","postcss-cli","cssnano")}if(updateAnswer.websocket||e.push("chokidar-cli"),updateAnswer.prisma||e.push("prisma","@prisma/client"),!updateAnswer.docker){[".dockerignore","docker-compose.yml","Dockerfile","apache.conf"].forEach((e=>{const s=path.join(y,e);fs.existsSync(s)&&fs.unlinkSync(s)}))}e.length>0&&await uninstallDependencies(y,e,!0)}const b=y.replace(/\\/g,"\\"),S=bsConfigUrls(b),j=d.prisma?"src/Lib/Prisma/Classes":"",v={projectName:d.projectName,projectRootPath:b,phpEnvironment:"XAMPP",phpRootPathExe:"C:\\xampp\\php\\php.exe",phpGenerateClassPath:j,bsTarget:S.bsTarget,bsPathRewrite:S.bsPathRewrite,backendOnly:d.backendOnly,swaggerDocs:d.swaggerDocs,tailwindcss:d.tailwindcss,websocket:d.websocket,prisma:d.prisma,docker:d.docker,version:u,excludeFiles:null!==(a=null==updateAnswer?void 0:updateAnswer.excludeFiles)&&void 0!==a?a:[]};fs.writeFileSync(path.join(y,"prisma-php.json"),JSON.stringify(v,null,2),{flag:"w"}),(null==updateAnswer?void 0:updateAnswer.isUpdate)?execSync("C:\\xampp\\php\\php.exe C:\\ProgramData\\ComposerSetup\\bin\\composer.phar update",{stdio:"inherit"}):execSync("C:\\xampp\\php\\php.exe C:\\ProgramData\\ComposerSetup\\bin\\composer.phar install",{stdio:"inherit"})}catch(e){process.exit(1)}}main();
|
|
2
|
+
import{execSync}from"child_process";import fs from"fs";import{fileURLToPath}from"url";import path from"path";import chalk from"chalk";import prompts from"prompts";import https from"https";const __filename=fileURLToPath(import.meta.url),__dirname=path.dirname(__filename);let updateAnswer=null;const nonBackendFiles=["favicon.ico","\\src\\app\\index.php","metadata.php","not-found.php"],dockerFiles=[".dockerignore","docker-compose.yml","Dockerfile","apache.conf"];function bsConfigUrls(e){const s=e.indexOf("\\htdocs\\");if(-1===s)return{bsTarget:"",bsPathRewrite:{}};const n=e.substring(0,s+"\\htdocs\\".length).replace(/\\/g,"\\\\"),t=e.replace(new RegExp(`^${n}`),"").replace(/\\/g,"/");let i=`http://localhost/${t}`;i=i.endsWith("/")?i.slice(0,-1):i;const c=i.replace(/(?<!:)(\/\/+)/g,"/"),o=t.replace(/\/\/+/g,"/");return{bsTarget:`${c}/`,bsPathRewrite:{"^/":`/${o.startsWith("/")?o.substring(1):o}/`}}}function configureBrowserSyncCommand(e){const s=path.join(e,"settings","bs-config.cjs");return fs.writeFileSync(s,'const { createProxyMiddleware } = require("http-proxy-middleware");\nconst fs = require("fs");\nconst chokidar = require("chokidar");\nconst { execSync } = require("child_process");\n\nconst jsonData = fs.readFileSync("prisma-php.json", "utf8");\nconst config = JSON.parse(jsonData);\n\n// Watch for file changes (create, delete, save)\nconst watcher = chokidar.watch("src/**/*", {\n ignored: /(^|[\\/\\\\])\\../,\n persistent: true,\n usePolling: true,\n interval: 1000,\n});\n\nwatcher\n .on("add", async (path) => {\n execSync("node settings/files-list-config.js");\n })\n .on("change", async (path) => {\n execSync("node settings/files-list-config.js");\n })\n .on("unlink", async (path) => {\n execSync("node settings/files-list-config.js");\n });\n\nmodule.exports = {\n proxy: "http://localhost:3000",\n middleware: [\n (req, res, next) => {\n res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");\n res.setHeader("Pragma", "no-cache");\n res.setHeader("Expires", "0");\n next();\n },\n createProxyMiddleware({\n target: config.bsTarget,\n changeOrigin: true,\n pathRewrite: config.bsPathRewrite,\n }),\n ],\n files: "src/**/*.*",\n notify: false,\n open: false,\n ghostMode: false,\n codeSync: true, // Disable synchronization of code changes across clients\n watchOptions: {\n usePolling: true,\n interval: 1000,\n },\n};',"utf8"),"browser-sync start --config settings/bs-config.cjs"}async function updatePackageJson(e,s){const n=path.join(e,"package.json");if(checkExcludeFiles(n))return;const t=JSON.parse(fs.readFileSync(n,"utf8")),i=configureBrowserSyncCommand(e);t.scripts=Object.assign(Object.assign({},t.scripts),{projectName:"node settings/project-name.cjs"});let c=[];s.tailwindcss&&(t.scripts=Object.assign(Object.assign({},t.scripts),{tailwind:"postcss ./src/app/css/tailwind.css -o ./src/app/css/styles.css --watch"}),c.push("tailwind")),s.websocket&&(t.scripts=Object.assign(Object.assign({},t.scripts),{websocket:"node ./settings/restart-websocket.cjs"}),c.push("websocket")),s.docker&&(t.scripts=Object.assign(Object.assign({},t.scripts),{docker:"docker-compose up"}),c.push("docker")),s.swaggerDocs&&(t.scripts=Object.assign(Object.assign({},t.scripts),{"create-swagger-docs":"node settings/swagger-setup.js"}),c.push("create-swagger-docs"));let o=Object.assign({},t.scripts);o.browserSync=i,o.npmRunAll=c.length>0?`npm-run-all -p ${c.join(" ")}`:'echo "No additional scripts to run"',o.dev="node settings/start-dev.js",t.scripts=o,t.type="module",s.prisma&&(t.prisma={seed:"node prisma/seed.js"}),fs.writeFileSync(n,JSON.stringify(t,null,2))}async function updateComposerJson(e,s){const n=path.join(e,"composer.json");if(checkExcludeFiles(n))return;let t;if(fs.existsSync(n)){{const e=fs.readFileSync(n,"utf8");t=JSON.parse(e)}s.websocket&&(t.require=Object.assign(Object.assign({},t.require),{"cboden/ratchet":"^0.4.4"})),s.prisma&&(t.require=Object.assign(Object.assign({},t.require),{"ramsey/uuid":"5.x-dev","hidehalo/nanoid-php":"1.x-dev"})),fs.writeFileSync(n,JSON.stringify(t,null,2))}}async function updateIndexJsForWebSocket(e,s){if(!s.websocket)return;const n=path.join(e,"src","app","js","index.js");if(checkExcludeFiles(n))return;let t=fs.readFileSync(n,"utf8");t+='\n// WebSocket initialization\nconst ws = new WebSocket("ws://localhost:8080");\n',fs.writeFileSync(n,t,"utf8")}async function createUpdateGitignoreFile(e,s){const n=path.join(e,".gitignore");if(checkExcludeFiles(n))return;let t="";s.forEach((e=>{t.includes(e)||(t+=`\n${e}`)})),t=t.trimStart(),fs.writeFileSync(n,t)}function copyRecursiveSync(e,s,n){var t;const i=fs.existsSync(e),c=i&&fs.statSync(e);if(i&&c&&c.isDirectory()){const i=s.toLowerCase();if(!n.websocket&&i.includes("src\\lib\\websocket"))return;if(!n.prisma&&i.includes("src\\lib\\prisma"))return;if(n.backendOnly&&i.includes("src\\app\\js")||n.backendOnly&&i.includes("src\\app\\css"))return;if(!n.swaggerDocs&&i.includes("src\\app\\swagger-docs"))return;const c=s.replace(/\\/g,"/");if(null===(t=null==updateAnswer?void 0:updateAnswer.excludeFilePath)||void 0===t?void 0:t.includes(c))return;fs.existsSync(s)||fs.mkdirSync(s,{recursive:!0}),fs.readdirSync(e).forEach((t=>{copyRecursiveSync(path.join(e,t),path.join(s,t),n)}))}else{if(checkExcludeFiles(s))return;if(!n.tailwindcss&&(s.includes("tailwind.css")||s.includes("styles.css")))return;if(!n.websocket&&(s.includes("restart-websocket.cjs")||s.includes("restart-websocket.bat")))return;if(!n.docker&&dockerFiles.some((e=>s.includes(e))))return;if(n.backendOnly&&nonBackendFiles.some((e=>s.includes(e))))return;if(!n.backendOnly&&s.includes("route.php"))return;if(!n.swaggerDocs&&s.includes("swagger-setup.js"))return;fs.copyFileSync(e,s,0)}}async function executeCopy(e,s,n){s.forEach((({srcDir:s,destDir:t})=>{copyRecursiveSync(path.join(__dirname,s),path.join(e,t),n)}))}function createOrUpdateTailwindConfig(e){const s=path.join(e,"tailwind.config.js");if(checkExcludeFiles(s))return;let n=fs.readFileSync(s,"utf8");const t=["./src/**/*.{html,js,php}"].map((e=>` "${e}"`)).join(",\n");n=n.replace(/content: \[\],/g,`content: [\n${t}\n],`),fs.writeFileSync(s,n,{flag:"w"})}function modifyPostcssConfig(e){const s=path.join(e,"postcss.config.js");if(checkExcludeFiles(s))return;fs.writeFileSync(s,"export default {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n cssnano: {},\n },\n};",{flag:"w"})}function modifyLayoutPHP(e,s){const n=path.join(e,"src","app","layout.php");if(!checkExcludeFiles(n))try{let e=fs.readFileSync(n,"utf8"),t="";s.backendOnly||(t='\n <link href="<?= $baseUrl; ?>/css/index.css" rel="stylesheet">\n <script src="<?= $baseUrl; ?>/js/index.js"><\/script>');let i="";s.backendOnly||(i=s.tailwindcss?` <link href="<?= $baseUrl; ?>/css/styles.css" rel="stylesheet"> ${t}`:` <script src="https://cdn.tailwindcss.com"><\/script> ${t}`);const c=i.length>0?"\n":"";e=e.replace("</head>",`${i}${c} \x3c!-- Dynamic Head --\x3e\n <?= implode("\\n", $mainLayoutHead); ?>\n</head>`),fs.writeFileSync(n,e,{flag:"w"})}catch(e){}}async function createOrUpdateEnvFile(e,s){const n=path.join(e,".env");checkExcludeFiles(n)||fs.writeFileSync(n,s,{flag:"w"})}function checkExcludeFiles(e){var s,n;return!!(null==updateAnswer?void 0:updateAnswer.isUpdate)&&(null!==(n=null===(s=null==updateAnswer?void 0:updateAnswer.excludeFilePath)||void 0===s?void 0:s.includes(e.replace(/\\/g,"/")))&&void 0!==n&&n)}async function createDirectoryStructure(e,s){const n=[{src:"/bootstrap.php",dest:"/bootstrap.php"},{src:"/.htaccess",dest:"/.htaccess"},{src:"/../composer.json",dest:"/composer.json"}];(null==updateAnswer?void 0:updateAnswer.isUpdate)&&(n.push({src:"/tsconfig.json",dest:"/tsconfig.json"}),updateAnswer.tailwindcss&&n.push({src:"/postcss.config.js",dest:"/postcss.config.js"},{src:"/tailwind.config.js",dest:"/tailwind.config.js"}));const t=[{srcDir:"/settings",destDir:"/settings"},{srcDir:"/src",destDir:"/src"}];s.backendOnly&&s.swaggerDocs&&t.push({srcDir:"/swagger-docs-layout.php",destDir:"/src/app/layout.php"}),s.prisma&&t.push({srcDir:"/prisma",destDir:"/prisma"}),s.docker&&t.push({srcDir:"/.dockerignore",destDir:"/.dockerignore"},{srcDir:"/docker-compose.yml",destDir:"/docker-compose.yml"},{srcDir:"/Dockerfile",destDir:"/Dockerfile"},{srcDir:"/apache.conf",destDir:"/apache.conf"}),n.forEach((({src:s,dest:n})=>{const t=path.join(__dirname,s),i=path.join(e,n);if(checkExcludeFiles(i))return;const c=fs.readFileSync(t,"utf8");fs.writeFileSync(i,c,{flag:"w"})})),await executeCopy(e,t,s),await updatePackageJson(e,s),await updateComposerJson(e,s),s.backendOnly||await updateIndexJsForWebSocket(e,s),s.tailwindcss&&(createOrUpdateTailwindConfig(e),modifyPostcssConfig(e)),(s.tailwindcss||!s.backendOnly||s.swaggerDocs)&&modifyLayoutPHP(e,s);const i='# Prisma PHP Auth Secret Key For development only - Change this in production\nAUTH_SECRET=uxsjXVPHN038DEYls2Kw0QUgBcXKUyrjv416nIFWPY4= \n \n# PHPMailer\n# SMTP_HOST=smtp.gmail.com or your SMTP host\n# SMTP_USERNAME=john.doe@gmail.com or your SMTP username\n# SMTP_PASSWORD=123456\n# SMTP_PORT=587 for TLS, 465 for SSL or your SMTP port\n# SMTP_ENCRYPTION=ssl or tls\n# MAIL_FROM=john.doe@gmail.com\n# MAIL_FROM_NAME="John Doe"\n\n# SHOW ERRORS - Set to true to show errors in the browser for development only - Change this in production to false\nSHOW_ERRORS=true\n\n# ChatGPT API Key\n# CHATGPT_API_KEY=sk-your-api-key\n\n# APP TIMEZONE - Set your application timezone - Default is "UTC"\nAPP_TIMEZONE="UTC"\n\n# APP ENV - Set your application environment - Default is "development" - Change this in production to "production"\nAPP_ENV=development';if(s.prisma){const s=`${'# Environment variables declared in this file are automatically made available to Prisma.\n# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema\n\n# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.\n# See the documentation for all the connection string options: https://pris.ly/d/connection-strings\n\nDATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"'}\n\n${i}`;await createOrUpdateEnvFile(e,s)}else await createOrUpdateEnvFile(e,i);await createUpdateGitignoreFile(e,["vendor",".env","node_modules"])}async function getAnswer(e={}){var s,n,t,i,c,o,r,a,l,p,d,u,h;const g=[];e.projectName||g.push({type:"text",name:"projectName",message:"What is your project named?",initial:"my-app"}),e.backendOnly||g.push({type:"toggle",name:"backendOnly",message:"Would you like to create a backend-only project?",initial:!1,active:"Yes",inactive:"No"});const m=()=>{process.exit(0)},f=await prompts(g,{onCancel:m}),y=[];f.backendOnly||e.backendOnly?(e.swaggerDocs||y.push({type:"toggle",name:"swaggerDocs",message:`Would you like to use ${chalk.blue("Swagger Docs")}?`,initial:!1,active:"Yes",inactive:"No"}),e.websocket||y.push({type:"toggle",name:"websocket",message:`Would you like to use ${chalk.blue("Websocket")}?`,initial:!0,active:"Yes",inactive:"No"}),e.prisma||y.push({type:"toggle",name:"prisma",message:`Would you like to use ${chalk.blue("Prisma PHP ORM")}?`,initial:!0,active:"Yes",inactive:"No"}),e.docker||y.push({type:"toggle",name:"docker",message:`Would you like to use ${chalk.blue("Docker")}?`,initial:!1,active:"Yes",inactive:"No"})):(e.swaggerDocs||y.push({type:"toggle",name:"swaggerDocs",message:`Would you like to use ${chalk.blue("Swagger Docs")}?`,initial:!1,active:"Yes",inactive:"No"}),e.tailwindcss||y.push({type:"toggle",name:"tailwindcss",message:`Would you like to use ${chalk.blue("Tailwind CSS")}?`,initial:!0,active:"Yes",inactive:"No"}),e.websocket||y.push({type:"toggle",name:"websocket",message:`Would you like to use ${chalk.blue("Websocket")}?`,initial:!0,active:"Yes",inactive:"No"}),e.prisma||y.push({type:"toggle",name:"prisma",message:`Would you like to use ${chalk.blue("Prisma PHP ORM")}?`,initial:!0,active:"Yes",inactive:"No"}),e.docker||y.push({type:"toggle",name:"docker",message:`Would you like to use ${chalk.blue("Docker")}?`,initial:!1,active:"Yes",inactive:"No"}));const w=await prompts(y,{onCancel:m});return{projectName:f.projectName?String(f.projectName).trim().replace(/ /g,"-"):null!==(s=e.projectName)&&void 0!==s?s:"my-app",backendOnly:null!==(t=null!==(n=f.backendOnly)&&void 0!==n?n:e.backendOnly)&&void 0!==t&&t,swaggerDocs:null!==(c=null!==(i=w.swaggerDocs)&&void 0!==i?i:e.swaggerDocs)&&void 0!==c&&c,tailwindcss:null!==(r=null!==(o=w.tailwindcss)&&void 0!==o?o:e.tailwindcss)&&void 0!==r&&r,websocket:null!==(l=null!==(a=w.websocket)&&void 0!==a?a:e.websocket)&&void 0!==l&&l,prisma:null!==(d=null!==(p=w.prisma)&&void 0!==p?p:e.prisma)&&void 0!==d&&d,docker:null!==(h=null!==(u=w.docker)&&void 0!==u?u:e.docker)&&void 0!==h&&h}}async function installDependencies(e,s,n=!1){fs.existsSync(path.join(e,"package.json"))||execSync("npm init -y",{stdio:"inherit",cwd:e}),s.forEach((e=>{}));const t=`npm install ${n?"--save-dev":""} ${s.join(" ")}`;execSync(t,{stdio:"inherit",cwd:e})}async function uninstallDependencies(e,s,n=!1){s.forEach((e=>{}));const t=`npm uninstall ${n?"--save-dev":"--save"} ${s.join(" ")}`;execSync(t,{stdio:"inherit",cwd:e})}function fetchPackageVersion(e){return new Promise(((s,n)=>{https.get(`https://registry.npmjs.org/${e}`,(e=>{let t="";e.on("data",(e=>t+=e)),e.on("end",(()=>{try{const e=JSON.parse(t);s(e["dist-tags"].latest)}catch(e){n(new Error("Failed to parse JSON response"))}}))})).on("error",(e=>n(e)))}))}const readJsonFile=e=>{const s=fs.readFileSync(e,"utf8");return JSON.parse(s)};function compareVersions(e,s){const n=e.split(".").map(Number),t=s.split(".").map(Number);for(let e=0;e<n.length;e++){if(n[e]>t[e])return 1;if(n[e]<t[e])return-1}return 0}function getInstalledPackageVersion(e){try{const s=execSync(`npm list -g ${e} --depth=0`).toString().match(new RegExp(`${e}@(\\d+\\.\\d+\\.\\d+)`));return s?s[1]:null}catch(e){return null}}async function main(){var e,s,n,t,i,c,o,r,a;try{const l=process.argv.slice(2);let p=l[0],d=null;if(p){const a={projectName:p,backendOnly:l.includes("--backend-only"),swaggerDocs:l.includes("--swagger-docs"),tailwindcss:l.includes("--tailwindcss"),websocket:l.includes("--websocket"),prisma:l.includes("--prisma"),docker:l.includes("--docker")};if(d=await getAnswer(a),null===d)return;const u=process.cwd(),h=path.join(u,"prisma-php.json"),g=readJsonFile(h);let m=[];null===(e=g.excludeFiles)||void 0===e||e.map((e=>{const s=path.join(u,e);fs.existsSync(s)&&m.push(s.replace(/\\/g,"/"))})),updateAnswer={projectName:p,backendOnly:null!==(s=null==d?void 0:d.backendOnly)&&void 0!==s&&s,swaggerDocs:null!==(n=null==d?void 0:d.swaggerDocs)&&void 0!==n&&n,tailwindcss:null!==(t=null==d?void 0:d.tailwindcss)&&void 0!==t&&t,websocket:null!==(i=null==d?void 0:d.websocket)&&void 0!==i&&i,prisma:null!==(c=null==d?void 0:d.prisma)&&void 0!==c&&c,docker:null!==(o=null==d?void 0:d.docker)&&void 0!==o&&o,isUpdate:!0,excludeFiles:null!==(r=g.excludeFiles)&&void 0!==r?r:[],excludeFilePath:null!=m?m:[],filePath:u}}else d=await getAnswer();if(null===d)return;const u=await fetchPackageVersion("create-prisma-php-app"),h=getInstalledPackageVersion("create-prisma-php-app");h?-1===compareVersions(h,u)&&(execSync("npm uninstall -g create-prisma-php-app",{stdio:"inherit"}),execSync("npm install -g create-prisma-php-app",{stdio:"inherit"})):execSync("npm install -g create-prisma-php-app",{stdio:"inherit"});const g=await fetchPackageVersion("browser-sync"),m=getInstalledPackageVersion("browser-sync");m?-1===compareVersions(m,g)&&(execSync("npm uninstall -g browser-sync",{stdio:"inherit"}),execSync("npm install -g browser-sync",{stdio:"inherit"})):execSync("npm install -g browser-sync",{stdio:"inherit"}),p||fs.mkdirSync(d.projectName);const f=process.cwd();let y=p?f:path.join(f,d.projectName);p||process.chdir(d.projectName);const w=["typescript","@types/node","ts-node","http-proxy-middleware@^3.0.0","chalk","npm-run-all"];d.swaggerDocs&&w.push("swagger-jsdoc"),d.tailwindcss&&w.push("tailwindcss","autoprefixer","postcss","postcss-cli","cssnano"),d.websocket&&w.push("chokidar-cli"),d.prisma&&w.push("prisma","@prisma/client"),await installDependencies(y,w,!0),p||execSync("npx tsc --init",{stdio:"inherit"}),d.tailwindcss&&execSync("npx tailwindcss init -p",{stdio:"inherit"}),d.prisma&&(fs.existsSync(path.join(y,"prisma"))||execSync("npx prisma init",{stdio:"inherit"})),await createDirectoryStructure(y,d);const k=path.join(y,"public");if(fs.existsSync(k)||fs.mkdirSync(k),d.swaggerDocs){const e=path.join(y,"src","app","swagger-docs");fs.existsSync(e)||fs.mkdirSync(e,{recursive:!0}),execSync(`git clone https://github.com/TheSteelNinjaCode/prisma-php-swagger-docs.git ${e}`,{stdio:"inherit"})}if(null==updateAnswer?void 0:updateAnswer.isUpdate){const e=[];if(updateAnswer.backendOnly){nonBackendFiles.forEach((e=>{const s=path.join(y,"src","app",e);fs.existsSync(s)&&fs.unlinkSync(s)}));["js","css"].forEach((e=>{const s=path.join(y,"src","app",e);fs.existsSync(s)&&fs.rmSync(s,{recursive:!0,force:!0})}))}if(!updateAnswer.swaggerDocs){const s=path.join(y,"src","app","swagger-docs");fs.existsSync(s)&&fs.rmSync(s,{recursive:!0,force:!0});["swagger-setup.js"].forEach((e=>{const s=path.join(y,"settings",e);fs.existsSync(s)&&fs.unlinkSync(s)})),e.push("swagger-jsdoc")}if(!updateAnswer.tailwindcss){["postcss.config.js","tailwind.config.js"].forEach((e=>{const s=path.join(y,e);fs.existsSync(s)&&fs.unlinkSync(s)})),e.push("tailwindcss","autoprefixer","postcss","postcss-cli","cssnano")}if(updateAnswer.websocket||e.push("chokidar-cli"),updateAnswer.prisma||e.push("prisma","@prisma/client"),!updateAnswer.docker){[".dockerignore","docker-compose.yml","Dockerfile","apache.conf"].forEach((e=>{const s=path.join(y,e);fs.existsSync(s)&&fs.unlinkSync(s)}))}e.length>0&&await uninstallDependencies(y,e,!0)}const S=y.replace(/\\/g,"\\"),b=bsConfigUrls(S),j=d.prisma?"src/Lib/Prisma/Classes":"",v={projectName:d.projectName,projectRootPath:S,phpEnvironment:"XAMPP",phpRootPathExe:"C:\\xampp\\php\\php.exe",phpGenerateClassPath:j,bsTarget:b.bsTarget,bsPathRewrite:b.bsPathRewrite,backendOnly:d.backendOnly,swaggerDocs:d.swaggerDocs,tailwindcss:d.tailwindcss,websocket:d.websocket,prisma:d.prisma,docker:d.docker,version:u,excludeFiles:null!==(a=null==updateAnswer?void 0:updateAnswer.excludeFiles)&&void 0!==a?a:[]};fs.writeFileSync(path.join(y,"prisma-php.json"),JSON.stringify(v,null,2),{flag:"w"}),(null==updateAnswer?void 0:updateAnswer.isUpdate)?execSync("C:\\xampp\\php\\php.exe C:\\ProgramData\\ComposerSetup\\bin\\composer.phar update",{stdio:"inherit"}):execSync("C:\\xampp\\php\\php.exe C:\\ProgramData\\ComposerSetup\\bin\\composer.phar install",{stdio:"inherit"})}catch(e){process.exit(1)}}main();
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { readdirSync, statSync, existsSync, writeFileSync } from "fs";
|
|
2
|
+
import path, { dirname } from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
|
|
5
|
+
// Define __dirname equivalent in ES modules
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = dirname(__filename);
|
|
8
|
+
|
|
9
|
+
const dirPath = path.join(__dirname, "..", "src", "app");
|
|
10
|
+
const jsonFilePath = path.join(__dirname, "files-list.json");
|
|
11
|
+
|
|
12
|
+
// Function to get all files in the directory
|
|
13
|
+
const getAllFiles = (dirPath) => {
|
|
14
|
+
const files = [];
|
|
15
|
+
|
|
16
|
+
// Check if directory exists before reading
|
|
17
|
+
if (!existsSync(dirPath)) {
|
|
18
|
+
console.error(`Directory not found: ${dirPath}`);
|
|
19
|
+
return files; // Return an empty array if the directory doesn't exist
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const items = readdirSync(dirPath);
|
|
23
|
+
items.forEach((item) => {
|
|
24
|
+
const fullPath = path.join(dirPath, item);
|
|
25
|
+
if (statSync(fullPath).isDirectory()) {
|
|
26
|
+
files.push(...getAllFiles(fullPath)); // Recursive call for subdirectories
|
|
27
|
+
} else {
|
|
28
|
+
// Generate the relative path and ensure it starts with ./src
|
|
29
|
+
const relativePath = `.${path.sep}${path.relative(
|
|
30
|
+
path.join(__dirname, ".."),
|
|
31
|
+
fullPath
|
|
32
|
+
)}`;
|
|
33
|
+
// Replace only the root backslashes with forward slashes and leave inner ones
|
|
34
|
+
files.push(relativePath.replace(/\\/g, "\\").replace(/^\.\.\//, ""));
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return files;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Function to generate the files-list.json
|
|
42
|
+
const generateFileListJson = () => {
|
|
43
|
+
const files = getAllFiles(dirPath);
|
|
44
|
+
|
|
45
|
+
// If files exist, generate JSON file
|
|
46
|
+
if (files.length > 0) {
|
|
47
|
+
writeFileSync(jsonFilePath, JSON.stringify(files, null, 2));
|
|
48
|
+
console.log(
|
|
49
|
+
`File list has been saved to: settings/files-list.json`
|
|
50
|
+
);
|
|
51
|
+
} else {
|
|
52
|
+
console.error("No files found to save in the JSON file.");
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Main function
|
|
57
|
+
async function processDirectory() {
|
|
58
|
+
generateFileListJson();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
processDirectory();
|
|
@@ -126,7 +126,7 @@ async function startDev() {
|
|
|
126
126
|
|
|
127
127
|
if (!browserSyncReady) {
|
|
128
128
|
browserSyncReady = true;
|
|
129
|
-
// Start
|
|
129
|
+
// Start npmRunAll after browserSync is ready
|
|
130
130
|
startDevProcess();
|
|
131
131
|
}
|
|
132
132
|
} else if (REGEX_PATTERNS.BROWSERSYNC.test(line)) {
|
|
@@ -148,10 +148,10 @@ async function startDev() {
|
|
|
148
148
|
console.error(`Failed to start browserSync process: ${err.message}`);
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
-
// Function to start
|
|
151
|
+
// Function to start npmRunAll process
|
|
152
152
|
function startDevProcess() {
|
|
153
|
-
console.log("Starting
|
|
154
|
-
devProcess = spawn("npm", ["run", "
|
|
153
|
+
console.log("Starting npmRunAll...");
|
|
154
|
+
devProcess = spawn("npm", ["run", "npmRunAll"], { shell: true });
|
|
155
155
|
|
|
156
156
|
devProcess.stdout.on("data", (data) => {
|
|
157
157
|
process.stdout.write(data);
|
|
@@ -72,6 +72,19 @@ class Boom
|
|
|
72
72
|
return new self(401, $message, $details);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Factory method for 402 Payment Required.
|
|
77
|
+
*
|
|
78
|
+
* @param string $message Error message.
|
|
79
|
+
* @param array $details Additional error details.
|
|
80
|
+
*
|
|
81
|
+
* @return self
|
|
82
|
+
*/
|
|
83
|
+
public static function paymentRequired(string $message = 'Payment Required', array $details = []): self
|
|
84
|
+
{
|
|
85
|
+
return new self(402, $message, $details);
|
|
86
|
+
}
|
|
87
|
+
|
|
75
88
|
/**
|
|
76
89
|
* Factory method for 403 Forbidden.
|
|
77
90
|
*
|
|
@@ -98,6 +111,32 @@ class Boom
|
|
|
98
111
|
return new self(404, $message, $details);
|
|
99
112
|
}
|
|
100
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Factory method for 405 Method Not Allowed.
|
|
116
|
+
*
|
|
117
|
+
* @param string $message Error message.
|
|
118
|
+
* @param array $details Additional error details.
|
|
119
|
+
*
|
|
120
|
+
* @return self
|
|
121
|
+
*/
|
|
122
|
+
public static function methodNotAllowed(string $message = 'Method Not Allowed', array $details = []): self
|
|
123
|
+
{
|
|
124
|
+
return new self(405, $message, $details);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Factory method for 406 Not Acceptable.
|
|
129
|
+
*
|
|
130
|
+
* @param string $message Error message.
|
|
131
|
+
* @param array $details Additional error details.
|
|
132
|
+
*
|
|
133
|
+
* @return self
|
|
134
|
+
*/
|
|
135
|
+
public static function notAcceptable(string $message = 'Not Acceptable', array $details = []): self
|
|
136
|
+
{
|
|
137
|
+
return new self(406, $message, $details);
|
|
138
|
+
}
|
|
139
|
+
|
|
101
140
|
/**
|
|
102
141
|
* Factory method for 500 Internal Server Error.
|
|
103
142
|
*
|
package/dist/src/app/layout.php
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
7
|
<meta name="pp-description" content="<?= htmlspecialchars($metadata['description']); ?>">
|
|
8
8
|
<title><?= htmlspecialchars($metadata['title']); ?></title>
|
|
9
|
-
<link rel="icon" href="<?= $baseUrl;
|
|
9
|
+
<link rel="icon" href="<?= $baseUrl; ?>/favicon.ico" type="image/x-icon">
|
|
10
10
|
</head>
|
|
11
11
|
|
|
12
12
|
<body>
|
package/dist/tailwind.config.js
CHANGED
package/dist/tsconfig.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
|
12
12
|
|
|
13
13
|
/* Language and Environment */
|
|
14
|
-
"target": "
|
|
14
|
+
"target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
|
15
15
|
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
|
16
16
|
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
|
17
17
|
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
|
26
26
|
|
|
27
27
|
/* Modules */
|
|
28
|
-
"module": "
|
|
28
|
+
"module": "NodeNext" /* Specify what module code is generated. */,
|
|
29
29
|
// "rootDir": "./", /* Specify the root folder within your source files. */
|
|
30
30
|
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
|
31
31
|
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
|
40
40
|
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
|
41
41
|
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
|
42
|
-
|
|
42
|
+
"resolveJsonModule": true /* Enable importing .json files. */,
|
|
43
43
|
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
|
|
44
44
|
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
|
45
45
|
|
|
@@ -77,12 +77,12 @@
|
|
|
77
77
|
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
|
78
78
|
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
|
|
79
79
|
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
|
80
|
-
"esModuleInterop": true
|
|
80
|
+
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
|
|
81
81
|
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
|
82
|
-
"forceConsistentCasingInFileNames": true
|
|
82
|
+
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
|
83
83
|
|
|
84
84
|
/* Type Checking */
|
|
85
|
-
"strict": true
|
|
85
|
+
"strict": true /* Enable all strict type-checking options. */,
|
|
86
86
|
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
|
87
87
|
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
|
88
88
|
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
|
@@ -104,8 +104,8 @@
|
|
|
104
104
|
|
|
105
105
|
/* Completeness */
|
|
106
106
|
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
|
107
|
-
"skipLibCheck": true
|
|
107
|
+
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
|
108
108
|
},
|
|
109
|
-
"include": ["src/**/*.ts"],
|
|
110
|
-
"exclude": ["node_modules"]
|
|
109
|
+
"include": ["src/**/*.ts", "settings/**/*.ts"],
|
|
110
|
+
"exclude": ["node_modules", "vendor"]
|
|
111
111
|
}
|