TypeRB Status
Last updated: 2026-08-28
TypeRB is an alpha compiler implemented in Go. The language, standard library, generated output, and command-line interface may change before beta.
Current capability
TypeRB uses one portable grammar and typed IR for Go, Ruby, and TypeScript
output. Projects have deterministic formatting, package configuration,
project-wide checking, configurable built-in linting, source generation,
temporary build-and-run, and Go executable compilation. Target-specific
behavior remains behind explicit trb/platform/<mode>/* imports.
Resolution, checking, and typed IR retain canonical declaration identities that distinguish module path, nested source owner, declaration kind, and class/instance dispatch. Portable display names and backend-generated names remain separate, so effect propagation and qualified type generation do not depend on reconstructing a declaration from its leaf name.
Checked record construction is a dedicated typed-IR expression rather than an ordinary call with optional record metadata. It retains canonical declaration identity, generic arguments, authored argument order, and declaration-order field contracts, so every backend and the REPL share the same construction and omitted-default semantics.
Short two-value choices use the typed conditional expression
condition ? value : alternative. Simple early exits use conditional
control-transfer statements such as return value if condition, next if condition, and break if condition; trailing if is not a general statement
modifier. Both forms normalize into the existing control-flow IR and therefore
share strict Boolean conditions, narrowing, lazy branches, and backend or REPL
semantics.
trb lint runs project checking before a small configurable built-in ruleset.
The recommended rules safely rewrite simple one-transfer guard blocks and
remove redundant terminal bare returns from Void callables. Built-in rules
share the TypeRB version, while JSON reports carry independent schemaVersion
and toolVersion fields. Third-party rule execution remains deferred until a
deterministic, resource-bounded extension protocol is designed.
The CLI can also run one self-contained .trb file without creating project
configuration. It defaults to Go, can explicitly select Ruby or TypeScript,
and isolates generated target source in an operating-system temporary
directory. A discoverable trbconfig.jsonc always restores project-wide
compilation and owns mode and runtime selection.
Projects can import trb/cli to generate a typed command-line parser from
records and payload enums as one native executable.
Unannotated fields are positional, @cli(:option) declares options, and
@cli(:subcommand) selects a closed command enum. Generated help, version,
scalar conversion, usage errors, record defaults, and payload construction use
only the Go standard library internally and compile into the same single
executable. The current build path requires mode: "go" and the Go toolchain;
this is a toolchain constraint rather than a Go API exposed to the application.
Ruby and TypeScript launcher generation is intentionally outside this package.
The initial distributed package system resolves TypeRB source directly from
Git repositories or explicit local paths. Short imports default to GitHub but
lock to canonical manifest identities. A deterministic trb.lock pins the
transitive graph, commit IDs, and SHA-256 content checksums; frozen and offline
installation are available for CI and disconnected builds. trb update can
re-resolve the complete graph or selected direct aliases and their transitive
dependencies while leaving other direct graphs pinned. Package source uses
the same parser, project-wide checker, typed IR, and Go, Ruby, or TypeScript
backend as application source. Target-native modules requested by a TypeRB
package are merged into the generated go.mod, Gemfile, or package.json.
TypeScript projects select a browser, Bun, or Node runtime independently from their npm or Bun package manager. Node remains the compatibility default, while Bun can be selected explicitly for server packages.
TypeScript projects can also import supported named functions and React
components directly from configured native packages. trb install derives a
cached semantic index from installed .d.ts files; ordinary builds, the REPL's
project compiler, and completion consume the cache without invoking TypeScript.
The indexer currently uses the TypeScript 6 compiler API; TypeScript 7 support
is deferred until its replacement programmatic API is stable.
Unsupported declaration shapes are diagnosed instead of becoming Any.
Installed TypeRB packages can supply a versioned, mode-independent declaration
adapter catalog with generic functions, classes whose instance and class
members remain distinct, non-constructible interfaces, records, and transparent
type aliases. The TypeScript adapter is the first consumer and generated code
continues to import the original npm package. The bridge preserves
discriminated generic results and emits transitive native type-only imports
without making their names source-visible. Adapter-declared Promise callback
boundaries can map a Result-returning TypeRB function to native resolution and
rejection without exposing Promise semantics in TypeRB source.
An installed package can instead pair its semantic declaration catalog with a
mode-specific Native Runtime Adapter Protocol file in Go, Ruby, or TypeScript
mode. The initial protocol maps package-owned wire exports to top-level native
shim functions and accepts only (String) -> String; package source and the
shim own JSON envelopes, SDK error normalization, and domain Result
conversion. Two declarative effect flags propagate TypeScript suspension and
the hidden Go, Ruby, or TypeScript execution scope through the ordinary call
graph. Direct Go module and Ruby gem declaration import, structural native
values, lifecycle hooks, and arbitrary native error mappers are not included.
Package authors can run trb adapter check to validate the manifest and every
catalog and runtime mapping through the selected ecosystem consumer before
publishing. Its optional versioned JSON report exposes deterministic adapter
and runtime-binding counts and diagnostics for CI and AI agents.
Packages can also declare a mode-specific conformance project for explicit
trb adapter test execution. The command validates the adapter, builds the
installed self-referencing fixture, and invokes its structured native check;
its versioned JSON report exposes stable phase states without implicitly
installing dependencies or running package code during ordinary builds.
The Amplify Auth dogfood fixture additionally verifies that generated native
configuration can remain in an application-owned TypeScript bootstrap while
TypeRB uses the existing String rejection bridge. Rich native error records
remain an explicit future mapper capability rather than falling back to Any.
The experimental TypeScript browser path accepts structured JSX in TypeRB
source and emits ordinary TSX for React tooling. Function components use typed
record props, JSX component calls are checked across project modules, and only
modules containing JSX use the .tsx extension. The explicit
trb/platform/typescript/react package supplies the React boundary, including
purpose-specific mouse, change, form, and keyboard event types. Its typed
use_state(initial) wrapper infers ReactState<T> and exposes checked value
and set(value) members while generated TSX uses React useState.
The implemented language includes functions, typed first-class function values
with lexical capture and checked Result control flow, positional-only and
bare-* named-only parameters with callee-owned defaults, immutable parameter
bindings with explicit implementation-local mut, and classes, modules
and generic interfaces, records with per-construction field defaults, ordinary
and raw-value enums, payload enums as sum types with positional and named-only
fields in constructors and patterns, enum instance methods, transparent
alias declarations, nominal
newtype declarations over concrete non-nullable representations, explicit
generics for enums, aliases, records,
classes, top-level functions and instance methods, normalized unions, immutable
and mutable local bindings, first-constraint inference for fresh empty mutable
Arrays and Hashes, typed collections and iteration, exhaustive pattern
matching, value-producing if and case expressions, and explicit Result
propagation and recovery with prefix try and postfix catch. See the
language guide and specification for the
current semantics. Generated Go targets Go 1.27 and represents generic class
instance methods directly with native generic methods instead of package-level
helper functions.
Array transformations such as map, select, reduce, predicate searches,
and key-based sorting accept ordinary statements followed by one final result
expression. Their structured typed IR runs the same block scope in generated
Go, Ruby, TypeScript, and the REPL. TypeScript lowers a transformation that
reaches a suspending platform operation to a sequential async loop without
adding async or await to TypeRB source.
TypeScript also lowers suspending parameter defaults into the function body. Module constants and class initialization cannot currently suspend because JavaScript namespace and constructor initialization have no async evaluation boundary; the compiler reports these initializers instead of emitting invalid code.
Arrays also provide import-free concurrent_map for bounded I/O fan-out. Its
fixed portable default is 8, an explicit positive limit can replace or
locally reduce that capacity, nested maps share one structured task group, and
results retain input order. Lowering uses bounded workers in Go, Ruby,
TypeScript, and the REPL; cancellation stops admission, reaches supported
active operations through the hidden execution scope, and all admitted work is
collected before return. The checker rejects outer assignment and unsafe
lexical captures. Result aggregation, heterogeneous task APIs, streaming, and
CPU-parallel guarantees are not included.
Integer and String literal types support status- and kind-indexed data.
Exhaustive case over a readonly literal field narrows the complete record or
class union in every backend and in the REPL. Ordinary scalar case remains
available for untyped external values that have no endpoint or data contract.
The compiler-owned portable library covers scalar and collection foundations,
including stable Array sorting, typed short-circuit predicates and nullable
searches, stable deduplication and non-destructive concatenation, canonical
strict and safe element access with negative indexes, value-based Array index
search, Range materialization, Range-based Array and Unicode String slicing,
code-point substring search, Result,
bytes, hexadecimal and Base64 encoding, legacy MD5/SHA-1 checksums,
SHA-256/SHA-512 hashing and HMAC, non-cryptographic and secure randomness,
constant-time byte comparison, Unicode text, logical paths,
URL component and query handling, filesystem and process access, JSON/JSONC,
and immutable date/time values. The portable time package separates Date,
TimeOfDay, civil DateTime, exact Instant, fixed Duration, and named
TimeZone; its canonical JSON codecs and DST error behavior run across all
three backends.
Raw-value enums use the same checked String or Integer representation for
conversion, JSON codecs, generated applications, and the REPL. Its
public contracts are listed in the
standard-library reference.
Runtime Integer arithmetic is checked against the shared exact range
-9007199254740991..9007199254740991 in generated Go, Ruby, TypeScript, and the
REPL; String, JSON, and ORM ingress use the same boundary. Float remains
binary64 and consistently exposes arithmetic Infinity and NaN while source
literals remain finite. Formatting preserves opaque native syntax and prevents
whitespace removal from fusing separate tokens into another operator.
The typed-IR REPL supports persistent state, auto-formatted multiline editing,
history, completion menus, project declaration auto-import, portable-standard
completion candidates, visible import edits for accepted completion
candidates, suggestions, syntax highlighting, interrupts, type inspection,
and mutable-binding result markers.
The same compiler and evaluator power the local and hosted playground and tour.
The hosted TypeRB website also renders the maintained user documentation,
including the language and package guides, references, and one page for every
built-in lint rule. Maintainer-only development and release material remains
in the source repository.
The repository also publishes a reusable TextMate grammar for lexical editor
highlighting. Its thin Visual Studio Code client packages that grammar and
snippets, starts trb lsp, and exposes compiler-backed diagnostics, completion,
formatting, and quick fixes without duplicating semantic logic. A minimal
Neovim plugin automatically activates configured .trb projects, starts
best-effort per-file sessions outside them, formats on save by default with an
explicit opt-out, and delegates syntax-aware behavior to the same language
server. JetBrains IDEs can import the packaged
TextMate grammar and connect trb lsp through LSP4IJ without a TypeRB-specific
IDE plugin. A Chrome extension applies the same TextMate grammar to GitHub
.trb files, pull request diffs, and explicit TypeRB Markdown code blocks while
native GitHub Linguist support is unavailable. In the VS
Code extension, open files outside configured projects
receive isolated file-root language-server
sessions that follow explicit local imports and editor overlays without
including unrelated siblings. Local Extension Development Host tests exercise
standalone language services and execution against current Stable and Insiders
builds without a Marketplace install. Focused unit tests cover private Go debug
artifact creation and cleanup. Command details belong in the
CLI reference.
Explicit tooling can consume the same compiler service through
trb compiler inspect. Its experimental version 3 JSON snapshot contains exact
source inputs, modules and authored imports, flattened checked declarations and
semantic types including nominal newtypes, and diagnostics without generating
target source. The command
is read-only and one-shot; mutable AST or typed IR access, backend hooks, and a
long-lived protocol server are not exposed. See the
compiler tooling protocol guide.
The early official trb/web package discovers file-based routes at compile
time and runs typed request, path-parameter, JSON decode, and JSON response
handlers through the same dispatcher in all three backends. Applications can
start a generated Go, Ruby, or TypeScript HTTP server with serve(). The
trb init --mode <target> --template web command creates a buildable portable
API project with file-based routing and an explicit editable middleware stack.
The optional configure_server value sets host, port, request-body limit, and
graceful-shutdown timeout through typed named arguments. Every adapter
validates that configuration before binding, handles SIGINT and SIGTERM, stops
accepting new work, and gives active requests the configured time to finish.
Unhandled handler failures become a portable JSON 500 response. Before
middleware runs, request methods are uppercased and header names are normalized
to lowercase while insertion order and repeated values are preserved. Request
paths are decoded exactly once as UTF-8 at the
dispatcher boundary. Malformed escapes, encoded separators, backslashes, and
dot segments receive a portable JSON 400 response. Repeated and trailing
slashes remain distinct paths instead of being silently collapsed. Terminal
catch-all files such as [...path].trb match one or more decoded path
segments and bind their slash-joined value. Static segments take precedence
over parameter segments, and the dispatcher selects the most specific path
before selecting its HTTP method. For the same method, route analysis rejects
overlapping catch-all patterns, sibling parameter patterns, and patterns whose
static specificity reverses between segments; catch-alls outside the final
position are always invalid. Calls to
Context#path_value
inside route files require a string literal naming a parameter declared by that
file's route pattern, so misspelled and dynamic names fail during the build.
Context#params<T>() binds all route parameters to a checked record and
verifies that the record fields exactly match the file-based route.
Request#query<T>() binds decoded query parameters to a record: scalar fields
are strict single values, nullable fields represent omission, and Array fields
preserve repeated keys. Boolean, portable numeric, raw-value enum, and
date/time conversions share the same semantics in every backend. Binding
failures remain explicit ParameterError results so applications choose their
own validation response policy.
Context#bind<T>() optionally combines path, query, and JSON body binding into
one ordinary endpoint input record. The reserved record fields params,
query, and body reuse the individual checked codecs, and failures retain
their original typed error inside EndpointInputError. Combined binding
remains optional, route parameter compatibility is still verified at build
time, and applications keep control of the corresponding HTTP error response.
The implementation is the first consumer of the experimental bundled-package
call specialization boundary: trb/web returns target-independent TypeRB
helper source, and the compiler re-parses, resolves, checks, and lowers that
source instead of carrying a Web-specific bind intrinsic through each backend.
Route modules may separately declare optional Endpoint subclasses that bind
an actual handler function, an optional input type, and response types keyed by
literal HTTP status. The handler reference is checked as (Context) -> Response, the class must map to a file-route handler in the same module, and
the declaration calls are omitted from all three runtime outputs. trb/web
owns the resulting version 1 endpoint catalog; the generic compiler IR only
transports it as package extension data. The catalog does not infer handler
bodies or perform validation. trb web openapi combines that package-owned
catalog with the read-only Project Declaration Input and emits deterministic
OpenAPI 3.1 JSON without invoking a target toolchain. It maps the existing
Context#bind<T>() envelope to path, query, and JSON request inputs and emits
status-specific JSON or Unit responses. Its initial shared-schema boundary
covers portable scalars and time values, Arrays, Hash<String, V>, records,
raw-value enums, transparent aliases, nominal newtypes, nullable values, and
@json wire names. Unsupported JSON shapes, generic schemas, recursive
records, and catch-all routes are generation-time diagnostics rather than new
language or trb check restrictions. trb web client consumes that same
catalog and schema boundary to emit a deterministic TypeRB facade over the
existing TypeScript browser HttpClient. It imports client-visible endpoint
types from authored shared modules, maps declared statuses to typed result-enum
variants, and keeps transport, decoding, and unexpected-status failures in the
existing RequestError model. It is target-toolchain-independent at generation
time and browser-specific at compilation time. Runtime validation, contract
compatibility policy, authentication descriptions, richer endpoint metadata,
and portable outbound HTTP remain subsequent package work.
Typed ContextKey<T> values let middleware pass authentication principals,
request identifiers, and other request-scoped state to handlers without casts
or string-key collisions. Context#with returns a new context and
Context#fetch infers Result<T, ContextValueError> from the key; the same
identity-based behavior runs in generated applications and the typed-IR REPL.
The experimental trb/auth/oidc and trb/web/auth/bearer packages build on
that context boundary with the same OIDC bearer-token profile in all three
backends. They discover provider metadata, cache JWKS documents, verify RS256
signatures and standard issuer, audience, time, and subject claims, refresh an
unknown signing key through a rate-limited path, and attach a typed
OidcPrincipal to authenticated requests. Server-managed browser sessions and
authorization-code flows remain future package work.
Typed Request#json<T>() accepts application/json and application/*+json,
rejects ambiguous content types and invalid UTF-8, and reports each failure as
a RequestError without exposing backend parser behavior. Root and nested
_middleware.trb files form the same outer-to-inner onion chain in every
backend. A single middleware file can build an explicit Array<Middleware>
and pass it to compose; the first item is the outermost layer, and Next can
still be called only once. Root middleware surrounds the complete dispatch
boundary, including generated 400, 404, 405, 413, and recovered 500 responses;
nested middleware remains scoped to matched routes. Packaged middleware expose
middleware() factories with specific option types such as LoggerOptions and
CORSOptions. The
logger emits JSONL access logs and supports typed output-selection and
path-exclusion options. It records the normalized routing path for valid
requests but omits the raw query string by default so secrets in URLs are not
copied into logs. A portable secure-headers middleware adds a conservative
browser-security preset and accepts an explicit typed header map. An opt-in
CORS middleware handles actual and preflight requests, explicit origin
policies, credentials, exposed and allowed headers, and typed preflight cache
duration. A request-ID middleware preserves bounded safe
incoming IDs or generates cryptographically random IDs and exposes the chosen
value to downstream handlers and the response. Opt-in response-compression
middleware negotiates gzip with Accept-Encoding, uses a typed minimum-size
option, and consistently excludes unsafe or unsuitable responses across all
three backends. An opt-in timeout middleware adds a portable request deadline,
returns a JSON 504 response, and propagates a compiler-owned cancellation scope
through handlers, ORM work, and browser HTTP without adding a source-level
async or context parameter. Additional middleware is still under development.
Routing distinguishes missing paths from unsupported methods and returns a
portable JSON 405 response with an Allow header. Request bodies use a
configurable limit of 1 MiB by default before dispatch, and oversized requests
receive the same JSON 413 response in every backend. Query parameters use the
portable URL decoder and preserve repeated keys and source order instead of
collapsing them into a hash. Request#query_values returns all repeated values,
while strict Request#query_value reports malformed, missing, and duplicate
values through a typed error. HEAD requests prefer an explicit handler,
otherwise reuse the matching GET handler and middleware chain, and never expose
a response body. OPTIONS requests likewise prefer explicit handlers; otherwise
a middleware-aware 204 response advertises the available methods through
Allow.
Request header lookup is case-insensitive; Request#header_value rejects
missing and duplicate values instead of choosing one implicitly. Request
headers can also be replaced, appended, or removed without mutating the
original request.
Portable cookie parsing preserves header order, duplicate names, and opaque
values without delegating
semantics to the target runtime. Request#cookie_values returns all matching
values, while strict Request#cookie_value reports missing and duplicate names
through a typed error.
Request, Response, and Context are immutable classes. Their method APIs
replace, append, remove, or inspect values by returning new instances where
state changes. Responses support case-insensitive header operations
without mutating the original response. Strict response lookup rejects missing
and duplicate values instead of selecting one. vary composes cache keys
without duplicating an existing field.
Typed response cookies support ordered Domain, Path, Max-Age, Secure,
HttpOnly, and SameSite attributes while preserving multiple Set-Cookie
header values. Cookie names, values, domains, paths, attribute uniqueness,
SameSite=None, and the __Secure- and __Host- prefixes are validated before
serialization. Invalid cookie construction reaches the same portable JSON 500
boundary as any other invalid response.
Portable text, bytes, empty, and redirect builders create common
responses with consistent default statuses and content types.
Response#with_status returns a copy with a different status.
Before a response leaves the portable dispatcher, every backend rejects invalid
status codes, header names, and CR/LF-bearing header values through the same
JSON 500 boundary.
The experimental official trb/orm package targets generated
Go, Ruby, and TypeScript; TypeScript server applications currently select Bun.
It reads SQLite, PostgreSQL, or MySQL schema metadata directly and exposes typed
models, immutable queries, associations and preload, aggregates, transactions,
batching, writes, conflict handling, and destroy lifecycles.
Each source directory is an ORM model group: separate model files can declare
typed direct and through associations without mutual imports, while ordinary
model references still require explicit imports. Cross-group object navigation
is a located project diagnostic; foreign-key based repository queries remain
available across the boundary. Runnable roots bootstrap Ruby and TypeScript
model registration without adding cyclic imports between model modules.
String- and Integer-backed enum columns preserve nominal enum types throughout
queries and writes, while ordinary enums use a checked lower-snake-case storage
convention. Unknown stored values become structured invalid-data errors.
Date, time-of-day, civil date-time, and instant columns are inferred from each
database schema and retain their portable types through predicates, writes,
projections, and aggregates. Instant storage is normalized through UTC.
The repository runs the same application contract across all nine backend and
database combinations, plus an ORM-backed JSON route across all three backends.
Database terminals, lazy association access, transactions, and streaming
return DbResult<T>. Applications propagate compatible errors with try,
recover with catch, or inspect the Result with exhaustive case. The REPL
uses the same schema-backed read and write API. A deterministic portable schema
lock removes the live database requirement from compiler checks and builds.
ORM declaration output uses the experimental bundled Declaration Protocol.
Schema-derived properties, literal-dependent terminals, and
structured transaction and streaming contracts cross a validated,
mode-independent data boundary before the compiler resolves them. Project model
discovery and backend runtime operations remain bundled while the protocol is
validated against another provider.
Optional trb db
commands provide plan, guarded apply, export, lock, and drift checks around a
pinned external sqldef executable on SQLite, PostgreSQL, and MySQL. Production
compatibility policy remains future work.
Portable trb/http owns the open HTTP method, ordered case-insensitive
headers, and buffered body value types shared by server and client packages.
TypeScript browser applications can import the official
trb/platform/typescript/browser package. Its single request primitive accepts
those shared methods and headers, repeated query parameters, text, bytes, form,
JSON, and native browser File bodies, and timeouts. Indexed native component
callbacks can pass a DOM File through the platform package's checked metadata
boundary and into a request without losing the underlying browser object.
File#read() and File#read_text() expose their buffered contents as Result
values from generated-TypeScript-only browser operations.
Fetch responses retain status, headers, final URL, and buffered bytes; explicit
JSON decoding produces Response<T> and preserves
the raw response in a classified RequestError when the contract is invalid.
Non-2xx statuses remain ordinary responses. The backend inserts suspension
only in generated TypeScript, so TypeRB source does not add target-specific
async syntax.
The experimental trb/jobs contract discovers typed Job classes and provides
typed immediate, relative-delay, and absolute-Instant enqueue operations. A
separate trb/jobs/sql adapter persists queue state in SQLite, PostgreSQL, or
MySQL and runs the same Job source in generated Go, Ruby, and Bun applications.
Projects select the adapter through a typed TypeRB composition module rather
than a string adapter name in packageOptions; Job definitions remain
independent from storage. The module exposes one explicitly typed
JOBS_ADAPTER constant, initialized once and reused by every enqueue wrapper,
so adapter lifetime is application-scoped rather than per-enqueue.
Jobs-derived perform_later, perform_in, and perform_at declarations cross
the same validated, mode-independent Declaration Protocol as ORM. Their typed
arguments, scheduling parameters, enqueue Results, and runtime operation names
use the generic protocol fields. Worker dispatch crosses the versioned Project
Generated Source Protocol as an ordinary TypeRB fragment:
one portable dispatcher validates payload versions, decodes scalar arguments,
calls the typed Job, and returns JobResult before all three backends lower it.
The same protocol emits a stable fragment per Job for payload serialization,
negative-delay validation, relative-to-absolute schedule normalization, and
dispatch through the ordinary TypeRB JobAdapter#enqueue/enqueue_at
contract. EnqueueRequest carries serialized payload and queue policy; the SQL
adapter owns ID generation, persistence, and native error mapping.
Generated-source responses contain stable fragment and module identity,
required named imports, authored origin spans, and located issues, but no AST,
typed IR, backend source, filesystem handles, or arbitrary provider data.
The compiler removes stale fragments, includes them in cache identity, and maps
their diagnostics and source locations to authored source. Project edits
currently use conservative full analysis while such fragments are active.
Retry policy, SQL worker lifecycle, and the SQL adapter's final native
persistence primitives remain a separate bundled runtime boundary. Jobs and
ORM declaration discovery also
consume versioned, JSON-serializable Project Declaration Input snapshots.
Version 7 separates canonical declaration identity from source/display names
and gives nested records and enums structured owner identities without
exposing generated backend identifiers or additional nested declaration
categories. It contains canonical module/import identity, aliases, newtypes and
their concrete boundary representations, record declarations and field
attributes, record-default presence, enum declarations and member attributes,
class declarations, top-level function and class method
signatures, authored and resolved types, resolved generic directive arguments,
declarative call values, structural block summaries, and source spans. The ORM
host combines that project snapshot with a separate versioned ORM schema
snapshot containing only the adapter and table, column, foreign-key, and
unique-constraint facts needed to derive its catalog. Database credentials,
parser nodes, function,
method, and block bodies, default expressions, resolver/checker state,
filesystem access, and backend objects do
not cross the declaration-provider input boundary. The ORM runtime manifest
remains a separate bundled integration boundary.
Their direct class-body DSL calls cross one generic Declaration Protocol
version 3 rule. The rule matches an exact provider package function and exact
project class, preserves ordinary signature checking, and marks the typed-IR
call as declaration-only so Go, Ruby, and TypeScript omit it from runtime
output. The generic rule keeps package-specific function-name checks out of
the ORM and Jobs backend generators.
Workers support queues, priorities, retry and failed state, heartbeats, stale
claim recovery, graceful stop, listing, manual retry, and discard. PostgreSQL
and MySQL use short locking claims for multiple workers. SQLite is deliberately
limited to one worker. Delivery is at least once, so Jobs remain responsible
for idempotence. A fallible job returns JobResult; Err enters the same retry
and failure policy as a runtime execution failure. Recurring schedules,
transactional outbox delivery, parallel
workers within one process, and forced-shutdown timeouts remain future work.
The compiler pipeline is:
lossless tokens -> syntax AST -> resolver/type checker -> typed IR -> backend
Backends consume typed IR and do not inspect parser state or rewrite source text. The repository suite covers compiler phases, formatter, language services, REPL, project builds, standard packages, type providers, generated target code, and browser tools.
Nullable lexical bindings narrow through direct nil comparisons in
conditional branches, loops, compatible short-circuit expressions, and
returning guards. A plain assignment remains checked against the binding's
declared nullable type and gives subsequent statements in that path the
assigned value's precise flow type. Direct record fields and readonly class
fields narrow when their receiver is a stable lexical binding. Reassigning a
receiver invalidates its field facts, while typed IR keeps every required
unwrap explicit for all backends and the REPL.
Compiler artifacts carry a versioned, backend-independent mapping from
generated statement ranges to original .trb paths and spans. Go mappings are
retained through target formatting; Ruby and TypeScript use the same internal
model. Virtual TypeRB helpers returned by bundled package call specializers map
back to their originating call rather than exposing synthetic source lines.
Emitting target-standard map files and translating runtime stack traces remain
follow-up work.
trb check validates a configured project without writing generated source or
starting a target toolchain. Its human diagnostics and versioned JSON report
share stable TRBxxxx codes, one-based source locations, related locations,
and atomic source-edit suggestions. Parser, resolver, checker, and project
integration errors use the same model, and independent errors across project
files are reported in one run. This model is the diagnostic boundary for the
language server and other machine clients.
The reusable compiler service owns versioned project snapshots and unsaved
document overlays above the ordinary compiler pipeline. Successful snapshots
carry checked artifacts and per-module completion contexts. When an incomplete
edit fails, the service publishes current diagnostics while retaining the last
successful context, so editor completion does not disappear during typing.
Concurrent edits invalidate obsolete analysis before it can become current.
Long-lived compiler-service and REPL sessions reuse prepared syntax trees for
compiler-identical source units. When one ordinary module changes, the analyzer
reuses unchanged resolution and checking results, and invalidates downstream
importers when its public catalog changes. Provider declaration changes
invalidate the whole project; compiler-owned dependency, configuration, and
multi-file changes conservatively fall back to complete analysis. trb check
already consumes this service. Finer phase-level invalidation, incremental
lowering, and a persistent build cache remain future work.
trb lsp exposes that service over standard LSP framing. Its capabilities are
project-wide live diagnostics, completion with explicit import insertion for
unambiguous standard and project types, checked hover information, signature
help, deterministic formatting, and quick fixes from structured diagnostic
edits. Ordered incremental updates and UTF-16 protocol positions are translated
at the adapter boundary; the compiler and formatter continue to use complete
UTF-8 source snapshots and offsets. The preview Visual Studio Code extension is
a published thin client over this boundary. Definition, reference, document
highlight, and rename queries follow stable source declaration identities
across project imports, receiver types, and common lexical bindings. Go to
Definition treats a complete project-import path as one module reference and
opens its resolved TypeRB source; project auto-imports omit a redundant
terminal /index. CLI and language-server formatting apply the same
resolution-aware canonicalization to existing imports without changing an
ambiguous or unresolved module selection.
Association model references supplied by declarative package providers also
participate in completion, hover, definition, references, and rename without
adding ordinary source imports. Document
symbols expose the structural outline from the lossless syntax tree even while
a file has type errors, and workspace symbol queries search the same
declarations across project files. Structural folding ranges cover declarations
and expression blocks from that syntax tree. Selection ranges expand from tokens
through source lines and enclosing structural blocks.
Full-document semantic tokens reuse the compiler-aware highlighting service
and translate UTF-8 byte spans to the UTF-16 positions required by editors.
The VS Code client discovers nested trbconfig.jsonc files, starts one language
server per project, and watches each project's .trb files independently. The
language server rejects editor overlays outside its configured source root and
updates the saved project snapshot beneath active overlays.
Files outside discovered projects receive isolated, configless language-server
sessions with configurable Go, Ruby, or TypeScript mode. Each session follows
the selected entry's explicit local import closure and rebuilds it from saved
files and unsaved editor overlays. Its top-level main() CodeLens runs the
file-root program through the same Debug Adapter Protocol process lifecycle
used by projects. A Go-mode standalone entry can also build a private,
session-scoped executable for source debugging through Delve.
Canonical type-name diagnostics carry structured fixes, so editors can replace
aliases such as Int with Integer without reconstructing source text.
Top-level main() declarations expose a compiler-owned run CodeLens in
non-browser projects. The VS Code client saves dirty TypeRB project files and
starts trb run through a Debug Adapter Protocol session when invoked without
debugging. Visual
Studio Code owns the standard start, stop, and restart lifecycle, while the
Debug Console reports the launch command, process identifier, program output,
and exit status immediately. Invoking the CodeLens again requests a DAP
restart. Go debug builds project the shared source map into Go line directives,
and the VS Code client connects directly to Delve DAP for TypeRB breakpoints,
stepping, stack frames, variables, watches, and evaluation. Ruby and TypeScript
source-debugger adapters remain staged; both modes retain Run Without Debugging.
Portable colocated tests use *_test.trb, nested describe suites, explicit
test cases, and typed expectations from trb/std/test. trb test executes
the same source through Go, Ruby, and TypeScript process backends, supports
positional file/directory selection, regular-expression name selection, and
JSON Lines events, preserves assertion locations, and
returns a nonzero failure status. The VS Code extension consumes compiler-owned
LSP discovery through the native Test Explorer and test CodeLens. Go test
selections can use the same Delve-backed TypeRB source debugger as application
entrypoints. Browser-hosted TypeScript execution, lifecycle hooks, and
higher-level testing packages remain staged.
Current limitations
The current alpha does not yet provide:
- a complete everyday receiver API;
- position-typed tuples or type-pattern narrowing for nullable, collection, and non-discriminated structured union alternatives;
- inferred type arguments, generic interface methods, or generic class methods;
- complete superclass construction, override, and mutation-effect semantics;
- general first-class call blocks;
- complete target-standard source maps and runtime stack mapping across Ruby and TypeScript, incremental builds, or a persistent build cache;
- semantic package version constraints, publishing or audit services, or a stable external compiler-extension protocol;
- namespace-stable public type identities across independent packages;
- compatibility guarantees for production use.
Future outcomes are tracked in the roadmap; executable scoped work is tracked as GitHub issues.