1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
# mf2clj
[](https://clojars.org/ac.eltr/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.*
## Usage
```clojure
(require '[mf2clj.core :as mf2clj])
(mf2clj/parse html-string)
```
## Development
Make sure you have [tinygo](https://tinygo.org/) compiler, [Leiningen](https://leiningen.org/) and [Babashka](http://babashka.org/) installed.
Run the following command to build WebAseembly and `.jar`.
```sh
bb build
```
---
## 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 compiled `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]
[clojure.walk :refer [keywordize-keys]]
[cheshire.core :as json])
(: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)]
(-> (.call plugin "parse" html-bytes)
(String. charset)
json/parse-string
keywordize-keys)))
```
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 2016. Both libraries are **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.
---
## License
mf2clj is free software licensed under the GNU Affero General Public License.
|