lisette_diagnostics/
module_graph.rs1use crate::LisetteDiagnostic;
2use syntax::ast::Span;
3
4pub fn module_not_found(
5 module_name: &str,
6 span: Span,
7 is_go_stdlib: bool,
8 standalone: bool,
9 src_prefix_hint: Option<String>,
10) -> LisetteDiagnostic {
11 let help = if let Some(stripped) = src_prefix_hint {
12 format!(
13 "Did you mean `import \"{}\"`? The `src/` prefix is not needed — imports are relative to the source directory.",
14 stripped
15 )
16 } else if is_go_stdlib {
17 format!(
18 "No `{}` module found in your local project. Did you mean `import \"go:{}\"` from Go's stdlib?",
19 module_name, module_name
20 )
21 } else if standalone {
22 "When executing `lis run` on an individual file, that file may import only from the Go standard library. To import modules normally, use `lis new` to create a project."
23 .to_string()
24 } else {
25 "Check the module path and ensure the file exists".to_string()
26 };
27
28 LisetteDiagnostic::error("Module not found")
29 .with_resolve_code("module_not_found")
30 .with_span_label(&span, "not found")
31 .with_help(help)
32}
33
34pub fn cannot_import_prelude(span: Span) -> LisetteDiagnostic {
35 LisetteDiagnostic::error("Invalid import")
36 .with_resolve_code("cannot_import_prelude")
37 .with_span_label(&span, "prelude is automatically available")
38 .with_help("Remove this import. Use e.g. `Option` or `prelude.Option` directly.")
39}
40
41pub fn test_file_not_supported(filename: &str) -> LisetteDiagnostic {
42 LisetteDiagnostic::error(format!("Test file `{}` is not yet supported", filename))
43 .with_resolve_code("test_file_not_supported")
44 .with_help("Files ending in `_test.lis` are reserved for future testing support. Rename this file to compile it.")
45}
46
47pub fn import_cycle(path: &[String]) -> LisetteDiagnostic {
48 let modules: Vec<_> = path[..path.len() - 1].to_vec();
49
50 let is_self_import = modules.len() == 1;
51
52 let chain = if is_self_import {
53 format!("{} -> {}", modules[0], modules[0])
54 } else {
55 modules.join(" -> ")
56 };
57
58 let first_module = &modules[0];
59 let first_end = first_module.len();
60 let first_center = first_module.len() / 2;
61
62 let last_module = if is_self_import {
63 &modules[0]
64 } else {
65 modules.last().expect("cycle must have at least one module")
66 };
67 let last_start = chain.len() - last_module.len();
68 let last_end = chain.len();
69 let last_center = last_start + last_module.len() / 2;
70
71 let mut underline = String::new();
72 for i in 0..chain.len() {
73 if i < first_end {
74 if i == first_center {
75 underline.push('┬');
76 } else {
77 underline.push('─');
78 }
79 } else if i >= last_start && i < last_end {
80 if i == last_center {
81 underline.push('┬');
82 } else {
83 underline.push('─');
84 }
85 } else {
86 underline.push(' ');
87 }
88 }
89
90 let mut connect_line = String::new();
91 for i in 0..=last_center {
92 if i < first_center {
93 connect_line.push(' ');
94 } else if i == first_center {
95 connect_line.push('╰');
96 } else if i < last_center {
97 connect_line.push('─');
98 } else {
99 connect_line.push('╯');
100 }
101 }
102
103 let art = format!("{}\n{}\n{}", chain, underline, connect_line);
104
105 let help = if is_self_import {
106 "Remove the self-import"
107 } else {
108 "To break the cycle, remove one of imports or extract common dependencies into a separate module"
109 };
110
111 LisetteDiagnostic::error(format!("Import cycle detected\n\n{}", art))
112 .with_resolve_code("import_cycle")
113 .with_help(help)
114}