Skip to content

Warn when running a deprecated or internal module main function #4283

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from

Conversation

Lioncat2002
Copy link

@Lioncat2002 Lioncat2002 commented Feb 26, 2025

This PR closes issue #2569

Features added:

A new is_deprecated field of type Deprecation has been introduced into ModuleFunction struct
updated struct looks like this:

pub struct ModuleFunction {
    pub package: EcoString,
    pub is_deprecated: Deprecation
}

The get_main_function inside of ModuleInterface has been updated to return the deprecation value from the value variable

        Ok(ModuleFunction {
            package: self.package.clone(),
            is_deprecated: value.deprecation.clone(),
        })

A new is_internal function has been introduced into the Built struct. It accepts the module similar to the other functions in the struct, fetches it's ModuleInterface and returns either a bool or an error based on if the module is present in the Hashmap

Added warning when the module being called is either deprecated or internal

 if built.is_internal(&module.clone().into()).is_ok() {
        let warning = Warning::InternalMain;
        warning_emitter.emit(warning);
    }

    // A module can not be run if it does not exist or does not have a public main function.
    let main_function = get_or_suggest_main_function(built, &module, target)?;

    //Warn incase the main function being run has been deprecated
    if main_function.deprecation.is_deprecated() {
        let deprecation_message=match main_function.deprecation{
            gleam_core::type_::Deprecation::Deprecated { message } => Some(message),
            gleam_core::type_::Deprecation::NotDeprecated=>None
        };
        let warning = Warning::DeprecatedMain{message: deprecation_message.unwrap()};
        warning_emitter.emit(warning);
    }

Copy link
Member

@GearsDatapacks GearsDatapacks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've addressed your questions in the related issue here

@GearsDatapacks
Copy link
Member

Looks good so far. Since this PR isn't ready to be merged yet, would you mind converting it to a draft?

@Lioncat2002
Copy link
Author

Yeah sure

@Lioncat2002 Lioncat2002 marked this pull request as draft February 26, 2025 18:56
@Lioncat2002 Lioncat2002 changed the title Fix issue #2569 ; Warn of running a deprecated or internal module main function Warn when running a deprecated or internal module main function Feb 26, 2025
@Lioncat2002 Lioncat2002 marked this pull request as ready for review February 28, 2025 10:48
@Lioncat2002
Copy link
Author

Lioncat2002 commented Feb 28, 2025

PR should be ready for review

@Lioncat2002
Copy link
Author

fixed failing workflows

Copy link
Member

@lpil lpil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thank you! I've left some notes inline. Could you also update the changelog file and add a snapshot test for each of the two warnings, so we can see what they look like.

@lpil
Copy link
Member

lpil commented Mar 1, 2025

Actually nevermind the snapshot tests, the warnings look simple enough. If you could add the module name to each of them though that would be great. Something like "The module x/y/z is internal" and "The main function in the module x/y/z is internal".

@Lioncat2002
Copy link
Author

Yeah sure, will add in the module names

@Lioncat2002 Lioncat2002 requested a review from lpil March 1, 2025 14:51
@Lioncat2002
Copy link
Author

Module names added

@Lioncat2002 Lioncat2002 force-pushed the main branch 2 times, most recently from 777d19b to 4f2f1b3 Compare March 4, 2025 19:38
@Lioncat2002
Copy link
Author

should I fix these conflicts?

@GearsDatapacks
Copy link
Member

At some point yes, although this won't be merged until 1.9 is released.
Make sure to rebase, as merge commits are not allowed in this codebase

@Lioncat2002
Copy link
Author

cool

Copy link
Member

@lpil lpil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I've left some notes inline.

@@ -220,6 +226,23 @@ pub enum DeprecatedSyntaxWarning {
impl Warning {
pub fn to_diagnostic(&self) -> Diagnostic {
match self {
Warning::DeprecatedMain { message } => Diagnostic {
title: "Deprecated main function".into(),
text: message.into(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Format this the same as the existing deprecation message please

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the deprecation text, but run function doesn't have access to the location data like path and src? I can pass the module name itself but I don't think that's correct?

@@ -120,9 +125,33 @@ fn setup(

let built = crate::build::main(paths, options, manifest)?;

// Warn incase the module being run has been as internal
let warning_emitter = WarningEmitter::new(Rc::new(ConsoleWarningEmitter));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is using a different warning emitter to build::main. I think we want to only use a single one per-run as we will be tracking things such as the total count when the project denys any warnings.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

Copy link
Author

@Lioncat2002 Lioncat2002 Mar 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lpil I fixed it by adding a new parameter in the crate::build::main for the warning emitter
Since currently Rc::new(ConsoleWarningEmitter) was being passed directly
Previous:

pub fn main(paths: &ProjectPaths, options: Options, manifest: Manifest) -> Result<Built> {
    main_with_warnings(paths, options, manifest, Rc::new(ConsoleWarningEmitter))
}

Current:

pub fn main(
    paths: &ProjectPaths,
    options: Options,
    manifest: Manifest,
    warnings: Rc<dyn WarningEmitterIO>, // --> new
) -> Result<Built> {
    main_with_warnings(paths, options, manifest, warnings)
}

is this fine?

let warning_emitter = WarningEmitter::new(Rc::new(ConsoleWarningEmitter));

// Warn incase the module being run has been as internal
let internal_module = built.is_internal(&module.clone().into()).unwrap_or(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When can the module be unknown at this point? Looking at the unwrap_or here.

Don't clone the module please. Build an ecostring beforehand and use that here and below.

Copy link
Author

@Lioncat2002 Lioncat2002 Mar 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed modules into a EcoString,
As for the unwrap_or it might happen when the module doesn't exist?

pub fn is_internal(&self, module: &EcoString) -> Result<bool, Error> {
        match self.module_interfaces.get(module) {
            Some(module_data) => Ok(module_data.is_internal),
            None => Err(Error::ModuleDoesNotExist {
                module: module.clone(),
                suggestion: None,
            }),
        }
    }

I had made this method to check if a particular module when passed by name is internal


// Warn incase the module being run has been as internal
let internal_module = built.is_internal(&module.clone().into()).unwrap_or(false);
if internal_module {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still warning for internal module from the root package!

Copy link
Author

@Lioncat2002 Lioncat2002 Mar 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must be misunderstanding a bit,

I am trying to test with

@internal
pub fn main() {
  io.println("hello")
}

marking @internal to the main will be giving the warning right?

can you please give an gleam code showing the case where it is happening?

level: diagnostic::Level::Warning,
location: None,
hint: None,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great to have snapshot tests for how these warnings look please!

@lpil lpil marked this pull request as draft March 18, 2025 16:01
@Lioncat2002 Lioncat2002 force-pushed the main branch 2 times, most recently from aae84a1 to 8a177a3 Compare March 22, 2025 14:58
@lpil
Copy link
Member

lpil commented Jun 16, 2025

Hello @Lioncat2002 ! Are you working on this atm?

@Lioncat2002
Copy link
Author

Hi @lpil , sorry, I have been tied up with irl stuff recently.
I think most of the requirements for the fix is done, some snapshot tests are left.
Feel free to reassign this to anyone else wanting to work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants