Skip to content
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

feat: JDK 22 string templates #640

Merged
merged 1 commit into from
Feb 15, 2024

Conversation

jtkiesel
Copy link
Contributor

@jtkiesel jtkiesel commented Jan 22, 2024

What changed with this PR:

JDK 22 string templates are now supported. The printing of certain more complex embedded expressions is far from perfect, but I didn't want that to hold up this support and can make improvements to that in a subsequent PR.

Example

Input

class TemplateExpression {

  String info = STR."My name is \{name}";

  String s = STR."\{x} + \{y} = \{x + y}";

  String s = STR."You have a \{getOfferType()} waiting for you!";

  String msg = STR."The file \{filePath} \{file.exists() ? "does" : "does not"} exist";

  String time = STR."The time is \{
    // The java.time.format package is very useful
    DateTimeFormatter
      .ofPattern("HH:mm:ss")
      .format(LocalTime.now())
  } right now";

  String data = STR."\{index++}, \{index++}, \{index++}, \{index++}";

  String s = STR."\{fruit[0]}, \{STR."\{fruit[1]}, \{fruit[2]}"}";

  String html = STR."""
    <html>
      <head>
        <title>\{title}</title>
      </head>
      <body>
        <p>\{text}</p>
      </body>
    </html>
    """;

  String table = STR."""
    Description  Width  Height  Area
    \{zone[0].name}  \{zone[0].width}  \{zone[0].height}     \{zone[0].area()}
    \{zone[1].name}  \{zone[1].width}  \{zone[1].height}     \{zone[1].area()}
    \{zone[2].name}  \{zone[2].width}  \{zone[2].height}     \{zone[2].area()}
    Total \{zone[0].area() + zone[1].area() + zone[2].area()}
    """;

  String table = FMT."""
    Description     Width    Height     Area
    %-12s\{zone[0].name}  %7.2f\{zone[0].width}  %7.2f\{zone[0].height}     %7.2f\{zone[0].area()}
    %-12s\{zone[1].name}  %7.2f\{zone[1].width}  %7.2f\{zone[1].height}     %7.2f\{zone[1].area()}
    %-12s\{zone[2].name}  %7.2f\{zone[2].width}  %7.2f\{zone[2].height}     %7.2f\{zone[2].area()}
    \{" ".repeat(28)} Total %7.2f\{zone[0].area() + zone[1].area() + zone[2].area()}
    """;

  PreparedStatement ps = DB."SELECT * FROM Person p WHERE p.last_name = \{name}";
}

Output

class TemplateExpression {

  String info = STR."My name is \{name}";

  String s = STR."\{x} + \{y} = \{x + y}";

  String s = STR."You have a \{getOfferType()} waiting for you!";

  String msg =
    STR."The file \{filePath} \{file.exists() ? "does" : "does not"} exist";

  String time =
    STR."The time is \{
      // The java.time.format package is very useful
      DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalTime.now())
    } right now";

  String data = STR."\{index++}, \{index++}, \{index++}, \{index++}";

  String s = STR."\{fruit[0]}, \{STR."\{fruit[1]}, \{fruit[2]}"}";

  String html =
    STR."""
    <html>
      <head>
        <title>\{title}</title>
      </head>
      <body>
        <p>\{text}</p>
      </body>
    </html>
    """;

  String table =
    STR."""
    Description  Width  Height  Area
    \{zone[0].name}  \{zone[0].width}  \{zone[0].height}     \{zone[0].area()}
    \{zone[1].name}  \{zone[1].width}  \{zone[1].height}     \{zone[1].area()}
    \{zone[2].name}  \{zone[2].width}  \{zone[2].height}     \{zone[2].area()}
    Total \{zone[0].area() + zone[1].area() + zone[2].area()}
    """;

  String table =
    FMT."""
    Description     Width    Height     Area
    %-12s\{zone[0].name}  %7.2f\{zone[0].width}  %7.2f\{
      zone[0].height
    }     %7.2f\{zone[0].area()}
    %-12s\{zone[1].name}  %7.2f\{zone[1].width}  %7.2f\{
      zone[1].height
    }     %7.2f\{zone[1].area()}
    %-12s\{zone[2].name}  %7.2f\{zone[2].width}  %7.2f\{
      zone[2].height
    }     %7.2f\{zone[2].area()}
    \{" ".repeat(28)} Total %7.2f\{
      zone[0].area() + zone[1].area() + zone[2].area()
    }
    """;

  PreparedStatement ps =
    DB."SELECT * FROM Person p WHERE p.last_name = \{name}";
}

Relative issues or prs:

Closes #618

@jtkiesel jtkiesel marked this pull request as draft January 22, 2024 05:07
@clementdessoude
Copy link
Contributor

I was struggling with if/else blocks when I checked a few weeks/months ago. I don't remember exactly, but I think that this snippet was causing some trouble :/

it("should still parse simple if/else", () => {
    const input = `
      String formatted = "unknown";
      if (o instanceof Integer i) {
          formatted = String.format("int %d", i);
      } else if (o instanceof Double d) {
          formatted = String.format("double %f", d);
      }
      `;

    javaParser.parse(input, "methodDeclaration");
    expect(() => javaParser.parse(input, "methodDeclaration")).to.not.throw();
  });

@jtkiesel
Copy link
Contributor Author

jtkiesel commented Jan 22, 2024

@clementdessoude I ran into something similar to that as well. I ended up resolving it by leveraging Chevrotain's lexer modes (see the changes I made to allTokens in tokens.js). Still running into an issue with idempotency when the embedded expression contains comments, which I'll need to look into.

@jtkiesel jtkiesel marked this pull request as ready for review February 10, 2024 23:32
@jtkiesel
Copy link
Contributor Author

jtkiesel commented Feb 10, 2024

The issue I mentioned above is now fixed. Tokens containing newlines are meant to be split into multiple docs with the newlines replaced with the literalline doc. When I wasn't doing so, I noticed that Prettier was determining line length (and therefore determining where to break) as if the newlines were nonexistent. Luckily, Prettier had a utility function that they use for this purpose that I was easily able to use.

@clementdessoude
Copy link
Contributor

I will look at this tomorrow :)

@clementdessoude clementdessoude merged commit 2bdfbd2 into jhipster:main Feb 15, 2024
6 checks passed
@jtkiesel jtkiesel deleted the feat/string-templates branch April 11, 2024 06:03
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.

Support JDK 22 string templates
2 participants