@rhseung/ps-cli 1.3.3 → 1.5.0

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.
@@ -1,21 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- getSupportedLanguages
4
- } from "../chunk-TQXMB7XV.js";
5
- import {
3
+ Command,
4
+ CommandBuilder,
5
+ CommandDef,
6
6
  getAutoOpenEditor,
7
7
  getDefaultLanguage,
8
8
  getEditor,
9
9
  getProblemDir,
10
10
  getSolvedAcHandle
11
- } from "../chunk-PNIGP6LX.js";
12
- import "../chunk-FYS2JH42.js";
11
+ } from "../chunk-7SVCS23X.js";
12
+ import {
13
+ __decorateClass,
14
+ getSupportedLanguages
15
+ } from "../chunk-7MQMPJ3X.js";
13
16
 
14
17
  // src/commands/init.tsx
15
- import { useState, useEffect } from "react";
16
- import { render, Text, Box } from "ink";
17
- import { mkdir, readFile, writeFile, access } from "fs/promises";
18
- import { join } from "path";
19
18
  import {
20
19
  Select,
21
20
  TextInput,
@@ -23,9 +22,14 @@ import {
23
22
  Alert,
24
23
  ConfirmInput
25
24
  } from "@inkjs/ui";
26
- import { execaCommand } from "execa";
27
- import { jsx, jsxs } from "react/jsx-runtime";
28
- function InitCommand({ onComplete }) {
25
+ import { Text, Box } from "ink";
26
+
27
+ // src/hooks/use-init.ts
28
+ import { mkdir, readFile, writeFile, access } from "fs/promises";
29
+ import { join } from "path";
30
+ import { execaCommand, execa } from "execa";
31
+ import { useEffect, useState, useCallback } from "react";
32
+ function useInit({ onComplete }) {
29
33
  const [currentStep, setCurrentStep] = useState("problem-dir");
30
34
  const [completedSteps, setCompletedSteps] = useState([]);
31
35
  const [confirmExit, setConfirmExit] = useState(false);
@@ -72,14 +76,14 @@ function InitCommand({ onComplete }) {
72
76
  setAutoOpen(projectConfig.autoOpenEditor);
73
77
  if (projectConfig.solvedAcHandle)
74
78
  setHandle(projectConfig.solvedAcHandle);
75
- } catch (err) {
79
+ } catch {
76
80
  } finally {
77
81
  setInitialized(true);
78
82
  }
79
83
  }
80
- loadProjectConfig();
84
+ void loadProjectConfig();
81
85
  }, []);
