release 1.5.6
This commit is contained in:
parent
234d1ef02b
commit
7af6d3925e
1
.gitignore
vendored
1
.gitignore
vendored
@ -31,3 +31,4 @@ test_output*.txt
|
|||||||
/bugcontents.db
|
/bugcontents.db
|
||||||
/bugs/
|
/bugs/
|
||||||
contents.db
|
contents.db
|
||||||
|
/docs/idea_plugin.md.deploy_backup
|
||||||
|
|||||||
25
CHANGELOG.md
25
CHANGELOG.md
@ -11,6 +11,31 @@ History note:
|
|||||||
|
|
||||||
- No unreleased entries yet.
|
- 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<T>()`, `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)
|
## 1.5.5 (2026-04-23)
|
||||||
|
|
||||||
### Concurrency and collections
|
### Concurrency and collections
|
||||||
|
|||||||
10
README.md
10
README.md
@ -48,12 +48,16 @@ assertEquals(A.E.One, A.One)
|
|||||||
|
|
||||||
- [Language home](https://lynglang.com)
|
- [Language home](https://lynglang.com)
|
||||||
- [introduction and tutorial](docs/tutorial.md) - start here please
|
- [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)
|
- [What's New in 1.5](docs/whats_new_1_5.md)
|
||||||
- [Testing and Assertions](docs/Testing.md)
|
- [Testing and Assertions](docs/Testing.md)
|
||||||
- [Filesystem and Processes (lyngio)](docs/lyngio.md)
|
- [Filesystem and Processes (lyngio)](docs/lyngio.md)
|
||||||
- [SQL Databases (lyng.io.db)](docs/lyng.io.db.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)
|
- [Time and Calendar Types](docs/time.md)
|
||||||
|
- [Json support](docs/json_and_kotlin_serialization.md)
|
||||||
- [Return Statement](docs/return_statement.md)
|
- [Return Statement](docs/return_statement.md)
|
||||||
- [Efficient Iterables in Kotlin Interop](docs/EfficientIterables.md)
|
- [Efficient Iterables in Kotlin Interop](docs/EfficientIterables.md)
|
||||||
- [Samples directory](docs/samples)
|
- [Samples directory](docs/samples)
|
||||||
@ -66,7 +70,7 @@ assertEquals(A.E.One, A.One)
|
|||||||
### Add dependency to your project
|
### Add dependency to your project
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
val lyngVersion = "1.5.5"
|
val lyngVersion = "1.5.6"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
// ...
|
// ...
|
||||||
@ -186,7 +190,7 @@ Designed to add scripting to kotlin multiplatform application in easy and effici
|
|||||||
|
|
||||||
# Language Roadmap
|
# 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:
|
Ready features:
|
||||||
|
|
||||||
|
|||||||
@ -1,16 +1,17 @@
|
|||||||
# What's New in Lyng
|
# 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.
|
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`.
|
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.
|
- 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.6` adds `lyng.io.process` with `sh(...)`, `exec(...)`, and `CommandRun` for shell scripting and external process control.
|
||||||
- `1.5.5` adds `Date`, the portable `lyng.io.db` layer, SQLite/JDBC providers, and a compatibility `lyng.legacy_digest` module.
|
- `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.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 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.
|
- The docs, homepage samples, and release metadata now point at the current stable version.
|
||||||
|
|
||||||
## User Highlights Across 1.5.x
|
## 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`
|
- Calendar `Date` support in `lyng.time`
|
||||||
- `Channel`, `LaunchPool`, and `joinAll()` for coroutine workflows
|
- `Channel`, `LaunchPool`, and `joinAll()` for coroutine workflows
|
||||||
- Immutable collections and opt-in `ObservableList`
|
- 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`
|
- Legacy SHA-1 compatibility helpers in `lyng.legacy_digest`
|
||||||
- CLI improvements including the built-in formatter `lyng fmt`
|
- CLI improvements including the built-in formatter `lyng fmt`
|
||||||
- Better IDE support and stronger docs around the released feature set
|
- 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<T>()`, 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: <safe>" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
## Language Features
|
||||||
|
|
||||||
### Descending Ranges and Loops
|
### Descending Ranges and Loops
|
||||||
@ -327,7 +435,7 @@ Singleton objects are declared using the `object` keyword. They provide a conven
|
|||||||
|
|
||||||
```lyng
|
```lyng
|
||||||
object Config {
|
object Config {
|
||||||
val version = "1.5.6-SNAPSHOT"
|
val version = "1.5.6"
|
||||||
fun show() = println("Config version: " + version)
|
fun show() = println("Config version: " + version)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
|
|||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
group = "net.sergeych"
|
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
|
// Removed legacy buildscript classpath declarations; plugins are applied via the plugins DSL below
|
||||||
|
|
||||||
|
|||||||
@ -104,14 +104,14 @@ class WebsiteSamplesTest {
|
|||||||
val name = "Lyng"
|
val name = "Lyng"
|
||||||
val base = { id:, name: } // Shorthand for id: id, name: name
|
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
|
full
|
||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
assertTrue(result is ObjMap)
|
assertTrue(result is ObjMap)
|
||||||
val m = result.map
|
val m = result.map
|
||||||
assertEquals(101L, (m[ObjString("id")] as ObjInt).value)
|
assertEquals(101L, (m[ObjString("id")] as ObjInt).value)
|
||||||
assertEquals("Lyng", (m[ObjString("name")] as ObjString).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)
|
assertEquals("stable", (m[ObjString("status")] as ObjString).value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -159,7 +159,7 @@ fun HomePage() {
|
|||||||
val id = 101
|
val id = 101
|
||||||
val name = "Lyng"
|
val name = "Lyng"
|
||||||
val base = { id:, name: }
|
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)
|
println(full)
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user