@tsrx/core@0.1.29
Ripple-TS/ripple@tsrx/core@0.1.29Jun 12, 2026by github-actions[bot]
AI Summary
Fixes internal lowering of TSRX nodes in expression position and CSS selector pruning.
Key Highlights
- Fixes lowering of style expressions and nested blocks to avoid 'Not implemented' errors
- Prunes unreachable CSS selectors across targets
- Unique style scope hashes per file and block
New Features
- Improved internal compiler handling for style expressions
Full Release Notes
### Patch Changes
- [#1257](https://github.com/Ripple-TS/ripple/pull/1257)
[`67de047`](https://github.com/Ripple-TS/ripple/commit/67de047d103f39673b25910e1a97760278820999)
Thanks [@leonidaz](https://github.com/leonidaz)! - Lower TSRX-only nodes inside
expression-position `@{ … }` code blocks. Setup statements of a code block used
as an expression (e.g. `const Test = @{ … }`) were carried into the generated
scoped IIFE verbatim without re-visiting them, so a style expression
(`const styles = <style> … </style>`) or a nested `@{ … }` block inside the
setup reached the printer as a raw `JSXStyleElement` / `JSXCodeBlock` node and
failed with "Not implemented: JSXStyleElement". The lowered scope is now
re-visited the same way function-body code blocks are, so style expressions
compile to their class maps (with the CSS emitted) and nested blocks lower into
their own scopes.
- [#1262](https://github.com/Ripple-TS/ripple/pull/1262)
[`1c645c8`](https://github.com/Ripple-TS/ripple/commit/1c645c8f854df23bb1271b3402d1885616b525cd)
Thanks [@leonidaz](https://github.com/leonidaz)! - Prune unreachable selectors
from `<style>` blocks consistently across targets.
For a style expression (`const styles = <style> … </style>`), only standalone
class selectors — scoped (`.x`) or global-wrapped (`:global(.x)`) — end up in
the generated class map, but the emitted CSS still contained every selector.
Top-level selectors that don't contribute a class map entry (element selectors,
compound selectors, descendant chains, global tag selectors) are now commented
out as unused, while standalone classes, `:global(.x)` selectors, and rules
nested inside a reachable rule (e.g. `&:hover`) are kept.
Free-standing `<style>` blocks in the shared JSX targets (react, preact, solid,
vue) now prune selectors that match no element, the same way the Ripple target
always has, instead of keeping every authored selector. Selector matching also
recognizes `className` as the class attribute for React-style targets.
- [#1260](https://github.com/Ripple-TS/ripple/pull/1260)
[`b1256fd`](https://github.com/Ripple-TS/ripple/commit/b1256fdb5bf279ee7dd20bf1a71dcfccc47e279c)
Thanks [@leonidaz](https://github.com/leonidaz)! - Make style scope hashes
unique per style block and per file. The hash was derived from the style block's
content alone, so two `<style>` blocks with identical CSS — in different
components of the same file, or in different files — collided and shared a
scope. The hash input now includes the filename and the line/column where the
`<style>` tag starts. Because the filename may be an absolute path, the hash
also switched from the reversible djb2 hash to the truncated SHA-256 hash so
file structure can't be recovered from class names in the shipped bundle.
The `filename` parameter of `parse`, `parseModule`, and the per-target `parse`
wrappers is now required (typed as a non-empty string), and parsing a `<style>`
element without one throws a clear error instead of silently seeding the hash
with an empty name. The prettier plugin and eslint parser pass their host's file
path through, falling back to a plugin-specific placeholder when formatting or
linting in-memory text.