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 "headphones",
54 "heart",
55 "house",
56 "info.circle",
57 "keyboard",
58 "line.3.horizontal.decrease",
59 "link",
60 "list.bullet.rectangle",
61 "magnifyingglass",
62 "minus",
63 "moon",
64 "music.note",
65 "note.text",
66 "paintbrush",
67 "paintpalette",
68 "paperplane",
69 "pause",
70 "pause.fill",
71 "person.crop.circle",
72 "photo",
73 "pip.enter",
74 "play",
75 "play.fill",
76 "play.rectangle",
77 "plus",
78 "power",
79 "puzzlepiece.extension",
80 "scissors",
81 "server.rack",
82 "shield",
83 "sidebar.right",
84 "slider.horizontal.3",
85 "sparkles",
86 "speaker.fill",
87 "speaker.slash.fill",
88 "speaker.wave.2",
89 "speaker.wave.3.fill",
90 "speedometer",
91 "square",
92 "square.and.arrow.up",
93 "square.grid.2x2",
94 "square.grid.3x3",
95 "square.on.square",
96 "star",
97 "star.fill",
98 "star.slash",
99 "sun.max.fill",
100 "sun.min",
101 "switch.2",
102 "text.bubble",
103 "text.rectangle",
104 "textformat",
105 "textformat.size",
106 "textformat.size.larger",
107 "textformat.size.smaller",
108 "trash",
109 "tray",
110 "tv",
111 "viewfinder",
112 "wifi",
113 "xmark",
114 "xmark.circle.fill",
115];
116
117pub fn check(app: &Application, set: &str, has: impl Fn(&str) -> bool) -> Vec<Diagnostic> {
120 let mut diagnostics = Vec::new();
121 app.walk(&mut |node: &Node, _| {
122 if let Node::Element(element) = node {
123 for (name, prop) in &element.props {
124 if let Prop::Icon { name: icon } = prop
125 && !has(icon)
126 {
127 diagnostics.push(
128 Diagnostic::error(format!(
129 "{set} has no `{icon}` (property `{name}` of `{}`)",
130 element.kind
131 ))
132 .at(element.source.clone()),
133 );
134 }
135 }
136 }
137 });
138 diagnostics
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn the_names_are_sorted_and_in_sf_symbols_naming() {
147 assert!(NAMES.windows(2).all(|pair| pair[0] < pair[1]));
148 for name in NAMES {
149 assert!(
150 name.chars()
151 .all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '.'),
152 "{name}"
153 );
154 }
155 }
156}