Skip to content

Commit 4768591

Browse files
committed
feat: initial implementation
1 parent 656a59c commit 4768591

File tree

21 files changed

+783
-264
lines changed

21 files changed

+783
-264
lines changed

README.md

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
1-
[![Published on Vaadin Directory](https://img.shields.io/badge/Vaadin%20Directory-published-00b4f0.svg)](https://vaadin.com/directory/component/template-add-on)
2-
[![Stars on vaadin.com/directory](https://img.shields.io/vaadin-directory/star/template-add-on.svg)](https://vaadin.com/directory/component/template-add-on)
3-
[![Build Status](https://jenkins.flowingcode.com/job/template-addon/badge/icon)](https://jenkins.flowingcode.com/job/template-addon)
4-
[![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)
5-
[![Javadoc](https://img.shields.io/badge/javadoc-00b4f0)](https://javadoc.flowingcode.com/artifact/com.flowingcode.vaadin.addons/template-addon)
1+
[![Published on Vaadin Directory](https://img.shields.io/badge/Vaadin%20Directory-published-00b4f0.svg)](https://vaadin.com/directory/component/regular-expression-field-add-on)
2+
[![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)
3+
[![Build Status](https://jenkins.flowingcode.com/job/regular-expression-field-addon/badge/icon)](https://jenkins.flowingcode.com/job/regular-expression-field-addon)
4+
[![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)
5+
[![Javadoc](https://img.shields.io/badge/javadoc-00b4f0)](https://javadoc.flowingcode.com/artifact/com.flowingcode.vaadin.addons/regular-expression-field-addon)
66

7-
# Template Add-on
7+
# Regular Expression Field Add-on
88

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

1111
## Features
1212

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

1518
## Online demo
1619

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

1922
## Download release
2023

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

2326
### Maven install
2427

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

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

72-
TEMPLATE_ADDON is written by Flowing Code S.A.
75+
Regular Expression Field Add-On is written by Flowing Code S.A.
7376

7477
# Developer Guide
7578

pom.xml

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
<modelVersion>4.0.0</modelVersion>
66

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

1414
<properties>
15-
<vaadin.version>24.4.6</vaadin.version>
15+
<vaadin.version>24.7.0</vaadin.version>
1616
<selenium.version>4.10.0</selenium.version>
1717
<maven.compiler.source>17</maven.compiler.source>
1818
<maven.compiler.target>17</maven.compiler.target>
@@ -21,7 +21,6 @@
2121
<drivers.dir>${project.basedir}/drivers</drivers.dir>
2222
<jetty.version>11.0.20</jetty.version>
2323
<flowingcode.commons.demo.version>4.2.0</flowingcode.commons.demo.version>
24-
<frontend.hotdeploy>true</frontend.hotdeploy>
2524
</properties>
2625

2726
<organization>
@@ -39,9 +38,9 @@
3938
</licenses>
4039

4140
<scm>
42-
<url>https://github.com/FlowingCode/AddonStarter24</url>
43-
<connection>scm:git:git://github.com/FlowingCode/AddonStarter24.git</connection>
44-
<developerConnection>scm:git:ssh://[email protected]:/FlowingCode/AddonStarter24.git</developerConnection>
41+
<url>https://github.com/FlowingCode/RegularExpressionField</url>
42+
<connection>scm:git:git://github.com/FlowingCode/RegularExpressionField.git</connection>
43+
<developerConnection>scm:git:ssh://[email protected]:/FlowingCode/RegularExpressionField.git</developerConnection>
4544
<tag>master</tag>
4645
</scm>
4746

@@ -122,6 +121,12 @@
122121
<artifactId>vaadin-core</artifactId>
123122
<optional>true</optional>
124123
</dependency>
124+
<dependency>
125+
<groupId>org.projectlombok</groupId>
126+
<artifactId>lombok</artifactId>
127+
<version>1.18.36</version>
128+
<scope>provided</scope>
129+
</dependency>
125130
<dependency>
126131
<groupId>com.flowingcode.vaadin.addons.demo</groupId>
127132
<artifactId>commons-demo</artifactId>
@@ -264,15 +269,12 @@
264269
<scan>3</scan>
265270
<!-- Use test scope because the UI/demo classes are in the test package. -->
266271
<useTestScope>true</useTestScope>
267-
<webApp>
268-
<resourceBases>
269-
<resourceBase>src/test/resources/META-INF/resources</resourceBase>
270-
<resourceBase>src/main/resources/META-INF/resources</resourceBase>
271-
</resourceBases>
272-
</webApp>
273272
<supportedPackagings>
274273
<supportedPackaging>jar</supportedPackaging>
275274
</supportedPackagings>
275+
<systemProperties>
276+
<vaadin.frontend.hotdeploy>true</vaadin.frontend.hotdeploy>
277+
</systemProperties>
276278
</configuration>
277279
</plugin>
278280
</plugins>
@@ -503,8 +505,11 @@
503505
</build>
504506
</profile>
505507

506-
<profile>
508+
<profile>
507509
<id>demo-war</id>
510+
<properties>
511+
<vaadin.productionMode>true</vaadin.productionMode>
512+
</properties>
508513
<dependencies>
509514
<dependency>
510515
<groupId>com.vaadin</groupId>
@@ -540,15 +545,21 @@
540545
<goal>run</goal>
541546
</goals>
542547
<configuration>
543-
<target name="copy-demo">
544-
<copy todir="${project.basedir}/src/main">
548+
<tasks>
549+
<copy todir="${project.basedir}/src/main" failonerror="false">
545550
<fileset dir="${project.basedir}/src/test">
546551
<include name="**"/>
547552
<exclude name="**/it/*"/>
548553
<exclude name="**/test/*"/>
549554
</fileset>
550555
</copy>
551-
</target>
556+
<copy todir="${project.basedir}/src/main/resources/META-INF/resources/frontend" failonerror="false">
557+
<fileset dir="${project.basedir}/src/main/resources/META-INF/frontend"/>
558+
</copy>
559+
<delete failonerror="false">
560+
<fileset dir="${project.basedir}/src/main/resources/META-INF/frontend"/>
561+
</delete>
562+
</tasks>
552563
</configuration>
553564
</execution>
554565
</executions>
@@ -586,7 +597,6 @@
586597
</plugins>
587598
</build>
588599
</profile>
589-
590600
</profiles>
591601

592602
</project>
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/*-
2+
* #%L
3+
* Regular Expression Field Add-on
4+
* %%
5+
* Copyright (C) 2025 Flowing Code
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
package com.flowingcode.vaadin.addons.regex;
21+
22+
import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.ADVANCED;
23+
import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.CONTAINS;
24+
import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.ENDS_WITH;
25+
import static com.flowingcode.vaadin.addons.regex.RegularExpressionOperator.STARTS_WITH;
26+
import java.util.regex.Pattern;
27+
import java.util.regex.PatternSyntaxException;
28+
import lombok.AccessLevel;
29+
import lombok.AllArgsConstructor;
30+
import lombok.EqualsAndHashCode;
31+
import lombok.Getter;
32+
import lombok.NonNull;
33+
import lombok.Setter;
34+
35+
/**
36+
* Represents a regular expression.
37+
*
38+
* <p>
39+
* This class assists in the creation and handling of regular expressions by providing pre-defined
40+
* operators for common patterns such as "starts with", "ends with", and "contains". It also
41+
* supports an advanced mode where users can input custom regular expressions.
42+
* </p>
43+
*
44+
* <p>
45+
* Instances of this class are immutable and validated upon creation.
46+
* </p>
47+
*
48+
* @author Javier Godoy
49+
*/
50+
@Getter
51+
@Setter
52+
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
53+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
54+
public final class RegularExpression {
55+
56+
private static final String ANY = ".*";
57+
58+
/** The operator defining the type of regular expression. */
59+
@EqualsAndHashCode.Include
60+
private final RegularExpressionOperator operator;
61+
62+
/** The input string used for generating the pattern. */
63+
@EqualsAndHashCode.Include
64+
private final String input;
65+
66+
/** The compiled {@code Pattern} for the regular expression. */
67+
private final Pattern pattern;
68+
69+
/**
70+
* Creates a new {@code RegularExpression} based on the specified {@code operator} and
71+
* {@code input}.
72+
*
73+
* @param operator the type of regular expression (e.g.,
74+
* {@link RegularExpressionOperator#CONTAINS})
75+
* @param input the string to be used for pattern creation
76+
* @throws PatternSyntaxException if the resulting pattern is invalid.
77+
*/
78+
public RegularExpression(@NonNull RegularExpressionOperator operator, @NonNull String input)
79+
throws PatternSyntaxException {
80+
this.operator = operator;
81+
this.input = input;
82+
83+
String regex = switch (operator) {
84+
case ADVANCED -> input;
85+
case CONTAINS -> ANY + quote(input) + ANY;
86+
case ENDS_WITH -> ANY + quote(input);
87+
case STARTS_WITH -> quote(input) + ANY;
88+
};
89+
90+
pattern = Pattern.compile(regex);
91+
}
92+
93+
private final static String CHARS = ".?+*\\[({$^|\\\\";
94+
95+
private final static Pattern SIMPLE_PATTERN =
96+
Pattern.compile("(?:[^CHARS]|\\\\[CHARS])+".replace("CHARS", CHARS));
97+
98+
private final static Pattern ESCAPE_PATTERN =
99+
Pattern.compile("[CHARS]".replace("CHARS", CHARS));
100+
101+
private final static Pattern UNQUOTE_PATTERN =
102+
Pattern.compile("\\\\([CHARS])".replace("CHARS", CHARS));
103+
104+
private static String quote(String input) {
105+
String s1 = ESCAPE_PATTERN.matcher(input).replaceAll("\\\\$0");
106+
String s2 = "\\Q" + input.replace("\\E", "\\E\\\\E\\Q") + "\\E";
107+
return (s1.length() < s2.length()) ? s1 : s2;
108+
}
109+
110+
/**
111+
* Creates a {@code RegularExpression} instance from a given {@link Pattern}.
112+
*
113+
* <p>
114+
* This method attempts to determine if the pattern corresponds to a simple
115+
* {@link RegularExpressionOperator} like "starts with", "ends with", or "contains". If it does, a
116+
* corresponding {@code RegularExpression} is returned. Otherwise, an advanced mode expression is
117+
* created.
118+
* </p>
119+
*
120+
* @param pattern the pattern to analyze
121+
* @return a {@code RegularExpression} instance
122+
*/
123+
public static RegularExpression of(Pattern pattern) {
124+
125+
String regex = pattern.pattern();
126+
boolean notStartsWith = false;
127+
boolean notEndsWith = false;
128+
if (regex.startsWith(ANY)) {
129+
notStartsWith = true;
130+
regex = regex.substring(2);
131+
}
132+
133+
if (regex.endsWith(ANY)) {
134+
notEndsWith = true;
135+
regex = regex.substring(0, regex.length() - 2);
136+
}
137+
138+
String input = null;
139+
if (notStartsWith || notEndsWith) {
140+
if (SIMPLE_PATTERN.matcher(regex).matches()) {
141+
input = UNQUOTE_PATTERN.matcher(regex).replaceAll("$1");
142+
} else if (regex.startsWith("\\Q") && regex.endsWith("\\E")) {
143+
input = regex.substring(2, regex.length() - 2).replace("\\E\\\\E\\Q", "\\E");
144+
}
145+
}
146+
147+
if (input != null) {
148+
if (notStartsWith && notEndsWith) {
149+
return new RegularExpression(CONTAINS, input);
150+
} else if (notStartsWith) {
151+
return new RegularExpression(ENDS_WITH, input);
152+
} else if (notEndsWith) {
153+
return new RegularExpression(STARTS_WITH, input);
154+
}
155+
}
156+
157+
return new RegularExpression(ADVANCED, pattern.pattern(), pattern);
158+
}
159+
160+
@Override
161+
public String toString() {
162+
return operator + " " + input;
163+
}
164+
165+
}

0 commit comments

Comments
 (0)