API / @aihu/compiler

@aihu/compiler

Compiler & tooling

Single File Component (.aihu) compiler — Rust binary + JS glue.

version
1.3.5
exports
61
values
45
types
16
01

_buildDeferredHydration

function
function _buildDeferredHydration(compiledCode: string, elementTag: string): string;

Rewrite an interactive-island module so its `connectedCallback` waits for the element to scroll into view before mounting.

02

_buildStaticIsland

function
function _buildStaticIsland(compiledCode: string, elementTag: string): string;

Build a static-island shim for a compiled module.

03

_clearTransformMemo

function
function _clearTransformMemo(): void;

Test/diagnostic hook — wipe the memo and its counters.

04

_compileViaBackend

function
function _compileViaBackend(source: string, legacyArgs: string[], options: CompileEnvelopeOptions): EnvelopeReply;

Run one compile through the active backend.

05

_deriveChildTags

function
function _deriveChildTags(compiledCode: string): string[];

Derive the `__aihu_child_tags__` set from SERVER-TARGET compiled code: the tags the compiled string renderer will actually look up, read off the `__aihu_schild('<tag>'` call sites the Rust codegen emitted.

06

_errMessage

function
function _errMessage(err: unknown): string;

Best-effort message text for an unknown thrown value.

07

_foldCssEngineStyles

function
function _foldCssEngineStyles(compiledCode: string, css: string): string;
08

_foldCssEngineStylesGlobal

function
function _foldCssEngineStylesGlobal(compiledCode: string, css: string, id: string): { code: string; virtualId: string; } | null;

Bug 6 — `shadowMode === 'light'` branch.

09

_foldSsrCssExport

function
function _foldSsrCssExport(compiledCode: string, css: string): string;

Fold css-engine utility CSS into the SERVER target's `__aihu_css__` export.

10

_formatExtractCensus

function
function _formatExtractCensus(census: ReadonlyMap<string, { read: string; call: string; }>): string[];

