diff --git a/.gitignore b/.gitignore index aa41c05..d2b04b1 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ test_output*.txt /bugcontents.db /bugs/ contents.db +/docs/idea_plugin.md.deploy_backup diff --git a/CHANGELOG.md b/CHANGELOG.md index e302c5a..f1f7fad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,31 @@ History note: - No unreleased entries yet. +## 1.5.6 (2026-05-16) + +### Process execution and CLI scripting +- Added `lyng.io.process` for coroutine-friendly external process execution. +- Added `sh(...)`, `exec(...)`, and `CommandRun` with captured output, streaming output, `wait()`, `check()`, and process status helpers. +- Documented safe shell-vs-argv usage and common script patterns for CLI automation. + +### HTTP server and HTML rendering +- Added the minimal `lyng.io.http.server` API for embedded HTTP/1.1 services, local tools, test fixtures, and lightweight app backends. +- Added exact-path, regex, and path-template routing with named route parameters. +- Added `RequestContext` receiver sugar, JSON helpers (`jsonBody()`, `respondJson(...)`), reusable routers, and WebSocket routes. +- Added `respondHtml { ... }` and the pure Lyng `lyng.io.html` builder DSL with escaped text, attributes, common tag helpers, and generic tag escape hatches. + +### Language and serialization +- Added receiver-stack function types and context receiver extensions for DSL-style APIs. +- Added canonical JSON round-trip APIs with `Json.encode(...)` / `Json.decode(...)`. +- Added typed canonical JSON APIs with `Json.encodeAs(Type, value)` / `Json.decodeAs(Type, text)`. +- Extended database serialization support with typed canonical JSON encoding, SQL object expansion, decode annotations, and preserved declaration metadata. + +### Runtime, docs, and samples +- Fixed nullable Elvis-with-`break` inference and callable return inference regressions. +- Fixed CLI bootstrap behavior for HTTP server scripts and CLI input handling. +- Expanded docs for HTTP, WebSocket, serialization, process execution, DSL receivers, and the generated site. +- Release metadata and README now point to `1.5.6`. + ## 1.5.5 (2026-04-23) ### Concurrency and collections diff --git a/README.md b/README.md index d9e1515..4a408e1 100644 --- a/README.md +++ b/README.md @@ -48,12 +48,16 @@ assertEquals(A.E.One, A.One) - [Language home](https://lynglang.com) - [introduction and tutorial](docs/tutorial.md) - start here please -- [Latest release notes (1.5.5)](docs/whats_new.md) +- [Latest release notes (1.5.6)](docs/whats_new.md) - [What's New in 1.5](docs/whats_new_1_5.md) - [Testing and Assertions](docs/Testing.md) - [Filesystem and Processes (lyngio)](docs/lyngio.md) - [SQL Databases (lyng.io.db)](docs/lyng.io.db.md) +- [HTTP Server (lyng.io.http.server)](docs/lyng.io.http.server.md) +- [HTML Builder (lyng.io.html)](docs/lyng.io.html.md) +- [Process Execution (lyng.io.process)](docs/lyng.io.process.md) - [Time and Calendar Types](docs/time.md) +- [Json support](docs/json_and_kotlin_serialization.md) - [Return Statement](docs/return_statement.md) - [Efficient Iterables in Kotlin Interop](docs/EfficientIterables.md) - [Samples directory](docs/samples) @@ -66,7 +70,7 @@ assertEquals(A.E.One, A.One) ### Add dependency to your project ```kotlin -val lyngVersion = "1.5.5" +val lyngVersion = "1.5.6" repositories { // ... @@ -186,7 +190,7 @@ Designed to add scripting to kotlin multiplatform application in easy and effici # Language Roadmap -The current stable release is **v1.5.5**: the 1.5 cycle now includes the database/date/concurrency additions as well as the latest compiler/runtime stabilization work, and the language, tooling, and site are aligned around this release. +The current stable release is **v1.5.6**: the 1.5 cycle now includes the database/date/concurrency additions, process execution, lightweight HTTP server and HTML DSL work, canonical Json serialization, and the latest compiler/runtime stabilization work. Ready features: diff --git a/docs/whats_new.md b/docs/whats_new.md index 640693c..881e8dd 100644 --- a/docs/whats_new.md +++ b/docs/whats_new.md @@ -1,16 +1,17 @@ # What's New in Lyng -This document highlights the current Lyng release, **1.5.5**, and the broader additions from the 1.5 cycle. +This document highlights the current Lyng release, **1.5.6**, and the broader additions from the 1.5 cycle. It is intentionally user-facing: new language features, new modules, new tools, and the practical things you can build with them. For a programmer-focused migration summary across 1.5.x, see `docs/whats_new_1_5.md`. -## Release 1.5.5 Highlights +## Release 1.5.6 Highlights -- `1.5.5` extends the 1.5 line with practical database APIs, first-class calendar dates, and better coroutine building blocks. +- `1.5.6` extends the 1.5 line with process execution helpers, a lightweight HTTP server, HTML rendering helpers, and better DSL support. - The 1.5 line now brings together richer ranges and loops, interpolation, math modules, immutable and observable collections, richer `lyngio`, and much better CLI/IDE support. -- `1.5.5` adds `Channel`, `LaunchPool`, and `joinAll()` so coroutine-heavy scripts can coordinate work more directly. -- `1.5.5` adds `Date`, the portable `lyng.io.db` layer, SQLite/JDBC providers, and a compatibility `lyng.legacy_digest` module. -- `1.5.5` also continues runtime/compiler hardening with better import dispatch, faster exact lambda calls, and correct `val +=`/`-=` behavior for mutating types versus real reassignment. +- `1.5.6` adds `lyng.io.process` with `sh(...)`, `exec(...)`, and `CommandRun` for shell scripting and external process control. +- `1.5.6` adds the `lyng.io.http.server` module for exact, regex, and path-template routing, JSON helpers, WebSocket routes, and `respondHtml { ... }`. +- `1.5.6` adds the pure Lyng `lyng.io.html` builder DSL and language support for receiver-stack function types and context receiver extensions. +- `1.5.6` expands serialization with canonical `Json.encode(...)` / `Json.decode(...)` and typed `Json.encodeAs(...)` / `Json.decodeAs(...)`. - The docs, homepage samples, and release metadata now point at the current stable version. ## User Highlights Across 1.5.x @@ -22,11 +23,118 @@ For a programmer-focused migration summary across 1.5.x, see `docs/whats_new_1_5 - Calendar `Date` support in `lyng.time` - `Channel`, `LaunchPool`, and `joinAll()` for coroutine workflows - Immutable collections and opt-in `ObservableList` -- Rich `lyngio` modules for SQLite/JDBC databases, console, HTTP, WebSocket, TCP, and UDP +- Rich `lyngio` modules for SQLite/JDBC databases, process execution, console, HTTP, HTTP servers, WebSocket, TCP, UDP, and HTML rendering - Legacy SHA-1 compatibility helpers in `lyng.legacy_digest` - CLI improvements including the built-in formatter `lyng fmt` - Better IDE support and stronger docs around the released feature set +## New in 1.5.6 + +### Process Execution (`lyng.io.process`) +Lyng scripts can now run external commands through a coroutine-friendly process API. +Use `sh(...)` for shell commands and `exec(...)` when command arguments come from data and should bypass shell parsing. + +```lyng +import lyng.io.process + +val branch = sh("git branch --show-current").out.trim() +println("Branch: " + branch) + +exec("git", ["status", "--short"]).check() + +for (file in sh("git ls-files").lines) { + if (file.endsWith(".lyng")) { + println(file) + } +} +``` + +`CommandRun` supports captured output (`out`, `err`), streaming line output (`lines`, `errorLines`), `wait()`, `check()`, and status helpers. +See [lyng.io.process](lyng.io.process.md). + +### HTTP Server Routes and HTML Responses +`lyng.io.http.server` now provides a compact HTTP/1.1 server API for embedded tools, local services, test fixtures, and lightweight app backends. +Routes can match exact paths, regexes, or path templates with named parameters. +Handlers run with `RequestContext` as the receiver, so request data and response helpers are available directly. + +```lyng +import lyng.io.http.server + +val server = HttpServer() + +server.getPath("/api/users/{id}") { + respondJson({ + id: routeParams["id"], + path: request.path, + ok: true + }) +} + +server.listen(8080, "127.0.0.1") +``` + +The server also supports reusable routers, JSON body decoding with `jsonBody()`, WebSocket routes, and `respondHtml { ... }`. +See [lyng.io.http.server](lyng.io.http.server.md). + +### HTML Builder DSL (`lyng.io.html`) +`lyng.io.html` provides a pure Lyng HTML builder that escapes text and attributes by default. +It is designed for server-side rendering, generated reports, and small embedded UI surfaces. + +```lyng +import lyng.io.html + +val page = html { + head { + title { +"Demo" } + } + body { + nav { + a(href: "/") { +"Home" } + } + p { +"Text is escaped: " } + } +} +``` + +When used with the HTTP server, `respondHtml { ... }` renders the same DSL directly as a `text/html` response. +See [lyng.io.html](lyng.io.html.md). + +### Receiver-Stack Function Types and Context Extensions +Lyng now supports receiver-stack function types such as `context(Html) Body.()->String`. +Nested receiver lambdas keep outer receivers in scope, `this@Type` can select a specific receiver, and ambiguous receiver lookup is reported at compile time. + +```lyng +class Html { fun htmlOnly() = "html" } +class Body { fun bodyOnly() = "body" } + +val block: context(Html) Body.()->String = { + this@Html.htmlOnly() + ":" + bodyOnly() +} +``` + +Context receiver extensions let APIs expose helpers only when the right implicit receiver is already active. +This is what makes HTML builder code like `+"text"` work inside tag blocks without global builder state. +See [Object Oriented Programming](OOP.md#receiver-stack-lambdas). + +### Canonical and Typed JSON Serialization +The serialization layer now has separate APIs for ordinary JSON projection, self-describing canonical JSON, and schema-guided typed canonical JSON. + +```lyng +import lyng.serialization + +closed class Point(x: Int, y: Int) +closed class Segment(a: Point, b: Point) + +val value = Segment(Point(0, 1), Point(2, 3)) +val encoded = Json.encodeAs(Segment, value) + +assertEquals("{\"a\":{\"x\":0,\"y\":1},\"b\":{\"x\":2,\"y\":3}}", encoded) +assertEquals(value, Json.decodeAs(Segment, encoded)) +``` + +Use `toJson()` / `toJsonString()` for ordinary JSON interop, `Json.encode(...)` / `Json.decode(...)` for Lyng-to-Lyng round trips without a schema, and `Json.encodeAs(...)` / `Json.decodeAs(...)` when both sides already know the type. +See [Json support](json_and_kotlin_serialization.md). + ## Language Features ### Descending Ranges and Loops @@ -327,7 +435,7 @@ Singleton objects are declared using the `object` keyword. They provide a conven ```lyng object Config { - val version = "1.5.6-SNAPSHOT" + val version = "1.5.6" fun show() = println("Config version: " + version) } diff --git a/lynglib/build.gradle.kts b/lynglib/build.gradle.kts index 8416ca1..253e44c 100644 --- a/lynglib/build.gradle.kts +++ b/lynglib/build.gradle.kts @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl import org.jetbrains.kotlin.gradle.dsl.JvmTarget group = "net.sergeych" -version = "1.5.6-SNAPSHOT" +version = "1.5.6" // Removed legacy buildscript classpath declarations; plugins are applied via the plugins DSL below diff --git a/lynglib/src/commonTest/kotlin/WebsiteSamplesTest.kt b/lynglib/src/commonTest/kotlin/WebsiteSamplesTest.kt index e3cb77b..2a5f608 100644 --- a/lynglib/src/commonTest/kotlin/WebsiteSamplesTest.kt +++ b/lynglib/src/commonTest/kotlin/WebsiteSamplesTest.kt @@ -104,14 +104,14 @@ class WebsiteSamplesTest { val name = "Lyng" val base = { id:, name: } // Shorthand for id: id, name: name - val full = { ...base, version: "1.5.5", status: "stable" } + val full = { ...base, version: "1.5.6", status: "stable" } full """.trimIndent()) assertTrue(result is ObjMap) val m = result.map assertEquals(101L, (m[ObjString("id")] as ObjInt).value) assertEquals("Lyng", (m[ObjString("name")] as ObjString).value) - assertEquals("1.5.5", (m[ObjString("version")] as ObjString).value) + assertEquals("1.5.6", (m[ObjString("version")] as ObjString).value) assertEquals("stable", (m[ObjString("status")] as ObjString).value) } diff --git a/site/src/jsMain/kotlin/HomePage.kt b/site/src/jsMain/kotlin/HomePage.kt index dfed20a..18ffa97 100644 --- a/site/src/jsMain/kotlin/HomePage.kt +++ b/site/src/jsMain/kotlin/HomePage.kt @@ -159,7 +159,7 @@ fun HomePage() { val id = 101 val name = "Lyng" val base = { id:, name: } - val full = { ...base, version: "1.5.5", status: "stable", tags: ["typed", "portable"] } + val full = { ...base, version: "1.5.6", status: "stable", tags: ["typed", "portable"] } println(full) """.trimIndent()