Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
[![Published on Vaadin Directory](https://img.shields.io/badge/Vaadin%20Directory-published-00b4f0.svg)](https://vaadin.com/directory/component/template-add-on)
[![Stars on vaadin.com/directory](https://img.shields.io/vaadin-directory/star/template-add-on.svg)](https://vaadin.com/directory/component/template-add-on)
[![Build Status](https://jenkins.flowingcode.com/job/template-addon/badge/icon)](https://jenkins.flowingcode.com/job/template-addon)
[![Maven Central](https://img.shields.io/maven-central/v/com.flowingcode.vaadin.addons/template-addon)](https://mvnrepository.com/artifact/com.flowingcode.vaadin.addons/template-addon)
[![Javadoc](https://img.shields.io/badge/javadoc-00b4f0)](https://javadoc.flowingcode.com/artifact/com.flowingcode.vaadin.addons/template-addon)
[![Published on Vaadin Directory](https://img.shields.io/badge/Vaadin%20Directory-published-00b4f0.svg)](https://vaadin.com/directory/component/regular-expression-field-add-on)
[![Stars on vaadin.com/directory](https://img.shields.io/vaadin-directory/star/regular-expression-field-add-on.svg)](https://vaadin.com/directory/component/regular-expression-field-add-on)
[![Build Status](https://jenkins.flowingcode.com/job/regular-expression-field-addon/badge/icon)](https://jenkins.flowingcode.com/job/regular-expression-field-addon)
[![Maven Central](https://img.shields.io/maven-central/v/com.flowingcode.vaadin.addons/regular-expression-field-addon)](https://mvnrepository.com/artifact/com.flowingcode.vaadin.addons/regular-expression-field-addon)
[![Javadoc](https://img.shields.io/badge/javadoc-00b4f0)](https://javadoc.flowingcode.com/artifact/com.flowingcode.vaadin.addons/regular-expression-field-addon)

# Template Add-on
# Regular Expression Field Add-on

This is a template project for building new Vaadin 24 add-ons
A field for Vaadin 24 that assists in creating regular expressions.

## Features

* List the features of your add-on in here
* A ComboBox option for creating simple regular expressions, such as "contains."
* Additional options for patterns like "starts with" and "ends with."
* An advanced mode that assists in creating complex regular expressions with automatic validation.


## Online demo

[Online demo here](http://addonsv24.flowingcode.com/template)
[Online demo here](http://addonsv24.flowingcode.com/regular-expression-field)

## Download release

[Available in Vaadin Directory](https://vaadin.com/directory/component/template-add-on)
[Available in Vaadin Directory](https://vaadin.com/directory/component/regular-expression-field-add-on)

### Maven install

Expand All @@ -27,7 +30,7 @@ Add the following dependencies in your pom.xml file:
```xml
<dependency>
<groupId>com.flowingcode.vaadin.addons</groupId>
<artifactId>template-addon</artifactId>
<artifactId>regular-expression-field-addon</artifactId>
<version>X.Y.Z</version>
</dependency>
```
Expand Down Expand Up @@ -69,7 +72,7 @@ Then, follow these steps for creating a contribution:

This add-on is distributed under Apache License 2.0. For license terms, see LICENSE.txt.

TEMPLATE_ADDON is written by Flowing Code S.A.
Regular Expression Field Add-On is written by Flowing Code S.A.

# Developer Guide

Expand Down
48 changes: 29 additions & 19 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
<modelVersion>4.0.0</modelVersion>

<groupId>com.flowingcode.vaadin.addons</groupId>
<artifactId>template-addon</artifactId>
<artifactId>regular-expression-field-addon</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>Template Add-on</name>
<description>Template Add-on for Vaadin Flow</description>
<name>Regular Expression Field Add-on</name>
<description>Regular Expression Field Add-on for Vaadin Flow</description>
<url>https://www.flowingcode.com/en/open-source/</url>

<properties>
<vaadin.version>24.4.6</vaadin.version>
<vaadin.version>24.7.0</vaadin.version>
<selenium.version>4.10.0</selenium.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
Expand All @@ -21,7 +21,6 @@
<drivers.dir>${project.basedir}/drivers</drivers.dir>
<jetty.version>11.0.20</jetty.version>
<flowingcode.commons.demo.version>4.2.0</flowingcode.commons.demo.version>
<frontend.hotdeploy>true</frontend.hotdeploy>
</properties>

<organization>
Expand All @@ -39,9 +38,9 @@
</licenses>

<scm>
<url>https://github.com/FlowingCode/AddonStarter24</url>
<connection>scm:git:git://github.com/FlowingCode/AddonStarter24.git</connection>
<developerConnection>scm:git:ssh://[email protected]:/FlowingCode/AddonStarter24.git</developerConnection>
<url>https://github.com/FlowingCode/RegularExpressionField</url>
<connection>scm:git:git://github.com/FlowingCode/RegularExpressionField.git</connection>
<developerConnection>scm:git:ssh://[email protected]:/FlowingCode/RegularExpressionField.git</developerConnection>
<tag>master</tag>
</scm>

Expand Down Expand Up @@ -122,6 +121,12 @@
<artifactId>vaadin-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.flowingcode.vaadin.addons.demo</groupId>
<artifactId>commons-demo</artifactId>
Expand Down Expand Up @@ -264,15 +269,12 @@
<scan>3</scan>
<!-- Use test scope because the UI/demo classes are in the test package. -->
<useTestScope>true</useTestScope>
<webApp>
<resourceBases>
<resourceBase>src/test/resources/META-INF/resources</resourceBase>
<resourceBase>src/main/resources/META-INF/resources</resourceBase>
</resourceBases>
</webApp>
<supportedPackagings>
<supportedPackaging>jar</supportedPackaging>
</supportedPackagings>
<systemProperties>
<vaadin.frontend.hotdeploy>true</vaadin.frontend.hotdeploy>
</systemProperties>
</configuration>
</plugin>
</plugins>
Expand Down Expand Up @@ -503,8 +505,11 @@
</build>
</profile>

<profile>
<profile>
<id>demo-war</id>
<properties>
<vaadin.productionMode>true</vaadin.productionMode>
</properties>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
Expand Down Expand Up @@ -540,15 +545,21 @@
<goal>run</goal>
</goals>
<configuration>
<target name="copy-demo">
<copy todir="${project.basedir}/src/main">
<tasks>
<copy todir="${project.basedir}/src/main" failonerror="false">
<fileset dir="${project.basedir}/src/test">
<include name="**"/>
<exclude name="**/it/*"/>
<exclude name="**/test/*"/>
</fileset>
</copy>
</target>
<copy todir="${project.basedir}/src/main/resources/META-INF/resources/frontend" failonerror="false">
<fileset dir="${project.basedir}/src/main/resources/META-INF/frontend"/>
</copy>
<delete failonerror="false">
<fileset dir="${project.basedir}/src/main/resources/META-INF/frontend"/>
</delete>
</tasks>
</configuration>
</execution>
</executions>
Expand Down Expand Up @@ -586,7 +597,6 @@
</plugins>
</build>
</profile>

</profiles>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*-
* #%L
* Regular Expression Field Add-on
* %%
* Copyright (C) 2025 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package com.flowingcode.vaadin.addons.regex;

import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.ADVANCED;
import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.CONTAINS;
import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.ENDS_WITH;
import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.STARTS_WITH;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull;

/**
* Represents a regular expression.
*
* <p>
* This class assists in the creation and handling of regular expressions by providing pre-defined
* operators for common patterns such as "starts with", "ends with", and "contains". It also
* supports an advanced mode where users can input custom regular expressions.
* </p>
*
* <p>
* Instances of this class are immutable and validated upon creation.
* </p>
*
* @author Javier Godoy
*/
@Getter
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public final class RegularExpression {

private static final String ANY = ".*";

/** The operator defining the type of regular expression. */
@EqualsAndHashCode.Include
private final RegularExpressionOperator operator;

/** The input string used for generating the pattern. */
@EqualsAndHashCode.Include
private final String input;

/** The compiled {@code Pattern} for the regular expression. */
private final Pattern pattern;

/**
* Creates a new {@code RegularExpression} based on the specified {@code operator} and
* {@code input}.
*
* @param operator the type of regular expression (e.g.,
* {@link RegularExpressionOperator#CONTAINS})
* @param input the string to be used for pattern creation
* @throws PatternSyntaxException if the resulting pattern is invalid.
*/
public RegularExpression(@NonNull RegularExpressionOperator operator, @NonNull String input)
throws PatternSyntaxException {
this.operator = operator;
this.input = input;

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);
}

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));

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;
}

/**
* Creates a {@code RegularExpression} instance from a given {@link Pattern}.
*
* <p>
* This method attempts to determine if the pattern corresponds to a simple
* {@link RegularExpressionOperator} like "starts with", "ends with", or "contains". If it does, a
* corresponding {@code RegularExpression} is returned. Otherwise, an advanced mode expression is
* created.
* </p>
*
* @param pattern the pattern to analyze
*
* @throws NullPointerException if {@code pattern} is {@code null}.
*
* @return a {@code RegularExpression} instance
*/
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;
if (regex.startsWith(ANY)) {
hasLeadingWildcard = true;
regex = regex.substring(2);
}

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

String input = null;
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 (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);
}
}

return new RegularExpression(ADVANCED, pattern.pattern(), pattern);
}

@Override
public String toString() {
return operator + " " + input;
}

}
Loading