@rhseung/ps-cli 1.3.3 → 1.4.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,42 +1,41 @@
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
+ openBrowser
4
+ } from "../chunk-QGMWUOJ3.js";
5
+ import {
6
+ Command,
7
+ CommandBuilder,
8
+ CommandDef,
9
+ getProblemId,
10
+ resolveProblemContext
11
+ } from "../chunk-7SVCS23X.js";
12
+ import {
13
+ __decorateClass
14
+ } from "../chunk-7MQMPJ3X.js";
7
15
 
8
16
  // src/commands/open.tsx
9
- import { useState, useEffect } from "react";
10
- import { render, Text, Box } from "ink";
11
17
  import { StatusMessage, Alert } from "@inkjs/ui";
12
18
  import { Spinner } from "@inkjs/ui";
13
- import { execaCommand } from "execa";
14
- import { jsx, jsxs } from "react/jsx-runtime";
19
+ import { Text, Box } from "ink";
20
+
21
+ // src/hooks/use-open-browser.ts
22
+ import { useEffect, useState } from "react";
15
23
  var BOJ_BASE_URL = "https://www.acmicpc.net";
16
- function OpenCommand({ problemId, onComplete }) {
24
+ function useOpenBrowser({
25
+ problemId,
26
+ onComplete
27
+ }) {
17
28
  const [status, setStatus] = useState(
18
29
  "loading"
19
30
  );
20
31
  const [error, setError] = useState(null);
21
32
  const [url, setUrl] = useState("");
22
33
  useEffect(() => {
23
- async function openBrowser() {
34
+ async function handleOpenBrowser() {
24
35
  try {
25
36
  const problemUrl = `${BOJ_BASE_URL}/problem/${problemId}`;
26
37
  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
- });
38
+ await openBrowser(problemUrl);
40
39
  setStatus("success");
41
40
  setTimeout(() => {
42
41
  onComplete?.();
@@ -49,8 +48,22 @@ function OpenCommand({ problemId, onComplete }) {
49
48
  }, 2e3);
50
49
  }
51
50
  }
52
- openBrowser();
51
+ void handleOpenBrowser();
53
52
  }, [problemId, onComplete]);
53
+ return {
54
+ status,
55
+ error,
56
+ url
57
+ };
58
+ }
59
+
60
+ // src/commands/open.tsx
61
+ import { jsx, jsxs } from "react/jsx-runtime";
62
+ function OpenView({ problemId, onComplete }) {
63
+ const { status, error, url } = useOpenBrowser({
64
+ problemId,
65
+ onComplete
66
+ });
54
67
  if (status === "loading") {
55
68
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
56
69
  /* @__PURE__ */ jsx(Spinner, { label: "\uBE0C\uB77C\uC6B0\uC800\uB97C \uC5EC\uB294 \uC911..." }),
@@ -88,62 +101,45 @@ function OpenCommand({ problemId, onComplete }) {
88
101
  ] })
89
102
  ] });
90
103
  }
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
+ var OpenCommand = class extends Command {
105
+ async execute(args, _flags) {
106
+ const problemId = getProblemId(args);
107
+ const context = await resolveProblemContext(
108
+ problemId !== null ? [problemId.toString()] : [],
109
+ { requireId: true }
104
110
  );
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.`
134
- );
135
- process.exit(1);
111
+ if (context.problemId === null) {
112
+ console.error("\uC624\uB958: \uBB38\uC81C \uBC88\uD638\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694.");
113
+ console.error(`\uC0AC\uC6A9\uBC95: ps open <\uBB38\uC81C\uBC88\uD638>`);
114
+ console.error(`\uB3C4\uC6C0\uB9D0: ps open --help`);
115
+ console.error(
116
+ `\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.`
117
+ );
118
+ process.exit(1);
119
+ return;
120
+ }
121
+ await this.renderView(OpenView, {
122
+ problemId: context.problemId
123
+ });
136
124
  }
137
- await openCommand(problemId);
138
- }
139
- var openCommandDef = {
140
- name: "open",
141
- help: openHelp,
142
- execute: openExecute
143
125
  };
144
- var open_default = openCommandDef;
126
+ OpenCommand = __decorateClass([
127
+ CommandDef({
128
+ name: "open",
129
+ description: `\uBC31\uC900 \uBB38\uC81C \uD398\uC774\uC9C0\uB97C \uBE0C\uB77C\uC6B0\uC800\uB85C \uC5FD\uB2C8\uB2E4.
130
+ - \uBB38\uC81C \uBC88\uD638\uB97C \uC778\uC790\uB85C \uC804\uB2EC\uD558\uAC70\uB098
131
+ - \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.`,
132
+ autoDetectProblemId: true,
133
+ requireProblemId: true,
134
+ examples: [
135
+ "open 1000 # 1000\uBC88 \uBB38\uC81C \uC5F4\uAE30",
136
+ "open # \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC2E4\uD589 \uC2DC \uC790\uB3D9 \uCD94\uB860",
137
+ "open --help # \uB3C4\uC6C0\uB9D0 \uD45C\uC2DC"
138
+ ]
139
+ })
140
+ ], OpenCommand);
141
+ var open_default = CommandBuilder.fromClass(OpenCommand);
145
142
  export {
146
- open_default as default,
147
- openExecute,
148
- openHelp
143
+ OpenCommand,
144
+ open_default as default
149
145
  };