//#region src/types.d.ts type TargetLanguage = 'swift' | 'kotlin'; interface EmitOptions { target: TargetLanguage; /** * Canonical font name → iOS PostScript name, from the shared * `fonts/` dir (read by the CLI's `build` step via `scanFontDir`). * `` emits `.font(.custom("", …))` on * iOS — the PostScript name is the only thing `Font.custom` accepts. * Android uses a runtime `res/font` lookup, so it doesn't need this. */ fonts?: Record; /** * The file this source came from, used only in diagnostics. * * A parse error is reported as `file:line:col: message`, and without this * every such message names the default `input.tsx` — a path that does not * exist, so the position is not just unhelpful but actively misleading. * Callers that have a real path should pass it; the default stays for * in-memory callers that genuinely have none. * * It is ALSO what marks the emit as one module of a multi-file build: when * set, the file-scope structs PMTC synthesizes for anonymous object literals * get a per-module suffix (`__Obj0_k3x9a`), so two generated files in one * Xcode target / Gradle source set cannot both declare `__Obj0`. Without it * the bare `__ObjN` names are kept, which is correct for a single file. */ filename?: string; } interface ComponentIR { /** Component name from `export function NAME(...)`. */ name: string; /** * Component props parsed from the function's first parameter when it * carries an object type annotation. The parameter binding name (`props`, * `p`, etc.) is captured separately so the emitter can rewrite member * accesses like `props.title` → `title` on the target. Empty when the * component takes no params or the param is untyped. */ props: PropIR[]; /** * The first-parameter binding name (`props`, `p`, etc.) used to recognise * `.field` member accesses inside the body and rewrite them to * bare field references on the target. Undefined for prop-less components. */ propsParamName: string | undefined; /** Top-level declarations inside the component body. */ decls: DeclIR[]; /** The expression the component returns. */ returnExpr: ExprIR; } interface PropIR { /** Prop name (the field key in the JSX `` site). */ name: string; /** Declared type from the TS annotation. */ type: TypeIR; } /** A JSON value — what an {@link ExtPayload} may hold (it must survive `structuredClone` and a JSON round trip). */ type ExtValue = string | number | boolean | null | readonly ExtValue[] | { readonly [key: string]: ExtValue; }; /** A plugin declaration's data: a JSON-serializable record. */ type ExtPayload = { readonly [key: string]: ExtValue; }; /** * The open declaration kind. A plugin's `CallRecognizer` produces one (the * compiler stamps `plugin` and `name`), and the same plugin's `DeclEmitter` * for `type` renders it on each target. `payload` is the plugin's own data and * must be JSON — the pass pipeline clones the IR with `structuredClone`. */ interface ExtDecl { readonly kind: 'ext'; /** The owning plugin's `name`. */ readonly plugin: string; /** The plugin-local declaration type (a key of that plugin's `decls`). */ readonly type: string; /** The binding the author wrote (`const = …`). */ readonly name: string; readonly payload: ExtPayload; } /** * The open FILE-SCOPE declaration: a plugin's own top-level item (a schema, a metadata record), emitted * beside the file's structs and enums and read by name from elsewhere in the file. A plugin's `topLevel` * recognizer produces one (the compiler stamps `plugin`), and the same plugin's `items[type]` emitter renders * it. `payload` must be JSON — the pass pipeline clones the IR with `structuredClone`; unlike an * {@link ExtDecl}'s it is mutable, because a plugin's own refinement passes edit it in place. */ interface ExtModuleItem { /** The owning plugin's `name`. */ plugin: string; /** The plugin-local item type (a key of that plugin's `items`). */ type: string; /** The binding the item declares. */ name: string; payload: { [key: string]: ExtValue; }; } type DeclIR = /** * Reactive signal declaration. The classic shape is `signal(initial)` * — emits as `@State` on Swift / `mutableStateOf` on Kotlin. * * G5 (TodoMVC walkthrough) adds `storageKey` for persistent signals * declared via `useStorage('key', default)`. When set, the Swift * emit shifts to `@AppStorage("key")` (SwiftUI's persistent property * wrapper) and the Kotlin emit shifts to `rememberSaveable` (Compose's * state-preservation primitive). `storageKey` is `undefined` for * regular signals — emit paths default to the non-storage shape. */ { kind: 'signal'; name: string; type: TypeIR; initial: ExprIR; storageKey?: string; } | /** * Computed value via `computed(() => expr)` or `computed(() => { ... })`. * The legacy single-expression form populates `expr`. Multi-statement * BlockStatement bodies populate `body` with the full statement * sequence — emit produces a multi-statement getter * (`private var X: T { let x = ...; if cond { return X } ; return Y }`). * * Exactly one of `expr` / `body` is populated. Phase 2 follow-up * closing the TodoMVC `visible: Any { xs }` typecheck blocker. */ { kind: 'computed'; name: string; expr?: ExprIR; body?: StatementIR[]; } | /** * Local function declaration via `const fn = () => { ... }` * (Parser-A from `native-platforms-todomvc-walkthrough.md`). Emits * as a `private func` on Swift / a private fn on Kotlin. * * Multi-statement BlockStatement bodies are supported via `body` * carrying StatementIR[]; a single-expression arrow body lands as * `body: [{ kind: 'return', expr }]` for uniformity. */ { kind: 'function'; name: string; params: { name: string; type: TypeIR; defaultValue?: ExprIR | undefined; }[]; returnType: TypeIR; body: StatementIR[]; } | /** * Router instance declaration via `createRouter({ routes: [...] })` * from `@pyreon/router`. Phase C4 shipped the SCAFFOLD (bare instance * emit); Phase C5 ADDS optional `routes: RouteIR[]` so the emitter * can produce per-target route definitions: * Swift → @State private var router = PyreonRouter() * + `.navigationDestination(for: String.self)` block * inside the `` content closure * Kotlin → val router = remember { PyreonRouter() } * + `NavHost { composable("/path") { Component() } }` * block replacing the bare RouterProvider content * * `routes` is undefined when the parser couldn't extract a literal * routes array (e.g. `createRouter()`, `createRouter(opts)` with a * non-literal config, or an object literal that doesn't match the * expected `{ routes: [{ path, component }, ...] }` shape). In that * case the emit falls back to the C4 bare-instance shape — back-compat. */ { kind: 'router'; name: string; routes?: RouteIR[]; /** * Global router-level guards: `beforeEach: [fn]` / `afterEach: [fn]` * on the createRouter config. Each entry is an IDENTIFIER REF * (function name captured at parse time, like `authGuard`). The * runtime PyreonRouter's `push`/`replace` chains beforeEach (any * returning false blocks the navigation), then runs afterEach * fan-out after the path commits. * * Conservative shape: identifier refs only. Inline arrow bodies * (`beforeEach: [(p) => isAuthed()]`) are NOT lowered (they'd need * the arrow-emit + closure-capture machinery that per-route boolean * guards already use — closure form is a documented follow-up) — but * they are no longer dropped SILENTLY: a non-identifier element emits * a named warning pointing at the named-function fix, because an * inline guard that vanishes would leave the navigation ungated with * no signal (a security foot-gun). * * Undefined when the config has no such field OR all entries * were dropped (back-compat). */ beforeEach?: string[]; afterEach?: string[]; } | /** * A component-body `onMount(() => { … })` call — the documented lifecycle * escape hatch ("call .start()/.connect() from an onMount"). Lowers to a * mount-time harness: SwiftUI `.onAppear { … }` on the stable-identity * host (the fetch-arc ZStack — a transparent Group redistributes the * modifier onto conditional branches and re-fires it per flip); Compose * `LaunchedEffect(Unit) { … }`. A returned cleanup fn is NOT emitted in * v1 (named warning). Pre-fix the whole call was a SILENT drop — the * component-body walker only handled declarations + return. */ { kind: 'on-mount'; body: StatementIR[]; } | /** * A PLAIN service container (`useShare`, `useLinking`, `useHaptics`, * `useNotifications`, `useBiometrics`, `useImagePicker`, `useFilePicker`, * `useCamera`) — see `services.ts`. `hook` names the entry in `SERVICES` * that supplies the Swift initialiser and the Kotlin declaration lines, so * adding another plain container is one descriptor and no new variant. * The hook takes no arguments and has NO reactive state; every call is a * member method that flows through unchanged (no `.value` rewrite, no * argument transformation). */ { kind: 'service'; name: string; hook: string; } | /** * A declaration a PLUGIN recognized and emits (`CompilerPlugin.calls` / * `.decls`). The core never switches on `type`: it dispatches by * `(plugin, type)` to the owner's `DeclEmitter`. See {@link ExtDecl}. */ ExtDecl | /** * Phase 5 (native data/services hook emit). Reactive-container hooks that * instantiate the @pyreon/native-runtime-{swift,kotlin} service containers * shipped this arc. Each mirrors the `network-status` / `permissions` * emit shape (Swift `@State` / Kotlin `remember`); reactive FIELD reads on * the binding append `.value` on Kotlin (Compose `MutableState`) and read * bare on Swift (`@Observable`), while method calls + plain-Bool getters * read bare on both. Per-hook field/method maps live in emit-{swift,kotlin}. * * useGeolocation() → PyreonGeolocation (lat/lon/accuracy/isAuthorized/error * + start/stop; maps + uber archetypes) * useWebSocket(url) → PyreonWebSocket (lastMessage/messages/isConnected/error * + send/close; realtime archetype) * useSecureStorage() → PyreonSecureStorage (write/read/remove/contains; finance/auth) * useDatabase() → PyreonDatabase (insert/get/all/find/delete/count; offline-first) * usePush() → PyreonPushNotifications (token/lastNotification/isAuthorized/error) * usePayments() → PyreonPayments (products/ownedProductIds/purchasing/error * + purchase/restore; IAP) * useMap() → PyreonMapState (camera/markers/selectedMarker * + moveTo/addMarker/selectMarker; maps view-state) * * `useAuth()` is generic (carries `userType`); the rest are non-generic. * `useWebSocket(url)` captures the string URL literal arg. */ /** * Phase 5b — a plain VALUE const in a component body: `const a = 5 + 3`, * `const label = 'Total: '`, `const doubled = base * 2`. Previously dropped * (only call-expression decls — signal/computed/hook/fn — were captured), * which silently vanished any local const → undefined references on native. * Emitted as a body-local `let` (Swift, inside the `body` ViewBuilder where * Swift infers the type + it may reference `@State`) / `val` (Kotlin * composable body). Captures-once like JS `const` — a `const x = sig()` * snapshots the signal (non-reactive), matching web semantics. Non-call, * non-arrow inits only (arrows → `function`, calls → signal/computed/hook). */ { kind: 'value'; name: string; expr: ExprIR; /** The declaration's annotation, when written — it steers an object/array literal to its named struct. */ type?: TypeIR; }; /** * Phase C5 — one route entry parsed from `createRouter({ routes: [...] })`. * Mirrors the web-side `RouteRecord` shape from `@pyreon/router`, * intentionally narrowed to PATH + COMPONENT for v1. * * `path` is captured as the string-literal pattern (`/`, `/users/:id`). * The native emit walks it character-by-character — literal segments * become exact `==` comparisons (Swift) / fixed strings (Compose); `:name` * segments become param-capture slots. * * `component` is an `ExprIR` so it can carry any reachable component * expression — bare identifier (`HomePage`), property access * (`pages.Home`), or even a call. Phase 0 supports identifier and * member shapes; other shapes fall back to literal emit (the verbatim * source string). It is OPTIONAL because a redirect-only route * (`{ path: '/', redirect: '/home' }`) carries no component of its own. * * `redirect` (Phase 3) is a static per-route redirect target — a literal * path string. The native emit treats it as a COMPILE-TIME ALIAS: the * dispatch branch for `path` renders the redirect target's component * directly (no router-runtime push, fully verifiable via swiftc/kotlinc). * Only literal `redirect: ''` is captured here; function redirects * and runtime `throw redirect()` are a later arc. Chains * (`/a → /b → /c`) resolve transitively with a cycle guard; redirect * source AND target must both be literal (non-`:param`) paths in v1. * * Deferred to future arcs: loader, guards, meta, middleware, children * (nested layouts), name. The rest extends when a real app needs it. */ interface RouteIR { /** Literal path pattern, e.g. `/` or `/users/:id`. */ path: string; /** * Component to render for this route. Optional — a redirect-only route * has no component (its `redirect` target supplies one). */ component?: ExprIR; /** * Phase 3 — static per-route redirect target (a literal path string, * e.g. `{ path: '/', redirect: '/home' }`). Compile-time alias to the * target route's component; see the interface doc for resolution rules. */ redirect?: string; /** * Phase 3 — per-route boolean guard from `beforeEnter: () => `. * The native emit wraps the matched component in an inline conditional: * `if () { Component() } else { }` — the dispatch runs * at navigation time, so the guard is checked before the route renders * (faithful to `beforeEnter`'s "before the route activates" semantic). * On failure the branch renders the router's catch-all fallback (the * wildcard component if one exists, else the no-route placeholder). * * v1 captures only an arrow with an EXPRESSION body (`() => isAuthed()`); * block-body guards and `throw redirect()` / async guards are a later arc * (they leave `guard` undefined → the route emits unguarded). */ guard?: ExprIR; /** * Phase 3 (nested routes) — child routes of a layout route. When present, * this route is a LAYOUT: its `component` renders a `` slot * that the matched child fills. The native emit flattens the tree into * full-path leaf branches and wraps each leaf in its ancestor layout chain * via a content-closure (`Layout { Child() }` on Swift / `Layout { Child() }` * on Compose) — see `flattenRouteTree`. Child `path`s are relative segments * joined onto the parent (`/app` + `dashboard` → `/app/dashboard`); a child * whose path already starts with `/` is treated as already-absolute * (mirrors `@pyreon/router`'s fs-router nested-absolute-path handling). * * v1 supports literal (non-`:param`) 2-level nesting; deeper trees flatten * recursively but param-bearing nested paths conservatively bail (no value * source at the alias site), same discipline as redirects. */ children?: RouteIR[]; /** * Phase 3 — per-route data loader from `loader: () => ` (or * `async () => `). The native emit wraps the matched component in a * runtime `PyreonRouteLoader(path:, load:)` host whose `.task` (Swift) / * `LaunchedEffect` (Compose) fires the loader ONCE on the route's appear * and stores the result via `router.setLoaderData(path, …)`, where the * already-shipped `useLoaderData()` reads it. The store is guarded * (`loaderData[path] == nil`) so re-renders don't re-run the loader. * * v1 captures only a ZERO-PARAM arrow with an EXPRESSION body * (`() => fetchAll()` / `async () => 42`). A param-using loader * (`(ctx) => fetch(ctx.params.id)` — `ctx` has no value source in the * load closure yet) and block-body loaders leave `loader` undefined and * warn → the route emits with NO loader (the component still renders; * `useLoaderData()` returns nil). `ctx.params` threading + truly-async * `await` bodies are a later arc. */ loader?: ExprIR; /** * True when the route's `loader: (ctx) => …` body reads `ctx.params.*` * (lowered to `params["…"]`). The emitter must then bind `params` from * `matchPath(path, "/x/:id")` in the dispatch branch even when the * component prop itself doesn't use params. */ loaderUsesParams?: boolean; } /** * Statement IR — sequence of operations inside a function body. The * existing parser walks Pyreon JSX components via top-level * VariableDeclaration / ReturnStatement; this adds the imperative * shape needed for TodoMVC's mutation functions (`addTodo`, `toggle`, * `remove`, `clearCompleted`). * * Kinds intentionally minimal for the immediate TodoMVC slice: * `let` (local const binding), `if` (with optional else), `return`, * and `expr` (call-expression as statement). Future expansions * (`for`, `while`, `try`) deliberately deferred. */ type StatementIR = /** * `const text = draft().trim()` — local binding inside a fn body. * `mutable` is set by `parseStatementBlock` when a later `assign` * statement in the SAME block reassigns this name — the emit then uses * `var` (Swift + Kotlin) instead of `let`/`val` so the reassignment * typechecks. */ { kind: 'let'; name: string; expr: ExprIR; mutable?: boolean; /** * The TS annotation when the source carries one. Needed because an EMPTY * collection literal carries no element type of its own: `const out: * Tick[] = []` emits `let out = []`, which Swift rejects ("empty * collection literal requires an explicit type") and Kotlin degrades to * `listOf()`. The annotation is the only place that element type exists. */ declaredType?: TypeIR; /** an ARRAY-literal local later mutated via push/pop/shift/unshift/splice — Kotlin must emit mutableListOf */ methodMutated?: boolean | undefined; } | /** * `let out: string` — a DECLARATION with no initializer, assigned later * (typically once per branch of an `if`/`switch`). Ordinary TypeScript, and * previously DROPPED: the parser returned null for a declarator with no * `init`, so every later assignment referenced a name that was never * declared ("cannot find 'out' in scope" / "unresolved reference"), with no * warning. Distinct from `let` because there is no expression to emit, and * the ANNOTATION is not optional here — it is the only thing that says what * the variable's type is, so a declaration without one is warned and dropped * rather than guessed at. */ { kind: 'declare'; name: string; declaredType: TypeIR; } | /** * Reassignment of a plain local / member / index target: * `t = t + x`, `acc += 1`. Signals reassign via `.set()` (a call, the * `expr` kind), so a raw `AssignmentExpression` is ALWAYS a plain * (non-signal) reassignment. `op` is `=` or a compound (`+= -= *= /= %=`); * both Swift and Kotlin take these verbatim. */ { kind: 'assign'; target: ExprIR; op: string; value: ExprIR; } | /** `if (cond) { then } [else { else }]`. */ { kind: 'if'; cond: ExprIR; then: StatementIR[]; elseBody?: StatementIR[]; } | /** `return [expr]` — bare early-return uses `expr: undefined`. */ { kind: 'return'; expr?: ExprIR; } | /** Bare expression statement: `todos.set([...])`, `draft.set('')`. */ { kind: 'expr'; expr: ExprIR; } | /** * `while (cond) { … }` — Swift `while cond { … }` / Kotlin * `while (cond) { … }`. Multi-statement handler control-flow. */ { kind: 'while'; cond: ExprIR; body: StatementIR[]; label?: string; } | /** * `for (const item of iterable) { … }` — Swift `for item in iterable` * / Kotlin `for (item in iterable)`. Only the `const`/`let` * single-identifier binding form lowers; destructured / C-style `for` * fall through to warn-drop. */ { kind: 'for-of'; item: string; iterable: ExprIR; body: StatementIR[]; label?: string; } | /** * `break` / `continue` — plain or LABELED (`break outer`). Both targets * support loop labels natively: Swift `outer: for … { break outer }`, * Kotlin `outer@ for … { break@outer }`. Pre-fix these statements were * warn-DROPPED, which is a SEMANTIC mis-emit (the loop runs every * iteration where JS would exit/skip). */ { kind: 'break'; label?: string; } | { kind: 'continue'; label?: string; } | /** * The canonical C-style count-loop `for (let i = 0; i < n; i++)` / * `i += k`, lowered to a native RANGE loop — Swift `for i in 0..= 0; i--)` / `i -= k`) — Swift `stride(by: -k)`, Kotlin `downTo`. */ down?: boolean; step?: ExprIR; body: StatementIR[]; } | /** * `do { … } while (cond)` — Swift `repeat { … } while cond`, Kotlin * `do { … } while (cond)`. Pre-fix this warn-dropped the WHOLE loop, * leaving semantically wrong residue (the post-loop reads saw the * initial values). */ { kind: 'do-while'; cond: ExprIR; body: StatementIR[]; } | /** * `switch (x) { case 'a': …; default: … }` — Swift `switch x { case * "a": … }` / Kotlin `when (x) { "a" -> { … } }`. Each entry groups * consecutive `case` labels (`tests`) that share one body; `tests: []` * is the `default` / `else` branch. JS fall-through is NOT modeled * beyond empty-case label grouping (Swift/Kotlin don't fall through) — * a trailing `break` per case is stripped at parse. */ { kind: 'switch'; discriminant: ExprIR; cases: { tests: ExprIR[]; body: StatementIR[]; }[]; }; /** Type annotation, parsed from `signal(...)` generics. */ type TypeIR = { kind: 'number'; float?: boolean; } | { kind: 'string'; } | { kind: 'boolean'; } | { kind: 'array'; element: TypeIR; } | /** `Map` → Swift `[K: V]` / Kotlin `MutableMap`. */ { kind: 'map'; key: TypeIR; value: TypeIR; } | /** `Set` → Swift `Set` / Kotlin `MutableSet`. */ { kind: 'set'; element: TypeIR; } | { kind: 'object'; fields: { name: string; type: TypeIR; }[]; } | { kind: 'null'; } | { kind: 'undefined'; } | /** * Union types — `string | number`, `Foo | null` (nullable), etc. * The branches are flat (no nested unions); the type mapper handles * the common nullable shapes (`T | null`, `T | undefined`) by * emitting Swift/Kotlin Optional / nullable types; mixed-type unions * (`string | number`) fall back to `Any` per target since neither * Swift nor Kotlin has a structural union primitive. */ { kind: 'union'; branches: TypeIR[]; } | /** * Named type reference — `Foo`, `MyInterface`. The Phase 0 parser * doesn't follow imports, so it can't resolve the referenced type. * The reference is preserved by name and emitted verbatim per target * (Swift / Kotlin both accept named type references resolved at * their respective compile time). Generic args (e.g. `Array`) * propagate. */ { kind: 'typeRef'; name: string; args: TypeIR[]; } | /** * Function type — `(a: number, b: string) => boolean`. Captures * each parameter's name (when present in source) + type, and the * return type. Names are kept in IR for debugging + future use; * Swift / Kotlin function types are positional so the emitter * drops the names at emit time. */ { kind: 'function'; params: { name?: string; type: TypeIR; }[]; returnType: TypeIR; } | { kind: 'unknown'; }; type ExprIR = { kind: 'literal'; value: string | number | boolean | null; float?: boolean; } | { kind: 'identifier'; name: string; } | /** * `f(args)` — a plain call, OR `f?.(args)` when `optional: true` (the * optional-call form: JS short-circuits to undefined if the callee is * nullish). Lowers to Swift `f?(args)` / Kotlin `f?.invoke(args)`. */ { kind: 'call'; callee: ExprIR; args: ExprIR[]; optional?: boolean; } | /** * The open expression: a plugin's own expression (`.(…)` its `methodCalls` recognizer, or a * call its `callExprs` recognizer, claimed), rendered and typed by the same plugin's `exprs[type]`. The compiler stamps `plugin`; `payload` * is JSON and `args` are the sub-expressions the plugin asked the parser for. */ { kind: 'ext-expr'; plugin: string; type: string; payload: ExtPayload; args: ExprIR[]; } | /** * `JSON.stringify(x)` → a native serialization of an Encodable/@Serializable * value. Swift `String(data: try! JSONEncoder().encode(x), …)`, Kotlin * `Json.encodeToString(x)`. Only the SAFE half lowers: `JSON.parse` throws, * which needs a native error model (a tracked follow-up), so it still warns. */ { kind: 'json-stringify'; arg: ExprIR; } | /** * `await expr` — an awaited async-result call inside an `async` handler * (M4.5). The emitter unwraps to `await ` (Swift) / `` (Kotlin * suspend calls carry no `await` keyword). Only meaningful inside an arrow * marked `async: true`, which the action emitters wrap in a `Task { … }` * (Swift) / `scope.launch { … }` (Kotlin) async scope. */ { kind: 'await'; expr: ExprIR; } | { kind: 'member'; object: ExprIR; property: string; optional?: boolean; } | /** * Computed member access — `xs[i]`, `tasks[tasks.length - 1]`. * Swift arrays and Kotlin lists share the `xs[i]` subscript syntax, * so the emit is verbatim per target. Pre-PR-D, `computed: true` * MemberExpressions fell into the `member` case with * `property: undefined` — the emit produced `tasks.undefined` * (the broken shape the original tasks scaffold shipped). */ /** * `xs[i]` — plain computed access (native index; OOB traps, the documented * simplification). `optional: true` = the `xs?.[i]` SAFE form: JS returns * undefined out-of-bounds, so it lowers to the guarded native idiom * (Swift `indices.contains ? xs[i] : nil` / Kotlin `getOrNull(i)`) and * infers `element | undefined` so `?? fallback` collapses. */ { kind: 'index'; object: ExprIR; index: ExprIR; optional?: boolean; } | /** * `new Map()` / `new Set()` / `new Set(seedArray)` — the two * supported collection constructors (the accumulator / dedup idioms). * `seed` is the optional Set-from-array argument. Other `new X()` * expressions stay the named unsupported warning. */ { kind: 'new-collection'; collection: 'map' | 'set'; keyType?: TypeIR; valueType?: TypeIR; elementType?: TypeIR; seed?: ExprIR; /** * Seeded `new Map([[k, v], …])` — scalar key/value pair entries. When * present the emit produces a native dict literal (`[k: v]` / `mutableMapOf(k to v)`) * instead of the empty constructor. `keyType`/`valueType` are inferred * from the first entry. */ entries?: [ExprIR, ExprIR][]; } | { kind: 'binary'; op: '+' | '-' | '*' | '/' | '%' | '&' | '|' | '^' | '<<' | '>>' | '**'; left: ExprIR; right: ExprIR; } | /** * Template literal — `` `Hello ${name}!` ``. String interpolation is the * single most common out-of-subset expression (labels, formatted values). * Lowered to NATIVE string interpolation (Swift `"Hello \(name)!"`, Kotlin * `"Hello ${name}!"`) — NOT `+`-concat, because Swift's `+` does not coerce * a non-String interpoland (`"n=" + count` is a Swift type error), while * interpolation coerces any type on both targets. `quasis` are the COOKED * literal segments (escaped per-target at emit); `exprs` interleave between * them (`quasis.length === exprs.length + 1`). Tagged templates stay * warn-dropped (no native equivalent). */ { kind: 'template'; quasis: string[]; exprs: ExprIR[]; } | /** * Comparison + equality operators emit as-is on both Swift and Kotlin * (`==` / `!=` / `<` / `>` / `<=` / `>=`). Added in the Parser-A slice * because TodoMVC's filter conditionals (`t.id === id`, `filter() === 'active'`) * require them. Pyreon source uses `===` / `!==` which JS-evaluates * the same as `==` / `!=` for the value types Pyreon signals carry; * the emitter coalesces to the native target's `==` / `!=`. */ { kind: 'comparison'; op: '==' | '!=' | '<' | '>' | '<=' | '>='; left: ExprIR; right: ExprIR; } | /** * Unary operators (Parser-B). TodoMVC uses `!t.done` in filter * callbacks. Both Swift and Kotlin support `!` / `-` / `+` as * prefix unary; the emitter passes them through verbatim. */ { kind: 'unary'; op: '!' | '-' | '+'; argument: ExprIR; } | /** * Logical operators (Parser-C). TodoMVC uses `e.key === 'Enter' && addTodo()` * in the keyboard handler. Swift and Kotlin both have `&&` / `||` with * the same short-circuit semantics. JS's `??` (nullish coalescing) maps * differently per target but isn't in the TodoMVC slice — deferred. */ { kind: 'logical'; op: '&&' | '||' | '??'; left: ExprIR; right: ExprIR; } | /** * Ternary conditional (`cond ? a : b`). Both Swift and Kotlin have * the ternary form verbatim (Kotlin uses `if (cond) a else b` as the * idiomatic equivalent — same expression-form semantics). TodoMVC's * `toggle` uses this in the map callback. */ { kind: 'ternary'; cond: ExprIR; then: ExprIR; otherwise: ExprIR; } | /** * Post-increment / -decrement (`x++`, `x--`). JavaScript evaluates * to the OLD value while side-effect-incrementing. In Pyreon source * the common use is `someCounter++` in an array literal (TodoMVC: * `{ id: nextId++, ... }`). The emit on both Swift and Kotlin * degrades to `x + 1` for the value (Swift @State / Kotlin var don't * support `++` natively in expression position) — the side-effect * increment is lost. Phase 2 refines if needed. */ { kind: 'update'; op: '++' | '--'; argument: ExprIR; } | /** * Arrow function. A single-expression body (`() => count.set(1)`) or a * block body with exactly one expression/return statement lands in * `body` (the compact form — most accessor / `.update` / handler sites). * A block body with MULTIPLE statements (`() => { a.set(1); b.set(2) }`) * — common for event handlers doing several things — additionally * carries the full statement list in `stmts`; `body` is a sentinel * empty literal in that case. `emitSwiftAction` / `emitKotlinAction` * emit `stmts` as a multi-statement closure body; without it the * earlier parse silently kept only the FIRST statement. */ { kind: 'arrow'; params: string[]; /** Per-param TS annotations, index-aligned with `params`; undefined where unannotated. */ paramTypes?: (TypeIR | undefined)[] | undefined; /** the arrow's declared RETURN annotation, when written */ returnAnnot?: TypeIR | undefined; body: ExprIR; stmts?: StatementIR[]; async?: boolean; } | { kind: 'jsx-element'; tag: string; attrs: AttrIR[]; children: ChildIR[]; } | { kind: 'jsx-fragment'; children: ChildIR[]; } | { kind: 'array'; elements: ExprIR[]; elementType?: TypeIR; } | /** * Object literal with optional spread members. The classic shape is * `{ a: 1, b: 2 }` (zero spreads); G4 (TodoMVC walkthrough) adds the * partial-update form `{ ...t, done: !t.done }` — the spread carries * the existing fields, the explicit fields override. * * Spreads are emitted in source order; emit targets that support a * native copy-with-overrides shape (Kotlin data class `.copy()`, * Swift struct construction) consume the array. `spreads.length === 0` * is the canonical zero-spread case; the field is optional for * backward compat with pre-G4 IR consumers. */ { kind: 'object'; /** * `afterSpreads` is how many SPREADS precede this field in source * order. The two arrays lost their relative order, which made * `{ a: 9, ...p }` and `{ ...p, a: 9 }` emit byte-identically while JS * answers `1` and `9` — see `spread-lowering.ts`. Absent means "order * unknown", which every non-parse constructor of this node implies and * which is read as "after all spreads" (the pre-existing behaviour). */ fields: { name: string; value: ExprIR; afterSpreads?: number; }[]; spreads?: ExprIR[]; } | { kind: 'paren'; inner: ExprIR; } | /** * Spread element in array literal (`[...todos(), newTodo]`) used by * TodoMVC's mutation functions. The emit on Swift becomes `todos + * [newTodo]` (immutable concat) — preserves the source's * value-semantics. Kotlin emit: `todos + listOf(newTodo)`. */ { kind: 'spread'; argument: ExprIR; }; /** A JSX element expression — the unit an element lowering claims and rewrites. */ type JsxElementIR = Extract; type AttrIR = /** Regular attribute: `each={items}`, `by={(i) => i.id}`, `when={visible}`. */ { kind: 'attr'; name: string; value: ExprIR; } | /** Event handler: `onClick={() => …}`. The 'on' prefix is stripped from `name`. */ { kind: 'event'; name: string; handler: ExprIR; } | /** * JSX spread attribute: `` / ``. * `argument` is the spread source. At emit, for a USER component the spread * expands to per-prop constructor args: an object-literal source expands its * own fields; an identifier/member source expands the TARGET component's * declared props, each sourced as `.`. Explicit sibling * attrs win (a spread prop they also set is skipped). Spreads onto * primitives have no native equivalent → warn-drop. */ { kind: 'spread'; argument: ExprIR; }; type ChildIR = /** Static text between JSX tags: `Hello`. */ { kind: 'text'; value: string; } | /** Interpolation: `{count}`. */ { kind: 'expr'; expr: ExprIR; }; /** * String-literal union type alias emitted as a native enum. Source: * * type Filter = 'all' | 'active' | 'completed' * * Swift emit: * * enum Filter: String { case all, active, completed } * * Kotlin emit: * * enum class Filter { all, active, completed } * * Pyreon's signal-based reactivity is structurally aligned with both * targets' enum primitives — using a native enum is strictly better * than emitting raw String (typesafe; pattern-match-able) AND lets the * compiler convert literal usages (`'all'` → `.all` on Swift) at the * use site. Closes gap G6 from `native-platforms-todomvc-walkthrough.md`. */ interface EnumIR { /** Alias name from `type X = ...` declaration. */ name: string; /** Allowed values from the union branches (`'all'` → `'all'`). */ cases: string[]; } /** * Object-shape type alias emitted as a native struct / data class. Source: * * type Todo = { id: number; text: string; done: boolean } * * Swift emit: * * struct Todo { var id: Int; var text: String; var done: Bool } * * Kotlin emit: * * data class Todo(var id: Int, var text: String, var done: Boolean) * * Closes the foundational Phase 2 gap surfaced by G5 #849's known * caveats: anonymous record types currently emit as labelled tuples, * blocking @AppStorage's Codable bridge (Swift) and rememberSaveable's * Parcelable/Saver requirements (Kotlin). Real structs let downstream * Phase 2 work add Codable conformance + Compose Savers. * * `var` fields (not `let` / `val`) so the G4 IIFE-copy pattern's tuple * mutation idiom — `{ var c = t; c.done = !t.done; return c }()` — * works structurally when `t` is upgraded from tuple to struct. * Kotlin's `data class .copy(done = ...)` doesn't need this but the * `var` default keeps the option open for direct field mutation. */ interface StructIR { /** Alias name from `type X = ...` declaration. */ name: string; /** Object-type fields. */ fields: { name: string; type: TypeIR; }[]; /** * Declared by an imported native runtime (the generated chart engine's * structs, `@pyreon/charts` native-plugin `engine-structs.ts`): used to TYPE object literals and * annotations, never DECLARED in the emit — the runtime already has it. */ external?: boolean; } /** * Module-level mutable binding emitted at file scope on the target. * Source: * * let nextId = 1 * const APP_VERSION = '1.0.0' * * Swift emit: * * private var nextId: Int = 1 * private let APP_VERSION: String = "1.0.0" * * Kotlin emit: * * private var nextId: Int = 1 * private val APP_VERSION: String = "1.0.0" * * Phase 2 follow-up closing the "TodoMVC's `nextId` undefined in Swift * scope" gap surfaced by the post-Phase-2-trilogy typecheck. The TS * source's `let` declares a mutable binding; `const` declares immutable. * Pyreon convention preserves the mutability through to the target — * `let` → `var`/`var`, `const` → `let`/`val`. * * Type field: explicit annotation when source carries one, otherwise * `unknown` (target falls back to type-inference at compile time). */ interface ModuleDeclIR { name: string; /** `var` (TS `let`) or `let` (TS `const`). Preserves source mutability. */ mutable: boolean; /** Type annotation; `unknown` when source omits it. */ type: TypeIR; /** Initial-value expression. */ initial: ExprIR; } interface ParseResult { /** Decoded static import specifiers, collected from the parser's AST. */ imports: string[]; components: ComponentIR[]; /** String-literal-union type aliases lifted to native enums. */ enums: EnumIR[]; /** Object-shape type aliases lifted to native structs / data classes. */ structs: StructIR[]; /** Module-level mutable / immutable bindings emitted at file scope. */ moduleDecls: ModuleDeclIR[]; /** * File-scope items plugins own (see {@link ExtModuleItem}): declarations a plugin's `topLevel` recognizer * claimed, then the ones its expression recognizers synthesized. Emitted in plugin-declared slots beside the * core's own module items. */ moduleItems: ExtModuleItem[]; /** * Top-level pure-logic HELPER functions — a function that takes value * parameters and returns a non-JSX value (`function dbl(x: number) { return * x * 2 }`, L1 "shared pure logic" in `.agents/guides/multiplatform/README.md`). Emitted at file scope as a * Swift `func` / Kotlin `fun` (a sibling of enums / structs / stores, BEFORE * the component View structs so components + store methods can call them). * A GENERIC helper (`function first(…)`) is NOT collected here — the IR * has no generic-parameter representation, so it stays a NAMED warning (see * `tryComponentFromTopLevel`). Distinct from function members (same * `DeclIR{kind:'function'}` shape, but those emit as CLASS methods on the * store singleton, these emit free at file scope). */ helperFns: Extract[]; /** * Local-name → source package + original imported name for package-specific * JSX hooks. The emit intercepts a tag ONLY when both match — so a user * component that happens to share a name (`Row` from `./my-components`) is * NOT mis-lowered as a coolgrid Row. An untracked name (absent from the map) * keeps prior behaviour, so this is a purely additive precision guard. */ aliasImports: Map; /** Diagnostic messages produced during IR construction. */ warnings: string[]; } interface TransformResult { /** Emitted source code for the target language. */ code: string; /** Diagnostic messages from the IR construction. */ warnings: string[]; } /** * A modifier in a parsed hotkey combo. `mod` is preserved rather than resolved: * the platform decides (Command on iOS, Ctrl on Android), and only the emitter * knows which platform it is. */ //#endregion //#region src/emit-context.d.ts type EmitTarget = 'swift' | 'kotlin'; /** A plugin-owned declaration scope, independent of any library or target class. */ interface MemberEmitScope { readonly name: string; readonly declarations: readonly DeclIR[]; /** The parameter through which member bodies address this scope's signal values. */ readonly receiver?: string | undefined; /** Use the target's observable-class member spelling (Swift Observation). */ readonly observable?: boolean | undefined; } /** A callback-local name, optionally typed and owned by a plugin receiver lowering. */ interface EmitBinding { readonly name: string; readonly type?: TypeIR | undefined; readonly declaration?: ExtDecl | undefined; } /** Validators offered by a loaded module item, rendered for the active target. */ interface EmitFieldValidators { readonly fields: readonly string[]; body(field: string, value: string): string; } /** A literal attribute value the compiler can read at compile time. */ type StaticAttrValue = string | number | boolean; /** The component being emitted, as a plugin may read it. */ interface ComponentInfo { /** The component's name (`''` outside a component). */ readonly name: string; /** The name of its props parameter (`props` in `(props: P) => …`), when it has one. */ readonly propsParamName: string | undefined; /** Its body-level `const`s (and their initializers) that are value-shaped — what a JSX attribute may name. */ readonly valueConsts: ReadonlyMap; /** Whether `tag` names a component declared in the file being emitted (so it is not the plugin's to claim). */ isDeclared(tag: string): boolean; } /** * The struct registry the emitter keeps for the file: structs the source * declared, and the ones synthesised for object literals. A plugin that builds * a typed container from a literal (a flow's node rows) must resolve to the * SAME names the rest of the file's literals do, so it asks here rather than * keeping a registry of its own. */ interface StructRegistry { /** * The struct for an inline object TYPE: a declared one with the same typed * fields, else one with the same field names, else a synthesised one (which * this call registers). `null` when the shape cannot be named. */ forTypeFields(fields: readonly { name: string; type: TypeIR; }[]): string | null; /** * The struct a LITERAL's fields resolve to — the lookup every `{…}` literal in * the file uses (declared by value shape, by field names, by subset, then a * synthesised one). `null` when none applies. */ forLiteralFields(fields: readonly { name: string; value: ExprIR; }[]): string | null; /** Register a NEW synthesised struct with these fields and return its name (a union of heterogeneous rows). */ synthesize(fields: readonly { name: string; type: TypeIR; }[]): string; } /** * The emitter's WebView plumbing, for a plugin that hosts a page in ``. * Each member delegates to the helper the core's own `` lowering uses. */ interface WebViewFacade { /** An attribute's value as a reactive expression (an accessor arrow unwrapped), or `undefined` when absent. */ dynamicAttr(el: JsxElementIR, name: string): ExprIR | undefined; /** A `data` / `graph` payload as the target's JSON-encoding call. */ dataArg(value: ExprIR): string; /** A `(message) => …` handler as the target's message callback. */ messageHandler(handler: ExprIR): string; } /** * The Swift emitter's per-component `@State` declaration list — the lines the * component body receives ahead of its own statements. A host that needs * private view state (a zoom window, a hover index) declares it here; the * emitter inserts the lines when the component ends. */ interface HostStateSlot { /** Add one declaration line (`@State private var … = …`). */ declare(line: string): void; /** The component's declarations so far, in order. */ lines(): readonly string[]; /** Replace every declaration from index `start` on (a host that renames or drops what it declared). */ replaceFrom(start: number, lines: readonly string[]): void; /** A number never returned before in this file — for suffixing a name two hosts would otherwise share. */ freshSuffix(): number; } /** Target control for a callback body; the owning plugin supplies its Kotlin lambda label. */ interface StatementEmitOptions { readonly kotlin?: { readonly returnLabel?: string | undefined; /** Evaluate a returned expression for side effects, then return Unit. */ readonly discardReturnValue?: boolean | undefined; } | undefined; } interface EmitContext { /** Own signals/computeds/functions and an optional signal receiver, scoped for the synchronous callback. */ memberScope(scope: MemberEmitScope, run: () => T): T; /** Emit a member function, including default parameters, return types and statement bodies. */ functionDeclaration(decl: Extract): string; /** Convert numeric arguments when the known parameter stores fractional values. */ argument(e: ExprIR, type: TypeIR | undefined, at?: number): string; /** The target's spelling for a member of an observable class. */ observableIdent(name: string): string; /** * Emit a custom provider's children under its registered colour scope. * Nested calls restore the enclosing scope on return and throw. * @example * ctx.withColorScope(el, () => el.children.map(child => ctx.child(child))) */ withColorScope(el: JsxElementIR, emit: () => T): T; readonly target: EmitTarget; /** Temporarily bind callback names and their receiver lowerings; restores on return and throw. A binding without a declaration hides an enclosing plugin receiver. */ withBindings(bindings: readonly EmitBinding[], emit: () => T): T; /** Field validators offered by a loaded module item named name. */ fieldValidators(name: string): EmitFieldValidators | undefined; /** Declaration shapes the loaded validator providers advise. */ fieldValidatorsAdvice(): string | undefined; /** Indentation (in spaces) of the element being emitted. */ readonly indent: number; /** Emit another element through the full dispatcher; `indent` defaults to this one's. */ emit(el: JsxElementIR, indent?: number): string; /** `n` spaces; defaults to this element's indentation. */ pad(n?: number): string; /** A literal / const-resolved attribute value, or `undefined` when absent or dynamic. */ staticAttr(el: JsxElementIR, name: string): StaticAttrValue | undefined; /** A quoted string literal in the target language. */ stringLiteral(value: string): string; /** A name made safe as an identifier in the target language (reserved words escaped). */ ident(name: string): string; /** Report a lowering limitation to the author. */ warn(message: string): void; /** An expression emitted through the full dispatcher, at `at` (default: this context's indentation). */ expr(e: ExprIR, at?: number): string; /** An expression emitted with `type` as the expected type (steers an object / array literal's struct); `undefined` clears an inherited expectation. */ exprAs(type: TypeIR | undefined, e: ExprIR, at?: number): string; /** A string attribute as target text — a literal, or an interpolation of the expression — or `undefined` when absent. */ stringAttr(el: JsxElementIR, name: string, at?: number): string | undefined; /** The modifier chain (`.padding(…).background(…)`) for the element's own styling props. */ layoutModifiers(el: JsxElementIR): string; /** An event handler as a closure body, at `at` (default: this context's indentation). */ action(handler: ExprIR, at?: number): string; /** The initializer of the module-level `const` named `name`, or `undefined`. */ constExpr(name: string): ExprIR | undefined; /** * The compile-time colour-mode scope enclosing the element, as the value its * owner stored — or `undefined` outside any scope. READ-ONLY: the scope is * entered and left by provider element emitters * handling and by any plugin-declared scope provider (`CompilerPlugin.scopes`; * saved and restored in `finally`, so providers nest and a sibling inherits nothing). The facade does not know * the value's type; the plugin that reads it names it (`colorScope()`). */ colorScope(): T | undefined; /** The ext declarations of `(plugin, type)` in the component being emitted. */ decls(plugin: string, type: string): readonly ExtDecl[]; /** * Plugin memory that lives for ONE component (a fresh bag per component, and * per file): `init` runs the first time `key` is read. Namespace the key with * your plugin name — the bag is shared by every plugin in the component. */ state(key: string, init: () => T): T; /** * An opaque token to embed in emitted text when the value is only known after * the component body has been emitted. It is replaced once the body is done; * `fallback` is used when nothing resolved it, and without one an unresolved * token is an ERROR naming `key` (a placeholder must never ship). Namespace * the key with your plugin name. */ deferred(key: string, fallback?: string): string; /** Supply the text for `key`; callable from any emit code that learns it later. */ resolveDeferred(key: string, value: string): void; /** The component being emitted: its name, props parameter, value constants. */ component(): ComponentInfo; /** Whether `name` is a function declared in the file. */ isFunctionName(name: string): boolean; /** One JSX child, emitted through the full dispatcher at `at` (default: this context's indentation). */ child(child: ChildIR, at?: number): string; /** * The element emitted as the compiler's generic component call (`Name(attr: …) { children }`), WITHOUT consulting * any lowering — what an element lowering falls back to when it declines a shape it cannot lower. `emit` would * re-enter the dispatcher and claim the same tag again. */ generic(el: JsxElementIR, at?: number): string; /** The target's spelling of `type`. */ typeText(type: TypeIR, options?: { synthesize?: boolean | undefined; }): string; /** * The target type name a typed container's ELEMENT spells to: a declared struct, the struct synthesized for an * inline object, or the scalar's own type — what a generic container (`PyreonTableState`) is instantiated * with. Unlike {@link EmitContext.typeText} it resolves against the component being emitted, so an element whose * struct the component itself synthesized names that struct. */ rowType(element: TypeIR): string; /** The fields of a container element: an inline object's own, or the declared / synthesized struct a type reference names. */ rowFields(element: TypeIR): readonly { name: string; type: TypeIR; }[]; /** The type the emitter infers for `e` in the active component. */ inferType(e: ExprIR): TypeIR; /** The file's struct registry (declared and synthesised structs). */ readonly structs: StructRegistry; /** Report a limitation unless the exact message was already reported. */ warnOnce(message: string): void; /** The WebView plumbing (see {@link WebViewFacade}). */ readonly webView: WebViewFacade; /** * Plugin memory that lives for ONE FILE: `init` runs the first time `key` is * read, and the value is shared by every component of the file and by * `prepareEmit`. Namespace the key with your plugin name. */ fileState(key: string, init: () => T): T; /** Like {@link EmitContext.layoutModifiers}, for an element whose `handled` props the caller consumed itself. */ layoutModifiersFor(el: JsxElementIR, handled: ReadonlySet): string; /** * A statement list (a callback body a recognizer carried in its payload) as target statements, one * string each. `locals` names parameters whose types the body's inference should know (`(ev) => …` * over a typed stream item); the Swift emitter seeds them (and the body's own `let`s), the Kotlin * emitter seeds the same callback locals and restores them on return or throw. */ statements(stmts: readonly StatementIR[], indent: number, locals?: ReadonlyMap, options?: StatementEmitOptions): string[]; } /** * The context a Swift element lowering receives: the shared facade plus the * members only the Swift emitter has state for. A member moves up to * {@link EmitContext} when the Kotlin emitter supplies it too (the string / * layout / action / const / colour-scope members did when the Kotlin chart * hosts moved); what is left here has no Compose analogue. */ interface SwiftEmitContext extends EmitContext { /** The name of the module-level function `handler` refers to, or `undefined` when it is anything else. */ handlerName(handler: ExprIR): string | undefined; /** `expr` with the component's value-shaped `const`s (and their initializers, transitively) substituted in. */ inlineConsts(e: ExprIR): ExprIR; /** Tell the emitter the component reads SwiftUI's colour scheme, so it injects `@Environment(\.colorScheme) pyreonColorScheme`. */ markColorSchemeUsed(): void; /** The component's `@State` declaration list (see {@link HostStateSlot}). */ readonly hostState: HostStateSlot; } /** * The context a Kotlin element lowering receives: the shared facade plus the * members only the Kotlin emitter has state for. */ interface KotlinEmitContext extends EmitContext { /** * An argument to a Kotlin API whose parameter is `Int` (a subscript, `take`, * a Compose parameter). TS integers are `Long` on Kotlin, so the value * narrows at exactly the call that needs it; a literal is emitted bare. */ intArg(e: ExprIR, at?: number): string; } //#endregion //#region src/theme-native.d.ts type AnyNode = any; /** A resolved, static theme vocabulary the native frontends resolve against. */ interface ThemeTable { color: Record; spacing: Record; radius: Record; fontSize: Record; fontWeight: Record; } declare const DEFAULT_THEME: ThemeTable; /** * Resolve a theme-token reference to a connector-parseable value, or null. * Accepts the value expression directly (`t.color.primary`) OR an arrow whose * body is the member chain (`(t) => t.color.primary`, `(p) => p.theme.color.primary`). * A color group → a #hex string; a spacing / radius group → a number. Resolves * against `theme` (the app theme merged over defaults). */ declare function resolveThemeToken(node: AnyNode | undefined, theme?: ThemeTable): string | number | null; //#endregion //#region src/module-items.d.ts /** What a top-level recognizer (or `ModuleParseContext.addItem`) returns. The compiler stamps `plugin`. */ interface ExtItemSpec { /** A key of the owning plugin's `items`. */ readonly type: string; /** The binding the item declares (what other code names it by). */ readonly name: string; /** JSON data for the emitter; defaults to `{}`. */ readonly payload?: ExtPayload | undefined; } /** What a module-level recognizer may read of the parser. */ interface ModuleParseContext { /** The file's source text. */ readonly source: string; /** Resolved static theme tokens, shared by target-independent style frontends. */ readonly theme: ThemeTable; /** The module-scope binding of a name; absent names retain standalone snippet syntax. */ binding(name: string): { readonly kind: 'import'; readonly module: string; readonly name: string; } | { readonly kind: 'local'; } | undefined; /** Report a limitation to the author exactly as written. */ report(message: string): void; /** Plugin-owned memory for THIS file (shared with `scanModule`); namespace the key with the plugin name. */ fileState(key: string, init: () => T): T; /** The statically-known string an argument denotes — a literal, or a module-scope `const` holding one — else `null`. */ staticString(node: AstNode | null | undefined): string | null; /** Parse any sub-node to the IR the emitters consume. */ expr(node: AstNode): ExprIR; /** * Build a native function declaration, including typed and defaulted parameters. * @example ctx.functionDeclaration('increment', actionNode) */ functionDeclaration(name: string, node: AstNode): Extract; /** * Infer a seed's native type, including fractional and homogeneous array literals. * @example ctx.initialType(ctx.expr(initializerNode)) */ initialType(initial: ExprIR): TypeIR; /** * Report that `node` (`what`) has no native lowering, `hint` saying how to write it so it does, and * return `null` — the verdict a {@link MethodCallRecognizer} gives for a call it claims but cannot lower. */ unsupported(node: AstNode, what: string, hint: string): null; /** * Report that `prop`'s computed key is only known at runtime, so the entry cannot be read at compile time * (the compiler's own wording). `where` is the prefix, e.g. `toast() options`. */ warnDynamicKey(prop: AstNode, where: string): void; /** The type arguments of a call or `new` node (`new Box(…)`), each parsed to a type; none when there are none. */ typeArgs(node: AstNode): TypeIR[]; /** The source location of `node` as the compiler spells it in its own messages (`file.tsx:3:14`), for a message that names a call. */ loc(node: AstNode): string; /** * Add an item found OUTSIDE a declaration (a schema synthesized from an inline `s.object({ … }).safeParse(x)`). * Appended after every declaration-level item, in the order added. */ addItem(spec: ExtItemSpec): void; } /** * Recognize a top-level node: an item, or `undefined` to DECLINE (the node then falls through the parser's * own chain). The first plugin that returns an item owns the node. */ type TopLevelRecognizer = (node: AstNode, ctx: ModuleParseContext) => ExtItemSpec | undefined; /** The names an item puts in the file's one value/type namespace, and how it follows a rename. */ interface ItemBindings { /** The value bindings the item declares — what a same-named type declaration would collide with. */ names(item: ExtModuleItem): readonly string[]; /** Every other name the item takes in the shared namespace (nested declarations), so a rename never collides with one. */ reserved?(item: ExtModuleItem): readonly string[]; /** * Apply `renames` (old → new, the primary names already decided) to the item, in place. May ADD entries * to `renames` for names that follow a renamed primary (`Book_Author` follows `Book`), choosing only * names absent from `taken` and recording them there; the compiler applies the finished map everywhere * else (identifiers, `useForm({ schema })`, expressions through {@link ExprEmitter.rename}). */ rename(item: ExtModuleItem, renames: Map, taken: Set): void; } /** Per-field validation an item may offer a form that names it (`useForm({ schema: Pet })`). */ interface FieldValidators { /** * What the "no declaration by that name" warning says declares such an item (`zodSchema/valibotSchema/…`), * so the core names no library. Absent: the warning names nothing. */ readonly declaredBy?: string | undefined; /** The fields a form can validate, in declaration order. */ fields(item: ExtModuleItem): readonly string[]; /** The validator body for `field`, as a call expression over the value variable `value` (returns `""` when valid). */ swift(item: ExtModuleItem, field: string, value: string): string; kotlin(item: ExtModuleItem, field: string, value: string): string; } /** A call or member chain rooted at a file-scope item's primary binding. */ interface ModuleReceiverSite { readonly expr: Extract; readonly receiver: ExtModuleItem; } /** * Lower expressions rooted at an item, including a callable binding (`useState().values.x`) * or an instance binding (`state.x()`). A component-local binding shadows the item. */ interface ModuleReceiverLowering { swift?(site: ModuleReceiverSite, ctx: SwiftEmitContext): string | undefined; kotlin?(site: ModuleReceiverSite, ctx: KotlinEmitContext): string | undefined; } /** The type evidence a file-scope item publishes to the compiler's inference passes. */ interface ModuleItemTyping { /** Live function declarations and their own signal/computed scope, refined before return inference. */ scopes?(item: ExtModuleItem): readonly MemberEmitScope[]; /** Mutable field IR, so seed/struct refinement edits the owning item rather than a detached copy. */ fields?(item: ExtModuleItem): readonly { name: string; type: TypeIR; initial: ExprIR; }[]; /** A read/call rooted at the item's primary binding, or `undefined` to decline. */ type?(item: ExtModuleItem, expr: ExprIR, infer: (expr: ExprIR, scope?: MemberEmitScope) => TypeIR): TypeIR | undefined; } /** Renders one item type, and says how it takes part in the core's cross-cutting passes. */ interface ModuleItemEmitter { /** * Where this item emits: after ordinary file bindings and before free helpers (`'bindings'`), after helpers (`'models'`, a legacy slot name), then the * plugin DECLARATIONS a file introduces by name before its schemas (`'declarations'` — a feature's schema struct * and its binding), then every other data declaration (`'data'`, the default). Items of one slot emit in file order. */ readonly after?: 'bindings' | 'models' | 'declarations' | 'data' | undefined; /** * Only an item that used to be a closed core array needs this: the name of the array it hashed in * (`moduleTag`, the hash that names synthesized structs, hashes each lane's payloads where the array stood). * A new plugin has no prior output to preserve and omits it. */ readonly legacyList?: 'models' | 'stores' | 'fieldMetas' | 'zodSchemas' | 'features' | 'styledComponents' | 'rocketstyleComponents' | 'attrsComponents' | undefined; /** Rewrite a JSX tag naming this item through ordinary element IR; undefined declines. */ readonly element?: ((item: ExtModuleItem, element: JsxElementIR, ctx: EmitContext) => JsxElementIR | undefined) | undefined; readonly bindings?: ItemBindings | undefined; readonly fieldValidators?: FieldValidators | undefined; /** Expression chains rooted at this item's primary binding; `undefined` declines. */ readonly receivers?: ModuleReceiverLowering | undefined; /** Field and expression type evidence supplied by the owning library. */ readonly typing?: ModuleItemTyping | undefined; /** The item's declarations, one string each (nested declarations first). */ swift(item: ExtModuleItem, ctx: EmitContext): readonly string[]; kotlin(item: ExtModuleItem, ctx: EmitContext): readonly string[]; } /** The open expression node — see `ExprIR`. */ type ExtExprIR = Extract; /** The call a {@link MethodCallRecognizer} is asked about: `.(…args)`. */ interface MethodCallSite { /** The whole call node. */ readonly node: AstNode; readonly receiver: AstNode; readonly method: string; readonly args: readonly AstNode[]; } /** What a method-call recognizer returns; the compiler stamps `plugin`. `args` are already-parsed expressions. */ interface ExtExprSpec { readonly type: string; readonly payload?: ExtPayload | undefined; readonly args?: readonly ExprIR[] | undefined; } /** * Recognize `.(…)`: an expression, `undefined` to DECLINE, or `null` to CLAIM the call * without lowering it (the recognizer reported why through {@link ModuleParseContext.unsupported}; the parser * substitutes the same empty literal it uses for every unsupported expression). */ type MethodCallRecognizer = (site: MethodCallSite, ctx: ModuleParseContext) => ExtExprSpec | null | undefined; /** The call a {@link CallExprRecognizer} is asked about. */ interface CallExprSite { /** The whole call node. */ readonly node: AstNode; /** The callee as written (`toast`, `toast.success`): the recognizer matches it against what its scan recorded. */ readonly callee: AstNode; readonly args: readonly AstNode[]; /** True for `new Name(…)`: a recognizer that claims a constructor checks it, and one that claims a call ignores a construction. */ readonly construct?: boolean | undefined; } /** * Recognize a call by its callee: an expression, `undefined` to DECLINE, or `null` to CLAIM the call without * lowering it (reported through {@link ModuleParseContext.unsupported}). Called for every call expression once a * plugin registers one, so the first check must be cheap — read the names the plugin's `scanModule` recorded in * `fileState` and return `undefined` when the file holds none. */ type CallExprRecognizer = (site: CallExprSite, ctx: ModuleParseContext) => ExtExprSpec | null | undefined; /** Renders and types one `ext-expr` type. */ interface ExprEmitter { swift(e: ExtExprIR, ctx: SwiftEmitContext): string; kotlin(e: ExtExprIR, ctx: KotlinEmitContext): string; /** How expressions over the node are typed (without it the node is `unknown`). */ readonly typing?: { /** * The node's own type. `infer` types any expression in the active component — a source read, an argument — for a * node whose type follows from its parts (`rx.filter(todos, p)` is an array of `todos`' element). */ type?(e: ExtExprIR, infer: (e: ExprIR) => TypeIR): TypeIR; /** The type of `.`; when present it decides every member read on the node. */ member?(e: ExtExprIR, property: string): TypeIR; /** * Whether a file-scope `const` initialized with this node is typed by `type` for the READS that follow it. * Default true; false when the node's `type` describes how it reads (a map) but not what it is (a class * whose own member surface must be emitted verbatim). */ seedsModuleConst?: boolean; } | undefined; /** * Only an expression that used to be a closed `ExprIR` kind needs this: the object `moduleTag` hashes in * its place. A new plugin omits it. */ legacyHash?(e: ExtExprIR): unknown; /** Apply a value rename (old → new) to the payload, in place. */ rename?(e: ExtExprIR, renames: ReadonlyMap): void; /** * The node is a reduction over a collection: its source, its reducer (an arrow whose second parameter is the element) and its * seed — returned as the SAME nodes the expression holds, since the core widens an integer-valued seed to a Double in place when * the reducer accumulates a fractional value. Without it a plugin reduction keeps the seed it was written with. */ reduce?(e: ExtExprIR): { readonly source: ExprIR; readonly reducer: ExprIR; readonly seed: ExprIR; } | undefined; } /** What a struct refinement may edit and read. */ interface StructRefinementTarget { /** The file's structs; field types may be edited in place. */ readonly structs: StructIR[]; /** Every declaration-level item (inline-synthesized ones are not evidence). */ readonly items: readonly ExtModuleItem[]; /** The decode sites plugins recorded (`ParseContext.recordDecode`): a hook's type argument + the schema its request names. */ readonly decodes: readonly { readonly type: TypeIR; readonly response: { readonly binding: string; readonly array: boolean; } | undefined; }[]; } /** * Edit the file's structs from the module items. Runs after the core's own struct float refinements and * before the inline-object ones, which read the field types it settles. */ type StructRefinement = (target: StructRefinementTarget) => void; /** What {@link ModuleFinish} may read and edit. */ interface ModuleFinishTarget { /** Every item, inline-synthesized ones included, in emit order. The items' payloads may be edited in place. */ readonly items: ExtModuleItem[]; report(message: string): void; fileState(key: string, init: () => T): T; } /** A last pass over the finished item list, run once per file after the parse. */ type ModuleFinish = (target: ModuleFinishTarget) => void; type ItemPlugin = { readonly name: string; readonly topLevel?: TopLevelRecognizer | undefined; readonly items?: Readonly> | undefined; readonly methodCalls?: Readonly> | undefined; readonly callExprs?: CallExprRecognizer | undefined; readonly exprs?: Readonly> | undefined; readonly refineStructs?: StructRefinement | undefined; readonly finishModule?: ModuleFinish | undefined; }; /** One compiler instance's module-level hooks. */ interface ItemRegistry { /** Top-level recognizers in plugin order. */ readonly topLevel: readonly { readonly owner: string; readonly recognize: TopLevelRecognizer; }[]; /** Plugin name → item type → emitter. */ readonly emitters: ReadonlyMap>; emitter(plugin: string, type: string): ModuleItemEmitter | undefined; /** Method name → recognizers in plugin order. A call with no claimant costs one `Map.get`. */ readonly methodCalls: ReadonlyMap; /** Recognizers registered under `'*'` — they see every method call, after the ones keyed by its own name. */ readonly anyMethodCalls: readonly { readonly owner: string; readonly recognize: MethodCallRecognizer; }[]; /** Call-expression recognizers in plugin order. */ readonly callExprs: readonly { readonly owner: string; readonly recognize: CallExprRecognizer; }[]; readonly exprEmitters: ReadonlyMap>; exprEmitter(plugin: string, type: string): ExprEmitter | undefined; readonly structRefinements: readonly { readonly owner: string; readonly refine: StructRefinement; }[]; readonly finishers: readonly { readonly owner: string; readonly finish: ModuleFinish; }[]; } /** * Build the registry from every plugin's module-level hooks, in plugin order. A `(plugin, type)` pair cannot * collide (the plugin name is the namespace) and recognizers are shape tests, not name claims — two plugins * may both see a `safeParse` call, and the first to return an expression owns it — so nothing here conflicts. * * @example * createItemRegistry([{ name: '@acme/toy', topLevel: () => undefined, items: { toy } }]) */ declare function createItemRegistry(plugins: readonly ItemPlugin[]): ItemRegistry; //#endregion //#region src/module-scan.d.ts /** What a scanner may read and record while the file's top level is walked. */ interface ModuleScan { /** The whole program node. */ readonly program: AstNode; /** The program's top-level statements. */ readonly body: readonly AstNode[]; /** The file's source text (for messages that quote a span). */ readonly source: string; /** Whether this identifier reference resolves to the named value import, accounting for lexical shadows. */ isImportedReference(node: AstNode, module: string, imported: string): boolean; /** The statically-known string an argument denotes — a literal, or a module-scope `const` holding one — else `null`. */ staticString(node: AstNode | null | undefined): string | null; /** A named import owned by a constant provider, including unresolved vocabulary entries. */ constant(node: AstNode): { readonly module: string; readonly name: string; readonly value: string | undefined; } | undefined; /** Plugin-owned memory for THIS file. Namespace the key with the plugin name; the core never reads it. */ fileState(key: string, init: () => T): T; /** Make the core skip every top-level node for which `skip` is true (a declaration that is metadata only). */ skipTopLevel(skip: (node: AstNode) => boolean): void; /** Mark `name` imported from `module` (`'*'`: from any module) as consumed by lowering, so it draws no "has NO native lowering" warning. */ lowered(module: string, name: string): void; /** Register a file-local factory whose identifier bindings substitute an expression without emitting a declaration. */ aliasFactory(name: string, alias: ExprIR, destructureDiagnostic?: string): void; /** Report a limitation to the author exactly as written. */ report(message: string): void; } /** A per-file pre-pass; runs once per compile, in plugin order. */ type ModuleScanner = (scan: ModuleScan) => void; /** What an element rewrite may ask of the parser. */ interface JsxRewriteContext { /** Plugin-owned memory for THIS file (shared with `scanModule`); namespace the key with the plugin name. */ fileState(key: string, init: () => T): T; /** * Ask for declarations on the component being parsed: `head` ahead of its own declarations, `tail` after them. * Requested once per `key` however many elements ask, and applied when the component is finished (a request made * while parsing something that turns out not to be a component is applied to the next one, as it always was). */ requestComponentDecls(key: string, decls: { readonly head?: readonly DeclIR[]; readonly tail?: readonly DeclIR[]; }): void; } /** * Rewrite a JSX element the parser just built — for a tag that names a LOCAL binding the plugin recorded when it scanned the * file (`const Box = kinetic('div').preset('fade')`), which no import guard can claim. Returns the element that replaces * it, or `undefined` to leave it. Called for every element once a plugin registers one, so the first check must be cheap. */ type JsxElementRewrite = (el: JsxElementIR, ctx: JsxRewriteContext) => JsxElementIR | undefined; /** A call of a plugin-known binding, lowered to a concrete request. */ interface ResolvedRequest { /** The URL as a compile-time constant (with `:name` placeholders when `urlExpr` is set). */ readonly url: string; /** Set when a path parameter is a RUNTIME value: a `template` the emit renders as native string interpolation. */ readonly urlExpr?: ExprIR | undefined; readonly method: string; readonly headers?: Record | undefined; readonly body?: string | undefined; /** The same-module schema binding the request's `response` names (evidence for the decode type's `Int`/`Double` fields). */ readonly response?: { readonly binding: string; readonly array: boolean; } | undefined; } /** What the CALLER can honour. */ interface RequestOptions { /** The caller re-runs when a path parameter changes (a keyed query), so a runtime value is honourable. */ readonly allowRuntimeParams: boolean; /** The caller consumes the RAW body as a stream. */ readonly streaming: boolean; } interface RequestSource { /** True when `name` is a binding this source resolves. */ has(name: string, ctx: ParseContext): boolean; /** The request for a call of `name` with `arg` as its first argument, or `null` after reporting why it stays web. */ resolve(name: string, arg: AstNode | undefined, options: RequestOptions, ctx: ParseContext): ResolvedRequest | null; } interface ScanRegistry { readonly constants: ReadonlyMap string | undefined>; readonly scanners: readonly { readonly owner: string; readonly scan: ModuleScanner; }[]; /** Element rewrites in plugin order. */ readonly elementRewriters: readonly { readonly owner: string; readonly rewrite: JsxElementRewrite; }[]; readonly sources: readonly { readonly owner: string; readonly source: RequestSource; }[]; /** Hooks whose result may be destructured (`const { data } = useQuery(…)`). */ readonly destructureCalls: ReadonlySet; /** Calls that lower only inside a component body (a file-scope declaration of one is reported as misplaced). */ readonly componentOnlyCalls: ReadonlySet; } //#endregion //#region src/call-lowering.d.ts /** The call a recognizer is asked about. */ interface CallSite { /** The hook / function name (after binding resolution, so an alias already reads as the canonical name). */ readonly callee: string; /** How many arguments the author passed. */ readonly argCount: number; /** True for `new Name(…)` — a recognizer that claims a constructor checks it. */ readonly construct?: boolean | undefined; } /** * The parser facade a {@link CallRecognizer} reads through. A plugin must not * import the parser (the boundary test enforces it), so this is everything it * can ask — each member delegates to an existing parse helper. */ interface ParseContext { /** The binding the author wrote: `chart` in `const chart = createChartHandle()`. */ readonly declName: string; /** Object pattern supplied to a pattern-position recognizer. */ readonly pattern?: AstNode | undefined; /** Parse a callback with the compiler's parameter/default/body builder. * @example ctx.functionDeclaration('action', ctx.args[0]!) */ functionDeclaration(name: string, node: AstNode): Extract; /** Initial expression type before component inference is available. * @example ctx.initialType(ctx.expr(ctx.args[0]!)) */ initialType(expression: ExprIR): TypeIR; /** Argument `index` when it is a string LITERAL, else `undefined` (a name, a template, a call, absent). */ stringLiteralArg(index: number): string | undefined; /** Report a limitation to the author, attributed to the declaration (the message is prefixed `Declaration :`). */ warn(message: string): void; /** Report a limitation to the author exactly as written — for a recognizer whose messages already name the declaration. */ report(message: string): void; /** * The call's arguments exactly as written (ESTree nodes). A recognizer that * reads a literal config object walks these; {@link ParseContext.expr} * parses any sub-node the emitter should receive as an `ExprIR`. */ readonly args: readonly AstNode[]; /** The first generic type argument (`createFlow(…)`) parsed to a type; `{ kind: 'unknown' }` when none was written. */ typeArg(): TypeIR; /** Parse an AST node to the IR expression the emitters consume. */ expr(node: AstNode): ExprIR; /** * `node` with an identifier chain resolved through the file's static * initializers (`const nodes = [...]` → the array literal), else `node`. */ resolveStatic(node: AstNode | undefined): AstNode | undefined; /** `node` with parentheses and TypeScript-only layers (`as`, `satisfies`, `!`) removed. */ unwrap(node: AstNode | undefined): AstNode | undefined; /** An object property's static key (`a`, `'a'`, `` `a` ``), or `undefined` for a computed one. */ propKey(prop: AstNode | undefined): string | undefined; /** True for a computed key that is not a static string (`{ [kind]: … }`). */ hasDynamicKey(prop: AstNode | undefined): boolean; /** The source text of a dynamic key, bracketed, for a warning (`[kind]`). */ dynamicKeyText(prop: AstNode): string; /** * Report that `prop`'s computed key is only known at runtime, so the entry cannot be read at compile * time (the compiler's own wording, so every plugin names the limit the same way). `where` is the * prefix, e.g. `createMachine declaration \`m\`: config`. */ warnDynamicKey(prop: AstNode, where: string): void; /** The statically-known string an argument denotes — a literal, or a module-scope `const` holding one — else `null`. */ staticString(node: AstNode | null | undefined): string | null; /** The statements of a function body (`{ … }`) parsed to IR, for a recognizer that carries a callback. */ statements(block: AstNode): StatementIR[]; /** Parse a callback through the same function builder as module and component helpers. */ functionDeclaration(name: string, node: AstNode): Extract; /** The first generic type argument of ANOTHER call node (`openEventStream(…)`), `{ kind: 'unknown' }` when none was written. */ typeArgOf(call: AstNode): TypeIR; /** Plugin-owned memory for THIS file (see {@link ModuleScan.fileState}); namespace the key with the plugin name. */ fileState(key: string, init: () => T): T; /** Requests plugins can resolve from a call of a binding they recorded (see `CompilerPlugin.requestSources`). */ readonly requests: { has(name: string): boolean; resolve(name: string, arg: AstNode | undefined, options: RequestOptions): ResolvedRequest | null; }; /** * Record that `type` is the decode type of a request whose `response` names a same-module schema, * so the schema's number fields can refine the type's `Int`/`Double` fields once the structs exist. */ recordDecode(type: TypeIR, response: ResolvedRequest['response']): void; } /** An ESTree node as the parser produced it. A plugin reads it structurally. */ type AstNode = { readonly type: string; readonly [key: string]: unknown; }; /** * What a recognizer returns. The compiler stamps the owning `plugin` and the * binding `name` on it, so a plugin cannot mis-attribute a declaration or * claim another plugin's `type`. */ interface ExtDeclSpec { /** A key of the owning plugin's `decls`. */ readonly type: string; /** JSON data for the emitter; defaults to `{}`. */ readonly payload?: ExtPayload | undefined; } /** * A call that is a plain SIGNAL: the core builds the `signal` declaration (reads, writes, `.update`, type inference and * struct synthesis are all its own), and the plugin only says which argument holds the initial value and whether the * signal outlives the process. See `signal-persistence.ts`. */ interface SignalSpec { /** The call argument holding the initial value; absent, the initial is `0` exactly as for `signal()`. */ readonly initial?: AstNode | undefined; /** * Persist the signal across launches under this compile-time key. Rendered by the loaded plugin's * `persistence`; omit for a signal that lives and dies with the process (a session or memory store). */ readonly persistKey?: string | undefined; } /** A recognizer's verdict for a call that is a plain signal (see {@link SignalSpec}). */ interface SignalDeclSpec { readonly signal: SignalSpec; } /** * A recognizer's verdict for a call that is a plain COMPUTED: the core declares it (a `computed` read like any other — no * parentheses, typed from the expression) around the plugin's own expression, which its `exprs` emitter renders and types. */ interface ComputedDeclSpec { readonly computed: ExtExprSpec; } /** A setup binding whose reads substitute a plugin-supplied expression without emitting a declaration. */ interface AliasDeclSpec { readonly alias: ExprIR; } /** Every verdict a declaration recognizer may give, besides declining (`undefined`) or claiming without declaring (`null`). */ type DeclVerdict = ExtDeclSpec | SignalDeclSpec | ComputedDeclSpec | AliasDeclSpec; /** * Returns the declaration, `undefined` to DECLINE (the parser falls through to the rest of its chain, as if * the plugin were absent), or `null` to CLAIM the call without declaring anything: the recognizer reported why * the call cannot lower, and the binding must not fall through to a generic emit that would reference a symbol * neither target has. */ type CallRecognizer = (call: CallSite, ctx: ParseContext) => DeclVerdict | undefined | null; /** The call a {@link DeclCallRecognizer} is asked about: the right-hand side of a `const x = ` declaration. */ interface DeclCallSite { /** The callee as written (`rx.filter`, `keep`): the recognizer matches it against what its scan recorded. */ readonly callee: AstNode; readonly args: readonly AstNode[]; } /** * Recognize a declaration by the SHAPE of its callee rather than a hook name — for a call whose callee is whatever local name * the file imported it as (`const active = rx.filter(todos, p)`, `const b = keep(todos, p)`), which no registry can key by * name without claiming every `filter` in the app. Verdicts as {@link CallRecognizer}; `undefined` declines and the parser * continues down its chain, `null` claims the declaration without declaring anything. Called for every call declaration once a * plugin registers one, so the first check must be cheap. */ type DeclCallRecognizer = (site: DeclCallSite, ctx: ParseContext) => DeclVerdict | undefined | null; /** A constructor used in a component declaration, with its complete expression node. */ interface DeclConstructSite extends DeclCallSite { readonly node: AstNode; } /** * Opt in to recognizing `const x = new PackageClass(...)` by callee shape. * Constructor sites never reach existing `declCalls` recognizers. Verdicts and * declaration emission follow the same contract as {@link DeclCallRecognizer}. */ type DeclConstructRecognizer = (site: DeclConstructSite, ctx: ParseContext) => DeclVerdict | undefined | null; /** Renders one declaration type on each target. */ /** * What a declaration contributes to its component's lifecycle. Both are * optional; a declaration with neither is pure state. */ interface DeclLifecycle { /** * Swift attaches a mount-time modifier (`.task`) to its host view, and * SwiftUI ties that task to the host's IDENTITY. A body that is a transparent * conditional re-identifies on every state flip and the task restarts forever, * so a component carrying such a declaration wraps its body in a concrete * stable container. Set it when the declaration's emit appends a mount-time * modifier. */ readonly stableHost?: boolean | undefined; /** * Emit this declaration's lines AFTER the compiler's own lifecycle modifiers, ordered by this * number (then by declaration order) across every plugin. A declaration without it is emitted * in declaration order before them. It exists so a moved lifecycle keeps the position it had. */ readonly tailOrder?: number | undefined; /** * Emit this declaration's lines where the compiler wires a state container to the component's own inputs, * ordered by this number (then by declaration order): on SwiftUI after the hotkey modifiers and before the * platform-service lifecycle, on Compose after the form wiring and before the timers. A container whose source * and sinks are closures over the component's own state binds them there, because a property initializer cannot * capture `self`. A declaration with neither `midOrder` nor `tailOrder` is emitted in declaration order, first. */ readonly midOrder?: number | undefined; /** Before component timers/mount hooks, after declarations are available; ordered across plugins. */ readonly earlyOrder?: number | undefined; /** Swift modifier lines (`.onDisappear { x.dispose() }`) appended after the component's view body. */ swift?(decl: ExtDecl, ctx: EmitContext): readonly string[]; /** Compose effect lines (`DisposableEffect(x) { … }`) appended to the component body, after mount effects. */ kotlin?(decl: ExtDecl, ctx: EmitContext): readonly string[]; } /** * What the compiler reads off a declaration's type to INFER an expression's type. * Without it a member read on a plugin's container is `unknown`, which the emitters * treat conservatively (no optional unwrapping, no numeric coercion). */ interface DeclTyping { /** The type of the zero-argument CALL read `.()` (the web's signal-read shape), or `undefined`. */ callRead?(decl: ExtDecl, property: string): TypeIR | undefined; /** * The type of the PROPERTY read `.` (the native shape), or `undefined`. A member that may be absent is * returned as a nullable union — which is what makes both emitters wrap its interpolation and lower a truthiness test on it * to a nil test. */ member?(decl: ExtDecl, property: string): TypeIR | undefined; /** * The type a METHOD call on the container returns (`secrets.read('k')`, `db.get(c, id)`), or `undefined`. A method whose * runtime return is optional is returned as a nullable union, so a local seeded from it classifies for the optional-condition * lowering (`if (token) { … }`) instead of emitting a bare optional as a condition. */ methodReturn?(decl: ExtDecl, method: string): TypeIR | undefined; } /** The conditions `` / `` OR over, as target text. */ interface AsyncState { /** True while the declaration's request is pending (`q.isPending`). */ readonly pending: string; /** True when it failed (`q.error != nil`). */ readonly error: string; } /** * What a declaration contributes to its component's generated SwiftUI `init()`. A `@State` property initializer cannot * reference another property (a synced signal's initializer names the doc), so a container that must be built from * its siblings is declared TYPED with no initializer and seeded here. The compiler writes the `init(…)` header (the * component's props, as the memberwise init would take them) and their assignments, then every contribution in * `order` (then declaration order), then the closing brace. Compose has no equivalent: its `remember {}` blocks run * sequentially, so a declaration can name an earlier one directly. */ interface DeclSwiftInit { /** Where among the plugin declarations' init lines this one lands (lower first): a doc before the signals that name it. */ readonly order: number; /** * Why the optional-slot initializers cannot coexist with the generated `init()` — the clause the "its optional render * props are emitted as required" warning gives (`its synced state already needs a generated init() that seeds it, …`). */ readonly optionalSlotReason: string; /** The init body lines for `decl` (unindented — the compiler indents them). */ lines(decl: ExtDecl, ctx: EmitContext): readonly string[]; } /** A container-owned expression used as a native field binding. */ interface DeclValueBinding { swift(value: ExprIR, decl: ExtDecl, ctx: EmitContext): string | undefined; kotlin(value: ExprIR, decl: ExtDecl, ctx: EmitContext): { readonly value: string; readonly onChange: string; } | undefined; } interface DeclEmitter { /** Wrap the component root once for this declaration type; next emits the previous wrapper at the requested indentation. * @example root: { kotlin: (_decls, ctx, next) => next(ctx.indent) } */ readonly root?: { readonly swift?: (decls: readonly ExtDecl[], ctx: EmitContext, next: (indent: number) => string) => string; readonly kotlin?: (decls: readonly ExtDecl[], ctx: EmitContext, next: (indent: number) => string) => string; } | undefined; /** A declaration that contributes only lifecycle statements has no stored-property text. */ readonly lifecycleOnly?: boolean | undefined; /** Shared environment reads used by canonical style and provider emission. */ readonly usesColorScheme?: boolean | undefined; readonly usesSizeClass?: boolean | undefined; /** Omit the synthetic binding from a previously nameless declaration's legacy hash. */ readonly legacyName?: boolean | undefined; /** Rename module-value links in this declaration's payload when the file's value/type namespace is separated. */ rename?(decl: ExtDecl, renames: ReadonlyMap): void; /** A field value rooted at this declaration. Return undefined to keep the normal controlled-field path. */ readonly valueBinding?: DeclValueBinding | undefined; /** Describe a For row over this container's source expression. The core supplies the plugin and row name. */ iteration?(source: ExprIR, decl: ExtDecl): ExtDeclSpec | undefined; /** * The binding is CALLABLE (`q()` through Swift's `callAsFunction` / Kotlin's `operator invoke`): a zero-argument call * of it keeps its parentheses and a bare reference as an event handler is called, where an unknown identifier's * zero-argument call reads as a property (`count()` → `count`). */ readonly callable?: boolean | undefined; /** * The declaration reads the active router (a search parameter, a path): on SwiftUI the View needs the router in * its environment (`@Environment(\.pyreonRouter)`). Compose reads `LocalPyreonRouter.current` directly and needs * nothing. */ readonly usesRouter?: boolean | undefined; /** Lifecycle contributions of this declaration type. */ readonly lifecycle?: DeclLifecycle | undefined; /** Lines this declaration seeds in the component's generated SwiftUI `init()` (see {@link DeclSwiftInit}). */ readonly swiftInit?: DeclSwiftInit | undefined; /** How expressions over this declaration's container are typed. */ readonly typing?: DeclTyping | undefined; /** * Marks the declaration as an ASYNC SOURCE: a component's `` shows its fallback * while ANY source is pending, and `` while ANY has failed. Read in declaration * order, after the core's own sources. */ readonly asyncState?: { swift(decl: ExtDecl, ctx: EmitContext): AsyncState; kotlin(decl: ExtDecl, ctx: EmitContext): AsyncState; } | undefined; /** One declaration line (or lines, joined with a newline). */ swift(decl: ExtDecl, ctx: EmitContext): string; /** One line, or several (joined with the same newline-and-indent a built-in multi-line declaration uses). */ kotlin(decl: ExtDecl, ctx: EmitContext): string | readonly string[]; /** * Only the compiler's own built-ins need this: the `kind` the declaration was * called before it became an `ext` one. `moduleTag` (the hash that names * synthesized structs) hashes it as `{ kind: legacyKind, name, ...payload }`, * which keeps emitted names byte-identical to before the move. A new plugin * has no prior output to preserve and omits it. */ readonly legacyKind?: string | undefined; } /** * A call EXPRESSION a plugin claims: `.(…)` where `` * is a binding declared by one of THIS plugin's `ext` declarations * (`chart.dispatch({ … })` for `const chart = createChartHandle()`). */ interface MemberCallSite { /** The declaration the receiver names — always one of the claiming plugin's own. */ readonly receiver: ExtDecl; /** The method name (the key it was registered under). */ readonly method: string; readonly args: readonly ExprIR[]; } /** * How a plugin lowers its receiver's member calls. Each target returns the * expression text, or `undefined` to DECLINE (the call then continues down the * generic path exactly as if the plugin were absent). */ interface MemberCallLowering { swift(call: MemberCallSite, ctx: EmitContext): string | undefined; kotlin(call: MemberCallSite, ctx: EmitContext): string | undefined; } interface RegisteredCall { readonly recognizer: CallRecognizer; /** The plugin that claimed the hook name. */ readonly owner: string; /** Import specifiers the owner serves (`CompilerPlugin.modules`), when it declared any. */ readonly modules?: readonly string[] | undefined; } /** One compiler instance's call recognizers and declaration emitters. */ interface CallRegistry { /** Hook name → recognizer + owner. */ readonly intrinsicCalls: ReadonlyMap; readonly calls: ReadonlyMap; readonly statementCalls: ReadonlyMap; readonly patternCalls: ReadonlyMap; /** Every claimed hook name. */ readonly names: ReadonlySet; /** Declaration recognizers keyed by callee shape, in plugin order. */ readonly declCalls: readonly { readonly owner: string; readonly recognize: DeclCallRecognizer; }[]; /** Constructor recognizers, explicitly opted in and isolated from call-only hooks. */ readonly declConstructs: readonly { readonly owner: string; readonly recognize: DeclConstructRecognizer; }[]; /** Callee name → the plugin that declared it `tier2Calls` (a call it ships no lowering for; see `CompilerPlugin.tier2Calls`). */ readonly tier2Calls: ReadonlyMap; /** Plugin name → declaration type → emitter. */ readonly emitters: ReadonlyMap>; /** The emitter for `(plugin, type)`, or `undefined`. */ emitter(plugin: string, type: string): DeclEmitter | undefined; /** Method name → owning plugin → member-call lowering. Looked up by method name first, so a call with no claimant costs one `Map.get`. */ readonly memberCalls: ReadonlyMap>; } type CallPlugin = { readonly name: string; readonly modules?: readonly string[] | undefined; readonly intrinsicCalls?: Readonly> | undefined; readonly calls?: Readonly> | undefined; readonly statementCalls?: Readonly> | undefined; readonly patternCalls?: Readonly> | undefined; readonly declCalls?: DeclCallRecognizer | undefined; readonly declConstructs?: DeclConstructRecognizer | undefined; readonly tier2Calls?: readonly string[] | undefined; readonly decls?: Readonly> | undefined; readonly memberCalls?: Readonly> | undefined; }; /** * Build the registry from every plugin's `calls` and `decls`, in plugin order. * Throws when a hook name is claimed by two plugins (the winner would depend on * plugin order, which the app cannot see) and names both owners. A `(plugin, * type)` pair cannot collide: the plugin NAME is the namespace, and a duplicate * plugin name is already a load-time error. * * @example * createCallRegistry([{ name: '@acme/toy', calls: { createToy: () => ({ type: 'toy' }) }, decls: { toy } }]) */ declare function createCallRegistry(plugins: readonly CallPlugin[]): CallRegistry; //#endregion //#region src/element-lowering.d.ts /** What a retag may do besides returning the new element: report a warning against the tag the author wrote. */ interface RetagContext { warn(message: string): void; } interface ElementLowering { /** Package root the tags must be imported from, e.g. `@pyreon/coolgrid`. */ readonly module: string; /** Tag names (the imported symbol, which must equal the local JSX tag) this lowering claims. */ readonly tags: readonly string[]; /** * Rewrite the element to another element, which re-enters the emitter's * dispatcher. Return `undefined` to decline (the element then goes to * `emit`). The result must not claim itself again (no `tag` loop). */ retag?(el: JsxElementIR, ctx: RetagContext): JsxElementIR | undefined; /** Emit target code. A target with no function here falls through to the generic path. */ readonly emit?: { swift?(el: JsxElementIR, ctx: SwiftEmitContext): string; kotlin?(el: JsxElementIR, ctx: KotlinEmitContext): string; }; /** * The tags may be the base of `styled()` / `rocketstyle()` / `attrs()` (they * lower to a canonical primitive, so the style connector applies unchanged). */ readonly styleBase?: boolean; /** * The tags are also claimed under an ALIAS: `import { FlowWebView as Hosted }` * lowers `` the same as ``. Off by default — a renamed * import of a layout primitive is usually the author's own component. */ readonly aliasable?: boolean; } /** * The guard the emitters pass: is `tag` eligible to be claimed for `module`? * `expectedImport` is the symbol the tag must have been imported as (default: * the tag itself); it differs from `tag` only for an aliased import. */ type ElementClaimGuard = (tag: string, module: string, expectedImport?: string) => boolean; interface RegisteredElementLowering { readonly lowering: ElementLowering; /** The plugin that declared it. */ readonly owner: string; } /** One compiler instance's element lowerings, with the lookups the emitters need. */ interface ElementRegistry { readonly entries: readonly RegisteredElementLowering[]; /** * The lowering that claims `tag` when `guard` accepts `(tag, module)`, or * `undefined`. `importedAs` is the symbol `tag` was imported as, when it is an * alias; only an `aliasable` lowering claims through it. */ find(tag: string, guard: ElementClaimGuard, importedAs?: string): ElementLowering | undefined; /** True when some lowering claims `name` (the parser then records where it was imported from). */ hasTag(name: string): boolean; /** True when `name` is a tag a lowering marks usable as a style base. */ isStyleBase(name: string): boolean; } /** * Build a registry from every plugin's `elements`, in plugin order. Throws when * a `(module, tag)` pair is claimed twice — two lowerings for one pair would * make the winner depend on plugin order, which the app cannot see — and names * both owners. * * @example * createElementRegistry([{ name: '@acme/grid', elements: [{ module: '@acme/grid', tags: ['Row'] }] }]) */ declare function createElementRegistry(plugins: readonly { readonly name: string; readonly elements?: readonly ElementLowering[] | undefined; }[]): ElementRegistry; //#endregion //#region src/expr-lowering.d.ts type CallExprIR = Extract; type MemberExprIR = Extract; /** A call or a member read whose chain is rooted at a binding one of the plugin's declarations created. */ type ReceiverSite = { readonly kind: 'call'; readonly expr: CallExprIR; readonly receiver: ExtDecl; } | { readonly kind: 'member'; readonly expr: MemberExprIR; readonly receiver: ExtDecl; }; /** `. ` where the path is rooted at a plugin declaration. */ interface ReceiverAssignSite { readonly target: MemberExprIR; readonly op: string; readonly value: ExprIR; /** The value operand as the emitter already spelled it (emitting it twice would repeat its warnings). */ readonly emitted: string; readonly receiver: ExtDecl; } interface ReceiverTargetLowering { /** The expression text for a call / member read, or `undefined` to decline. */ expr?(site: ReceiverSite, ctx: C): string | undefined; /** The VALUE operand's replacement text, or `undefined` to keep the one the emitter produced. */ assignValue?(site: ReceiverAssignSite, ctx: C): string | undefined; } interface ReceiverLowering { readonly swift?: ReceiverTargetLowering; readonly kotlin?: ReceiverTargetLowering; } /** A plain `name(args)` call. */ interface FunctionSite { readonly name: string; readonly args: readonly ExprIR[]; } interface FunctionLowering { /** * The callee spelling the parser leaves in the IR for a claimed call, when it * must differ from the author's name. The IR is hashed into the names of the * structs a file synthesises, so a library that shipped before functions were * plugin-owned keeps its spelling (`__pyreonFlowComputeLayout`) to keep emitted * names stable. A plugin with no prior output omits it. */ readonly irName?: string | undefined; swift?(site: FunctionSite, ctx: SwiftEmitContext): string | undefined; kotlin?(site: FunctionSite, ctx: KotlinEmitContext): string | undefined; } /** * A bare identifier that names a library constant (`DEFAULT_NODE_WIDTH`). Each * target returns the expression text, or `undefined` to decline (the identifier * then emits as written). */ interface IdentifierLowering { swift?(name: string, ctx: SwiftEmitContext): string | undefined; kotlin?(name: string, ctx: KotlinEmitContext): string | undefined; } /** * A member read the plugin recognises by SHAPE. Each target returns the * expression text, or `undefined` to decline (the read then emits as without the * plugin). */ interface MemberReadLowering { swift?(e: MemberExprIR, ctx: SwiftEmitContext): string | undefined; kotlin?(e: MemberExprIR, ctx: KotlinEmitContext): string | undefined; } /** * A lowercase tag the plugin claims while `applies` holds. `applies` reads the * facade (typically `ctx.component()`), so the claim is as narrow as the * plugin's own context: outside it the tag keeps the core's behaviour. */ /** * A modifier a plugin appends to an element's layout chain from the value of its `ref` attribute — the web * shape a library hands back as a ref callback (`ref={s.containerRef}`, `ref={s.itemRef(key)}`) lowers on native to * a view modifier / Compose `Modifier` extension instead. Each target returns the modifier text (`.foo(state)`), * or `undefined` when the ref is not one of the plugin's (an unrelated `ref` keeps its existing behaviour: ignored). * It is appended LAST, so it wraps the element's own padding / background. */ interface RefModifierLowering { swift?(ref: ExprIR, el: JsxElementIR, ctx: SwiftEmitContext): string | undefined; kotlin?(ref: ExprIR, el: JsxElementIR, ctx: KotlinEmitContext): string | undefined; } interface IntrinsicLowering { readonly tags: readonly string[]; applies(ctx: EmitContext): boolean; readonly emit: { swift?(el: JsxElementIR, ctx: SwiftEmitContext): string | undefined; kotlin?(el: JsxElementIR, ctx: KotlinEmitContext): string | undefined; }; } /** What the emitter knows when a file's emit starts. */ interface EmitPreparationInput { readonly components: readonly ComponentIR[]; /** The initializer of the module-level `const` named `name`, or `undefined`. */ moduleConst(name: string): ExprIR | undefined; } /** What a preparation may contribute: components emitted after the file's own, registered like them. */ interface EmitPreparationResult { readonly components?: readonly ComponentIR[] | undefined; } type EmitPreparation = (input: EmitPreparationInput, ctx: EmitContext) => EmitPreparationResult | void; interface RegisteredFunction { readonly lowering: FunctionLowering; readonly owner: string; readonly modules?: readonly string[] | undefined; } /** One compiler instance's expression hooks. */ interface ExprRegistry { /** Plugin name → declaration type → receiver lowering. */ readonly receivers: ReadonlyMap>; readonly functions: ReadonlyMap; /** IR callee spelling (`FunctionLowering.irName`) → the claimed function name. */ readonly functionsByIrName: ReadonlyMap; readonly memberReads: readonly { readonly lowering: MemberReadLowering; readonly owner: string; }[]; readonly identifiers: ReadonlyMap; readonly intrinsics: readonly { readonly lowering: IntrinsicLowering; readonly owner: string; }[]; /** Every tag some intrinsic lowering names (the parser then records nothing; the emitters short-circuit on it). */ readonly intrinsicTags: ReadonlySet; readonly refModifiers: readonly { readonly lowering: RefModifierLowering; readonly owner: string; }[]; readonly preparations: readonly { readonly owner: string; readonly prepare: EmitPreparation; }[]; /** Sentences plugins append to the "DOM/SVG element has no native lowering" warning, in plugin order. */ readonly intrinsicAdvice: readonly string[]; } //#endregion //#region src/parse-extensions.d.ts /** * What a plugin's {@link ParseRefinement} may edit: the freshly parsed * components and the file's top-level helper functions. Both are owned by the * `parsePyreon` call in flight (never shared between compilations), which is * why this hook may mutate them in place — unlike a `transformIR` pass, which * runs later on a module and, for a third-party plugin, on a clone. */ interface ParseRefinementTarget { readonly components: ComponentIR[]; readonly helperFns: Extract[]; } /** * An IR→IR edit that must land DURING parse, after components are collected and * before helper return types are inferred. */ type ParseRefinement = (target: ParseRefinementTarget) => void; interface RegisteredParseRefinement { readonly owner: string; readonly refine: ParseRefinement; } /** What a props-type resolver may ask the parser while it resolves one annotation. */ interface PropsTypeContext { /** * The struct the parser declared for an inline object type argument * (`NodeProps<{ label: string }>`), when the resolver asked for it to be * lifted (`liftInlineArg`) — the SAME name the plugin's own literals resolve to. */ liftedStruct(inline: TypeIR): string | undefined; } /** * How a library's PROPS TYPE (`NodeComponentProps` — imported, not declared * in the consumer's file) resolves to the object shape a component's * parameters are read from. Without it the parser sees an unresolvable named * type and emits a zero-prop component whose body references unbound fields. */ interface PropsTypeResolver { /** * Declare ONE struct per distinct inline object type argument, named after * the first component that uses it (``), before the * components are parsed — so the resolved props and the plugin's own literals * agree on a type name. */ readonly liftInlineArg?: { readonly suffix: string; } | undefined; /** The props object type for `Name`, or `undefined` to decline (the type then warns as unresolved). */ resolve(type: { readonly name: string; readonly args: readonly TypeIR[]; }, ctx: PropsTypeContext): TypeIR | undefined; } interface RegisteredPropsType { readonly owner: string; readonly resolver: PropsTypeResolver; } //#endregion //#region src/scope-provider.d.ts /** What a provider receives when its element is entered. */ interface ScopeEnterContext { /** Report a limitation to the author. */ warn(message: string): void; /** The scope in force around the element, or `undefined` outside any. */ readonly outer: object | undefined; } interface ScopeProvider { /** Package root the tags must be imported from, e.g. `@pyreon/core`. */ readonly module: string; /** Tag names this provider claims (the imported symbol, which must equal the local JSX tag). */ readonly tags: readonly string[]; /** * The scope the element's children are emitted under. Returning `undefined` * leaves the children with NO scope (an enclosing one is not inherited * implicitly — return `ctx.outer` to keep it). */ enter(el: JsxElementIR, ctx: ScopeEnterContext): object | undefined; /** * The element exists ONLY to provide the scope: the core emits its children * under it, in a transparent wrapper, and nothing else. Leave it off for an * element with its own wrapper emitter (which calls `withColorScope`) or a * canonical provider the core already emits. */ readonly transparent?: boolean | undefined; } interface RegisteredScopeProvider { readonly provider: ScopeProvider; /** The plugin that declared it. */ readonly owner: string; } /** One compiler instance's scope providers. */ interface ScopeRegistry { readonly entries: readonly RegisteredScopeProvider[]; /** The provider that claims `tag` when `guard` accepts `(tag, module)`, or `undefined`. */ find(tag: string, guard: ElementClaimGuard, importedAs?: string): ScopeProvider | undefined; /** True when some provider claims `name` (the parser then records where it was imported from). */ hasTag(name: string): boolean; } //#endregion //#region src/signal-persistence.d.ts /** What the core knows about a persisted signal declaration when it asks the backend to render it. */ interface PersistedSignalSite { /** The binding as the author named it (render it through `ctx.ident`). */ readonly name: string; /** The storage key, baked at compile time (render it through `ctx.stringLiteral`). */ readonly key: string; /** The target spelling of the signal's type (SwiftUI's annotation, Compose's `typeStr`). */ readonly type: string; /** The initial value, already emitted as target text. */ readonly initial: string; /** * The PLATFORM's own persistence handles this type directly (SwiftUI's `@AppStorage` for scalars, enums and * optionals of them; Compose's `rememberSaveable` for Bundle-friendly types). A backend uses the platform * primitive then and its own runtime for everything else (structs, lists, objects). */ readonly nativeType: boolean; /** The type is a list seeded with an EMPTY array literal (Kotlin spells it `listOf()`, since the element type is not inferable). */ readonly emptyList: boolean; } /** What a Kotlin backend returns: a complete declaration, or the `remember`-like wrapper the core's own `mutableStateOf` line uses. */ type KotlinPersistedSignal = { readonly line: string; } | { readonly wrapper: string; }; interface SignalPersistence { /** The complete SwiftUI property declaration (`@AppStorage("k") private var x: T = v`). */ swift(site: PersistedSignalSite, ctx: EmitContext): string; /** * `{ line }` replaces the core's declaration entirely. `{ wrapper }` keeps it (null seeds, empty lists and all) * and swaps only the delegate: `var x by { mutableStateOf(v) }`. */ kotlin(site: PersistedSignalSite, ctx: EmitContext): KotlinPersistedSignal; } interface RegisteredPersistence { readonly owner: string; readonly persistence: SignalPersistence; } //#endregion //#region src/unlowered-modules.d.ts /** * Pyreon modules whose exports have no (or only partial) native lowering, and * the per-module advice the "has NO native lowering" warning names. * * The compiler keeps hand-maintained entries for modules without a plugin * (`UNLOWERED_PYREON_MODULES` in `parse.ts`); a plugin supplies its own through * `CompilerPlugin.unlowered`, merged here into the compiler instance's * registries — a plugin's entry wins over a core entry for the same module. */ interface UnloweredModule { /** What to do instead, named per module — a generic refusal leaves the author guessing. */ readonly advice: string; /** Exports from this module that DO lower and must stay silent. */ readonly supported?: ReadonlySet | undefined; /** * Warn ONLY these exports, leaving everything else silent. * * Required for @pyreon/core and @pyreon/reactivity, where the overwhelming * majority of exports lower (`signal`, `computed`, `effect`, `h`, `Fragment`, * `Show`, `For`, …) and only a handful do not. Listing what is SUPPORTED * there would mean enumerating almost the whole public surface and * false-warning on anything missed — the @pyreon/rx over-generalisation at * much larger scale, in the two most-used packages in the framework. */ readonly unsupported?: ReadonlySet; /** * Exports the emitters DROP with their own named warning at the use site * (a web-only component). The blanket "reproduced verbatim … the native build * fails" line would be false for them, so it is skipped. */ readonly dropped?: ReadonlySet | undefined; } /** What a plugin supplies per module (`CompilerPlugin.unlowered`); plain data, so it survives a JSON round trip. */ interface UnloweredSpec { /** Warn only these exports when the remainder is core syntax. */ readonly unsupported?: readonly string[] | undefined; readonly advice: string; /** Exports that DO lower and must stay silent. */ readonly supported?: readonly string[] | undefined; /** Exports the emitters drop with their own named warning (so the blanket "verbatim" line is skipped for them). */ readonly dropped?: readonly string[] | undefined; } interface RegisteredUnlowered extends UnloweredModule { /** The plugin that supplied it. */ readonly owner: string; } //#endregion //#region src/services.d.ts interface ServiceDescriptor { /** The hook the author calls, e.g. `useShare`. */ readonly hook: string; /** * The decl kind this hook lowered to BEFORE it was a descriptor. A module's * synthesized-struct suffix (`__Obj0_ab12cd`) hashes the parsed IR * (`moduleTag`), so moving a hook onto the generic `service` declaration * would rename every anonymous struct in every file that uses it — output * that is otherwise byte-identical. `moduleTag` hashes a service decl as * `{ kind: legacyKind, name }` so the names hold. Droppable the next time * the golden is deliberately re-baselined. */ readonly legacyKind: string; /** * Swift initialiser expression, placed after `@State private var = `. * Emitted verbatim. */ readonly swift: string; /** * Kotlin declaration lines, emitted in order and joined with `\n `. `{id}` * is replaced by the declaration's Kotlin identifier (every occurrence), so a * descriptor may hoist a composition-local into a sibling val * (`val {id}Ctx = LocalContext.current`) or wire a launcher after the `val`. * A line carries its OWN extra indentation, so a continuation line renders * exactly as the hand-written emit did. */ readonly kotlin: readonly string[]; /** * Members the web reads as ACCESSORS (`copied()`) that the native container * stores as properties: a zero-argument member call of one lowers to the * property read on BOTH targets (Kotlin appends `.value` for members also * listed in `kotlinState`). */ readonly accessorReads?: readonly string[]; /** * The property a BARE zero-argument call of the container reads — web * accessors like `useOnline()` are called (`net()`); natively it is a * property (`net.isOnline`, + `.value` on Kotlin when listed in `kotlinState`). */ readonly callRead?: string; /** * Members that are Compose `MutableState` on Kotlin: a read — member form or * zero-argument call form — appends `.value`. Members NOT listed read bare * (plain getters, methods). Swift's @Observable properties need no rewrite. */ readonly kotlinState?: readonly string[]; /** * A reactive monitor that must be started or the hook ships frozen at its * initial value. `'start-stop'` → Swift `.onAppear { x.start() }` + * `.onDisappear { x.stop() }`; `'start'` → `.onAppear` only. Kotlin has no * emit-side wiring: its descriptor line is the self-installing * `rememberPyreon()` factory. */ readonly lifecycle?: 'start' | 'start-stop'; /** `const { x } = useHook()` destructure aliases onto the container. */ readonly destructure?: true; /** * Members the runtimes declare optional, mapped to their value type — typed * as nullable so BOTH emitters wrap the interpolation and the condition * lowering fires (web renders nothing; native would print `Optional(…)`). */ readonly optionalFields?: Readonly>; } /** Render a descriptor's Kotlin lines for a Kotlin identifier. */ declare function renderKotlinService(s: ServiceDescriptor, id: string): string; //#endregion //#region src/service-registry.d.ts interface RegisteredService { readonly descriptor: ServiceDescriptor; /** The plugin that claimed the hook. */ readonly owner: string; /** Import specifiers the owning plugin serves (`CompilerPlugin.modules`), when it declared any. */ readonly modules?: readonly string[] | undefined; } type ServiceRegistry = ReadonlyMap; type ServicePlugin = Pick; /** A descriptor list as the `services` record a plugin would declare. */ declare function serviceSpecsOf(descriptors: readonly ServiceDescriptor[]): Record; /** * Hook → descriptor + owner, from every plugin's `services` — there is no private * table beside this one. Two owners for one hook is an error: * silently picking one would make the emitted code depend on plugin order, * which the app cannot see. * * @example * const registry = createServiceRegistry([hooksPlugin, { name: '@acme/camera', services: { useShare: … } }]) * // throws: hook "useShare" is claimed by both "@pyreon/hooks" and "@acme/camera" */ declare function createServiceRegistry(plugins: readonly ServicePlugin[]): ServiceRegistry; /** * Tables the parser and emitters read at hot sites, derived ONCE when the * registry is built (never per call). Registry order is preserved (plugin order, then each plugin's own declaration order), * which is the order the Swift lifecycle modifiers emit in. */ interface ServiceTables { /** Every descriptor, in registry order. */ readonly descriptors: readonly ServiceDescriptor[]; readonly byHook: ReadonlyMap; /** Every service hook name. */ readonly hooks: ReadonlySet; /** Hooks whose descriptor declares `destructure`. */ readonly destructureHooks: ReadonlySet; } /** * Order plugins so each follows everything it `requires`. Stable: among the * plugins that are ready, the one that came first in the input runs first, so * a plugin list with no `requires` keeps its order exactly. */ declare function orderPlugins>(plugins: readonly T[]): T[]; interface DiscoveredSelection { /** Discovered plugins that should be loaded, in discovery order. */ readonly kept: T[]; /** Names of built-in plugins a discovered plugin replaced. */ readonly replaced: string[]; } /** * Identity is by NAME. A discovered plugin replaces a same-named `builtIn` * plugin silently (the library now ships the lowering the compiler used to); * an explicit plugin of the same name wins over the discovered one (the app * asked for it); two discovered plugins sharing a name is a real conflict. */ declare function selectDiscovered(builtIn: readonly Pick[], explicit: readonly Pick[], discovered: readonly T[]): DiscoveredSelection; //#endregion //#region src/active-registries.d.ts interface CompilerRegistries { /** Hook → descriptor + owner. */ readonly services: ServiceRegistry; /** Tables derived once from `services` (hook sets, registry-order list). */ readonly serviceTables: ServiceTables; /** `(module, tag)` → element lowering + owner. */ readonly elements: ElementRegistry; /** `(module, tag)` → colour-scope provider + owner. */ readonly scopes: ScopeRegistry; /** Hook name → call recognizer, and `(plugin, type)` → declaration emitter. */ readonly calls: CallRegistry; /** Module → plugin-supplied unlowered-module metadata (advice + the exports that do lower). */ readonly unlowered: ReadonlyMap; /** Runtime-declared type name → owning plugin (resolved as known types by the parser). */ readonly runtimeTypes: ReadonlyMap; /** Plugin parse refinements, in plugin order. */ readonly parseRefinements: readonly RegisteredParseRefinement[]; /** Props type name → resolver (a library's imported props types the parser resolves to object shapes). */ readonly propsTypes: ReadonlyMap; /** Receiver, function, member-read, intrinsic and preparation hooks. */ readonly exprs: ExprRegistry; /** Per-file scanners, request sources and destructurable hooks. */ readonly scan: ScanRegistry; /** The one plugin that renders persisted signals (`CompilerPlugin.persistence`), if any is loaded. */ readonly persistence: RegisteredPersistence | undefined; /** File-scope item recognizers and emitters, method-call recognizers, `ext-expr` emitters, struct refinements and module finishers. */ readonly items: ItemRegistry; /** * Every import specifier a loaded plugin serves: its name (a package-owned * plugin is named after its package) plus `CompilerPlugin.modules`. * The parser compares a `@pyreon/*` import against it to tell a package whose * plugin is simply NOT LOADED (warn: declare the dependency) from one that * lowers in the core. */ readonly loadedModules: ReadonlySet; } //#endregion //#region src/stub-augmentation.d.ts /** * Extra type-gate stub text a library's emit needs. * * The compile gates (`validateSwiftWithStubs`, `validateKotlin`, and their * multi-file twins) compile an emit against hand-written stubs of SwiftUI / * Compose and the Pyreon runtime, because the real SDKs are not available * everywhere. A library whose emit names types those stubs do not declare — a * runtime view, a generated engine — supplies them HERE, per target, from the * emitted `source`; the stub text it returns is appended to the bundle only * for the inputs that need it (return `''` for any other). * * The same rule applies as for the core stubs: mirror the real surface EXACTLY. * A superset stub masks real breakage, a narrower one manufactures it. */ interface StubAugmentation { /** Swift stub text `source` needs beyond the SwiftUI bundle, or `''`. */ swift?(source: string): string; /** Kotlin stub text `source` needs beyond the Compose bundle, or `''`. */ kotlin?(source: string): string; } /** Options every compile gate accepts. */ interface ValidateOptions { /** Library stub augmentations (typically each loaded plugin's `stubs`). */ readonly augment?: readonly StubAugmentation[] | undefined; } //#endregion //#region src/plugin.d.ts /** * @deprecated Legacy API 1 descriptor constant, deliberately frozen at 1. * Old plugins import this value at runtime. Advancing it would make an old * plugin falsely advertise compatibility with a newer IR. Pin a descriptor * to the version it was written against, or use a version-named constant. */ declare const NATIVE_COMPILER_PLUGIN_API_VERSION: 1; /** API 2: package-owned module items replace the closed style definition arrays. Never renumber this constant. */ declare const NATIVE_COMPILER_PLUGIN_API_V2: 2; /** Every plugin `apiVersion` this compiler can load. */ declare const SUPPORTED_PLUGIN_API_VERSIONS: readonly number[]; /** * One service a plugin contributes: a {@link ServiceDescriptor} without its * `hook` (the hook is the key of {@link CompilerPlugin.services}). Derived from * the descriptor type so it follows when the descriptor vocabulary grows. */ type ServiceSpec = Omit & { /** * Only the compiler's own built-in hooks need this (it keeps their emitted * names byte-identical to before they were descriptors). A plugin has no * prior output to preserve, so it is optional and defaults to `'service'`. */ readonly legacyKind?: string | undefined; }; /** Target-neutral module shared by compiler passes and output backends. */ type CompilerModule = ParseResult; type CompilerOptions = Omit & { target: Target; }; interface CompilerContext { /** Infer against the pass's own module, including refined helpers and optional local bindings. * @example ctx.inferType(module, expression, module.components[0]) */ inferType(module: CompilerModule, expression: ExprIR, component?: ComponentIR, locals?: ReadonlyMap): TypeIR; readonly source: string; readonly options: Readonly>; /** Reports a warning attributed to the active plugin or backend. */ warn(message: string): void; /** * Hook name → service descriptor + owning plugin, built once at * `createCompiler` time. The parser and emitters read the same registry * (through the compiler's scoped registries), so a plugin's hook is lowered * on both targets. */ readonly services: ServiceRegistry; } interface CompilerBackend { readonly target: Target; emit(module: CompilerModule, context: CompilerContext): TransformResult; } type CompilerPass = (module: CompilerModule, context: CompilerContext) => CompilerModule | void; interface CompilerPlugin { readonly name: string; readonly apiVersion: typeof NATIVE_COMPILER_PLUGIN_API_V2; /** * Plain service hooks this plugin lowers, keyed by hook name (`useShare`). * Two owners for one hook is a load-time error — the app must pick one. */ readonly services?: Readonly> | undefined; /** * JSX element lowerings this plugin contributes: tags imported from a * package that retag to another element or emit target code through the * `EmitContext` facade. A `(module, tag)` pair claimed by two owners is a * load-time error naming both. */ readonly elements?: readonly ElementLowering[] | undefined; /** * Colour-scope providers this plugin contributes: compile-time scopes entered * by `` / `` (or an element of the * plugin's own) while their children are emitted, read back by the plugin's * own elements through `EmitContext.colorScope()`. A `(module, tag)` pair * claimed by two owners is a load-time error naming both. */ readonly scopes?: readonly ScopeProvider[] | undefined; /** * Type-gate stub text this plugin's emit needs beyond the SwiftUI / Compose * stub bundle (see {@link StubAugmentation}). The compiler never reads it; a * caller of the compile gates passes it as `ValidateOptions.augment`. */ readonly stubs?: StubAugmentation | undefined; /** * Calls this plugin RECOGNIZES, keyed by hook / function name * (`createChartHandle`). A recognizer reads the call through the `ParseContext` * facade and returns the plugin's own declaration (type + JSON payload), or * `undefined` to decline — the parser then continues as if the plugin were * absent. A name is claimed under the same rule as a `services` hook: when it * is imported from `@pyreon/*` or from one of `modules`. Two owners for one * name is a load-time error. Pair it with `decls`. */ /** Component-body calls at statement position; receive the same parser facade as declarations. */ readonly statementCalls?: Readonly> | undefined; /** Calls bound through an object pattern; ParseContext.pattern contains the written binding. */ readonly patternCalls?: Readonly> | undefined; /** Map package exports onto generic core state operations; their IR and target semantics remain in the compiler. */ readonly intrinsicCalls?: Readonly> | undefined; /** Resolve imported compile-time string vocabulary owned by this package. Undefined names are known but unsupported. */ readonly constants?: ((name: string) => string | undefined) | undefined; readonly calls?: Readonly> | undefined; /** * A declaration recognizer keyed by the SHAPE of the callee, not a name (see `DeclCallRecognizer`): `const active = rx.filter(todos, p)` * where `rx` / `filter` are whatever this file imported. Pair it with `exprs` (a `computed` verdict) or `decls`. */ readonly declCalls?: DeclCallRecognizer | undefined; /** * Opt in to constructor declarations (`const cache = new ImportedCache(...)`). * Match the imported callee shape and return package-owned storage through `decls`. * Existing `declCalls` hooks continue receiving call expressions only. */ readonly declConstructs?: DeclConstructRecognizer | undefined; /** * Calls of this package that ship NO native lowering, by callee name (`defineFeature` for a package whose literal form lowers * at file scope but whose component-body form does not). A declaration `const x = (…)` that no recognizer claimed gets * the standing Tier-2 diagnostic naming this plugin — the setup call would otherwise emit as an unresolved reference — and * nothing is emitted. Unlike `calls` it does not CLAIM the name: it is matched by the callee as written, whatever it was * imported from, so another module's same-named function is never mistaken for this package's by the hook-binding pass. */ readonly tier2Calls?: readonly string[] | undefined; /** * How this plugin's declarations render on each target, keyed by the * declaration `type` a `calls` recognizer returns. The emitter receives the * `EmitContext` facade and returns declaration text. */ readonly decls?: Readonly> | undefined; /** * Call EXPRESSIONS this plugin lowers, keyed by method name (`dispatch`): * `.(…)` where `` is a binding one of THIS plugin's * `decls` created. The plugin never sees a call on any other receiver, so two * plugins may both claim `dispatch` — the receiver decides. Each target returns * the expression text, or `undefined` to decline. Requires `decls`. */ readonly memberCalls?: Readonly> | undefined; /** * Calls, member reads and assignments ROOTED at a binding one of this plugin's * `decls` created (`flow.fitView()`, `flow.nodes.set(x)`, `flow.config.zoom = * 2`), keyed by the declaration `type`. Generalises `memberCalls`, which sees * only the one-hop `.(…)` shape. Each target may decline * (`undefined`); the expression then emits as without the plugin. Requires `decls`. */ readonly receivers?: Readonly> | undefined; /** * Plain calls `name(args)` this plugin lowers (`getBezierPath({…})`), keyed by * function name. The name is claimed like a hook — imported from `@pyreon/*` or * one of `modules` — and an aliased import is renamed back to it; a same-named * user function or foreign import is left alone. Two owners for one name is a * load-time error. */ readonly functions?: Readonly> | undefined; /** * Member READS the plugin recognises by shape rather than by root binding * (`MarkerType.Arrow`, `props.edge.data.x`). Called for every member read once * a plugin registers it, so the first check must be cheap; each target may * decline (`undefined`). */ readonly memberReads?: MemberReadLowering | undefined; /** * Bare identifiers that name library constants (`DEFAULT_NODE_WIDTH`), keyed by * name. Two owners for one name is a load-time error. */ readonly identifiers?: Readonly> | undefined; /** * Lowercase DOM tags (`path`, `svg`, `div`) the plugin claims while a predicate * holds — inside its own renderer components. Unlike `elements` they are not * imported from a package, so the claim is the predicate. */ readonly intrinsics?: readonly IntrinsicLowering[] | undefined; /** * A modifier appended to an element's layout chain from the value of its `ref` attribute (see * {@link RefModifierLowering}): how a library's ref callbacks (`ref={s.itemRef(key)}`) lower on native. */ readonly refModifiers?: RefModifierLowering | undefined; /** * A per-file pass each emitter runs after the file's components and module * constants are known and before any component is emitted. It may keep * file-scoped memory (`EmitContext.fileState`) and return extra components, * which are emitted after the file's own and registered like them. */ readonly prepareEmit?: EmitPreparation | undefined; /** * A sentence the "DOM/SVG element has no native lowering" warning appends * (`", or, for … , use …"`) when this plugin is loaded: the route the plugin * offers for markup it cannot lower. Without it the warning carries only the * core's own advice. */ readonly intrinsicAdvice?: string | undefined; /** * Props types the plugin's library exports (`NodeComponentProps`), keyed by * the type's name: how each resolves to the object shape a component's * parameters are read from. Two owners for one name is a load-time error. */ readonly propsTypes?: Readonly> | undefined; /** * Unlowered-module metadata for the package(s) this plugin owns, keyed by * module: the advice the "has NO native lowering" warning names, and the * exports that DO lower and must stay silent. A module supplied by two * plugins is a load-time error; a plugin's entry wins over the compiler's own * hand-maintained one. */ readonly unlowered?: Readonly> | undefined; /** * Import specifiers this plugin serves (`@acme/camera`, matched exactly or as * a `name/` prefix). A hook in `services` is claimed when it is imported from * `@pyreon/*` OR from one of these — so a package-owned plugin's hook lowers * from its own package. A package-owned plugin is also lazily activated from * the `pyreon.native.modules` manifest field, because that decision must be * made WITHOUT loading the plugin. */ readonly modules?: readonly string[] | undefined; /** * Type names the plugin's RUNTIME declares (so a helper typed against one, * `(c: TooltipContent) => string`, resolves on the target instead of being * rejected as an unknown object type). Declaring the type itself in the * emitted file is still the plugin's `prepareIR`. Two plugins declaring one * name is a load-time error naming both. */ readonly runtimeTypes?: readonly string[] | undefined; /** * An IR→IR edit that must run DURING parse — after components and helper * functions are collected, before helper return types are inferred over * their parameters. Use it only for what a later `transformIR` would be too * late for (e.g. widening a helper's parameter to `Double` so the return * type is inferred over it). It receives the live, call-owned IR and * mutates it in place; everything else belongs in `transformIR`. */ readonly refineParse?: ParseRefinement | undefined; /** * A per-file pre-pass over the program's top-level nodes (see {@link ModuleScanner}): record * plugin-owned facts, make the core skip metadata-only declarations, mark imports that lower. */ readonly scanModule?: ModuleScanner | undefined; /** * Resolvers that turn a call of a binding this plugin recorded (`getUser({ params })`) into a * concrete request, read by the core's `useFetch` and by other plugins through * `ParseContext.requests`. The first source whose `has` accepts the name resolves it. */ readonly requestSources?: readonly RequestSource[] | undefined; /** * Recognizes this plugin's FILE-SCOPE declarations (`const Pet = s.object({ … })`): called for each * top-level node the core did not claim; the first plugin to return an item owns the node, `undefined` * declines. Pair it with `items`. See `module-items.ts`. */ readonly topLevel?: TopLevelRecognizer | undefined; /** How each file-scope item `type` a `topLevel` recognizer (or `addItem`) produces renders on each target. */ readonly items?: Readonly> | undefined; /** * Method calls `.(…)` this plugin recognizes by SHAPE, keyed by METHOD name * (`safeParse`); the key `'*'` sees EVERY method call, after the recognizers keyed by its own name * (for a plugin that must warn about any method on a binding it owns). Each recognizer returns an `ext-expr` spec, `undefined` to decline, or `null` to claim * a call it reported as unsupported. Pair it with `exprs`. */ readonly methodCalls?: Readonly> | undefined; /** * Recognizes a CALL by its callee, for a binding the plugin recorded when it scanned the file (`scanModule`) — * `toast("x")` and `toast.success("x")` where `toast` is whatever local name the file imported it as. Returns an * `ext-expr` spec, `undefined` to decline, or `null` to claim a call it reported as unsupported. Called for every * call expression, so the first check must be cheap. Pair it with `exprs`. */ readonly callExprs?: CallExprRecognizer | undefined; /** How each `ext-expr` type a `methodCalls` / `callExprs` recognizer produces renders on each target and is typed. */ readonly exprs?: Readonly> | undefined; /** * Edit the file's structs from the module items and from the decode sites other plugins recorded * (`ParseContext.recordDecode`). Runs after the core's own struct float refinements, before the * inline-object ones that read the field types it settles. */ readonly refineStructs?: StructRefinement | undefined; /** A last pass over the finished item list (inline-synthesized items included), once per file. */ readonly finishModule?: ModuleFinish | undefined; /** * Rewrite a JSX element the parser just built, for a tag that names a LOCAL binding this plugin recorded when it scanned * the file (see `JsxElementRewrite`). The rewrite may ask for declarations on the component being parsed. */ readonly rewriteElement?: JsxElementRewrite | undefined; /** Hooks of this plugin whose result may be destructured (`const { data, isPending } = useQuery(…)`). */ readonly destructureCalls?: readonly string[] | undefined; /** * Calls of this plugin (a subset of `calls`) that lower ONLY inside a component body — the declaration becomes * a `remember {}` / an `@State`, which has no meaning at file scope. A file-scope declaration of one gets a * named warning saying the placement is wrong, instead of printing the call verbatim into the emit. */ readonly componentOnlyCalls?: readonly string[] | undefined; /** * How a signal that outlives the process (a recognizer's `SignalDeclSpec` with a `persistKey`) is declared on each * target — the library's own persistence primitive. A compiler has exactly one backend; two plugins declaring one is * a load-time error. See `signal-persistence.ts`. */ readonly persistence?: SignalPersistence | undefined; /** Names of other plugins that must be loaded; also orders the passes. */ readonly requires?: readonly string[] | undefined; /** Marks a compiler-shipped plugin that a discovered plugin may replace by name. */ readonly builtIn?: boolean | undefined; /** Source-level IR transformations run before any target preparation. */ readonly transformIR?: CompilerPass | undefined; /** Adds backend/runtime metadata after all source-level transformations. */ readonly prepareIR?: CompilerPass | undefined; readonly backends?: readonly CompilerBackend[] | undefined; } interface CompilerConfig { readonly plugins?: readonly CompilerPlugin[] | undefined; /** * Plugins found by package discovery. Unlike `plugins`, a discovered plugin * whose name equals a `builtIn` plugin REPLACES it silently, and an explicit * plugin of the same name wins over a discovered one. */ readonly discovered?: readonly CompilerPlugin[] | undefined; } interface NativeCompiler { readonly targets: readonly Target[]; /** The service registry every pass sees (built-in + plugin services). */ readonly services: ServiceRegistry; /** Everything this instance owns: services, derived tables, element lowerings. */ readonly registries: CompilerRegistries; transform(source: string, options: CompilerOptions): TransformResult; } //#endregion export { ElementLowering as $, StructRefinementTarget as $t, SignalPersistence as A, ModuleDeclIR as An, ModuleScanner as At, EmitPreparationResult as B, FieldValidators as Bt, serviceSpecsOf as C, EnumIR as Cn, RegisteredCall as Ct, UnloweredSpec as D, ExtPayload as Dn, JsxElementRewrite as Dt, UnloweredModule as E, ExtModuleItem as En, createCallRegistry as Et, PropsTypeContext as F, StructIR as Fn, CallExprSite as Ft, MemberExprIR as G, ModuleFinish as Gt, FunctionSite as H, ItemRegistry as Ht, PropsTypeResolver as I, TargetLanguage as In, ExprEmitter as It, ReceiverLowering as J, ModuleItemTyping as Jt, MemberReadLowering as K, ModuleFinishTarget as Kt, CallExprIR as L, TransformResult as Ln, ExtExprIR as Lt, ScopeProvider as M, PropIR as Mn, RequestSource as Mt, ParseRefinement as N, RouteIR as Nn, ResolvedRequest as Nt, KotlinPersistedSignal as O, ExtValue as On, JsxRewriteContext as Ot, ParseRefinementTarget as P, StatementIR as Pn, CallExprRecognizer as Pt, ElementClaimGuard as Q, StructRefinement as Qt, EmitPreparation as R, TypeIR as Rn, ExtExprSpec as Rt, selectDiscovered as S, EmitOptions as Sn, ParseContext as St, renderKotlinService as T, ExtDecl as Tn, SignalSpec as Tt, IdentifierLowering as U, MethodCallRecognizer as Ut, FunctionLowering as V, ItemBindings as Vt, IntrinsicLowering as W, MethodCallSite as Wt, ReceiverTargetLowering as X, ModuleReceiverLowering as Xt, ReceiverSite as Y, ModuleParseContext as Yt, RefModifierLowering as Z, ModuleReceiverSite as Zt, RegisteredService as _, WebViewFacade as _n, DeclValueBinding as _t, CompilerOptions as a, ComponentInfo as an, AstNode as at, createServiceRegistry as b, ComponentIR as bn, MemberCallLowering as bt, NATIVE_COMPILER_PLUGIN_API_V2 as c, EmitFieldValidators as cn, CallSite as ct, SUPPORTED_PLUGIN_API_VERSIONS as d, KotlinEmitContext as dn, DeclCallSite as dt, TopLevelRecognizer as en, ElementRegistry as et, ServiceSpec as f, MemberEmitScope as fn, DeclConstructRecognizer as ft, DiscoveredSelection as g, SwiftEmitContext as gn, DeclSwiftInit as gt, CompilerRegistries as h, StructRegistry as hn, DeclLifecycle as ht, CompilerModule as i, resolveThemeToken as in, AliasDeclSpec as it, ScopeEnterContext as j, ParseResult as jn, RequestOptions as jt, PersistedSignalSite as k, JsxElementIR as kn, ModuleScan as kt, NATIVE_COMPILER_PLUGIN_API_VERSION as l, EmitTarget as ln, ComputedDeclSpec as lt, ValidateOptions as m, StaticAttrValue as mn, DeclEmitter as mt, CompilerConfig as n, DEFAULT_THEME as nn, RetagContext as nt, CompilerPass as o, EmitBinding as on, CallRecognizer as ot, StubAugmentation as p, StatementEmitOptions as pn, DeclConstructSite as pt, ReceiverAssignSite as q, ModuleItemEmitter as qt, CompilerContext as r, ThemeTable as rn, createElementRegistry as rt, CompilerPlugin as s, EmitContext as sn, CallRegistry as st, CompilerBackend as t, createItemRegistry as tn, RegisteredElementLowering as tt, NativeCompiler as u, HostStateSlot as un, DeclCallRecognizer as ut, ServiceRegistry as v, AttrIR as vn, DeclVerdict as vt, ServiceDescriptor as w, ExprIR as wn, SignalDeclSpec as wt, orderPlugins as x, DeclIR as xn, MemberCallSite as xt, ServiceTables as y, ChildIR as yn, ExtDeclSpec as yt, EmitPreparationInput as z, ExtItemSpec as zt };