2 명령어 실행의 성공과 실패에 대한 이야기
3 매개변수에 대해서
4 앱을 좀더 그럴듯 하게 만들기
앱을 좀더 그럴듯 하게 만들기
CLI 기반의 앱들은 암묵적 룰처럼 정해놓고 보통 공통적으로 가지는 옵션이 있습니다. -v, --version, --help 와 같은것들인데 버전과 도움말 화면을 볼 수 있습니다. node --version node --help 해보면 그 모습을 볼 수 있죠 우리의 hello 앱은 그런게 아직 없죠 hello --version 라고 입력하면 Two numbers required 라고 나올뿐이죠 그래서 이런 도움말페이지나 버전정보를 보여줄 수 있도록 만들어보겠습니다. 이런 기본적인 틀을 제공해주는 모듈이 있습니다 commander 이라는 모듈입니다 npm i commander 해서 설치합니다
IyEvdXNyL2Jpbi9lbnYgbm9kZQppbXBvcnQgeyBDb21tYW5kIH0gZnJvbSAiY29tbWFuZGVyIjsKY29uc3QgcHJvZ3JhbSA9IG5ldyBDb21tYW5kKCk7CnByb2dyYW0KICAgIC5uYW1lKCdoZWxsbycpCiAgICAuZGVzY3JpcHRpb24oJ015IGZpcnN0IENMSSBBcHAnKQogICAgLnZlcnNpb24oJzAuMC4xJykKICAgIC5vcHRpb24oJy1hJywgJ015IGN1c3RvbSBvcHRpb24gMScpCiAgICAub3B0aW9uKCctaycsICdNeSBjdXN0b20gb3B0aW9uIDInKQogICAgLmFjdGlvbigoc3RyLCBvcHRpb25zKSA9PiB7CiAgICAgICAgY29uc29sZS5sb2coJ09QVElPTlMnLCBzdHIpCiAgICAgICAgY29uc29sZS5sb2coJ0FSR1MnLCBvcHRpb25zLmFyZ3MpCiAgICB9KTsKcHJvZ3JhbS5wYXJzZSgpOw==
#!/usr/bin/env node
import { Command } from "commander";
const program = new Command();
program
.name('hello')
.description('My first CLI App')
.version('0.0.1')
.option('-a', 'My custom option 1')
.option('-k', 'My custom option 2')
.action((str, options) => {
console.log('OPTIONS', str)
console.log('ARGS', options.args)
});
program.parse();
이렇게 해서 hello --help 라고 실행해봅니다. 그럴듯한 도움말 화면이 나옵니다 hello -V 혹은 hello --version 로 실행해보면 앱의 버전도 나옵니다. 기존에 만든앱은 process.argv 배열값을 이용해서 매개변수를 받아온 반면 commander 를 사용하면 알아서 구분해서 준비해줍니다. hello -a a b c 라고 실행하면 OPTIONS { a: true } ARGS [ 'a', 'b', 'c' ] 라고 출력됩니다 hello -a -k a b c 혹은 hello -ak a b c 라고 실행하면 OPTIONS { a: true, k: true } ARGS [ 'a', 'b', 'c' ] 라고 출력됩니다 hello -ad a b c 라고 실행하면 d는 정의되지 않은 옵션인 이유로 error: unknown option '-d' 가 출력됩니다 이때 echo $? 를 확인해보면 1이 나오는것이 확인됩니다 기존에 만든 hello 앱을 commander 를 이용해서 조금 더 개선해보자면 다음과 같아집니다
IyEvdXNyL2Jpbi9lbnYgbm9kZQppbXBvcnQgeyBDb21tYW5kIH0gZnJvbSAiY29tbWFuZGVyIjsKaW1wb3J0IGNoYWxrIGZyb20gImNoYWxrIjsKaW1wb3J0IHJlYWRsaW5lIGZyb20gInJlYWRsaW5lIjsKY29uc3QgcHJvZ3JhbSA9IG5ldyBDb21tYW5kKCk7CnByb2dyYW0KICAgIC5uYW1lKCdoZWxsbycpCiAgICAuZGVzY3JpcHRpb24oJ015IGZpcnN0IENMSSBBcHAnKQogICAgLnZlcnNpb24oJzAuMC4xJykKICAgIC5vcHRpb24oJy1uLCAtLW51bWJlciA8bnVtYmVycy4uLj4nLCAnc3BlY2lmeSBudW1iZXJzJykKICAgIC5hY3Rpb24oYXN5bmMgKHN0ciwgb3B0aW9ucykgPT4gewogICAgICAgIGlmICghc3RyLm51bWJlcikgcmV0dXJuOwogICAgICAgIGlmIChzdHIubnVtYmVyLmxlbmd0aCA8IDIpIHsKICAgICAgICAgICAgY29uc29sZS5sb2coY2hhbGsuYm9sZC5yZWQoJ1R3byBudW1iZXJzIHJlcXVpcmVkJykpOwogICAgICAgICAgICBwcm9jZXNzLmV4aXQoMSk7CiAgICAgICAgfQogICAgICAgIGxldCBwZXJjZW50ID0gMDsKICAgICAgICB3aGlsZSAodHJ1ZSkgewogICAgICAgICAgICBwZXJjZW50Kys7CiAgICAgICAgICAgIHJlYWRsaW5lLmN1cnNvclRvKHByb2Nlc3Muc3Rkb3V0LCAwKTsKICAgICAgICAgICAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoYFByb2dyZXNzICR7Y2hhbGsuYm9sZC55ZWxsb3coYCR7cGVyY2VudH1gKX0gJWApOwogICAgICAgICAgICBpZiAocGVyY2VudCA9PT0gMTAwKSBicmVhazsKICAgICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UociA9PiBzZXRUaW1lb3V0KHIsIDIwKSk7CiAgICAgICAgfQogICAgICAgIGNvbnNvbGUubG9nKCcnKTsKICAgICAgICBjb25zb2xlLmxvZyhgUmVzdWx0IGlzICR7Y2hhbGsuYm9sZC5ncmVlbihzdHIubnVtYmVyWzBdICogc3RyLm51bWJlclsxXSl9YCk7CiAgICAgICAgcHJvY2Vzcy5leGl0KDApOwogICAgfSk7CnByb2dyYW0ucGFyc2UoKTs=
#!/usr/bin/env node
import { Command } from "commander";
import chalk from "chalk";
import readline from "readline";
const program = new Command();
program
.name('hello')
.description('My first CLI App')
.version('0.0.1')
.option('-n, --number <numbers...>', 'specify numbers')
.action(async (str, options) => {
if (!str.number) return;
if (str.number.length < 2) {
console.log(chalk.bold.red('Two numbers required'));
process.exit(1);
}
let percent = 0;
while (true) {
percent++;
readline.cursorTo(process.stdout, 0);
process.stdout.write(`Progress ${chalk.bold.yellow(`${percent}`)} %`);
if (percent === 100) break;
await new Promise(r => setTimeout(r, 20));
}
console.log('');
console.log(`Result is ${chalk.bold.green(str.number[0] * str.number[1])}`);
process.exit(0);
});
program.parse();