2121import org .junit .jupiter .api .DisplayName ;
2222import org .junit .jupiter .api .Test ;
2323
24+ import java .util .Arrays ;
2425import java .util .List ;
2526import java .util .regex .Pattern ;
2627
2728import static org .junit .jupiter .api .Assertions .assertEquals ;
2829import static org .junit .jupiter .api .Assertions .assertFalse ;
2930import static org .junit .jupiter .api .Assertions .assertTrue ;
3031
32+ import com .mirkoddd .sift .core .dsl .CharacterClassConnectorStep ;
3133import com .mirkoddd .sift .core .dsl .ConnectorStep ;
3234import com .mirkoddd .sift .core .dsl .SiftContext ;
35+ import com .mirkoddd .sift .core .dsl .SiftPattern ;
36+ import com .mirkoddd .sift .core .dsl .VariableCharacterClassConnectorStep ;
37+ import com .mirkoddd .sift .core .dsl .VariableConnectorStep ;
3338
3439/**
3540 * Validates the real-world examples provided in the COOKBOOK.md file.
@@ -63,16 +68,16 @@ void testUuidValidatorRecipe() {
6368 // Define the basic building blocks using fromAnywhere() (in this case is the static Fragment shortcut exactly())
6469 // This ensures these blocks don't carry a '^' anchor, allowing them
6570 // to be safely placed in the middle or end of our final chain.
66- var hex8 = exactly (8 ).hexDigits ();
67- var hex4 = exactly (4 ).hexDigits ();
68- var hex12 = exactly (12 ).hexDigits ();
69- var separator = exactly (1 ).character ('-' );
71+ CharacterClassConnectorStep < SiftContext . Fragment > hex8 = exactly (8 ).hexDigits ();
72+ CharacterClassConnectorStep < SiftContext . Fragment > hex4 = exactly (4 ).hexDigits ();
73+ CharacterClassConnectorStep < SiftContext . Fragment > hex12 = exactly (12 ).hexDigits ();
74+ ConnectorStep < SiftContext . Fragment > separator = exactly (1 ).character ('-' );
7075
7176 // Compose reusable intermediate blocks
72- var hex4andSeparator = hex4 .followedBy (separator );
77+ ConnectorStep < SiftContext . Fragment > hex4andSeparator = hex4 .followedBy (separator );
7378
7479 // define the list of steps to follow in the final pattern
75- List <ConnectorStep <SiftContext .Fragment >> steps = List . of (
80+ List <ConnectorStep <SiftContext .Fragment >> steps = Arrays . asList (
7681 separator ,
7782 hex4andSeparator ,
7883 hex4andSeparator ,
@@ -99,20 +104,20 @@ void testUuidValidatorRecipe() {
99104 @ DisplayName ("Recipe 2: Parsing Log Files (TSV Format with discrete semantic parts)" )
100105 void testLogParserRecipe () {
101106 // Define discrete temporal components
102- var year = Sift .fromAnywhere ().exactly (4 ).digits ();
103- var month = Sift .fromAnywhere ().exactly (2 ).digits ();
104- var day = Sift .fromAnywhere ().exactly (2 ).digits (); // same as month, but more readable
105- var dash = Sift .fromAnywhere ().character ('-' ); // you could also use literal("-"), less verbose
107+ CharacterClassConnectorStep < SiftContext . Fragment > year = Sift .fromAnywhere ().exactly (4 ).digits ();
108+ CharacterClassConnectorStep < SiftContext . Fragment > month = Sift .fromAnywhere ().exactly (2 ).digits ();
109+ CharacterClassConnectorStep < SiftContext . Fragment > day = Sift .fromAnywhere ().exactly (2 ).digits (); // same as month, but more readable
110+ ConnectorStep < SiftContext . Fragment > dash = Sift .fromAnywhere ().character ('-' ); // you could also use literal("-"), less verbose
106111
107- var dateBlock = year .followedBy (List . of (dash , month , dash , day ));
112+ ConnectorStep < SiftContext . Fragment > dateBlock = year .followedBy (Arrays . asList (dash , month , dash , day ));
108113
109114 // Define structural components
110- var tab = Sift .fromAnywhere ().tab ();
111- var newline = Sift .fromAnywhere ().newline ();
115+ ConnectorStep < SiftContext . Fragment > tab = Sift .fromAnywhere ().tab ();
116+ ConnectorStep < SiftContext . Fragment > newline = Sift .fromAnywhere ().newline ();
112117
113118 // Define payload components
114- var logLevel = Sift .fromAnywhere ().oneOrMore ().upperCaseLetters ();
115- var message = Sift .fromAnywhere ().oneOrMore ().anyCharacter ();
119+ ConnectorStep < SiftContext . Fragment > logLevel = Sift .fromAnywhere ().oneOrMore ().upperCaseLetters ();
120+ ConnectorStep < SiftContext . Fragment > message = Sift .fromAnywhere ().oneOrMore ().anyCharacter ();
116121
117122 // Assemble the final pattern like a natural language sentence
118123 String logParserRegex = dateBlock
@@ -125,7 +130,7 @@ void testLogParserRecipe() {
125130
126131 // you can also be more concise:
127132 String altLogParserRegex = dateBlock
128- .followedBy (List . of (tab , logLevel , tab , message , newline ))
133+ .followedBy (Arrays . asList (tab , logLevel , tab , message , newline ))
129134 .shake ();
130135
131136 // or be more verbose
@@ -156,17 +161,17 @@ void testStrictTokenValidatorRecipe() {
156161 // Notice the use of fromStart() here.
157162 // We enforce that the token MUST begin with this exact prefix,
158163 // anchoring the entire evaluation to the start of the string.
159- var prefix = Sift .fromStart ().exactly (2 ).upperCaseLetters ();
164+ CharacterClassConnectorStep < SiftContext . Root > prefix = Sift .fromStart ().exactly (2 ).upperCaseLetters ();
160165
161166 // The rest of the blocks use fromAnywhere() for composition
162- var body = Sift .fromAnywhere ().between (4 , 6 ).alphanumeric ();
163- var suffix = Sift .fromAnywhere ().oneOrMore ().punctuation ();
167+ CharacterClassConnectorStep < SiftContext . Fragment > body = Sift .fromAnywhere ().between (4 , 6 ).alphanumeric ();
168+ ConnectorStep < SiftContext . Fragment > suffix = Sift .fromAnywhere ().oneOrMore ().punctuation ();
164169
165- var underscore = Sift .fromAnywhere ().character ('_' );
170+ ConnectorStep < SiftContext . Fragment > underscore = Sift .fromAnywhere ().character ('_' );
166171
167172 // Create logical compound blocks
168- var prefixWithUnderscore = prefix .followedBy (underscore );
169- var bodyWithUnderscore = body .followedBy (underscore );
173+ ConnectorStep < SiftContext . Root > prefixWithUnderscore = prefix .followedBy (underscore );
174+ ConnectorStep < SiftContext . Fragment > bodyWithUnderscore = body .followedBy (underscore );
170175
171176 // Final assembly
172177 String securityTokenRegex = prefixWithUnderscore
@@ -191,7 +196,7 @@ void testStrictTokenValidatorRecipe() {
191196 @ DisplayName ("Recipe 4: IP Address Validation (Highly Reusable Blocks)" )
192197 void testIpAddressValidatorRecipe () {
193198 // built-in pattern for IPv4
194- var libIPv4 = SiftCatalog .ipv4 ();
199+ SiftPattern < SiftContext . Fragment > libIPv4 = SiftCatalog .ipv4 ();
195200
196201 // Building the IPv4 structure using the built-in pattern, enforcing anchor start and anchor end
197202 String ipv4Regex = Sift .fromStart ()
@@ -224,27 +229,27 @@ void testAdvancedExtractionRecipe() {
224229 char closeBracket = '>' ;
225230 String closingTagPrefix = "</" ;
226231
227- var tagName = Sift .fromAnywhere ().oneOrMore ().alphanumeric ();
228- var tagContent = Sift .fromAnywhere ().oneOrMore ().anyCharacter ();
232+ VariableCharacterClassConnectorStep < SiftContext . Fragment > tagName = Sift .fromAnywhere ().oneOrMore ().alphanumeric ();
233+ VariableConnectorStep < SiftContext . Fragment > tagContent = Sift .fromAnywhere ().oneOrMore ().anyCharacter ();
229234
230235 // 1. Defining Named Captures to extract specific data blocks
231- var groupTag = SiftPatterns .capture ("tag" , tagName );
232- var groupContent = SiftPatterns .capture ("content" , tagContent );
236+ NamedCapture groupTag = SiftPatterns .capture ("tag" , tagName );
237+ NamedCapture groupContent = SiftPatterns .capture ("content" , tagContent );
233238
234- var openTag = Sift .fromAnywhere ()
239+ ConnectorStep < SiftContext . Fragment > openTag = Sift .fromAnywhere ()
235240 .character (openBracket )
236241 .then ().namedCapture (groupTag )
237242 .then ().character (closeBracket );
238243
239- var content = Sift .fromAnywhere ().namedCapture (groupContent );
244+ ConnectorStep < SiftContext . Fragment > content = Sift .fromAnywhere ().namedCapture (groupContent );
240245
241- var closeTag = Sift .fromAnywhere ()
246+ ConnectorStep < SiftContext . Fragment > closeTag = Sift .fromAnywhere ()
242247 .pattern (literal (closingTagPrefix ))
243248 .then ().backreference (groupTag )
244249 .then ().character (closeBracket );
245250
246251 // 2. Building the pattern. Notice how SiftGlobalFlag is elegantly applied at the root!
247- var htmlTagPattern = Sift
252+ SiftPattern < SiftContext . Root > htmlTagPattern = Sift
248253 .filteringWith (SiftGlobalFlag .CASE_INSENSITIVE )
249254 .fromStart ()
250255 .pattern (openTag )
@@ -277,17 +282,17 @@ void testLookaheadAndAnyOfRecipe() {
277282 // Goal 1: Validate a complex password using Lookaheads
278283 // Must contain at least one uppercase, one digit, and be at least 8 chars long.
279284
280- var requiresUppercase = Sift .fromAnywhere ()
285+ ConnectorStep < SiftContext . Fragment > requiresUppercase = Sift .fromAnywhere ()
281286 .pattern (SiftPatterns .positiveLookahead (
282287 Sift .fromAnywhere ().zeroOrMore ().anyCharacter ().then ().exactly (1 ).upperCaseLetters ()
283288 ));
284289
285- var requiresDigit = Sift .fromAnywhere ()
290+ ConnectorStep < SiftContext . Fragment > requiresDigit = Sift .fromAnywhere ()
286291 .pattern (SiftPatterns .positiveLookahead (
287292 Sift .fromAnywhere ().zeroOrMore ().anyCharacter ().then ().exactly (1 ).digits ()
288293 ));
289294
290- var passwordPattern = Sift .fromStart ()
295+ String passwordPattern = Sift .fromStart ()
291296 .pattern (requiresUppercase )
292297 .then ().pattern (requiresDigit )
293298 .then ().between (8 , 64 ).anyCharacter ()
@@ -301,13 +306,13 @@ void testLookaheadAndAnyOfRecipe() {
301306
302307 // Goal 2: Match specific keywords using Alternation (anyOf)
303308 // Extracting valid HTTP methods
304- var httpMethodPattern = Sift .fromStart ()
309+ String httpMethodPattern = Sift .fromStart ()
305310 .pattern (SiftPatterns .anyOf (
306- SiftPatterns . literal ("GET" ),
307- SiftPatterns . literal ("POST" ),
308- SiftPatterns . literal ("PUT" ),
309- SiftPatterns . literal ("DELETE" ),
310- SiftPatterns . literal ("PATCH" )
311+ literal ("GET" ),
312+ literal ("POST" ),
313+ literal ("PUT" ),
314+ literal ("DELETE" ),
315+ literal ("PATCH" )
311316 ))
312317 .andNothingElse ()
313318 .shake ();
@@ -323,7 +328,7 @@ void testReDoSMitigationRecipe() {
323328 // We use the possessive modifier (.withoutBacktracking()) to tell the engine to NEVER give back
324329 // matched characters. This prevents infinite loop evaluations.
325330
326- var safePayloadExtractor = Sift .fromStart ()
331+ String safePayloadExtractor = Sift .fromStart ()
327332 .character ('{' )
328333 // We use wordCharacters() so it stops capturing BEFORE the '}'.
329334 // Using .withoutBacktracking() prevents the engine from trying alternative
@@ -342,7 +347,7 @@ void testReDoSMitigationRecipe() {
342347 assertDoesNotMatch (safePayloadExtractor , "{invalid payload}" );
343348
344349 // Example of LAZY matching (finding the shortest path instead of greedy)
345- var lazyTagExtractor = Sift .fromStart ()
350+ String lazyTagExtractor = Sift .fromStart ()
346351 .character ('<' )
347352 .then ().oneOrMore ().anyCharacter ().asFewAsPossible () // Translates to "+?"
348353 .then ().character ('>' )
0 commit comments