Files
upstream-mirror 702cc698a7
Some checks failed
Build & Test / Analyze (javascript, affine) (push) Failing after 4s
Build & Test / Analyze (typescript, affine) (push) Failing after 3s
Build & Test / Rust test filter (push) Failing after 4s
Build & Test / Check yarn binary (push) Failing after 3s
Build & Test / E2E BlockSuite Test (3) (push) Failing after 3s
Build & Test / Analyze (javascript, blocksuite) (push) Failing after 3s
Build & Test / Analyze (typescript, blocksuite) (push) Failing after 3s
Build & Test / Mobile native build filter (push) Failing after 3s
Build & Test / E2E BlockSuite Test (1) (push) Failing after 4s
Build & Test / E2E BlockSuite Test (2) (push) Failing after 4s
Build & Test / E2E Mobile Test (1) (push) Failing after 3s
Build & Test / Unit Test (1) (push) Has been skipped
Build & Test / Unit Test (2) (push) Has been skipped
Build & Test / Unit Test (3) (push) Has been skipped
Build & Test / Unit Test (4) (push) Has been skipped
Build & Test / Unit Test (5) (push) Has been skipped
Build & Test / Native Unit Test (push) Has been skipped
Build & Test / E2E BlockSuite Test (4) (push) Failing after 3s
Build & Test / E2E BlockSuite Test (5) (push) Failing after 3s
Build & Test / E2E BlockSuite Cross Browser Test (push) Failing after 3s
Build & Test / E2E Mobile Test (2) (push) Failing after 3s
Build & Test / Build AFFiNE native (x86_64-unknown-linux-gnu) (push) Failing after 3s
Build & Test / Build Server native (push) Failing after 3s
Build & Test / Check Git Status (push) Has been skipped
Build & Test / Server Test (0, 4) (push) Has been skipped
Build & Test / Server Test (1, 4) (push) Has been skipped
Build & Test / Server Test (2, 4) (push) Has been skipped
Build & Test / Server Test (3, 4) (push) Has been skipped
Build & Test / Server Test with Elasticsearch (push) Has been skipped
Build & Test / Build @affine/electron renderer (push) Failing after 3s
Build & Test / Copilot test filter (push) Failing after 4s
Build & Test / Lint Rust (push) Has been skipped
Build & Test / Server Test with Embedded Search (push) Has been skipped
Build & Test / Server Test with Manticore Search (push) Has been skipped
Build & Test / Server E2E Test (push) Has been skipped
Build & Test / Cloud Desktop E2E Test (push) Has been skipped
Build & Test / Cloud E2E Test 1/2 (push) Has been skipped
Build & Test / Cloud E2E Test 2/2 (push) Has been skipped
Build & Test / Build Android app (push) Has been skipped
Build & Test / Test Android app (push) Has been skipped
Build & Test / Run native tests (push) Has been skipped
Build & Test / Server Copilot Api Test (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (1, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (2, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (3, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (4, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (5, 5) (push) Has been skipped
Release / Canary Gate (push) Has been skipped
Build & Test / Build AFFiNE native (aarch64-apple-darwin) (push) Has been cancelled
Build & Test / Lint (push) Has been cancelled
Build & Test / Typecheck (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-apple-darwin) (push) Has been cancelled
Build & Test / Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true) (push) Has been cancelled
Build & Test / Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true) (push) Has been cancelled
Build & Test / E2E Test (1) (push) Has been cancelled
Build & Test / E2E Test (2) (push) Has been cancelled
Build & Test / E2E Test (3) (push) Has been cancelled
Build & Test / E2E Test (4) (push) Has been cancelled
Build & Test / E2E Test (5) (push) Has been cancelled
Build & Test / Build AFFiNE native (aarch64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, x64, x86_64-apple-darwin, false) (push) Has been cancelled
Build & Test / 3, 2, 1 Launch (push) Has been cancelled
Build & Test / Build iOS app (push) Has been cancelled
Copilot Test Automatically / Setup Test (push) Failing after 1s
Release / Prepare (push) Failing after 2s
Release / Release Cloud (push) Has been skipped
Release / Release Desktop (push) Has been skipped
Release / Release Docker Image (push) Has been skipped
Release / Release Mobile (push) Has been skipped
snapshot of https://github.com/toeverything/AFFiNE.git (canary, 2026-09-16; blobs > 131072B omitted)
2026-09-16 04:01:20 +05:00

261 lines
6.4 KiB
TypeScript

import fs from 'node:fs';
import { join } from 'node:path/posix';
import { formatCode, Path } from '@affine-tools/utils';
import { parse } from 'path-to-regexp';
const curdir = Path.dir(import.meta.url);
const inputFile = curdir.join('routes.json').value;
const routerOutputFile = curdir.join('src', 'routes.ts').value;
interface RawRoutesSchema {
route: string;
children: {
[key: string]: string | RawRoutesSchema;
};
}
interface RouteSchema {
name: string;
fromParent: string;
fromRoot: string;
children: Array<RouteSchema>;
}
function loadRoutesSchema(): RouteSchema {
const rawSchema = JSON.parse(
fs.readFileSync(inputFile, 'utf-8')
) as RawRoutesSchema;
const build = (
name: string,
schema: RawRoutesSchema | string,
fromRoot: string = ''
): RouteSchema => {
if (typeof schema === 'string') {
return {
name,
fromParent: schema,
fromRoot: join(fromRoot, schema),
children: [],
};
}
const absolute = join(fromRoot, schema.route);
return {
name,
fromParent: schema.route,
fromRoot: absolute,
children: Object.entries(schema.children).map(([key, value]) => {
return build(key, value, absolute);
}),
};
};
return build('home', rawSchema);
}
interface BuiltRouteSchema {
name: string;
type?: string;
factory: string;
fromRoot: string;
fromParent: string;
children: BuiltRouteSchema[];
parent: BuiltRouteSchema | null;
}
function buildRoutes(
schema: RouteSchema,
parent: BuiltRouteSchema | null = null
): BuiltRouteSchema {
const { tokens } = parse(schema.fromRoot);
const types: string[] = [];
const factories: string[] = [];
for (const token of tokens) {
switch (token.type) {
case 'param':
case 'wildcard':
types.push(token.name);
factories.push(`\${params.${token.name}}`);
break;
case 'text': {
factories.push(token.value);
break;
}
}
}
// [a, b, c] -> '{ a: string; b: string; c: string }'
const type = types.length
? `{ ${types.map(type => `${type}: string`).join('; ')} }`
: undefined;
const builtResult: BuiltRouteSchema = {
name: schema.name,
type,
factory: factories.join(''),
fromRoot: schema.fromRoot,
fromParent: schema.fromParent,
parent: parent,
children: [],
};
builtResult.children = schema.children.map(child =>
buildRoutes(child, builtResult)
);
return builtResult;
}
function printSchemaTypes(schema: BuiltRouteSchema, level: number = 1): string {
const types: string[] = [];
if (schema.type) {
if (schema.children.length) {
types.push(`index: ${schema.type};`);
} else {
return schema.type;
}
}
for (const child of schema.children) {
const childType = printSchemaTypes(child, level + 1);
if (childType) {
types.push(`${child.name}: ${childType};`);
}
}
if (types.length > 0) {
const output = `{ ${types.join('\n')} }`;
return level === 1 ? `export interface RouteParamsTypes ${output}` : output;
}
return '';
}
function printAbsolutePaths(schema: BuiltRouteSchema, level = 1): string {
const absolutes: string[] = [];
if (schema.children.length) {
absolutes.push(`index: '${schema.fromRoot}'`);
} else {
return `'${schema.fromRoot}'`;
}
for (const child of schema.children) {
const childRoute = printAbsolutePaths(child, level + 1);
absolutes.push(`${child.name}: ${childRoute}`);
}
const output = `{ ${absolutes.join('\n,')} }`;
return level === 1 ? `export const ROUTES = ${output}` : output;
}
function printRelativePaths(schema: BuiltRouteSchema, level = 1): string {
const relatives: string[] = [];
if (schema.children.length) {
relatives.push(`index: '${schema.fromParent}'`);
} else {
return `'${schema.fromParent}'`;
}
for (const child of schema.children) {
const childRoute = printRelativePaths(child, level + 1);
relatives.push(`${child.name}: ${childRoute}`);
}
const output = `{ ${relatives.join('\n,')} }`;
return level === 1 ? `export const RELATIVE_ROUTES = ${output}` : output;
}
function printFactories(schema: BuiltRouteSchema): string {
const factories: string[] = [];
const factory = schema.type
? `(params: ${schema.type}) => \`${schema.factory}\``
: `() => '${schema.factory}'`;
let parent: BuiltRouteSchema | null = schema.parent;
let nameFromRoot: string[] = [schema.name];
while (parent) {
// ignore home
if (parent.parent) {
nameFromRoot = [parent.name, ...nameFromRoot];
}
parent = parent.parent;
}
if (schema.children.length) {
// with children, we do
const visitor = nameFromRoot.join('_');
// 1. const workspace_doc = () => 'workspace/doc'
factories.push(`const ${visitor} = ${factory}`);
for (const child of schema.children) {
// 2. generate children for workspace_doc
factories.push(printFactories(child));
}
// 3. workspace.doc = workspace_doc
const parentNameFromRoot = nameFromRoot.slice(0, -1).join('_');
if (parentNameFromRoot) {
factories.push(`${parentNameFromRoot}.${schema.name} = ${visitor}`);
}
} else {
// without children, we directly
const parentNameFromRoot = nameFromRoot.slice(0, -1).join('_');
if (parentNameFromRoot) {
// parent.child = () => 'child'
factories.push(`${parentNameFromRoot}.${schema.name} = ${factory}`);
} else {
// const route = () => 'route'
factories.push(`const ${schema.name} = ${factory}`);
}
}
const output = factories.join('\n');
if (!schema.parent) {
const firstLevelNames = schema.children.map(child => child.name);
firstLevelNames.push(schema.name);
return `${output}\nexport const FACTORIES = { ${firstLevelNames.join(
', '
)} };`;
}
return output;
}
async function printRoutes(schema: BuiltRouteSchema) {
const parts = {
['Path Parameter Types']: printSchemaTypes,
['Absolute Paths']: printAbsolutePaths,
['Relative Paths']: printRelativePaths,
['Path Factories']: printFactories,
};
const content = await formatCode(
Object.entries(parts)
.map(([key, print]) => {
return `// #region ${key}\n${print(schema)}\n// #endregion`;
})
.join('\n\n'),
routerOutputFile
);
fs.writeFileSync(routerOutputFile, content, 'utf-8');
}
async function build() {
const schema = loadRoutesSchema();
const builtSchema = buildRoutes(schema);
await printRoutes(builtSchema);
}
await build();