From b85d76db3e17188ee73d5c0455e8b1976ce9a5cc Mon Sep 17 00:00:00 2001 From: eltrac Date: Sun, 20 Sep 2026 15:55:47 +0800 Subject: clj: finish clojure wrapper of wasm add README.md --- .gitignore | 4 +++ Makefile | 6 +++++ README.md | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++ go/Makefile | 2 -- project.clj | 10 ++++++++ src/mf2clj/core.clj | 19 ++++++++++++++ 6 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 README.md delete mode 100644 go/Makefile create mode 100644 project.clj create mode 100644 src/mf2clj/core.clj diff --git a/.gitignore b/.gitignore index 6572aed..d3be789 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ /.clj-kondo/.cache/v1 /.lsp/.cache /resources/mf2go.wasm +/.lein-repl-history +/.nrepl-port +/target +/native/ diff --git a/Makefile b/Makefile index 5f54d8c..3995594 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,9 @@ build-wasm: @cd go && tinygo build -o ../resources/mf2go.wasm -target wasip1 -buildmode=c-shared main.go +build-jar: + @lein uberjar + +build: + @make build-wasm + @make build-jar diff --git a/README.md b/README.md new file mode 100644 index 0000000..a00007c --- /dev/null +++ b/README.md @@ -0,0 +1,72 @@ +# mf2clj + +A Clojure library that parses [microformats](http://microformats.org/). Under the hood, it's a thin wrapper of a [Extism](https://extism.org/) plugin written in Go (source of which is also in this repository), and the plugin itself is a wrapper of Will Norris' [microformats parser](https://github.com/willnorris/microformats). *Yes, that's a lot of wrappers! I have a good excuse for that.* + +## How It Works + +1. `go/main.go` defines `parse()` function, which wraps [microformats.Parse()](https://pkg.go.dev/willnorris.com/go/microformats#Parse) and makes it callable after compiled to WebAssembly. +2. `src/mf2clj/core.clj` loads compile `mf2go.wasm` from `resources/` and calls `parse`. +3. User/client calls `mf2clj.core/parse` with no knowledge of the wrappers and WebAssembly. + +The code is so simple that you're probably better off copy-pasting it to your codebase directly. + +```go +// go/main.go +package main + +import ( + "bytes" + + "github.com/extism/go-pdk" + "willnorris.com/go/microformats" +) + +//go:wasmexport parse +func parse() int32 { + input := pdk.Input() + r := bytes.NewReader(input) + data := microformats.Parse(r, nil) + + pdk.OutputJSON(data) + return 0 +} +``` + +```clojure +;; src/mf2clj/core.clj +(ns mf2clj.core + (:require [clojure.java.io :as io]) + (:import [org.extism.sdk.chicory Manifest ManifestWasm Plugin] + [java.nio.charset StandardCharsets])) + +(defn- manifest-from-wasm [wasm] + (Manifest/ofWasms (into-array ManifestWasm [wasm]))) + +(def plugin + (-> "mf2go.wasm" io/resource io/input-stream .readAllBytes + ManifestWasm/fromBytes .build + manifest-from-wasm .build + Plugin/ofManifest .build)) + +(defn parse [html-string] + (let [charset StandardCharsets/UTF_8 + html-bytes (.getBytes html-string charset)] + (String. (.call plugin "parse" html-bytes) charset))) +``` + +Seriously, that's all of it. + +## *What's your excuse?* + +microformats is a very *niche* standard that's only popular*-ish* in the [IndieWeb](https://indieweb.org/) community. Clojure is more niche even within this small community. It makes no sense to develop and maintain a *native* Clojure parser. + +Currently, the closest thing available is [this library](https://codeberg.org/alinnow/microformats) by [Alin](https://codeberg.org/alinnow), whose last commit was in 2014. The next best thing would be a Java library since Clojure can call Java code with no problem, but [mf2j](https://github.com/karadaisy/mf2j) hasn't been updated since 2026. Both libraries is **incomplete**. + +I see no reason why a new Clojure/Java parser wouldn't be abandoned either. + +The [go parser](https://github.com/willnorris/microformats) isn't exactly actively maintained, but at least it's complete and stable. It just makes more sense to use an existing stable library. + +Programming languages aren't really a barrier any more. Many languages can compile to WebAssembly and even more can run WebAssembly. So here we are: A Clojure library that runs WebAssembly written in Go under the hood. + +I suppose I could use [Rust](https://crates.io/crates/microformats/0.2.0), but it doesn't really make a difference. + diff --git a/go/Makefile b/go/Makefile deleted file mode 100644 index 45477be..0000000 --- a/go/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -build-wasm: - @tinygo build -o mf2go.wasm -target wasip1 -buildmode=c-shared main.go diff --git a/project.clj b/project.clj new file mode 100644 index 0000000..0eba58d --- /dev/null +++ b/project.clj @@ -0,0 +1,10 @@ +(defproject mf2clj "v0.0.1" + :description "A Clojure wrapper of Will Norris' microformats parser in Go, which runs WebAssembly under the hood." + :url "https://src.eltr.ac/eltrac/mf2clj" + :min-lein-version "2.0.0" + :dependencies [[org.clojure/clojure "1.12.4"] + [org.extism.sdk/chicory-sdk-core "0.3.0"]] + :profiles {:uberjar {:aot :all}} + :license {:name "GNU Affero General Public License" + :url "https://www.gnu.org/licenses/agpl-3.0.html" + :distribution :repo}) diff --git a/src/mf2clj/core.clj b/src/mf2clj/core.clj new file mode 100644 index 0000000..8d655b1 --- /dev/null +++ b/src/mf2clj/core.clj @@ -0,0 +1,19 @@ +(ns mf2clj.core + (:require [clojure.java.io :as io]) + (:import [org.extism.sdk.chicory Manifest ManifestWasm Plugin] + [java.nio.charset StandardCharsets])) + +(defn- manifest-from-wasm [wasm] + (Manifest/ofWasms (into-array ManifestWasm [wasm]))) + +(def plugin + (-> "mf2go.wasm" io/resource io/input-stream .readAllBytes + ManifestWasm/fromBytes .build + manifest-from-wasm .build + Plugin/ofManifest .build)) + +(defn parse [html-string] + (let [charset StandardCharsets/UTF_8 + html-bytes (.getBytes html-string charset)] + (String. (.call plugin "parse" html-bytes) charset))) + -- cgit v1.2.3