create-prisma-php-app 4.0.0-alpha.2 → 4.0.0-alpha.21
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/.htaccess +54 -41
- package/dist/bootstrap.php +143 -98
- package/dist/index.js +264 -99
- package/dist/settings/auto-swagger-docs.ts +196 -95
- package/dist/settings/bs-config.ts +56 -58
- package/dist/settings/files-list.json +1 -1
- package/dist/settings/restart-mcp.ts +58 -0
- package/dist/settings/restart-websocket.ts +51 -45
- package/dist/settings/utils.ts +240 -0
- package/dist/src/Lib/AI/ChatGPTClient.php +147 -0
- package/dist/src/Lib/Auth/Auth.php +544 -0
- package/dist/src/Lib/Auth/AuthConfig.php +89 -0
- package/dist/src/Lib/CacheHandler.php +121 -0
- package/dist/src/Lib/ErrorHandler.php +322 -0
- package/dist/src/Lib/FileManager/UploadFile.php +383 -0
- package/dist/src/Lib/Headers/Boom.php +192 -0
- package/dist/src/Lib/IncludeTracker.php +59 -0
- package/dist/src/Lib/MCP/WeatherTools.php +104 -0
- package/dist/src/Lib/MCP/mcp-server.php +80 -0
- package/dist/src/Lib/MainLayout.php +230 -0
- package/dist/src/Lib/Middleware/AuthMiddleware.php +154 -0
- package/dist/src/Lib/Middleware/CorsMiddleware.php +145 -0
- package/dist/src/Lib/PHPMailer/Mailer.php +169 -0
- package/dist/src/Lib/PHPX/Exceptions/ComponentValidationException.php +49 -0
- package/dist/src/Lib/PHPX/Fragment.php +32 -0
- package/dist/src/Lib/PHPX/IPHPX.php +22 -0
- package/dist/src/Lib/PHPX/PHPX.php +287 -0
- package/dist/src/Lib/PHPX/TemplateCompiler.php +641 -0
- package/dist/src/Lib/PHPX/TwMerge.php +346 -0
- package/dist/src/Lib/PHPX/TypeCoercer.php +490 -0
- package/dist/src/Lib/PartialRenderer.php +40 -0
- package/dist/src/Lib/PrismaPHPSettings.php +181 -0
- package/dist/src/Lib/Request.php +479 -0
- package/dist/src/Lib/Security/RateLimiter.php +33 -0
- package/dist/src/Lib/Set.php +102 -0
- package/dist/src/Lib/StateManager.php +127 -0
- package/dist/src/Lib/Validator.php +752 -0
- package/dist/src/{Websocket → Lib/Websocket}/ConnectionManager.php +1 -1
- package/dist/src/Lib/Websocket/websocket-server.php +118 -0
- package/dist/src/app/error.php +1 -1
- package/dist/src/app/index.php +24 -5
- package/dist/src/app/js/index.js +1 -1
- package/dist/src/app/layout.php +2 -2
- package/package.json +1 -1
- package/dist/settings/restart-websocket.bat +0 -28
- package/dist/src/app/assets/images/prisma-php-black.svg +0 -6
- package/dist/websocket-server.php +0 -22
- package/vendor/autoload.php +0 -25
- package/vendor/composer/ClassLoader.php +0 -579
- package/vendor/composer/InstalledVersions.php +0 -359
- package/vendor/composer/LICENSE +0 -21
- package/vendor/composer/autoload_classmap.php +0 -10
- package/vendor/composer/autoload_namespaces.php +0 -9
- package/vendor/composer/autoload_psr4.php +0 -10
- package/vendor/composer/autoload_real.php +0 -38
- package/vendor/composer/autoload_static.php +0 -25
- package/vendor/composer/installed.json +0 -825
- package/vendor/composer/installed.php +0 -132
- package/vendor/composer/platform_check.php +0 -26
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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";import{randomBytes}from"crypto";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","error.php"],dockerFiles=[".dockerignore","docker-compose.yml","Dockerfile","apache.conf"];function bsConfigUrls(e){const s=e.indexOf("\\htdocs\\");if(-1===s)return{bsTarget:"",bsPathRewrite:{}};const t=e.substring(0,s+"\\htdocs\\".length).replace(/\\/g,"\\\\"),n=e.replace(new RegExp(`^${t}`),"").replace(/\\/g,"/");let c=`http://localhost/${n}`;c=c.endsWith("/")?c.slice(0,-1):c;const o=c.replace(/(?<!:)(\/\/+)/g,"/"),i=n.replace(/\/\/+/g,"/");return{bsTarget:`${o}/`,bsPathRewrite:{"^/":`/${i.startsWith("/")?i.substring(1):i}/`}}}async function updatePackageJson(e,s){const t=path.join(e,"package.json");if(checkExcludeFiles(t))return;const n=JSON.parse(fs.readFileSync(t,"utf8"));n.scripts={...n.scripts,projectName:"tsx settings/project-name.ts"};let c=[];if(s.tailwindcss&&(n.scripts={...n.scripts,tailwind:"postcss src/app/css/tailwind.css -o src/app/css/styles.css --watch","tailwind:build":"postcss src/app/css/tailwind.css -o src/app/css/styles.css"},c.push("tailwind")),s.websocket&&(n.scripts={...n.scripts,websocket:"tsx settings/restart-websocket.ts"},c.push("websocket")),s.docker&&(n.scripts={...n.scripts,docker:"docker-compose up"},c.push("docker")),s.swaggerDocs){const e=s.prisma?"tsx settings/auto-swagger-docs.ts":"tsx settings/swagger-config.ts";n.scripts={...n.scripts,"create-swagger-docs":e}}let o={...n.scripts};o.browserSync="tsx settings/bs-config.ts",o["browserSync:build"]="tsx settings/build.ts",o.dev=`npm-run-all projectName -p browserSync ${c.join(" ")}`,o.build=`npm-run-all${s.tailwindcss?" tailwind:build":""} browserSync:build`,n.scripts=o,n.type="module",fs.writeFileSync(t,JSON.stringify(n,null,2))}async function updateComposerJson(e){const s=path.join(e,"composer.json");if(checkExcludeFiles(s))return;let t;if(fs.existsSync(s)){{const e=fs.readFileSync(s,"utf8");t=JSON.parse(e)}t.autoload={"psr-4":{"":"src/"}},t.version="1.0.0",fs.writeFileSync(s,JSON.stringify(t,null,2))}}async function updateIndexJsForWebSocket(e,s){if(!s.websocket)return;const t=path.join(e,"src","app","js","index.js");if(checkExcludeFiles(t))return;let n=fs.readFileSync(t,"utf8");n+='\n// WebSocket initialization\nvar ws = new WebSocket("ws://localhost:8080");\n',fs.writeFileSync(t,n,"utf8")}function generateAuthSecret(){return randomBytes(33).toString("base64")}function generateHexEncodedKey(e=16){return randomBytes(e).toString("hex")}function copyRecursiveSync(e,s,t){const n=fs.existsSync(e),c=n&&fs.statSync(e);if(n&&c&&c.isDirectory()){const n=s.toLowerCase();if(!t.websocket&&n.includes("src\\websocket"))return;if(t.backendOnly&&n.includes("src\\app\\js")||t.backendOnly&&n.includes("src\\app\\css")||t.backendOnly&&n.includes("src\\app\\assets"))return;if(!t.swaggerDocs&&n.includes("src\\app\\swagger-docs"))return;const c=s.replace(/\\/g,"/");if(updateAnswer?.excludeFilePath?.includes(c))return;fs.existsSync(s)||fs.mkdirSync(s,{recursive:!0}),fs.readdirSync(e).forEach((n=>{copyRecursiveSync(path.join(e,n),path.join(s,n),t)}))}else{if(checkExcludeFiles(s))return;if(!t.tailwindcss&&(s.includes("tailwind.css")||s.includes("styles.css")))return;if(!t.websocket&&(s.includes("restart-websocket.ts")||s.includes("restart-websocket.bat")||s.includes("websocket-server.php")))return;if(!t.docker&&dockerFiles.some((e=>s.includes(e))))return;if(t.backendOnly&&nonBackendFiles.some((e=>s.includes(e))))return;if(!t.backendOnly&&s.includes("route.php"))return;if(t.backendOnly&&!t.swaggerDocs&&s.includes("layout.php"))return;if(!t.swaggerDocs&&s.includes("swagger-config.ts"))return;if(t.tailwindcss&&s.includes("index.css"))return;if((!t.swaggerDocs||!t.prisma)&&(s.includes("auto-swagger-docs.ts")||s.includes("prisma-schema-config.json")))return;fs.copyFileSync(e,s,0)}}async function executeCopy(e,s,t){s.forEach((({src:s,dest:n})=>{copyRecursiveSync(path.join(__dirname,s),path.join(e,n),t)}))}function modifyPostcssConfig(e){const s=path.join(e,"postcss.config.js");if(checkExcludeFiles(s))return;fs.writeFileSync(s,'export default {\n plugins: {\n "@tailwindcss/postcss": {},\n cssnano: {},\n },\n};',{flag:"w"})}function modifyLayoutPHP(e,s){const t=path.join(e,"src","app","layout.php");if(!checkExcludeFiles(t))try{let e=fs.readFileSync(t,"utf8"),n="";s.backendOnly||(s.tailwindcss||(n='\n <link href="<?= Request::baseUrl; ?>/css/index.css" rel="stylesheet" />'),n+='\n <script src="<?= Request::baseUrl; ?>/js/morphdom-umd.min.js"><\/script>\n <script src="<?= Request::baseUrl; ?>/js/json5.min.js"><\/script>\n <script src="<?= Request::baseUrl; ?>/js/index.js"><\/script>');let c="";s.backendOnly||(c=s.tailwindcss?` <link href="<?= Request::baseUrl; ?>/css/styles.css" rel="stylesheet" /> ${n}`:n),e=e.replace("</head>",`${c}\n</head>`),fs.writeFileSync(t,e,{flag:"w"})}catch(e){}}async function createOrUpdateEnvFile(e,s){const t=path.join(e,".env");checkExcludeFiles(t)||fs.writeFileSync(t,s,{flag:"w"})}function checkExcludeFiles(e){return!!updateAnswer?.isUpdate&&(updateAnswer?.excludeFilePath?.includes(e.replace(/\\/g,"/"))??!1)}async function createDirectoryStructure(e,s){const t=[{src:"/bootstrap.php",dest:"/bootstrap.php"},{src:"/.htaccess",dest:"/.htaccess"},{src:"/tsconfig.json",dest:"/tsconfig.json"},{src:"/app-gitignore",dest:"/.gitignore"}];s.tailwindcss&&t.push({src:"/postcss.config.js",dest:"/postcss.config.js"}),s.websocket&&t.push({src:"/websocket-server.php",dest:"/websocket-server.php"});const n=[{src:"/settings",dest:"/settings"},{src:"/src",dest:"/src"}];s.docker&&n.push({src:"/.dockerignore",dest:"/.dockerignore"},{src:"/docker-compose.yml",dest:"/docker-compose.yml"},{src:"/Dockerfile",dest:"/Dockerfile"},{src:"/apache.conf",dest:"/apache.conf"}),t.forEach((({src:s,dest:t})=>{const n=path.join(__dirname,s),c=path.join(e,t);if(checkExcludeFiles(c))return;const o=fs.readFileSync(n,"utf8");fs.writeFileSync(c,o,{flag:"w"})})),await executeCopy(e,n,s),await updatePackageJson(e,s),await updateComposerJson(e),s.backendOnly||await updateIndexJsForWebSocket(e,s),s.tailwindcss&&modifyPostcssConfig(e),(s.tailwindcss||!s.backendOnly||s.swaggerDocs)&&modifyLayoutPHP(e,s);const c=generateAuthSecret(),o=generateHexEncodedKey(),i=`# Authentication secret key for JWT or session encryption.\nAUTH_SECRET="${c}"\n# Name of the authentication cookie.\nAUTH_COOKIE_NAME="${generateHexEncodedKey(8)}"\n\n# PHPMailer SMTP configuration (uncomment and set as needed)\n# SMTP_HOST="smtp.gmail.com" # Your SMTP host\n# SMTP_USERNAME="john.doe@gmail.com" # Your SMTP username\n# SMTP_PASSWORD="123456" # Your SMTP password\n# SMTP_PORT="587" # 587 for TLS, 465 for SSL, or your SMTP port\n# SMTP_ENCRYPTION="ssl" # ssl or tls\n# MAIL_FROM="john.doe@gmail.com" # Sender email address\n# MAIL_FROM_NAME="John Doe" # Sender name\n\n# Show errors in the browser (development only). Set to false in production.\nSHOW_ERRORS="true"\n\n# Application timezone (default: UTC)\nAPP_TIMEZONE="UTC"\n\n# Application environment (development or production)\nAPP_ENV="development"\n\n# Enable or disable application cache (default: false)\nCACHE_ENABLED="false"\n# Cache time-to-live in seconds (default: 600)\nCACHE_TTL="600"\n\n# Local storage key for browser storage (auto-generated if not set).\n# Spaces will be replaced with underscores and converted to lowercase.\nLOCALSTORE_KEY="${o}"\n\n# Secret key for encrypting function calls.\nFUNCTION_CALL_SECRET="${generateHexEncodedKey(32)}"`;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)}async function getAnswer(e={}){const s=[];e.projectName||s.push({type:"text",name:"projectName",message:"What is your project named?",initial:"my-app"}),e.backendOnly||s.push({type:"toggle",name:"backendOnly",message:`Would you like to create a ${chalk.blue("backend-only project")}?`,initial:!1,active:"Yes",inactive:"No"});const t=()=>{process.exit(0)},n=await prompts(s,{onCancel:t}),c=[];n.backendOnly||e.backendOnly?(e.swaggerDocs||c.push({type:"toggle",name:"swaggerDocs",message:`Would you like to use ${chalk.blue("Swagger Docs")}?`,initial:!1,active:"Yes",inactive:"No"}),e.websocket||c.push({type:"toggle",name:"websocket",message:`Would you like to use ${chalk.blue("Websocket")}?`,initial:!0,active:"Yes",inactive:"No"}),e.prisma||c.push({type:"toggle",name:"prisma",message:`Would you like to use ${chalk.blue("Prisma PHP ORM")}?`,initial:!0,active:"Yes",inactive:"No"}),e.docker||c.push({type:"toggle",name:"docker",message:`Would you like to use ${chalk.blue("Docker")}?`,initial:!1,active:"Yes",inactive:"No"})):(e.swaggerDocs||c.push({type:"toggle",name:"swaggerDocs",message:`Would you like to use ${chalk.blue("Swagger Docs")}?`,initial:!1,active:"Yes",inactive:"No"}),e.tailwindcss||c.push({type:"toggle",name:"tailwindcss",message:`Would you like to use ${chalk.blue("Tailwind CSS")}?`,initial:!1,active:"Yes",inactive:"No"}),e.websocket||c.push({type:"toggle",name:"websocket",message:`Would you like to use ${chalk.blue("Websocket")}?`,initial:!1,active:"Yes",inactive:"No"}),e.prisma||c.push({type:"toggle",name:"prisma",message:`Would you like to use ${chalk.blue("Prisma PHP ORM")}?`,initial:!1,active:"Yes",inactive:"No"}),e.docker||c.push({type:"toggle",name:"docker",message:`Would you like to use ${chalk.blue("Docker")}?`,initial:!1,active:"Yes",inactive:"No"}));const o=await prompts(c,{onCancel:t});return{projectName:n.projectName?String(n.projectName).trim().replace(/ /g,"-"):e.projectName??"my-app",backendOnly:n.backendOnly??e.backendOnly??!1,swaggerDocs:o.swaggerDocs??e.swaggerDocs??!1,tailwindcss:o.tailwindcss??e.tailwindcss??!1,websocket:o.websocket??e.websocket??!1,prisma:o.prisma??e.prisma??!1,docker:o.docker??e.docker??!1}}async function uninstallNpmDependencies(e,s,t=!1){s.forEach((e=>{}));const n=`npm uninstall ${t?"--save-dev":"--save"} ${s.join(" ")}`;execSync(n,{stdio:"inherit",cwd:e})}async function uninstallComposerDependencies(e,s){s.forEach((e=>{}));const t=`C:\\xampp\\php\\php.exe C:\\ProgramData\\ComposerSetup\\bin\\composer.phar remove ${s.join(" ")}`;execSync(t,{stdio:"inherit",cwd:e})}function fetchPackageVersion(e){return new Promise(((s,t)=>{https.get(`https://registry.npmjs.org/${e}`,(e=>{let n="";e.on("data",(e=>n+=e)),e.on("end",(()=>{try{const e=JSON.parse(n);s(e["dist-tags"].latest)}catch(e){t(new Error("Failed to parse JSON response"))}}))})).on("error",(e=>t(e)))}))}const readJsonFile=e=>{const s=fs.readFileSync(e,"utf8");return JSON.parse(s)};function compareVersions(e,s){const t=e.split(".").map(Number),n=s.split(".").map(Number);for(let e=0;e<t.length;e++){if(t[e]>n[e])return 1;if(t[e]<n[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}}
|
|
2
|
+
import{execSync,spawnSync}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";import{randomBytes}from"crypto";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","error.php"],dockerFiles=[".dockerignore","docker-compose.yml","Dockerfile","apache.conf"];function bsConfigUrls(e){const s=e.indexOf("\\htdocs\\");if(-1===s)return{bsTarget:"",bsPathRewrite:{}};const t=e.substring(0,s+"\\htdocs\\".length).replace(/\\/g,"\\\\"),n=e.replace(new RegExp(`^${t}`),"").replace(/\\/g,"/");let c=`http://localhost/${n}`;c=c.endsWith("/")?c.slice(0,-1):c;const o=c.replace(/(?<!:)(\/\/+)/g,"/"),i=n.replace(/\/\/+/g,"/");return{bsTarget:`${o}/`,bsPathRewrite:{"^/":`/${i.startsWith("/")?i.substring(1):i}/`}}}async function updatePackageJson(e,s){const t=path.join(e,"package.json");if(checkExcludeFiles(t))return;const n=JSON.parse(fs.readFileSync(t,"utf8"));n.scripts={...n.scripts,projectName:"tsx settings/project-name.ts"};let c=[];if(s.tailwindcss&&(n.scripts={...n.scripts,tailwind:"postcss src/app/css/tailwind.css -o src/app/css/styles.css --watch","tailwind:build":"postcss src/app/css/tailwind.css -o src/app/css/styles.css"},c.push("tailwind")),s.websocket&&(n.scripts={...n.scripts,websocket:"tsx settings/restart-websocket.ts"},c.push("websocket")),s.docker&&(n.scripts={...n.scripts,docker:"docker-compose up"},c.push("docker")),s.swaggerDocs){const e=s.prisma?"tsx settings/auto-swagger-docs.ts":"tsx settings/swagger-config.ts";n.scripts={...n.scripts,"create-swagger-docs":e}}let o={...n.scripts};o.browserSync="tsx settings/bs-config.ts",o["browserSync:build"]="tsx settings/build.ts",o.dev=`npm-run-all projectName -p browserSync ${c.join(" ")}`,o.build=`npm-run-all${s.tailwindcss?" tailwind:build":""} browserSync:build`,n.scripts=o,n.type="module",fs.writeFileSync(t,JSON.stringify(n,null,2))}async function updateComposerJson(e){checkExcludeFiles(path.join(e,"composer.json"))}async function updateIndexJsForWebSocket(e,s){if(!s.websocket)return;const t=path.join(e,"src","app","js","index.js");if(checkExcludeFiles(t))return;let n=fs.readFileSync(t,"utf8");n+='\n// WebSocket initialization\nvar ws = new WebSocket("ws://localhost:8080");\n',fs.writeFileSync(t,n,"utf8")}function generateAuthSecret(){return randomBytes(33).toString("base64")}function generateHexEncodedKey(e=16){return randomBytes(e).toString("hex")}function copyRecursiveSync(e,s,t){const n=fs.existsSync(e),c=n&&fs.statSync(e);if(n&&c&&c.isDirectory()){const n=s.toLowerCase();if(!t.websocket&&n.includes("src\\lib\\websocket"))return;if(t.backendOnly&&n.includes("src\\app\\js")||t.backendOnly&&n.includes("src\\app\\css")||t.backendOnly&&n.includes("src\\app\\assets"))return;if(!t.swaggerDocs&&n.includes("src\\app\\swagger-docs"))return;const c=s.replace(/\\/g,"/");if(updateAnswer?.excludeFilePath?.includes(c))return;fs.existsSync(s)||fs.mkdirSync(s,{recursive:!0}),fs.readdirSync(e).forEach((n=>{copyRecursiveSync(path.join(e,n),path.join(s,n),t)}))}else{if(checkExcludeFiles(s))return;if(!t.tailwindcss&&(s.includes("tailwind.css")||s.includes("styles.css")))return;if(!t.websocket&&s.includes("restart-websocket.ts"))return;if(!t.docker&&dockerFiles.some((e=>s.includes(e))))return;if(t.backendOnly&&nonBackendFiles.some((e=>s.includes(e))))return;if(!t.backendOnly&&s.includes("route.php"))return;if(t.backendOnly&&!t.swaggerDocs&&s.includes("layout.php"))return;if(!t.swaggerDocs&&s.includes("swagger-config.ts"))return;if(t.tailwindcss&&s.includes("index.css"))return;if((!t.swaggerDocs||!t.prisma)&&(s.includes("auto-swagger-docs.ts")||s.includes("prisma-schema-config.json")))return;fs.copyFileSync(e,s,0)}}async function executeCopy(e,s,t){s.forEach((({src:s,dest:n})=>{copyRecursiveSync(path.join(__dirname,s),path.join(e,n),t)}))}function modifyPostcssConfig(e){const s=path.join(e,"postcss.config.js");if(checkExcludeFiles(s))return;fs.writeFileSync(s,'export default {\n plugins: {\n "@tailwindcss/postcss": {},\n cssnano: {},\n },\n};',{flag:"w"})}function modifyLayoutPHP(e,s){const t=path.join(e,"src","app","layout.php");if(!checkExcludeFiles(t))try{let e=fs.readFileSync(t,"utf8"),n="";s.backendOnly||(s.tailwindcss||(n='\n <link href="<?= Request::baseUrl; ?>/css/index.css" rel="stylesheet" />'),n+='\n <script src="<?= Request::baseUrl; ?>/js/morphdom-umd.min.js"><\/script>\n <script src="<?= Request::baseUrl; ?>/js/json5.min.js"><\/script>\n <script src="<?= Request::baseUrl; ?>/js/index.js"><\/script>');let c="";s.backendOnly||(c=s.tailwindcss?` <link href="<?= Request::baseUrl; ?>/css/styles.css" rel="stylesheet" /> ${n}`:n),e=e.replace("</head>",`${c}\n</head>`),fs.writeFileSync(t,e,{flag:"w"})}catch(e){}}async function createOrUpdateEnvFile(e,s){const t=path.join(e,".env");checkExcludeFiles(t)||fs.writeFileSync(t,s,{flag:"w"})}function checkExcludeFiles(e){return!!updateAnswer?.isUpdate&&(updateAnswer?.excludeFilePath?.includes(e.replace(/\\/g,"/"))??!1)}async function createDirectoryStructure(e,s){const t=[{src:"/bootstrap.php",dest:"/bootstrap.php"},{src:"/.htaccess",dest:"/.htaccess"},{src:"/tsconfig.json",dest:"/tsconfig.json"},{src:"/app-gitignore",dest:"/.gitignore"}];s.tailwindcss&&t.push({src:"/postcss.config.js",dest:"/postcss.config.js"});const n=[{src:"/settings",dest:"/settings"},{src:"/src",dest:"/src"}];s.docker&&n.push({src:"/.dockerignore",dest:"/.dockerignore"},{src:"/docker-compose.yml",dest:"/docker-compose.yml"},{src:"/Dockerfile",dest:"/Dockerfile"},{src:"/apache.conf",dest:"/apache.conf"}),t.forEach((({src:s,dest:t})=>{const n=path.join(__dirname,s),c=path.join(e,t);if(checkExcludeFiles(c))return;const o=fs.readFileSync(n,"utf8");fs.writeFileSync(c,o,{flag:"w"})})),await executeCopy(e,n,s),await updatePackageJson(e,s),await updateComposerJson(e),s.backendOnly||await updateIndexJsForWebSocket(e,s),s.tailwindcss&&modifyPostcssConfig(e),(s.tailwindcss||!s.backendOnly||s.swaggerDocs)&&modifyLayoutPHP(e,s);const c=generateAuthSecret(),o=generateHexEncodedKey(),i=`# Authentication secret key for JWT or session encryption.\nAUTH_SECRET="${c}"\n# Name of the authentication cookie.\nAUTH_COOKIE_NAME="${generateHexEncodedKey(8)}"\n\n# PHPMailer SMTP configuration (uncomment and set as needed)\n# SMTP_HOST="smtp.gmail.com" # Your SMTP host\n# SMTP_USERNAME="john.doe@gmail.com" # Your SMTP username\n# SMTP_PASSWORD="123456" # Your SMTP password\n# SMTP_PORT="587" # 587 for TLS, 465 for SSL, or your SMTP port\n# SMTP_ENCRYPTION="ssl" # ssl or tls\n# MAIL_FROM="john.doe@gmail.com" # Sender email address\n# MAIL_FROM_NAME="John Doe" # Sender name\n\n# Show errors in the browser (development only). Set to false in production.\nSHOW_ERRORS="true"\n\n# Application timezone (default: UTC)\nAPP_TIMEZONE="UTC"\n\n# Application environment (development or production)\nAPP_ENV="development"\n\n# Enable or disable application cache (default: false)\nCACHE_ENABLED="false"\n# Cache time-to-live in seconds (default: 600)\nCACHE_TTL="600"\n\n# Local storage key for browser storage (auto-generated if not set).\n# Spaces will be replaced with underscores and converted to lowercase.\nLOCALSTORE_KEY="${o}"\n\n# Secret key for encrypting function calls.\nFUNCTION_CALL_SECRET="${generateHexEncodedKey(32)}"\n\n# Single or multiple origins (CSV or JSON array)\nCORS_ALLOWED_ORIGINS=[]\n\n# If you need cookies/Authorization across origins, keep this true\nCORS_ALLOW_CREDENTIALS="true"\n\n# Optional tuning\nCORS_ALLOWED_METHODS="GET,POST,PUT,PATCH,DELETE,OPTIONS"\nCORS_ALLOWED_HEADERS="Content-Type,Authorization,X-Requested-With"\nCORS_EXPOSE_HEADERS=""\nCORS_MAX_AGE="86400"`;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)}async function getAnswer(e={}){const s=[];e.projectName||s.push({type:"text",name:"projectName",message:"What is your project named?",initial:"my-app"}),e.backendOnly||updateAnswer?.isUpdate||s.push({type:"toggle",name:"backendOnly",message:`Would you like to create a ${chalk.blue("backend-only project")}?`,initial:!1,active:"Yes",inactive:"No"});const t=()=>{process.exit(0)},n=await prompts(s,{onCancel:t}),c=[];n.backendOnly??e.backendOnly??!1?(e.swaggerDocs||c.push({type:"toggle",name:"swaggerDocs",message:`Would you like to use ${chalk.blue("Swagger Docs")}?`,initial:!1,active:"Yes",inactive:"No"}),e.websocket||c.push({type:"toggle",name:"websocket",message:`Would you like to use ${chalk.blue("Websocket")}?`,initial:!1,active:"Yes",inactive:"No"}),e.prisma||c.push({type:"toggle",name:"prisma",message:`Would you like to use ${chalk.blue("Prisma PHP ORM")}?`,initial:!1,active:"Yes",inactive:"No"}),e.docker||c.push({type:"toggle",name:"docker",message:`Would you like to use ${chalk.blue("Docker")}?`,initial:!1,active:"Yes",inactive:"No"})):(e.swaggerDocs||c.push({type:"toggle",name:"swaggerDocs",message:`Would you like to use ${chalk.blue("Swagger Docs")}?`,initial:!1,active:"Yes",inactive:"No"}),e.tailwindcss||c.push({type:"toggle",name:"tailwindcss",message:`Would you like to use ${chalk.blue("Tailwind CSS")}?`,initial:!1,active:"Yes",inactive:"No"}),e.websocket||c.push({type:"toggle",name:"websocket",message:`Would you like to use ${chalk.blue("Websocket")}?`,initial:!1,active:"Yes",inactive:"No"}),e.prisma||c.push({type:"toggle",name:"prisma",message:`Would you like to use ${chalk.blue("Prisma PHP ORM")}?`,initial:!1,active:"Yes",inactive:"No"}),e.docker||c.push({type:"toggle",name:"docker",message:`Would you like to use ${chalk.blue("Docker")}?`,initial:!1,active:"Yes",inactive:"No"}));const o=await prompts(c,{onCancel:t});return{projectName:n.projectName?String(n.projectName).trim().replace(/ /g,"-"):e.projectName??"my-app",backendOnly:n.backendOnly??e.backendOnly??!1,swaggerDocs:o.swaggerDocs??e.swaggerDocs??!1,tailwindcss:o.tailwindcss??e.tailwindcss??!1,websocket:o.websocket??e.websocket??!1,prisma:o.prisma??e.prisma??!1,docker:o.docker??e.docker??!1}}async function uninstallNpmDependencies(e,s,t=!1){s.forEach((e=>{}));const n=`npm uninstall ${t?"--save-dev":"--save"} ${s.join(" ")}`;execSync(n,{stdio:"inherit",cwd:e})}async function uninstallComposerDependencies(e,s){s.forEach((e=>{}));const t=`C:\\xampp\\php\\php.exe C:\\ProgramData\\ComposerSetup\\bin\\composer.phar remove ${s.join(" ")}`;execSync(t,{stdio:"inherit",cwd:e})}function fetchPackageVersion(e){return new Promise(((s,t)=>{https.get(`https://registry.npmjs.org/${e}`,(e=>{let n="";e.on("data",(e=>n+=e)),e.on("end",(()=>{try{const e=JSON.parse(n);s(e["dist-tags"].latest)}catch(e){t(new Error("Failed to parse JSON response"))}}))})).on("error",(e=>t(e)))}))}const readJsonFile=e=>{const s=fs.readFileSync(e,"utf8");return JSON.parse(s)};function compareVersions(e,s){const t=e.split(".").map(Number),n=s.split(".").map(Number);for(let e=0;e<t.length;e++){if(t[e]>n[e])return 1;if(t[e]<n[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}}
|
|
3
3
|
/**
|
|
4
4
|
* Install dependencies in the specified directory.
|
|
5
5
|
* @param {string} baseDir - The base directory where to install the dependencies.
|
|
@@ -7,7 +7,11 @@ import{execSync}from"child_process";import fs from"fs";import{fileURLToPath}from
|
|
|
7
7
|
* @param {boolean} [isDev=false] - Whether to install the dependencies as devDependencies.
|
|
8
8
|
*/
|
|
9
9
|
async function installNpmDependencies(baseDir, dependencies, isDev = false) {
|
|
10
|
-
|
|
10
|
+
if (!fs.existsSync(path.join(baseDir, "package.json"))) {
|
|
11
|
+
console.log("Initializing new Node.js project...");
|
|
12
|
+
} else {
|
|
13
|
+
console.log("Updating existing Node.js project...");
|
|
14
|
+
}
|
|
11
15
|
// Initialize a package.json if it doesn't exist
|
|
12
16
|
if (!fs.existsSync(path.join(baseDir, "package.json"))) {
|
|
13
17
|
execSync("npm init -y", {
|
|
@@ -32,27 +36,99 @@ async function installNpmDependencies(baseDir, dependencies, isDev = false) {
|
|
|
32
36
|
cwd: baseDir,
|
|
33
37
|
});
|
|
34
38
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
function getComposerCmd() {
|
|
40
|
+
try {
|
|
41
|
+
execSync("composer --version", { stdio: "ignore" });
|
|
42
|
+
return { cmd: "composer", baseArgs: [] };
|
|
43
|
+
} catch {
|
|
44
|
+
return {
|
|
45
|
+
cmd: "C:\\xampp\\php\\php.exe",
|
|
46
|
+
baseArgs: ["C:\\ProgramData\\ComposerSetup\\bin\\composer.phar"],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export async function installComposerDependencies(baseDir, dependencies) {
|
|
51
|
+
const { cmd, baseArgs } = getComposerCmd();
|
|
52
|
+
const composerJsonPath = path.join(baseDir, "composer.json");
|
|
53
|
+
const existsAlready = fs.existsSync(composerJsonPath);
|
|
54
|
+
console.log(
|
|
55
|
+
chalk.green(
|
|
56
|
+
`Composer project initialization: ${
|
|
57
|
+
existsAlready ? "Updating existing project…" : "Setting up new project…"
|
|
58
|
+
}`
|
|
59
|
+
)
|
|
60
|
+
);
|
|
61
|
+
/* ------------------------------------------------------------------ */
|
|
62
|
+
/* 1. Try composer init (quietly fall back if it fails) */
|
|
63
|
+
/* ------------------------------------------------------------------ */
|
|
64
|
+
if (!existsAlready) {
|
|
65
|
+
const initArgs = [
|
|
66
|
+
...baseArgs,
|
|
67
|
+
"init",
|
|
68
|
+
"--no-interaction",
|
|
69
|
+
"--name",
|
|
70
|
+
"tsnc/prisma-php-app",
|
|
71
|
+
"--require",
|
|
72
|
+
"php:^8.2",
|
|
73
|
+
"--type",
|
|
74
|
+
"project",
|
|
75
|
+
"--version",
|
|
76
|
+
"1.0.0",
|
|
77
|
+
];
|
|
78
|
+
const res = spawnSync(cmd, initArgs, { cwd: baseDir });
|
|
79
|
+
if (res.status !== 0) {
|
|
80
|
+
// Silent fallback: no logs, just write a minimal composer.json
|
|
81
|
+
fs.writeFileSync(
|
|
82
|
+
composerJsonPath,
|
|
83
|
+
JSON.stringify(
|
|
84
|
+
{
|
|
85
|
+
name: "tsnc/prisma-php-app",
|
|
86
|
+
type: "project",
|
|
87
|
+
version: "1.0.0",
|
|
88
|
+
require: { php: "^8.2" },
|
|
89
|
+
autoload: { "psr-4": { "": "src/" } },
|
|
90
|
+
},
|
|
91
|
+
null,
|
|
92
|
+
2
|
|
93
|
+
)
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/* 2. Ensure PSR-4 autoload entry ---------------------------------- */
|
|
98
|
+
const json = JSON.parse(fs.readFileSync(composerJsonPath, "utf8"));
|
|
99
|
+
json.autoload ??= {};
|
|
100
|
+
json.autoload["psr-4"] ??= {};
|
|
101
|
+
json.autoload["psr-4"][""] ??= "src/";
|
|
102
|
+
fs.writeFileSync(composerJsonPath, JSON.stringify(json, null, 2));
|
|
103
|
+
/* 3. Install dependencies ----------------------------------------- */
|
|
104
|
+
if (dependencies.length) {
|
|
105
|
+
console.log("Installing Composer dependencies:");
|
|
106
|
+
dependencies.forEach((d) => console.log(`- ${chalk.blue(d)}`));
|
|
39
107
|
execSync(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
108
|
+
`${cmd} ${[
|
|
109
|
+
...baseArgs,
|
|
110
|
+
"require",
|
|
111
|
+
"--no-interaction",
|
|
112
|
+
...dependencies,
|
|
113
|
+
].join(" ")}`,
|
|
114
|
+
{ stdio: "inherit", cwd: baseDir }
|
|
45
115
|
);
|
|
46
116
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
117
|
+
/* 4. Refresh lock when updating ----------------------------------- */
|
|
118
|
+
if (existsAlready) {
|
|
119
|
+
execSync(
|
|
120
|
+
`${cmd} ${[
|
|
121
|
+
...baseArgs,
|
|
122
|
+
"update",
|
|
123
|
+
"--lock",
|
|
124
|
+
"--no-install",
|
|
125
|
+
"--no-interaction",
|
|
126
|
+
].join(" ")}`,
|
|
127
|
+
{ stdio: "inherit", cwd: baseDir }
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
/* 5. Regenerate autoloader ---------------------------------------- */
|
|
131
|
+
execSync(`${cmd} ${[...baseArgs, "dump-autoload", "--quiet"].join(" ")}`, {
|
|
56
132
|
stdio: "inherit",
|
|
57
133
|
cwd: baseDir,
|
|
58
134
|
});
|
|
@@ -60,21 +136,21 @@ async function installComposerDependencies(baseDir, dependencies) {
|
|
|
60
136
|
const npmPinnedVersions = {
|
|
61
137
|
"@tailwindcss/postcss": "^4.1.11",
|
|
62
138
|
"@types/browser-sync": "^2.29.0",
|
|
63
|
-
"@types/node": "^24.
|
|
139
|
+
"@types/node": "^24.2.1",
|
|
64
140
|
"@types/prompts": "^2.4.9",
|
|
65
141
|
"browser-sync": "^3.0.4",
|
|
66
|
-
chalk: "^5.
|
|
142
|
+
chalk: "^5.5.0",
|
|
67
143
|
"chokidar-cli": "^3.0.0",
|
|
68
|
-
cssnano: "^7.0
|
|
144
|
+
cssnano: "^7.1.0",
|
|
69
145
|
"http-proxy-middleware": "^3.0.5",
|
|
70
146
|
"npm-run-all": "^4.1.5",
|
|
71
|
-
"php-parser": "^3.2.
|
|
147
|
+
"php-parser": "^3.2.5",
|
|
72
148
|
postcss: "^8.5.6",
|
|
73
149
|
"postcss-cli": "^11.0.1",
|
|
74
150
|
prompts: "^2.4.2",
|
|
75
151
|
tailwindcss: "^4.1.11",
|
|
76
152
|
tsx: "^4.20.3",
|
|
77
|
-
typescript: "^5.
|
|
153
|
+
typescript: "^5.9.2",
|
|
78
154
|
};
|
|
79
155
|
function npmPkg(name) {
|
|
80
156
|
return npmPinnedVersions[name] ? `${name}@${npmPinnedVersions[name]}` : name;
|
|
@@ -88,7 +164,7 @@ const composerPinnedVersions = {
|
|
|
88
164
|
"symfony/uid": "^7.2.0",
|
|
89
165
|
"brick/math": "^0.13.1",
|
|
90
166
|
"cboden/ratchet": "^0.4.4",
|
|
91
|
-
"tsnc/prisma-php": "^1.0.
|
|
167
|
+
"tsnc/prisma-php": "^1.0.0",
|
|
92
168
|
};
|
|
93
169
|
function composerPkg(name) {
|
|
94
170
|
return composerPinnedVersions[name]
|
|
@@ -101,29 +177,11 @@ async function main() {
|
|
|
101
177
|
let projectName = args[0];
|
|
102
178
|
let answer = null;
|
|
103
179
|
if (projectName) {
|
|
104
|
-
|
|
105
|
-
let useSwaggerDocs = args.includes("--swagger-docs");
|
|
106
|
-
let useTailwind = args.includes("--tailwindcss");
|
|
107
|
-
let useWebsocket = args.includes("--websocket");
|
|
108
|
-
let usePrisma = args.includes("--prisma");
|
|
109
|
-
let useDocker = args.includes("--docker");
|
|
110
|
-
const predefinedAnswers = {
|
|
111
|
-
projectName,
|
|
112
|
-
backendOnly: useBackendOnly,
|
|
113
|
-
swaggerDocs: useSwaggerDocs,
|
|
114
|
-
tailwindcss: useTailwind,
|
|
115
|
-
websocket: useWebsocket,
|
|
116
|
-
prisma: usePrisma,
|
|
117
|
-
docker: useDocker,
|
|
118
|
-
};
|
|
119
|
-
answer = await getAnswer(predefinedAnswers);
|
|
120
|
-
if (answer === null) {
|
|
121
|
-
console.log(chalk.red("Installation cancelled."));
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
180
|
+
// Check if it's an update FIRST
|
|
124
181
|
const currentDir = process.cwd();
|
|
125
182
|
const configPath = path.join(currentDir, "prisma-php.json");
|
|
126
183
|
if (fs.existsSync(configPath)) {
|
|
184
|
+
// It's an update - read existing settings
|
|
127
185
|
const localSettings = readJsonFile(configPath);
|
|
128
186
|
let excludeFiles = [];
|
|
129
187
|
localSettings.excludeFiles?.map((file) => {
|
|
@@ -131,21 +189,75 @@ async function main() {
|
|
|
131
189
|
if (fs.existsSync(filePath))
|
|
132
190
|
excludeFiles.push(filePath.replace(/\\/g, "/"));
|
|
133
191
|
});
|
|
192
|
+
// Set updateAnswer with OLD settings initially (for checkExcludeFiles function)
|
|
134
193
|
updateAnswer = {
|
|
135
194
|
projectName,
|
|
136
|
-
backendOnly:
|
|
137
|
-
swaggerDocs:
|
|
138
|
-
tailwindcss:
|
|
139
|
-
websocket:
|
|
140
|
-
prisma:
|
|
141
|
-
docker:
|
|
195
|
+
backendOnly: localSettings.backendOnly,
|
|
196
|
+
swaggerDocs: localSettings.swaggerDocs,
|
|
197
|
+
tailwindcss: localSettings.tailwindcss,
|
|
198
|
+
websocket: localSettings.websocket,
|
|
199
|
+
prisma: localSettings.prisma,
|
|
200
|
+
docker: localSettings.docker,
|
|
142
201
|
isUpdate: true,
|
|
143
202
|
excludeFiles: localSettings.excludeFiles ?? [],
|
|
144
203
|
excludeFilePath: excludeFiles ?? [],
|
|
145
204
|
filePath: currentDir,
|
|
146
205
|
};
|
|
206
|
+
// For updates, use existing settings but allow CLI overrides
|
|
207
|
+
const predefinedAnswers = {
|
|
208
|
+
projectName,
|
|
209
|
+
backendOnly:
|
|
210
|
+
args.includes("--backend-only") || localSettings.backendOnly,
|
|
211
|
+
swaggerDocs:
|
|
212
|
+
args.includes("--swagger-docs") || localSettings.swaggerDocs,
|
|
213
|
+
tailwindcss:
|
|
214
|
+
args.includes("--tailwindcss") || localSettings.tailwindcss,
|
|
215
|
+
websocket: args.includes("--websocket") || localSettings.websocket,
|
|
216
|
+
prisma: args.includes("--prisma") || localSettings.prisma,
|
|
217
|
+
docker: args.includes("--docker") || localSettings.docker,
|
|
218
|
+
};
|
|
219
|
+
answer = await getAnswer(predefinedAnswers);
|
|
220
|
+
// IMPORTANT: Update updateAnswer with the NEW answer after getting user input
|
|
221
|
+
if (answer !== null) {
|
|
222
|
+
updateAnswer = {
|
|
223
|
+
projectName,
|
|
224
|
+
backendOnly: answer.backendOnly,
|
|
225
|
+
swaggerDocs: answer.swaggerDocs,
|
|
226
|
+
tailwindcss: answer.tailwindcss,
|
|
227
|
+
websocket: answer.websocket,
|
|
228
|
+
prisma: answer.prisma,
|
|
229
|
+
docker: answer.docker,
|
|
230
|
+
isUpdate: true,
|
|
231
|
+
excludeFiles: localSettings.excludeFiles ?? [],
|
|
232
|
+
excludeFilePath: excludeFiles ?? [],
|
|
233
|
+
filePath: currentDir,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
} else {
|
|
237
|
+
// It's a new project - use CLI arguments
|
|
238
|
+
let useBackendOnly = args.includes("--backend-only");
|
|
239
|
+
let useSwaggerDocs = args.includes("--swagger-docs");
|
|
240
|
+
let useTailwind = args.includes("--tailwindcss");
|
|
241
|
+
let useWebsocket = args.includes("--websocket");
|
|
242
|
+
let usePrisma = args.includes("--prisma");
|
|
243
|
+
let useDocker = args.includes("--docker");
|
|
244
|
+
const predefinedAnswers = {
|
|
245
|
+
projectName,
|
|
246
|
+
backendOnly: useBackendOnly,
|
|
247
|
+
swaggerDocs: useSwaggerDocs,
|
|
248
|
+
tailwindcss: useTailwind,
|
|
249
|
+
websocket: useWebsocket,
|
|
250
|
+
prisma: usePrisma,
|
|
251
|
+
docker: useDocker,
|
|
252
|
+
};
|
|
253
|
+
answer = await getAnswer(predefinedAnswers);
|
|
254
|
+
}
|
|
255
|
+
if (answer === null) {
|
|
256
|
+
console.log(chalk.red("Installation cancelled."));
|
|
257
|
+
return;
|
|
147
258
|
}
|
|
148
259
|
} else {
|
|
260
|
+
// No project name provided - interactive mode
|
|
149
261
|
answer = await getAnswer();
|
|
150
262
|
}
|
|
151
263
|
if (answer === null) {
|
|
@@ -201,7 +313,7 @@ async function main() {
|
|
|
201
313
|
composerPkg("ezyang/htmlpurifier"),
|
|
202
314
|
composerPkg("symfony/uid"),
|
|
203
315
|
composerPkg("brick/math"),
|
|
204
|
-
composerPkg("tsnc/prisma-php"),
|
|
316
|
+
// composerPkg("tsnc/prisma-php"),
|
|
205
317
|
];
|
|
206
318
|
if (answer.swaggerDocs) {
|
|
207
319
|
npmDependencies.push(
|
|
@@ -266,24 +378,57 @@ async function main() {
|
|
|
266
378
|
if (updateAnswer?.isUpdate) {
|
|
267
379
|
const updateUninstallNpmDependencies = [];
|
|
268
380
|
const updateUninstallComposerDependencies = [];
|
|
381
|
+
// Helper function to check if a composer package is installed
|
|
382
|
+
const isComposerPackageInstalled = (packageName) => {
|
|
383
|
+
try {
|
|
384
|
+
const composerJsonPath = path.join(projectPath, "composer.json");
|
|
385
|
+
if (fs.existsSync(composerJsonPath)) {
|
|
386
|
+
const composerJson = JSON.parse(
|
|
387
|
+
fs.readFileSync(composerJsonPath, "utf8")
|
|
388
|
+
);
|
|
389
|
+
return !!(
|
|
390
|
+
composerJson.require && composerJson.require[packageName]
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
return false;
|
|
394
|
+
} catch {
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
// Helper function to check if an npm package is installed
|
|
399
|
+
const isNpmPackageInstalled = (packageName) => {
|
|
400
|
+
try {
|
|
401
|
+
const packageJsonPath = path.join(projectPath, "package.json");
|
|
402
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
403
|
+
const packageJson = JSON.parse(
|
|
404
|
+
fs.readFileSync(packageJsonPath, "utf8")
|
|
405
|
+
);
|
|
406
|
+
return !!(
|
|
407
|
+
(packageJson.dependencies &&
|
|
408
|
+
packageJson.dependencies[packageName]) ||
|
|
409
|
+
(packageJson.devDependencies &&
|
|
410
|
+
packageJson.devDependencies[packageName])
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
return false;
|
|
414
|
+
} catch {
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
};
|
|
269
418
|
if (updateAnswer.backendOnly) {
|
|
270
419
|
nonBackendFiles.forEach((file) => {
|
|
271
420
|
const filePath = path.join(projectPath, "src", "app", file);
|
|
272
421
|
if (fs.existsSync(filePath)) {
|
|
273
|
-
fs.unlinkSync(filePath);
|
|
422
|
+
fs.unlinkSync(filePath);
|
|
274
423
|
console.log(`${file} was deleted successfully.`);
|
|
275
|
-
} else {
|
|
276
|
-
console.log(`${file} does not exist.`);
|
|
277
424
|
}
|
|
278
425
|
});
|
|
279
426
|
const backendOnlyFolders = ["js", "css"];
|
|
280
427
|
backendOnlyFolders.forEach((folder) => {
|
|
281
428
|
const folderPath = path.join(projectPath, "src", "app", folder);
|
|
282
429
|
if (fs.existsSync(folderPath)) {
|
|
283
|
-
fs.rmSync(folderPath, { recursive: true, force: true });
|
|
430
|
+
fs.rmSync(folderPath, { recursive: true, force: true });
|
|
284
431
|
console.log(`${folder} was deleted successfully.`);
|
|
285
|
-
} else {
|
|
286
|
-
console.log(`${folder} does not exist.`);
|
|
287
432
|
}
|
|
288
433
|
});
|
|
289
434
|
}
|
|
@@ -295,81 +440,92 @@ async function main() {
|
|
|
295
440
|
"swagger-docs"
|
|
296
441
|
);
|
|
297
442
|
if (fs.existsSync(swaggerDocsFolder)) {
|
|
298
|
-
fs.rmSync(swaggerDocsFolder, { recursive: true, force: true });
|
|
443
|
+
fs.rmSync(swaggerDocsFolder, { recursive: true, force: true });
|
|
299
444
|
console.log(`swagger-docs was deleted successfully.`);
|
|
300
445
|
}
|
|
301
446
|
const swaggerFiles = ["swagger-config.ts"];
|
|
302
447
|
swaggerFiles.forEach((file) => {
|
|
303
448
|
const filePath = path.join(projectPath, "settings", file);
|
|
304
449
|
if (fs.existsSync(filePath)) {
|
|
305
|
-
fs.unlinkSync(filePath);
|
|
450
|
+
fs.unlinkSync(filePath);
|
|
306
451
|
console.log(`${file} was deleted successfully.`);
|
|
307
|
-
} else {
|
|
308
|
-
console.log(`${file} does not exist.`);
|
|
309
452
|
}
|
|
310
453
|
});
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
"
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
454
|
+
// Only add to uninstall list if packages are actually installed
|
|
455
|
+
if (isNpmPackageInstalled("swagger-jsdoc")) {
|
|
456
|
+
updateUninstallNpmDependencies.push("swagger-jsdoc");
|
|
457
|
+
}
|
|
458
|
+
if (isNpmPackageInstalled("@types/swagger-jsdoc")) {
|
|
459
|
+
updateUninstallNpmDependencies.push("@types/swagger-jsdoc");
|
|
460
|
+
}
|
|
461
|
+
if (isNpmPackageInstalled("prompts")) {
|
|
462
|
+
updateUninstallNpmDependencies.push("prompts");
|
|
463
|
+
}
|
|
464
|
+
if (isNpmPackageInstalled("@types/prompts")) {
|
|
465
|
+
updateUninstallNpmDependencies.push("@types/prompts");
|
|
466
|
+
}
|
|
317
467
|
}
|
|
318
468
|
if (!updateAnswer.tailwindcss) {
|
|
319
469
|
const tailwindFiles = ["postcss.config.js"];
|
|
320
470
|
tailwindFiles.forEach((file) => {
|
|
321
471
|
const filePath = path.join(projectPath, file);
|
|
322
472
|
if (fs.existsSync(filePath)) {
|
|
323
|
-
fs.unlinkSync(filePath);
|
|
473
|
+
fs.unlinkSync(filePath);
|
|
324
474
|
console.log(`${file} was deleted successfully.`);
|
|
325
|
-
} else {
|
|
326
|
-
console.log(`${file} does not exist.`);
|
|
327
475
|
}
|
|
328
476
|
});
|
|
329
|
-
|
|
477
|
+
// Only add to uninstall list if packages are actually installed
|
|
478
|
+
const tailwindPackages = [
|
|
330
479
|
"tailwindcss",
|
|
331
480
|
"postcss",
|
|
332
481
|
"postcss-cli",
|
|
333
482
|
"@tailwindcss/postcss",
|
|
334
|
-
"cssnano"
|
|
335
|
-
|
|
483
|
+
"cssnano",
|
|
484
|
+
];
|
|
485
|
+
tailwindPackages.forEach((pkg) => {
|
|
486
|
+
if (isNpmPackageInstalled(pkg)) {
|
|
487
|
+
updateUninstallNpmDependencies.push(pkg);
|
|
488
|
+
}
|
|
489
|
+
});
|
|
336
490
|
}
|
|
337
491
|
if (!updateAnswer.websocket) {
|
|
338
|
-
const websocketFiles = [
|
|
339
|
-
"restart-websocket.ts",
|
|
340
|
-
"restart-websocket.bat",
|
|
341
|
-
];
|
|
492
|
+
const websocketFiles = ["restart-websocket.ts"];
|
|
342
493
|
websocketFiles.forEach((file) => {
|
|
343
494
|
const filePath = path.join(projectPath, "settings", file);
|
|
344
495
|
if (fs.existsSync(filePath)) {
|
|
345
|
-
fs.unlinkSync(filePath);
|
|
496
|
+
fs.unlinkSync(filePath);
|
|
346
497
|
console.log(`${file} was deleted successfully.`);
|
|
347
|
-
} else {
|
|
348
|
-
console.log(`${file} does not exist.`);
|
|
349
498
|
}
|
|
350
499
|
});
|
|
351
|
-
const websocketFolder = path.join(
|
|
500
|
+
const websocketFolder = path.join(
|
|
501
|
+
projectPath,
|
|
502
|
+
"src",
|
|
503
|
+
"Lib",
|
|
504
|
+
"Websocket"
|
|
505
|
+
);
|
|
352
506
|
if (fs.existsSync(websocketFolder)) {
|
|
353
|
-
fs.rmSync(websocketFolder, { recursive: true, force: true });
|
|
507
|
+
fs.rmSync(websocketFolder, { recursive: true, force: true });
|
|
354
508
|
console.log(`Websocket folder was deleted successfully.`);
|
|
355
509
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
"
|
|
359
|
-
|
|
360
|
-
if (
|
|
361
|
-
|
|
362
|
-
console.log(`websocket-server.php was deleted successfully.`);
|
|
510
|
+
// Only add to uninstall list if packages are actually installed
|
|
511
|
+
if (isNpmPackageInstalled("chokidar-cli")) {
|
|
512
|
+
updateUninstallNpmDependencies.push("chokidar-cli");
|
|
513
|
+
}
|
|
514
|
+
if (isComposerPackageInstalled("cboden/ratchet")) {
|
|
515
|
+
updateUninstallComposerDependencies.push("cboden/ratchet");
|
|
363
516
|
}
|
|
364
|
-
updateUninstallNpmDependencies.push("chokidar-cli");
|
|
365
|
-
updateUninstallComposerDependencies.push("cboden/ratchet");
|
|
366
517
|
}
|
|
367
518
|
if (!updateAnswer.prisma) {
|
|
368
|
-
|
|
519
|
+
const prismaPackages = [
|
|
369
520
|
"prisma",
|
|
370
521
|
"@prisma/client",
|
|
371
|
-
"@prisma/internals"
|
|
372
|
-
|
|
522
|
+
"@prisma/internals",
|
|
523
|
+
];
|
|
524
|
+
prismaPackages.forEach((pkg) => {
|
|
525
|
+
if (isNpmPackageInstalled(pkg)) {
|
|
526
|
+
updateUninstallNpmDependencies.push(pkg);
|
|
527
|
+
}
|
|
528
|
+
});
|
|
373
529
|
}
|
|
374
530
|
if (!updateAnswer.docker) {
|
|
375
531
|
const dockerFiles = [
|
|
@@ -381,14 +537,18 @@ async function main() {
|
|
|
381
537
|
dockerFiles.forEach((file) => {
|
|
382
538
|
const filePath = path.join(projectPath, file);
|
|
383
539
|
if (fs.existsSync(filePath)) {
|
|
384
|
-
fs.unlinkSync(filePath);
|
|
540
|
+
fs.unlinkSync(filePath);
|
|
385
541
|
console.log(`${file} was deleted successfully.`);
|
|
386
|
-
} else {
|
|
387
|
-
console.log(`${file} does not exist.`);
|
|
388
542
|
}
|
|
389
543
|
});
|
|
390
544
|
}
|
|
545
|
+
// Only uninstall if there are packages to uninstall
|
|
391
546
|
if (updateUninstallNpmDependencies.length > 0) {
|
|
547
|
+
console.log(
|
|
548
|
+
`Uninstalling npm packages: ${updateUninstallNpmDependencies.join(
|
|
549
|
+
", "
|
|
550
|
+
)}`
|
|
551
|
+
);
|
|
392
552
|
await uninstallNpmDependencies(
|
|
393
553
|
projectPath,
|
|
394
554
|
updateUninstallNpmDependencies,
|
|
@@ -396,6 +556,11 @@ async function main() {
|
|
|
396
556
|
);
|
|
397
557
|
}
|
|
398
558
|
if (updateUninstallComposerDependencies.length > 0) {
|
|
559
|
+
console.log(
|
|
560
|
+
`Uninstalling composer packages: ${updateUninstallComposerDependencies.join(
|
|
561
|
+
", "
|
|
562
|
+
)}`
|
|
563
|
+
);
|
|
399
564
|
await uninstallComposerDependencies(
|
|
400
565
|
projectPath,
|
|
401
566
|
updateUninstallComposerDependencies
|