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

Code before:
      {
        deduplicated_recipes.insert(recipe.clone());
      }
    }

    let recipes = RecipeResolver::resolve_recipes(&assignments, &settings, deduplicated_recipes)?;

    let mut aliases = Table::new();
    while let Some(alias) = self.aliases.pop() {
      aliases.insert(Self::resolve_alias(&recipes, alias)?);
    }

    for recipe in recipes.values() {
      for attribute in &recipe.attributes {
        if let Attribute::Script(_) = attribute {
          unstable_features.insert(UnstableFeature::ScriptAttribute);
          break;
        }
      }
    }

    if settings.script_interpreter.is_some() {
      unstable_features.insert(UnstableFeature::ScriptInterpreterSetting);
    }

    let source = root.canonicalize().unwrap();
    let root = paths.get(root).unwrap();

    Ok(Justfile {
      aliases,
      assignments,
      default: recipes
        .values()
        .filter(|recipe| recipe.name.path == root)
        .fold(None, |accumulator, next| match accumulator {
          None => Some(Rc::clone(next)),
          Some(previous) => Some(if previous.line_number() < next.line_number() {
            previous
          } else {
            Rc::clone(next)
          }),
        }),
      doc,
      groups: groups.into(),
      loaded: loaded.into(),
      modules: self.modules,
      name,
      recipes,
      settings,
      source,
      unexports: self.unexports,

Review comment (bug):
Canonicalize produces weird paths. On Unix, it resolves symlinks, which is often not what you want, and on Windows it produces paths prefixed with `\\?\` which is not very nice.

Canonicalize is also a system call, which means it can fail with an I/O error, so we can't unwrap here.

If we need to clean the path, we should use `.lexiclean()` instead of canonicalize, which cannot fail and doesn't produce weird paths.

Code after:

      if deduplicated_recipes
        .get(recipe.name.lexeme())
        .map_or(true, |original| recipe.file_depth <= original.file_depth)
      {
        deduplicated_recipes.insert(recipe.clone());
      }
    }

    let recipes = RecipeResolver::resolve_recipes(&assignments, &settings, deduplicated_recipes)?;

    let mut aliases = Table::new();
    while let Some(alias) = self.aliases.pop() {
      aliases.insert(Self::resolve_alias(&recipes, alias)?);
    }

    for recipe in recipes.values() {
      if recipe.attributes.contains(AttributeDiscriminant::Script) {
        unstable_features.insert(UnstableFeature::ScriptAttribute);
        break;
      }
    }

    if settings.script_interpreter.is_some() {
      unstable_features.insert(UnstableFeature::ScriptInterpreterSetting);
    }

    let source = root.to_owned();
    let root = paths.get(root).unwrap();

    Ok(Justfile {
      aliases,
      assignments,
      default: recipes
        .values()
        .filter(|recipe| recipe.name.path == root)
        .fold(None, |accumulator, next| match accumulator {
          None => Some(Rc::clone(next)),
          Some(previous) => Some(if previous.line_number() < next.line_number() {
            previous
          } else {
            Rc::clone(next)
          }),
        }),
      doc,
      groups: groups.into(),
      loaded: loaded.into(),
      modules: self.modules,
      name,
      recipes,
      settings,