feat: init
15673be7
4 file(s) · +438 −0
| 1 | + | # bhvr/.gitignore |
|
| 2 | + | # dependencies |
|
| 3 | + | node_modules |
|
| 4 | + | .pnp |
|
| 5 | + | .pnp.js |
|
| 6 | + | ||
| 7 | + | # testing |
|
| 8 | + | coverage |
|
| 9 | + | ||
| 10 | + | # production |
|
| 11 | + | dist |
|
| 12 | + | build |
|
| 13 | + | ||
| 14 | + | # misc |
|
| 15 | + | .DS_Store |
|
| 16 | + | .env |
|
| 17 | + | .env.local |
|
| 18 | + | .env.development.local |
|
| 19 | + | .env.test.local |
|
| 20 | + | .env.production.local |
|
| 21 | + | .env*.local |
|
| 22 | + | ||
| 23 | + | # logs |
|
| 24 | + | npm-debug.log* |
|
| 25 | + | yarn-debug.log* |
|
| 26 | + | yarn-error.log* |
|
| 27 | + | pnpm-debug.log* |
|
| 28 | + | ||
| 29 | + | # editor directories and files |
|
| 30 | + | .idea |
|
| 31 | + | .vscode/* |
|
| 32 | + | !.vscode/extensions.json |
|
| 33 | + | !.vscode/settings.json |
|
| 34 | + | *.suo |
|
| 35 | + | *.ntvs* |
|
| 36 | + | *.njsproj |
|
| 37 | + | *.sln |
|
| 38 | + | *.sw? |
|
| 39 | + | ||
| 40 | + | # Bun |
|
| 41 | + | bun.lockb |
| 1 | + | { |
|
| 2 | + | "lockfileVersion": 1, |
|
| 3 | + | "workspaces": { |
|
| 4 | + | "": { |
|
| 5 | + | "name": "create-bhvr", |
|
| 6 | + | "dependencies": { |
|
| 7 | + | "chalk": "^5.3.0", |
|
| 8 | + | "commander": "^11.1.0", |
|
| 9 | + | "degit": "^2.8.4", |
|
| 10 | + | "execa": "^7.1.1", |
|
| 11 | + | "fs-extra": "^11.2.0", |
|
| 12 | + | "ora": "^6.3.1", |
|
| 13 | + | "prompts": "^2.4.2", |
|
| 14 | + | }, |
|
| 15 | + | }, |
|
| 16 | + | }, |
|
| 17 | + | "packages": { |
|
| 18 | + | "ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], |
|
| 19 | + | ||
| 20 | + | "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], |
|
| 21 | + | ||
| 22 | + | "bl": ["bl@5.1.0", "", { "dependencies": { "buffer": "^6.0.3", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ=="], |
|
| 23 | + | ||
| 24 | + | "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], |
|
| 25 | + | ||
| 26 | + | "chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="], |
|
| 27 | + | ||
| 28 | + | "cli-cursor": ["cli-cursor@4.0.0", "", { "dependencies": { "restore-cursor": "^4.0.0" } }, "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg=="], |
|
| 29 | + | ||
| 30 | + | "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="], |
|
| 31 | + | ||
| 32 | + | "clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], |
|
| 33 | + | ||
| 34 | + | "commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], |
|
| 35 | + | ||
| 36 | + | "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], |
|
| 37 | + | ||
| 38 | + | "defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "^1.0.2" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="], |
|
| 39 | + | ||
| 40 | + | "degit": ["degit@2.8.4", "", { "bin": { "degit": "degit" } }, "sha512-vqYuzmSA5I50J882jd+AbAhQtgK6bdKUJIex1JNfEUPENCgYsxugzKVZlFyMwV4i06MmnV47/Iqi5Io86zf3Ng=="], |
|
| 41 | + | ||
| 42 | + | "execa": ["execa@7.2.0", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.1", "human-signals": "^4.3.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^3.0.7", "strip-final-newline": "^3.0.0" } }, "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA=="], |
|
| 43 | + | ||
| 44 | + | "fs-extra": ["fs-extra@11.3.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew=="], |
|
| 45 | + | ||
| 46 | + | "get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], |
|
| 47 | + | ||
| 48 | + | "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], |
|
| 49 | + | ||
| 50 | + | "human-signals": ["human-signals@4.3.1", "", {}, "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ=="], |
|
| 51 | + | ||
| 52 | + | "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], |
|
| 53 | + | ||
| 54 | + | "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], |
|
| 55 | + | ||
| 56 | + | "is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="], |
|
| 57 | + | ||
| 58 | + | "is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="], |
|
| 59 | + | ||
| 60 | + | "is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="], |
|
| 61 | + | ||
| 62 | + | "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], |
|
| 63 | + | ||
| 64 | + | "jsonfile": ["jsonfile@6.1.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="], |
|
| 65 | + | ||
| 66 | + | "kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], |
|
| 67 | + | ||
| 68 | + | "log-symbols": ["log-symbols@5.1.0", "", { "dependencies": { "chalk": "^5.0.0", "is-unicode-supported": "^1.1.0" } }, "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA=="], |
|
| 69 | + | ||
| 70 | + | "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], |
|
| 71 | + | ||
| 72 | + | "mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="], |
|
| 73 | + | ||
| 74 | + | "npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="], |
|
| 75 | + | ||
| 76 | + | "onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="], |
|
| 77 | + | ||
| 78 | + | "ora": ["ora@6.3.1", "", { "dependencies": { "chalk": "^5.0.0", "cli-cursor": "^4.0.0", "cli-spinners": "^2.6.1", "is-interactive": "^2.0.0", "is-unicode-supported": "^1.1.0", "log-symbols": "^5.1.0", "stdin-discarder": "^0.1.0", "strip-ansi": "^7.0.1", "wcwidth": "^1.0.1" } }, "sha512-ERAyNnZOfqM+Ao3RAvIXkYh5joP220yf59gVe2X/cI6SiCxIdi4c9HZKZD8R6q/RDXEje1THBju6iExiSsgJaQ=="], |
|
| 79 | + | ||
| 80 | + | "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], |
|
| 81 | + | ||
| 82 | + | "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="], |
|
| 83 | + | ||
| 84 | + | "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], |
|
| 85 | + | ||
| 86 | + | "restore-cursor": ["restore-cursor@4.0.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg=="], |
|
| 87 | + | ||
| 88 | + | "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], |
|
| 89 | + | ||
| 90 | + | "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], |
|
| 91 | + | ||
| 92 | + | "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], |
|
| 93 | + | ||
| 94 | + | "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], |
|
| 95 | + | ||
| 96 | + | "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], |
|
| 97 | + | ||
| 98 | + | "stdin-discarder": ["stdin-discarder@0.1.0", "", { "dependencies": { "bl": "^5.0.0" } }, "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ=="], |
|
| 99 | + | ||
| 100 | + | "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], |
|
| 101 | + | ||
| 102 | + | "strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], |
|
| 103 | + | ||
| 104 | + | "strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="], |
|
| 105 | + | ||
| 106 | + | "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], |
|
| 107 | + | ||
| 108 | + | "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], |
|
| 109 | + | ||
| 110 | + | "wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="], |
|
| 111 | + | ||
| 112 | + | "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], |
|
| 113 | + | ||
| 114 | + | "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], |
|
| 115 | + | ||
| 116 | + | "restore-cursor/onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], |
|
| 117 | + | ||
| 118 | + | "restore-cursor/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], |
|
| 119 | + | } |
|
| 120 | + | } |
| 1 | + | #!/usr/bin/env node |
|
| 2 | + | ||
| 3 | + | import fs from 'fs-extra'; |
|
| 4 | + | import path from 'path'; |
|
| 5 | + | import { fileURLToPath } from 'url'; |
|
| 6 | + | import prompts from 'prompts'; |
|
| 7 | + | import { program } from 'commander'; |
|
| 8 | + | import chalk from 'chalk'; |
|
| 9 | + | import ora from 'ora'; |
|
| 10 | + | import { execa } from 'execa'; |
|
| 11 | + | import degit from 'degit'; |
|
| 12 | + | ||
| 13 | + | const __filename = fileURLToPath(import.meta.url); |
|
| 14 | + | const __dirname = path.dirname(__filename); |
|
| 15 | + | ||
| 16 | + | // GitHub repository for the template |
|
| 17 | + | const DEFAULT_REPO = 'stevedylandev/bhvr'; // Replace with your actual repo |
|
| 18 | + | ||
| 19 | + | // Set up the CLI program |
|
| 20 | + | program |
|
| 21 | + | .name('create-bhvr') |
|
| 22 | + | .description('Create a bhvr monorepo starter project') |
|
| 23 | + | .argument('[project-directory]', 'directory to create the project in') |
|
| 24 | + | .option('-y, --yes', 'skip confirmation prompts') |
|
| 25 | + | .option('--ts, --typescript', 'use TypeScript (default)') |
|
| 26 | + | .option('--repo <repo>', 'specify a custom GitHub repository as source', DEFAULT_REPO) |
|
| 27 | + | .option('--branch <branch>', 'specify a branch to use from the repository', 'main') |
|
| 28 | + | .action(async (projectDirectory, options) => { |
|
| 29 | + | try { |
|
| 30 | + | const result = await createProject(projectDirectory, options); |
|
| 31 | + | if (result) { |
|
| 32 | + | console.log(chalk.green.bold('\n🎉 Project created successfully!')); |
|
| 33 | + | console.log('\nNext steps:'); |
|
| 34 | + | ||
| 35 | + | if (!result.dependenciesInstalled) { |
|
| 36 | + | console.log(chalk.cyan(` cd ${result.projectName}`)); |
|
| 37 | + | console.log(chalk.cyan(' bun install')); |
|
| 38 | + | } else { |
|
| 39 | + | console.log(chalk.cyan(` cd ${result.projectName}`)); |
|
| 40 | + | } |
|
| 41 | + | ||
| 42 | + | console.log(chalk.cyan(' bun run dev:client # Start the client')); |
|
| 43 | + | console.log(chalk.cyan(' bun run dev:server # Start the server in another terminal')); |
|
| 44 | + | return |
|
| 45 | + | } |
|
| 46 | + | } catch (err) { |
|
| 47 | + | console.error(chalk.red('Error creating project:'), err); |
|
| 48 | + | process.exit(1); |
|
| 49 | + | } |
|
| 50 | + | }); |
|
| 51 | + | ||
| 52 | + | program.parse(); |
|
| 53 | + | ||
| 54 | + | async function createProject(projectDirectory, options) { |
|
| 55 | + | // If project directory not provided, prompt for it |
|
| 56 | + | let projectName = projectDirectory; |
|
| 57 | + | ||
| 58 | + | if (!projectName && !options.yes) { |
|
| 59 | + | const response = await prompts({ |
|
| 60 | + | type: 'text', |
|
| 61 | + | name: 'projectName', |
|
| 62 | + | message: 'What is the name of your project?', |
|
| 63 | + | initial: 'my-bhvr-app' |
|
| 64 | + | }); |
|
| 65 | + | ||
| 66 | + | if (!response.projectName) { |
|
| 67 | + | console.log(chalk.yellow('Project creation cancelled.')); |
|
| 68 | + | return null; |
|
| 69 | + | } |
|
| 70 | + | ||
| 71 | + | projectName = response.projectName; |
|
| 72 | + | } else if (!projectName) { |
|
| 73 | + | projectName = 'my-bhvr-app'; |
|
| 74 | + | } |
|
| 75 | + | ||
| 76 | + | // Create the project directory |
|
| 77 | + | const projectPath = path.resolve(process.cwd(), projectName); |
|
| 78 | + | ||
| 79 | + | // Check if directory exists and is not empty |
|
| 80 | + | if (fs.existsSync(projectPath)) { |
|
| 81 | + | const files = fs.readdirSync(projectPath); |
|
| 82 | + | ||
| 83 | + | if (files.length > 0 && !options.yes) { |
|
| 84 | + | const { overwrite } = await prompts({ |
|
| 85 | + | type: 'confirm', |
|
| 86 | + | name: 'overwrite', |
|
| 87 | + | message: `The directory ${projectName} already exists and is not empty. Do you want to overwrite it?`, |
|
| 88 | + | initial: false |
|
| 89 | + | }); |
|
| 90 | + | ||
| 91 | + | if (!overwrite) { |
|
| 92 | + | console.log(chalk.yellow('Project creation cancelled.')); |
|
| 93 | + | return null; |
|
| 94 | + | } |
|
| 95 | + | ||
| 96 | + | // Clear directory if overwriting |
|
| 97 | + | await fs.emptyDir(projectPath); |
|
| 98 | + | } |
|
| 99 | + | } |
|
| 100 | + | ||
| 101 | + | // Create directory if it doesn't exist |
|
| 102 | + | fs.ensureDirSync(projectPath); |
|
| 103 | + | ||
| 104 | + | // Clone template from GitHub |
|
| 105 | + | const repoPath = options.repo || DEFAULT_REPO; |
|
| 106 | + | const branchSpecifier = options.branch ? `#${options.branch}` : ''; |
|
| 107 | + | const repoUrl = `${repoPath}${branchSpecifier}`; |
|
| 108 | + | ||
| 109 | + | //console.log(chalk.blue(`\nCreating a new bhvr project in ${chalk.bold(projectPath)}`)); |
|
| 110 | + | //console.log(chalk.blue(`Downloading template from ${chalk.bold(repoUrl)}...`)); |
|
| 111 | + | ||
| 112 | + | const spinner = ora('Downloading template...').start(); |
|
| 113 | + | ||
| 114 | + | try { |
|
| 115 | + | const emitter = degit(repoUrl, { |
|
| 116 | + | cache: false, |
|
| 117 | + | force: true, |
|
| 118 | + | verbose: false, |
|
| 119 | + | }); |
|
| 120 | + | ||
| 121 | + | await emitter.clone(projectPath); |
|
| 122 | + | spinner.succeed('Template downloaded successfully'); |
|
| 123 | + | ||
| 124 | + | // Update package.json with project name |
|
| 125 | + | const pkgJsonPath = path.join(projectPath, 'package.json'); |
|
| 126 | + | if (fs.existsSync(pkgJsonPath)) { |
|
| 127 | + | const pkgJson = await fs.readJson(pkgJsonPath); |
|
| 128 | + | pkgJson.name = projectName; |
|
| 129 | + | await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 }); |
|
| 130 | + | console.log(chalk.blue('Updated package.json with project name')); |
|
| 131 | + | } |
|
| 132 | + | ||
| 133 | + | // Remove the .git directory if it exists |
|
| 134 | + | const gitDir = path.join(projectPath, '.git'); |
|
| 135 | + | if (fs.existsSync(gitDir)) { |
|
| 136 | + | await fs.remove(gitDir); |
|
| 137 | + | console.log(chalk.blue('Removed .git directory')); |
|
| 138 | + | } |
|
| 139 | + | ||
| 140 | + | // Initialize git repository? |
|
| 141 | + | let gitInitialized = false; |
|
| 142 | + | ||
| 143 | + | if (!options.yes) { |
|
| 144 | + | const gitResponse = await prompts({ |
|
| 145 | + | type: 'confirm', |
|
| 146 | + | name: 'initGit', |
|
| 147 | + | message: 'Initialize a git repository?', |
|
| 148 | + | initial: true |
|
| 149 | + | }); |
|
| 150 | + | ||
| 151 | + | if (gitResponse.initGit) { |
|
| 152 | + | try { |
|
| 153 | + | spinner.start('Initializing git repository...'); |
|
| 154 | + | await execa('git', ['init'], { cwd: projectPath }); |
|
| 155 | + | await execa('git', ['add', '.'], { cwd: projectPath }); |
|
| 156 | + | await execa('git', ['commit', '-m', 'Initial commit from create-bhvr'], { cwd: projectPath }); |
|
| 157 | + | spinner.succeed('Git repository initialized'); |
|
| 158 | + | gitInitialized = true; |
|
| 159 | + | } catch (err) { |
|
| 160 | + | spinner.fail('Failed to initialize git repository. Is git installed?'); |
|
| 161 | + | console.error(chalk.red('Git error:'), err.message); |
|
| 162 | + | } |
|
| 163 | + | } |
|
| 164 | + | } else { |
|
| 165 | + | // If using --yes, automatically initialize git |
|
| 166 | + | try { |
|
| 167 | + | spinner.start('Initializing git repository...'); |
|
| 168 | + | await execa('git', ['init'], { cwd: projectPath }); |
|
| 169 | + | await execa('git', ['add', '.'], { cwd: projectPath }); |
|
| 170 | + | await execa('git', ['commit', '-m', 'Initial commit from create-bhvr'], { cwd: projectPath }); |
|
| 171 | + | spinner.succeed('Git repository initialized'); |
|
| 172 | + | gitInitialized = true; |
|
| 173 | + | } catch (err) { |
|
| 174 | + | spinner.fail('Failed to initialize git repository. Is git installed?'); |
|
| 175 | + | } |
|
| 176 | + | } |
|
| 177 | + | ||
| 178 | + | // Install dependencies? |
|
| 179 | + | let dependenciesInstalled = false; |
|
| 180 | + | ||
| 181 | + | if (!options.yes) { |
|
| 182 | + | const depsResponse = await prompts({ |
|
| 183 | + | type: 'confirm', |
|
| 184 | + | name: 'installDeps', |
|
| 185 | + | message: 'Install dependencies?', |
|
| 186 | + | initial: true |
|
| 187 | + | }); |
|
| 188 | + | ||
| 189 | + | if (depsResponse.installDeps) { |
|
| 190 | + | spinner.start('Installing dependencies...'); |
|
| 191 | + | try { |
|
| 192 | + | // Try with bun first |
|
| 193 | + | await execa('bun', ['install'], { cwd: projectPath }); |
|
| 194 | + | spinner.succeed('Dependencies installed with bun'); |
|
| 195 | + | dependenciesInstalled = true; |
|
| 196 | + | } catch (bunErr) { |
|
| 197 | + | // If bun fails, try with npm |
|
| 198 | + | try { |
|
| 199 | + | spinner.text = 'Installing dependencies with npm...'; |
|
| 200 | + | await execa('npm', ['install'], { cwd: projectPath }); |
|
| 201 | + | spinner.succeed('Dependencies installed with npm'); |
|
| 202 | + | dependenciesInstalled = true; |
|
| 203 | + | } catch (npmErr) { |
|
| 204 | + | spinner.fail('Failed to install dependencies.'); |
|
| 205 | + | console.log(chalk.yellow('You can install them manually after navigating to the project directory.')); |
|
| 206 | + | } |
|
| 207 | + | } |
|
| 208 | + | } |
|
| 209 | + | } else { |
|
| 210 | + | // If using --yes, automatically install dependencies |
|
| 211 | + | spinner.start('Installing dependencies...'); |
|
| 212 | + | try { |
|
| 213 | + | await execa('bun', ['install'], { cwd: projectPath }); |
|
| 214 | + | spinner.succeed('Dependencies installed with bun'); |
|
| 215 | + | dependenciesInstalled = true; |
|
| 216 | + | } catch (bunErr) { |
|
| 217 | + | try { |
|
| 218 | + | spinner.text = 'Installing dependencies with npm...'; |
|
| 219 | + | await execa('npm', ['install'], { cwd: projectPath }); |
|
| 220 | + | spinner.succeed('Dependencies installed with npm'); |
|
| 221 | + | dependenciesInstalled = true; |
|
| 222 | + | } catch (npmErr) { |
|
| 223 | + | spinner.fail('Failed to install dependencies. You can install them manually later.'); |
|
| 224 | + | } |
|
| 225 | + | } |
|
| 226 | + | } |
|
| 227 | + | ||
| 228 | + | return { |
|
| 229 | + | projectName, |
|
| 230 | + | gitInitialized, |
|
| 231 | + | dependenciesInstalled |
|
| 232 | + | }; |
|
| 233 | + | } catch (err) { |
|
| 234 | + | spinner.fail('Failed to download template'); |
|
| 235 | + | throw err; |
|
| 236 | + | } |
|
| 237 | + | } |
| 1 | + | { |
|
| 2 | + | "name": "create-bhvr", |
|
| 3 | + | "version": "0.0.5", |
|
| 4 | + | "description": "Create a new bhvr monorepo starter project", |
|
| 5 | + | "main": "index.js", |
|
| 6 | + | "type": "module", |
|
| 7 | + | "bin": { |
|
| 8 | + | "create-vrhb": "index.js" |
|
| 9 | + | }, |
|
| 10 | + | "files": [ |
|
| 11 | + | "index.js" |
|
| 12 | + | ], |
|
| 13 | + | "scripts": { |
|
| 14 | + | "test": "echo \"Error: no test specified\" && exit 1" |
|
| 15 | + | }, |
|
| 16 | + | "keywords": [ |
|
| 17 | + | "bun", |
|
| 18 | + | "vite", |
|
| 19 | + | "react", |
|
| 20 | + | "hono", |
|
| 21 | + | "monorepo", |
|
| 22 | + | "starter", |
|
| 23 | + | "template", |
|
| 24 | + | "create" |
|
| 25 | + | ], |
|
| 26 | + | "author": "Steve Simkins", |
|
| 27 | + | "license": "MIT", |
|
| 28 | + | "dependencies": { |
|
| 29 | + | "chalk": "^5.3.0", |
|
| 30 | + | "commander": "^11.1.0", |
|
| 31 | + | "fs-extra": "^11.2.0", |
|
| 32 | + | "prompts": "^2.4.2", |
|
| 33 | + | "degit": "^2.8.4", |
|
| 34 | + | "ora": "^6.3.1", |
|
| 35 | + | "execa": "^7.1.1" |
|
| 36 | + | }, |
|
| 37 | + | "engines": { |
|
| 38 | + | "node": ">=14.16" |
|
| 39 | + | } |
|
| 40 | + | } |