feat(glossy): add type-checking

- adds type-checking via the valkyrie package
- fixes handling of groups parameter on #glossary()
- new test for relevant changes
This commit is contained in:
swaits committed 2024-12-16 18:30:09 -07:00
1 parent d2e44f4131
commit 0a87404a18
9 files changed
+112 -10

No files matched your search

+29 -10
View File
@@ -1,3 +1,7 @@
// TODO: replace with @preview when back online
#import "@preview/valkyrie:0.2.1" as z
#import "./schemas.typ": *
#import "./themes.typ": *
#import "./utils.typ": *
@@ -332,10 +336,15 @@
show-term: (term-body) => term-body,
body
) = context {
// Validate entries parameter type
if type(entries) != dictionary {
panic("entries must be a dictionary, instead got: " + repr(entries))
// Type checking
let checked-entries = (:)
for (key, entry) in entries {
let checked-key = z.parse(key, z.string(), scope: ("dictionary key",))
let checked-entry = z.parse(entry, dict-schema, scope: ("dictionary entry",))
checked-entries.insert(checked-key, checked-entry)
}
let checked-show-term = z.parse(show-term, z.function(), scope: ("show-term",))
let checked-body = z.parse(body, z.content(), scope: ("body",))
// Process and store each glossary entry
for (key, entry) in entries {
@@ -396,6 +405,12 @@
ignore-case: false,
groups: (),
) = context {
// Type checking
let checked-title = z.parse(title, z.content(), scope: ("title",))
let checked-groups = z.parse(groups, groups-list-schema, scope: ("groups",))
let checked-ignore-case = z.parse(ignore-case, z.boolean(), scope: ("ignore-case",))
let checked-theme = z.parse(theme, theme-schema, scope: ("theme",))
// Collect and organize entries by group
let output = (:)
let all_entries = __gloss_entries.final()
@@ -405,19 +420,23 @@
let all_groups = all_entries
.values()
.map(e => e.at("group"))
.map(g => { if g == none { "" } else { g } })
.dedup()
.sorted()
let target_groups = if groups.len() == 0 {
let target_groups = if checked-groups.len() == 0 {
all_groups
} else {
// Validate requested groups exist
for g in groups {
for g in checked-groups {
if g == none {
g = ""
}
if g not in all_groups {
panic("Requested group not found: " + g)
panic("Requested group, '" + g + "', not found.")
}
}
groups
checked-groups
}
// Process entries group by group
@@ -459,15 +478,15 @@
// Render the glossary using the theme
let group_index = 0
(theme.section)(
(checked-theme.section)(
title,
for (group, entries) in output {
(theme.group)(
(checked-theme.group)(
group,
group_index,
output.len(),
for (i, entry) in entries.enumerate() {
(theme.entry)(entry, i, entries.len())
(checked-theme.entry)(entry, i, entries.len())
}
)
group_index += 1
+26
View File
@@ -0,0 +1,26 @@
// TODO: change to @preview when online
#import "@preview/valkyrie:0.2.1" as z
#let dict-schema = z.either(
z.string(),
z.dictionary(
(
short: z.content(), // this is the only required field
plural: z.content(optional: true),
long: z.content(optional: true),
longplural: z.content(optional: true),
description: z.content(optional: true),
group: z.content(optional: true),
)
)
)
#let theme-schema = z.dictionary(
(
section: z.function(),
group: z.function(),
entry: z.function(),
)
)
#let groups-list-schema = z.array(pre-transform: z.coerce.array)