diff --git a/src/Hox/SelectorParser.fs b/src/Hox/SelectorParser.fs index cdd55aa..0b22d82 100644 --- a/src/Hox/SelectorParser.fs +++ b/src/Hox/SelectorParser.fs @@ -36,15 +36,24 @@ let private pClass: Parser = >>= fun cls -> preturn(Class cls) let private pAttribute: Parser = - let name = manyChars(letter <|> digit <|> pchar '-') + let name = + letter .>>. manyChars(letter <|> digit <|> pchar '-') + >>= fun (initial, rest) -> preturn $"{initial}{rest}" + let eq = pchar '=' let value = manySatisfy(fun ch -> ch <> ']') - pchar '[' >>. name .>> eq .>>. value + pchar '[' >>. name .>> opt eq .>>. opt value .>> unicodeSpaces .>> pchar ']' .>> unicodeSpaces - >>= fun (name, value) -> preturn(Attribute { name = name; value = value }) + >>= fun (name, value) -> + preturn( + Attribute { + name = name + value = defaultArg value System.String.Empty + } + ) let private pSelector: Parser = unicodeSpaces >>. tagName .>> unicodeSpaces diff --git a/tests/Hox.Tests/Parser.fs b/tests/Hox.Tests/Parser.fs index 49f02bd..23fabe4 100644 --- a/tests/Hox.Tests/Parser.fs +++ b/tests/Hox.Tests/Parser.fs @@ -249,3 +249,19 @@ let ``Attributes can have arbitrary content within '[' ']'``() = """~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?1234567890-=qwertyuiop\asdfghjkl;'zxcvbnm,./"""), attributes ) + +[] +let ``Can parse selector without value``() = + let expected = { + tag = "div" + attributes = LinkedList [ Attribute { name = "data-foo"; value = "" } ] + children = LinkedList [] + } + + let actual = Parsers.selector "div[data-foo]" + Assert.Equal(expected.tag, actual.tag) + + match actual.attributes.First.Value with + | Attribute { name = "data-foo"; value = "" } -> () + | _ -> + Assert.Fail("Expected an attribute with the name 'data-foo' and value ''")