Files
WRNexusJS/packages/compiler/src/index.ts
T
ClintchizandClaude Opus 5 17aa3b98eb feat(islands): wire islands end to end
The island pieces existed but nothing connected .wrn compilation to island
emission. Now:

- codegen emits a data-wrn-island placeholder for component tags bound to
  .tsx imports, keeping .wrn components on the normal mount path
- the dev pipeline and static build resolve island imports, thread the
  names into codegen, and build the bundles
- collectScripts adds /__wrnexus/islands.js only when island markup is
  present, so island-free pages still ship nothing
- island routes classify as static-interactive via hasIslands

Three bugs found by driving a real page in the browser:

1. The mount runtime was never built anywhere, so the bootstrap 404'd and
   no island mounted.
2. Building the runtime separately from the islands gave each its own copy
   of React: "Cannot read properties of null (reading 'useState')". The
   runtime is now an entrypoint of the same build so React stays in one
   shared chunk. The existing single-React test only compared bundles
   within one build and could not see across build boundaries.
3. Island props arrived as attribute strings, so start={3} was "3" and
   incrementing produced "31" then "311". Props now follow JSX semantics:
   {…} parses as JSON, quoted values stay strings, and a runtime
   expression is a WRN-ISLAND-PROPS build error rather than a silent
   wrong value.

island-codegen.ts no longer imports @wrnexus/core. Compiler modules are
bundled into the Node-only VS Code extension, which contains no other
packages, so a runtime import of core broke the editor compiler; the two
helpers are implemented locally and the core dependency is dropped again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 16:16:03 +05:30

141 lines
4.6 KiB
TypeScript

/**
* @wrnexus/compiler — the `.wrn` language compiler.
*
* Parsing and language diagnostics are provided by the canonical
* `@wrnexus/syntax` package. This package owns platform-specific codegen.
*/
import {
assertValidAst,
diagnose,
diagnosticFromError,
formatDiagnostic,
parse,
ParseError,
type PageAst,
type WrnDiagnostic,
} from "@wrnexus/syntax";
export { formatWrn } from "@wrnexus/syntax";
export type { FormatWrnOptions } from "@wrnexus/syntax";
import { generate } from "./codegen.ts";
import { generateNative } from "./native-codegen.ts";
export {
assertValidAst,
diagnose,
diagnosticFromError,
formatDiagnostic,
parse,
ParseError,
} from "@wrnexus/syntax";
export { generate } from "./codegen.ts";
export { generateTargets } from "./targets.ts";
export { generateBrowserModule } from "./client-codegen.ts";
export { generateServerFunctionsModule, rpcManifest } from "./server-codegen.ts";
export { generateDeclarations } from "./type-codegen.ts";
export { generateStoreBrowserModule, generateStoreModule } from "./store-codegen.ts";
export { createComponentContract } from "./component-contract.ts";
export { resolveWrnImport, resolveWrnImports } from "./import-resolver.ts";
export { createWrnSourceMap } from "./source-map.ts";
export { analyzeOptimizations, analyzeRuntimeRequirements, optimizeAst } from "./analysis.ts";
export type { OptimizationReport, RouteExecutionKind, RuntimeRequirements } from "./analysis.ts";
export { analyzeRuntimeImports, runtimeCapabilities } from "./runtime-capabilities.ts";
export type {
DeploymentRuntime,
RuntimeCapability,
RuntimeCapabilityDiagnostic,
} from "./runtime-capabilities.ts";
export { generateNative, NativeCompileError } from "./native-codegen.ts";
export { Lexer, LexError } from "@wrnexus/syntax";
export { eraseFunctionTypes, inferredRuntimeType, runtimeTypeOf } from "@wrnexus/syntax";
export type {
ActionBlock,
ApiBlock,
Attr,
ComputedDecl,
DataApiBlock,
DataMode,
EffectBlock,
EventDecl,
OutputDecl,
RuntimeFunctionDecl,
StateRuntime,
StoreKind,
StructuredImportDecl,
LoadBlock,
ModeFunctionsBlock,
PageAst,
PropDecl,
RealtimeBlock,
SeoBlock,
StateDecl,
ViewNode,
WrnDiagnostic,
} from "@wrnexus/syntax";
export interface CompileResult {
code: string;
ast: PageAst;
/** Backward-compatible plain diagnostic messages. */
diagnostics: string[];
/** Structured diagnostics for editors, CI, and the DevToolbar. */
richDiagnostics: WrnDiagnostic[];
}
/** Compile `.wrn` source into an Expo Router React Native screen. */
export function compileNativeWrnFile(source: string): string {
const ast = parse(source);
assertValidAst(ast);
return generateNative(ast);
}
/**
* Compile `.wrn` source into TypeScript source. Errors include a stable code,
* source location, code frame, and actionable hint whenever available.
*/
export function compileWrnFile(source: string, filePath = "<inline .wrn>"): string {
try {
const ast = parse(source);
assertValidAst(ast, { file: filePath, accessibility: true });
return `// compiled from .wrn\n${generate(ast)}`;
} catch (error) {
const diagnostic = diagnosticFromError(source, error, { file: filePath });
throw new Error(`Failed to parse ${filePath}:\n\n${formatDiagnostic(source, diagnostic)}`, {
cause: error,
});
}
}
/** Richer entry point returning the AST and structured diagnostics. */
export function compile(source: string, filePath = "<inline .wrn>"): CompileResult {
const richDiagnostics = diagnose(source, { file: filePath, accessibility: true });
const errors = richDiagnostics.filter((diagnostic) => diagnostic.severity === "error");
if (errors.length > 0) {
throw new ParseError(
errors.map((diagnostic) => diagnostic.message).join("\n"),
errors[0]!.code,
);
}
const ast = parse(source);
return {
code: `// compiled from .wrn\n${generate(ast)}`,
ast,
diagnostics: richDiagnostics.map((diagnostic) => `${diagnostic.code}: ${diagnostic.message}`),
richDiagnostics,
};
}
export { compilationKey, createCompilationCache, DependencyGraph } from "./cache.ts";
export type { CompilationCache, CompilationCacheEntry, CompilationCacheOptions } from "./cache.ts";
export {
islandNamesFrom,
islandPropValue,
parseIslandStrategy,
renderIslandMarker,
serializeIslandProps,
} from "./island-codegen.ts";
export type { IslandDiagnostic, IslandStrategy } from "./island-codegen.ts";
export { assertReactAvailable, buildIslands, generateIslandEntry } from "./island-bundle.ts";
export type { IslandBuildResult, IslandInput } from "./island-bundle.ts";
export { routeNeedsIslands } from "./analysis.ts";