@itz4blitz/agentful 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,240 +0,0 @@
1
- /**
2
- * Template Engine
3
- *
4
- * Simple template engine for variable interpolation in agent templates.
5
- * Supports nested objects, arrays, and conditional rendering.
6
- */
7
-
8
- class TemplateEngine {
9
- /**
10
- * Render template with data
11
- */
12
- static render(template, data) {
13
- let content = template;
14
-
15
- // Handle arrays and objects with special formatting FIRST
16
- // This allows formatComplexTypes to format arrays before conditionals/loops process them
17
- content = this.formatComplexTypes(content, data);
18
-
19
- // Handle conditionals and loops (after complex types are formatted)
20
- content = this.processConditionals(content, data);
21
- content = this.processLoops(content, data);
22
-
23
- // Replace simple variables: {{variable}}
24
- content = this.replaceVariables(content, data);
25
-
26
- // Add timestamp if needed
27
- if (content.includes('{{generated_at}}')) {
28
- content = content.replace(/\{\{generated_at\}\}/g, new Date().toISOString());
29
- }
30
-
31
- return content;
32
- }
33
-
34
- /**
35
- * Process {{#if variable}}...{{else}}...{{/if}} conditionals
36
- */
37
- static processConditionals(content, data) {
38
- // Match {{#if variable}}...{{else}}...{{/if}} or {{#if variable}}...{{/if}}
39
- const ifRegex = /\{\{#if\s+(\w+(?:\.\w+)*)\s*\}\}([\s\S]*?)(?:\{\{else\}\}([\s\S]*?))?\{\{\/if\}\}/g;
40
-
41
- return content.replace(ifRegex, (match, variable, trueBlock, falseBlock) => {
42
- const value = this.getNestedValue(data, variable);
43
- const isTruthy = this.isTruthy(value);
44
-
45
- if (isTruthy) {
46
- return trueBlock || '';
47
- } else {
48
- return falseBlock || '';
49
- }
50
- });
51
- }
52
-
53
- /**
54
- * Process {{#each array}}...{{/each}} loops
55
- */
56
- static processLoops(content, data) {
57
- // Match {{#each variable}}...{{/each}}
58
- const eachRegex = /\{\{#each\s+(\w+(?:\.\w+)*)\s*\}\}([\s\S]*?)\{\{\/each\}\}/g;
59
-
60
- return content.replace(eachRegex, (match, variable, block) => {
61
- const array = this.getNestedValue(data, variable);
62
-
63
- if (!Array.isArray(array) || array.length === 0) {
64
- return '';
65
- }
66
-
67
- return array.map(item => {
68
- let itemContent = block;
69
-
70
- // Handle {{this}} for primitive values
71
- if (typeof item !== 'object') {
72
- itemContent = itemContent.replace(/\{\{this\}\}/g, String(item));
73
- } else {
74
- // Handle {{this.property}} for objects
75
- itemContent = itemContent.replace(/\{\{this\.(\w+)\}\}/g, (m, prop) => {
76
- const value = item[prop];
77
- return value !== undefined ? String(value) : '';
78
- });
79
-
80
- // Handle {{this}} for objects
81
- // Smart default: if object has 'code' or 'name' property, use that; otherwise stringify
82
- itemContent = itemContent.replace(/\{\{this\}\}/g, () => {
83
- if (item.code !== undefined) return String(item.code);
84
- if (item.name !== undefined) return String(item.name);
85
- return JSON.stringify(item);
86
- });
87
- }
88
-
89
- return itemContent;
90
- }).join('');
91
- });
92
- }
93
-
94
- /**
95
- * Get nested value from object using dot notation
96
- */
97
- static getNestedValue(obj, path) {
98
- return path.split('.').reduce((current, prop) => {
99
- return current?.[prop];
100
- }, obj);
101
- }
102
-
103
- /**
104
- * Check if value is truthy (for conditionals)
105
- */
106
- static isTruthy(value) {
107
- if (value === null || value === undefined) return false;
108
- if (typeof value === 'boolean') return value;
109
- if (typeof value === 'number') return value !== 0;
110
- if (typeof value === 'string') return value.length > 0;
111
- if (Array.isArray(value)) return value.length > 0;
112
- if (typeof value === 'object') return Object.keys(value).length > 0;
113
- return true;
114
- }
115
-
116
- /**
117
- * Replace simple variables
118
- */
119
- static replaceVariables(content, data) {
120
- for (const [key, value] of Object.entries(data)) {
121
- const placeholder = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
122
- content = content.replace(placeholder, this.formatValue(value));
123
- }
124
- return content;
125
- }
126
-
127
- /**
128
- * Format complex types (arrays, objects)
129
- */
130
- static formatComplexTypes(content, data) {
131
- // Handle code_samples first (before generic samples check)
132
- if (data.codeSamples && Array.isArray(data.codeSamples)) {
133
- const placeholder = new RegExp('\\{\\{code_samples\\}\\}', 'g');
134
- const formatted = this.formatSamples(data.codeSamples);
135
- content = content.replace(placeholder, formatted);
136
- }
137
-
138
- // Handle samples array
139
- if (data.samples && Array.isArray(data.samples)) {
140
- const placeholder = new RegExp('\\{\\{samples\\}\\}', 'g');
141
- const formatted = this.formatSamples(data.samples);
142
- content = content.replace(placeholder, formatted);
143
- }
144
- // Handle patterns array - format as bullet points
145
- if (data.patterns && Array.isArray(data.patterns)) {
146
- const placeholder = new RegExp('\\{\\{patterns\\}\\}', 'g');
147
- const formatted = data.patterns
148
- .map(p => {
149
- if (typeof p === 'string') return `- ${p}`;
150
- if (p.keyword && p.context) {
151
- return `- **${p.keyword}**: Found in codebase`;
152
- }
153
- return JSON.stringify(p);
154
- })
155
- .join('\n');
156
- content = content.replace(placeholder, formatted);
157
- }
158
-
159
- // Handle conventions array
160
- if (data.conventions && Array.isArray(data.conventions)) {
161
- const placeholder = new RegExp('\\{\\{conventions\\}\\}', 'g');
162
- const formatted = data.conventions
163
- .filter(c => c && c.trim())
164
- .map(c => `- ${c}`)
165
- .join('\n');
166
- content = content.replace(placeholder, formatted || 'No specific conventions detected');
167
- }
168
-
169
- // Handle features array
170
- if (data.features && Array.isArray(data.features)) {
171
- const placeholder = new RegExp('\\{\\{features\\}\\}', 'g');
172
- const formatted = data.features
173
- .map(f => `- **${f.name}**: ${f.description || 'No description'}`)
174
- .join('\n');
175
- content = content.replace(placeholder, formatted || 'No features detected');
176
- }
177
-
178
- // Handle endpoints array
179
- if (data.endpoints && Array.isArray(data.endpoints)) {
180
- const placeholder = new RegExp('\\{\\{endpoints\\}\\}', 'g');
181
- const formatted = data.endpoints
182
- .map(e => `- \`${e.code || e}\``)
183
- .join('\n');
184
- content = content.replace(placeholder, formatted || 'No endpoints detected');
185
- }
186
-
187
- // Handle models array
188
- if (data.models && Array.isArray(data.models)) {
189
- const placeholder = new RegExp('\\{\\{models\\}\\}', 'g');
190
- const formatted = data.models
191
- .map(m => `- \`${m.code || m}\``)
192
- .join('\n');
193
- content = content.replace(placeholder, formatted || 'No models detected');
194
- }
195
-
196
- return content;
197
- }
198
-
199
- /**
200
- * Format code samples for display
201
- */
202
- static formatSamples(samples) {
203
- if (!samples || samples.length === 0) {
204
- return 'No code samples available yet.';
205
- }
206
-
207
- return samples
208
- .slice(0, 5) // Limit to 5 samples
209
- .map(sample => {
210
- if (typeof sample === 'string') return sample;
211
-
212
- const path = sample.path || 'unknown';
213
- const content = sample.content || '';
214
-
215
- return `#### ${path}\n\`\`\`\n${content.substring(0, 800)}${content.length > 800 ? '\n...' : ''}\n\`\`\``;
216
- })
217
- .join('\n\n');
218
- }
219
-
220
- /**
221
- * Format value for template
222
- */
223
- static formatValue(value) {
224
- if (value === null || value === undefined) {
225
- return '';
226
- }
227
-
228
- if (Array.isArray(value)) {
229
- return value.join(', ');
230
- }
231
-
232
- if (typeof value === 'object') {
233
- return JSON.stringify(value, null, 2);
234
- }
235
-
236
- return String(value);
237
- }
238
- }
239
-
240
- export default TemplateEngine;