Compiler Supported Syntax Reference
This page is compiler-specific (sloppyc) and lists enforced source-shape rules.
Input and Parse
- Entry and module files must use
.js,.mjs, or.ts. - Parse failures return
SLOPPYC_E_PARSE. - Unsupported extension returns
SLOPPYC_E_UNSUPPORTED_INPUT.
Sloppy Imports
Web compiler entry input must import:
Sloppyfrom"sloppy"
Files that contain route handlers calling Results.* must also import Results from "sloppy" in that same file. A thin entry file that only creates the app and registers function modules can import Sloppy alone; child route modules import Results when their handlers use it.
These imports must be named and unaliased in the current compiler subset.
Supported Import Modules
Compiler-recognized modules:
"sloppy"(Sloppy,Results, framework metadata types,data,sql,Migrations,ProviderHealth)"sloppy/data"(sql,Migrations,ProviderHealth)"sloppy/providers/sqlite"(sqlite,Sqlite)"sloppy/providers/postgres"(Postgres)"sloppy/providers/sqlserver"(SqlServer)"sloppy/fs","sloppy/time","sloppy/crypto","sloppy/codec","sloppy/cache","sloppy/net","sloppy/os","sloppy/workers","sloppy/ffi"- relative imports constrained to source root
- installed pure-JavaScript package imports in Program Mode
- supported Node shim specifiers such as
node:pathin Program Mode
Unsupported specifiers/import names fail with a diagnostic that points at the import. The most common ones are:
SLOPPYC_E_UNSUPPORTED_IMPORT_SPECIFIERSLOPPYC_E_UNSUPPORTED_IMPORTSLOPPYC_E_PACKAGE_NOT_FOUNDSLOPPYC_E_PACKAGE_EXPORT_UNSUPPORTEDSLOPPYC_E_NATIVE_ADDON_UNSUPPORTEDSLOPPYC_E_UNSUPPORTED_NODE_BUILTIN
Web app extraction still rejects dynamic import with SLOPPYC_E_UNSUPPORTED_DYNAMIC_IMPORT. Program Mode supports string-literal dynamic imports and computed dynamic imports over explicit moduleInclude graphs.
RequestId and RequestLogging are supported for static middleware defaults. TestHost, experimental TestServices, Testing, FakeClock, and TestData are framework test helpers; compiler input rejects them with SLOPPYC_E_UNSUPPORTED_TESTING_IMPORT.
Program Mode Source
Program Mode supports route-free source files that use static ESM imports and exports. Oxc parses the source and strips supported TypeScript syntax before Sloppy rewrites supported module syntax into the generated artifact bundle.
Supported entrypoint shapes are:
console.log("hello");
export async function main() {
console.log("hello");
}
export default async function main() {
console.log("hello");
}If both named main and default function exports exist, named main wins. Non-function default exports are ignored as entrypoints after their module top-level code has executed.
main and default function entrypoints receive (args, ctx). args contains the strings passed after -- to sloppy run. ctx is the Program context:
{
kind: "program",
args: string[],
cwd: string,
environment: string,
plan: {
kind: "program",
metadataCompleteness: "opaque"
}
}Program Mode installs a Sloppy-owned console while the entry module runs. log, info, and debug write to stdout; warn and error write to stderr. Returning an integer from 0 through 255 sets the process exit code. Throwing, rejecting, or returning an out-of-range exit code exits non-zero with a diagnostic.
Program Mode accepts static relative imports, installed pure-JavaScript npm packages, CommonJS/JSON modules, the documented Sloppy stdlib subpaths, and the Node APIs that already have Sloppy compatibility shims. It also accepts sloppy/providers/sqlite as a bundled Program Mode module. That lets CLI tools create or inspect SQLite provider descriptors without pretending they are web apps.
Type-only imports are erased and do not turn on runtime features. Dynamic import("literal") calls are resolved at build time. Computed dynamic imports work only for modules you explicitly seal into the artifact graph with moduleInclude.
Some imports are still rejected because Sloppy cannot run them yet, not because the TypeScript syntax is invalid:
- Remote URL imports, such as
import "https://example.com/mod.ts", are not fetched during build. Sloppy currently builds from local files and installed packages so the artifact graph is repeatable. - Node native addons, such as packages that load
.nodebinaries throughnode-gyp, are not supported by the Sloppy runtime. Pure JavaScript package entries can work; compiled Node ABI modules cannot. - Node builtins are supported only when the compatibility registry has a shim for that module. Unsupported builtins fail clearly instead of being replaced with a fake object.
- Package
exportsshapes outside Sloppy's resolver subset are rejected until the resolver knows how to choose a compatible entry. - Provider modules need a Program Mode stdlib surface. Today that includes
sloppy/providers/sqlite; other provider modules remain web/compiler metadata only.
Program Mode supports local exports, source re-exports such as export { value } from "./dep", export-all declarations, and namespace re-exports such as export * as dep from "./dep".
Package and compatibility diagnostics
Representative dependency diagnostics:
SLOPPYC_E_PACKAGE_NOT_FOUNDSLOPPYC_E_PACKAGE_EXPORT_UNSUPPORTEDSLOPPYC_E_NATIVE_ADDON_UNSUPPORTEDSLOPPYC_E_UNSUPPORTED_NODE_BUILTIN
Node compatibility is intentionally incremental. A supported shim means Sloppy has a local module for that Node API; it does not mean every Node global or every edge case from Node itself exists. Import node:process or node:buffer explicitly when that partial shim is supported.
Stdlib subpath imports
The compiler accepts named, unaliased imports from each stdlib subpath listed below. Each subpath emits the matching stdlib.* runtime feature into the Plan when imported. Default imports and import aliases are rejected with SLOPPYC_E_UNSUPPORTED_IMPORT; unsupported names fail with the same code.
| Subpath | Supported names | Plan feature |
|---|---|---|
sloppy/fs | File, Directory, FileHandle, FileWatcher, Path | stdlib.fs |
sloppy/net | HttpClient, TcpClient, TcpListener, TcpConnection, LocalEndpoint, UnixSocket, NamedPipe, NetworkAddress, SloppyNetError | stdlib.net (HttpClient emits stdlib.httpclient) |
sloppy/os | System, Environment, Process, ProcessHandle, Signals, OsError | stdlib.os |
sloppy/time | Time, Deadline, CancellationController, TimeoutError, CancelledError, InvalidDeadlineError, TimerDisposedError | stdlib.time |
sloppy/crypto | Random, Hash, Hmac, Password, ConstantTime, Secret, NonCryptoHash | stdlib.crypto |
sloppy/codec | Base64, Base64Url, Hex, Text, Binary, Compression, Checksums | stdlib.codec |
sloppy/cache | Cache, SloppyCacheError | stdlib.cache |
sloppy/workers | BackgroundService, WorkQueue, WorkerPool, Worker, WorkerCancellationController, WorkerCancellationSignal, SloppyWorkerError | stdlib.workers |
sloppy/ffi | unsafeFfi, t | stdlib.ffi |
Examples:
import { File, Directory } from "sloppy/fs";
import { HttpClient } from "sloppy/net";
import { System, Environment, Process, Signals } from "sloppy/os";
import { Time, Deadline, CancellationController } from "sloppy/time";
import { Random, Hash, Hmac, Secret } from "sloppy/crypto";
import { Base64, Hex, Text, Binary } from "sloppy/codec";
import { Cache } from "sloppy/cache";
import { BackgroundService, WorkQueue } from "sloppy/workers";
import { unsafeFfi as ffi, t } from "sloppy/ffi";FFI declarations
sloppy/ffi declarations must be static so the compiler can emit Plan-visible ABI metadata. Supported shapes are top-level ffi.library(...), ffi.fn(...), and ffi.struct(...) calls with literal library names, symbols, calling conventions, object specs, and t.* type descriptors.
Dynamic library names, generated descriptor objects, computed function names, non-t type descriptors, callbacks, unsupported return buffer types, and non-sequential struct layouts fail with FFI diagnostics such as SLOPPYC_E_FFI_DYNAMIC_DECLARATION, SLOPPYC_E_FFI_INVALID_TYPE, and SLOPPYC_E_FFI_UNSUPPORTED_CALLBACK.
Route Extraction Rules
Static route declarations are strongest when they are top-level statements on app/group receivers. Sloppy does not require every route to be statically understood. If the compiler can emit runnable JavaScript, the app can run. Static source gives stronger Plan metadata; dynamic source produces partial metadata and findings.
Route methods:
- GET, POST, PUT, PATCH, DELETE (
map*and plain verb forms)
Supported route metadata:
app.get("/path", handler).withName("Name")app.get("/path", { name: "Name", tags: ["tag"] }, handler)app.group("/prefix").withTags("tag")app.group("/prefix").withTags("tag").requireAuth(...)app.mapHealthChecks(...)with literal paths and literal check metadata- top-level
app.use(fn)andgroup.use(fn)middleware with inline or top-level static functions; - top-level
app.useCors({...})with literal policy objects; - top-level
app.use(RequestId.defaults({...}))andapp.use(RequestLogging.defaults({...}))with static options; - top-level
app.mapController(...)/app.controller(...)with a top-level plain controller class and literal mapper calls;
Route metadata options must be literal objects. name must be a non-empty string literal. tags must be an array of non-empty string literals. Health options must be omitted, a string literal aggregate path, or a literal object with path, livenessPath, readinessPath, and checks. Check objects must use literal names, boolean liveness/readiness flags, and inline check functions.
Common route failures:
SLOPPYC_E_UNSUPPORTED_ROUTE_SHAPESLOPPYC_E_UNSUPPORTED_HTTP_METHODSLOPPYC_E_UNSUPPORTED_ROUTE_PATTERNSLOPPYC_E_UNSUPPORTED_ROUTE_NAMESLOPPYC_E_UNSUPPORTED_ROUTE_OPTIONSSLOPPYC_E_UNSUPPORTED_HEALTH_CHECKS
Dynamic route uncertainty is reported as Plan findings instead of fatal metadata extraction diagnostics:
SLOPPYC_W_DYNAMIC_ROUTESLOPPYC_W_PARTIAL_ROUTE_METADATASLOPPYC_W_DYNAMIC_RESPONSE_METADATA
Schema metadata supports local Schema.* declarations, concrete TypeScript aliases/interfaces, .accepts(...), .returns(...), ctx.body.validate(...), and named schema references such as Schema.array(User) or object fields that refer to another local schema. Plan emission resolves schema references into runtime-supported schema JSON. If a reference graph cannot be fully resolved, the compiler emits partial runtime-safe metadata and a schema.reference.partial doctor check instead of blocking otherwise runnable source.
Health checks must be inline functions that do not capture module-level locals. Captured values fail with SLOPPYC_E_UNSUPPORTED_HEALTH_CHECKS.
Framework Static Subset
These app-host features are emitted when they stay inside the static subset:
- middleware functions must be inline or top-level functions with supported captures;
- CORS policies must be literal objects;
- RequestId options must be static and cannot use generator callbacks;
- RequestLogging options must be static booleans;
- controller mappings must target a top-level plain class and literal mapper route calls.
Unsupported dynamic framework features fail with SLOPPYC_E_UNSUPPORTED_MIDDLEWARE, SLOPPYC_E_UNSUPPORTED_CORS, SLOPPYC_E_UNSUPPORTED_REQUEST_ID, SLOPPYC_E_UNSUPPORTED_REQUEST_LOGGING, or SLOPPYC_E_UNSUPPORTED_CONTROLLER instead of accepting a partial Plan.
Services And Config
Literal service registrations are supported on both app.services and builder.services:
addSingleton("Token", () => value)addScoped("Token", () => value)addTransient("Token", () => value)
Factories must be inline functions. They may reference their scope parameter, local values, JavaScript globals, and compiler-emitted top-level helper functions. They may not capture the extracted app object or arbitrary top-level state that the generated artifact cannot preserve.
Config<"KEY"> typed parameters read the environment value first. When the source also contains a literal app.config.getString("KEY", "default") default, the generated wrapper uses that default if the environment value is absent.
Pattern Rules
Compiler-enforced route grammar:
/- static segments without braces
{name},{name:str},{name:int},{name:uuid},{name:alpha},{name:float}
Normalization:
- framework
:nameis normalized to{name}before validation
Handler Diagnostics
Representative handler diagnostics:
SLOPPYC_E_UNSUPPORTED_HANDLERSLOPPYC_E_UNSUPPORTED_HANDLER_PARAMETERSSLOPPYC_E_UNSUPPORTED_TYPESCRIPT_HANDLERSLOPPYC_E_UNSUPPORTED_HANDLER_VALUESLOPPYC_E_UNSUPPORTED_ASYNC_HANDLER_BODY
Typed Handler Binding Diagnostics
Representative typed-binding diagnostics:
SLOPPYC_E_UNSUPPORTED_HEADER_BINDINGSLOPPYC_E_DYNAMIC_PROVIDER_NAMESLOPPYC_E_UNKNOWN_INJECTION_MARKERSLOPPYC_E_UNRESOLVED_TYPESLOPPYC_E_MULTIPLE_BODY_BINDINGSSLOPPYC_E_ROUTE_BINDING_MISMATCHSLOPPYC_E_UNBOUND_ROUTE_PARAMETERSLOPPYC_E_AMBIGUOUS_BINDING
Provider Bridge Limitation
Compiler metadata recognizes sqlite/postgres/sqlserver providers. Typed provider parameters emit generated wrappers for all three provider kinds, with PostgreSQL and SQL Server execution gated on provider config, active bridge support, and live service dependencies.
Generated static provider handles are narrower: app.provider("sqlite:main") is the current executable static-handle path. Static non-SQLite handles such as app.provider("postgres:main") are rejected with SLOPPYC_E_UNSUPPORTED_PROVIDER_BRIDGE.