diff --git a/src/analyzer.rs b/src/analyzer.rs index 3e5f3538b1..3a9607ac1a 100644 --- a/src/analyzer.rs +++ b/src/analyzer.rs @@ -20,9 +20,12 @@ impl<'run, 'src> Analyzer<'run, 'src> { loaded: &[PathBuf], name: Option>, paths: &HashMap, + private: bool, root: &Path, ) -> RunResult<'src, Justfile<'src>> { - Self::default().justfile(asts, config, doc, groups, loaded, name, paths, root) + Self::default().justfile( + asts, config, doc, groups, loaded, name, paths, root, private, + ) } fn justfile( @@ -35,6 +38,7 @@ impl<'run, 'src> Analyzer<'run, 'src> { name: Option>, paths: &HashMap, root: &Path, + private: bool, ) -> RunResult<'src, Justfile<'src>> { let mut definitions = HashMap::new(); let mut imports = HashSet::new(); @@ -69,6 +73,7 @@ impl<'run, 'src> Analyzer<'run, 'src> { doc, groups, name, + private, .. } => { if let Some(absolute) = absolute { @@ -81,6 +86,7 @@ impl<'run, 'src> Analyzer<'run, 'src> { loaded, Some(*name), paths, + *private, absolute, )?); } @@ -231,6 +237,7 @@ impl<'run, 'src> Analyzer<'run, 'src> { module_path: ast.module_path.clone(), modules: self.modules, name, + private, recipes, settings, source, diff --git a/src/compiler.rs b/src/compiler.rs index 2953702083..465c7209e1 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -101,7 +101,7 @@ impl Compiler { asts.insert(current.path, ast.clone()); } - let justfile = Analyzer::analyze(&asts, config, None, &[], &loaded, None, &paths, root)?; + let justfile = Analyzer::analyze(&asts, config, None, &[], &loaded, None, &paths, false, root)?; Ok(Compilation { asts, @@ -234,6 +234,7 @@ impl Compiler { &[], None, &paths, + false, &root, ) } diff --git a/src/item.rs b/src/item.rs index fa82005b5a..a7cd931525 100644 --- a/src/item.rs +++ b/src/item.rs @@ -17,6 +17,7 @@ pub(crate) enum Item<'src> { groups: Vec>, name: Name<'src>, optional: bool, + private: bool, relative: Option>, }, Recipe(UnresolvedRecipe<'src>), diff --git a/src/justfile.rs b/src/justfile.rs index 95d2376513..b6e06395fc 100644 --- a/src/justfile.rs +++ b/src/justfile.rs @@ -15,6 +15,8 @@ pub(crate) struct Justfile<'src> { pub(crate) modules: Table<'src, Justfile<'src>>, #[serde(skip)] pub(crate) name: Option>, + #[serde(skip)] + pub(crate) private: bool, pub(crate) recipes: Table<'src, Arc>>, pub(crate) settings: Settings, pub(crate) source: PathBuf, @@ -391,8 +393,12 @@ impl<'src> Justfile<'src> { Ok(()) } - pub(crate) fn modules(&self, config: &Config) -> Vec<&Justfile> { - let mut modules = self.modules.values().collect::>(); + pub(crate) fn public_modules(&self, config: &Config) -> Vec<&Justfile> { + let mut modules = self + .modules + .values() + .filter(|module| !module.private) + .collect::>(); if config.unsorted { modules.sort_by_key(|module| { @@ -440,7 +446,7 @@ impl<'src> Justfile<'src> { } } - for submodule in self.modules.values() { + for submodule in self.public_modules(config) { for group in submodule.groups() { groups.push((&[], submodule.name.unwrap().offset, group.to_string())); } diff --git a/src/parser.rs b/src/parser.rs index b903a5b2fe..1c8fb7fffa 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -413,7 +413,11 @@ impl<'run, 'src> Parser<'run, 'src> { attributes.ensure_valid_attributes( "Module", *name, - &[AttributeDiscriminant::Doc, AttributeDiscriminant::Group], + &[ + AttributeDiscriminant::Doc, + AttributeDiscriminant::Group, + AttributeDiscriminant::Private, + ], )?; let doc = match attributes.get(AttributeDiscriminant::Doc) { @@ -423,6 +427,8 @@ impl<'run, 'src> Parser<'run, 'src> { _ => unreachable!(), }; + let private = attributes.contains(AttributeDiscriminant::Private); + let mut groups = Vec::new(); for attribute in attributes { if let Attribute::Group(group) = attribute { @@ -431,11 +437,12 @@ impl<'run, 'src> Parser<'run, 'src> { } items.push(Item::Module { - groups, absolute: None, doc, + groups, name, optional, + private, relative, }); } diff --git a/src/subcommand.rs b/src/subcommand.rs index 0658941e62..d3e6a90f73 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -551,7 +551,8 @@ impl Subcommand { } } if !config.list_submodules { - for (name, _) in &module.modules { + for submodule in module.public_modules(config) { + let name = submodule.name(); signature_widths.insert(name, UnicodeWidthStr::width(format!("{name} ...").as_str())); } } @@ -589,7 +590,7 @@ impl Subcommand { let submodule_groups = { let mut groups = BTreeMap::, Vec<&Justfile>>::new(); - for submodule in module.modules(config) { + for submodule in module.public_modules(config) { let submodule_groups = submodule.groups(); if submodule_groups.is_empty() { groups.entry(None).or_default().push(submodule); @@ -752,7 +753,8 @@ impl Subcommand { *printed += 1; } - for (name, module) in &justfile.modules { + for module in justfile.public_modules(config) { + let name = module.name(); components.push(name); Self::summary_recursive(config, components, printed, module); components.pop(); diff --git a/src/testing.rs b/src/testing.rs index ecf75a394a..05f8c21418 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -77,6 +77,7 @@ pub(crate) fn analysis_error( &[], None, &paths, + false, &root, ) { Ok(_) => panic!("Analysis unexpectedly succeeded"), diff --git a/tests/private.rs b/tests/private.rs index 73d4636c59..2f40f2f3fa 100644 --- a/tests/private.rs +++ b/tests/private.rs @@ -39,6 +39,29 @@ fn private_attribute_for_alias() { .run(); } +#[test] +fn private_attribute_for_module() { + Test::new() + .write("foo.just", "bar:") + .justfile( + r" + [private] + mod foo + + baz: + ", + ) + .test_round_trip(false) + .arg("--list") + .stdout( + " + Available recipes: + baz + ", + ) + .run(); +} + #[test] fn private_variables_are_not_listed() { Test::new()