Allow mod statements with path to source file (#1786)

This commit is contained in:
Casey Rodarmor 2023-12-28 04:23:58 -08:00 committed by GitHub
parent 2846df7e27
commit 94b3af6cb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 85 additions and 6 deletions

View File

@ -77,7 +77,7 @@ impl<'src> Analyzer<'src> {
Item::Import { absolute, .. } => { Item::Import { absolute, .. } => {
stack.push(asts.get(absolute.as_ref().unwrap()).unwrap()); stack.push(asts.get(absolute.as_ref().unwrap()).unwrap());
} }
Item::Mod { absolute, name } => { Item::Mod { absolute, name, .. } => {
define(*name, "module", false)?; define(*name, "module", false)?;
modules.insert( modules.insert(
name.to_string(), name.to_string(),

View File

@ -27,7 +27,11 @@ impl Compiler {
for item in &mut ast.items { for item in &mut ast.items {
match item { match item {
Item::Mod { name, absolute } => { Item::Mod {
name,
absolute,
path,
} => {
if !unstable { if !unstable {
return Err(Error::Unstable { return Err(Error::Unstable {
message: "Modules are currently unstable.".into(), message: "Modules are currently unstable.".into(),
@ -36,7 +40,11 @@ impl Compiler {
let parent = current.parent().unwrap(); let parent = current.parent().unwrap();
let import = Self::find_module_file(parent, *name)?; let import = if let Some(path) = path {
parent.join(&path.cooked)
} else {
Self::find_module_file(parent, *name)?
};
if srcs.contains_key(&import) { if srcs.contains_key(&import) {
return Err(Error::CircularImport { current, import }); return Err(Error::CircularImport { current, import });

View File

@ -13,6 +13,7 @@ pub(crate) enum Item<'src> {
Mod { Mod {
name: Name<'src>, name: Name<'src>,
absolute: Option<PathBuf>, absolute: Option<PathBuf>,
path: Option<StringLiteral<'src>>,
}, },
Recipe(UnresolvedRecipe<'src>), Recipe(UnresolvedRecipe<'src>),
Set(Set<'src>), Set(Set<'src>),
@ -25,7 +26,15 @@ impl<'src> Display for Item<'src> {
Item::Assignment(assignment) => write!(f, "{assignment}"), Item::Assignment(assignment) => write!(f, "{assignment}"),
Item::Comment(comment) => write!(f, "{comment}"), Item::Comment(comment) => write!(f, "{comment}"),
Item::Import { relative, .. } => write!(f, "import {relative}"), Item::Import { relative, .. } => write!(f, "import {relative}"),
Item::Mod { name, .. } => write!(f, "mod {name}"), Item::Mod { name, path, .. } => {
write!(f, "mod {name}")?;
if let Some(path) = path {
write!(f, " {path}")?;
}
Ok(())
}
Item::Recipe(recipe) => write!(f, "{}", recipe.color_display(Color::never())), Item::Recipe(recipe) => write!(f, "{}", recipe.color_display(Color::never())),
Item::Set(set) => write!(f, "{set}"), Item::Set(set) => write!(f, "{set}"),
} }

View File

@ -335,11 +335,24 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
absolute: None, absolute: None,
}); });
} }
Some(Keyword::Mod) if self.next_are(&[Identifier, Identifier]) => { Some(Keyword::Mod)
if self.next_are(&[Identifier, Identifier, StringToken])
|| self.next_are(&[Identifier, Identifier, Eof])
|| self.next_are(&[Identifier, Identifier, Eol]) =>
{
self.presume_keyword(Keyword::Mod)?; self.presume_keyword(Keyword::Mod)?;
let name = self.parse_name()?;
let path = if self.next_is(StringToken) {
Some(self.parse_string_literal()?)
} else {
None
};
items.push(Item::Mod { items.push(Item::Mod {
name: self.parse_name()?, name,
absolute: None, absolute: None,
path,
}); });
} }
Some(Keyword::Set) Some(Keyword::Set)

View File

@ -444,3 +444,52 @@ fn dotenv_settings_in_submodule_are_ignored() {
.stdout("dotenv-value\n") .stdout("dotenv-value\n")
.run(); .run();
} }
#[test]
fn modules_may_specify_path() {
Test::new()
.write("commands/foo.just", "foo:\n @echo FOO")
.justfile(
"
mod foo 'commands/foo.just'
",
)
.test_round_trip(false)
.arg("--unstable")
.arg("foo")
.arg("foo")
.stdout("FOO\n")
.run();
}
#[test]
fn modules_with_paths_are_dumped_correctly() {
Test::new()
.write("commands/foo.just", "foo:\n @echo FOO")
.justfile(
"
mod foo 'commands/foo.just'
",
)
.test_round_trip(false)
.arg("--unstable")
.arg("--dump")
.stdout("mod foo 'commands/foo.just'\n")
.run();
}
#[test]
fn recipes_may_be_named_mod() {
Test::new()
.justfile(
"
mod foo:
@echo FOO
",
)
.test_round_trip(false)
.arg("mod")
.arg("bar")
.stdout("FOO\n")
.run();
}