GX Phase 1 (#437-GX) — format the per-value extract census (the DA-e census pattern from #437: every build PRINTS the posture distribution, so the default-vs-declared migration story stays visible rather than silent).

11

_getCompilerNativeStateKind

function
function _getCompilerNativeStateKind(): CompilerNativeState['kind'];

Returns the cached state kind (resolving if needed).

12

_globalizeAuthoredStyle

function
function _globalizeAuthoredStyle(code: string): string;

Light-DOM (`shadowMode:'light'`) recipes: redirect the authored `@style` block's per-instance `host.adoptedStyleSheets = [__style__]` assignment to `document.adoptedStyleSheets` so the recipe's class-scoped CSS reaches the global cascade (a light-DOM host has no shadow root, making the original setter a silent no-op).

13

_hashIdForUtilityCss

function
function _hashIdForUtilityCss(id: string): string;

Stable short hash for keying the virtual-CSS module per source-SFC id.

14

_injectAutoWiring

function
function _injectAutoWiring(code: string): string;

Inject `_setMount(mount)` + `_setSignal(signal)` auto-wiring into a compiled `.aihu` module.

15

_injectLightScopeId

function
function _injectLightScopeId(code: string, lightScopeId: string): string;

Fill the Rust codegen's `__AIHU_LIGHT_SCOPE_ID__` placeholder with the component's real light-DOM scope id (LDF §10 step 3).

16

_injectShadowMode

function
function _injectShadowMode(code: string, mode: 'light' | 'shadow', lightScopeId?: string): string;

Inject `shadowMode: '...'` (and, for light mode, `lightScopeId: '...'` in the SAME options object) into the third argument of the emitted `defineElement('tag', defineComponent(...))` call — appending the options object when the call has two arguments, or merging the fields into an existing third argument (`$form` emits `, { formAssociated: true }`).

17

_isLayoutFile

function
function _isLayoutFile(rawId: string, layoutsDir: string): boolean;

Is `rawId` a layout SFC (a `.aihu` file under the configured layouts dir)?

18

_isViteMissing

function
function _isViteMissing(err: unknown): boolean;

Is this `import('vite')` rejection the ONE legitimate "there is no Vite here" case — a standalone `transform()` caller, a unit test, any non-Vite host?

19

_layoutTag

function
function _layoutTag(stem: string): string;

Layout custom-element tag for a filename stem.

20

_lightScopeId

function
function _lightScopeId(id: string): string;

Deterministic 8-hex-char scope id for a light-DOM component's `data-a` attribute (light-DOM leaf flip, LDF §10 step 1 / step 3).

21

_parseComponentTagsMarker

function
function _parseComponentTagsMarker(compiledCode: string): string[];

§22 — parse the `//

22

_parseExtractMarker

function
function _parseExtractMarker(code: string): { read: string; call: string; } | null;

GX Phase 1 (#437-GX) — parse the `//

23

_parseIslandMarker

function
function _parseIslandMarker(compiledCode: string): 'static' | 'interactive';

Read the compiler's AUTHORITATIVE island classification from the `//

24

_passivizeOutlet

function
function _passivizeOutlet(code: string): string;

Collapse the reactive `<outlet>` boundary the Rust codegen emits into a passive `data-aihu-outlet` marker.

25

_resetCompileBackend

function
function _resetCompileBackend(): void;

Reset the cached backend (tests).

26

_resetCompilerNative

function
function _resetCompilerNative(): void;

Reset the cached state.

27

_resolveCompileBackend

function
function _resolveCompileBackend(): CompileBackend;

Resolve (once) which backend serves compiles for this process.

28

_stripFailure

function
function _stripFailure(fn: 'transformWithOxc' | 'transformWithEsbuild', id: string, viteVersion: string, isServerEnv: boolean, err: unknown): string;

The message for a strip that failed with Vite present — names the branch, the Vite version, the environment and the file, and says why it is fatal rather than swallowed.

29

_stripTypes

functionagent
function _stripTypes(vite: ViteStripApi, code: string, id: string, isServerEnv: boolean): Promise<StripTypesResult>;

Strip TypeScript from compiler output using whichever transform the resolved Vite exposes.

30

_transformMemoStats

function
function _transformMemoStats(): { size: number; hits: number; misses: number; seeds: number; };

Test/diagnostic hook — current memo size + hit/miss/seed counters.

31

aihuCompilerPlugin

function
function aihuCompilerPlugin(options?: AihuCompilerPluginOptions): VitePlugin;
32

compileRouteMeta

function
function compileRouteMeta(source: string, id?: string): RouteMeta | null;
33

compileSidecar

functionagent
function compileSidecar(source: string, id?: string, options?: { /** * #486 step 4 — emit the attribute/component-prop type layer * (`--strict-templates`). Default off: the surface stays byte-identical * to the pre-#486 sidecar. */ strictTemplates?: boolean; /** * Build target threaded to the compiler binary (`--target`), same flag * `transform()` passes. Defaults to the binary's own default * (`universal`) when omitted. * * This is NOT cosmetic: `--target` changes what `compile_full_with_options` * produces (packages/compiler/src/bin/main.rs), which `sidecar_ts` is * derived from — e.g. a `target: 'client'` build elides server-only * artifacts. A caller that never passes this always type-checks against * the `universal` surface regardless of the project's actual configured * target, which can pass tsc on code the real build would elide or * reject. `islands`/`shadowMode` are deliberately NOT parameters here: * both are applied as JS-side post-processing on the RUNTIME JS output * (see `transform()`), never touch `sidecar_ts`, and have no bearing on * type-check accuracy. */ target?: 'client' | 'server' | 'universal'; }): string;

Compile an SFC to its TYPE-CHECK SURFACE and return it as a string — the `.aihu.ts` sidecar's content, without writing a file.

34

compileToAst

function
function compileToAst(source: string, id?: string): SfcAst;
35

kebabComponentTag

function
function kebabComponentTag(raw: string): string;

O1a (tag naming) — JS mirror of the Rust compiler's `tags::kebab_component_tag` (packages/compiler/src/tags.rs).

36

loadCompilerNative

function
function loadCompilerNative(): CompilerNativeState;

Resolve (and cache) the native compiler addon.

37

matchBrace

function
function matchBrace(s: string, i: number): number;

Matching `}` for the `{` at `i` (string/comment aware).

38

matchParen

function
function matchParen(s: string, i: number): number;

Matching `)` for the `(` at `i` (string/comment/brace aware).

39

migrate

function
function migrate(source: string): MigrateResult;
40

migrateStateWrappers

function
function migrateStateWrappers(source: string, options?: StateWrapperOptions): StateWrapperResult;
41

migrateTemplateGrammar

function
function migrateTemplateGrammar(source: string): TemplateGrammarResult;

Run every template-grammar-v2 pass over one `.aihu` source (or a markdown document containing `.aihu` snippets — the transforms are anchored to template-syntax shapes and leave prose alone).

42

transform

function
function transform(source: string, id: string, options?: { sidecarOut?: string; target?: 'client' | 'server' | 'universal'; /** Override the registered custom-element tag (default: file stem). Used for layouts. */ tag?: string; /** * #486 step 4 — emit the sidecar's attribute/component-prop type layer * (`--strict-templates`). Affects only the type-check surface written to * `sidecarOut`; the compiled JS is identical either way. Default off. */ strictTemplates?: boolean; }): { code: string; map: null; };

Compile a .aihu source string to TypeScript.

43

_MEMO_MAX_ENTRIES

const
const _MEMO_MAX_ENTRIES

FIFO size bound.

44

resolveCompilerBinary

const
const resolveCompilerBinary
45

VIRTUAL_UTILITY_PREFIX

const
const VIRTUAL_UTILITY_PREFIX

Virtual-module prefix used by the `shadowMode === 'light'` branch to route per-SFC utility CSS through Vite's built-in CSS pipeline.

46

AihuCompilerPluginOptions

interface
interface AihuCompilerPluginOptions {
  /**
   * When `true` (default), components the compiler classified as `'static'`
   * (read from the `// @aihu:island` marker via `_parseIslandMarker()`) are
   * emitted with a minimal HTML-only registration shim that ships **zero**
   * `@aihu/runtime` and `@aihu/signals` JS to the browser. Components
   * classified as `'interactive'` retain the full runtime path.
   *
   * Setting `islands: false` opts every component back into the unified
   * runtime path (Plan 3.2 baseline behaviour).
   */
  islands?: boolean;
  /**
   * Project-wide rendering mode applied to every `.aihu` SFC compiled
   * by this plugin instance. When set, the plugin post-processes the
   * compiled JS to inject `, { shadowMode: '<mode>' }` as the third arg
   * to the emitted `defineElement(tag, defineComponent(...))` call.
   *
   * BINARY vocabulary (DA4 #437):
   * - `'shadow'` — shadow DOM (`attachShadow({ mode: 'open' })` internally;
   *               open is the only browser mode aihu's composition/hydration
   *               can use). `this.shadowRoot` is the non-null root.
   * - `'light'`  — **no shadow root.** The component mounts into its own
   *               element (`this.shadowRoot === null`). Required for global
   *               utility-class CSS frameworks like Tailwind, UnoCSS, Pico
   *               that rely on the cascade.
   *
   * Per-file override: the `$shadow: 'light' | 'shadow'` macro outranks this
   * config. Unset, pages/layouts default to `'light'` and leaves to
   * `'shadow'`.
   */
  shadowMode?: 'light' | 'shadow';
  /**
   * Build target threaded to the compiler binary (`--target`). Defaults to the
   * compiler's `universal` target (current behaviour). Set to `'client'` for a
   * browser bundle that must NOT ship the server `__agentBinding` (policy) and
   * instead gets the policy-free `@agent` opaque-ID dispatcher + the per-instance
   * `_registerAgentDispatcher` wiring the capability bridge reads after mount.
   * See `examples/agent-driven-demo`.
   */
  target?: 'client' | 'server' | 'universal';
  /**
   * Directory (relative to the project root) holding layout SFCs. Default:
   * `'src/layouts'`. Files under this directory are compiled in **layout mode**:
   * their custom element is registered under the namespaced tag
   * `aihu-layout-<stem>` (a layout stem like `app` is not a valid custom-element
   * name on its own), and their `<outlet>` lowers to a **passive**
   * `data-aihu-outlet` marker rather than the reactive route-driven boundary —
   * because `@aihu/app`'s client renderer fills the marker imperatively and the
   * reactive boundary would otherwise clear it on mount.
   *
   * Kept in sync with `@aihu/router`'s `layoutTagFor()` (`virtual:aihu-layouts`).
   */
  layoutsDir?: string;
}

Options for `aihuCompilerPlugin()` (Plan 3.3 — Islands).

47

CompileEnvelope

interface
interface CompileEnvelope {
  envelope: number;
  targets: Record<string, {
    js?: string;
    manifest?: string;
  }>;
  astJson?: string;
  routeJson?: string;
  diagnostics: unknown[];
}

The wire shape of a compile envelope (Rust `Envelope`, camelCase).

48

CompileEnvelopeOptions

interface
interface CompileEnvelopeOptions {
  tag?: string;
  path?: string;
  targets?: string[];
  emits?: Array<'js' | 'ast' | 'route' | 'manifest'>;
  strictTemplates?: boolean;
  exprParser?: string;
}

Options forwarded to the Rust envelope API (Rust `EnvelopeOptions`).

49

MigrateResult

interface
interface MigrateResult {
  readonly rewritten: string;
  readonly warnings: readonly string[];
}

macro-simplification codemod (B6.2) Transforms v1 `.aihu` source into v2 collection-form per `docs/superpowers/specs/2026-05-05-spec-macro-vocabulary-v2.md`.

50

RouteMeta

interface
interface RouteMeta {
  pattern?: string;
  name?: string;
  layout?: string;
  middleware?: string[];
  ssr?: boolean;
  params?: string[];
  head?: unknown;
  /**
   * GX Phase 1 fan-out (#437-GX): the resolved `extract` policy — always
   * present in the binary's route-json output since 0.1.12 (the default is
   * recorded, never implied by absence). Typed loose here: consumers
   * normalize fail-closed (`deriveReadPolicy` in `@aihu/server`).
   */
  extract?: {
    read?: unknown;
    call?: unknown;
  };
  /**
   * GX Phase 4 fan-out (#466): the `data:` governed-resource declaration
   * (70-governed-data-access §2.1) — present only when the route declares one
   * (0.1.14+). `type` keys the server registry's provider; `preview` lists
   * the locked-state fields (omitted when none declared). Consumers: the
   * server runtime's boot validation + generated loader, and the router Vite
   * layer's C486 sibling-loader conflict check (§4.7).
   */
  data?: {
    type?: string;
    preview?: string[];
  };
}

Structured `@route` metadata (the `.route.json` sidecar shape).

51

SfcAst

interface
interface SfcAst {
  /** Resolved custom-element tag name (meta.name → route.name → file stem). */
  tag: string;
  /** AST schema version — bumped on any breaking shape change (semver-tied). */
  astVersion: 1;
  /** The @style block, if the SFC declared one. */
  style: SfcStyleBlock | null;
  /** Parsed template tree. null when the SFC has no @template block. */
  template: SfcNode[] | null;
  /** SFC-level metadata. */
  meta: SfcMeta;
  /**
   * The compiler-assigned light-DOM scope id for this component's `data-a`
   * attribute, present only when it resolved to `shadowMode: 'light'`
   * (light-DOM leaf flip, LDF §10 step 1). Absent (not just `undefined`, the
   * key itself omitted on the wire) for shadow-mode components — additive,
   * mirrors `aihu-css-core`'s `SfcAst.light_scope_id: Option<String>`.
   */
  lightScopeId?: string;
}

Top-level AST export — one per .aihu SFC.

52

SfcMeta

interface
interface SfcMeta {
  /** From @meta { name } / @route { name } / file stem — never null after resolution. */
  name: string;
}
53

SfcStyleBlock

interface
interface SfcStyleBlock {
  /** Verbatim CSS body of the @style block (braces stripped, $global token removed). */
  content: string;
  /** 'scoped' (default) or 'global' (@style { $global ... }). */
  scope: 'scoped' | 'global';
}
54

StateWrapperOptions

interface
interface StateWrapperOptions {
  /** Run only stage 1 ($-macros + bare typed decls). */
  macrosOnly?: boolean;
  /** Run only stage 2 (signal tuples + call sites). */
  tuplesOnly?: boolean;
  /**
   * Binding names that must stay PLAIN even when the reactive heuristic says
   * `state(…)` (e.g. a fixture guard depends on the plain-let lowering).
   */
  keepPlain?: readonly string[];
}
55

StateWrapperResult

interface
interface StateWrapperResult {
  readonly rewritten: string;
  readonly warnings: readonly string[];
  /** True when the file was left byte-untouched (nothing to do, or aborted). */
  readonly skipped: boolean;
  /** Which change classes were applied — drives the verification bucket. */
  readonly changes: {
    macros: boolean;
    tuples: boolean;
    bareTyped: boolean;
  };
  /** Tuple pairs migrated: authored setter name → state binding name. */
  readonly renamedSetters: ReadonlyArray<{
    getter: string;
    setter: string;
  }>;
}

state-wrapper codemod (#487 §7 — waves 1 + 2, the app-corpus migration) Migrates an `.aihu` file's `@state` block from the retired forms to the ratified wrapper model (`docs/plans/state-model/40-spec.md`): Stage 1 — `$`-macros → wrappers / statement calls / directives (§2, §3): $prop: { x: { … } } → const|let x = prop<T>({ … }) $computed: { x: fn } → const x = derived(cfg?, fn) $action: { f: fn } → const f = action(cfg?, fn) $resource: { r: fn } → const r = resource(cfg?, fn) $controller: { c: {value} }→ const c = controller(cfg?, factory) $effect: fn / { name: fn } → effect(fn) / effect({ on: […] }, fn) $lifecycle: { mount, … } → onMount(fn), onDispose(fn), … $aria: { … } / $form: { … }→ aria({ … }) / form({ … }) $context: {provide,consume}→ provide('k', v) / const k = consume<T>('k') $route name → const name = route() $before/afterNavigate(fn) → beforeNavigate(fn) / afterNavigate(fn) $extends: X / $shadow: 'm' → base: X / shadow: 'm' bare typed decl `x: T = v` → let x = state(v) (reactive) | plain let/const (inert; §3 row 21 + W627) Stage 2 — signal tuples → `state` (§7 wave 2), INCLUDING call sites: const [x, setX] = signal(v) → let x = state(v) x() → x setX(v) → x = v (statement / handler) setX(p => expr) → x = expr[p→x] (updater desugar) Byte-identity contract: `$`-macro migrations lower onto the SAME IR, so a stage-1-only migration emits byte-identical JS (modulo the old parser's `strip_line_comments` artifact — authored `//` comments inside metadata-bag bodies were BLANKED in old emission and are preserved by the wrapper path).

56

StripTypesResult

interface
interface StripTypesResult {
  readonly code: string;
  readonly map: null;
  /** Rolldown-only hint; set ONLY on the last-resort no-transform branch. */
  readonly moduleType?: 'ts';
}

What the Vite plugin's `transform` hook hands back after the strip.

57

TemplateGrammarResult

interface
interface TemplateGrammarResult {
  readonly rewritten: string;
  readonly changed: boolean;
}

template-grammar-v2 codemod — migrate v1 template syntax to the prefix-less grammar (docs/plans/template-grammar/40-spec.md).

58

ViteStripApi

interface
interface ViteStripApi {
  readonly version?: string;
  readonly transformWithOxc?: (code: string, id: string, ...rest: any[]) => Promise<{
    code: string;
  }>;
  readonly transformWithEsbuild?: (code: string, id: string, ...rest: any[]) => Promise<{
    code: string;
  }>;
}

The subset of the Vite module `_stripTypes` uses — the seam tests fake.

59

SfcAttr

type
type SfcAttr = {
  kind: 'static';
  name: string;
  value: string;
} | {
  kind: 'binding';
  name: string;
  expr: string;
} | {
  kind: 'macro';
  name: string;
  value: SfcMacroValue;
};

Discriminated union mirroring Rust `Attr` — the three class-forms key on `kind`.

60

SfcMacroValue

type
type SfcMacroValue = {
  form: 'quoted';
  value: string;
} | {
  form: 'curly';
  expr: string;
} | {
  form: 'boolean';
};
61

SfcNode

type
type SfcNode = {
  kind: 'element';
  tag: string;
  attrs: SfcAttr[];
  children: SfcNode[];
} | {
  kind: 'macroElement';
  name: string;
  attrs: SfcAttr[];
  children: SfcNode[];
} | {
  kind: 'text';
  value: string;
} | {
  kind: 'interpolation';
  expr: string;
} | {
  kind: 'ifBlock';
  branches: Array<{
    cond: string;
    body: SfcNode[];
  }>;
} | {
  kind: 'eachBlock';
  list: string;
  item: string;
  idx: string | null;
  key: string | null;
  body: SfcNode[];
  emptyBody: SfcNode[] | null;
} | {
  kind: 'htmlBlock';
  expr: string;
};

Discriminated union mirroring Rust `TemplateNode`.