js-on-sx: 10 new String.prototype methods (at, codePointAt, lastIndexOf, localeCompare, replaceAll, normalize, ...)

New methods added:
- at(i) — negative-index aware
- codePointAt(i) — returns char code at index
- lastIndexOf — walks right-to-left via js-string-last-index-of helper
- localeCompare — simple lexicographic (ignores locale)
- replaceAll — works with strings and regex-source
- normalize — no-op stub
- toLocaleLowerCase / toLocaleUpperCase — delegate to non-locale variants
- isWellFormed / toWellFormed — assume always well-formed

10 new unit tests, 489/491 total.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-24 07:35:27 +00:00
parent 30ef085844
commit fd73c43eba
2 changed files with 131 additions and 0 deletions

View File

@@ -1624,6 +1624,61 @@
(= idx -1)
nil
(let ((res (list))) (append! res needle) res))))))))
((= name "at")
(fn
(i)
(let
((idx (js-num-to-int i)))
(let
((actual (if (< idx 0) (+ (len s) idx) idx)))
(if
(or (< actual 0) (>= actual (len s)))
:js-undefined (char-at s actual))))))
((= name "codePointAt")
(fn
(i)
(let
((idx (js-num-to-int i)))
(if
(or (< idx 0) (>= idx (len s)))
:js-undefined (char-code (char-at s idx))))))
((= name "lastIndexOf")
(fn
(&rest args)
(if
(empty? args)
-1
(let
((needle (js-to-string (nth args 0))))
(js-string-last-index-of s needle (- (len s) (len needle)))))))
((= name "localeCompare")
(fn
(&rest args)
(if
(empty? args)
0
(let
((other (js-to-string (nth args 0))))
(cond ((< s other) -1) ((> s other) 1) (else 0))))))
((= name "replaceAll")
(fn
(&rest args)
(if
(< (len args) 2)
s
(let
((needle-arg (nth args 0)) (repl (nth args 1)))
(let
((needle (if (js-regex? needle-arg) (get needle-arg "source") (js-to-string needle-arg))))
(js-string-replace-all
s
needle
(if (js-function? repl) repl (js-to-string repl))))))))
((= name "normalize") (fn (&rest args) s))
((= name "toLocaleLowerCase") (fn (&rest args) (js-lower-case s)))
((= name "toLocaleUpperCase") (fn (&rest args) (js-upper-case s)))
((= name "isWellFormed") (fn () true))
((= name "toWellFormed") (fn () s))
(else js-undefined))))
(define
@@ -1654,6 +1709,36 @@
((js-string-matches? s needle i 0) i)
(else (js-string-index-of s needle (+ i 1))))))
(define
js-string-last-index-of
(fn
(s needle start)
(cond
((< start 0) -1)
((= needle "") start)
((js-string-matches? s needle start 0) start)
(else (js-string-last-index-of s needle (- start 1))))))
(define
js-string-replace-all
(fn
(s needle repl)
(if
(= needle "")
s
(let
((idx (js-string-index-of s needle 0)))
(if
(= idx -1)
s
(str
(js-string-slice s 0 idx)
(if (js-function? repl) (repl needle) repl)
(js-string-replace-all
(js-string-slice s (+ idx (len needle)) (len s))
needle
repl)))))))
(define
js-string-matches?
(fn
@@ -1791,6 +1876,18 @@
((= key "replace") (js-string-method obj "replace"))
((= key "search") (js-string-method obj "search"))
((= key "match") (js-string-method obj "match"))
((= key "at") (js-string-method obj "at"))
((= key "codePointAt") (js-string-method obj "codePointAt"))
((= key "lastIndexOf") (js-string-method obj "lastIndexOf"))
((= key "localeCompare") (js-string-method obj "localeCompare"))
((= key "replaceAll") (js-string-method obj "replaceAll"))
((= key "normalize") (js-string-method obj "normalize"))
((= key "toLocaleLowerCase")
(js-string-method obj "toLocaleLowerCase"))
((= key "toLocaleUpperCase")
(js-string-method obj "toLocaleUpperCase"))
((= key "isWellFormed") (js-string-method obj "isWellFormed"))
((= key "toWellFormed") (js-string-method obj "toWellFormed"))
(else js-undefined)))
((= (type-of obj) "dict")
(js-dict-get-walk obj (js-to-string key)))