Skip to content

Commit d6b8fd8

Browse files
committed
replaces JSONPath with pure kotlin local version
1 parent 35e3e1b commit d6b8fd8

File tree

22 files changed

+4082
-195
lines changed

22 files changed

+4082
-195
lines changed

build.gradle.kts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,22 @@ kotlin {
2323
val commonTest by getting {
2424
dependencies {
2525
implementation(kotlin("test"))
26+
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
2627
}
2728
}
2829
val jvmMain by getting {
2930
dependencies {
30-
implementation("com.jayway.jsonpath:json-path:2.9.0")
31+
// implementation("com.jayway.jsonpath:json-path:2.9.0")
3132
}
3233
}
3334
val jvmTest by getting
3435
val jsMain by getting
35-
val jsTest by getting
36+
val jsTest by getting {
37+
dependencies {
38+
implementation(npm("fs", "0.0.1-security"))
39+
implementation("org.jetbrains.kotlin-wrappers:kotlin-node:18.16.12-pre.610")
40+
}
41+
}
3642
}
3743
}
3844

kotlin-js-store/yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ fs.realpath@^1.0.0:
177177
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
178178
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
179179

180+
181+
version "0.0.1-security"
182+
resolved "https://registry.yarnpkg.com/fs/-/fs-0.0.1-security.tgz#8a7bd37186b6dddf3813f23858b57ecaaf5e41d4"
183+
integrity sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==
184+
180185
fsevents@~2.3.2:
181186
version "2.3.3"
182187
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
Lines changed: 186 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,190 @@
11
package io.zenwave360.zdl.antlr
22