82
- function getStepLabel(step) {
86
+ const getStepLabel = useCallback((step) => {
83
87
  switch (step) {
84
88
  case "problem-dir":
85
89
  return "\uBB38\uC81C \uB514\uB809\uD1A0\uB9AC \uC124\uC815";
@@ -94,46 +98,27 @@ function InitCommand({ onComplete }) {
94
98
  default:
95
99
  return "";
96
100
  }
97
- }
98
- function moveToNextStep(selectedValue, stepLabel) {
99
- setCompletedSteps((prev) => [
100
- ...prev,
101
- { label: stepLabel, value: selectedValue }
102
- ]);
103
- const stepOrder = [
104
- "problem-dir",
105
- "language",
106
- "editor",
107
- "auto-open",
108
- "handle",
109
- "done"
110
- ];
111
- const currentIndex = stepOrder.indexOf(currentStep);
112
- if (currentIndex < stepOrder.length - 1) {
113
- const nextStep = stepOrder[currentIndex + 1];
114
- setCurrentStep(nextStep);
115
- if (nextStep === "done") {
116
- void executeInit();
101
+ }, []);
102
+ const getStepValue = useCallback(
103
+ (step) => {
104
+ switch (step) {
105
+ case "problem-dir":
106
+ return problemDir === "." ? "\uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8" : problemDir;
107
+ case "language":
108
+ return language;
109
+ case "editor":
110
+ return editor;
111
+ case "auto-open":
112
+ return autoOpen ? "\uC608" : "\uC544\uB2C8\uC624";
113
+ case "handle":
114
+ return handle || "(\uC2A4\uD0B5)";
115
+ default:
116
+ return "";
117
117
  }
118
- }
119
- }
120
- function getStepValue(step) {
121
- switch (step) {
122
- case "problem-dir":
123
- return problemDir === "." ? "\uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8" : problemDir;
124
- case "language":
125
- return language;
126
- case "editor":
127
- return editor;
128
- case "auto-open":
129
- return autoOpen ? "\uC608" : "\uC544\uB2C8\uC624";
130
- case "handle":
131
- return handle || "(\uC2A4\uD0B5)";
132
- default:
133
- return "";
134
- }
135
- }
136
- async function executeInit() {
118
+ },
119
+ [problemDir, language, editor, autoOpen, handle]
120
+ );
121
+ const executeInit = useCallback(async () => {
137
122
  try {
138
123
  const cwd = process.cwd();
139
124
  const projectConfigPath = join(cwd, ".ps-cli.json");
@@ -209,12 +194,13 @@ ${gitignorePattern}
209
194
  } catch {
210
195
  }
211
196
  if (filesToAdd.length > 0) {
212
- await execaCommand(`git add ${filesToAdd.join(" ")}`, { cwd });
197
+ await execa("git", ["add", ...filesToAdd], { cwd });
213
198
  try {
214
- await execaCommand("git rev-parse --verify HEAD", { cwd });
199
+ await execa("git", ["rev-parse", "--verify", "HEAD"], { cwd });
215
200
  } catch {
216
- await execaCommand(
217
- 'git commit -m "chore: ps-cli \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654"',
201
+ await execa(
202
+ "git",
203
+ ["commit", "-m", "chore: ps-cli \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654"],
218
204
  { cwd }
219
205
  );
220
206
  setCreated((prev) => [...prev, "\uCD08\uAE30 \uCEE4\uBC0B \uC0DD\uC131"]);
@@ -236,7 +222,84 @@ ${gitignorePattern}
236
222
  onComplete();
237
223
  }, 2e3);
238
224
  }
239
- }
225
+ }, [problemDir, language, editor, autoOpen, handle, onComplete]);
226
+ const moveToNextStep = useCallback(
227
+ (selectedValue, stepLabel) => {
228
+ setCompletedSteps((prev) => [
229
+ ...prev,
230
+ { label: stepLabel, value: selectedValue }
231
+ ]);
232
+ const stepOrder = [
233
+ "problem-dir",
234
+ "language",
235
+ "editor",
236
+ "auto-open",
237
+ "handle",
238
+ "done"
239
+ ];
240
+ const currentIndex = stepOrder.indexOf(currentStep);
241
+ if (currentIndex < stepOrder.length - 1) {
242
+ const nextStep = stepOrder[currentIndex + 1];
243
+ setCurrentStep(nextStep);
244
+ if (nextStep === "done") {
245
+ void executeInit();
246
+ }
247
+ }
248
+ },
249
+ [currentStep, executeInit]
250
+ );
251
+ return {
252
+ currentStep,
253
+ completedSteps,
254
+ confirmExit,
255
+ initialized,
256
+ problemDir,
257
+ language,
258
+ editor,
259
+ autoOpen,
260
+ handle,
261
+ handleInputMode,
262
+ created,
263
+ cancelled,
264
+ setProblemDirValue,
265
+ setLanguage,
266
+ setEditorValue,
267
+ setAutoOpen,
268
+ setHandle,
269
+ setHandleInputMode,
270
+ setConfirmExit,
271
+ setCurrentStep,
272
+ setCancelled,
273
+ moveToNextStep,
274
+ getStepLabel,
275
+ getStepValue
276
+ };
277
+ }
278
+
279
+ // src/commands/init.tsx
280
+ import { jsx, jsxs } from "react/jsx-runtime";
281
+ function InitView({ onComplete }) {
282
+ const {
283
+ currentStep,
284
+ completedSteps,
285
+ confirmExit,
286
+ initialized,
287
+ handleInputMode,
288
+ created,
289
+ cancelled,
290
+ setProblemDirValue,
291
+ setLanguage,
292
+ setEditorValue,
293
+ setAutoOpen,
294
+ setHandle,
295
+ setHandleInputMode,
296
+ setConfirmExit,
297
+ setCurrentStep,
298
+ setCancelled,
299
+ moveToNextStep,
300
+ getStepLabel,
301
+ getStepValue: _getStepValue
302
+ } = useInit({ onComplete });
240
303
  function renderQuestionCard(title, children) {
241
304
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
242
305
  /* @__PURE__ */ jsx(Alert, { variant: "info", children: title }),
@@ -426,49 +489,23 @@ ${created.map((item) => `\u2022 ${item}`).join("\n")}` : "";
426
489
  renderStepContent()
427
490
  ] });
428
491
  }
429
- async function initCommand() {
430
- return new Promise((resolve) => {
431
- const { unmount } = render(
432
- /* @__PURE__ */ jsx(
433
- InitCommand,
434
- {
435
- onComplete: () => {
436
- unmount();
437
- resolve();
438
- }
439
- }
440
- )
441
- );
442
- });
443
- }
444
- var initHelp = `
445
- \uC0AC\uC6A9\uBC95:
446
- $ ps init
447
-
448
- \uC124\uBA85:
449
- \uD604\uC7AC \uB514\uB809\uD1A0\uB9AC\uB97C ps-cli \uD504\uB85C\uC81D\uD2B8\uB85C \uB300\uD654\uD615\uC73C\uB85C \uCD08\uAE30\uD654\uD569\uB2C8\uB2E4.
450
- - \uB2E8\uACC4\uBCC4\uB85C \uC124\uC815\uC744 \uBB3C\uC5B4\uBD05\uB2C8\uB2E4
451
- - \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC, \uAE30\uBCF8 \uC5B8\uC5B4, \uC5D0\uB514\uD130 \uB4F1\uC744 \uC124\uC815\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4
452
-
453
- \uC608\uC81C:
454
- $ ps init
455
- `;
456
- async function initExecute(args, flags) {
457
- if (flags.help) {
458
- console.log(initHelp.trim());
459
- process.exit(0);
460
- return;
492
+ var InitCommand = class extends Command {
493
+ async execute(_args, _flags) {
494
+ await this.renderView(InitView, {});
461
495
  }
462
- await initCommand();
463
- }
464
- var initCommandDef = {
465
- name: "init",
466
- help: initHelp,
467
- execute: initExecute
468
496
  };
469
- var init_default = initCommandDef;
497
+ InitCommand = __decorateClass([
498
+ CommandDef({
499
+ name: "init",
500
+ description: `\uD604\uC7AC \uB514\uB809\uD1A0\uB9AC\uB97C ps-cli \uD504\uB85C\uC81D\uD2B8\uB85C \uB300\uD654\uD615\uC73C\uB85C \uCD08\uAE30\uD654\uD569\uB2C8\uB2E4.
501
+ - \uB2E8\uACC4\uBCC4\uB85C \uC124\uC815\uC744 \uBB3C\uC5B4\uBD05\uB2C8\uB2E4
502
+ - \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC, \uAE30\uBCF8 \uC5B8\uC5B4, \uC5D0\uB514\uD130 \uB4F1\uC744 \uC124\uC815\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4`,
503
+ autoDetectProblemId: false,
504
+ examples: ["init"]
505
+ })
506
+ ], InitCommand);
507
+ var init_default = CommandBuilder.fromClass(InitCommand);
470
508
  export {
471
- init_default as default,
472
- initExecute,
473
- initHelp
509
+ InitCommand,
510
+ init_default as default
474
511
  };
@@ -1,56 +1,29 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- getProblemId
4
- } from "../chunk-6ENX5K3C.js";
5
- import "../chunk-PNIGP6LX.js";
6
- import "../chunk-FYS2JH42.js";
3
+ useOpenBrowser
4
+ } from "../chunk-GCOFFYJ3.js";
5
+ import "../chunk-QGMWUOJ3.js";
6
+ import {
7
+ Command,
8
+ CommandBuilder,
9
+ CommandDef,
10
+ getProblemId,
11
+ resolveProblemContext
12
+ } from "../chunk-7SVCS23X.js";
13
+ import {
14
+ __decorateClass
15
+ } from "../chunk-7MQMPJ3X.js";
7
16
 
8
17
  // src/commands/open.tsx
9
- import { useState, useEffect } from "react";
10
- import { render, Text, Box } from "ink";
11
18
  import { StatusMessage, Alert } from "@inkjs/ui";
12
19
  import { Spinner } from "@inkjs/ui";
13
- import { execaCommand } from "execa";
20
+ import { Text, Box } from "ink";
14
21
  import { jsx, jsxs } from "react/jsx-runtime";
15
- var BOJ_BASE_URL = "https://www.acmicpc.net";
16
- function OpenCommand({ problemId, onComplete }) {
17
- const [status, setStatus] = useState(
18
- "loading"
19
- );
20
- const [error, setError] = useState(null);
21
- const [url, setUrl] = useState("");
22
- useEffect(() => {
23
- async function openBrowser() {
24
- try {
25
- const problemUrl = `${BOJ_BASE_URL}/problem/${problemId}`;
26
- setUrl(problemUrl);
27
- let command;
28
- if (process.platform === "win32") {
29
- command = `start "" "${problemUrl}"`;
30
- } else if (process.platform === "darwin") {
31
- command = `open "${problemUrl}"`;
32
- } else {
33
- command = `xdg-open "${problemUrl}"`;
34
- }
35
- await execaCommand(command, {
36
- shell: true,
37
- detached: true,
38
- stdio: "ignore"
39
- });
40
- setStatus("success");
41
- setTimeout(() => {
42
- onComplete?.();
43
- }, 1500);
44
- } catch (err) {
45
- setStatus("error");
46
- setError(err instanceof Error ? err.message : String(err));
47
- setTimeout(() => {
48
- onComplete?.();
49
- }, 2e3);
50
- }
51
- }
52
- openBrowser();
53
- }, [problemId, onComplete]);
22
+ function OpenView({ problemId, onComplete }) {
23
+ const { status, error, url } = useOpenBrowser({
24
+ problemId,
25
+ onComplete
26
+ });
54
27
  if (status === "loading") {
55
28
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
56
29
  /* @__PURE__ */ jsx(Spinner, { label: "\uBE0C\uB77C\uC6B0\uC800\uB97C \uC5EC\uB294 \uC911..." }),
@@ -88,62 +61,45 @@ function OpenCommand({ problemId, onComplete }) {
88
61
  ] })
89
62
  ] });
90
63
  }
91
- async function openCommand(problemId) {
92
- return new Promise((resolve) => {
93
- const { unmount } = render(
94
- /* @__PURE__ */ jsx(
95
- OpenCommand,
96
- {
97
- problemId,
98
- onComplete: () => {
99
- unmount();
100
- resolve();
101
- }
102
- }
103
- )
104
- );
105
- });
106
- }
107
- var openHelp = `
108
- \uC0AC\uC6A9\uBC95:
109
- $ ps open [\uBB38\uC81C\uBC88\uD638]
110
-
111
- \uC124\uBA85:
112
- \uBC31\uC900 \uBB38\uC81C \uD398\uC774\uC9C0\uB97C \uBE0C\uB77C\uC6B0\uC800\uB85C \uC5FD\uB2C8\uB2E4.
113
- - \uBB38\uC81C \uBC88\uD638\uB97C \uC778\uC790\uB85C \uC804\uB2EC\uD558\uAC70\uB098
114
- - \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC2E4\uD589\uD558\uBA74 \uC790\uB3D9\uC73C\uB85C \uBB38\uC81C \uBC88\uD638\uB97C \uCD94\uB860\uD569\uB2C8\uB2E4.
115
-
116
- \uC608\uC81C:
117
- $ ps open 1000 # 1000\uBC88 \uBB38\uC81C \uC5F4\uAE30
118
- $ ps open # \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC2E4\uD589 \uC2DC \uC790\uB3D9 \uCD94\uB860
119
- $ ps open --help # \uB3C4\uC6C0\uB9D0 \uD45C\uC2DC
120
- `;
121
- async function openExecute(args, flags) {
122
- if (flags.help) {
123
- console.log(openHelp.trim());
124
- process.exit(0);
125
- return;
126
- }
127
- const problemId = getProblemId(args);
128
- if (problemId === null) {
129
- console.error("\uC624\uB958: \uBB38\uC81C \uBC88\uD638\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694.");
130
- console.error(`\uC0AC\uC6A9\uBC95: ps open <\uBB38\uC81C\uBC88\uD638>`);
131
- console.error(`\uB3C4\uC6C0\uB9D0: ps open --help`);
132
- console.error(
133
- `\uD78C\uD2B8: problems/{\uBB38\uC81C\uBC88\uD638} \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC2E4\uD589\uD558\uBA74 \uC790\uB3D9\uC73C\uB85C \uBB38\uC81C \uBC88\uD638\uB97C \uCD94\uB860\uD569\uB2C8\uB2E4.`
64
+ var OpenCommand = class extends Command {
65
+ async execute(args, _flags) {
66
+ const problemId = getProblemId(args);
67
+ const context = await resolveProblemContext(
68
+ problemId !== null ? [problemId.toString()] : [],
69
+ { requireId: true }
134
70
  );
135
- process.exit(1);
71
+ if (context.problemId === null) {
72
+ console.error("\uC624\uB958: \uBB38\uC81C \uBC88\uD638\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694.");
73
+ console.error(`\uC0AC\uC6A9\uBC95: ps open <\uBB38\uC81C\uBC88\uD638>`);
74
+ console.error(`\uB3C4\uC6C0\uB9D0: ps open --help`);
75
+ console.error(
76
+ `\uD78C\uD2B8: problems/{\uBB38\uC81C\uBC88\uD638} \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC2E4\uD589\uD558\uBA74 \uC790\uB3D9\uC73C\uB85C \uBB38\uC81C \uBC88\uD638\uB97C \uCD94\uB860\uD569\uB2C8\uB2E4.`
77
+ );
78
+ process.exit(1);
79
+ return;
80
+ }
81
+ await this.renderView(OpenView, {
82
+ problemId: context.problemId
83
+ });
136
84
  }
137
- await openCommand(problemId);
138
- }
139
- var openCommandDef = {
140
- name: "open",
141
- help: openHelp,
142
- execute: openExecute
143
85
  };
144
- var open_default = openCommandDef;
86
+ OpenCommand = __decorateClass([
87
+ CommandDef({
88
+ name: "open",
89
+ description: `\uBC31\uC900 \uBB38\uC81C \uD398\uC774\uC9C0\uB97C \uBE0C\uB77C\uC6B0\uC800\uB85C \uC5FD\uB2C8\uB2E4.
90
+ - \uBB38\uC81C \uBC88\uD638\uB97C \uC778\uC790\uB85C \uC804\uB2EC\uD558\uAC70\uB098
91
+ - \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC2E4\uD589\uD558\uBA74 \uC790\uB3D9\uC73C\uB85C \uBB38\uC81C \uBC88\uD638\uB97C \uCD94\uB860\uD569\uB2C8\uB2E4.`,
92
+ autoDetectProblemId: true,
93
+ requireProblemId: true,
94
+ examples: [
95
+ "open 1000 # 1000\uBC88 \uBB38\uC81C \uC5F4\uAE30",
96
+ "open # \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC2E4\uD589 \uC2DC \uC790\uB3D9 \uCD94\uB860",
97
+ "open --help # \uB3C4\uC6C0\uB9D0 \uD45C\uC2DC"
98
+ ]
99
+ })
100
+ ], OpenCommand);
101
+ var open_default = CommandBuilder.fromClass(OpenCommand);
145
102
  export {
146
- open_default as default,
147
- openExecute,
148
- openHelp
103
+ OpenCommand,
104
+ open_default as default
149
105
  };