@boundless-oss/atlas
Version:
Atlas - MCP Server for comprehensive startup project management
127 lines • 4.71 kB
JavaScript
export class VariableResolver {
/**
* Resolve variables in an object by replacing ${variable} patterns
* with actual values from the context
*/
async resolveVariables(obj, context) {
if (typeof obj === 'string') {
return this.resolveString(obj, context);
}
if (Array.isArray(obj)) {
return Promise.all(obj.map(item => this.resolveVariables(item, context)));
}
if (obj && typeof obj === 'object') {
const resolved = {};
for (const [key, value] of Object.entries(obj)) {
resolved[key] = await this.resolveVariables(value, context);
}
return resolved;
}
return obj;
}
/**
* Resolve variables in a string
*/
resolveString(str, context) {
return str.replace(/\$\{([^}]+)\}/g, (match, path) => {
const value = this.getValueByPath(context, path.trim());
return value !== undefined ? String(value) : match;
});
}
/**
* Get a value from an object using a dot-notation path
*/
getValueByPath(obj, path) {
const parts = path.split('.');
let current = obj;
for (const part of parts) {
if (current && typeof current === 'object' && part in current) {
current = current[part];
}
else {
return undefined;
}
}
return current;
}
/**
* Evaluate a condition expression
*/
async evaluateCondition(condition, context) {
// First resolve any variables in the condition
const resolvedCondition = this.resolveString(condition, context);
try {
// Simple expression evaluation
// In production, use a proper expression evaluator like expr-eval
// Handle basic comparisons
const comparisonMatch = resolvedCondition.match(/^(.+?)\s*(===?|!==?|>=?|<=?)\s*(.+)$/);
if (comparisonMatch) {
const [, left, operator, right] = comparisonMatch;
const leftValue = this.parseValue(left.trim(), context);
const rightValue = this.parseValue(right.trim(), context);
switch (operator) {
case '==':
case '===':
return leftValue == rightValue;
case '!=':
case '!==':
return leftValue != rightValue;
case '>':
return Number(leftValue) > Number(rightValue);
case '>=':
return Number(leftValue) >= Number(rightValue);
case '<':
return Number(leftValue) < Number(rightValue);
case '<=':
return Number(leftValue) <= Number(rightValue);
}
}
// Handle boolean values
if (resolvedCondition === 'true')
return true;
if (resolvedCondition === 'false')
return false;
// Check if it's a variable that evaluates to truthy
const value = this.getValueByPath(context, resolvedCondition);
return Boolean(value);
}
catch (error) {
console.error('Error evaluating condition:', error);
return false;
}
}
/**
* Parse a value that might be a literal or a variable reference
*/
parseValue(str, context) {
// Remove quotes if present
if ((str.startsWith('"') && str.endsWith('"')) ||
(str.startsWith("'") && str.endsWith("'"))) {
return str.slice(1, -1);
}
// Check if it's a number
if (!isNaN(Number(str))) {
return Number(str);
}
// Check if it's a boolean
if (str === 'true')
return true;
if (str === 'false')
return false;
// Try to get it as a variable
const value = this.getValueByPath(context, str);
return value !== undefined ? value : str;
}
/**
* Evaluate a complex expression (for future enhancement)
*/
async evaluateExpression(expression, context) {
// This could be enhanced to support:
// - Mathematical expressions: ${price * quantity}
// - Function calls: ${format(date, 'YYYY-MM-DD')}
// - Array operations: ${items.filter(i => i.active).length}
// For now, just resolve variables
return this.resolveString(expression, context);
}
}
//# sourceMappingURL=variable-resolver.js.map