初始化

This commit is contained in:
2026-03-26 20:18:20 +08:00
commit 120a5b4dfd
368 changed files with 35926 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import process from 'node:process';
import { fileURLToPath } from 'node:url';
import { setupElegantRouter } from '../build/plugins/router.ts';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const rootDir = path.resolve(__dirname, '..');
const generatedFiles = [
path.resolve(rootDir, 'src/router/elegant/imports.ts'),
path.resolve(rootDir, 'src/router/elegant/routes.ts'),
path.resolve(rootDir, 'src/router/elegant/transform.ts'),
path.resolve(rootDir, 'src/typings/elegant-router.d.ts')
];
async function getMtimeMs(filePath) {
try {
const stat = await fs.stat(filePath);
return stat.mtimeMs;
} catch {
return 0;
}
}
async function getGeneratedFileMtimes() {
return Promise.all(generatedFiles.map(getMtimeMs));
}
function isGenerated(before, after) {
return after.some((mtimeMs, index) => mtimeMs !== before[index]);
}
async function waitForGeneration(beforeMtimes, timeoutMs = 10000) {
const startTime = Date.now();
while (Date.now() - startTime < timeoutMs) {
const afterMtimes = await getGeneratedFileMtimes();
if (isGenerated(beforeMtimes, afterMtimes)) {
return;
}
await new Promise(resolve => setTimeout(resolve, 100));
}
throw new Error('Timed out while waiting for elegant-router generated files.');
}
process.chdir(rootDir);
const beforeMtimes = await getGeneratedFileMtimes();
setupElegantRouter();
await waitForGeneration(beforeMtimes);
console.log('Generated elegant-router files.');

View File

@@ -0,0 +1,206 @@
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { customRoutes } from '../src/router/routes/custom-routes.ts';
import { generatedRoutes } from '../src/router/elegant/routes.ts';
import zhCn from '../src/locales/langs/zh-cn.ts';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const rootDir = path.resolve(__dirname, '..');
const outputPath = path.resolve(rootDir, 'docs/frontend-page-resource-manifest.json');
const excludedPageResourceRouteNames = new Set(['exception_403', 'exception_404', 'exception_500']);
const excludedPageResourcePathPrefixes = ['/function/', '/plugin/'];
function isConstantRoute(route) {
return Boolean(route.meta?.constant);
}
function getRouteOrder(route) {
const order = Number(route.meta?.order);
if (Number.isFinite(order)) {
return order;
}
return Number.MAX_SAFE_INTEGER;
}
function sortRoutes(routes) {
return [...routes].sort((next, prev) => {
const orderDiff = getRouteOrder(next) - getRouteOrder(prev);
if (orderDiff !== 0) {
return orderDiff;
}
return String(next.path || '').localeCompare(String(prev.path || ''));
});
}
function getPageComponent(component) {
if (!component) {
return null;
}
if (component.startsWith('view.')) {
return component;
}
if (component.startsWith('layout.') && component.includes('$view.')) {
return component;
}
return null;
}
function getPageType(component) {
if (!component) {
return null;
}
if (component.startsWith('view.')) {
return 'leaf';
}
if (component.startsWith('layout.') && component.includes('$view.')) {
return 'single';
}
return null;
}
function shouldExcludePageResource(route) {
if (excludedPageResourceRouteNames.has(route.name)) {
return true;
}
return excludedPageResourcePathPrefixes.some(prefix => String(route.path || '').startsWith(prefix));
}
function getNumberMetaValue(value) {
const parsed = Number(value);
if (Number.isFinite(parsed)) {
return parsed;
}
return null;
}
function normalizeRouteProps(props) {
if (props === true) {
return true;
}
if (props && typeof props === 'object') {
return props;
}
return null;
}
function getRouteLabel(route) {
const routeLocales = zhCn.route || {};
const i18nKey = route.meta?.i18nKey;
if (typeof i18nKey === 'string' && i18nKey.startsWith('route.')) {
const localeKey = i18nKey.slice('route.'.length);
if (routeLocales[localeKey]) {
return routeLocales[localeKey];
}
}
if (routeLocales[route.name]) {
return routeLocales[route.name];
}
return route.meta?.title || route.name;
}
function collectPageResources(routes, options, items) {
const { parentName = null, source } = options;
const orderedRoutes = sortRoutes(routes);
for (const route of orderedRoutes) {
const pageComponent = getPageComponent(route.component);
const hideInMenu = Boolean(route.meta?.hideInMenu);
// The backend page-node whitelist only contains menu-visible pages.
if (pageComponent && !hideInMenu && !shouldExcludePageResource(route)) {
const order = getNumberMetaValue(route.meta?.order);
const fixedIndexInTab = getNumberMetaValue(route.meta?.fixedIndexInTab);
const props = normalizeRouteProps(route.props);
const meta = {
title: getRouteLabel(route),
i18nKey: route.meta?.i18nKey || null,
icon: route.meta?.icon || null,
localIcon: route.meta?.localIcon || null,
order,
keepAlive: Boolean(route.meta?.keepAlive),
hideInMenu,
activeMenu: route.meta?.activeMenu || null,
multiTab: Boolean(route.meta?.multiTab),
fixedIndexInTab
};
items.push({
name: route.name,
path: route.path,
component: pageComponent,
title: meta.title,
routeTitle: route.meta?.title || route.name,
i18nKey: meta.i18nKey,
icon: meta.icon,
localIcon: meta.localIcon,
order,
hideInMenu,
keepAlive: meta.keepAlive,
activeMenu: meta.activeMenu,
multiTab: meta.multiTab,
fixedIndexInTab,
redirect: route.redirect || null,
props,
meta,
parentName,
pageType: getPageType(pageComponent),
source
});
}
if (route.children?.length) {
collectPageResources(route.children, { parentName: route.name, source }, items);
}
}
}
function getPageResources() {
const items = [];
collectPageResources(customRoutes.filter(route => !isConstantRoute(route)), { source: 'custom' }, items);
collectPageResources(generatedRoutes.filter(route => !isConstantRoute(route)), { source: 'generated' }, items);
const uniqueItems = Array.from(new Map(items.map(item => [item.name, item])).values());
return uniqueItems;
}
const pageResources = getPageResources();
const result = {
generatedAt: new Date().toISOString(),
description: 'Frontend visible page resource whitelist for backend route/menu configuration.',
rules: {
directoryComponent: 'layout.base',
pageComponentPattern: 'view.<routeName>',
singlePageComponentPattern: 'layout.<layoutName>$view.<routeName>'
},
total: pageResources.length,
items: pageResources
};
fs.writeFileSync(outputPath, `${JSON.stringify(result, null, 2)}\n`, 'utf8');
console.log(`Generated ${pageResources.length} page resources -> ${path.relative(rootDir, outputPath)}`);