chore: 更新版本号至0.0.77,升级 @kevisual/query 至 0.0.47,重构 JSON Schema 处理函数并添加测试
This commit is contained in:
4
bun.lock
4
bun.lock
@@ -13,7 +13,7 @@
|
|||||||
"@kevisual/dts": "^0.0.4",
|
"@kevisual/dts": "^0.0.4",
|
||||||
"@kevisual/js-filter": "^0.0.5",
|
"@kevisual/js-filter": "^0.0.5",
|
||||||
"@kevisual/local-proxy": "^0.0.8",
|
"@kevisual/local-proxy": "^0.0.8",
|
||||||
"@kevisual/query": "^0.0.46",
|
"@kevisual/query": "^0.0.47",
|
||||||
"@kevisual/use-config": "^1.0.30",
|
"@kevisual/use-config": "^1.0.30",
|
||||||
"@opencode-ai/plugin": "^1.2.6",
|
"@opencode-ai/plugin": "^1.2.6",
|
||||||
"@types/bun": "^1.3.9",
|
"@types/bun": "^1.3.9",
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
|
|
||||||
"@kevisual/local-proxy": ["@kevisual/local-proxy@0.0.8", "", {}, "sha512-VX/P+6/Cc8ruqp34ag6gVX073BchUmf5VNZcTV/6MJtjrNE76G8V6TLpBE8bywLnrqyRtFLIspk4QlH8up9B5Q=="],
|
"@kevisual/local-proxy": ["@kevisual/local-proxy@0.0.8", "", {}, "sha512-VX/P+6/Cc8ruqp34ag6gVX073BchUmf5VNZcTV/6MJtjrNE76G8V6TLpBE8bywLnrqyRtFLIspk4QlH8up9B5Q=="],
|
||||||
|
|
||||||
"@kevisual/query": ["@kevisual/query@0.0.46", "", {}, "sha512-JwHV16ehk8JWM5wiWW5kz9yTg4HrOmmnci5QvwQYdhXYXDzGpUrOxeoz3wloMs4kX3bkowz97iLLW6uQdgUoTw=="],
|
"@kevisual/query": ["@kevisual/query@0.0.47", "", {}, "sha512-ZR7WXeDDGUSzBtcGVU3J173sA0hCqrGTw5ybGbdNGlM0VyJV/XQIovCcSoZh1YpnciLRRqJvzXUgTnCkam+M3g=="],
|
||||||
|
|
||||||
"@kevisual/use-config": ["@kevisual/use-config@1.0.30", "", { "dependencies": { "@kevisual/load": "^0.0.6" }, "peerDependencies": { "dotenv": "^17" } }, "sha512-kPdna0FW/X7D600aMdiZ5UTjbCo6d8d4jjauSc8RMmBwUU6WliFDSPUNKVpzm2BsDX5Nth1IXFPYMqH+wxqAmw=="],
|
"@kevisual/use-config": ["@kevisual/use-config@1.0.30", "", { "dependencies": { "@kevisual/load": "^0.0.6" }, "peerDependencies": { "dotenv": "^17" } }, "sha512-kPdna0FW/X7D600aMdiZ5UTjbCo6d8d4jjauSc8RMmBwUU6WliFDSPUNKVpzm2BsDX5Nth1IXFPYMqH+wxqAmw=="],
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package",
|
"$schema": "https://json.schemastore.org/package",
|
||||||
"name": "@kevisual/router",
|
"name": "@kevisual/router",
|
||||||
"version": "0.0.76",
|
"version": "0.0.77",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/router.js",
|
"main": "./dist/router.js",
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
"@kevisual/dts": "^0.0.4",
|
"@kevisual/dts": "^0.0.4",
|
||||||
"@kevisual/js-filter": "^0.0.5",
|
"@kevisual/js-filter": "^0.0.5",
|
||||||
"@kevisual/local-proxy": "^0.0.8",
|
"@kevisual/local-proxy": "^0.0.8",
|
||||||
"@kevisual/query": "^0.0.46",
|
"@kevisual/query": "^0.0.47",
|
||||||
"@kevisual/use-config": "^1.0.30",
|
"@kevisual/use-config": "^1.0.30",
|
||||||
"@opencode-ai/plugin": "^1.2.6",
|
"@opencode-ai/plugin": "^1.2.6",
|
||||||
"@types/bun": "^1.3.9",
|
"@types/bun": "^1.3.9",
|
||||||
|
|||||||
55
src/route.ts
55
src/route.ts
@@ -252,7 +252,7 @@ export const extractArgs = (args: any) => {
|
|||||||
return args || {};
|
return args || {};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const toJSONSchema = (route: RouteInfo) => {
|
const toJSONSchemaRoute = (route: RouteInfo) => {
|
||||||
const pickValues = pick(route, pickValue as any);
|
const pickValues = pick(route, pickValue as any);
|
||||||
if (pickValues?.metadata?.args) {
|
if (pickValues?.metadata?.args) {
|
||||||
let args = pickValues.metadata.args;
|
let args = pickValues.metadata.args;
|
||||||
@@ -273,23 +273,62 @@ export const toJSONSchema = (route: RouteInfo) => {
|
|||||||
}
|
}
|
||||||
return pickValues;
|
return pickValues;
|
||||||
}
|
}
|
||||||
|
const fromJSONSchemaRoute = (route: RouteInfo): RouteInfo => {
|
||||||
export const fromJSONSchema = (route: RouteInfo): RouteInfo => {
|
|
||||||
const args = route?.metadata?.args;
|
const args = route?.metadata?.args;
|
||||||
if (!args) return route;
|
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): { [key: string]: any } => {
|
||||||
|
// 如果 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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')) {
|
if (args["$schema"] || (args.type === 'object' && args.properties && typeof args.properties === 'object')) {
|
||||||
// 可能是整个schema
|
// 可能是整个schema
|
||||||
route.metadata.args = z.fromJSONSchema(args);
|
const objectSchema = z.fromJSONSchema(args);
|
||||||
return route;
|
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 keys = Object.keys(args);
|
||||||
const newArgs: { [key: string]: any } = {};
|
const newArgs: { [key: string]: any } = {};
|
||||||
for (let key of keys) {
|
for (let key of keys) {
|
||||||
const item = args[key];
|
const item = args[key];
|
||||||
newArgs[key] = z.fromJSONSchema(item);
|
newArgs[key] = z.fromJSONSchema(item);
|
||||||
}
|
}
|
||||||
route.metadata.args = newArgs;
|
resultArgs = newArgs;
|
||||||
return route;
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -698,7 +737,7 @@ export class QueryRouter {
|
|||||||
ctx.body = {
|
ctx.body = {
|
||||||
list: list.map((item) => {
|
list: list.map((item) => {
|
||||||
const route = pick(item, ['id', 'path', 'key', 'description', 'middleware', 'metadata'] as const);
|
const route = pick(item, ['id', 'path', 'key', 'description', 'middleware', 'metadata'] as const);
|
||||||
return toJSONSchema(route);
|
return toJSONSchemaRoute(route);
|
||||||
}),
|
}),
|
||||||
isUser
|
isUser
|
||||||
};
|
};
|
||||||
|
|||||||
14
src/test/schema.ts
Normal file
14
src/test/schema.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { toJSONSchema, fromJSONSchema } from "@/route.ts";
|
||||||
|
import { z } from "zod";
|
||||||
|
const schema = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
age: z.number(),
|
||||||
|
|
||||||
|
});
|
||||||
|
// console.log("schema", schema);
|
||||||
|
const jsonSchema = toJSONSchema(schema);
|
||||||
|
console.log("jsonSchema", jsonSchema);
|
||||||
|
|
||||||
|
const newSchema = fromJSONSchema<true>(jsonSchema, { mergeObject: true });
|
||||||
|
console.log("newSchema shape", Object.keys(newSchema.shape));
|
||||||
|
console.log('check', newSchema.safeParse({ name: "Alice", age: "30" })?.success);
|
||||||
Reference in New Issue
Block a user