Skip to main content

webfont_generator/
types.rs

1use std::collections::HashMap;
2
3#[cfg(feature = "napi")]
4use napi_derive::napi;
5use serde_json::{Map, Value};
6
7/// What happened to a file, for [`crate::GenerateWebfontsResult::regenerate`]. `name` is the
8/// caller-resolved glyph name (the `rename` callback, if any, is applied by the caller).
9pub enum GlyphChange {
10    /// A new file. `name` overrides the file-stem glyph name when `Some`.
11    Added { name: Option<String> },
12    /// An existing file's contents changed. `name` overrides the glyph name when `Some`.
13    Changed { name: Option<String> },
14    /// The file was deleted.
15    Removed,
16}
17
18/// One entry in the `changes` array passed to the Node binding's `regenerate`. The complete
19/// ordered file list passed alongside it controls final glyph order; this only describes which
20/// files need re-reading, renaming, or removal.
21#[cfg_attr(feature = "napi", napi(object))]
22pub struct GlyphChangeEntry {
23    /// Path of the changed file.
24    pub path: String,
25    /// What happened to the file.
26    #[cfg_attr(feature = "napi", napi(ts_type = "'added' | 'changed' | 'removed'"))]
27    pub change_type: String,
28    /// Resolved glyph name (with the caller's `rename` already applied). Optional for `'added'`
29    /// and `'changed'` (defaults to the file stem/current name); ignored for `'removed'`.
30    pub name: Option<String>,
31}
32
33/// Complete ordered input membership for a regeneration operation. The case must match the
34/// result's generation mode. Synchronous methods borrow this value; async methods consume it.
35pub enum RegenerationFiles {
36    /// Single-design font inputs, in the order a fresh generation would use.
37    Single(Vec<String>),
38    /// Complete file sets for every configured variant, each named exactly once. The order of
39    /// these entries does not change configured design order. Paths can be shared between
40    /// designs; each design's file list independently determines its membership and order.
41    Variants(Vec<VariantFileSet>),
42}
43
44/// Complete file set for one configured variant during regeneration.
45#[cfg_attr(feature = "napi", napi(object))]
46pub struct VariantFileSet {
47    /// Existing variant name. Full re-diff requires every configured variant exactly once.
48    pub variant: String,
49    /// Complete ordered file set for this variant.
50    pub files: Vec<String>,
51}
52
53/// Node regeneration input. Supply exactly one of `files` or `variants`.
54#[cfg(feature = "napi")]
55#[napi(object)]
56pub struct RegenerationFileOptions {
57    /// Complete single-design input file list.
58    pub files: Option<Vec<String>>,
59    /// Complete per-design file lists for a multi-variant family.
60    pub variants: Option<Vec<VariantFileSet>>,
61}
62
63/// Font output format. Used in the `types` and `order` options to control which
64/// formats are generated and the order they appear in the CSS `@font-face`
65/// `src:` descriptor.
66#[cfg_attr(feature = "napi", napi(string_enum = "lowercase"))]
67#[cfg_attr(feature = "cli", derive(clap::ValueEnum))]
68#[derive(Clone, Copy, PartialEq, Eq, Hash)]
69#[cfg_attr(
70    feature = "cli",
71    derive(serde::Deserialize),
72    serde(rename_all = "lowercase")
73)]
74pub enum FontType {
75    /// SVG font (`.svg`). Legacy format; intermediate representation that all
76    /// other formats are derived from.
77    Svg,
78    /// TrueType font (`.ttf`).
79    Ttf,
80    /// Embedded OpenType (`.eot`). Legacy format for older Internet Explorer.
81    Eot,
82    /// Web Open Font Format 1.0 (`.woff`).
83    Woff,
84    /// Web Open Font Format 2.0 (`.woff2`). Best compression; preferred for
85    /// modern browsers.
86    Woff2,
87}
88
89/// One named SVG design in a multi-variant icon family.
90#[cfg_attr(feature = "napi", napi(object))]
91#[derive(Clone)]
92#[cfg_attr(
93    feature = "cli",
94    derive(serde::Deserialize),
95    serde(rename_all = "camelCase", deny_unknown_fields)
96)]
97pub struct FontVariant {
98    /// User-facing variant name, used to derive CSS modifier classes.
99    pub name: String,
100    /// SVG files that belong to this variant.
101    pub files: Vec<String>,
102    /// Optional explicit CSS weight coordinate in the range 1 through 1000. Automatic weights
103    /// resolve outward from the default in steps of 100, or evenly when an interval is crowded.
104    pub weight: Option<u16>,
105    /// Whether this is the family's default variant. Exactly one variant must set this to `true`.
106    pub default: Option<bool>,
107}
108
109/// Family-wide behavior when a logical glyph is absent from a variant.
110#[cfg_attr(feature = "napi", napi(string_enum = "lowercase"))]
111#[derive(Clone, Copy, PartialEq, Eq)]
112#[cfg_attr(
113    feature = "cli",
114    derive(serde::Deserialize),
115    serde(rename_all = "lowercase")
116)]
117pub enum MissingGlyphBehavior {
118    /// Use an empty outline while retaining the logical glyph's advance.
119    Blank,
120    /// Reject generation and report every missing variant/glyph pair.
121    Error,
122    /// Reuse the outline from the named fallback variant, which must contain every logical glyph.
123    Fallback,
124}
125
126/// Family-wide missing-glyph policy for multi-variant generation.
127#[cfg_attr(feature = "napi", napi(object))]
128#[derive(Clone)]
129#[cfg_attr(
130    feature = "cli",
131    derive(serde::Deserialize),
132    serde(rename_all = "camelCase", deny_unknown_fields)
133)]
134pub struct MissingGlyphOptions {
135    /// Missing-glyph behavior. Variant mode defaults to [`MissingGlyphBehavior::Blank`] when this
136    /// object is omitted.
137    pub behavior: MissingGlyphBehavior,
138    /// Fallback variant name. Required only when `behavior` is `fallback`; the named variant must
139    /// contain every logical glyph in the family.
140    pub variant: Option<String>,
141}
142
143impl FontType {
144    /// Returns the CSS `format()` value (e.g., "truetype", "woff2").
145    #[inline]
146    pub fn css_format(self) -> &'static str {
147        match self {
148            FontType::Svg => "svg",
149            FontType::Ttf => "truetype",
150            FontType::Eot => "embedded-opentype",
151            FontType::Woff => "woff",
152            FontType::Woff2 => "woff2",
153        }
154    }
155
156    /// Returns the file extension (e.g., "svg", "ttf", "woff2").
157    #[inline]
158    pub fn as_extension(self) -> &'static str {
159        match self {
160            FontType::Svg => "svg",
161            FontType::Ttf => "ttf",
162            FontType::Eot => "eot",
163            FontType::Woff => "woff",
164            FontType::Woff2 => "woff2",
165        }
166    }
167}
168
169/// SVG-format–specific options for the intermediate SVG font and the per-glyph
170/// path processing that feeds every other format.
171#[cfg_attr(feature = "napi", napi(object))]
172#[derive(Clone, Default)]
173#[cfg_attr(
174    feature = "cli",
175    derive(serde::Deserialize),
176    serde(rename_all = "camelCase", deny_unknown_fields)
177)]
178pub struct SvgFormatOptions {
179    /// SVG-format override of the top-level `centerVertically` option. When set,
180    /// it wins over the top-level value; centers each glyph vertically inside
181    /// the em-square based on its bounding box.
182    pub center_vertically: Option<bool>,
183    /// Value of the SVG font's `id` attribute. Defaults to `fontName` when
184    /// omitted.
185    pub font_id: Option<String>,
186    /// Content embedded inside the generated SVG font's `<metadata>` element.
187    pub metadata: Option<String>,
188    /// SVG-format override of the top-level `optimizeOutput` option. When set,
189    /// it wins over the top-level value; runs an SVG path optimizer over each
190    /// glyph, trading a small amount of build time for smaller output bytes.
191    pub optimize_output: Option<bool>,
192    /// SVG-format override of the top-level `preserveAspectRatio` option. When
193    /// set, it wins over the top-level value; preserves the source viewBox
194    /// aspect ratio when scaling glyphs into the em-square.
195    pub preserve_aspect_ratio: Option<bool>,
196}
197
198/// TTF-format–specific options. Populates fields in the generated TTF `name`
199/// and `head` tables.
200#[cfg_attr(feature = "napi", napi(object))]
201#[derive(Clone)]
202#[cfg_attr(
203    feature = "cli",
204    derive(serde::Deserialize),
205    serde(rename_all = "camelCase", deny_unknown_fields)
206)]
207pub struct TtfFormatOptions {
208    /// Copyright string written to the TTF `name` table (record id 0).
209    pub copyright: Option<String>,
210    /// Description string written to the TTF `name` table (record id 10).
211    pub description: Option<String>,
212    /// Unix timestamp in seconds used for the `created` and `modified` fields
213    /// in the TTF `head` table. Pin to a fixed value to produce byte-stable
214    /// reproducible builds.
215    pub ts: Option<i64>,
216    /// Manufacturer URL written to the TTF `name` table (record id 11).
217    pub url: Option<String>,
218    /// Version string written to the TTF `name` table (record id 5).
219    pub version: Option<String>,
220}
221
222/// WOFF-format–specific options. Affects only WOFF1 output; WOFF2 ignores these.
223#[cfg_attr(feature = "napi", napi(object))]
224#[derive(Clone)]
225#[cfg_attr(
226    feature = "cli",
227    derive(serde::Deserialize),
228    serde(rename_all = "camelCase", deny_unknown_fields)
229)]
230pub struct WoffFormatOptions {
231    /// XML string embedded in the WOFF1 metadata block.
232    pub metadata: Option<String>,
233}
234
235/// WOFF2-format–specific options. Affects only WOFF2 output.
236#[cfg_attr(feature = "napi", napi(object))]
237#[derive(Clone)]
238#[cfg_attr(
239    feature = "cli",
240    derive(serde::Deserialize),
241    serde(rename_all = "camelCase", deny_unknown_fields)
242)]
243pub struct Woff2FormatOptions {
244    /// Brotli compression quality used when encoding WOFF2, from `0` (fastest,
245    /// largest output) to `11` (slowest, smallest output). This tunes compression
246    /// effort only and never changes glyph fidelity — the decompressed font is
247    /// identical at every level. Defaults to `11` for the smallest output; lower it
248    /// (e.g. to `10`) for faster encoding at a marginal size cost. Must be between
249    /// `0` and `11`; other values are rejected.
250    pub compression_quality: Option<u8>,
251}
252
253/// Per-format configuration object. Each field carries options that only apply
254/// to the corresponding output format.
255#[cfg_attr(feature = "napi", napi(object))]
256#[derive(Clone, Default)]
257#[cfg_attr(
258    feature = "cli",
259    derive(serde::Deserialize),
260    serde(rename_all = "camelCase", deny_unknown_fields)
261)]
262pub struct FormatOptions {
263    /// SVG-format options.
264    pub svg: Option<SvgFormatOptions>,
265    /// TTF-format options.
266    pub ttf: Option<TtfFormatOptions>,
267    /// WOFF1-format options.
268    pub woff: Option<WoffFormatOptions>,
269    /// WOFF2-format options.
270    pub woff2: Option<Woff2FormatOptions>,
271}
272
273/// Resolved variant metadata supplied to CSS and HTML template callbacks.
274#[cfg_attr(feature = "napi", napi(object))]
275#[derive(Clone)]
276pub struct TemplateVariant {
277    /// User-provided variant name.
278    pub name: String,
279    /// Resolved CSS weight coordinate.
280    pub weight: u32,
281    /// Whether this is the family's default design.
282    pub default: bool,
283    /// Unescaped modifier class for use in HTML.
284    pub class_name: String,
285    /// CSS-escaped modifier class identifier, without a leading dot.
286    pub selector: String,
287}
288
289/// Fields supplied to a `cssContext` callback. Additional keys from
290/// user-supplied `templateOptions` are merged into the same object at runtime,
291/// so the JS-side type widens this with an open-ended index signature.
292#[cfg_attr(feature = "napi", napi(object))]
293#[derive(Clone)]
294pub struct CssContext {
295    /// Name of the generated font, mirroring the `fontName` option.
296    pub font_name: String,
297    /// Pre-rendered value for the CSS `@font-face` `src:` descriptor — a
298    /// comma-separated list of `url(...) format(...)` entries derived from the
299    /// configured `types`, `order`, and `cssFontsUrl`.
300    pub src: String,
301    /// Map from glyph name to its assigned codepoint as a hex-encoded string
302    /// (e.g. `"add" -> "f101"`), suitable for use inside CSS `content`
303    /// declarations like `content: "\f101"`.
304    pub codepoints: HashMap<String, String>,
305    /// Ordered resolved variants; absent in ordinary mode unless supplied by template options.
306    /// The mode-independent Node declaration is unknown because ordinary template data is arbitrary.
307    #[cfg_attr(feature = "napi", napi(ts_type = "unknown"))]
308    pub variants: Option<Vec<TemplateVariant>>,
309    /// Modifier class prefix, supplied in variant mode.
310    #[cfg_attr(feature = "napi", napi(ts_type = "unknown"))]
311    pub variant_class_prefix: Option<String>,
312    /// Resolved default weight, supplied in variant mode.
313    #[cfg_attr(feature = "napi", napi(ts_type = "unknown"))]
314    pub default_weight: Option<u32>,
315    /// Resolved font style, supplied in variant mode.
316    #[cfg_attr(feature = "napi", napi(ts_type = "unknown"))]
317    pub font_style: Option<String>,
318}
319
320/// Fields supplied to an `htmlContext` callback. Additional keys
321/// from user-supplied `templateOptions` are merged into the same object at
322/// runtime, so the JS-side type widens this with an open-ended index signature.
323#[cfg_attr(feature = "napi", napi(object))]
324#[derive(Clone)]
325pub struct HtmlContext {
326    /// Name of the generated font, mirroring the `fontName` option.
327    pub font_name: String,
328    /// Glyph names in declaration order, after any `rename` callback has been
329    /// applied. Useful for iterating over icons in a preview template.
330    pub names: Vec<String>,
331    /// Pre-rendered CSS (the same string the engine writes to the `.css`
332    /// output) so HTML templates can embed it inline for self-contained
333    /// previews without an external stylesheet reference.
334    pub styles: String,
335    /// Map from glyph name to its assigned codepoint as a numeric value
336    /// (e.g. `"add" -> 0xF101`). Use the CSS context's hex form if you need a
337    /// string for embedding into CSS `content` declarations.
338    pub codepoints: HashMap<String, u32>,
339    /// Ordered resolved variants; absent in ordinary mode unless supplied by template options.
340    /// The mode-independent Node declaration is unknown because ordinary template data is arbitrary.
341    #[cfg_attr(feature = "napi", napi(ts_type = "unknown"))]
342    pub variants: Option<Vec<TemplateVariant>>,
343    /// Modifier class prefix, supplied in variant mode.
344    #[cfg_attr(feature = "napi", napi(ts_type = "unknown"))]
345    pub variant_class_prefix: Option<String>,
346    /// Resolved default weight, supplied in variant mode.
347    #[cfg_attr(feature = "napi", napi(ts_type = "unknown"))]
348    pub default_weight: Option<u32>,
349    /// Resolved font style, supplied in variant mode.
350    #[cfg_attr(feature = "napi", napi(ts_type = "unknown"))]
351    pub font_style: Option<String>,
352}
353
354/// Top-level options controlling webfont generation. `dest` and exactly one source, ordinary
355/// `files` or `variants`, are required. Every other field has a sensible default.
356/// With the `cli` feature, options deserialize from camelCase JSON with unknown fields rejected.
357#[cfg_attr(feature = "napi", napi(object))]
358#[derive(Clone, Default)]
359#[cfg_attr(
360    feature = "cli",
361    derive(serde::Deserialize),
362    serde(rename_all = "camelCase", deny_unknown_fields)
363)]
364pub struct GenerateWebfontsOptions {
365    /// Font ascent in font units. Overrides the value computed from the source
366    /// glyphs.
367    pub ascent: Option<f64>,
368    /// When `true`, centers each glyph horizontally inside the em-square based
369    /// on its bounding box.
370    pub center_horizontally: Option<bool>,
371    /// When `true`, centers each glyph vertically inside the em-square based
372    /// on its bounding box. Convenience alias for
373    /// `formatOptions.svg.centerVertically`.
374    pub center_vertically: Option<bool>,
375    /// Whether to generate a CSS file. Defaults to `true`.
376    pub css: Option<bool>,
377    /// Output path for the generated CSS file. Defaults to
378    /// `path.join(dest, fontName + '.css')`.
379    pub css_dest: Option<String>,
380    /// Path to a custom Handlebars template for CSS generation. The template
381    /// receives the `cssContext` shape plus any `templateOptions` keys.
382    pub css_template: Option<String>,
383    /// Explicit Unicode codepoints for specific glyphs, keyed by glyph name.
384    /// Glyphs not listed here are auto-assigned starting at `startCodepoint`.
385    pub codepoints: Option<HashMap<String, u32>>,
386    /// URL prefix for font files in the generated CSS. Defaults to the
387    /// relative path from `cssDest` to `dest`.
388    pub css_fonts_url: Option<String>,
389    /// Font descent in font units. Overrides the value computed from the
390    /// source glyphs.
391    pub descent: Option<f64>,
392    /// Output directory for generated font files. Required.
393    pub dest: String,
394    /// Paths to the SVG files to include in an ordinary font. Must be empty when `variants` is set.
395    #[cfg_attr(feature = "cli", serde(default))]
396    pub files: Vec<String>,
397    /// When `true`, produces a monospace font sized to the widest glyph.
398    pub fixed_width: Option<bool>,
399    /// Per-format option overrides. See `FormatOptions`.
400    pub format_options: Option<FormatOptions>,
401    /// Whether to generate an HTML preview file. Defaults to `false`.
402    pub html: Option<bool>,
403    /// Output path for the generated HTML preview file. Defaults to
404    /// `path.join(dest, fontName + '.html')`.
405    pub html_dest: Option<String>,
406    /// Path to a custom Handlebars template for HTML preview generation.
407    pub html_template: Option<String>,
408    /// Retain parsed glyph data on the result so `regenerate` can rebuild after file changes
409    /// without re-parsing unchanged glyphs. Defaults to `false`; enable for watch/dev. One-shot
410    /// builds (CLI, production) should leave it off to avoid holding the parsed geometry in memory.
411    /// Multi-variant results retain per-design parse/process caches. Pass
412    /// `RegenerationFiles::Variants` to the same regeneration methods for these results.
413    pub incremental: Option<bool>,
414    /// Explicit output font height in units per em. Overrides the height
415    /// computed from the source glyphs.
416    pub font_height: Option<f64>,
417    /// Name of the generated font family; also used as the base name for
418    /// output files. Defaults to `'iconfont'`.
419    pub font_name: Option<String>,
420    /// CSS `font-style` value for the generated `@font-face` rule.
421    pub font_style: Option<String>,
422    /// CSS `font-weight` value for the generated `@font-face` rule.
423    pub font_weight: Option<String>,
424    /// Enable ligature support so each glyph can be referenced by its name as
425    /// a text ligature. Defaults to `true`.
426    pub ligature: Option<bool>,
427    /// Family-wide missing-glyph policy for multi-variant generation. Defaults to `blank` and is
428    /// invalid without `variants`.
429    pub missing_glyphs: Option<MissingGlyphOptions>,
430    /// Scale icons to the height of the tallest icon. Defaults to `true`.
431    pub normalize: Option<bool>,
432    /// Order of `@font-face` `src:` entries in the generated CSS. Every entry
433    /// must also appear in `types`. Defaults to
434    /// `['eot', 'woff2', 'woff', 'ttf', 'svg']` filtered to the requested
435    /// `types`.
436    pub order: Option<Vec<FontType>>,
437    /// Run an SVG path optimizer over each glyph, trading a small amount of
438    /// build time for smaller output bytes. Convenience alias for
439    /// `formatOptions.svg.optimizeOutput`.
440    pub optimize_output: Option<bool>,
441    /// Preserve the source viewBox aspect ratio when scaling glyphs into the
442    /// em-square. Convenience alias for `formatOptions.svg.preserveAspectRatio`.
443    pub preserve_aspect_ratio: Option<bool>,
444    /// SVG path coordinate rounding precision.
445    pub round: Option<f64>,
446    /// Starting codepoint for auto-assigned glyphs. Defaults to `0xF101`.
447    pub start_codepoint: Option<u32>,
448    /// Additional key-value pairs merged into the Handlebars template
449    /// context for both CSS and HTML rendering. Typical home for
450    /// `classPrefix` and `baseSelector`.
451    pub template_options: Option<Map<String, Value>>,
452    /// Font formats to generate. Ordinary mode defaults to `['eot', 'woff', 'woff2']`;
453    /// variant mode defaults to `['woff', 'woff2']` and rejects SVG and EOT.
454    pub types: Option<Vec<FontType>>,
455    /// Prefix for generated variant modifier classes. Defaults to `icon--` in variant mode and is
456    /// invalid without `variants`.
457    pub variant_class_prefix: Option<String>,
458    /// Ordered named SVG designs for one logical icon family. Variant generation emits shared
459    /// variable TTF/WOFF/WOFF2 fonts. SVG and EOT output are unsupported in variant mode.
460    /// Default CSS emits exact-weight faces sharing those fonts, with modifier classes and no
461    /// synthetic weights. CSS/HTML companions are written when enabled; HTML uses one default grid.
462    /// Template contexts include ordered `variants`, `variantClassPrefix`, `defaultWeight`, and
463    /// `fontStyle`. The SCSS mixin uses each family's default weight and style.
464    pub variants: Option<Vec<FontVariant>>,
465    /// Whether to write generated files to disk. Set to `false` for
466    /// in-memory usage. Defaults to `true`.
467    pub write_files: Option<bool>,
468}