summaryrefslogtreecommitdiff
path: root/README.md
blob: 5cefe8c28fed5520cbf84b41b741463cf238e73a (plain)
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
105
106
107
108
# mf2clj

[![Clojars Project](https://img.shields.io/clojars/v/ac.eltr/mf2clj.svg)](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 

```
[ac.eltr/mf2clj "0.0.3"]
```

```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 [just](https://github.com/casey/just) installed. *Why not `make`, you say? Because, my friend, [make is crap](https://invidio.us/watch?v=YjXfjdCmfD4).*

```sh 
# compile Go to WebAssembly (WASIP1)
just build-wasm

# compile Clojure wrapper to .jar
just build-jar # or lein uberjar

# compile both 
just 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])
  (: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 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.