Compare commits
5 Commits
Author | SHA1 | Date |
---|---|---|
|
51de7d013a | 3 weeks ago |
|
409cc131ce | 3 weeks ago |
|
661f7d4dab | 3 weeks ago |
|
11eb1670b3 | 3 weeks ago |
|
754c68bb40 | 3 weeks ago |
@ -1 +0,0 @@
|
||||
../detect-libc/bin/detect-libc.js
|
@ -1 +0,0 @@
|
||||
../sass/sass.js
|
@ -1,804 +0,0 @@
|
||||
{
|
||||
"name": "wanderhome",
|
||||
"version": "2.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"node_modules/@inquirer/checkbox": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.0.tgz",
|
||||
"integrity": "sha512-fdSw07FLJEU5vbpOPzXo5c6xmMGDzbZE2+niuDHX5N6mc6V0Ebso/q3xiHra4D73+PMsC8MJmcaZKuAAoaQsSA==",
|
||||
"dependencies": {
|
||||
"@inquirer/core": "^10.1.15",
|
||||
"@inquirer/figures": "^1.0.13",
|
||||
"@inquirer/type": "^3.0.8",
|
||||
"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.14",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.14.tgz",
|
||||
"integrity": "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q==",
|
||||
"dependencies": {
|
||||
"@inquirer/core": "^10.1.15",
|
||||
"@inquirer/type": "^3.0.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/core": {
|
||||
"version": "10.1.15",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.15.tgz",
|
||||
"integrity": "sha512-8xrp836RZvKkpNbVvgWUlxjT4CraKk2q+I3Ksy+seI2zkcE+y6wNs1BVhgcv8VyImFecUhdQrYLdW32pAjwBdA==",
|
||||
"dependencies": {
|
||||
"@inquirer/figures": "^1.0.13",
|
||||
"@inquirer/type": "^3.0.8",
|
||||
"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/editor": {
|
||||
"version": "4.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.16.tgz",
|
||||
"integrity": "sha512-iSzLjT4C6YKp2DU0fr8T7a97FnRRxMO6CushJnW5ktxLNM2iNeuyUuUA5255eOLPORoGYCrVnuDOEBdGkHGkpw==",
|
||||
"dependencies": {
|
||||
"@inquirer/core": "^10.1.15",
|
||||
"@inquirer/external-editor": "^1.0.0",
|
||||
"@inquirer/type": "^3.0.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/expand": {
|
||||
"version": "4.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.17.tgz",
|
||||
"integrity": "sha512-PSqy9VmJx/VbE3CT453yOfNa+PykpKg/0SYP7odez1/NWBGuDXgPhp4AeGYYKjhLn5lUUavVS/JbeYMPdH50Mw==",
|
||||
"dependencies": {
|
||||
"@inquirer/core": "^10.1.15",
|
||||
"@inquirer/type": "^3.0.8",
|
||||
"yoctocolors-cjs": "^2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/external-editor": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.0.tgz",
|
||||
"integrity": "sha512-5v3YXc5ZMfL6OJqXPrX9csb4l7NlQA2doO1yynUjpUChT9hg4JcuBVP0RbsEJ/3SL/sxWEyFjT2W69ZhtoBWqg==",
|
||||
"dependencies": {
|
||||
"chardet": "^2.1.0",
|
||||
"iconv-lite": "^0.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/figures": {
|
||||
"version": "1.0.13",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz",
|
||||
"integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/input": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.1.tgz",
|
||||
"integrity": "sha512-tVC+O1rBl0lJpoUZv4xY+WGWY8V5b0zxU1XDsMsIHYregdh7bN5X5QnIONNBAl0K765FYlAfNHS2Bhn7SSOVow==",
|
||||
"dependencies": {
|
||||
"@inquirer/core": "^10.1.15",
|
||||
"@inquirer/type": "^3.0.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/number": {
|
||||
"version": "3.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.17.tgz",
|
||||
"integrity": "sha512-GcvGHkyIgfZgVnnimURdOueMk0CztycfC8NZTiIY9arIAkeOgt6zG57G+7vC59Jns3UX27LMkPKnKWAOF5xEYg==",
|
||||
"dependencies": {
|
||||
"@inquirer/core": "^10.1.15",
|
||||
"@inquirer/type": "^3.0.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/password": {
|
||||
"version": "4.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.17.tgz",
|
||||
"integrity": "sha512-DJolTnNeZ00E1+1TW+8614F7rOJJCM4y4BAGQ3Gq6kQIG+OJ4zr3GLjIjVVJCbKsk2jmkmv6v2kQuN/vriHdZA==",
|
||||
"dependencies": {
|
||||
"@inquirer/core": "^10.1.15",
|
||||
"@inquirer/type": "^3.0.8",
|
||||
"ansi-escapes": "^4.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/prompts": {
|
||||
"version": "7.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.1.tgz",
|
||||
"integrity": "sha512-LpBPeIpyCF1H3C7SK/QxJQG4iV1/SRmJdymfcul8PuwtVhD0JI1CSwqmd83VgRgt1QEsDojQYFSXJSgo81PVMw==",
|
||||
"dependencies": {
|
||||
"@inquirer/checkbox": "^4.2.0",
|
||||
"@inquirer/confirm": "^5.1.14",
|
||||
"@inquirer/editor": "^4.2.16",
|
||||
"@inquirer/expand": "^4.0.17",
|
||||
"@inquirer/input": "^4.2.1",
|
||||
"@inquirer/number": "^3.0.17",
|
||||
"@inquirer/password": "^4.0.17",
|
||||
"@inquirer/rawlist": "^4.1.5",
|
||||
"@inquirer/search": "^3.1.0",
|
||||
"@inquirer/select": "^4.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/rawlist": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.5.tgz",
|
||||
"integrity": "sha512-R5qMyGJqtDdi4Ht521iAkNqyB6p2UPuZUbMifakg1sWtu24gc2Z8CJuw8rP081OckNDMgtDCuLe42Q2Kr3BolA==",
|
||||
"dependencies": {
|
||||
"@inquirer/core": "^10.1.15",
|
||||
"@inquirer/type": "^3.0.8",
|
||||
"yoctocolors-cjs": "^2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/search": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.1.0.tgz",
|
||||
"integrity": "sha512-PMk1+O/WBcYJDq2H7foV0aAZSmDdkzZB9Mw2v/DmONRJopwA/128cS9M/TXWLKKdEQKZnKwBzqu2G4x/2Nqx8Q==",
|
||||
"dependencies": {
|
||||
"@inquirer/core": "^10.1.15",
|
||||
"@inquirer/figures": "^1.0.13",
|
||||
"@inquirer/type": "^3.0.8",
|
||||
"yoctocolors-cjs": "^2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/select": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.1.tgz",
|
||||
"integrity": "sha512-Gfl/5sqOF5vS/LIrSndFgOh7jgoe0UXEizDqahFRkq5aJBLegZ6WjuMh/hVEJwlFQjyLq1z9fRtvUMkb7jM1LA==",
|
||||
"dependencies": {
|
||||
"@inquirer/core": "^10.1.15",
|
||||
"@inquirer/figures": "^1.0.13",
|
||||
"@inquirer/type": "^3.0.8",
|
||||
"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.8",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz",
|
||||
"integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
|
||||
"integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"detect-libc": "^1.0.3",
|
||||
"is-glob": "^4.0.3",
|
||||
"micromatch": "^4.0.5",
|
||||
"node-addon-api": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@parcel/watcher-android-arm64": "2.5.1",
|
||||
"@parcel/watcher-darwin-arm64": "2.5.1",
|
||||
"@parcel/watcher-darwin-x64": "2.5.1",
|
||||
"@parcel/watcher-freebsd-x64": "2.5.1",
|
||||
"@parcel/watcher-linux-arm-glibc": "2.5.1",
|
||||
"@parcel/watcher-linux-arm-musl": "2.5.1",
|
||||
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
|
||||
"@parcel/watcher-linux-arm64-musl": "2.5.1",
|
||||
"@parcel/watcher-linux-x64-glibc": "2.5.1",
|
||||
"@parcel/watcher-linux-x64-musl": "2.5.1",
|
||||
"@parcel/watcher-win32-arm64": "2.5.1",
|
||||
"@parcel/watcher-win32-ia32": "2.5.1",
|
||||
"@parcel/watcher-win32-x64": "2.5.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-x64-glibc": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
|
||||
"integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-x64-musl": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
|
||||
"integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.1.tgz",
|
||||
"integrity": "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~7.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-escapes": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
|
||||
"integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
|
||||
"dependencies": {
|
||||
"type-fest": "^0.21.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"fill-range": "^7.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/chardet": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz",
|
||||
"integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA=="
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"readdirp": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.16.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"detect-libc": "bin/detect-libc.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz",
|
||||
"integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/inquirer": {
|
||||
"version": "12.9.1",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.9.1.tgz",
|
||||
"integrity": "sha512-G7uXAb9OiLcd+9jmA/7KKrItvFF00kKk/jb6CtG+Tm2zSPWfzzhyJwDhVCy+mBmE32o2zJnB5JnknIIv2Ft+AA==",
|
||||
"dependencies": {
|
||||
"@inquirer/core": "^10.1.15",
|
||||
"@inquirer/prompts": "^7.8.1",
|
||||
"@inquirer/type": "^3.0.8",
|
||||
"ansi-escapes": "^4.3.2",
|
||||
"mute-stream": "^2.0.0",
|
||||
"run-async": "^4.0.5",
|
||||
"rxjs": "^7.8.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"braces": "^3.0.3",
|
||||
"picomatch": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"engines": {
|
||||
"node": "^18.17.0 || >=20.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
|
||||
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/run-async": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz",
|
||||
"integrity": "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ==",
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rxjs": {
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
|
||||
"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=="
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.90.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz",
|
||||
"integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chokidar": "^4.0.0",
|
||||
"immutable": "^5.0.2",
|
||||
"source-map-js": ">=0.6.2 <2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"sass": "sass.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@parcel/watcher": "^2.4.1"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "0.21.3",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
|
||||
"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.10.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
|
||||
"integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
|
||||
"peer": true
|
||||
},
|
||||
"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==",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
Copyright (c) 2025 Simon Boudrias
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
@ -1,182 +0,0 @@
|
||||
# `@inquirer/checkbox`
|
||||
|
||||
Simple interactive command line prompt to display a list of checkboxes (multi select).
|
||||
|
||||

|
||||
|
||||
# Special Thanks
|
||||
|
||||
<div align="center" markdown="1">
|
||||
|
||||
[](https://graphite.dev/?utm_source=npmjs&utm_medium=repo&utm_campaign=inquirerjs)<br>
|
||||
|
||||
### [Graphite is the AI developer productivity platform helping teams on GitHub ship higher quality software, faster](https://graphite.dev/?utm_source=npmjs&utm_medium=repo&utm_campaign=inquirerjs)
|
||||
|
||||
</div>
|
||||
|
||||
# Installation
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>npm</th>
|
||||
<th>yarn</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
```sh
|
||||
npm install @inquirer/prompts
|
||||
```
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
```sh
|
||||
yarn add @inquirer/prompts
|
||||
```
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colSpan="2" align="center">Or</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
```sh
|
||||
npm install @inquirer/checkbox
|
||||
```
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
```sh
|
||||
yarn add @inquirer/checkbox
|
||||
```
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
# Usage
|
||||
|
||||
```js
|
||||
import { checkbox, Separator } from '@inquirer/prompts';
|
||||
// Or
|
||||
// import checkbox, { Separator } from '@inquirer/checkbox';
|
||||
|
||||
const answer = await checkbox({
|
||||
message: 'Select a package manager',
|
||||
choices: [
|
||||
{ name: 'npm', value: 'npm' },
|
||||
{ name: 'yarn', value: 'yarn' },
|
||||
new Separator(),
|
||||
{ name: 'pnpm', value: 'pnpm', disabled: true },
|
||||
{
|
||||
name: 'pnpm',
|
||||
value: 'pnpm',
|
||||
disabled: '(pnpm is not available)',
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
| Property | Type | Required | Description |
|
||||
| --------- | --------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| message | `string` | yes | The question to ask |
|
||||
| choices | `Choice[]` | yes | List of the available choices. |
|
||||
| pageSize | `number` | no | By default, lists of choice longer than 7 will be paginated. Use this option to control how many choices will appear on the screen at once. |
|
||||
| loop | `boolean` | no | Defaults to `true`. When set to `false`, the cursor will be constrained to the top and bottom of the choice list without looping. |
|
||||
| required | `boolean` | no | When set to `true`, ensures at least one choice must be selected. |
|
||||
| validate | `async (Choice[]) => boolean \| string` | no | On submit, validate the choices. When returning a string, it'll be used as the error message displayed to the user. Note: returning a rejected promise, we'll assume a code error happened and crash. |
|
||||
| shortcuts | [See Shortcuts](#Shortcuts) | no | Customize shortcut keys for `all` and `invert`. |
|
||||
| theme | [See Theming](#Theming) | no | Customize look of the prompt. |
|
||||
|
||||
`Separator` objects can be used in the `choices` array to render non-selectable lines in the choice list. By default it'll render a line, but you can provide the text as argument (`new Separator('-- Dependencies --')`). This option is often used to add labels to groups within long list of options.
|
||||
|
||||
### `Choice` object
|
||||
|
||||
The `Choice` object is typed as
|
||||
|
||||
```ts
|
||||
type Choice<Value> = {
|
||||
value: Value;
|
||||
name?: string;
|
||||
description?: string;
|
||||
short?: string;
|
||||
checked?: boolean;
|
||||
disabled?: boolean | string;
|
||||
};
|
||||
```
|
||||
|
||||
Here's each property:
|
||||
|
||||
- `value`: The value is what will be returned by `await checkbox()`.
|
||||
- `name`: This is the string displayed in the choice list.
|
||||
- `description`: Option for a longer description string that'll appear under the list when the cursor highlight a given choice.
|
||||
- `short`: Once the prompt is done (press enter), we'll use `short` if defined to render next to the question. By default we'll use `name`.
|
||||
- `checked`: If `true`, the option will be checked by default.
|
||||
- `disabled`: Disallow the option from being selected. If `disabled` is a string, it'll be used as a help tip explaining why the choice isn't available.
|
||||
|
||||
Also note the `choices` array can contain `Separator`s to help organize long lists.
|
||||
|
||||
`choices` can also be an array of string, in which case the string will be used both as the `value` and the `name`.
|
||||
|
||||
## Shortcuts
|
||||
|
||||
You can customize the shortcut keys for `all` and `invert` or disable them by setting them to `null`.
|
||||
|
||||
```ts
|
||||
type Shortcuts = {
|
||||
all?: string | null; // default: 'a'
|
||||
invert?: string | null; // default: 'i'
|
||||
};
|
||||
```
|
||||
|
||||
## Theming
|
||||
|
||||
You can theme a prompt by passing a `theme` object option. The theme object only need to includes the keys you wish to modify, we'll fallback on the defaults for the rest.
|
||||
|
||||
```ts
|
||||
type Theme = {
|
||||
prefix: string | { idle: string; done: string };
|
||||
spinner: {
|
||||
interval: number;
|
||||
frames: string[];
|
||||
};
|
||||
style: {
|
||||
answer: (text: string) => string;
|
||||
message: (text: string, status: 'idle' | 'done' | 'loading') => string;
|
||||
error: (text: string) => string;
|
||||
defaultAnswer: (text: string) => string;
|
||||
help: (text: string) => string;
|
||||
highlight: (text: string) => string;
|
||||
key: (text: string) => string;
|
||||
disabledChoice: (text: string) => string;
|
||||
description: (text: string) => string;
|
||||
renderSelectedChoices: <T>(
|
||||
selectedChoices: ReadonlyArray<Choice<T>>,
|
||||
allChoices: ReadonlyArray<Choice<T> | Separator>,
|
||||
) => string;
|
||||
};
|
||||
icon: {
|
||||
checked: string;
|
||||
unchecked: string;
|
||||
cursor: string;
|
||||
};
|
||||
helpMode: 'always' | 'never' | 'auto';
|
||||
};
|
||||
```
|
||||
|
||||
### `theme.helpMode`
|
||||
|
||||
- `auto` (default): Hide the help tips after an interaction occurs. The scroll tip will hide after any interactions, the selection tip will hide as soon as a first selection is done.
|
||||
- `always`: The help tips will always show and never hide.
|
||||
- `never`: The help tips will never show.
|
||||
|
||||
# License
|
||||
|
||||
Copyright (c) 2023 Simon Boudrias (twitter: [@vaxilart](https://twitter.com/Vaxilart))<br/>
|
||||
Licensed under the MIT license.
|
@ -1,52 +0,0 @@
|
||||
import { Separator, type Theme } from '@inquirer/core';
|
||||
import type { PartialDeep } from '@inquirer/type';
|
||||
type CheckboxTheme = {
|
||||
icon: {
|
||||
checked: string;
|
||||
unchecked: string;
|
||||
cursor: string;
|
||||
};
|
||||
style: {
|
||||
disabledChoice: (text: string) => string;
|
||||
renderSelectedChoices: <T>(selectedChoices: ReadonlyArray<NormalizedChoice<T>>, allChoices: ReadonlyArray<NormalizedChoice<T> | Separator>) => string;
|
||||
description: (text: string) => string;
|
||||
};
|
||||
helpMode: 'always' | 'never' | 'auto';
|
||||
};
|
||||
type CheckboxShortcuts = {
|
||||
all?: string | null;
|
||||
invert?: string | null;
|
||||
};
|
||||
type Choice<Value> = {
|
||||
value: Value;
|
||||
name?: string;
|
||||
description?: string;
|
||||
short?: string;
|
||||
disabled?: boolean | string;
|
||||
checked?: boolean;
|
||||
type?: never;
|
||||
};
|
||||
type NormalizedChoice<Value> = {
|
||||
value: Value;
|
||||
name: string;
|
||||
description?: string;
|
||||
short: string;
|
||||
disabled: boolean | string;
|
||||
checked: boolean;
|
||||
};
|
||||
declare const _default: <Value>(config: {
|
||||
message: string;
|
||||
prefix?: string | undefined;
|
||||
pageSize?: number | undefined;
|
||||
instructions?: string | boolean | undefined;
|
||||
choices: readonly (string | Separator)[] | readonly (Separator | Choice<Value>)[];
|
||||
loop?: boolean | undefined;
|
||||
required?: boolean | undefined;
|
||||
validate?: ((choices: readonly Choice<Value>[]) => boolean | string | Promise<string | boolean>) | undefined;
|
||||
theme?: PartialDeep<Theme<CheckboxTheme>> | undefined;
|
||||
shortcuts?: CheckboxShortcuts | undefined;
|
||||
}, context?: import("@inquirer/type").Context) => Promise<Value[]> & {
|
||||
cancel: () => void;
|
||||
};
|
||||
export default _default;
|
||||
export { Separator } from '@inquirer/core';
|
@ -1,207 +0,0 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Separator = void 0;
|
||||
const core_1 = require("@inquirer/core");
|
||||
const yoctocolors_cjs_1 = __importDefault(require("yoctocolors-cjs"));
|
||||
const figures_1 = __importDefault(require("@inquirer/figures"));
|
||||
const ansi_escapes_1 = __importDefault(require("ansi-escapes"));
|
||||
const checkboxTheme = {
|
||||
icon: {
|
||||
checked: yoctocolors_cjs_1.default.green(figures_1.default.circleFilled),
|
||||
unchecked: figures_1.default.circle,
|
||||
cursor: figures_1.default.pointer,
|
||||
},
|
||||
style: {
|
||||
disabledChoice: (text) => yoctocolors_cjs_1.default.dim(`- ${text}`),
|
||||
renderSelectedChoices: (selectedChoices) => selectedChoices.map((choice) => choice.short).join(', '),
|
||||
description: (text) => yoctocolors_cjs_1.default.cyan(text),
|
||||
},
|
||||
helpMode: 'auto',
|
||||
};
|
||||
function isSelectable(item) {
|
||||
return !core_1.Separator.isSeparator(item) && !item.disabled;
|
||||
}
|
||||
function isChecked(item) {
|
||||
return isSelectable(item) && Boolean(item.checked);
|
||||
}
|
||||
function toggle(item) {
|
||||
return isSelectable(item) ? { ...item, checked: !item.checked } : item;
|
||||
}
|
||||
function check(checked) {
|
||||
return function (item) {
|
||||
return isSelectable(item) ? { ...item, checked } : item;
|
||||
};
|
||||
}
|
||||
function normalizeChoices(choices) {
|
||||
return choices.map((choice) => {
|
||||
if (core_1.Separator.isSeparator(choice))
|
||||
return choice;
|
||||
if (typeof choice === 'string') {
|
||||
return {
|
||||
value: choice,
|
||||
name: choice,
|
||||
short: choice,
|
||||
disabled: false,
|
||||
checked: false,
|
||||
};
|
||||
}
|
||||
const name = choice.name ?? String(choice.value);
|
||||
const normalizedChoice = {
|
||||
value: choice.value,
|
||||
name,
|
||||
short: choice.short ?? name,
|
||||
disabled: choice.disabled ?? false,
|
||||
checked: choice.checked ?? false,
|
||||
};
|
||||
if (choice.description) {
|
||||
normalizedChoice.description = choice.description;
|
||||
}
|
||||
return normalizedChoice;
|
||||
});
|
||||
}
|
||||
exports.default = (0, core_1.createPrompt)((config, done) => {
|
||||
const { instructions, pageSize = 7, loop = true, required, validate = () => true, } = config;
|
||||
const shortcuts = { all: 'a', invert: 'i', ...config.shortcuts };
|
||||
const theme = (0, core_1.makeTheme)(checkboxTheme, config.theme);
|
||||
const firstRender = (0, core_1.useRef)(true);
|
||||
const [status, setStatus] = (0, core_1.useState)('idle');
|
||||
const prefix = (0, core_1.usePrefix)({ status, theme });
|
||||
const [items, setItems] = (0, core_1.useState)(normalizeChoices(config.choices));
|
||||
const bounds = (0, core_1.useMemo)(() => {
|
||||
const first = items.findIndex(isSelectable);
|
||||
const last = items.findLastIndex(isSelectable);
|
||||
if (first === -1) {
|
||||
throw new core_1.ValidationError('[checkbox prompt] No selectable choices. All choices are disabled.');
|
||||
}
|
||||
return { first, last };
|
||||
}, [items]);
|
||||
const [active, setActive] = (0, core_1.useState)(bounds.first);
|
||||
const [showHelpTip, setShowHelpTip] = (0, core_1.useState)(true);
|
||||
const [errorMsg, setError] = (0, core_1.useState)();
|
||||
(0, core_1.useKeypress)(async (key) => {
|
||||
if ((0, core_1.isEnterKey)(key)) {
|
||||
const selection = items.filter(isChecked);
|
||||
const isValid = await validate([...selection]);
|
||||
if (required && !items.some(isChecked)) {
|
||||
setError('At least one choice must be selected');
|
||||
}
|
||||
else if (isValid === true) {
|
||||
setStatus('done');
|
||||
done(selection.map((choice) => choice.value));
|
||||
}
|
||||
else {
|
||||
setError(isValid || 'You must select a valid value');
|
||||
}
|
||||
}
|
||||
else if ((0, core_1.isUpKey)(key) || (0, core_1.isDownKey)(key)) {
|
||||
if (loop ||
|
||||
((0, core_1.isUpKey)(key) && active !== bounds.first) ||
|
||||
((0, core_1.isDownKey)(key) && active !== bounds.last)) {
|
||||
const offset = (0, core_1.isUpKey)(key) ? -1 : 1;
|
||||
let next = active;
|
||||
do {
|
||||
next = (next + offset + items.length) % items.length;
|
||||
} while (!isSelectable(items[next]));
|
||||
setActive(next);
|
||||
}
|
||||
}
|
||||
else if ((0, core_1.isSpaceKey)(key)) {
|
||||
setError(undefined);
|
||||
setShowHelpTip(false);
|
||||
setItems(items.map((choice, i) => (i === active ? toggle(choice) : choice)));
|
||||
}
|
||||
else if (key.name === shortcuts.all) {
|
||||
const selectAll = items.some((choice) => isSelectable(choice) && !choice.checked);
|
||||
setItems(items.map(check(selectAll)));
|
||||
}
|
||||
else if (key.name === shortcuts.invert) {
|
||||
setItems(items.map(toggle));
|
||||
}
|
||||
else if ((0, core_1.isNumberKey)(key)) {
|
||||
const selectedIndex = Number(key.name) - 1;
|
||||
// Find the nth item (ignoring separators)
|
||||
let selectableIndex = -1;
|
||||
const position = items.findIndex((item) => {
|
||||
if (core_1.Separator.isSeparator(item))
|
||||
return false;
|
||||
selectableIndex++;
|
||||
return selectableIndex === selectedIndex;
|
||||
});
|
||||
const selectedItem = items[position];
|
||||
if (selectedItem && isSelectable(selectedItem)) {
|
||||
setActive(position);
|
||||
setItems(items.map((choice, i) => (i === position ? toggle(choice) : choice)));
|
||||
}
|
||||
}
|
||||
});
|
||||
const message = theme.style.message(config.message, status);
|
||||
let description;
|
||||
const page = (0, core_1.usePagination)({
|
||||
items,
|
||||
active,
|
||||
renderItem({ item, isActive }) {
|
||||
if (core_1.Separator.isSeparator(item)) {
|
||||
return ` ${item.separator}`;
|
||||
}
|
||||
if (item.disabled) {
|
||||
const disabledLabel = typeof item.disabled === 'string' ? item.disabled : '(disabled)';
|
||||
return theme.style.disabledChoice(`${item.name} ${disabledLabel}`);
|
||||
}
|
||||
if (isActive) {
|
||||
description = item.description;
|
||||
}
|
||||
const checkbox = item.checked ? theme.icon.checked : theme.icon.unchecked;
|
||||
const color = isActive ? theme.style.highlight : (x) => x;
|
||||
const cursor = isActive ? theme.icon.cursor : ' ';
|
||||
return color(`${cursor}${checkbox} ${item.name}`);
|
||||
},
|
||||
pageSize,
|
||||
loop,
|
||||
});
|
||||
if (status === 'done') {
|
||||
const selection = items.filter(isChecked);
|
||||
const answer = theme.style.answer(theme.style.renderSelectedChoices(selection, items));
|
||||
return `${prefix} ${message} ${answer}`;
|
||||
}
|
||||
let helpTipTop = '';
|
||||
let helpTipBottom = '';
|
||||
if (theme.helpMode === 'always' ||
|
||||
(theme.helpMode === 'auto' &&
|
||||
showHelpTip &&
|
||||
(instructions === undefined || instructions))) {
|
||||
if (typeof instructions === 'string') {
|
||||
helpTipTop = instructions;
|
||||
}
|
||||
else {
|
||||
const keys = [
|
||||
`${theme.style.key('space')} to select`,
|
||||
shortcuts.all ? `${theme.style.key(shortcuts.all)} to toggle all` : '',
|
||||
shortcuts.invert
|
||||
? `${theme.style.key(shortcuts.invert)} to invert selection`
|
||||
: '',
|
||||
`and ${theme.style.key('enter')} to proceed`,
|
||||
];
|
||||
helpTipTop = ` (Press ${keys.filter((key) => key !== '').join(', ')})`;
|
||||
}
|
||||
if (items.length > pageSize &&
|
||||
(theme.helpMode === 'always' ||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
(theme.helpMode === 'auto' && firstRender.current))) {
|
||||
helpTipBottom = `\n${theme.style.help('(Use arrow keys to reveal more choices)')}`;
|
||||
firstRender.current = false;
|
||||
}
|
||||
}
|
||||
const choiceDescription = description
|
||||
? `\n${theme.style.description(description)}`
|
||||
: ``;
|
||||
let error = '';
|
||||
if (errorMsg) {
|
||||
error = `\n${theme.style.error(errorMsg)}`;
|
||||
}
|
||||
return `${prefix} ${message}${helpTipTop}\n${page}${helpTipBottom}${choiceDescription}${error}${ansi_escapes_1.default.cursorHide}`;
|
||||
});
|
||||
var core_2 = require("@inquirer/core");
|
||||
Object.defineProperty(exports, "Separator", { enumerable: true, get: function () { return core_2.Separator; } });
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
import { Separator, type Theme } from '@inquirer/core';
|
||||
import type { PartialDeep } from '@inquirer/type';
|
||||
type CheckboxTheme = {
|
||||
icon: {
|
||||
checked: string;
|
||||
unchecked: string;
|
||||
cursor: string;
|
||||
};
|
||||
style: {
|
||||
disabledChoice: (text: string) => string;
|
||||
renderSelectedChoices: <T>(selectedChoices: ReadonlyArray<NormalizedChoice<T>>, allChoices: ReadonlyArray<NormalizedChoice<T> | Separator>) => string;
|
||||
description: (text: string) => string;
|
||||
};
|
||||
helpMode: 'always' | 'never' | 'auto';
|
||||
};
|
||||
type CheckboxShortcuts = {
|
||||
all?: string | null;
|
||||
invert?: string | null;
|
||||
};
|
||||
type Choice<Value> = {
|
||||
value: Value;
|
||||
name?: string;
|
||||
description?: string;
|
||||
short?: string;
|
||||
disabled?: boolean | string;
|
||||
checked?: boolean;
|
||||
type?: never;
|
||||
};
|
||||
type NormalizedChoice<Value> = {
|
||||
value: Value;
|
||||
name: string;
|
||||
description?: string;
|
||||
short: string;
|
||||
disabled: boolean | string;
|
||||
checked: boolean;
|
||||
};
|
||||
declare const _default: <Value>(config: {
|
||||
message: string;
|
||||
prefix?: string | undefined;
|
||||
pageSize?: number | undefined;
|
||||
instructions?: string | boolean | undefined;
|
||||
choices: readonly (string | Separator)[] | readonly (Separator | Choice<Value>)[];
|
||||
loop?: boolean | undefined;
|
||||
required?: boolean | undefined;
|
||||
validate?: ((choices: readonly Choice<Value>[]) => boolean | string | Promise<string | boolean>) | undefined;
|
||||
theme?: PartialDeep<Theme<CheckboxTheme>> | undefined;
|
||||
shortcuts?: CheckboxShortcuts | undefined;
|
||||
}, context?: import("@inquirer/type").Context) => Promise<Value[]> & {
|
||||
cancel: () => void;
|
||||
};
|
||||
export default _default;
|
||||
export { Separator } from '@inquirer/core';
|
@ -1,200 +0,0 @@
|
||||
import { createPrompt, useState, useKeypress, usePrefix, usePagination, useRef, useMemo, makeTheme, isUpKey, isDownKey, isSpaceKey, isNumberKey, isEnterKey, ValidationError, Separator, } from '@inquirer/core';
|
||||
import colors from 'yoctocolors-cjs';
|
||||
import figures from '@inquirer/figures';
|
||||
import ansiEscapes from 'ansi-escapes';
|
||||
const checkboxTheme = {
|
||||
icon: {
|
||||
checked: colors.green(figures.circleFilled),
|
||||
unchecked: figures.circle,
|
||||
cursor: figures.pointer,
|
||||
},
|
||||
style: {
|
||||
disabledChoice: (text) => colors.dim(`- ${text}`),
|
||||
renderSelectedChoices: (selectedChoices) => selectedChoices.map((choice) => choice.short).join(', '),
|
||||
description: (text) => colors.cyan(text),
|
||||
},
|
||||
helpMode: 'auto',
|
||||
};
|
||||
function isSelectable(item) {
|
||||
return !Separator.isSeparator(item) && !item.disabled;
|
||||
}
|
||||
function isChecked(item) {
|
||||
return isSelectable(item) && Boolean(item.checked);
|
||||
}
|
||||
function toggle(item) {
|
||||
return isSelectable(item) ? { ...item, checked: !item.checked } : item;
|
||||
}
|
||||
function check(checked) {
|
||||
return function (item) {
|
||||
return isSelectable(item) ? { ...item, checked } : item;
|
||||
};
|
||||
}
|
||||
function normalizeChoices(choices) {
|
||||
return choices.map((choice) => {
|
||||
if (Separator.isSeparator(choice))
|
||||
return choice;
|
||||
if (typeof choice === 'string') {
|
||||
return {
|
||||
value: choice,
|
||||
name: choice,
|
||||
short: choice,
|
||||
disabled: false,
|
||||
checked: false,
|
||||
};
|
||||
}
|
||||
const name = choice.name ?? String(choice.value);
|
||||
const normalizedChoice = {
|
||||
value: choice.value,
|
||||
name,
|
||||
short: choice.short ?? name,
|
||||
disabled: choice.disabled ?? false,
|
||||
checked: choice.checked ?? false,
|
||||
};
|
||||
if (choice.description) {
|
||||
normalizedChoice.description = choice.description;
|
||||
}
|
||||
return normalizedChoice;
|
||||
});
|
||||
}
|
||||
export default createPrompt((config, done) => {
|
||||
const { instructions, pageSize = 7, loop = true, required, validate = () => true, } = config;
|
||||
const shortcuts = { all: 'a', invert: 'i', ...config.shortcuts };
|
||||
const theme = makeTheme(checkboxTheme, config.theme);
|
||||
const firstRender = useRef(true);
|
||||
const [status, setStatus] = useState('idle');
|
||||
const prefix = usePrefix({ status, theme });
|
||||
const [items, setItems] = useState(normalizeChoices(config.choices));
|
||||
const bounds = useMemo(() => {
|
||||
const first = items.findIndex(isSelectable);
|
||||
const last = items.findLastIndex(isSelectable);
|
||||
if (first === -1) {
|
||||
throw new ValidationError('[checkbox prompt] No selectable choices. All choices are disabled.');
|
||||
}
|
||||
return { first, last };
|
||||
}, [items]);
|
||||
const [active, setActive] = useState(bounds.first);
|
||||
const [showHelpTip, setShowHelpTip] = useState(true);
|
||||
const [errorMsg, setError] = useState();
|
||||
useKeypress(async (key) => {
|
||||
if (isEnterKey(key)) {
|
||||
const selection = items.filter(isChecked);
|
||||
const isValid = await validate([...selection]);
|
||||
if (required && !items.some(isChecked)) {
|
||||
setError('At least one choice must be selected');
|
||||
}
|
||||
else if (isValid === true) {
|
||||
setStatus('done');
|
||||
done(selection.map((choice) => choice.value));
|
||||
}
|
||||
else {
|
||||
setError(isValid || 'You must select a valid value');
|
||||
}
|
||||
}
|
||||
else if (isUpKey(key) || isDownKey(key)) {
|
||||
if (loop ||
|
||||
(isUpKey(key) && active !== bounds.first) ||
|
||||
(isDownKey(key) && active !== bounds.last)) {
|
||||
const offset = isUpKey(key) ? -1 : 1;
|
||||
let next = active;
|
||||
do {
|
||||
next = (next + offset + items.length) % items.length;
|
||||
} while (!isSelectable(items[next]));
|
||||
setActive(next);
|
||||
}
|
||||
}
|
||||
else if (isSpaceKey(key)) {
|
||||
setError(undefined);
|
||||
setShowHelpTip(false);
|
||||
setItems(items.map((choice, i) => (i === active ? toggle(choice) : choice)));
|
||||
}
|
||||
else if (key.name === shortcuts.all) {
|
||||
const selectAll = items.some((choice) => isSelectable(choice) && !choice.checked);
|
||||
setItems(items.map(check(selectAll)));
|
||||
}
|
||||
else if (key.name === shortcuts.invert) {
|
||||
setItems(items.map(toggle));
|
||||
}
|
||||
else if (isNumberKey(key)) {
|
||||
const selectedIndex = Number(key.name) - 1;
|
||||
// Find the nth item (ignoring separators)
|
||||
let selectableIndex = -1;
|
||||
const position = items.findIndex((item) => {
|
||||
if (Separator.isSeparator(item))
|
||||
return false;
|
||||
selectableIndex++;
|
||||
return selectableIndex === selectedIndex;
|
||||
});
|
||||
const selectedItem = items[position];
|
||||
if (selectedItem && isSelectable(selectedItem)) {
|
||||
setActive(position);
|
||||
setItems(items.map((choice, i) => (i === position ? toggle(choice) : choice)));
|
||||
}
|
||||
}
|
||||
});
|
||||
const message = theme.style.message(config.message, status);
|
||||
let description;
|
||||
const page = usePagination({
|
||||
items,
|
||||
active,
|
||||
renderItem({ item, isActive }) {
|
||||
if (Separator.isSeparator(item)) {
|
||||
return ` ${item.separator}`;
|
||||
}
|
||||
if (item.disabled) {
|
||||
const disabledLabel = typeof item.disabled === 'string' ? item.disabled : '(disabled)';
|
||||
return theme.style.disabledChoice(`${item.name} ${disabledLabel}`);
|
||||
}
|
||||
if (isActive) {
|
||||
description = item.description;
|
||||
}
|
||||
const checkbox = item.checked ? theme.icon.checked : theme.icon.unchecked;
|
||||
const color = isActive ? theme.style.highlight : (x) => x;
|
||||
const cursor = isActive ? theme.icon.cursor : ' ';
|
||||
return color(`${cursor}${checkbox} ${item.name}`);
|
||||
},
|
||||
pageSize,
|
||||
loop,
|
||||
});
|
||||
if (status === 'done') {
|
||||
const selection = items.filter(isChecked);
|
||||
const answer = theme.style.answer(theme.style.renderSelectedChoices(selection, items));
|
||||
return `${prefix} ${message} ${answer}`;
|
||||
}
|
||||
let helpTipTop = '';
|
||||
let helpTipBottom = '';
|
||||
if (theme.helpMode === 'always' ||
|
||||
(theme.helpMode === 'auto' &&
|
||||
showHelpTip &&
|
||||
(instructions === undefined || instructions))) {
|
||||
if (typeof instructions === 'string') {
|
||||
helpTipTop = instructions;
|
||||
}
|
||||
else {
|
||||
const keys = [
|
||||
`${theme.style.key('space')} to select`,
|
||||
shortcuts.all ? `${theme.style.key(shortcuts.all)} to toggle all` : '',
|
||||
shortcuts.invert
|
||||
? `${theme.style.key(shortcuts.invert)} to invert selection`
|
||||
: '',
|
||||
`and ${theme.style.key('enter')} to proceed`,
|
||||
];
|
||||
helpTipTop = ` (Press ${keys.filter((key) => key !== '').join(', ')})`;
|
||||
}
|
||||
if (items.length > pageSize &&
|
||||
(theme.helpMode === 'always' ||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
(theme.helpMode === 'auto' && firstRender.current))) {
|
||||
helpTipBottom = `\n${theme.style.help('(Use arrow keys to reveal more choices)')}`;
|
||||
firstRender.current = false;
|
||||
}
|
||||
}
|
||||
const choiceDescription = description
|
||||
? `\n${theme.style.description(description)}`
|
||||
: ``;
|
||||
let error = '';
|
||||
if (errorMsg) {
|
||||
error = `\n${theme.style.error(errorMsg)}`;
|
||||
}
|
||||
return `${prefix} ${message}${helpTipTop}\n${page}${helpTipBottom}${choiceDescription}${error}${ansiEscapes.cursorHide}`;
|
||||
});
|
||||
export { Separator } from '@inquirer/core';
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
{
|
||||
"name": "@inquirer/checkbox",
|
||||
"version": "4.2.0",
|
||||
"description": "Inquirer checkbox prompt",
|
||||
"keywords": [
|
||||
"answer",
|
||||
"answers",
|
||||
"ask",
|
||||
"base",
|
||||
"cli",
|
||||
"command",
|
||||
"command-line",
|
||||
"confirm",
|
||||
"enquirer",
|
||||
"generate",
|
||||
"generator",
|
||||
"hyper",
|
||||
"input",
|
||||
"inquire",
|
||||
"inquirer",
|
||||
"interface",
|
||||
"iterm",
|
||||
"javascript",
|
||||
"menu",
|
||||
"node",
|
||||
"nodejs",
|
||||
"prompt",
|
||||
"promptly",
|
||||
"prompts",
|
||||
"question",
|
||||
"readline",
|
||||
"scaffold",
|
||||
"scaffolder",
|
||||
"scaffolding",
|
||||
"stdin",
|
||||
"stdout",
|
||||
"terminal",
|
||||
"tty",
|
||||
"ui",
|
||||
"yeoman",
|
||||
"yo",
|
||||
"zsh"
|
||||
],
|
||||
"homepage": "https://github.com/SBoudrias/Inquirer.js/blob/main/packages/checkbox/README.md",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/SBoudrias/Inquirer.js.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "Simon Boudrias <admin@simonboudrias.com>",
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"import": {
|
||||
"types": "./dist/esm/index.d.ts",
|
||||
"default": "./dist/esm/index.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/commonjs/index.d.ts",
|
||||
"default": "./dist/commonjs/index.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"main": "./dist/commonjs/index.js",
|
||||
"module": "./dist/esm/index.js",
|
||||
"types": "./dist/commonjs/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"attw": "attw --pack",
|
||||
"tsc": "tshy"
|
||||
},
|
||||
"dependencies": {
|
||||
"@inquirer/core": "^10.1.15",
|
||||
"@inquirer/figures": "^1.0.13",
|
||||
"@inquirer/type": "^3.0.8",
|
||||
"ansi-escapes": "^4.3.2",
|
||||
"yoctocolors-cjs": "^2.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@arethetypeswrong/cli": "^0.18.2",
|
||||
"@inquirer/testing": "^2.1.49",
|
||||
"tshy": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"tshy": {
|
||||
"exclude": [
|
||||
"src/**/*.test.ts"
|
||||
],
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": "./src/index.ts"
|
||||
}
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"gitHead": "c1a755fe8b50377b685ea5951e0794985ce8d356"
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
Copyright (c) 2025 Simon Boudrias
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
@ -1,102 +0,0 @@
|
||||
# `@inquirer/confirm`
|
||||
|
||||
Simple interactive command line prompt to gather boolean input from users.
|
||||
|
||||

|
||||
|
||||
# Special Thanks
|
||||
|
||||
<div align="center" markdown="1">
|
||||
|
||||
[](https://graphite.dev/?utm_source=npmjs&utm_medium=repo&utm_campaign=inquirerjs)<br>
|
||||
|
||||
### [Graphite is the AI developer productivity platform helping teams on GitHub ship higher quality software, faster](https://graphite.dev/?utm_source=npmjs&utm_medium=repo&utm_campaign=inquirerjs)
|
||||
|
||||
</div>
|
||||
|
||||
# Installation
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>npm</th>
|
||||
<th>yarn</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
```sh
|
||||
npm install @inquirer/prompts
|
||||
```
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
```sh
|
||||
yarn add @inquirer/prompts
|
||||
```
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colSpan="2" align="center">Or</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
```sh
|
||||
npm install @inquirer/confirm
|
||||
```
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
```sh
|
||||
yarn add @inquirer/confirm
|
||||
```
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
# Usage
|
||||
|
||||
```js
|
||||
import { confirm } from '@inquirer/prompts';
|
||||
// Or
|
||||
// import confirm from '@inquirer/confirm';
|
||||
|
||||
const answer = await confirm({ message: 'Continue?' });
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
| Property | Type | Required | Description |
|
||||
| ----------- | ----------------------- | -------- | ------------------------------------------------------- |
|
||||
| message | `string` | yes | The question to ask |
|
||||
| default | `boolean` | no | Default answer (true or false) |
|
||||
| transformer | `(boolean) => string` | no | Transform the prompt printed message to a custom string |
|
||||
| theme | [See Theming](#Theming) | no | Customize look of the prompt. |
|
||||
|
||||
## Theming
|
||||
|
||||
You can theme a prompt by passing a `theme` object option. The theme object only need to includes the keys you wish to modify, we'll fallback on the defaults for the rest.
|
||||
|
||||
```ts
|
||||
type Theme = {
|
||||
prefix: string | { idle: string; done: string };
|
||||
spinner: {
|
||||
interval: number;
|
||||
frames: string[];
|
||||
};
|
||||
style: {
|
||||
answer: (text: string) => string;
|
||||
message: (text: string, status: 'idle' | 'done' | 'loading') => string;
|
||||
defaultAnswer: (text: string) => string;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
# License
|
||||
|
||||
Copyright (c) 2023 Simon Boudrias (twitter: [@vaxilart](https://twitter.com/Vaxilart))<br/>
|
||||
Licensed under the MIT license.
|
@ -1,10 +0,0 @@
|
||||
import { type Theme } from '@inquirer/core';
|
||||
import type { PartialDeep } from '@inquirer/type';
|
||||
type ConfirmConfig = {
|
||||
message: string;
|
||||
default?: boolean;
|
||||
transformer?: (value: boolean) => string;
|
||||
theme?: PartialDeep<Theme>;
|
||||
};
|
||||
declare const _default: import("@inquirer/type").Prompt<boolean, ConfirmConfig>;
|
||||
export default _default;
|
@ -1,48 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const core_1 = require("@inquirer/core");
|
||||
function getBooleanValue(value, defaultValue) {
|
||||
let answer = defaultValue !== false;
|
||||
if (/^(y|yes)/i.test(value))
|
||||
answer = true;
|
||||
else if (/^(n|no)/i.test(value))
|
||||
answer = false;
|
||||
return answer;
|
||||
}
|
||||
function boolToString(value) {
|
||||
return value ? 'Yes' : 'No';
|
||||
}
|
||||
exports.default = (0, core_1.createPrompt)((config, done) => {
|
||||
const { transformer = boolToString } = config;
|
||||
const [status, setStatus] = (0, core_1.useState)('idle');
|
||||
const [value, setValue] = (0, core_1.useState)('');
|
||||
const theme = (0, core_1.makeTheme)(config.theme);
|
||||
const prefix = (0, core_1.usePrefix)({ status, theme });
|
||||
(0, core_1.useKeypress)((key, rl) => {
|
||||
if ((0, core_1.isEnterKey)(key)) {
|
||||
const answer = getBooleanValue(value, config.default);
|
||||
setValue(transformer(answer));
|
||||
setStatus('done');
|
||||
done(answer);
|
||||
}
|
||||
else if (key.name === 'tab') {
|
||||
const answer = boolToString(!getBooleanValue(value, config.default));
|
||||
rl.clearLine(0); // Remove the tab character.
|
||||
rl.write(answer);
|
||||
setValue(answer);
|
||||
}
|
||||
else {
|
||||
setValue(rl.line);
|
||||
}
|
||||
});
|
||||
let formattedValue = value;
|
||||
let defaultValue = '';
|
||||
if (status === 'done') {
|
||||
formattedValue = theme.style.answer(value);
|
||||
}
|
||||
else {
|
||||
defaultValue = ` ${theme.style.defaultAnswer(config.default === false ? 'y/N' : 'Y/n')}`;
|
||||
}
|
||||
const message = theme.style.message(config.message, status);
|
||||
return `${prefix} ${message}${defaultValue} ${formattedValue}`;
|
||||
});
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import { type Theme } from '@inquirer/core';
|
||||
import type { PartialDeep } from '@inquirer/type';
|
||||
type ConfirmConfig = {
|
||||
message: string;
|
||||
default?: boolean;
|
||||
transformer?: (value: boolean) => string;
|
||||
theme?: PartialDeep<Theme>;
|
||||
};
|
||||
declare const _default: import("@inquirer/type").Prompt<boolean, ConfirmConfig>;
|
||||
export default _default;
|
@ -1,46 +0,0 @@
|
||||
import { createPrompt, useState, useKeypress, isEnterKey, usePrefix, makeTheme, } from '@inquirer/core';
|
||||
function getBooleanValue(value, defaultValue) {
|
||||
let answer = defaultValue !== false;
|
||||
if (/^(y|yes)/i.test(value))
|
||||
answer = true;
|
||||
else if (/^(n|no)/i.test(value))
|
||||
answer = false;
|
||||
return answer;
|
||||
}
|
||||
function boolToString(value) {
|
||||
return value ? 'Yes' : 'No';
|
||||
}
|
||||
export default createPrompt((config, done) => {
|
||||
const { transformer = boolToString } = config;
|
||||
const [status, setStatus] = useState('idle');
|
||||
const [value, setValue] = useState('');
|
||||
const theme = makeTheme(config.theme);
|
||||
const prefix = usePrefix({ status, theme });
|
||||
useKeypress((key, rl) => {
|
||||
if (isEnterKey(key)) {
|
||||
const answer = getBooleanValue(value, config.default);
|
||||
setValue(transformer(answer));
|
||||
setStatus('done');
|
||||
done(answer);
|
||||
}
|
||||
else if (key.name === 'tab') {
|
||||
const answer = boolToString(!getBooleanValue(value, config.default));
|
||||
rl.clearLine(0); // Remove the tab character.
|
||||
rl.write(answer);
|
||||
setValue(answer);
|
||||
}
|
||||
else {
|
||||
setValue(rl.line);
|
||||
}
|
||||
});
|
||||
let formattedValue = value;
|
||||
let defaultValue = '';
|
||||
if (status === 'done') {
|
||||
formattedValue = theme.style.answer(value);
|
||||
}
|
||||
else {
|
||||
defaultValue = ` ${theme.style.defaultAnswer(config.default === false ? 'y/N' : 'Y/n')}`;
|
||||
}
|
||||
const message = theme.style.message(config.message, status);
|
||||
return `${prefix} ${message}${defaultValue} ${formattedValue}`;
|
||||
});
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
{
|
||||
"name": "@inquirer/confirm",
|
||||
"version": "5.1.14",
|
||||
"description": "Inquirer confirm prompt",
|
||||
"keywords": [
|
||||
"answer",
|
||||
"answers",
|
||||
"ask",
|
||||
"base",
|
||||
"cli",
|
||||
"command",
|
||||
"command-line",
|
||||
"confirm",
|
||||
"enquirer",
|
||||
"generate",
|
||||
"generator",
|
||||
"hyper",
|
||||
"input",
|
||||
"inquire",
|
||||
"inquirer",
|
||||
"interface",
|
||||
"iterm",
|
||||
"javascript",
|
||||
"menu",
|
||||
"node",
|
||||
"nodejs",
|
||||
"prompt",
|
||||
"promptly",
|
||||
"prompts",
|
||||
"question",
|
||||
"readline",
|
||||
"scaffold",
|
||||
"scaffolder",
|
||||
"scaffolding",
|
||||
"stdin",
|
||||
"stdout",
|
||||
"terminal",
|
||||
"tty",
|
||||
"ui",
|
||||
"yeoman",
|
||||
"yo",
|
||||
"zsh"
|
||||
],
|
||||
"homepage": "https://github.com/SBoudrias/Inquirer.js/blob/main/packages/confirm/README.md",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/SBoudrias/Inquirer.js.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "Simon Boudrias <admin@simonboudrias.com>",
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"import": {
|
||||
"types": "./dist/esm/index.d.ts",
|
||||
"default": "./dist/esm/index.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/commonjs/index.d.ts",
|
||||
"default": "./dist/commonjs/index.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"main": "./dist/commonjs/index.js",
|
||||
"module": "./dist/esm/index.js",
|
||||
"types": "./dist/commonjs/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"attw": "attw --pack",
|
||||
"tsc": "tshy"
|
||||
},
|
||||
"dependencies": {
|
||||
"@inquirer/core": "^10.1.15",
|
||||
"@inquirer/type": "^3.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@arethetypeswrong/cli": "^0.18.2",
|
||||
"@inquirer/testing": "^2.1.49",
|
||||
"tshy": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"tshy": {
|
||||
"exclude": [
|
||||
"src/**/*.test.ts"
|
||||
],
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": "./src/index.ts"
|
||||
}
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"gitHead": "c1a755fe8b50377b685ea5951e0794985ce8d356"
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
Copyright (c) 2025 Simon Boudrias
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
@ -1,13 +0,0 @@
|
||||
export * from './lib/key.ts';
|
||||
export * from './lib/errors.ts';
|
||||
export { usePrefix } from './lib/use-prefix.ts';
|
||||
export { useState } from './lib/use-state.ts';
|
||||
export { useEffect } from './lib/use-effect.ts';
|
||||
export { useMemo } from './lib/use-memo.ts';
|
||||
export { useRef } from './lib/use-ref.ts';
|
||||
export { useKeypress } from './lib/use-keypress.ts';
|
||||
export { makeTheme } from './lib/make-theme.ts';
|
||||
export type { Theme, Status } from './lib/theme.ts';
|
||||
export { usePagination } from './lib/pagination/use-pagination.ts';
|
||||
export { createPrompt } from './lib/create-prompt.ts';
|
||||
export { Separator } from './lib/Separator.ts';
|
@ -1,39 +0,0 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Separator = exports.createPrompt = exports.usePagination = exports.makeTheme = exports.useKeypress = exports.useRef = exports.useMemo = exports.useEffect = exports.useState = exports.usePrefix = void 0;
|
||||
__exportStar(require("./lib/key.js"), exports);
|
||||
__exportStar(require("./lib/errors.js"), exports);
|
||||
var use_prefix_ts_1 = require("./lib/use-prefix.js");
|
||||
Object.defineProperty(exports, "usePrefix", { enumerable: true, get: function () { return use_prefix_ts_1.usePrefix; } });
|
||||
var use_state_ts_1 = require("./lib/use-state.js");
|
||||
Object.defineProperty(exports, "useState", { enumerable: true, get: function () { return use_state_ts_1.useState; } });
|
||||
var use_effect_ts_1 = require("./lib/use-effect.js");
|
||||
Object.defineProperty(exports, "useEffect", { enumerable: true, get: function () { return use_effect_ts_1.useEffect; } });
|
||||
var use_memo_ts_1 = require("./lib/use-memo.js");
|
||||
Object.defineProperty(exports, "useMemo", { enumerable: true, get: function () { return use_memo_ts_1.useMemo; } });
|
||||
var use_ref_ts_1 = require("./lib/use-ref.js");
|
||||
Object.defineProperty(exports, "useRef", { enumerable: true, get: function () { return use_ref_ts_1.useRef; } });
|
||||
var use_keypress_ts_1 = require("./lib/use-keypress.js");
|
||||
Object.defineProperty(exports, "useKeypress", { enumerable: true, get: function () { return use_keypress_ts_1.useKeypress; } });
|
||||
var make_theme_ts_1 = require("./lib/make-theme.js");
|
||||
Object.defineProperty(exports, "makeTheme", { enumerable: true, get: function () { return make_theme_ts_1.makeTheme; } });
|
||||
var use_pagination_ts_1 = require("./lib/pagination/use-pagination.js");
|
||||
Object.defineProperty(exports, "usePagination", { enumerable: true, get: function () { return use_pagination_ts_1.usePagination; } });
|
||||
var create_prompt_ts_1 = require("./lib/create-prompt.js");
|
||||
Object.defineProperty(exports, "createPrompt", { enumerable: true, get: function () { return create_prompt_ts_1.createPrompt; } });
|
||||
var Separator_ts_1 = require("./lib/Separator.js");
|
||||
Object.defineProperty(exports, "Separator", { enumerable: true, get: function () { return Separator_ts_1.Separator; } });
|
@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Separator object
|
||||
* Used to space/separate choices group
|
||||
*/
|
||||
export declare class Separator {
|
||||
readonly separator: string;
|
||||
readonly type: string;
|
||||
constructor(separator?: string);
|
||||
static isSeparator(choice: unknown): choice is Separator;
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Separator = void 0;
|
||||
const yoctocolors_cjs_1 = __importDefault(require("yoctocolors-cjs"));
|
||||
const figures_1 = __importDefault(require("@inquirer/figures"));
|
||||
/**
|
||||
* Separator object
|
||||
* Used to space/separate choices group
|
||||
*/
|
||||
class Separator {
|
||||
separator = yoctocolors_cjs_1.default.dim(Array.from({ length: 15 }).join(figures_1.default.line));
|
||||
type = 'separator';
|
||||
constructor(separator) {
|
||||
if (separator) {
|
||||
this.separator = separator;
|
||||
}
|
||||
}
|
||||
static isSeparator(choice) {
|
||||
return Boolean(choice &&
|
||||
typeof choice === 'object' &&
|
||||
'type' in choice &&
|
||||
choice.type === 'separator');
|
||||
}
|
||||
}
|
||||
exports.Separator = Separator;
|
@ -1,4 +0,0 @@
|
||||
import { type Prompt, type Prettify } from '@inquirer/type';
|
||||
type ViewFunction<Value, Config> = (config: Prettify<Config>, done: (value: Value) => void) => string | [string, string | undefined];
|
||||
export declare function createPrompt<Value, Config>(view: ViewFunction<Value, Config>): Prompt<Value, Config>;
|
||||
export {};
|
@ -1,156 +0,0 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createPrompt = createPrompt;
|
||||
const readline = __importStar(require("node:readline"));
|
||||
const node_async_hooks_1 = require("node:async_hooks");
|
||||
const mute_stream_1 = __importDefault(require("mute-stream"));
|
||||
const signal_exit_1 = require("signal-exit");
|
||||
const screen_manager_ts_1 = __importDefault(require("./screen-manager.js"));
|
||||
const promise_polyfill_ts_1 = require("./promise-polyfill.js");
|
||||
const hook_engine_ts_1 = require("./hook-engine.js");
|
||||
const errors_ts_1 = require("./errors.js");
|
||||
function getCallSites() {
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const _prepareStackTrace = Error.prepareStackTrace;
|
||||
let result = [];
|
||||
try {
|
||||
Error.prepareStackTrace = (_, callSites) => {
|
||||
const callSitesWithoutCurrent = callSites.slice(1);
|
||||
result = callSitesWithoutCurrent;
|
||||
return callSitesWithoutCurrent;
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
new Error().stack;
|
||||
}
|
||||
catch {
|
||||
// An error will occur if the Node flag --frozen-intrinsics is used.
|
||||
// https://nodejs.org/api/cli.html#--frozen-intrinsics
|
||||
return result;
|
||||
}
|
||||
Error.prepareStackTrace = _prepareStackTrace;
|
||||
return result;
|
||||
}
|
||||
function createPrompt(view) {
|
||||
const callSites = getCallSites();
|
||||
const prompt = (config, context = {}) => {
|
||||
// Default `input` to stdin
|
||||
const { input = process.stdin, signal } = context;
|
||||
const cleanups = new Set();
|
||||
// Add mute capabilities to the output
|
||||
const output = new mute_stream_1.default();
|
||||
output.pipe(context.output ?? process.stdout);
|
||||
const rl = readline.createInterface({
|
||||
terminal: true,
|
||||
input,
|
||||
output,
|
||||
});
|
||||
const screen = new screen_manager_ts_1.default(rl);
|
||||
const { promise, resolve, reject } = promise_polyfill_ts_1.PromisePolyfill.withResolver();
|
||||
const cancel = () => reject(new errors_ts_1.CancelPromptError());
|
||||
if (signal) {
|
||||
const abort = () => reject(new errors_ts_1.AbortPromptError({ cause: signal.reason }));
|
||||
if (signal.aborted) {
|
||||
abort();
|
||||
return Object.assign(promise, { cancel });
|
||||
}
|
||||
signal.addEventListener('abort', abort);
|
||||
cleanups.add(() => signal.removeEventListener('abort', abort));
|
||||
}
|
||||
cleanups.add((0, signal_exit_1.onExit)((code, signal) => {
|
||||
reject(new errors_ts_1.ExitPromptError(`User force closed the prompt with ${code} ${signal}`));
|
||||
}));
|
||||
// SIGINT must be explicitly handled by the prompt so the ExitPromptError can be handled.
|
||||
// Otherwise, the prompt will stop and in some scenarios never resolve.
|
||||
// Ref issue #1741
|
||||
const sigint = () => reject(new errors_ts_1.ExitPromptError(`User force closed the prompt with SIGINT`));
|
||||
rl.on('SIGINT', sigint);
|
||||
cleanups.add(() => rl.removeListener('SIGINT', sigint));
|
||||
// Re-renders only happen when the state change; but the readline cursor could change position
|
||||
// and that also requires a re-render (and a manual one because we mute the streams).
|
||||
// We set the listener after the initial workLoop to avoid a double render if render triggered
|
||||
// by a state change sets the cursor to the right position.
|
||||
const checkCursorPos = () => screen.checkCursorPos();
|
||||
rl.input.on('keypress', checkCursorPos);
|
||||
cleanups.add(() => rl.input.removeListener('keypress', checkCursorPos));
|
||||
return (0, hook_engine_ts_1.withHooks)(rl, (cycle) => {
|
||||
// The close event triggers immediately when the user press ctrl+c. SignalExit on the other hand
|
||||
// triggers after the process is done (which happens after timeouts are done triggering.)
|
||||
// We triggers the hooks cleanup phase on rl `close` so active timeouts can be cleared.
|
||||
const hooksCleanup = node_async_hooks_1.AsyncResource.bind(() => hook_engine_ts_1.effectScheduler.clearAll());
|
||||
rl.on('close', hooksCleanup);
|
||||
cleanups.add(() => rl.removeListener('close', hooksCleanup));
|
||||
cycle(() => {
|
||||
try {
|
||||
const nextView = view(config, (value) => {
|
||||
setImmediate(() => resolve(value));
|
||||
});
|
||||
// Typescript won't allow this, but not all users rely on typescript.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (nextView === undefined) {
|
||||
const callerFilename = callSites[1]?.getFileName();
|
||||
throw new Error(`Prompt functions must return a string.\n at ${callerFilename}`);
|
||||
}
|
||||
const [content, bottomContent] = typeof nextView === 'string' ? [nextView] : nextView;
|
||||
screen.render(content, bottomContent);
|
||||
hook_engine_ts_1.effectScheduler.run();
|
||||
}
|
||||
catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
return Object.assign(promise
|
||||
.then((answer) => {
|
||||
hook_engine_ts_1.effectScheduler.clearAll();
|
||||
return answer;
|
||||
}, (error) => {
|
||||
hook_engine_ts_1.effectScheduler.clearAll();
|
||||
throw error;
|
||||
})
|
||||
// Wait for the promise to settle, then cleanup.
|
||||
.finally(() => {
|
||||
cleanups.forEach((cleanup) => cleanup());
|
||||
screen.done({ clearContent: Boolean(context.clearPromptOnDone) });
|
||||
output.end();
|
||||
})
|
||||
// Once cleanup is done, let the expose promise resolve/reject to the internal one.
|
||||
.then(() => promise), { cancel });
|
||||
});
|
||||
};
|
||||
return prompt;
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
export declare class AbortPromptError extends Error {
|
||||
name: string;
|
||||
message: string;
|
||||
constructor(options?: {
|
||||
cause?: unknown;
|
||||
});
|
||||
}
|
||||
export declare class CancelPromptError extends Error {
|
||||
name: string;
|
||||
message: string;
|
||||
}
|
||||
export declare class ExitPromptError extends Error {
|
||||
name: string;
|
||||
}
|
||||
export declare class HookError extends Error {
|
||||
name: string;
|
||||
}
|
||||
export declare class ValidationError extends Error {
|
||||
name: string;
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ValidationError = exports.HookError = exports.ExitPromptError = exports.CancelPromptError = exports.AbortPromptError = void 0;
|
||||
class AbortPromptError extends Error {
|
||||
name = 'AbortPromptError';
|
||||
message = 'Prompt was aborted';
|
||||
constructor(options) {
|
||||
super();
|
||||
this.cause = options?.cause;
|
||||
}
|
||||
}
|
||||
exports.AbortPromptError = AbortPromptError;
|
||||
class CancelPromptError extends Error {
|
||||
name = 'CancelPromptError';
|
||||
message = 'Prompt was canceled';
|
||||
}
|
||||
exports.CancelPromptError = CancelPromptError;
|
||||
class ExitPromptError extends Error {
|
||||
name = 'ExitPromptError';
|
||||
}
|
||||
exports.ExitPromptError = ExitPromptError;
|
||||
class HookError extends Error {
|
||||
name = 'HookError';
|
||||
}
|
||||
exports.HookError = HookError;
|
||||
class ValidationError extends Error {
|
||||
name = 'ValidationError';
|
||||
}
|
||||
exports.ValidationError = ValidationError;
|
@ -1,23 +0,0 @@
|
||||
import type { InquirerReadline } from '@inquirer/type';
|
||||
export declare function withHooks<T>(rl: InquirerReadline, cb: (cycle: (render: () => void) => void) => T): T;
|
||||
export declare function readline(): InquirerReadline;
|
||||
export declare function withUpdates<Args extends unknown[], R>(fn: (...args: Args) => R): (...args: Args) => R;
|
||||
type SetPointer<Value> = {
|
||||
get(): Value;
|
||||
set(value: Value): void;
|
||||
initialized: true;
|
||||
};
|
||||
type UnsetPointer<Value> = {
|
||||
get(): void;
|
||||
set(value: Value): void;
|
||||
initialized: false;
|
||||
};
|
||||
type Pointer<Value> = SetPointer<Value> | UnsetPointer<Value>;
|
||||
export declare function withPointer<Value, ReturnValue>(cb: (pointer: Pointer<Value>) => ReturnValue): ReturnValue;
|
||||
export declare function handleChange(): void;
|
||||
export declare const effectScheduler: {
|
||||
queue(cb: (readline: InquirerReadline) => void | (() => void)): void;
|
||||
run(): void;
|
||||
clearAll(): void;
|
||||
};
|
||||
export {};
|
@ -1,118 +0,0 @@
|
||||
"use strict";
|
||||
/* eslint @typescript-eslint/no-explicit-any: ["off"] */
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.effectScheduler = void 0;
|
||||
exports.withHooks = withHooks;
|
||||
exports.readline = readline;
|
||||
exports.withUpdates = withUpdates;
|
||||
exports.withPointer = withPointer;
|
||||
exports.handleChange = handleChange;
|
||||
const node_async_hooks_1 = require("node:async_hooks");
|
||||
const errors_ts_1 = require("./errors.js");
|
||||
const hookStorage = new node_async_hooks_1.AsyncLocalStorage();
|
||||
function createStore(rl) {
|
||||
const store = {
|
||||
rl,
|
||||
hooks: [],
|
||||
hooksCleanup: [],
|
||||
hooksEffect: [],
|
||||
index: 0,
|
||||
handleChange() { },
|
||||
};
|
||||
return store;
|
||||
}
|
||||
// Run callback in with the hook engine setup.
|
||||
function withHooks(rl, cb) {
|
||||
const store = createStore(rl);
|
||||
return hookStorage.run(store, () => {
|
||||
function cycle(render) {
|
||||
store.handleChange = () => {
|
||||
store.index = 0;
|
||||
render();
|
||||
};
|
||||
store.handleChange();
|
||||
}
|
||||
return cb(cycle);
|
||||
});
|
||||
}
|
||||
// Safe getStore utility that'll return the store or throw if undefined.
|
||||
function getStore() {
|
||||
const store = hookStorage.getStore();
|
||||
if (!store) {
|
||||
throw new errors_ts_1.HookError('[Inquirer] Hook functions can only be called from within a prompt');
|
||||
}
|
||||
return store;
|
||||
}
|
||||
function readline() {
|
||||
return getStore().rl;
|
||||
}
|
||||
// Merge state updates happening within the callback function to avoid multiple renders.
|
||||
function withUpdates(fn) {
|
||||
const wrapped = (...args) => {
|
||||
const store = getStore();
|
||||
let shouldUpdate = false;
|
||||
const oldHandleChange = store.handleChange;
|
||||
store.handleChange = () => {
|
||||
shouldUpdate = true;
|
||||
};
|
||||
const returnValue = fn(...args);
|
||||
if (shouldUpdate) {
|
||||
oldHandleChange();
|
||||
}
|
||||
store.handleChange = oldHandleChange;
|
||||
return returnValue;
|
||||
};
|
||||
return node_async_hooks_1.AsyncResource.bind(wrapped);
|
||||
}
|
||||
function withPointer(cb) {
|
||||
const store = getStore();
|
||||
const { index } = store;
|
||||
const pointer = {
|
||||
get() {
|
||||
return store.hooks[index];
|
||||
},
|
||||
set(value) {
|
||||
store.hooks[index] = value;
|
||||
},
|
||||
initialized: index in store.hooks,
|
||||
};
|
||||
const returnValue = cb(pointer);
|
||||
store.index++;
|
||||
return returnValue;
|
||||
}
|
||||
function handleChange() {
|
||||
getStore().handleChange();
|
||||
}
|
||||
exports.effectScheduler = {
|
||||
queue(cb) {
|
||||
const store = getStore();
|
||||
const { index } = store;
|
||||
store.hooksEffect.push(() => {
|
||||
store.hooksCleanup[index]?.();
|
||||
const cleanFn = cb(readline());
|
||||
if (cleanFn != null && typeof cleanFn !== 'function') {
|
||||
throw new errors_ts_1.ValidationError('useEffect return value must be a cleanup function or nothing.');
|
||||
}
|
||||
store.hooksCleanup[index] = cleanFn;
|
||||
});
|
||||
},
|
||||
run() {
|
||||
const store = getStore();
|
||||
withUpdates(() => {
|
||||
store.hooksEffect.forEach((effect) => {
|
||||
effect();
|
||||
});
|
||||
// Warning: Clean the hooks before exiting the `withUpdates` block.
|
||||
// Failure to do so means an updates would hit the same effects again.
|
||||
store.hooksEffect.length = 0;
|
||||
})();
|
||||
},
|
||||
clearAll() {
|
||||
const store = getStore();
|
||||
store.hooksCleanup.forEach((cleanFn) => {
|
||||
cleanFn?.();
|
||||
});
|
||||
store.hooksEffect.length = 0;
|
||||
store.hooksCleanup.length = 0;
|
||||
},
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
export type KeypressEvent = {
|
||||
name: string;
|
||||
ctrl: boolean;
|
||||
};
|
||||
export declare const isUpKey: (key: KeypressEvent) => boolean;
|
||||
export declare const isDownKey: (key: KeypressEvent) => boolean;
|
||||
export declare const isSpaceKey: (key: KeypressEvent) => boolean;
|
||||
export declare const isBackspaceKey: (key: KeypressEvent) => boolean;
|
||||
export declare const isNumberKey: (key: KeypressEvent) => boolean;
|
||||
export declare const isEnterKey: (key: KeypressEvent) => boolean;
|
@ -1,27 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.isEnterKey = exports.isNumberKey = exports.isBackspaceKey = exports.isSpaceKey = exports.isDownKey = exports.isUpKey = void 0;
|
||||
const isUpKey = (key) =>
|
||||
// The up key
|
||||
key.name === 'up' ||
|
||||
// Vim keybinding
|
||||
key.name === 'k' ||
|
||||
// Emacs keybinding
|
||||
(key.ctrl && key.name === 'p');
|
||||
exports.isUpKey = isUpKey;
|
||||
const isDownKey = (key) =>
|
||||
// The down key
|
||||
key.name === 'down' ||
|
||||
// Vim keybinding
|
||||
key.name === 'j' ||
|
||||
// Emacs keybinding
|
||||
(key.ctrl && key.name === 'n');
|
||||
exports.isDownKey = isDownKey;
|
||||
const isSpaceKey = (key) => key.name === 'space';
|
||||
exports.isSpaceKey = isSpaceKey;
|
||||
const isBackspaceKey = (key) => key.name === 'backspace';
|
||||
exports.isBackspaceKey = isBackspaceKey;
|
||||
const isNumberKey = (key) => '1234567890'.includes(key.name);
|
||||
exports.isNumberKey = isNumberKey;
|
||||
const isEnterKey = (key) => key.name === 'enter' || key.name === 'return';
|
||||
exports.isEnterKey = isEnterKey;
|
@ -1,3 +0,0 @@
|
||||
import type { Prettify, PartialDeep } from '@inquirer/type';
|
||||
import { type Theme } from './theme.ts';
|
||||
export declare function makeTheme<SpecificTheme extends object>(...themes: ReadonlyArray<undefined | PartialDeep<Theme<SpecificTheme>>>): Prettify<Theme<SpecificTheme>>;
|
@ -1,33 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.makeTheme = makeTheme;
|
||||
const theme_ts_1 = require("./theme.js");
|
||||
function isPlainObject(value) {
|
||||
if (typeof value !== 'object' || value === null)
|
||||
return false;
|
||||
let proto = value;
|
||||
while (Object.getPrototypeOf(proto) !== null) {
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
}
|
||||
return Object.getPrototypeOf(value) === proto;
|
||||
}
|
||||
function deepMerge(...objects) {
|
||||
const output = {};
|
||||
for (const obj of objects) {
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
const prevValue = output[key];
|
||||
output[key] =
|
||||
isPlainObject(prevValue) && isPlainObject(value)
|
||||
? deepMerge(prevValue, value)
|
||||
: value;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
function makeTheme(...themes) {
|
||||
const themesToMerge = [
|
||||
theme_ts_1.defaultTheme,
|
||||
...themes.filter((theme) => theme != null),
|
||||
];
|
||||
return deepMerge(...themesToMerge);
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import type { Prettify } from '@inquirer/type';
|
||||
export declare function usePagination<T>({ items, active, renderItem, pageSize, loop, }: {
|
||||
items: ReadonlyArray<T>;
|
||||
/** The index of the active item. */
|
||||
active: number;
|
||||
/** Renders an item as part of a page. */
|
||||
renderItem: (layout: Prettify<{
|
||||
item: T;
|
||||
index: number;
|
||||
isActive: boolean;
|
||||
}>) => string;
|
||||
/** The size of the page. */
|
||||
pageSize: number;
|
||||
/** Allows creating an infinitely looping list. `true` if unspecified. */
|
||||
loop?: boolean;
|
||||
}): string;
|
@ -1,124 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.usePagination = usePagination;
|
||||
const use_ref_ts_1 = require("../use-ref.js");
|
||||
const utils_ts_1 = require("../utils.js");
|
||||
function usePointerPosition({ active, renderedItems, pageSize, loop, }) {
|
||||
const state = (0, use_ref_ts_1.useRef)({
|
||||
lastPointer: active,
|
||||
lastActive: undefined,
|
||||
});
|
||||
const { lastPointer, lastActive } = state.current;
|
||||
const middle = Math.floor(pageSize / 2);
|
||||
const renderedLength = renderedItems.reduce((acc, item) => acc + item.length, 0);
|
||||
const defaultPointerPosition = renderedItems
|
||||
.slice(0, active)
|
||||
.reduce((acc, item) => acc + item.length, 0);
|
||||
let pointer = defaultPointerPosition;
|
||||
if (renderedLength > pageSize) {
|
||||
if (loop) {
|
||||
/**
|
||||
* Creates the next position for the pointer considering an infinitely
|
||||
* looping list of items to be rendered on the page.
|
||||
*
|
||||
* The goal is to progressively move the cursor to the middle position as the user move down, and then keep
|
||||
* the cursor there. When the user move up, maintain the cursor position.
|
||||
*/
|
||||
// By default, keep the cursor position as-is.
|
||||
pointer = lastPointer;
|
||||
if (
|
||||
// First render, skip this logic.
|
||||
lastActive != null &&
|
||||
// Only move the pointer down when the user moves down.
|
||||
lastActive < active &&
|
||||
// Check user didn't move up across page boundary.
|
||||
active - lastActive < pageSize) {
|
||||
pointer = Math.min(
|
||||
// Furthest allowed position for the pointer is the middle of the list
|
||||
middle, Math.abs(active - lastActive) === 1
|
||||
? Math.min(
|
||||
// Move the pointer at most the height of the last active item.
|
||||
lastPointer + (renderedItems[lastActive]?.length ?? 0),
|
||||
// If the user moved by one item, move the pointer to the natural position of the active item as
|
||||
// long as it doesn't move the cursor up.
|
||||
Math.max(defaultPointerPosition, lastPointer))
|
||||
: // Otherwise, move the pointer down by the difference between the active and last active item.
|
||||
lastPointer + active - lastActive);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/**
|
||||
* Creates the next position for the pointer considering a finite list of
|
||||
* items to be rendered on a page.
|
||||
*
|
||||
* The goal is to keep the pointer in the middle of the page whenever possible, until
|
||||
* we reach the bounds of the list (top or bottom). In which case, the cursor moves progressively
|
||||
* to the bottom or top of the list.
|
||||
*/
|
||||
const spaceUnderActive = renderedItems
|
||||
.slice(active)
|
||||
.reduce((acc, item) => acc + item.length, 0);
|
||||
pointer =
|
||||
spaceUnderActive < pageSize - middle
|
||||
? // If the active item is near the end of the list, progressively move the cursor towards the end.
|
||||
pageSize - spaceUnderActive
|
||||
: // Otherwise, progressively move the pointer to the middle of the list.
|
||||
Math.min(defaultPointerPosition, middle);
|
||||
}
|
||||
}
|
||||
// Save state for the next render
|
||||
state.current.lastPointer = pointer;
|
||||
state.current.lastActive = active;
|
||||
return pointer;
|
||||
}
|
||||
function usePagination({ items, active, renderItem, pageSize, loop = true, }) {
|
||||
const width = (0, utils_ts_1.readlineWidth)();
|
||||
const bound = (num) => ((num % items.length) + items.length) % items.length;
|
||||
const renderedItems = items.map((item, index) => {
|
||||
if (item == null)
|
||||
return [];
|
||||
return (0, utils_ts_1.breakLines)(renderItem({ item, index, isActive: index === active }), width).split('\n');
|
||||
});
|
||||
const renderedLength = renderedItems.reduce((acc, item) => acc + item.length, 0);
|
||||
const renderItemAtIndex = (index) => renderedItems[index] ?? [];
|
||||
const pointer = usePointerPosition({ active, renderedItems, pageSize, loop });
|
||||
// Render the active item to decide the position.
|
||||
// If the active item fits under the pointer, we render it there.
|
||||
// Otherwise, we need to render it to fit at the bottom of the page; moving the pointer up.
|
||||
const activeItem = renderItemAtIndex(active).slice(0, pageSize);
|
||||
const activeItemPosition = pointer + activeItem.length <= pageSize ? pointer : pageSize - activeItem.length;
|
||||
// Create an array of lines for the page, and add the lines of the active item into the page
|
||||
const pageBuffer = Array.from({ length: pageSize });
|
||||
pageBuffer.splice(activeItemPosition, activeItem.length, ...activeItem);
|
||||
// Store to prevent rendering the same item twice
|
||||
const itemVisited = new Set([active]);
|
||||
// Fill the page under the active item
|
||||
let bufferPointer = activeItemPosition + activeItem.length;
|
||||
let itemPointer = bound(active + 1);
|
||||
while (bufferPointer < pageSize &&
|
||||
!itemVisited.has(itemPointer) &&
|
||||
(loop && renderedLength > pageSize ? itemPointer !== active : itemPointer > active)) {
|
||||
const lines = renderItemAtIndex(itemPointer);
|
||||
const linesToAdd = lines.slice(0, pageSize - bufferPointer);
|
||||
pageBuffer.splice(bufferPointer, linesToAdd.length, ...linesToAdd);
|
||||
// Move pointers for next iteration
|
||||
itemVisited.add(itemPointer);
|
||||
bufferPointer += linesToAdd.length;
|
||||
itemPointer = bound(itemPointer + 1);
|
||||
}
|
||||
// Fill the page over the active item
|
||||
bufferPointer = activeItemPosition - 1;
|
||||
itemPointer = bound(active - 1);
|
||||
while (bufferPointer >= 0 &&
|
||||
!itemVisited.has(itemPointer) &&
|
||||
(loop && renderedLength > pageSize ? itemPointer !== active : itemPointer < active)) {
|
||||
const lines = renderItemAtIndex(itemPointer);
|
||||
const linesToAdd = lines.slice(Math.max(0, lines.length - bufferPointer - 1));
|
||||
pageBuffer.splice(bufferPointer - linesToAdd.length + 1, linesToAdd.length, ...linesToAdd);
|
||||
// Move pointers for next iteration
|
||||
itemVisited.add(itemPointer);
|
||||
bufferPointer -= linesToAdd.length;
|
||||
itemPointer = bound(itemPointer - 1);
|
||||
}
|
||||
return pageBuffer.filter((line) => typeof line === 'string').join('\n');
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
export declare class PromisePolyfill<T> extends Promise<T> {
|
||||
static withResolver<T>(): {
|
||||
promise: Promise<T>;
|
||||
resolve: (value: T) => void;
|
||||
reject: (error: unknown) => void;
|
||||
};
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.PromisePolyfill = void 0;
|
||||
// TODO: Remove this class once Node 22 becomes the minimum supported version.
|
||||
class PromisePolyfill extends Promise {
|
||||
// Available starting from Node 22
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
|
||||
static withResolver() {
|
||||
let resolve;
|
||||
let reject;
|
||||
const promise = new Promise((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
return { promise, resolve: resolve, reject: reject };
|
||||
}
|
||||
}
|
||||
exports.PromisePolyfill = PromisePolyfill;
|
@ -1,14 +0,0 @@
|
||||
import type { InquirerReadline } from '@inquirer/type';
|
||||
export default class ScreenManager {
|
||||
private height;
|
||||
private extraLinesUnderPrompt;
|
||||
private cursorPos;
|
||||
private readonly rl;
|
||||
constructor(rl: InquirerReadline);
|
||||
write(content: string): void;
|
||||
render(content: string, bottomContent?: string): void;
|
||||
checkCursorPos(): void;
|
||||
done({ clearContent }: {
|
||||
clearContent: boolean;
|
||||
}): void;
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const node_util_1 = require("node:util");
|
||||
const ansi_escapes_1 = __importDefault(require("ansi-escapes"));
|
||||
const utils_ts_1 = require("./utils.js");
|
||||
const height = (content) => content.split('\n').length;
|
||||
const lastLine = (content) => content.split('\n').pop() ?? '';
|
||||
function cursorDown(n) {
|
||||
return n > 0 ? ansi_escapes_1.default.cursorDown(n) : '';
|
||||
}
|
||||
class ScreenManager {
|
||||
// These variables are keeping information to allow correct prompt re-rendering
|
||||
height = 0;
|
||||
extraLinesUnderPrompt = 0;
|
||||
cursorPos;
|
||||
rl;
|
||||
constructor(rl) {
|
||||
this.rl = rl;
|
||||
this.cursorPos = rl.getCursorPos();
|
||||
}
|
||||
write(content) {
|
||||
this.rl.output.unmute();
|
||||
this.rl.output.write(content);
|
||||
this.rl.output.mute();
|
||||
}
|
||||
render(content, bottomContent = '') {
|
||||
// Write message to screen and setPrompt to control backspace
|
||||
const promptLine = lastLine(content);
|
||||
const rawPromptLine = (0, node_util_1.stripVTControlCharacters)(promptLine);
|
||||
// Remove the rl.line from our prompt. We can't rely on the content of
|
||||
// rl.line (mainly because of the password prompt), so just rely on it's
|
||||
// length.
|
||||
let prompt = rawPromptLine;
|
||||
if (this.rl.line.length > 0) {
|
||||
prompt = prompt.slice(0, -this.rl.line.length);
|
||||
}
|
||||
this.rl.setPrompt(prompt);
|
||||
// SetPrompt will change cursor position, now we can get correct value
|
||||
this.cursorPos = this.rl.getCursorPos();
|
||||
const width = (0, utils_ts_1.readlineWidth)();
|
||||
content = (0, utils_ts_1.breakLines)(content, width);
|
||||
bottomContent = (0, utils_ts_1.breakLines)(bottomContent, width);
|
||||
// Manually insert an extra line if we're at the end of the line.
|
||||
// This prevent the cursor from appearing at the beginning of the
|
||||
// current line.
|
||||
if (rawPromptLine.length % width === 0) {
|
||||
content += '\n';
|
||||
}
|
||||
let output = content + (bottomContent ? '\n' + bottomContent : '');
|
||||
/**
|
||||
* Re-adjust the cursor at the correct position.
|
||||
*/
|
||||
// We need to consider parts of the prompt under the cursor as part of the bottom
|
||||
// content in order to correctly cleanup and re-render.
|
||||
const promptLineUpDiff = Math.floor(rawPromptLine.length / width) - this.cursorPos.rows;
|
||||
const bottomContentHeight = promptLineUpDiff + (bottomContent ? height(bottomContent) : 0);
|
||||
// Return cursor to the input position (on top of the bottomContent)
|
||||
if (bottomContentHeight > 0)
|
||||
output += ansi_escapes_1.default.cursorUp(bottomContentHeight);
|
||||
// Return cursor to the initial left offset.
|
||||
output += ansi_escapes_1.default.cursorTo(this.cursorPos.cols);
|
||||
/**
|
||||
* Render and store state for future re-rendering
|
||||
*/
|
||||
this.write(cursorDown(this.extraLinesUnderPrompt) +
|
||||
ansi_escapes_1.default.eraseLines(this.height) +
|
||||
output);
|
||||
this.extraLinesUnderPrompt = bottomContentHeight;
|
||||
this.height = height(output);
|
||||
}
|
||||
checkCursorPos() {
|
||||
const cursorPos = this.rl.getCursorPos();
|
||||
if (cursorPos.cols !== this.cursorPos.cols) {
|
||||
this.write(ansi_escapes_1.default.cursorTo(cursorPos.cols));
|
||||
this.cursorPos = cursorPos;
|
||||
}
|
||||
}
|
||||
done({ clearContent }) {
|
||||
this.rl.setPrompt('');
|
||||
let output = cursorDown(this.extraLinesUnderPrompt);
|
||||
output += clearContent ? ansi_escapes_1.default.eraseLines(this.height) : '\n';
|
||||
output += ansi_escapes_1.default.cursorShow;
|
||||
this.write(output);
|
||||
this.rl.close();
|
||||
}
|
||||
}
|
||||
exports.default = ScreenManager;
|
@ -1,155 +0,0 @@
|
||||
import type { Prettify } from '@inquirer/type';
|
||||
/**
|
||||
* Union type representing the possible statuses of a prompt.
|
||||
*
|
||||
* - `'loading'`: The prompt is currently loading.
|
||||
* - `'idle'`: The prompt is loaded and currently waiting for the user to
|
||||
* submit an answer.
|
||||
* - `'done'`: The user has submitted an answer and the prompt is finished.
|
||||
* - `string`: Any other string: The prompt is in a custom state.
|
||||
*/
|
||||
export type Status = 'loading' | 'idle' | 'done' | (string & {});
|
||||
type DefaultTheme = {
|
||||
/**
|
||||
* Prefix to prepend to the message. If a function is provided, it will be
|
||||
* called with the current status of the prompt, and the return value will be
|
||||
* used as the prefix.
|
||||
*
|
||||
* @remarks
|
||||
* If `status === 'loading'`, this property is ignored and the spinner (styled
|
||||
* by the `spinner` property) will be displayed instead.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (status) => status === 'done' ? colors.green('✔') : colors.blue('?')
|
||||
* ```
|
||||
*/
|
||||
prefix: string | Prettify<Omit<Record<Status, string>, 'loading'>>;
|
||||
/**
|
||||
* Configuration for the spinner that is displayed when the prompt is in the
|
||||
* `'loading'` state.
|
||||
*
|
||||
* We recommend the use of {@link https://github.com/sindresorhus/cli-spinners|cli-spinners} for a list of available spinners.
|
||||
*/
|
||||
spinner: {
|
||||
/**
|
||||
* The time interval between frames, in milliseconds.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* 80
|
||||
* ```
|
||||
*/
|
||||
interval: number;
|
||||
/**
|
||||
* A list of frames to show for the spinner.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
|
||||
* ```
|
||||
*/
|
||||
frames: string[];
|
||||
};
|
||||
/**
|
||||
* Object containing functions to style different parts of the prompt.
|
||||
*/
|
||||
style: {
|
||||
/**
|
||||
* Style to apply to the user's answer once it has been submitted.
|
||||
*
|
||||
* @param text - The user's answer.
|
||||
* @returns The styled answer.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (text) => colors.cyan(text)
|
||||
* ```
|
||||
*/
|
||||
answer: (text: string) => string;
|
||||
/**
|
||||
* Style to apply to the message displayed to the user.
|
||||
*
|
||||
* @param text - The message to style.
|
||||
* @param status - The current status of the prompt.
|
||||
* @returns The styled message.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (text, status) => colors.bold(text)
|
||||
* ```
|
||||
*/
|
||||
message: (text: string, status: Status) => string;
|
||||
/**
|
||||
* Style to apply to error messages.
|
||||
*
|
||||
* @param text - The error message.
|
||||
* @returns The styled error message.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (text) => colors.red(`> ${text}`)
|
||||
* ```
|
||||
*/
|
||||
error: (text: string) => string;
|
||||
/**
|
||||
* Style to apply to the default answer when one is provided.
|
||||
*
|
||||
* @param text - The default answer.
|
||||
* @returns The styled default answer.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (text) => colors.dim(`(${text})`)
|
||||
* ```
|
||||
*/
|
||||
defaultAnswer: (text: string) => string;
|
||||
/**
|
||||
* Style to apply to help text.
|
||||
*
|
||||
* @param text - The help text.
|
||||
* @returns The styled help text.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (text) => colors.dim(text)
|
||||
* ```
|
||||
*/
|
||||
help: (text: string) => string;
|
||||
/**
|
||||
* Style to apply to highlighted text.
|
||||
*
|
||||
* @param text - The text to highlight.
|
||||
* @returns The highlighted text.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (text) => colors.cyan(text)
|
||||
* ```
|
||||
*/
|
||||
highlight: (text: string) => string;
|
||||
/**
|
||||
* Style to apply to keyboard keys referred to in help texts.
|
||||
*
|
||||
* @param text - The key to style.
|
||||
* @returns The styled key.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (text) => colors.cyan(colors.bold(`<${text}>`))
|
||||
* ```
|
||||
*/
|
||||
key: (text: string) => string;
|
||||
};
|
||||
};
|
||||
export type Theme<Extension extends object = object> = Prettify<Extension & DefaultTheme>;
|
||||
export declare const defaultTheme: DefaultTheme;
|
||||
export {};
|
@ -1,28 +0,0 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.defaultTheme = void 0;
|
||||
const yoctocolors_cjs_1 = __importDefault(require("yoctocolors-cjs"));
|
||||
const figures_1 = __importDefault(require("@inquirer/figures"));
|
||||
exports.defaultTheme = {
|
||||
prefix: {
|
||||
idle: yoctocolors_cjs_1.default.blue('?'),
|
||||
// TODO: use figure
|
||||
done: yoctocolors_cjs_1.default.green(figures_1.default.tick),
|
||||
},
|
||||
spinner: {
|
||||
interval: 80,
|
||||
frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'].map((frame) => yoctocolors_cjs_1.default.yellow(frame)),
|
||||
},
|
||||
style: {
|
||||
answer: yoctocolors_cjs_1.default.cyan,
|
||||
message: yoctocolors_cjs_1.default.bold,
|
||||
error: (text) => yoctocolors_cjs_1.default.red(`> ${text}`),
|
||||
defaultAnswer: (text) => yoctocolors_cjs_1.default.dim(`(${text})`),
|
||||
help: yoctocolors_cjs_1.default.dim,
|
||||
highlight: yoctocolors_cjs_1.default.cyan,
|
||||
key: (text) => yoctocolors_cjs_1.default.cyan(yoctocolors_cjs_1.default.bold(`<${text}>`)),
|
||||
},
|
||||
};
|
@ -1,2 +0,0 @@
|
||||
import type { InquirerReadline } from '@inquirer/type';
|
||||
export declare function useEffect(cb: (rl: InquirerReadline) => void | (() => void), depArray: ReadonlyArray<unknown>): void;
|
@ -1,14 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.useEffect = useEffect;
|
||||
const hook_engine_ts_1 = require("./hook-engine.js");
|
||||
function useEffect(cb, depArray) {
|
||||
(0, hook_engine_ts_1.withPointer)((pointer) => {
|
||||
const oldDeps = pointer.get();
|
||||
const hasChanged = !Array.isArray(oldDeps) || depArray.some((dep, i) => !Object.is(dep, oldDeps[i]));
|
||||
if (hasChanged) {
|
||||
hook_engine_ts_1.effectScheduler.queue(cb);
|
||||
}
|
||||
pointer.set(depArray);
|
||||
});
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
import { type InquirerReadline } from '@inquirer/type';
|
||||
import { type KeypressEvent } from './key.ts';
|
||||
export declare function useKeypress(userHandler: (event: KeypressEvent, rl: InquirerReadline) => void | Promise<void>): void;
|
@ -1,23 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.useKeypress = useKeypress;
|
||||
const use_ref_ts_1 = require("./use-ref.js");
|
||||
const use_effect_ts_1 = require("./use-effect.js");
|
||||
const hook_engine_ts_1 = require("./hook-engine.js");
|
||||
function useKeypress(userHandler) {
|
||||
const signal = (0, use_ref_ts_1.useRef)(userHandler);
|
||||
signal.current = userHandler;
|
||||
(0, use_effect_ts_1.useEffect)((rl) => {
|
||||
let ignore = false;
|
||||
const handler = (0, hook_engine_ts_1.withUpdates)((_input, event) => {
|
||||
if (ignore)
|
||||
return;
|
||||
void signal.current(event, rl);
|
||||
});
|
||||
rl.input.on('keypress', handler);
|
||||
return () => {
|
||||
ignore = true;
|
||||
rl.input.removeListener('keypress', handler);
|
||||
};
|
||||
}, []);
|
||||
}
|
@ -1 +0,0 @@
|
||||
export declare function useMemo<Value>(fn: () => Value, dependencies: ReadonlyArray<unknown>): Value;
|
@ -1,17 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.useMemo = useMemo;
|
||||
const hook_engine_ts_1 = require("./hook-engine.js");
|
||||
function useMemo(fn, dependencies) {
|
||||
return (0, hook_engine_ts_1.withPointer)((pointer) => {
|
||||
const prev = pointer.get();
|
||||
if (!prev ||
|
||||
prev.dependencies.length !== dependencies.length ||
|
||||
prev.dependencies.some((dep, i) => dep !== dependencies[i])) {
|
||||
const value = fn();
|
||||
pointer.set({ value, dependencies });
|
||||
return value;
|
||||
}
|
||||
return prev.value;
|
||||
});
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
import type { Theme, Status } from './theme.ts';
|
||||
export declare function usePrefix({ status, theme, }: {
|
||||
status?: Status;
|
||||
theme?: Theme;
|
||||
}): string;
|
@ -1,38 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.usePrefix = usePrefix;
|
||||
const use_state_ts_1 = require("./use-state.js");
|
||||
const use_effect_ts_1 = require("./use-effect.js");
|
||||
const make_theme_ts_1 = require("./make-theme.js");
|
||||
function usePrefix({ status = 'idle', theme, }) {
|
||||
const [showLoader, setShowLoader] = (0, use_state_ts_1.useState)(false);
|
||||
const [tick, setTick] = (0, use_state_ts_1.useState)(0);
|
||||
const { prefix, spinner } = (0, make_theme_ts_1.makeTheme)(theme);
|
||||
(0, use_effect_ts_1.useEffect)(() => {
|
||||
if (status === 'loading') {
|
||||
let tickInterval;
|
||||
let inc = -1;
|
||||
// Delay displaying spinner by 300ms, to avoid flickering
|
||||
const delayTimeout = setTimeout(() => {
|
||||
setShowLoader(true);
|
||||
tickInterval = setInterval(() => {
|
||||
inc = inc + 1;
|
||||
setTick(inc % spinner.frames.length);
|
||||
}, spinner.interval);
|
||||
}, 300);
|
||||
return () => {
|
||||
clearTimeout(delayTimeout);
|
||||
clearInterval(tickInterval);
|
||||
};
|
||||
}
|
||||
else {
|
||||
setShowLoader(false);
|
||||
}
|
||||
}, [status]);
|
||||
if (showLoader) {
|
||||
return spinner.frames[tick];
|
||||
}
|
||||
// There's a delay before we show the loader. So we want to ignore `loading` here, and pass idle instead.
|
||||
const iconName = status === 'loading' ? 'idle' : status;
|
||||
return typeof prefix === 'string' ? prefix : (prefix[iconName] ?? prefix['idle']);
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
export declare function useRef<Value>(val: Value): {
|
||||
current: Value;
|
||||
};
|
||||
export declare function useRef<Value>(val?: Value): {
|
||||
current: Value | undefined;
|
||||
};
|
@ -1,7 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.useRef = useRef;
|
||||
const use_state_ts_1 = require("./use-state.js");
|
||||
function useRef(val) {
|
||||
return (0, use_state_ts_1.useState)({ current: val })[0];
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
type NotFunction<T> = T extends (...args: never) => unknown ? never : T;
|
||||
export declare function useState<Value>(defaultValue: NotFunction<Value> | (() => Value)): [Value, (newValue: Value) => void];
|
||||
export declare function useState<Value>(defaultValue?: NotFunction<Value> | (() => Value)): [Value | undefined, (newValue?: Value) => void];
|
||||
export {};
|
@ -1,23 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.useState = useState;
|
||||
const node_async_hooks_1 = require("node:async_hooks");
|
||||
const hook_engine_ts_1 = require("./hook-engine.js");
|
||||
function useState(defaultValue) {
|
||||
return (0, hook_engine_ts_1.withPointer)((pointer) => {
|
||||
const setState = node_async_hooks_1.AsyncResource.bind(function setState(newValue) {
|
||||
// Noop if the value is still the same.
|
||||
if (pointer.get() !== newValue) {
|
||||
pointer.set(newValue);
|
||||
// Trigger re-render
|
||||
(0, hook_engine_ts_1.handleChange)();
|
||||
}
|
||||
});
|
||||
if (pointer.initialized) {
|
||||
return [pointer.get(), setState];
|
||||
}
|
||||
const value = typeof defaultValue === 'function' ? defaultValue() : defaultValue;
|
||||
pointer.set(value);
|
||||
return [value, setState];
|
||||
});
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Force line returns at specific width. This function is ANSI code friendly and it'll
|
||||
* ignore invisible codes during width calculation.
|
||||
* @param {string} content
|
||||
* @param {number} width
|
||||
* @return {string}
|
||||
*/
|
||||
export declare function breakLines(content: string, width: number): string;
|
||||
/**
|
||||
* Returns the width of the active readline, or 80 as default value.
|
||||
* @returns {number}
|
||||
*/
|
||||
export declare function readlineWidth(): number;
|
@ -1,32 +0,0 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.breakLines = breakLines;
|
||||
exports.readlineWidth = readlineWidth;
|
||||
const cli_width_1 = __importDefault(require("cli-width"));
|
||||
const wrap_ansi_1 = __importDefault(require("wrap-ansi"));
|
||||
const hook_engine_ts_1 = require("./hook-engine.js");
|
||||
/**
|
||||
* Force line returns at specific width. This function is ANSI code friendly and it'll
|
||||
* ignore invisible codes during width calculation.
|
||||
* @param {string} content
|
||||
* @param {number} width
|
||||
* @return {string}
|
||||
*/
|
||||
function breakLines(content, width) {
|
||||
return content
|
||||
.split('\n')
|
||||
.flatMap((line) => (0, wrap_ansi_1.default)(line, width, { trim: false, hard: true })
|
||||
.split('\n')
|
||||
.map((str) => str.trimEnd()))
|
||||
.join('\n');
|
||||
}
|
||||
/**
|
||||
* Returns the width of the active readline, or 80 as default value.
|
||||
* @returns {number}
|
||||
*/
|
||||
function readlineWidth() {
|
||||
return (0, cli_width_1.default)({ defaultWidth: 80, output: (0, hook_engine_ts_1.readline)().output });
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
export * from './lib/key.ts';
|
||||
export * from './lib/errors.ts';
|
||||
export { usePrefix } from './lib/use-prefix.ts';
|
||||
export { useState } from './lib/use-state.ts';
|
||||
export { useEffect } from './lib/use-effect.ts';
|
||||
export { useMemo } from './lib/use-memo.ts';
|
||||
export { useRef } from './lib/use-ref.ts';
|
||||
export { useKeypress } from './lib/use-keypress.ts';
|
||||
export { makeTheme } from './lib/make-theme.ts';
|
||||
export type { Theme, Status } from './lib/theme.ts';
|
||||
export { usePagination } from './lib/pagination/use-pagination.ts';
|
||||
export { createPrompt } from './lib/create-prompt.ts';
|
||||
export { Separator } from './lib/Separator.ts';
|
@ -1,12 +0,0 @@
|
||||
export * from "./lib/key.js";
|
||||
export * from "./lib/errors.js";
|
||||
export { usePrefix } from "./lib/use-prefix.js";
|
||||
export { useState } from "./lib/use-state.js";
|
||||
export { useEffect } from "./lib/use-effect.js";
|
||||
export { useMemo } from "./lib/use-memo.js";
|
||||
export { useRef } from "./lib/use-ref.js";
|
||||
export { useKeypress } from "./lib/use-keypress.js";
|
||||
export { makeTheme } from "./lib/make-theme.js";
|
||||
export { usePagination } from "./lib/pagination/use-pagination.js";
|
||||
export { createPrompt } from "./lib/create-prompt.js";
|
||||
export { Separator } from "./lib/Separator.js";
|
@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Separator object
|
||||
* Used to space/separate choices group
|
||||
*/
|
||||
export declare class Separator {
|
||||
readonly separator: string;
|
||||
readonly type: string;
|
||||
constructor(separator?: string);
|
||||
static isSeparator(choice: unknown): choice is Separator;
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import colors from 'yoctocolors-cjs';
|
||||
import figures from '@inquirer/figures';
|
||||
/**
|
||||
* Separator object
|
||||
* Used to space/separate choices group
|
||||
*/
|
||||
export class Separator {
|
||||
separator = colors.dim(Array.from({ length: 15 }).join(figures.line));
|
||||
type = 'separator';
|
||||
constructor(separator) {
|
||||
if (separator) {
|
||||
this.separator = separator;
|
||||
}
|
||||
}
|
||||
static isSeparator(choice) {
|
||||
return Boolean(choice &&
|
||||
typeof choice === 'object' &&
|
||||
'type' in choice &&
|
||||
choice.type === 'separator');
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
import { type Prompt, type Prettify } from '@inquirer/type';
|
||||
type ViewFunction<Value, Config> = (config: Prettify<Config>, done: (value: Value) => void) => string | [string, string | undefined];
|
||||
export declare function createPrompt<Value, Config>(view: ViewFunction<Value, Config>): Prompt<Value, Config>;
|
||||
export {};
|
@ -1,117 +0,0 @@
|
||||
import * as readline from 'node:readline';
|
||||
import { AsyncResource } from 'node:async_hooks';
|
||||
import MuteStream from 'mute-stream';
|
||||
import { onExit as onSignalExit } from 'signal-exit';
|
||||
import ScreenManager from "./screen-manager.js";
|
||||
import { PromisePolyfill } from "./promise-polyfill.js";
|
||||
import { withHooks, effectScheduler } from "./hook-engine.js";
|
||||
import { AbortPromptError, CancelPromptError, ExitPromptError } from "./errors.js";
|
||||
function getCallSites() {
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const _prepareStackTrace = Error.prepareStackTrace;
|
||||
let result = [];
|
||||
try {
|
||||
Error.prepareStackTrace = (_, callSites) => {
|
||||
const callSitesWithoutCurrent = callSites.slice(1);
|
||||
result = callSitesWithoutCurrent;
|
||||
return callSitesWithoutCurrent;
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
new Error().stack;
|
||||
}
|
||||
catch {
|
||||
// An error will occur if the Node flag --frozen-intrinsics is used.
|
||||
// https://nodejs.org/api/cli.html#--frozen-intrinsics
|
||||
return result;
|
||||
}
|
||||
Error.prepareStackTrace = _prepareStackTrace;
|
||||
return result;
|
||||
}
|
||||
export function createPrompt(view) {
|
||||
const callSites = getCallSites();
|
||||
const prompt = (config, context = {}) => {
|
||||
// Default `input` to stdin
|
||||
const { input = process.stdin, signal } = context;
|
||||
const cleanups = new Set();
|
||||
// Add mute capabilities to the output
|
||||
const output = new MuteStream();
|
||||
output.pipe(context.output ?? process.stdout);
|
||||
const rl = readline.createInterface({
|
||||
terminal: true,
|
||||
input,
|
||||
output,
|
||||
});
|
||||
const screen = new ScreenManager(rl);
|
||||
const { promise, resolve, reject } = PromisePolyfill.withResolver();
|
||||
const cancel = () => reject(new CancelPromptError());
|
||||
if (signal) {
|
||||
const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
|
||||
if (signal.aborted) {
|
||||
abort();
|
||||
return Object.assign(promise, { cancel });
|
||||
}
|
||||
signal.addEventListener('abort', abort);
|
||||
cleanups.add(() => signal.removeEventListener('abort', abort));
|
||||
}
|
||||
cleanups.add(onSignalExit((code, signal) => {
|
||||
reject(new ExitPromptError(`User force closed the prompt with ${code} ${signal}`));
|
||||
}));
|
||||
// SIGINT must be explicitly handled by the prompt so the ExitPromptError can be handled.
|
||||
// Otherwise, the prompt will stop and in some scenarios never resolve.
|
||||
// Ref issue #1741
|
||||
const sigint = () => reject(new ExitPromptError(`User force closed the prompt with SIGINT`));
|
||||
rl.on('SIGINT', sigint);
|
||||
cleanups.add(() => rl.removeListener('SIGINT', sigint));
|
||||
// Re-renders only happen when the state change; but the readline cursor could change position
|
||||
// and that also requires a re-render (and a manual one because we mute the streams).
|
||||
// We set the listener after the initial workLoop to avoid a double render if render triggered
|
||||
// by a state change sets the cursor to the right position.
|
||||
const checkCursorPos = () => screen.checkCursorPos();
|
||||
rl.input.on('keypress', checkCursorPos);
|
||||
cleanups.add(() => rl.input.removeListener('keypress', checkCursorPos));
|
||||
return withHooks(rl, (cycle) => {
|
||||
// The close event triggers immediately when the user press ctrl+c. SignalExit on the other hand
|
||||
// triggers after the process is done (which happens after timeouts are done triggering.)
|
||||
// We triggers the hooks cleanup phase on rl `close` so active timeouts can be cleared.
|
||||
const hooksCleanup = AsyncResource.bind(() => effectScheduler.clearAll());
|
||||
rl.on('close', hooksCleanup);
|
||||
cleanups.add(() => rl.removeListener('close', hooksCleanup));
|
||||
cycle(() => {
|
||||
try {
|
||||
const nextView = view(config, (value) => {
|
||||
setImmediate(() => resolve(value));
|
||||
});
|
||||
// Typescript won't allow this, but not all users rely on typescript.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (nextView === undefined) {
|
||||
const callerFilename = callSites[1]?.getFileName();
|
||||
throw new Error(`Prompt functions must return a string.\n at ${callerFilename}`);
|
||||
}
|
||||
const [content, bottomContent] = typeof nextView === 'string' ? [nextView] : nextView;
|
||||
screen.render(content, bottomContent);
|
||||
effectScheduler.run();
|
||||
}
|
||||
catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
return Object.assign(promise
|
||||
.then((answer) => {
|
||||
effectScheduler.clearAll();
|
||||
return answer;
|
||||
}, (error) => {
|
||||
effectScheduler.clearAll();
|
||||
throw error;
|
||||
})
|
||||
// Wait for the promise to settle, then cleanup.
|
||||
.finally(() => {
|
||||
cleanups.forEach((cleanup) => cleanup());
|
||||
screen.done({ clearContent: Boolean(context.clearPromptOnDone) });
|
||||
output.end();
|
||||
})
|
||||
// Once cleanup is done, let the expose promise resolve/reject to the internal one.
|
||||
.then(() => promise), { cancel });
|
||||
});
|
||||
};
|
||||
return prompt;
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
export declare class AbortPromptError extends Error {
|
||||
name: string;
|
||||
message: string;
|
||||
constructor(options?: {
|
||||
cause?: unknown;
|
||||
});
|
||||
}
|
||||
export declare class CancelPromptError extends Error {
|
||||
name: string;
|
||||
message: string;
|
||||
}
|
||||
export declare class ExitPromptError extends Error {
|
||||
name: string;
|
||||
}
|
||||
export declare class HookError extends Error {
|
||||
name: string;
|
||||
}
|
||||
export declare class ValidationError extends Error {
|
||||
name: string;
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
export class AbortPromptError extends Error {
|
||||
name = 'AbortPromptError';
|
||||
message = 'Prompt was aborted';
|
||||
constructor(options) {
|
||||
super();
|
||||
this.cause = options?.cause;
|
||||
}
|
||||
}
|
||||
export class CancelPromptError extends Error {
|
||||
name = 'CancelPromptError';
|
||||
message = 'Prompt was canceled';
|
||||
}
|
||||
export class ExitPromptError extends Error {
|
||||
name = 'ExitPromptError';
|
||||
}
|
||||
export class HookError extends Error {
|
||||
name = 'HookError';
|
||||
}
|
||||
export class ValidationError extends Error {
|
||||
name = 'ValidationError';
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
import type { InquirerReadline } from '@inquirer/type';
|
||||
export declare function withHooks<T>(rl: InquirerReadline, cb: (cycle: (render: () => void) => void) => T): T;
|
||||
export declare function readline(): InquirerReadline;
|
||||
export declare function withUpdates<Args extends unknown[], R>(fn: (...args: Args) => R): (...args: Args) => R;
|
||||
type SetPointer<Value> = {
|
||||
get(): Value;
|
||||
set(value: Value): void;
|
||||
initialized: true;
|
||||
};
|
||||
type UnsetPointer<Value> = {
|
||||
get(): void;
|
||||
set(value: Value): void;
|
||||
initialized: false;
|
||||
};
|
||||
type Pointer<Value> = SetPointer<Value> | UnsetPointer<Value>;
|
||||
export declare function withPointer<Value, ReturnValue>(cb: (pointer: Pointer<Value>) => ReturnValue): ReturnValue;
|
||||
export declare function handleChange(): void;
|
||||
export declare const effectScheduler: {
|
||||
queue(cb: (readline: InquirerReadline) => void | (() => void)): void;
|
||||
run(): void;
|
||||
clearAll(): void;
|
||||
};
|
||||
export {};
|
@ -1,110 +0,0 @@
|
||||
/* eslint @typescript-eslint/no-explicit-any: ["off"] */
|
||||
import { AsyncLocalStorage, AsyncResource } from 'node:async_hooks';
|
||||
import { HookError, ValidationError } from "./errors.js";
|
||||
const hookStorage = new AsyncLocalStorage();
|
||||
function createStore(rl) {
|
||||
const store = {
|
||||
rl,
|
||||
hooks: [],
|
||||
hooksCleanup: [],
|
||||
hooksEffect: [],
|
||||
index: 0,
|
||||
handleChange() { },
|
||||
};
|
||||
return store;
|
||||
}
|
||||
// Run callback in with the hook engine setup.
|
||||
export function withHooks(rl, cb) {
|
||||
const store = createStore(rl);
|
||||
return hookStorage.run(store, () => {
|
||||
function cycle(render) {
|
||||
store.handleChange = () => {
|
||||
store.index = 0;
|
||||
render();
|
||||
};
|
||||
store.handleChange();
|
||||
}
|
||||
return cb(cycle);
|
||||
});
|
||||
}
|
||||
// Safe getStore utility that'll return the store or throw if undefined.
|
||||
function getStore() {
|
||||
const store = hookStorage.getStore();
|
||||
if (!store) {
|
||||
throw new HookError('[Inquirer] Hook functions can only be called from within a prompt');
|
||||
}
|
||||
return store;
|
||||
}
|
||||
export function readline() {
|
||||
return getStore().rl;
|
||||
}
|
||||
// Merge state updates happening within the callback function to avoid multiple renders.
|
||||
export function withUpdates(fn) {
|
||||
const wrapped = (...args) => {
|
||||
const store = getStore();
|
||||
let shouldUpdate = false;
|
||||
const oldHandleChange = store.handleChange;
|
||||
store.handleChange = () => {
|
||||
shouldUpdate = true;
|
||||
};
|
||||
const returnValue = fn(...args);
|
||||
if (shouldUpdate) {
|
||||
oldHandleChange();
|
||||
}
|
||||
store.handleChange = oldHandleChange;
|
||||
return returnValue;
|
||||
};
|
||||
return AsyncResource.bind(wrapped);
|
||||
}
|
||||
export function withPointer(cb) {
|
||||
const store = getStore();
|
||||
const { index } = store;
|
||||
const pointer = {
|
||||
get() {
|
||||
return store.hooks[index];
|
||||
},
|
||||
set(value) {
|
||||
store.hooks[index] = value;
|
||||
},
|
||||
initialized: index in store.hooks,
|
||||
};
|
||||
const returnValue = cb(pointer);
|
||||
store.index++;
|
||||
return returnValue;
|
||||
}
|
||||
export function handleChange() {
|
||||
getStore().handleChange();
|
||||
}
|
||||
export const effectScheduler = {
|
||||
queue(cb) {
|
||||
const store = getStore();
|
||||
const { index } = store;
|
||||
store.hooksEffect.push(() => {
|
||||
store.hooksCleanup[index]?.();
|
||||
const cleanFn = cb(readline());
|
||||
if (cleanFn != null && typeof cleanFn !== 'function') {
|
||||
throw new ValidationError('useEffect return value must be a cleanup function or nothing.');
|
||||
}
|
||||
store.hooksCleanup[index] = cleanFn;
|
||||
});
|
||||
},
|
||||
run() {
|
||||
const store = getStore();
|
||||
withUpdates(() => {
|
||||
store.hooksEffect.forEach((effect) => {
|
||||
effect();
|
||||
});
|
||||
// Warning: Clean the hooks before exiting the `withUpdates` block.
|
||||
// Failure to do so means an updates would hit the same effects again.
|
||||
store.hooksEffect.length = 0;
|
||||
})();
|
||||
},
|
||||
clearAll() {
|
||||
const store = getStore();
|
||||
store.hooksCleanup.forEach((cleanFn) => {
|
||||
cleanFn?.();
|
||||
});
|
||||
store.hooksEffect.length = 0;
|
||||
store.hooksCleanup.length = 0;
|
||||
},
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
export type KeypressEvent = {
|
||||
name: string;
|
||||
ctrl: boolean;
|
||||
};
|
||||
export declare const isUpKey: (key: KeypressEvent) => boolean;
|
||||
export declare const isDownKey: (key: KeypressEvent) => boolean;
|
||||
export declare const isSpaceKey: (key: KeypressEvent) => boolean;
|
||||
export declare const isBackspaceKey: (key: KeypressEvent) => boolean;
|
||||
export declare const isNumberKey: (key: KeypressEvent) => boolean;
|
||||
export declare const isEnterKey: (key: KeypressEvent) => boolean;
|
@ -1,18 +0,0 @@
|
||||
export const isUpKey = (key) =>
|
||||
// The up key
|
||||
key.name === 'up' ||
|
||||
// Vim keybinding
|
||||
key.name === 'k' ||
|
||||
// Emacs keybinding
|
||||
(key.ctrl && key.name === 'p');
|
||||
export const isDownKey = (key) =>
|
||||
// The down key
|
||||
key.name === 'down' ||
|
||||
// Vim keybinding
|
||||
key.name === 'j' ||
|
||||
// Emacs keybinding
|
||||
(key.ctrl && key.name === 'n');
|
||||
export const isSpaceKey = (key) => key.name === 'space';
|
||||
export const isBackspaceKey = (key) => key.name === 'backspace';
|
||||
export const isNumberKey = (key) => '1234567890'.includes(key.name);
|
||||
export const isEnterKey = (key) => key.name === 'enter' || key.name === 'return';
|
@ -1,3 +0,0 @@
|
||||
import type { Prettify, PartialDeep } from '@inquirer/type';
|
||||
import { type Theme } from './theme.ts';
|
||||
export declare function makeTheme<SpecificTheme extends object>(...themes: ReadonlyArray<undefined | PartialDeep<Theme<SpecificTheme>>>): Prettify<Theme<SpecificTheme>>;
|
@ -1,30 +0,0 @@
|
||||
import { defaultTheme } from "./theme.js";
|
||||
function isPlainObject(value) {
|
||||
if (typeof value !== 'object' || value === null)
|
||||
return false;
|
||||
let proto = value;
|
||||
while (Object.getPrototypeOf(proto) !== null) {
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
}
|
||||
return Object.getPrototypeOf(value) === proto;
|
||||
}
|
||||
function deepMerge(...objects) {
|
||||
const output = {};
|
||||
for (const obj of objects) {
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
const prevValue = output[key];
|
||||
output[key] =
|
||||
isPlainObject(prevValue) && isPlainObject(value)
|
||||
? deepMerge(prevValue, value)
|
||||
: value;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
export function makeTheme(...themes) {
|
||||
const themesToMerge = [
|
||||
defaultTheme,
|
||||
...themes.filter((theme) => theme != null),
|
||||
];
|
||||
return deepMerge(...themesToMerge);
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import type { Prettify } from '@inquirer/type';
|
||||
export declare function usePagination<T>({ items, active, renderItem, pageSize, loop, }: {
|
||||
items: ReadonlyArray<T>;
|
||||
/** The index of the active item. */
|
||||
active: number;
|
||||
/** Renders an item as part of a page. */
|
||||
renderItem: (layout: Prettify<{
|
||||
item: T;
|
||||
index: number;
|
||||
isActive: boolean;
|
||||
}>) => string;
|
||||
/** The size of the page. */
|
||||
pageSize: number;
|
||||
/** Allows creating an infinitely looping list. `true` if unspecified. */
|
||||
loop?: boolean;
|
||||
}): string;
|
@ -1,121 +0,0 @@
|
||||
import { useRef } from "../use-ref.js";
|
||||
import { readlineWidth, breakLines } from "../utils.js";
|
||||
function usePointerPosition({ active, renderedItems, pageSize, loop, }) {
|
||||
const state = useRef({
|
||||
lastPointer: active,
|
||||
lastActive: undefined,
|
||||
});
|
||||
const { lastPointer, lastActive } = state.current;
|
||||
const middle = Math.floor(pageSize / 2);
|
||||
const renderedLength = renderedItems.reduce((acc, item) => acc + item.length, 0);
|
||||
const defaultPointerPosition = renderedItems
|
||||
.slice(0, active)
|
||||
.reduce((acc, item) => acc + item.length, 0);
|
||||
let pointer = defaultPointerPosition;
|
||||
if (renderedLength > pageSize) {
|
||||
if (loop) {
|
||||
/**
|
||||
* Creates the next position for the pointer considering an infinitely
|
||||
* looping list of items to be rendered on the page.
|
||||
*
|
||||
* The goal is to progressively move the cursor to the middle position as the user move down, and then keep
|
||||
* the cursor there. When the user move up, maintain the cursor position.
|
||||
*/
|
||||
// By default, keep the cursor position as-is.
|
||||
pointer = lastPointer;
|
||||
if (
|
||||
// First render, skip this logic.
|
||||
lastActive != null &&
|
||||
// Only move the pointer down when the user moves down.
|
||||
lastActive < active &&
|
||||
// Check user didn't move up across page boundary.
|
||||
active - lastActive < pageSize) {
|
||||
pointer = Math.min(
|
||||
// Furthest allowed position for the pointer is the middle of the list
|
||||
middle, Math.abs(active - lastActive) === 1
|
||||
? Math.min(
|
||||
// Move the pointer at most the height of the last active item.
|
||||
lastPointer + (renderedItems[lastActive]?.length ?? 0),
|
||||
// If the user moved by one item, move the pointer to the natural position of the active item as
|
||||
// long as it doesn't move the cursor up.
|
||||
Math.max(defaultPointerPosition, lastPointer))
|
||||
: // Otherwise, move the pointer down by the difference between the active and last active item.
|
||||
lastPointer + active - lastActive);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/**
|
||||
* Creates the next position for the pointer considering a finite list of
|
||||
* items to be rendered on a page.
|
||||
*
|
||||
* The goal is to keep the pointer in the middle of the page whenever possible, until
|
||||
* we reach the bounds of the list (top or bottom). In which case, the cursor moves progressively
|
||||
* to the bottom or top of the list.
|
||||
*/
|
||||
const spaceUnderActive = renderedItems
|
||||
.slice(active)
|
||||
.reduce((acc, item) => acc + item.length, 0);
|
||||
pointer =
|
||||
spaceUnderActive < pageSize - middle
|
||||
? // If the active item is near the end of the list, progressively move the cursor towards the end.
|
||||
pageSize - spaceUnderActive
|
||||
: // Otherwise, progressively move the pointer to the middle of the list.
|
||||
Math.min(defaultPointerPosition, middle);
|
||||
}
|
||||
}
|
||||
// Save state for the next render
|
||||
state.current.lastPointer = pointer;
|
||||
state.current.lastActive = active;
|
||||
return pointer;
|
||||
}
|
||||
export function usePagination({ items, active, renderItem, pageSize, loop = true, }) {
|
||||
const width = readlineWidth();
|
||||
const bound = (num) => ((num % items.length) + items.length) % items.length;
|
||||
const renderedItems = items.map((item, index) => {
|
||||
if (item == null)
|
||||
return [];
|
||||
return breakLines(renderItem({ item, index, isActive: index === active }), width).split('\n');
|
||||
});
|
||||
const renderedLength = renderedItems.reduce((acc, item) => acc + item.length, 0);
|
||||
const renderItemAtIndex = (index) => renderedItems[index] ?? [];
|
||||
const pointer = usePointerPosition({ active, renderedItems, pageSize, loop });
|
||||
// Render the active item to decide the position.
|
||||
// If the active item fits under the pointer, we render it there.
|
||||
// Otherwise, we need to render it to fit at the bottom of the page; moving the pointer up.
|
||||
const activeItem = renderItemAtIndex(active).slice(0, pageSize);
|
||||
const activeItemPosition = pointer + activeItem.length <= pageSize ? pointer : pageSize - activeItem.length;
|
||||
// Create an array of lines for the page, and add the lines of the active item into the page
|
||||
const pageBuffer = Array.from({ length: pageSize });
|
||||
pageBuffer.splice(activeItemPosition, activeItem.length, ...activeItem);
|
||||
// Store to prevent rendering the same item twice
|
||||
const itemVisited = new Set([active]);
|
||||
// Fill the page under the active item
|
||||
let bufferPointer = activeItemPosition + activeItem.length;
|
||||
let itemPointer = bound(active + 1);
|
||||
while (bufferPointer < pageSize &&
|
||||
!itemVisited.has(itemPointer) &&
|
||||
(loop && renderedLength > pageSize ? itemPointer !== active : itemPointer > active)) {
|
||||
const lines = renderItemAtIndex(itemPointer);
|
||||
const linesToAdd = lines.slice(0, pageSize - bufferPointer);
|
||||
pageBuffer.splice(bufferPointer, linesToAdd.length, ...linesToAdd);
|
||||
// Move pointers for next iteration
|
||||
itemVisited.add(itemPointer);
|
||||
bufferPointer += linesToAdd.length;
|
||||
itemPointer = bound(itemPointer + 1);
|
||||
}
|
||||
// Fill the page over the active item
|
||||
bufferPointer = activeItemPosition - 1;
|
||||
itemPointer = bound(active - 1);
|
||||
while (bufferPointer >= 0 &&
|
||||
!itemVisited.has(itemPointer) &&
|
||||
(loop && renderedLength > pageSize ? itemPointer !== active : itemPointer < active)) {
|
||||
const lines = renderItemAtIndex(itemPointer);
|
||||
const linesToAdd = lines.slice(Math.max(0, lines.length - bufferPointer - 1));
|
||||
pageBuffer.splice(bufferPointer - linesToAdd.length + 1, linesToAdd.length, ...linesToAdd);
|
||||
// Move pointers for next iteration
|
||||
itemVisited.add(itemPointer);
|
||||
bufferPointer -= linesToAdd.length;
|
||||
itemPointer = bound(itemPointer - 1);
|
||||
}
|
||||
return pageBuffer.filter((line) => typeof line === 'string').join('\n');
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
export declare class PromisePolyfill<T> extends Promise<T> {
|
||||
static withResolver<T>(): {
|
||||
promise: Promise<T>;
|
||||
resolve: (value: T) => void;
|
||||
reject: (error: unknown) => void;
|
||||
};
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
// TODO: Remove this class once Node 22 becomes the minimum supported version.
|
||||
export class PromisePolyfill extends Promise {
|
||||
// Available starting from Node 22
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
|
||||
static withResolver() {
|
||||
let resolve;
|
||||
let reject;
|
||||
const promise = new Promise((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
return { promise, resolve: resolve, reject: reject };
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import type { InquirerReadline } from '@inquirer/type';
|
||||
export default class ScreenManager {
|
||||
private height;
|
||||
private extraLinesUnderPrompt;
|
||||
private cursorPos;
|
||||
private readonly rl;
|
||||
constructor(rl: InquirerReadline);
|
||||
write(content: string): void;
|
||||
render(content: string, bottomContent?: string): void;
|
||||
checkCursorPos(): void;
|
||||
done({ clearContent }: {
|
||||
clearContent: boolean;
|
||||
}): void;
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
import { stripVTControlCharacters } from 'node:util';
|
||||
import ansiEscapes from 'ansi-escapes';
|
||||
import { breakLines, readlineWidth } from "./utils.js";
|
||||
const height = (content) => content.split('\n').length;
|
||||
const lastLine = (content) => content.split('\n').pop() ?? '';
|
||||
function cursorDown(n) {
|
||||
return n > 0 ? ansiEscapes.cursorDown(n) : '';
|
||||
}
|
||||
export default class ScreenManager {
|
||||
// These variables are keeping information to allow correct prompt re-rendering
|
||||
height = 0;
|
||||
extraLinesUnderPrompt = 0;
|
||||
cursorPos;
|
||||
rl;
|
||||
constructor(rl) {
|
||||
this.rl = rl;
|
||||
this.cursorPos = rl.getCursorPos();
|
||||
}
|
||||
write(content) {
|
||||
this.rl.output.unmute();
|
||||
this.rl.output.write(content);
|
||||
this.rl.output.mute();
|
||||
}
|
||||
render(content, bottomContent = '') {
|
||||
// Write message to screen and setPrompt to control backspace
|
||||
const promptLine = lastLine(content);
|
||||
const rawPromptLine = stripVTControlCharacters(promptLine);
|
||||
// Remove the rl.line from our prompt. We can't rely on the content of
|
||||
// rl.line (mainly because of the password prompt), so just rely on it's
|
||||
// length.
|
||||
let prompt = rawPromptLine;
|
||||
if (this.rl.line.length > 0) {
|
||||
prompt = prompt.slice(0, -this.rl.line.length);
|
||||
}
|
||||
this.rl.setPrompt(prompt);
|
||||
// SetPrompt will change cursor position, now we can get correct value
|
||||
this.cursorPos = this.rl.getCursorPos();
|
||||
const width = readlineWidth();
|
||||
content = breakLines(content, width);
|
||||
bottomContent = breakLines(bottomContent, width);
|
||||
// Manually insert an extra line if we're at the end of the line.
|
||||
// This prevent the cursor from appearing at the beginning of the
|
||||
// current line.
|
||||
if (rawPromptLine.length % width === 0) {
|
||||
content += '\n';
|
||||
}
|
||||
let output = content + (bottomContent ? '\n' + bottomContent : '');
|
||||
/**
|
||||
* Re-adjust the cursor at the correct position.
|
||||
*/
|
||||
// We need to consider parts of the prompt under the cursor as part of the bottom
|
||||
// content in order to correctly cleanup and re-render.
|
||||
const promptLineUpDiff = Math.floor(rawPromptLine.length / width) - this.cursorPos.rows;
|
||||
const bottomContentHeight = promptLineUpDiff + (bottomContent ? height(bottomContent) : 0);
|
||||
// Return cursor to the input position (on top of the bottomContent)
|
||||
if (bottomContentHeight > 0)
|
||||
output += ansiEscapes.cursorUp(bottomContentHeight);
|
||||
// Return cursor to the initial left offset.
|
||||
output += ansiEscapes.cursorTo(this.cursorPos.cols);
|
||||
/**
|
||||
* Render and store state for future re-rendering
|
||||
*/
|
||||
this.write(cursorDown(this.extraLinesUnderPrompt) +
|
||||
ansiEscapes.eraseLines(this.height) +
|
||||
output);
|
||||
this.extraLinesUnderPrompt = bottomContentHeight;
|
||||
this.height = height(output);
|
||||
}
|
||||
checkCursorPos() {
|
||||
const cursorPos = this.rl.getCursorPos();
|
||||
if (cursorPos.cols !== this.cursorPos.cols) {
|
||||
this.write(ansiEscapes.cursorTo(cursorPos.cols));
|
||||
this.cursorPos = cursorPos;
|
||||
}
|
||||
}
|
||||
done({ clearContent }) {
|
||||
this.rl.setPrompt('');
|
||||
let output = cursorDown(this.extraLinesUnderPrompt);
|
||||
output += clearContent ? ansiEscapes.eraseLines(this.height) : '\n';
|
||||
output += ansiEscapes.cursorShow;
|
||||
this.write(output);
|
||||
this.rl.close();
|
||||
}
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
import type { Prettify } from '@inquirer/type';
|
||||
/**
|
||||
* Union type representing the possible statuses of a prompt.
|
||||
*
|
||||
* - `'loading'`: The prompt is currently loading.
|
||||
* - `'idle'`: The prompt is loaded and currently waiting for the user to
|
||||
* submit an answer.
|
||||
* - `'done'`: The user has submitted an answer and the prompt is finished.
|
||||
* - `string`: Any other string: The prompt is in a custom state.
|
||||
*/
|
||||
export type Status = 'loading' | 'idle' | 'done' | (string & {});
|
||||
type DefaultTheme = {
|
||||
/**
|
||||
* Prefix to prepend to the message. If a function is provided, it will be
|
||||
* called with the current status of the prompt, and the return value will be
|
||||
* used as the prefix.
|
||||
*
|
||||
* @remarks
|
||||
* If `status === 'loading'`, this property is ignored and the spinner (styled
|
||||
* by the `spinner` property) will be displayed instead.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (status) => status === 'done' ? colors.green('✔') : colors.blue('?')
|
||||
* ```
|
||||
*/
|
||||
prefix: string | Prettify<Omit<Record<Status, string>, 'loading'>>;
|
||||
/**
|
||||
* Configuration for the spinner that is displayed when the prompt is in the
|
||||
* `'loading'` state.
|
||||
*
|
||||
* We recommend the use of {@link https://github.com/sindresorhus/cli-spinners|cli-spinners} for a list of available spinners.
|
||||
*/
|
||||
spinner: {
|
||||
/**
|
||||
* The time interval between frames, in milliseconds.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* 80
|
||||
* ```
|
||||
*/
|
||||
interval: number;
|
||||
/**
|
||||
* A list of frames to show for the spinner.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
|
||||
* ```
|
||||
*/
|
||||
frames: string[];
|
||||
};
|
||||
/**
|
||||
* Object containing functions to style different parts of the prompt.
|
||||
*/
|
||||
style: {
|
||||
/**
|
||||
* Style to apply to the user's answer once it has been submitted.
|
||||
*
|
||||
* @param text - The user's answer.
|
||||
* @returns The styled answer.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (text) => colors.cyan(text)
|
||||
* ```
|
||||
*/
|
||||
answer: (text: string) => string;
|
||||
/**
|
||||
* Style to apply to the message displayed to the user.
|
||||
*
|
||||
* @param text - The message to style.
|
||||
* @param status - The current status of the prompt.
|
||||
* @returns The styled message.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (text, status) => colors.bold(text)
|
||||
* ```
|
||||
*/
|
||||
message: (text: string, status: Status) => string;
|
||||
/**
|
||||
* Style to apply to error messages.
|
||||
*
|
||||
* @param text - The error message.
|
||||
* @returns The styled error message.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (text) => colors.red(`> ${text}`)
|
||||
* ```
|
||||
*/
|
||||
error: (text: string) => string;
|
||||
/**
|
||||
* Style to apply to the default answer when one is provided.
|
||||
*
|
||||
* @param text - The default answer.
|
||||
* @returns The styled default answer.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (text) => colors.dim(`(${text})`)
|
||||
* ```
|
||||
*/
|
||||
defaultAnswer: (text: string) => string;
|
||||
/**
|
||||
* Style to apply to help text.
|
||||
*
|
||||
* @param text - The help text.
|
||||
* @returns The styled help text.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (text) => colors.dim(text)
|
||||
* ```
|
||||
*/
|
||||
help: (text: string) => string;
|
||||
/**
|
||||
* Style to apply to highlighted text.
|
||||
*
|
||||
* @param text - The text to highlight.
|
||||
* @returns The highlighted text.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (text) => colors.cyan(text)
|
||||
* ```
|
||||
*/
|
||||
highlight: (text: string) => string;
|
||||
/**
|
||||
* Style to apply to keyboard keys referred to in help texts.
|
||||
*
|
||||
* @param text - The key to style.
|
||||
* @returns The styled key.
|
||||
*
|
||||
* @defaultValue
|
||||
* ```ts
|
||||
* // import colors from 'yoctocolors-cjs';
|
||||
* (text) => colors.cyan(colors.bold(`<${text}>`))
|
||||
* ```
|
||||
*/
|
||||
key: (text: string) => string;
|
||||
};
|
||||
};
|
||||
export type Theme<Extension extends object = object> = Prettify<Extension & DefaultTheme>;
|
||||
export declare const defaultTheme: DefaultTheme;
|
||||
export {};
|
@ -1,22 +0,0 @@
|
||||
import colors from 'yoctocolors-cjs';
|
||||
import figures from '@inquirer/figures';
|
||||
export const defaultTheme = {
|
||||
prefix: {
|
||||
idle: colors.blue('?'),
|
||||
// TODO: use figure
|
||||
done: colors.green(figures.tick),
|
||||
},
|
||||
spinner: {
|
||||
interval: 80,
|
||||
frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'].map((frame) => colors.yellow(frame)),
|
||||
},
|
||||
style: {
|
||||
answer: colors.cyan,
|
||||
message: colors.bold,
|
||||
error: (text) => colors.red(`> ${text}`),
|
||||
defaultAnswer: (text) => colors.dim(`(${text})`),
|
||||
help: colors.dim,
|
||||
highlight: colors.cyan,
|
||||
key: (text) => colors.cyan(colors.bold(`<${text}>`)),
|
||||
},
|
||||
};
|
@ -1,2 +0,0 @@
|
||||
import type { InquirerReadline } from '@inquirer/type';
|
||||
export declare function useEffect(cb: (rl: InquirerReadline) => void | (() => void), depArray: ReadonlyArray<unknown>): void;
|
@ -1,11 +0,0 @@
|
||||
import { withPointer, effectScheduler } from "./hook-engine.js";
|
||||
export function useEffect(cb, depArray) {
|
||||
withPointer((pointer) => {
|
||||
const oldDeps = pointer.get();
|
||||
const hasChanged = !Array.isArray(oldDeps) || depArray.some((dep, i) => !Object.is(dep, oldDeps[i]));
|
||||
if (hasChanged) {
|
||||
effectScheduler.queue(cb);
|
||||
}
|
||||
pointer.set(depArray);
|
||||
});
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
import { type InquirerReadline } from '@inquirer/type';
|
||||
import { type KeypressEvent } from './key.ts';
|
||||
export declare function useKeypress(userHandler: (event: KeypressEvent, rl: InquirerReadline) => void | Promise<void>): void;
|
@ -1,20 +0,0 @@
|
||||
import { useRef } from "./use-ref.js";
|
||||
import { useEffect } from "./use-effect.js";
|
||||
import { withUpdates } from "./hook-engine.js";
|
||||
export function useKeypress(userHandler) {
|
||||
const signal = useRef(userHandler);
|
||||
signal.current = userHandler;
|
||||
useEffect((rl) => {
|
||||
let ignore = false;
|
||||
const handler = withUpdates((_input, event) => {
|
||||
if (ignore)
|
||||
return;
|
||||
void signal.current(event, rl);
|
||||
});
|
||||
rl.input.on('keypress', handler);
|
||||
return () => {
|
||||
ignore = true;
|
||||
rl.input.removeListener('keypress', handler);
|
||||
};
|
||||
}, []);
|
||||
}
|
@ -1 +0,0 @@
|
||||
export declare function useMemo<Value>(fn: () => Value, dependencies: ReadonlyArray<unknown>): Value;
|
@ -1,14 +0,0 @@
|
||||
import { withPointer } from "./hook-engine.js";
|
||||
export function useMemo(fn, dependencies) {
|
||||
return withPointer((pointer) => {
|
||||
const prev = pointer.get();
|
||||
if (!prev ||
|
||||
prev.dependencies.length !== dependencies.length ||
|
||||
prev.dependencies.some((dep, i) => dep !== dependencies[i])) {
|
||||
const value = fn();
|
||||
pointer.set({ value, dependencies });
|
||||
return value;
|
||||
}
|
||||
return prev.value;
|
||||
});
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
import type { Theme, Status } from './theme.ts';
|
||||
export declare function usePrefix({ status, theme, }: {
|
||||
status?: Status;
|
||||
theme?: Theme;
|
||||
}): string;
|
@ -1,35 +0,0 @@
|
||||
import { useState } from "./use-state.js";
|
||||
import { useEffect } from "./use-effect.js";
|
||||
import { makeTheme } from "./make-theme.js";
|
||||
export function usePrefix({ status = 'idle', theme, }) {
|
||||
const [showLoader, setShowLoader] = useState(false);
|
||||
const [tick, setTick] = useState(0);
|
||||
const { prefix, spinner } = makeTheme(theme);
|
||||
useEffect(() => {
|
||||
if (status === 'loading') {
|
||||
let tickInterval;
|
||||
let inc = -1;
|
||||
// Delay displaying spinner by 300ms, to avoid flickering
|
||||
const delayTimeout = setTimeout(() => {
|
||||
setShowLoader(true);
|
||||
tickInterval = setInterval(() => {
|
||||
inc = inc + 1;
|
||||
setTick(inc % spinner.frames.length);
|
||||
}, spinner.interval);
|
||||
}, 300);
|
||||
return () => {
|
||||
clearTimeout(delayTimeout);
|
||||
clearInterval(tickInterval);
|
||||
};
|
||||
}
|
||||
else {
|
||||
setShowLoader(false);
|
||||
}
|
||||
}, [status]);
|
||||
if (showLoader) {
|
||||
return spinner.frames[tick];
|
||||
}
|
||||
// There's a delay before we show the loader. So we want to ignore `loading` here, and pass idle instead.
|
||||
const iconName = status === 'loading' ? 'idle' : status;
|
||||
return typeof prefix === 'string' ? prefix : (prefix[iconName] ?? prefix['idle']);
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
export declare function useRef<Value>(val: Value): {
|
||||
current: Value;
|
||||
};
|
||||
export declare function useRef<Value>(val?: Value): {
|
||||
current: Value | undefined;
|
||||
};
|
@ -1,4 +0,0 @@
|
||||
import { useState } from "./use-state.js";
|
||||
export function useRef(val) {
|
||||
return useState({ current: val })[0];
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
type NotFunction<T> = T extends (...args: never) => unknown ? never : T;
|
||||
export declare function useState<Value>(defaultValue: NotFunction<Value> | (() => Value)): [Value, (newValue: Value) => void];
|
||||
export declare function useState<Value>(defaultValue?: NotFunction<Value> | (() => Value)): [Value | undefined, (newValue?: Value) => void];
|
||||
export {};
|
@ -1,20 +0,0 @@
|
||||
import { AsyncResource } from 'node:async_hooks';
|
||||
import { withPointer, handleChange } from "./hook-engine.js";
|
||||
export function useState(defaultValue) {
|
||||
return withPointer((pointer) => {
|
||||
const setState = AsyncResource.bind(function setState(newValue) {
|
||||
// Noop if the value is still the same.
|
||||
if (pointer.get() !== newValue) {
|
||||
pointer.set(newValue);
|
||||
// Trigger re-render
|
||||
handleChange();
|
||||
}
|
||||
});
|
||||
if (pointer.initialized) {
|
||||
return [pointer.get(), setState];
|
||||
}
|
||||
const value = typeof defaultValue === 'function' ? defaultValue() : defaultValue;
|
||||
pointer.set(value);
|
||||
return [value, setState];
|
||||
});
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Force line returns at specific width. This function is ANSI code friendly and it'll
|
||||
* ignore invisible codes during width calculation.
|
||||
* @param {string} content
|
||||
* @param {number} width
|
||||
* @return {string}
|
||||
*/
|
||||
export declare function breakLines(content: string, width: number): string;
|
||||
/**
|
||||
* Returns the width of the active readline, or 80 as default value.
|
||||
* @returns {number}
|
||||
*/
|
||||
export declare function readlineWidth(): number;
|
@ -1,25 +0,0 @@
|
||||
import cliWidth from 'cli-width';
|
||||
import wrapAnsi from 'wrap-ansi';
|
||||
import { readline } from "./hook-engine.js";
|
||||
/**
|
||||
* Force line returns at specific width. This function is ANSI code friendly and it'll
|
||||
* ignore invisible codes during width calculation.
|
||||
* @param {string} content
|
||||
* @param {number} width
|
||||
* @return {string}
|
||||
*/
|
||||
export function breakLines(content, width) {
|
||||
return content
|
||||
.split('\n')
|
||||
.flatMap((line) => wrapAnsi(line, width, { trim: false, hard: true })
|
||||
.split('\n')
|
||||
.map((str) => str.trimEnd()))
|
||||
.join('\n');
|
||||
}
|
||||
/**
|
||||
* Returns the width of the active readline, or 80 as default value.
|
||||
* @returns {number}
|
||||
*/
|
||||
export function readlineWidth() {
|
||||
return cliWidth({ defaultWidth: 80, output: readline().output });
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
{
|
||||
"name": "@inquirer/core",
|
||||
"version": "10.1.15",
|
||||
"description": "Core Inquirer prompt API",
|
||||
"keywords": [
|
||||
"answer",
|
||||
"answers",
|
||||
"ask",
|
||||
"base",
|
||||
"cli",
|
||||
"command",
|
||||
"command-line",
|
||||
"confirm",
|
||||
"enquirer",
|
||||
"generate",
|
||||
"generator",
|
||||
"hyper",
|
||||
"input",
|
||||
"inquire",
|
||||
"inquirer",
|
||||
"interface",
|
||||
"iterm",
|
||||
"javascript",
|
||||
"menu",
|
||||
"node",
|
||||
"nodejs",
|
||||
"prompt",
|
||||
"promptly",
|
||||
"prompts",
|
||||
"question",
|
||||
"readline",
|
||||
"scaffold",
|
||||
"scaffolder",
|
||||
"scaffolding",
|
||||
"stdin",
|
||||
"stdout",
|
||||
"terminal",
|
||||
"tty",
|
||||
"ui",
|
||||
"yeoman",
|
||||
"yo",
|
||||
"zsh"
|
||||
],
|
||||
"homepage": "https://github.com/SBoudrias/Inquirer.js/blob/main/packages/core/README.md",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/SBoudrias/Inquirer.js.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "Simon Boudrias <admin@simonboudrias.com>",
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"import": {
|
||||
"types": "./dist/esm/index.d.ts",
|
||||
"default": "./dist/esm/index.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/commonjs/index.d.ts",
|
||||
"default": "./dist/commonjs/index.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"main": "./dist/commonjs/index.js",
|
||||
"module": "./dist/esm/index.js",
|
||||
"types": "./dist/commonjs/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"attw": "attw --pack",
|
||||
"tsc": "tshy"
|
||||
},
|
||||
"dependencies": {
|
||||
"@inquirer/figures": "^1.0.13",
|
||||
"@inquirer/type": "^3.0.8",
|
||||
"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"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@arethetypeswrong/cli": "^0.18.2",
|
||||
"@inquirer/testing": "^2.1.49",
|
||||
"@types/mute-stream": "^0.0.4",
|
||||
"@types/node": "^24.0.15",
|
||||
"@types/wrap-ansi": "^3.0.0",
|
||||
"tshy": "^3.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"tshy": {
|
||||
"exclude": [
|
||||
"src/**/*.test.ts"
|
||||
],
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": "./src/index.ts"
|
||||
}
|
||||
},
|
||||
"gitHead": "c1a755fe8b50377b685ea5951e0794985ce8d356"
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
Copyright (c) 2025 Simon Boudrias
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue