diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index b53dd0d..5323e6f 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -10,7 +10,7 @@ import com.fasterxml.jackson.module.kotlin.registerKotlinModule import util.newObjectNode data class Config( - val proxies: List + val fakeIPs: Int ) fun main() { @@ -34,8 +34,10 @@ fun main() { // """.trimIndent() // val proxies = yamlMapper.readValue(yamlStr) // println(yamlMapper.writeValueAsString(proxies)) - val clash = Clash.parseFromFile("/Users/rainbus/Projects/Join/Java/subconverter4j/src/main/resources/taishan.yaml") - println(yamlMapper.writeValueAsString(clash)) +// val clash = Clash.parseFromFile("/Users/rainbus/Projects/Join/Java/subconverter4j/src/main/resources/taishan.yaml") +// println(yamlMapper.writeValueAsString(clash)) + val config = Config(fakeIPs = 1) + println(yamlMapper.writeValueAsString(config)) } // //import com.fasterxml.jackson.annotation.JsonSubTypes diff --git a/src/main/kotlin/conf/Clash.kt b/src/main/kotlin/conf/Clash.kt index b9d9d72..89e3a74 100644 --- a/src/main/kotlin/conf/Clash.kt +++ b/src/main/kotlin/conf/Clash.kt @@ -96,9 +96,9 @@ data class Clash( data class Experimental( val fingerprints: List? = null, - val quicGoDisableGSO: Boolean? = null, - val quicGoDisableECN: Boolean? = null, - val ip4pEnable: Boolean? = null, + val quicGoDisableGso: Boolean? = null, + val quicGoDisableEcn: Boolean? = null, + val dialerIp4pConvert: Boolean? = null, ) data class Profile( @@ -110,6 +110,10 @@ data class Clash( val stack: String? = null, val autoRoute: Boolean? = null, val autoRedirect: Boolean? = null, + val autoRedirectInputMark: Int? = null, + val autoRedirectOutputMark: Int? = null, + @Deprecated("") val inet4Address: List? = null, + val inet6Address: List? = null, val autoDetectInterface: Boolean? = null, val dnsHijack: List? = null, val device: String? = null, @@ -134,6 +138,7 @@ data class Clash( val includeAndroidUser: List? = null, val includePackage: List? = null, val excludePackage: List? = null, + val fileDescriptor: Int? = null, @Deprecated("") val inet4RouteAddress: List? = null, @Deprecated("") val inet6RouteAddress: List? = null, @Deprecated("") val inet4RouteExcludeAddress: List? = null, @@ -179,9 +184,9 @@ data class Clash( val fallbackFilter: FallbackFilter? = null, val listen: String? = null, val enhancedMode: String? = null, - val fakeIPRange: String? = null, - val fakeIPFilter: List? = null, - val fakeIPFilterMode: String? = null, + val fakeIpRange: String? = null, + val fakeIpFilter: List? = null, + val fakeIpFilterMode: String? = null, val defaultNameserver: List? = null, val cacheAlgorithm: String? = null, val nameserverPolicy: LinkedHashMap>? = null, @@ -190,7 +195,7 @@ data class Clash( val directNameserverFollowPolicy: Boolean? = null ) - data class FallbackFilter( + data class FallbackFilter( val geoip: Boolean? = null, val geoipCode: String? = null, val ipcidr: List? = null, @@ -219,7 +224,7 @@ data class Clash( JsonSubTypes.Type(value = Proxy.MieruProxy::class, name = "mieru"), JsonSubTypes.Type(value = Proxy.AnyTLSOption::class, name = "anytls") ) - abstract class Proxy { + sealed class Proxy { abstract val tfo: Boolean? abstract val mptcp: Boolean? abstract val interfaceName: String? @@ -316,11 +321,11 @@ data class Clash( val skipCertVerify: Boolean? = null, val fingerprint: String? = null, val alpn: List? = null, - val customCA: String? = null, - val customCAString: String? = null, - val receiveWindowConn: Int? = null, - val receiveWindow: Int? = null, - val disableMTUDiscovery: Boolean? = null, + val ca: String? = null, + val caStr: String? = null, + val recvWindowConn: Int? = null, + val recvWindow: Int? = null, + val disableMtuDiscovery: Boolean? = null, val fastOpen: Boolean? = null, val hopInterval: Int? = null, override val tfo: Boolean? = null, @@ -524,11 +529,11 @@ data class Clash( val cwnd: Int? = null, val skipCertVerify: Boolean? = null, val fingerprint: String? = null, - val customCA: String? = null, - val customCAString: String? = null, - val receiveWindowConn: Int? = null, - val receiveWindow: Int? = null, - val disableMTUDiscovery: Boolean? = null, + val ca: String? = null, + val caStr: String? = null, + val recvWindowConn: Int? = null, + val recvWindow: Int? = null, + val disableMtuDiscovery: Boolean? = null, val maxDatagramFrameSize: Int? = null, val sni: String? = null, val udpOverStream: Boolean? = null, @@ -557,14 +562,14 @@ data class Clash( val network: String? = null, val realityOpts: RealityOptions? = null, val httpOpts: HTTPOptions? = null, - val http2Opts: HTTP2Options? = null, + val h2Opts: HTTP2Options? = null, val grpcOpts: GrpcOptions? = null, val wsOpts: WSOptions? = null, val wsPath: String? = null, val wsHeaders: Map? = null, val skipCertVerify: Boolean? = null, val fingerprint: String? = null, - val serverName: String? = null, + val servername: String? = null, val clientFingerprint: String? = null, override val tfo: Boolean? = null, override val mptcp: Boolean? = null, @@ -591,7 +596,7 @@ data class Clash( val serverName: String? = null, val realityOpts: RealityOptions? = null, val httpOpts: HTTPOptions? = null, - val http2Opts: HTTP2Options? = null, + val h2Opts: HTTP2Options? = null, val grpcOpts: GrpcOptions? = null, val wsOpts: WSOptions? = null, val packetAddr: Boolean? = null, @@ -618,11 +623,19 @@ data class Clash( val mtu: Int? = null, val udp: Boolean? = null, val persistentKeepalive: Int? = null, - val amneziaWGOption: AmneziaWGOption? = null, + val amneziaWgOption: AmneziaWGOption? = null, val peers: List? = null, val remoteDnsResolve: Boolean? = null, val dns: List? = null, - val refreshServerIPInterval: Int? = null, + val refreshServerIpInterval: Int? = null, + + val server: String? = null, + val port: Int? = null, + val publicKey: String? = null, + val preSharedKey: String? = null, + val reserved: List? = null, + val allowedIps: List? = null, + override val tfo: Boolean? = null, override val mptcp: Boolean? = null, override val interfaceName: String? = null, @@ -634,7 +647,7 @@ data class Clash( data class RealityOptions( val publicKey: String? = null, - val shortID: String? = null, + val shortId: String? = null, ) data class GrpcOptions( @@ -673,13 +686,13 @@ data class Clash( val publicKey: String? = null, val preSharedKey: String? = null, val reserved: List? = null, - val allowedIPs: List? = null, + val allowedIps: List? = null, ) data class AmneziaWGOption( val jc: Int? = null, - val jMin: Int? = null, - val jMax: Int? = null, + val jmin: Int? = null, + val jmax: Int? = null, val s1: Int? = null, val s2: Int? = null, val h1: UInt? = null, @@ -712,6 +725,14 @@ data class Clash( ) } + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") + @JsonSubTypes( + JsonSubTypes.Type(value = ProxyGroup.UrlTest::class, name = "url-test"), + JsonSubTypes.Type(value = ProxyGroup.Select::class, name = "select"), + JsonSubTypes.Type(value = ProxyGroup.Fallback::class, name = "fallback"), + JsonSubTypes.Type(value = ProxyGroup.LoadBalance::class, name = "load-balance"), + JsonSubTypes.Type(value = ProxyGroup.Relay::class, name = "relay") + ) sealed class ProxyGroup { abstract val name: String? abstract val proxies: List? @@ -721,9 +742,11 @@ data class Clash( abstract val lazy: Boolean? abstract val timeout: Int? abstract val maxFailedTimes: Int? - abstract val disableUDP: Boolean? - @Deprecated("") abstract val interfaceName: String? - @Deprecated("") abstract val routingMark: Int? + abstract val disableUdp: Boolean? + @Deprecated("") + abstract val interfaceName: String? + @Deprecated("") + abstract val routingMark: Int? abstract val includeAll: Boolean? abstract val includeAllProxies: Boolean? abstract val includeAllProviders: Boolean? @@ -743,7 +766,7 @@ data class Clash( override val lazy: Boolean? = null, override val timeout: Int? = null, override val maxFailedTimes: Int? = null, - override val disableUDP: Boolean? = null, + override val disableUdp: Boolean? = null, override val interfaceName: String? = null, override val routingMark: Int? = null, override val includeAll: Boolean? = null, @@ -767,7 +790,7 @@ data class Clash( override val lazy: Boolean? = null, override val timeout: Int? = null, override val maxFailedTimes: Int? = null, - override val disableUDP: Boolean? = null, + override val disableUdp: Boolean? = null, override val interfaceName: String? = null, override val routingMark: Int? = null, override val includeAll: Boolean? = null, @@ -790,7 +813,7 @@ data class Clash( override val lazy: Boolean? = null, override val timeout: Int? = null, override val maxFailedTimes: Int? = null, - override val disableUDP: Boolean? = null, + override val disableUdp: Boolean? = null, override val interfaceName: String? = null, override val routingMark: Int? = null, override val includeAll: Boolean? = null, @@ -813,7 +836,7 @@ data class Clash( override val lazy: Boolean? = null, override val timeout: Int? = null, override val maxFailedTimes: Int? = null, - override val disableUDP: Boolean? = null, + override val disableUdp: Boolean? = null, override val interfaceName: String? = null, override val routingMark: Int? = null, override val includeAll: Boolean? = null, @@ -837,7 +860,7 @@ data class Clash( override val lazy: Boolean? = null, override val timeout: Int? = null, override val maxFailedTimes: Int? = null, - override val disableUDP: Boolean? = null, + override val disableUdp: Boolean? = null, override val interfaceName: String? = null, override val routingMark: Int? = null, override val includeAll: Boolean? = null, @@ -852,8 +875,13 @@ data class Clash( ) : ProxyGroup() } + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") + @JsonSubTypes( + JsonSubTypes.Type(value = ProxyProvider.FileProvider::class, name = "file"), + JsonSubTypes.Type(value = ProxyProvider.HttpProvider::class, name = "http"), + JsonSubTypes.Type(value = ProxyProvider.InlineProvider::class, name = "inline") + ) sealed class ProxyProvider { - abstract val name: String? abstract val interval: Int? abstract val filter: String? abstract val excludeFilter: String? @@ -863,7 +891,6 @@ data class Clash( abstract val override: Override? data class FileProvider( - override val name: String? = null, override val interval: Int? = null, override val filter: String? = null, override val excludeFilter: String? = null, @@ -875,7 +902,6 @@ data class Clash( ) : ProxyProvider() data class HttpProvider( - override val name: String? = null, override val interval: Int? = null, override val filter: String? = null, override val excludeFilter: String? = null, @@ -891,7 +917,6 @@ data class Clash( ) : ProxyProvider() data class InlineProvider( - override val name: String? = null, override val interval: Int? = null, override val filter: String? = null, override val excludeFilter: String? = null, @@ -934,6 +959,12 @@ data class Clash( ) } + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") + @JsonSubTypes( + JsonSubTypes.Type(value = RuleProvider.FileProvider::class, name = "file"), + JsonSubTypes.Type(value = RuleProvider.HttpProvider::class, name = "http"), + JsonSubTypes.Type(value = RuleProvider.InlineProvider::class, name = "inline") + ) sealed class RuleProvider { abstract val behavior: String? @@ -960,45 +991,22 @@ data class Clash( ) : RuleProvider() } - data class Header( - val userAgent: List? = null, val accept: List? = null, val authorization: List? = null + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") + @JsonSubTypes( + JsonSubTypes.Type(value = Listener.AnyTLSListener::class, name = "anytls"), + JsonSubTypes.Type(value = Listener.HTTPListener::class, name = "http"), + JsonSubTypes.Type(value = Listener.Hysteria2Listener::class, name = "hysteria2"), + JsonSubTypes.Type(value = Listener.RedirListener::class, name = "redir"), + JsonSubTypes.Type(value = Listener.ShadowSocksListener::class, name = "shadowsocks"), + JsonSubTypes.Type(value = Listener.SocksListener::class, name = "socks"), + JsonSubTypes.Type(value = Listener.TProxyListener::class, name = "tproxy"), + JsonSubTypes.Type(value = Listener.TrojanListener::class, name = "trojan"), + JsonSubTypes.Type(value = Listener.TuicListener::class, name = "tuic"), + JsonSubTypes.Type(value = Listener.TunListener::class, name = "tun"), + JsonSubTypes.Type(value = Listener.TunnelListener::class, name = "tunnel"), + JsonSubTypes.Type(value = Listener.VlessListener::class, name = "vless"), + JsonSubTypes.Type(value = Listener.VmessListener::class, name = "vmess") ) - - data class HealthCheck( - val enable: Boolean? = null, - val interval: Int? = null, - val lazy: Boolean? = null, - val url: String? = null, - val expectedStatus: Int? = null - ) - - data class Override( - val skipCertVerify: Boolean? = null, - val udp: Boolean? = null, - val down: String? = null, - val up: String? = null, - val dialerProxy: String? = null, - val interfaceName: String? = null, - val routingMark: Int? = null, - val ipVersion: String? = null, - val additionalPrefix: String? = null, - val additionalSuffix: String? = null, - val proxyName: List? = null - ) - - data class ProxyName( - val pattern: String? = null, val target: String? = null - ) - - data class Payload( - val name: String? = null, - val type: String? = null, - val server: String? = null, - val port: Int? = null, - val cipher: String? = null, - val password: String? = null - ) - sealed class Listener { abstract val name: String? abstract val port: Int? @@ -1006,39 +1014,54 @@ data class Clash( abstract val rule: String? abstract val proxy: String? - data class HttpListener( + data class AnyTLSListener( override val name: String? = null, override val port: Int? = null, override val listen: String? = null, override val rule: String? = null, override val proxy: String? = null, - val users: List? = null, + val users: Map? = null, val certificate: String? = null, - val privateKey: String? = null + val privateKey: String? = null, + val paddingScheme: String? = null ) : Listener() - data class SocksListener( + data class HTTPListener( override val name: String? = null, override val port: Int? = null, override val listen: String? = null, override val rule: String? = null, override val proxy: String? = null, - val udp: Boolean? = null, - val users: List? = null, + val users: List? = null, val certificate: String? = null, - val privateKey: String? = null + val privateKey: String? = null, + val realityConfig: RealityConfig? = null ) : Listener() - data class MixedListener( + data class Hysteria2Listener( override val name: String? = null, override val port: Int? = null, override val listen: String? = null, override val rule: String? = null, override val proxy: String? = null, - val udp: Boolean? = null, - val users: List? = null, + val users: Map? = null, + val obfs: String? = null, + val obfsPassword: String? = null, val certificate: String? = null, - val privateKey: String? = null + val privateKey: String? = null, + val maxIdleTime: Int? = null, + val alpn: List? = null, + val up: String? = null, + val down: String? = null, + val ignoreClientBandwidth: Boolean? = null, + val masquerade: String? = null, + val cwnd: Int? = null, + val udpMtu: Int? = null, + val muxOption: MuxOption? = null, + val initialStreamReceiveWindow: ULong? = null, + val maxStreamReceiveWindow: ULong? = null, + val initialConnectionReceiveWindow: ULong? = null, + val maxConnectionReceiveWindow: ULong? = null ) : Listener() data class RedirListener( @@ -1049,6 +1072,31 @@ data class Clash( override val proxy: String? = null ) : Listener() + data class ShadowSocksListener( + override val name: String? = null, + override val port: Int? = null, + override val listen: String? = null, + override val rule: String? = null, + override val proxy: String? = null, + val password: String? = null, + val cipher: String? = null, + val udp: Boolean? = null, + val muxOption: MuxOption? = null + ) : Listener() + + data class SocksListener( + override val name: String? = null, + override val port: Int? = null, + override val listen: String? = null, + override val rule: String? = null, + override val proxy: String? = null, + val users: List? = null, + val udp: Boolean? = null, + val certificate: String? = null, + val privateKey: String? = null, + val realityConfig: RealityConfig? = null + ) : Listener() + data class TProxyListener( override val name: String? = null, override val port: Int? = null, @@ -1058,54 +1106,20 @@ data class Clash( val udp: Boolean? = null ) : Listener() - data class TunListener( + data class TrojanListener( override val name: String? = null, override val port: Int? = null, override val listen: String? = null, override val rule: String? = null, override val proxy: String? = null, - val stack: String? = null, - val dnsHijack: List? = null, - val inet4Address: List? = null, - val inet6Address: List? = null, - val autoDetectInterface: Boolean? = null, - val autoRoute: Boolean? = null, - val mtu: Int? = null, - val strictRoute: Boolean? = null, - val inet4RouteAddress: List? = null, - val inet6RouteAddress: List? = null, - val endpointIndependentNat: Boolean? = null, - val includeUid: List? = null, - val includeUidRange: List? = null, - val excludeUid: List? = null, - val excludeUidRange: List? = null, - val includeAndroidUser: List? = null, - val includePackage: List? = null, - val excludePackage: List? = null - ) : Listener() - - data class ShadowsocksListener( - override val name: String? = null, - override val port: Int? = null, - override val listen: String? = null, - override val rule: String? = null, - override val proxy: String? = null, - val password: String? = null, - val cipher: String? = null, - val udp: Boolean? = null - ) : Listener() - - data class VmessListener( - override val name: String? = null, - override val port: Int? = null, - override val listen: String? = null, - override val rule: String? = null, - override val proxy: String? = null, - val users: List? = null, - val privateKey: String? = null, - val certificate: String? = null, + val users: List? = null, val wsPath: String? = null, - val realityConfig: RealityConfig? = null + val grpcServiceName: String? = null, + val certificate: String? = null, + val privateKey: String? = null, + val realityConfig: RealityConfig? = null, + val muxOption: MuxOption? = null, + val ssOption: TrojanSSOption? = null ) : Listener() data class TuicListener( @@ -1122,25 +1136,53 @@ data class Clash( val maxIdleTime: Int? = null, val authenticationTimeout: Int? = null, val alpn: List? = null, - val maxUdpRelayPacketSize: Int? = null + val maxUdpRelayPacketSize: Int? = null, + val cwnd: Int? = null, + val muxOption: MuxOption? = null ) : Listener() - data class Hysteria2Listener( + data class TunListener( override val name: String? = null, override val port: Int? = null, override val listen: String? = null, override val rule: String? = null, override val proxy: String? = null, - val users: Map? = null, - val up: Int? = null, - val down: Int? = null, - val ignoreClientBandwidth: Boolean? = null, - val obfs: String? = null, - val obfsPassword: String? = null, - val masquerade: String? = null, - val alpn: List? = null, - val certificate: String? = null, - val privateKey: String? = null + val device: String? = null, + val stack: String? = null, + val dnsHijack: List? = null, + val autoRoute: Boolean? = null, + val autoDetectInterface: Boolean? = null, + val mtu: UInt? = null, + val gso: Boolean? = null, + val gsoMaxSize: UInt? = null, + val inet4Address: List? = null, + val inet6Address: List? = null, + val ipRoute2TableIndex: Int? = null, + val ipRoute2RuleIndex: Int? = null, + val autoRedirect: Boolean? = null, + val autoRedirectInputMark: UInt? = null, + val autoRedirectOutputMark: UInt? = null, + val strictRoute: Boolean? = null, + val routeAddress: List? = null, + val routeAddressSet: List? = null, + val routeExcludeAddress: List? = null, + val routeExcludeAddressSet: List? = null, + val includeInterface: List? = null, + val excludeInterface: List? = null, + val includeUid: List? = null, + val includeUidRange: List? = null, + val excludeUid: List? = null, + val excludeUidRange: List? = null, + val includeAndroidUser: List? = null, + val includePackage: List? = null, + val excludePackage: List? = null, + val endpointIndependentNat: Boolean? = null, + val udpTimeout: Long? = null, + val fileDescriptor: Int? = null, + val inet4RouteAddress: List? = null, + val inet6RouteAddress: List? = null, + val inet4RouteExcludeAddress: List? = null, + val inet6RouteExcludeAddress: List? = null ) : Listener() data class TunnelListener( @@ -1161,28 +1203,74 @@ data class Clash( override val proxy: String? = null, val users: List? = null, val wsPath: String? = null, + val grpcServiceName: String? = null, val certificate: String? = null, val privateKey: String? = null, - val realityConfig: RealityConfig? = null + val realityConfig: RealityConfig? = null, + val muxOption: MuxOption? = null ) : Listener() - data class User( - val username: String? = null, val password: String? = null + data class VmessListener( + override val name: String? = null, + override val port: Int? = null, + override val listen: String? = null, + override val rule: String? = null, + override val proxy: String? = null, + val users: List? = null, + val wsPath: String? = null, + val grpcServiceName: String? = null, + val certificate: String? = null, + val privateKey: String? = null, + val realityConfig: RealityConfig? = null, + val muxOption: MuxOption? = null + ) : Listener() + + data class AuthUser( + val username: String? = null, + val password: String? = null ) - data class VmessUser( - val username: String? = null, val uuid: String? = null, val alterId: Int? = null + data class TrojanUser( + val username: String? = null, + val password: String? = null ) data class VlessUser( - val username: String? = null, val uuid: String? = null, val flow: String? = null + val username: String? = null, + val uuid: String? = null, + val flow: String? = null + ) + + data class VmessUser( + val username: String? = null, + val uuid: String? = null, + val alterId: Int? = null ) data class RealityConfig( val dest: String? = null, val privateKey: String? = null, val shortId: List? = null, - val serverNames: List? = null + val serverNames: List? = null, + val maxTimeDifference: Int? = null, + val proxy: String? = null + ) + + data class TrojanSSOption( + val enabled: Boolean? = null, + val method: String? = null, + val password: String? = null + ) + + data class BrutalOptions( + val enabled: Boolean? = null, + val up: String? = null, + val down: String? = null + ) + + data class MuxOption( + val padding: Boolean? = null, + val brutal: BrutalOptions? = null ) } @@ -1226,10 +1314,11 @@ data class Clash( companion object { - private val yamlMapper: ObjectMapper = ObjectMapper(YAMLFactory().disable(YAMLGenerator.Feature.USE_NATIVE_TYPE_ID)).apply { - registerKotlinModule() - propertyNamingStrategy = PropertyNamingStrategies.KEBAB_CASE - } + private val yamlMapper: ObjectMapper = + ObjectMapper(YAMLFactory().disable(YAMLGenerator.Feature.USE_NATIVE_TYPE_ID)).apply { + registerKotlinModule() + propertyNamingStrategy = PropertyNamingStrategies.KEBAB_CASE + } private fun preprocessYamlNode(yamlNode: JsonNode) { preprocessHostsNode(yamlNode) @@ -1241,11 +1330,11 @@ data class Clash( private fun preprocessHostsNode(yamlNode: JsonNode) { (yamlNode["hosts"] as? ObjectNode)?.let { hostsNode -> - hostsNode.fields().forEach { (k, v) -> - if (v is TextNode) { - hostsNode.replace(k, v.toArrayNode()) - } - } + hostsNode.fields().forEach { (k, v) -> + if (v is TextNode) { + hostsNode.replace(k, v.toArrayNode()) + } + } } } @@ -1257,12 +1346,14 @@ data class Clash( val tunnelText = element.textValue() val parts = tunnelText.split(",").map { it.trim() } require(parts.size == 4) { "Tunnel configuration must have 4 comma-separated values: $tunnelText" } - val tunnelObject = util.newObjectNode(mapOf( - "network" to util.newArrayNode(parts[0].split("/").map { util.newTextNode(it.trim()) }), - "address" to util.newTextNode(parts[1]), - "target" to util.newTextNode(parts[2]), - "proxy" to util.newTextNode(parts[3]) - )) + val tunnelObject = util.newObjectNode( + mapOf( + "network" to util.newArrayNode(parts[0].split("/").map { util.newTextNode(it.trim()) }), + "address" to util.newTextNode(parts[1]), + "target" to util.newTextNode(parts[2]), + "proxy" to util.newTextNode(parts[3]) + ) + ) tunnelsArray.set(index, tunnelObject) } } @@ -1300,15 +1391,15 @@ data class Clash( } jsonNode.fields().forEach { (_, value) -> preprocessKeyCase(value) } } + is ArrayNode -> jsonNode.forEach { preprocessKeyCase(it) } } } - @JvmStatic fun parseFromString(yamlStr: String): Clash { - val yamlNode = yamlMapper.readTree(yamlStr); + val yamlNode = yamlMapper.readTree(yamlStr) preprocessYamlNode(yamlNode) return yamlMapper.treeToValue(yamlNode, Clash::class.java) }