OCaml library for JSONfeed parsing and creation
1(** Feed items in a JSON Feed.
2
3 An item represents a single entry in a feed, such as a blog post, podcast episode,
4 or microblog entry. Each item must have a unique identifier and content.
5
6 @see <https://www.jsonfeed.org/version/1.1/> JSON Feed Specification *)
7
8
9(** The type representing a feed item. *)
10type t
11
12(** Content representation for an item.
13
14 The JSON Feed specification requires that each item has at least one
15 form of content. This type enforces that requirement at compile time.
16
17 - [`Html s]: Item has HTML content only
18 - [`Text s]: Item has plain text content only
19 - [`Both (html, text)]: Item has both HTML and plain text versions *)
20type content =
21 [ `Html of string
22 | `Text of string
23 | `Both of string * string
24 ]
25
26
27(** {1 Construction} *)
28
29(** [create ~id ~content ?url ?external_url ?title ?summary ?image ?banner_image
30 ?date_published ?date_modified ?authors ?tags ?language ?attachments ()]
31 creates a feed item.
32
33 @param id Unique identifier for the item (required). Should be a full URL if possible.
34 @param content The item's content in HTML and/or plain text (required)
35 @param url Permalink to the item
36 @param external_url URL of an external resource (useful for linkblogs)
37 @param title Plain text title of the item
38 @param summary Plain text summary/excerpt of the item
39 @param image URL of the main featured image for the item
40 @param banner_image URL of a banner image for the item
41 @param date_published Publication date/time (RFC 3339 format)
42 @param date_modified Last modification date/time (RFC 3339 format)
43 @param authors Item-specific authors (overrides feed-level authors)
44 @param tags Plain text tags/categories for the item
45 @param language Primary language of the item (RFC 5646 format, e.g. ["en-US"])
46 @param attachments Related resources like audio files or downloads
47 @param references References to cited sources (extension)
48
49 {b Examples:}
50 {[
51 (* Simple blog post *)
52 let item = Item.create
53 ~id:"https://example.com/posts/42"
54 ~content:(`Html "<p>Hello, world!</p>")
55 ~title:"My First Post"
56 ~url:"https://example.com/posts/42" ()
57
58 (* Microblog entry with plain text *)
59 let item = Item.create
60 ~id:"https://example.com/micro/123"
61 ~content:(`Text "Just posted a new photo!")
62 ~date_published:(Ptime.of_float_s (Unix.time ()) |> Option.get) ()
63
64 (* Article with both HTML and plain text *)
65 let item = Item.create
66 ~id:"https://example.com/article/99"
67 ~content:(`Both ("<p>Rich content</p>", "Plain version"))
68 ~title:"Article Title"
69 ~tags:["ocaml"; "programming"] ()
70
71 (* Podcast episode with attachment *)
72 let attachment = Attachment.create
73 ~url:"https://example.com/ep1.mp3"
74 ~mime_type:"audio/mpeg"
75 ~duration_in_seconds:1800 () in
76 let item = Item.create
77 ~id:"https://example.com/podcast/1"
78 ~content:(`Html "<p>Episode description</p>")
79 ~title:"Episode 1"
80 ~attachments:[attachment] ()
81
82 (* Article with references *)
83 let reference = Reference.create
84 ~url:"https://doi.org/10.5281/zenodo.16755947"
85 ~doi:"10.5281/zenodo.16755947"
86 ~cito:[`CitesAsRecommendedReading; `UsesMethodIn] () in
87 let item = Item.create
88 ~id:"https://doi.org/10.59350/krw9n-dv417"
89 ~content:(`Html "<p>Research article content</p>")
90 ~title:"One Million IUPAC names #4: a lot is happening"
91 ~url:"https://chem-bla-ics.linkedchemistry.info/2025/08/09/one-million-iupac-names-4.html"
92 ~references:[reference] ()
93 ]} *)
94val create :
95 id:string ->
96 content:content ->
97 ?url:string ->
98 ?external_url:string ->
99 ?title:string ->
100 ?summary:string ->
101 ?image:string ->
102 ?banner_image:string ->
103 ?date_published:Ptime.t ->
104 ?date_modified:Ptime.t ->
105 ?authors:Author.t list ->
106 ?tags:string list ->
107 ?language:string ->
108 ?attachments:Attachment.t list ->
109 ?references:Reference.t list ->
110 unit ->
111 t
112
113
114(** {1 Accessors} *)
115
116(** [id t] returns the item's unique identifier. *)
117val id : t -> string
118
119(** [content t] returns the item's content. *)
120val content : t -> content
121
122(** [url t] returns the item's permalink URL, if set. *)
123val url : t -> string option
124
125(** [external_url t] returns the external resource URL, if set. *)
126val external_url : t -> string option
127
128(** [title t] returns the item's title, if set. *)
129val title : t -> string option
130
131(** [summary t] returns the item's summary, if set. *)
132val summary : t -> string option
133
134(** [image t] returns the item's featured image URL, if set. *)
135val image : t -> string option
136
137(** [banner_image t] returns the item's banner image URL, if set. *)
138val banner_image : t -> string option
139
140(** [date_published t] returns the item's publication date, if set. *)
141val date_published : t -> Ptime.t option
142
143(** [date_modified t] returns the item's last modification date, if set. *)
144val date_modified : t -> Ptime.t option
145
146(** [authors t] returns the item's authors, if set. *)
147val authors : t -> Author.t list option
148
149(** [tags t] returns the item's tags, if set. *)
150val tags : t -> string list option
151
152(** [language t] returns the item's language code, if set. *)
153val language : t -> string option
154
155(** [attachments t] returns the item's attachments, if set. *)
156val attachments : t -> Attachment.t list option
157
158(** [references t] returns the item's references, if set. *)
159val references : t -> Reference.t list option
160
161
162(** {1 Content Helpers} *)
163
164(** [content_html t] extracts HTML content from the item.
165
166 Returns [Some html] if the item has HTML content (either [Html] or [Both]),
167 [None] otherwise. *)
168val content_html : t -> string option
169
170(** [content_text t] extracts plain text content from the item.
171
172 Returns [Some text] if the item has plain text content (either [Text] or [Both]),
173 [None] otherwise. *)
174val content_text : t -> string option
175
176
177(** {1 Comparison} *)
178
179(** [equal a b] tests equality between two items.
180
181 Items are considered equal if they have the same ID. *)
182val equal : t -> t -> bool
183
184(** [compare a b] compares two items by their publication dates.
185
186 Items without publication dates are considered older than items with dates.
187 Useful for sorting items chronologically. *)
188val compare : t -> t -> int
189
190
191(** {1 Pretty Printing} *)
192
193(** [pp ppf t] pretty prints an item to the formatter.
194
195 The output is human-readable and suitable for debugging.
196
197 {b Example output:}
198 {v [2024-11-03] My First Post (https://example.com/posts/42) v} *)
199val pp : Format.formatter -> t -> unit
200
201(** [pp_content ppf content] pretty prints content to the formatter.
202
203 {b Example output:}
204 {v HTML (123 chars) v}
205 {v Text (56 chars) v}
206 {v Both (HTML: 123 chars, Text: 56 chars) v} *)
207val pp_content : Format.formatter -> content -> unit