Releases: nerima-lisp/cl-cc-javascript
Releases · nerima-lisp/cl-cc-javascript
Release list
v0.2.0
Added
.github/workflows/:ci.yml,docs.yml,release.ymlandflake-update.yml, plus
the sharednix-setupcomposite action. This repository previously had no CI at all.flake.lock. The flake declared ten inputs and locked none of them, so no two builds
resolved to the same dependency tree.CHANGELOG.mdand thedocs/site (MkDocs Material), neither of which existed.checks.formatting(treefmt/nixfmt) andchecks.docs(mkdocs --strict) alongside
the existing compile and test checks, and anapps.testentry point.packages.coverage-reportandchecks.coverage:scripts/run-coverage.lisp
(SB-COVER + cl-weave) existed but was never wired intoflake.nix, so no CI run or
localnix buildever produced a coverage report.checks.coverageasserts the
report exists; it does not gate on a percentage yet (nocheck-coverage.pl-equivalent
exists in this repository, unlike some siblings).- A
cl-weavecustom matcher,:to-have-set-values, replacing a helper function
(%jr-assert-set-has-all) that issued multiple disconnectedexpectcalls internally
with one properly-reported assertion. - A second
cl-weavecustom matcher,:to-be-js-undefined(t/runtime-core-test.lisp,
loaded first so everyruntime-*-test.lispfile can use it), replacing the verbose
(expect ... :to-be cl-cc/javascript::+js-undefined+)spelling repeated at 43 call
sites across 13 test files with(expect ... :to-be-js-undefined). Defined via the
publicdefmatchermacro (not cl-weave's internal, unexporteddefpredicate-matcher
that its own built-in zero-argument matchers like:to-be-truthyuse) — same pattern
as the pre-existing:to-have-set-valuesmatcher above. No behavior change:eq
against+js-undefined+is exactly what the old:to-bespelling already checked
(:to-beitself iseql, and this runtime's+js-undefined+is a single interned
sentinel, soeq/eqlagree here). - Two new
cl-weaveit-propertytests, extending this codebase's very sparse use of
property-based testing (previously exactly oneit-property, forbtoa/atob) to
two more genuine round-trip functions:js-rt-encode-decode-uri-component-roundtrip- property(decodeURIComponent(encodeURIComponent(s)) = s,
t/runtime-collections-weak-test.lisp) andjs-rt-text-encoder-decoder-roundtrip- property(TextDecoder().decode(TextEncoder().encode(s)) = s,
t/runtime-builtins-platform-test.lisp, exercising 1/2/3-byte UTF-8 sequences via a
mixed ASCII/é/€ generator alphabet). Both complement pre-existing fixed-example tests
covering the same functions rather than replacing them — the generated cases cover
many more character-run orderings and lengths than a handful of hand-picked strings
can. cl-concurrent-kit(pinnedv0.1.0), anerima-lispdependency-free SBCL concurrency
toolkit, adopted directly — not through an adapter — for the generator runtime's
suspend/resume coroutine hand-off (src/runtime-generator.lisp).%js-generator- channelpreviously hand-rolled a mutex, condition variable, and an explicit:body/
:driverturn flag to enforce that exactly one of the two threads runs at a time.
Replaced with a pair ofcl-concurrent-kit:channels (make-channel's default,
unbuffered/rendezvous mode): an unbuffered channel'ssendalready blocks until the
matchingrecvtakes the value, so eachsend/recvpair below is itself the
synchronization point — no separate turn-tracking is needed at all. Wired through the
standard four points othernerima-lispsource-tree dependencies in this repo use:
flake.nix(input pinned to the tag,CL_CC_JAVASCRIPT_CL_CONCURRENT_KIT_ROOTenv
var),cl-cc-javascript.asd(:depends-on),scripts/dependency-roots.lisp
(env-var → sibling-dir mapping),src/package.lisp(:import-from). This was
specifically evaluated on its own merits (not as a side effect of another dependency
bump) per a standing note inflake.nix'scl-log-kitcomment flagging it as worth
revisiting. No observable behavior change — verified via two consecutivenix build .#checks.aarch64-darwin.defaultruns (concurrency-sensitive code warrants more than
one pass): 1319 passed both times, 0 failed.docs/src/architecture.md/docs/src/development.mdcorrected to match this session's
changes: stale file/line counts (t/file count,package.lisp's line count), a gate
table missing the newchecks.coverage, the coverage section not mentioning the
nix build .#coverage-reportpath, and a reference tot/parser-stmt-test.lisp,
which no longer exists after this session's test-file split.%jr-assert-string-props(a test helper checking several object properties in one
call, e.g. every URL component) now wraps its checks incl-weave's
with-soft-assertions, so a mismatch on one property no longer hides mismatches on
the others — previously the first failingexpectaborted the whole helper.cl-date-kit(pinnedv0.2.0), adopted
directly (no adapter) for real IANA time zone support in the Temporal runtime, which was
previously silently hardcoded to"UTC"everywhere — an undisclosed gap this now both
fixes and documents honestly.Temporal.Now.timeZoneIdreports the host's actual IANA
zone (viaTZor/etc/localtime) instead of a literal"UTC", and
Temporal.Now.zonedDateTimeISO,Temporal.Instant.prototype.toZonedDateTimeISO, and the
Temporal.ZonedDateTimeepoch-based constructor now project an absolute instant into any
IANA zonecl-date-kit's tzdata recognizes — an unambiguous instant → local-zone
projection, not the reverse (constructing from local wall-clock fields in a non-UTC zone,
which needs a DST gap/overlap disambiguation policy, is explicitly out of scope and
documented as such indocs/src/compatibility.md).flake.nix'schecks.default,
apps.test, anddevShells.defaultnow pointTZDIRat nixpkgs'tzdatapackage so
this is exercised for real inside the Nix sandbox, not silently skipped.Date.prototype.getTimezoneOffset()now uses the samecl-date-kithost-zone
discovery and instant → local-zone projection as Temporal (above), reporting genuine
minutes-west-of-UTC for the host's discovered IANA zone instead of a hardcoded0.
Unlike the Temporal gap, this one already had an honest docstring ("UTC assumed"), so
this is a feature addition built on newly-adopted infrastructure, not a disclosure fix.
Falls back to0under the same conditions Temporal's zone functions do (unresolvable
host zone, no readable tzdata).cl-json-kit(pinnedv1.0.1), adopted
directly (no adapter, through its own:null-value/:false-value/:true-value/
:number-encoderparse and write hooks) to replaceruntime-json.lisp's ~100-line
hand-rolled JSON parser/writer with an RFC-8259-conformant one (95/95 JSONTestSuite
must-accept, 188/188 must-reject, per its own README) — comparing the two surfaced
three real, previously undisclosedJSON.parse/JSON.stringifybugs, all now fixed:\uXXXXescapes were never decoded duringJSON.parse. The hand-rolled string
scanner's escapecasehad no\uclause at all, soJSON.parse("\"\\u0041\"")
produced the six literal charactersu0041prefixed by nothing sensible, not"A".JSON.parseon malformed input silently returnedundefinedinstead of
throwing — realJSON.parsethrows aSyntaxError.%js-json-parsenow signals a
genuine*js-syntax-error-class*instance via%js-throw, JS-catchable like any
other thrown error.JSON.stringifynever omittedundefined-valued object properties. The
omission check (unless (string= vs "undefined") ...) compared against the
stringified text of the value, butundefineditself always stringified to the
text"null"first — so the comparison could never be true, and
JSON.stringify({a: undefined})produced{"a":null}instead of{}. Fixed with
genuinely context-aware handling (%js-json-stringify-normalize): an
undefined/function/Symbol value is omitted from an object property, becomes
nullin an array, and makes a top-levelJSON.stringifycall returnundefined
itself (not a string) — three different real-JS behaviors the old code conflated
into one wrong one.
JSON.rawJSON's raw-fragment splicing (json-kit has no native "write this text
verbatim" leaf type) is done via a marker-substitution pass — normalize each raw
wrapper to a uniquegensym-named string, letjson-kit:stringifywrite it as an
ordinary JSON string, then replace that string's own quoted form in the output text
with the real raw text. Previously implemented but never actually tested end-to-end;
now covered by the existingjs-rt-json-raw-jsontest, unchanged and still green.
Number formatting (bare digits for a whole number,~Fotherwise) is preserved
exactly via:number-encoder—json-kit's own default keeps a float's decimal
point unconditionally (for CL integer/float round-trip fidelity, a distinction JS
numbers don't make), which would have regressed every whole-numberJSON.stringify
call from"42"to"42.0"without this hook. Verified vianix build .#checks.aarch64-darwin.default: 1333 → 1336 passed (one case removed — subsumed by
a dedicated new test — one existing test's assertion corrected, four new), 0 failed —
including the E2E tests that exerciseJSON.parse/stringify/rawJSONthrough
actually-compiled JS source.
scripts/coverage-summary.lisp: parses the LCOV report (see below) and prints an
aggregate line-coverage percentage for this repository's ownsrc/*.lispfiles —
filtered by absolute path, unlike the HTML report's basename-keyed per-file links,...