extractVariablesSync method
Extract variables from JavaScript code (synchronous)
Implementation
@override
dynamic extractVariablesSync(String script, List<String>? variableNames) {
var processedScript = script;
//_log.warning('Extracting variables from script: $script');
try {
// Stop if too many consecutive errors
if (_consecutiveErrors >= _maxConsecutiveErrors) {
_log.severe(
'Too many consecutive errors ($_consecutiveErrors), stopping execution');
return null;
}
// Handle large scripts
if (processedScript.length > maxScriptSize) {
if (truncateLargeScripts) {
_log.warning(
'JavaScript script truncated from ${processedScript.length} to $maxScriptSize bytes');
processedScript = processedScript.substring(0, maxScriptSize);
} else {
_log.warning(
'JavaScript script too large: ${processedScript.length} bytes (max: $maxScriptSize)');
_consecutiveErrors++;
return null;
}
}
// Use existing runtime (reset should be called once per QueryString.execute())
// Check runtime health first
if (_runtime != null && !_isRuntimeHealthy()) {
_log.warning('Runtime unhealthy, resetting');
_resetRuntime();
}
final runtime = _getRuntime();
// Build the capture script
final captureScript = _buildCaptureScript(processedScript, variableNames);
// Check total script size after wrapping (allow 5x for wrapper code)
const maxWrappedSize = 5 * 1024 * 1024; // 5MB max for wrapped script
if (captureScript.length > maxWrappedSize) {
_log.warning(
'Wrapped script too large: ${captureScript.length} bytes (max: $maxWrappedSize)');
return null;
}
// Execute the script with error handling
JsEvalResult result;
try {
result = runtime.evaluate(captureScript);
} catch (e) {
_log.warning('Runtime evaluation crashed: $e');
_consecutiveErrors++;
// Reset runtime on crash
_resetRuntime();
return null;
}
if (result.isError) {
_consecutiveErrors++;
// Only log first few errors to avoid spam
//if (_consecutiveErrors <= 3) {
_log.warning(
'JavaScript variable extraction error: ${result.stringResult}');
//}
return null;
}
// Success - reset error counter
_consecutiveErrors = 0;
// Get the JSON string result
final jsonResult = result.stringResult;
if (jsonResult.isEmpty ||
jsonResult == 'undefined' ||
jsonResult == 'null') {
return null;
}
// Check result size limit
if (jsonResult.length > maxResultSize) {
_log.warning(
'JavaScript result too large: ${jsonResult.length} bytes (max: $maxResultSize)');
return null;
}
// Parse the JSON string
try {
final updatedJsonResult = jsonResult.replaceAll("undefined", '""');
final parsed = jsonDecode(updatedJsonResult);
// If result is empty map, return null (no variables found)
if (parsed is Map && parsed.isEmpty) {
return null;
}
// If only one variable requested (and not a wildcard), return its value directly
if (variableNames != null &&
variableNames.length == 1 &&
!variableNames.first.contains('*') &&
!variableNames.first.contains('?') &&
parsed is Map) {
return parsed[variableNames.first];
}
return parsed;
} catch (e) {
_log.warning('Failed to parse JSON result: $jsonResult, error: $e');
return null;
}
} catch (e) {
_log.warning('Failed to extract variables: $e');
// Reset runtime on any error
_resetRuntime();
return null;
}
}