Skip to content

Conversation

@javier-godoy
Copy link
Member

@javier-godoy javier-godoy commented Mar 20, 2025

https://github.com/FlowingCode/AddonsInternal/issues/19

  • Combobox for creating simple regular expressions like "contains", "starts", "ends with"
  • Advanced mode for helping in creating regular expressions with automatic validation

Summary by CodeRabbit

  • New Features

    • Introduced a Regular Expression Field UI component for Vaadin 24, enabling users to create, validate, and test regular expressions interactively.
    • Added support for multiple pattern modes: starts with, ends with, contains, and advanced custom regex.
    • Provided a test field to validate sample strings against the defined pattern, with instant feedback.
  • Documentation

    • Updated documentation to reflect the new add-on name, features, and usage instructions.
    • Enhanced README with detailed feature descriptions and updated links.
  • Style

    • Improved and expanded CSS for the new components, including visual feedback for regex validation results.
  • Tests

    • Added comprehensive unit and demo tests to ensure correct behavior of the new regular expression field and its features.
  • Chores

    • Cleaned up obsolete files and updated project configuration to match the new add-on identity.
    • Upgraded Vaadin version and improved build/dependency management.

@javier-godoy javier-godoy force-pushed the initial-implementation branch 2 times, most recently from e7d16cb to a24eef1 Compare March 20, 2025 19:34
@javier-godoy javier-godoy requested a review from paodb March 21, 2025 16:34
@javier-godoy javier-godoy force-pushed the initial-implementation branch 2 times, most recently from 58ae78d to 82d2ba6 Compare March 31, 2025 12:06
@javier-godoy javier-godoy changed the title WIP: feat: initial implementation feat: initial implementation Mar 31, 2025
@javier-godoy javier-godoy force-pushed the initial-implementation branch from 82d2ba6 to 982600d Compare April 3, 2025 15:21
@javier-godoy javier-godoy requested a review from paodb April 7, 2025 13:07
Copy link
Member

@paodb paodb left a comment

Choose a reason for hiding this comment

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

Also please check in pom, information in scm tag needs to be updated accordingly. And ViewIT still checks for "paper-input" element. Done.

Copy link
Member

@paodb paodb left a comment

Choose a reason for hiding this comment

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

Please check punctuation in block tags like param and return as they are not supposed to end with period. See FlowingCode/DevelopmentConventions#49 (comment) Done.

@github-project-automation github-project-automation bot moved this from To Do to In Progress in Flowing Code Addons Apr 28, 2025
@javier-godoy javier-godoy force-pushed the initial-implementation branch from dc2063f to ce9c7ed Compare April 29, 2025 13:16
@javier-godoy javier-godoy requested a review from paodb April 29, 2025 13:16
@javier-godoy javier-godoy force-pushed the initial-implementation branch from ce9c7ed to 4768591 Compare May 7, 2025 13:14
@javier-godoy javier-godoy requested a review from paodb May 7, 2025 13:14
@paodb
Copy link
Member

paodb commented May 8, 2025

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented May 8, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented May 8, 2025

Walkthrough

This update introduces a new Vaadin add-on, "Regular Expression Field Add-on," replacing the previous "Template Add-on." It adds new Java classes for regular expression construction, validation, and testing UI components, updates documentation and configuration files to reflect the new add-on identity, and removes obsolete template-related files and tests. The Maven configuration is revised, and test/demo code is adapted for the new functionality.

Changes

