clojurescript 2026-04-27

😢

ClojureScript
cljs.user=> (require '[clojure.string :as str])
nil
cljs.user=> (str/replace-first "~{}.prop" "~{}" "$$1")
"$1.prop"
Clojure 1.12.1
user=> (require '[clojure.string :as str])
nil
user=> (str/replace-first "~{}.prop" "~{}" "$$1")
"$$1.prop"

is this a bug or a "feature" of javascript maybe?

some JS odd behavior

👍 1

it's not documented in the docstring though. @dnolen thoughts?

> "~{}.prop".replace("~{}", "$$1")
'$1.prop'

👀 1

maybe it could be changed to pass a function returning the replacement string instead

the implementation of replace-first in CLJS just calls String.replace one of the ways to use the given replacement string literally is to pass a function returning the replacement string instead @nbtheduke but i havent really looked at it for more than a few seconds there may be expectations of the behavior of replace-first that I'm not familiar with

I certaintly didn't expect this gotcha, but it's a JS gotcha. With regex you know there's differences between CLJ and CLJS but with a core function like str/replace-first it's less obvious

👍 1

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_the_replacement

$ node
Welcome to Node.js v25.9.0.
Type ".help" for more information.
> 'axb'.replace('x','$$1')
'a$1b'
> 'axb'.replace('x','$&')
'axb'

https://github.com/clojure/clojurescript/blob/v1.12/src/main/cljs/clojure/string.cljs#L98 (.replace s match (.replaceAll replacement "$", "$$$$")) I think that every replacement should become (.replaceAll replacement "$", "$$$$") Maybe add a (defn escape-replacement helper?!