js-on-sx: Object.assign ToObjects target, throws on null, walks string sources
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 41s

This commit is contained in:
2026-05-09 21:42:15 +00:00
parent 793eccfce2
commit 7d575cb1fe
2 changed files with 38 additions and 11 deletions

View File

@@ -4039,20 +4039,45 @@
(fn
(&rest args)
(cond
((= (len args) 0) (dict))
((= (len args) 0)
(raise (js-new-call TypeError (js-args "Object.assign called on null or undefined"))))
(else
(let
((target (nth args 0)))
(for-each
(fn
(src)
(when
(dict? src)
((raw-target (nth args 0)))
(cond
((or (= raw-target nil) (js-undefined? raw-target))
(raise (js-new-call TypeError (js-args "Object.assign called on null or undefined"))))
(else
(let
((target (js-coerce-this-arg raw-target)))
(for-each
(fn (k) (dict-set! target k (get src k)))
(keys src))))
(rest args))
target)))))
(fn
(src)
(cond
((or (= src nil) (js-undefined? src)) nil)
((dict? src)
(for-each
(fn
(k)
(if (js-key-internal? k) nil (dict-set! target k (get src k))))
(js-object-keys src)))
((= (type-of src) "string")
(let
((n (len src)))
(begin (js-object-assign-string-loop target src 0 n))))))
(rest args))
target))))))))
(define
js-object-assign-string-loop
(fn
(target s i n)
(cond
((>= i n) nil)
(else
(begin
(dict-set! target (js-to-string i) (char-at s i))
(js-object-assign-string-loop target s (+ i 1) n))))))
(define js-object-freeze (fn (o) o))

View File

@@ -158,6 +158,8 @@ Each item: implement → tests → update progress. Mark `[x]` when tests green.
Append-only record of completed iterations. Loop writes one line per iteration: date, what was done, test count delta.
- 2026-05-09 — **`Object.assign` ToObject's target, throws TypeError on null/undefined, copies own enumerable props from string sources.** Was returning the raw target unchanged when given a primitive (`Object.assign("a")` returned the string `"a"`), and silently no-op'd on null/undefined target instead of throwing per spec. Now coerces target via `js-coerce-this-arg` (boxes primitives), guards null/undefined with TypeError, and walks each source: dict → copy own keys (skipping internal `__js_order__` / `__proto__`), string → copy each character at numeric index, null/undefined → skip. Now `Object.assign("a")` returns a String wrapper whose `valueOf()` is `"a"`, and `Object.assign(null)` throws TypeError. Result: built-ins/Object/assign 5/25 → 13/25 (+8). Object 30/30 holds. conformance.sh: 148/148.
- 2026-05-09 — **`Number.prototype.toFixed`/`toString`/etc. unwrap Number wrappers and throw TypeError on non-Number receivers.** Was passing `(js-this)` straight through to `js-number-to-fixed`, so calling `Number.prototype.toFixed(1)` directly on `Number.prototype` (a Number wrapper dict) raised `"Expected number, got dict"`. Per spec, these methods must extract the Number primitive value (from primitive or wrapper) and throw TypeError otherwise. Added `js-number-this-val` helper that handles primitive number, rational, `__js_number_value__`-marked wrapper, and raises TypeError for everything else. Routed all six Number.prototype methods through it. Result: built-ins/Number/prototype/toFixed 5/13 → 7/13. Number 26/30 holds. conformance.sh: 148/148.
- 2026-05-09 — **`Array.prototype` methods carry spec lengths and names.** Continuation of the same fix. `js-array-proto-fn` was returning bare lambdas → `Array.prototype.push.length === 0` instead of `1`. Added `js-array-proto-fn-length` (lookup table for the ~30 method names — `push:1`, `slice:2`, `splice:2`, `concat:1`, `forEach:1`, `every:1`, `flat:0`, etc.) and changed the helper to return the dict-with-`__callable__` form. Now `Array.prototype.push.length === 1`, `Array.prototype.slice.length === 2`. Array 27/50, Array.prototype 8/30, Object 30/30 unchanged. conformance.sh: 148/148.