Skip to content

Commit bbaef05

Browse files
committed
build: allow non-hyperapps in hyperapp-containing package
1 parent 6420a54 commit bbaef05

1 file changed

Lines changed: 69 additions & 28 deletions

File tree

src/build/caller_utils_generator.rs

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -254,42 +254,74 @@ struct SignatureStruct {
254254
args_comment: Option<String>, // Parsed from // args: (name: type, ...) comment
255255
}
256256

257-
// Find all interface imports in the world WIT file
257+
// Find all interface imports in the selected world WIT file(s)
258258
#[instrument(level = "trace", skip_all)]
259-
fn find_interfaces_in_world(api_dir: &Path) -> Result<Vec<String>> {
260-
debug!(dir = ?api_dir, "Finding interface imports in world definitions");
261-
let mut interfaces = Vec::new();
259+
fn find_interfaces_in_world(api_dir: &Path, world_name: &str) -> Result<Vec<String>> {
260+
debug!(dir = ?api_dir, world = %world_name, "Finding interface imports in world definitions");
261+
let mut world_defs: HashMap<String, String> = HashMap::new();
262262

263-
// Find world definition files
263+
// Index world definition files by world name
264264
for entry in WalkDir::new(api_dir)
265265
.max_depth(1)
266266
.into_iter()
267267
.filter_map(Result::ok)
268268
{
269269
let path = entry.path();
270+
if !(path.is_file() && path.extension().map_or(false, |ext| ext == "wit")) {
271+
continue;
272+
}
273+
let Ok(content) = fs::read_to_string(path) else {
274+
continue;
275+
};
276+
if !content.contains("world ") {
277+
continue;
278+
}
279+
if let Some(world_line) = content.lines().find(|line| line.trim().starts_with("world ")) {
280+
if let Some(name) = world_line.trim().split_whitespace().nth(1) {
281+
let clean_name = name.trim_end_matches(" {").trim_start_matches('%');
282+
world_defs.insert(clean_name.to_string(), content);
283+
debug!(file = %path.display(), world = %clean_name, "Indexed world definition");
284+
}
285+
}
286+
}
270287

271-
if path.is_file() && path.extension().map_or(false, |ext| ext == "wit") {
272-
if let Ok(content) = fs::read_to_string(path) {
273-
if content.contains("world ") {
274-
debug!(file = %path.display(), "Analyzing world definition file for imports");
275-
276-
// Extract import statements
277-
for line in content.lines() {
278-
let line = line.trim();
279-
if line.starts_with("import ") && line.ends_with(";") {
280-
let interface = line
281-
.trim_start_matches("import ")
282-
.trim_end_matches(";")
283-
.trim();
284-
285-
interfaces.push(interface.to_string());
286-
debug!(interface = %interface, "Found interface import");
287-
}
288-
}
289-
}
288+
let mut interfaces = Vec::new();
289+
let mut visited = std::collections::HashSet::new();
290+
let mut stack = vec![world_name.to_string()];
291+
292+
while let Some(current_world) = stack.pop() {
293+
let clean_world = current_world.trim_start_matches('%').to_string();
294+
if !visited.insert(clean_world.clone()) {
295+
continue;
296+
}
297+
let Some(content) = world_defs.get(&clean_world) else {
298+
debug!(world = %clean_world, "World definition not found for imports");
299+
continue;
300+
};
301+
302+
debug!(world = %clean_world, "Analyzing world definition file for imports");
303+
for line in content.lines() {
304+
let line = line.trim();
305+
if line.starts_with("import ") && line.ends_with(';') {
306+
let interface = line
307+
.trim_start_matches("import ")
308+
.trim_end_matches(';')
309+
.trim()
310+
.trim_start_matches('%');
311+
interfaces.push(interface.to_string());
312+
debug!(interface = %interface, "Found interface import");
313+
} else if line.starts_with("include ") && line.ends_with(';') {
314+
let include_world = line
315+
.trim_start_matches("include ")
316+
.trim_end_matches(';')
317+
.trim()
318+
.trim_start_matches('%')
319+
.to_string();
320+
stack.push(include_world);
290321
}
291322
}
292323
}
324+
293325
debug!(count = interfaces.len(), interfaces = ?interfaces, "Found interface imports");
294326
Ok(interfaces)
295327
}
@@ -620,8 +652,8 @@ crate-type = ["cdylib", "lib"]
620652
"types"
621653
};
622654

623-
// Get all interfaces from the world file
624-
let interface_imports = find_interfaces_in_world(api_dir)?;
655+
// Get all interfaces from the selected world
656+
let interface_imports = find_interfaces_in_world(api_dir, world_name)?;
625657

626658
// Store all types from each interface
627659
let mut interface_types: HashMap<String, Vec<String>> = HashMap::new();
@@ -638,8 +670,17 @@ crate-type = ["cdylib", "lib"]
638670
// Exclude world definition files
639671
if let Ok(content) = fs::read_to_string(path) {
640672
if !content.contains("world ") {
641-
debug!(file = %path.display(), "Adding WIT file for parsing");
642-
wit_files.push(path.to_path_buf());
673+
let interface_name = path.file_stem().unwrap().to_string_lossy();
674+
let interface_name = interface_name.trim_start_matches('%');
675+
if interface_imports
676+
.iter()
677+
.any(|i| i.trim_start_matches('%') == interface_name)
678+
{
679+
debug!(file = %path.display(), "Adding WIT file for parsing");
680+
wit_files.push(path.to_path_buf());
681+
} else {
682+
debug!(file = %path.display(), "Skipping WIT file not in selected world");
683+
}
643684
} else {
644685
debug!(file = %path.display(), "Skipping world definition WIT file");
645686
}

0 commit comments

Comments
 (0)