tylersong 1.0.8 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -4,6 +4,9 @@ import inquirer from "inquirer";
4
4
  import chalk from "chalk";
5
5
  import { program } from "commander";
6
6
  import { exec } from "child_process";
7
+ import { readFileSync } from "fs";
8
+ import { fileURLToPath } from "url";
9
+ import { dirname, join } from "path";
7
10
 
8
11
  interface ProgramOptions {
9
12
  github?: boolean;
@@ -13,6 +16,28 @@ interface UserAnswer {
13
16
  showInfo: boolean;
14
17
  }
15
18
 
19
+ interface PackageJson {
20
+ version: string;
21
+ name: string;
22
+ description: string;
23
+ }
24
+
25
+ // package.json에서 버전 동적으로 읽기
26
+ const getPackageVersion = (): string => {
27
+ try {
28
+ const __filename = fileURLToPath(import.meta.url);
29
+ const __dirname = dirname(__filename);
30
+ const packagePath = join(__dirname, "..", "package.json");
31
+ const packageJson = JSON.parse(
32
+ readFileSync(packagePath, "utf-8")
33
+ ) as PackageJson;
34
+ return packageJson.version;
35
+ } catch (error) {
36
+ console.error(chalk.red("⚠️ 버전 정보를 읽을 수 없습니다."));
37
+ return "1.0.0";
38
+ }
39
+ };
40
+
16
41
  const openUrl = (url: string): void => {
17
42
  const command: string =
18
43
  process.platform === "win32"
@@ -20,10 +45,16 @@ const openUrl = (url: string): void => {
20
45
  : process.platform === "darwin"
21
46
  ? "open"
22
47
  : "xdg-open";
23
- exec(`${command} ${url}`);
48
+
49
+ exec(`${command} ${url}`, (error) => {
50
+ if (error) {
51
+ console.error(chalk.red("❌ 브라우저를 열 수 없습니다."));
52
+ console.error(chalk.yellow(`수동으로 방문해주세요: ${url}`));
53
+ }
54
+ });
24
55
  };
25
56
 
26
- program.version("1.0.8");
57
+ program.version(getPackageVersion());
27
58
 
28
59
  program.option("-g, --github", "GitHub 프로필 열기");
29
60
 
@@ -37,10 +68,11 @@ if (Object.keys(options).length > 0) {
37
68
  }
38
69
 
39
70
  const main = async (): Promise<void> => {
40
- // 도움말 옵션 체크
41
- if (process.argv.includes("--help")) {
42
- console.log(
43
- chalk.yellow(`
71
+ try {
72
+ // 도움말 옵션 체크
73
+ if (process.argv.includes("--help")) {
74
+ console.log(
75
+ chalk.yellow(`
44
76
  ╭───────────────────────────────╮
45
77
  │ 사용 방법 │
46
78
  ├───────────────────────────────┤
@@ -52,45 +84,58 @@ const main = async (): Promise<void> => {
52
84
  │ -h, --help 도움말 │
53
85
  ╰───────────────────────────────╯
54
86
  `)
55
- );
56
- process.exit(0);
57
- }
87
+ );
88
+ process.exit(0);
89
+ }
90
+
91
+ // 사용자 질문
92
+ const answer: UserAnswer = await inquirer.prompt([
93
+ {
94
+ type: "confirm",
95
+ name: "showInfo",
96
+ message: chalk.cyan("✨ 저에 대해 궁금하신가요?"),
97
+ default: true,
98
+ },
99
+ ]);
58
100
 
59
- // 사용자 질문
60
- const answer: UserAnswer = await inquirer.prompt([
61
- {
62
- type: "confirm",
63
- name: "showInfo",
64
- message: chalk.cyan("✨ 저에 대해 궁금하신가요?"),
65
- default: true,
66
- },
67
- ]);
68
-
69
- if (answer.showInfo) {
70
- console.log(
71
- chalk.bold.cyan(`
101
+ if (answer.showInfo) {
102
+ console.log(
103
+ chalk.bold.cyan(`
72
104
  ╭───────────────────────────────────────────╮
73
105
  │ 🚀 Developer Profile 🚀 │
74
106
  ╰───────────────────────────────────────────╯
75
107
 
76
108
  `) +
77
- chalk.green(`👋 안녕하세요!
109
+ chalk.green(`👋 안녕하세요!
78
110
  💻 개발자 ${chalk.bold.yellow("송민성")}입니다.
79
111
 
80
112
  `) +
81
- chalk.hex("#fef6e1")(`📌 Github: ${chalk.underline.whiteBright(
82
- `https://github.com/alstjd0051`
83
- )}
113
+ chalk.hex("#fef6e1")(`📌 Github: ${chalk.underline.whiteBright(
114
+ `https://github.com/alstjd0051`
115
+ )}
84
116
  `) +
85
- chalk.blue(`✉️ E-mail: ${chalk.underline.whiteBright(
86
- `wsc7202@gmail.com`
87
- )}
117
+ chalk.blue(`✉️ E-mail: ${chalk.underline.whiteBright(
118
+ `wsc7202@gmail.com`
119
+ )}
88
120
  `) +
89
- chalk.magenta(`
121
+ chalk.magenta(`
90
122
  💡 더 많은 정보는 ${chalk.bold("--help")}를 통해 확인해주세요.
91
123
  `)
92
- );
124
+ );
125
+ }
126
+ } catch (error) {
127
+ console.error(chalk.red("\n❌ 오류가 발생했습니다:"));
128
+ if (error instanceof Error) {
129
+ console.error(chalk.yellow(error.message));
130
+ } else {
131
+ console.error(chalk.yellow("알 수 없는 오류가 발생했습니다."));
132
+ }
133
+ process.exit(1);
93
134
  }
94
135
  };
95
136
 
96
- main().catch(console.error);
137
+ main().catch((error) => {
138
+ console.error(chalk.red("\n❌ 치명적인 오류가 발생했습니다:"));
139
+ console.error(error);
140
+ process.exit(1);
141
+ });
@@ -0,0 +1,167 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { exec } from "child_process";
3
+
4
+ // exec 모킹
5
+ vi.mock("child_process", () => ({
6
+ exec: vi.fn(),
7
+ }));
8
+
9
+ // chalk 모킹
10
+ vi.mock("chalk", () => ({
11
+ default: {
12
+ yellow: vi.fn((str: string) => str),
13
+ cyan: vi.fn((str: string) => str),
14
+ bold: {
15
+ cyan: vi.fn((str: string) => str),
16
+ yellow: vi.fn((str: string) => str),
17
+ },
18
+ green: vi.fn((str: string) => str),
19
+ hex: vi.fn(() => vi.fn((str: string) => str)),
20
+ blue: vi.fn((str: string) => str),
21
+ magenta: vi.fn((str: string) => str),
22
+ red: vi.fn((str: string) => str),
23
+ underline: {
24
+ whiteBright: vi.fn((str: string) => str),
25
+ },
26
+ },
27
+ }));
28
+
29
+ // inquirer 모킹
30
+ vi.mock("inquirer", () => ({
31
+ default: {
32
+ prompt: vi.fn(),
33
+ },
34
+ }));
35
+
36
+ // commander 모킹
37
+ vi.mock("commander", () => ({
38
+ program: {
39
+ version: vi.fn().mockReturnThis(),
40
+ option: vi.fn().mockReturnThis(),
41
+ parse: vi.fn().mockReturnThis(),
42
+ opts: vi.fn().mockReturnValue({}),
43
+ },
44
+ }));
45
+
46
+ describe("CLI 도구 테스트", () => {
47
+ beforeEach(() => {
48
+ vi.clearAllMocks();
49
+ });
50
+
51
+ afterEach(() => {
52
+ vi.restoreAllMocks();
53
+ });
54
+
55
+ describe("openUrl 함수", () => {
56
+ it("macOS에서 올바른 명령어를 사용해야 함", () => {
57
+ const mockExec = vi.mocked(exec);
58
+ const platform = process.platform;
59
+
60
+ if (platform === "darwin") {
61
+ // macOS에서는 'open' 명령어를 사용
62
+ expect(mockExec).toBeDefined();
63
+ }
64
+ });
65
+
66
+ it("URL을 여는 명령어가 실행되어야 함", () => {
67
+ const mockExec = vi.mocked(exec);
68
+ expect(mockExec).toBeDefined();
69
+ });
70
+ });
71
+
72
+ describe("CLI 옵션 테스트", () => {
73
+ it("--version 옵션이 정의되어 있어야 함", async () => {
74
+ // commander가 버전을 설정하는지 확인
75
+ const { program } = await import("commander");
76
+ expect(typeof program.version).toBe("function");
77
+ });
78
+
79
+ it("--github 옵션이 정의되어 있어야 함", async () => {
80
+ const { program } = await import("commander");
81
+ expect(typeof program.option).toBe("function");
82
+ });
83
+ });
84
+
85
+ describe("사용자 인터페이스 테스트", () => {
86
+ it("inquirer prompt가 올바르게 정의되어 있어야 함", async () => {
87
+ const inquirer = (await import("inquirer")).default;
88
+ expect(inquirer.prompt).toBeDefined();
89
+ });
90
+ });
91
+
92
+ describe("타입 정의 테스트", () => {
93
+ it("ProgramOptions 인터페이스가 올바른 타입을 가져야 함", () => {
94
+ interface ProgramOptions {
95
+ github?: boolean;
96
+ }
97
+
98
+ const testOptions: ProgramOptions = {
99
+ github: true,
100
+ };
101
+
102
+ expect(testOptions.github).toBe(true);
103
+ });
104
+
105
+ it("UserAnswer 인터페이스가 올바른 타입을 가져야 함", () => {
106
+ interface UserAnswer {
107
+ showInfo: boolean;
108
+ }
109
+
110
+ const testAnswer: UserAnswer = {
111
+ showInfo: true,
112
+ };
113
+
114
+ expect(testAnswer.showInfo).toBe(true);
115
+ });
116
+ });
117
+
118
+ describe("플랫폼별 명령어 테스트", () => {
119
+ it("Windows에서는 start 명령어를 사용해야 함", () => {
120
+ const getCommand = (platform: string): string => {
121
+ return platform === "win32"
122
+ ? "start"
123
+ : platform === "darwin"
124
+ ? "open"
125
+ : "xdg-open";
126
+ };
127
+
128
+ expect(getCommand("win32")).toBe("start");
129
+ });
130
+
131
+ it("macOS에서는 open 명령어를 사용해야 함", () => {
132
+ const getCommand = (platform: string): string => {
133
+ return platform === "win32"
134
+ ? "start"
135
+ : platform === "darwin"
136
+ ? "open"
137
+ : "xdg-open";
138
+ };
139
+
140
+ expect(getCommand("darwin")).toBe("open");
141
+ });
142
+
143
+ it("Linux에서는 xdg-open 명령어를 사용해야 함", () => {
144
+ const getCommand = (platform: string): string => {
145
+ return platform === "win32"
146
+ ? "start"
147
+ : platform === "darwin"
148
+ ? "open"
149
+ : "xdg-open";
150
+ };
151
+
152
+ expect(getCommand("linux")).toBe("xdg-open");
153
+ });
154
+ });
155
+
156
+ describe("URL 검증 테스트", () => {
157
+ it("GitHub URL이 올바른 형식이어야 함", () => {
158
+ const githubUrl = "https://github.com/alstjd0051";
159
+ expect(githubUrl).toMatch(/^https:\/\/github\.com\/[\w-]+$/);
160
+ });
161
+
162
+ it("이메일 주소가 올바른 형식이어야 함", () => {
163
+ const email = "wsc7202@gmail.com";
164
+ expect(email).toMatch(/^[\w.-]+@[\w.-]+\.\w+$/);
165
+ });
166
+ });
167
+ });
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "noEmit": true
5
+ },
6
+ "include": ["src/**/*", "test/**/*"],
7
+ "exclude": ["node_modules", "dist"]
8
+ }
9
+
package/tsconfig.json CHANGED
@@ -16,5 +16,5 @@
16
16
  "allowSyntheticDefaultImports": true
17
17
  },
18
18
  "include": ["src/**/*"],
19
- "exclude": ["node_modules", "dist"]
19
+ "exclude": ["node_modules", "dist", "test"]
20
20
  }
@@ -0,0 +1,22 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: 'node',
7
+ coverage: {
8
+ provider: 'v8',
9
+ reporter: ['text', 'json', 'html'],
10
+ exclude: [
11
+ 'node_modules/**',
12
+ 'dist/**',
13
+ 'test/**',
14
+ '**/*.config.*',
15
+ '**/*.d.ts',
16
+ ],
17
+ },
18
+ include: ['test/**/*.test.ts'],
19
+ exclude: ['node_modules', 'dist'],
20
+ },
21
+ });
22
+