Analyze JavaScript code for Chrome API usage
(source: &str)
| 53 | |
| 54 | /// Analyze JavaScript code for Chrome API usage |
| 55 | pub fn analyze_javascript(source: &str) -> Result<Vec<ChromeApiCall>> { |
| 56 | let mut calls = Vec::new(); |
| 57 | |
| 58 | // Find all chrome.* API calls |
| 59 | for (line_num, line) in source.lines().enumerate() { |
| 60 | // Check for API calls |
| 61 | for cap in CHROME_API_PATTERN.captures_iter(line) { |
| 62 | let api_name = format!("chrome.{}", &cap[1]); |
| 63 | let is_callback = CALLBACK_PATTERN.is_match(line); |
| 64 | let is_chrome_only = is_chrome_only_api(&api_name); |
| 65 | |
| 66 | calls.push(ChromeApiCall { |
| 67 | line: line_num + 1, |
| 68 | column: cap.get(0).map(|m| m.start()).unwrap_or(0), |
| 69 | api_name: api_name.clone(), |
| 70 | full_call: format!("{}(...)", api_name), |
| 71 | is_callback_style: is_callback, |
| 72 | is_chrome_only, |
| 73 | }); |
| 74 | } |
| 75 | |
| 76 | // Also check for property access (not just calls) |
| 77 | for cap in CHROME_PROPERTY_PATTERN.captures_iter(line) { |
| 78 | let api_name = format!("chrome.{}", &cap[1]); |
| 79 | |
| 80 | // Skip if we already found this as a call |
| 81 | if !calls.iter().any(|c| c.line == line_num + 1 && c.api_name == api_name) { |
| 82 | calls.push(ChromeApiCall { |
| 83 | line: line_num + 1, |
| 84 | column: cap.get(0).map(|m| m.start()).unwrap_or(0), |
| 85 | api_name: api_name.clone(), |
| 86 | full_call: api_name.clone(), |
| 87 | is_callback_style: false, |
| 88 | is_chrome_only: is_chrome_only_api(&api_name), |
| 89 | }); |
| 90 | } |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | Ok(calls) |
| 95 | } |
| 96 | |
| 97 | fn is_chrome_only_api(api_name: &str) -> bool { |
| 98 | // Use the dynamic dataset first |