chore: 更新版本号至0.0.80,并在 route.ts 中重构 toJSONSchema 和 fromJSONSchema 函数以使用新的 schema.ts 模块

This commit is contained in:
2026-02-18 13:28:49 +08:00
parent 058e6843b1
commit e1a0e11052
3 changed files with 106 additions and 103 deletions

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package",
"name": "@kevisual/router",
"version": "0.0.79",
"version": "0.0.80",
"description": "",
"type": "module",
"main": "./dist/router.js",

View File

@@ -3,6 +3,8 @@ import { pick } from './utils/pick.ts';
import { listenProcess, MockProcess } from './utils/listen-process.ts';
import { z } from 'zod';
import { randomId } from './utils/random.ts';
import * as schema from './validator/schema.ts';
export type RouterContextT = { code?: number;[key: string]: any };
export type RouteContext<T = { code?: number }, S = any> = {
/**
@@ -245,101 +247,17 @@ export class Route<U = { [key: string]: any }, T extends SimpleObject = SimpleOb
throw new CustomError(...args);
}
}
const extractArgs = (args: any) => {
if (args && typeof args === 'object' && typeof args.shape === 'object') {
return args.shape as z.ZodRawShape;
}
return args || {};
};
const toJSONSchemaRoute = (route: RouteInfo) => {
const pickValues = pick(route, pickValue as any);
if (pickValues?.metadata?.args) {
let args = pickValues.metadata.args;
// 如果 args 本身是一个 zod object schema先提取 shape
args = extractArgs(args);
const keys = Object.keys(args);
const newArgs: { [key: string]: any } = {};
for (let key of keys) {
const item = args[key] as z.ZodAny;
if (item && typeof item === 'object' && typeof item.toJSONSchema === 'function') {
newArgs[key] = item.toJSONSchema();
} else {
newArgs[key] = args[key]; // 可能不是schema
}
}
pickValues.metadata.args = newArgs;
pickValues.metadata.args = toJSONSchema(pickValues?.metadata?.args, { mergeObject: false });
}
return pickValues;
}
const fromJSONSchemaRoute = (route: RouteInfo): RouteInfo => {
const args = route?.metadata?.args;
if (!args) return route;
const newArgs = fromJSONSchema(args);
route.metadata.args = newArgs;
return route;
}
/**
* 剥离第一层schema转换为JSON Schema无论是skill还是其他的infer比纯粹的zod object schema更合适因为它可能包含其他的字段而不仅仅是schema
* @param args
* @returns
*/
export const toJSONSchema = (args: any, opts?: { mergeObject?: boolean }): { [key: string]: any } => {
const mergeObject = opts?.mergeObject ?? true;
if (!args) return {};
if (mergeObject) {
if (typeof args === 'object' && typeof args.toJSONSchema === 'function') {
return args.toJSONSchema();
}
const schema = z.object(args);
return schema.toJSONSchema();
}
// 如果 args 本身是一个 zod object schema先提取 shape
args = extractArgs(args);
const keys = Object.keys(args);
let newArgs: { [key: string]: any } = {};
for (let key of keys) {
const item = args[key] as z.ZodAny;
if (item && typeof item === 'object' && typeof item.toJSONSchema === 'function') {
newArgs[key] = item.toJSONSchema();
} else {
newArgs[key] = args[key]; // 可能不是schema
}
}
return newArgs;
}
export const fromJSONSchema = <Merge extends boolean = true>(args: any = {}, opts?: { mergeObject?: boolean }) => {
let resultArgs: any = null;
const mergeObject = opts?.mergeObject ?? true;
if (args["$schema"] || (args.type === 'object' && args.properties && typeof args.properties === 'object')) {
// 可能是整个schema
const objectSchema = z.fromJSONSchema(args);
const extract = extractArgs(objectSchema);
const keys = Object.keys(extract);
const newArgs: { [key: string]: any } = {};
for (let key of keys) {
newArgs[key] = extract[key];
}
resultArgs = newArgs;
}
if (!resultArgs) {
const keys = Object.keys(args);
const newArgs: { [key: string]: any } = {};
for (let key of keys) {
const item = args[key];
// fromJSONSchema 可能会失败,所以先 optional等使用的时候再验证
newArgs[key] = z.fromJSONSchema(item).optional();
}
resultArgs = newArgs;
}
if (mergeObject) {
resultArgs = z.object(resultArgs);
}
type ResultArgs = Merge extends true ? z.ZodObject<{ [key: string]: any }> : { [key: string]: z.ZodTypeAny };
return resultArgs as unknown as ResultArgs;
}
export const toJSONSchema = schema.toJSONSchema;
export const fromJSONSchema = schema.fromJSONSchema;
/**
* @parmas overwrite 是否覆盖已存在的route默认true
@@ -657,21 +575,6 @@ export class QueryRouter {
getList(filter?: (route: Route) => boolean): RouteInfo[] {
return this.routes.filter(filter || (() => true)).map((r) => {
const pickValues = pick(r, pickValue as any);
if (pickValues?.metadata?.args) {
// const demoArgs = { k: tool.schema.string().describe('示例参数') };
const args = pickValues.metadata.args;
const keys = Object.keys(args);
const newArgs: { [key: string]: any } = {};
for (let key of keys) {
const item = args[key] as z.ZodAny;
if (item && typeof item === 'object' && typeof item.toJSONSchema === 'function') {
newArgs[key] = item.toJSONSchema();
} else {
newArgs[key] = args[key]; // 可能不是schema
}
}
pickValues.metadata.args = newArgs;
}
return pickValues;
});
}

100
src/validator/schema.ts Normal file
View File

@@ -0,0 +1,100 @@
import { z } from "zod";
const extractArgs = (args: any) => {
if (args && typeof args === 'object' && typeof args.shape === 'object') {
return args.shape as z.ZodRawShape;
}
return args || {};
};
type ZodOverride = (opts: { jsonSchema: any; path: string[]; zodSchema: z.ZodTypeAny }) => void;
/**
* 剥离第一层schema转换为JSON Schema无论是skill还是其他的infer比纯粹的zod object schema更合适因为它可能包含其他的字段而不仅仅是schema
* @param args
* @returns
*/
export const toJSONSchema = (args: any, opts?: { mergeObject?: boolean, override?: ZodOverride }): { [key: string]: any } => {
const mergeObject = opts?.mergeObject ?? false;
if (!args) return {};
const _override = ({ jsonSchema, path, zodSchema }) => {
if (Array.isArray(path) && path.length > 0) {
return
}
const isOptional = (zodSchema as any).isOptional?.();
if (isOptional) {
// 添加自定义属性
jsonSchema.optional = true;
}
}
const isError = (keys: string[]) => {
const errorKeys: string[] = ["toJSONSchema", "def", "type", "parse"]
const hasErrorKeys = errorKeys.every(key => keys.includes(key));
return hasErrorKeys;
}
const override: any = opts?.override || _override;
if (mergeObject) {
if (typeof args === 'object' && typeof args.toJSONSchema === 'function') {
return args.toJSONSchema();
}
if (isError(Object.keys(args))) {
return {};
}
// 如果 mergeObject 为 true直接将整个对象转换为 JSON Schema
// 先检测是否是一个错误的 schema
const schema = z.object(args);
return schema.toJSONSchema();
}
// 如果 args 本身是一个 zod object schema先提取 shape
args = extractArgs(args);
let keys = Object.keys(args);
if (isError(keys)) {
console.error(`[toJSONSchema error]: 解析到的 schema 可能不正确包含了zod默认的value的schema. 请检查输入的 schema 是否正确。`);
args = {};
keys = [];
}
if (mergeObject) {
}
let newArgs: { [key: string]: any } = {};
for (let key of keys) {
const item = args[key] as z.ZodAny;
if (item && typeof item === 'object' && typeof item.toJSONSchema === 'function') {
newArgs[key] = item.toJSONSchema({ override });
} else {
newArgs[key] = args[key]; // 可能不是schema
}
}
return newArgs;
}
export const fromJSONSchema = <Merge extends boolean = false>(args: any = {}, opts?: { mergeObject?: boolean }) => {
let resultArgs: any = null;
const mergeObject = opts?.mergeObject ?? false;
if (args["$schema"] || (args.type === 'object' && args.properties && typeof args.properties === 'object')) {
// 可能是整个schema
const objectSchema = z.fromJSONSchema(args);
const extract = extractArgs(objectSchema);
const keys = Object.keys(extract);
const newArgs: { [key: string]: any } = {};
for (let key of keys) {
newArgs[key] = extract[key];
}
resultArgs = newArgs;
}
if (!resultArgs) {
const keys = Object.keys(args);
const newArgs: { [key: string]: any } = {};
for (let key of keys) {
const item = args[key];
// fromJSONSchema 可能会失败,所以先 optional等使用的时候再验证
newArgs[key] = z.fromJSONSchema(item)
if (item.optional) {
newArgs[key] = newArgs[key].optional();
}
}
resultArgs = newArgs;
}
if (mergeObject) {
resultArgs = z.object(resultArgs);
}
type ResultArgs = Merge extends true ? z.ZodObject<{ [key: string]: any }> : { [key: string]: z.ZodTypeAny };
return resultArgs as unknown as ResultArgs;
}