mirror of https://git.nuv.sh/nuv/condition_overload

fix parser issues with mixed multi / single line entries

nnuuvv 1b3fd026 44671123

Changed files
+107 -86
src
+107 -86
src/condition_overload.gleam
··· 13 13 pub fn main() { 14 14 let assert Ok(search) = 15 15 argv.load().arguments 16 - |> list.first() 16 + |> list.reduce(fn(acc, x) { acc <> " " <> x }) 17 17 as "search has to be supplied as argument" 18 18 let search = string.lowercase(search) 19 19 20 - let _ = 21 - [ 22 - "https://wiki.warframe.com/w/Condition_Overload_%28Mechanic%29?action=edit&section=7", 23 - "https://wiki.warframe.com/w/Condition_Overload_%28Mechanic%29?action=edit&section=8", 24 - ] 25 - |> list.map(get_page_data) 26 - |> promise.await_list() 27 - |> promise.map(result.values) 28 - |> promise.map(list.flatten) 29 - |> promise.map( 30 - list.find(_, fn(item) { 31 - item.names 32 - |> list.any(fn(name) { 33 - let lower = string.lowercase(name) 34 - string.contains(lower, search) 35 - }) 36 - }), 37 - ) 38 - // print value 39 - |> promise.map(result.map(_, fn(x) { io.println(format_row(x)) })) 40 - // print error 41 - |> promise.map( 42 - result.map_error(_, fn(x) { 43 - io.println("something went wrong: " <> string.inspect(x)) 44 - }), 45 - ) 20 + [ 21 + "https://wiki.warframe.com/w/Condition_Overload_%28Mechanic%29?action=edit&section=7", 22 + "https://wiki.warframe.com/w/Condition_Overload_%28Mechanic%29?action=edit&section=8", 23 + ] 24 + |> list.map(get_page_data) 25 + |> promise.await_list() 26 + |> promise.map(result.values) 27 + |> promise.map(list.flatten) 28 + |> promise.map( 29 + list.filter(_, fn(item) { 30 + item.names 31 + |> list.any(fn(name) { 32 + let lower = string.lowercase(name) 33 + string.contains(lower, search) 34 + }) 35 + }), 36 + ) 37 + |> promise.map(list.take(_, 4)) 38 + // print values 39 + |> promise.map(list.map(_, fn(x) { io.println(format_row(x)) })) 46 40 } 47 41 42 + // format row into human readable string 43 + // 48 44 fn format_row(row: Row) -> String { 49 - case row { 45 + let rating = case row { 50 46 Row(math_behavior: "Multiplying", ..) -> "very good" 51 47 Row(math_behavior: "Adding", co_bonus_rel_base:, ..) -> { 52 48 let co_bonus_rel_base = ··· 68 64 69 65 _ -> "some secret third option" 70 66 } 67 + 68 + let Row( 69 + names:, 70 + attack:, 71 + projectile: _, 72 + base_damage: _, 73 + co_bonus_at_100: _, 74 + co_bonus_rel_base: _, 75 + math_behavior: _, 76 + notes: _, 77 + ) = row 78 + 79 + let name = 80 + list.first(names) 81 + |> result.unwrap("") 82 + 83 + "The '" 84 + <> name 85 + <> "' '" 86 + <> attack 87 + <> "' attack has a " 88 + <> rating 89 + <> " interaction with GunCO" 71 90 } 72 91 73 92 // do request and return Row if successful ··· 158 177 fn process_lines(lines: List(String), acc: List(Row)) -> List(Row) { 159 178 case lines { 160 179 ["|{{Weapon|" <> name_line, ..rest] -> { 161 - let row = case rest { 162 - ["|-", ..] -> { 163 - parse_values_line(name_line) 164 - } 165 - [] | _ -> { 166 - let #(names, _) = parse_names(name_line, []) 167 - let row = parse_values_vertical(names, rest) 168 - row 169 - } 170 - } 180 + let #(row, rest) = parse_row(name_line, rest) 171 181 172 182 process_lines(rest, [row, ..acc]) 173 183 } ··· 188 198 // 189 199 // |{{Weapon|Braton}}/{{Weapon|MK1-Braton|MK1}}/{{Weapon|Braton Prime|Prime}}/{{Weapon|Braton Vandal|Vandal}}||Incarnon Form AoE||AoE||74||70||95%||Adding||Listed values for Braton Prime with inactive Daring Reverie. Radial hit only receives CO bonus on target directly hit by bullet. AoE does not scale off multishot. 190 200 // 191 - fn parse_values_line(line: String) -> Row { 192 - let #(names, rest) = parse_names(line, []) 193 - 194 - let sep = splitter.new(["||"]) 195 - 196 - let #(attack, _, rest) = splitter.split(sep, rest) 197 - let #(projectile, _, rest) = splitter.split(sep, rest) 198 - let #(base_damage, _, rest) = splitter.split(sep, rest) 199 - let #(co_bonus_at_100, _, rest) = splitter.split(sep, rest) 200 - let #(co_bonus_rel_base, _, rest) = splitter.split(sep, rest) 201 - let #(math_behavior, _, rest) = splitter.split(sep, rest) 202 - let #(notes, _, _) = splitter.split(sep, rest) 203 - Row( 204 - names:, 205 - attack:, 206 - projectile:, 207 - base_damage:, 208 - co_bonus_at_100:, 209 - co_bonus_rel_base:, 210 - math_behavior:, 211 - notes:, 212 - ) 213 - } 214 - 215 201 // multi line - single & multi name 216 202 // 217 203 // |{{Weapon|Evensong}} ··· 224 210 // |Does not apply 225 211 // |- 226 212 // 227 - fn parse_values_vertical(names: List(String), lines: List(String)) -> Row { 228 - let #(attack, rest) = parse_value(lines) 229 - let #(projectile, rest) = parse_value(rest) 230 - let #(base_damage, rest) = parse_value(rest) 231 - let #(co_bonus_at_100, rest) = parse_value(rest) 232 - let #(co_bonus_rel_base, rest) = parse_value(rest) 233 - let #(math_behavior, rest) = parse_value(rest) 234 - let #(notes, _) = parse_value(rest) 213 + fn parse_row(name_line: String, lines: List(String)) -> #(Row, List(String)) { 214 + let #(names, line_rest) = parse_names(name_line, []) 235 215 236 - Row( 237 - names:, 238 - attack:, 239 - projectile:, 240 - base_damage:, 241 - co_bonus_at_100:, 242 - co_bonus_rel_base:, 243 - math_behavior:, 244 - notes:, 216 + let #(attack, line_rest, rest) = parse_next_value(line_rest, lines) 217 + let #(projectile, line_rest, rest) = parse_next_value(line_rest, rest) 218 + let #(base_damage, line_rest, rest) = parse_next_value(line_rest, rest) 219 + let #(co_bonus_at_100, line_rest, rest) = parse_next_value(line_rest, rest) 220 + let #(co_bonus_rel_base, line_rest, rest) = parse_next_value(line_rest, rest) 221 + let #(math_behavior, line_rest, rest) = parse_next_value(line_rest, rest) 222 + let #(notes, _, rest) = parse_next_value(line_rest, rest) 223 + 224 + #( 225 + Row( 226 + names:, 227 + attack:, 228 + projectile:, 229 + base_damage:, 230 + co_bonus_at_100:, 231 + co_bonus_rel_base:, 232 + math_behavior:, 233 + notes:, 234 + ), 235 + rest, 245 236 ) 246 237 } 247 238 248 - // read values one at a time until the next |- 249 - // 250 - fn parse_value(lines: List(String)) { 239 + fn parse_next_value( 240 + line_rest: String, 241 + lines: List(String), 242 + ) -> #(String, String, List(String)) { 243 + let sep = splitter.new(["||"]) 244 + 245 + case splitter.split(sep, line_rest) { 246 + #("", _, _) -> do_lines(sep, lines) 247 + #(value, "||", line_rest) -> #(value, line_rest, lines) 248 + #(value, "", _) -> #(value, "", lines) 249 + #(_, _, _) -> do_lines(sep, lines) 250 + } 251 + } 252 + 253 + fn do_lines(sep, lines) { 251 254 case lines { 252 - ["|-", ..] -> #("", lines) 253 - ["|" <> value, ..rest] -> #(value, rest) 254 - [] | [_] | [_, _, ..] -> #("", lines) 255 + ["|-", ..] -> #("", "", lines) 256 + ["|" <> value, ..rest] -> { 257 + case splitter.split(sep, value) { 258 + #(value, "||", line_rest) -> #(value, line_rest, rest) 259 + #(value, _, _) -> #(value, "", rest) 260 + } 261 + } 262 + [] | [_] | [_, _, ..] -> #("", "", lines) 255 263 } 256 264 } 257 265 ··· 262 270 263 271 let #(name, split_by, rest) = splitter.split(sep, line) 264 272 273 + let name = 274 + string.split_once(name, "|") 275 + |> result.map(pair.first) 276 + |> result.unwrap(name) 277 + 265 278 case split_by { 266 279 "}}/{{Weapon|" | "}}/{{Weapon" -> parse_names(rest, [name, ..acc]) 267 - _ -> #([name, ..acc], rest) 280 + _ -> { 281 + // handle special cases where extra text is included after the weapon names 282 + let rest = 283 + string.split_once(rest, "||") 284 + |> result.map(pair.second) 285 + |> result.unwrap(rest) 286 + 287 + #([name, ..acc], rest) 288 + } 268 289 } 269 290 }