use command: Don't create a variable with empty record if it doesn't define any constants (#14051)

# Description
Fixes: #13967

The key changes lays in `nu-protocol/src/module.rs`, when resolving
import pattern, nushell only needs to bring `$module` with a record
value if it defines any constants.

# User-Facing Changes
```nushell
module spam {}
use spam
```
Will no longer create a `$spam` variable with an empty record.

# Tests + Formatting
Adjusted some tests and added some tests.
This commit is contained in:
Wind 2024-10-17 10:25:45 +08:00 committed by sholderbach
parent b0427ca9ff
commit d7014e671d
3 changed files with 49 additions and 26 deletions

View File

@ -161,20 +161,25 @@ impl Module {
} }
let span = self.span.unwrap_or(backup_span); let span = self.span.unwrap_or(backup_span);
let const_record = Value::record(
const_rows // only needs to bring `$module` with a record value if it defines any constants.
.into_iter() let constants = if const_rows.is_empty() {
.map(|(name, val)| (String::from_utf8_lossy(&name).to_string(), val)) vec![]
.collect(), } else {
span, vec![(
); final_name.clone(),
Value::record(
const_rows
.into_iter()
.map(|(name, val)| (String::from_utf8_lossy(&name).to_string(), val))
.collect(),
span,
),
)]
};
return ( return (
ResolvedImportPattern::new( ResolvedImportPattern::new(decls, vec![(final_name.clone(), self_id)], constants),
decls,
vec![(final_name.clone(), self_id)],
vec![(final_name, const_record)],
),
errors, errors,
); );
}; };

View File

@ -238,13 +238,30 @@ fn complex_const_export() {
let actual = nu!(&inp.join("; ")); let actual = nu!(&inp.join("; "));
assert_eq!(actual.out, "eats"); assert_eq!(actual.out, "eats");
let inp = &[ let inp = &[MODULE_SETUP, "use spam", "'none' in $spam.eggs.bacon"];
MODULE_SETUP,
"use spam",
"($spam.eggs.bacon.none | is-empty)",
];
let actual = nu!(&inp.join("; ")); let actual = nu!(&inp.join("; "));
assert_eq!(actual.out, "true"); assert_eq!(actual.out, "false");
}
#[test]
fn only_nested_module_have_const() {
let setup = r#"
module spam {
export module eggs {
export module bacon {
export const viking = 'eats'
export module none {}
}
}
}
"#;
let inp = &[setup, "use spam", "$spam.eggs.bacon.viking"];
let actual = nu!(&inp.join("; "));
assert_eq!(actual.out, "eats");
let inp = &[setup, "use spam", "'none' in $spam.eggs.bacon"];
let actual = nu!(&inp.join("; "));
assert_eq!(actual.out, "false");
} }
#[test] #[test]
@ -261,20 +278,16 @@ fn complex_const_glob_export() {
let actual = nu!(&inp.join("; ")); let actual = nu!(&inp.join("; "));
assert_eq!(actual.out, "eats"); assert_eq!(actual.out, "eats");
let inp = &[MODULE_SETUP, "use spam *", "($eggs.bacon.none | is-empty)"]; let inp = &[MODULE_SETUP, "use spam *", "'none' in $eggs.bacon"];
let actual = nu!(&inp.join("; ")); let actual = nu!(&inp.join("; "));
assert_eq!(actual.out, "true"); assert_eq!(actual.out, "false");
} }
#[test] #[test]
fn complex_const_drill_export() { fn complex_const_drill_export() {
let inp = &[ let inp = &[MODULE_SETUP, "use spam eggs bacon none", "$none"];
MODULE_SETUP,
"use spam eggs bacon none",
"($none | is-empty)",
];
let actual = nu!(&inp.join("; ")); let actual = nu!(&inp.join("; "));
assert_eq!(actual.out, "true"); assert!(actual.err.contains("variable not found"));
} }
#[test] #[test]

View File

@ -120,6 +120,11 @@ fn export_consts() -> TestResult {
) )
} }
#[test]
fn dont_export_module_name_as_a_variable() -> TestResult {
fail_test(r#"module spam { }; use spam; $spam"#, "variable not found")
}
#[test] #[test]
fn func_use_consts() -> TestResult { fn func_use_consts() -> TestResult {
run_test( run_test(