forked from extern/nushell
Allow recursive module dirs; Require mod.nu in dirs (#9185)
This commit is contained in:
parent
92c1051143
commit
8d8304cf91
@ -1825,14 +1825,22 @@ pub fn parse_module_file_or_dir(
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut file_paths = vec![];
|
||||
let mod_nu_path = module_path.join("mod.nu");
|
||||
|
||||
if !(mod_nu_path.exists() && mod_nu_path.is_file()) {
|
||||
working_set.error(ParseError::ModuleMissingModNuFile(path_span));
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut paths = vec![];
|
||||
|
||||
for entry in dir_contents.flatten() {
|
||||
let entry_path = entry.path();
|
||||
|
||||
if entry_path.is_file()
|
||||
if (entry_path.is_file()
|
||||
&& entry_path.extension() == Some(OsStr::new("nu"))
|
||||
&& entry_path.file_stem() != Some(OsStr::new("mod"))
|
||||
&& entry_path.file_stem() != Some(OsStr::new("mod")))
|
||||
|| (entry_path.is_dir() && entry_path.join("mod.nu").exists())
|
||||
{
|
||||
if entry_path.file_stem() == Some(OsStr::new(&module_name)) {
|
||||
working_set.error(ParseError::InvalidModuleFileName(
|
||||
@ -1843,28 +1851,28 @@ pub fn parse_module_file_or_dir(
|
||||
return None;
|
||||
}
|
||||
|
||||
file_paths.push(entry_path);
|
||||
paths.push(entry_path);
|
||||
}
|
||||
}
|
||||
|
||||
file_paths.sort();
|
||||
paths.sort();
|
||||
|
||||
// working_set.enter_scope();
|
||||
|
||||
let mut submodules = vec![];
|
||||
|
||||
for file_path in file_paths {
|
||||
if let Some(submodule_id) =
|
||||
parse_module_file(working_set, file_path, path_span, None)
|
||||
{
|
||||
for p in paths {
|
||||
if let Some(submodule_id) = parse_module_file_or_dir(
|
||||
working_set,
|
||||
p.to_string_lossy().as_bytes(),
|
||||
path_span,
|
||||
None,
|
||||
) {
|
||||
let submodule_name = working_set.get_module(submodule_id).name();
|
||||
submodules.push((submodule_name, submodule_id));
|
||||
}
|
||||
}
|
||||
|
||||
let mod_nu_path = module_path.join("mod.nu");
|
||||
|
||||
if mod_nu_path.exists() && mod_nu_path.is_file() {
|
||||
if let Some(module_id) = parse_module_file(
|
||||
working_set,
|
||||
mod_nu_path,
|
||||
@ -1886,22 +1894,12 @@ pub fn parse_module_file_or_dir(
|
||||
vec![]
|
||||
};
|
||||
|
||||
let new_module_id =
|
||||
working_set.add_module(&module_name, module, module_comments);
|
||||
let new_module_id = working_set.add_module(&module_name, module, module_comments);
|
||||
|
||||
Some(new_module_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
let mut module = Module::new(module_name.as_bytes().to_vec());
|
||||
|
||||
for (submodule_name, submodule_id) in submodules {
|
||||
module.add_submodule(submodule_name, submodule_id);
|
||||
}
|
||||
|
||||
Some(working_set.add_module(&module_name, module, vec![]))
|
||||
}
|
||||
} else {
|
||||
working_set.error(ParseError::ModuleNotFound(path_span));
|
||||
None
|
||||
|
@ -193,6 +193,13 @@ pub enum ParseError {
|
||||
)]
|
||||
ModuleNotFound(#[label = "module not found"] Span),
|
||||
|
||||
#[error("Missing mod.nu file.")]
|
||||
#[diagnostic(
|
||||
code(nu::parser::module_missing_mod_nu_file),
|
||||
help("When importing a directory as a Nushell module, it needs to contain a mod.nu file (can be empty). Alternatively, you can use .nu files in the directory as modules individually.")
|
||||
)]
|
||||
ModuleMissingModNuFile(#[label = "module directory is missing a mod.nu file"] Span),
|
||||
|
||||
#[error("Cyclical module import.")]
|
||||
#[diagnostic(code(nu::parser::cyclical_module_import), help("{0}"))]
|
||||
CyclicalModuleImport(String, #[label = "detected cyclical module import"] Span),
|
||||
@ -484,6 +491,7 @@ impl ParseError {
|
||||
ParseError::AliasNotValid(s) => *s,
|
||||
ParseError::CommandDefNotValid(s) => *s,
|
||||
ParseError::ModuleNotFound(s) => *s,
|
||||
ParseError::ModuleMissingModNuFile(s) => *s,
|
||||
ParseError::NamedAsModule(_, _, _, s) => *s,
|
||||
ParseError::ModuleDoubleMain(_, s) => *s,
|
||||
ParseError::InvalidModuleFileName(_, _, s) => *s,
|
||||
|
@ -641,6 +641,27 @@ fn module_dir() {
|
||||
assert_eq!(actual.out, "spambaz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn module_dir_deep() {
|
||||
let import = "use samples/spam";
|
||||
|
||||
let inp = &[import, "spam bacon"];
|
||||
let actual_repl = nu!(cwd: "tests/modules", pipeline(&inp.join("; ")));
|
||||
assert_eq!(actual_repl.out, "bacon");
|
||||
|
||||
let inp = &[import, "spam bacon foo"];
|
||||
let actual_repl = nu!(cwd: "tests/modules", pipeline(&inp.join("; ")));
|
||||
assert_eq!(actual_repl.out, "bacon foo");
|
||||
|
||||
let inp = &[import, "spam bacon beans"];
|
||||
let actual_repl = nu!(cwd: "tests/modules", pipeline(&inp.join("; ")));
|
||||
assert_eq!(actual_repl.out, "beans");
|
||||
|
||||
let inp = &[import, "spam bacon beans foo"];
|
||||
let actual_repl = nu!(cwd: "tests/modules", pipeline(&inp.join("; ")));
|
||||
assert_eq!(actual_repl.out, "beans foo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn module_dir_import_twice_no_panic() {
|
||||
let import = "use samples/spam";
|
||||
@ -656,6 +677,13 @@ fn not_allowed_submodule_file() {
|
||||
assert!(actual.err.contains("invalid_module_file_name"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn module_dir_missing_mod_nu() {
|
||||
let inp = &["use samples/missing_mod_nu"];
|
||||
let actual = nu!(cwd: "tests/modules", pipeline(&inp.join("; ")));
|
||||
assert!(actual.err.contains("module_missing_mod_nu_file"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allowed_local_module() {
|
||||
let inp = &["module spam { module spam {} }"];
|
||||
|
0
tests/modules/samples/missing_mod_nu/test.nu
Normal file
0
tests/modules/samples/missing_mod_nu/test.nu
Normal file
0
tests/modules/samples/not_allowed/mod.nu
Normal file
0
tests/modules/samples/not_allowed/mod.nu
Normal file
1
tests/modules/samples/spam/bacon/beans/foo.nu
Normal file
1
tests/modules/samples/spam/bacon/beans/foo.nu
Normal file
@ -0,0 +1 @@
|
||||
export def main [] { 'beans foo' }
|
3
tests/modules/samples/spam/bacon/beans/mod.nu
Normal file
3
tests/modules/samples/spam/bacon/beans/mod.nu
Normal file
@ -0,0 +1,3 @@
|
||||
export def test [] { 'test' }
|
||||
|
||||
export def main [] { 'beans' }
|
1
tests/modules/samples/spam/bacon/foo.nu
Normal file
1
tests/modules/samples/spam/bacon/foo.nu
Normal file
@ -0,0 +1 @@
|
||||
export def main [] { 'bacon foo' }
|
3
tests/modules/samples/spam/bacon/mod.nu
Normal file
3
tests/modules/samples/spam/bacon/mod.nu
Normal file
@ -0,0 +1,3 @@
|
||||
export def test [] { 'test' }
|
||||
|
||||
export def main [] { 'bacon' }
|
Loading…
Reference in New Issue
Block a user