wowlab_cli/commands/snapshot/assisted_rotas/
dsl.rs1use serde_json::{Value, json};
2use wowlab_parsers::DbcData;
3use wowlab_types::sim::FastMap;
4
5pub(super) fn resolve_spell_id(overrides: &FastMap<i32, i32>, spell_id: i32) -> i32 {
6 overrides.get(&spell_id).copied().unwrap_or(spell_id)
7}
8
9pub(super) fn spell_token_for_id(dbc: &DbcData, spell_id: i32) -> String {
10 let name = dbc
11 .spell_name
12 .get(&spell_id)
13 .and_then(|row| row.Name_lang.as_deref())
14 .unwrap_or("");
15 let token = slugify(name);
16
17 if token.is_empty() {
18 format!("spell_{spell_id}")
19 } else {
20 token
21 }
22}
23
24pub(super) fn condition_spell_ref(
25 dbc: &DbcData,
26 overrides: &FastMap<i32, i32>,
27 spell_id: i32,
28 fallback: &str,
29) -> String {
30 if spell_id > 0 {
31 spell_token_for_id(dbc, resolve_spell_id(overrides, spell_id))
32 } else {
33 fallback.to_string()
34 }
35}
36
37#[expect(
38 clippy::needless_pass_by_value,
39 reason = "the comparison node takes ownership of both JSON subtrees"
40)]
41pub(super) fn compare(op: &str, left: Value, right: Value) -> Value {
42 json!({ "type": "compare", "op": op, "left": left, "right": right })
43}
44
45pub(super) fn int(v: i32) -> Value {
46 json!({ "type": "int", "value": v })
47}
48
49pub(super) fn float(v: f64) -> Value {
50 json!({ "type": "float", "value": v })
51}
52
53pub(super) fn read(domain: &str, name: &str) -> Value {
54 json!({ "type": "read", "domain": domain, "name": name })
55}
56
57pub(super) fn read_key(domain: &str, name: &str, key: &str) -> Value {
58 json!({ "type": "read", "domain": domain, "name": name, "key": key })
59}
60
61pub(super) fn read_aura(aura: &str, name: &str, on: Option<&str>) -> Value {
62 match on {
63 Some(target) => json!({
64 "type": "read", "domain": "aura", "name": name, "key": aura, "on": target
65 }),
66 None => read_key("aura", name, aura),
67 }
68}
69
70pub(super) fn slugify_or(input: &str, fallback: impl FnOnce() -> String) -> String {
71 let slug = slugify(input);
72
73 if slug.is_empty() { fallback() } else { slug }
74}
75
76fn slugify(input: &str) -> String {
77 let mut output = String::with_capacity(input.len());
78 let mut last_was_separator = true;
79
80 for character in input.chars() {
81 if character.is_ascii_alphanumeric() {
82 output.push(character.to_ascii_lowercase());
83 last_was_separator = false;
84 } else if character == '\'' || character == '\u{2019}' {
85 } else if !last_was_separator {
86 output.push('_');
87 last_was_separator = true;
88 }
89 }
90
91 while output.ends_with('_') {
92 output.pop();
93 }
94
95 if output.starts_with(|character: char| character.is_ascii_digit()) {
96 format!("spell_{output}")
97 } else {
98 output
99 }
100}