use crate::error::Result;
use crate::graph::FileFacts;
use crate::lang::Language;
use super::Extractor;
use super::typescript::extract_ecmascript;
pub struct JavaScriptExtractor;
impl Extractor for JavaScriptExtractor {
fn lang(&self) -> Language {
Language::JavaScript
}
fn extract(&self, source: &str, file: &str) -> Result<FileFacts> {
extract_ecmascript(source, file, Language::JavaScript)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::graph::types::{SymbolKind, Visibility};
#[test]
fn extracts_exported_decls() {
let src = "\
export function validateToken(tok) { return helper(); }
export class Config {}
export const MAX = 3;
function internal() {}
";
let facts = JavaScriptExtractor.extract(src, "src/auth/jwt.js").unwrap();
let by_name = |n: &str| facts.symbols.iter().find(|s| s.name == n).cloned();
let vt = by_name("validateToken").unwrap();
assert_eq!(
vt.id.to_scip_string(),
"codegraph . . . src/auth/jwt/validateToken()."
);
assert_eq!(vt.kind, SymbolKind::Function);
assert_eq!(vt.visibility, Visibility::Public);
assert_eq!(facts.lang, "javascript");
let cfg = by_name("Config").unwrap();
assert_eq!(cfg.kind, SymbolKind::Class);
assert_eq!(cfg.visibility, Visibility::Public);
let max = by_name("MAX").unwrap();
assert_eq!(max.kind, SymbolKind::Const);
assert_eq!(max.visibility, Visibility::Public);
let internal = by_name("internal").expect("internal must now be emitted as Private");
assert_eq!(internal.kind, SymbolKind::Function);
assert_eq!(internal.visibility, Visibility::Private);
}
#[test]
fn default_export_function_in_jsx() {
let facts = JavaScriptExtractor
.extract(
"export default function App() { return <div/>; }",
"src/App.jsx",
)
.unwrap();
assert_eq!(facts.symbols.len(), 2);
let app = facts.symbols.iter().find(|s| s.name == "App").unwrap();
assert_eq!(app.id.to_scip_string(), "codegraph . . . src/App/App().");
}
#[test]
fn extracts_call_references_in_esm() {
let facts = JavaScriptExtractor
.extract(
"function main() { validateToken('t'); helper(); }",
"src/main.mjs",
)
.unwrap();
let names: Vec<&str> = facts.references.iter().map(|r| r.name.as_str()).collect();
assert!(names.contains(&"validateToken"));
assert!(names.contains(&"helper"));
}
}