Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/publish-pages-only.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ jobs:
distribution: 'temurin'
java-version: '17'
- name: Build Dokka HTML
run: ./gradlew dokkaHtml
run: ./gradlew :jsonpath4k:dokkaGenerate
- name: Setup Pages
uses: actions/configure-pages@v3
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
# Upload docs folder
path: './build/dokka'
path: './docs'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
4 changes: 2 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ jobs:
with:
submodules: recursive
- name: Build Dokka HTML
run: ./gradlew dokkaHtml
run: ./gradlew :jsonpath4k:dokkaGenerate
- name: Setup Pages
uses: actions/configure-pages@v3
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
# Upload docs folder
path: './build/dokka'
path: './docs'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
2 changes: 1 addition & 1 deletion .github/workflows/test-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
distribution: 'temurin'
java-version: '17'
- name: Build klibs
run: ./gradlew iosArm64MainKlibrary iosX64MainKlibrary
run: ./gradlew iosArm64MainKlibrary
- name: Run tests
run: ./gradlew iosSimulatorArm64Test
- name: Test Report
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test-jvm.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Test JVM implementation
name: Test all non-Apple implementations
on: [push]
jobs:
build:
Expand All @@ -13,7 +13,7 @@ jobs:
distribution: 'temurin'
java-version: '17'
- name: Run tests
run: ./gradlew jvmTest
run: ./gradlew allTests
- name: Test Report
uses: dorny/test-reporter@v1
if: success() || failure()
Expand Down
16 changes: 14 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
# CHANGELOG

# Release 3.2.0-SNAPSHOT
* TODO
# Release 4.0.0-SNAPSHOT
* Support all KMP targets
* Logging through Napier is only supported on
* Android (ART)
* JVM
* iOS
* tvOS
* macOS
* JVM
* Logging on other targets defaults to NOOP
* Kotlin 2.4.0
* Fix race condition thanks to latest ANTLR 1.0.12
* Remove deprecations
* Change Serializer names to work on web targets too

