Release notes
VibeLang is v0, so a new version can change the language in breaking ways. Read
the notes for every version between yours and the new one before you update, and
update vibelang, vibelang-runtime, and vibelang-vite together.
0.0.2
Eleven packages: vibelang, six native compilers
(vibelang-{darwin,linux,win32}-{arm64,x64}), vibelang-runtime,
vibelang-vite, vibelang-unplugin, and create-vibelang. Windows and
vibelang-unplugin are new in this release.
Changes that can break code that compiled on 0.0.1
Each change is a compile error that names the problem. None changes what compiled code does without telling you.
Platform globals through globalThis are EK4402
process.env was already EK4402. globalThis.process.env,
globalThis.fetch, globalThis.crypto.subtle, globalThis.location,
globalThis.navigator, and the other platform globals now are too.
// expect-error: EK4402
function home() {
return globalThis.process.env.HOME
}Read configuration with Config from Effect:
function homeDir() {
return Config.String("HOME")()
}Otherwise, read the global in a TypeScript module the project trusts, such as
platformEnv.ts:
// TypeScript (.ts)
/** @vibelang trusted */
export const processEnv = () => globalThis.process?.envA call typed as a union of Effects runs where it stands
A call to a function that returns Effect<A> | Effect<never, E> now runs the
program, as yield* decide(flag) does in TypeScript. In 0.0.1 it held the
program without saying so.
error Rejected
function decide(flag: boolean): Effect.Effect<number> | Effect.Effect<never, Rejected> {
return flag ? Effect.succeed(1) : Effect.fail(new Rejected())
}Code that worked around 0.0.1 by holding the program and then calling it no longer compiles:
// expect-error: TS2349
function total(flag: boolean) {
const held = decide(flag)
return held() + 1
}Delete the workaround and use the value:
function total(flag: boolean) {
const value = decide(flag)
return value + 1
}
// number!Rejected!A function annotated with a union of Effects whose branches return decided
Exits, such as cond ? Exit.fail(e) : Exit.void, runs the chosen Exit.
Request is the web-standard class
Web-standard globals keep their names, as JavaScript's built-ins do: Request,
Response, Headers, URL, URLSearchParams, TextEncoder, TextDecoder,
AbortController, AbortSignal, Blob, FormData, structuredClone, and
fetch. Of Effect's root names only Request collides, so Request.tagged
without an import is now TS2339 or TS2702. Import Effect's module:
import { Request } from "effect"
interface Lookup extends Request.Request<string> {
_tag: "Lookup"
id: string
}
const Lookup = Request.tagged<Lookup>("Lookup")A const with a declared Effect type holds the program
const p: Effect.Effect<A, E> = make() keeps the program that make() returns
cold instead of running it, at any scope. When the call returns a program that
produces a program, as Effect.cached(...) does, the annotation must name the
outer program, or the compiler reports TS2322 or TS2375. Annotate the outer type,
Effect.Effect<Effect.Effect<A, E>>, or drop the annotation to run the call.
A throw expression can't be an operator's left operand (EK1010)
throw cond ? a : b in expression position threw cond and discarded the rest.
It is now EK1010. Write throw (cond ? a : b). A statement that starts with
throw is unchanged.
A curried pipe stage after a call keeps the call
x |> f(args)(%) becomes x.pipe(f(args)) only when x calls nothing. When a
call builds the left side, bind it first: const s = Schema.NullOr(Schema.String),
then s |> f(args)(%).
Fixes
- An Effect subtype returned at an Effect boundary runs. A value that the
contract's written success type accepts is returned as data; for example,
keep(command): ChildProcess.Command!never!Scopereturns the command. - A discarded structured Effect call is diagnosed (EK4301). A program cast and
piped with
|>is passed by name. - Callback cleanup waits for async and Effect finalizers on interrupt. Copied declaration types import prelude names.
- A
function*annotatedGenerator<...>stays a JavaScript generator. - Function-valued service implementations and contract-annotated arrows keep their programs.
- Nested Effect function declarations hoist, so a call above the declaration works.
- The checker no longer overflows the stack on a shorthand discriminant property under a union context.
- By-name tail programs, conditional by-name arms, and optional program fields run as written.
- Diagnostics: inline boundary callbacks,
Effect.fnspan advice, non-adjustable EK option policies, and.d.tsJSDoc that matches tsc.
Known issues
- A throwing local arrow with no contract, inside a function with a plain return
annotation, reports EK2003 on the outer annotation. Annotate the local arrow,
for example
(value: number): void => { ... }. - EK4802 can warn on a local annotated
Effect<Effect<...>>that returns its program unrun. The emitted code is correct. - Programs that by-name lowering wraps spend extra Effect operations.
- A recursive
Schema.ClasswhoseSchema.suspendcallback writes an Effect contract,(): Schema.Codec<Crate, CrateWire>!! => Crate, reports TS2506 and TS2740. Annotate the plain return type instead,(): Schema.Codec<Crate, CrateWire> => Crate. Both compile to the same JavaScript.