feat: support WRN imports and dynamic public shell

This commit is contained in:
2026-07-21 11:15:06 +05:30
parent 0013c0771d
commit 2ca2d02b22
82 changed files with 959 additions and 174 deletions
+2
View File
@@ -660,6 +660,7 @@ export function generate(ast: PageAst): string {
}
const out: string[] = [];
if (ast.imports.length > 0) out.push(ast.imports.join("\n"));
const ssrBindings: SsrBinding[] = [];
const csrBindings: CsrBinding[] = [];
const helpers = ast.functions
@@ -1292,6 +1293,7 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
function generateComponent(ast: PageAst): string {
const out: string[] = [];
if (ast.imports.length > 0) out.push(ast.imports.join("\n"));
const hasServerEach = viewHasServerEach(ast.view);
if (hasServerEach) {
+1 -1
View File
@@ -233,5 +233,5 @@ export function generateNative(ast: PageAst): string {
.map((block) => block.trim())
.filter(Boolean)
.join("\n\n");
return `// generated from .wrn for Expo/React Native\nimport React, { useState } from "react";\nimport { ActivityIndicator, FlatList, Image, Pressable, SafeAreaView, ScrollView, StyleSheet, Text, TextInput, View } from "react-native";\nimport { useRouter } from "expo-router";\n\n${typeSource}\n\nexport default function ${ast.name}() {\n const router = useRouter();\n${hooks}\n return <>${body}</>;\n}\n\n${nativeStyles(ast.styles)}\n`;
return `// generated from .wrn for Expo/React Native\nimport React, { useState } from "react";\nimport { ActivityIndicator, FlatList, Image, Pressable, SafeAreaView, ScrollView, StyleSheet, Text, TextInput, View } from "react-native";\nimport { useRouter } from "expo-router";\n${ast.imports.join("\n")}\n\n${typeSource}\n\nexport default function ${ast.name}() {\n const router = useRouter();\n${hooks}\n return <>${body}</>;\n}\n\n${nativeStyles(ast.styles)}\n`;
}
+18
View File
@@ -146,6 +146,8 @@ export interface PropDecl {
export interface PageAst {
type: "page";
/** Static ES module imports declared before the WRN root declaration. */
imports: string[];
/**
* `page` is a route, `component` is a reusable fragment,
* and `layout` is a reusable page wrapper.
@@ -197,6 +199,21 @@ function unescapeSeoValue(value: string): string {
export function parse(source: string): PageAst {
const lx = new Lexer(source);
const imports: string[] = [];
const importPattern = /import\s+(?:type\s+)?(?:[\s\S]*?\s+from\s+)?["'][^"'\r\n]+["']\s*;?/y;
while (true) {
while (/\s/u.test(source[lx.pos] ?? "")) lx.pos++;
if (source.startsWith("//", lx.pos)) {
while (lx.pos < source.length && source[lx.pos] !== "\n") lx.pos++;
continue;
}
importPattern.lastIndex = lx.pos;
const statement = importPattern.exec(source);
if (!statement) break;
imports.push(statement[0].trim());
lx.pos = importPattern.lastIndex;
}
const expect = (type: Token["type"]): Token => {
const t = lx.next();
if (t.type !== type) {
@@ -474,6 +491,7 @@ export function parse(source: string): PageAst {
return {
type: "page",
imports,
kind,
name,
layout,