///|
pub fn parse(text : String) -> Robots {
let groups : Array[Group] = []
let sitemaps : Array[String] = []
let hosts : Array[String] = []
let mut agents : Array[String] = []
let mut rules : Array[Rule] = []
let mut delay : Int? = None
let mut saw_rule = false
fn flush() {
if !agents.is_empty() || !rules.is_empty() || delay is Some(_) {
groups.push({ agents, rules, crawl_delay: delay })
}
agents = []
rules = []
delay = None
saw_rule = false
}
for raw in split_lines(text) {
let line = trim_ascii(strip_inline_comment(raw))
if line == "" {
flush()
continue
}
let parts = split_once(line, ":")
if parts.length() < 2 {
continue
}
let key = lower_ascii(trim_ascii(parts[0]))
let value = trim_ascii(parts[1])
if key == "user-agent" {
if saw_rule {
flush()
}
agents.push(lower_ascii(value))
} else if key == "allow" {
saw_rule = true
rules.push(allow_rule(normalize_path(value)))
} else if key == "disallow" {
saw_rule = true
if value != "" {
rules.push(disallow_rule(normalize_path(value)))
}
} else if key == "crawl-delay" {
saw_rule = true
delay = parse_non_negative_int(value)
} else if key == "sitemap" {
sitemaps.push(value)
} else if key == "host" {
hosts.push(value)
}
}
flush()
{ groups, sitemaps, hosts }
}
///|
pub fn parse_report(text : String) -> String {
let robots = parse(text)
"groups=" +
robots.groups.length().to_string() +
"\nsitemaps=" +
robots.sitemaps.length().to_string() +
"\nhosts=" +
robots.hosts.length().to_string()
}
///|
pub fn parse_errors(text : String) -> Array[String] {
let errors : Array[String] = []
let mut line_no = 0
for raw in split_lines(text) {
line_no += 1
let line = trim_ascii(strip_inline_comment(raw))
if line == "" {
continue
}
let parts = split_once(line, ":")
if parts.length() < 2 {
errors.push("line " + line_no.to_string() + ": missing ':'")
continue
}
let key = lower_ascii(trim_ascii(parts[0]))
let value = trim_ascii(parts[1])
if key == "crawl-delay" && parse_non_negative_int(value) is None {
errors.push("line " + line_no.to_string() + ": invalid crawl-delay")
} else if key == "user-agent" && value == "" {
errors.push("line " + line_no.to_string() + ": empty user-agent")
}
}
errors
}
///|
pub fn validation_report(text : String) -> String {
let errors = parse_errors(text)
if errors.is_empty() {
"ok"
} else {
join_lines(errors)
}
}