@rhseung/ps-cli 1.0.0 → 1.3.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.
- package/README.md +60 -7
- package/dist/chunk-BM3ZMA4K.js +65 -0
- package/dist/{chunk-KFQFQJYT.js → chunk-CIG2LEJC.js} +57 -24
- package/dist/commands/config.js +342 -119
- package/dist/commands/fetch.js +13 -13
- package/dist/commands/init.js +438 -0
- package/dist/commands/run.js +14 -16
- package/dist/commands/stats.js +11 -12
- package/dist/commands/submit.js +21 -39
- package/dist/commands/test.js +22 -58
- package/dist/index.js +25 -0
- package/package.json +6 -4
- package/dist/chunk-IJLJBKLK.js +0 -1689
- package/dist/chunk-OOTPZD7O.js +0 -42
package/README.md
CHANGED
|
@@ -36,6 +36,31 @@ bunx @rhseung/ps-cli fetch 1000
|
|
|
36
36
|
|
|
37
37
|
## 명령어
|
|
38
38
|
|
|
39
|
+
### `init` - 프로젝트 초기화
|
|
40
|
+
|
|
41
|
+
현재 디렉토리를 ps-cli 프로젝트로 초기화합니다.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
ps init
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**기능:**
|
|
48
|
+
|
|
49
|
+
- `problems/` 디렉토리 생성
|
|
50
|
+
- `.gitignore`에 `problems/` 추가 (이미 있으면 스킵)
|
|
51
|
+
|
|
52
|
+
**예제:**
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# 프로젝트 폴더에서 초기화
|
|
56
|
+
mkdir my-algorithm-problems
|
|
57
|
+
cd my-algorithm-problems
|
|
58
|
+
ps init
|
|
59
|
+
|
|
60
|
+
# 이제 문제를 가져올 수 있습니다
|
|
61
|
+
ps fetch 1000
|
|
62
|
+
```
|
|
63
|
+
|
|
39
64
|
### `fetch` - 문제 가져오기
|
|
40
65
|
|
|
41
66
|
백준 문제를 가져와서 로컬에 파일을 생성합니다.
|
|
@@ -206,6 +231,7 @@ ps config --list
|
|
|
206
231
|
- `editor`: 에디터 명령어 (예: code, vim, nano)
|
|
207
232
|
- `auto-open-editor`: fetch 후 자동으로 에디터 열기 (true/false)
|
|
208
233
|
- `solved-ac-handle`: Solved.ac 핸들 (stats 명령어용)
|
|
234
|
+
- `problem-dir`: 문제 디렉토리 경로 (기본값: `problems`, `"."` 또는 `""`는 프로젝트 루트에 직접 저장)
|
|
209
235
|
|
|
210
236
|
**옵션:**
|
|
211
237
|
|
|
@@ -247,24 +273,27 @@ ps <명령어> --help
|
|
|
247
273
|
### 전체 워크플로우
|
|
248
274
|
|
|
249
275
|
```bash
|
|
250
|
-
# 1.
|
|
276
|
+
# 1. 프로젝트 초기화 (최초 1회)
|
|
277
|
+
ps init
|
|
278
|
+
|
|
279
|
+
# 2. 문제 가져오기
|
|
251
280
|
ps fetch 1000 --language python
|
|
252
281
|
|
|
253
|
-
#
|
|
282
|
+
# 3. 문제 디렉토리로 이동
|
|
254
283
|
cd problems/1000
|
|
255
284
|
|
|
256
|
-
#
|
|
285
|
+
# 4. 코드 작성 (solution.py 편집)
|
|
257
286
|
|
|
258
|
-
#
|
|
287
|
+
# 5. 로컬 테스트
|
|
259
288
|
ps test
|
|
260
289
|
|
|
261
|
-
#
|
|
290
|
+
# 6. Watch 모드로 개발 (파일 저장 시 자동 테스트)
|
|
262
291
|
ps test --watch
|
|
263
292
|
|
|
264
|
-
#
|
|
293
|
+
# 7. 단일 입력으로 실행 테스트
|
|
265
294
|
ps run
|
|
266
295
|
|
|
267
|
-
#
|
|
296
|
+
# 8. BOJ에 제출
|
|
268
297
|
ps submit
|
|
269
298
|
```
|
|
270
299
|
|
|
@@ -283,6 +312,30 @@ ps config solved-ac-handle myhandle
|
|
|
283
312
|
# fetch 후 자동으로 VS Code 열기
|
|
284
313
|
ps config editor code
|
|
285
314
|
ps config auto-open-editor true
|
|
315
|
+
|
|
316
|
+
# 문제 디렉토리 설정
|
|
317
|
+
ps config problem-dir "problems" # problems 디렉토리 사용 (기본값)
|
|
318
|
+
ps config problem-dir "." # 프로젝트 루트에 직접 저장
|
|
319
|
+
ps config problem-dir "solutions" # solutions 디렉토리 사용
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### 문제 디렉토리 설정
|
|
323
|
+
|
|
324
|
+
`problem-dir` 설정을 통해 문제 파일이 저장되는 위치를 변경할 수 있습니다:
|
|
325
|
+
|
|
326
|
+
- **기본값 (`problems`)**: `problems/{문제번호}/` 형식으로 저장
|
|
327
|
+
- **프로젝트 루트 (`"."` 또는 `""`)**: 프로젝트 루트에 `{문제번호}/` 형식으로 직접 저장
|
|
328
|
+
|
|
329
|
+
**예제:**
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
# 프로젝트 루트에 직접 저장하도록 설정
|
|
333
|
+
ps config problem-dir "."
|
|
334
|
+
|
|
335
|
+
# 문제 가져오기 (프로젝트 루트에 1000/ 디렉토리 생성)
|
|
336
|
+
ps fetch 1000
|
|
337
|
+
|
|
338
|
+
# 결과: ./1000/solution.py, ./1000/input1.txt 등
|
|
286
339
|
```
|
|
287
340
|
|
|
288
341
|
## 라이선스
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getProblemDir
|
|
4
|
+
} from "./chunk-CIG2LEJC.js";
|
|
5
|
+
|
|
6
|
+
// src/utils/problem-id.ts
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
function detectProblemIdFromPath(cwd = process.cwd()) {
|
|
9
|
+
const problemDir = getProblemDir();
|
|
10
|
+
const normalizedPath = cwd.replace(/\\/g, "/");
|
|
11
|
+
if (problemDir === "." || problemDir === "") {
|
|
12
|
+
const segments = normalizedPath.split("/").filter(Boolean);
|
|
13
|
+
const lastSegment = segments[segments.length - 1];
|
|
14
|
+
if (lastSegment) {
|
|
15
|
+
const problemId2 = parseInt(lastSegment, 10);
|
|
16
|
+
if (!isNaN(problemId2) && problemId2 > 0 && lastSegment === problemId2.toString()) {
|
|
17
|
+
return problemId2;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const dirPattern = `/${problemDir}/`;
|
|
23
|
+
const dirIndex = normalizedPath.indexOf(dirPattern);
|
|
24
|
+
if (dirIndex === -1) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const afterDir = normalizedPath.substring(dirIndex + dirPattern.length);
|
|
28
|
+
if (!afterDir) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const firstSegment = afterDir.split("/")[0];
|
|
32
|
+
if (!firstSegment) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const problemId = parseInt(firstSegment, 10);
|
|
36
|
+
if (isNaN(problemId) || problemId <= 0) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
if (firstSegment !== problemId.toString()) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return problemId;
|
|
43
|
+
}
|
|
44
|
+
function getProblemId(args, cwd = process.cwd()) {
|
|
45
|
+
if (args.length > 0 && args[0]) {
|
|
46
|
+
const problemId = parseInt(args[0], 10);
|
|
47
|
+
if (!isNaN(problemId) && problemId > 0) {
|
|
48
|
+
return problemId;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return detectProblemIdFromPath(cwd);
|
|
52
|
+
}
|
|
53
|
+
function getProblemDirPath(problemId, cwd = process.cwd()) {
|
|
54
|
+
const problemDir = getProblemDir();
|
|
55
|
+
if (problemDir === "." || problemDir === "") {
|
|
56
|
+
return join(cwd, problemId.toString());
|
|
57
|
+
}
|
|
58
|
+
return join(cwd, problemDir, problemId.toString());
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export {
|
|
62
|
+
detectProblemIdFromPath,
|
|
63
|
+
getProblemId,
|
|
64
|
+
getProblemDirPath
|
|
65
|
+
};
|
|
@@ -9878,6 +9878,8 @@ var Conf = class {
|
|
|
9878
9878
|
};
|
|
9879
9879
|
|
|
9880
9880
|
// src/utils/config.ts
|
|
9881
|
+
import { readFileSync, existsSync } from "fs";
|
|
9882
|
+
import { join } from "path";
|
|
9881
9883
|
var config = new Conf({
|
|
9882
9884
|
projectName: "ps-cli",
|
|
9883
9885
|
defaults: {
|
|
@@ -9888,9 +9890,40 @@ var config = new Conf({
|
|
|
9888
9890
|
// 기본값: VS Code
|
|
9889
9891
|
autoOpenEditor: false,
|
|
9890
9892
|
// 기본값: 자동 열기 비활성화
|
|
9891
|
-
solvedAcHandle: void 0
|
|
9893
|
+
solvedAcHandle: void 0,
|
|
9894
|
+
problemDir: "problems"
|
|
9895
|
+
// 기본값: problems 디렉토리
|
|
9892
9896
|
}
|
|
9893
9897
|
});
|
|
9898
|
+
var projectConfigCache = null;
|
|
9899
|
+
var projectConfigCachePath = null;
|
|
9900
|
+
function getProjectConfigSync() {
|
|
9901
|
+
try {
|
|
9902
|
+
const cwd = process.cwd();
|
|
9903
|
+
const projectConfigPath = join(cwd, ".ps-cli.json");
|
|
9904
|
+
if (projectConfigCache && projectConfigCachePath === projectConfigPath) {
|
|
9905
|
+
return projectConfigCache;
|
|
9906
|
+
}
|
|
9907
|
+
if (!existsSync(projectConfigPath)) {
|
|
9908
|
+
projectConfigCache = null;
|
|
9909
|
+
projectConfigCachePath = null;
|
|
9910
|
+
return null;
|
|
9911
|
+
}
|
|
9912
|
+
try {
|
|
9913
|
+
const content = readFileSync(projectConfigPath, "utf-8");
|
|
9914
|
+
const projectConfig = JSON.parse(content);
|
|
9915
|
+
projectConfigCache = projectConfig;
|
|
9916
|
+
projectConfigCachePath = projectConfigPath;
|
|
9917
|
+
return projectConfig;
|
|
9918
|
+
} catch {
|
|
9919
|
+
projectConfigCache = null;
|
|
9920
|
+
projectConfigCachePath = null;
|
|
9921
|
+
return null;
|
|
9922
|
+
}
|
|
9923
|
+
} catch {
|
|
9924
|
+
return null;
|
|
9925
|
+
}
|
|
9926
|
+
}
|
|
9894
9927
|
function getBojSessionCookie() {
|
|
9895
9928
|
const envCookie = process.env.PS_CLI_BOJ_COOKIE;
|
|
9896
9929
|
if (envCookie) {
|
|
@@ -9898,51 +9931,51 @@ function getBojSessionCookie() {
|
|
|
9898
9931
|
}
|
|
9899
9932
|
return config.get("bojSessionCookie");
|
|
9900
9933
|
}
|
|
9901
|
-
function setBojSessionCookie(cookie) {
|
|
9902
|
-
config.set("bojSessionCookie", cookie);
|
|
9903
|
-
}
|
|
9904
9934
|
function getDefaultLanguage() {
|
|
9935
|
+
const projectConfig = getProjectConfigSync();
|
|
9936
|
+
if (projectConfig?.defaultLanguage) {
|
|
9937
|
+
return projectConfig.defaultLanguage;
|
|
9938
|
+
}
|
|
9905
9939
|
return config.get("defaultLanguage") ?? "python";
|
|
9906
9940
|
}
|
|
9907
|
-
function setDefaultLanguage(language) {
|
|
9908
|
-
config.set("defaultLanguage", language);
|
|
9909
|
-
}
|
|
9910
9941
|
function getCodeOpen() {
|
|
9911
9942
|
return config.get("codeOpen") ?? false;
|
|
9912
9943
|
}
|
|
9913
|
-
function setCodeOpen(open) {
|
|
9914
|
-
config.set("codeOpen", open);
|
|
9915
|
-
}
|
|
9916
9944
|
function getEditor() {
|
|
9945
|
+
const projectConfig = getProjectConfigSync();
|
|
9946
|
+
if (projectConfig?.editor) {
|
|
9947
|
+
return projectConfig.editor;
|
|
9948
|
+
}
|
|
9917
9949
|
return config.get("editor") ?? "code";
|
|
9918
9950
|
}
|
|
9919
|
-
function setEditor(editor) {
|
|
9920
|
-
config.set("editor", editor);
|
|
9921
|
-
}
|
|
9922
9951
|
function getAutoOpenEditor() {
|
|
9952
|
+
const projectConfig = getProjectConfigSync();
|
|
9953
|
+
if (projectConfig?.autoOpenEditor !== void 0) {
|
|
9954
|
+
return projectConfig.autoOpenEditor;
|
|
9955
|
+
}
|
|
9923
9956
|
return config.get("autoOpenEditor") ?? false;
|
|
9924
9957
|
}
|
|
9925
|
-
function setAutoOpenEditor(enabled) {
|
|
9926
|
-
config.set("autoOpenEditor", enabled);
|
|
9927
|
-
}
|
|
9928
9958
|
function getSolvedAcHandle() {
|
|
9959
|
+
const projectConfig = getProjectConfigSync();
|
|
9960
|
+
if (projectConfig?.solvedAcHandle) {
|
|
9961
|
+
return projectConfig.solvedAcHandle;
|
|
9962
|
+
}
|
|
9929
9963
|
return config.get("solvedAcHandle");
|
|
9930
9964
|
}
|
|
9931
|
-
function
|
|
9932
|
-
|
|
9965
|
+
function getProblemDir() {
|
|
9966
|
+
const projectConfig = getProjectConfigSync();
|
|
9967
|
+
if (projectConfig?.problemDir !== void 0) {
|
|
9968
|
+
return projectConfig.problemDir;
|
|
9969
|
+
}
|
|
9970
|
+
return config.get("problemDir") ?? "problems";
|
|
9933
9971
|
}
|
|
9934
9972
|
|
|
9935
9973
|
export {
|
|
9936
9974
|
getBojSessionCookie,
|
|
9937
|
-
setBojSessionCookie,
|
|
9938
9975
|
getDefaultLanguage,
|
|
9939
|
-
setDefaultLanguage,
|
|
9940
9976
|
getCodeOpen,
|
|
9941
|
-
setCodeOpen,
|
|
9942
9977
|
getEditor,
|
|
9943
|
-
setEditor,
|
|
9944
9978
|
getAutoOpenEditor,
|
|
9945
|
-
setAutoOpenEditor,
|
|
9946
9979
|
getSolvedAcHandle,
|
|
9947
|
-
|
|
9980
|
+
getProblemDir
|
|
9948
9981
|
};
|