Skip to content

Releases: nerima-lisp/cl-cc-javascript

Release list

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 02 Aug 13:02
v0.2.0
07bf60e

Added

  • .github/workflows/: ci.yml, docs.yml, release.yml and flake-update.yml, plus
    the shared nix-setup composite 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.md and the docs/ site (MkDocs Material), neither of which existed.
  • checks.formatting (treefmt/nixfmt) and checks.docs (mkdocs --strict) alongside
    the existing compile and test checks, and an apps.test entry point.
  • packages.coverage-report and checks.coverage: scripts/run-coverage.lisp
    (SB-COVER + cl-weave) existed but was never wired into flake.nix, so no CI run or
    local nix build ever produced a coverage report. checks.coverage asserts the
    report exists; it does not gate on a percentage yet (no check-coverage.pl-equivalent
    exists in this repository, unlike some siblings).
  • A cl-weave custom matcher, :to-have-set-values, replacing a helper function
    (%jr-assert-set-has-all) that issued multiple disconnected expect calls internally
    with one properly-reported assertion.
  • A second cl-weave custom matcher, :to-be-js-undefined (t/runtime-core-test.lisp,
    loaded first so every runtime-*-test.lisp file 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
    public defmatcher macro (not cl-weave's internal, unexported defpredicate-matcher
    that its own built-in zero-argument matchers like :to-be-truthy use) — same pattern
    as the pre-existing :to-have-set-values matcher above. No behavior change: eq
    against +js-undefined+ is exactly what the old :to-be spelling already checked
    (:to-be itself is eql, and this runtime's +js-undefined+ is a single interned
    sentinel, so eq/eql agree here).
  • Two new cl-weave it-property tests, extending this codebase's very sparse use of
    property-based testing (previously exactly one it-property, for btoa/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) and js-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 (pinned v0.1.0), a nerima-lisp dependency-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- channel previously hand-rolled a mutex, condition variable, and an explicit :body/
    :driver turn flag to enforce that exactly one of the two threads runs at a time.
    Replaced with a pair of cl-concurrent-kit:channels (make-channel's default,
    unbuffered/rendezvous mode): an unbuffered channel's send already blocks until the
    matching recv takes the value, so each send/recv pair below is itself the
    synchronization point — no separate turn-tracking is needed at all. Wired through the
    standard four points other nerima-lisp source-tree dependencies in this repo use:
    flake.nix (input pinned to the tag, CL_CC_JAVASCRIPT_CL_CONCURRENT_KIT_ROOT env
    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 in flake.nix's cl-log-kit comment flagging it as worth
    revisiting. No observable behavior change — verified via two consecutive nix build .#checks.aarch64-darwin.default runs (concurrency-sensitive code warrants more than
    one pass): 1319 passed both times, 0 failed.
  • docs/src/architecture.md/docs/src/development.md corrected to match this session's
    changes: stale file/line counts (t/ file count, package.lisp's line count), a gate
    table missing the new checks.coverage, the coverage section not mentioning the
    nix build .#coverage-report path, and a reference to t/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 in cl-weave's
    with-soft-assertions, so a mismatch on one property no longer hides mismatches on
    the others — previously the first failing expect aborted the whole helper.
  • cl-date-kit (pinned v0.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.timeZoneId reports the host's actual IANA
    zone (via TZ or /etc/localtime) instead of a literal "UTC", and
    Temporal.Now.zonedDateTimeISO, Temporal.Instant.prototype.toZonedDateTimeISO, and the
    Temporal.ZonedDateTime epoch-based constructor now project an absolute instant into any
    IANA zone cl-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 in docs/src/compatibility.md). flake.nix's checks.default,
    apps.test, and devShells.default now point TZDIR at nixpkgs' tzdata package so
    this is exercised for real inside the Nix sandbox, not silently skipped.
  • Date.prototype.getTimezoneOffset() now uses the same cl-date-kit host-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 hardcoded 0.
    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 to 0 under the same conditions Temporal's zone functions do (unresolvable
    host zone, no readable tzdata).
  • cl-json-kit (pinned v1.0.1), adopted
    directly (no adapter, through its own :null-value/:false-value/:true-value/
    :number-encoder parse and write hooks) to replace runtime-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 undisclosed JSON.parse/JSON.stringify bugs, all now fixed:
    1. \uXXXX escapes were never decoded during JSON.parse. The hand-rolled string
      scanner's escape case had no \u clause at all, so JSON.parse("\"\\u0041\"")
      produced the six literal characters u0041 prefixed by nothing sensible, not "A".
    2. JSON.parse on malformed input silently returned undefined instead of
      throwing — real JSON.parse throws a SyntaxError. %js-json-parse now signals a
      genuine *js-syntax-error-class* instance via %js-throw, JS-catchable like any
      other thrown error.
    3. JSON.stringify never omitted undefined-valued object properties. The
      omission check (unless (string= vs "undefined") ...) compared against the
      stringified text of the value, but undefined itself 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
      null in an array, and makes a top-level JSON.stringify call return undefined
      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 unique gensym-named string, let json-kit:stringify write 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 existing js-rt-json-raw-json test, unchanged and still green.
      Number formatting (bare digits for a whole number, ~F otherwise) is preserved
      exactly via :number-encoderjson-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-number JSON.stringify
      call from "42" to "42.0" without this hook. Verified via nix 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 exercise JSON.parse/stringify/rawJSON through
      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 own src/*.lisp files —
    filtered by absolute path, unlike the HTML report's basename-keyed per-file links,...
Read more