3-
expect object JSONPath {
4-
fun <T> get(source: Any?, path: String): T?
3+
object JSONPath {
4+
fun <T> get(source: Any?, path: String): T? = get(source, path, null)
55

6-
fun <T> get(source: Any?, path: String, defaultValue: T?): T?
7-
}
6+
@Suppress("UNCHECKED_CAST")
7+
fun <T> get(source: Any?, path: String, defaultValue: T): T {
8+
if (source == null) return defaultValue
9+
10+
// Normalize path: remove leading "$." if present, or just "$" if that's all
11+
val normalizedPath = when {
12+
path.startsWith("$..") -> path.substring(1)
13+
path.startsWith("$.") -> path.substring(2)
14+
path.startsWith("$") -> path.substring(1)
15+
else -> path
16+
}
17+
18+
// Split path into segments
19+
val segments = parsePath(normalizedPath)
20+
21+
try {
22+
val result = evaluatePath(source, segments)
23+
// if(segments.last() == "[*]" && result is Map<*, *>) {
24+
// return result.values.toList() as? T ?: defaultValue
25+
// }
26+
return result as? T ?: defaultValue
27+
} catch (e: Exception) {
28+
return defaultValue
29+
}
30+
}
31+
32+
private fun parsePath(path: String): List<String> {
33+
if (path.isEmpty()) return emptyList()
34+
35+
val segments = mutableListOf<String>()
36+
var current = ""
37+
var i = 0
38+
39+
while (i < path.length) {
40+
when {
41+
// Handle recursive descent operator ".."
42+
i < path.length - 1 && path[i] == '.' && path[i + 1] == '.' -> {
43+
if (current.isNotEmpty()) {
44+
segments.add(current)
45+
current = ""
46+
}
47+
segments.add("..")
48+
i += 2
49+
continue
50+
}
51+
path[i] == '.' -> {
52+
if (current.isNotEmpty()) {
53+
segments.add(current)
54+
current = ""
55+
}
56+
}
57+
path[i] == '[' -> {
58+
if (current.isNotEmpty()) {
59+
segments.add(current)
60+
current = ""
61+
}
62+
// Find the closing bracket
63+
val closingBracket = path.indexOf(']', i)
64+
if (closingBracket != -1) {
65+
val bracketContent = path.substring(i + 1, closingBracket)
66+
// Handle quoted strings in brackets
67+
val segment = if (bracketContent.startsWith("'") && bracketContent.endsWith("'")) {
68+
bracketContent.substring(1, bracketContent.length - 1)
69+
} else {
70+
"[$bracketContent]"
71+
}
72+
segments.add(segment)
73+
i = closingBracket
74+
} else {
75+
current += path[i]
76+
}
77+
}
78+
else -> current += path[i]
79+
}
80+
i++
81+
}
82+
83+
if (current.isNotEmpty()) {
84+
segments.add(current)
85+
}
86+
87+
return segments
88+
}
889

90+
private fun evaluatePath(current: Any?, segments: List<String>): Any? {
91+
if (current == null || segments.isEmpty()) return current
92+
93+
val segment = segments.first()
94+
val remaining = segments.drop(1)
95+
96+
val result = when {
97+
segment == ".." -> {
98+
// Recursive descent - collect all matching paths
99+
val results = mutableListOf<Any?>()
100+
101+
// If there are remaining segments, apply them recursively
102+
if (remaining.isNotEmpty()) {
103+
collectRecursive(current, remaining, results)
104+
} else {
105+
// If no remaining segments, return current
106+
results.add(current)
107+
}
108+
109+
results.flatMap { result ->
110+
when (result) {
111+
is List<*> -> result
112+
else -> listOf(result)
113+
}
114+
}
115+
}
116+
segment == "[*]" -> {
117+
when (current) {
118+
is List<*> -> {
119+
if (remaining.isEmpty()) current
120+
else {
121+
val results = current.mapNotNull { evaluatePath(it, remaining) }
122+
results.flatMap { result ->
123+
when (result) {
124+
is List<*> -> result
125+
else -> listOf(result)
126+
}
127+
}
128+
}
129+
}
130+
is Map<*, *> -> {
131+
if (remaining.isEmpty()) current.values.toList()
132+
else {
133+
val results = current.values.mapNotNull { evaluatePath(it, remaining) }
134+
results.flatMap { result ->
135+
when (result) {
136+
is List<*> -> result
137+
else -> listOf(result)
138+
}
139+
}
140+
}
141+
}
142+
else -> null
143+
}
144+
}
145+
segment.startsWith("[") && segment.endsWith("]") -> {
146+
val index = segment.removeSurrounding("[", "]").toIntOrNull()
147+
when {
148+
index != null && current is List<*> -> {
149+
evaluatePath(current.getOrNull(index), remaining)
150+
}
151+
else -> null
152+
}
153+
}
154+
else -> {
155+
when (current) {
156+
is Map<*, *> -> evaluatePath(current[segment], remaining)
157+
else -> null
158+
}
159+
}
160+
}
161+
return result
162+
}
163+
164+
private fun collectRecursive(current: Any?, segments: List<String>, results: MutableList<Any?>) {
165+
if (current == null) return
166+
167+
// Try to evaluate the path from current position
168+
val directResult = evaluatePath(current, segments)
169+
if (directResult != null) {
170+
when (directResult) {
171+
is List<*> -> results.addAll(directResult)
172+
else -> results.add(directResult)
173+
}
174+
}
175+
176+
// Recursively search in children
177+
when (current) {
178+
is Map<*, *> -> {
179+
current.values.forEach { value ->
180+
collectRecursive(value, segments, results)
181+
}
182+
}
183+
is List<*> -> {
184+
current.forEach { item ->
185+
collectRecursive(item, segments, results)
186+
}
187+
}
188+
}
189+
}
190+
}

src/commonMain/kotlin/io/zenwave360/zdl/antlr/ZdlModelPostProcessor.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ class ZdlModelPostProcessor {
1010
val enums = model.getEnums()
1111
val events = model.getEvents()
1212

13-
@Suppress("UNCHECKED_CAST")
14-
val fields: List<MutableMap<String, Any?>> = JSONPath.get(model, "$..fields[*]", listOf<MutableMap<String, Any?>>())
15-
?: emptyList()
13+
val fields = JSONPath.get(model, "$..fields[*]", listOf<MutableMap<String, Any?>>())
1614
for (field in fields) {
1715
val type = field["type"]
1816
if (type != null) {

0 commit comments

Comments
 (0)