@rhseung/ps-cli 1.6.0 → 1.7.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/dist/chunk-A6STXEAE.js +54 -0
- package/dist/{chunk-RVD22OUQ.js → chunk-TNGUME4H.js} +332 -11
- package/dist/commands/config.js +32 -2
- package/dist/commands/fetch.js +9 -8
- package/dist/commands/init.js +209 -117
- package/dist/commands/open.js +1 -1
- package/dist/commands/run.js +1 -1
- package/dist/commands/search.js +7 -7
- package/dist/commands/solve.js +42 -4
- package/dist/commands/stats.js +7 -7
- package/dist/commands/submit.js +1 -1
- package/dist/commands/test.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-NH36IFWR.js +0 -255
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/services/solved-api.ts
|
|
4
|
+
var BASE_URL = "https://solved.ac/api/v3";
|
|
5
|
+
var USER_AGENT = "ps-cli/1.0.0";
|
|
6
|
+
async function fetchWithRetry(url, options = {}, maxRetries = 3) {
|
|
7
|
+
let lastError = null;
|
|
8
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
9
|
+
try {
|
|
10
|
+
const response = await fetch(url, {
|
|
11
|
+
...options,
|
|
12
|
+
headers: {
|
|
13
|
+
"User-Agent": USER_AGENT,
|
|
14
|
+
...options.headers
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
if (response.status === 429) {
|
|
18
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
19
|
+
const waitTime = retryAfter ? parseInt(retryAfter, 10) * 1e3 : (attempt + 1) * 1e3;
|
|
20
|
+
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
25
|
+
}
|
|
26
|
+
return response;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
29
|
+
if (attempt < maxRetries - 1) {
|
|
30
|
+
await new Promise(
|
|
31
|
+
(resolve) => setTimeout(resolve, (attempt + 1) * 1e3)
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
throw lastError || new Error("Request failed after retries");
|
|
37
|
+
}
|
|
38
|
+
async function getProblem(problemId) {
|
|
39
|
+
const url = `${BASE_URL}/problem/show?problemId=${problemId}`;
|
|
40
|
+
const response = await fetchWithRetry(url);
|
|
41
|
+
const data = await response.json();
|
|
42
|
+
return data;
|
|
43
|
+
}
|
|
44
|
+
async function getUserStats(handle) {
|
|
45
|
+
const url = `${BASE_URL}/user/show?handle=${handle}`;
|
|
46
|
+
const response = await fetchWithRetry(url);
|
|
47
|
+
const data = await response.json();
|
|
48
|
+
return data;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export {
|
|
52
|
+
getProblem,
|
|
53
|
+
getUserStats
|
|
54
|
+
};
|
|
@@ -10023,12 +10023,250 @@ function getSolvingDir() {
|
|
|
10023
10023
|
}
|
|
10024
10024
|
return config.get("solvingDir") ?? "solving";
|
|
10025
10025
|
}
|
|
10026
|
+
function getArchiveStrategy() {
|
|
10027
|
+
const projectConfig = getProjectConfigSync();
|
|
10028
|
+
if (projectConfig?.archiveStrategy !== void 0) {
|
|
10029
|
+
return projectConfig.archiveStrategy;
|
|
10030
|
+
}
|
|
10031
|
+
return config.get("archiveStrategy") ?? "flat";
|
|
10032
|
+
}
|
|
10033
|
+
|
|
10034
|
+
// src/utils/tier.ts
|
|
10035
|
+
import gradient from "gradient-string";
|
|
10036
|
+
var TIER_NAMES = [
|
|
10037
|
+
void 0,
|
|
10038
|
+
"Bronze V",
|
|
10039
|
+
"Bronze IV",
|
|
10040
|
+
"Bronze III",
|
|
10041
|
+
"Bronze II",
|
|
10042
|
+
"Bronze I",
|
|
10043
|
+
"Silver V",
|
|
10044
|
+
"Silver IV",
|
|
10045
|
+
"Silver III",
|
|
10046
|
+
"Silver II",
|
|
10047
|
+
"Silver I",
|
|
10048
|
+
"Gold V",
|
|
10049
|
+
"Gold IV",
|
|
10050
|
+
"Gold III",
|
|
10051
|
+
"Gold II",
|
|
10052
|
+
"Gold I",
|
|
10053
|
+
"Platinum V",
|
|
10054
|
+
"Platinum IV",
|
|
10055
|
+
"Platinum III",
|
|
10056
|
+
"Platinum II",
|
|
10057
|
+
"Platinum I",
|
|
10058
|
+
"Diamond V",
|
|
10059
|
+
"Diamond IV",
|
|
10060
|
+
"Diamond III",
|
|
10061
|
+
"Diamond II",
|
|
10062
|
+
"Diamond I",
|
|
10063
|
+
"Ruby V",
|
|
10064
|
+
"Ruby IV",
|
|
10065
|
+
"Ruby III",
|
|
10066
|
+
"Ruby II",
|
|
10067
|
+
"Ruby I",
|
|
10068
|
+
"Master"
|
|
10069
|
+
];
|
|
10070
|
+
var TIER_COLORS = [
|
|
10071
|
+
void 0,
|
|
10072
|
+
"#9d4900",
|
|
10073
|
+
"#a54f00",
|
|
10074
|
+
"#ad5600",
|
|
10075
|
+
"#b55d0a",
|
|
10076
|
+
"#c67739",
|
|
10077
|
+
"#38546e",
|
|
10078
|
+
"#3d5a74",
|
|
10079
|
+
"#435f7a",
|
|
10080
|
+
"#496580",
|
|
10081
|
+
"#4e6a86",
|
|
10082
|
+
"#d28500",
|
|
10083
|
+
"#df8f00",
|
|
10084
|
+
"#ec9a00",
|
|
10085
|
+
"#f9a518",
|
|
10086
|
+
"#ffb028",
|
|
10087
|
+
"#00c78b",
|
|
10088
|
+
"#00d497",
|
|
10089
|
+
"#27e2a4",
|
|
10090
|
+
"#3ef0b1",
|
|
10091
|
+
"#51fdbd",
|
|
10092
|
+
"#009ee5",
|
|
10093
|
+
"#00a9f0",
|
|
10094
|
+
"#00b4fc",
|
|
10095
|
+
"#2bbfff",
|
|
10096
|
+
"#41caff",
|
|
10097
|
+
"#e0004c",
|
|
10098
|
+
"#ea0053",
|
|
10099
|
+
"#f5005a",
|
|
10100
|
+
"#ff0062",
|
|
10101
|
+
"#ff3071",
|
|
10102
|
+
"#b300e0"
|
|
10103
|
+
];
|
|
10104
|
+
var TIER_IMAGE_BASE_URL = "https://d2gd6pc034wcta.cloudfront.net/tier";
|
|
10105
|
+
var MASTER_TIER_GRADIENT = [
|
|
10106
|
+
{ r: 255, g: 124, b: 168 },
|
|
10107
|
+
{ r: 180, g: 145, b: 255 },
|
|
10108
|
+
{ r: 124, g: 249, b: 255 }
|
|
10109
|
+
];
|
|
10110
|
+
var TIER_MIN_RATINGS = [
|
|
10111
|
+
0,
|
|
10112
|
+
// Unrated (tier 0): 0-29
|
|
10113
|
+
30,
|
|
10114
|
+
// Bronze V (tier 1)
|
|
10115
|
+
60,
|
|
10116
|
+
// Bronze IV (tier 2)
|
|
10117
|
+
90,
|
|
10118
|
+
// Bronze III (tier 3)
|
|
10119
|
+
120,
|
|
10120
|
+
// Bronze II (tier 4)
|
|
10121
|
+
150,
|
|
10122
|
+
// Bronze I (tier 5)
|
|
10123
|
+
200,
|
|
10124
|
+
// Silver V (tier 6)
|
|
10125
|
+
300,
|
|
10126
|
+
// Silver IV (tier 7)
|
|
10127
|
+
400,
|
|
10128
|
+
// Silver III (tier 8)
|
|
10129
|
+
500,
|
|
10130
|
+
// Silver II (tier 9)
|
|
10131
|
+
650,
|
|
10132
|
+
// Silver I (tier 10)
|
|
10133
|
+
800,
|
|
10134
|
+
// Gold V (tier 11)
|
|
10135
|
+
950,
|
|
10136
|
+
// Gold IV (tier 12)
|
|
10137
|
+
1100,
|
|
10138
|
+
// Gold III (tier 13)
|
|
10139
|
+
1250,
|
|
10140
|
+
// Gold II (tier 14)
|
|
10141
|
+
1400,
|
|
10142
|
+
// Gold I (tier 15)
|
|
10143
|
+
1600,
|
|
10144
|
+
// Platinum V (tier 16)
|
|
10145
|
+
1750,
|
|
10146
|
+
// Platinum IV (tier 17)
|
|
10147
|
+
1900,
|
|
10148
|
+
// Platinum III (tier 18)
|
|
10149
|
+
2e3,
|
|
10150
|
+
// Platinum II (tier 19)
|
|
10151
|
+
2100,
|
|
10152
|
+
// Platinum I (tier 20)
|
|
10153
|
+
2200,
|
|
10154
|
+
// Diamond V (tier 21)
|
|
10155
|
+
2300,
|
|
10156
|
+
// Diamond IV (tier 22)
|
|
10157
|
+
2400,
|
|
10158
|
+
// Diamond III (tier 23)
|
|
10159
|
+
2500,
|
|
10160
|
+
// Diamond II (tier 24)
|
|
10161
|
+
2600,
|
|
10162
|
+
// Diamond I (tier 25)
|
|
10163
|
+
2700,
|
|
10164
|
+
// Ruby V (tier 26)
|
|
10165
|
+
2800,
|
|
10166
|
+
// Ruby IV (tier 27)
|
|
10167
|
+
2850,
|
|
10168
|
+
// Ruby III (tier 28)
|
|
10169
|
+
2900,
|
|
10170
|
+
// Ruby II (tier 29)
|
|
10171
|
+
2950,
|
|
10172
|
+
// Ruby I (tier 30)
|
|
10173
|
+
3e3
|
|
10174
|
+
// Master (tier 31)
|
|
10175
|
+
];
|
|
10176
|
+
function getTierMinRating(tier) {
|
|
10177
|
+
if (tier >= 0 && tier < TIER_MIN_RATINGS.length) {
|
|
10178
|
+
return TIER_MIN_RATINGS[tier] ?? 0;
|
|
10179
|
+
}
|
|
10180
|
+
return 0;
|
|
10181
|
+
}
|
|
10182
|
+
function getNextTierMinRating(tier) {
|
|
10183
|
+
if (tier === 31) {
|
|
10184
|
+
return null;
|
|
10185
|
+
}
|
|
10186
|
+
if (tier >= 0 && tier < TIER_MIN_RATINGS.length - 1) {
|
|
10187
|
+
return TIER_MIN_RATINGS[tier + 1] ?? null;
|
|
10188
|
+
}
|
|
10189
|
+
return null;
|
|
10190
|
+
}
|
|
10191
|
+
function calculateTierProgress(currentRating, tier) {
|
|
10192
|
+
if (tier === 31) {
|
|
10193
|
+
return 100;
|
|
10194
|
+
}
|
|
10195
|
+
const currentTierMin = getTierMinRating(tier);
|
|
10196
|
+
const nextTierMin = getNextTierMinRating(tier);
|
|
10197
|
+
if (nextTierMin === null) {
|
|
10198
|
+
return 100;
|
|
10199
|
+
}
|
|
10200
|
+
if (currentRating < currentTierMin) {
|
|
10201
|
+
return 0;
|
|
10202
|
+
}
|
|
10203
|
+
if (currentRating >= nextTierMin) {
|
|
10204
|
+
return 100;
|
|
10205
|
+
}
|
|
10206
|
+
const progress = (currentRating - currentTierMin) / (nextTierMin - currentTierMin) * 100;
|
|
10207
|
+
return Math.max(0, Math.min(100, progress));
|
|
10208
|
+
}
|
|
10209
|
+
function getTierName(level) {
|
|
10210
|
+
if (level === 0) return "Unrated";
|
|
10211
|
+
if (level >= 1 && level < TIER_NAMES.length) {
|
|
10212
|
+
return TIER_NAMES[level] || "Unrated";
|
|
10213
|
+
}
|
|
10214
|
+
return "Unrated";
|
|
10215
|
+
}
|
|
10216
|
+
function getTierColor(level) {
|
|
10217
|
+
if (level === 0) return "#2d2d2d";
|
|
10218
|
+
if (level === 31) {
|
|
10219
|
+
return gradient([...MASTER_TIER_GRADIENT]);
|
|
10220
|
+
}
|
|
10221
|
+
if (level >= 1 && level < TIER_COLORS.length) {
|
|
10222
|
+
return TIER_COLORS[level] || "#2d2d2d";
|
|
10223
|
+
}
|
|
10224
|
+
return "#2d2d2d";
|
|
10225
|
+
}
|
|
10226
|
+
function getTierImageUrl(level) {
|
|
10227
|
+
return `${TIER_IMAGE_BASE_URL}/${level}.svg`;
|
|
10228
|
+
}
|
|
10026
10229
|
|
|
10027
10230
|
// src/utils/problem-id.ts
|
|
10028
10231
|
import { join as join2 } from "path";
|
|
10232
|
+
function sanitizeFileName(name) {
|
|
10233
|
+
return name.replace(/[<>:"/\\|?*]/g, "").replace(/\s+/g, "-").toLowerCase().trim();
|
|
10234
|
+
}
|
|
10235
|
+
function getTierDirName(level) {
|
|
10236
|
+
const tierName = getTierName(level);
|
|
10237
|
+
if (tierName === "Unrated") {
|
|
10238
|
+
return "unrated";
|
|
10239
|
+
}
|
|
10240
|
+
return sanitizeFileName(tierName);
|
|
10241
|
+
}
|
|
10242
|
+
function getArchiveSubPath(problemId, strategy = "flat", problem) {
|
|
10243
|
+
switch (strategy) {
|
|
10244
|
+
case "flat":
|
|
10245
|
+
return "";
|
|
10246
|
+
case "by-range": {
|
|
10247
|
+
const range = Math.floor(problemId / 1e3) * 1e3;
|
|
10248
|
+
return String(range).padStart(5, "0");
|
|
10249
|
+
}
|
|
10250
|
+
case "by-tier": {
|
|
10251
|
+
if (!problem) {
|
|
10252
|
+
return "";
|
|
10253
|
+
}
|
|
10254
|
+
return getTierDirName(problem.level);
|
|
10255
|
+
}
|
|
10256
|
+
case "by-tag": {
|
|
10257
|
+
if (!problem || !problem.tags || problem.tags.length === 0) {
|
|
10258
|
+
return "";
|
|
10259
|
+
}
|
|
10260
|
+
return sanitizeFileName(problem.tags[0]);
|
|
10261
|
+
}
|
|
10262
|
+
default:
|
|
10263
|
+
return "";
|
|
10264
|
+
}
|
|
10265
|
+
}
|
|
10029
10266
|
function detectProblemIdFromPath(cwd = process.cwd()) {
|
|
10030
10267
|
const problemDir = getProblemDir();
|
|
10031
10268
|
const solvingDir = getSolvingDir();
|
|
10269
|
+
const archiveStrategy = getArchiveStrategy();
|
|
10032
10270
|
const normalizedPath = cwd.replace(/\\/g, "/");
|
|
10033
10271
|
const dirsToCheck = [problemDir, solvingDir].filter(
|
|
10034
10272
|
(dir) => dir && dir !== "." && dir !== ""
|
|
@@ -10054,18 +10292,61 @@ function detectProblemIdFromPath(cwd = process.cwd()) {
|
|
|
10054
10292
|
if (!afterDir) {
|
|
10055
10293
|
continue;
|
|
10056
10294
|
}
|
|
10057
|
-
const
|
|
10058
|
-
if (
|
|
10295
|
+
const segments = afterDir.split("/").filter(Boolean);
|
|
10296
|
+
if (segments.length === 0) {
|
|
10059
10297
|
continue;
|
|
10060
10298
|
}
|
|
10061
|
-
|
|
10062
|
-
if (
|
|
10063
|
-
|
|
10299
|
+
let problemId = null;
|
|
10300
|
+
if (archiveStrategy === "flat") {
|
|
10301
|
+
const firstSegment = segments[0];
|
|
10302
|
+
if (firstSegment) {
|
|
10303
|
+
const id = parseInt(firstSegment, 10);
|
|
10304
|
+
if (!isNaN(id) && id > 0 && firstSegment === id.toString() && segments.length === 1) {
|
|
10305
|
+
problemId = id;
|
|
10306
|
+
}
|
|
10307
|
+
}
|
|
10308
|
+
} else if (archiveStrategy === "by-range") {
|
|
10309
|
+
if (segments.length === 2) {
|
|
10310
|
+
const secondSegment = segments[1];
|
|
10311
|
+
if (secondSegment) {
|
|
10312
|
+
const id = parseInt(secondSegment, 10);
|
|
10313
|
+
if (!isNaN(id) && id > 0 && secondSegment === id.toString()) {
|
|
10314
|
+
problemId = id;
|
|
10315
|
+
}
|
|
10316
|
+
}
|
|
10317
|
+
}
|
|
10318
|
+
} else if (archiveStrategy === "by-tier" || archiveStrategy === "by-tag") {
|
|
10319
|
+
if (segments.length === 2) {
|
|
10320
|
+
const secondSegment = segments[1];
|
|
10321
|
+
if (secondSegment) {
|
|
10322
|
+
const id = parseInt(secondSegment, 10);
|
|
10323
|
+
if (!isNaN(id) && id > 0 && secondSegment === id.toString()) {
|
|
10324
|
+
problemId = id;
|
|
10325
|
+
}
|
|
10326
|
+
}
|
|
10327
|
+
}
|
|
10064
10328
|
}
|
|
10065
|
-
if (
|
|
10066
|
-
|
|
10329
|
+
if (!problemId) {
|
|
10330
|
+
const lastSegment = segments[segments.length - 1];
|
|
10331
|
+
if (lastSegment) {
|
|
10332
|
+
const id = parseInt(lastSegment, 10);
|
|
10333
|
+
if (!isNaN(id) && id > 0 && lastSegment === id.toString() && segments.length === 1) {
|
|
10334
|
+
problemId = id;
|
|
10335
|
+
}
|
|
10336
|
+
}
|
|
10337
|
+
if (!problemId && segments.length === 2) {
|
|
10338
|
+
const secondSegment = segments[1];
|
|
10339
|
+
if (secondSegment) {
|
|
10340
|
+
const id = parseInt(secondSegment, 10);
|
|
10341
|
+
if (!isNaN(id) && id > 0 && secondSegment === id.toString()) {
|
|
10342
|
+
problemId = id;
|
|
10343
|
+
}
|
|
10344
|
+
}
|
|
10345
|
+
}
|
|
10346
|
+
}
|
|
10347
|
+
if (problemId) {
|
|
10348
|
+
return problemId;
|
|
10067
10349
|
}
|
|
10068
|
-
return problemId;
|
|
10069
10350
|
}
|
|
10070
10351
|
return null;
|
|
10071
10352
|
}
|
|
@@ -10078,16 +10359,24 @@ function getProblemId(args, cwd = process.cwd()) {
|
|
|
10078
10359
|
}
|
|
10079
10360
|
return detectProblemIdFromPath(cwd);
|
|
10080
10361
|
}
|
|
10081
|
-
function getProblemDirPath(problemId, cwd = process.cwd()) {
|
|
10362
|
+
function getProblemDirPath(problemId, cwd = process.cwd(), problem) {
|
|
10082
10363
|
const problemDir = getProblemDir();
|
|
10364
|
+
const archiveStrategy = getArchiveStrategy();
|
|
10083
10365
|
const projectRoot = findProjectRoot(cwd);
|
|
10084
10366
|
const baseDir = projectRoot || cwd;
|
|
10367
|
+
const subPath = getArchiveSubPath(problemId, archiveStrategy, problem);
|
|
10085
10368
|
if (problemDir === "." || problemDir === "") {
|
|
10369
|
+
if (subPath) {
|
|
10370
|
+
return join2(baseDir, subPath, problemId.toString());
|
|
10371
|
+
}
|
|
10086
10372
|
return join2(baseDir, problemId.toString());
|
|
10087
10373
|
}
|
|
10374
|
+
if (subPath) {
|
|
10375
|
+
return join2(baseDir, problemDir, subPath, problemId.toString());
|
|
10376
|
+
}
|
|
10088
10377
|
return join2(baseDir, problemDir, problemId.toString());
|
|
10089
10378
|
}
|
|
10090
|
-
function getSolvingDirPath(problemId, cwd = process.cwd()) {
|
|
10379
|
+
function getSolvingDirPath(problemId, cwd = process.cwd(), _) {
|
|
10091
10380
|
const solvingDir = getSolvingDir();
|
|
10092
10381
|
const projectRoot = findProjectRoot(cwd);
|
|
10093
10382
|
const baseDir = projectRoot || cwd;
|
|
@@ -10098,8 +10387,17 @@ function getSolvingDirPath(problemId, cwd = process.cwd()) {
|
|
|
10098
10387
|
}
|
|
10099
10388
|
|
|
10100
10389
|
// src/utils/execution-context.ts
|
|
10390
|
+
import { access } from "fs/promises";
|
|
10101
10391
|
import { readdir } from "fs/promises";
|
|
10102
10392
|
import { join as join3 } from "path";
|
|
10393
|
+
async function directoryExists(dirPath) {
|
|
10394
|
+
try {
|
|
10395
|
+
await access(dirPath);
|
|
10396
|
+
return true;
|
|
10397
|
+
} catch {
|
|
10398
|
+
return false;
|
|
10399
|
+
}
|
|
10400
|
+
}
|
|
10103
10401
|
async function resolveProblemContext(args, options = {}) {
|
|
10104
10402
|
const { requireId = false } = options;
|
|
10105
10403
|
const currentPathProblemId = detectProblemIdFromPath(process.cwd());
|
|
@@ -10110,7 +10408,24 @@ async function resolveProblemContext(args, options = {}) {
|
|
|
10110
10408
|
);
|
|
10111
10409
|
}
|
|
10112
10410
|
const isCurrentDir = problemId === null || problemId !== null && currentPathProblemId === problemId;
|
|
10113
|
-
|
|
10411
|
+
let problemDir;
|
|
10412
|
+
if (problemId && !isCurrentDir) {
|
|
10413
|
+
const solvingDirPath = getSolvingDirPath(problemId);
|
|
10414
|
+
const problemDirPath = getProblemDirPath(problemId);
|
|
10415
|
+
const solvingDirExists = await directoryExists(solvingDirPath);
|
|
10416
|
+
if (solvingDirExists) {
|
|
10417
|
+
problemDir = solvingDirPath;
|
|
10418
|
+
} else {
|
|
10419
|
+
const problemDirExists = await directoryExists(problemDirPath);
|
|
10420
|
+
if (problemDirExists) {
|
|
10421
|
+
problemDir = problemDirPath;
|
|
10422
|
+
} else {
|
|
10423
|
+
problemDir = solvingDirPath;
|
|
10424
|
+
}
|
|
10425
|
+
}
|
|
10426
|
+
} else {
|
|
10427
|
+
problemDir = process.cwd();
|
|
10428
|
+
}
|
|
10114
10429
|
return {
|
|
10115
10430
|
problemId,
|
|
10116
10431
|
problemDir,
|
|
@@ -10281,6 +10596,12 @@ export {
|
|
|
10281
10596
|
getSolvedAcHandle,
|
|
10282
10597
|
getProblemDir,
|
|
10283
10598
|
getSolvingDir,
|
|
10599
|
+
getArchiveStrategy,
|
|
10600
|
+
getNextTierMinRating,
|
|
10601
|
+
calculateTierProgress,
|
|
10602
|
+
getTierName,
|
|
10603
|
+
getTierColor,
|
|
10604
|
+
getTierImageUrl,
|
|
10284
10605
|
detectProblemIdFromPath,
|
|
10285
10606
|
getProblemId,
|
|
10286
10607
|
getProblemDirPath,
|
package/dist/commands/config.js
CHANGED
|
@@ -3,12 +3,13 @@ import {
|
|
|
3
3
|
Command,
|
|
4
4
|
CommandBuilder,
|
|
5
5
|
CommandDef,
|
|
6
|
+
getArchiveStrategy,
|
|
6
7
|
getAutoOpenEditor,
|
|
7
8
|
getDefaultLanguage,
|
|
8
9
|
getEditor,
|
|
9
10
|
getProblemDir,
|
|
10
11
|
getSolvedAcHandle
|
|
11
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-TNGUME4H.js";
|
|
12
13
|
import {
|
|
13
14
|
__decorateClass,
|
|
14
15
|
getSupportedLanguages,
|
|
@@ -104,6 +105,18 @@ function useConfig({
|
|
|
104
105
|
case "problem-dir":
|
|
105
106
|
updatedConfig.problemDir = value;
|
|
106
107
|
break;
|
|
108
|
+
case "archive-strategy": {
|
|
109
|
+
const validStrategies = ["flat", "by-range", "by-tier", "by-tag"];
|
|
110
|
+
if (!validStrategies.includes(value)) {
|
|
111
|
+
console.error(
|
|
112
|
+
`\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC544\uCE74\uC774\uBE59 \uC804\uB7B5\uC785\uB2C8\uB2E4: ${value}
|
|
113
|
+
\uC9C0\uC6D0 \uC804\uB7B5: ${validStrategies.join(", ")}`
|
|
114
|
+
);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
updatedConfig.archiveStrategy = value;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
107
120
|
default:
|
|
108
121
|
console.error(`\uC54C \uC218 \uC5C6\uB294 \uC124\uC815 \uD0A4: ${configKey}`);
|
|
109
122
|
process.exit(1);
|
|
@@ -147,6 +160,7 @@ function getConfigHelp() {
|
|
|
147
160
|
auto-open-editor fetch \uD6C4 \uC790\uB3D9\uC73C\uB85C \uC5D0\uB514\uD130 \uC5F4\uAE30 (true/false)
|
|
148
161
|
solved-ac-handle Solved.ac \uD578\uB4E4 (stats \uBA85\uB839\uC5B4\uC6A9)
|
|
149
162
|
problem-dir \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC \uACBD\uB85C (\uAE30\uBCF8\uAC12: problems, "." \uB610\uB294 ""\uB294 \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8)
|
|
163
|
+
archive-strategy \uC544\uCE74\uC774\uBE59 \uC804\uB7B5 (flat, by-range, by-tier, by-tag)
|
|
150
164
|
|
|
151
165
|
\uC635\uC158:
|
|
152
166
|
--help, -h \uB3C4\uC6C0\uB9D0 \uD45C\uC2DC
|
|
@@ -166,7 +180,8 @@ var CONFIG_KEYS = [
|
|
|
166
180
|
{ label: "editor", value: "editor" },
|
|
167
181
|
{ label: "auto-open-editor", value: "auto-open-editor" },
|
|
168
182
|
{ label: "solved-ac-handle", value: "solved-ac-handle" },
|
|
169
|
-
{ label: "problem-dir", value: "problem-dir" }
|
|
183
|
+
{ label: "problem-dir", value: "problem-dir" },
|
|
184
|
+
{ label: "archive-strategy", value: "archive-strategy" }
|
|
170
185
|
];
|
|
171
186
|
function ConfigView({
|
|
172
187
|
configKey,
|
|
@@ -199,6 +214,7 @@ function ConfigView({
|
|
|
199
214
|
const autoOpen = config?.autoOpenEditor ?? getAutoOpenEditor();
|
|
200
215
|
const handle = config?.solvedAcHandle ?? getSolvedAcHandle();
|
|
201
216
|
const problemDir = config?.problemDir ?? getProblemDir();
|
|
217
|
+
const archiveStrategy = config?.archiveStrategy ?? getArchiveStrategy();
|
|
202
218
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
203
219
|
/* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2699\uFE0F \uD604\uC7AC \uC124\uC815 (.ps-cli.json)" }) }),
|
|
204
220
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
@@ -226,6 +242,11 @@ function ConfigView({
|
|
|
226
242
|
/* @__PURE__ */ jsx(Text, { color: "gray", children: "problem-dir:" }),
|
|
227
243
|
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
228
244
|
/* @__PURE__ */ jsx(Text, { bold: true, children: problemDir })
|
|
245
|
+
] }),
|
|
246
|
+
/* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
247
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "archive-strategy:" }),
|
|
248
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
249
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: archiveStrategy })
|
|
229
250
|
] })
|
|
230
251
|
] })
|
|
231
252
|
] });
|
|
@@ -248,6 +269,9 @@ function ConfigView({
|
|
|
248
269
|
case "problem-dir":
|
|
249
270
|
configValue = config?.problemDir ?? getProblemDir();
|
|
250
271
|
break;
|
|
272
|
+
case "archive-strategy":
|
|
273
|
+
configValue = config?.archiveStrategy ?? getArchiveStrategy();
|
|
274
|
+
break;
|
|
251
275
|
default:
|
|
252
276
|
console.error(`\uC54C \uC218 \uC5C6\uB294 \uC124\uC815 \uD0A4: ${configKey}`);
|
|
253
277
|
process.exit(1);
|
|
@@ -418,6 +442,8 @@ var ConfigCommand = class extends Command {
|
|
|
418
442
|
return "Solved.ac \uD578\uB4E4 \uC785\uB825";
|
|
419
443
|
case "problem-dir":
|
|
420
444
|
return "\uBB38\uC81C \uB514\uB809\uD1A0\uB9AC \uACBD\uB85C \uC785\uB825";
|
|
445
|
+
case "archive-strategy":
|
|
446
|
+
return "\uC544\uCE74\uC774\uBE59 \uC804\uB7B5 \uC785\uB825 (flat, by-range, by-tier, by-tag)";
|
|
421
447
|
default:
|
|
422
448
|
return "\uAC12 \uC785\uB825";
|
|
423
449
|
}
|
|
@@ -434,6 +460,8 @@ var ConfigCommand = class extends Command {
|
|
|
434
460
|
return "Solved.ac \uC0AC\uC6A9\uC790 \uD578\uB4E4";
|
|
435
461
|
case "problem-dir":
|
|
436
462
|
return '\uBB38\uC81C \uB514\uB809\uD1A0\uB9AC \uACBD\uB85C (\uAE30\uBCF8\uAC12: "problems", \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8: ".")';
|
|
463
|
+
case "archive-strategy":
|
|
464
|
+
return "\uC544\uCE74\uC774\uBE59 \uC804\uB7B5: flat (\uD3C9\uBA74), by-range (1000\uBC88\uB300 \uBB36\uAE30), by-tier (\uD2F0\uC5B4\uBCC4), by-tag (\uD0DC\uADF8\uBCC4)";
|
|
437
465
|
default:
|
|
438
466
|
return "";
|
|
439
467
|
}
|
|
@@ -448,6 +476,8 @@ var ConfigCommand = class extends Command {
|
|
|
448
476
|
return ["true", "false"];
|
|
449
477
|
case "problem-dir":
|
|
450
478
|
return ["problems", ".", ""];
|
|
479
|
+
case "archive-strategy":
|
|
480
|
+
return ["flat", "by-range", "by-tier", "by-tag"];
|
|
451
481
|
default:
|
|
452
482
|
return [];
|
|
453
483
|
}
|
package/dist/commands/fetch.js
CHANGED
|
@@ -3,11 +3,8 @@ import {
|
|
|
3
3
|
scrapeProblem
|
|
4
4
|
} from "../chunk-AG6KWWHS.js";
|
|
5
5
|
import {
|
|
6
|
-
getProblem
|
|
7
|
-
|
|
8
|
-
getTierImageUrl,
|
|
9
|
-
getTierName
|
|
10
|
-
} from "../chunk-NH36IFWR.js";
|
|
6
|
+
getProblem
|
|
7
|
+
} from "../chunk-A6STXEAE.js";
|
|
11
8
|
import {
|
|
12
9
|
Command,
|
|
13
10
|
CommandBuilder,
|
|
@@ -15,8 +12,11 @@ import {
|
|
|
15
12
|
getAutoOpenEditor,
|
|
16
13
|
getEditor,
|
|
17
14
|
getProblemId,
|
|
18
|
-
getSolvingDirPath
|
|
19
|
-
|
|
15
|
+
getSolvingDirPath,
|
|
16
|
+
getTierColor,
|
|
17
|
+
getTierImageUrl,
|
|
18
|
+
getTierName
|
|
19
|
+
} from "../chunk-TNGUME4H.js";
|
|
20
20
|
import {
|
|
21
21
|
__decorateClass,
|
|
22
22
|
getLanguageConfig,
|
|
@@ -84,7 +84,7 @@ function getProjectRoot() {
|
|
|
84
84
|
return join(__dirname, "../..");
|
|
85
85
|
}
|
|
86
86
|
async function generateProblemFiles(problem, language = "python") {
|
|
87
|
-
const problemDir = getSolvingDirPath(problem.id);
|
|
87
|
+
const problemDir = getSolvingDirPath(problem.id, process.cwd(), problem);
|
|
88
88
|
await mkdir(problemDir, { recursive: true });
|
|
89
89
|
const langConfig = getLanguageConfig(language);
|
|
90
90
|
const projectRoot = getProjectRoot();
|
|
@@ -186,6 +186,7 @@ ${tags}
|
|
|
186
186
|
id: problem.id,
|
|
187
187
|
title: problem.title,
|
|
188
188
|
level: problem.level,
|
|
189
|
+
tags: problem.tags,
|
|
189
190
|
timeLimit: problem.timeLimit,
|
|
190
191
|
timeLimitMs: parseTimeLimitToMs(problem.timeLimit),
|
|
191
192
|
memoryLimit: problem.memoryLimit
|