Repository: casey/just
File: src/analyzer.rs (Rust)

Code before:
            self.aliases.insert(alias.clone());
          }
          Item::Assignment(assignment) => {
            self.assignments.push(assignment);
          }
          Item::Comment(_) => (),
          Item::Import { absolute, .. } => {
            if let Some(absolute) = absolute {
              if imports.insert(absolute) {
                stack.push(asts.get(absolute).unwrap());
              }
            }
          }
          Item::Module {
            absolute,
            name,
            doc,
            attributes,
            ..
          } => {
            let mut doc_attr: Option<&str> = None;
            let mut groups = Vec::new();
            attributes.ensure_valid_attributes(
              "Module",
              **name,
              &[AttributeDiscriminant::Doc, AttributeDiscriminant::Group],
            )?;

            for attribute in attributes.iter() {
              if let Attribute::Doc(ref doc) = attribute {
                doc_attr = Some(doc.as_ref().map(|s| s.cooked.as_ref()).unwrap_or_default());
              } else if let Attribute::Group(ref group) = attribute {
                groups.push(group.cooked.clone());
              }
            }

            if let Some(absolute) = absolute {
              Self::define(&mut definitions, *name, "module", false)?;
              self.modules.insert(Self::analyze(
                asts,
                doc_attr.or(*doc).map(ToOwned::to_owned),
                groups.as_slice(),
                loaded,
                Some(*name),
                paths,
                absolute,
              )?);
            }
          }
          Item::Recipe(recipe) => {
            if recipe.enabled() {

Review comment (suggestion):
I think we should keep the error checking in the `else` below, otherwise the set of allowed attributes is in two places, here, where we call `ensure_valid_attributes`, and below, in the `if / else` statement.

Code after:
          Item::Alias(alias) => {
            Self::define(&mut definitions, alias.name, "alias", false)?;
            Self::analyze_alias(alias)?;
            self.aliases.insert(alias.clone());
          }
          Item::Assignment(assignment) => {
            self.assignments.push(assignment);
          }
          Item::Comment(_) => (),
          Item::Import { absolute, .. } => {
            if let Some(absolute) = absolute {
              if imports.insert(absolute) {
                stack.push(asts.get(absolute).unwrap());
              }
            }
          }
          Item::Module {
            absolute,
            name,
            doc,
            attributes,
            ..
          } => {
            let mut doc_attr: Option<&str> = None;
            let mut groups = Vec::new();
            attributes.ensure_valid_attributes(
              "Module",
              **name,
              &[AttributeDiscriminant::Doc, AttributeDiscriminant::Group],
            )?;

            for attribute in attributes {
              match attribute {
                Attribute::Doc(ref doc) => {
                  doc_attr = Some(doc.as_ref().map(|s| s.cooked.as_ref()).unwrap_or_default());
                }
                Attribute::Group(ref group) => {
                  groups.push(group.cooked.clone());
                }
                _ => unreachable!(),
              }
            }

            if let Some(absolute) = absolute {
              Self::define(&mut definitions, *name, "module", false)?;
              self.modules.insert(Self::analyze(
                asts,
                doc_attr.or(*doc).map(ToOwned::to_owned),
                groups.as_slice(),
                loaded,
                Some(*name),