feat: support WRN imports and dynamic public shell
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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`;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user