Files
2026-11-05 01:04:53 +08:00

20 lines
2.1 KiB
TypeScript

export type Field={name:string;type:'string'|'number'|'boolean'|'object'|'array';description:string;fields?:Field[]};
export class InputError extends Error{}
export function buildSchema(fields:Field[],depth=0):any{
if(!Array.isArray(fields)||!fields.length||fields.length>40||depth>5)throw new InputError('每层需要 1–40 个字段,最多嵌套 5 层');
const properties:Record<string,any>={};
for(const f of fields){
if(!f||typeof f.name!=='string'||!/^[a-zA-Z_][a-zA-Z0-9_]{0,63}$/.test(f.name)||Object.hasOwn(properties,f.name)||['__proto__','constructor','prototype'].includes(f.name))throw new InputError('字段名需唯一,仅用字母、数字和下划线,以字母或下划线开头');
if(typeof f.description!=='string'||f.description.length>2000)throw new InputError('字段描述必须是最多 2000 字符的文本');
let s:any;
if(f.type==='object')s=buildSchema(f.fields!,depth+1);
else if(f.type==='array')s={type:'array',items:f.fields?.length?buildSchema(f.fields,depth+1):{type:'string'}};
else if(['string','number','boolean'].includes(f.type))s={type:[f.type,'null']};
else throw new InputError('不支持的字段类型');
properties[f.name]={...s,description:f.description};
}
return {type:'object',properties,required:Object.keys(properties),additionalProperties:false};
}
export const sampleFields:Field[]=[{name:'patientName',type:'string',description:'患者姓名'},{name:'allergies',type:'array',description:'过敏史'},{name:'vitalSigns',type:'array',description:'按时间记录的生命体征',fields:[{name:'time',type:'string',description:'测量时间'},{name:'heartRate',type:'number',description:'心率,次/分钟'},{name:'bloodPressure',type:'string',description:'血压,mmHg'}]},{name:'medications',type:'array',description:'用药记录',fields:[{name:'name',type:'string',description:'药物名称'},{name:'dose',type:'string',description:'剂量及单位'}]}];
export const sampleText='入院记录\n患者姓名:陈晓雨\n过敏史:青霉素\n2026-11-02 09:00 心率 78 次/分,血压 120/80 mmHg。\n2026-11-02 11:00 心率 75 次/分,血压 118/78 mmHg。\n用药:氯化钠注射液 500 mL。';