source_map_php/adapters/
mod.rs1mod hyperf;
2mod laravel;
3
4use std::fs;
5use std::path::Path;
6
7use anyhow::Result;
8use regex::Regex;
9
10use crate::Framework;
11use crate::models::{RouteDoc, SchemaDoc, make_stable_id};
12use crate::sanitizer::Sanitizer;
13
14pub fn detect_framework(repo: &Path, requested: Framework, package_names: &[String]) -> Framework {
15 if requested != Framework::Auto {
16 return requested;
17 }
18 if package_names.iter().any(|name| name == "hyperf/hyperf")
19 || repo.join("bin/hyperf.php").exists()
20 {
21 Framework::Hyperf
22 } else if package_names.iter().any(|name| name == "laravel/framework")
23 || repo.join("artisan").exists()
24 {
25 Framework::Laravel
26 } else {
27 Framework::Auto
28 }
29}
30
31pub fn extract_routes(
32 repo: &Path,
33 repo_name: &str,
34 framework: Framework,
35 sanitizer: &Sanitizer,
36) -> Result<Vec<RouteDoc>> {
37 match framework {
38 Framework::Laravel => laravel::extract_routes(repo, repo_name, sanitizer),
39 Framework::Hyperf => hyperf::extract_routes(repo, repo_name, sanitizer),
40 Framework::Auto => Ok(Vec::new()),
41 }
42}
43
44pub fn extract_schema(repo: &Path, repo_name: &str) -> Result<Vec<SchemaDoc>> {
45 let migration_roots = [repo.join("database/migrations"), repo.join("migrations")];
46 let create_re = Regex::new(r#"Schema::create\(\s*['"]([^'"]+)['"]"#).unwrap();
47 let table_re = Regex::new(r#"Schema::table\(\s*['"]([^'"]+)['"]"#).unwrap();
48 let mut docs = Vec::new();
49 for migrations in migration_roots {
50 if !migrations.exists() {
51 continue;
52 }
53 for entry in walkdir::WalkDir::new(&migrations)
54 .into_iter()
55 .filter_map(Result::ok)
56 .filter(|entry| entry.file_type().is_file())
57 .filter(|entry| entry.path().extension().and_then(|ext| ext.to_str()) == Some("php"))
58 {
59 let contents = fs::read_to_string(entry.path())?;
60 for (idx, line) in contents.lines().enumerate() {
61 let capture = create_re.captures(line).or_else(|| table_re.captures(line));
62 if let Some(capture) = capture {
63 let table = capture.get(1).unwrap().as_str().to_string();
64 let operation = if line.contains("Schema::create") {
65 "create"
66 } else {
67 "table"
68 };
69 let path = entry
70 .path()
71 .strip_prefix(repo)
72 .unwrap()
73 .to_string_lossy()
74 .into_owned();
75 docs.push(SchemaDoc {
76 id: make_stable_id(&[repo_name, &path, &table, operation]),
77 repo: repo_name.to_string(),
78 migration: entry.file_name().to_string_lossy().into_owned(),
79 table: Some(table),
80 operation: operation.to_string(),
81 path,
82 line_start: idx + 1,
83 });
84 }
85 }
86 }
87 }
88 Ok(docs)
89}