Files/Paths Change Summary
README.md, pom.xml Updated all references from "template-addon" to "regular-expression-field-addon"; revised badges, URLs, artifact IDs, and project names. Upgraded Vaadin version, restructured plugin configs, added Lombok dependency, and improved demo profile.
src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpression.java
src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionField.java
src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionOperator.java
src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionTestField.java
Introduced new Java classes: RegularExpression for regex encapsulation, RegularExpressionField as a Vaadin UI component for regex creation and validation, RegularExpressionOperator as an enum for regex modes, and RegularExpressionTestField for testing regexes against multiple inputs.
src/main/resources/META-INF/VAADIN/package.properties Removed Vaadin allowed-packages configuration line.
src/main/resources/META-INF/frontend/styles/fc-regex-test-strings.css Updated add-on name, copyright year, license formatting, and added new CSS rules for regex test field UI.
src/main/resources/META-INF/frontend/styles/static_addon_styles
src/main/resources/META-INF/resources/static_addon_resources
Deleted unused placeholder files for static styles and resources.
src/test/java/com/flowingcode/vaadin/addons/DemoLayout.java Updated license header for new add-on name and year.
src/test/java/com/flowingcode/vaadin/addons/regex/DemoView.java
src/test/java/com/flowingcode/vaadin/addons/regex/RegularExpressionFieldView.java
Changed package declarations, route annotations, and internal references to reflect new add-on identity and structure.
src/test/java/com/flowingcode/vaadin/addons/regex/RegularExpressionFieldDemo.java Added new demo class showcasing the RegularExpressionField component, including test mode and value change listener.
src/test/java/com/flowingcode/vaadin/addons/regex/test/RegularExpressionTest.java Added new test class covering various RegularExpression behaviors, operators, quoting, and round-trip conversions.
src/test/java/com/flowingcode/vaadin/addons/regex/test/SerializationTest.java Updated serialization test to use RegularExpressionField instead of the old template component.
src/test/java/com/flowingcode/vaadin/addons/template/TemplateDemo.java
src/test/java/com/flowingcode/vaadin/addons/template/it/AbstractViewTest.java
src/test/java/com/flowingcode/vaadin/addons/template/it/ViewIT.java
Deleted demo and integration test classes related to the old template add-on.
src/test/resources/META-INF/frontend/styles/shared-styles.css
src/test/resources/META-INF/resources/static_addon_test_resources
Deleted unused test resource and style placeholder files.

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (7)
src/test/java/com/flowingcode/vaadin/addons/regex/test/SerializationTest.java (1)

45-51: Enhance serialization test with explicit assertions. Currently the test only fails on exceptions. To strengthen it, capture the result of obj.getClass().cast(...) and add an Assert.assertNotNull(...) (or equivalent) to verify the object was deserialized correctly.

README.md (1)

75-75: Inconsistent capitalization in author line. Change "Regular Expression Field Add-On" to "Regular Expression Field Add-on" to match branding elsewhere.

src/test/java/com/flowingcode/vaadin/addons/regex/RegularExpressionFieldDemo.java (1)

41-51: Consider extracting the conditional debug code.

