···11-name = "houdini"
11+name = "houdinis_publicist"
22version = "1.2.0"
33-description = "🪄 Fast HTML escaping"
33+description = "HTML attribute escaping, that can omit quotes if safe to do so"
44licences = ["Apache-2.0"]
55-repository = { type = "github", user = "giacomocavalieri", repo = "houdini" }
55+repository = { type = "github", user = "bentomas", repo = "houdinis_publicist" }
6677[dev-dependencies]
88gleeunit = ">= 1.0.0 and < 2.0.0"
+38-1
src/houdini.gleam
src/houdinis_publicist.gleam
···1212/// assert escape("wibble & wobble") == "wibble & wobble"
1313/// assert escape("wibble > wobble") == "wibble > wobble"
1414/// ```
1515-///
1615@external(javascript, "./houdini.ffi.mjs", "escape")
1716pub fn escape(string: String) -> String {
1817 // This version is highly optimised for the Erlang target, it treats Strings
···2423 // we know that the BitArray we build is definitely a valid string, so we can
2524 // skip verifying that again as well as dealing with the `Result`.
2625 unsafe_bit_array_to_string(result)
2626+}
2727+2828+pub fn escape_attribute(string: String) -> String {
2929+ let bits = <<string:utf8>>
3030+ let result = do_escape_attribute(bits, bits, 0)
3131+3232+ // we know that the BitArray we build is definitely a valid string, so we can
3333+ // skip verifying that again as well as dealing with the `Result`.
3434+ unsafe_bit_array_to_string(result)
3535+}
3636+3737+fn do_escape_attribute(bin: BitArray, original: BitArray, length: Int) {
3838+ // case expression that checks if the first bit of the string is in a
3939+ // alphanumeric character range of ascii
4040+ case bin {
4141+ <<c, rest:bits>> if c >= 48 && c <= 57 ->
4242+ do_escape_attribute(rest, original, length + 1)
4343+ <<c, rest:bits>> if c >= 65 && c <= 90 ->
4444+ do_escape_attribute(rest, original, length + 1)
4545+ <<c, rest:bits>> if c >= 97 && c <= 122 ->
4646+ do_escape_attribute(rest, original, length + 1)
4747+ <<"-", rest:bits>>
4848+ | <<"_", rest:bits>>
4949+ | <<".", rest:bits>>
5050+ | <<":", rest:bits>> -> do_escape_attribute(rest, original, length + 1)
5151+5252+ // didn't ever find something that wasn't whitelisted, can go ahead and
5353+ // use original string
5454+ <<>> -> original
5555+ // otherwise do regular houdini escaping
5656+ <<_, _:bits>> -> {
5757+ let h = do_escape_normal(bin, 0, original, <<>>, length)
5858+ <<"\"", h:bits, "\"">>
5959+ }
6060+6161+ _ ->
6262+ panic as "do_escape_check: non byte aligned string, all strings should be byte aligned"
6363+ }
2764}
28652966// A possible way to escape chars would be to split the string into graphemes,