///|
pub struct CatalogEntry {
path : String
name : String
kind : TokenKind
value : ThemeValue
description : String
} derive(Debug, Eq)
///|
pub struct CatalogStats {
total : Int
color_count : Int
number_count : Int
text_count : Int
boolean_count : Int
described_count : Int
} derive(Debug, Eq)
///|
pub struct TokenCatalog {
entries : Array[CatalogEntry]
} derive(Debug, Eq)
///|
pub fn CatalogEntry::from_theme_token(token : ThemeToken) -> CatalogEntry {
{
path: token.path.canonical(),
name: last_path_segment(token.path),
kind: token.kind,
value: token.value,
description: token.description,
}
}
///|
pub fn TokenCatalog::empty() -> TokenCatalog {
{ entries: [] }
}
///|
pub fn TokenCatalog::from_theme_document(
document : ThemeDocument,
) -> TokenCatalog {
let entries : Array[CatalogEntry] = []
for token in document.sorted().tokens {
entries.push(CatalogEntry::from_theme_token(token))
}
{ entries, }
}
///|
pub fn TokenCatalog::from_brand_book(book : BrandBook) -> TokenCatalog {
TokenCatalog::from_theme_document(book.theme_document())
}
///|
pub fn TokenCatalog::add(
self : TokenCatalog,
entry : CatalogEntry,
) -> TokenCatalog {
let entries : Array[CatalogEntry] = []
for item in self.entries {
entries.push(item)
}
entries.push(entry)
{ entries, }
}
///|
pub fn TokenCatalog::len(self : TokenCatalog) -> Int {
self.entries.length()
}
///|
pub fn TokenCatalog::is_empty(self : TokenCatalog) -> Bool {
self.entries.length() == 0
}
///|
pub fn TokenCatalog::entries(self : TokenCatalog) -> Array[CatalogEntry] {
let result : Array[CatalogEntry] = []
for entry in self.entries {
result.push(entry)
}
result
}
///|
pub fn TokenCatalog::names(self : TokenCatalog) -> Array[String] {
let result : Array[String] = []
for entry in self.entries {
result.push(entry.name)
}
result
}
///|
pub fn TokenCatalog::paths(self : TokenCatalog) -> Array[String] {
let result : Array[String] = []
for entry in self.entries {
result.push(entry.path)
}
result
}
///|
pub fn TokenCatalog::find(self : TokenCatalog, path : String) -> CatalogEntry? {
let wanted = TokenPath::from_string(path).canonical()
for entry in self.entries {
if entry.path == wanted {
return Some(entry)
}
}
None
}
///|
pub fn TokenCatalog::contains(self : TokenCatalog, path : String) -> Bool {
self.find(path) is Some(_)
}
///|
pub fn TokenCatalog::by_kind(
self : TokenCatalog,
kind : TokenKind,
) -> Array[CatalogEntry] {
let result : Array[CatalogEntry] = []
for entry in self.entries {
if entry.kind == kind {
result.push(entry)
}
}
result
}
///|
pub fn TokenCatalog::by_prefix(
self : TokenCatalog,
prefix : String,
) -> Array[CatalogEntry] {
let normalized = TokenPath::from_string(prefix).canonical()
let result : Array[CatalogEntry] = []
for entry in self.entries {
if entry.path == normalized || entry.path.has_prefix(normalized + ".") {
result.push(entry)
}
}
result
}
///|
pub fn TokenCatalog::search(
self : TokenCatalog,
query : String,
) -> Array[CatalogEntry] {
let wanted = ascii_lower(query)
let result : Array[CatalogEntry] = []
for entry in self.entries {
if ascii_lower(entry.path).contains(wanted) ||
ascii_lower(entry.name).contains(wanted) ||
ascii_lower(entry.description).contains(wanted) {
result.push(entry)
}
}
result
}
///|
pub fn TokenCatalog::stats(self : TokenCatalog) -> CatalogStats {
let mut colors = 0
let mut numbers = 0
let mut texts = 0
let mut booleans = 0
let mut described = 0
for entry in self.entries {
match entry.kind {
Color => colors += 1
Number => numbers += 1
Text => texts += 1
Boolean => booleans += 1
}
if entry.description.trim().to_owned() != "" {
described += 1
}
}
{
total: self.entries.length(),
color_count: colors,
number_count: numbers,
text_count: texts,
boolean_count: booleans,
described_count: described,
}
}
///|
pub fn CatalogStats::documentation_rate(self : CatalogStats) -> Int {
if self.total == 0 {
0
} else {
self.described_count * 100 / self.total
}
}
///|
pub fn TokenCatalog::to_markdown(self : TokenCatalog) -> String {
let lines : Array[String] = [
"## Token catalog", "", "| Path | Kind | Value | Description |", "| --- | --- | --- | --- |",
]
for entry in self.entries {
lines.push(
"| `" +
entry.path +
"` | " +
token_kind_name(entry.kind) +
" | " +
theme_value_display(entry.value) +
" | " +
entry.description +
" |",
)
}
lines.join("\n")
}
///|
fn last_path_segment(path : TokenPath) -> String {
if path.segments.length() == 0 {
""
} else {
path.segments[path.segments.length() - 1]
}
}
///|
fn theme_value_display(value : ThemeValue) -> String {
match value {
ColorValue(text) => "`" + text + "`"
NumberValue(number) => number.to_string()
TextValue(text) => "`" + text + "`"
BooleanValue(flag) => if flag { "true" } else { "false" }
}
}