I calendar parsing
1

Configure Feed

Select the types of activity you want to include in your feed.

rename splitter -> parser

+48 -55
+48 -55
src/gcal.gleam
··· 77 77 input: String, 78 78 tz: String, 79 79 ) -> Result(Calendar, Error) { 80 - let splitters = new_parser() 80 + let parser = new_parser() 81 81 82 - let lines = unfold_lines(input, splitters) 82 + let lines = unfold_lines(input, parser) 83 83 let non_empty = list.filter(lines, fn(line) { line != "" }) 84 84 85 - case parse_all_components(non_empty, [], splitters) { 86 - Ok(components) -> build_calendar(components, tz, splitters) 85 + case parse_all_components(non_empty, [], parser) { 86 + Ok(components) -> build_calendar(components, tz, parser) 87 87 Error(err) -> Error(err) 88 88 } 89 89 } 90 90 91 - fn unfold_lines(input: String, splitters: Parser) -> List(String) { 92 - do_unfold_lines(input, splitters, []) 91 + fn unfold_lines(input: String, parser: Parser) -> List(String) { 92 + do_unfold_lines(input, parser, []) 93 93 |> list.reverse 94 94 } 95 95 96 96 fn do_unfold_lines( 97 97 input: String, 98 - splitters: Parser, 98 + parser: Parser, 99 99 acc: List(String), 100 100 ) -> List(String) { 101 - case splitter.split(splitters.lines, input) { 101 + case splitter.split(parser.lines, input) { 102 102 #(line, "", "") -> 103 103 case acc { 104 104 [] -> [line] 105 105 [prev, ..rest] -> 106 106 case string.starts_with(line, " ") || string.starts_with(line, "\t") { 107 107 True -> { 108 - let #(_, remaining) = splitter.split_after(splitters.ws, line) 108 + let #(_, remaining) = splitter.split_after(parser.ws, line) 109 109 [prev <> remaining, ..rest] 110 110 } 111 111 False -> [line, prev, ..rest] ··· 113 113 } 114 114 #(line, _, remaining) -> 115 115 case acc { 116 - [] -> do_unfold_lines(remaining, splitters, [line]) 116 + [] -> do_unfold_lines(remaining, parser, [line]) 117 117 [prev, ..rest] -> 118 118 case string.starts_with(line, " ") || string.starts_with(line, "\t") { 119 119 True -> { 120 - let #(_, remaining_line) = 121 - splitter.split_after(splitters.ws, line) 122 - do_unfold_lines(remaining, splitters, [ 120 + let #(_, remaining_line) = splitter.split_after(parser.ws, line) 121 + do_unfold_lines(remaining, parser, [ 123 122 prev <> remaining_line, 124 123 ..rest 125 124 ]) 126 125 } 127 - False -> do_unfold_lines(remaining, splitters, [line, prev, ..rest]) 126 + False -> do_unfold_lines(remaining, parser, [line, prev, ..rest]) 128 127 } 129 128 } 130 129 } ··· 133 132 fn parse_all_components( 134 133 lines: List(String), 135 134 acc: List(Component), 136 - splitters: Parser, 135 + parser: Parser, 137 136 ) -> Result(List(Component), Error) { 138 137 case lines { 139 138 [] -> Ok(list.reverse(acc)) 140 139 [line, ..rest] -> 141 - case splitter.split(splitters.begin, line) { 140 + case splitter.split(parser.begin, line) { 142 141 #("", "BEGIN:", kind) -> 143 - case parse_component(kind, rest, [], [], splitters) { 142 + case parse_component(kind, rest, [], [], parser) { 144 143 Ok(#(component, remaining)) -> 145 - parse_all_components(remaining, [component, ..acc], splitters) 144 + parse_all_components(remaining, [component, ..acc], parser) 146 145 Error(err) -> Error(err) 147 146 } 148 147 _ -> Error(ParseError("Unexpected line: " <> line)) ··· 155 154 lines: List(String), 156 155 props: List(Property), 157 156 children: List(Component), 158 - splitters: Parser, 157 + parser: Parser, 159 158 ) -> Result(#(Component, List(String)), Error) { 160 159 let end_marker = "END:" <> kind 161 160 case lines { ··· 168 167 rest, 169 168 )) 170 169 False -> 171 - case splitter.split(splitters.begin, line) { 170 + case splitter.split(parser.begin, line) { 172 171 #("", "BEGIN:", subkind) -> 173 - case parse_component(subkind, rest, [], [], splitters) { 172 + case parse_component(subkind, rest, [], [], parser) { 174 173 Ok(#(child, remaining)) -> 175 174 parse_component( 176 175 kind, 177 176 remaining, 178 177 props, 179 178 [child, ..children], 180 - splitters, 179 + parser, 181 180 ) 182 181 Error(err) -> Error(err) 183 182 } 184 183 _ -> 185 - case parse_property(line, splitters) { 184 + case parse_property(line, parser) { 186 185 Ok(prop) -> 187 - parse_component( 188 - kind, 189 - rest, 190 - [prop, ..props], 191 - children, 192 - splitters, 193 - ) 186 + parse_component(kind, rest, [prop, ..props], children, parser) 194 187 Error(err) -> Error(err) 195 188 } 196 189 } ··· 198 191 } 199 192 } 200 193 201 - fn parse_property(line: String, splitters: Parser) -> Result(Property, Error) { 202 - case splitter.split(splitters.colon, line) { 194 + fn parse_property(line: String, parser: Parser) -> Result(Property, Error) { 195 + case splitter.split(parser.colon, line) { 203 196 #(name_part, ":", value) -> { 204 - let #(name, params) = parse_name_and_params(name_part, splitters) 197 + let #(name, params) = parse_name_and_params(name_part, parser) 205 198 Ok(Property(name, params, unescape_text(value))) 206 199 } 207 200 _ -> Error(ParseError("Invalid property line: " <> line)) ··· 210 203 211 204 fn parse_name_and_params( 212 205 part: String, 213 - splitters: Parser, 206 + parser: Parser, 214 207 ) -> #(String, List(Parameter)) { 215 - case splitter.split(splitters.semi, part) { 216 - #(name, ";", params_str) -> #(name, parse_params(params_str, splitters)) 208 + case splitter.split(parser.semi, part) { 209 + #(name, ";", params_str) -> #(name, parse_params(params_str, parser)) 217 210 _ -> #(part, []) 218 211 } 219 212 } 220 213 221 - fn parse_params(params_str: String, splitters: Parser) -> List(Parameter) { 222 - do_parse_params(params_str, [], splitters) 214 + fn parse_params(params_str: String, parser: Parser) -> List(Parameter) { 215 + do_parse_params(params_str, [], parser) 223 216 } 224 217 225 218 fn do_parse_params( 226 219 input: String, 227 220 acc: List(Parameter), 228 - splitters: Parser, 221 + parser: Parser, 229 222 ) -> List(Parameter) { 230 - case splitter.split(splitters.semi, input) { 223 + case splitter.split(parser.semi, input) { 231 224 #(param, ";", remaining) -> 232 - case parse_single_param(param, splitters) { 233 - Ok(p) -> do_parse_params(remaining, [p, ..acc], splitters) 234 - Error(_) -> do_parse_params(remaining, acc, splitters) 225 + case parse_single_param(param, parser) { 226 + Ok(p) -> do_parse_params(remaining, [p, ..acc], parser) 227 + Error(_) -> do_parse_params(remaining, acc, parser) 235 228 } 236 229 #(param, "", "") -> 237 - case parse_single_param(param, splitters) { 230 + case parse_single_param(param, parser) { 238 231 Ok(p) -> list.reverse([p, ..acc]) 239 232 Error(_) -> list.reverse(acc) 240 233 } ··· 244 237 245 238 fn parse_single_param( 246 239 param: String, 247 - splitters: Parser, 240 + parser: Parser, 248 241 ) -> Result(Parameter, Error) { 249 - case splitter.split(splitters.eq, param) { 242 + case splitter.split(parser.eq, param) { 250 243 #(name, "=", value) -> Ok(Parameter(name, value)) 251 244 _ -> Error(ParseError("Invalid parameter: " <> param)) 252 245 } ··· 332 325 333 326 fn parse_datetime_value( 334 327 value: String, 335 - splitters: Parser, 328 + parser: Parser, 336 329 ) -> Result(#(calendar.Date, calendar.TimeOfDay, Bool), Error) { 337 - case splitter.split(splitters.t_sep, value) { 330 + case splitter.split(parser.t_sep, value) { 338 331 #(date_str, sep, time_str) -> 339 332 case sep == "T" || sep == "t" { 340 333 True -> { ··· 378 371 @internal 379 372 pub fn parse_datetime( 380 373 prop: Property, 381 - splitters: Parser, 374 + parser: Parser, 382 375 fallback_tz: String, 383 376 ) -> timestamp.Timestamp { 384 377 let value = prop.value ··· 403 396 False -> value 404 397 } 405 398 406 - case parse_datetime_value(clean_value, splitters) { 399 + case parse_datetime_value(clean_value, parser) { 407 400 Ok(#(date, time, _)) -> { 408 401 let tzid = case is_utc { 409 402 True -> Error(ParseError("UTC")) ··· 456 449 457 450 fn build_event( 458 451 props: List(Property), 459 - splitters: Parser, 452 + parser: Parser, 460 453 fallback_tz: String, 461 454 ) -> Event { 462 455 let uid = extract_prop(props, "UID") ··· 471 464 472 465 let dtstart = 473 466 dtstart_prop 474 - |> result.map(fn(p) { parse_datetime(p, splitters, fallback_tz) }) 467 + |> result.map(fn(p) { parse_datetime(p, parser, fallback_tz) }) 475 468 |> result.unwrap(timestamp.unix_epoch) 476 469 let dtend = 477 470 dtend_prop 478 - |> result.map(fn(p) { parse_datetime(p, splitters, fallback_tz) }) 471 + |> result.map(fn(p) { parse_datetime(p, parser, fallback_tz) }) 479 472 |> result.unwrap(timestamp.unix_epoch) 480 473 481 474 Event(uid, summary, dtstart, dtend, is_all_day, props) ··· 484 477 fn build_calendar( 485 478 components: List(Component), 486 479 tz_override: String, 487 - splitters: Parser, 480 + parser: Parser, 488 481 ) -> Result(Calendar, Error) { 489 482 let flat = 490 483 components ··· 511 504 cal_children 512 505 |> list.filter_map(fn(c) { 513 506 case c.kind { 514 - "VEVENT" -> Ok(build_event(c.properties, splitters, detected_tz)) 507 + "VEVENT" -> Ok(build_event(c.properties, parser, detected_tz)) 515 508 _ -> Error(Nil) 516 509 } 517 510 })