@route-forge/core 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/codegen.cjs +89 -61
- package/dist/codegen.cjs.map +1 -1
- package/dist/codegen.d.cts +22 -13
- package/dist/codegen.d.ts +22 -13
- package/dist/codegen.js +89 -61
- package/dist/codegen.js.map +1 -1
- package/dist/index.cjs +308 -153
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +498 -19
- package/dist/index.d.ts +498 -19
- package/dist/index.js +308 -154
- package/dist/index.js.map +1 -1
- package/dist/manifest-bjy4P_B4.d.cts +76 -0
- package/dist/manifest-bjy4P_B4.d.ts +76 -0
- package/dist/route-forge.global.js +308 -153
- package/dist/route-forge.global.js.map +1 -1
- package/dist/route-forge.global.min.js +2 -2
- package/package.json +1 -1
- package/dist/types-B_vdcRqx.d.cts +0 -501
- package/dist/types-B_vdcRqx.d.ts +0 -501
package/dist/codegen.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/codegen/index.ts"],"names":[],"mappings":"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","file":"codegen.js","sourcesContent":["#!/usr/bin/env node\n/**\n * @route-forge/core codegen CLI\n * @see .docs/SPEC.md §4.2\n *\n * 用法:\n * npx @route-forge/core codegen \\\n * --endpoint http://localhost/_forge/routes \\\n * --levels public,client,manage,admin \\\n * --out src/types/forge-routes.d.ts\n */\n\nimport type { RouteMeta } from '../types.js';\n\nexport interface CodegenOptions {\n endpoint: string;\n levels: string[];\n out: string;\n}\n\nconst BODY_METHODS = new Set(['POST', 'PUT', 'PATCH']);\n\n/**\n * 解析 argv(最小手写实现,不引入 commander/yargs)\n * 支持:--endpoint VALUE / --endpoint=VALUE / --levels a,b,c / --out PATH\n */\nexport function parseArgs(argv: string[]): CodegenOptions {\n const opts: Partial<CodegenOptions> = {};\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n const next = (): string => {\n const v = argv[++i];\n if (v === undefined) {\n throw new Error(`[route-forge/codegen] missing value for ${arg}`);\n }\n return v;\n };\n\n if (arg === '--endpoint') {\n opts.endpoint = next();\n } else if (arg?.startsWith('--endpoint=')) {\n opts.endpoint = arg.slice('--endpoint='.length);\n } else if (arg === '--levels') {\n opts.levels = next().split(',').map((s) => s.trim()).filter(Boolean);\n } else if (arg?.startsWith('--levels=')) {\n opts.levels = arg.slice('--levels='.length).split(',').map((s) => s.trim()).filter(Boolean);\n } else if (arg === '--out') {\n opts.out = next();\n } else if (arg?.startsWith('--out=')) {\n opts.out = arg.slice('--out='.length);\n } else if (arg === '--responseTypes' || arg?.startsWith('--responseTypes=')) {\n // 该参数从未实现(解析后被静默忽略);现显式报错并给出迁移方式,不再无声吞掉\n console.error(\n '[route-forge/codegen] --responseTypes has been removed (it was never implemented). ' +\n 'Edit the \"response\" field in the generated d.ts directly, or use module augmentation on ForgeRouteMap.',\n );\n process.exit(1);\n } else if (arg === '--help' || arg === '-h') {\n printHelp();\n process.exit(0);\n }\n }\n\n if (!opts.endpoint) {\n console.error('[route-forge/codegen] --endpoint is required');\n printHelp();\n process.exit(1);\n }\n if (!opts.out) {\n console.error('[route-forge/codegen] --out is required');\n printHelp();\n process.exit(1);\n }\n\n return {\n endpoint: opts.endpoint,\n levels: opts.levels ?? [],\n out: opts.out,\n };\n}\n\nfunction printHelp(): void {\n console.log(`\nroute-forge codegen - generate TS route types from backend summary endpoint\n\nUsage:\n npx @route-forge/core codegen --endpoint URL --out PATH [--levels a,b,c]\n\nOptions:\n --endpoint URL Backend summary endpoint (e.g. http://localhost/_forge/routes)\n --levels a,b,c Optional: explicit level list (skip auto-discovery)\n --out PATH Output .d.ts file path\n -h, --help Show this help\n`);\n}\n\n/**\n * 拉取摘要端点(仅用于自动发现层级名;unassigned 现是 levels 中的真实层级,与其余层级一样按 HTTP 懒加载拉取)\n */\nexport async function fetchSummary(endpoint: string): Promise<{\n levels: Record<string, unknown>;\n}> {\n const resp = await fetch(endpoint, { method: 'GET' });\n if (!resp.ok) {\n throw new Error(`summary endpoint ${endpoint} returned ${resp.status}`);\n }\n return (await resp.json()) as { levels: Record<string, unknown> };\n}\n\n/**\n * 拉取单个层级的路由元信息\n */\nexport async function fetchLevel(endpoint: string, level: string): Promise<{ routes: Record<string, RouteMeta> }> {\n const base = endpoint.replace(/\\/$/, '');\n const url = `${base}/${encodeURIComponent(level)}`;\n const resp = await fetch(url, { method: 'GET' });\n if (!resp.ok) {\n throw new Error(`level endpoint ${url} returned ${resp.status}`);\n }\n const data = (await resp.json()) as { routes?: Record<string, RouteMeta> };\n return { routes: data.routes ?? {} };\n}\n\n/**\n * 生成 d.ts 内容\n * @param routesByLevel 按层级分组的路由元信息:{ level: { routeName: meta } }\n */\nexport function generateRouteTypes(routesByLevel: Record<string, Record<string, RouteMeta>>): string {\n const levelEntries = Object.entries(routesByLevel).map(([level, routes]) => {\n const routeEntries = Object.entries(routes).map(([name, meta]) => {\n const defaults = meta.parameter_defaults ?? {};\n const params = (meta.parameters ?? []).map((p) => {\n // URI 中的 {p?} 或有后端默认值的参数 → 生成可选字段,避免调用方被迫传参\n const optional = meta.uri?.includes(`{${p}?}`) || p in defaults;\n return `${p}${optional ? '?' : ''}: string | number;`;\n }).join(' ');\n const method = meta.methods?.find((m) => m.toUpperCase() !== 'HEAD') ?? 'GET';\n const methodUpper = method.toUpperCase();\n const bodyField = BODY_METHODS.has(methodUpper) ? '\\n body: unknown;' : '';\n return ` ${JSON.stringify(name)}: {\\n method: ${JSON.stringify(methodUpper)};\\n params: { ${params} };${bodyField}\\n response: unknown;\\n };`;\n });\n return ` ${JSON.stringify(level)}: {\\n${routeEntries.join('\\n')}\\n };`;\n });\n return `// AUTO-GENERATED by @route-forge/core codegen. Do not edit.\n\n/**\n * 二级路由类型映射:level → routeName → routeMeta\n * 可通过 module augmentation 增强:\n * declare module '@route-forge/core' {\n * interface ForgeRouteMap { admin: { 'users.show': { method: 'GET'; params: { user: string | number }; response: User } } }\n * }\n */\nexport interface ForgeRouteMap {\n${levelEntries.join('\\n')}\n}\n`;\n}\n\n/**\n * CLI 主入口\n */\nexport async function main(argv: string[] = process.argv.slice(2)): Promise<void> {\n const opts = parseArgs(argv);\n\n // 未指定 --levels 时从摘要端点自动发现层级(unassigned 现是 levels 中的真实层级,一并纳入)\n let levels = opts.levels;\n // 摘要端点数据(用于自动发现层级)\n let summaryData: Awaited<ReturnType<typeof fetchSummary>> | null = null;\n if (levels.length === 0) {\n try {\n summaryData = await fetchSummary(opts.endpoint);\n levels = Object.keys(summaryData.levels);\n } catch (e) {\n console.error(`[route-forge/codegen] failed to auto-discover levels from summary endpoint: ${(e as Error).message}`);\n console.error('hint: pass --levels explicitly to skip auto-discovery');\n process.exit(1);\n }\n }\n\n if (levels.length === 0) {\n console.error('[route-forge/codegen] no levels found; pass --levels explicitly');\n process.exit(1);\n }\n\n // 所有层级(含 unassigned 真实层级)统一按 HTTP 懒加载拉取(SPEC §3.1.6)\n const levelFetches = await Promise.allSettled(\n levels.map((lvl) => fetchLevel(opts.endpoint, lvl)),\n );\n\n const routesByLevel: Record<string, Record<string, RouteMeta>> = {};\n let failedLevels = 0;\n levelFetches.forEach((res, idx) => {\n const lvl = levels[idx]!;\n if (res.status === 'fulfilled') {\n routesByLevel[lvl] = res.value.routes;\n } else {\n failedLevels++;\n console.warn(`[route-forge/codegen] failed to fetch level \"${lvl}\": ${(res.reason as Error).message}`);\n }\n });\n\n const totalRoutes = Object.values(routesByLevel).reduce((sum, r) => sum + Object.keys(r).length, 0);\n if (totalRoutes === 0) {\n console.error('[route-forge/codegen] no routes collected from any level');\n process.exit(1);\n }\n\n const dts = generateRouteTypes(routesByLevel);\n\n const fs = await import('node:fs/promises');\n const path = await import('node:path');\n const outPath = path.resolve(opts.out);\n const dir = path.dirname(outPath);\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(outPath, dts, 'utf8');\n\n console.log(`[route-forge/codegen] written ${totalRoutes} routes across ${Object.keys(routesByLevel).length} level(s) to ${outPath}`);\n if (failedLevels > 0) {\n console.warn(`[route-forge/codegen] ${failedLevels} level(s) failed; output may be incomplete`);\n }\n}\n\nconst invokedFromCli = (() => {\n try {\n if (!process.argv[1]) return false;\n const argv1 = process.argv[1].replace(/\\\\/g, '/');\n return argv1.endsWith('/codegen.js') || argv1.endsWith('/codegen.cjs') || argv1.endsWith('/codegen');\n } catch {\n return false;\n }\n})();\n\nif (invokedFromCli) {\n main().catch((err) => {\n console.error(err);\n process.exit(1);\n });\n}\n\nexport { main as runCodegen };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/url/utils.ts","../src/codegen/summary-client.ts","../src/codegen/emit.ts","../src/codegen/cli.ts","../src/codegen/index.ts"],"names":[],"mappings":"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","file":"codegen.js","sourcesContent":["/**\n * URL 基础拼接工具:统一「base + path」的斜杠规范化。\n *\n * 语义:\n * - base 去掉一个结尾 `/`(若有)\n * - path 补一个开头 `/`(若缺)\n * - 结果 = 规范化 base + 规范化 path\n */\n\n/** 去掉结尾的一个 `/`(若有)。 */\nexport function trimTrailingSlash(s: string): string {\n return s.endsWith('/') ? s.slice(0, -1) : s;\n}\n\n/** 保证开头有一个 `/`(若缺则补)。 */\nexport function withLeadingSlash(s: string): string {\n return s.startsWith('/') ? s : `/${s}`;\n}\n\n/** 规范化 base(去尾斜杠)与 path(补头斜杠)后拼接。 */\nexport function joinBaseAndPath(base: string, path: string): string {\n return `${trimTrailingSlash(base)}${withLeadingSlash(path)}`;\n}\n","/**\n * codegen 后端摘要 / 层级明细拉取(Node 环境,直接用全局 fetch)。\n *\n * 与运行时懒加载对齐:层级明细 URL 优先取摘要 `levels[].route.uri`(routeUri),\n * 缺省时回退 `endpoint/{level}` 兜底组合(等价于运行时 RouteStore.fetchLevel 的两分支)。\n */\n\nimport type { RouteMeta, SummaryResponse } from '../types.js';\nimport { joinBaseAndPath } from '../url-utils.js';\n\n/** 拉取摘要端点(自动发现层级名 + 各层级 route.uri)。 */\nexport async function fetchSummary(endpoint: string): Promise<SummaryResponse> {\n const resp = await fetch(endpoint, { method: 'GET' });\n if (!resp.ok) {\n throw new Error(`summary endpoint ${endpoint} returned ${resp.status}`);\n }\n return (await resp.json()) as SummaryResponse;\n}\n\n/**\n * route.uri 是后端下发的绝对路径(如 `/_forge/routes/admin`):\n * - endpoint 为绝对 URL(http(s)://host/...)→ 取其 origin 再拼 route.uri\n * - endpoint 为相对路径(无 origin,测试常用)→ route.uri 本身即完整路径,直接沿用\n */\nfunction levelUrlFromUri(endpoint: string, uri: string): string {\n try {\n return joinBaseAndPath(new URL(endpoint).origin, uri);\n } catch {\n return uri;\n }\n}\n\n/**\n * 拉取单个层级的路由元信息。\n * @param routeUri 摘要 `levels[level].route.uri`(绝对路径);缺省时回退 endpoint 拼接\n */\nexport async function fetchLevel(\n endpoint: string,\n level: string,\n routeUri?: string,\n): Promise<{ routes: Record<string, RouteMeta> }> {\n const url = routeUri\n ? levelUrlFromUri(endpoint, routeUri)\n : `${endpoint.replace(/\\/$/, '')}/${encodeURIComponent(level)}`;\n const resp = await fetch(url, { method: 'GET' });\n if (!resp.ok) {\n throw new Error(`level endpoint ${url} returned ${resp.status}`);\n }\n const data = (await resp.json()) as { routes?: Record<string, RouteMeta> };\n return { routes: data.routes ?? {} };\n}\n","/**\n * codegen d.ts 内容生成(纯字符串拼装,无副作用,最易单测)。\n */\n\nimport type { RouteMeta } from '../types.js';\n\nconst BODY_METHODS = new Set(['POST', 'PUT', 'PATCH']);\n\n/**\n * 生成 d.ts 内容\n * @param routesByLevel 按层级分组的路由元信息:{ level: { routeName: meta } }\n */\nexport function generateRouteTypes(routesByLevel: Record<string, Record<string, RouteMeta>>): string {\n const levelEntries = Object.entries(routesByLevel).map(([level, routes]) => {\n const routeEntries = Object.entries(routes).map(([name, meta]) => {\n const defaults = meta.parameter_defaults ?? {};\n const params = (meta.parameters ?? []).map((p) => {\n // URI 中的 {p?} 或有后端默认值的参数 → 生成可选字段,避免调用方被迫传参\n const optional = meta.uri?.includes(`{${p}?}`) || p in defaults;\n return `${p}${optional ? '?' : ''}: string | number;`;\n }).join(' ');\n const method = meta.methods?.find((m) => m.toUpperCase() !== 'HEAD') ?? 'GET';\n const methodUpper = method.toUpperCase();\n const bodyField = BODY_METHODS.has(methodUpper) ? '\\n body: unknown;' : '';\n return ` ${JSON.stringify(name)}: {\\n method: ${JSON.stringify(methodUpper)};\\n params: { ${params} };${bodyField}\\n response: unknown;\\n };`;\n });\n return ` ${JSON.stringify(level)}: {\\n${routeEntries.join('\\n')}\\n };`;\n });\n return `// AUTO-GENERATED by @route-forge/core codegen. Do not edit.\n\n/**\n * 二级路由类型映射:level → routeName → routeMeta\n * 可通过 module augmentation 增强:\n * declare module '@route-forge/core' {\n * interface ForgeRouteMap { admin: { 'users.show': { method: 'GET'; params: { user: string | number }; response: User } } }\n * }\n */\nexport interface ForgeRouteMap {\n${levelEntries.join('\\n')}\n}\n`;\n}\n","/**\n * @route-forge/core codegen CLI:参数解析、帮助与主流程编排。\n * @see .docs/SPEC.md §4.2\n *\n * 用法:\n * npx @route-forge/core codegen \\\n * --endpoint http://localhost/_forge/routes \\\n * --levels public,client,manage,admin \\\n * --out src/types/forge-routes.d.ts\n */\n\nimport { fetchLevel, fetchSummary } from './summary-client.js';\nimport { generateRouteTypes } from './emit.js';\nimport type { RouteMeta } from '../types.js';\n\nexport interface CodegenOptions {\n endpoint: string;\n levels: string[];\n out: string;\n}\n\n/**\n * 解析 argv(最小手写实现,不引入 commander/yargs)\n * 支持:--endpoint VALUE / --endpoint=VALUE / --levels a,b,c / --out PATH\n */\nexport function parseArgs(argv: string[]): CodegenOptions {\n const opts: Partial<CodegenOptions> = {};\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n const next = (): string => {\n const v = argv[++i];\n if (v === undefined) {\n throw new Error(`[route-forge/codegen] missing value for ${arg}`);\n }\n return v;\n };\n\n if (arg === '--endpoint') {\n opts.endpoint = next();\n } else if (arg?.startsWith('--endpoint=')) {\n opts.endpoint = arg.slice('--endpoint='.length);\n } else if (arg === '--levels') {\n opts.levels = next().split(',').map((s) => s.trim()).filter(Boolean);\n } else if (arg?.startsWith('--levels=')) {\n opts.levels = arg.slice('--levels='.length).split(',').map((s) => s.trim()).filter(Boolean);\n } else if (arg === '--out') {\n opts.out = next();\n } else if (arg?.startsWith('--out=')) {\n opts.out = arg.slice('--out='.length);\n } else if (arg === '--responseTypes' || arg?.startsWith('--responseTypes=')) {\n // 该参数从未实现(解析后被静默忽略);现显式报错并给出迁移方式,不再无声吞掉\n console.error(\n '[route-forge/codegen] --responseTypes has been removed (it was never implemented). ' +\n 'Edit the \"response\" field in the generated d.ts directly, or use module augmentation on ForgeRouteMap.',\n );\n process.exit(1);\n } else if (arg === '--help' || arg === '-h') {\n printHelp();\n process.exit(0);\n }\n }\n\n if (!opts.endpoint) {\n console.error('[route-forge/codegen] --endpoint is required');\n printHelp();\n process.exit(1);\n }\n if (!opts.out) {\n console.error('[route-forge/codegen] --out is required');\n printHelp();\n process.exit(1);\n }\n\n return {\n endpoint: opts.endpoint,\n levels: opts.levels ?? [],\n out: opts.out,\n };\n}\n\nfunction printHelp(): void {\n console.log(`\nroute-forge codegen - generate TS route types from backend summary endpoint\n\nUsage:\n npx @route-forge/core codegen --endpoint URL --out PATH [--levels a,b,c]\n\nOptions:\n --endpoint URL Backend summary endpoint (e.g. http://localhost/_forge/routes)\n --levels a,b,c Optional: explicit level list (skip auto-discovery)\n --out PATH Output .d.ts file path\n -h, --help Show this help\n`);\n}\n\n/**\n * CLI 主入口\n */\nexport async function main(argv: string[] = process.argv.slice(2)): Promise<void> {\n const opts = parseArgs(argv);\n\n // 尽力拉取摘要:既用于自动发现层级名,也用于取各层级 route.uri 拼明细端点\n // (与运行时 RouteStore.fetchLevel 对齐——优先 route.uri,缺省回退 endpoint 拼接)。\n // 未显式传 --levels 时:摘要拉取失败即致命(无从发现层级)。\n // 显式传 --levels 时:摘要拉取失败仅降级为「全部层级用 endpoint 兜底拼接」,不致命。\n let summary: Awaited<ReturnType<typeof fetchSummary>> | null = null;\n try {\n summary = await fetchSummary(opts.endpoint);\n } catch (e) {\n if (opts.levels.length === 0) {\n console.error(`[route-forge/codegen] failed to auto-discover levels from summary endpoint: ${(e as Error).message}`);\n console.error('hint: pass --levels explicitly to skip auto-discovery');\n process.exit(1);\n }\n console.warn(\n `[route-forge/codegen] summary endpoint unreachable: ${(e as Error).message}; falling back to endpoint-derived level URLs`,\n );\n }\n\n // 未指定 --levels 时从摘要自动发现层级(unassigned 现是 levels 中的真实层级,一并纳入)\n let levels = opts.levels;\n if (levels.length === 0 && summary) {\n levels = Object.keys(summary.levels);\n }\n\n if (levels.length === 0) {\n console.error('[route-forge/codegen] no levels found; pass --levels explicitly');\n process.exit(1);\n }\n\n // 所有层级(含 unassigned 真实层级)统一按 HTTP 懒加载拉取(SPEC §3.1.6):\n // 优先用摘要 levels[].route.uri,缺省时回退 endpoint 拼接\n const levelFetches = await Promise.allSettled(\n levels.map((lvl) => fetchLevel(opts.endpoint, lvl, summary?.levels[lvl]?.route?.uri)),\n );\n\n const routesByLevel: Record<string, Record<string, RouteMeta>> = {};\n let failedLevels = 0;\n levelFetches.forEach((res, idx) => {\n const lvl = levels[idx]!;\n if (res.status === 'fulfilled') {\n routesByLevel[lvl] = res.value.routes;\n } else {\n failedLevels++;\n console.warn(`[route-forge/codegen] failed to fetch level \"${lvl}\": ${(res.reason as Error).message}`);\n }\n });\n\n const totalRoutes = Object.values(routesByLevel).reduce((sum, r) => sum + Object.keys(r).length, 0);\n if (totalRoutes === 0) {\n console.error('[route-forge/codegen] no routes collected from any level');\n process.exit(1);\n }\n\n const dts = generateRouteTypes(routesByLevel);\n\n const fs = await import('node:fs/promises');\n const path = await import('node:path');\n const outPath = path.resolve(opts.out);\n const dir = path.dirname(outPath);\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(outPath, dts, 'utf8');\n\n console.log(`[route-forge/codegen] written ${totalRoutes} routes across ${Object.keys(routesByLevel).length} level(s) to ${outPath}`);\n if (failedLevels > 0) {\n console.warn(`[route-forge/codegen] ${failedLevels} level(s) failed; output may be incomplete`);\n }\n}\n","#!/usr/bin/env node\n/**\n * @route-forge/core codegen 入口(tsup bin 入口 `src/codegen/index.ts`)。\n *\n * 实现按功能拆分:\n * - codegen/summary-client.ts 摘要 / 层级明细拉取(route.uri 优先,endpoint 兜底)\n * - codegen/emit.ts d.ts 内容生成(纯字符串)\n * - codegen/cli.ts 参数解析 / 帮助 / 主流程编排\n * 本文件仅做 re-export(保持 `parseArgs` / `main` / `generateRouteTypes` /\n * `fetchSummary` / `fetchLevel` / `runCodegen` / `CodegenOptions` 等导入路径稳定)\n * 并承载「作为 CLI 直接执行时」的自调用守卫。\n *\n * @see .docs/SPEC.md §4.2\n */\n\nexport {\n parseArgs,\n main,\n type CodegenOptions,\n} from './cli.js';\nexport { generateRouteTypes } from './emit.js';\nexport { fetchSummary, fetchLevel } from './summary-client.js';\nexport { main as runCodegen } from './cli.js';\n\nimport { main as runCodegenMain } from './cli.js';\n\nconst invokedFromCli = (() => {\n try {\n if (!process.argv[1]) return false;\n const argv1 = process.argv[1].replace(/\\\\/g, '/');\n return argv1.endsWith('/codegen.js') || argv1.endsWith('/codegen.cjs') || argv1.endsWith('/codegen');\n } catch {\n return false;\n }\n})();\n\nif (invokedFromCli) {\n runCodegenMain().catch((err) => {\n console.error(err);\n process.exit(1);\n });\n}\n"]}
|