20 lines
2.1 KiB
TypeScript
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。';
|