https://github.com/aygp-dr/atom-validator
Clojure library for RFC 4287 Atom feed validation. Validates required elements, content types, date formats. Publishes to Clojars.
https://github.com/aygp-dr/atom-validator
atom clojure feed property-based-testing rfc4287 validation
Last synced: about 14 hours ago
JSON representation
Clojure library for RFC 4287 Atom feed validation. Validates required elements, content types, date formats. Publishes to Clojars.
- Host: GitHub
- URL: https://github.com/aygp-dr/atom-validator
- Owner: aygp-dr
- License: mit
- Created: 2026-06-19T15:40:21.000Z (5 days ago)
- Default Branch: main
- Last Pushed: 2026-06-22T18:11:21.000Z (2 days ago)
- Last Synced: 2026-06-23T03:22:32.123Z (1 day ago)
- Topics: atom, clojure, feed, property-based-testing, rfc4287, validation
- Language: Clojure
- Size: 1.68 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.org
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.org
- License: LICENSE
Awesome Lists containing this project
README
#+TITLE: atom-validator
#+AUTHOR: aygp-dr
#+DATE: 2026-06-19
[[https://github.com/aygp-dr/atom-validator/actions/workflows/ci.yml][https://img.shields.io/github/actions/workflow/status/aygp-dr/atom-validator/ci.yml.svg?branch=main&label=CI]]
[[https://clojars.org/org.clojars.apace/atom-validator][https://img.shields.io/clojars/v/org.clojars.apace/atom-validator.svg]]
[[https://cljdoc.org/d/org.clojars.apace/atom-validator][https://img.shields.io/badge/cljdoc-docs-blue.svg]]
[[https://opensource.org/licenses/MIT][https://img.shields.io/badge/License-MIT-blue.svg]]
[[https://datatracker.ietf.org/doc/html/rfc4287][RFC 4287]] Atom feed validator with property-based testing for Clojure.
* Features
- Structural validation per [[https://datatracker.ietf.org/doc/html/rfc4287][RFC 4287]] (required elements, dates)
- Semantic checks (day-of-week in titles, feed freshness)
- URL/IRI validation (detects typos like =wal.shsite= → =wal.sh/site=)
- Property-based testing with [[https://github.com/clojure/test.check][test.check]] generators
* Installation
** deps.edn
#+begin_src clojure
{:deps {org.clojars.apace/atom-validator {:mvn/version "RELEASE"}}}
#+end_src
** Leiningen
#+begin_src clojure
[org.clojars.apace/atom-validator "RELEASE"]
#+end_src
* Development Workflow
Org-mode literate programming with live REPL evaluation:
[[file:images/04-error-handling.png]]
See [[file:doc/emacs-setup.org][Emacs setup guide]] for configuration.
* Quick Start
** Require the namespace
#+begin_src clojure
(require '[atom-validator.core :as v])
#+end_src
** Validate a feed map
#+begin_src clojure
(def feed {:id "urn:uuid:feed-1"
:title "My Blog"
:updated "2026-06-19T12:00:00Z"
:entries [{:id "urn:uuid:entry-1"
:title "Morning Brief: Thursday, June 19"
:updated "2026-06-19T00:00:00Z"
:links [{:href "https://example.com/1/" :rel "alternate"}]}]})
(v/validate-feed feed)
;; => {:valid? false
;; :errors [{:type :error
;; :code :day-of-week-mismatch
;; :message "Title says 'Thursday' but updated date is a Friday"
;; :path [:entries 0 :title]}]
;; :warnings []}
#+end_src
** Parse and validate XML
#+begin_src clojure
(def feed-xml "
urn:uuid:feed-1
My Blog
2026-06-19T12:00:00Z
")
(v/validate-feed feed-xml)
;; => {:valid? true :errors [] :warnings [...]}
#+end_src
* REPL Examples
** Start the REPL
#+begin_src bash
# With [[https://docs.cider.mx][CIDER]] middleware for Emacs
make repl
# Or with [[https://github.com/flow-storm/flow-storm-debugger][FlowStorm]] time-travel debugger
make storm
#+end_src
** Fetch and validate a real Atom feed
#+begin_src clojure
(require '[atom-validator.core :as v]
'[clojure.java.io :as io])
;; Fetch a real Atom feed (GitHub releases)
(def github-feed
(slurp "https://github.com/clojure/clojure/releases.atom"))
(def result (v/validate-feed github-feed))
(:valid? result)
;; => true (or false with :errors)
;; Check specific errors
(map :code (:errors result))
;; => (:stale-feed-updated :invalid-url-host ...)
#+end_src
** Generate random valid feeds (for testing)
#+begin_src clojure
(require '[clojure.test.check.generators :as gen]
'[atom-validator.generators :as g])
;; Generate a valid Atom feed
(gen/generate g/gen-valid-atom-feed)
;; => {:id "urn:uuid:..."
;; :title "Article Update"
;; :updated "2025-03-15T14:22:33Z"
;; :entries [...]}
;; Generate an entry with day-of-week mismatch (for testing Issue #1)
(gen/generate (g/gen-entry-with-mismatched-day))
;; => {:title "Morning Brief: Thursday, June 19"
;; :updated "2026-06-19T00:00:00Z" ; Friday!
;; ...}
;; Generate a feed with stale updated timestamp (for testing Issue #2)
(gen/generate (g/gen-feed-with-stale-updated))
;; => {:updated "2026-06-14T..."
;; :entries [{:updated "2026-06-19T..." ...}]} ; newer than feed!
#+end_src
** Interactive validation workflow
#+begin_src clojure
;; Step 1: Parse the feed
(def feed (v/parse-feed github-feed))
(:title feed)
;; => "Release notes from clojure"
;; Step 2: Check feed metadata
(count (:entries feed))
;; => 10
;; Step 3: Validate individual entries
(v/validate-entry (first (:entries feed)))
;; => {:valid? true ...}
;; Step 4: Find problematic entries
(->> (:entries feed)
(map-indexed (fn [i e] [i (:title e) (:valid? (v/validate-entry e))]))
(filter (fn [[_ _ valid?]] (not valid?))))
;; => ([3 "Bad Entry Title" false] ...)
#+end_src
* Validation Rules
| Issue | Check | Error Code |
|-------+-------+------------|
| #1 | Title day-of-week matches == date | =:day-of-week-mismatch= |
| #2 | Feed == >= max(entry ==) | =:stale-feed-updated= |
| #3 | Entry URLs are valid absolute URLs | =:invalid-url-host= |
* Development
** Commands
| Command | Description |
|---------+-------------|
| =make test= | Run unit tests + property-based tests |
| =make lint= | Run [[https://github.com/clj-kondo/clj-kondo][clj-kondo]] static analysis |
| =make repl= | Start [[https://docs.cider.mx][CIDER]]-enabled [[https://nrepl.org][nREPL]] on port 7888 |
| =make storm= | Start [[https://github.com/flow-storm/flow-storm-debugger][FlowStorm]] time-travel debugger |
| =make check= | Run lint + test |
| =make jar= | Build JAR file |
| =make install= | Install to local Maven repo |
| =make deploy= | Deploy to [[https://clojars.org][Clojars]] (requires credentials) |
** Connect from Emacs
#+begin_src bash
# Terminal 1: Start REPL in [[https://github.com/tmux/tmux][tmux]]
tmux new-session -s atom-validator -d 'make repl'
# Emacs: Connect
M-x cider-connect RET localhost RET 7888
#+end_src
** Project Structure
| File | Description |
|------+-------------|
| [[file:src/atom_validator/core.clj][core.clj]] | Main API: validate-feed, validate-entry, parse-feed |
| [[file:src/atom_validator/parser.clj][parser.clj]] | XML parsing with [[https://github.com/clojure/data.xml][clojure.data.xml]] |
| [[file:src/atom_validator/rules.clj][rules.clj]] | [[https://datatracker.ietf.org/doc/html/rfc4287][RFC 4287]] structural validation |
| [[file:src/atom_validator/semantic.clj][semantic.clj]] | Semantic checks (day-of-week) |
| [[file:src/atom_validator/url.clj][url.clj]] | URL/IRI validation |
| [[file:test/atom_validator/core_test.clj][core_test.clj]] | Unit + property-based tests |
| [[file:test/atom_validator/generators.clj][generators.clj]] | [[https://github.com/clojure/test.check][test.check]] generators for Atom feeds |
* API Reference
** =validate-feed=
#+begin_src clojure
(v/validate-feed feed)
(v/validate-feed feed {:semantic? true :strict? false})
#+end_src
Returns ={:valid? bool :errors [...] :warnings [...] :feed parsed-map}=
Options:
- =:semantic?= - Enable semantic checks like day-of-week (default =true=)
- =:strict?= - Treat warnings as errors (default =false=)
** =validate-entry=
#+begin_src clojure
(v/validate-entry entry)
(v/validate-entry entry {:semantic? true})
#+end_src
Returns ={:valid? bool :errors [...] :warnings [...]}=
** =parse-feed=
#+begin_src clojure
(v/parse-feed xml-string-or-input-stream)
#+end_src
Returns parsed feed as Clojure map with =:id=, =:title=, =:updated=, =:entries=, etc.
** =valid?=
#+begin_src clojure
(v/valid? feed)
(v/valid? feed {:semantic? false})
#+end_src
Quick check - returns =true= or =false=.
* License
MIT
* Related
- [[https://datatracker.ietf.org/doc/html/rfc4287][RFC 4287 - The Atom Syndication Format]]
- [[https://validator.w3.org/feed/][W3C Feed Validation Service]]