import { statSync, mkdirSync, writeFileSync } from 'fs'
import { join } from 'path'
import { format } from './format'
import { parseConfig } from './parse'
import type { IConfig, IRoute } from '../types'
/**
* 创建 .neoi 文件夹
* @param cwd
*/
function generateTemp(cwd?: string) {
const tempPath = join(cwd ?? process.cwd(), 'src', '.neoi')
try {
const stats = statSync(tempPath)
if (!stats.isDirectory()) {
mkdirSync(tempPath)
}
} catch (_) {
mkdirSync(tempPath)
}
}
function getRouteElement(route: IRoute): string {
const routeProps = {
exact: route.exact,
path: route.path,
}
if (route.routes) {
const routes = route.routes.map((_route) => ({
..._route,
path: route.path + _route.path,
}))
return `${
route.redirect
? ``
: ''
} {
// @ts-ignore
const Component = React.lazy(() => import('${route.component}'))
return (
${routes.map((_route) => getRouteElement(_route)).join('')}
)
}}
/>`
} else if (route.redirect) {
return ``
} else {
return ` {
// @ts-ignore
const Component = React.lazy(() => import('${route.component}'))
return
}}
/>`
}
}
interface IGenerateRouter {
refresh: boolean
config?: IConfig
cwd?: string
}
/**
* 根据 config.routes 配置生成 router.tsx
* @param IGenerateRouter
* @returns
*/
export async function generateRouter({
refresh,
config,
cwd,
}: IGenerateRouter) {
config = config || (await parseConfig(refresh)) || undefined
if (config && Array.isArray(config.routes)) {
const content = format(`import React from 'react'
import { BrowserRouter, Switch, Route, Redirect } from 'neoi'
export default function Router() {
return (
${config.routes.map((route) => getRouteElement(route)).join('')}
)
}
`)
return writeFileSync(
join(cwd ?? process.cwd(), 'src', '.neoi', 'router.tsx'),
content,
{
encoding: 'utf-8',
}
)
}
}
const hasRouter = (config: IConfig | null) => Array.isArray(config?.routes)
const hasStore = (config: IConfig | null) => !!config?.store
/**
* 生成 store.ts
* @param cwd
* @returns
*/
async function generateStore(cwd?: string) {
const config = await parseConfig()
const content = format(`import { createContext, useContext } from 'react'
import * as stores from '../stores'
type Stores = typeof stores
type ValueOf = T[keyof T]
export const StoreContext = createContext(stores)
export function useStore(
storeName: T
): ValueOf {
const store = useContext(StoreContext) as Stores
if (storeName in store) {
return store[storeName]
}
throw new Error(\`No store named \${storeName} found!\`)
}
export { stores }
`)
if (config?.store) {
return writeFileSync(
join(cwd ?? process.cwd(), 'src', '.neoi', 'store.ts'),
content,
{
encoding: 'utf-8',
}
)
}
}
/**
* 生成 exports.ts
* @param cwd
* @returns
*/
async function generateExports(cwd?: string) {
const config = await parseConfig()
const content = format(`${hasStore(config) ? `export * from './store'` : ''}`)
return writeFileSync(
join(cwd ?? process.cwd(), 'src', '.neoi', 'exports.ts'),
content,
{
encoding: 'utf-8',
}
)
}
/**
* 生成 main.tsx
* @param cwd
* @returns
*/
async function generateMain(cwd?: string) {
const config = await parseConfig()
const content = format(`import React from 'react'
import { render } from 'neoi'
${
hasRouter(config)
? `import Router from './router'`
: `import Home from '../pages'`
}
${hasStore(config) ? `import { StoreContext, stores } from './store'` : ''}
function App() {
return (
${
hasStore(config)
? `
`
: hasRouter(config)
? ''
: ''
}
)
}
render(, '#root')
`)
return writeFileSync(
join(cwd ?? process.cwd(), 'src', '.neoi', 'main.tsx'),
content,
{
encoding: 'utf-8',
}
)
}
export function generate() {
const cwd = process.cwd()
generateTemp(cwd)
generateRouter({ refresh: false, cwd })
generateStore(cwd)
generateExports(cwd)
generateMain(cwd)
}