diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index dd6ac9a..a772d51 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -34,7 +34,7 @@ jobs: # Configure Gradle for optimal use in GitHub Actions, including caching of downloaded dependencies. # See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md - name: Setup Gradle - uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 + uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 - name: Build with Gradle Wrapper run: ./gradlew build @@ -57,7 +57,7 @@ jobs: distribution: 'temurin' - name: Setup Gradle - uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 + uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 - name: Build with Gradle Wrapper run: ./gradlew koverXmlReport @@ -88,5 +88,5 @@ jobs: # Generates and submits a dependency graph, enabling Dependabot Alerts for all project dependencies. # See: https://github.com/gradle/actions/blob/main/dependency-submission/README.md - name: Generate and submit dependency graph - uses: gradle/actions/dependency-submission@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 + uses: gradle/actions/dependency-submission@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 1e16934..3efb2d8 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 2758df8..756b302 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -4,7 +4,7 @@ - + \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..f1863f1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,73 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +OpenGraphKt is a minimalist Kotlin multiplatform library for parsing Open Graph protocol tags from HTML. It wraps Ksoup (a Kotlin port of JSoup) to extract and structure Open Graph metadata. + +**Current Status**: Pre-alpha - Protocol implementation is complete for `og:` tags, but type system needs refinement. + +## Project Structure + +This is a multi-module Gradle project: + +- `opengraphkt/` - Core library module (published to Maven Central as `fr.lengrand:opengraphkt`) +- `demo/` - Local file parsing examples +- `demo-remote/` - Remote URL parsing examples (see Main.kt for usage) +- `scrape-test/` - Testing/scraping utilities + +## Common Commands + +### Build and Test +```bash +./gradlew build # Build all modules +./gradlew test # Run all tests +./gradlew :opengraphkt:test # Run tests for core library only +``` + +### Code Coverage +```bash +./gradlew koverXmlReport # Generate XML coverage report +./gradlew koverVerify # Verify coverage meets 70% minimum threshold +``` + +### Publishing +```bash +./gradlew publishToMavenLocal # Publish to local Maven repo for testing +``` + +## Architecture + +### Core Components + +**Parser (`Parser.kt`)**: Main entry point that accepts multiple input types: +- `parse(url: URL)` - Fetches and parses remote HTML +- `parse(html: String)` - Parses raw HTML string +- `parse(file: File)` - Parses local HTML file +- `parse(document: Document)` - Parses Ksoup Document + +The parser extracts `meta[property^=og:]` tags and builds structured data models. + +**Data Models (`Models.kt`)**: Type-safe representations of Open Graph data: +- `Data` - Main container with `isValid()` method checking required fields (title, type, image, url) +- Base types: `Image`, `Video`, `Audio` +- Content-specific types: `Article`, `Book`, `Profile` +- Music types: `MusicSong`, `MusicAlbum`, `MusicPlaylist`, `MusicRadioStation` +- Video types: `VideoMovie`, `VideoEpisode` + +### Key Implementation Details + +**Tag Grouping**: Tags are grouped by namespace (prefix before first colon) to handle structured properties like `og:image:width`, `og:image:height` that belong to the preceding `og:image` tag. + +**Date Handling**: ISO 8601 datetime parsing with fallback for date-only formats (appends `T00:00:00Z`). + +**Structured Property Association**: Images/Videos/Audio with their metadata (width, height, type, etc.) are associated by parsing sequential tags - each base tag (`og:image`) is paired with following attribute tags (`og:image:width`) until the next base tag. + +## Development Notes + +- **JVM Toolchain**: Java 24 (see `jvmToolchain(24)` in build files) +- **Testing**: CI matrix tests on Java 17 and 23 via GitHub Actions +- **Dependencies**: Core library uses Ksoup (v0.2.5) for HTML parsing and network requests +- **Maven Coordinates**: Group `fr.lengrand`, artifact `opengraphkt`, currently at `0.1.2-SNAPSHOT` +- **Code Coverage**: Kover plugin enforces 70% minimum coverage threshold diff --git a/build.gradle.kts b/build.gradle.kts index 50f2ab2..17b387b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,3 @@ plugins { - kotlin("jvm") version "2.1.21" apply false + kotlin("jvm") version "2.2.20" apply false } \ No newline at end of file diff --git a/demo-remote/build.gradle.kts b/demo-remote/build.gradle.kts index 0e72d45..8d69871 100644 --- a/demo-remote/build.gradle.kts +++ b/demo-remote/build.gradle.kts @@ -19,7 +19,7 @@ tasks.test { } kotlin { - jvmToolchain(23) + jvmToolchain(24) } application { diff --git a/demo/build.gradle.kts b/demo/build.gradle.kts index f749742..9030d4b 100644 --- a/demo/build.gradle.kts +++ b/demo/build.gradle.kts @@ -12,9 +12,9 @@ repositories { } dependencies { - implementation("com.fleeksoft.ksoup:ksoup:0.2.4") - implementation("com.fleeksoft.ksoup:ksoup-kotlinx:0.2.4") - implementation("com.fleeksoft.ksoup:ksoup-network:0.2.4") + implementation("com.fleeksoft.ksoup:ksoup:0.2.5") + implementation("com.fleeksoft.ksoup:ksoup-kotlinx:0.2.5") + implementation("com.fleeksoft.ksoup:ksoup-network:0.2.5") implementation(project(":opengraphkt")) testImplementation(kotlin("test")) } @@ -24,7 +24,7 @@ tasks.test { } kotlin { - jvmToolchain(23) + jvmToolchain(24) } application { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ff23a68..d4081da 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/opengraphkt/build.gradle.kts b/opengraphkt/build.gradle.kts index 27a03f0..775d2f8 100644 --- a/opengraphkt/build.gradle.kts +++ b/opengraphkt/build.gradle.kts @@ -14,9 +14,9 @@ repositories { } dependencies { - implementation("com.fleeksoft.ksoup:ksoup:0.2.4") - implementation("com.fleeksoft.ksoup:ksoup-kotlinx:0.2.4") - implementation("com.fleeksoft.ksoup:ksoup-network:0.2.4") + implementation("com.fleeksoft.ksoup:ksoup:0.2.5") + implementation("com.fleeksoft.ksoup:ksoup-kotlinx:0.2.5") + implementation("com.fleeksoft.ksoup:ksoup-network:0.2.5") testImplementation(kotlin("test")) } @@ -36,7 +36,7 @@ tasks.jar { } kotlin { - jvmToolchain(23) + jvmToolchain(24) } mavenPublishing { diff --git a/scrape-test/build.gradle.kts b/scrape-test/build.gradle.kts index 9c23c86..bf5d03e 100644 --- a/scrape-test/build.gradle.kts +++ b/scrape-test/build.gradle.kts @@ -11,18 +11,18 @@ repositories { } dependencies { - testImplementation(platform("org.junit:junit-bom:5.13.1")) + testImplementation(platform("org.junit:junit-bom:5.14.0")) testImplementation("org.junit.jupiter:junit-jupiter") implementation(kotlin("stdlib-jdk8")) implementation(project(":opengraphkt")) - implementation("io.ktor:ktor-client-core:3.1.3") - implementation("io.ktor:ktor-client-cio:3.1.3") + implementation("io.ktor:ktor-client-core:3.3.1") + implementation("io.ktor:ktor-client-cio:3.3.1") } tasks.test { useJUnitPlatform() } kotlin { - jvmToolchain(23) + jvmToolchain(24) } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index c60c12f..26c2154 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,6 @@ pluginManagement { plugins { - kotlin("jvm") version "2.1.21" + kotlin("jvm") version "2.2.20" } } plugins {