Skip to content

Commit 399d7b7

Browse files
committed
feat(apipost): 新Curl Parser,支持本地curl文件目录
1 parent 37deb5b commit 399d7b7

File tree

3 files changed

+75
-80
lines changed

3 files changed

+75
-80
lines changed

plugin-apipost/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
group = "me.leon.toolsfx"
2-
version = "1.10.0"
2+
version = "1.11.0"
33

44
plugins {
55
`java-library`

plugin-apipost/src/main/kotlin/me/leon/toolsfx/plugin/ApiPostView.kt

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import javafx.geometry.Pos
1010
import javafx.scene.control.*
1111
import javafx.scene.control.cell.CheckBoxTableCell
1212
import javafx.scene.text.Text
13+
import kotlin.io.walk
1314
import kotlinx.coroutines.*
1415
import me.leon.*
1516
import me.leon.ext.*
@@ -24,8 +25,8 @@ import tornadofx.*
2425
private const val MAX_SHOW_LENGTH = 1_000_000
2526

2627
class ApiPostView : PluginFragment("ApiPost") {
27-
override val version = "v1.10.0"
28-
override val date: String = "2025-07-27"
28+
override val version = "v1.11.0"
29+
override val date: String = "2025-09-07"
2930
override val author = "Leon406"
3031
override val description = "ApiPost"
3132

@@ -154,8 +155,20 @@ class ApiPostView : PluginFragment("ApiPost") {
154155
.copy()
155156
}
156157
}
157-
val curlFiles = ApiConfig.curlDir.toFile().listFiles()?.map { it.nameWithoutExtension }
158-
if (curlFiles != null && curlFiles.isNotEmpty()) {
158+
val configFile = ApiConfig.curlDir.toFile()
159+
val curlFiles =
160+
configFile
161+
.walk()
162+
.filter { it.isFile && it.extension == "curl" }
163+
.map {
164+
it.absolutePath
165+
.replace(configFile.absolutePath, "")
166+
.trimStart('/', '\\')
167+
.replace(".curl", "")
168+
.replace("\\", "/")
169+
}
170+
.toList()
171+
if (curlFiles.isNotEmpty()) {
159172
val newCurlFiles = curlFiles.toMutableList()
160173
newCurlFiles.add(0, "")
161174
selectedUrl.set("")
Lines changed: 57 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package me.leon.toolsfx.plugin.net
22

3-
import me.leon.ext.fromJson
43
import me.leon.ext.toJson
54
import me.leon.toolsfx.plugin.net.HttpUrlUtil.toParams
65

@@ -25,95 +24,78 @@ fun String.cookieParse() =
2524
}
2625
}
2726

28-
fun String.parseCurl() =
29-
trim()
30-
// 去掉浏览器多余的分割符
31-
.replace("""[\^\\]""".toRegex(), "")
32-
.split("""\n|\r\n""".toRegex())
27+
val separator = """\s*[\^\\]\s+""".toRegex()
28+
val winEscapeReg = """\^([{%\d])""".toRegex()
29+
30+
fun String.winEscape() = replace("^\\^\"", "\"").replace(winEscapeReg, "$1")
31+
32+
fun String.parseCurl(): Request {
33+
var r = this
34+
// 兼容旧版
35+
if (r.contains("\n") && !r.contains(separator)) {
36+
r = r.replace("\n", " \\\n")
37+
}
38+
return r.split(separator)
3339
.map { it.trim() }
34-
.fold(Request(this)) { acc, s ->
35-
acc.apply {
36-
when {
37-
s.startsWith("curl") -> acc.url = s.removeFirstAndEndQuotes(5)
38-
s.startsWith("-X") -> acc.method = s.removeFirstAndEndQuotes(3)
39-
s.startsWith("--data-raw") ->
40-
acc.method = "POST".also { acc.rawBody = s.removeFirstAndEndQuotes(11) }
41-
s.startsWith("-d") ->
42-
acc.method =
43-
("POST".takeIf { acc.method == "GET" } ?: acc.method).also {
44-
val value = s.removeFirstAndEndQuotes(3)
45-
if (value.contains("@file")) {
46-
if (value.startsWith("{") || value.startsWith("[")) {
47-
acc.params.putAll(
48-
value.fromJson(MutableMap::class.java)
49-
as Map<out String, Any>
50-
)
51-
} else {
52-
acc.params.putAll(value.paramsParse().also { println(it) })
53-
}
54-
} else if (
55-
this@parseCurl.contains("Content-Type: application/json", true)
56-
) {
57-
acc.rawBody = value
58-
} else {
59-
acc.params.putAll(value.paramsParse())
60-
}
61-
}
62-
s.startsWith("--data-binary") ->
63-
acc.method =
64-
("POST".takeIf { acc.method == "GET" } ?: acc.method).also {
65-
acc.rawBody = s.removeFirstAndEndQuotes(14)
66-
}
67-
s.startsWith("--data") ->
68-
acc.method =
69-
("POST".takeIf { acc.method == "GET" } ?: acc.method).also {
70-
val value = s.removeFirstAndEndQuotes(7)
71-
if (value.contains("@file")) {
72-
acc.params.putAll(
73-
value.fromJson(MutableMap::class.java)
74-
as Map<out String, Any>
75-
)
76-
} else if (
77-
this@parseCurl.contains("Content-Type: application/json", true)
78-
) {
79-
acc.rawBody = value
80-
} else {
81-
acc.params.putAll(value.paramsParse())
82-
}
83-
}
84-
s.startsWith("-H") ->
85-
with(s.removeFirstAndEndQuotes(3)) {
86-
acc.headers[substringBefore(":")] = substringAfter(":").trim()
40+
.fold(Request("")) { req, s ->
41+
when {
42+
s.startsWith("-X") -> req.method = s.removeFirstAndEndQuotes(3).trim()
43+
s.startsWith("-H") ->
44+
with(s.removeFirstAndEndQuotes(3)) {
45+
req.headers[substringBefore(":")] = substringAfter(":").trim().winEscape()
46+
}
47+
48+
s.startsWith("-d") -> req.rawBody = s.removeFirstAndEndQuotes(3).winEscape()
49+
s.startsWith("--data-raw") ->
50+
req.rawBody = s.removeFirstAndEndQuotes(11).winEscape().winEscape()
51+
52+
s.startsWith("--data-binary") ->
53+
req.rawBody = s.removeFirstAndEndQuotes(14).trim().winEscape()
54+
55+
s.startsWith("--data") -> req.rawBody = s.removeFirstAndEndQuotes(7).winEscape()
56+
s.startsWith("curl") ->
57+
with(s.removeFirstAndEndQuotes(5)) {
58+
if (startsWith("-X")) {
59+
val str = substring(3)
60+
req.method = str.substringBefore(" ").trim()
61+
req.url = str.substringAfter(" ").removeFirstAndEndQuotes()
62+
} else {
63+
req.url = this
8764
}
88-
else -> {}
89-
}
65+
}
66+
67+
else ->
68+
if (s.startsWith("http")) {
69+
req.url = this
70+
}
9071
}
72+
req
9173
}
92-
.also { println(it) }
74+
}
9375

9476
fun Request.toCurl(): String =
95-
StringBuilder()
96-
.append("curl $url")
97-
.also {
98-
if (method == "GET" && params.isNotEmpty()) it.append("?").append(params.toParams())
99-
}
100-
.appendLine()
101-
.append("-X $method")
102-
.appendLine()
103-
.also {
77+
buildString {
78+
append("curl \"$url\" \\")
79+
if (method == "GET" && params.isNotEmpty()) append("?").append(params.toParams())
80+
appendLine()
81+
append("-X $method \\")
82+
if (headers.isNotEmpty() || params.isNotEmpty() || rawBody.isNotEmpty()) {
83+
appendLine()
84+
}
10485
for ((key, value) in headers) {
105-
it.append("-H \"$key:$value\"").appendLine()
86+
append("-H \"$key:$value\" \\").appendLine()
10687
}
10788
if (fileParamName.isNotEmpty()) params[fileParamName] = "@file"
10889
val data =
10990
if (isJson) params.toJson() else if (method != "GET") params.toParams() else ""
11091
if (rawBody.isNotEmpty()) {
111-
it.append("--data-raw $rawBody")
92+
append("--data-raw $rawBody")
11293
} else if (data.isNotEmpty()) {
113-
it.append("-d \"${data.replace("\"", "\\\"")}\"")
94+
append("-d \"${data.replace("\"", "\\\"")}\"")
11495
}
11596
}
116-
.toString()
97+
.trimEnd('\\')
98+
.trim()
11799

118100
fun String.removeFirstAndEndQuotes(from: Int = 0) =
119101
substring(from).replace("^([\"'])(.*?)\\1?$".toRegex(), "$2").trim()

0 commit comments

Comments
 (0)