From c332e42a733d83f7de39ce67f74a8cbe4cd1cf1b Mon Sep 17 00:00:00 2001 From: Ion Gireada Date: Fri, 4 Jul 2025 10:38:32 +0300 Subject: [PATCH 1/8] refactor: :zap: refactored setup.js to use inquirer --- package-lock.json | 678 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 1 + setup.js | 343 +++++++++++------------ 3 files changed, 831 insertions(+), 191 deletions(-) diff --git a/package-lock.json b/package-lock.json index d8fd799..c4fa2d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "js-quality-starter", + "name": "{{PROJECT_NAME}}", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "js-quality-starter", + "name": "{{PROJECT_NAME}}", "version": "1.0.0", "license": "MIT", "devDependencies": { @@ -13,6 +13,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-jest": "^28.2.0", "husky": "^8.0.0", + "inquirer": "^12.7.0", "jest": "^29.7.0", "lint-staged": "^15.2.2", "markdownlint-cli": "^0.45.0", @@ -653,6 +654,384 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@inquirer/checkbox": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.1.9.tgz", + "integrity": "sha512-DBJBkzI5Wx4jFaYm221LHvAhpKYkhVS0k9plqHwaHhofGNxvYB7J3Bz8w+bFJ05zaMb0sZNHo4KdmENQFlNTuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.14", + "@inquirer/figures": "^1.0.12", + "@inquirer/type": "^3.0.7", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.13", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.13.tgz", + "integrity": "sha512-EkCtvp67ICIVVzjsquUiVSd+V5HRGOGQfsqA4E4vMWhYnB7InUL0pa0TIWt1i+OfP16Gkds8CdIu6yGZwOM1Yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.14", + "@inquirer/type": "^3.0.7" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.1.14", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.14.tgz", + "integrity": "sha512-Ma+ZpOJPewtIYl6HZHZckeX1STvDnHTCB2GVINNUlSEn2Am6LddWwfPkIGY0IUFVjUUrr/93XlBwTK6mfLjf0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/figures": "^1.0.12", + "@inquirer/type": "^3.0.7", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@inquirer/core/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/core/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.14.tgz", + "integrity": "sha512-yd2qtLl4QIIax9DTMZ1ZN2pFrrj+yL3kgIWxm34SS6uwCr0sIhsNyudUjAo5q3TqI03xx4SEBkUJqZuAInp9uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.14", + "@inquirer/type": "^3.0.7", + "external-editor": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.16.tgz", + "integrity": "sha512-oiDqafWzMtofeJyyGkb1CTPaxUkjIcSxePHHQCfif8t3HV9pHcw1Kgdw3/uGpDvaFfeTluwQtWiqzPVjAqS3zA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.14", + "@inquirer/type": "^3.0.7", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.12.tgz", + "integrity": "sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.0.tgz", + "integrity": "sha512-opqpHPB1NjAmDISi3uvZOTrjEEU5CWVu/HBkDby8t93+6UxYX0Z7Ps0Ltjm5sZiEbWenjubwUkivAEYQmy9xHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.14", + "@inquirer/type": "^3.0.7" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.16.tgz", + "integrity": "sha512-kMrXAaKGavBEoBYUCgualbwA9jWUx2TjMA46ek+pEKy38+LFpL9QHlTd8PO2kWPUgI/KB+qi02o4y2rwXbzr3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.14", + "@inquirer/type": "^3.0.7" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.16.tgz", + "integrity": "sha512-g8BVNBj5Zeb5/Y3cSN+hDUL7CsIFDIuVxb9EPty3lkxBaYpjL5BNRKSYOF9yOLe+JOcKFd+TSVeADQ4iSY7rbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.14", + "@inquirer/type": "^3.0.7", + "ansi-escapes": "^4.3.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.6.0.tgz", + "integrity": "sha512-jAhL7tyMxB3Gfwn4HIJ0yuJ5pvcB5maYUcouGcgd/ub79f9MqZ+aVnBtuFf+VC2GTkCBF+R+eo7Vi63w5VZlzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.1.9", + "@inquirer/confirm": "^5.1.13", + "@inquirer/editor": "^4.2.14", + "@inquirer/expand": "^4.0.16", + "@inquirer/input": "^4.2.0", + "@inquirer/number": "^3.0.16", + "@inquirer/password": "^4.0.16", + "@inquirer/rawlist": "^4.1.4", + "@inquirer/search": "^3.0.16", + "@inquirer/select": "^4.2.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.4.tgz", + "integrity": "sha512-5GGvxVpXXMmfZNtvWw4IsHpR7RzqAR624xtkPd1NxxlV5M+pShMqzL4oRddRkg8rVEOK9fKdJp1jjVML2Lr7TQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.14", + "@inquirer/type": "^3.0.7", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.0.16.tgz", + "integrity": "sha512-POCmXo+j97kTGU6aeRjsPyuCpQQfKcMXdeTMw708ZMtWrj5aykZvlUxH4Qgz3+Y1L/cAVZsSpA+UgZCu2GMOMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.14", + "@inquirer/figures": "^1.0.12", + "@inquirer/type": "^3.0.7", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.2.4.tgz", + "integrity": "sha512-unTppUcTjmnbl/q+h8XeQDhAqIOmwWYWNyiiP2e3orXrg6tOaa5DHXja9PChCSbChOsktyKgOieRZFnajzxoBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.14", + "@inquirer/figures": "^1.0.12", + "@inquirer/type": "^3.0.7", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.7.tgz", + "integrity": "sha512-PfunHQcjwnju84L+ycmcMKB/pTPIngjUJvfnRhKY6FKPuYXlM4aQCb/nIdTFR6BEhMjFvngzvng/vBAJMZpLSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, "node_modules/@isaacs/balanced-match": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", @@ -1279,6 +1658,118 @@ "node": ">= 8" } }, + "node_modules/@oxlint/darwin-arm64": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@oxlint/darwin-arm64/-/darwin-arm64-1.5.0.tgz", + "integrity": "sha512-CxzOtmOwQfaXXwAAJzPInNHhzldMeFsga7oe9mUp5bYIa/mm/Aqs0lxyAP9RZXoxaUHJTbfJovSsl6PU6gbCHw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oxlint/darwin-x64": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@oxlint/darwin-x64/-/darwin-x64-1.5.0.tgz", + "integrity": "sha512-awD5yNGIRy2DrfzbrfeTSjZ+ITKr9+FGGvufquAB7kzfveFZNa621FpmCJ8MQY8hzXFD99iP7ClMNbaCzDfV/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oxlint/linux-arm64-gnu": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@oxlint/linux-arm64-gnu/-/linux-arm64-gnu-1.5.0.tgz", + "integrity": "sha512-Nr8oUAEo20WIBo/qi76dBo5IGw2bQcl7d2YbaigOSQoAGfHR9xE9hAySYhIsnv7W0jtAZu1YTn0So7Tg0idExw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxlint/linux-arm64-musl": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@oxlint/linux-arm64-musl/-/linux-arm64-musl-1.5.0.tgz", + "integrity": "sha512-H2MBL0LZnl3GP09r12tFfcv3Y2fvetMD1TYbf5cetYCQ7hG7aIYTsuOTENjZ0SDK+L9Id35YWFNP3YES+3tsgw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxlint/linux-x64-gnu": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@oxlint/linux-x64-gnu/-/linux-x64-gnu-1.5.0.tgz", + "integrity": "sha512-pRu77WJ+Uy0l6OkCjljnHuzOlSbMsN1mFDeAyzh8R69O44Mc2C7f1Fe+fbbW2kjgIwFQq8JkUffvPWr1MCMa+A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxlint/linux-x64-musl": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@oxlint/linux-x64-musl/-/linux-x64-musl-1.5.0.tgz", + "integrity": "sha512-qHG2YR+06pEAF4Gfp3T8hSaiI/IchdbuditnnVYxy32pN43vNMVDO7fU5hnNzJpxh6HozAD3uRrskBNvxgeSrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxlint/win32-arm64": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@oxlint/win32-arm64/-/win32-arm64-1.5.0.tgz", + "integrity": "sha512-/YRDPf1sPCF6B026buZTvh1vOF/pS+75aBDnxrDWIFhP1w3flqcI9v5QVjtq/sOZEWAoP2ee46CrxcxK5UuYag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oxlint/win32-x64": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@oxlint/win32-x64/-/win32-x64-1.5.0.tgz", + "integrity": "sha512-4HmkdYgDmejTxXESV1EBXd0zFLsoNJad+VrWZizzpTCmBnWEL5+tueEmEBBb4F55/sFZt8bdD//RbaTM9aOQJA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -2065,6 +2556,13 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true, + "license": "MIT" + }, "node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -2121,6 +2619,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -2777,6 +3285,21 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3152,6 +3675,19 @@ "url": "https://github.com/sponsors/typicode" } }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -3238,6 +3774,33 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/inquirer": { + "version": "12.7.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.7.0.tgz", + "integrity": "sha512-KKFRc++IONSyE2UYw9CJ1V0IWx5yQKomwB+pp3cWomWs+v2+ZsG11G2OVfAjFS6WWCppKw+RfKmpqGfSzD5QBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.14", + "@inquirer/prompts": "^7.6.0", + "@inquirer/type": "^3.0.7", + "ansi-escapes": "^4.3.2", + "mute-stream": "^2.0.0", + "run-async": "^4.0.4", + "rxjs": "^7.8.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, "node_modules/is-alphabetical": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", @@ -5384,6 +5947,16 @@ "dev": true, "license": "MIT" }, + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -5472,6 +6045,43 @@ "node": ">= 0.8.0" } }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/oxlint": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.5.0.tgz", + "integrity": "sha512-Oh48XZy6BY2jE9xKwN4DjwpK/l7LOUHfPJsZ/rUKudWN1RXHXBnJkubsgIHlfTwWJGYJU2LAlyXKZcE46mD4OQ==", + "dev": true, + "license": "MIT", + "bin": { + "oxc_language_server": "bin/oxc_language_server", + "oxlint": "bin/oxlint" + }, + "engines": { + "node": ">=8.*" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxlint/darwin-arm64": "1.5.0", + "@oxlint/darwin-x64": "1.5.0", + "@oxlint/linux-arm64-gnu": "1.5.0", + "@oxlint/linux-arm64-musl": "1.5.0", + "@oxlint/linux-x64-gnu": "1.5.0", + "@oxlint/linux-x64-musl": "1.5.0", + "@oxlint/win32-arm64": "1.5.0", + "@oxlint/win32-x64": "1.5.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -6037,6 +6647,20 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/run-async": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.4.tgz", + "integrity": "sha512-2cgeRHnV11lSXBEhq7sN7a5UVjTKm9JTb9x8ApIT//16D7QL96AgnNeWSGoB4gIHc0iYw/Ha0Z+waBaCYZVNhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "oxlint": "^1.2.0", + "prettier": "^3.5.3" + }, + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/run-con": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.3.2.tgz", @@ -6077,6 +6701,23 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, "node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -6443,6 +7084,19 @@ "dev": true, "license": "MIT" }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -6476,6 +7130,13 @@ "typescript": ">=4.8.4" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6868,6 +7529,19 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index edbc1c6..fbaf836 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-jest": "^28.2.0", "husky": "^8.0.0", + "inquirer": "^12.7.0", "jest": "^29.7.0", "lint-staged": "^15.2.2", "markdownlint-cli": "^0.45.0", diff --git a/setup.js b/setup.js index 3d8aef1..048485b 100644 --- a/setup.js +++ b/setup.js @@ -1,75 +1,88 @@ -// setup.js +// setup.js (using Inquirer.js) -const readline = require('readline'); const fs = require('fs'); const path = require('path'); - -// Configure readline interface for user input -const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, -}); +const inquirer = require('inquirer'); // Import Inquirer // List of files that need to be modified by the script const filesToModify = [ - 'project.json', - 'CONTRIBUTING.md', - 'LICENSE', - 'CODE_OF_CONDUCT.md', - 'README.md', + 'package.json', + 'CONTRIBUTING.md', + 'LICENSE', + 'CODE_OF_CONDUCT.md', + 'README.md' ]; /** - * Prompts the user with a question and returns their answer. - * @param {string} query The question to ask the user. - * @returns {Promise} A promise that resolves with the user's answer. - */ -function askQuestion(query) { - return new Promise((resolve) => rl.question(query, resolve)); -} - -/** - * Collects all necessary inputs from the user. + * Collects all necessary inputs from the user using Inquirer. * @returns {Promise} An object containing all user inputs. */ async function getUserInputs() { - console.log('\n--- Project Setup ---'); - console.log("Let's personalize your new repository."); - console.log('Please provide the following information:'); - - const inputs = {}; - - inputs.projectName = await askQuestion( - '1. Enter the name for your new project (e.g., my-awesome-app): ' - ); - inputs.projectDescription = await askQuestion( - '2. Enter a short description for your project: ' - ); - inputs.projectKeywords = await askQuestion( - '3. Enter keywords for your project, separated by commas (e.g., javascript, web, utility): ' - ); - inputs.authorName = await askQuestion( - "4. Enter the author's name (e.g., John Doe or My Company Inc.): " - ); - inputs.contactEmail = await askQuestion( - '5. Enter a contact email for your project (e.g., contact@yourproject.com): ' - ); - - const currentYear = new Date().getFullYear(); - inputs.licenseYear = - (await askQuestion( - `6. Enter the copyright year (default: ${currentYear}): ` - )) || currentYear.toString(); // Ensure string for replacement - - inputs.githubUsername = await askQuestion( - '7. Enter your GitHub username or organization name (e.g., octocat): ' - ); - inputs.codecovToken = await askQuestion( - '8. Enter your Codecov token (optional, leave blank if not using): ' - ); - - rl.close(); // Close the readline interface after all questions are asked - return inputs; + console.log('\n--- Project Setup ---'); + console.log('Let\'s personalize your new repository.'); + console.log('Please provide the following information:'); + + const currentYear = new Date().getFullYear().toString(); // Ensure year is a string for direct replacement + + const answers = await inquirer.prompt([ + { + type: 'input', + name: 'projectName', + message: '1. Enter the name for your new project:', + default: 'my-awesome-app', + validate: input => input.trim().length > 0 || 'Project name cannot be empty.' + }, + { + type: 'input', + name: 'projectDescription', + message: '2. Enter a short description for your project:', + default: 'A modern JavaScript project.' + }, + { + type: 'input', + name: 'projectKeywords', + message: '3. Enter keywords for your project, separated by commas (e.g., javascript, web, utility):', + default: 'javascript, template, quality' + }, + { + type: 'input', + name: 'authorName', + message: '4. Enter the author\'s name (e.g., John Doe or My Company Inc.):', + validate: input => input.trim().length > 0 || 'Author name cannot be empty.' + }, + { + type: 'input', + name: 'contactEmail', + message: '5. Enter a contact email for your project:', + validate: input => { + // Basic email regex validation + return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input) || 'Please enter a valid email address.'; + } + }, + { + type: 'input', + name: 'licenseYear', + message: '6. Enter the copyright year:', + default: currentYear, + validate: input => { + const year = parseInt(input); + return (!isNaN(year) && year > 1900 && year <= new Date().getFullYear() + 10) || 'Please enter a valid year.'; + } + }, + { + type: 'input', + name: 'githubUsername', + message: '7. Enter your GitHub username or organization name (e.g., octocat):', + validate: input => input.trim().length > 0 || 'GitHub username cannot be empty.' + }, + { + type: 'input', + name: 'codecovToken', + message: '8. Enter your Codecov token (optional, leave blank if not using Codecov badge):' + } + ]); + + return answers; } /** @@ -77,144 +90,96 @@ async function getUserInputs() { * @param {Object} inputs An object containing all user inputs. */ async function processFiles(inputs) { - for (const file of filesToModify) { - const filePath = path.join(process.cwd(), file); // Assumes script is run from repo root - console.log(`\nProcessing ${file}...`); - - try { - let content = fs.readFileSync(filePath, 'utf8'); - - // --- Generic Replacements (order matters if placeholders overlap) --- - content = content.replace( - new RegExp('{{PROJECT_NAME}}', 'g'), - inputs.projectName - ); - content = content.replace( - new RegExp('{{PROJECT_DESCRIPTION}}', 'g'), - inputs.projectDescription - ); - content = content.replace( - new RegExp('{{AUTHOR_NAME}}', 'g'), - inputs.authorName - ); - content = content.replace( - new RegExp('{{CONTACT_EMAIL}}', 'g'), - inputs.contactEmail - ); - content = content.replace( - new RegExp('{{LICENSE_YEAR}}', 'g'), - inputs.licenseYear - ); - content = content.replace( - new RegExp('{{GITHUB_USERNAME}}', 'g'), - inputs.githubUsername - ); - // Handle optional Codecov token - content = content.replace( - new RegExp('{{CODECOV_TOKEN}}', 'g'), - inputs.codecovToken || '' - ); - - // --- Specific handling for project.json --- - if (file === 'project.json') { - let projectJson = JSON.parse(content); - - // Update specific fields that might have been generically replaced but need JSON structure - projectJson.name = inputs.projectName; - projectJson.description = inputs.projectDescription; - projectJson.author = inputs.authorName; - - // Handle keywords array: convert comma-separated string to array - if (inputs.projectKeywords) { - projectJson.keywords = inputs.projectKeywords - .split(',') - .map((kw) => kw.trim()) - .filter((kw) => kw.length > 0); - } else { - projectJson.keywords = []; // Set to empty array if no keywords provided + for (const file of filesToModify) { + const filePath = path.join(process.cwd(), file); + console.log(`\nProcessing ${file}...`); + + try { + if (!fs.existsSync(filePath)) { + console.warn(`Warning: File not found at ${filePath}. Skipping.`); + continue; + } + + let content = fs.readFileSync(filePath, 'utf8'); + + // --- Generic Replacements (order matters if placeholders overlap) --- + content = content.replace(new RegExp('{{PROJECT_NAME}}', 'g'), inputs.projectName); + content = content.replace(new RegExp('{{PROJECT_DESCRIPTION}}', 'g'), inputs.projectDescription); + content = content.replace(new RegExp('{{AUTHOR_NAME}}', 'g'), inputs.authorName); + content = content.replace(new RegExp('{{CONTACT_EMAIL}}', 'g'), inputs.contactEmail); + content = content.replace(new RegExp('{{LICENSE_YEAR}}', 'g'), inputs.licenseYear); + content = content.replace(new RegExp('{{GITHUB_USERNAME}}', 'g'), inputs.githubUsername); + content = content.replace(new RegExp('{{CODECOV_TOKEN}}', 'g'), inputs.codecovToken || ''); + + // --- Specific handling for package.json --- + if (file === 'package.json') { + let packageJson = JSON.parse(content); + + packageJson.name = inputs.projectName; + packageJson.description = inputs.projectDescription; + packageJson.author = inputs.authorName; + + if (inputs.projectKeywords) { + packageJson.keywords = inputs.projectKeywords.split(',').map(kw => kw.trim()).filter(kw => kw.length > 0); + } else { + packageJson.keywords = []; + } + + content = JSON.stringify(packageJson, null, 2); + } + + // --- Specific handling for README.md --- + if (file === 'README.md') { + content = content.replace(/\[LICENSE\]\(LICENSE\.md\)/g, '[LICENSE](LICENSE)'); + + const postTemplateSetupRegex = /(## Post-Template Setup[\s\S]*?)(?=##|$)/; + const newPostTemplateSetupContent = `## Post-Template Setup\n\nAfter creating your repository from this template, you've successfully run this setup script to personalize your project. You're ready to start building!\n\n*(This section was updated by the setup script.)*`; + + if (content.match(postTemplateSetupRegex)) { + content = content.replace(postTemplateSetupRegex, newPostTemplateSetupContent); + } else { + console.warn('Warning: "Post-Template Setup" section not found in README.md. Appending new content.'); + content += `\n${newPostTemplateSetupContent}`; + } + } + + fs.writeFileSync(filePath, content, 'utf8'); + console.log(`Successfully updated ${file}.`); + + } catch (error) { + console.error(`Error processing ${file}: ${error.message}`); + if (file === 'package.json' && error instanceof SyntaxError) { + console.error('Make sure package.json is valid JSON before running the script.'); + } } - - content = JSON.stringify(projectJson, null, 2); // Pretty print JSON with 2 spaces - } - - // --- Specific handling for README.md --- - if (file === 'README.md') { - // Correct the LICENSE link from LICENSE.md to LICENSE - content = content.replace( - /\[LICENSE\]\(LICENSE\.md\)/g, - '[LICENSE](LICENSE)' - ); - - // Update the 'Post-Template Setup' section - // This regex captures the section content up to the next '##' heading or end of file - const postTemplateSetupRegex = - /(## Post-Template Setup[\s\S]*?)(?=##|$)/; - const newPostTemplateSetupContent = `## Post-Template Setup\n\nAfter creating your repository from this template, you've successfully run this setup script to personalize your project. You're ready to start building!\n\n*(This section was updated by the setup script.)*`; - - if (content.match(postTemplateSetupRegex)) { - content = content.replace( - postTemplateSetupRegex, - newPostTemplateSetupContent - ); - } else { - // If the section isn't found (e.g., file was heavily modified), append it - console.warn( - 'Warning: "Post-Template Setup" section not found in README.md. Appending new content.' - ); - content += `\n${newPostTemplateSetupContent}`; - } - } - - fs.writeFileSync(filePath, content, 'utf8'); - console.log(`Successfully updated ${file}.`); - } catch (error) { - console.error(`Error processing ${file}: ${error.message}`); - if (file === 'project.json' && error instanceof SyntaxError) { - console.error( - 'Make sure project.json is valid JSON before running the script.' - ); - } } - } } /** * Main function to run the setup script. */ async function runSetup() { - try { - const inputs = await getUserInputs(); - await processFiles(inputs); - - console.log('\n--- Setup Complete! ---'); - console.log('Your repository has been successfully personalized.'); - console.log('Here are some quick reminders:'); - console.log(`- Project Name: ${inputs.projectName}`); - console.log(`- Author: ${inputs.authorName}`); - console.log( - `- GitHub Repository: https://github.com/${inputs.githubUsername}/${inputs.projectName}` - ); - if (inputs.codecovToken) { - console.log( - `- Remember to add your Codecov token as a secret named 'CODECOV_TOKEN' in your GitHub repository settings for CI integration.` - ); - } - console.log( - '\n- Please review the modified files to ensure everything looks correct and fine-tune as needed.' - ); - console.log( - "- Don't forget to initialize your Git repository if you haven't already!" - ); - console.log('\nHappy coding!'); - } catch (error) { - console.error('\nAn unexpected error occurred during setup:', error); - process.exit(1); // Exit with an error code - } finally { - if (!rl.closed) { - rl.close(); // Ensure readline interface is closed even on error + try { + const inputs = await getUserInputs(); + await processFiles(inputs); + + console.log('\n--- Setup Complete! ---'); + console.log('Your repository has been successfully personalized.'); + console.log('Here are some quick reminders:'); + console.log(`- Project Name: ${inputs.projectName}`); + console.log(`- Author: ${inputs.authorName}`); + console.log(`- GitHub Repository: https://github.com/${inputs.githubUsername}/${inputs.projectName}`); + if (inputs.codecovToken) { + console.log(`- Remember to add your Codecov token as a secret named 'CODECOV_TOKEN' in your GitHub repository settings for CI integration.`); + } + console.log('\n- Please review the modified files to ensure everything looks correct and fine-tune as needed.'); + console.log('- Don\'t forget to initialize your Git repository if you haven\'t already!'); + console.log('\nHappy coding!'); + } catch (error) { + console.error('\nAn unexpected error occurred during setup:', error); + process.exit(1); } - } } // Execute the setup script -runSetup(); +runSetup(); \ No newline at end of file From 37f761e072c9c1423a694922276f1af2a5b31c5c Mon Sep 17 00:00:00 2001 From: Ion Gireada Date: Fri, 4 Jul 2025 10:59:23 +0300 Subject: [PATCH 2/8] docs: :art: clean up redundant files --- setup.js | 349 +++++++++++++++++------------ src/index.js | 14 +- src/index.test.js | 11 - src/utils/normalize-string.js | 32 --- src/utils/normalize-string.test.js | 53 ----- 5 files changed, 207 insertions(+), 252 deletions(-) delete mode 100644 src/index.test.js delete mode 100644 src/utils/normalize-string.js delete mode 100644 src/utils/normalize-string.test.js diff --git a/setup.js b/setup.js index ed3d52f..d60c3ed 100644 --- a/setup.js +++ b/setup.js @@ -18,71 +18,86 @@ const filesToModify = [ * @returns {Promise} An object containing all user inputs. */ async function getUserInputs() { - console.log('\n--- Project Setup ---'); - console.log('Let\'s personalize your new repository.'); - console.log('Please provide the following information:'); - - const currentYear = new Date().getFullYear().toString(); // Ensure year is a string for direct replacement - - const answers = await inquirer.prompt([ - { - type: 'input', - name: 'projectName', - message: '1. Enter the name for your new project:', - default: 'my-awesome-app', - validate: input => input.trim().length > 0 || 'Project name cannot be empty.' - }, - { - type: 'input', - name: 'projectDescription', - message: '2. Enter a short description for your project:', - default: 'A modern JavaScript project.' - }, - { - type: 'input', - name: 'projectKeywords', - message: '3. Enter keywords for your project, separated by commas (e.g., javascript, web, utility):', - default: 'javascript, template, quality' - }, - { - type: 'input', - name: 'authorName', - message: '4. Enter the author\'s name (e.g., John Doe or My Company Inc.):', - validate: input => input.trim().length > 0 || 'Author name cannot be empty.' - }, - { - type: 'input', - name: 'contactEmail', - message: '5. Enter a contact email for your project:', - validate: input => { - // Basic email regex validation - return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input) || 'Please enter a valid email address.'; - } - }, - { - type: 'input', - name: 'licenseYear', - message: '6. Enter the copyright year:', - default: currentYear, - validate: input => { - const year = parseInt(input); - return (!isNaN(year) && year > 1900 && year <= new Date().getFullYear() + 10) || 'Please enter a valid year.'; - } - }, - { - type: 'input', - name: 'githubUsername', - message: '7. Enter your GitHub username or organization name (e.g., octocat):', - validate: input => input.trim().length > 0 || 'GitHub username cannot be empty.' - }, - { - type: 'input', - name: 'codecovToken', - message: '8. Enter your Codecov token (optional, leave blank if not using Codecov badge):' - } - ]); - - return answers; + console.log('\n--- Project Setup ---'); + console.log("Let's personalize your new repository."); + console.log('Please provide the following information:'); + + const currentYear = new Date().getFullYear().toString(); // Ensure year is a string for direct replacement + + const answers = await inquirer.prompt([ + { + type: 'input', + name: 'projectName', + message: '1. Enter the name for your new project:', + default: 'my-awesome-app', + validate: (input) => + input.trim().length > 0 || 'Project name cannot be empty.', + }, + { + type: 'input', + name: 'projectDescription', + message: '2. Enter a short description for your project:', + default: 'A modern JavaScript project.', + }, + { + type: 'input', + name: 'projectKeywords', + message: + '3. Enter keywords for your project, separated by commas (e.g., javascript, web, utility):', + default: 'javascript, template, quality', + }, + { + type: 'input', + name: 'authorName', + message: + "4. Enter the author's name (e.g., John Doe or My Company Inc.):", + validate: (input) => + input.trim().length > 0 || 'Author name cannot be empty.', + }, + { + type: 'input', + name: 'contactEmail', + message: '5. Enter a contact email for your project:', + validate: (input) => { + // Basic email regex validation + return ( + /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input) || + 'Please enter a valid email address.' + ); + }, + }, + { + type: 'input', + name: 'licenseYear', + message: '6. Enter the copyright year:', + default: currentYear, + validate: (input) => { + const year = parseInt(input); + return ( + (!isNaN(year) && + year > 1900 && + year <= new Date().getFullYear() + 10) || + 'Please enter a valid year.' + ); + }, + }, + { + type: 'input', + name: 'githubUsername', + message: + '7. Enter your GitHub username or organization name (e.g., octocat):', + validate: (input) => + input.trim().length > 0 || 'GitHub username cannot be empty.', + }, + { + type: 'input', + name: 'codecovToken', + message: + '8. Enter your Codecov token (optional, leave blank if not using Codecov badge):', + }, + ]); + + return answers; } /** @@ -90,96 +105,138 @@ async function getUserInputs() { * @param {Object} inputs An object containing all user inputs. */ async function processFiles(inputs) { - for (const file of filesToModify) { - const filePath = path.join(process.cwd(), file); - console.log(`\nProcessing ${file}...`); - - try { - if (!fs.existsSync(filePath)) { - console.warn(`Warning: File not found at ${filePath}. Skipping.`); - continue; - } - - let content = fs.readFileSync(filePath, 'utf8'); - - // --- Generic Replacements (order matters if placeholders overlap) --- - content = content.replace(new RegExp('{{PROJECT_NAME}}', 'g'), inputs.projectName); - content = content.replace(new RegExp('{{PROJECT_DESCRIPTION}}', 'g'), inputs.projectDescription); - content = content.replace(new RegExp('{{AUTHOR_NAME}}', 'g'), inputs.authorName); - content = content.replace(new RegExp('{{CONTACT_EMAIL}}', 'g'), inputs.contactEmail); - content = content.replace(new RegExp('{{LICENSE_YEAR}}', 'g'), inputs.licenseYear); - content = content.replace(new RegExp('{{GITHUB_USERNAME}}', 'g'), inputs.githubUsername); - content = content.replace(new RegExp('{{CODECOV_TOKEN}}', 'g'), inputs.codecovToken || ''); - - // --- Specific handling for package.json --- - if (file === 'package.json') { - let packageJson = JSON.parse(content); - - packageJson.name = inputs.projectName; - packageJson.description = inputs.projectDescription; - packageJson.author = inputs.authorName; - - if (inputs.projectKeywords) { - packageJson.keywords = inputs.projectKeywords.split(',').map(kw => kw.trim()).filter(kw => kw.length > 0); - } else { - packageJson.keywords = []; - } - - content = JSON.stringify(packageJson, null, 2); - } - - // --- Specific handling for README.md --- - if (file === 'README.md') { - content = content.replace(/\[LICENSE\]\(LICENSE\.md\)/g, '[LICENSE](LICENSE)'); - - const postTemplateSetupRegex = /(## Post-Template Setup[\s\S]*?)(?=##|$)/; - const newPostTemplateSetupContent = `## Post-Template Setup\n\nAfter creating your repository from this template, you've successfully run this setup script to personalize your project. You're ready to start building!\n\n*(This section was updated by the setup script.)*`; - - if (content.match(postTemplateSetupRegex)) { - content = content.replace(postTemplateSetupRegex, newPostTemplateSetupContent); - } else { - console.warn('Warning: "Post-Template Setup" section not found in README.md. Appending new content.'); - content += `\n${newPostTemplateSetupContent}`; - } - } - - fs.writeFileSync(filePath, content, 'utf8'); - console.log(`Successfully updated ${file}.`); - - } catch (error) { - console.error(`Error processing ${file}: ${error.message}`); - if (file === 'package.json' && error instanceof SyntaxError) { - console.error('Make sure package.json is valid JSON before running the script.'); - } + for (const file of filesToModify) { + const filePath = path.join(process.cwd(), file); + console.log(`\nProcessing ${file}...`); + + try { + if (!fs.existsSync(filePath)) { + console.warn(`Warning: File not found at ${filePath}. Skipping.`); + continue; + } + + let content = fs.readFileSync(filePath, 'utf8'); + + // --- Generic Replacements (order matters if placeholders overlap) --- + content = content.replace( + new RegExp('{{PROJECT_NAME}}', 'g'), + inputs.projectName + ); + content = content.replace( + new RegExp('{{PROJECT_DESCRIPTION}}', 'g'), + inputs.projectDescription + ); + content = content.replace( + new RegExp('{{AUTHOR_NAME}}', 'g'), + inputs.authorName + ); + content = content.replace( + new RegExp('{{CONTACT_EMAIL}}', 'g'), + inputs.contactEmail + ); + content = content.replace( + new RegExp('{{LICENSE_YEAR}}', 'g'), + inputs.licenseYear + ); + content = content.replace( + new RegExp('{{GITHUB_USERNAME}}', 'g'), + inputs.githubUsername + ); + content = content.replace( + new RegExp('{{CODECOV_TOKEN}}', 'g'), + inputs.codecovToken || '' + ); + + // --- Specific handling for package.json --- + if (file === 'package.json') { + let packageJson = JSON.parse(content); + + packageJson.name = inputs.projectName; + packageJson.description = inputs.projectDescription; + packageJson.author = inputs.authorName; + + if (inputs.projectKeywords) { + packageJson.keywords = inputs.projectKeywords + .split(',') + .map((kw) => kw.trim()) + .filter((kw) => kw.length > 0); + } else { + packageJson.keywords = []; + } + + content = JSON.stringify(packageJson, null, 2); + } + + // --- Specific handling for README.md --- + if (file === 'README.md') { + content = content.replace( + /\[LICENSE\]\(LICENSE\.md\)/g, + '[LICENSE](LICENSE)' + ); + + const postTemplateSetupRegex = + /(## Post-Template Setup[\s\S]*?)(?=##|$)/; + const newPostTemplateSetupContent = `## Post-Template Setup\n\nAfter creating your repository from this template, you've successfully run this setup script to personalize your project. You're ready to start building!\n\n*(This section was updated by the setup script.)*`; + + if (content.match(postTemplateSetupRegex)) { + content = content.replace( + postTemplateSetupRegex, + newPostTemplateSetupContent + ); + } else { + console.warn( + 'Warning: "Post-Template Setup" section not found in README.md. Appending new content.' + ); + content += `\n${newPostTemplateSetupContent}`; } + } + + fs.writeFileSync(filePath, content, 'utf8'); + console.log(`Successfully updated ${file}.`); + } catch (error) { + console.error(`Error processing ${file}: ${error.message}`); + if (file === 'package.json' && error instanceof SyntaxError) { + console.error( + 'Make sure package.json is valid JSON before running the script.' + ); + } } + } } /** * Main function to run the setup script. */ async function runSetup() { - try { - const inputs = await getUserInputs(); - await processFiles(inputs); - - console.log('\n--- Setup Complete! ---'); - console.log('Your repository has been successfully personalized.'); - console.log('Here are some quick reminders:'); - console.log(`- Project Name: ${inputs.projectName}`); - console.log(`- Author: ${inputs.authorName}`); - console.log(`- GitHub Repository: https://github.com/${inputs.githubUsername}/${inputs.projectName}`); - if (inputs.codecovToken) { - console.log(`- Remember to add your Codecov token as a secret named 'CODECOV_TOKEN' in your GitHub repository settings for CI integration.`); - } - console.log('\n- Please review the modified files to ensure everything looks correct and fine-tune as needed.'); - console.log('- Don\'t forget to initialize your Git repository if you haven\'t already!'); - console.log('\nHappy coding!'); - } catch (error) { - console.error('\nAn unexpected error occurred during setup:', error); - process.exit(1); + try { + const inputs = await getUserInputs(); + await processFiles(inputs); + + console.log('\n--- Setup Complete! ---'); + console.log('Your repository has been successfully personalized.'); + console.log('Here are some quick reminders:'); + console.log(`- Project Name: ${inputs.projectName}`); + console.log(`- Author: ${inputs.authorName}`); + console.log( + `- GitHub Repository: https://github.com/${inputs.githubUsername}/${inputs.projectName}` + ); + if (inputs.codecovToken) { + console.log( + `- Remember to add your Codecov token as a secret named 'CODECOV_TOKEN' in your GitHub repository settings for CI integration.` + ); } + console.log( + '\n- Please review the modified files to ensure everything looks correct and fine-tune as needed.' + ); + console.log( + "- Don't forget to initialize your Git repository if you haven't already!" + ); + console.log('\nHappy coding!'); + } catch (error) { + console.error('\nAn unexpected error occurred during setup:', error); + process.exit(1); + } } // Execute the setup script -runSetup(); \ No newline at end of file +runSetup(); diff --git a/src/index.js b/src/index.js index 413c1c9..b228fb0 100644 --- a/src/index.js +++ b/src/index.js @@ -1,11 +1,5 @@ -/** - * A simple function to demonstrate testing. - * @param {number} a - The first number. - * @param {number} b - The second number. - * @returns {number} The sum of a and b. - */ -function add(a, b) { - return a + b; -} +// index.js -module.exports = { add }; +// +++ +// your code here +// --- diff --git a/src/index.test.js b/src/index.test.js deleted file mode 100644 index 8ce5029..0000000 --- a/src/index.test.js +++ /dev/null @@ -1,11 +0,0 @@ -const { add } = require('./index'); - -describe('add function', () => { - test('should add two numbers correctly', () => { - expect(add(1, 2)).toBe(3); - }); - - test('should handle negative numbers', () => { - expect(add(-1, -1)).toBe(-2); - }); -}); diff --git a/src/utils/normalize-string.js b/src/utils/normalize-string.js deleted file mode 100644 index 3059f06..0000000 --- a/src/utils/normalize-string.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Normalizes a string by trimming whitespace, converting to lowercase, - * replacing non-alphanumeric characters with dashes, collapsing multiple dashes, - * and removing leading/trailing dashes. This is commonly used to create URL-friendly "slugs". - * - * @param {string} str The input string to normalize. - * @returns {string} The normalized string. - * @throws {Error} If the input is null or undefined. - */ -function normalizeString(str) { - if (str === null || str === undefined) { - throw new Error('Input cannot be null or undefined.'); - } - - let s = String(str); - - s = s.trim(); - s = s.toLowerCase(); - - // Replace non-alphanumeric (excluding dash and underscore) with a dash - s = s.replace(/[^a-z0-9_-]/g, '-'); - - // Replace multiple dashes with a single dash - s = s.replace(/-+/g, '-'); - - // Remove leading/trailing dashes - s = s.replace(/^-+|-+$/g, ''); - - return s; -} - -module.exports = normalizeString; diff --git a/src/utils/normalize-string.test.js b/src/utils/normalize-string.test.js deleted file mode 100644 index fb92047..0000000 --- a/src/utils/normalize-string.test.js +++ /dev/null @@ -1,53 +0,0 @@ -const normalizeString = require('./normalize-string'); - -describe('normalizeString', () => { - test('should convert a basic string with spaces to kebab-case', () => { - expect(normalizeString('Hello World')).toBe('hello-world'); - }); - - test('should trim leading and trailing whitespace', () => { - expect(normalizeString(' leading and trailing ')).toBe( - 'leading-and-trailing' - ); - }); - - test('should convert the entire string to lowercase', () => { - expect(normalizeString('UPPERCASE STRING')).toBe('uppercase-string'); - }); - - test('should replace various special characters with a dash', () => { - expect(normalizeString('a!b@c#d$e%f^g&h*i(j)k')).toBe( - 'a-b-c-d-e-f-g-h-i-j-k' - ); - }); - - test('should collapse multiple dashes and spaces into a single dash', () => { - expect(normalizeString('multiple---dashes')).toBe('multiple-dashes'); - expect(normalizeString('a b c')).toBe('a-b-c'); - }); - - test('should remove leading and trailing dashes', () => { - expect(normalizeString('-leading-and-trailing-')).toBe( - 'leading-and-trailing' - ); - }); - - test('should handle a complex mix of operations correctly', () => { - expect(normalizeString(' --My Awesome Post #1! --')).toBe( - 'my-awesome-post-1' - ); - }); - - test('should return an empty string if the input is an empty string', () => { - expect(normalizeString('')).toBe(''); - }); - - test('should throw an error for null or undefined input', () => { - expect(() => normalizeString(null)).toThrow( - 'Input cannot be null or undefined.' - ); - expect(() => normalizeString(undefined)).toThrow( - 'Input cannot be null or undefined.' - ); - }); -}); From cc10d845c15fbde030fdc24012cd91a9b604fe7b Mon Sep 17 00:00:00 2001 From: Ion Gireada Date: Fri, 4 Jul 2025 11:04:56 +0300 Subject: [PATCH 3/8] fix: :bug: skip Run tests in ci.yml action when no test files exist --- .github/workflows/ci.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ff440f..93b33ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,5 +33,15 @@ jobs: run: npm run format:md - name: Audit for vulnerabilities run: npm audit --production + - name: Check for test files + id: check_files + shell: bash + run: | + shopt -s globstar nullglob + files=(**/*.test.js **/*.spec.js) + if [ ${#files[@]} -gt 0 ]; then + echo "exists=true" >> $GITHUB_OUTPUT + fi - name: Run tests + if: steps.check_files.outputs.exists == 'true' run: npm test From d23965ea4d36c2cfe7cd9393e165f76bbd773dd7 Mon Sep 17 00:00:00 2001 From: Ion Gireada Date: Fri, 4 Jul 2025 11:08:15 +0300 Subject: [PATCH 4/8] fix: :art: accept npm test when no test files exist --- .github/workflows/ci.yml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93b33ac..2453998 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,15 +33,5 @@ jobs: run: npm run format:md - name: Audit for vulnerabilities run: npm audit --production - - name: Check for test files - id: check_files - shell: bash - run: | - shopt -s globstar nullglob - files=(**/*.test.js **/*.spec.js) - if [ ${#files[@]} -gt 0 ]; then - echo "exists=true" >> $GITHUB_OUTPUT - fi - name: Run tests - if: steps.check_files.outputs.exists == 'true' - run: npm test + run: npm test --passWithNoTests From 6bcbac1148308dffaa30bf4a87eb092845f9a401 Mon Sep 17 00:00:00 2001 From: Ion Gireada Date: Fri, 4 Jul 2025 11:11:11 +0300 Subject: [PATCH 5/8] fix: :fire: update audit and test run --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2453998..97ba7ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,6 +32,6 @@ jobs: - name: Check Markdown formatting run: npm run format:md - name: Audit for vulnerabilities - run: npm audit --production + run: npm audit --omit-dev --omit=optional --omit=peer - name: Run tests run: npm test --passWithNoTests From f3ac01b81dd13adc8f31779cf8dad028cc39e934 Mon Sep 17 00:00:00 2001 From: Ion Gireada Date: Fri, 4 Jul 2025 11:16:14 +0300 Subject: [PATCH 6/8] fix: :fire: add generic test file --- src/index.test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/index.test.js diff --git a/src/index.test.js b/src/index.test.js new file mode 100644 index 0000000..ab23501 --- /dev/null +++ b/src/index.test.js @@ -0,0 +1,15 @@ +describe('index.js', () => { + it('should have a valid structure', () => { + // This test checks if the index.js file exists and has a basic structure. + const fs = require('fs'); + const path = require('path'); + + const indexPath = path.join(__dirname, 'index.js'); + expect(fs.existsSync(indexPath)).toBe(true); + + const content = fs.readFileSync(indexPath, 'utf8'); + expect(content).toMatch(/\/\/ index\.js/); + }); +}); +// This test checks if the index.js file has the expected comment at the top. +// It ensures that the file is not empty and has a basic structure. \ No newline at end of file From e43493f974a36c57eab090cff0646e1681d3eca8 Mon Sep 17 00:00:00 2001 From: Ion Gireada Date: Fri, 4 Jul 2025 11:17:07 +0300 Subject: [PATCH 7/8] fix: :zap: run tests --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97ba7ef..81aebf6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,4 +34,4 @@ jobs: - name: Audit for vulnerabilities run: npm audit --omit-dev --omit=optional --omit=peer - name: Run tests - run: npm test --passWithNoTests + run: npm test From 99f473f5d010826cf4e120d6713c9cd6baa1e17c Mon Sep 17 00:00:00 2001 From: Ion Gireada Date: Fri, 4 Jul 2025 11:19:03 +0300 Subject: [PATCH 8/8] ci: :zap: update CI/CD flow --- src/index.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.test.js b/src/index.test.js index ab23501..f764f2d 100644 --- a/src/index.test.js +++ b/src/index.test.js @@ -12,4 +12,4 @@ describe('index.js', () => { }); }); // This test checks if the index.js file has the expected comment at the top. -// It ensures that the file is not empty and has a basic structure. \ No newline at end of file +// It ensures that the file is not empty and has a basic structure.