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)]
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}
141
142/// A replacement color, or a theme's own replacements.
143#[derive(Clone, Debug, Deserialize)]
144#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
145#[serde(untagged)]
146pub enum ColorReplacement {
147    Color(String),
148    Theme(BTreeMap<String, String>),
149}
150
151/// How inline code names its language.
152#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize)]
153#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
154pub enum InlineCode {
155    #[serde(rename = "tailing-curly-colon")]
156    TailingCurlyColon,
157}
158
159/// A transformer of @shikijs/transformers: its name alone, or its name and options.
160#[derive(Clone, Debug, Deserialize)]
161#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
162#[serde(untagged)]
163pub enum HighlightTransformer {
164    Name(TransformerName),
165    Configured(ConfiguredTransformer),
166}
167
168/// The transformers `html.highlight` runs natively.
169#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize)]
170#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
171#[serde(rename_all = "camelCase")]
172pub enum TransformerName {
173    NotationDiff,
174    NotationFocus,
175    NotationHighlight,
176    NotationErrorLevel,
177    MetaHighlight,
178    RenderLineNumber,
179}
180
181/// A transformer with its options, as @shikijs/transformers names them.
182#[derive(Clone, Debug, Deserialize)]
183#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
184#[serde(tag = "name", rename_all = "camelCase")]
185pub enum ConfiguredTransformer {
186    /// `[!code ++]` and `[!code --]` mark added and removed lines.
187    #[serde(rename_all = "camelCase")]
188    NotationDiff {
189        class_line_add: Option<Classes>,
190        class_line_remove: Option<Classes>,
191        class_active_pre: Option<Classes>,
192        class_active_code: Option<Classes>,
193    },
194    /// `[!code focus]` marks focused lines.
195    #[serde(rename_all = "camelCase")]
196    NotationFocus {
197        class_active_line: Option<Classes>,
198        class_active_pre: Option<Classes>,
199        class_active_code: Option<Classes>,
200    },
201    /// `[!code highlight]` and `[!code hl]` mark highlighted lines.
202    #[serde(rename_all = "camelCase")]
203    NotationHighlight {
204        class_active_line: Option<Classes>,
205        class_active_pre: Option<Classes>,
206        class_active_code: Option<Classes>,
207    },
208    /// `[!code error]`, `[!code warning]` and `[!code info]` mark lines by level.
209    #[serde(rename_all = "camelCase")]
210    NotationErrorLevel {
211        class_map: Option<BTreeMap<String, Classes>>,
212        class_active_pre: Option<Classes>,
213        class_active_code: Option<Classes>,
214    },
215    /// `{1,3-5}` in the meta marks highlighted lines.
216    #[serde(rename_all = "camelCase")]
217    MetaHighlight {
218        class_name: Option<Classes>,
219        #[serde(default)]
220        zero_indexed: bool,
221    },
222    /// A number at the start of each line.
223    #[serde(rename_all = "camelCase")]
224    RenderLineNumber {
225        class_line_number: Option<Classes>,
226        start: Option<usize>,
227    },
228}
229
230/// Class names: a list, or one string of them separated by white space.
231#[derive(Clone, Debug, Deserialize)]
232#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
233#[serde(untagged)]
234pub enum Classes {
235    One(String),
236    Many(Vec<String>),
237}
238
239/// `html.slug`: ids on headings, from their text; options named as rehype-slug names
240/// them.
241#[derive(Clone, Debug, Default, Deserialize)]
242#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
243#[serde(default, rename_all = "camelCase")]
244#[cfg_attr(feature = "schema", schemars(rename = "SlugOptions"))]
245pub struct Slug {
246    /// Put before each id.
247    pub prefix: String,
248}
249
250/// `html.toMarkdown`: hast into mdast; options named as hast-util-to-mdast names them.
251#[derive(Clone, Debug, Default, Deserialize)]
252#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
253#[serde(default, rename_all = "camelCase")]
254#[cfg_attr(feature = "schema", schemars(rename = "ToMarkdownOptions"))]
255pub struct ToMarkdown {
256    /// Wrap all phrasing content of the root in paragraphs, as for a whole document.
257    pub document: bool,
258    /// Collapse whitespace holding a line ending to that line ending instead of a space.
259    pub newlines: bool,
260    /// The text of a checked checkbox or radio, `[x]` by default.
261    pub checked: Option<String>,
262    /// The text of an unchecked checkbox or radio, `[ ]` by default.
263    pub unchecked: Option<String>,
264    /// The quotes `<q>` uses, an opening and closing character each, alternating by how
265    /// deep it nests; `"` by default.
266    pub quotes: Option<Vec<String>>,
267}
268
269/// `html.raw`: reparse raw HTML and fix nesting through the HTML parser; options named as
270/// hast-util-raw names them.
271#[derive(Clone, Debug, Default, Deserialize)]
272#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
273#[serde(default, rename_all = "camelCase")]
274#[cfg_attr(feature = "schema", schemars(rename = "RawOptions"))]
275pub struct Raw {
276    /// Node types, unknown to hast, to copy through as they are; their children are
277    /// reparsed on their own.
278    pub pass_through: Vec<String>,
279    /// Escape the opening `<` of the tags GFM's tagfilter disallows in raw nodes.
280    pub tagfilter: bool,
281}
282
283/// `html.format`: indent and collapse whitespace for readable HTML; options named as
284/// hast-util-format names them.
285#[derive(Clone, Debug, Default, Deserialize)]
286#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
287#[serde(default, rename_all = "camelCase")]
288#[cfg_attr(feature = "schema", schemars(rename = "FormatOptions"))]
289pub struct Format {
290    /// Tag names of elements to put a blank line between, when both are one.
291    pub blanks: Vec<String>,
292    /// One level of indentation: a number of spaces or the text itself; two spaces when
293    /// left out.
294    pub indent: Option<Indent>,
295    /// Indent the first level, usually `<html>`'s `head` and `body`; `true` when left out.
296    pub indent_initial: Option<bool>,
297}
298
299/// One level of indentation.
300#[derive(Clone, Debug, Deserialize)]
301#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
302#[serde(untagged)]
303pub enum Indent {
304    Spaces(usize),
305    Text(String),
306}