# Release 3.1.0
* Add: structural equality check for `NormalizedJsonPath` and `NormalizedJsonPathSegment`
Expand Down
40 changes: 23 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![A-SIT Plus Official](https://raw.githubusercontent.com/a-sit-plus/a-sit-plus.github.io/709e802b3e00cb57916cbb254ca5e1a5756ad2a8/A-SIT%20Plus_%20official_opt.svg)](https://plus.a-sit.at/open-source.html)
[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-brightgreen.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0)
[![Kotlin](https://img.shields.io/badge/kotlin-multiplatform-orange.svg?logo=kotlin)](http://kotlinlang.org)
[![Kotlin](https://img.shields.io/badge/kotlin-2.0.20-blue.svg?logo=kotlin)](http://kotlinlang.org)
[![Kotlin](https://img.shields.io/badge/kotlin-2.4.0-blue.svg?logo=kotlin)](http://kotlinlang.org)
[![Java](https://img.shields.io/badge/java-17+-blue.svg?logo=OPENJDK)](https://www.oracle.com/java/technologies/downloads/#java17)
[![Maven Central](https://img.shields.io/maven-central/v/at.asitplus/jsonpath4k)](https://mvnrepository.com/artifact/at.asitplus/jsonpath4k/)

Expand All @@ -17,14 +17,15 @@ This is a Kotlin Multiplatform Library for using Json Paths as specified in [RFC

## Architecture

This library was built for [Kotlin Multiplatform](https://kotlinlang.org/docs/multiplatform.html) targeting JVM/Android and iOS. Other targets might work, but are
not tested or even built.
This library was built for [Kotlin Multiplatform](https://kotlinlang.org/docs/multiplatform.html), supporting all KMP targets, except WASI.

Notable features for multiplatform are:

- Use of [Napier](https://github.com/AAkira/Napier) as the logging framework for the default compiler instance
- Use of [Kotest](https://kotest.io/) for unit tests
- Use of [Napier](https://github.com/AAkira/Napier) for default compiler error logging on JVM/Android, iOS, macOS, tvOS, JS, and WasmJS.
- By default, no `Antilog` is registered.
- On watchOS, Linux, Windows (mingw), and Android Native, the default listener does not log, due to Napier not supporting those platforms; provide a custom error listener if logging is required on those platforms.
- Use of [kotlinx-serialization](https://github.com/Kotlin/kotlinx.serialization) for serialization from/to JSON and to have JsonElement as evaluation target for JsonPathQuery
- Use of [TestBalloon](https://infix-de.github.io/testBalloon/latest/) with [TestBalloon Addons](https://github.com/a-sit-plus/testballoon-addons) for unit tests.

## Using the Library
1. Add JsonPath4K as a dependency in your project (`at.asitplus:jsonpath4k:$version`)
Expand All @@ -47,10 +48,10 @@ val jsonValue = nodeList[0].value.jsonPrimitive
val normalizedPath = nodeList[0].normalizedJsonPath
```

## Function extensions
## Function Extensions
This library supports the function extensions specified in [RFC9535](https://www.rfc-editor.org/rfc/rfc9535.html#name-function-extensions) by default.

### Custom function extensions
### Custom Function Extensions
Custom function extensions can be added using `JsonPath.defaultFunctionExtensionRepository.addExtension`:
```kotlin
// adding a logical type function extension with 1 parameter of type NodesType
Expand Down Expand Up @@ -118,14 +119,14 @@ JsonPath.defaultFunctionExtensionRepository.addExtension("count") {
}
```

### Removing Function extensions
### Removing Function Extensions
Function extensions can be removed from the default repository by setting the value of `JsonPath.defaultFunctionExtensionRepository` to a new repository.

Existing functions can be preserved by exporting them using `JsonPath.defaultFunctionExtensionRepository.export()` and selectively importing them into the new repository.



### Testing custom function extensions
### Testing Custom Function Extensions
In order to test custom function extensions without polluting the default function extension repository, it is recommended to make an export and use the resulting map to build a new function extension retriever.

```kotlin
Expand All @@ -143,17 +144,22 @@ val jsonPath = JsonPath(jsonPathStatement, functionExtensionRetriever = testRetr
jsonPath.query(buildJsonElement {})
```

## Error handeling
The default compiler uses Napier for reporting errors.
It is possible to implement a custom error listener by extending `AntlrJsonPathCompilerErrorListener` and setting a new default compiler:
## Error Handling
Invalid JSONPath expressions fail during `JsonPath` construction with a `JsonPathCompilerException`. The compiler's error listener only receives diagnostic details; it does not suppress or replace that exception.

On JVM/Android, iOS, macOS, tvOS, JS, and WasmJS, the default listener sends diagnostics to Napier (provided the application has registered an `Antilog`). On watchOS, Linux, Windows (mingw), and Android Native, the default listener is a no-op. Compilation failures still throw on these platforms, but logging requires a custom implementation of `AntlrJsonPathCompilerErrorListener`.

Pass a compiler with that listener to one `JsonPath`, or assign it as the global default:
```kotlin
JsonPath.defaultCompiler = AntlrJsonPathCompiler(
errorListener = object : AntlrJsonPathCompilerErrorListener {
//TODO: IMPLEMENT MEMBERS
},
)
val compiler = AntlrJsonPathCompiler(errorListener = myErrorListener)
val jsonPath = JsonPath(jsonPathExpression, compiler = compiler)

// Optional: use it for subsequent JsonPath instances that do not specify a compiler.
JsonPath.defaultCompiler = compiler
```

Using a single, shared default works because operations only use an ANTLR cache as global state and this cache is guarded to enable concurrent access and mutation.

## Contributing
External contributions are greatly appreciated!
Just be sure to observe the contribution guidelines (see [CONTRIBUTING.md](CONTRIBUTING.md)).
Expand Down
37 changes: 14 additions & 23 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
plugins {
// this is necessary to avoid the plugins to be loaded multiple times
// in each subproject's classloader
alias(libs.plugins.gradle.nexus.publish)
alias(libs.plugins.android.library) apply (false)
}

repositories {
maven("https://maven.pkg.jetbrains.space/kotlin/p/dokka/dev")
mavenCentral()
google()
gradlePluginPortal()
}
import org.gradle.kotlin.dsl.support.listFilesOrdered

nexusPublishing {
nexusPublishing {
repositories {
sonatype {
nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/"))
snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/"))
}
}
}
plugins {
kotlin("multiplatform") version libs.versions.kotlin.get() apply false
kotlin("plugin.serialization") version libs.versions.kotlin.get() apply false
alias(libs.plugins.android.kmp.library) apply false
alias(libs.plugins.asp.conventions)
}

val artifactVersion: String by extra
group = "at.asitplus"
version = artifactVersion
version = artifactVersion

tasks.register<Sync>("dokkaGenerateSite") {
dependsOn(":jsonpath4k:dokkaGeneratePublicationHtml")
from(project(":jsonpath4k").layout.buildDirectory.dir("dokka/html"))
from(rootDir.listFilesOrdered { it.extension.lowercase() == "png" || it.extension.lowercase() == "svg" })
into(rootProject.layout.projectDirectory.dir("docs"))
}
13 changes: 6 additions & 7 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#Gradle
org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M"
# Tests use TestBalloon + the matrix addon (wired in by the asp-conventions plugin).
# Keep the legacy Kotest helper disabled; TestBalloon supplies the Kotest assertion/property integration.
systemProp.KOTEST_NO_ASP_HELPER=true

#Kotlin
kotlin.code.style=official
Expand All @@ -13,11 +16,7 @@ kotlin.mpp.stability.nowarn=true
kotlin.native.ignoreDisabledTargets=true


# workaround dokka bug (need to wait for next snapshot build)
org.jetbrains.dokka.classpath.excludePlatformDependencyFiles=true

artifactVersion = 3.2.0-SNAPSHOT
artifactVersion = 4.0.0-SNAPSHOT
jdk.version=17

android.experimental.lint.version=8.5.0
android.lint.useK2Uast=true
android.minSdk=30
android.compileSdk=34
34 changes: 8 additions & 26 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,33 +1,15 @@
[versions]
antlr-kotlin = "1.0.3"
kotest = "5.9.1"
kotest-plugin = "6.0.0.M1"
jetbrains-kotlin = "2.1.0"
jetbrains-kotlinx-serialization = "1.8.0"
jetbrains-dokka = "1.9.20"
napier = "2.7.1"
gradle-nexus-publish = "2.0.0"
agp = "8.2.2"
kotlin = "2.4.0"
asp-conventions = "20260722"
agp = "9.0.1"
antlr-kotlin = "1.0.12"
testballoon = "1.0.1-K2.4.0"

[libraries]
antlr-kotlin = { group = "com.strumenta", name = "antlr-kotlin-runtime", version.ref = "antlr-kotlin" }
napier = { module = "io.github.aakira:napier", version.ref = "napier" }

kotest-common = { module = "io.kotest:kotest-common", version.ref = "kotest" }
kotest-property = { module = "io.kotest:kotest-property", version.ref = "kotest" }
kotest-assertions-core = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest" }
kotest-framework-engine = { module = "io.kotest:kotest-framework-engine", version.ref = "kotest" }
kotest-framework-datatest = { module = "io.kotest:kotest-framework-datatest", version.ref = "kotest" }
kotest-runner-junit5 = { module = "io.kotest:kotest-runner-junit5", version.ref = "kotest" }

jetbrains-kotlinx-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "jetbrains-kotlinx-serialization" }


[plugins]
asp-conventions = { id = "at.asitplus.gradle.conventions", version.ref = "asp-conventions" }
android-kmp-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" }
antlr-kotlin-plugin = { id = "com.strumenta.antlr-kotlin", version.ref = "antlr-kotlin" }
kotest-multiplatform = { id = "io.kotest.multiplatform", version.ref = "kotest-plugin" }
jetbrains-kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "jetbrains-kotlin" }
jetbrains-kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "jetbrains-kotlin" }
jetbrains-dokka = { id = "org.jetbrains.dokka", version.ref = "jetbrains-dokka" }
gradle-nexus-publish = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "gradle-nexus-publish" }
android-library = {id = "com.android.library", version.ref = "agp"}
testballoon = { id = "de.infix.testBalloon", version.ref = "testballoon" }
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
28 changes: 14 additions & 14 deletions gradlew

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading