Skip to main content

textlane_html/models/
options.rs

1use std::collections::{BTreeMap, HashMap};
2
3use serde::Deserialize;
4
5/// `html.stringify`: hast into HTML; options named as hast-util-to-html names them.
6#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
7#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
8#[serde(default, rename_all = "camelCase")]
9#[cfg_attr(feature = "schema", schemars(rename = "StringifyOptions"))]
10pub struct Stringify {
11    /// Write raw nodes as they are instead of escaping them.
12    pub allow_dangerous_html: bool,
13    /// Leave characters that are only dangerous in some contexts, such as `` ` ``, as they are.
14    pub allow_dangerous_characters: bool,
15    /// Leave characters as they are where browsers accept them though the spec does not.
16    pub allow_parse_errors: bool,
17    /// Write comments as bogus comments, `<?a>`.
18    pub bogus_comments: bool,
19    /// Close empty foreign elements, `<a />`.
20    pub close_empty_elements: bool,
21    /// Close void elements, `<br />`.
22    pub close_self_closing: bool,
23    /// Write empty attributes as bare names, `a` rather than `a=""`.
24    pub collapse_empty_attributes: bool,
25    /// Leave out tags the HTML spec lets a parser imply.
26    pub omit_optional_tags: bool,
27    /// Leave attribute values unquoted where that is safe.
28    pub prefer_unquoted: bool,
29    /// The quote attribute values are wrapped in: `"` or `'`.
30    pub quote: Option<String>,
31    /// Use the other quote when the value holds more of the preferred one.
32    pub quote_smart: bool,
33    /// The space the tree is in: `html` or `svg`.
34    pub space: Option<String>,
35    /// Leave out the space between quoted attributes.
36    pub tight_attributes: bool,
37    /// Join comma-separated values with `,` rather than `, `.
38    pub tight_comma_separated_lists: bool,
39    /// Write `<!doctypehtml>`.
40    pub tight_doctype: bool,
41    /// Leave out the space before `/>` when the attributes allow.
42    pub tight_self_closing: bool,
43    /// Write `<!DOCTYPE html>`.
44    pub upper_doctype: bool,
45    /// The tag names of void elements, which have no closing tag.
46    pub voids: Option<Vec<String>>,
47}
48
49/// `html.parse`: HTML into hast; options named as rehype-parse names them.
50#[derive(Clone, Debug, Default, Deserialize)]
51#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
52#[serde(default, rename_all = "camelCase")]
53#[cfg_attr(feature = "schema", schemars(rename = "ParseOptions"))]
54pub struct Parse {
55    /// Parse a fragment, as in a `template`, rather than a whole document.
56    pub fragment: bool,
57    /// Report parse errors as messages on the file.
58    pub emit_parse_errors: bool,
59    /// Add the positions of opening and closing tags and attributes to elements.
60    pub verbose: bool,
61}
62
63/// `html.sanitize`: keep only what a schema allows; options: hast-util-sanitize's schema,
64/// where a field left out keeps the default schema's, which is GitHub's.
65#[derive(Clone, Debug, Default, Deserialize)]
66#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
67#[serde(default, rename_all = "camelCase")]
68#[cfg_attr(feature = "schema", schemars(rename = "SanitizeOptions"))]
69pub struct Sanitize {
70    /// Keep comments.
71    pub allow_comments: Option<bool>,
72    /// Keep doctypes.
73    pub allow_doctypes: Option<bool>,
74    /// Elements allowed only inside one of these ancestors, by tag name.
75    pub ancestors: Option<HashMap<String, Vec<String>>>,
76    /// Properties allowed per tag name, `*` for every element; a list names a property and
77    /// the values it may have.
78    pub attributes: Option<HashMap<String, Vec<AttributeDefinition>>>,
79    /// Properties whose values get `clobber_prefix`, so they cannot clobber globals.
80    pub clobber: Option<Vec<String>>,
81    /// The prefix of clobbered values.
82    pub clobber_prefix: Option<String>,
83    /// URL properties and the protocols they may use.
84    pub protocols: Option<HashMap<String, Vec<String>>>,
85    /// Properties set on elements whatever they had, by tag name.
86    pub required: Option<HashMap<String, BTreeMap<String, Primitive>>>,
87    /// Elements dropped with their content rather than unwrapped.
88    pub strip: Option<Vec<String>>,
89    /// The elements kept.
90    pub tag_names: Option<Vec<String>>,
91}
92
93/// A property a sanitize schema allows: by name, or a name and its allowed values.
94#[derive(Clone, Debug, Deserialize)]
95#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
96#[serde(untagged)]
97pub enum AttributeDefinition {
98    Name(String),
99    Values(Vec<Primitive>),
100}
101
102/// A primitive property value.
103#[derive(Clone, Debug, PartialEq, Deserialize)]
104#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
105#[serde(untagged)]
106pub enum Primitive {
107    Boolean(bool),
108    Number(f64),
109    String(String),
110}
111
112/// `html.highlight`: code blocks colored as Shiki colors them, natively by giallo;
113/// options named as @shikijs/rehype names them.
114#[derive(Clone, Debug, Default, Deserialize)]
115#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
116#[serde(default, rename_all = "camelCase")]
117#[cfg_attr(feature = "schema", schemars(rename = "HighlightOptions"))]
118pub struct Highlight {
119    /// The theme of each color mode, `light` first, as `{"light": …, "dark": …}`.
120    pub themes: Option<serde_json::Map<String, serde_json::Value>>,
121    /// The one theme, when `themes` is not given.
122    pub theme: Option<String>,
123    /// The language of a block that names none; such a block is left alone without it.
124    pub default_language: Option<String>,
125    /// The language of a block naming one Shiki does not know; left alone without it.
126    pub fallback_language: Option<String>,
127    /// Colors to replace, by their lowercase spelling: a color for every theme, or a theme's
128    /// name to a map of its own.
129    pub color_replacements: BTreeMap<String, ColorReplacement>,
130    /// Add `language-<name>` to each highlighted `<code>`.
131    pub add_language_class: bool,
132    /// Highlight inline code too, by how it names its language: `tailing-curly-colon`
133    /// reads `` `a(){:js}` ``.
134    pub inline: Option<InlineCode>,
135    /// The `<pre>` property that gets a block's meta, the text after its language; the JSON
136    /// stand-in for `parseMetaString: meta => ({ [name]: meta })`.
137    pub meta_property: Option<String>,
138    /// The transformers of @shikijs/transformers to run, in order, by name or with options.
139    pub transformers: Vec<HighlightTransformer>,
140    /// Lines at least this long, in UTF-16 units, are left one plain token as Shiki's own
141    /// option leaves them; 2,000 when left out, where Shiki has no limit, since a grammar's
142    /// time grows with the square of a line's length. `0` lifts it.
143    pub tokenize_max_line_length: Option<usize>,
144}
145
146/// A replacement color, or a theme's own replacements.
147#[derive(Clone, Debug, Deserialize)]
148#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
149#[serde(untagged)]
150pub enum ColorReplacement {
151    Color(String),
152    Theme(BTreeMap<String, String>),
153}
154
155/// How inline code names its language.
156#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize)]
157#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
158pub enum InlineCode {
159    #[serde(rename = "tailing-curly-colon")]
160    TailingCurlyColon,
161}
162
163/// A transformer of @shikijs/transformers: its name alone, or its name and options.
164#[derive(Clone, Debug, Deserialize)]
165#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
166#[serde(untagged)]
167pub enum HighlightTransformer {
168    Name(TransformerName),
169    Configured(ConfiguredTransformer),
170}
171
172/// The transformers `html.highlight` runs natively.
173#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize)]
174#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
175#[serde(rename_all = "camelCase")]
176pub enum TransformerName {
177    NotationDiff,
178    NotationFocus,
179    NotationHighlight,
180    NotationErrorLevel,
181    MetaHighlight,
182    MetaWordHighlight,
183    RenderLineNumber,
184}
185
186/// A transformer with its options, as @shikijs/transformers names them.
187#[derive(Clone, Debug, Deserialize)]
188#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
189#[serde(tag = "name", rename_all = "camelCase")]
190pub enum ConfiguredTransformer {
191    /// `[!code ++]` and `[!code --]` mark added and removed lines.
192    #[serde(rename_all = "camelCase")]
193    NotationDiff {
194        class_line_add: Option<Classes>,
195        class_line_remove: Option<Classes>,
196        class_active_pre: Option<Classes>,
197        class_active_code: Option<Classes>,
198    },
199    /// `[!code focus]` marks focused lines.
200    #[serde(rename_all = "camelCase")]
201    NotationFocus {
202        class_active_line: Option<Classes>,
203        class_active_pre: Option<Classes>,
204        class_active_code: Option<Classes>,
205    },
206    /// `[!code highlight]` and `[!code hl]` mark highlighted lines.
207    #[serde(rename_all = "camelCase")]
208    NotationHighlight {
209        class_active_line: Option<Classes>,
210        class_active_pre: Option<Classes>,
211        class_active_code: Option<Classes>,
212    },
213    /// `[!code error]`, `[!code warning]` and `[!code info]` mark lines by level.
214    #[serde(rename_all = "camelCase")]
215    NotationErrorLevel {
216        class_map: Option<BTreeMap<String, Classes>>,
217        class_active_pre: Option<Classes>,
218        class_active_code: Option<Classes>,
219    },
220    /// `{1,3-5}` in the meta marks highlighted lines.
221    #[serde(rename_all = "camelCase")]
222    MetaHighlight {
223        class_name: Option<Classes>,
224        #[serde(default)]
225        zero_indexed: bool,
226    },
227    /// `/word/` in the meta marks every occurrence of the word.
228    #[serde(rename_all = "camelCase")]
229    MetaWordHighlight { class_name: Option<Classes> },
230    /// A number at the start of each line.
231    #[serde(rename_all = "camelCase")]
232    RenderLineNumber {
233        class_line_number: Option<Classes>,
234        start: Option<usize>,
235    },
236}
237
238/// Class names: a list, or one string of them separated by white space.
239#[derive(Clone, Debug, Deserialize)]
240#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
241#[serde(untagged)]
242pub enum Classes {
243    One(String),
244    Many(Vec<String>),
245}
246
247/// `html.externalLinks`: `rel`, `target` and more on links to other sites, as
248/// rehype-external-links adds them; options named as it names them, JSON values only.
249#[derive(Clone, Debug, Default, Deserialize)]
250#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
251#[serde(default, rename_all = "camelCase")]
252#[cfg_attr(feature = "schema", schemars(rename = "ExternalLinksOptions"))]
253pub struct ExternalLinks {
254    /// The `target` of each external link, such as `_blank`.
255    pub target: Option<String>,
256    /// The `rel` of each external link: a list, or tokens separated by white space;
257    /// `nofollow` when left out or empty, none for an empty list.
258    pub rel: Option<Tokens>,
259    /// The protocols of absolute URLs that count as external; `http` and `https` when left
260    /// out. A protocol-relative `//…` URL always counts.
261    pub protocols: Option<Vec<String>>,
262    /// More properties for each external link, as hast names them.
263    pub properties: Option<serde_json::Map<String, serde_json::Value>>,
264    /// hast content appended to each external link in a `<span>`: one node or a list.
265    pub content: Option<serde_json::Value>,
266    /// The properties of that `<span>`.
267    pub content_properties: Option<serde_json::Map<String, serde_json::Value>>,
268}
269
270/// Tokens: a list, or one string of them separated by white space.
271#[derive(Clone, Debug, Deserialize)]
272#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
273#[serde(untagged)]
274pub enum Tokens {
275    One(String),
276    Many(Vec<String>),
277}
278
279/// `html.katex`: math rendered as rehype-katex renders it, natively by katex-rs; options
280/// named as KaTeX names them.
281#[derive(Clone, Debug, Default, Deserialize)]
282#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
283#[serde(default, rename_all = "camelCase")]
284#[cfg_attr(feature = "schema", schemars(rename = "KatexOptions"))]
285pub struct Katex {
286    /// The markup to write, both HTML and MathML by default.
287    pub output: Option<KatexOutput>,
288    /// Put equation numbers on the left.
289    pub leqno: bool,
290    /// Align display math to the left instead of centering it.
291    pub fleqn: bool,
292    /// The color of math that fails to render, `#cc0000` by default.
293    pub error_color: Option<String>,
294    /// Macros by name, each to the TeX it expands to, as `{"\\RR": "\\mathbb{R}"}`.
295    pub macros: BTreeMap<String, String>,
296    /// The thinnest a rule, such as a fraction line, is drawn, in ems.
297    pub min_rule_thickness: Option<f64>,
298    /// Let `\color` color the text after it, as LaTeX does.
299    pub color_is_text_color: bool,
300    /// What to do with input LaTeX would reject: `true` or `"error"` fails it, `"warn"`
301    /// prints a warning, `false` or `"ignore"` (the default) accepts it.
302    pub strict: Option<KatexStrict>,
303    /// Allow commands that can run untrusted input, such as `\href` and `\includegraphics`.
304    pub trust: bool,
305    /// The largest a user-given size may be, in ems.
306    pub max_size: Option<f64>,
307    /// How many macro expansions one formula may take, 1000 by default.
308    pub max_expand: Option<usize>,
309    /// Let definitions such as `\def` last past the formula they are in.
310    pub global_group: bool,
311}
312
313/// The markup KaTeX writes.
314#[derive(Clone, Copy, Debug, PartialEq, Deserialize)]
315#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
316#[serde(rename_all = "camelCase")]
317pub enum KatexOutput {
318    Html,
319    Mathml,
320    HtmlAndMathml,
321}
322
323/// How strictly KaTeX holds input to LaTeX.
324#[derive(Clone, Debug, PartialEq, Deserialize)]
325#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
326#[serde(untagged)]
327pub enum KatexStrict {
328    Boolean(bool),
329    Mode(KatexStrictMode),
330}
331
332/// One level of KaTeX's strictness.
333#[derive(Clone, Copy, Debug, PartialEq, Deserialize)]
334#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
335#[serde(rename_all = "camelCase")]
336pub enum KatexStrictMode {
337    Ignore,
338    Warn,
339    Error,
340}
341
342/// `html.extractToc`: the headings, nested by rank, as the file's `data.toc`, as
343/// @stefanprobst/rehype-extract-toc stores them.
344#[derive(Clone, Debug, Default, Deserialize)]
345#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
346#[serde(default, rename_all = "camelCase")]
347#[cfg_attr(feature = "schema", schemars(rename = "ExtractTocOptions"))]
348pub struct ExtractToc {
349    /// Attributes, such as `data-toc-hidden`, that keep a heading out of the table of
350    /// contents; what would nest under it nests under the heading before.
351    pub skip: Vec<String>,
352}
353
354/// `html.slug`: ids on headings, from their text; options named as rehype-slug names
355/// them.
356#[derive(Clone, Debug, Default, Deserialize)]
357#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
358#[serde(default, rename_all = "camelCase")]
359#[cfg_attr(feature = "schema", schemars(rename = "SlugOptions"))]
360pub struct Slug {
361    /// Put before each id.
362    pub prefix: String,
363}
364
365/// `html.toMarkdown`: hast into mdast; options named as hast-util-to-mdast names them.
366#[derive(Clone, Debug, Default, Deserialize)]
367#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
368#[serde(default, rename_all = "camelCase")]
369#[cfg_attr(feature = "schema", schemars(rename = "ToMarkdownOptions"))]
370pub struct ToMarkdown {
371    /// Wrap all phrasing content of the root in paragraphs, as for a whole document.
372    pub document: bool,
373    /// Collapse whitespace holding a line ending to that line ending instead of a space.
374    pub newlines: bool,
375    /// The text of a checked checkbox or radio, `[x]` by default.
376    pub checked: Option<String>,
377    /// The text of an unchecked checkbox or radio, `[ ]` by default.
378    pub unchecked: Option<String>,
379    /// The quotes `<q>` uses, an opening and closing character each, alternating by how
380    /// deep it nests; `"` by default.
381    pub quotes: Option<Vec<String>>,
382}
383
384/// `html.raw`: reparse raw HTML and fix nesting through the HTML parser; options named as
385/// hast-util-raw names them.
386#[derive(Clone, Debug, Default, Deserialize)]
387#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
388#[serde(default, rename_all = "camelCase")]
389#[cfg_attr(feature = "schema", schemars(rename = "RawOptions"))]
390pub struct Raw {
391    /// Node types, unknown to hast, to copy through as they are; their children are
392    /// reparsed on their own.
393    pub pass_through: Vec<String>,
394    /// Escape the opening `<` of the tags GFM's tagfilter disallows in raw nodes.
395    pub tagfilter: bool,
396}
397
398/// `html.format`: indent and collapse whitespace for readable HTML; options named as
399/// hast-util-format names them.
400#[derive(Clone, Debug, Default, Deserialize)]
401#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
402#[serde(default, rename_all = "camelCase")]
403#[cfg_attr(feature = "schema", schemars(rename = "FormatOptions"))]
404pub struct Format {
405    /// Tag names of elements to put a blank line between, when both are one.
406    pub blanks: Vec<String>,
407    /// One level of indentation: a number of spaces or the text itself; two spaces when
408    /// left out.
409    pub indent: Option<Indent>,
410    /// Indent the first level, usually `<html>`'s `head` and `body`; `true` when left out.
411    pub indent_initial: Option<bool>,
412}
413
414/// One level of indentation.
415#[derive(Clone, Debug, Deserialize)]
416#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
417#[serde(untagged)]
418pub enum Indent {
419    Spaces(usize),
420    Text(String),
421}