mockingjar-lib
Version:
A TypeScript library for AI-powered JSON mock data generation using schema-based configuration
1 lines • 4.89 kB
JavaScript
;Object.defineProperty(exports,"__esModule",{value:!0}),exports.generateJsonData=generateJsonData;const validation_1=require("./validation"),schema_1=require("./schema"),lodash_1=require("lodash");function removeUnidentifiedFields(e,t){const n=(0,lodash_1.cloneDeep)(e),a=t.map(e=>e.affectedField);for(const e of a)(0,lodash_1.unset)(n,e);return n}function generatePartialSchema(e,t){if(0===t.length)return e;const n=e.fields||[],a=[],r=new Map;for(const e of t){const t=buildMinimalFieldStructure(n,e.split("."));t&&mergeIntoPartialFields(a,r,t)}return{...e,fields:a}}function buildMinimalFieldStructure(e,t){if(0===t.length)return null;const[n,...a]=t,r=n.replace(/\[\d+\]$/,""),s=e.find(e=>e.name===r);if(!s)return null;if(0===a.length)return(0,lodash_1.cloneDeep)(s);if("object"===s.type&&s.children){const e=buildMinimalFieldStructure(s.children,a);if(e)return{...(0,lodash_1.pick)(s,["id","name","type","logic"]),children:[e]}}return"array"===s.type&&s.arrayItemType,(0,lodash_1.cloneDeep)(s)}function mergeIntoPartialFields(e,t,n){const a=t.get(n.name);if(a){if("object"===n.type&&n.children&&a.children){const e=[...a.children],t=new Map(a.children.map(e=>[e.name,e]));for(const a of n.children)t.has(a.name)||(e.push(a),t.set(a.name,a));a.children=e}}else e.push(n),t.set(n.name,n)}function extractValidContext(e,t){const n=(0,lodash_1.cloneDeep)(e),a=t.map(e=>e.affectedField);for(const e of a)(0,lodash_1.unset)(n,e);return n}function stripMarkdown(e){let t=e.replace(/```(?:json)?\s*([\s\S]*?)\s*```/g,"$1");if(t===e){const n=e.match(/(\{[\s\S]*\}|\[[\s\S]*\])/);n&&(t=n[1])}return t.trim()}function createMessages(e,t,n,a){const r=[{role:"assistant",content:"Hello, I am structured data assistant. My task is to generate valid JSON values based on user's prompt. I will respond only with valid JSON, no markdown or explanations."}];if(e.length>0){const t=e[e.length-1];r.push({role:"user",content:`Here is the previously generated data example:\n ${JSON.stringify(t,null,2)}\n\n Please do not make an exact copy of this data, but use it as a reference to generate new data that follows the same structure, rules and relevance.`})}return a&&Object.keys(a).length>0&&r.push({role:"assistant",content:`I have the following context to work with, and will make sure the generated data is related and relevant to this:\n ${JSON.stringify(a,null,2)}\n `}),r.push({role:"assistant",content:`\n I will generate data based on the following JSON structure and its rules.\n\n OUTPUT STRUCTURE TO BE STRICTLY FOLLOWED:\n ${JSON.stringify(n,null,2)}\n\n RULES:\n 1. Follow each field's type and structure exactly.\n 2. Follow each field's name and type as specified in the output structure.\n 3. Follow each field's constraints and requirements defined.\n\n As I said, I will respond only with valid JSON, no markdown or explanations.\n `}),r.push({role:"user",content:`\n Generate a JSON object that relevant to this prompt:\n "${t}"\n `}),r}function simplifyFieldName(e){return e.replace(/\[\d+\]/g,"")}async function generateJsonData(e,t,n,a={}){const{maxAttempts:r=5,timeout:s=3e4,count:o=1}=a,i=[],l=Date.now(),d=[];async function c(t,a=null,o=0){if(o>=r)throw new Error(`Maximum recursion depth (${r}) exceeded. Unable to fix validation errors after ${o} attempts.`);o++;const l=a?(0,lodash_1.cloneDeep)(a):null,u=(0,schema_1.convertSchemaToJson)(t),f=e.messages.create({model:"claude-4-sonnet-20250514",max_tokens:4096,temperature:.1,messages:createMessages(d,n,u,l||void 0)});let h;const m=await(s?Promise.race([f,new Promise((e,t)=>{h=setTimeout(()=>t(new Error("Request timeout")),s)})]).finally(()=>{h&&clearTimeout(h)}):f),p=m.content?.[0];if(!p||"text"!==p.type)throw new Error("Claude response did not include valid text content");const g=stripMarkdown(p.text);let w;try{w=JSON.parse(g)}catch{throw new Error("Invalid JSON response from Claude")}const y=(0,validation_1.jsonValidator)(w,t),v=y.filter(e=>"Unidentified field"===e.reason),F=y.filter(e=>"Unidentified field"!==e.reason),S=[];for(const e of F)if(e.structure){const t=simplifyFieldName(e.affectedField);S.includes(t)||S.push(t),i.includes(t)||i.push(t)}if(v.length>0&&(w=removeUnidentifiedFields(w,v)),0===F.length){const e=(0,lodash_1.merge)(l,w);return void d.push(e)}const x=extractValidContext(w,F);return c(generatePartialSchema(t,S),(0,lodash_1.merge)(l,x),o)}try{for(let e=0;e<o;e++)await c(t);const e=Date.now()-l;return{success:!0,data:d,metadata:{totalFields:t.fields.length,validFields:t.fields.length,regeneratedFields:i,generationTime:e}}}catch(e){return{success:!1,errors:[e instanceof Error?`Generation failed: ${e.message}`:"Generation failed: Unknown error occurred"],metadata:{totalFields:t.fields.length,validFields:0,regeneratedFields:i,generationTime:Date.now()-l}}}}