tusktsk
Version:
TuskTsk - The Freedom Configuration Language. Query databases, use any syntax, never bow to any king!
1,752 lines (1,464 loc) • 126 kB
JavaScript
/**
* TuskLang Enhanced for JavaScript - The Freedom Parser
* =====================================================
* "We don't bow to any king" - Support ALL syntax styles
*
* Features:
* - Multiple grouping: [], {}, <>
* - $global vs section-local variables
* - Cross-file communication
* - Database queries (with adapters)
* - All @ operators
* - Maximum flexibility
*/
class TuskLangEnhanced {
constructor() {
this.globalVariables = {};
this.sectionVariables = {};
this.currentSection = null;
this.parsedData = {};
this.crossFileCache = {};
this.databaseAdapter = null;
this.cache = new Map();
}
/**
* Set database adapter for @query operations
*/
setDatabaseAdapter(adapter) {
this.databaseAdapter = adapter;
}
/**
* Parse TuskLang content
*/
parse(content) {
const lines = content.split('\n');
const result = {};
let position = 0;
while (position < lines.length) {
const line = lines[position].trim();
// Skip empty lines and comments
if (!line || line.startsWith('#') || line.startsWith('//')) {
position++;
continue;
}
// Remove optional semicolon
const cleanLine = line.replace(/;$/, '');
// Check for section declarations []
if (/^\[([a-zA-Z_]\w*)\]$/.test(cleanLine)) {
const match = cleanLine.match(/^\[([a-zA-Z_]\w*)\]$/);
this.currentSection = match[1];
result[this.currentSection] = {};
this.sectionVariables[this.currentSection] = {};
position++;
continue;
}
// Check for angle bracket objects >
if (/^([a-zA-Z_]\w*)\s*>$/.test(cleanLine)) {
const match = cleanLine.match(/^([a-zA-Z_]\w*)\s*>$/);
const obj = this.parseAngleBracketObject(lines, position, match[1]);
if (this.currentSection) {
result[this.currentSection][obj.key] = obj.value;
} else {
result[obj.key] = obj.value;
}
position = obj.newPosition;
continue;
}
// Check for curly brace objects {
if (/^([a-zA-Z_]\w*)\s*\{/.test(cleanLine)) {
const match = cleanLine.match(/^([a-zA-Z_]\w*)\s*\{/);
const obj = this.parseCurlyBraceObject(lines, position, match[1]);
if (this.currentSection) {
result[this.currentSection][obj.key] = obj.value;
} else {
result[obj.key] = obj.value;
}
position = obj.newPosition;
continue;
}
// Parse key-value pairs
if (/^([$]?[a-zA-Z_][\w-]*)\s*[:=]\s*(.+)$/.test(cleanLine)) {
const match = cleanLine.match(/^([$]?[a-zA-Z_][\w-]*)\s*[:=]\s*(.+)$/);
const key = match[1];
const value = this.parseValue(match[2].trim());
// Store in result
if (this.currentSection) {
result[this.currentSection][key] = value;
// Store section-local variable if not global
if (!key.startsWith('$')) {
this.sectionVariables[this.currentSection][key] = value;
}
} else {
result[key] = value;
}
// Store global variables
if (key.startsWith('$')) {
this.globalVariables[key.substring(1)] = value;
}
this.parsedData[key] = value;
}
position++;
}
return this.resolveReferences(result);
}
/**
* Parse angle bracket object
*/
parseAngleBracketObject(lines, startPos, key) {
let position = startPos + 1;
const obj = {};
while (position < lines.length) {
const line = lines[position].trim();
// End of angle bracket object
if (line === '<') {
return { key, value: obj, newPosition: position + 1 };
}
// Skip empty lines and comments
if (!line || line.startsWith('#')) {
position++;
continue;
}
// Remove optional semicolon
const cleanLine = line.replace(/;$/, '');
// Parse nested content
if (/^([$]?[a-zA-Z_][\w-]*)\s*[:=]\s*(.+)$/.test(cleanLine)) {
const match = cleanLine.match(/^([$]?[a-zA-Z_][\w-]*)\s*[:=]\s*(.+)$/);
obj[match[1]] = this.parseValue(match[2].trim());
} else if (/^([a-zA-Z_]\w*)\s*>$/.test(cleanLine)) {
const match = cleanLine.match(/^([a-zA-Z_]\w*)\s*>$/);
const nested = this.parseAngleBracketObject(lines, position, match[1]);
obj[nested.key] = nested.value;
position = nested.newPosition - 1;
} else if (/^([a-zA-Z_]\w*)\s*\{/.test(cleanLine)) {
const match = cleanLine.match(/^([a-zA-Z_]\w*)\s*\{/);
const nested = this.parseCurlyBraceObject(lines, position, match[1]);
obj[nested.key] = nested.value;
position = nested.newPosition - 1;
}
position++;
}
return { key, value: obj, newPosition: position };
}
/**
* Parse curly brace object
*/
parseCurlyBraceObject(lines, startPos, key) {
let position = startPos;
const obj = {};
// Check if opening brace is on same line
const firstLine = lines[position].trim();
const sameLine = firstLine.includes('{');
if (sameLine) {
position++;
}
while (position < lines.length) {
const line = lines[position].trim();
// End of object
if (line === '}' || line.startsWith('}')) {
return { key, value: obj, newPosition: position + 1 };
}
// Skip empty lines and comments
if (!line || line.startsWith('#')) {
position++;
continue;
}
// Remove optional semicolon
const cleanLine = line.replace(/;$/, '');
// Parse nested content
if (/^([$]?[a-zA-Z_][\w-]*)\s*[:=]\s*(.+)$/.test(cleanLine)) {
const match = cleanLine.match(/^([$]?[a-zA-Z_][\w-]*)\s*[:=]\s*(.+)$/);
obj[match[1]] = this.parseValue(match[2].trim());
}
position++;
}
return { key, value: obj, newPosition: position };
}
/**
* Parse values with all enhancements
*/
parseValue(value) {
// Basic types
if (value === 'true') return true;
if (value === 'false') return false;
if (value === 'null') return null;
// Numbers
if (/^-?\d+(\.\d+)?$/.test(value)) {
return value.includes('.') ? parseFloat(value) : parseInt(value);
}
// $variable references (global)
if (/^\$([a-zA-Z_]\w*)$/.test(value)) {
const match = value.match(/^\$([a-zA-Z_]\w*)$/);
return this.globalVariables[match[1]] || null;
}
// Section-local variable references
if (/^[a-zA-Z_]\w*$/.test(value) &&
this.currentSection &&
this.sectionVariables[this.currentSection]?.[value] !== undefined) {
return this.sectionVariables[this.currentSection][value];
}
// Cross-file references: @file.tsk.get('key')
if (/^@([\w-]+)\.tsk\.get\(["']([^"']+)["']\)$/.test(value)) {
const match = value.match(/^@([\w-]+)\.tsk\.get\(["']([^"']+)["']\)$/);
return this.crossFileGet(match[1], match[2]);
}
// Cross-file set: @file.tsk.set('key', value)
if (/^@([\w-]+)\.tsk\.set\(["']([^"']+)["'],\s*(.+)\)$/.test(value)) {
const match = value.match(/^@([\w-]+)\.tsk\.set\(["']([^"']+)["'],\s*(.+)\)$/);
return this.crossFileSet(match[1], match[2], this.parseValue(match[3]));
}
// @date function
if (/^@date\(["']([^"']+)["']\)$/.test(value)) {
const match = value.match(/^@date\(["']([^"']+)["']\)$/);
return this.formatDate(match[1]);
}
// Ranges: 8888-9999
if (/^(\d+)-(\d+)$/.test(value)) {
const match = value.match(/^(\d+)-(\d+)$/);
return {
min: parseInt(match[1]),
max: parseInt(match[2]),
type: 'range'
};
}
// @ operators
if (/^@(\w+)\((.+)\)$/.test(value)) {
const match = value.match(/^@(\w+)\((.+)\)$/);
return this.executeOperator(match[1], match[2]);
}
// Arrays
if (value.startsWith('[') && value.endsWith(']')) {
try {
return JSON.parse(value);
} catch {
// Simple array parsing
const content = value.slice(1, -1);
return content.split(',').map(item => this.parseValue(item.trim()));
}
}
// Inline objects
if (value.startsWith('{') && value.endsWith('}')) {
try {
return JSON.parse(value);
} catch {
// Simple object parsing
const obj = {};
const content = value.slice(1, -1);
const pairs = content.split(',');
pairs.forEach(pair => {
const [k, v] = pair.split(':').map(s => s.trim());
if (k && v) {
obj[k.replace(/["']/g, '')] = this.parseValue(v);
}
});
return obj;
}
}
// String values (remove quotes)
if ((value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))) {
return value.slice(1, -1);
}
// String concatenation
if (value.includes(' + ')) {
const parts = value.split(' + ').map(part => {
const parsed = this.parseValue(part.trim());
return parsed !== null ? String(parsed) : '';
});
return parts.join('');
}
// Conditional/ternary
if (value.includes(' ? ') && value.includes(' : ')) {
const [condition, rest] = value.split(' ? ');
const [trueVal, falseVal] = rest.split(' : ');
const condResult = this.evaluateCondition(condition.trim());
return condResult ?
this.parseValue(trueVal.trim()) :
this.parseValue(falseVal.trim());
}
// Environment variables
if (/^@env\(["']([^"']+)["'](?:,\s*(.+))?\)$/.test(value)) {
const match = value.match(/^@env\(["']([^"']+)["'](?:,\s*(.+))?\)$/);
const envVar = match[1];
const defaultVal = match[2] ? this.parseValue(match[2]) : null;
return process.env[envVar] || defaultVal;
}
return value;
}
/**
* Execute @ operators
*/
async executeOperator(operator, params) {
switch (operator) {
case 'variable':
return this.executeVariableOperator(params);
case 'query':
return this.executeQuery(params);
case 'cache':
return this.executeCacheOperator(params);
case 'learn':
return this.executeLearnOperator(params);
case 'optimize':
return this.executeOptimizeOperator(params);
case 'metrics':
return this.executeMetricsOperator(params);
case 'feature':
return this.executeFeatureOperator(params);
case 'if':
return this.executeIfOperator(params);
case 'switch':
return this.executeSwitchOperator(params);
case 'for':
return this.executeForOperator(params);
case 'while':
return this.executeWhileOperator(params);
case 'each':
return this.executeEachOperator(params);
case 'filter':
return this.executeFilterOperator(params);
case 'string':
return this.executeStringOperator(params);
case 'regex':
return this.executeRegexOperator(params);
case 'hash':
return this.executeHashOperator(params);
case 'base64':
return this.executeBase64Operator(params);
case 'xml':
return this.executeXmlOperator(params);
case 'yaml':
return this.executeYamlOperator(params);
case 'csv':
return this.executeCsvOperator(params);
case 'template':
return this.executeTemplateOperator(params);
case 'encrypt':
return this.executeEncryptOperator(params);
case 'decrypt':
return this.executeDecryptOperator(params);
case 'jwt':
return this.executeJwtOperator(params);
case 'email':
return this.executeEmailOperator(params);
case 'sms':
return this.executeSmsOperator(params);
case 'webhook':
return this.executeWebhookOperator(params);
case 'websocket':
return this.executeWebSocketOperator(params);
case 'graphql':
return this.executeGraphQLOperator(params);
case 'grpc':
return this.executeGrpcOperator(params);
case 'sse':
return this.executeSseOperator(params);
case 'nats':
return this.executeNatsOperator(params);
case 'amqp':
return this.executeAmqpOperator(params);
case 'kafka':
return this.executeKafkaOperator(params);
case 'etcd':
return this.executeEtcdOperator(params);
case 'elasticsearch':
return this.executeElasticsearchOperator(params);
case 'prometheus':
return this.executePrometheusOperator(params);
case 'jaeger':
return this.executeJaegerOperator(params);
case 'zipkin':
return this.executeZipkinOperator(params);
case 'grafana':
return this.executeGrafanaOperator(params);
case 'istio':
return this.executeIstioOperator(params);
case 'consul':
return this.executeConsulOperator(params);
case 'vault':
return this.executeVaultOperator(params);
case 'temporal':
return this.executeTemporalOperator(params);
case 'mongodb':
return this.executeMongoDbOperator(params);
case 'redis':
return this.executeRedisOperator(params);
case 'postgresql':
return this.executePostgreSqlOperator(params);
case 'mysql':
return this.executeMySqlOperator(params);
case 'influxdb':
return this.executeInfluxDbOperator(params);
case 'oauth':
return this.executeOAuthOperator(params);
case 'saml':
return this.executeSamlOperator(params);
case 'ldap':
return this.executeLdapOperator(params);
case 'kubernetes':
return this.executeKubernetesOperator(params);
case 'docker':
return this.executeDockerOperator(params);
case 'aws':
return this.executeAwsOperator(params);
case 'azure':
return this.executeAzureOperator(params);
case 'gcp':
return this.executeGcpOperator(params);
case 'terraform':
return this.executeTerraformOperator(params);
case 'ansible':
return this.executeAnsibleOperator(params);
case 'puppet':
return this.executePuppetOperator(params);
case 'chef':
return this.executeChefOperator(params);
case 'jenkins':
return this.executeJenkinsOperator(params);
case 'github':
return this.executeGitHubOperator(params);
case 'gitlab':
return this.executeGitLabOperator(params);
case 'logs':
return this.executeLogsOperator(params);
case 'alerts':
return this.executeAlertsOperator(params);
case 'health':
return this.executeHealthOperator(params);
case 'status':
return this.executeStatusOperator(params);
case 'uptime':
return this.executeUptimeOperator(params);
case 'slack':
return this.executeSlackOperator(params);
case 'teams':
return this.executeTeamsOperator(params);
case 'discord':
return this.executeDiscordOperator(params);
case 'rbac':
return this.executeRbacOperator(params);
case 'audit':
return this.executeAuditOperator(params);
case 'compliance':
return this.executeComplianceOperator(params);
case 'governance':
return this.executeGovernanceOperator(params);
case 'policy':
return this.executePolicyOperator(params);
case 'workflow':
return this.executeWorkflowOperator(params);
case 'ai':
return this.executeAiOperator(params);
case 'blockchain':
return this.executeBlockchainOperator(params);
case 'iot':
return this.executeIoTOperator(params);
case 'edge':
return this.executeEdgeOperator(params);
case 'quantum':
return this.executeQuantumOperator(params);
case 'neural':
return this.executeNeuralOperator(params);
case 'env':
// Already handled in parseValue
return `@${operator}(${params})`;
default:
// Unknown operator
return `@${operator}(${params})`;
}
}
/**
* Execute database query
*/
async executeQuery(params) {
try {
// Parse query parameters
const match = params.match(/^["']([^"']+)["'](?:,\s*(.+))?$/);
if (!match) {
throw new Error('Invalid @query syntax. Expected: "sql", args');
}
const sql = match[1];
const args = match[2] ? this.parseQueryArgs(match[2]) : [];
// Real database implementation using SQLite3 as default
const sqlite3 = require('sqlite3').verbose();
const path = require('path');
// Use configured database or default to memory
const dbPath = process.env.DB_PATH || ':memory:';
const db = new sqlite3.Database(dbPath);
return new Promise((resolve, reject) => {
if (sql.trim().toLowerCase().startsWith('select')) {
// SELECT query
db.all(sql, args, (err, rows) => {
if (err) {
resolve({ success: false, error: err.message, data: [] });
} else {
resolve({ success: true, data: rows, count: rows.length });
}
});
} else {
// INSERT, UPDATE, DELETE query
db.run(sql, args, function(err) {
if (err) {
resolve({ success: false, error: err.message });
} else {
resolve({
success: true,
changes: this.changes,
lastID: this.lastID
});
}
});
}
});
} catch (error) {
console.error('Query error:', error);
return { success: false, error: error.message, data: [] };
}
}
/**
* Cache operator
*/
executeCacheOperator(params) {
const match = params.match(/^["']([^"']+)["'],\s*(.+)$/);
if (!match) return null;
const ttl = match[1];
const value = this.parseValue(match[2]);
const key = JSON.stringify({ operator: 'cache', params, value });
// Check cache
const cached = this.cache.get(key);
if (cached && cached.expires > Date.now()) {
return cached.value;
}
// Store in cache
const ttlMs = this.parseTTL(ttl);
this.cache.set(key, {
value,
expires: Date.now() + ttlMs
});
return value;
}
/**
* Learn operator (placeholder)
*/
executeLearnOperator(params) {
const match = params.match(/^["']([^"']+)["'],\s*(.+)$/);
if (!match) return null;
const key = match[1];
const defaultValue = this.parseValue(match[2]);
// In a real implementation, this would use ML
return defaultValue;
}
/**
* Optimize operator (placeholder)
*/
executeOptimizeOperator(params) {
const match = params.match(/^["']([^"']+)["'],\s*(.+)$/);
if (!match) return null;
const param = match[1];
const initialValue = this.parseValue(match[2]);
// In a real implementation, this would auto-tune
return initialValue;
}
/**
* Metrics operator (placeholder)
*/
executeMetricsOperator(params) {
const match = params.match(/^["']([^"']+)["'](?:,\s*(.+))?$/);
if (!match) return 0;
const metric = match[1];
const value = match[2] ? this.parseValue(match[2]) : null;
// In a real implementation, this would track metrics
return value || 0;
}
/**
* Feature flag operator
*/
executeFeatureOperator(params) {
const feature = params.replace(/["']/g, '');
// In a real implementation, check feature flags
return false;
}
/**
* If operator - conditional expressions
*/
executeIfOperator(params) {
try {
// Parse condition and values: "condition ? trueValue : falseValue"
const match = params.match(/^(.+)\s*\?\s*(.+)\s*:\s*(.+)$/);
if (!match) {
throw new Error('Invalid @if syntax. Expected: condition ? trueValue : falseValue');
}
const condition = match[1].trim();
const trueValue = match[2].trim();
const falseValue = match[3].trim();
const result = this.evaluateCondition(condition);
return result ? this.parseValue(trueValue) : this.parseValue(falseValue);
} catch (error) {
console.error('@if operator error:', error);
return null;
}
}
/**
* Switch operator - switch statements
*/
executeSwitchOperator(params) {
try {
// Parse switch expression and cases: "expression { case1: value1, case2: value2, default: defaultValue }"
const match = params.match(/^(.+)\s*\{([^}]+)\}$/);
if (!match) {
throw new Error('Invalid @switch syntax. Expected: expression { case1: value1, case2: value2, default: defaultValue }');
}
const expression = this.parseValue(match[1].trim());
const casesStr = match[2].trim();
// Parse cases
const cases = {};
const casePairs = casesStr.split(',').map(pair => pair.trim());
for (const pair of casePairs) {
const [key, value] = pair.split(':').map(s => s.trim());
if (key && value) {
const cleanKey = key.replace(/["']/g, '');
cases[cleanKey] = this.parseValue(value);
}
}
// Find matching case or default
if (cases[expression] !== undefined) {
return cases[expression];
}
return cases['default'] || null;
} catch (error) {
console.error('@switch operator error:', error);
return null;
}
}
/**
* For operator - for loops
*/
executeForOperator(params) {
try {
// Parse for loop: "start, end, step, expression"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 3) {
throw new Error('Invalid @for syntax. Expected: start, end, step, expression');
}
const start = parseInt(this.parseValue(parts[0]));
const end = parseInt(this.parseValue(parts[1]));
const step = parseInt(this.parseValue(parts[2]));
const expression = parts[3] || 'i';
const results = [];
for (let i = start; i <= end; i += step) {
// Set loop variable in global scope
this.globalVariables[expression] = i;
results.push(i);
}
return results;
} catch (error) {
console.error('@for operator error:', error);
return [];
}
}
/**
* While operator - while loops
*/
executeWhileOperator(params) {
try {
// Parse while loop: "condition, expression, maxIterations"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 2) {
throw new Error('Invalid @while syntax. Expected: condition, expression, maxIterations');
}
const condition = parts[0];
const expression = parts[1];
const maxIterations = parts[2] ? parseInt(this.parseValue(parts[2])) : 1000;
const results = [];
let iterations = 0;
while (this.evaluateCondition(condition) && iterations < maxIterations) {
const result = this.parseValue(expression);
results.push(result);
iterations++;
}
return results;
} catch (error) {
console.error('@while operator error:', error);
return [];
}
}
/**
* Each operator - array iteration
*/
executeEachOperator(params) {
try {
// Parse each: "array, expression"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 2) {
throw new Error('Invalid @each syntax. Expected: array, expression');
}
const array = this.parseValue(parts[0]);
const expression = parts[1];
if (!Array.isArray(array)) {
throw new Error('@each requires an array as first parameter');
}
const results = [];
for (let i = 0; i < array.length; i++) {
// Set iteration variables
this.globalVariables['item'] = array[i];
this.globalVariables['index'] = i;
this.globalVariables['key'] = i;
const result = this.parseValue(expression);
results.push(result);
}
return results;
} catch (error) {
console.error('@each operator error:', error);
return [];
}
}
/**
* Filter operator - array filtering
*/
executeFilterOperator(params) {
try {
// Parse filter: "array, condition"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 2) {
throw new Error('Invalid @filter syntax. Expected: array, condition');
}
const array = this.parseValue(parts[0]);
const condition = parts[1];
if (!Array.isArray(array)) {
throw new Error('@filter requires an array as first parameter');
}
const results = [];
for (let i = 0; i < array.length; i++) {
// Set iteration variables
this.globalVariables['item'] = array[i];
this.globalVariables['index'] = i;
this.globalVariables['key'] = i;
if (this.evaluateCondition(condition)) {
results.push(array[i]);
}
}
return results;
} catch (error) {
console.error('@filter operator error:', error);
return [];
}
}
/**
* String operator - string manipulation
*/
executeStringOperator(params) {
try {
// Parse string operations: "operation, value, ...args"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 2) {
throw new Error('Invalid @string syntax. Expected: operation, value, ...args');
}
const operation = parts[0].replace(/["']/g, '');
const value = this.parseValue(parts[1]);
const args = parts.slice(2).map(arg => this.parseValue(arg));
switch (operation) {
case 'length':
return String(value).length;
case 'upper':
return String(value).toUpperCase();
case 'lower':
return String(value).toLowerCase();
case 'trim':
return String(value).trim();
case 'substring':
const start = args[0] || 0;
const end = args[1];
return String(value).substring(start, end);
case 'replace':
const search = args[0];
const replace = args[1];
return String(value).replace(new RegExp(search, 'g'), replace);
case 'split':
const delimiter = args[0] || ',';
return String(value).split(delimiter);
case 'join':
const separator = args[0] || '';
return Array.isArray(value) ? value.join(separator) : value;
default:
throw new Error(`Unknown string operation: ${operation}`);
}
} catch (error) {
console.error('@string operator error:', error);
return '';
}
}
/**
* Regex operator - regular expressions
*/
executeRegexOperator(params) {
try {
// Parse regex operations: "operation, pattern, value, ...args"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 3) {
throw new Error('Invalid @regex syntax. Expected: operation, pattern, value, ...args');
}
const operation = parts[0].replace(/["']/g, '');
const pattern = parts[1].replace(/["']/g, '');
const value = this.parseValue(parts[2]);
const args = parts.slice(3).map(arg => this.parseValue(arg));
const regex = new RegExp(pattern, args[0] || '');
switch (operation) {
case 'test':
return regex.test(String(value));
case 'match':
return String(value).match(regex);
case 'replace':
const replacement = args[1] || '';
return String(value).replace(regex, replacement);
case 'split':
return String(value).split(regex);
default:
throw new Error(`Unknown regex operation: ${operation}`);
}
} catch (error) {
console.error('@regex operator error:', error);
return null;
}
}
/**
* Hash operator - hashing functions
*/
executeHashOperator(params) {
try {
// Parse hash operations: "algorithm, value"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 2) {
throw new Error('Invalid @hash syntax. Expected: algorithm, value');
}
const algorithm = parts[0].replace(/["']/g, '');
const value = this.parseValue(parts[1]);
// Simple hash implementation (in production, use crypto library)
switch (algorithm) {
case 'md5':
return this.simpleHash(String(value), 'md5');
case 'sha1':
return this.simpleHash(String(value), 'sha1');
case 'sha256':
return this.simpleHash(String(value), 'sha256');
default:
throw new Error(`Unknown hash algorithm: ${algorithm}`);
}
} catch (error) {
console.error('@hash operator error:', error);
return '';
}
}
/**
* Simple hash implementation
*/
simpleHash(str, algorithm) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32-bit integer
}
return Math.abs(hash).toString(16);
}
/**
* Base64 operator - base64 encoding/decoding
*/
executeBase64Operator(params) {
try {
// Parse base64 operations: "operation, value"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 2) {
throw new Error('Invalid @base64 syntax. Expected: operation, value');
}
const operation = parts[0].replace(/["']/g, '');
const value = this.parseValue(parts[1]);
switch (operation) {
case 'encode':
return Buffer.from(String(value)).toString('base64');
case 'decode':
return Buffer.from(String(value), 'base64').toString('utf8');
default:
throw new Error(`Unknown base64 operation: ${operation}`);
}
} catch (error) {
console.error('@base64 operator error:', error);
return '';
}
}
/**
* XML operator - XML parsing
*/
executeXmlOperator(params) {
try {
// Parse XML operations: "operation, value, ...args"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 2) {
throw new Error('Invalid @xml syntax. Expected: operation, value, ...args');
}
const operation = parts[0].replace(/["']/g, '');
const value = this.parseValue(parts[1]);
switch (operation) {
case 'parse':
// Simple XML parsing (in production, use proper XML parser)
return this.simpleXmlParse(String(value));
case 'stringify':
return this.simpleXmlStringify(value);
default:
throw new Error(`Unknown XML operation: ${operation}`);
}
} catch (error) {
console.error('@xml operator error:', error);
return null;
}
}
/**
* Simple XML parsing
*/
simpleXmlParse(xml) {
// Very basic XML parsing - in production use a proper XML parser
const result = {};
const tagRegex = /<(\w+)[^>]*>(.*?)<\/\1>/g;
let match;
while ((match = tagRegex.exec(xml)) !== null) {
result[match[1]] = match[2];
}
return result;
}
/**
* Simple XML stringification
*/
simpleXmlStringify(obj) {
if (typeof obj !== 'object') {
return `<value>${obj}</value>`;
}
let xml = '';
for (const [key, value] of Object.entries(obj)) {
xml += `<${key}>${value}</${key}>`;
}
return xml;
}
/**
* YAML operator - YAML parsing
*/
executeYamlOperator(params) {
try {
// Parse YAML operations: "operation, value"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 2) {
throw new Error('Invalid @yaml syntax. Expected: operation, value');
}
const operation = parts[0].replace(/["']/g, '');
const value = this.parseValue(parts[1]);
switch (operation) {
case 'parse':
// Simple YAML parsing (in production, use proper YAML parser)
return this.simpleYamlParse(String(value));
case 'stringify':
return this.simpleYamlStringify(value);
default:
throw new Error(`Unknown YAML operation: ${operation}`);
}
} catch (error) {
console.error('@yaml operator error:', error);
return null;
}
}
/**
* Simple YAML parsing
*/
simpleYamlParse(yaml) {
// Very basic YAML parsing - in production use a proper YAML parser
const result = {};
const lines = yaml.split('\n');
for (const line of lines) {
const match = line.match(/^(\w+):\s*(.+)$/);
if (match) {
result[match[1]] = match[2].trim();
}
}
return result;
}
/**
* Simple YAML stringification
*/
simpleYamlStringify(obj) {
if (typeof obj !== 'object') {
return String(obj);
}
let yaml = '';
for (const [key, value] of Object.entries(obj)) {
yaml += `${key}: ${value}\n`;
}
return yaml.trim();
}
/**
* CSV operator - CSV processing
*/
executeCsvOperator(params) {
try {
// Parse CSV operations: "operation, value, ...args"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 2) {
throw new Error('Invalid @csv syntax. Expected: operation, value, ...args');
}
const operation = parts[0].replace(/["']/g, '');
const value = this.parseValue(parts[1]);
const args = parts.slice(2).map(arg => this.parseValue(arg));
switch (operation) {
case 'parse':
const delimiter = args[0] || ',';
return this.parseCsv(String(value), delimiter);
case 'stringify':
const separator = args[0] || ',';
return this.stringifyCsv(value, separator);
default:
throw new Error(`Unknown CSV operation: ${operation}`);
}
} catch (error) {
console.error('@csv operator error:', error);
return null;
}
}
/**
* Parse CSV string
*/
parseCsv(csv, delimiter = ',') {
const lines = csv.split('\n');
const result = [];
for (const line of lines) {
if (line.trim()) {
const fields = line.split(delimiter).map(field => field.trim());
result.push(fields);
}
}
return result;
}
/**
* Stringify to CSV
*/
stringifyCsv(data, delimiter = ',') {
if (!Array.isArray(data)) {
return String(data);
}
return data.map(row => {
if (Array.isArray(row)) {
return row.join(delimiter);
}
return String(row);
}).join('\n');
}
/**
* Template operator - template engine
*/
executeTemplateOperator(params) {
try {
// Parse template operations: "template, data"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 2) {
throw new Error('Invalid @template syntax. Expected: template, data');
}
const template = this.parseValue(parts[0]);
const data = this.parseValue(parts[1]);
return this.renderTemplate(String(template), data);
} catch (error) {
console.error('@template operator error:', error);
return '';
}
}
/**
* Render template with data
*/
renderTemplate(template, data) {
let result = template;
if (typeof data === 'object') {
for (const [key, value] of Object.entries(data)) {
const placeholder = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
result = result.replace(placeholder, String(value));
}
}
return result;
}
/**
* Encrypt operator - data encryption
*/
executeEncryptOperator(params) {
try {
// Parse encrypt operations: "algorithm, value, key"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 3) {
throw new Error('Invalid @encrypt syntax. Expected: algorithm, value, key');
}
const algorithm = parts[0].replace(/["']/g, '');
const value = this.parseValue(parts[1]);
const key = this.parseValue(parts[2]);
// Simple encryption (in production, use proper crypto library)
return this.simpleEncrypt(String(value), String(key), algorithm);
} catch (error) {
console.error('@encrypt operator error:', error);
return '';
}
}
/**
* Simple encryption implementation
*/
simpleEncrypt(text, key, algorithm) {
// Very basic encryption - in production use proper crypto
let result = '';
for (let i = 0; i < text.length; i++) {
const charCode = text.charCodeAt(i) ^ key.charCodeAt(i % key.length);
result += String.fromCharCode(charCode);
}
return Buffer.from(result).toString('base64');
}
/**
* Decrypt operator - data decryption
*/
executeDecryptOperator(params) {
try {
// Parse decrypt operations: "algorithm, value, key"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 3) {
throw new Error('Invalid @decrypt syntax. Expected: algorithm, value, key');
}
const algorithm = parts[0].replace(/["']/g, '');
const value = this.parseValue(parts[1]);
const key = this.parseValue(parts[2]);
// Simple decryption (in production, use proper crypto library)
return this.simpleDecrypt(String(value), String(key), algorithm);
} catch (error) {
console.error('@decrypt operator error:', error);
return '';
}
}
/**
* Simple decryption implementation
*/
simpleDecrypt(encryptedText, key, algorithm) {
// Very basic decryption - in production use proper crypto
const decoded = Buffer.from(encryptedText, 'base64').toString();
let result = '';
for (let i = 0; i < decoded.length; i++) {
const charCode = decoded.charCodeAt(i) ^ key.charCodeAt(i % key.length);
result += String.fromCharCode(charCode);
}
return result;
}
/**
* JWT operator - JWT tokens
*/
executeJwtOperator(params) {
try {
// Parse JWT operations: "operation, value, ...args"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 2) {
throw new Error('Invalid @jwt syntax. Expected: operation, value, ...args');
}
const operation = parts[0].replace(/["']/g, '');
const value = this.parseValue(parts[1]);
const args = parts.slice(2).map(arg => this.parseValue(arg));
switch (operation) {
case 'encode':
const secret = args[0] || 'default-secret';
return this.simpleJwtEncode(value, secret);
case 'decode':
return this.simpleJwtDecode(String(value));
case 'verify':
const verifySecret = args[0] || 'default-secret';
return this.simpleJwtVerify(String(value), verifySecret);
default:
throw new Error(`Unknown JWT operation: ${operation}`);
}
} catch (error) {
console.error('@jwt operator error:', error);
return null;
}
}
/**
* Simple JWT encoding
*/
simpleJwtEncode(payload, secret) {
const header = { alg: 'HS256', typ: 'JWT' };
const encodedHeader = Buffer.from(JSON.stringify(header)).toString('base64');
const encodedPayload = Buffer.from(JSON.stringify(payload)).toString('base64');
const signature = this.simpleHash(encodedHeader + '.' + encodedPayload + secret, 'sha256');
return `${encodedHeader}.${encodedPayload}.${signature}`;
}
/**
* Simple JWT decoding
*/
simpleJwtDecode(token) {
const parts = token.split('.');
if (parts.length !== 3) {
throw new Error('Invalid JWT token format');
}
try {
return JSON.parse(Buffer.from(parts[1], 'base64').toString());
} catch {
throw new Error('Invalid JWT payload');
}
}
/**
* Simple JWT verification
*/
simpleJwtVerify(token, secret) {
try {
const parts = token.split('.');
if (parts.length !== 3) {
return false;
}
const expectedSignature = this.simpleHash(parts[0] + '.' + parts[1] + secret, 'sha256');
return parts[2] === expectedSignature;
} catch {
return false;
}
}
/**
* Email operator - email sending
*/
async executeEmailOperator(params) {
try {
// Parse email operations: "to, subject, body, ...options"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 3) {
throw new Error('Invalid @email syntax. Expected: to, subject, body, ...options');
}
const to = this.parseValue(parts[0]);
const subject = this.parseValue(parts[1]);
const body = this.parseValue(parts[2]);
// Real email implementation using Node.js built-in modules
const nodemailer = require('nodemailer');
// Create transporter (in production, use real SMTP settings)
const transporter = nodemailer.createTransporter({
host: process.env.SMTP_HOST || 'localhost',
port: process.env.SMTP_PORT || 587,
secure: false,
auth: {
user: process.env.SMTP_USER || 'user@example.com',
pass: process.env.SMTP_PASS || 'password'
}
});
// Send email
const mailOptions = {
from: process.env.SMTP_FROM || 'noreply@example.com',
to: to,
subject: subject,
text: body,
html: body
};
const result = await transporter.sendMail(mailOptions);
return {
success: true,
messageId: result.messageId,
response: result.response
};
} catch (error) {
console.error('@email operator error:', error);
return { success: false, error: error.message };
}
}
/**
* SMS operator - SMS messaging
*/
async executeSmsOperator(params) {
try {
// Parse SMS operations: "to, message, ...options"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 2) {
throw new Error('Invalid @sms syntax. Expected: to, message, ...options');
}
const to = this.parseValue(parts[0]);
const message = this.parseValue(parts[1]);
// Real SMS implementation using Twilio API
const twilio = require('twilio');
const accountSid = process.env.TWILIO_ACCOUNT_SID || 'your_account_sid';
const authToken = process.env.TWILIO_AUTH_TOKEN || 'your_auth_token';
const fromNumber = process.env.TWILIO_FROM_NUMBER || '+1234567890';
const client = twilio(accountSid, authToken);
const result = await client.messages.create({
body: message,
from: fromNumber,
to: to
});
return {
success: true,
messageId: result.sid,
status: result.status,
price: result.price
};
} catch (error) {
console.error('@sms operator error:', error);
return { success: false, error: error.message };
}
}
/**
* Webhook operator - webhook handling
*/
executeWebhookOperator(params) {
try {
// Parse webhook operations: "url, method, data, ...options"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 2) {
throw new Error('Invalid @webhook syntax. Expected: url, method, data, ...options');
}
const url = this.parseValue(parts[0]);
const method = parts[1] ? this.parseValue(parts[1]) : 'POST';
const data = parts[2] ? this.parseValue(parts[2]) : {};
// Real HTTP request implementation
const https = require('https');
const http = require('http');
const urlObj = new URL(url);
const postData = JSON.stringify(data);
const options = {
hostname: urlObj.hostname,
port: urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80),
path: urlObj.pathname + urlObj.search,
method: method,
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData),
'User-Agent': 'TuskLang/1.0'
}
};
return new Promise((resolve, reject) => {
const req = (urlObj.protocol === 'https:' ? https : http).request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
resolve({
success: res.statusCode >= 200 && res.statusCode < 300,
statusCode: res.statusCode,
headers: res.headers,
data: responseData
});
});
});
req.on('error', (error) => {
resolve({ success: false, error: error.message });
});
req.write(postData);
req.end();
});
} catch (error) {
console.error('@webhook operator error:', error);
return { success: false, error: error.message };
}
}
/**
* WebSocket operator - WebSocket connections
*/
async executeWebSocketOperator(params) {
try {
// Parse WebSocket operations: "url, message, ...options"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 2) {
throw new Error('Invalid @websocket syntax. Expected: url, message, ...options');
}
const url = this.parseValue(parts[0]);
const message = this.parseValue(parts[1]);
const options = parts[2] ? this.parseValue(parts[2]) : {};
// Dynamic import for WebSocket
const WebSocket = await import('ws').then(m => m.default);
return new Promise((resolve) => {
const ws = new WebSocket(url, options);
ws.on('open', () => {
ws.send(message);
resolve({ success: true, connected: true, sent: true });
});
ws.on('message', (data) => {
resolve({ success: true, connected: true, received: data.toString() });
ws.close();
});
ws.on('error', (error) => {
resolve({ success: false, error: error.message });
});
ws.on('close', () => {
resolve({ success: true, connected: false, closed: true });
});
// Timeout after 10 seconds
setTimeout(() => {
ws.close();
resolve({ success: false, error: 'Connection timeout' });
}, 10000);
});
} catch (error) {
console.error('@websocket operator error:', error);
return { success: false, error: error.message };
}
}
/**
* GraphQL operator - GraphQL client
*/
async executeGraphQLOperator(params) {
try {
// Parse GraphQL operations: "url, query, variables, ...options"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 2) {
throw new Error('Invalid @graphql syntax. Expected: url, query, variables, ...options');
}
const url = this.parseValue(parts[0]);
const query = this.parseValue(parts[1]);
const variables = parts[2] ? this.parseValue(parts[2]) : {};
const options = parts[3] ? this.parseValue(parts[3]) : {};
const https = require('https');
const http = require('http');
const postData = JSON.stringify({
query: query,
variables: variables,
...options
});
const urlObj = new URL(url);
const isHttps = urlObj.protocol === 'https:';
const client = isHttps ? https : http;
const requestOptions = {
hostname: urlObj.hostname,
port: urlObj.port || (isHttps ? 443 : 80),
path: urlObj.pathname + urlObj.search,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData),
...options.headers
}
};
return new Promise((resolve) => {
const req = client.request(requestOptions, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const result = JSON.parse(data);
resolve({ success: true, data: result });
} catch (error) {
resolve({ success: false, error: 'Invalid JSON response' });
}
});
});
req.on('error', (error) => {
resolve({ success: false, error: error.message });
});
req.write(postData);
req.end();
});
} catch (error) {
console.error('@graphql operator error:', error);
return { success: false, error: error.message };
}
}
/**
* gRPC operator - gRPC communication
*/
executeGrpcOperator(params) {
try {
// Parse gRPC operations: "url, method, data, ...options"
const parts = params.split(',').map(p => p.trim());
if (parts.length < 3) {
throw new Error('Invalid @grpc syntax. Expected: url, method, data, ...options');
}
const url = this.parseValue(parts[0]);
const method = this.parseValue(parts[1]);
const data = this.parseValue(parts[2]);
// In production, make gRPC call
console.log(`gRPC call would be made to: ${url}`);
console.log(