js-on-sx: String.prototype extensions + Object/Array builtins

Strings: includes, startsWith, endsWith, trim, trimStart, trimEnd,
repeat, padStart, padEnd, toString, valueOf.

Object: keys, values, entries, assign, freeze (no-op).
Array: isArray, of.

All wired into js-global. 17 new unit tests.

357/359 unit (+17), 148/148 slice unchanged.
This commit is contained in:
2026-04-23 20:58:24 +00:00
parent 6c4001a299
commit 275d2ecbae
3 changed files with 222 additions and 1 deletions

View File

@@ -885,6 +885,36 @@
((>= i (len arr)) acc)
(else (js-list-reduce-loop f (f acc (nth arr i)) arr (+ i 1))))))
(define
js-string-repeat
(fn
(s n acc)
(if (<= n 0) acc (js-string-repeat s (- n 1) (str acc s)))))
(define
js-string-pad
(fn
(s target pad at-start)
(let
((slen (len s)))
(if
(or (<= target slen) (= (len pad) 0))
s
(let
((needed (- target slen)))
(let
((padding (js-string-pad-build pad needed "")))
(if at-start (str padding s) (str s padding))))))))
(define
js-string-pad-build
(fn
(pad needed acc)
(cond
((<= needed 0) acc)
((>= (len acc) needed) (js-string-slice acc 0 needed))
(else (js-string-pad-build pad needed (str acc pad))))))
(define
js-string-method
(fn
@@ -933,6 +963,51 @@
((= name "split") (fn (sep) (js-string-split s (js-to-string sep))))
((= name "concat")
(fn (&rest args) (js-string-concat-loop s args 0)))
((= name "includes")
(fn
(&rest args)
(let
((needle (if (= (len args) 0) "" (js-to-string (nth args 0)))))
(>= (js-string-index-of s needle 0) 0))))
((= name "startsWith")
(fn
(&rest args)
(let
((needle (if (= (len args) 0) "" (js-to-string (nth args 0))))
(start (if (< (len args) 2) 0 (js-num-to-int (nth args 1)))))
(js-string-matches? s needle start 0))))
((= name "endsWith")
(fn
(&rest args)
(let
((needle (if (= (len args) 0) "" (js-to-string (nth args 0)))))
(let
((end-len (len s)) (n-len (len needle)))
(if
(> n-len end-len)
false
(js-string-matches? s needle (- end-len n-len) 0))))))
((= name "trim") (fn () (js-trim s)))
((= name "trimStart") (fn () (js-trim-left s)))
((= name "trimEnd") (fn () (js-trim-right s)))
((= name "repeat")
(fn (n) (js-string-repeat s (js-num-to-int n) "")))
((= name "padStart")
(fn
(&rest args)
(let
((target (if (= (len args) 0) 0 (js-num-to-int (nth args 0))))
(pad (if (< (len args) 2) " " (js-to-string (nth args 1)))))
(js-string-pad s target pad true))))
((= name "padEnd")
(fn
(&rest args)
(let
((target (if (= (len args) 0) 0 (js-num-to-int (nth args 0))))
(pad (if (< (len args) 2) " " (js-to-string (nth args 1)))))
(js-string-pad s target pad false))))
((= name "toString") (fn () s))
((= name "valueOf") (fn () s))
(else js-undefined))))
(define
@@ -1061,6 +1136,17 @@
((= key "toLowerCase") (js-string-method obj "toLowerCase"))
((= key "split") (js-string-method obj "split"))
((= key "concat") (js-string-method obj "concat"))
((= key "includes") (js-string-method obj "includes"))
((= key "startsWith") (js-string-method obj "startsWith"))
((= key "endsWith") (js-string-method obj "endsWith"))
((= key "trim") (js-string-method obj "trim"))
((= key "trimStart") (js-string-method obj "trimStart"))
((= key "trimEnd") (js-string-method obj "trimEnd"))
((= key "repeat") (js-string-method obj "repeat"))
((= key "padStart") (js-string-method obj "padStart"))
((= key "padEnd") (js-string-method obj "padEnd"))
((= key "toString") (js-string-method obj "toString"))
((= key "valueOf") (js-string-method obj "valueOf"))
(else js-undefined)))
((= (type-of obj) "dict")
(js-dict-get-walk obj (js-to-string key)))
@@ -1347,6 +1433,80 @@
(dict-set! p "value" reason)
(js-promise-flush-callbacks! p))))))
(define
js-object-keys
(fn
(o)
(cond
((dict? o)
(let
((result (list)))
(for-each (fn (k) (append! result k)) (keys o))
result))
(else (list)))))
(define
js-object-values
(fn
(o)
(cond
((dict? o)
(let
((result (list)))
(for-each (fn (k) (append! result (get o k))) (keys o))
result))
(else (list)))))
(define
js-object-entries
(fn
(o)
(cond
((dict? o)
(let
((result (list)))
(for-each
(fn
(k)
(let
((pair (list)))
(append! pair k)
(append! pair (get o k))
(append! result pair)))
(keys o))
result))
(else (list)))))
(define
js-object-assign
(fn
(&rest args)
(cond
((= (len args) 0) (dict))
(else
(let
((target (nth args 0)))
(for-each
(fn
(src)
(when
(dict? src)
(for-each
(fn (k) (dict-set! target k (get src k)))
(keys src))))
(rest args))
target)))))
(define js-object-freeze (fn (o) o))
(define Object {:entries js-object-entries :values js-object-values :freeze js-object-freeze :assign js-object-assign :keys js-object-keys})
(define js-array-is-array (fn (v) (list? v)))
(define js-array-of (fn (&rest args) args))
(define Array {:isArray js-array-is-array :of js-array-of})
(define
js-promise-flush-callbacks!
(fn
@@ -1761,4 +1921,4 @@
(str "/" (get rx "source") "/" (get rx "flags")))
(else js-undefined))))
(define js-global {:isFinite js-global-is-finite :console console :Number Number :Math Math :NaN 0 :Infinity inf :isNaN js-global-is-nan :undefined js-undefined})
(define js-global {:isFinite js-global-is-finite :console console :Number Number :Math Math :Array Array :NaN 0 :Infinity inf :isNaN js-global-is-nan :Object Object :undefined js-undefined})