1use crate::Diagnostic;
8use bern_ir::{Application, Node, Prop};
9
10pub const NAMES: &[&str] = &[
12 "archivebox",
13 "arrow.down",
14 "arrow.down.circle",
15 "arrow.down.right.and.arrow.up.left",
16 "arrow.left",
17 "arrow.triangle.2.circlepath",
18 "arrow.triangle.branch",
19 "arrow.up.arrow.down",
20 "arrow.up.left.and.arrow.down.right",
21 "arrow.up.right.square",
22 "backward.end.fill",
23 "calendar",
24 "camera",
25 "captions.bubble",
26 "character.cursor.ibeam",
27 "checkmark",
28 "checkmark.circle",
29 "chevron.down",
30 "chevron.left",
31 "chevron.right",
32 "chevron.up",
33 "chevron.up.chevron.down",
34 "circle",
35 "circle.fill",
36 "clock.arrow.circlepath",
37 "doc",
38 "dot.radiowaves.left.and.right",
39 "ellipsis",
40 "ellipsis.circle",
41 "exclamationmark.triangle",
42 "eye.slash",
43 "film",
44 "film.stack",
45 "folder",
46 "forward.end.fill",
47 "gearshape",
48 "gearshape.2",
49 "globe",
50 "gobackward.10",
51 "goforward.10",
52 "hand.tap",
53 "heart",
54 "house",
55 "info.circle",
56 "keyboard",
57 "line.3.horizontal.decrease",
58 "link",
59 "list.bullet.rectangle",
60 "magnifyingglass",
61 "minus",
62 "moon",
63 "music.note",
64 "note.text",
65 "paintbrush",
66 "paintpalette",
67 "paperplane",
68 "pause",
69 "pause.fill",
70 "person.crop.circle",
71 "photo",
72 "pip.enter",
73 "play",
74 "play.fill",
75 "play.rectangle",
76 "plus",
77 "power",
78 "puzzlepiece.extension",
79 "scissors",
80 "server.rack",
81 "shield",
82 "sidebar.right",
83 "slider.horizontal.3",
84 "sparkles",
85 "speaker.fill",
86 "speaker.slash.fill",
87 "speaker.wave.2",
88 "speaker.wave.3.fill",
89 "speedometer",
90 "square",
91 "square.and.arrow.up",
92 "square.grid.2x2",
93 "square.grid.3x3",
94 "square.on.square",
95 "star",
96 "star.fill",
97 "star.slash",
98 "sun.max.fill",
99 "sun.min",
100 "switch.2",
101 "text.bubble",
102 "text.rectangle",
103 "textformat",
104 "textformat.size",
105 "textformat.size.larger",
106 "textformat.size.smaller",
107 "trash",
108 "tray",
109 "tv",
110 "viewfinder",
111 "wifi",
112 "xmark",
113 "xmark.circle.fill",
114];
115
116pub fn check(app: &Application, set: &str, has: impl Fn(&str) -> bool) -> Vec<Diagnostic> {
119 let mut diagnostics = Vec::new();
120 app.walk(&mut |node: &Node, _| {
121 if let Node::Element(element) = node {
122 for (name, prop) in &element.props {
123 if let Prop::Icon { name: icon } = prop
124 && !has(icon)
125 {
126 diagnostics.push(
127 Diagnostic::error(format!(
128 "{set} has no `{icon}` (property `{name}` of `{}`)",
129 element.kind
130 ))
131 .at(element.source.clone()),
132 );
133 }
134 }
135 }
136 });
137 diagnostics
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn the_names_are_sorted_and_in_sf_symbols_naming() {
146 assert!(NAMES.windows(2).all(|pair| pair[0] < pair[1]));
147 for name in NAMES {
148 assert!(
149 name.chars()
150 .all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '.'),
151 "{name}"
152 );
153 }
154 }
155}