The conditional compilation directive (#if vaadin eq 0) contains UI logic that might be better separated into a private method for clarity. This would improve code organization, especially if more debugging features are added in the future.

 add(field);
 // #if vaadin eq 0
-Div div1 = new Div();
-Div div2 = new Div();
-add(div1, div2);
-field.addValueChangeListener(
-    ev -> {
-      div1.setText(Optional.ofNullable(ev.getValue()).map(Object::toString).orElse(""));
-      div2.setText(Optional.ofNullable(ev.getValue()).map(RegularExpression::getPattern)
-          .map(Pattern::pattern).orElse(""));
-    });
+addDebugComponents(field);
 // #endif
+
+// #if vaadin eq 0
+private void addDebugComponents(RegularExpressionField field) {
+  Div div1 = new Div();
+  Div div2 = new Div();
+  add(div1, div2);
+  field.addValueChangeListener(
+      ev -> {
+        div1.setText(Optional.ofNullable(ev.getValue()).map(Object::toString).orElse(""));
+        div2.setText(Optional.ofNullable(ev.getValue()).map(RegularExpression::getPattern)
+            .map(Pattern::pattern).orElse(""));
+      });
+}
+// #endif
src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionTestField.java (2)

53-101: Consider extracting complex grid setup logic to separate methods.

The grid setup and configuration logic is quite extensive. Consider refactoring this by extracting different aspects (editor setup, button creation, event handling) into separate private methods to improve readability and maintainability.

For example, you could extract event handlers to separate methods:

-    grid.addItemClickListener(ev -> grid.getEditor().editItem(ev.getItem()));
-    editField.addBlurListener(ev -> {
-      grid.getEditor().closeEditor();
-    });
-    grid.getEditor().addCloseListener(ev -> {
-      if (ev.getItem()[0].isEmpty()) {
-        grid.getListDataView().removeItem(ev.getItem());
-      }
-    });
-    grid.getEditor().addOpenListener(ev -> {
-      editField.focus();
-    });
+    setupGridListeners(grid, editField);

And add the extracted method:

private void setupGridListeners(Grid<String[]> grid, TextField editField) {
  grid.addItemClickListener(ev -> grid.getEditor().editItem(ev.getItem()));
  editField.addBlurListener(ev -> grid.getEditor().closeEditor());
  grid.getEditor().addCloseListener(ev -> {
    if (ev.getItem()[0].isEmpty()) {
      grid.getListDataView().removeItem(ev.getItem());
    }
  });
  grid.getEditor().addOpenListener(ev -> editField.focus());
}

110-129: Consider adding null checks for pattern parameter.

The setPattern method doesn't explicitly check if the pattern is null before using it. Although the current implementation handles null through Optional in the RegularExpression method, it's good practice to include explicit validation.

public void setPattern(Pattern pattern) {
+   // null pattern will clear the current pattern
    this.pattern = pattern;
    grid.getDataProvider().refreshAll();
}
src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionField.java (2)

57-68: Initialize testFieldEnabled in constructor.

The visibility of the testField depends on testFieldEnabled, but testFieldEnabled is not explicitly initialized in the constructor. While it defaults to false as a class field, consider initializing it explicitly in the constructor for clarity.

public RegularExpressionField() {
    operatorField = new Select<>();
    operatorField.setItems(RegularExpressionOperator.values());
    inputField = new TextField();

    testField = new RegularExpressionTestField();
    testField.setVisible(false);
+   testFieldEnabled = false;
    add(new HorizontalLayout(operatorField, inputField), testField);

    operatorField.addValueChangeListener(ev -> setTestFieldEnabled(testFieldEnabled));
    addValueChangeListener(ev -> testField.setPattern(getValue()));
}

70-88: Simplify generateModelValue by handling empty fields first.

The method can be simplified by restructuring to handle empty fields case first, which would reduce nesting and improve readability.

@Override
protected RegularExpression generateModelValue() {
    if (hasPatternSyntaxError) {
        onPatternSyntaxException(null, 0);
        hasPatternSyntaxError = false;
    }
-   if (!inputField.isEmpty() && !operatorField.isEmpty()) {
-       try {
-           var r = new RegularExpression(operatorField.getValue(), inputField.getValue());
-           return r;
-       } catch (PatternSyntaxException e) {
-           onPatternSyntaxException(e.getDescription(), e.getIndex());
-           hasPatternSyntaxError = true;
-           return null;
-       }
-   } else {
+   if (inputField.isEmpty() || operatorField.isEmpty()) {
        return null;
+   }
+       
+   try {
+       var r = new RegularExpression(operatorField.getValue(), inputField.getValue());
+       return r;
+   } catch (PatternSyntaxException e) {
+       onPatternSyntaxException(e.getDescription(), e.getIndex());
+       hasPatternSyntaxError = true;
+       return null;
    }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 656a59c and 4768591.

📒 Files selected for processing (21)
  • README.md (3 hunks)
  • pom.xml (6 hunks)
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpression.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionField.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionOperator.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionTestField.java (1 hunks)
  • src/main/resources/META-INF/VAADIN/package.properties (0 hunks)
  • src/main/resources/META-INF/frontend/styles/fc-regex-test-strings.css (1 hunks)
  • src/main/resources/META-INF/frontend/styles/static_addon_styles (0 hunks)
  • src/main/resources/META-INF/resources/static_addon_resources (0 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/DemoLayout.java (1 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/regex/DemoView.java (3 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/regex/RegularExpressionFieldDemo.java (1 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/regex/RegularExpressionFieldView.java (2 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/regex/test/RegularExpressionTest.java (1 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/regex/test/SerializationTest.java (2 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/template/TemplateDemo.java (0 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/template/it/AbstractViewTest.java (0 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/template/it/ViewIT.java (0 hunks)
  • src/test/resources/META-INF/frontend/styles/shared-styles.css (0 hunks)
  • src/test/resources/META-INF/resources/static_addon_test_resources (0 hunks)
💤 Files with no reviewable changes (8)
  • src/test/resources/META-INF/resources/static_addon_test_resources
  • src/main/resources/META-INF/frontend/styles/static_addon_styles
  • src/main/resources/META-INF/resources/static_addon_resources
  • src/main/resources/META-INF/VAADIN/package.properties
  • src/test/resources/META-INF/frontend/styles/shared-styles.css
  • src/test/java/com/flowingcode/vaadin/addons/template/TemplateDemo.java
  • src/test/java/com/flowingcode/vaadin/addons/template/it/ViewIT.java
  • src/test/java/com/flowingcode/vaadin/addons/template/it/AbstractViewTest.java
🔇 Additional comments (30)
src/test/java/com/flowingcode/vaadin/addons/DemoLayout.java (1)

3-6: License header updated correctly. The add-on name and copyright year have been updated consistently with the new branding.

src/test/java/com/flowingcode/vaadin/addons/regex/test/SerializationTest.java (2)

3-6: License header updated correctly. The add-on name and copyright year have been bumped to 2025.


20-23: Package and import adjustments are accurate. The test now references the new com.flowingcode.vaadin.addons.regex package and imports RegularExpressionField.

src/test/java/com/flowingcode/vaadin/addons/regex/DemoView.java (3)

3-6: License header updated to new add-on. The header reflects the renamed add-on and updated year.


21-21: Package declaration updated. Moved to the regex namespace to match the component’s package.


34-34: Navigation target updated. Forwarding to RegularExpressionFieldView aligns the demo with the new view class.

src/main/resources/META-INF/frontend/styles/fc-regex-test-strings.css (2)

3-6: License header updated. The file header now correctly names the Regular Expression Field Add-on and year.


20-40: New CSS rules look correct. Styles for grid cells, buttons, and feedback parts are defined properly and leverage Lumo tokens appropriately.

README.md (5)

1-5: Badges updated successfully. All directory, build, and Maven Central badges point to the new regular-expression-field-add-on artifact.


7-7: Project title updated. The heading correctly identifies the add-on as "Regular Expression Field Add-on."


13-15: Features section revised. The new bullet points accurately describe the simple and advanced regex capabilities.


20-20: Demo link updated. The online demo URL now reflects the regular-expression-field path.


33-33: Dependency artifactId updated. The Maven coordinates now use regular-expression-field-addon.

src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionOperator.java (1)

20-42: Well-structured enum definition with clear documentation.

The enum definition is clean, concise, and follows Java best practices. Each operator's purpose is clearly documented, making the API easy to understand for developers.

src/test/java/com/flowingcode/vaadin/addons/regex/RegularExpressionFieldView.java (2)

31-32: GitHub link has been properly updated.

The GitHub link has been updated to reflect the new repository location, addressing the previous review comment.


34-37: Class constructor properly initializes the demo.

The constructor properly initializes the TabbedDemo with the appropriate demo class for the regular expression field.

src/test/java/com/flowingcode/vaadin/addons/regex/RegularExpressionFieldDemo.java (1)

35-40: Well-structured demo initialization with test data.

The demo initializes the RegularExpressionField with an appropriate test pattern and sample strings, providing a good demonstration of the component's functionality.

pom.xml (4)

15-15: Vaadin version updated appropriately.

Upgrading from 24.4.6 to 24.7.0 ensures the add-on uses a more recent version of the framework.


124-129: Lombok dependency added with appropriate scope.

The addition of Lombok with 'provided' scope is appropriate, ensuring it's available during compile time but not included in the final artifact.


275-277: Frontend hotdeploy property correctly moved to system properties.

Moving the frontend.hotdeploy property to the Jetty plugin's systemProperties section ensures it's properly set when Jetty runs.


548-562: Antrun tasks updated with proper frontend resource handling.

The Maven Antrun plugin configuration has been updated to properly handle frontend resources, ensuring they're correctly placed for the demo-war build profile.

src/test/java/com/flowingcode/vaadin/addons/regex/test/RegularExpressionTest.java (4)

28-39: Well-structured test cases with comprehensive assertions.

The test structure is clear and effective, with proper assertions using Hamcrest matchers to validate both the pattern generation and the input preservation. The test also verifies the reconstruction from a Pattern back to a RegularExpression instance.


41-50: Good test for special character escaping in STARTS_WITH mode.

This test properly verifies that the square bracket character is correctly escaped when used with the STARTS_WITH operator, and that the original input is preserved. The pattern generation and round-trip conversion are both validated.


85-94: Thorough handling of edge case with escape sequences.

The test effectively validates the correct handling of a complex case involving the \E escape sequence, which is a potential edge case in regular expression quoting.


118-129: Excellent coverage of regular expression metacharacters.

The test iterates through all common regex metacharacters to ensure they're properly escaped in CONTAINS mode patterns. This is a comprehensive approach to testing character escaping.

src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionTestField.java (2)

38-46: Well-documented class purpose with clear Javadoc.

The class documentation clearly describes its purpose and functionality, addressing the previous review comment.


93-99: Good use of part name generator for visual feedback.

The implementation using setPartNameGenerator to provide visual feedback on regex matching is clean and effective. This allows CSS styling to be applied based on match results.

src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpression.java (2)

35-47: Well-documented class with clear Javadoc.

The class documentation clearly describes its purpose and functionality, addressing the previous review comment.


93-108: Clever optimization for regex quoting strategies.

The quote method intelligently selects between two different quoting strategies based on which produces the shorter result. This optimization helps keep regular expressions as concise as possible.

src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionField.java (1)

29-42: Well-documented class with comprehensive Javadoc.

The class documentation clearly describes its purpose and features, addressing the previous review comment.

@javier-godoy javier-godoy force-pushed the initial-implementation branch from 4768591 to cfe0278 Compare May 8, 2025 14:47
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpression.java (1)

126-128: Null check implemented correctly.

The null check for the pattern parameter has been properly implemented as suggested in a previous review.

🧹 Nitpick comments (3)
src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpression.java (3)

76-89: Consider validating empty input strings.

The constructor accepts empty input strings, which might produce unexpected regex patterns for operators like CONTAINS, STARTS_WITH, and ENDS_WITH. Consider adding validation to ensure input is not empty for these operators.

public RegularExpression(@NonNull RegularExpressionOperator operator, @NonNull String input)
    throws PatternSyntaxException {
  this.operator = operator;
  this.input = input;

+ // Validate input for non-ADVANCED operators
+ if (operator != ADVANCED && input.isEmpty()) {
+   throw new IllegalArgumentException("Input string cannot be empty for " + operator + " operator");
+ }

  String regex = switch (operator) {
    case ADVANCED -> input;
    case CONTAINS -> ANY + quote(input) + ANY;
    case ENDS_WITH -> ANY + quote(input);
    case STARTS_WITH -> quote(input) + ANY;
  };

  pattern = Pattern.compile(regex);
}

91-106: Improve robustness of pattern creation.

The current approach of using string replacement to incorporate the CHARS constant into pattern definitions could be error-prone if CHARS changes. Consider using Pattern.quote() for simpler cases or creating a more robust pattern builder.

private final static String CHARS = ".?+*\\[({$^|\\\\";

-private final static Pattern SIMPLE_PATTERN =
-    Pattern.compile("(?:[^CHARS]|\\\\[CHARS])+".replace("CHARS", CHARS));
-
-private final static Pattern ESCAPE_PATTERN =
-    Pattern.compile("[CHARS]".replace("CHARS", CHARS));
-
-private final static Pattern UNQUOTE_PATTERN =
-    Pattern.compile("\\\\([CHARS])".replace("CHARS", CHARS));
+// Improved pattern definitions for better readability and maintainability
+private final static Pattern SIMPLE_PATTERN = Pattern.compile(
+    "(?:[^" + CHARS + "]|\\\\" + "[" + CHARS + "])+");
+
+private final static Pattern ESCAPE_PATTERN = Pattern.compile(
+    "[" + CHARS + "]");
+
+private final static Pattern UNQUOTE_PATTERN = Pattern.compile(
+    "\\\\([" + CHARS + "])");

124-163: Improve readability of the factory method.

The factory method contains complex logic that could benefit from more descriptive variable names and possibly breaking down into smaller methods.

public static RegularExpression of(Pattern pattern) {
  if (pattern == null) {
    throw new NullPointerException("Pattern cannot be null");
  }

  String regex = pattern.pattern();
-  boolean notStartsWith = false;
-  boolean notEndsWith = false;
+  boolean hasLeadingWildcard = false;
+  boolean hasTrailingWildcard = false;
  if (regex.startsWith(ANY)) {
-    notStartsWith = true;
+    hasLeadingWildcard = true;
    regex = regex.substring(2);
  }

  if (regex.endsWith(ANY)) {
-    notEndsWith = true;
+    hasTrailingWildcard = true;
    regex = regex.substring(0, regex.length() - 2);
  }

  String input = null;
-  if (notStartsWith || notEndsWith) {
+  if (hasLeadingWildcard || hasTrailingWildcard) {
    if (SIMPLE_PATTERN.matcher(regex).matches()) {
      input = UNQUOTE_PATTERN.matcher(regex).replaceAll("$1");
    } else if (regex.startsWith("\\Q") && regex.endsWith("\\E")) {
      input = regex.substring(2, regex.length() - 2).replace("\\E\\\\E\\Q", "\\E");
    }
  }

  if (input != null) {
-    if (notStartsWith && notEndsWith) {
+    if (hasLeadingWildcard && hasTrailingWildcard) {
      return new RegularExpression(CONTAINS, input);
-    } else if (notStartsWith) {
+    } else if (hasLeadingWildcard) {
      return new RegularExpression(ENDS_WITH, input);
-    } else if (notEndsWith) {
+    } else if (hasTrailingWildcard) {
      return new RegularExpression(STARTS_WITH, input);
    }
  }

  return new RegularExpression(ADVANCED, pattern.pattern(), pattern);
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4768591 and cfe0278.

📒 Files selected for processing (21)
  • README.md (3 hunks)
  • pom.xml (6 hunks)
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpression.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionField.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionOperator.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionTestField.java (1 hunks)
  • src/main/resources/META-INF/VAADIN/package.properties (0 hunks)
  • src/main/resources/META-INF/frontend/styles/fc-regex-test-strings.css (1 hunks)
  • src/main/resources/META-INF/frontend/styles/static_addon_styles (0 hunks)
  • src/main/resources/META-INF/resources/static_addon_resources (0 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/DemoLayout.java (1 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/regex/DemoView.java (3 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/regex/RegularExpressionFieldDemo.java (1 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/regex/RegularExpressionFieldView.java (2 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/regex/test/RegularExpressionTest.java (1 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/regex/test/SerializationTest.java (2 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/template/TemplateDemo.java (0 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/template/it/AbstractViewTest.java (0 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/template/it/ViewIT.java (0 hunks)
  • src/test/resources/META-INF/frontend/styles/shared-styles.css (0 hunks)
  • src/test/resources/META-INF/resources/static_addon_test_resources (0 hunks)
💤 Files with no reviewable changes (8)
  • src/test/resources/META-INF/frontend/styles/shared-styles.css
  • src/main/resources/META-INF/resources/static_addon_resources
  • src/test/resources/META-INF/resources/static_addon_test_resources
  • src/main/resources/META-INF/frontend/styles/static_addon_styles
  • src/main/resources/META-INF/VAADIN/package.properties
  • src/test/java/com/flowingcode/vaadin/addons/template/TemplateDemo.java
  • src/test/java/com/flowingcode/vaadin/addons/template/it/ViewIT.java
  • src/test/java/com/flowingcode/vaadin/addons/template/it/AbstractViewTest.java
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionTestField.java
🚧 Files skipped from review as they are similar to previous changes (11)
  • src/test/java/com/flowingcode/vaadin/addons/DemoLayout.java
  • src/test/java/com/flowingcode/vaadin/addons/regex/test/SerializationTest.java
  • src/test/java/com/flowingcode/vaadin/addons/regex/DemoView.java
  • src/main/resources/META-INF/frontend/styles/fc-regex-test-strings.css
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionOperator.java
  • src/test/java/com/flowingcode/vaadin/addons/regex/RegularExpressionFieldDemo.java
  • src/test/java/com/flowingcode/vaadin/addons/regex/RegularExpressionFieldView.java
  • README.md
  • pom.xml
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionField.java
  • src/test/java/com/flowingcode/vaadin/addons/regex/test/RegularExpressionTest.java
🔇 Additional comments (2)
src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpression.java (2)

49-65: LGTM - Good immutable class design!

The class is properly designed as immutable with final fields and no setters. The use of Lombok annotations reduces boilerplate while maintaining clean semantics.


34-48: Well-documented class with clear purpose.

The class documentation clearly explains the purpose and behavior of the RegularExpression class, addressing the previous review comment.

@javier-godoy javier-godoy force-pushed the initial-implementation branch from cfe0278 to cc846e0 Compare May 8, 2025 14:57
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpression.java (1)

1-170: Consider adding validation tests for edge cases

As mentioned in a previous review comment, this class would benefit from comprehensive unit tests for edge cases.

Ensure that you've implemented unit tests for:

  • Empty input strings with different operators
  • Input containing special regex characters
  • Long patterns
  • Complex escaping sequences
  • Round-trip conversion tests

These tests are crucial to verify the robustness of this implementation.

🧹 Nitpick comments (3)
src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpression.java (3)

102-106: Add more detailed documentation for the quote method

The quote method intelligently chooses between two quoting strategies to optimize the pattern's readability and length, but this logic isn't documented.

/**
+ * Quotes a string for use in a regular expression.
+ * 
+ * <p>This method selects the more efficient quoting strategy between:
+ * <ol>
+ *   <li>Escaping individual special characters</li>
+ *   <li>Using \Q...\E literal quotation with special handling for \E sequences</li>
+ * </ol>
+ * The method chooses the strategy that results in the shorter output string.
+ * 
+ * @param input the string to be quoted
+ * @return the quoted string ready for use in a regex pattern
+ */
 private static String quote(String input) {
   String s1 = ESCAPE_PATTERN.matcher(input).replaceAll("\\\\$0");
   String s2 = "\\Q" + input.replace("\\E", "\\E\\\\E\\Q") + "\\E";
   return (s1.length() < s2.length()) ? s1 : s2;
 }

124-163: Enhance documentation for pattern analysis in the of() method

The pattern reverse-engineering logic is quite complex but lacks detailed documentation explaining the steps involved in determining the operator type.

The method already has good high-level documentation, but adding comments within the method would make the implementation more maintainable:

public static RegularExpression of(Pattern pattern) {

  if (pattern == null) {
    throw new NullPointerException("Pattern cannot be null");
  }

  String regex = pattern.pattern();
  boolean hasLeadingWildcard = false;
  boolean hasTrailingWildcard = false;
+ // Check if the pattern starts with a wildcard (.*) and remove it if present
  if (regex.startsWith(ANY)) {
    hasLeadingWildcard = true;
    regex = regex.substring(2);
  }

+ // Check if the pattern ends with a wildcard (.*) and remove it if present
  if (regex.endsWith(ANY)) {
    hasTrailingWildcard = true;
    regex = regex.substring(0, regex.length() - 2);
  }

  String input = null;
  if (hasLeadingWildcard || hasTrailingWildcard) {
+   // Try to extract the input string by checking if it's a simple pattern
+   // or a pattern enclosed in \Q...\E quotation markers
    if (SIMPLE_PATTERN.matcher(regex).matches()) {
      input = UNQUOTE_PATTERN.matcher(regex).replaceAll("$1");
    } else if (regex.startsWith("\\Q") && regex.endsWith("\\E")) {
      input = regex.substring(2, regex.length() - 2).replace("\\E\\\\E\\Q", "\\E");
    }
  }

+ // Determine which operator to use based on the wildcard positions
  if (input != null) {
    if (hasLeadingWildcard && hasTrailingWildcard) {
      return new RegularExpression(CONTAINS, input);
    } else if (hasLeadingWildcard) {
      return new RegularExpression(ENDS_WITH, input);
    } else if (hasTrailingWildcard) {
      return new RegularExpression(STARTS_WITH, input);
    }
  }

+ // Default to advanced mode if we couldn't determine a simple operator
  return new RegularExpression(ADVANCED, pattern.pattern(), pattern);
}

91-101: Document the regex pattern constants

The constants for regex patterns lack documentation explaining their purpose and usage.

+ /** Characters that need special handling in regex patterns */
 private final static String CHARS = ".?+*\\[({$^|\\\\";

+ /** Pattern for identifying a simple regex containing only literal characters or escaped special characters */
 private final static Pattern SIMPLE_PATTERN =
     Pattern.compile("(?:[^CHARS]|\\\\[CHARS])+".replace("CHARS", CHARS));

+ /** Pattern for identifying special regex characters that need escaping */
 private final static Pattern ESCAPE_PATTERN =
     Pattern.compile("[CHARS]".replace("CHARS", CHARS));

+ /** Pattern for identifying already escaped special characters to be unescaped */
 private final static Pattern UNQUOTE_PATTERN =
     Pattern.compile("\\\\([CHARS])".replace("CHARS", CHARS));
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cfe0278 and cc846e0.

📒 Files selected for processing (21)
  • README.md (3 hunks)
  • pom.xml (6 hunks)
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpression.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionField.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionOperator.java (1 hunks)
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionTestField.java (1 hunks)
  • src/main/resources/META-INF/VAADIN/package.properties (0 hunks)
  • src/main/resources/META-INF/frontend/styles/fc-regex-test-strings.css (1 hunks)
  • src/main/resources/META-INF/frontend/styles/static_addon_styles (0 hunks)
  • src/main/resources/META-INF/resources/static_addon_resources (0 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/DemoLayout.java (1 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/regex/DemoView.java (3 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/regex/RegularExpressionFieldDemo.java (1 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/regex/RegularExpressionFieldView.java (2 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/regex/test/RegularExpressionTest.java (1 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/regex/test/SerializationTest.java (2 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/template/TemplateDemo.java (0 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/template/it/AbstractViewTest.java (0 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/template/it/ViewIT.java (0 hunks)
  • src/test/resources/META-INF/frontend/styles/shared-styles.css (0 hunks)
  • src/test/resources/META-INF/resources/static_addon_test_resources (0 hunks)
💤 Files with no reviewable changes (8)
  • src/test/resources/META-INF/resources/static_addon_test_resources
  • src/main/resources/META-INF/VAADIN/package.properties
  • src/main/resources/META-INF/frontend/styles/static_addon_styles
  • src/test/resources/META-INF/frontend/styles/shared-styles.css
  • src/main/resources/META-INF/resources/static_addon_resources
  • src/test/java/com/flowingcode/vaadin/addons/template/TemplateDemo.java
  • src/test/java/com/flowingcode/vaadin/addons/template/it/ViewIT.java
  • src/test/java/com/flowingcode/vaadin/addons/template/it/AbstractViewTest.java
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionTestField.java
🚧 Files skipped from review as they are similar to previous changes (11)
  • src/main/resources/META-INF/frontend/styles/fc-regex-test-strings.css
  • src/test/java/com/flowingcode/vaadin/addons/DemoLayout.java
  • src/test/java/com/flowingcode/vaadin/addons/regex/test/SerializationTest.java
  • README.md
  • src/test/java/com/flowingcode/vaadin/addons/regex/DemoView.java
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionOperator.java
  • src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpressionField.java
  • src/test/java/com/flowingcode/vaadin/addons/regex/RegularExpressionFieldView.java
  • src/test/java/com/flowingcode/vaadin/addons/regex/RegularExpressionFieldDemo.java
  • src/test/java/com/flowingcode/vaadin/addons/regex/test/RegularExpressionTest.java
  • pom.xml
🔇 Additional comments (4)
src/main/java/com/flowingcode/vaadin/addons/regex/RegularExpression.java (4)

34-46: Javadoc well-documented addressing previous feedback

The class Javadoc clearly explains the purpose and behavior of the RegularExpression class, addressing the previous review comment about including a description of the class purpose.


126-128: Good null check implementation

The null check for the pattern parameter properly addresses the previous code review comment.


49-51: Appropriate Lombok annotations for immutability

The class correctly uses Lombok annotations to implement an immutable class pattern. The @Setter annotation has been removed as suggested in a previous review.


81-89: Well-implemented switch expression with proper pattern handling

The switch expression nicely handles the different operators and generates the appropriate regex pattern for each case. The code leverages modern Java language features effectively.

@paodb paodb merged commit 10a8751 into master May 12, 2025
3 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Pending release in Flowing Code Addons May 12, 2025
@paodb paodb deleted the initial-implementation branch May 12, 2025 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Pending release

Development

Successfully merging this pull request may close these issues.

3 participants