takari / polyglot-maven

Support alternative markup for Apache Maven POM files
Eclipse Public License 1.0
893 stars 101 forks source link

[Enhancement] Java parsing with something like JShell instead? #265

Open Mechite opened 1 year ago

Mechite commented 1 year ago

The way JShell can parse Java is very interesting. For example, you have projects like JBang that can parse a script as if it is a sequence of JShell commands.

This way, instead of having a syntax like the following:

public class pom extends org.sonatype.maven.polyglot.java.dsl.ModelFactory {

    @SuppressWarnings({ "unchecked" })
    public void project() {

        modelVersion = "4.0.0";
        groupId = "org.sample1";
        artifactId = "project1";
        packaging = "jar";
        version = "1.0-SNAPSHOT";

        properties(
            property(name1 -> "property_1"),
            property(name2 -> "property_2")
        );

        dependencies(
            dependency(groupId -> "junit", artifactId -> "junit", version -> "3.8.1", scope -> "test")
        );

    }
}

where it is clear that you are not only dealing with having to make the compiler happy with a class that follows the file name, etc, you could have something along these lines (other changes included here as syntactical feedback, as a lot of things don't make much sense currently; the feedback given here is rushed and doesnt consider other scenarios, such as e.g. will defining an annotationProcessorPath give you a DependencyScope? more considerations should be made):

project("Project :: Submodule", () -> { // ProjectScope
    modelVersion = "4.0.0";

    groupId = "org.sample1";
    artifactId = "project1";
    packaging = "jar";
    version = "1.0-SNAPSHOT";

    properties(() -> { // PropertyScope
        put("key", "value");
        put("otherKey", "otherValue");
    });

    dependencies(() -> { // DependencyScope

        // Each method is named after the scope it represents.
        // Multiple signatures are available:
        //     (String, String) - groupId, artifactId
        //     (String, String. String) - groupId, artifactId, version
        //     (String, String, DependencyDescriptor...) - groupId, artifactId, extra metadata
        //     DependencyDescriptor will have some static constants such as methods such as:
        //          DependencyDescriptor.exclude(...) - alias for <exclude/>
        //          DependencyDescriptor.optional() - alias for <optional>true</optional>
        //     it will be one of the implicitly statically imported things (running the evaluator that JShell uses allows you to add imports before parsing)

        compile("org.apache.commons", "commons-lang3");
        provided("org.apache.commons", "commons-math3", optional(), exclude(() -> { // DependencyExcludeScope
            // less signatures for exclusion* methods as obviously there are less possibilities there
            exclusion("com.example", "example-exclusion")
        }));
        test("junit", "junit", "3.8.1")
    });
});

A scripting-like approach can really make the Java syntax worthwile, and provide the ability for people to get good IDE support even without any extra support added. However, some polyglot plugins to add support for ctrl+click to go to dependencies, project structure reading nicely, etc will always be appreciated by people, as well as adding the maven reload button for intellij users

Going on a tangent, people can always appreciate a seperation between project metadata and building information like dependencies and plugins. This is something Maven 4 is trying to bring, "consumer" and "build" POM. Perhaps by separating these things into different top-level blocks, e.g. project(...) & build(...), this can already be achieved (you just scroll 'till indentation ends!)