//! The plain domain-list format: one candidate name per line. Pure, `std` only.

const std = @import("std");
const parsers = @import("parsers.zig");

pub fn parseLine(line: []const u8) parsers.Line {
    // Both comment markers appear in domain lists in the wild.
    const marker = std.mem.findAny(u8, line, "#!") orelse line.len;
    const text = std.mem.trim(u8, line[0..marker], &std.ascii.whitespace);
    if (text.len == 0) return .{ .kind = .ignore };
    if (text[0] == '/') return .{ .kind = .regex };
    // A second field means the list is a mis-detected hosts file. Counting that
    // is honest; guessing which field is the name is not.
    if (std.mem.findAny(u8, text, &std.ascii.whitespace) != null) return .{ .kind = .unsupported };
    return .{ .kind = .domain, .text = text };
}

const testing = std.testing;

test "a bare name" {
    const line = parseLine("ads.example.com");
    try testing.expectEqual(parsers.Kind.domain, line.kind);
    try testing.expectEqualStrings("ads.example.com", line.text);
}

test "a bang comment line is ignored" {
    try testing.expectEqual(parsers.Kind.ignore, parseLine("! comment").kind);
}

test "a hash comment line is ignored" {
    try testing.expectEqual(parsers.Kind.ignore, parseLine("# comment").kind);
}

test "an inline comment is removed" {
    const line = parseLine("example.com # x");
    try testing.expectEqual(parsers.Kind.domain, line.kind);
    try testing.expectEqualStrings("example.com", line.text);
}

test "a regex line is recognized" {
    try testing.expectEqual(parsers.Kind.regex, parseLine("/re/").kind);
}

test "a hosts line in a domains list is unsupported" {
    try testing.expectEqual(parsers.Kind.unsupported, parseLine("0.0.0.0 example.com").kind);
}
